3857 lines
156 KiB
C#
3857 lines
156 KiB
C#
using CMS_CORE_Library;
|
|
using CMS_CORE_Library.Models;
|
|
using CMS_CORE_Library.S7Net;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Configuration;
|
|
using System.Globalization;
|
|
using System.Linq;
|
|
using Thermo.Active.Database.Controllers;
|
|
using Thermo.Active.Model.ConfigModels;
|
|
using Thermo.Active.Model.DatabaseModels;
|
|
using Thermo.Active.Model.DTOModels;
|
|
using Thermo.Active.Model.DTOModels.AlarmModels;
|
|
using Thermo.Active.Model.DTOModels.MaintenanceModels;
|
|
using Thermo.Active.Model.DTOModels.Scada;
|
|
using Thermo.Active.Model.DTOModels.ThAxes;
|
|
using Thermo.Active.Model.DTOModels.ThIO;
|
|
using Thermo.Active.Model.DTOModels.ThModules;
|
|
using Thermo.Active.Model.DTOModels.ThProd;
|
|
using Thermo.Active.Model.DTOModels.ThRecipe;
|
|
using Thermo.Active.Model.DTOModels.ThSchedulModels;
|
|
using Thermo.Active.Model.DTOModels.ThWarmers;
|
|
using Thermo.Active.Utils;
|
|
using static CMS_CORE_Library.Models.DataStructures;
|
|
using static Thermo.Active.Config.ServerConfig;
|
|
using static Thermo.Active.Model.Constants;
|
|
|
|
namespace Thermo.Active.NC
|
|
{
|
|
public class NcAdapter : IDisposable
|
|
{
|
|
#region Private Fields
|
|
|
|
/// <summary>
|
|
/// Lock semaphore for PLC connection step
|
|
/// </summary>
|
|
private readonly static object connectLock = new object();
|
|
|
|
/// <summary>
|
|
/// variabili delle richieste da PLC: tutte nella status command
|
|
/// </summary>
|
|
private static List<ushort> statusCmd = new List<ushort>();
|
|
|
|
#endregion Private Fields
|
|
|
|
#region Protected Fields
|
|
|
|
/// <summary>
|
|
/// Indica che per i dati del prodPanel è necessario rileggere il DB (modificato)
|
|
/// </summary>
|
|
protected static bool forceProdPanelDbReload = false;
|
|
|
|
/// <summary>
|
|
/// Last recipe data from PLC
|
|
/// </summary>
|
|
protected static Dictionary<int, DTOAxisInfoModel> lastAxisData = new Dictionary<int, DTOAxisInfoModel>();
|
|
|
|
/// <summary>
|
|
/// Last AxisInfo data from PLC
|
|
/// </summary>
|
|
protected static Dictionary<int, ThermoModels.AxisInfo> lastAxisInfoReadData = new Dictionary<int, ThermoModels.AxisInfo>();
|
|
|
|
|
|
/// <summary>
|
|
/// Last LogCycle data from PLC
|
|
/// </summary>
|
|
protected static DTOCycleLog lastCycleLogData = new DTOCycleLog();
|
|
|
|
/// <summary>
|
|
/// Last prod info from PLC
|
|
/// </summary>
|
|
protected static ThermoModels.ProdInfoModel lastProdInfoData = new ThermoModels.ProdInfoModel();
|
|
|
|
/// <summary>
|
|
/// Ultimi dati prodPanel
|
|
/// </summary>
|
|
protected static DTOThermoPanelProd LastProdPanelData = new DTOThermoPanelProd();
|
|
|
|
/// <summary>
|
|
/// Last recipe data from PLC
|
|
/// </summary>
|
|
protected static Dictionary<string, DTORecipeParam> lastRecipe = new Dictionary<string, DTORecipeParam>();
|
|
|
|
/// <summary>
|
|
/// Immagine corrente dalla thermocam (FISSA)
|
|
/// </summary>
|
|
protected string currThermoImage = "_last.jpg";
|
|
|
|
/// <summary>
|
|
/// Ultimo ciclo registrato (secondi)
|
|
/// </summary>
|
|
protected double lastCycle = 9999;
|
|
|
|
/// <summary>
|
|
/// Ultimo ciclo NETTO registrato (secondi)
|
|
/// </summary>
|
|
protected double lastCycleNet = 9999;
|
|
|
|
/// <summary>
|
|
/// Ultima fine prod pz
|
|
/// </summary>
|
|
protected DateTime lastProdEnd;
|
|
|
|
/// <summary>
|
|
/// Ultimo avvio prod pz
|
|
/// </summary>
|
|
protected DateTime lastProdStart;
|
|
|
|
#endregion Protected Fields
|
|
|
|
#region Public Fields
|
|
|
|
/// <summary>
|
|
/// Versione Live dei task schedulati
|
|
/// </summary>
|
|
public static List<DTOSchedTaskModels> LiveSchedTask = new List<DTOSchedTaskModels>();
|
|
|
|
/// <summary>
|
|
/// Recipe Live data
|
|
/// </summary>
|
|
public static LiveData RecipeLiveData = new LiveData();
|
|
|
|
/// <summary>
|
|
/// ultima immagine scattata dalla thermocam x salvataggio in PROD
|
|
/// </summary>
|
|
public static string lastThermoImage = "_last";
|
|
|
|
/// <summary>
|
|
/// Avvio prod lotto
|
|
/// </summary>
|
|
public DateTime lottoStart = DateTime.Today;
|
|
|
|
/// <summary>
|
|
/// NC object
|
|
/// </summary>
|
|
public NcThermo numericalControl;
|
|
|
|
/// <summary>
|
|
/// Indica se la FLIR camera è connessa
|
|
/// </summary>
|
|
public static bool cameraIsConnected = false;
|
|
|
|
#endregion Public Fields
|
|
|
|
#region Public Constructors
|
|
|
|
public NcAdapter() =>
|
|
// Choose NC
|
|
numericalControl = SetNumericalControl();
|
|
|
|
#endregion Public Constructors
|
|
|
|
#region Private Properties
|
|
|
|
private static bool ThermoCameraReqImage
|
|
{
|
|
get
|
|
{
|
|
bool answ = false;
|
|
if (statusCmd != null)
|
|
{
|
|
if (statusCmd.Count > 0)
|
|
{
|
|
try
|
|
{
|
|
answ = checkBitOnWord(statusCmd[0], 12);
|
|
}
|
|
catch
|
|
{ }
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
}
|
|
|
|
private static bool ThermoFlirImageReq
|
|
{
|
|
get
|
|
{
|
|
bool answ = false;
|
|
if (statusCmd != null)
|
|
{
|
|
if (statusCmd.Count > 0)
|
|
{
|
|
try
|
|
{
|
|
answ = checkBitOnWord(statusCmd[0], 12);
|
|
}
|
|
catch
|
|
{ }
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
}
|
|
|
|
private static bool ThermoProdEndStr
|
|
{
|
|
get
|
|
{
|
|
bool answ = false;
|
|
if (statusCmd != null)
|
|
{
|
|
if (statusCmd.Count > 0)
|
|
{
|
|
try
|
|
{
|
|
answ = checkBitOnWord(statusCmd[0], 11);
|
|
}
|
|
catch
|
|
{ }
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
}
|
|
|
|
private static bool ThermoProdStartStr
|
|
{
|
|
get
|
|
{
|
|
bool answ = false;
|
|
if (statusCmd != null)
|
|
{
|
|
if (statusCmd.Count > 0)
|
|
{
|
|
try
|
|
{
|
|
answ = checkBitOnWord(statusCmd[0], 10);
|
|
}
|
|
catch
|
|
{ }
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
}
|
|
|
|
private static bool ThermoProdUpdatedStr
|
|
{
|
|
get
|
|
{
|
|
bool answ = false;
|
|
if (statusCmd != null)
|
|
{
|
|
if (statusCmd.Count > 0)
|
|
{
|
|
try
|
|
{
|
|
answ = checkBitOnWord(statusCmd[0], 3);
|
|
}
|
|
catch
|
|
{ }
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
}
|
|
|
|
private static bool ThermoReqConfRecipeStr
|
|
{
|
|
get
|
|
{
|
|
bool answ = false;
|
|
if (statusCmd.Count > 0)
|
|
{
|
|
try
|
|
{
|
|
answ = checkBitOnWord(statusCmd[0], 8);
|
|
}
|
|
catch
|
|
{ }
|
|
}
|
|
return answ;
|
|
}
|
|
}
|
|
|
|
private static bool ThermoReqConfWarmerStr
|
|
{
|
|
get
|
|
{
|
|
bool answ = false;
|
|
if (statusCmd.Count > 0)
|
|
{
|
|
try
|
|
{
|
|
answ = checkBitOnWord(statusCmd[0], 7);
|
|
}
|
|
catch
|
|
{ }
|
|
}
|
|
return answ;
|
|
}
|
|
}
|
|
|
|
private static bool ThermoSetpointHmiInvalidated
|
|
{
|
|
get
|
|
{
|
|
bool answ = false;
|
|
if (statusCmd != null)
|
|
{
|
|
if (statusCmd.Count > 0)
|
|
{
|
|
try
|
|
{
|
|
answ = checkBitOnWord(statusCmd[0], 14);
|
|
}
|
|
catch
|
|
{ }
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
}
|
|
|
|
#endregion Private Properties
|
|
|
|
#region Public Properties
|
|
|
|
/// <summary>
|
|
/// Delay between single param write operation
|
|
/// </summary>
|
|
public int delayParamWrite
|
|
{
|
|
get
|
|
{
|
|
int answ = 5;
|
|
int.TryParse(ConfigurationManager.AppSettings["delayParamWrite"], out answ);
|
|
return answ;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parametro lambda per EWMA smoothing
|
|
/// </summary>
|
|
public double ewmaLambda
|
|
{
|
|
get
|
|
{
|
|
int answ = 50;
|
|
int.TryParse(ConfigurationManager.AppSettings["ewmaPar100"], out answ);
|
|
return (double)answ / 100;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Max number of param writable as single operation
|
|
/// </summary>
|
|
public int nMaxParamWrite
|
|
{
|
|
get
|
|
{
|
|
int answ = 5;
|
|
int.TryParse(ConfigurationManager.AppSettings["nMaxParamWrite"], out answ);
|
|
return answ;
|
|
}
|
|
}
|
|
|
|
#endregion Public Properties
|
|
|
|
#region Private Methods
|
|
|
|
private int GetMaxCountBetweenLayerComponents(ScadaSchemaLayerModel layer)
|
|
{
|
|
// Choose which list contains the maximum number of elements
|
|
int max = layer.Buttons.Count();
|
|
|
|
if (layer.Labels.Count() > max)
|
|
max = layer.Labels.Count();
|
|
|
|
if (layer.Images.Count() > max)
|
|
max = layer.Images.Count();
|
|
|
|
if (layer.Inputs.Count() > max)
|
|
max = layer.Inputs.Count();
|
|
|
|
if (layer.ProgressBars.Count() > max)
|
|
max = layer.ProgressBars.Count();
|
|
|
|
return max;
|
|
}
|
|
|
|
#endregion Private Methods
|
|
|
|
#region Protected Methods
|
|
|
|
/// <summary>
|
|
/// Check bit on word
|
|
/// </summary>
|
|
/// <param name="value"></param>
|
|
/// <param name="numBit"></param>
|
|
/// <returns></returns>
|
|
protected static bool checkBitOnWord(ushort value, int numBit)
|
|
{
|
|
bool answ = false;
|
|
try
|
|
{
|
|
ushort pow = (ushort)(1 << numBit);
|
|
answ = (value & pow) == pow;
|
|
}
|
|
catch
|
|
{ }
|
|
return answ;
|
|
}
|
|
|
|
protected double getDimRatio(DTORecipeParam singlePar)
|
|
{
|
|
double ratio = 1;
|
|
if (singlePar != null)
|
|
{
|
|
try
|
|
{
|
|
if (singlePar.Range.Max > 0)
|
|
ratio = singlePar.SetpointPLC / singlePar.Range.Max;
|
|
}
|
|
catch
|
|
{ }
|
|
}
|
|
return ratio;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Conversione stringa --> enum
|
|
/// </summary>
|
|
/// <param name="strVal"></param>
|
|
/// <returns></returns>
|
|
protected RecipeSection getRecipeSection(string strVal)
|
|
{
|
|
RecipeSection answ = (RecipeSection)Enum.Parse(typeof(RecipeSection), strVal, true);
|
|
|
|
return answ;
|
|
}
|
|
|
|
protected string getUM(int um)
|
|
{
|
|
// default: no translation...
|
|
string answ = $"{um}";
|
|
// cerco in dictionary...
|
|
if (UnitMeasuresConfig.ContainsKey(um))
|
|
{
|
|
answ = UnitMeasuresConfig[um];
|
|
}
|
|
return answ;
|
|
}
|
|
|
|
#endregion Protected Methods
|
|
|
|
#region Public Methods
|
|
|
|
public CmsError checkFlirImageRequest(out bool flirImageRequest)
|
|
{
|
|
flirImageRequest = ThermoCameraReqImage;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
public CmsError checkSetpointInvalidated(out bool setpointHmiInvalidated)
|
|
{
|
|
setpointHmiInvalidated = ThermoSetpointHmiInvalidated;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Comando conferma dati ricetta
|
|
/// </summary>
|
|
/// <param name="confirmUpdate">true: HMI --> PLC, false: PLC --> HMI</param>
|
|
/// <returns></returns>
|
|
public CmsError ConfirmRecipeData(bool confirmUpdate)
|
|
{
|
|
// solo x S7...
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
// call NC for update
|
|
CmsError libraryError = numericalControl.PLC_WRecipeEdit(confirmUpdate);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
}
|
|
else
|
|
{
|
|
return FUNCTION_NOT_ALLOWED_ERROR;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
public CmsError Connect()
|
|
{
|
|
lock (connectLock)
|
|
{
|
|
// Connect NC
|
|
if (!numericalControl.NC_IsConnected())
|
|
return numericalControl.NC_Connect();
|
|
}
|
|
lastProdStart = DateTime.Now;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
public void Disconnect()
|
|
{
|
|
numericalControl.NC_Disconnect();
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
if (NcConfig.NcVendor != NC_VENDOR.SIEMENS)
|
|
numericalControl.NC_Disconnect();
|
|
}
|
|
|
|
public CmsError doAckSetpointInvalidated()
|
|
{
|
|
numericalControl.PLC_WAckSetpointInvalidated();
|
|
return NO_ERROR;
|
|
}
|
|
|
|
public CmsError GetActiveClient(out int clientId)
|
|
{
|
|
clientId = 0;
|
|
return numericalControl.PLC_RActiveClient(ref clientId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce elenco di eventi LOG del ciclo
|
|
/// </summary>
|
|
/// <param name="doRefresh">Ricarica da PLC il cycle log o rilegge solamente</param>
|
|
/// <param name="machineLog">Oggetto elenco elementi LOG registrati da macchina</param>
|
|
/// <returns></returns>
|
|
public CmsError GetCycleLog(int from, int to, out DTOCycleLog currCycleLog)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
currCycleLog = new DTOCycleLog();
|
|
|
|
// fix valori
|
|
from = from > 0 ? from - 1 : 0;
|
|
//selezione
|
|
currCycleLog.events = lastCycleLogData.events.Skip(from).Take(to - from).ToList();
|
|
|
|
// restituisco cod errore se trovato
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Legge dal PLC elenco di eventi LOG del ciclo e li salva in memoria
|
|
/// </summary>
|
|
/// <param name="machineLog">Oggetto elenco elementi LOG registrati da macchina</param>
|
|
/// <returns></returns>
|
|
public CmsError RefreshCycleLog(out int numRec)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
DTOCycleLog machineLog = new DTOCycleLog();
|
|
|
|
// recupero l'oggetto dall'NC...
|
|
List<ThermoModels.LogCycleData> currLogCycleData = new List<ThermoModels.LogCycleData>();
|
|
// get LogCycle Data
|
|
libraryError = numericalControl.PLC_RLogCycleData(out currLogCycleData);
|
|
|
|
// effettuo traduzione e riordino
|
|
foreach (var item in currLogCycleData.OrderByDescending(i => i.DtEvent))
|
|
{
|
|
machineLog.events.Add(new CycleEvent() { dtEvent = item.DtEvent, code = item.Code });
|
|
}
|
|
// salvo
|
|
lastCycleLogData = machineLog;
|
|
|
|
numRec = machineLog.events.Count;
|
|
|
|
// restituisco cod errore se trovato
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Legge dal PLC elenco di eventi LOG del ciclo e li salva in memoria
|
|
/// </summary>
|
|
/// <param name="machineLog">Oggetto elenco elementi LOG registrati da macchina</param>
|
|
/// <returns></returns>
|
|
public CmsError SendAxisCommand(int AxisId, Model.DTOModels.ThAxes.AxisCommand currCommand, double TargetPos)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
Dictionary<DateTime, int> machineLog = new Dictionary<DateTime, int>();
|
|
|
|
// sistemo i valori...
|
|
bool writeTargetPos = currCommand == AxisCommand.Reset;
|
|
uint biteCommand = 0;
|
|
bool doWrite = false;
|
|
switch (currCommand)
|
|
{
|
|
case AxisCommand.None:
|
|
break;
|
|
case AxisCommand.MoveAbsolute:
|
|
doWrite = true;
|
|
biteCommand = 1;
|
|
break;
|
|
case AxisCommand.JogIncPlus:
|
|
doWrite = true;
|
|
biteCommand = 2;
|
|
break;
|
|
case AxisCommand.JogIncMinus:
|
|
doWrite = true;
|
|
biteCommand = 3;
|
|
break;
|
|
case AxisCommand.Align:
|
|
doWrite = true;
|
|
biteCommand = 4;
|
|
break;
|
|
case AxisCommand.Probe:
|
|
doWrite = true;
|
|
biteCommand = 5;
|
|
break;
|
|
case AxisCommand.SetSlavePosition:
|
|
doWrite = true;
|
|
biteCommand = 6;
|
|
break;
|
|
case AxisCommand.Reset:
|
|
doWrite = true;
|
|
biteCommand = 7;
|
|
break;
|
|
case AxisCommand.Num07:
|
|
break;
|
|
case AxisCommand.Num08:
|
|
break;
|
|
case AxisCommand.Num09:
|
|
break;
|
|
case AxisCommand.Num10:
|
|
break;
|
|
case AxisCommand.Num11:
|
|
break;
|
|
case AxisCommand.Num12:
|
|
break;
|
|
case AxisCommand.Num13:
|
|
break;
|
|
case AxisCommand.Num14:
|
|
break;
|
|
case AxisCommand.Num15:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (doWrite)
|
|
{
|
|
// effettua chaiamta!
|
|
libraryError = numericalControl.PLC_WAxisCommand(AxisId, biteCommand, writeTargetPos, TargetPos);
|
|
}
|
|
|
|
// restituisco cod errore se trovato
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError GetExpiredMaintenances(out List<DTOExpiredMaintenanceModel> expiredMaintenance)
|
|
{
|
|
// Return value
|
|
expiredMaintenance = new List<DTOExpiredMaintenanceModel>();
|
|
|
|
// Get counters values from PLC
|
|
CmsError libraryError = GetMainenancesCounter(out List<CounterModel> counters);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
using (MaintenancesController maintenancesController = new MaintenancesController())
|
|
{
|
|
// Get the last performed maintenance for each maintenance
|
|
List<PerformedMaintenanceModel> performedMaintenances = maintenancesController.FindLastPerformedMaintenances();
|
|
|
|
// Get all the active maintenances
|
|
List<MaintenanceModel> maintenances = maintenancesController.FindAll(); // TODO db or config file?
|
|
|
|
foreach (var currMaintenance in maintenances)
|
|
{
|
|
// Get matching last performed maintenance for current maintenance
|
|
var performed = performedMaintenances.Find(x => x.MaintenanceId == currMaintenance.MaintenanceId);
|
|
|
|
switch (currMaintenance.Type)
|
|
{
|
|
case MAINTENANCE_TYPE.MACHINE_INTERVAL:
|
|
{
|
|
// Get matching counter for the current maintenance
|
|
var counter = counters.Find(x => x.Id == currMaintenance.CounterId);
|
|
|
|
int perfVal = 0;
|
|
if (performed != null)
|
|
perfVal = performed.CounterValue;
|
|
|
|
// MAINTENANCE_INTERVAL <= PLC - LASTPERFORMED
|
|
if (SupportFunctions.ConvertInMinutes(currMaintenance.Interval.Value, currMaintenance.UnitOfMeasure.Value) <= (counter.Value / 60) - perfVal)
|
|
{
|
|
// Update last expiration date if null
|
|
if (currMaintenance.LastExpirationDate == null)
|
|
{
|
|
maintenancesController.UpdateLastExpirationDate(currMaintenance.MaintenanceId, DateTime.Now);
|
|
currMaintenance.LastExpirationDate = DateTime.Now;
|
|
}
|
|
|
|
// Add item to return list
|
|
expiredMaintenance.Add(new DTOExpiredMaintenanceModel()
|
|
{
|
|
Id = currMaintenance.MaintenanceId,
|
|
ExpirationDate = (DateTime)currMaintenance.LastExpirationDate,
|
|
CreatedByCms = currMaintenance.UserId == null,
|
|
Title = currMaintenance.UserId == null ? "" : currMaintenance.Title
|
|
});
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MAINTENANCE_TYPE.EXP_DATE:
|
|
{
|
|
// Already performed
|
|
if (performed != null)
|
|
break;
|
|
// DEADLINE <= NOW
|
|
if (currMaintenance.Deadline <= DateTime.Now)
|
|
{
|
|
maintenancesController.UpdateLastExpirationDate(currMaintenance.MaintenanceId, currMaintenance.Deadline);
|
|
currMaintenance.LastExpirationDate = currMaintenance.Deadline;
|
|
|
|
// Add item to return list
|
|
expiredMaintenance.Add(new DTOExpiredMaintenanceModel()
|
|
{
|
|
Id = currMaintenance.MaintenanceId,
|
|
ExpirationDate = currMaintenance.Deadline,
|
|
CreatedByCms = currMaintenance.UserId == null,
|
|
Title = currMaintenance.UserId == null ? "" : currMaintenance.Title,
|
|
});
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MAINTENANCE_TYPE.TIME_INTERVAL:
|
|
{
|
|
// Get last performed, default value is maintenance creation date
|
|
DateTime perfDate = currMaintenance.CreationDate;
|
|
if (performed != null)
|
|
perfDate = performed.Date;
|
|
|
|
// Now - last performed = elapsed interval since last maintenance
|
|
TimeSpan timePassedFromLastMaint = DateTime.Now.Subtract(perfDate);
|
|
// Convert in minutes
|
|
double minutesPassedFromLastMaint = timePassedFromLastMaint.TotalMinutes;
|
|
|
|
// Interval - passed minutes since last maintenance
|
|
if (SupportFunctions.ConvertInMinutes(currMaintenance.Interval.Value, currMaintenance.UnitOfMeasure.Value) <= minutesPassedFromLastMaint)
|
|
{
|
|
// Update last expiration date
|
|
if (currMaintenance.LastExpirationDate == null)
|
|
{
|
|
// Exp date = now - ( expiration intervall)
|
|
DateTime expirationDate = DateTime.Now.Subtract(TimeSpan.FromMinutes(minutesPassedFromLastMaint - currMaintenance.Interval.Value));
|
|
|
|
maintenancesController.UpdateLastExpirationDate(currMaintenance.MaintenanceId, expirationDate);
|
|
currMaintenance.LastExpirationDate = expirationDate;
|
|
}
|
|
|
|
// Add item to return list
|
|
expiredMaintenance.Add(new DTOExpiredMaintenanceModel()
|
|
{
|
|
Id = currMaintenance.MaintenanceId,
|
|
ExpirationDate = (DateTime)currMaintenance.LastExpirationDate,
|
|
CreatedByCms = currMaintenance.UserId == null,
|
|
Title = currMaintenance.UserId == null ? "" : currMaintenance.Title,
|
|
});
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError GetFunctionsMappedWithNC(out List<DTORuntimeFunctionalityModel> functionsAccessList)
|
|
{
|
|
functionsAccessList = new List<DTORuntimeFunctionalityModel>();
|
|
// Read plc functionality
|
|
List<FunctionalityModel> functionalityList = null;
|
|
CmsError libraryError = numericalControl.PLC_RFunctionAccess(ref functionalityList);
|
|
|
|
// If empty return
|
|
if (functionalityList == null || functionalityList.Count == 0)
|
|
return libraryError;
|
|
|
|
using (FunctionsAccessController functionsAccessController = new FunctionsAccessController())
|
|
{
|
|
// Map plc and database data
|
|
functionsAccessList = functionsAccessController.GetFunctionsMappedWithPlc(functionalityList);
|
|
}
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError GetHeadsData(out List<DTOHeadModel> heads)
|
|
{
|
|
// Returned value
|
|
heads = new List<DTOHeadModel>();
|
|
// Number of configured heads
|
|
int headsNumber = HeadsConfig.Count;
|
|
|
|
List<HeadDataModel> plcHeads = new List<HeadDataModel>();
|
|
// Read value from PLC
|
|
CmsError libraryError = numericalControl.PLC_RHeadsData(plcHeads, headsNumber);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
foreach (var head in plcHeads)
|
|
{
|
|
// Get current head config
|
|
var configuredHead = HeadsConfig.Find(x => x.Id == head.Id);
|
|
// Create different model according on type
|
|
|
|
// 2020.08.27 update core.library ha sminchionato --> commentato!
|
|
#if false
|
|
switch (configuredHead.Type)
|
|
{
|
|
case HEAD_TYPE.SPINDLE:
|
|
{
|
|
heads.Add(new DTOSpindleModel()
|
|
{
|
|
Id = head.Id,
|
|
Process = head.Process,
|
|
Type = configuredHead.Type.ToString(),
|
|
FixedHead = configuredHead.FixedHead,
|
|
inWarning = head.Load_Abrasive >= configuredHead.WarningLimit,
|
|
inAlarm = head.Load_Abrasive >= configuredHead.AlarmLimit,
|
|
OverrideEditable = head.OverrideEditable,
|
|
ActualSpeed = head.ActualSpeed_Pressure,
|
|
Load = head.Load_Abrasive,
|
|
Override = head.Override,
|
|
IsActive = head.IsActive,
|
|
IsSelected = head.IsSelected,
|
|
AbrasiveIsActive = head.AbrasiveIsActive,
|
|
Configured = head.Configured,
|
|
Rotation = head.Rotation,
|
|
WorkedTime = head.WorkedTime
|
|
});
|
|
}
|
|
break;
|
|
|
|
case HEAD_TYPE.WJ:
|
|
{
|
|
heads.Add(new DTOWaterJet()
|
|
{
|
|
Id = head.Id,
|
|
Process = head.Process,
|
|
Type = configuredHead.Type.ToString(),
|
|
FixedHead = configuredHead.FixedHead,
|
|
inAlarm = false,
|
|
inWarning = false,
|
|
ActualPressure = head.ActualSpeed_Pressure,
|
|
OverrideEditable = head.OverrideEditable,
|
|
Override = head.Override,
|
|
IsActive = head.IsActive,
|
|
IsSelected = head.IsSelected,
|
|
AbrasiveIsActive = head.AbrasiveIsActive,
|
|
WorkedTime = head.WorkedTime
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get historical prodinfo data from DB (paginated ASC by date)
|
|
/// </summary>
|
|
/// <param name="prodInfoDataList"></param>
|
|
/// <param name="numStart">Num start</param>
|
|
/// <param name="numRec">num rec to retrieve, ex 30 (--> 50..80)</param>
|
|
/// <returns></returns>
|
|
public CmsError GetHistProdInfoDataAsc(out List<ThermoModels.ProdInfoModel> prodInfoDataList, int numStart, int numRec)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
prodInfoDataList = new List<ThermoModels.ProdInfoModel>();
|
|
|
|
using (ProdInfoController prodInfoController = new ProdInfoController())
|
|
{
|
|
List<ProdInfoModel> results = prodInfoController.GetPaginatedAsc(numStart, numRec);
|
|
// converto!
|
|
prodInfoDataList = results.Select(x => new ThermoModels.ProdInfoModel()
|
|
{
|
|
DtEvent = x.DtEvent,
|
|
NumTarget = x.NumTarget,
|
|
NumDone = x.NumDone,
|
|
// FIXME TODO: eliminare caso vuoto con immagine "_last"
|
|
ThermoImage = !string.IsNullOrEmpty(x.ThermoImage) ? x.ThermoImage : "_last.jpg",
|
|
TimeWarm = x.TimeWarm,
|
|
TimeVent = x.TimeVent,
|
|
TimeVacuum = x.TimeVacuum,
|
|
TimeCycleGross = x.TimeCycleGross,
|
|
TimeCycleNet = x.TimeCycleNet,
|
|
MaterialTempEndWarm = x.MaterialTempEndWarm,
|
|
MaterialTempEndVent = x.MaterialTempEndVent,
|
|
MoldTemp = x.MoldTemp,
|
|
VacuumReadVal = x.VacuumReadVal,
|
|
MouldEnergyOUT = x.MouldEnergyOUT,
|
|
MouldEnergyIN = x.MouldEnergyIN,
|
|
IsScrap = x.IsScrap
|
|
}).ToList();
|
|
}
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get historical prodinfo data from DB (paginated DESC by date)
|
|
/// </summary>
|
|
/// <param name="prodInfoDataList"></param>
|
|
/// <param name="numStart">First value, ex 100</param>
|
|
/// <param name="numRec">num rec to retrieve, ex 30 (--> 70..100)</param>
|
|
/// <returns></returns>
|
|
public CmsError GetHistProdInfoDataDesc(out List<ThermoModels.ProdInfoModel> prodInfoDataList, int numStart, int numRec)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
prodInfoDataList = new List<ThermoModels.ProdInfoModel>();
|
|
|
|
using (ProdInfoController prodInfoController = new ProdInfoController())
|
|
{
|
|
List<ProdInfoModel> results = prodInfoController.GetPaginatedDesc(numStart, numRec);
|
|
// converto!
|
|
prodInfoDataList = results.Select(x => new ThermoModels.ProdInfoModel()
|
|
{
|
|
DtEvent = x.DtEvent,
|
|
NumTarget = x.NumTarget,
|
|
NumDone = x.NumDone,
|
|
// FIXME TODO: eliminare caso vuoto con immagine "_last"
|
|
ThermoImage = !string.IsNullOrEmpty(x.ThermoImage) ? x.ThermoImage : "_last.jpg",
|
|
TimeWarm = x.TimeWarm,
|
|
TimeVent = x.TimeVent,
|
|
TimeVacuum = x.TimeVacuum,
|
|
TimeCycleGross = x.TimeCycleGross,
|
|
TimeCycleNet = x.TimeCycleNet,
|
|
MaterialTempEndWarm = x.MaterialTempEndWarm,
|
|
MaterialTempEndVent = x.MaterialTempEndVent,
|
|
MoldTemp = x.MoldTemp,
|
|
VacuumReadVal = x.VacuumReadVal,
|
|
MouldEnergyOUT = x.MouldEnergyOUT,
|
|
MouldEnergyIN = x.MouldEnergyIN,
|
|
IsScrap = x.IsScrap
|
|
}).ToList();
|
|
}
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError GetM154Data(out List<M154DataModel> data, out bool MTCStatus)
|
|
{
|
|
MTCStatus = false;
|
|
data = new List<M154DataModel>();
|
|
|
|
return numericalControl.PLC_RM154Data(ref data, ref MTCStatus);
|
|
}
|
|
|
|
public CmsError GetM155Data(out List<DTOM155InputModel> data)
|
|
{
|
|
data = new List<DTOM155InputModel>();
|
|
List<M155InputIsNeededModel> ncData = new List<M155InputIsNeededModel>();
|
|
CmsError libraryError = numericalControl.PLC_ROperatorInputIsNeeded(ref ncData);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
data = ncData.Select(x => new DTOM155InputModel()
|
|
{
|
|
Buttons = x.Buttons,
|
|
IsNeeded = x.IsNeeded,
|
|
Message = x.Message,
|
|
Process = x.Process,
|
|
Type = x.Type.ToString(),
|
|
Value = x.Value
|
|
}).ToList();
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
public CmsError GetM156Data(out List<DTOM156InputModel> data)
|
|
{
|
|
data = new List<DTOM156InputModel>();
|
|
List<M156InputIsNeededModel> ncData = new List<M156InputIsNeededModel>();
|
|
CmsError cmsError = numericalControl.PLC_RM156Data(ref ncData);
|
|
if (cmsError.IsError())
|
|
return cmsError;
|
|
|
|
if (ncData.Count() > 0)
|
|
{
|
|
foreach (var m156Message in ncData)
|
|
{
|
|
var inp = InputsOperatorConfig.Where(x => m156Message.Id == x.Id).FirstOrDefault();
|
|
|
|
if (inp != null)
|
|
{
|
|
var buttons = inp.Buttons?.ToDictionary(x => x.Key, x => x.Key.ToString());
|
|
data.Add(new DTOM156InputModel()
|
|
{
|
|
Id = inp.Id,
|
|
isM156 = true,
|
|
Buttons = buttons,
|
|
Type = inp.Type,
|
|
Process = m156Message.Process,
|
|
Value = m156Message.Value
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
public CmsError GetMainenancesCounter(out List<CounterModel> counters)
|
|
{
|
|
// List of PLC counters
|
|
counters = new List<CounterModel>();
|
|
// Get counters values from PLC
|
|
CmsError libraryError = numericalControl.PLC_RMachineCounters(ref counters);
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError GetMaintenanceDataById(int maintenanceId, int userId, out DTOMaintenanceModel dTOMaintenance)
|
|
{
|
|
dTOMaintenance = null;
|
|
|
|
CmsError libraryError = GetMaintenancesWithPermissions(out List<DTOMaintenanceModel> maintenance, userId);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
dTOMaintenance = maintenance.Where(x => x.Id == maintenanceId).FirstOrDefault();
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError GetMaintenancesWithPermissions(out List<DTOMaintenanceModel> dtoMaintenancesModel, int userId)
|
|
{
|
|
// Return value
|
|
dtoMaintenancesModel = new List<DTOMaintenanceModel>();
|
|
|
|
// Get counters values from PLC
|
|
CmsError libraryError = GetMainenancesCounter(out List<CounterModel> counters);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
using (MaintenancesController maintenancesController = new MaintenancesController())
|
|
{
|
|
// Get the last performed maintenance for each maintenance
|
|
List<PerformedMaintenanceModel> performedMaintenances = maintenancesController.FindLastPerformedMaintenances();
|
|
|
|
// Get all the active maintenances
|
|
List<MaintenanceModel> maintenances = maintenancesController.FindAll(); // TODO db or config file?
|
|
|
|
double percentage = 0;
|
|
TimeSpan missingDays = new TimeSpan();
|
|
CounterModel counter = new CounterModel();
|
|
uint counterValue = 0;
|
|
|
|
bool canEdit = false;
|
|
bool canPerform = false;
|
|
foreach (var currMaintenance in maintenances)
|
|
{
|
|
// Get matching last performed maintenance for current maintenance
|
|
PerformedMaintenanceModel performed = performedMaintenances.Find(x => x.MaintenanceId == currMaintenance.MaintenanceId);
|
|
|
|
switch (currMaintenance.Type)
|
|
{
|
|
case MAINTENANCE_TYPE.MACHINE_INTERVAL:
|
|
{
|
|
// Get matching counter for the current maintenance
|
|
counter = counters.Find(x => x.Id == currMaintenance.CounterId);
|
|
|
|
// Convert from seconds to minuts
|
|
var counterVal = counter.Value / 60;
|
|
|
|
int perfVal = 0;
|
|
if (performed != null)
|
|
perfVal = performed.CounterValue;
|
|
|
|
counterValue = (uint)Math.Ceiling(SupportFunctions.ConvertInUmeas(counterVal, currMaintenance.UnitOfMeasure.Value));
|
|
|
|
// Calc percentage = PLC - PERFORMED VALUE * 100 / interval
|
|
percentage = ((counterVal - perfVal) * 100) / SupportFunctions.ConvertInMinutes(currMaintenance.Interval.Value, currMaintenance.UnitOfMeasure.Value);
|
|
missingDays = TimeSpan.FromMinutes(-1 * (counterVal - perfVal - SupportFunctions.ConvertInMinutes(currMaintenance.Interval.Value, currMaintenance.UnitOfMeasure.Value)));
|
|
}
|
|
break;
|
|
|
|
case MAINTENANCE_TYPE.EXP_DATE:
|
|
{
|
|
// Already performed
|
|
if (performed != null)
|
|
{
|
|
percentage = 100;
|
|
missingDays = TimeSpan.Zero;
|
|
}
|
|
else
|
|
{
|
|
percentage = ((DateTime.Now - currMaintenance.CreationDate).TotalMinutes * 100) / (currMaintenance.Deadline - currMaintenance.CreationDate).TotalMinutes; // TimeSpan.FromTicks((currMaintenance.Deadline.Ticks)).TotalMinutes
|
|
missingDays = currMaintenance.Deadline - DateTime.Now;
|
|
counter = new CounterModel();
|
|
}
|
|
}
|
|
break;
|
|
|
|
case MAINTENANCE_TYPE.TIME_INTERVAL:
|
|
{
|
|
// Get last performed, default value is maintenance creation date
|
|
DateTime perfDate = currMaintenance.CreationDate;
|
|
if (performed != null)
|
|
perfDate = performed.Date;
|
|
|
|
// Now - last performed = elapsed interval since last maintenance
|
|
TimeSpan timePassedFromLastMaint = DateTime.Now.Subtract(perfDate);
|
|
// Convert in minutes
|
|
double minutesPassedFromLastMaint = timePassedFromLastMaint.TotalMinutes;
|
|
|
|
// percentage = Passed minutes since last maintenance * 100 / Interval
|
|
percentage = (minutesPassedFromLastMaint * 100) / SupportFunctions.ConvertInMinutes(currMaintenance.Interval.Value, currMaintenance.UnitOfMeasure.Value);
|
|
missingDays = TimeSpan.FromMinutes(-1 * (minutesPassedFromLastMaint - SupportFunctions.ConvertInMinutes(currMaintenance.Interval.Value, currMaintenance.UnitOfMeasure.Value)));
|
|
counter = new CounterModel();
|
|
}
|
|
break;
|
|
}
|
|
|
|
canEdit = false;
|
|
using (MachinesUsersController machineUsersController = new MachinesUsersController())
|
|
{
|
|
if (currMaintenance.UserId != null)
|
|
{
|
|
// Check if user can edit the maintenance -> caller id - maintenance user id
|
|
int comparision = machineUsersController.CompareUsersRole(userId, currMaintenance.UserId.Value, MachineConfig.MachineId);
|
|
if (comparision >= 0)
|
|
canPerform = canEdit = true;
|
|
}
|
|
else
|
|
{
|
|
canEdit = false;
|
|
canPerform = machineUsersController.UserIsCmsAdmin(MachineConfig.MachineId, userId);
|
|
}
|
|
}
|
|
|
|
if (performed != null && performed.ControlWord == -2)
|
|
{
|
|
performed = null;
|
|
}
|
|
|
|
dtoMaintenancesModel.Add(new DTOMaintenanceModel()
|
|
{
|
|
Id = currMaintenance.MaintenanceId,
|
|
Title = currMaintenance.UserId == null ? "" : currMaintenance.Title,
|
|
CreationDate = currMaintenance.CreationDate,
|
|
Deadline = currMaintenance.Deadline,
|
|
Description = currMaintenance.Description,
|
|
Interval = currMaintenance.Interval,
|
|
LastExpirationDate = currMaintenance.LastExpirationDate,
|
|
LastPerformedDate = performed?.Date,
|
|
Type = currMaintenance.Type.ToString(),
|
|
UnitOfMeasure = currMaintenance.UnitOfMeasure.ToString(),
|
|
PercentageOfCompletion = percentage >= 0 && percentage < 100 ? Convert.ToInt32(percentage) : 100,
|
|
MissingDays = missingDays,
|
|
PlcCounter = counterValue,
|
|
OriginalPlcCounter = counter.Value,
|
|
CreatedByCms = currMaintenance.UserId == null,
|
|
CanEdit = canEdit,
|
|
CanPerform = canPerform,
|
|
Maintainer = performed?.Maintainer == null ? null : (DTOMessageUserModel)performed.Maintainer
|
|
});
|
|
}
|
|
}
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError GetNcAlarms(out DTOAlarmsModel alarms)
|
|
{
|
|
alarms = new DTOAlarmsModel();
|
|
List<AlarmModel> tmpAlarms = new List<AlarmModel>();
|
|
|
|
// Read NC active alarms
|
|
CmsError libraryError = numericalControl.NC_RActiveAlarms(ref tmpAlarms);
|
|
if (libraryError.errorCode != 0)
|
|
return libraryError;
|
|
|
|
// Create response list from NC data
|
|
foreach (AlarmModel ncAlarm in tmpAlarms)
|
|
{
|
|
alarms.NcAlarms.Add(new GenericAlarmModel()
|
|
{
|
|
Id = ncAlarm.Id,
|
|
Message = ncAlarm.Message,
|
|
DateTime = DateTime.Now,
|
|
RestorationIsEnabled = false
|
|
});
|
|
}
|
|
// Select distints
|
|
//alarms.NcAlarms = alarms.NcAlarms?.GroupBy(x => x.Id).Select(x => x.First()).ToList();
|
|
|
|
// Get NC max process number
|
|
ushort maxProcNumber = 0;
|
|
libraryError = numericalControl.NC_RProcessesNum(ref maxProcNumber);
|
|
if (libraryError.errorCode != 0)
|
|
return libraryError;
|
|
|
|
// For each process
|
|
for (ushort i = 1; i <= maxProcNumber; i++)
|
|
{
|
|
// Get process active alarms
|
|
numericalControl.PROC_RActiveAlarms(i, ref tmpAlarms);
|
|
// Create response list from NC data
|
|
foreach (AlarmModel processAlarm in tmpAlarms)
|
|
{
|
|
alarms.ProcessAlarms.Add(new ProcessAlarmModel()
|
|
{
|
|
Id = processAlarm.Id,
|
|
Message = processAlarm.Message,
|
|
Process = processAlarm.Process,
|
|
DateTime = DateTime.Now,
|
|
RestorationIsEnabled = false
|
|
});
|
|
}
|
|
}
|
|
|
|
List<PlcAlarmModel> plcAlarms = new List<PlcAlarmModel>();
|
|
// Read PLC Active Messages
|
|
libraryError = numericalControl.PLC_RActiveMessages(ref plcAlarms);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
bool restorationIsEnabled = false;
|
|
foreach (PlcAlarmModel plcAlarm in plcAlarms)
|
|
{
|
|
var configuredAlarm = InitialAlarmsConfig.Where(x => x.PlcId == plcAlarm.Id).FirstOrDefault();
|
|
if (configuredAlarm == null)
|
|
restorationIsEnabled = false;
|
|
else
|
|
restorationIsEnabled = configuredAlarm.RestoreIsActive;
|
|
|
|
// Create response list from plc data
|
|
alarms.PlcAlarms.Add(new DTOPlcAlarmModel()
|
|
{
|
|
Id = plcAlarm.Id,
|
|
IsWarning = plcAlarm.IsWarning,
|
|
Process = plcAlarm.Process,
|
|
RestorationIsActive = plcAlarm.RestorationIsActive,
|
|
DateTime = DateTime.Now,
|
|
RestorationIsEnabled = restorationIsEnabled
|
|
});
|
|
}
|
|
if (libraryError.errorCode != 0)
|
|
return libraryError;
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError GetNcGenericData(out DTONcGenericDataModel genericData)
|
|
{
|
|
genericData = new DTONcGenericDataModel(MachineConfig.Model);
|
|
|
|
// Get date time
|
|
DateTime dateTime = new DateTime();
|
|
CmsError libraryError = numericalControl.NC_RDateTime(ref dateTime);
|
|
if (libraryError.errorCode != 0)
|
|
return libraryError;
|
|
|
|
genericData.DateTime = dateTime;
|
|
|
|
// Get language
|
|
CultureInfo lang = new CultureInfo("en");
|
|
libraryError = numericalControl.NC_RLanguage(ref lang);
|
|
if (libraryError.errorCode != 0)
|
|
return libraryError;
|
|
|
|
genericData.Language = lang.TwoLetterISOLanguageName;
|
|
|
|
string tmpInfo = "";
|
|
// Get serial number
|
|
libraryError = numericalControl.NC_RSerialNumber(ref tmpInfo);
|
|
if (libraryError.errorCode != 0)
|
|
return libraryError;
|
|
|
|
genericData.SerialNumber = tmpInfo;
|
|
|
|
// Get software version
|
|
libraryError = numericalControl.NC_RSoftwareVersion(ref tmpInfo);
|
|
if (libraryError.errorCode != 0)
|
|
return libraryError;
|
|
|
|
genericData.NcSoftwareVersion = tmpInfo;
|
|
|
|
// Get model name
|
|
libraryError = numericalControl.NC_RModelName(ref tmpInfo);
|
|
if (libraryError.errorCode != 0)
|
|
return libraryError;
|
|
|
|
genericData.NcModel = tmpInfo;
|
|
|
|
// Get machine number
|
|
libraryError = numericalControl.NC_RMachineNumber(NcConfig.MachineNumberHasLetters, ref tmpInfo);
|
|
if (libraryError.errorCode != 0)
|
|
return libraryError;
|
|
|
|
genericData.CmsMachineIdNumber = tmpInfo;
|
|
|
|
// Get max process number
|
|
ushort procNum = 0;
|
|
libraryError = numericalControl.NC_RProcessesNum(ref procNum);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
// Max process number
|
|
genericData.ProcessNumber = procNum;
|
|
// Get Installation Date
|
|
genericData.InstallationDate = DateTime.ParseExact(NcConfig.InstallationDate, DATE_FORMATS, CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
|
|
// Get PLC version
|
|
genericData.PlcVersion = "1.0.0";
|
|
// Get PLC version
|
|
libraryError = numericalControl.NC_RUnitOfMeasure(ref tmpInfo);
|
|
if (libraryError.errorCode != 0)
|
|
return libraryError;
|
|
genericData.UnitOfMeasurement = tmpInfo;
|
|
|
|
// Get Server version
|
|
genericData.ServerVersion = SupportFunctions.GetSoftwareVersionAndBuildDate();
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError GetPowerOnData(out DTOPowerOnDataModel resultPowerOnData)
|
|
{
|
|
resultPowerOnData = new DTOPowerOnDataModel();
|
|
|
|
// Init object
|
|
PreAndPostPowerOnModel prePostPowerOn = new PreAndPostPowerOnModel
|
|
{
|
|
PostPowerOn = new PostPowerOnModel(),
|
|
PrePowerOn = new PrePowerOnModel()
|
|
};
|
|
|
|
// Read pre and post power on data
|
|
CmsError libraryError = numericalControl.PLC_RPowerOnData(ref prePostPowerOn);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// Set return object
|
|
resultPowerOnData.PrePowerOn = prePostPowerOn.PrePowerOn;
|
|
resultPowerOnData.PostPowerOn = prePostPowerOn.PostPowerOn;
|
|
|
|
// Read axes procedure data from
|
|
libraryError = numericalControl.PLC_RAxesResetData(ref resultPowerOnData.AxisReset);
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError GetProcessesData(out DTOProcessesDataModel processesData)
|
|
{
|
|
processesData = new DTOProcessesDataModel();
|
|
|
|
// Get NC max process number
|
|
ushort maxProcNumber = 0;
|
|
CmsError libraryError = numericalControl.NC_RProcessesNum(ref maxProcNumber);
|
|
if (libraryError.errorCode != 0)
|
|
return libraryError;
|
|
|
|
PROC_STATUS status = PROC_STATUS.IDLE;
|
|
// For each process get info
|
|
for (ushort i = 1; i <= maxProcNumber; i++)
|
|
{
|
|
ProcessDataModel tmpProcPP = new ProcessDataModel();
|
|
// Get process status
|
|
libraryError = numericalControl.PROC_RStatusAndData(i, ref tmpProcPP);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// if at least one process is in run, NC is running
|
|
// Add to list
|
|
processesData.processes.Add(new ProcessModel()
|
|
{
|
|
Id = tmpProcPP.Id,
|
|
IsInAlarm = tmpProcPP.IsInAlarm,
|
|
PartProgramName = tmpProcPP.PartProgramName,
|
|
Reps = tmpProcPP.Reps,
|
|
Status = tmpProcPP.Status,
|
|
Type = tmpProcPP.Type,
|
|
Visible = tmpProcPP.Visible,
|
|
CanLoadProgram = tmpProcPP.CanLoadProgram
|
|
});
|
|
|
|
if (tmpProcPP.IsSelected && processesData.SelectedProcess == 0)
|
|
{
|
|
processesData.SelectedProcess = (ushort)tmpProcPP.Id;
|
|
processesData.CanLoadProgram = tmpProcPP.CanLoadProgram;
|
|
}
|
|
|
|
// Check if there are running process
|
|
if (!processesData.IsRunning)
|
|
{
|
|
// Get process status
|
|
libraryError = numericalControl.PROC_RStatus(i, ref status);
|
|
if (status == PROC_STATUS.RUN || status == PROC_STATUS.HOLD)
|
|
processesData.IsRunning = true;
|
|
else
|
|
status = PROC_STATUS.IDLE;
|
|
}
|
|
}
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Legge tutti i parametri della ricetta e calcolo la overview dei vari steps
|
|
/// </summary>
|
|
/// <param name="currOverview">Oggetto overview ricetta corrente HMI</param>
|
|
/// <returns></returns>
|
|
public CmsError GetRecipeOverview(out Dictionary<RecipeSection, RecipeCatStatus> currOverview)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
// overview di base: ultima salvata...
|
|
currOverview = new Dictionary<RecipeSection, RecipeCatStatus>();
|
|
var err2fix = new Dictionary<RecipeSection, RecipeCatStatus>();
|
|
|
|
// leggo la ricetta dal PLC!
|
|
var currRecipe = new Dictionary<string, DTORecipeParam>();
|
|
//libraryError = ReadFullRecipe(out currRecipe);
|
|
libraryError = ReadRecipeData(true, true, out currRecipe);
|
|
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// leggo l'intero array delle DB... QUI FAKE sulle DB configurate...
|
|
List<DTORecipeConfigModel> recipeConfig = RecipeConfig.Select(x => new DTORecipeConfigModel()
|
|
{
|
|
Id = x.Id,
|
|
ScaleFactor = x.ScaleFactor,
|
|
NumDec = x.NumDec,
|
|
Category = x.Category.ToString(),
|
|
SubCategory_1 = x.SubCategory_1,
|
|
SubCategory_2 = x.SubCategory_2,
|
|
Name = x.Name,
|
|
Description = x.Description,
|
|
Format = x.Format,
|
|
Label = $"{x.Category}_{x.SubCategory_1}_{x.SubCategory_2}_{x.Name}".Replace("__", "_").Replace("__", "_").ToLower(),
|
|
EnumVal = x.EnumVal
|
|
}).ToList();
|
|
|
|
RecipeCatStatus currStatus = RecipeCatStatus.Unchanged;
|
|
|
|
// da conf ricetta --> se ci sono li leggo da li...
|
|
if (NcFileAdapter.RecipeLiveData.RecipeOverview != null)
|
|
{
|
|
currOverview = NcFileAdapter.RecipeLiveData.RecipeOverview;
|
|
}
|
|
|
|
// verifico eventualmente se mancasse qualcosa...
|
|
bool changed = false;
|
|
foreach (var item in recipeConfig)
|
|
{
|
|
if (!currOverview.ContainsKey(getRecipeSection(item.Category)))
|
|
{
|
|
currOverview.Add(getRecipeSection(item.Category), RecipeCatStatus.Unchanged);
|
|
changed = true;
|
|
}
|
|
}
|
|
|
|
// ricerco SE co fossero errori --> reset come changedOK
|
|
foreach (var item in currOverview)
|
|
{
|
|
if (item.Value == RecipeCatStatus.HasError)
|
|
err2fix.Add(item.Key, RecipeCatStatus.ChangedOk);
|
|
}
|
|
foreach (var item in err2fix)
|
|
{
|
|
currOverview[item.Key] = item.Value;
|
|
changed = true;
|
|
}
|
|
|
|
// se cambiato --> salvo in live data...
|
|
if (changed)
|
|
{
|
|
NcFileAdapter.RecipeLiveData.RecipeOverview = currOverview;
|
|
}
|
|
|
|
// ORA percorro conf ricetta x cercare eventuali ERRORI......
|
|
foreach (var item in recipeConfig)
|
|
{
|
|
currStatus = currOverview[getRecipeSection(item.Category)];
|
|
|
|
// se lo stato è errore --> esco...
|
|
if (currStatus == RecipeCatStatus.HasError)
|
|
{
|
|
continue;
|
|
}
|
|
// altrimenti controllo
|
|
else
|
|
{
|
|
// se in errore AND visibile --> registro...
|
|
bool checkCondition = false;
|
|
checkCondition = (currRecipe[item.Label].Status.HasError);
|
|
// 2020.07.29 - controllo condizione secondo status debug/release...
|
|
if (checkCondition)
|
|
{
|
|
currOverview[getRecipeSection(item.Category)] = RecipeCatStatus.HasError;
|
|
}
|
|
}
|
|
}
|
|
|
|
// restituisco cod errore se trovato
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError GetStarredUserSoftKeys(out List<DTOUserSoftKeyModel> softKeys)
|
|
{
|
|
softKeys = new List<DTOUserSoftKeyModel>();
|
|
List<SoftKeysModel> plcSoftKeys = new List<SoftKeysModel>();
|
|
|
|
// Get softkeys data from PLC
|
|
CmsError libraryError = numericalControl.PLC_RUserSoftKeys(ref plcSoftKeys);
|
|
if (libraryError.IsError() || plcSoftKeys.Count == 0)
|
|
return libraryError;
|
|
|
|
foreach (var softKey in SoftKeysConfig)
|
|
{
|
|
// Check type of the selected softkey
|
|
if (softKey.Type == SOFTKEY_TYPE.GROUP)
|
|
{
|
|
// Foreach subkey create a softkey
|
|
foreach (var subkey in softKey.SubKeys)
|
|
{
|
|
// Find the plc matching data
|
|
var plcSoftKey = plcSoftKeys.Find(x => x.Id == subkey.PlcId);
|
|
if (softKey.IsStarred)
|
|
{
|
|
// Create and add new user softkey model
|
|
softKeys.Add(new DTOUserSoftKeyModel()
|
|
{
|
|
Id = subkey.Id,
|
|
Active = plcSoftKey.Active,
|
|
Starred = softKey.IsStarred,
|
|
RefCallParam = softKey.RefCallParam,
|
|
RefCallLabel = softKey.RefCallLabel,
|
|
OperatorConfirmationNeeded = softKey.OperatorConfirmationNeeded,
|
|
Category = softKey.Category,
|
|
Value = plcSoftKey.Value
|
|
});
|
|
}
|
|
}
|
|
|
|
if (softKey.IsStarred)
|
|
{
|
|
softKeys.Add(new DTOUserSoftKeyModel()
|
|
{
|
|
Id = softKey.Id,
|
|
Category = softKey.Category,
|
|
OperatorConfirmationNeeded = softKey.OperatorConfirmationNeeded,
|
|
Visible = softKey.IsVisible
|
|
});
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Find the plc matching data
|
|
var plcSoftKey = plcSoftKeys.Find(x => x.Id == softKey.PlcId);
|
|
if (softKey.IsStarred)
|
|
{
|
|
softKeys.Add(new DTOUserSoftKeyModel()
|
|
{
|
|
Id = softKey.Id,
|
|
Active = plcSoftKey.Active,
|
|
Starred = softKey.IsStarred,
|
|
RefCallParam = softKey.RefCallParam,
|
|
RefCallLabel = softKey.RefCallLabel,
|
|
OperatorConfirmationNeeded = softKey.OperatorConfirmationNeeded,
|
|
Category = softKey.Category,
|
|
Visible = softKey.IsVisible,
|
|
Value = plcSoftKey.Value
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError GetUserSoftKeys(out List<DTOUserSoftKeyModel> softKeys)
|
|
{
|
|
softKeys = new List<DTOUserSoftKeyModel>();
|
|
List<SoftKeysModel> plcSoftKeys = new List<SoftKeysModel>();
|
|
|
|
// Get softkeys data from PLC
|
|
CmsError libraryError = numericalControl.PLC_RUserSoftKeys(ref plcSoftKeys);
|
|
if (libraryError.IsError() || plcSoftKeys.Count == 0)
|
|
return libraryError;
|
|
|
|
foreach (var softKey in SoftKeysConfig)
|
|
{
|
|
// Check type of the selected softkey
|
|
if (softKey.Type == SOFTKEY_TYPE.GROUP)
|
|
{
|
|
// Foreach subkey create a softkey
|
|
foreach (var subkey in softKey.SubKeys)
|
|
{
|
|
// Find the plc matching data
|
|
var plcSoftKey = plcSoftKeys.Find(x => x.Id == subkey.PlcId);
|
|
// Create and add new user softkey model
|
|
softKeys.Add(new DTOUserSoftKeyModel()
|
|
{
|
|
Id = subkey.Id,
|
|
Active = plcSoftKey.Active,
|
|
Starred = softKey.IsStarred,
|
|
RefCallParam = softKey.RefCallParam,
|
|
RefCallLabel = softKey.RefCallLabel,
|
|
OperatorConfirmationNeeded = softKey.OperatorConfirmationNeeded,
|
|
Category = softKey.Category,
|
|
Value = plcSoftKey.Value
|
|
});
|
|
}
|
|
|
|
softKeys.Add(new DTOUserSoftKeyModel()
|
|
{
|
|
Id = softKey.Id,
|
|
Category = softKey.Category,
|
|
OperatorConfirmationNeeded = softKey.OperatorConfirmationNeeded,
|
|
Visible = softKey.IsVisible
|
|
});
|
|
}
|
|
else
|
|
{
|
|
// Find the plc matching data
|
|
var plcSoftKey = plcSoftKeys.Find(x => x.Id == softKey.PlcId);
|
|
softKeys.Add(new DTOUserSoftKeyModel()
|
|
{
|
|
Id = softKey.Id,
|
|
Active = plcSoftKey.Active,
|
|
Starred = softKey.IsStarred,
|
|
RefCallParam = softKey.RefCallParam,
|
|
RefCallLabel = softKey.RefCallLabel,
|
|
OperatorConfirmationNeeded = softKey.OperatorConfirmationNeeded,
|
|
Category = softKey.Category,
|
|
Visible = softKey.IsVisible,
|
|
Value = plcSoftKey.Value
|
|
});
|
|
}
|
|
}
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError GetWarmersChannelCenterPoints(out Dictionary<int, ThermoPoint> centerPoints)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
centerPoints = new Dictionary<int, ThermoPoint>();
|
|
var upperReflectors = RiskChannelConfig.Where(x => x.IdReflector == 0);
|
|
foreach (var item in upperReflectors)
|
|
{
|
|
centerPoints.Add(item.IdChannel, item.refPos);
|
|
}
|
|
// chiude!
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns resistances configuration
|
|
/// </summary>
|
|
/// <param name="currWarmersResistances">List of configured resistances</param>
|
|
/// <returns></returns>
|
|
public CmsError GetWarmersResistances(out Dictionary<int, Model.ConfigModels.RiskResistModel> currWarmersResistances)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
currWarmersResistances = new Dictionary<int, Model.ConfigModels.RiskResistModel>();
|
|
|
|
// read and return config
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
foreach (var item in RiskResistConfig)
|
|
{
|
|
currWarmersResistances.Add(item.Id, item);
|
|
}
|
|
}
|
|
|
|
// restituisco cod errore se trovato
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get area for material from parameters list
|
|
/// </summary>
|
|
/// <param name="currAreaPerc">dictionary X/Y and double value</param>
|
|
/// <returns></returns>
|
|
public CmsError GetWarmMaterialArea(out Dictionary<string, double> currAreaPerc)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
currAreaPerc = new Dictionary<string, double>();
|
|
DTORecipeParam currParam = new DTORecipeParam();
|
|
var currRecipe = new Dictionary<string, DTORecipeParam>();
|
|
|
|
// read recipe
|
|
libraryError = ReadRecipeData(true, true, out currRecipe);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// use 2 fixed data for calculus: general_sizes_sheet_dim_x / general_sizes_sheet_dim_y
|
|
currAreaPerc.Add("X", getDimRatio(currRecipe["general_sizes_sheet_dim_x"]));
|
|
currAreaPerc.Add("Y", getDimRatio(currRecipe["general_sizes_sheet_dim_y"]));
|
|
|
|
// restituisco cod errore se trovato
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError ManageCandies()
|
|
{
|
|
// Check if i have to Manage it
|
|
if (!CandiesController.IsTimeToMangeCandies())
|
|
return NO_ERROR;
|
|
|
|
// Read Machine ID
|
|
string strMachNumber = "0";
|
|
CmsError libraryError = numericalControl.NC_RMachineNumber(NcConfig.MachineNumberHasLetters, ref strMachNumber);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
SupportFunctions.ConvertStringMachineNumberIntoNumber(strMachNumber, out bool containsLetters, out int machNumber);
|
|
|
|
// Read Data from NC & elaborate it
|
|
long NcCandy = 0;
|
|
libraryError = numericalControl.PLC_RCandy(ref NcCandy);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
bool bNC_OK = CandiesController.GetDataFromLincense(NcCandy, containsLetters, out long NCLic, out int NCMatr, out long NCParam);
|
|
bool bNC_VALID = machNumber == NCMatr && bNC_OK;
|
|
|
|
// Read Data from PC
|
|
bool bPC_OK = CandiesController.GetPCLincense(containsLetters, out long PcPLic, out int PCMatr, out long PCParam);
|
|
bool bPC_VALID = machNumber == PCMatr && bPC_OK;
|
|
|
|
// Elaborate Licence and write it
|
|
CandiesController.ElaborateLincense(bPC_VALID, bNC_VALID, PCParam, NCParam, PcPLic, NCLic, out DateTime newDate, out bool bRewrite);
|
|
if (bRewrite)
|
|
WriteCandy(newDate, machNumber);
|
|
|
|
// Read Expired Lincense Bit on NC
|
|
bool bNcCandy = false;
|
|
libraryError = numericalControl.PLC_RExpiredCandy(ref bNcCandy);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// Manage Expired Lincense Bit
|
|
if (CandiesController.ElaborateExpiredBit(newDate, bNcCandy, out bool bNewCandy))
|
|
{
|
|
//Write Expired Lincense Bit on NC
|
|
libraryError = numericalControl.PLC_WExpiredCandy(bNewCandy);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
public CmsError ManageConfRequest()
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
if (NcFileAdapter.RecipeLiveData != null)
|
|
{
|
|
// controllo SE HO richieste di configurazione
|
|
if (ThermoReqConfWarmerStr)
|
|
{
|
|
if (NcFileAdapter.RecipeLiveData.ChannelSetpoints != null)
|
|
{
|
|
// se si in questo caso scrivo configurazione...
|
|
WriteRecipeWarmConfig();
|
|
// Ack !
|
|
libraryError = numericalControl.PLC_WAckConfRiskRequest();
|
|
}
|
|
}
|
|
if (ThermoReqConfRecipeStr)
|
|
{
|
|
if (NcFileAdapter.RecipeLiveData.RecipeParameters != null)
|
|
{
|
|
// copy data to PLC
|
|
libraryError = ReadFullRecipe(out Dictionary<string, DTORecipeParam> prevRecipe);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
// save parameters to PLC!!!
|
|
Dictionary<string, DTORecipeParam> updtRecipe = new Dictionary<string, DTORecipeParam>();
|
|
foreach (var item in NcFileAdapter.RecipeLiveData.RecipeParameters)
|
|
{
|
|
if (prevRecipe.ContainsKey(item.Key))
|
|
{
|
|
// aggiorno il valore HMI nel parametro
|
|
var currParam = prevRecipe[item.Key];
|
|
currParam.SetpointHMI = item.Value;
|
|
// salvo (1 parametro, potrei fare N...)
|
|
updtRecipe.Add(item.Key, currParam);
|
|
}
|
|
else
|
|
{
|
|
return NOT_FOUND_ERROR;
|
|
}
|
|
}
|
|
// se si in questo caso scrivo configurazione attuale...
|
|
WriteRecipeParams(updtRecipe, nMaxParamWrite, delayParamWrite);
|
|
|
|
using (UserSoftkeysController controller = new UserSoftkeysController())
|
|
{
|
|
DTOKeyboardSoftKeyModel keybKey = controller.GetKeyboardFavoriteSoftkeysLoggedUser();
|
|
libraryError = WriteKeyboardStarSoftkey(keybKey.IdStar1, keybKey.IdStar2);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
}
|
|
|
|
// process ch load setup...
|
|
Dictionary<int, int> newRisk = new Dictionary<int, int>();
|
|
foreach (var item in NcAdapter.RecipeLiveData.ChannelSetpoints)
|
|
{
|
|
newRisk.Add(item.Key, item.Value);
|
|
}
|
|
|
|
// write to PLC SetPointHMI (%)
|
|
libraryError = WriteRecipeWarmChSetpHMI(newRisk);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// Ack !
|
|
libraryError = numericalControl.PLC_WAckConfRecipeRequest();
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// do conferma come se avessi appena approvata ricetta...
|
|
libraryError = ConfirmRecipeData(true);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
}
|
|
}
|
|
}
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError ManageFlirStrobe()
|
|
{
|
|
return numericalControl.PLC_WAckFlirRequest();
|
|
}
|
|
|
|
public CmsError ManageStatusCommand()
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
// recupero i dati
|
|
libraryError = numericalControl.PLC_RStatusCommand(ref statusCmd);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// restituisco errore
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError ManageWatchdog()
|
|
{
|
|
return numericalControl.PLC_RWManageWatchdog();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Comparazione elenco parametri della ricetta
|
|
/// </summary>
|
|
/// <param name="dictSource"></param>
|
|
/// <param name="dictDest"></param>
|
|
/// <param name="isEqual"></param>
|
|
/// <returns></returns>
|
|
public CmsError paramsComparer(Dictionary<string, double> dictSource, Dictionary<string, double> dictDest, out bool isEqual)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
// inizio dal count
|
|
isEqual = dictSource.Count == dictDest.Count;
|
|
// se uguale conteggio procedo...
|
|
if (isEqual)
|
|
{
|
|
foreach (var pair in dictSource)
|
|
{
|
|
double value;
|
|
if (dictDest.TryGetValue(pair.Key, out value))
|
|
{
|
|
// Require value be equal.
|
|
if (value != pair.Value)
|
|
{
|
|
isEqual = false;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Require key be present.
|
|
isEqual = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// return ok!
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError PutOverride(uint id, string action)
|
|
{
|
|
HEAD_OVERRIDE_SIGN sign = HEAD_OVERRIDE_SIGN.MINUS;
|
|
if (action == "plus")
|
|
sign = HEAD_OVERRIDE_SIGN.PLUS;
|
|
|
|
return numericalControl.PLC_WHeadOverride(id, sign);
|
|
}
|
|
|
|
public CmsError PutPowerOnData(uint id)
|
|
{
|
|
// Set to true power on data by id
|
|
return numericalControl.PLC_WPowerOnData(id, true);
|
|
}
|
|
|
|
public CmsError PutSelectAxis(byte axisId)
|
|
{
|
|
return numericalControl.AXES_WSelectAxis(axisId);
|
|
}
|
|
|
|
public CmsError PutSelectProcess(ushort procNumber)
|
|
{
|
|
return numericalControl.PROC_WSelectProcess(procNumber);
|
|
}
|
|
|
|
public CmsError PutUserSoftKeyClick(uint id)
|
|
{
|
|
// Write user softkey press to plc
|
|
return numericalControl.PLC_WUserSoftKey(id);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Dati assi da CONF + letture PLC
|
|
/// </summary>
|
|
/// <param name="axisData"></param>
|
|
/// <returns></returns>
|
|
public CmsError ReadAxisData(bool refreshOnlyRT, out Dictionary<int, DTOAxisInfoModel> axisData)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
// initi della config ricetta (x poter poi ciclare...)
|
|
var axisConfig = AxesConfig.Select(x => new DTOAxisInfoModel()
|
|
{
|
|
ID = x.Id,
|
|
name = x.Name,
|
|
masterID = x.MasterId,
|
|
enabledWord = (AxisCommand)x.EnabledWord,
|
|
type = x.Type.ToString(),
|
|
visible = x.IsVisible
|
|
}).ToDictionary(x => x.ID, x => x);
|
|
|
|
// se ho valori in cache uso quelli, altrimenti init obj
|
|
if (lastAxisData != null && lastAxisData.Count > 0)
|
|
{
|
|
axisData = lastAxisData;
|
|
}
|
|
else
|
|
{
|
|
// conversione al volo a dictionary
|
|
axisData = AxesConfig.Select(x => new DTOAxisInfoModel()
|
|
{
|
|
ID = x.Id,
|
|
name = x.Name,
|
|
masterID = x.MasterId,
|
|
enabledWord = (AxisCommand)x.EnabledWord,
|
|
type = x.Type.ToString(),
|
|
visible = x.IsVisible
|
|
}).ToDictionary(x => x.ID, x => x);
|
|
}
|
|
|
|
// solo x S7Net...
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
Dictionary<int, ThermoModels.AxisRT> currAxisRtData = new Dictionary<int, ThermoModels.AxisRT>();
|
|
Dictionary<int, ThermoModels.AxisInfo> currAxisInfoData = new Dictionary<int, ThermoModels.AxisInfo>();
|
|
|
|
if (lastAxisInfoReadData == null)
|
|
{
|
|
// init!
|
|
lastAxisInfoReadData = currAxisInfoData;
|
|
}
|
|
|
|
// leggo SICURAMENTE i dati RT
|
|
libraryError = numericalControl.PLC_RAxisRTList(ref currAxisRtData);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// se NON solo RT leggo tutti!
|
|
if (!refreshOnlyRT)
|
|
{
|
|
libraryError = numericalControl.PLC_RAxisInfoList(ref currAxisInfoData);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// salvo valori acquisiti
|
|
lastAxisInfoReadData = currAxisInfoData;
|
|
}
|
|
else
|
|
{
|
|
currAxisInfoData = lastAxisInfoReadData;
|
|
}
|
|
|
|
// ora completo i mancanti
|
|
foreach (var item in axisConfig)
|
|
{
|
|
// aggiorno (se c'è) il dato RT
|
|
if (currAxisRtData.ContainsKey(item.Key))
|
|
{
|
|
axisData[item.Key].position = currAxisRtData[item.Key].Position;
|
|
axisData[item.Key].speed = currAxisRtData[item.Key].Speed;
|
|
axisData[item.Key].load = currAxisRtData[item.Key].Load;
|
|
}
|
|
|
|
// aggiorno (se c'è) il dato INFO
|
|
if (currAxisInfoData.ContainsKey(item.Key))
|
|
{
|
|
axisData[item.Key].errorCode = currAxisInfoData[item.Key].ErrorCode;
|
|
axisData[item.Key].movPhase = currAxisInfoData[item.Key].MovPhase;
|
|
axisData[item.Key].statusCode = currAxisInfoData[item.Key].StatusWord;
|
|
}
|
|
}
|
|
lastAxisData = axisData;
|
|
}
|
|
else
|
|
{
|
|
lastAxisData = axisData;
|
|
}
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restituisce intero set dati IO Channels (conf + valori)
|
|
/// </summary>
|
|
/// <param name="currChannelsIO"></param>
|
|
/// <returns></returns>
|
|
public CmsError ReadFullIO(out DTOChannelsIO currChannelsIO)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
currChannelsIO = new DTOChannelsIO();
|
|
|
|
// read and return channel IO data
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
// lettura da PLC
|
|
Dictionary<int, ThermoModels.ModuleBlock> currModBlock = new Dictionary<int, ThermoModels.ModuleBlock>();
|
|
ThermoModels.ChanIOVis currThermoIOVis = new ThermoModels.ChanIOVis();
|
|
ThermoModels.ChanIOVal currThermoIOVal = new ThermoModels.ChanIOVal();
|
|
ThermoModels.ChanIOFor currThermoIOFor = new ThermoModels.ChanIOFor();
|
|
ThermoModels.ChanIOValFor currThermoIOValFor = new ThermoModels.ChanIOValFor();
|
|
libraryError = numericalControl.PLC_RIOChannelsConf(ref currThermoIOVis);
|
|
libraryError = numericalControl.PLC_RIOChannelsVal(ref currThermoIOVal, ref currThermoIOFor, ref currThermoIOValFor);
|
|
|
|
// setup da config
|
|
List<DigitalIN> listDI = IOConfig.Where(x => x.Category == Model.Constants.TACT_IO_TYPE.DI).Select(x => new DigitalIN()
|
|
{
|
|
Id = x.Id,
|
|
Bank = x.Bank,
|
|
Position = x.Position,
|
|
//Page = x.Category.ToString(),
|
|
Page = x.Page,
|
|
Wire = x.Wire,
|
|
Profinet = x.Profinet,
|
|
Label = x.Label.Replace("__", "_").Replace("__", "_").ToLower(),
|
|
Visible = currThermoIOVis.DI.ContainsKey(x.Id) ? currThermoIOVis.DI[x.Id] : false,
|
|
Value = currThermoIOVal.DI.ContainsKey(x.Id) ? currThermoIOVal.DI[x.Id] : false
|
|
}).ToList();
|
|
List<DigitalOUT> listDO = IOConfig.Where(x => x.Category == Model.Constants.TACT_IO_TYPE.DO).Select(x => new DigitalOUT()
|
|
{
|
|
Id = x.Id,
|
|
Bank = x.Bank,
|
|
Position = x.Position,
|
|
//Page = x.Category.ToString(),
|
|
Page = x.Page,
|
|
Wire = x.Wire,
|
|
Profinet = x.Profinet,
|
|
Label = x.Label.Replace("__", "_").Replace("__", "_").ToLower(),
|
|
ForceEnabled = !x.DisableForce,
|
|
Visible = currThermoIOVis.DO.ContainsKey(x.Id) ? currThermoIOVis.DO[x.Id] : false,
|
|
Value = currThermoIOVal.DO.ContainsKey(x.Id) ? currThermoIOVal.DO[x.Id] : false,
|
|
IsForced = currThermoIOFor.DO.ContainsKey(x.Id) ? currThermoIOFor.DO[x.Id] : false,
|
|
ForceOne = currThermoIOValFor.DO.ContainsKey(x.Id) ? currThermoIOValFor.DO[x.Id] : false,
|
|
ForceZero = currThermoIOValFor.DO.ContainsKey(x.Id) ? !currThermoIOValFor.DO[x.Id] : false
|
|
}).ToList();
|
|
List<AnalogIN> listAI = IOConfig.Where(x => x.Category == Model.Constants.TACT_IO_TYPE.AI).Select(x => new AnalogIN()
|
|
{
|
|
Id = x.Id,
|
|
Bank = x.Bank,
|
|
Position = x.Position,
|
|
//Page = x.Category.ToString(),
|
|
Page = x.Page,
|
|
Wire = x.Wire,
|
|
Profinet = x.Profinet,
|
|
Label = x.Label.Replace("__", "_").Replace("__", "_").ToLower(),
|
|
Visible = currThermoIOVis.AI.ContainsKey(x.Id) ? currThermoIOVis.AI[x.Id] : false,
|
|
Value = currThermoIOVal.AI.ContainsKey(x.Id) ? currThermoIOVal.AI[x.Id] : 0
|
|
}).ToList();
|
|
List<AnalogOUT> listAO = IOConfig.Where(x => x.Category == Model.Constants.TACT_IO_TYPE.AO).Select(x => new AnalogOUT()
|
|
{
|
|
Id = x.Id,
|
|
Bank = x.Bank,
|
|
Position = x.Position,
|
|
//Page = x.Category.ToString(),
|
|
Page = x.Page,
|
|
Wire = x.Wire,
|
|
Profinet = x.Profinet,
|
|
Label = x.Label.Replace("__", "_").Replace("__", "_").ToLower(),
|
|
ForceEnabled = !x.DisableForce,
|
|
Visible = currThermoIOVis.AO.ContainsKey(x.Id) ? currThermoIOVis.AO[x.Id] : false,
|
|
Value = currThermoIOVal.AO.ContainsKey(x.Id) ? currThermoIOVal.AO[x.Id] : 0,
|
|
IsForced = currThermoIOFor.AO.ContainsKey(x.Id) ? currThermoIOFor.AO[x.Id] : false,
|
|
ForcedValue = currThermoIOValFor.AO.ContainsKey(x.Id) ? currThermoIOValFor.AO[x.Id] : 0
|
|
}).ToList();
|
|
|
|
// assegno!
|
|
currChannelsIO.DI = listDI;
|
|
currChannelsIO.DO = listDO;
|
|
currChannelsIO.AI = listAI;
|
|
currChannelsIO.AO = listAO;
|
|
}
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Legge tutti i parametri della ricetta
|
|
/// </summary>
|
|
/// <param name="currRecipe">Oggetto ricetta corrente HMI</param>
|
|
/// <returns></returns>
|
|
public CmsError ReadFullRecipe(out Dictionary<string, DTORecipeParam> currRecipe)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
currRecipe = new Dictionary<string, DTORecipeParam>();
|
|
|
|
DTORecipeParam currParam = new DTORecipeParam();
|
|
|
|
// gestione errore
|
|
libraryError = ReadRecipeData(false, false, out currRecipe);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// restituisco cod errore se trovato
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError ReadGaugeData(out Dictionary<string, DTOThermoProd> currentLiveProd)
|
|
{
|
|
// preparo oggetti OUT
|
|
ThermoModels.LiveProdDataModel gaugeData = new ThermoModels.LiveProdDataModel();
|
|
currentLiveProd = new Dictionary<string, DTOThermoProd>();
|
|
DTOThermoProd currProdData = new DTOThermoProd();
|
|
double valore = 0;
|
|
CmsError libraryError = NO_ERROR;
|
|
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
// leggo dal PLC
|
|
libraryError = numericalControl.PLC_RGaugeData(ref gaugeData);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// dictionary da config...
|
|
foreach (var item in ThermoProdConfig)
|
|
{
|
|
// a secondo del valore cerco uno di quelli rilevati dal PLC...
|
|
switch (item.Name)
|
|
{
|
|
case "air":
|
|
valore = gaugeData.Air;
|
|
break;
|
|
|
|
case "vacuum":
|
|
valore = gaugeData.Vacuum;
|
|
break;
|
|
|
|
case "power":
|
|
valore = gaugeData.Power;
|
|
break;
|
|
|
|
case "timeAdv":
|
|
valore = gaugeData.TimeAdv;
|
|
break;
|
|
|
|
default:
|
|
valore = 0;
|
|
break;
|
|
}
|
|
|
|
// creo obj contenuto
|
|
currProdData = new DTOThermoProd()
|
|
{
|
|
Category = item.Category,
|
|
Name = item.Name,
|
|
Label = item.Label,
|
|
UM = item.UM,
|
|
Value = valore / item.ScaleFactor,
|
|
ScaleFactor = item.ScaleFactor,
|
|
NumDec = item.NumDec,
|
|
MinVal = item.MinVal / item.ScaleFactor,
|
|
MaxVal = item.MaxVal / item.ScaleFactor
|
|
};
|
|
// fix: se + timeAdv uso come max ultimo TC rilevato...
|
|
if (item.Name == "timeAdv")
|
|
{
|
|
currProdData.MaxVal = (int)Math.Ceiling((double)lastProdInfoData.TimeCycleGross / 1000);
|
|
}
|
|
// aggiungo a dictionary!
|
|
if (currentLiveProd.ContainsKey(item.Name))
|
|
{
|
|
currentLiveProd[item.Name] = currProdData;
|
|
}
|
|
else
|
|
{
|
|
currentLiveProd.Add(item.Name, currProdData);
|
|
}
|
|
}
|
|
}
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
public bool ReadHeadWTime(int Head, out uint hour)
|
|
{
|
|
hour = 0;
|
|
CmsError libraryError = numericalControl.PLC_RWorkedTimeHead(Head, ref hour);
|
|
if (libraryError.IsError())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool ReadMachineWTime(out uint hour)
|
|
{
|
|
hour = 0;
|
|
CmsError libraryError = numericalControl.PLC_RWorkedTimeMachine(ref hour);
|
|
if (libraryError.IsError())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public CmsError ReadModBlock(out Dictionary<int, DTOModulesBlock> currModules)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
currModules = new Dictionary<int, DTOModulesBlock>();
|
|
DTOModulesBlock currVal = new DTOModulesBlock();
|
|
|
|
// read and return warmers data
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
Dictionary<int, ThermoModels.ModuleBlock> currModBlock = new Dictionary<int, ThermoModels.ModuleBlock>();
|
|
libraryError = numericalControl.PLC_RModulesBlockList(false, ref currModBlock);
|
|
|
|
foreach (var item in ModBlockConfig)
|
|
{
|
|
try
|
|
{
|
|
ThermoModels.ModuleBlock currModule = currModBlock[item.Id];
|
|
currVal = new DTOModulesBlock()
|
|
{
|
|
Id = item.Id,
|
|
Label = item.Label,
|
|
Type = item.Type,
|
|
Section = item.Section,
|
|
IdParam = item.IdParam,
|
|
ShowDelay = item.ShowDelay,
|
|
Priority = item.Priority,
|
|
ScaleFactor = item.ScaleFactor,
|
|
NumDec = item.NumDec,
|
|
ActualDelay = (double)currModule.ActualDelay / item.ScaleFactor,
|
|
ActualDuration = (double)currModule.ActualDuration / item.ScaleFactor,
|
|
EstimatedDelay = (double)currModule.EstimatedDelay / item.ScaleFactor,
|
|
EstimatedDuration = (double)currModule.EstimatedDuration / item.ScaleFactor,
|
|
PrecedingId = currModule.PrecedingId,
|
|
Visible = currModule.Visible,
|
|
Running = currModule.Running,
|
|
HasError = currModule.HasError,
|
|
Terminated = currModule.Terminated,
|
|
Category = item.Category,
|
|
SubCategory_1 = item.SubCategory_1,
|
|
SubCategory_2 = item.SubCategory_2
|
|
};
|
|
currModules.Add(item.Id, currVal);
|
|
}
|
|
catch
|
|
{ }
|
|
}
|
|
}
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Legge tutti i parametri della ricetta
|
|
/// </summary>
|
|
/// <param name="currModules">Oggetto elenco modules block</param>
|
|
/// <returns></returns>
|
|
public CmsError ReadModulesBlock(out Dictionary<int, DTOModulesBlock> currModules)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
currModules = new Dictionary<int, DTOModulesBlock>();
|
|
|
|
// gestione errore
|
|
libraryError = ReadModBlock(out currModules);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// restituisco cod errore se trovato
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError ReadNcScada(ScadaSchemaModel scadaSchema, out DTOScadaModel scadaValue)
|
|
{
|
|
//ReadScadaDataSiemens(scadaSchema, out scadaValue);
|
|
|
|
//return NO_ERROR;
|
|
CmsError libraryError = NO_ERROR;
|
|
scadaValue = new DTOScadaModel()
|
|
{
|
|
Id = scadaSchema.Id,
|
|
Name = scadaSchema.Name,
|
|
IsInProductionPage = scadaSchema.IsInProductionPage,
|
|
Buttons = new List<DTOScadaButtonModel>()
|
|
};
|
|
|
|
// Cycle inside layers
|
|
foreach (var layer in scadaSchema.Layers)
|
|
{
|
|
object val = null;
|
|
object val2 = null;
|
|
// Cycle through elements, use the max number of elements between layer components in order to be optimized
|
|
for (int i = 0; i < GetMaxCountBetweenLayerComponents(layer); i++)
|
|
{
|
|
if (layer.Labels.ElementAtOrDefault(i) != null)
|
|
{
|
|
if (layer.Labels[i].MemEnabledIndex != null)
|
|
{
|
|
// Read enabled from PLC
|
|
libraryError = numericalControl.PLC_RScadaValue(layer.Labels[i].MemEnabledIndex, SCADA_MEM_TYPE.BOOL, ref val);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
// Populate & add new object into scada model
|
|
scadaValue.Labels.Add(new DTOScadaLabelModel()
|
|
{
|
|
Id = layer.Labels[i].Id,
|
|
IsVisible = Convert.ToBoolean(val)
|
|
});
|
|
}
|
|
else
|
|
{
|
|
scadaValue.Labels.Add(new DTOScadaLabelModel()
|
|
{
|
|
Id = layer.Labels[i].Id,
|
|
IsVisible = true
|
|
});
|
|
}
|
|
}
|
|
if (layer.Buttons.ElementAtOrDefault(i) != null)
|
|
{
|
|
// Read enabled from PLC
|
|
libraryError = numericalControl.PLC_RScadaValue(layer.Buttons[i].Status.MemEnabledIndex, SCADA_MEM_TYPE.BOOL, ref val);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// Populate & add new object into scada model
|
|
scadaValue.Buttons.Add(new DTOScadaButtonModel()
|
|
{
|
|
Id = layer.Buttons[i].Id,
|
|
IsEnabled = Convert.ToBoolean(val)
|
|
});
|
|
}
|
|
|
|
if (layer.Images.ElementAtOrDefault(i) != null)
|
|
{
|
|
// Read isVisible from PLC
|
|
libraryError = numericalControl.PLC_RScadaValue(layer.Images[i].Status.MemVisibleIndex, SCADA_MEM_TYPE.BOOL, ref val);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
var negate = layer.Images[i].Status.Negate;
|
|
// Populate & add new object into scada model
|
|
scadaValue.Images.Add(new DTOScadaImageModel()
|
|
{
|
|
Id = layer.Images[i].Id,
|
|
IsVisible = negate ? !Convert.ToBoolean(val) : Convert.ToBoolean(val)
|
|
});
|
|
}
|
|
|
|
if (layer.ProgressBars.ElementAtOrDefault(i) != null)
|
|
{
|
|
// Read value from PLC
|
|
libraryError = numericalControl.PLC_RScadaValue(layer.ProgressBars[i].MemValueIndex, SCADA_MEM_TYPE.BYTE, ref val);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
// Populate & add new object into scada model
|
|
scadaValue.ProgressBars.Add(new DTOScadaProgressBarModel()
|
|
{
|
|
Id = layer.ProgressBars[i].Id,
|
|
Value = Convert.ToByte(val)
|
|
});
|
|
}
|
|
|
|
if (layer.Inputs.ElementAtOrDefault(i) != null)
|
|
{
|
|
if (layer.Inputs.ElementAtOrDefault(i) != null && layer.Inputs[i].Status.Action.ToLower() == "read")
|
|
{
|
|
SCADA_MEM_TYPE type = SupportFunctions.GetMemTypeFromString(layer.Inputs[i].Status.Type);
|
|
// Read value from PLC
|
|
libraryError = numericalControl.PLC_RScadaValue(layer.Inputs[i].Status.MemValueIndex, type, ref val2);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// if type is real approximate to configurated decimal digits
|
|
if (type == SCADA_MEM_TYPE.REAL)
|
|
{
|
|
double tmpVal = Math.Round(Convert.ToDouble(val2), layer.Inputs[i].Status.Round);
|
|
val2 = tmpVal;
|
|
}
|
|
|
|
// Populate & add new object into scada model
|
|
scadaValue.Inputs.Add(new DTOScadaInputModel()
|
|
{
|
|
Id = layer.Inputs[i].Id,
|
|
Value = new DTOScadaValueModel()
|
|
{
|
|
IsEnabled = false, //Convert.ToBoolean(val),
|
|
Value = val2
|
|
}
|
|
});
|
|
}
|
|
else
|
|
{
|
|
// Read isVisible from PLC
|
|
libraryError = numericalControl.PLC_RScadaValue(layer.Inputs[i].Status.MemEnabledIndex, SCADA_MEM_TYPE.BOOL, ref val);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
SCADA_MEM_TYPE type = SupportFunctions.GetMemTypeFromString(layer.Inputs[i].Status.Type);
|
|
// Read value from PLC
|
|
libraryError = numericalControl.PLC_RScadaValue(layer.Inputs[i].Status.MemValueIndex, type, ref val2);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// Populate & add new object into scada model
|
|
scadaValue.Inputs.Add(new DTOScadaInputModel()
|
|
{
|
|
Id = layer.Inputs[i].Id,
|
|
Value = new DTOScadaValueModel()
|
|
{
|
|
IsEnabled = Convert.ToBoolean(val), //Convert.ToBoolean(val),
|
|
Value = val2
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get cycle prod data
|
|
/// </summary>
|
|
/// <param name="prodCycleData"></param>
|
|
/// <returns></returns>
|
|
public CmsError ReadProdCycleData(out ThermoModels.ProdCycleModel prodCycleData)
|
|
{
|
|
prodCycleData = new ThermoModels.ProdCycleModel();
|
|
CmsError libraryError = numericalControl.PLC_RProdCycle(ref prodCycleData);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Lettura dati ProdInfo (LIVE)
|
|
/// </summary>
|
|
/// <param name="prodInfoData"></param>
|
|
/// <returns></returns>
|
|
public CmsError ReadProdInfoData(out DTOProdInfo prodInfoData)
|
|
{
|
|
prodInfoData = new DTOProdInfo();
|
|
ThermoModels.ProdInfoModel pInfoRaw = new ThermoModels.ProdInfoModel();
|
|
CmsError libraryError = numericalControl.PLC_RProdInfo(ref pInfoRaw);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// DI DEFAULT aggiungo ULTIMA immagine scattata da thermocamera... x salvataggio su DB
|
|
pInfoRaw.ThermoImage = lastThermoImage;
|
|
|
|
// converto 1:1 dati da ThermoModels.ProdInfoModel --> DTOProdInfo
|
|
prodInfoData = new DTOProdInfo(pInfoRaw);
|
|
// a livello di dato current invio SEMPRE il valore "_last.jpg che è immagine costante"
|
|
prodInfoData.ThermoImage = currThermoImage;
|
|
|
|
// 2020.09.02: incremento di 1 il NUMERO dei pezzi, in modo che mostro il pezzo corrente (n=fatti + 1)
|
|
prodInfoData.NumDone++;
|
|
|
|
// se nullo lo popolo
|
|
if (lastProdInfoData == null)
|
|
{
|
|
lastProdInfoData = pInfoRaw;
|
|
}
|
|
|
|
// do comparison with old record and if changed --> persist on DB!
|
|
if (!pInfoRaw.Equals(lastProdInfoData))
|
|
{
|
|
// update last info data
|
|
lastProdInfoData = pInfoRaw;
|
|
}
|
|
else
|
|
{
|
|
pInfoRaw = lastProdInfoData;
|
|
}
|
|
|
|
// se ho update da strobe... sennò restituisco ultima lettura...
|
|
if (ThermoProdUpdatedStr)
|
|
{
|
|
// save on DB! attenzione: RAW DATA perché salvo pezzo PRECEDENTE...
|
|
using (ProdInfoController prodInfoController = new ProdInfoController())
|
|
{
|
|
string imgName = string.IsNullOrEmpty(pInfoRaw.ThermoImage) ? "_last" : pInfoRaw.ThermoImage;
|
|
if (imgName == "_last")
|
|
{
|
|
imgName = "UNDEFINED";
|
|
}
|
|
prodInfoController.Create(pInfoRaw.NumTarget, pInfoRaw.NumDone, pInfoRaw.TimeWarm, pInfoRaw.TimeVent, pInfoRaw.TimeVacuum, pInfoRaw.TimeCycleGross, pInfoRaw.TimeCycleNet, pInfoRaw.MaterialTempEndWarm, pInfoRaw.MaterialTempEndVent, pInfoRaw.MoldTemp, pInfoRaw.VacuumReadVal, pInfoRaw.MouldEnergyOUT, pInfoRaw.MouldEnergyIN, false, pInfoRaw.ThermoImage);
|
|
// indico di rileggere il DB...
|
|
forceProdPanelDbReload = true;
|
|
}
|
|
// manage strobe/ack!
|
|
libraryError = numericalControl.PLC_WAckProdUpdate();
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
}
|
|
|
|
// ora controllo inizio/fine produzione
|
|
if (ThermoProdStartStr)
|
|
{
|
|
lastProdStart = DateTime.Now;
|
|
// manage strobe/ack!
|
|
libraryError = numericalControl.PLC_WAckPzProdStart();
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
}
|
|
else if (ThermoProdEndStr)
|
|
{
|
|
lastProdEnd = DateTime.Now;
|
|
// calcolo ultimo ciclo...
|
|
var lastDuration = lastProdEnd.Subtract(lastProdStart).TotalSeconds;
|
|
// se il valore SALVATO è > 3 * valore rilevato --> uso SOLO ultimo
|
|
if (lastCycle > 3 * lastDuration)
|
|
{
|
|
lastCycle = lastDuration;
|
|
}
|
|
// altrimenti EWMA da parametro calcolato standard, default 50%
|
|
else
|
|
{
|
|
//lastCycle = 0.5 * lastCycle + 0.5 * lastDuration;
|
|
lastCycle = ewmaLambda * lastDuration + (1 - ewmaLambda) * lastCycle;
|
|
}
|
|
// salvo anche nei live data della ricetta...
|
|
RecipeLiveData.TC_last = lastCycle;
|
|
|
|
// manage strobe/ack!
|
|
libraryError = numericalControl.PLC_WAckPzProdEnd();
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
// salvo x sicurezza ultimo start...
|
|
lastProdStart = DateTime.Now;
|
|
}
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Lettura dati ProdPanel
|
|
/// </summary>
|
|
/// <param name="currentProdPanel"></param>
|
|
/// <returns></returns>
|
|
public CmsError ReadProdPanel(out DTOThermoPanelProd currentProdPanel)
|
|
{
|
|
// preparo oggetti OUT
|
|
currentProdPanel = new DTOThermoPanelProd();
|
|
Dictionary<int, double> TS_Cad = new Dictionary<int, double>();
|
|
Dictionary<int, double> TS_TC = new Dictionary<int, double>();
|
|
CmsError libraryError = NO_ERROR;
|
|
bool dataChanged = false;
|
|
int numTcOk = 0;
|
|
|
|
// dati ricetta da live
|
|
currentProdPanel.NomeRicetta = NcFileAdapter.RecipeLiveData.RecipeName;
|
|
// se NON HO dati già letti --> cambiati devo rileggere
|
|
if (LastProdPanelData == null)
|
|
{
|
|
dataChanged = true;
|
|
}
|
|
// se non sono variati dati di produzione --> li riutilizzo!
|
|
else
|
|
{
|
|
// verifico se siano ancora validi i dati precedenti...
|
|
if (lastProdInfoData == null)
|
|
{
|
|
dataChanged = true;
|
|
}
|
|
else
|
|
{
|
|
// confronto ultimo pezzo --> se diverso sono cambiati
|
|
bool changeSetpoint = true;
|
|
if (lastRecipe != null)
|
|
{
|
|
if (lastRecipe.ContainsKey("pyrometer_pyrometer_setpoint"))
|
|
{
|
|
changeSetpoint = LastProdPanelData.TempSetpoint != lastRecipe["pyrometer_pyrometer_setpoint"].SetpointPLC;
|
|
}
|
|
}
|
|
bool changeNumPz = LastProdPanelData.NumDone != lastProdInfoData.NumDone;
|
|
bool changeNumTarget = lastProdInfoData.NumTarget != LastProdPanelData.NumTarget;
|
|
bool changeNumPreHot = lastProdInfoData.NumPreHot != LastProdPanelData.NumPreHot;
|
|
dataChanged = changeNumPz || changeSetpoint || changeNumTarget || changeNumPreHot || forceProdPanelDbReload;
|
|
}
|
|
}
|
|
if (dataChanged)
|
|
{
|
|
// parto dai dati di lastProdInfoData...
|
|
if (lastProdInfoData != null)
|
|
{
|
|
currentProdPanel.NumDone = lastProdInfoData.NumDone;
|
|
currentProdPanel.NumTarget = lastProdInfoData.NumTarget;
|
|
currentProdPanel.NumPreHot = lastProdInfoData.NumPreHot;
|
|
}
|
|
// dai parametri sistemo i setpoints
|
|
if (lastRecipe != null)
|
|
{
|
|
if (lastRecipe.ContainsKey("pyrometer_pyrometer_setpoint"))
|
|
{
|
|
currentProdPanel.TempAct = lastRecipe["pyrometer_pyrometer_setpoint"].ValueAct;
|
|
currentProdPanel.TempSetpoint = lastRecipe["pyrometer_pyrometer_setpoint"].SetpointPLC;
|
|
}
|
|
}
|
|
// dal DB recupero i dati dei TC storici... cablato a last 30 x ora... ma CALCOLO SOLO i cicli "positivi" = NON i riscaldi...
|
|
if (currentProdPanel.NumDone > 0)
|
|
{
|
|
// parto dai dati di lastProdInfoData...
|
|
if (lastProdInfoData != null)
|
|
{
|
|
currentProdPanel.LastTCiclo = Math.Round((double)lastProdInfoData.TimeCycleGross / 1000, 2);
|
|
if (lastProdInfoData.TimeCycleGross > 0)
|
|
{
|
|
currentProdPanel.LastCadenza = Math.Round((double)3600000 / lastProdInfoData.TimeCycleGross, 2);
|
|
}
|
|
// 2020.10.19 aggiungo TCicloNetto
|
|
currentProdPanel.LastTCicloNetto = Math.Round((double)lastProdInfoData.TimeCycleNet / 1000, 2);
|
|
|
|
// se NON HO un last value...
|
|
if (lastCycle == 0)
|
|
{
|
|
lastCycle = currentProdPanel.LastTCiclo;
|
|
lastCycleNet = currentProdPanel.LastTCicloNetto;
|
|
}
|
|
// se il valore SALVATO è > 3 * valore rilevato --> uso SOLO ultimo
|
|
else if (lastCycle > 3 * currentProdPanel.LastTCiclo)
|
|
{
|
|
lastCycle = currentProdPanel.LastTCiclo;
|
|
lastCycleNet = currentProdPanel.LastTCicloNetto;
|
|
}
|
|
// altrimenti EWMA da parametro calcolato standard, default 50%
|
|
else
|
|
{
|
|
//lastCycle = 0.5 * lastCycle + 0.5 * lastDuration;
|
|
lastCycle = ewmaLambda * currentProdPanel.LastTCiclo + (1 - ewmaLambda) * lastCycle;
|
|
lastCycleNet = ewmaLambda * currentProdPanel.LastTCicloNetto + (1 - ewmaLambda) * lastCycleNet;
|
|
// sistemo ponderato il ciclo netto rilevato
|
|
currentProdPanel.LastTCicloNetto = lastCycleNet;
|
|
}
|
|
|
|
// salvo anche nei live data della ricetta...
|
|
RecipeLiveData.TC_last = lastCycle;
|
|
|
|
// stima durata da pz fatti... SOLO SE il NumTarget è > 0
|
|
currentProdPanel.StimaDurata = 0;
|
|
if (currentProdPanel.NumTarget > 0)
|
|
{
|
|
// 2020.09.03 uso dati da ricetta corrente... stimata con EWMA, in SECONDI!
|
|
currentProdPanel.StimaDurata = Math.Round((currentProdPanel.NumTarget - currentProdPanel.NumDone) * lastCycle, 2) / 60;
|
|
}
|
|
// se stima negativa (+ pezzi di quanti richiesti...) --> ZERO!
|
|
currentProdPanel.StimaDurata = currentProdPanel.StimaDurata < 0 ? 0 : currentProdPanel.StimaDurata;
|
|
}
|
|
|
|
libraryError = GetHistProdInfoDataDesc(out List<ThermoModels.ProdInfoModel> prodInfoDataList, currentProdPanel.NumDone, numRecProdPanelGraph);
|
|
// se ci sono dati --> creo le 2 TS!
|
|
if (prodInfoDataList != null)
|
|
{
|
|
// annullo richiesta reload Db (eventuale)
|
|
forceProdPanelDbReload = false;
|
|
// ciclo
|
|
foreach (var item in prodInfoDataList)
|
|
{
|
|
if (TS_TC.ContainsKey(item.NumDone))
|
|
{
|
|
TS_TC[item.NumDone] = Math.Round((double)item.TimeCycleGross / 1000, 2);
|
|
}
|
|
else
|
|
{
|
|
TS_TC.Add(item.NumDone, Math.Round((double)item.TimeCycleGross / 1000, 2));
|
|
}
|
|
if (item.TimeCycleGross > 0)
|
|
{
|
|
if (TS_Cad.ContainsKey(item.NumDone))
|
|
{
|
|
TS_Cad[item.NumDone] = Math.Round((double)3600000 / item.TimeCycleGross, 2);
|
|
}
|
|
else
|
|
{
|
|
TS_Cad.Add(item.NumDone, Math.Round((double)3600000 / item.TimeCycleGross, 2));
|
|
}
|
|
numTcOk++;
|
|
}
|
|
}
|
|
// accodo!
|
|
currentProdPanel.TS_Cadenza = TS_Cad;
|
|
currentProdPanel.TS_TCiclo = TS_TC;
|
|
}
|
|
// già che ci sono recupero prima record x prodStart... in ordine DESC dal 1°...
|
|
libraryError = GetHistProdInfoDataDesc(out List<ThermoModels.ProdInfoModel> prodInfoFirstDesc, 1, 1);
|
|
// cerco in ordine INVERSO
|
|
libraryError = GetHistProdInfoDataAsc(out List<ThermoModels.ProdInfoModel> prodInfoFirstAsc, 1, 1);
|
|
// se ci sono dati --> fix start
|
|
ThermoModels.ProdInfoModel dataRecord = new ThermoModels.ProdInfoModel();
|
|
if (prodInfoFirstDesc != null && prodInfoFirstDesc.Count > 0)
|
|
{
|
|
try
|
|
{
|
|
// sottraggo ad inizio il tempo ciclo in secondi...
|
|
dataRecord = prodInfoFirstDesc.FirstOrDefault();
|
|
currentProdPanel.InizioProd = dataRecord.DtEvent.AddSeconds(-dataRecord.TimeCycleGross / 1000);
|
|
lottoStart = currentProdPanel.InizioProd != null ? Convert.ToDateTime(currentProdPanel.InizioProd) : lottoStart;
|
|
}
|
|
catch
|
|
{ }
|
|
}
|
|
else if (prodInfoFirstAsc != null && prodInfoFirstAsc.Count > 0)
|
|
{
|
|
try
|
|
{
|
|
dataRecord = prodInfoFirstAsc.FirstOrDefault();
|
|
currentProdPanel.InizioProd = dataRecord.DtEvent.AddSeconds(-dataRecord.TimeCycleGross / 1000);
|
|
lottoStart = currentProdPanel.InizioProd != null ? Convert.ToDateTime(currentProdPanel.InizioProd) : lottoStart;
|
|
}
|
|
catch
|
|
{ }
|
|
}
|
|
}
|
|
// salvo ultimi dati!
|
|
LastProdPanelData = currentProdPanel;
|
|
}
|
|
else
|
|
{
|
|
// uso ultimi dati
|
|
currentProdPanel = LastProdPanelData;
|
|
}
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Vero metodo lettura ricetta da 2 aree memoria PLC
|
|
/// </summary>
|
|
/// <param name="refreshOnlyRT">Indica se aggiornare SOLO i dati RT</param>
|
|
/// <param name="useLastRead">Indica se usare ultimi dati letti dal PLC senza effettiva lettura (via cache)</param>
|
|
/// <param name="currentRecipe"></param>
|
|
/// <returns></returns>
|
|
public CmsError ReadRecipeData(bool refreshOnlyRT, bool useLastRead, out Dictionary<string, DTORecipeParam> currentRecipe)
|
|
{
|
|
// per sicurezza: SE NON HO una last recipe --> leggo cmq tutto!
|
|
if (lastRecipe == null || lastRecipe.Count == 0)
|
|
{
|
|
refreshOnlyRT = false;
|
|
}
|
|
// init obj
|
|
currentRecipe = new Dictionary<string, DTORecipeParam>();
|
|
RPRange currRange = new RPRange();
|
|
RPStatus currStatus = new RPStatus();
|
|
CmsError libraryError = NO_ERROR;
|
|
// solo x S7...
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
Dictionary<int, ThermoModels.RecipeParam> currPlcRecipe = new Dictionary<int, ThermoModels.RecipeParam>();
|
|
if (useLastRead && lastRecipe.Count > 0)
|
|
{
|
|
currentRecipe = lastRecipe;
|
|
return libraryError;
|
|
}
|
|
else
|
|
{
|
|
libraryError = numericalControl.PLC_RRecipeParamList(refreshOnlyRT, ref currPlcRecipe);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
}
|
|
|
|
DTORecipeParam currParam = new DTORecipeParam();
|
|
// leggo l'intero array delle DB... QUI FAKE sulle DB configurate...
|
|
List<DTORecipeConfigModel> recipeConfig = RecipeConfig.Select(x => new DTORecipeConfigModel()
|
|
{
|
|
Id = x.Id,
|
|
ScaleFactor = x.ScaleFactor,
|
|
NumDec = x.NumDec,
|
|
Category = x.Category.ToString(),
|
|
SubCategory_1 = x.SubCategory_1,
|
|
SubCategory_2 = x.SubCategory_2,
|
|
Name = x.Name,
|
|
Description = x.Description,
|
|
Format = x.Format,
|
|
Label = $"{x.Category}_{x.SubCategory_1}_{x.SubCategory_2}_{x.Name}".Replace("__", "_").Replace("__", "_").ToLower(),
|
|
EnumVal = x.EnumVal
|
|
}).ToList();
|
|
|
|
foreach (var item in recipeConfig)
|
|
{
|
|
if (currPlcRecipe.ContainsKey(item.Id))
|
|
{
|
|
// recupero da mem PLC
|
|
ThermoModels.RecipeParam paramPLC = currPlcRecipe[item.Id];
|
|
currRange = new RPRange()
|
|
{
|
|
Min = paramPLC.ValMin / item.ScaleFactor,
|
|
Max = paramPLC.ValMax / item.ScaleFactor
|
|
};
|
|
currStatus = new RPStatus()
|
|
{
|
|
Visible = paramPLC.Visible,
|
|
Enabled = paramPLC.Enabled,
|
|
HasError = paramPLC.HasError
|
|
};
|
|
// calcolo intero oggetto
|
|
currParam = new DTORecipeParam()
|
|
{
|
|
Id = item.Id,
|
|
Range = currRange,
|
|
Status = currStatus,
|
|
UnitMeasure = getUM(paramPLC.UnitMeasure),
|
|
ValueAct = paramPLC.ValueAct / item.ScaleFactor,
|
|
SetpointHMI = paramPLC.SetpointHMI / item.ScaleFactor,
|
|
SetpointPLC = paramPLC.SetpointPLC / item.ScaleFactor,
|
|
ScaleFactor = item.ScaleFactor,
|
|
NumDec = item.NumDec,
|
|
EnumVal = item.EnumVal
|
|
};
|
|
}
|
|
else
|
|
{
|
|
currRange = new RPRange()
|
|
{
|
|
Min = 0,
|
|
Max = 999999
|
|
};
|
|
currStatus = new RPStatus()
|
|
{
|
|
Visible = true,
|
|
Enabled = true,
|
|
HasError = false
|
|
};
|
|
// calcolo intero oggetto
|
|
currParam = new DTORecipeParam()
|
|
{
|
|
Id = item.Id,
|
|
Range = currRange,
|
|
Status = currStatus,
|
|
UnitMeasure = "",
|
|
ValueAct = 0,
|
|
ScaleFactor = 1,
|
|
NumDec = 0,
|
|
EnumVal = new Dictionary<string, Model.ConfigModels.EnumDetail>()
|
|
};
|
|
}
|
|
currentRecipe.Add(item.Label, currParam);
|
|
}
|
|
// salvo!
|
|
lastRecipe = currentRecipe;
|
|
}
|
|
else
|
|
{
|
|
currentRecipe = new Dictionary<string, DTORecipeParam>();
|
|
lastRecipe = currentRecipe;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
public CmsError ReadScadaData(ScadaSchemaModel schema, out DTOScadaModel scadaValue)
|
|
{
|
|
if (NcConfig.NcVendor != NC_VENDOR.SIEMENS)
|
|
{
|
|
// Read OSAI FANUC schema
|
|
CmsError libraryError = ReadNcScada(schema, out scadaValue);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
}
|
|
else
|
|
{
|
|
// Read SIEMENS schema
|
|
CmsError libraryError = ReadSiemensScadaSiemens(schema, out scadaValue);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
public CmsError ReadScadasData(List<ScadaSchemaModel> schemasToRead, out List<DTOScadaModel> scadas)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
scadas = new List<DTOScadaModel>();
|
|
|
|
List<int> alreadyReadScada = new List<int>();
|
|
|
|
foreach (var schema in schemasToRead)
|
|
{
|
|
DTOScadaModel scadaValue = new DTOScadaModel();
|
|
// Avoid duplicated reads
|
|
if (!alreadyReadScada.Contains(schema.Id))
|
|
{
|
|
// Read one schema
|
|
libraryError = ReadScadaData(schema, out scadaValue);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// Add value to return list
|
|
scadas.Add(scadaValue);
|
|
// Add id to read scada
|
|
alreadyReadScada.Add(schema.Id);
|
|
}
|
|
}
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError ReadSiemensScadaSiemens(ScadaSchemaModel scadaSchema, out DTOScadaModel scadaValue)
|
|
{
|
|
List<ScadaObjectModel> inputData = new List<ScadaObjectModel>();
|
|
List<ScadaObjectModel> booleanValue = new List<ScadaObjectModel>();
|
|
CmsError libraryError = NO_ERROR;
|
|
scadaValue = new DTOScadaModel()
|
|
{
|
|
Id = scadaSchema.Id,
|
|
Name = scadaSchema.Name,
|
|
IsInProductionPage = scadaSchema.IsInProductionPage,
|
|
Buttons = new List<DTOScadaButtonModel>()
|
|
};
|
|
|
|
// Cycle inside layers
|
|
foreach (var layer in scadaSchema.Layers)
|
|
{
|
|
object val = null;
|
|
// Cycle through elements, use the max number of elements between layer components in order to be optimized
|
|
for (int i = 0; i < GetMaxCountBetweenLayerComponents(layer); i++)
|
|
{
|
|
if (layer.Labels.ElementAtOrDefault(i) != null)
|
|
{
|
|
if (layer.Labels[i].MemEnabledIndex != null)
|
|
{
|
|
var label = layer.Labels[i];
|
|
// Add labelVisible to the list of bolean values to be readed
|
|
booleanValue.Add(new ScadaObjectModel()
|
|
{
|
|
Id = label.Id,
|
|
Address = label.MemEnabledIndex,
|
|
MemType = SCADA_MEM_TYPE.BOOL,
|
|
Round = 0,
|
|
Action = SCADA_ACTION.READ,
|
|
ObjectType = (int)SCADA_ELEMENT_TYPE.LABEL
|
|
});
|
|
}
|
|
else
|
|
{
|
|
// if memory index is not declared, automatically the label is visible
|
|
scadaValue.Labels.Add(new DTOScadaLabelModel()
|
|
{
|
|
Id = layer.Labels[i].Id,
|
|
IsVisible = true
|
|
});
|
|
}
|
|
}
|
|
|
|
if (layer.Buttons.ElementAtOrDefault(i) != null)
|
|
{
|
|
var button = layer.Buttons[i];
|
|
// Add buttonEnabled to the list of bolean values to be readed
|
|
booleanValue.Add(new ScadaObjectModel()
|
|
{
|
|
Id = button.Id,
|
|
Address = button.Status.MemEnabledIndex,
|
|
MemType = SCADA_MEM_TYPE.BOOL,
|
|
Round = 0,
|
|
Action = SCADA_ACTION.READ,
|
|
ObjectType = (int)SCADA_ELEMENT_TYPE.BUTTON
|
|
});
|
|
}
|
|
|
|
if (layer.Images.ElementAtOrDefault(i) != null)
|
|
{
|
|
var negate = layer.Images[i].Status.Negate;
|
|
var image = layer.Images[i];
|
|
// Add imageVisible to the list of bolean values to be readed
|
|
booleanValue.Add(new ScadaObjectModel()
|
|
{
|
|
Id = image.Id,
|
|
Address = image.Status.MemVisibleIndex,
|
|
MemType = SCADA_MEM_TYPE.BOOL,
|
|
Round = 0,
|
|
Action = SCADA_ACTION.READ,
|
|
ObjectType = negate ? (int)SCADA_ELEMENT_TYPE.NEGATE_IMAGE : (int)SCADA_ELEMENT_TYPE.IMAGE
|
|
});
|
|
}
|
|
|
|
if (layer.ProgressBars.ElementAtOrDefault(i) != null)
|
|
{
|
|
// Read value from PLC
|
|
libraryError = numericalControl.PLC_RScadaValue(layer.ProgressBars[i].MemValueIndex, SCADA_MEM_TYPE.BYTE, ref val);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// Populate & add new object into scada model
|
|
scadaValue.ProgressBars.Add(new DTOScadaProgressBarModel()
|
|
{
|
|
Id = layer.ProgressBars[i].Id,
|
|
Value = Convert.ToByte(val)
|
|
});
|
|
}
|
|
|
|
if (layer.Inputs.ElementAtOrDefault(i) != null)
|
|
{
|
|
var input = layer.Inputs[i];
|
|
SCADA_MEM_TYPE type = SupportFunctions.GetMemTypeFromString(input.Status.Type);
|
|
// InputData list is made up of the values of inputs and the next element of each value is the isVisible field of the same input
|
|
|
|
// Add Value information
|
|
inputData.Add(new ScadaObjectModel()
|
|
{
|
|
Id = input.Id,
|
|
Address = input.Status.MemValueIndex,
|
|
MemType = type,
|
|
Round = input.Status.Round,
|
|
Action = input.Status.Action,
|
|
});
|
|
|
|
// Add is visible to the item to be readed
|
|
inputData.Add(new ScadaObjectModel()
|
|
{
|
|
Id = input.Id,
|
|
Address = input.Status.MemEnabledIndex,
|
|
MemType = SCADA_MEM_TYPE.BOOL,
|
|
Round = input.Status.Round,
|
|
Action = input.Status.Action,
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
//Stopwatch st = new Stopwatch();
|
|
//st.Start();
|
|
|
|
// Read input data ( value, isEnabled, value2, isEnabled2 ...)
|
|
libraryError = numericalControl.PLC_RScadaSiemens(ref inputData);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// Read bolean values (isVisible, isEnabled, isEnabled ...)
|
|
libraryError = numericalControl.PLC_RScadaSiemens(ref booleanValue);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
for (int i = 0; i < booleanValue.Count() - 1; i++)
|
|
{
|
|
var enabled = booleanValue[i];
|
|
|
|
switch (enabled.ObjectType)
|
|
{
|
|
case (int)SCADA_ELEMENT_TYPE.BUTTON:
|
|
{
|
|
// Populate & add new object into scada model
|
|
scadaValue.Buttons.Add(new DTOScadaButtonModel()
|
|
{
|
|
Id = enabled.Id,
|
|
IsEnabled = Convert.ToBoolean(enabled.Value)
|
|
});
|
|
}
|
|
break;
|
|
|
|
case (int)SCADA_ELEMENT_TYPE.IMAGE:
|
|
case (int)SCADA_ELEMENT_TYPE.NEGATE_IMAGE:
|
|
{
|
|
// Populate & add new object into scada model
|
|
scadaValue.Images.Add(new DTOScadaImageModel()
|
|
{
|
|
Id = enabled.Id,
|
|
IsVisible = enabled.ObjectType == (int)SCADA_ELEMENT_TYPE.NEGATE_IMAGE ? !Convert.ToBoolean(enabled.Value) : Convert.ToBoolean(enabled.Value)
|
|
});
|
|
}
|
|
break;
|
|
|
|
case (int)SCADA_ELEMENT_TYPE.LABEL:
|
|
{
|
|
// Populate & add new object into scada model
|
|
scadaValue.Labels.Add(new DTOScadaLabelModel()
|
|
{
|
|
Id = enabled.Id,
|
|
IsVisible = Convert.ToBoolean(enabled.Value)
|
|
});
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < inputData.Count() - 1; i += 2)
|
|
{
|
|
var obj = inputData[i];
|
|
var enabled = inputData[i + 1];
|
|
|
|
// Populate & add new object into scada model
|
|
scadaValue.Inputs.Add(new DTOScadaInputModel()
|
|
{
|
|
Id = obj.Id,
|
|
Value = new DTOScadaValueModel()
|
|
{
|
|
IsEnabled = obj.Action.ToLower() == SCADA_ACTION.READ ? false : Convert.ToBoolean(enabled.Value),
|
|
Value = obj.Value
|
|
}
|
|
});
|
|
}
|
|
|
|
//st.Stop();
|
|
//Console.WriteLine(st.ElapsedMilliseconds);
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
public static bool EnableThermocam
|
|
{
|
|
get
|
|
{
|
|
bool answ = false;
|
|
bool.TryParse(AdditionalParametersConfig["EnableThermocam"], out answ);
|
|
return answ;
|
|
}
|
|
}
|
|
|
|
public CmsError ReadTCamData(out DTOThermoCam currTCamData)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
currTCamData = new DTOThermoCam();
|
|
// solo x S7...
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
numericalControl.PLC_RWarmerTCamData(out ThermoModels.ThermoCam currPlcTCamData);
|
|
currTCamData = new DTOThermoCam()
|
|
{
|
|
ThermoOptionActive = currPlcTCamData.ThermoOptionActive,
|
|
ThermoCamMode = currPlcTCamData.ThermoCamMode,
|
|
ThermoCamOnOff = currPlcTCamData.ThermoCamOnOff
|
|
};
|
|
// aggiungo dati da parametri addizionali...
|
|
int dimX = 100;
|
|
int dimY = 100;
|
|
int.TryParse(AdditionalParametersConfig["flirImgX"], out dimX);
|
|
int.TryParse(AdditionalParametersConfig["flirImgY"], out dimY);
|
|
currTCamData.ImageSize = new Size()
|
|
{
|
|
X = dimX,
|
|
Y = dimY
|
|
};
|
|
double minVal = 0;
|
|
double maxVal = 100;
|
|
double.TryParse(AdditionalParametersConfig["RangeTempMin"], out minVal);
|
|
double.TryParse(AdditionalParametersConfig["RangeTempMax"], out maxVal);
|
|
currTCamData.RangeTemperature = new RangeVal()
|
|
{
|
|
Min = minVal,
|
|
Max = maxVal
|
|
};
|
|
// controllo se connessa
|
|
currTCamData.ThermoCamConnected = cameraIsConnected;
|
|
}
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Restitusice SOLO VALORI IO Channels
|
|
/// </summary>
|
|
/// <param name="currChannelsIoVal"></param>
|
|
/// <returns></returns>
|
|
public CmsError ReadValIO(out DTOChannelsIOVal currChannelsIoVal)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
currChannelsIoVal = new DTOChannelsIOVal();
|
|
// read and return channel IO data
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
// lettura da PLC
|
|
Dictionary<int, ThermoModels.ModuleBlock> currModBlock = new Dictionary<int, ThermoModels.ModuleBlock>();
|
|
ThermoModels.ChanIOVal currThermoIOVal = new ThermoModels.ChanIOVal();
|
|
ThermoModels.ChanIOFor currThermoIOFor = new ThermoModels.ChanIOFor();
|
|
ThermoModels.ChanIOValFor currThermoIOValFor = new ThermoModels.ChanIOValFor();
|
|
libraryError = numericalControl.PLC_RIOChannelsVal(ref currThermoIOVal, ref currThermoIOFor, ref currThermoIOValFor);
|
|
|
|
// setup da config
|
|
List<DigInVal> listDI = IOConfig.Where(x => x.Category == Model.Constants.TACT_IO_TYPE.DI).Select(x => new DigInVal()
|
|
{
|
|
Id = x.Id,
|
|
Value = currThermoIOVal.DI.ContainsKey(x.Id) ? currThermoIOVal.DI[x.Id] : false
|
|
}).ToList();
|
|
List<DigOutVal> listDO = IOConfig.Where(x => x.Category == Model.Constants.TACT_IO_TYPE.DO).Select(x => new DigOutVal()
|
|
{
|
|
Id = x.Id,
|
|
ForceEnabled = !x.DisableForce,
|
|
Value = currThermoIOVal.DO.ContainsKey(x.Id) ? currThermoIOVal.DO[x.Id] : false,
|
|
IsForced = currThermoIOFor.DO.ContainsKey(x.Id) ? currThermoIOFor.DO[x.Id] : false,
|
|
ForceOne = currThermoIOValFor.DO.ContainsKey(x.Id) ? currThermoIOValFor.DO[x.Id] : false,
|
|
ForceZero = currThermoIOValFor.DO.ContainsKey(x.Id) ? !currThermoIOValFor.DO[x.Id] : false
|
|
}).ToList();
|
|
List<AnalInVal> listAI = IOConfig.Where(x => x.Category == Model.Constants.TACT_IO_TYPE.AI).Select(x => new AnalInVal()
|
|
{
|
|
Id = x.Id,
|
|
Value = currThermoIOVal.AI.ContainsKey(x.Id) ? currThermoIOVal.AI[x.Id] : 0
|
|
}).ToList();
|
|
List<AnalOutVal> listAO = IOConfig.Where(x => x.Category == Model.Constants.TACT_IO_TYPE.AO).Select(x => new AnalOutVal()
|
|
{
|
|
Id = x.Id,
|
|
ForceEnabled = !x.DisableForce,
|
|
Value = currThermoIOVal.AO.ContainsKey(x.Id) ? currThermoIOVal.AO[x.Id] : 0,
|
|
IsForced = currThermoIOFor.AO.ContainsKey(x.Id) ? currThermoIOFor.AO[x.Id] : false,
|
|
ForcedValue = currThermoIOValFor.AO.ContainsKey(x.Id) ? currThermoIOValFor.AO[x.Id] : 0
|
|
}).ToList();
|
|
|
|
// assegno!
|
|
currChannelsIoVal.DI = listDI;
|
|
currChannelsIoVal.DO = listDO;
|
|
currChannelsIoVal.AI = listAI;
|
|
currChannelsIoVal.AO = listAO;
|
|
}
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get all warmers data by channel
|
|
/// </summary>
|
|
/// <param name="useCache">if true uises cached data, if false reads from PLC</param>
|
|
/// <param name="currWarmers">List of <= 1024 warmers channels</param>
|
|
/// <returns></returns>
|
|
public CmsError ReadWarmers(bool useCache, out Dictionary<int, DTOWarmers> currWarmers)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
currWarmers = new Dictionary<int, DTOWarmers>();
|
|
// solo x S7...
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
// leggo stato ricetta da PLC
|
|
Dictionary<int, ThermoModels.WarmerChannel> currPlcWarmers = new Dictionary<int, ThermoModels.WarmerChannel>();
|
|
libraryError = numericalControl.PLC_RWarmerChannelList(useCache, ref currPlcWarmers);
|
|
|
|
// valori in 1/10 di °C
|
|
int dataScale = 10;
|
|
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
try
|
|
{
|
|
// compongo con il resto delle info da config... do x scontato di avere TUTIT i 1024 channels
|
|
List<DTOWarmers> warmersConfig = RiskChannelConfig.Select(x => new DTOWarmers()
|
|
{
|
|
IdChannel = x.IdChannel,
|
|
IdReflector = x.IdReflector,
|
|
//SetpointHMI = x.SetpointRecipe,
|
|
SetpointHMI = currPlcWarmers[x.IdChannel].SetpointHMI,
|
|
TCamActive = currPlcWarmers[x.IdChannel].TCamActive,
|
|
TCamTempAct = currPlcWarmers[x.IdChannel].TCamTempActual / dataScale,
|
|
TCamTempSet = currPlcWarmers[x.IdChannel].TCamTempSet / dataScale,
|
|
SetpointPLC = currPlcWarmers[x.IdChannel].SetpointPLC,
|
|
ChannelStatus = currPlcWarmers[x.IdChannel].ChStatus,
|
|
ActualCurrent = currPlcWarmers[x.IdChannel].CurrAct,
|
|
ActualPerc = currPlcWarmers[x.IdChannel].PercAct,
|
|
MaxPower = x.MaxPower
|
|
}).ToList();
|
|
|
|
// preparo output
|
|
foreach (var item in warmersConfig)
|
|
{
|
|
currWarmers.Add(item.IdChannel, item);
|
|
}
|
|
}
|
|
catch
|
|
{ }
|
|
}
|
|
else
|
|
{
|
|
currWarmers = new Dictionary<int, DTOWarmers>();
|
|
}
|
|
|
|
// restituisco cod errore se trovato
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError RefreshAlarm(uint id)
|
|
{
|
|
// Write in memory the request to refresh the alarm
|
|
return numericalControl.PLC_WRefreshMessage(id);
|
|
}
|
|
|
|
public CmsError RefreshAllAlarms()
|
|
{
|
|
return numericalControl.PLC_WRefreshAllMessages();
|
|
}
|
|
|
|
public bool ResetHeadWTime(int Head)
|
|
{
|
|
CmsError libraryError = numericalControl.PLC_WResetWorkedTimeHead(Head);
|
|
if (libraryError.IsError())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool ResetMachineWTime(uint hour)
|
|
{
|
|
CmsError libraryError = numericalControl.PLC_WResetWorkedTimeMachine(hour);
|
|
if (libraryError.IsError())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public bool ResetMaintenanceCounter(uint counter)
|
|
{
|
|
CmsError libraryError = numericalControl.PLC_WResetMachineCounters(counter);
|
|
if (libraryError.IsError())
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
public CmsError RestoreAlarm(uint id)
|
|
{
|
|
// Write in memory the request to restore the alarm
|
|
return numericalControl.PLC_WRestoreMessage(id);
|
|
}
|
|
|
|
public CmsError SendTCamImageReadyStrb()
|
|
{
|
|
return numericalControl.PLC_WStrFlirAcquired();
|
|
}
|
|
|
|
public CmsError SetActiveLanguage(CultureInfo language)
|
|
{
|
|
//if(NC_VENDOR.OSAI)
|
|
//// Set to true power on data by id
|
|
//return numericalControl.NC_WLanguage(language);
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
public CmsError SetActiveScreen(short screen)
|
|
{
|
|
// Set to true power on data by id
|
|
return numericalControl.NC_SetScreenVisible((NcThermo.SCREEN_PAGE)screen);
|
|
}
|
|
|
|
public NcThermo SetNumericalControl()
|
|
{
|
|
// Return new Numerical control instance choosed from the configuration
|
|
switch (NcConfig.NcVendor)
|
|
{
|
|
case NC_VENDOR.S7NET:
|
|
return new Nc_S7Net(NcConfig.NcIpAddress, NcConfig.NcPort, 2000);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Get historical prodinfo data from DB
|
|
/// </summary>
|
|
/// <param name="num"></param>
|
|
/// <param name="isScrap"></param>
|
|
/// <returns></returns>
|
|
public CmsError SetScrap(int num, bool isScrap)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
|
|
using (ProdInfoController prodInfoController = new ProdInfoController())
|
|
{
|
|
prodInfoController.SetScrap(num, isScrap);
|
|
}
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set Functionality OnOff for ThermoCamera driven regulation (HMI)
|
|
/// </summary>
|
|
/// <param name="enableTCam">Ture = enabled / false = disabled</param>
|
|
/// <returns></returns>
|
|
public CmsError SetTCamActiv(bool enableTCam)
|
|
{
|
|
CmsError libraryError = numericalControl.PLC_WTCamActiv(enableTCam);
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set global mode for ThermoCamera driven regulation (conf)
|
|
/// </summary>
|
|
/// <param name="enableTCam">Ture = enabled / false = disabled</param>
|
|
/// <returns></returns>
|
|
public CmsError SetTCamMode(bool enableTCam)
|
|
{
|
|
CmsError libraryError = numericalControl.PLC_WTCamMode(enableTCam);
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gestione strobe richiesta cambio modo
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public CmsError StrobeMode(Model.DTOModels.ThProd.Mode mode)
|
|
{
|
|
// solo x S7...
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
// call NC for update
|
|
CmsError libraryError = numericalControl.PLC_WModeSel((int)mode);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
}
|
|
else
|
|
{
|
|
return FUNCTION_NOT_ALLOWED_ERROR;
|
|
}
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Update requested prod quantity
|
|
/// </summary>
|
|
/// <param name="numTarget">Total qty requested</param>
|
|
/// <param name="newWorkOrder">Reset counter = new order</param>
|
|
/// <param name="preWarmCycle">Number of pre-warm cycle requested</param>
|
|
/// <returns></returns>
|
|
public CmsError UpdateProdInfoData(short numTarget, bool newWorkOrder, short preWarmCycle)
|
|
{
|
|
CmsError libraryError = NO_ERROR;
|
|
|
|
using (ProdInfoController prodInfoController = new ProdInfoController())
|
|
{
|
|
// registro dati aggiornati sul PLC
|
|
libraryError = numericalControl.PLC_WProdInfo(numTarget, newWorkOrder, preWarmCycle);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// svuoto il db se richiesto reset...
|
|
if (newWorkOrder)
|
|
{
|
|
prodInfoController.PurgeAll();
|
|
}
|
|
}
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// ChannelsID: write AO to PLC (values + setForce)
|
|
/// </summary>
|
|
/// <param name="newValues">Oggetto parametri da aggiornare (from HMI)</param>
|
|
/// <returns></returns>
|
|
public CmsError Write_IO_AO_ToPLC(Dictionary<int, int> newValues)
|
|
{
|
|
// solo x S7...
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
// scrivo!
|
|
CmsError libraryError = numericalControl.PLC_W_IO_AO_Val(newValues);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
}
|
|
else
|
|
{
|
|
return FUNCTION_NOT_ALLOWED_ERROR;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/// <summary>
|
|
/// ChannelsID: write DO to PLC (values + setForce)
|
|
/// </summary>
|
|
/// <param name="newValues">Oggetto parametri da aggiornare (from HMI)</param>
|
|
/// <returns></returns>
|
|
public CmsError Write_IO_DO_ToPLC(Dictionary<int, bool> newValues)
|
|
{
|
|
// solo x S7...
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
// scrivo!
|
|
CmsError libraryError = numericalControl.PLC_W_IO_DO_Val(newValues);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
}
|
|
else
|
|
{
|
|
return FUNCTION_NOT_ALLOWED_ERROR;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Set AdvMode for AXES
|
|
/// </summary>
|
|
/// <param name="advMode">Boolean for advmode true/false</param>
|
|
/// <returns></returns>
|
|
public CmsError SetAxesAdvMode(bool advMode)
|
|
{
|
|
// solo x S7...
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
// scrivo!
|
|
CmsError libraryError = numericalControl.PLC_WAxisGeneralControl(advMode);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
}
|
|
else
|
|
{
|
|
return FUNCTION_NOT_ALLOWED_ERROR;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Get AdvMode for AXES
|
|
/// </summary>
|
|
/// <param name="advMode">Boolean for advmode true/false</param>
|
|
/// <returns></returns>
|
|
public CmsError GetAxesAdvMode(out bool advMode)
|
|
{
|
|
advMode = false;
|
|
// solo x S7...
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
// scrivo!
|
|
CmsError libraryError = numericalControl.PLC_RAxisGeneralStatus(ref advMode);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
}
|
|
else
|
|
{
|
|
return FUNCTION_NOT_ALLOWED_ERROR;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
public void WriteCandy(DateTime value, int machNumber)
|
|
{
|
|
long nDays;
|
|
long Lic = 0;
|
|
nDays = (value.Ticks / TimeSpan.TicksPerDay);
|
|
|
|
//Imposto nel registro
|
|
CandiesController.SetPCLincense(machNumber, nDays);
|
|
|
|
//Imposto nel CN
|
|
Lic = long.Parse(CandiesController.SetLincenseFromData(machNumber, nDays));
|
|
numericalControl.PLC_WCandy(Lic);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scrive le softkey star
|
|
/// </summary>
|
|
/// <param name="idKey1">Softkey ID of the first button</param>
|
|
/// <param name="idKey2">Softkey ID of the second button</param>
|
|
/// <returns></returns>
|
|
public CmsError WriteKeyboardStarSoftkey(int idkey1, int idkey2)
|
|
{
|
|
int val1 = 0;
|
|
int val2 = 0;
|
|
|
|
UserSoftKeyConfigModel userSoftkey1 = SoftKeysConfig.Where(X => X.Id == idkey1).FirstOrDefault();
|
|
UserSoftKeyConfigModel userSoftkey2 = SoftKeysConfig.Where(X => X.Id == idkey2).FirstOrDefault();
|
|
if (userSoftkey1 != null)
|
|
val1 = userSoftkey1.PlcId;
|
|
if (userSoftkey2 != null)
|
|
val2 = userSoftkey2.PlcId;
|
|
|
|
CmsError libraryError = numericalControl.PLC_WKeyboardSoftkey((ushort)val1, (ushort)val2);
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
public CmsError WriteM154Ack(int processId)
|
|
{
|
|
return numericalControl.PLC_W154ManageAck(processId);
|
|
}
|
|
|
|
public CmsError WriteM155Data(int process, double responseValue)
|
|
{
|
|
return numericalControl.PLC_WOperatorInputResponse(process, responseValue);
|
|
}
|
|
|
|
public CmsError WriteM156Data(int process, double responseValue)
|
|
{
|
|
return numericalControl.PLC_WM156Response(process, responseValue);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Recipe Parameters write to PLC (only SetpointHMI)
|
|
/// </summary>
|
|
/// <param name="updtRecipe">Oggetto parametri da aggiornare (from HMI)</param>
|
|
/// <param name="nMaxParamWrite">num max parametri da scrivere singolarmente</param>
|
|
/// <param name="delayParamWrite">delay in scrittura multi parametri singoli</param>
|
|
/// <returns></returns>
|
|
public CmsError WriteRecipeParametersToPLC(Dictionary<string, DTORecipeParam> updtRecipe, int nMaxParamWrite, int delayParamWrite)
|
|
{
|
|
Dictionary<int, int> newParameters = new Dictionary<int, int>();
|
|
// solo x S7...
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
// ciclo x ogni valore della ricetta aggiornata ricevuto
|
|
foreach (var item in updtRecipe)
|
|
{
|
|
newParameters.Add(item.Value.Id, (int)(item.Value.SetpointHMI * item.Value.ScaleFactor));
|
|
}
|
|
// scrivo!
|
|
CmsError libraryError = numericalControl.PLC_WRecipeParameters(newParameters, nMaxParamWrite, delayParamWrite);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
}
|
|
else
|
|
{
|
|
return FUNCTION_NOT_ALLOWED_ERROR;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Scrive tutti i parametri della ricetta indicati
|
|
/// </summary>
|
|
/// <param name="updtRecipe">Oggetto parametri da aggiornare (from HMI)</param>
|
|
/// <param name="nMaxParamWrite">num max parametri da scrivere singolarmente</param>
|
|
/// <param name="delayParamWrite">delay in scrittura multi parametri singoli</param>
|
|
/// <returns></returns>
|
|
public CmsError WriteRecipeParams(Dictionary<string, DTORecipeParam> updtRecipe, int nMaxParamWrite, int delayParamWrite)
|
|
{
|
|
CmsError libraryError = WriteRecipeParametersToPLC(updtRecipe, nMaxParamWrite, delayParamWrite);
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write all warmers load for recipe
|
|
/// </summary>
|
|
/// <param name="updtSetpHmi">Oggetto parametri da aggiornare (from HMI)</param>
|
|
/// <returns></returns>
|
|
public CmsError WriteRecipeWarmChSetpHMI(Dictionary<int, int> updtSetpHmi)
|
|
{
|
|
CmsError libraryError = numericalControl.PLC_WWarmerChSetpHmi(updtSetpHmi);
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write all warmers state as enabled/disabled for thermocam driven regulation
|
|
/// </summary>
|
|
/// <param name="actualStates">Dictionary ChannelId + enabled status for ThermoCam usage</param>
|
|
/// <returns></returns>
|
|
public CmsError WriteRecipeWarmChTCamEnab(Dictionary<int, bool> actualStates)
|
|
{
|
|
CmsError libraryError = numericalControl.PLC_WWarmerChTCamEnab(actualStates);
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write all warmers ACTUAL termocam TEMP data
|
|
/// </summary>
|
|
/// <param name="actualTemp">Dictionary ChannelId + LastRead Temp (from FLIR)</param>
|
|
/// <returns></returns>
|
|
public CmsError WriteRecipeWarmChTCamTempAct(Dictionary<int, double> actualTemp)
|
|
{
|
|
CmsError libraryError = numericalControl.PLC_WWarmerChTCamTempAct(actualTemp);
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write all warmers termocam TEMP data for reference
|
|
/// </summary>
|
|
/// <param name="referenceTemp">Dictionary ChannelId + REF Temp (from HMI)</param>
|
|
/// <returns></returns>
|
|
public CmsError WriteRecipeWarmChTCamTempSet(Dictionary<int, double> referenceTemp)
|
|
{
|
|
CmsError libraryError = numericalControl.PLC_WWarmerChTCamTempSet(referenceTemp);
|
|
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Write all warmers CONFIG data
|
|
/// </summary>
|
|
/// <param name="updtSetpTCam">Oggetto parametri da aggiornare (from HMI)</param>
|
|
/// <returns></returns>
|
|
public CmsError WriteRecipeWarmConfig()
|
|
{
|
|
Dictionary<int, int> newData = new Dictionary<int, int>();
|
|
CmsError libraryError = NO_ERROR;
|
|
|
|
// scrivo l'abilitazione dei canali...
|
|
foreach (var item in RiskBoardConfig)
|
|
{
|
|
newData.Add(item.IdBoard, item.NumChannels > 0 ? 1 : 0);
|
|
}
|
|
libraryError = numericalControl.PLC_WWarmerConfBoardEnabl(newData);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// processo riflettori...
|
|
newData = new Dictionary<int, int>();
|
|
foreach (var item in RiskChannelConfig)
|
|
{
|
|
newData.Add(item.IdChannel, item.IdReflector);
|
|
}
|
|
libraryError = numericalControl.PLC_WWarmerConfRefl(newData);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// recupero parametro VUMin...
|
|
ushort VUMin = 1;
|
|
libraryError = numericalControl.PLC_RWarmerConfVUMin(ref VUMin);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
// check div0!
|
|
if (VUMin == 0)
|
|
{
|
|
VUMin = 230;
|
|
}
|
|
|
|
// processo corrente minima!
|
|
var newFloatTData = new Dictionary<int, double>();
|
|
double minICh = 0;
|
|
int calcPower = 0;
|
|
foreach (var item in RiskChannelConfig)
|
|
{
|
|
minICh = 0;
|
|
if (item.CalcIchMin)
|
|
{
|
|
calcPower = (item.NumResist - 1) * item.MaxPower + item.MaxPower / 2;
|
|
minICh = (double)calcPower / VUMin;
|
|
}
|
|
newFloatTData.Add(item.IdChannel, minICh);
|
|
}
|
|
libraryError = numericalControl.PLC_WWarmerConfMinCurr(newFloatTData);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
|
|
// scrivo altre info della parte warmers da ricetta (resetto temperature actual, set riferimento, abilitazione canali, boolean...)
|
|
numericalControl.PLC_WTCamMode(false);
|
|
numericalControl.PLC_WTCamActiv(false);
|
|
Dictionary<int, bool> resetTCamEnab = new Dictionary<int, bool>();
|
|
Dictionary<int, double> resetTCamTemp = new Dictionary<int, double>();
|
|
foreach (var item in RecipeLiveData.ChannelTCamEnab)
|
|
{
|
|
resetTCamEnab.Add(item.Key, false);
|
|
resetTCamTemp.Add(item.Key, 0);
|
|
}
|
|
numericalControl.PLC_WWarmerChTCamEnab(resetTCamEnab);
|
|
numericalControl.PLC_WWarmerChTCamTempAct(resetTCamTemp);
|
|
numericalControl.PLC_WWarmerChTCamTempSet(resetTCamTemp);
|
|
// esce
|
|
return libraryError;
|
|
}
|
|
|
|
/// <summary>
|
|
/// ChannelsID: Write RESET (not forced) for DO + AO to PLC (setForce = false)
|
|
/// </summary>
|
|
/// <param name="newValues">Oggetto parametri da aggiornare (from HMI)</param>
|
|
/// <param name="nMaxParamWrite">num max parametri da scrivere singolarmente</param>
|
|
/// <param name="delayParamWrite">delay in scrittura multi parametri singoli</param>
|
|
/// <returns></returns>
|
|
public CmsError WriteReset_IO_ALL_ToPLC()
|
|
{
|
|
// solo x S7...
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
// scrivo!
|
|
CmsError libraryError = numericalControl.PLC_W_IO_ResetAll();
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
}
|
|
else
|
|
{
|
|
return FUNCTION_NOT_ALLOWED_ERROR;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/// <summary>
|
|
/// ChannelsID: Write RESET (not forced) for AO to PLC (setForce = false)
|
|
/// </summary>
|
|
/// <param name="channels">Oggetto parametri da aggiornare (from HMI)</param>
|
|
/// <returns></returns>
|
|
public CmsError WriteReset_IO_AO_ToPLC(List<int> channels)
|
|
{
|
|
// solo x S7...
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
Dictionary<int, bool> newForced = new Dictionary<int, bool>();
|
|
foreach (var item in channels)
|
|
{
|
|
newForced.Add(item, false);
|
|
}
|
|
// scrivo!
|
|
CmsError libraryError = numericalControl.PLC_W_IO_AO_Reset(newForced);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
}
|
|
else
|
|
{
|
|
return FUNCTION_NOT_ALLOWED_ERROR;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
/// <summary>
|
|
/// ChannelsID: Write RESET (not forced) for DO to PLC (setForce = false)
|
|
/// </summary>
|
|
/// <param name="channels">Oggetto parametri da aggiornare (from HMI)</param>
|
|
/// <returns></returns>
|
|
public CmsError WriteReset_IO_DO_ToPLC(List<int> channels)
|
|
{
|
|
// solo x S7...
|
|
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
|
|
{
|
|
Dictionary<int, bool> newForced = new Dictionary<int, bool>();
|
|
foreach (var item in channels)
|
|
{
|
|
newForced.Add(item, false);
|
|
}
|
|
// scrivo!
|
|
CmsError libraryError = numericalControl.PLC_W_IO_DO_Reset(newForced);
|
|
if (libraryError.IsError())
|
|
return libraryError;
|
|
}
|
|
else
|
|
{
|
|
return FUNCTION_NOT_ALLOWED_ERROR;
|
|
}
|
|
return NO_ERROR;
|
|
}
|
|
|
|
public CmsError WriteScada(string memIndex, SCADA_MEM_TYPE memType, object value)
|
|
{
|
|
return numericalControl.PLC_WScadaValue(memIndex, memType, value);
|
|
}
|
|
|
|
#endregion Public Methods
|
|
}
|
|
} |