Files
cms_thermo_active/Thermo.Active.NC/NcAdapter.cs
T
2020-09-02 13:26:16 +02:00

2844 lines
115 KiB
C#

using CMS_CORE_Library;
using CMS_CORE_Library.Models;
using CMS_CORE_Library.S7Net;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Thermo.Active.Database.Controllers;
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.ThModules;
using Thermo.Active.Model.DTOModels.ThProd;
using Thermo.Active.Model.DTOModels.ThRecipe;
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
{
/// <summary>
/// NC object
/// </summary>
public NcThermo numericalControl;
/// <summary>
/// Lock semaphore for PLC connection step
/// </summary>
private readonly static object connectLock = new object();
/// <summary>
/// Avvio prod lotto
/// </summary>
public DateTime lottoStart;
/// <summary>
/// Ultimo avvio prod pz
/// </summary>
protected DateTime lastProdStart;
/// <summary>
/// Ultima fine prod pz
/// </summary>
protected DateTime lastProdEnd;
/// <summary>
/// Ultimo ciclo registrato(secondi)
/// </summary>
protected double lastCycle = 9999;
/// <summary>
/// Recipe Live data
/// </summary>
public static LiveData RecipeLiveData = new LiveData();
public NcAdapter() =>
// Choose NC
numericalControl = SetNumericalControl();
public void Dispose()
{
if (NcConfig.NcVendor != NC_VENDOR.SIEMENS)
numericalControl.NC_Disconnect();
}
public void Disconnect()
{
numericalControl.NC_Disconnect();
}
public CmsError Connect()
{
lock (connectLock)
{
// Connect NC
if (!numericalControl.NC_IsConnected())
return numericalControl.NC_Connect();
}
lastProdStart = DateTime.Now;
return NO_ERROR;
}
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;
}
#region StatusCommand words
/// <summary>
/// variabili delle richieste da PLC: tutte nella status command
/// </summary>
private static List<ushort> statusCmd = new List<ushort>();
/// <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;
}
private static bool ThermoReqConfWarmerStr
{
get
{
bool answ = false;
if (statusCmd.Count > 0)
{
try
{
answ = checkBitOnWord(statusCmd[0], 7);
}
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 ThermoProdUpdatedStr
{
get
{
bool answ = false;
if (statusCmd != null)
{
if (statusCmd.Count > 0)
{
try
{
answ = checkBitOnWord(statusCmd[0], 3);
}
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 ThermoProdEndStr
{
get
{
bool answ = false;
if (statusCmd != null)
{
if (statusCmd.Count > 0)
{
try
{
answ = checkBitOnWord(statusCmd[0], 11);
}
catch
{ }
}
}
return answ;
}
}
#endregion
#region cached data
/// <summary>
/// Last recipe data from PLC
/// </summary>
protected static Dictionary<string, DTORecipeParam> lastRecipe = new Dictionary<string, DTORecipeParam>();
/// <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();
#endregion
#region Read Data
#region Axes
public CmsError GetAxesPositions(out List<DTOAxesModel> axes)
{
axes = new List<DTOAxesModel>();
// Get NC max process number
ushort maxProcNumber = 0;
CmsError libraryError = numericalControl.NC_RProcessesNum(ref maxProcNumber);
if (libraryError.errorCode != 0)
return libraryError;
// For each process
for (ushort i = 1; i <= maxProcNumber; i++)
{
libraryError = GetAxesPositionsByProcess(i, out DTOAxesModel axis);
if (libraryError.errorCode != 0)
return libraryError;
axes.Add(axis);
}
return libraryError;
}
public CmsError GetAxesPositionsBySelectedProcess(out DTOAxesModel axes)
{
axes = new DTOAxesModel();
// Get selectedProcess process number
ushort selectedProcess = 0;
CmsError libraryError = numericalControl.PROC_RSelectedProcess(ref selectedProcess);
if (libraryError.IsError())
return libraryError;
if (selectedProcess > 0)
libraryError = GetAxesPositionsByProcess(selectedProcess, out axes);
return libraryError;
}
public CmsError GetAxesPositionsByProcess(ushort processNum, out DTOAxesModel axes)
{
axes = new DTOAxesModel();
CmsError libraryError = numericalControl.AXES_RInterpPosition(processNum, ref axes.interpolated);
if (libraryError.errorCode != 0)
return libraryError;
libraryError = numericalControl.AXES_RMachinePosition(processNum, ref axes.machine);
if (libraryError.errorCode != 0)
return libraryError;
libraryError = numericalControl.AXES_RProgrPosition(processNum, ref axes.programmePos);
if (libraryError.errorCode != 0)
return libraryError;
libraryError = numericalControl.AXES_RDistanceToGo(processNum, ref axes.toGo);
if (libraryError.errorCode != 0)
return libraryError;
//numericalControl.AXES_RFollowingError(1, ref axes.followingErr);
return libraryError;
}
public CmsError ReadAxisData(out List<DTOAxisNameModel> axesNames)
{
axesNames = new List<DTOAxisNameModel>();
List<AxisModel> plcAxes = new List<AxisModel>();
// Read selected process
ushort selectedProcess = 0;
CmsError libraryError = numericalControl.PROC_RSelectedProcess(ref selectedProcess);
if (libraryError.IsError())
return libraryError;
if (selectedProcess != 0)
{
// Read axes names
libraryError = numericalControl.AXES_RAxesNames(selectedProcess, ref plcAxes);
axesNames = plcAxes.Select(x => new DTOAxisNameModel()
{
Id = x.Id,
Name = x.Name,
IsSelectable = x.IsSelectable,
Type = x.Type.ToString()
}).ToList();
}
return libraryError;
}
#endregion Axes
public CmsError ManageWatchdog()
{
return numericalControl.PLC_RWManageWatchdog();
}
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 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);
// 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 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 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 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;
}
}
#if false
// Read selected axes
libraryError = numericalControl.AXES_RSelectedAxis(ref processesData.SelectedAxis);
if (libraryError.IsError())
return libraryError;
QueueStatusModel queueStatus = new QueueStatusModel();
// Get queue data
libraryError = numericalControl.FILES_RQueueDataByProcess(ref queueStatus, processesData.SelectedProcess);
if (libraryError.IsError())
return libraryError;
// Get selectedProcessData
SelectedProcessData selectedData = new SelectedProcessData();
libraryError = numericalControl.PROC_RSelectedProcessData(processesData.SelectedProcess, ref selectedData);
if (libraryError.IsError())
return libraryError;
String UMeas = "mm";
// Get process status
libraryError = numericalControl.NC_RUnitOfMeasure(ref UMeas);
if (libraryError.IsError())
return libraryError;
// Set data
processesData.QueueStatus = queueStatus.Status;
processesData.StartStopQueueEnabled = queueStatus.StartStopQueueEnabled;
// Selected process data
processesData.ActiveOrigin = selectedData.Origin;
processesData.ActiveOffsetId = selectedData.ActiveOffsetId;
processesData.ProcessMessage = selectedData.ProcessMessage;
// Overrides
processesData.RapidOverride = selectedData.RapidOverride;
processesData.WorkOverride = selectedData.WorkOverride;
processesData.offsetData = selectedData.OffsetData;
// Measure
processesData.UnitMeasure = UMeas;
processesData.FeedOverride = selectedData.FeedOverride;
#endif
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 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 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 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 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 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;
}
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 GetM154Data(out List<M154DataModel> data, out bool MTCStatus)
{
MTCStatus = false;
data = new List<M154DataModel>();
return numericalControl.PLC_RM154Data(ref data, ref MTCStatus);
}
public CmsError WriteM154Ack(int processId)
{
return numericalControl.PLC_W154ManageAck(processId);
}
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 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 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 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;
// inizio da ncAdapter.lottoStart
currentProdPanel.InizioProd = lottoStart;
// 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
dataChanged = (LastProdPanelData.NumDone != lastProdInfoData.NumDone);
}
}
if (dataChanged)
{
// parto dai dati di lastProdInfoData...
if (lastProdInfoData != null)
{
currentProdPanel.NumDone = lastProdInfoData.NumDone;
currentProdPanel.NumTarget = lastProdInfoData.NumTarget;
currentProdPanel.LastTCiclo = Math.Round((double)lastProdInfoData.TimeCycleGross / 1000, 2);
if (lastProdInfoData.TimeCycleGross > 0)
{
currentProdPanel.LastCadenza = Math.Round((double)3600000 / lastProdInfoData.TimeCycleGross, 2);
}
// stima durata da pz fatti...
currentProdPanel.StimaDurata = Math.Round((currentProdPanel.NumTarget - currentProdPanel.NumDone) * currentProdPanel.LastTCiclo, 2);
// se stima negativa (+ pezzi di quanti richiesti...) --> ZERO!
currentProdPanel.StimaDurata = currentProdPanel.StimaDurata < 0 ? 0 : currentProdPanel.StimaDurata;
}
// 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...
if (currentProdPanel.NumDone > 0)
{
libraryError = GetHistProdInfoData(out List<ThermoModels.ProdInfoModel> prodInfoDataList, currentProdPanel.NumDone, numRecProdPanelGraph);
// se ci sono dati --> creo le 2 TS!
if (prodInfoDataList != null)
{
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...
libraryError = GetHistProdInfoData(out List<ThermoModels.ProdInfoModel> prodInfoFirst, 1, 1);
// se ci sono dati --> fix start
if (prodInfoFirst != null && prodInfoFirst.Count > 0)
{
try
{
currentProdPanel.InizioProd = prodInfoFirst.FirstOrDefault().DtEvent;
}
catch
{ }
}
}
// salvo ultimi dati!
LastProdPanelData = currentProdPanel;
}
else
{
// uso ultimi dati
currentProdPanel = LastProdPanelData;
}
return libraryError;
}
/// <summary>
/// Lettura dati ProdInfo
/// </summary>
/// <param name="prodInfoData"></param>
/// <returns></returns>
public CmsError ReadProdInfoData(out DTOProdInfo prodInfoData)
{
prodInfoData = new DTOProdInfo();
ThermoModels.ProdInfoModel prodInfoRawData = new ThermoModels.ProdInfoModel();
CmsError libraryError = numericalControl.PLC_RProdInfo(ref prodInfoRawData);
if (libraryError.IsError())
return libraryError;
// converto 1:1 dati da ThermoModels.ProdInfoModel --> DTOProdInfo
prodInfoData = new DTOProdInfo(prodInfoRawData);
// if lastProdInfo is missing --> populate!
if (lastProdInfoData == null)
lastProdInfoData = prodInfoRawData;
// se ho update OPPURE differenza di lettura..., sennò restituisco ultima lettura...
if (ThermoProdUpdatedStr || (lastProdInfoData.NumDone != prodInfoRawData.NumDone))
{
// do comparison with old record and if changed --> persist on DB!
if (!prodInfoRawData.Equals(lastProdInfoData))
{
// save on DB!
using (ProdInfoController prodInfoController = new ProdInfoController())
prodInfoController.Create(prodInfoRawData.NumTarget, prodInfoRawData.NumDone, prodInfoRawData.TimeWarm, prodInfoRawData.TimeVent, prodInfoRawData.TimeVacuum, prodInfoRawData.TimeCycleGross, prodInfoRawData.TimeCycleNet, prodInfoRawData.MaterialTempEndWarm, prodInfoRawData.MaterialTempEndVent, prodInfoRawData.MoldTemp, prodInfoRawData.VacuumReadVal, prodInfoRawData.MouldEnergyOUT, prodInfoRawData.MouldEnergyIN);
// update last info data
lastProdInfoData = prodInfoRawData;
// manage strobe/ack!
libraryError = numericalControl.PLC_WAckProdUpdate();
if (libraryError.IsError())
return libraryError;
}
}
else
{
prodInfoRawData = lastProdInfoData;
}
// 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 (ma NON inferiore a 1/3...) --> uso SOLO ultimo
if ((lastCycle > 3 * lastDuration) && (lastCycle / 3 < lastDuration))
{
lastCycle = lastDuration;
}
// altrimenti EWMA 50%
else
{
lastCycle = 0.5 * lastCycle + 0.5 * lastDuration;
}
// 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>
/// Get historical prodinfo data from DB
/// </summary>
/// <param name="prodInfoDataList"></param>
/// <param name="numStart"></param>
/// <param name="numRec"></param>
/// <returns></returns>
public CmsError GetHistProdInfoData(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.GetPaginated(numStart, numRec);
// converto!
prodInfoDataList = results.Select(x => new ThermoModels.ProdInfoModel()
{
DtEvent = x.DtEvent,
NumTarget = x.NumTarget,
NumDone = x.NumDone,
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
}).ToList();
}
return libraryError;
}
/// <summary>
/// Update requested prod quantity
/// </summary>
/// <param name="numTarget"></param>
/// <param name="newWorkOrder"></param>
/// <returns></returns>
public CmsError UpdateProdInfoData(short numTarget, bool newWorkOrder)
{
CmsError libraryError = NO_ERROR;
using (ProdInfoController prodInfoController = new ProdInfoController())
{
// registro dati aggiornati sul PLC
libraryError = numericalControl.PLC_WProdInfo(numTarget, newWorkOrder);
if (libraryError.IsError())
return libraryError;
// svuoto il db se richiesto reset...
if (newWorkOrder)
{
prodInfoController.PurgeAll();
}
}
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>
/// 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 = "",
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;
}
/// <summary>
/// Recipe Parameters write to PLC (only SetpointHMI)
/// </summary>
/// <param name="updtRecipe"></param>
/// <returns></returns>
public CmsError WriteRecipeParametersToPLC(Dictionary<string, DTORecipeParam> updtRecipe)
{
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);
if (libraryError.IsError())
return libraryError;
}
else
{
return FUNCTION_NOT_ALLOWED_ERROR;
}
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;
}
/// <summary>
/// Vero metodo lettura Warmers data da memoria PLC
/// </summary>
/// <param name="currentWarmers"></param>
/// <returns></returns>
public CmsError ReadWarmersData(out Dictionary<int, DTOWarmers> currentWarmers)
{
// init obj
currentWarmers = new Dictionary<int, DTOWarmers>();
// solo x S7...
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
{
CmsError libraryError = NO_ERROR;
// leggo stato ricetta da PLC
Dictionary<int, ThermoModels.WarmerChannel> currPlcWarmers = new Dictionary<int, ThermoModels.WarmerChannel>();
libraryError = numericalControl.PLC_RWarmerChannelList(ref currPlcWarmers);
if (libraryError.IsError())
return libraryError;
// 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,
SetpointTermocam = 0, // FIXME TODO x.SetpointTer,
SetpointPLC = currPlcWarmers[x.IdChannel].SetpointPLC,
ChannelStatus = currPlcWarmers[x.IdChannel].ChStatus,
ActualCurrent = currPlcWarmers[x.IdChannel].CurrAct,
ActualPerc = currPlcWarmers[x.IdChannel].PercAct,
MaxPower = x.MaxPower
}).ToList();
}
else
{
currentWarmers = new Dictionary<int, DTOWarmers>();
}
return NO_ERROR;
}
/// <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;
}
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;
}
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;
}
/// <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, true, out currRecipe);
if (libraryError.IsError())
return libraryError;
// restituisco cod errore se trovato
return libraryError;
}
/// <summary>
/// Scrive tutti i parametri della ricetta indicati
/// </summary>
/// <param name="updtRecipe">Oggetto parametri da aggiornare (from HMI)</param>
/// <returns></returns>
public CmsError WriteRecipeParams(Dictionary<string, DTORecipeParam> updtRecipe)
{
CmsError libraryError = WriteRecipeParametersToPLC(updtRecipe);
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);
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;
#if DEBUG
checkCondition = (currRecipe[item.Label].Status.HasError && currRecipe[item.Label].Status.Visible);
#else
checkCondition = (currRecipe[item.Label].Status.HasError);
#endif
// 2020.07.29 - controllo condizione secondo status debug/release...
if (checkCondition)
{
currOverview[getRecipeSection(item.Category)] = RecipeCatStatus.HasError;
}
}
}
// restituisco cod errore se trovato
return libraryError;
}
/// <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;
}
/// <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 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
};
currModules.Add(item.Id, currVal);
}
catch
{ }
}
}
return libraryError;
}
/// <summary>
/// GEt all warmers data by channel
/// </summary>
/// <param name="currWarmers">List of <= 1024 warmers channels</param>
/// <returns></returns>
public CmsError ReadWarmers(out Dictionary<int, DTOWarmers> currWarmers)
{
CmsError libraryError = NO_ERROR;
currWarmers = new Dictionary<int, DTOWarmers>();
DTOWarmers currVal = new DTOWarmers();
// read and return warmers data
if (NcConfig.NcVendor == NC_VENDOR.S7NET)
{
Dictionary<int, ThermoModels.WarmerChannel> currPlcWarmChan = new Dictionary<int, ThermoModels.WarmerChannel>();
libraryError = numericalControl.PLC_RWarmerChannelList(ref currPlcWarmChan);
foreach (var item in RiskChannelConfig)
{
try
{
ThermoModels.WarmerChannel currWarm = currPlcWarmChan[item.IdChannel];
currVal = new DTOWarmers()
{
IdChannel = item.IdChannel,
IdReflector = item.IdReflector,
SetpointHMI = currWarm.SetpointHMI,
SetpointTermocam = currWarm.SetpointThermoCam,
SetpointPLC = currWarm.SetpointPLC,
ChannelStatus = currWarm.ChStatus,
ActualCurrent = currWarm.CurrAct,
ActualPerc = currWarm.PercAct,
MaxPower = item.MaxPower
};
currWarmers.Add(item.IdChannel, currVal);
}
catch
{ }
}
}
// gestione errore
if (libraryError.IsError())
return libraryError;
// restituisco cod errore se trovato
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(false, 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;
}
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>
/// 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 termocam data for recipe
/// </summary>
/// <param name="updtSetpTCam">Oggetto parametri da aggiornare (from HMI)</param>
/// <returns></returns>
public CmsError WriteRecipeWarmChSetpTermoCam(Dictionary<int, int> updtSetpTCam)
{
CmsError libraryError = numericalControl.PLC_WWarmerChSetpTCam(updtSetpTCam);
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;
return libraryError;
}
#endregion Read Data
#region Write data
public CmsError PutUserSoftKeyClick(uint id)
{
// Write user softkey press to plc
return numericalControl.PLC_WUserSoftKey(id);
}
public CmsError RefreshAlarm(uint id)
{
// Write in memory the request to refresh the alarm
return numericalControl.PLC_WRefreshMessage(id);
}
public CmsError RestoreAlarm(uint id)
{
// Write in memory the request to restore the alarm
return numericalControl.PLC_WRestoreMessage(id);
}
public CmsError RefreshAllAlarms()
{
return numericalControl.PLC_WRefreshAllMessages();
}
public CmsError PutSelectProcess(ushort procNumber)
{
return numericalControl.PROC_WSelectProcess(procNumber);
}
public CmsError PutSelectAxis(byte axisId)
{
return numericalControl.AXES_WSelectAxis(axisId);
}
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 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 CmsError WriteM155Data(int process, double responseValue)
{
return numericalControl.PLC_WOperatorInputResponse(process, responseValue);
}
public CmsError WriteScada(string memIndex, SCADA_MEM_TYPE memType, object value)
{
return numericalControl.PLC_WScadaValue(memIndex, memType, value);
}
#endregion Write data
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;
}
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 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);
}
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 ResetHeadWTime(int Head)
{
CmsError libraryError = numericalControl.PLC_WResetWorkedTimeHead(Head);
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 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 GetActiveClient(out int clientId)
{
clientId = 0;
return numericalControl.PLC_RActiveClient(ref clientId);
}
}
}