1419 lines
36 KiB
C#
1419 lines
36 KiB
C#
using MapoSDK;
|
|
using NLog;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Configuration;
|
|
using System.Data;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Net;
|
|
using System.Net.NetworkInformation;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace IOB_UT
|
|
{
|
|
|
|
/// <summary>
|
|
/// Override metodo WebClient con gesitone TimeOut corto
|
|
/// </summary>
|
|
public class WebClientWT : WebClient
|
|
{
|
|
/// <summary>
|
|
/// timeout da conf
|
|
/// </summary>
|
|
protected int urlCallTOut
|
|
{
|
|
get
|
|
{
|
|
int answ = 5000;
|
|
answ = baseUtils.CRI("urlCallTOut");
|
|
if (answ < 0 || answ > 10000)
|
|
{
|
|
answ = 3000;
|
|
}
|
|
return answ;
|
|
}
|
|
}
|
|
protected override WebRequest GetWebRequest(Uri address)
|
|
{
|
|
WebRequest wr = base.GetWebRequest(address);
|
|
wr.Timeout = urlCallTOut; // timeout in milliseconds (ms)
|
|
return wr;
|
|
}
|
|
}
|
|
|
|
public class baseUtils
|
|
{
|
|
/// <summary>
|
|
/// Variabile in cui viene salvato lo stato del server MP-IO
|
|
/// </summary>
|
|
public static bool MPIO_Online = false;
|
|
/// <summary>
|
|
/// Indicazione VETO PING a server sino alla data-ora indicata
|
|
/// </summary>
|
|
public static DateTime dtVetoPing = DateTime.Now;
|
|
/// <summary>
|
|
/// Indicazione VETO invio a server sino alla data-ora indicata
|
|
/// </summary>
|
|
public static DateTime dtVetoSend = DateTime.Now;
|
|
/// <summary>
|
|
/// Calcola una pausa con errore casuale x il prossimo send programmato verso SERVER
|
|
/// </summary>
|
|
public static int nextPauseSendMSec
|
|
{
|
|
get
|
|
{
|
|
// parto dal dato std di veto per pauseSendMSec
|
|
int answ = CRI("pauseSendMSec");
|
|
// aggiungo NOISE... +/- 33%
|
|
Random rnd = new Random();
|
|
int noise = rnd.Next(1, answ / 3);
|
|
answ += noise - (answ / 6);
|
|
return answ;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// oggetto static x gestione baseUtils
|
|
/// </summary>
|
|
public static baseUtils mgr = new baseUtils();
|
|
/// <summary>
|
|
/// Classe logger
|
|
/// </summary>
|
|
public static Logger lg = LogManager.GetCurrentClassLogger();
|
|
/// <summary>
|
|
/// Fattore di riduzione dei log
|
|
/// </summary>
|
|
public static int logReduxFactor = 10;
|
|
/// <summary>
|
|
/// Conteggio valori true in un array di boolean
|
|
/// </summary>
|
|
/// <param name="args"></param>
|
|
/// <returns></returns>
|
|
public static int CountTrue(params bool[] args)
|
|
{
|
|
return args.Count(t => t);
|
|
}
|
|
/// <summary>
|
|
/// legge conf in formato char
|
|
/// </summary>
|
|
/// <param name="key"></param>
|
|
/// <returns></returns>
|
|
public static char CRC(string key)
|
|
{
|
|
char answ = '-';
|
|
try
|
|
{
|
|
answ = ConfigurationManager.AppSettings[key].ToCharArray()[0];
|
|
}
|
|
catch
|
|
{ }
|
|
return answ;
|
|
}
|
|
/// <summary>
|
|
/// legge conf in formato stringa
|
|
/// </summary>
|
|
/// <param name="key"></param>
|
|
/// <returns></returns>
|
|
public static string CRS(string key)
|
|
{
|
|
string answ = "";
|
|
try
|
|
{
|
|
answ = ConfigurationManager.AppSettings[key].ToString();
|
|
}
|
|
catch
|
|
{ }
|
|
return answ;
|
|
}
|
|
/// <summary>
|
|
/// legge conf in formato INT
|
|
/// </summary>
|
|
/// <param name="key"></param>
|
|
/// <returns></returns>
|
|
public static Int32 CRI(string key)
|
|
{
|
|
int answ = 0;
|
|
try
|
|
{
|
|
answ = Convert.ToInt32(CRS(key));
|
|
}
|
|
catch
|
|
{ }
|
|
return answ;
|
|
}
|
|
/// <summary>
|
|
/// legge conf in formato BOOLean
|
|
/// </summary>
|
|
/// <param name="key"></param>
|
|
/// <returns></returns>
|
|
public static bool CRB(string key)
|
|
{
|
|
bool answ = false;
|
|
try
|
|
{
|
|
answ = Convert.ToBoolean(CRS(key));
|
|
}
|
|
catch
|
|
{ }
|
|
return answ;
|
|
}
|
|
/// <summary>
|
|
/// verifica se un dato bit sia alzato (come flag di strobe)
|
|
/// </summary>
|
|
/// <param name="value">valore da testare</param>
|
|
/// <param name="flag">valore cercato, può essere un singolo valore o un insieme in modalità AND</param>
|
|
/// <returns></returns>
|
|
public static bool IsSetAll(StFlag32 value, StFlag32 flag)
|
|
{
|
|
return ((value & flag) == flag);
|
|
}
|
|
/// <summary>
|
|
/// verifica se un dato bit sia alzato (come flag di strobe)
|
|
/// </summary>
|
|
/// <param name="value">valore da testare</param>
|
|
/// <param name="flag">valore cercato, può essere un singolo valore o un insieme in modalità OR</param>
|
|
/// <returns></returns>
|
|
public static bool IsSetAny(StFlag32 value, StFlag32 flag)
|
|
{
|
|
return ((value & flag) != 0);
|
|
}
|
|
/// <summary>
|
|
/// formatta un numero in forma binaria 0/1
|
|
/// </summary>
|
|
/// <param name="valore"></param>
|
|
/// <returns></returns>
|
|
public static string binaryForm(int valore)
|
|
{
|
|
string answ = "";
|
|
try
|
|
{
|
|
answ = string.Format(new BinaryFormatter(), "{0:B}", valore);
|
|
}
|
|
catch
|
|
{ }
|
|
return answ;
|
|
}
|
|
/// <summary>
|
|
/// Method to convert an integer to a string containing the number in binary. A negative
|
|
/// number will be formatted as a 32-character binary number in two's compliment.
|
|
/// </summary>
|
|
/// <param name="theNumber">self-explanatory</param>
|
|
/// <param name="minimumDigits">if binary number contains fewer characters leading zeros are added</param>
|
|
/// <returns>string as described above</returns>
|
|
public static string IntToBinStr(int theNumber, int minimumDigits)
|
|
{
|
|
return Convert.ToString(theNumber, 2).PadLeft(minimumDigits, '0');
|
|
}
|
|
/// <summary>
|
|
/// Effettua reverse della stringa
|
|
/// </summary>
|
|
/// <param name="s"></param>
|
|
/// <returns></returns>
|
|
public static string reverseStr(string s)
|
|
{
|
|
char[] arr = s.ToCharArray();
|
|
Array.Reverse(arr);
|
|
return new string(arr);
|
|
}
|
|
/// <summary>
|
|
/// imposta un bit al valore richiesto duplicando il valore IN come OUT
|
|
/// </summary>
|
|
/// <param name="original">valore originale da aggiornare</param>
|
|
/// <param name="bitBool">valore richiesto x il bit (0/1)</param>
|
|
/// <param name="bitIndex">indice bit, 0 based (es: 0..31 per 32bit)</param>
|
|
/// <returns></returns>
|
|
public static byte[] setBitOnStFlag(byte[] original, bool bitBool, int bitIndex)
|
|
{
|
|
int bitVal = 0;
|
|
if (bitBool)
|
|
{
|
|
bitVal = 1;
|
|
}
|
|
// risposta è identica ad originale...
|
|
byte[] answ = original;
|
|
// verifico se il bit è 0/1b
|
|
if (bitVal <= 1 && bitVal >= 0)
|
|
{
|
|
// verifico se si possa aggiornare il bit richiesto (<= al totale dei bit...)
|
|
if (bitIndex <= original.Length * 8 - 1)
|
|
{
|
|
// calcolo byte
|
|
int byteIndex = bitIndex / 8;
|
|
// bit nel byte
|
|
int bitInByteIndex = bitIndex % 8;
|
|
// bit richiesto
|
|
byte mask = (byte)(bitVal << bitInByteIndex);
|
|
// imposto!
|
|
answ[byteIndex] |= mask;
|
|
}
|
|
}
|
|
return answ;
|
|
}
|
|
/// <summary>
|
|
/// Converte un bitarray a byte[]
|
|
/// </summary>
|
|
/// <param name="bits"></param>
|
|
/// <returns></returns>
|
|
public static byte[] ToByteArray(BitArray bits)
|
|
{
|
|
int numBytes = bits.Count / 8;
|
|
if (bits.Count % 8 != 0)
|
|
{
|
|
numBytes++;
|
|
}
|
|
|
|
byte[] bytes = new byte[numBytes];
|
|
int byteIndex = 0, bitIndex = 0;
|
|
|
|
for (int i = 0; i < bits.Count; i++)
|
|
{
|
|
if (bits[i])
|
|
{
|
|
bytes[byteIndex] |= (byte)(1 << (7 - bitIndex));
|
|
}
|
|
|
|
bitIndex++;
|
|
if (bitIndex == 8)
|
|
{
|
|
bitIndex = 0;
|
|
byteIndex++;
|
|
}
|
|
}
|
|
|
|
return bytes;
|
|
}
|
|
/// <summary>
|
|
/// Scrittura dictionary su file
|
|
/// </summary>
|
|
/// <param name="dictionary"></param>
|
|
/// <param name="file"></param>
|
|
public static void WriteBin(Dictionary<string, string> dictionary, string file)
|
|
{
|
|
using (FileStream fs = File.OpenWrite(file))
|
|
using (BinaryWriter writer = new BinaryWriter(fs))
|
|
{
|
|
// Put count.
|
|
writer.Write(dictionary.Count);
|
|
// Write pairs.
|
|
foreach (var pair in dictionary)
|
|
{
|
|
writer.Write(pair.Key);
|
|
writer.Write(pair.Value);
|
|
}
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Lettura dictionary da file
|
|
/// </summary>
|
|
/// <param name="file"></param>
|
|
/// <returns></returns>
|
|
public static Dictionary<string, string> ReadBin(string file)
|
|
{
|
|
var result = new Dictionary<string, string>();
|
|
// verifico file esista...
|
|
if (!File.Exists(file))
|
|
{
|
|
FileStream fs = File.Create(file);
|
|
fs.Close();
|
|
}
|
|
using (FileStream fs = File.OpenRead(file))
|
|
using (BinaryReader reader = new BinaryReader(fs))
|
|
{
|
|
// Get count.
|
|
int count = 0;
|
|
try
|
|
{
|
|
count = reader.ReadInt32();
|
|
}
|
|
catch
|
|
{ }
|
|
// Read in all pairs.
|
|
for (int i = 0; i < count; i++)
|
|
{
|
|
string key = reader.ReadString();
|
|
string value = reader.ReadString();
|
|
result[key] = value;
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
/// <summary>
|
|
/// Scrittura dictionary su file
|
|
/// </summary>
|
|
/// <param name="dictionary"></param>
|
|
/// <param name="file"></param>
|
|
public static void WritePlain(Dictionary<string, string> dictionary, string file)
|
|
{
|
|
string dirPath = file.Substring(0, file.LastIndexOf('\\'));
|
|
// verifico directory
|
|
if (!Directory.Exists(dirPath))
|
|
{
|
|
Directory.CreateDirectory(dirPath);
|
|
}
|
|
string[] lines = dictionary.OrderBy(i => i.Key).Select(kvp => kvp.Key + ":" + kvp.Value).ToArray();
|
|
try
|
|
{
|
|
File.WriteAllLines(file, lines);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lg.Info(exc, string.Format("Errore in scrittura file {0}", file));
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Lettura dictionary da file
|
|
/// </summary>
|
|
/// <param name="file"></param>
|
|
/// <returns></returns>
|
|
public static Dictionary<string, string> ReadPlain(string file)
|
|
{
|
|
// inizializzo num righe lette...
|
|
int numRow = 0;
|
|
var result = new Dictionary<string, string>();
|
|
// verifico file esista...
|
|
if (!File.Exists(file))
|
|
{
|
|
FileStream fs = File.Create(file);
|
|
fs.Close();
|
|
}
|
|
try
|
|
{
|
|
string[] lines = File.ReadAllLines(file);
|
|
result = lines.Select(l => l.Split(':')).ToDictionary(a => a[0], a => a[1]);
|
|
numRow = result.Count;
|
|
}
|
|
catch
|
|
{ }
|
|
// se leggesse un valore NON coerente (senza righe) restituisce un file vuoto...
|
|
if (numRow == 0)
|
|
{
|
|
result = new Dictionary<string, string>();
|
|
}
|
|
return result;
|
|
}
|
|
/// <summary>
|
|
/// Test ping x indirizzo indicato
|
|
/// </summary>
|
|
/// <param name="address"></param>
|
|
/// <returns></returns>
|
|
public static bool pingAddress(IPAddress address)
|
|
{
|
|
bool answ = false;
|
|
try
|
|
{
|
|
Ping pingSender = new Ping();
|
|
PingReply reply = pingSender.Send(address, 100);
|
|
// se passa il ping do OK...
|
|
if (reply.Status == IPStatus.Success)
|
|
{
|
|
answ = true;
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lg.Error(exc);
|
|
}
|
|
return answ;
|
|
}
|
|
/// <summary>
|
|
/// IP della macchina
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static string GetIP()
|
|
{
|
|
NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
|
|
String sIpAddr = string.Empty;
|
|
try
|
|
{
|
|
foreach (NetworkInterface adapter in nics)
|
|
{
|
|
if (sIpAddr == String.Empty)// only return IP Address from first card
|
|
{
|
|
IPInterfaceProperties properties = adapter.GetIPProperties();
|
|
foreach (var item in properties.UnicastAddresses)
|
|
{
|
|
if (item.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
|
|
{
|
|
sIpAddr = item.Address.ToString();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
lg.Error(exc);
|
|
}
|
|
return sIpAddr;
|
|
}
|
|
/// <summary>
|
|
/// Macaddress della macchina
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public static string GetMACAddress()
|
|
{
|
|
NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
|
|
String sMacAddress = string.Empty;
|
|
foreach (NetworkInterface adapter in nics)
|
|
{
|
|
if (sMacAddress == String.Empty)// only return MAC Address from first card
|
|
{
|
|
IPInterfaceProperties properties = adapter.GetIPProperties();
|
|
//sMacAddress = adapter.GetPhysicalAddress().ToString();
|
|
sMacAddress = string.Join(":", (from z in adapter.GetPhysicalAddress().GetAddressBytes() select z.ToString("X2")).ToArray());
|
|
}
|
|
}
|
|
return sMacAddress;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua chiamata URL IMMEDIATAMENTE e restituisce risultato
|
|
/// </summary>
|
|
/// <param name="URL"></param>
|
|
/// <returns></returns>
|
|
public static string callUrlNow(string URL)
|
|
{
|
|
string answ = "";
|
|
var client = new WebClientWT();
|
|
//var client = new WebClient();
|
|
client.Headers.Add("user-agent", CRS("appName"));
|
|
try
|
|
{
|
|
answ = client.DownloadString(URL);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
// imposto veto
|
|
int pauseSendMSec = nextPauseSendMSec;
|
|
dtVetoSend = DateTime.Now.AddMilliseconds(pauseSendMSec);
|
|
|
|
|
|
// log ogni
|
|
lg.Info($"Errore in callURL verso {URL}: impostato attesa di {pauseSendMSec} ms prima della prossima chiamata");
|
|
logReduxFactor--;
|
|
if (logReduxFactor <= 0)
|
|
{
|
|
lg.Error($"Eccezione in esecuzione callURL: {URL}{Environment.NewLine}{exc}");
|
|
logReduxFactor = 10;
|
|
}
|
|
}
|
|
// restituisco valore!
|
|
return answ;
|
|
}
|
|
/// <summary>
|
|
/// Effettua chiamata IMMEDIATAMENTE URL e restituisce risultato
|
|
/// </summary>
|
|
/// <param name="URL"></param>
|
|
/// <param name="payload"></param>
|
|
/// <returns></returns>
|
|
public static string callUrlNow(string URL, string payload)
|
|
{
|
|
string answ = "";
|
|
var client = new WebClientWT();
|
|
//var client = new WebClient();
|
|
client.Headers.Add("user-agent", CRS("appName"));
|
|
try
|
|
{
|
|
answ = client.UploadString(URL, payload);
|
|
}
|
|
catch (Exception exc)
|
|
{
|
|
// imposto veto
|
|
int pauseSendMSec = nextPauseSendMSec;
|
|
dtVetoSend = DateTime.Now.AddMilliseconds(pauseSendMSec);
|
|
|
|
// log ogni
|
|
lg.Info($"Errore in callURL con PAYLOAD verso {URL}: impostato attesa di {pauseSendMSec} ms prima della prossima chiamata");
|
|
logReduxFactor--;
|
|
if (logReduxFactor <= 0)
|
|
{
|
|
lg.Error($"Eccezione in esecuzione callURL: {URL}{Environment.NewLine}con payload: {payload}{Environment.NewLine}{exc}");
|
|
logReduxFactor = 10;
|
|
}
|
|
}
|
|
// restituisco valore!
|
|
return answ;
|
|
}
|
|
/// <summary>
|
|
/// Effettua chiamata URL e restituisce risultato, SE NON E' in veto send (x mmitigare chiamate...)
|
|
/// </summary>
|
|
/// <param name="URL"></param>
|
|
/// <returns></returns>
|
|
public static string callUrl(string URL)
|
|
{
|
|
string answ = "";
|
|
// controllo se ho un VETO all'invio...
|
|
if (dtVetoSend < DateTime.Now)
|
|
{
|
|
answ = callUrlNow(URL);
|
|
}
|
|
return answ;
|
|
}
|
|
/// <summary>
|
|
/// Effettua chiamata URL e restituisce risultato
|
|
/// </summary>
|
|
/// <param name="URL"></param>
|
|
/// <param name="payload"></param>
|
|
/// <returns></returns>
|
|
public static string callUrl(string URL, string payload)
|
|
{
|
|
string answ = "";
|
|
// controllo se ho un VETO all'invio...
|
|
if (dtVetoSend < DateTime.Now)
|
|
{
|
|
callUrlNow(URL, payload);
|
|
}
|
|
// restituisco valore!
|
|
return answ;
|
|
}
|
|
/// <summary>
|
|
/// Versione async della chiamata ad URL
|
|
/// </summary>
|
|
/// <param name="URL"></param>
|
|
/// <returns></returns>
|
|
public static string callUrlAsync(string URL)
|
|
{
|
|
// Chiamo in modalità task...
|
|
var resp = TaskEx.Run(() => callUrl(URL));
|
|
return resp.Result;
|
|
}
|
|
/// <summary>
|
|
/// Versione async della chiamata ad URL
|
|
/// </summary>
|
|
/// <param name="URL"></param>
|
|
/// <param name="payload"></param>
|
|
/// <returns></returns>
|
|
public static string callUrlAsync(string URL, string payload)
|
|
{
|
|
// Chiamo in modalità task...
|
|
var resp = TaskEx.Run(() => callUrl(URL, payload));
|
|
return resp.Result;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// provvede a verificare la dim della cartella dei log e cancella i + vecchi fino a restare a dim inferiori a _logMaxMb
|
|
/// </summary>
|
|
public static void shrinkDir(string dirPath)
|
|
{
|
|
// obj filemover...
|
|
fileMover.obj.setDirectory(dirPath);
|
|
float dirSizeMb = fileMover.obj.totalMb();
|
|
lg.Info("Inizio shrinkDir LOG folder: {0} Mb", dirSizeMb);
|
|
|
|
// ottengo elenco files *.txt
|
|
FileInfo[] _fis = fileMover.obj.elencoFiles_FI("*.log");
|
|
int numDdMax = 2;
|
|
try
|
|
{
|
|
numDdMax = CRI("zipLogOldDay");
|
|
}
|
|
catch
|
|
{ }
|
|
foreach (FileInfo _file in _fis)
|
|
{
|
|
if (_file.LastWriteTime < DateTime.Now.AddDays(-1)) // zippo files + vecchi di 2 gg...
|
|
{
|
|
fileMover.obj.zippaSingoloFile(_file);
|
|
// cancello l'originale...
|
|
fileMover.obj.eliminaFile(_file);
|
|
}
|
|
}
|
|
// ora controllo SE sia superata la dim max della directory --> in tal caso cancello dal + vecchio...
|
|
dirSizeMb = fileMover.obj.totalMb();
|
|
int maxLogDirSize = CRI("maxLogDirSize");
|
|
int maxTry = 100;
|
|
// controllo se serva eliminare...
|
|
if (dirSizeMb > maxLogDirSize)
|
|
{
|
|
lg.Info("Continuo shrinkDir LOG folder: {0} Mb --> ELIMINAZIONE FILES", dirSizeMb);
|
|
while (dirSizeMb > maxLogDirSize)
|
|
{
|
|
fileMover.obj.deleteOldest();
|
|
maxTry--;
|
|
if (maxTry > 0)
|
|
{
|
|
dirSizeMb = fileMover.obj.totalMb();
|
|
}
|
|
else
|
|
{
|
|
// per uscire fingo di aver ridotto...
|
|
dirSizeMb = maxLogDirSize - 1;
|
|
}
|
|
}
|
|
dirSizeMb = fileMover.obj.totalMb();
|
|
lg.Info("Completata shrinkDir LOG folder: {0} Mb", dirSizeMb);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Oggetto timing x archiviazione dati perfomances
|
|
/// </summary>
|
|
public class TimeRec
|
|
{
|
|
/// <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>
|
|
/// Tempo medio chiamata
|
|
/// </summary>
|
|
public double avgMsec
|
|
{
|
|
get
|
|
{
|
|
return totMsec.TotalMilliseconds / numCall;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Totale Msec accumulati
|
|
/// </summary>
|
|
public TimeSpan totMsec;
|
|
/// <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);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Classe gestione valori campionati su periodo
|
|
/// </summary>
|
|
public class sampleVect
|
|
{
|
|
/// <summary>
|
|
/// Dimensione finestra di campionamento (secondi)
|
|
/// </summary>
|
|
protected int windSize;
|
|
/// <summary>
|
|
/// vettore valori temporali della serie
|
|
/// </summary>
|
|
protected List<DateTime> lTime;
|
|
/// <summary>
|
|
/// vettore valoti puntuali della serie
|
|
/// </summary>
|
|
protected List<int> lVal;
|
|
/// <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>();
|
|
}
|
|
/// <summary>
|
|
/// Conteggio elementi
|
|
/// </summary>
|
|
protected int numElem
|
|
{
|
|
get
|
|
{
|
|
int answ = 0;
|
|
try
|
|
{
|
|
answ = lTime.Count;
|
|
}
|
|
catch
|
|
{ }
|
|
return answ;
|
|
}
|
|
}
|
|
/// <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>
|
|
/// 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;
|
|
}
|
|
}
|
|
/// <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...
|
|
}
|
|
}
|
|
/// <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);
|
|
}
|
|
}
|
|
|
|
}
|
|
/// <summary>
|
|
/// GEstione dati di timing
|
|
/// </summary>
|
|
public static class TimingData
|
|
{
|
|
public static List<TimeRec> results = new List<TimeRec>();
|
|
|
|
/// <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>();
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Gestione Endianness
|
|
/// </summary>
|
|
public static class Endian
|
|
{
|
|
/// <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);
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Tipologie di DUMP memoria
|
|
/// </summary>
|
|
public enum dumpType
|
|
{
|
|
/// <summary>
|
|
/// Salvataggio all'avvio aree memoria (con sovrascrittura)
|
|
/// </summary>
|
|
STARTUP,
|
|
/// <summary>
|
|
/// Campionamento periodico
|
|
/// </summary>
|
|
SAMPLE
|
|
}
|
|
/// <summary>
|
|
/// Tipologia di adapters ammessi
|
|
/// </summary>
|
|
public enum tipoAdapter
|
|
{
|
|
/// <summary>
|
|
/// Adapter SIMULAZIONE
|
|
/// </summary>
|
|
SIMULA,
|
|
/// <summary>
|
|
/// adapter FANUC
|
|
/// </summary>
|
|
FANUC,
|
|
/// <summary>
|
|
/// adapter KAWASAKI e-controller
|
|
/// </summary>
|
|
KAWASAKI,
|
|
/// <summary>
|
|
/// Adapter non specificato
|
|
/// </summary>
|
|
ND,
|
|
/// <summary>
|
|
/// Adapter MTConnect
|
|
/// </summary>
|
|
MTConnect,
|
|
/// <summary>
|
|
/// Adapter OMRON
|
|
/// </summary>
|
|
OMRON,
|
|
/// <summary>
|
|
/// Adapter OSAI CNDEX (Cndex)
|
|
/// </summary>
|
|
OSAI_CNDEX,
|
|
/// <summary>
|
|
/// Adapter OSAI OPEN (ws)
|
|
/// </summary>
|
|
OSAI_OPEN,
|
|
/// <summary>
|
|
/// Adapter OSAI VB6
|
|
/// </summary>
|
|
OSAI_VB6,
|
|
/// <summary>
|
|
/// Adapter SIEMENS
|
|
/// </summary>
|
|
SIEMENS,
|
|
/// <summary>
|
|
/// Adapter SIEMENS, interfaccia versione APROCHIM (filtro liquidi rettifiche)
|
|
/// </summary>
|
|
SIEMENS_APROCHIM,
|
|
/// <summary>
|
|
/// Adapter SIEMENS, interfaccia versione VIPA @2001
|
|
/// </summary>
|
|
SIEMENS_AT2001,
|
|
/// <summary>
|
|
/// Adapter SIEMENS, interfaccia versione FAPE (punzonatrici)
|
|
/// </summary>
|
|
SIEMENS_FAPE,
|
|
/// <summary>
|
|
/// Adapter SIEMENS, interfaccia versione COMUR (dentatrice)
|
|
/// </summary>
|
|
SIEMENS_COMUR,
|
|
/// <summary>
|
|
/// Adapter SIEMENS, interfaccia versione INGENIA (Valvital, Automazione)
|
|
/// </summary>
|
|
SIEMENS_INGENIA,
|
|
/// <summary>
|
|
/// Adapter SIEMENS, interfaccia versione LASCO (Valvital, Pressa Bilancere)
|
|
/// </summary>
|
|
SIEMENS_LASCO,
|
|
/// <summary>
|
|
/// Adapter SIEMENS, interfaccia versione PRESSOIL + CEI (Valvital, Pressa Idraulica)
|
|
/// </summary>
|
|
SIEMENS_PRESSOIL_CEI,
|
|
/// <summary>
|
|
/// Adapter SIEMENS, interfaccia versione SAET (Valvital, forni / tempra)
|
|
/// </summary>
|
|
SIEMENS_SAET,
|
|
/// <summary>
|
|
/// Adapter SIEMENS, interfaccia versione Torri
|
|
/// </summary>
|
|
SIEMENS_TORRI,
|
|
/// <summary>
|
|
/// Metodi di WPS WebPageScraping (es x compressori Atlas Copco)
|
|
/// </summary>
|
|
WPS
|
|
}
|
|
/// <summary>
|
|
/// Tipo di ciclo da processare
|
|
/// </summary>
|
|
public enum gatherCycle
|
|
{
|
|
/// <summary>
|
|
/// Very High Frequency (solo x invii...)
|
|
/// </summary>
|
|
VHF,
|
|
/// <summary>
|
|
/// lettura dati ad alta frequenza
|
|
/// </summary>
|
|
HF,
|
|
/// <summary>
|
|
/// lettura dati standard
|
|
/// </summary>
|
|
MF,
|
|
/// <summary>
|
|
/// lettura dati bassa freq
|
|
/// </summary>
|
|
LF,
|
|
/// <summary>
|
|
/// lettura dati bassissima priorità (re-sync stato allarmi)
|
|
/// </summary>
|
|
VLF
|
|
}
|
|
/// <summary>
|
|
/// Classe conf x item DynData
|
|
/// </summary>
|
|
public class DynDataItem
|
|
{
|
|
public string key { get; set; } = "";
|
|
public string name { get; set; } = "";
|
|
public string val { get; set; } = "";
|
|
public string unit { get; set; } = "";
|
|
public string func { get; set; } = "";
|
|
public int sPeriod { get; set; } = 60;
|
|
/// <summary>
|
|
/// Valore effettivo da salvare
|
|
/// </summary>
|
|
public string actVal { get; set; } = "";
|
|
/// <summary>
|
|
/// DataOra scadenza invio forzato
|
|
/// </summary>
|
|
public DateTime DTScad = DateTime.Now;
|
|
}
|
|
/// <summary>
|
|
/// Classe conf x decodifica stsatus
|
|
/// </summary>
|
|
public class StatusItem : DynDataItem
|
|
{
|
|
public Dictionary<string, string> codeMapping;
|
|
}
|
|
/// <summary>
|
|
/// Classe conf server html
|
|
/// </summary>
|
|
public class srvData
|
|
{
|
|
public string baseUri { get; set; } = "";
|
|
public string driverName { get; set; } = "";
|
|
}
|
|
/// <summary>
|
|
/// Elenco oggetti del monitoraggio (DynData, Status)
|
|
/// </summary>
|
|
public class MonitoredItemsConf
|
|
{
|
|
public srvData SrvData { get; set; }
|
|
public List<DynDataItem> DynData { get; set; }
|
|
public List<StatusItem> Status { get; set; }
|
|
}
|
|
/// <summary>
|
|
/// Configurazione per Eventi/Variabili
|
|
/// </summary>
|
|
public class EVData
|
|
{
|
|
/// <summary>
|
|
/// Unità di misura
|
|
/// </summary>
|
|
public string UM { get; set; } = "num";
|
|
/// <summary>
|
|
/// Valore salvato
|
|
/// </summary>
|
|
public string Val { get; set; } = "";
|
|
/// <summary>
|
|
/// DataOra scadenza invio forzato
|
|
/// </summary>
|
|
public DateTime DTScad = DateTime.Now;
|
|
}
|
|
/// <summary>
|
|
/// Configurazione per Variabili Casuali
|
|
/// </summary>
|
|
public class VCData
|
|
{
|
|
/// <summary>
|
|
/// Periodo di riferimento
|
|
/// </summary>
|
|
public int Period { get; set; } = 60;
|
|
/// <summary>
|
|
/// Tipologia di funzione da applicare
|
|
/// </summary>
|
|
public VC_func Funzione { get; set; } = VC_func.POINT;
|
|
/// <summary>
|
|
/// DataOra inizio periodo di elaborazione
|
|
/// </summary>
|
|
public DateTime DTStart;
|
|
/// <summary>
|
|
/// Array dati per calcolo
|
|
/// </summary>
|
|
public List<double> dataArray;
|
|
}
|
|
|
|
/// <summary>
|
|
/// informazioni di produzione
|
|
/// </summary>
|
|
public struct prodData
|
|
{
|
|
public string Operator;
|
|
|
|
public bool Status;
|
|
public int AccTime;
|
|
public int Power;
|
|
public string FuncMode;
|
|
public bool EmrStop;
|
|
public string MessageCode;
|
|
public string MessageText;
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Dato generico (per decodifica)
|
|
/// </summary>
|
|
public class otherData
|
|
{
|
|
public string codNum;
|
|
public string memAddr;
|
|
public string varName;
|
|
public string dataType;
|
|
public otherData()
|
|
{
|
|
codNum = "";
|
|
memAddr = "";
|
|
varName = "";
|
|
dataType = "";
|
|
}
|
|
public otherData(string _codNum, string _memAddr, string _varName, string _dataType)
|
|
{
|
|
codNum = _codNum;
|
|
memAddr = _memAddr;
|
|
varName = _varName;
|
|
dataType = _dataType;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// Classe che contiene tutte le NUOVE informaizoni da aggiornare sulla form
|
|
/// </summary>
|
|
public class newDisplayData
|
|
{
|
|
/// <summary>
|
|
/// Dati tipo IN (RAW)
|
|
/// </summary>
|
|
public string newInData { get; set; } = "";
|
|
/// <summary>
|
|
/// Dati tipo Signal
|
|
/// </summary>
|
|
public string newSignalData { get; set; } = "";
|
|
/// <summary>
|
|
/// Dati tipo FluxLog
|
|
/// </summary>
|
|
public string newFLogData { get; set; } = "";
|
|
/// <summary>
|
|
/// Dati tipo UrlCall
|
|
/// </summary>
|
|
public string newUrlCallData { get; set; } = "";
|
|
/// <summary>
|
|
/// Dati tipo LiveLog
|
|
/// </summary>
|
|
public string newLiveLogData { get; set; } = "";
|
|
/// <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>
|
|
/// 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;
|
|
/// <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>
|
|
/// StFlag8: set di 8 bit (1 word) contente semaforo di variabili
|
|
/// </summary>
|
|
[Flags]
|
|
public enum StFlag8 : int
|
|
{
|
|
NONE = 0,
|
|
B0 = 1 << 0,
|
|
B1 = 1 << 1,
|
|
B2 = 1 << 2,
|
|
B3 = 1 << 3,
|
|
B4 = 1 << 4,
|
|
B5 = 1 << 5,
|
|
B6 = 1 << 6,
|
|
B7 = 1 << 7
|
|
}
|
|
/// <summary>
|
|
/// StFlag32: set di 32 bit (4 word) contente semaforo di variabili
|
|
/// </summary>
|
|
[Flags]
|
|
public enum StFlag32 : int
|
|
{
|
|
NONE = 0,
|
|
B00 = 1 << 0,
|
|
B01 = 1 << 1,
|
|
B02 = 1 << 2,
|
|
B03 = 1 << 3,
|
|
B04 = 1 << 4,
|
|
B05 = 1 << 5,
|
|
B06 = 1 << 6,
|
|
B07 = 1 << 7,
|
|
B08 = 1 << 8,
|
|
B09 = 1 << 9,
|
|
B10 = 1 << 10,
|
|
B11 = 1 << 11,
|
|
B12 = 1 << 12,
|
|
B13 = 1 << 13,
|
|
B14 = 1 << 14,
|
|
B15 = 1 << 15,
|
|
B16 = 1 << 16,
|
|
B17 = 1 << 17,
|
|
B18 = 1 << 18,
|
|
B19 = 1 << 19,
|
|
B20 = 1 << 20,
|
|
B21 = 1 << 21,
|
|
B22 = 1 << 22,
|
|
B23 = 1 << 23,
|
|
B24 = 1 << 24,
|
|
B25 = 1 << 25,
|
|
B26 = 1 << 26,
|
|
B27 = 1 << 27,
|
|
B28 = 1 << 28,
|
|
B29 = 1 << 29,
|
|
B30 = 1 << 30,
|
|
B31 = 1 << 31
|
|
}
|
|
/// <summary>
|
|
/// Enumerazione tipi di semaforo
|
|
/// </summary>
|
|
public enum Semaforo
|
|
{
|
|
/// <summary>
|
|
/// Stato non definito
|
|
/// </summary>
|
|
ND,
|
|
/// <summary>
|
|
/// Verde
|
|
/// </summary>
|
|
SV,
|
|
/// <summary>
|
|
/// Giallo
|
|
/// </summary>
|
|
SG,
|
|
/// <summary>
|
|
/// Rosso
|
|
/// </summary>
|
|
SR,
|
|
/// <summary>
|
|
/// Grigio/Spento
|
|
/// </summary>
|
|
SS
|
|
}
|
|
/// <summary>
|
|
/// Enumerazione tipi di tipi di URL x invio
|
|
/// </summary>
|
|
public enum urlType
|
|
{
|
|
/// <summary>
|
|
/// Salvataggio FluxLog (valori estesi che non provocano calcoli di macchine a stati, eventi...)
|
|
/// </summary>
|
|
FLog,
|
|
/// <summary>
|
|
/// INPUT segnali in ingresso (standard base MAPO)
|
|
/// </summary>
|
|
SignIN
|
|
}
|
|
|
|
/// <summary>
|
|
/// Elenco STATI CNC OSAI
|
|
/// </summary>
|
|
public enum CNC_STATUS_OSAI
|
|
{
|
|
IDLE = 1,
|
|
CYCLE,
|
|
HODA,
|
|
RUNH,
|
|
HRUN,
|
|
ERRO,
|
|
WAIT,
|
|
RESET,
|
|
EMERG,
|
|
INPUT
|
|
}
|
|
/// <summary>
|
|
/// Elenco MODI CNC
|
|
/// </summary>
|
|
public enum CNC_MODE
|
|
{
|
|
/// <summary>
|
|
/// Non definito
|
|
/// </summary>
|
|
ND = 0,
|
|
/// <summary>
|
|
/// AUTOMATICO
|
|
/// </summary>
|
|
AUTO,
|
|
/// <summary>
|
|
/// EDIT (MEMORY EDIT)
|
|
/// </summary>
|
|
EDIT,
|
|
/// <summary>
|
|
/// MEN (MEMORY OPERATION)
|
|
/// </summary>
|
|
MEN,
|
|
/// <summary>
|
|
/// MDI (MANUAL DATA INPUT)
|
|
/// </summary>
|
|
MDI,
|
|
/// <summary>
|
|
/// HANDLE/INC (MANUAL HANDLE / INCREMENTAL FEED)
|
|
/// </summary>
|
|
HANDLE_INC,
|
|
/// <summary>
|
|
/// HOME
|
|
/// </summary>
|
|
HOME,
|
|
/// <summary>
|
|
/// JOG (MANUAL CONTINUOUS FEED)
|
|
/// </summary>
|
|
JOG,
|
|
/// <summary>
|
|
/// JOG MAN
|
|
/// </summary>
|
|
JOG_MAN,
|
|
/// <summary>
|
|
/// JOG_INC
|
|
/// </summary>
|
|
JOG_INC,
|
|
/// <summary>
|
|
/// PROFILE
|
|
/// </summary>
|
|
PROFILE,
|
|
/// <summary>
|
|
/// SEMI
|
|
/// </summary>
|
|
SEMI,
|
|
/// <summary>
|
|
/// THND (TEACH IN HANDLE)
|
|
/// </summary>
|
|
THND,
|
|
/// <summary>
|
|
/// TJOG (TEACH IN JOG)
|
|
/// </summary>
|
|
TJOG,
|
|
/// <summary>
|
|
/// RMT (DNC OPERATION)
|
|
/// </summary>
|
|
RMT,
|
|
/// <summary>
|
|
/// REF (MANUAL REFERENCE POSITION RETURN)
|
|
/// </summary>
|
|
REF
|
|
}
|
|
} |