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; namespace IOB_UT { public class baseUtils { /// /// classe logger /// public static Logger lg; /// /// legge conf in formato char /// /// /// public static char CRC(string key) { char answ = '-'; try { answ = ConfigurationManager.AppSettings[key].ToCharArray()[0]; } catch { } return answ; } /// /// legge conf in formato stringa /// /// /// public static string CRS(string key) { string answ = ""; try { answ = ConfigurationManager.AppSettings[key].ToString(); } catch { } return answ; } /// /// legge conf in formato INT /// /// /// public static Int32 CRI(string key) { int answ = 0; try { answ = Convert.ToInt32(CRS(key)); } catch { } return answ; } /// /// legge conf in formato BOOLean /// /// /// public static bool CRB(string key) { bool answ = false; try { answ = Convert.ToBoolean(CRS(key)); } catch { } return answ; } /// /// verifica se un dato bit sia alzato (come flag di strobe) /// /// valore da testare /// valore cercato, può essere un singolo valore o un insieme in modalità AND /// public static bool IsSetAll(Strobe value, Strobe flag) { return ((value & flag) == flag); } /// /// verifica se un dato bit sia alzato (come flag di strobe) /// /// valore da testare /// valore cercato, può essere un singolo valore o un insieme in modalità OR /// public static bool IsSetAny(Strobe value, Strobe flag) { return ((value & flag) != 0); } /// /// verifica se un dato bit sia alzato (come flag di strobe) /// /// valore da testare /// valore cercato, può essere un singolo valore o un insieme in modalità AND /// public static bool IsSetAll(StatusBitMap value, StatusBitMap flag) { return ((value & flag) == flag); } /// /// verifica se un dato bit sia alzato (come flag di strobe) /// /// valore da testare /// valore cercato, può essere un singolo valore o un insieme in modalità OR /// public static bool IsSetAny(StatusBitMap value, StatusBitMap flag) { return ((value & flag) != 0); } /// /// formatta un numero in forma binaria 0/1 /// /// /// public static string binaryForm(int valore) { string answ = ""; try { answ = string.Format(new BinaryFormatter(), "{0:B}", valore); } catch { } return answ; } /// /// 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. /// /// self-explanatory /// if binary number contains fewer characters leading zeros are added /// string as described above public static string IntToBinStr(int theNumber, int minimumDigits) { return Convert.ToString(theNumber, 2).PadLeft(minimumDigits, '0'); } /// /// imposta un bit al valore richiesto duplicando il valore IN come OUT /// /// valore originale da aggiornare /// valore richiesto x il bit (0/1) /// indice bit, 0 based (es: 0..31 per 32bit) /// 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; } /// /// Converte un bitarray a byte[] /// /// /// 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; } /// /// Scrittura dictionary su file /// /// /// public static void WriteBin(Dictionary 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); } } } /// /// Lettura dictionary da file /// /// /// public static Dictionary ReadBin(string file) { var result = new Dictionary(); // 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; } /// /// Scrittura dictionary su file /// /// /// public static void WritePlain(Dictionary 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)); } } /// /// Lettura dictionary da file /// /// /// public static Dictionary ReadPlain(string file) { // inizializzo num righe lette... int numRow = 0; var result = new Dictionary(); // 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(); } return result; } /// /// Test ping x indirizzo indicato /// /// /// public static bool pingAddress(IPAddress address) { bool answ = false; Ping pingSender = new Ping(); PingReply reply = pingSender.Send(address, 100); // se passa il ping do OK... if (reply.Status == IPStatus.Success) { answ = true; } return answ; } /// /// IP della macchina /// /// 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; } /// /// Macaddress della macchina /// /// 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; } /// /// Effettua chaimata URL e restituisce risultato /// /// /// public static string callUrl(string URL) { string answ = ""; var client = new WebClient(); client.Headers.Add("user-agent", CRS("appName")); answ = client.DownloadString(URL); // restituisco valore! return answ; } } /// /// Oggetto timing x archiviazione dati perfomances /// public class TimeRec { /// /// Classe chiamante della funzione (es codice univoco IOB) /// public string classCall; /// /// Codice univoco chiamata: tipo R4 (read 4 byte), W2 (write 2 Byte) /// public string codCall; /// /// Num chiamate totale /// public int numCall; /// /// Tempo medio chiamata /// public double avgMsec { get { return totMsec.TotalMilliseconds / numCall; } } /// /// Totale Msec accumulati /// public TimeSpan totMsec; /// /// Classe record timing /// public TimeRec() { codCall = ""; numCall = 0; totMsec = new TimeSpan(0); } /// /// Classe record timing /// /// /// /// public TimeRec(string caller, string codice, long nTicks) { classCall = caller; codCall = codice; numCall = 1; totMsec = new TimeSpan(nTicks); } } /// /// Classe gestione valori campionati su periodo /// public class sampleVect { /// /// Dimensione finestra di campionamento (secondi) /// protected int windSize; /// /// vettore valori temporali della serie /// protected List lTime; /// /// vettore valoti puntuali della serie /// protected List lVal; /// /// Inizializzo l'oggetto /// public sampleVect() { // init valori default... windSize = baseUtils.CRI("countWindSize") > 0 ? baseUtils.CRI("countWindSize") : 60; lTime = new List(); lVal = new List(); } /// /// Conteggio elementi /// protected int numElem { get { int answ = 0; try { answ = lTime.Count; } catch { } return answ; } } /// /// Verifica ampiezza finestra valori First-Last /// protected double flWindSize { get { double answ = 0; if (numElem > 1) { answ = lTime.Last().Subtract(lTime[0]).TotalSeconds; } return answ; } } /// /// Verifica ampiezza finestra valori Second-Last /// 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; } } /// /// Aggiunge un valore alla serie ed eventualmente elimina i valori superflui a garantirne una finestra temporale valida /// /// /// 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... } } /// /// Calcola il valore mediano... /// 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; } } /// /// Verifica se la vc sia valida (ovvero almeno 2 valori e intervallo > window richiesta) /// public bool vcValid { get { return (flWindSize > windSize && numElem > 1); } } } public static class TimingData { public static List results = new List(); /// /// aggiorno vettore aggiungendo risultato /// /// Codice chiamante /// Codice da registrare (univoco con chiamante) /// Tempo esecuzione in ticks 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)); } } /// /// Resetta i dati registrati (ad avvio adapter...) /// public static void resetData() { results = new List(); } } /// /// Gestione Endianness /// public static class Endian { /// /// Scambia MSB/LSB per 16bit /// /// /// public static UInt16 SwapUInt16(UInt16 inValue) { return (UInt16)(((inValue & 0xff00) >> 8) | ((inValue & 0x00ff) << 8)); } /// /// Scambia MSB/LSB per 32bit /// /// /// public static UInt32 SwapUInt32(UInt32 inValue) { return ((inValue & 0xff000000) >> 24) | ((inValue & 0x00ff0000) >> 8) | ((inValue & 0x0000ff00) << 8) | ((inValue & 0x000000ff) << 24); } } /// /// Tipologie di DUMP memoria /// public enum dumpType { /// /// Salvataggio all'avvio aree memoria (con sovrascrittura) /// STARTUP, /// /// Campionamento periodico /// SAMPLE } public enum tipoAdapter { /// /// Adapter generico/demo /// DEMO, /// /// adapter FANUC /// FANUC, /// /// adapter KAWASAKI e-controller /// KAWASAKI, /// /// Adapter non specificato /// ND, /// /// Adapter OSAI CNDEX (Cndex) /// OSAI_CNDEX, /// /// Adapter OSAI OPEN (ws) /// OSAI_OPEN, /// /// Adapter SIEMENS /// SIEMENS, /// /// Adapter SIEMENS, interfaccia versione Torri /// SIEMENS_TORRI } public enum gatherCycle { /// /// Very High Frequency (solo x invii...) /// VHF, /// /// lettura dati ad alta frequenza /// HF, /// /// lettura dati standard /// MF, /// /// lettura dati bassa freq /// LF, /// /// lettura dati bassissima priorità (re-sync stato allarmi) /// VLF } /// /// informazioni di produzione /// 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; } public struct PathData { public int PathSel; public string PathType; // LAVOR/ASSERV public string RunMode; public string ExeMode; public int pzTot; public string ProgramName; public string ProgrRow; public string PartId; public string ActiveAxes; public string CodG_Act; public string SubMode; public int PathFeedrate; public int PathFeedrateOver; public int PathRapidOver; public int PathJogOver; public int PathSpindleOver_01; public int PathSpindleOver_02; public int PathSpindleOver_03; public int PathSpindleOver_04; public position PathPosAct; } public struct UnOpData { public int UnOpSel; public int UnOpToolId; public int UnOpNumCU; public string UnOpStatus; public int UnOpVitaRes; public int UnOpSpeed; public int UnOpLoad; public int UnOpAccTime; } public struct AxisData { public int AxisSel; public string AxisMainProc; public bool AxisIsMaster; public string AxisMastId; public string AxisType; public string AxisDir; public int AxisLoad; public int AxisPosAct; public int AxisPosTgt; public int AxisFeedAct; public int AxisFeedOver; public string AxisAccel; public string AxisAccTime; public string AxisBattery; public string DistDone; public string InvDDone; } /// /// Vettore completo posizione (X-Y-Z con versori i-j-k) /// public class position { public float x; public float y; public float z; public float i; public float j; public float k; public position() { x = 0; y = 0; z = 0; i = 0; j = 0; k = 0; } } /// /// Dati Prod SCM (per decodifica) /// public class datiProdSCM { public string area; public string fileName; public string dimensioni; public DateTime start; public DateTime stop; public TimeSpan tEff; public TimeSpan tTot; public int qta; public TimeSpan tMed; public datiProdSCM() { area = ""; fileName = ""; dimensioni = ""; start = DateTime.Now; stop = DateTime.Now; tEff = new TimeSpan(0); tTot = new TimeSpan(0); qta = 0; tMed = new TimeSpan(0); } /// /// crea un nuovo oggetto a partire da un array di stringhe /// /// public datiProdSCM(string[] valori) { try { area = valori[0]; fileName = valori[1]; dimensioni = string.Format("{0}x{1}x{2}", valori[3], valori[4], valori[5]); start = DateTime.Today.AddHours(Convert.ToInt16(valori[6])).AddMinutes(Convert.ToInt16(valori[7])).AddSeconds(Convert.ToInt16(valori[8])); stop = DateTime.Today.AddHours(Convert.ToInt16(valori[9])).AddMinutes(Convert.ToInt16(valori[10])).AddSeconds(Convert.ToInt16(valori[11])); // se ore == 0 --> aggiungo 1 gg!!! if (Convert.ToInt16(valori[9]) == 0) stop.AddDays(1); tEff = new TimeSpan(Convert.ToInt16(valori[12]), Convert.ToInt16(valori[13]), Convert.ToInt16(valori[14])); tTot = new TimeSpan(Convert.ToInt16(valori[15]), Convert.ToInt16(valori[16]), Convert.ToInt16(valori[17])); qta = Convert.ToInt16(valori[18]); tMed = new TimeSpan(Convert.ToInt16(valori[19]), Convert.ToInt16(valori[20]), Convert.ToInt16(valori[22]), Convert.ToInt16(valori[23])); } catch { } } } /// /// Allarme (per decodifica) /// public class allarme { public string codNum; public string gruppo; public string livello; public string descrizione; public allarme() { codNum = ""; gruppo = ""; livello = ""; descrizione = ""; } public allarme(string _codNum, string _gruppo, string _livello, string _descrizione) { codNum = _codNum; gruppo = _gruppo; livello = _livello; descrizione = _descrizione; } } /// /// Dato generico (per decodifica) /// 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; } } /// /// Strobe: contiene il set di strobe di comunicazione /// /// rif: http://stackoverflow.com/questions/17209054/parse-bits-in-a-byte-to-enum /// [Flags] public enum Strobe : int { NONE = 0, M_CODE = 1 << 0, S_CODE = 1 << 1, T_CODE = 1 << 2, PZ_OK = 1 << 3, PZ_KO = 1 << 4, FEED_SPEED = 1 << 5, POS_ACT = 1 << 6, SP07 = 1 << 7, SP08 = 1 << 8, SP09 = 1 << 9, SP10 = 1 << 10, SP11 = 1 << 11, SP12 = 1 << 12, SP13 = 1 << 13, SP14 = 1 << 14, SP15 = 1 << 15, SP16 = 1 << 16, SP17 = 1 << 17, SP18 = 1 << 18, SP19 = 1 << 19, SP20 = 1 << 20, SP21 = 1 << 21, SP22 = 1 << 22, SP23 = 1 << 23, SP24 = 1 << 24, SP25 = 1 << 25, SP26 = 1 << 26, SP27 = 1 << 27, SP28 = 1 << 28, SP29 = 1 << 29, SP30 = 1 << 30, SP31 = 1 << 31 } /// /// StFlag8: set di 8 bit (1 word) contente semaforo di variabili /// [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 } /// /// StFlag32: set di 32 bit (4 word) contente semaforo di variabili /// [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 } /// /// StatusBitMap: contiene il set di semafori/flag x status + allarmi (x classi) /// [Flags] public enum StatusBitMap : int { NONE = 0, ESTOP = 1 << 0, RM_AUTO = 1 << 1, RM_MANUAL = 1 << 2, RM_MDI = 1 << 3, RM_EDIT = 1 << 4, EM_RUN = 1 << 5, EM_READY = 1 << 6, EM_STOP = 1 << 7, EM_FEEDHOLD = 1 << 8, HM = 1 << 9, ST11 = 1 << 10, ST12 = 1 << 11, ST13 = 1 << 12, ST14 = 1 << 13, ST15 = 1 << 14, ST16 = 1 << 15, AL01 = 1 << 16, AL02 = 1 << 17, AL03 = 1 << 18, AL04 = 1 << 19, AL05 = 1 << 20, AL06 = 1 << 21, AL07 = 1 << 22, AL08 = 1 << 23, AL09 = 1 << 24, AL10 = 1 << 25, AL11 = 1 << 26, AL12 = 1 << 27, AL13 = 1 << 28, AL14 = 1 << 29, AL15 = 1 << 30, AL16 = 1 << 31 } /// /// Enumerazione tipi di semaforo /// public enum Semaforo { /// /// Verde /// SV, /// /// Giallo /// SG, /// /// Rosso /// SR, /// /// Grigio/Spento /// SS } /// /// Enumerazione tipi di tipi di URL x invio /// public enum urlType { /// /// Salvataggio FluxLog (valori estesi che non provocano calcoli di macchine a stati, eventi...) /// FLog, /// /// INPUT segnali in ingresso (standard base MAPO) /// SignIN } /// /// Elenco STATI CNC OSAI /// public enum CNC_STATUS_OSAI { IDLE = 1, CYCLE, HODA, RUNH, HRUN, ERRO, WAIT, RESET, EMERG, INPUT } /// /// Elenco MODI CNC /// public enum CNC_MODE { /// /// Non definito /// ND = 0, /// /// AUTOMATICO /// AUTO, /// /// EDIT (MEMORY EDIT) /// EDIT, /// /// MEN (MEMORY OPERATION) /// MEN, /// /// MDI (MANUAL DATA INPUT) /// MDI, /// /// HANDLE/INC (MANUAL HANDLE / INCREMENTAL FEED) /// HANDLE_INC, /// /// HOME /// HOME, /// /// JOG (MANUAL CONTINUOUS FEED) /// JOG, /// /// JOG MAN /// JOG_MAN, /// /// JOG_INC /// JOG_INC, /// /// PROFILE /// PROFILE, /// /// SEMI /// SEMI, /// /// THND (TEACH IN HANDLE) /// THND, /// /// TJOG (TEACH IN JOG) /// TJOG, /// /// RMT (DNC OPERATION) /// RMT, /// /// REF (MANUAL REFERENCE POSITION RETURN) /// REF } }