using IOB_UT;
using Newtonsoft.Json;
using NLog;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
namespace IOB_WIN
{
public class IobGeneric
{
#region variabili ed oggetti base
///
/// Indicazione VETO invio a server sino alla data-ora indicata
///
public static DateTime dtVetoPing = DateTime.Now;
///
/// Contapezzi attuale
///
protected Int32 contapezzi;
///
/// Ultima lettura variabile contapezzi da CNC
///
protected Int32 lastCountCNC;
///
/// ODL attualmente sulla macchina
///
public Int32 currIdxODL;
///
/// Ultimo invio contapezzi (x invio delayed)
///
protected DateTime lastPzCountSend;
///
/// Ultima registrazione warning x ODL mancante (x scrivere solo ogni 15 secondi)
///
protected DateTime lastWarnODL;
///
/// Ritardo minimo x invio contapezzi
///
protected int pzCountDelay;
///
/// Abilitazione lettura PrgName
///
public bool enablePrgName = true;
///
/// Indica se si debba leggere e fare DUMP delle aree di memoria (1 volta solo all'avvio x debug...)
///
public bool doStartMemDump;
///
/// Indica se sia richiesto campionamento memoria PERIODICO
///
public bool doSampleMemory;
///
/// Evento Iob ha subito un refresh
///
public event EventHandler eh_refreshed;
///
/// Determina se sia encessario convertire valori little/big endian (SIEMENS=true, OSAI=FALSE)
///
public bool hasBigEndian = false;
///
/// alias booleano false = R
///
public bool R = false;
///
/// alias booleano true = W
///
public bool W = true;
///
/// wrapper di log
///
protected static Logger lg;
///
/// ULtimo valore inviato (in caso di disconnessione lo reinvia x garantire watchdog...)
///
public string lastSignInVal = "";
///
/// dataOra ultimo log periodico...
///
public DateTime lastPeriodicLog;
///
/// dataOra ultimo segnale inviato...
///
public DateTime lastWatchDog;
///
/// dataOra ultima verifica CNC disconnesso...
///
public DateTime lastDisconnCheck;
///
/// dataOra ultimo PING inviato...
///
public DateTime lastPING;
///
/// Oggetto della coda degli elementi letti (e non ancora trasmessi)
///
public Queue QueueIN = new Queue();
///
/// Oggetto della coda degli elementi letti di tipo FluxLog (e non ancora trasmessi)
///
public Queue QueueFLog = new Queue();
///
/// Coda valori simulazione deterministica...
///
public Queue QueueSIM = new Queue();
///
/// Coda valori letti x DEBUG...
///
public Queue QueueDebug = new Queue();
///
/// valore booleano di check se sia in fase di COMUNICAZIONE ATTIVA con il PLC/NC
///
protected bool adpCommAct;
///
/// valore booleano di check se sia stato AVVIATO l'adapter (Running)
///
public bool adpRunning = false;
///
/// valore booleano di check se l'adapter STIA SALVANDO
///
public bool adpSaving = false;
///
/// valore booleano (richiesta di riavvio automatico)
///
public bool adpTryRestart;
///
/// Verifica se sia in modalità DEMO --> da tipo IOB SIMULA...
///
public bool DemoIn
{
get
{
return (cIobConf.tipoIob == tipoAdapter.SIMULA);// baseUtils.CRB("DemoIn");
}
}
///
/// Verifica se sia in modalità DEMO avanzata (campionamento da set di valori ammessi...)
///
public bool DemoInSample
{
get
{
return baseUtils.CRB("DemoInSample");
}
}
///
/// Numero simulazioni ammesse...
///
protected int numSim { get; set; }
///
/// Numero letture IN da avvio
///
protected int nReadIN { get; set; }
///
/// Numero letture IN da avvio
///
protected int nReadFilt { get; set; }
///
/// Numero invii OUT (svuotamento coda)
///
protected int nSendOut { get; set; }
///
/// Verifica se sia in modalità DEMO x dati OUTPUT
///
public bool DemoOut
{
get
{
return utils.CRB("DemoOut");
}
}
///
/// Contatore x invio dati SignalIN
///
public int counterSigIN { get; set; }
///
/// Contatore x invio dati FluxLog
///
public int counterFLog { get; set; }
///
/// Ultimo URL
///
public string lastUrl { get; set; }
///
/// Ultimo programma letto
///
public string lastPrgName { get; set; }
///
/// Ultimo SysInfo letto
///
public string lastSysInfo { get; set; }
///
/// Ultimo DynData letto
///
public string lastDynData { get; set; }
///
/// Ultimo Alarm letto
///
public string lastAlarm { get; set; }
///
/// Ultimo Override set letto
///
public string lastOverrideFS { get; set; }
///
/// Ultimo Override set letto
///
public string lastOverrideRapid { get; set; }
///
/// Array dei contatori x segnali blinking
///
protected int[] i_counters;
///
/// Vettore 16 BIT valori precedenti
///
protected int B_previous;
///
/// Vettore 16 BIT valori in ingresso al filtro
///
protected int B_input;
///
/// Vettore 16 BIT valori in uscita dal filtro
///
protected int B_output;
///
/// 32 byte input base (es strobe, 8 word da 32 bit di flags...)
///
public byte[] RawInput = new byte[32];
///
/// 32 byte output base (es ack, 8 word da 32 bit di flags...)
///
public byte[] RawOutput = new byte[32];
///
/// Modo corrente (da classe ENUM)
///
public CNC_MODE currMode;
///
/// Verifica SE si debba fare log verboso (verboso + ogni tot letture IN)
///
public bool verboseLog
{
get
{
bool answ = false;
int logEvery = utils.CRI("logEvery");
if (logEvery < 1)
{
logEvery = 10;
}
answ = utils.CRB("verbose") && (nReadIN % logEvery == 0);
return answ;
}
}
///
/// Verifica SE si debba fare log periodico (ogni "verboseLogTOut" sec...)
///
public bool periodicLog
{
get
{
bool answ = false;
answ = (DateTime.Now.Subtract(lastPeriodicLog).TotalSeconds > utils.CRI("verboseLogTOut"));
if (answ)
{
lastPeriodicLog = DateTime.Now;
}
return answ;
}
}
///
/// Determina se utilizzare blocchi di memoria IOT contigui (e quindi processing "monoblocco" semplificato"=
///
public bool procIotMem = false;
///
/// porta x adapter (x restart)
///
protected int adpPortNum;
///
/// DataOra ultimo avvio adapter x watchdog
///
protected DateTime adpStartRun;
///
/// Data/ora ultimo avvio adapter
///
public DateTime dtAvvioAdp = DateTime.Now;
///
/// Data/ora ultimo spegnimento adapter
///
public DateTime dtStopAdp = DateTime.Now;
///
/// Oggetto cronometro x campionamento durate chiamate
///
public Stopwatch stopwatch = new Stopwatch();
///
/// Conteggio ATTUALE ore macchina ON
///
public double contOreMaccOn;
///
/// Conteggio ATTUALE ore macchina IN LAVORO
///
public double contOreMaccLav;
///
/// stato Online/Offline della IOB
///
public bool IobOnline;
///
/// stato Online/Offline della IOB
///
public bool MPOnline;
///
/// Dizionario di VC da trattare come TimeSeries (con conf decodificata + processing successivo...)
///
protected Dictionary TSVC_Data = new Dictionary();
#endregion
///
/// Form chiamante
///
protected AdapterForm parentForm;
///
/// Conf adapter corrente
///
public IobConfiguration cIobConf;
///
/// indica se serva refresh parametri e quindi PLC...
///
protected bool needRefresh = true;
///
/// inizializzo l'oggetto sulla form SULLA BASE DEL FILE DI CONFIGURAZIONE letto
///
///
///
public IobGeneric(AdapterForm caller, IobConfiguration IOBConf)
{
// configurazione...
cIobConf = IOBConf;
// aggiungo nel logger IDX Macchina
lg = LogManager.GetCurrentClassLogger();
lgInfo("Avvio preliminare AdapterGeneric");
// aggiungo altri defaults
setDefaults(true);
// salvo il form chiamante
parentForm = caller;
// checkLogDir x shrink!
checkShrinkDir();
// concluso!
lgInfo("Istanziata classe preliminare IOBGeneric");
}
///
/// Imposto alcuni valori di default
///
/// indica se sia richeisto di SVUOTARE le code delel info
private void setDefaults(bool resetQueue)
{
numSim = utils.CRI("numSim");
lastPrgName = "";
nReadIN = 0;
nReadFilt = 0;
nSendOut = 0;
currMode = 0;
lastAlarm = "";
doStartMemDump = utils.CRB("doStartMemDump");
doSampleMemory = utils.CRB("doSampleMemory");
// svuoto code se richiesto
if (resetQueue)
{
QueueIN.Clear();
QueueFLog.Clear();
QueueSIM.Clear();
}
// imposto contatori blink a zero...
i_counters = new int[32];
lastPeriodicLog = DateTime.Now;
// fix parametri generali...
enablePrgName = true;
}
///
/// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere...
///
///
protected void lgInfo(string message)
{
lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
lg.Info(message);
}
///
/// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere...
///
///
///
protected void lgInfo(string message, params object[] args)
{
lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
lg.Info(message, args);
}
///
/// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere...
///
///
protected void lgError(string message)
{
lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
lg.Error(message);
}
///
/// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere...
///
///
///
protected void lgError(string message, params object[] args)
{
lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
lg.Error(message, args);
}
///
/// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere...
///
///
///
///
protected void lgError(Exception exception, string message, params object[] args)
{
lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
lg.Error(exception, message, args);
}
///
/// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere...
///
///
protected void lgFatal(string message)
{
lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
lg.Fatal(message);
}
///
/// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere...
///
///
///
protected void lgFatal(string message, params object[] args)
{
lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
lg.Fatal(message, args);
}
///
/// Effettua logging FATAL corretto impostanto anche la variabile IOB prima di scrivere...
///
///
///
///
protected void lgFatal(Exception exception, string message, params object[] args)
{
lg.Factory.Configuration.Variables["codIOB"] = cIobConf.codIOB;
lg.Fatal(exception, message, args);
}
#region metodi adapter
///
/// Invia informazioni associazione IOB 2 machine
///
protected void sendM2IOB()
{
if (checkServerAlive)
{
lgInfo("chiamata URL " + urlSetM2IOB);
utils.callUrl(urlSetM2IOB);
}
}
///
/// Chiede elenco dei task da eseguire
/// - formato Json
/// - array di KVP / Dictionary
/// - formato definito da API x MP/IO/:
/// - KEY: task
/// - VALUE: array JSon KVP
///
protected string getTask2exe()
{
string answ = "";
if (checkServerAlive)
{
string url2call = $"{urlGetTask2Exe}";
lgInfo("chiamata URL " + url2call);
answ = utils.callUrl(url2call);
}
return answ;
}
///
/// Cancella dal server i task eseguiti
///
protected string remTask2exe(string taskName)
{
string answ = "";
if (checkServerAlive)
{
string url2call = $"{urlRemTask2Exe}{taskName}";
lgInfo("chiamata URL " + url2call);
answ = utils.callUrl(url2call);
}
return answ;
}
///
/// Invia al server IO i valori dei parametri opzionali (es counters)
///
/// Nome parametro
/// Valore parametro
protected void sendOptVal(string paramName, string paramValue)
{
if (checkServerAlive)
{
string url2call = $"{urlSetOptVal}pName={paramName}&pValue={paramValue}";
lgInfo("chiamata URL " + url2call);
utils.callUrl(url2call);
}
}
///
/// Invia al server IO i valori dei parametri opzionali (es counters)
///
/// Nome parametro
/// Valore parametro INT
protected void sendOptVal(string paramName, int paramValueInt)
{
// override!
sendOptVal(paramName, paramValueInt.ToString());
}
///
/// Effettua rilettura del contapezzi dal server MP/IO
///
/// Forza rilettura da DB tempi ciclo rilevati
protected void pzCntReload(bool forceCountRec)
{
// legge da IO server ULTIMO valore CONTPEZZI al riavvio...
string currServerCount = "";
string lastIdxODL = "";
if (checkServerAlive)
{
// se ho valori in coda da trasmettere uso dati REDIS
if (QueueIN.Count > 0 && !forceCountRec)
{
currServerCount = utils.callUrl(urlGetPzCount);
lgInfo("Lettura contapezzi dall'url {0}", urlGetPzCount);
}
// altrimenti uso dati da TCiclo registrati...
else
{
// leggo PRIMA ODL ....
lastIdxODL = utils.callUrl(urlGetCurrODL);
lgInfo("Lettura ODL dall'url {0} --> {1}", urlGetPzCountRec, lastIdxODL);
// POI leggo i pezzi
currServerCount = utils.callUrl(urlGetPzCountRec);
lgInfo("Lettura contapezzi da TCiclo dall'url {0} --> num pz: {1}", urlGetPzCountRec, currServerCount);
}
// controllo: SE NON HO ODL...
if (lastIdxODL == "" || lastIdxODL == "0")
{
// NON AGGIORNO
contapezzi = lastCountCNC;
lgInfo(string.Format("Errore lettura ODL: {0} - uso lastCountCNC --> {1}", lastIdxODL, contapezzi));
}
else
{
if (currServerCount != "")
{
// se "-1" resto a ultimo...
if (currServerCount != "-1")
{
int.TryParse(currServerCount, out contapezzi);
lgInfo("Ricevuta conferma da server di {0} pezzi registrati per ODL", currServerCount);
}
else
{
// NON AGGIORNO
contapezzi = lastCountCNC;
lgInfo("Errore lettura contapezzi (-1) - uso lastCountCNC --> " + contapezzi);
}
}
else
{
// registro che ho UN NUOVO ODL
lgInfo(string.Format("Lettura ODL in pzCntReload, {0} --> {1}", currIdxODL, lastIdxODL));
// provo a salvare nuovo ODL
int.TryParse(lastIdxODL, out currIdxODL);
// segno contapezzi a zero...
contapezzi = 0;
lgInfo("RESET contapezzi (ZERO)");
}
}
}
else
{
// se server NON pronto...
contapezzi = lastCountCNC;
lgError("Errore server NON pronto in pzCntReload");
}
}
///
/// Avvia l'adapter sulla porta richiesta
///
/// indica se sia richeisto di SVUOTARE le code delel info
public virtual void startAdapter(bool resetQueue)
{
lgInfo("Starting adapter...");
parentForm.commPlcActive = false;
adpRunning = true;
dtAvvioAdp = DateTime.Now;
lastWatchDog = dtAvvioAdp;
lastPING = dtAvvioAdp;
lastDisconnCheck = dtAvvioAdp;
TimingData.resetData();
// aggiungo altri defaults
setDefaults(resetQueue);
adpTryRestart = true;
parentForm.displayTaskAndLog("Adapter Started!");
}
///
/// ferma l'adapter...
///
/// indica se si debba tentare di riavviare l'adapter (con caduta connessione viene fermato in automatico)
/// indica se sia richeisto di SVUOTARE le code delel info
public void stopAdapter(bool tryRestart, bool forceDequeue)
{
if (forceDequeue)
{
// svuoto le code dei valori letti e non ancora trasmessi...
parentForm.displayTaskAndLog("Svuotamento FORZATO coda segnali...");
while (QueueIN.Count > 0)
{
// INVIO COMUNQUE...!!!
sendToMoonPro(urlType.SignIN, QueueIN.Dequeue());
}
parentForm.displayTaskAndLog("Svuotamento FORZATO coda FluxLOG...");
while (QueueFLog.Count > 0)
{
// INVIO COMUNQUE...!!!
sendToMoonPro(urlType.FLog, QueueFLog.Dequeue());
}
}
parentForm.displayTaskAndLog("Stopping adapter...");
adpTryRestart = false;
parentForm.displayTaskAndLog("Stopping adapter - last periodic data read...");
// chiudo la connessione all'adapter...
tryDisconnect();
dtStopAdp = DateTime.Now;
adpTryRestart = tryRestart;
adpRunning = false;
// chiudo!
parentForm.displayTaskAndLog("Adapter Stopped.");
parentForm.commPlcActive = false;
}
///
/// effettua recupero dati ed invio valori modificati...
///
///
public void getAndSend(gatherCycle ciclo)
{
// IN OGNI CASO a prima di tutto EFFETTUO GESTIONE INVII dati da code!!!
try
{
// gestione queue SignalIN (invio, display)
svuotaCodaSignIN();
// gestione queue FluxLog (invio, display)
svuotaCodaFLog();
}
catch (Exception exc)
{
lgError(exc, "Errore in gestione svuotamento/invio preliminare code memoria");
}
// controllo connessione/connettività
if (connectionOk)
{
// controllo non sia già in esecuzione...
if (!adpCommAct)
{
// provo ad avviare
try
{
// imposto flag adapter running..
adpCommAct = true;
adpStartRun = DateTime.Now;
}
catch (Exception exc)
{
parentForm.displayTaskAndLog(string.Format("Adapter NOT STARTED!!!{0}{1}", Environment.NewLine, exc));
adpCommAct = false;
adpStartRun = DateTime.Now;
}
if (adpCommAct)
{
// try / catch generale altrimenti segno che è disconnesso...
try
{
bool showDebugData = false;
if (ciclo == gatherCycle.VHF)
{
processVHF();
}
// processing dati memoria (lettura, filtraggio, enqueque)
else if (ciclo == gatherCycle.HF)
{
processAllMemory();
processMode();
}
else if (ciclo == gatherCycle.MF)
{
processServerRequests();
processOverride();
processContapezzi();
processCncAlarms();
processDynData();
}
else if (ciclo == gatherCycle.LF)
{
processOtherCounters();
processProgram();
}
else if (ciclo == gatherCycle.VLF)
{
if (utils.CRB("enableContapezzi"))
{
// rilettura contapezzi da server... SE ABILITATA
pzCntReload(false);
// refresh associazione Macchina - IOB
sendM2IOB();
}
// recupero dati SETUP (sysinfo) e li invio/mostro se variati...
processSysInfo();
// checkLogDir x shrink!
checkShrinkDir();
// eventuale log!
if (utils.CRB("recTime"))
{
logTimeResults();
}
}
// mostra eventuali altri dati di processo...
reportDataProc();
if (showDebugData)
{
// verifica se debba salvare e mostrare dati
checkSavePersDataLayer();
}
}
catch (Exception exc)
{
// segnalo eccezione e indico disconnesso...
lgError(exc, string.Format("Errore in gestione ciclo principale ADP, fermo adapter{0}{1}", Environment.NewLine, exc));
parentForm.fermaAdapter(true, false);
}
// tolgo flag running
adpCommAct = false;
}
else
{
if (periodicLog)
{
lgInfo("ADP not running...");
}
}
}
else
{
// log ADP running
lgError("Non eseguo chiamata: ADP ancora in running");
// se è bloccato da oltre maxSec lo sblocco...
if (DateTime.Now.Subtract(adpStartRun).TotalSeconds > utils.CRI("maxAdapterLockSec"))
{
// tolgo flag running
adpCommAct = false;
adpStartRun = DateTime.Now;
}
}
}
else
{
// provo a riconnettere SE abilitato tryRestart...
if (adpTryRestart && !connectionOk)
{
tryConnect();
}
}
// segnalo refresh!
if (eh_refreshed != null)
{
eh_refreshed(this, new EventArgs());
}
}
///
/// Effettua ciclo controllo richieste server
///
public void processServerRequests()
{
Dictionary task2exe = new Dictionary();
Dictionary taskDone = new Dictionary();
// recupero elenco delle cose da fare
string resp = getTask2exe();
if (resp != "")
{
try
{
task2exe = JsonConvert.DeserializeObject>(resp);
// se ho da fare chiamo esecuzione..
if (task2exe.Count > 0)
{
// chiamo procedura esecutiva (diversa x ogni IOB)
taskDone = executeTasks(task2exe);
}
// ora chiamo la cancellazione dei task eseguiti...
foreach (var item in taskDone)
{
remTask2exe(item.Key);
}
}
catch
{ }
}
}
///
/// Esecuzione dei task richiesti e pulizia coda richieste eseguite
///
///
public virtual Dictionary executeTasks(Dictionary task2exe)
{
// Verificare il protocollo: dovrebeb togliere SOLO i task eseguiti...
Dictionary taskDone = new Dictionary();
bool taskOk = false;
string taskVal = "";
// cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4
foreach (var item in task2exe)
{
taskOk = false;
taskVal = "";
// controllo sulal KEY
switch (item.Key)
{
case "startSetup":
// reset contapezzi inizio setup
taskOk = resetContapezziCNC();
taskVal = taskOk ? "RESET: SETUP START" : "PZ RESET DISABLED | NO EXEC";
break;
case "stopSetup":
// reset contapezzi fine setup
taskOk = resetContapezziCNC();
taskVal = taskOk ? "RESET: SETUP END" : "PZ RESET DISABLED | NO EXEC";
break;
default:
// anche se non faccio nulla SEGNO con value = SKIPPED
taskVal = "SKIPPED | NO EXEC";
break;
}
taskDone.Add(item.Key, taskVal);
}
return taskDone;
}
///
/// Metodo generico di reset contapezzi...
///
///
public virtual bool resetContapezziCNC()
{
return false;
}
///
/// Verifica e se necessario comprime directory log...
///
private void checkShrinkDir()
{
string path = string.Format("{0}logs\\{1}", AppDomain.CurrentDomain.BaseDirectory, cIobConf.codIOB);
baseUtils.shrinkDir(path);
}
private void reportDataProc()
{
// update valori visualizzazione...
parentForm.dataProcLabel = string.Format("RAW: {0} --> IN: {1} --> OUT: {2}", nReadIN, nReadFilt, nSendOut);
}
///
/// riporta il log di tutti i dati di results temporali registrati
///
public void logTimeResults()
{
if (TimingData.results.Count > 0)
{
lgInfo("{0}--------------- START TIMING DATA ---------------", Environment.NewLine);
int globNumCall = 0;
TimeSpan globAvgMsec = new TimeSpan(0);
foreach (TimeRec item in TimingData.results)
{
// loggo SOLO se del mio IOB corrente...
if (item.classCall == cIobConf.codIOB)
{
lgInfo("{4}|Chiamate {0}: effettuate {1}, tempo medio {2:N2} msec | impegno canale {3:P3}", item.codCall, item.numCall, item.avgMsec, item.totMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds, cIobConf.codIOB);
globNumCall += item.numCall;
globAvgMsec += item.totMsec;
}
}
// riporto conteggio medio al secondo...
lgInfo("{4}|Chiamate GLOBALI: {0}, periodo: {1:N2} minuti.cent, tempo medio {2:N2} msec | impegno canale {3:P3}", globNumCall, DateTime.Now.Subtract(dtAvvioAdp).TotalMinutes, globAvgMsec.TotalMilliseconds / globNumCall, globAvgMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds, cIobConf.codIOB);
lgInfo("{0}--------------- STOP TIMING DATA ---------------{0}", Environment.NewLine);
// mostro in form statistiche globali!
parentForm.updateComStats(string.Format("Periodo: {0:N2}min | {1} x {2:N2}ms | canale {3:P3}", DateTime.Now.Subtract(dtAvvioAdp).TotalMinutes, globNumCall, globAvgMsec.TotalMilliseconds / globNumCall, globAvgMsec.TotalSeconds / DateTime.Now.Subtract(dtAvvioAdp).TotalSeconds));
}
}
///
/// processa dataLayer e se necessario salva/mostra
///
public void checkSavePersDataLayer()
{
}
public void resetDebugConsole()
{
}
///
/// Metodo base connessione...
///
public virtual void tryConnect()
{
dtAvvioAdp = DateTime.Now;
}
///
/// Metodo base disconnessione...
///
public virtual void tryDisconnect()
{
}
protected bool _connOk = false;
///
/// Salva verifica stato connessione OK
///
///
public virtual bool connectionOk
{
get
{
return _connOk || DemoIn;
}
set
{
_connOk = value;
}
}
///
/// test ping all'indirizzo impostato nei parametri
///
///
protected IPStatus testPing()
{
IPStatus answ = IPStatus.Unknown; ;
IPAddress address;
PingReply reply;
Ping pingSender = new Ping();
address = IPAddress.Loopback;
IPAddress.TryParse(cIobConf.cncIpAddr, out address);
int pingMsTimeout = cIobConf.pingMsTimeout;
reply = pingSender.Send(address, pingMsTimeout);
answ = reply.Status;
return answ;
}
#endregion
#region layer persistenza dati
///
/// Dizionario di persistenza per i valori da salvare da/su file
///
public Dictionary persistenceLayer;
///
/// recupera valore salvato in persistence layer (se non c'è crea...)
///
///
///
private string getStoredVal(string keyVal)
{
string value = "";
try
{
if (persistenceLayer != null)
{
if (!persistenceLayer.TryGetValue(keyVal, out value))
{
persistenceLayer.Add(keyVal, "0");
}
}
}
catch (Exception exc)
{
lgError(string.Format("Eccezione in getStoredVal: {0}{1}", Environment.NewLine, exc));
}
return value;
}
///
/// recupera valore salvato in persistence layer (se non c'è crea...) come UINT
///
///
///
private uint getStoredValUInt(string keyVal)
{
uint answ = 0;
try
{
answ = Convert.ToUInt32(getStoredVal(keyVal));
}
catch (Exception exc)
{
lgError(string.Format("Eccezione in getStoredValUInt: {0}{1}", Environment.NewLine, exc));
}
// verifico che il valore sia minore di 9/10 del valore massimo...
answ = (answ < (uint.MaxValue / 10 * 9)) ? answ : 0;
return answ;
}
///
/// recupera valore salvato in persistence layer (se non c'è crea...) come INT
///
///
///
private long getStoredValLong(string keyVal)
{
long answ = 0;
try
{
answ = Convert.ToInt64(getStoredVal(keyVal));
}
catch
{ }
// verifico che il valore sia minore di 9/10 del valore massimo...
answ = (answ < (long.MaxValue / 10 * 9)) ? answ : 0;
return answ;
}
///
/// recupera valore salvato in persistence layer (se non c'è crea...) come double
///
///
///
private double getStoredValDouble(string keyVal)
{
double answ = 0;
try
{
answ = Convert.ToDouble(getStoredVal(keyVal));
}
catch (Exception exc)
{
lgError(string.Format("Eccezione in getStoredValDouble: {0}{1}", Environment.NewLine, exc));
}
answ = (answ < (double.MaxValue / 10 * 9)) ? answ : 0;
return answ;
}
///
/// Aggiorna un valore del dizionario in SOSTITUZIONE
///
///
///
///
/// Nuovo valore incrementato
private void updateValString(int i, string newVal, string searchString)
{
// stringa da cercare..
string keyVal = string.Format(searchString, i + 1);
// salvo in ram!
persistenceLayer[keyVal] = newVal;
}
///
/// Aggiorna un valore del dizionario in SOSTITUZIONE e lo restituisce
///
///
///
///
/// Nuovo valore incrementato
private void updateValUInt(int i, uint newVal, string searchString)
{
// stringa da cercare..
string keyVal = string.Format(searchString, i + 1);
// salvo in ram!
persistenceLayer[keyVal] = newVal.ToString();
}
///
/// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce
///
///
///
///
/// Nuovo valore incrementato
private uint updateValUIntByIncr(int i, uint delta, string searchString)
{
// stringa da cercare..
string keyVal = string.Format(searchString, i + 1);
// recupero valore precedente...
uint contAct = getStoredValUInt(keyVal);
// nuovo valore...
contAct += delta;
// salvo in ram!
persistenceLayer[keyVal] = contAct.ToString();
// rendo il valore!
return contAct;
}
///
/// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce
///
///
///
///
/// Nuovo valore incrementato
private long updateValLongByIncr(int i, long delta, string searchString)
{
// stringa da cercare..
string keyVal = string.Format(searchString, i + 1);
// recupero valore precedente...
long contAct = getStoredValLong(keyVal);
// nuovo valore...
contAct += delta;
// salvo in ram!
persistenceLayer[keyVal] = contAct.ToString();
// rendo il valore!
return contAct;
}
///
/// Aggiorna un valore del dizionario in INCREMENTO e lo restituisce
///
///
///
///
/// Nuovo valore incrementato
private double updateValDoubleByIncr(int i, double delta, string searchString)
{
// stringa da cercare..
string keyVal = string.Format(searchString, i + 1);
// recupero valore precedente...
double contAct = getStoredValDouble(keyVal);
// nuovo valore...
contAct += delta;
// salvo in ram!
persistenceLayer[keyVal] = contAct.ToString();
// rendo il valore!
return contAct;
}
#endregion
#region area lettura configurazioni
///
/// Legge il file di conf di una MAP di informazioni da gestire con lettura set memoria
///
/// nome vettore memoria
/// file origine
/// dimensione (in byte) della memoria
/// dimensione (in byte) della memoria
protected void loadConfFile(ref otherData[] vettoreConf, string nomeFile, int memSize, ref int numVett)
{
otherData lastData = new otherData();
int totRighe = 0;
string linea;
totRighe = File.ReadLines(nomeFile).Count();
// creo un vettore della dimensione corretta... conta anche commenti tanto poi riduco...
vettoreConf = new otherData[File.ReadLines(nomeFile).Count()];
// carica da file...
StreamReader file = new StreamReader(nomeFile);
// leggo 1 linea alla volta...
int numRiga = 0;
int bitNum = 0;
int byteNum = 0;
while ((linea = file.ReadLine()) != null)
{
// SE non è un commento...
if (linea.Substring(0, 1) != "#")
{
// se finisce per BIT allora processo bit-a-bit...
if (linea.EndsWith("BOOL"))
{
try
{
string[] memIdx = linea.Split(utils.CRC("testCharSep"))[0].Split('.');
// calcolo bit e byte number...
int.TryParse(memIdx[0], out byteNum);
if (memIdx.Length > 1)
{
int.TryParse(memIdx[1], out bitNum);
}
else
{
bitNum = 0;
}
}
catch
{
byteNum = 0;
bitNum = 0;
}
lastData = decodeBitData(linea, utils.CRC("testCharSep"), byteNum, 1, bitNum);
vettoreConf[numRiga] = lastData;
}
else
{
lastData = decodeOtherData(linea, utils.CRC("testCharSep"), "", 1, memSize);
vettoreConf[numRiga] = lastData;
}
numRiga++;
}
}
// salvo lunghezza file...
try
{
numVett = Convert.ToInt32(lastData.memAddr) + 1;
}
catch
{
numVett = numRiga + 1;
}
// chiudo file
file.Close();
// ora trimmo vettore al solo numero VERO dei valori caricati...
Array.Resize(ref vettoreConf, numRiga);
if (utils.CRB("verbose"))
{
lgInfo(string.Format("Fine caricamento vettore di {0} variabili per file {1}", numRiga, nomeFile));
}
}
///
/// Decodifica file MAP generico
///
///
///
///
///
///
///
protected otherData decodeOtherData(string linea, char separator, string memPre, int baseAddr, int memSize)
{
string[] valori = linea.Split(separator);
int shift = 0;
try
{
shift = Convert.ToInt32(valori[0]) - 1;
}
catch
{ }
string memAddr = string.Format("{0}{1}", memPre, baseAddr + shift * memSize);
return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim());
}
///
/// Decodifica file MAP (caso .bit)
///
///
///
/// indirizzo Byte: indirizzo di partenza memoria
/// dimensione singolo slot in byte
/// indirizzo bit: numero riga x calcolo indice bit
///
protected otherData decodeBitData(string linea, char separator, int ByteNum, int memSize, int BitNum)
{
string[] valori = linea.Split(separator);
int shift = 0;
try
{
shift = Convert.ToInt32(valori[0]) - 1;
}
catch
{ }
int resto = 0;
Math.DivRem(BitNum, 8, out resto);
string memAddr = string.Format("{0}.{1}", ByteNum + shift * memSize, resto);
return new otherData(valori[0], memAddr, valori[1].Trim(), valori[2].Trim());
}
///
/// Cerca se esiste il parametro opzionale e lo restituisce
///
///
///
public string getOptPar(string key)
{
string answ = "";
if (cIobConf.optPar.Count > 0)
{
// controllo SE salvare contapezzo
if (cIobConf.optPar.ContainsKey(key))
{
answ = cIobConf.optPar[key];
}
}
return answ;
}
///
/// Cerca parametri opzionali in modalità "like" del nome
///
///
///
public Dictionary findOptPar(string keyStartSearch = "")
{
Dictionary answ = new Dictionary();
// controllo SE keySearch !=""
if (keyStartSearch != "")
{
if (cIobConf.optPar.Count > 0)
{
// ciclo su tutti e cerco occorrenze che INIZINO...
foreach (var item in cIobConf.optPar)
{
if (item.Key.StartsWith(keyStartSearch))
{
answ.Add(item.Key, item.Value);
}
}
}
}
return answ;
}
#endregion
///
/// effettua ogni log period una rilettura di TUTTI gli allarmi...
///
public virtual void forceAlarmCheck()
{
}
#region IOB METHODS
///
/// Valore del num max invii consecutivi da coda...
///
protected int nMaxSend
{
get
{
int answ = 5;
try
{
answ = utils.CRI("nMaxSend");
}
catch
{ }
return answ;
}
}
///
/// DateTime Ultimo valore simulazione generato
///
public DateTime lastSim;
///
/// contatore x simulazione valori input
///
public int countSim = 0;
///
/// URL per check alive...
///
public string urlAlive
{
get
{
return string.Format(@"http://{0}{1}{2}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE);
}
}
///
/// URL per check alive...
///
public string urlIobEnabled
{
get
{
return string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDENABLED, cIobConf.codIOB);
}
}
///
/// URL per segnalazione reboot...
///
public string urlReboot
{
get
{
string answ = "";
try
{
answ = string.Format(@"http://{0}{1}{2}{3}&mac={4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDREBO, cIobConf.codIOB, GetMACAddress());
}
catch
{
answ = string.Format(@"http://{0}{1}{2}{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDREBO, cIobConf.codIOB);
}
return answ;
}
}
///
/// URL per salvataggio contapezzi...
///
public string urlGetCurrODL
{
get
{
string answ = "";
try
{
answ = string.Format(@"http://{0}{1}{2}/getCurrODL/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
}
catch (Exception exc)
{
lgError(exc, "Errore in composizione urlGetCurrODL");
}
return answ;
}
}
///
/// URL per salvataggio contapezzi...
///
public string urlSetPzCount
{
get
{
string answ = "";
try
{
answ = string.Format(@"http://{0}{1}{2}/setCounter/{3}?counter=", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
}
catch (Exception exc)
{
lgError(exc, "Errore in composizione urlSetPzCount");
}
return answ;
}
}
///
/// URL per salvataggio VALORI opzionali...
///
public string urlSetOptVal
{
get
{
string answ = "";
try
{
answ = string.Format(@"http://{0}{1}{2}/addOptPar/{3}?", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
}
catch (Exception exc)
{
lgError(exc, "Errore in composizione urlSetOptVal");
}
return answ;
}
}
///
/// URL per richiamo task da eseguire...
///
public string urlGetTask2Exe
{
get
{
string answ = "";
try
{
answ = string.Format(@"http://{0}{1}{2}/getTask2Exe/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
}
catch (Exception exc)
{
lgError(exc, "Errore in composizione urlGetTask2Exe");
}
return answ;
}
}
///
/// URL per richiamo task da eseguire...
///
public string urlRemTask2Exe
{
get
{
string answ = "";
try
{
answ = string.Format(@"http://{0}{1}{2}/remTask2Exe/{3}?taskName=", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
}
catch (Exception exc)
{
lgError(exc, "Errore in composizione urlRemTask2Exe");
}
return answ;
}
}
///
/// URL per recupero contapezzi...
///
public string urlGetPzCount
{
get
{
string answ = "";
try
{
answ = string.Format(@"http://{0}{1}{2}/getCounter/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
}
catch (Exception exc)
{
lgError(exc, "Errore in composizione urlGetPzCount");
}
return answ;
}
}
///
/// URL per recupero contapezzi REGISTRATI da TC...
///
public string urlGetPzCountRec
{
get
{
string answ = "";
try
{
answ = string.Format(@"http://{0}{1}{2}/getCounterTCRec/{3}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB);
}
catch (Exception exc)
{
lgError(exc, "Errore in composizione urlGetPzCountRec");
}
return answ;
}
}
///
/// URL per salvataggio dati associazione Machine 2 IOB...
///
public string urlSetM2IOB
{
get
{
string answ = "";
try
{
string machineName = Environment.MachineName;
answ = string.Format(@"http://{0}{1}{2}/setM2IOB/{3}?IOB_name={4}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDALIVE, cIobConf.codIOB, machineName);
}
catch (Exception exc)
{
lgError(exc, "Errore in composizione urlSetM2IOB");
}
return answ;
}
}
public 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;
}
///
/// Fornisce URL INPUT per i parametri richiesti
///
/// valore salvato in coda formato dtEve#valore#counter
///
public string urlInput(string queueVal)
{
// URL base x input
string answ = string.Format(@"http://{0}{1}{2}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDBASE);
// decodifica valore!
string[] valori = qDecodeIN(queueVal);
// aggiungo macchina e valore...
answ += string.Format(@"{0}?valore={1}", cIobConf.codIOB, valori[1]);
// aggiondo dataOra evento e corrente + contatore...
answ += string.Format(@"&&dtEve={0}&&dtCurr={1:yyyyMMddHHmmssfff}&&cnt={2}", valori[0], DateTime.Now, valori[2]);
return answ;
}
///
/// Fornisce URL di tipo FluxLog
///
/// valore salvato in coda nel formato dtEve#flux#valore#counter
///
public string urlFLog(string queueVal)
{
// URL base x input
string answ = string.Format(@"http://{0}{1}{2}", cIobConf.serverData.MPIP, cIobConf.serverData.MPURL, cIobConf.serverData.CMDFLOG);
// decodifica valore!
string[] valori = qDecodeIN(queueVal);
// aggiungo macchina e valore...
answ += string.Format(@"{0}?flux={1}&&valore={2}", cIobConf.codIOB, valori[1], valori[2]);
// aggiondo dataOra evento e corrente + contatore...
answ += string.Format(@"&&dtEve={0}&&dtCurr={1:yyyyMMddHHmmssfff}&&cnt={2}", valori[0], DateTime.Now, valori[3]);
return answ;
}
///
/// Effettua chiamata URL e restituisce risultato
///
///
///
public string callUrl(string URL)
{
return utils.callUrl(URL);
}
///
/// test ping all'indirizzo impostato nei parametri
///
///
private IPStatus testPingServer()
{
IPStatus answ = IPStatus.Unknown; ;
IPAddress address;
PingReply reply;
Ping pingSender = new Ping();
address = IPAddress.Loopback;
string ipAdrr = cIobConf.serverData.MPIP.Replace("http://", "").Replace("https://", "");
IPAddress.TryParse(ipAdrr, out address);
int pingMsTimeout = utils.CRI("pingMsTimeout");
reply = pingSender.Send(address, pingMsTimeout);
answ = reply.Status;
return answ;
}
///
/// Verifica se il server sia ALIVE (tramite PING)
///
public bool checkServerAlive
{
get
{
bool answ = false;
// controllo se ho un VETO all'invio...
if (dtVetoPing < DateTime.Now)
{
if (DemoOut)
{
answ = false;
}
else
{
IPStatus pingStatus = testPingServer();
// se passa il ping faccio il resto...
if (pingStatus == IPStatus.Success)
{
try
{
// chiamo URL, se restituisce "OK" è alive!
answ = (callUrl(urlAlive) == "OK");
}
catch (Exception exc)
{
lgError("Errore in checkServerAlive:{0}{1}", Environment.NewLine, exc);
}
// verifico SE è variato stato online/offline...
if (MPOnline != answ)
{
// se ORA sono online riporto...
if (answ)
{
lgInfo("SERVER ONLINE");
parentForm.commSrvActive = 1;
dtVetoPing = DateTime.Now.AddMinutes(-5);
utils.dtVetoSend = DateTime.Now.AddMinutes(-5);
}
else
{
lgInfo("SERVER OFFLINE");
parentForm.commSrvActive = 0;
}
// salvo nuovo status...
MPOnline = answ;
}
}
else
{
lgInfo("SERVER NOT RESPONDING (PING)");
// imposto un veto per pauseSendMSec
int pauseSendMSec = utils.CRI("pauseSendMSec");
// aggiungo NOISE... +/- 33%
Random rnd = new Random();
int noise = rnd.Next(1, pauseSendMSec / 3);
pauseSendMSec += noise - (pauseSendMSec / 6);
// imposto veto
dtVetoPing = DateTime.Now.AddMilliseconds(pauseSendMSec);
}
}
}
return answ;
}
}
///
/// Verifica se la IOB sia ENABLED (da server o Demo)
///
private bool checkIobEnabled
{
get
{
bool answ = false;
if (DemoOut)
{
answ = (QueueIN.Count + QueueFLog.Count >= nMaxSend);
}
else
{
try
{
// chiamo URL, se restituisce "OK" è enabled!
answ = (callUrl(urlIobEnabled) == "OK");
}
catch
{ }
}
// verifico SE è variato stato online/offline...
if (IobOnline != answ)
{
// se ORA sono online riporto...
if (answ)
{
lgInfo("IOB ONLINE");
}
else
{
lgInfo("IOB OFFLINE");
}
// salvo nuovo status...
IobOnline = answ;
}
// fix colore
if (answ)
{
parentForm.commSrvActive = 2;
}
else
{
parentForm.commSrvActive = 1;
}
return answ;
}
}
///
/// Processo la coda SignalIN...
///
public void svuotaCodaSignIN()
{
// verifico SE la coda abbia dei valori...
if (QueueIN.Count > 0)
{
// verifico se risponde il server...
if (checkServerAlive)
{
// verifico SE posso inviare dati
if (checkIobEnabled)
{
// invio pacchetto di dati (max da conf)
for (int i = 0; i < nMaxSend; i++)
{
trySendQueuedVal();
}
}
else
{
// mostro VETO-SEND x invio... GIALLO
parentForm.sOUT = Semaforo.SG;
if (periodicLog)
{
lgInfo("IOB - VETO SEND");
}
}
}
else
{
// mostro SERVER KO x invio... ROSSO
parentForm.sOUT = Semaforo.SR;
if (periodicLog)
{
lgInfo("IOB - SERVER NOT READY");
}
}
}
}
///
/// Invio del + vecchio valore in coda (se c'è)
///
private void trySendQueuedVal()
{
// SE ho qualcosa in coda...
if (QueueIN.Count > 0)
{
// recupero ed aggiorno ULTIMO valore...
lastSignInVal = QueueIN.Dequeue();
// INVIO!!!
sendToMoonPro(urlType.SignIN, lastSignInVal);
}
}
///
/// Processo la coda FLog...
///
private void svuotaCodaFLog()
{
//controllo se è passato oltre watchdog e non ho inviato nulla --> RE-INVIO (ultimo inviato)!!!!
if (DateTime.Now.Subtract(lastWatchDog).TotalSeconds > utils.CRI("watchdogMaxSec"))
{
string wdStatus = "elapsed";
string sVal = string.Format("[WDST]{0}", wdStatus);
// chiamo accodamento...
accodaFLog(sVal, qEncodeFLog("WDST", wdStatus));
lastWatchDog = DateTime.Now;
}
// verifico SE la coda abbia dei valori...
if (QueueFLog.Count > 0)
{
// verifico se risponde il server...
if (checkServerAlive)
{
// verifico SE posso inviare dati
if (checkIobEnabled)
{
// invio pacchetto di dati (max da conf)
for (int i = 0; i < nMaxSend; i++)
{
// SE ho qualcosa in coda...
if (QueueFLog.Count > 0)
{
// INVIO!!!
sendToMoonPro(urlType.FLog, QueueFLog.Dequeue());
}
}
}
else
{
// mostro VETO-SEND x invio... GIALLO
parentForm.sOUT = Semaforo.SG;
}
}
else
{
// mostro SERVER KO x invio... ROSSO
parentForm.sOUT = Semaforo.SR;
}
}
}
///
/// Classe fittizia in caso di processing task in VHF
///
public virtual void processVHF()
{
}
///
/// Classe fittizia in caso di processing GLOBALE di tutto in 1 solo colpo...
///
private void processAllMemory()
{
// in primis SALVO valori previous/precedenti
B_previous = B_output;
// poi faccio lettura NUOVI valori
readAllData();
// eseguo il filtering dei valori (per i bit "blinking")
filterData();
// effettuo confronto valori vecchi/nuovi... SE trovo variazione OPPURE se è passato + di un timeout di controllo...
if (B_output != B_previous)
{
accodaSigIN();
}
}
///
/// Processa gestione memoria x invio dati QUANDO IOB è disconnesso da CNC...
///
public void processMemoryDiscon()
{
// controllo contatore invio "keepalive"... invio solo a scadenza
if (DateTime.Now.Subtract(lastDisconnCheck).TotalSeconds > utils.CRI("disconMaxSec"))
{
// resetto tutti i vlaori BYTE IN/PREV/OUT... così invio macchina spenta...
B_input = 0;
B_output = 0;
B_previous = 0;
accodaSigIN();
// update controllo
lastDisconnCheck = DateTime.Now;
}
}
///
/// Esegue filtraggio dati x bit blinking!!!
///
private void filterData()
{
// effettuo filtraggio dei valori letti... inizializzo OUT!
B_output = 0;
// in primis verifico SE ci siano bit blinkng... se non ci sono OUT=IN...
if (cIobConf.BLINK_FILT == 0)
{
B_output = B_input;
}
else
{
// incomincio con i valori NON blinking: questi "passano invariati", inizio a sommare nel valore OUT...
B_output = B_input & ~cIobConf.BLINK_FILT;
// calcolo il valore dei BIT che "passano la maschera"
int iBlink = B_input & cIobConf.BLINK_FILT;
// ...aggiungo i "bit che passano"
B_output += iBlink;
// calcolo QUALI valori (tra quelli blink) siano PASSATI da 0 a 1 --> init counters...
BitArray bBlinkStart = new BitArray(new byte[] { Convert.ToByte(iBlink) });
int[] bitsUp = bBlinkStart.Cast().Select(bit => bit ? 1 : 0).ToArray();
for (int i = 0; i < bitsUp.Length; i++)
{
// SE 1... impostiamo contatori al MAX
if (bitsUp[i] == 1)
{
// se era zero indico START blink...
if (i_counters[i] == 0)
{
lgInfo("START BLINK: B{0}", i);
}
// imposto comunque contatore al cambio fronte...
i_counters[i] = cIobConf.MAX_COUNTER_BLINK;
}
}
// quelli che sono zero... LI RECUPERO E LI PROCESSO...
int iZero = ~B_input & cIobConf.BLINK_FILT;
BitArray bBlinkEnd = new BitArray(new byte[] { Convert.ToByte(iZero) });
int[] bitsDown = bBlinkEnd.Cast().Select(bit => bit ? 1 : 0).ToArray();
for (int i = 0; i < bitsDown.Length; i++)
{
// se era a zero (invertito...)
if (bitsDown[i] == 1)
{
// SE è in corso il conteggio...
if (i_counters[i] > 0)
{
// decremento!
i_counters[i] -= 1;
// se è zero NON faccio nulla, altrimenti SOMMO...
if (i_counters[i] > 0)
{
B_output += 1 << i;
}
else
{
lgInfo("END BLINK: B{0}", i);
}
}
}
}
}
}
///
/// Effettua lettura dati
///
public virtual void readAllData()
{
if (DemoIn)
{
// segnalo che sono in Demo
parentForm.sIN = Semaforo.SV;
}
if (connectionOk)
{
readSemafori();
}
else
{
lgError("Errore connessione mancante x readSemafori");
}
nReadIN++;
// aggiorno valore mostrato...
displayRawData();
}
///
/// Effettua gestioen programma: legge e mostra su display...
///
private void processProgram()
{
string currPrgName = "";
// se abilitata lettura prgName
if (enablePrgName)
{
if (connectionOk)
{
currPrgName = getPrgName();
}
else
{
lgError("Errore connessione mancante x getPrgName");
}
}
else
{
currPrgName = lastPrgName;
}
// verifico SE sia cambiato il programma...
if (lastPrgName != currPrgName)
{
// salvo!
lastPrgName = currPrgName;
string sVal = string.Format("[PROG]{0}", currPrgName);
// chiamo accodamento...
accodaFLog(sVal, qEncodeFLog("PROG", currPrgName));
}
}
///
/// Processo lettura dati sysinfo
///
private void processSysInfo()
{
if (utils.CRB("enableSysInfo"))
{
Dictionary currSysInfo = new Dictionary();
if (connectionOk)
{
currSysInfo = getSysInfo();
}
else
{
lgError("Errore connessione mancante x getSysInfo");
}
// verifico SE sia cambiato il programma...
if (lastSysInfo != currSysInfo["SYSINFO"])
{
// salvo!
lastSysInfo = currSysInfo["SYSINFO"];
// per ogni valore del dizionario mostro ed accodo!
string sVal = "";
foreach (var item in currSysInfo)
{
sVal = string.Format("[SYSINFO]{0}|{1}", item.Key, item.Value);
// chiamo accodamento...
accodaFLog(sVal, qEncodeFLog(item.Key, item.Value));
}
}
}
}
///
/// Restituisce info sistema
///
///
public virtual Dictionary getSysInfo()
{
Dictionary outVal = new Dictionary();
return outVal;
}
///
/// Restituisce info DINAMICHE
///
///
public virtual Dictionary getDynData()
{
Dictionary outVal = new Dictionary();
return outVal;
}
///
/// Restituisce info OVERRIDES
///
///
public virtual Dictionary getOverrides()
{
Dictionary outVal = new Dictionary();
return outVal;
}
///
/// Recupera eventuali allarmi CNC...
///
public virtual Dictionary getCncAlarms()
{
Dictionary outVal = new Dictionary();
return outVal;
}
///
/// Restituisce programma in esecuzione
///
public virtual string getPrgName()
{
return "";
}
///
/// Effettua lettura semafori principale
///
public virtual void readSemafori()
{
}
///
/// Effettua processing contapezzi (ed eventualmente alza il bit di contapezzo...)
///
public virtual void processContapezzi()
{ }
///
/// Effettua processing ALTRI contatori/parametri (ed invia ad IO)
///
public virtual void processOtherCounters()
{ }
///
/// Effettua processing mode/status (EDIT/MDI/...)
///
public virtual void processMode()
{ }
///
/// Effettua processing del recupero delle speed (RPM, feedrate) degli assi
///
public void processDynData()
{
bool enableByApp = utils.CRB("enableDynData");
bool enableByIob = (getOptPar("ENABLE_DYN_DATA") == "TRUE");
Dictionary currDynData = new Dictionary();
if (enableByApp || enableByIob)
{
lgInfo("Inizio processDynData");
if (connectionOk)
{
currDynData = getDynData();
}
else
{
lgError("Errore connessione mancante x getDynData");
}
try
{
// verifico SE sia cambiato il programma...
if (lastDynData != currDynData["DYNDATA"])
{
// salvo!
lastDynData = currDynData["DYNDATA"];
// per ogni valore del dizionario mostro ed accodo!
string sVal = "";
foreach (var item in currDynData)
{
sVal = string.Format("[DYNDATA]{0}|{1}", item.Key, item.Value);
// chiamo accodamento...
accodaFLog(sVal, qEncodeFLog(item.Key, item.Value));
}
}
}
catch (Exception exc)
{
lgError(exc, "Eccezione in processDynData");
}
}
}
///
/// Processing di VC x TS, accoda valori x la VC (se esiste) e restituisce bool val se SCADUTO periodo controllo
///
/// Nome della VC
/// Valore (nuovo) delal VC
///
public bool stackVal_TSVC(string VCName, double VCVal)
{
bool answ = false;
// cerco VC...
if (TSVC_Data.ContainsKey(VCName))
{
TSVC_Data[VCName].dataArray.Add(VCVal);
// ora verifico scadenza...
if (TSVC_Data[VCName].DTStart.AddSeconds(TSVC_Data[VCName].Periodo) < DateTime.Now)
{
answ = true;
}
}
return answ;
}
///
/// Recupera la VC x TS, svuotando lista e resettando periodo partenza
///
/// Nome della VC
/// Reimposta e resetta array VC
///
public double getVal_TSVC(string VCName, bool doReset)
{
double answ = 0;
// cerco VC...
if (TSVC_Data.ContainsKey(VCName))
{
// !!!FARE!!! vero calcolo... x ora FIX a MAX...
foreach (var item in TSVC_Data[VCName].dataArray)
{
answ = item > answ ? item : answ;
}
// ora resetto... SE richiesto..
if (doReset)
{
TSVC_Data[VCName].dataArray = new List();
TSVC_Data[VCName].DTStart = DateTime.Now;
}
}
return answ;
}
///
/// Effettua processing del recupero delle speed (RPM, feedrate) degli assi
///
public void processCncAlarms()
{
if (utils.CRB("enableAlarms"))
{
Dictionary currAlarms = new Dictionary();
if (connectionOk)
{
currAlarms = getCncAlarms();
}
else
{
lgError("Errore connessione mancante x getCncAlarms");
}
// verifico SE sia cambiato il programma...
if (currAlarms.Count > 0)
{
try
{
if (lastAlarm != currAlarms["CNC_ALARM"])
{
// salvo!
lastAlarm = currAlarms["CNC_ALARM"];
// per ogni valore del dizionario mostro ed accodo!
string sVal = "";
foreach (var item in currAlarms)
{
sVal = string.Format("[CNC_ALARM]{0}|{1}", item.Key, item.Value);
// chiamo accodamento...
accodaFLog(sVal, qEncodeFLog(item.Key, item.Value));
}
}
}
catch (Exception exc)
{
lgError("Eccezione in processCncAlarms{0}{1}", Environment.NewLine, exc);
}
}
}
}
///
/// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid)
///
public virtual void processOverride()
{
bool enableByApp = utils.CRB("enableOverrides");
bool enableByIob = (getOptPar("ENABLE_OVERRIDES") == "TRUE");
Dictionary currOverride = new Dictionary();
if (enableByApp || enableByIob)
{
lgInfo("Inizio processOverride");
if (connectionOk)
{
currOverride = getOverrides();
}
else
{
lgError("Errore connessione mancante x getOverrides");
}
// SE sono connesso...
if (connectionOk)
{
// se HO dei valori override...
if (currOverride.Count > 0)
{
// verifico SE sia cambiato il programma...
if (lastOverrideFS != currOverride["FEED_OVER"] || lastOverrideRapid != currOverride["RAPID_OVER"])
{
// salvo!
lastOverrideFS = currOverride["FEED_OVER"];
lastOverrideRapid = currOverride["RAPID_OVER"];
// per ogni valore del dizionario mostro ed accodo!
string sVal = "";
foreach (var item in currOverride)
{
sVal = string.Format("[OVERRIDES]{0}|{1}", item.Key, item.Value);
// chiamo accodamento...
accodaFLog(sVal, qEncodeFLog(item.Key, item.Value));
}
}
}
}
}
}
///
/// metodo dummy x salvataggio aree memoria conf x CN
///
/// tipo di DUMP
public virtual void saveMemDump(dumpType tipo)
{
}
#endregion
#region gestione code (accumulo, invio)
///
/// Fornisce il valore letto da BITMAP in formato valido x messa in coda nel formato dtEve#value#cont
///
protected string qEncodeIN
{
get
{
string answ = "";
try
{
answ = string.Format("{0:yyyyMMddHHmmssfff}#{1:X2}#{2}", DateTime.Now, B_output, counterSigIN);
}
catch
{ }
return answ;
}
}
///
/// Fornisce il valore di flusso e valore in formato valido x messa in coda nel formato dtEve#flux#value#cont
///
public string qEncodeFLog(string flusso, string valore)
{
string answ = "";
try
{
answ = string.Format("{0:yyyyMMddHHmmssfff}#{1}#{2}#{3}", DateTime.Now, flusso, valore, counterFLog);
}
catch
{ }
return answ;
}
///
/// Decodifica valore della coda IN nel formato
/// answ[0]=dtEve
/// answ[1]=valore
/// answ[2]=counter
///
/// dtEve + '#' + value + '#' + cont
///
protected string[] qDecodeIN(string queueVal)
{
return queueVal.Split('#');
}
///
/// Accumula in coda i valori Signal IN e logga...
///
public void accodaSigIN()
{
// mostro dati variati letti...
displayInData();
// --> accodo (valore già formattato)!
QueueIN.Enqueue(qEncodeIN);
// loggo!
lgInfo(string.Format("[QUEUE-IN] {0}", qEncodeIN));
// aggiorno counters ed eventuale reset
nReadFilt++;
if (nReadFilt > int.MaxValue - 1)
{
nReadFilt = 0; // per evitare buffer overflow...
}
counterSigIN++;
if (counterSigIN > 9999)
{
counterSigIN = 0;
}
}
///
/// Accumula in coda i valori Signal IN e logga...
///
/// VALORE RAW (x display)
/// VALORE già processato con qEncodeFLog(...)
public void accodaFLog(string val, string encodedVal)
{
// mostro dati variati letti...
displayOtherData(val);
// --> accodo (valore già formattato)!
QueueFLog.Enqueue(encodedVal);
// loggo!
lgInfo(string.Format("[QUEUE-FLOG] {0}", encodedVal));
counterFLog++;
if (counterFLog > 9999)
{
counterFLog = 0;
}
}
///
/// Effettua invio a MoonPro del valore richiesto
///
///
/// Valore da trasmettere: es
/// INPUT: lo status rilevato in HEX
/// FLog: il valore da trasmettere per il flusso indicato
public void sendToMoonPro(urlType tipoUrl, string queueVal)
{
// recupero e formatto URL dati da coda...
switch (tipoUrl)
{
case urlType.FLog:
lastUrl = urlFLog(queueVal);
break;
case urlType.SignIN:
lastUrl = urlInput(queueVal);
break;
default:
lastUrl = "";
break;
}
// se NON sono in demo effettuo invio!
if (!DemoOut)
{
// chiamo URL!
string answ = callUrl(lastUrl);
// loggo!
lgInfo(string.Format("[SEND] {0} -> {1}", queueVal, answ));
// se "OK" verde, altrimenti errore --> ROSSO
if (answ == "OK")
{
parentForm.sOUT = Semaforo.SV;
}
else
{
parentForm.sOUT = Semaforo.SR;
}
}
else
{
parentForm.sOUT = Semaforo.SV;
// loggo!
lgInfo(string.Format("{0} -> [SIM]", queueVal));
}
nSendOut++;
// riporto cosa inviato
displayOutData();
// aggiorno data ultimo watchdog...
lastWatchDog = DateTime.Now;
}
#endregion
#region gestione dataMonitor (update visualizzazione valori)
///
/// Mostra i dati grezzi letti in esadecimale
///
private void displayRawData()
{
// mostro update...
string newString = string.Format("{0:X}", B_input);
accodaRawData(newString);
// salvo coda debug...
QueueDebug.Enqueue(B_input);
}
///
/// Update visualizzaizone BIT in ingresso
///
public void displayInData()
{
// mostro update...
string newString = string.Format("{0:0000}|{1}", counterSigIN, utils.IntToBinStr(B_output, 8));
accodaSignaInlData(newString);
}
///
/// Mostra cosa ha/avrebbe inviato
///
public void displayOutData()
{
accodaUrlData(lastUrl);
}
///
/// Mostra cosa ha/avrebbe inviato
///
///
public void displayOtherData(string newData)
{
// mostro update...
accodaOtherData(newData);
}
///
/// Accoda (visualizzando in cima allo stack) la nuova stringa di output per area OTHER DATA
///
///
public void accodaRawData(string newLine)
{
// inserisco in cima allo stack, trimmo e aggiorno display
parentForm.dataMonitor_0 = limitLine2show(string.Format("{0}{1}{2}", newLine, Environment.NewLine, parentForm.dataMonitor_0));
}
///
/// Accoda (visualizzando in cima allo stack) la nuova stringa di output per area OTHER DATA
///
///
public void accodaSignaInlData(string newLine)
{
// inserisco in cima allo stack, trimmo e aggiorno display
parentForm.dataMonitor_1 = limitLine2show(string.Format("{0}{1}{2}", newLine, Environment.NewLine, parentForm.dataMonitor_1));
}
///
/// Accoda (visualizzando in cima allo stack) la nuova stringa di output per area OTHER DATA
///
///
public void accodaUrlData(string newLine)
{
// inserisco in cima allo stack, trimmo e aggiorno display
parentForm.dataMonitor_2 = limitLine2show(string.Format("{0}{1}{2}", newLine, Environment.NewLine, parentForm.dataMonitor_2));
}
///
/// Accoda (visualizzando in cima allo stack) la nuova stringa di output per area OTHER DATA
///
///
public void accodaOtherData(string newLine)
{
// inserisco in cima allo stack, trimmo e aggiorno display
parentForm.dataMonitor_3 = limitLine2show(string.Format("{0}{1}{2}", newLine, Environment.NewLine, parentForm.dataMonitor_3));
}
///
/// Effettua un trim della stringa al numero max di linee da mostrare a video
///
///
///
private string limitLine2show(string newString)
{
// se num righe superiore a limite trimmo...
if (newString.Split('\n').Length > parentForm.nLine2show)
{
//int idx = newString.LastIndexOf('\r');
int idx = newString.LastIndexOf(Environment.NewLine);
newString = newString.Substring(0, idx);
}
return newString;
}
#endregion
}
}