Files
2021-04-28 19:37:53 +02:00

738 lines
19 KiB
C#

using MapoSDK;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace IOB_UT
{
/// <summary>
/// informazioni di produzione
/// </summary>
public struct prodData
{
#region Public Fields
public int AccTime;
public bool EmrStop;
public string FuncMode;
public string MessageCode;
public string MessageText;
public string Operator;
public int Power;
public bool Status;
#endregion Public Fields
}
/// <summary>
/// Gestione Endianness
/// </summary>
public static class Endian
{
#region Public Methods
/// <summary>
/// Scambia MSB/LSB per 16bit
/// </summary>
/// <param name="inValue"></param>
/// <returns></returns>
public static UInt16 SwapUInt16(UInt16 inValue)
{
return (UInt16)(((inValue & 0xff00) >> 8) |
((inValue & 0x00ff) << 8));
}
/// <summary>
/// Scambia MSB/LSB per 32bit
/// </summary>
/// <param name="inValue"></param>
/// <returns></returns>
public static UInt32 SwapUInt32(UInt32 inValue)
{
return ((inValue & 0xff000000) >> 24) |
((inValue & 0x00ff0000) >> 8) |
((inValue & 0x0000ff00) << 8) |
((inValue & 0x000000ff) << 24);
}
#endregion Public Methods
}
/// <summary>
/// GEstione dati di timing
/// </summary>
public static class TimingData
{
#region Public Fields
public static List<TimeRec> results = new List<TimeRec>();
#endregion Public Fields
#region Public Methods
/// <summary>
/// aggiorno vettore aggiungendo risultato
/// </summary>
/// <param name="caller">Codice chiamante</param>
/// <param name="codice">Codice da registrare (univoco con chiamante)</param>
/// <param name="ticks">Tempo esecuzione in ticks</param>
public static void addResult(string caller, string codice, long ticks)
{
if (results.Count == 0)
{
results.Add(new TimeRec(caller, codice, ticks));
}
int indice = -1;
for (int i = 0; i < results.Count; i++)
{
// se il codice è quello cercato...
if (results[i].codCall == codice && results[i].classCall == caller)
{
indice = i;
}
}
// se c'è aggiorno...
if (indice >= 0)
{
results[indice].numCall++;
results[indice].totMsec = results[indice].totMsec.Add(new TimeSpan(ticks));
}
// altrimenti aggiungo...
else
{
results.Add(new TimeRec(caller, codice, ticks));
}
}
/// <summary>
/// Resetta i dati registrati (ad avvio adapter...)
/// </summary>
public static void resetData()
{
results = new List<TimeRec>();
}
#endregion Public Methods
}
/// <summary>
/// Cache a tempo valori INT
/// </summary>
public class CachedInt
{
#region Public Properties
public DateTime ValidUntil { get; set; } = DateTime.Now;
public int Value { get; set; } = 0;
#endregion Public Properties
}
/// <summary>
/// Cache a tempo valori String
/// </summary>
public class CachedString
{
#region Public Properties
public DateTime ValidUntil { get; set; } = DateTime.Now;
public string Value { get; set; } = "";
#endregion Public Properties
}
/// <summary>
/// Classe conf x item DynData
/// </summary>
public class DynDataItem
{
#region Public Fields
/// <summary>
/// DataOra scadenza invio forzato
/// </summary>
public DateTime DTScad = DateTime.Now;
#endregion Public Fields
#region Public Properties
/// <summary>
/// Valore effettivo da salvare
/// </summary>
public string actVal { get; set; } = "";
public string func { get; set; } = "";
public string key { get; set; } = "";
public string name { get; set; } = "";
public int sPeriod { get; set; } = 60;
public string unit { get; set; } = "";
public string val { get; set; } = "";
#endregion Public Properties
}
/// <summary>
/// Configurazione per Eventi/Variabili
/// </summary>
public class EVData
{
#region Public Fields
/// <summary>
/// DataOra scadenza invio forzato
/// </summary>
public DateTime DTScad = DateTime.Now;
#endregion Public Fields
#region Public Properties
/// <summary>
/// Unità di misura
/// </summary>
public string UM { get; set; } = "num";
/// <summary>
/// Valore salvato
/// </summary>
public string Val { get; set; } = "";
#endregion Public Properties
}
/// <summary>
/// Rappresentazione dello stato corrente dell'IOB
/// </summary>
public class IobWinStatus
{
#region Public Properties
/// <summary>
/// ID univoco
/// </summary>
public string CodIob { get; set; } = "0";
/// <summary>
/// Contatore IOB
/// </summary>
public float counterIOB { get; set; } = 0;
/// <summary>
/// Contatore Macchina
/// </summary>
public float counterMAC { get; set; } = 0;
/// <summary>
/// DataOra ultima comunicazione IN (con PLC)
/// </summary>
public DateTime lastDataIn { get; set; } = DateTime.Now.AddMinutes(-1);
/// <summary>
/// DataOra ultima comunicazione OUT (con MP Server)
/// </summary>
public DateTime lastUpdate { get; set; } = DateTime.Now.AddDays(-1);
/// <summary>
/// Status del SINGOLO IOB
/// </summary>
public bool online { get; set; } = false;
#if false
/// <summary>
/// Indica se sia correntemente in setup
/// </summary>
public bool inSetup { get; set; } = false;
/// <summary>
/// Semaforo IN (IOB-PLC)
/// </summary>
public Semaforo SemIn { get; set; } = Semaforo.ND;
/// <summary>
/// Semaforo OUT (IOB-MPserver)
/// </summary>
public Semaforo SemOut { get; set; } = Semaforo.ND;
#endif
/// <summary>
/// Lungh coda ALLARMI in uscita
/// </summary>
public int queueAlLen { get; set; } = 0;
/// <summary>
/// Lunghezza coda EVENTI in uscita
/// </summary>
public int queueEvLen { get; set; } = 0;
/// <summary>
/// Lunghezza coda FluxLog in uscita
/// </summary>
public int queueFlLen { get; set; } = 0;
/// <summary>
/// Lungh coda MESSAGGI in uscita
/// </summary>
public int queueMsLen { get; set; } = 0;
#endregion Public Properties
#if false
/// <summary>
/// DataOra ultima comunicazione OUT (con MP Server)
/// </summary>
public DateTime lastDataOut { get; set; } = DateTime.Now.AddDays(-1);
/// <summary>
/// Ultimo stato noto dei parametri in memoria letti da PLC
/// </summary>
public Dictionary<string, string> currParams { get; set; } = null;
#endif
}
/// <summary>
/// Elenco oggetti del monitoraggio (DynData, Status) per WPS
/// </summary>
public class MonitoredItemsConf
{
#region Public Properties
public List<DynDataItem> DynData { get; set; }
public srvData SrvData { get; set; }
public List<StatusItem> Status { get; set; }
#endregion Public Properties
}
/// <summary>
/// Classe che contiene tutte le NUOVE informazioni da aggiornare sulla form
/// </summary>
public class newDisplayData
{
#region Public Properties
/// <summary>
/// Oggetto COUTNER generico (pezzi, portata...)
/// </summary>
public int counter { get; set; } = -9999;
/// <summary>
/// Bitmap attuale segnali letti
/// </summary>
public string currBitmap { get; set; } = "";
/// <summary>
/// Verifica se contenga valori (NON default/empty)
/// </summary>
public bool hasData
{
get
{
bool answ = false;
// true se qualcosa NON E' come default
if (!string.IsNullOrWhiteSpace(newInData) || !string.IsNullOrWhiteSpace(newSignalData) || !string.IsNullOrWhiteSpace(newFLogData) || !string.IsNullOrWhiteSpace(newUrlCallData) || !string.IsNullOrWhiteSpace(newLiveLogData) || counter > -9999 || !string.IsNullOrWhiteSpace(currBitmap) || semIn != Semaforo.ND || semOut != Semaforo.ND)
{
answ = true;
}
return answ;
}
}
/// <summary>
/// Dati tipo FluxLog
/// </summary>
public string newFLogData { get; set; } = "";
/// <summary>
/// Dati tipo IN (RAW)
/// </summary>
public string newInData { get; set; } = "";
/// <summary>
/// Dati tipo LiveLog
/// </summary>
public string newLiveLogData { get; set; } = "";
/// <summary>
/// Dati tipo Signal
/// </summary>
public string newSignalData { get; set; } = "";
/// <summary>
/// Dati tipo UrlCall
/// </summary>
public string newUrlCallData { get; set; } = "";
/// <summary>
/// Stato semaforo IN verso PLC
/// </summary>
public Semaforo semIn { get; set; } = Semaforo.ND;
/// <summary>
/// Stato semaforo OUT verso MES
/// </summary>
public Semaforo semOut { get; set; } = Semaforo.ND;
#endregion Public Properties
}
/// <summary>
/// Dato generico (per decodifica)
/// </summary>
public class otherData
{
#region Public Fields
public string codNum;
public string dataType;
public string memAddr;
public string varName;
#endregion Public Fields
#region Public Constructors
public otherData()
{
codNum = "";
memAddr = "";
varName = "";
dataType = "";
}
public otherData(string _codNum, string _memAddr, string _varName, string _dataType)
{
codNum = _codNum;
memAddr = _memAddr;
varName = _varName;
dataType = _dataType;
}
#endregion Public Constructors
}
/// <summary>
/// Classe gestione valori campionati su periodo
/// </summary>
public class sampleVect
{
#region Protected Fields
/// <summary>
/// vettore valori temporali della serie
/// </summary>
protected List<DateTime> lTime;
/// <summary>
/// vettore valoti puntuali della serie
/// </summary>
protected List<int> lVal;
/// <summary>
/// Dimensione finestra di campionamento (secondi)
/// </summary>
protected int windSize;
#endregion Protected Fields
#region Public Constructors
/// <summary>
/// Inizializzo l'oggetto
/// </summary>
public sampleVect()
{
// init valori default...
windSize = baseUtils.CRI("countWindSize") > 0 ? baseUtils.CRI("countWindSize") : 60;
lTime = new List<DateTime>();
lVal = new List<int>();
}
#endregion Public Constructors
#region Protected Properties
/// <summary>
/// Verifica ampiezza finestra valori First-Last
/// </summary>
protected double flWindSize
{
get
{
double answ = 0;
if (numElem > 1)
{
answ = lTime.Last().Subtract(lTime[0]).TotalSeconds;
}
return answ;
}
}
/// <summary>
/// Conteggio elementi
/// </summary>
protected int numElem
{
get
{
int answ = 0;
try
{
answ = lTime.Count;
}
catch
{ }
return answ;
}
}
/// <summary>
/// Verifica ampiezza finestra valori Second-Last
/// </summary>
protected double slWindSize
{
get
{
double answ = 0;
if (numElem > 2) // altrimenti SE non ne ho almeno 3 NON posso avere secondo/ultimo...
{
answ = lTime.Last().Subtract(lTime[1]).TotalSeconds;
}
return answ;
}
}
#endregion Protected Properties
#region Public Properties
/// <summary>
/// Calcola il valore mediano...
/// </summary>
public double vcMedian
{
get
{
double answ = 0;
// restituisce la mediana SE valida, altrimenti null...
if (numElem > 2 && flWindSize > windSize)
{
try
{
// calcolo mediana!
//answ = Statistics.Median(lVal.ToArray());
// rif: https://blogs.msmvps.com/deborahk/linq-mean-median-and-mode/
var sortedNumbers = lVal.OrderBy(n => n);
int numCount = lVal.Count;
int indice50 = lVal.Count / 2;
if ((numCount % 2) == 0)
{
answ = ((sortedNumbers.ElementAt(indice50) + sortedNumbers.ElementAt(indice50 - 1)) / 2);
}
else
{
answ = sortedNumbers.ElementAt(indice50);
}
}
catch
{ }
}
return answ;
}
}
/// <summary>
/// Verifica se la vc sia valida (ovvero almeno 2 valori e intervallo > window richiesta)
/// </summary>
public bool vcValid
{
get
{
return (flWindSize > windSize && numElem > 1);
}
}
#endregion Public Properties
#region Public Methods
/// <summary>
/// Aggiunge un valore alla serie ed eventualmente elimina i valori superflui a garantirne una finestra temporale valida
/// </summary>
/// <param name="tempo"></param>
/// <param name="valore"></param>
public void addValue(DateTime tempo, int valore)
{
lTime.Add(tempo);
lVal.Add(valore);
// verifico se siano da accorciare le serie... ovvero i 2 intervalli ENTRAMBI sono superiori al periodo minimo (in tal caso riduco..
while (flWindSize > windSize && slWindSize > windSize)
{
// elimino i 2 valori + vecchi
lTime.RemoveAt(0);
lVal.RemoveAt(0);
// ora ricontrollo...
}
}
#endregion Public Methods
}
/// <summary>
/// Classe x descrivere status server MP
/// </summary>
public class ServerMpStatus
{
#region Public Properties
/// <summary>
/// IP server
/// </summary>
public string IP { get; set; }
/// <summary>
/// DataOra ultima comunicazione OUT (con MP Server)
/// </summary>
public DateTime lastUpdate { get; set; } = DateTime.Now.AddDays(-1);
/// <summary>
/// Status del server
/// </summary>
public bool online { get; set; } = false;
#endregion Public Properties
}
/// <summary>
/// Classe conf server html
/// </summary>
public class srvData
{
#region Public Properties
public string baseUri { get; set; } = "";
public string driverName { get; set; } = "";
#endregion Public Properties
}
/// <summary>
/// Classe conf x decodifica stsatus
/// </summary>
public class StatusItem : DynDataItem
{
#region Public Fields
public Dictionary<string, string> codeMapping;
#endregion Public Fields
}
/// <summary>
/// Oggetto timing x archiviazione dati perfomances
/// </summary>
public class TimeRec
{
#region Public Fields
/// <summary>
/// Classe chiamante della funzione (es codice univoco IOB)
/// </summary>
public string classCall;
/// <summary>
/// Codice univoco chiamata: tipo R4 (read 4 byte), W2 (write 2 Byte)
/// </summary>
public string codCall;
/// <summary>
/// Num chiamate totale
/// </summary>
public int numCall;
/// <summary>
/// Totale Msec accumulati
/// </summary>
public TimeSpan totMsec;
#endregion Public Fields
#region Public Constructors
/// <summary>
/// Classe record timing
/// </summary>
public TimeRec()
{
codCall = "";
numCall = 0;
totMsec = new TimeSpan(0);
}
/// <summary>
/// Classe record timing
/// </summary>
/// <param name="caller"></param>
/// <param name="codice"></param>
/// <param name="ticks"></param>
public TimeRec(string caller, string codice, long nTicks)
{
classCall = caller;
codCall = codice;
numCall = 1;
totMsec = new TimeSpan(nTicks);
}
#endregion Public Constructors
#region Public Properties
/// <summary>
/// Tempo medio chiamata
/// </summary>
public double avgMsec
{
get
{
return totMsec.TotalMilliseconds / numCall;
}
}
#endregion Public Properties
}
/// <summary>
/// Configurazione per Variabili Casuali
/// </summary>
public class VCData
{
#region Public Fields
/// <summary>
/// Array dati per calcolo
/// </summary>
public List<double> dataArray;
/// <summary>
/// DataOra inizio periodo di elaborazione
/// </summary>
public DateTime DTStart;
#endregion Public Fields
#region Public Properties
/// <summary>
/// Tipologia di funzione da applicare
/// </summary>
public VC_func Funzione { get; set; } = VC_func.POINT;
/// <summary>
/// Periodo di riferimento
/// </summary>
public int Period { get; set; } = 60;
#endregion Public Properties
}
}