diff --git a/CVCncLib/CVCncLib.dll b/CVCncLib/CVCncLib.dll index fa1d7911..77ac5221 100644 Binary files a/CVCncLib/CVCncLib.dll and b/CVCncLib/CVCncLib.dll differ diff --git a/IOB-UT-NEXT/Enums.cs b/IOB-UT-NEXT/Enums.cs index 82854520..99e1da4b 100644 --- a/IOB-UT-NEXT/Enums.cs +++ b/IOB-UT-NEXT/Enums.cs @@ -269,6 +269,16 @@ namespace IOB_UT_NEXT /// ND, + /// + /// Adapter ModBus TCP generico + /// + MODBUS_TCP, + + /// + /// Adapter ModBus TCP versione HAM (Pizzaferri) + /// + MODBUS_TCP_HAM, + /// /// Adapter MTConnect /// diff --git a/IOB-UT-NEXT/IOB-UT-NEXT.csproj b/IOB-UT-NEXT/IOB-UT-NEXT.csproj index 663002a2..e727dce1 100644 --- a/IOB-UT-NEXT/IOB-UT-NEXT.csproj +++ b/IOB-UT-NEXT/IOB-UT-NEXT.csproj @@ -59,8 +59,8 @@ ..\packages\SharpZipLib.1.3.1\lib\net45\ICSharpCode.SharpZipLib.dll - - ..\packages\MapoSDK.6.13.2105.1421\lib\net40\MapoSDK.dll + + ..\packages\MapoSDK.6.13.2109.1112\lib\net40\MapoSDK.dll ..\packages\Microsoft.Bcl.AsyncInterfaces.5.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll diff --git a/IOB-UT-NEXT/ToMapo.cs b/IOB-UT-NEXT/ToMapo.cs index b559c19d..6b391f1a 100644 --- a/IOB-UT-NEXT/ToMapo.cs +++ b/IOB-UT-NEXT/ToMapo.cs @@ -188,6 +188,82 @@ namespace IOB_UT_NEXT #endregion Public Methods } +#if false + /// + /// Struttura della conf memoria ModBus + /// + public class BaseModbusConf + { + public enum DataType + { + ND = 0, + BIT, + INT, + REAL + } + + public enum MemType + { + ND = 0, + DiscreteInput = 1, + Coil = 2, + InputRegister = 3, + HoldingRegister = 4 + } + + /// + /// Elenco aree memoria ModBus in lettura + /// + public List mMapRead { get; set; } = new List(); + + /// + /// Elenco aree memoria ModBus in scrittura + /// + public List mMapWrite { get; set; } = new List(); + + /// + /// struttura di base memoria ModBus + /// + public class ModbusMemArea + { + public ushort BaseAddr { get; set; } = 0; + public string RawAddr { get; set; } = ""; + public ushort Size { get; set; } = 0; + + [JsonConverter(typeof(StringEnumConverter))] + public MemType Type { get; set; } = MemType.ND; + + public List VarList { get; set; } = new List(); + } + + public class VarConf + { + public string description { get; set; } = ""; + public int factor { get; set; } = 1; + + public bool hasRange + { + get + { + return !this.minVal.Equals(this.maxVal); + } + } + + public ushort index { get; set; } = 0; + public int maxVal { get; set; } = 0; + public string memAddr { get; set; } = ""; + public int minVal { get; set; } = 0; + public string name { get; set; } = "none"; + public ushort size { get; set; } = 0; + + [JsonConverter(typeof(StringEnumConverter))] + public DataType tipoMem { get; set; } = DataType.ND; + + public string value { get; set; } = ""; + } + } +#endif + /// /// Classe gestione configurazione parametri di base x configuraizone estesa (es MTConnect, OPC-UA, ...) /// diff --git a/IOB-UT-NEXT/packages.config b/IOB-UT-NEXT/packages.config index 70c5455c..3ad1f452 100644 --- a/IOB-UT-NEXT/packages.config +++ b/IOB-UT-NEXT/packages.config @@ -1,6 +1,6 @@  - + diff --git a/IOB-WIN-NEXT/AdapterForm.cs b/IOB-WIN-NEXT/AdapterForm.cs index d319f5b8..4af037c8 100644 --- a/IOB-WIN-NEXT/AdapterForm.cs +++ b/IOB-WIN-NEXT/AdapterForm.cs @@ -1186,6 +1186,16 @@ namespace IOB_WIN_NEXT start.Enabled = true; break; + case tipoAdapter.MODBUS_TCP: + iobObj = new IobModbusTCP(this, IOBConf); + start.Enabled = true; + break; + + case tipoAdapter.MODBUS_TCP_HAM: + iobObj = new IobModbusTCPHam(this, IOBConf); + start.Enabled = true; + break; + case tipoAdapter.MTConnect: iobObj = new IobMTC(this, IOBConf); start.Enabled = true; diff --git a/IOB-WIN-NEXT/AdapterForm.cs.bak b/IOB-WIN-NEXT/AdapterForm.cs.bak deleted file mode 100644 index 3fd42bdd..00000000 --- a/IOB-WIN-NEXT/AdapterForm.cs.bak +++ /dev/null @@ -1,1783 +0,0 @@ -using IOB_UT_NEXT; -using MapoSDK; -using Newtonsoft.Json; -using NLog; -using NLog.Config; -using NLog.Targets; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Drawing; -using System.IO; -using System.Threading; -using System.Windows.Forms; - -namespace IOB_WIN_NEXT -{ - public partial class AdapterForm : Form - { - #region Protected Fields - - /// - /// contatore veloce - /// - protected int fastCount; - - /// - /// Data-Ora prima apertura FORM... - /// - protected DateTime firstStart; - - /// - /// Oggetto ultimo inviato stato IOB x REDIS - /// - protected IobWinStatus lastIobStatus = new IobWinStatus(); - - /// - /// Oggetto ultimo inviato stato MP-IO x REDIS - /// - protected ServerMpStatus lastSrvStatus = new ServerMpStatus(); - - /// - /// ultimo tentativo riavvio... - /// - protected DateTime lastStartTry; - - /// - /// contatore normale - /// - protected int normCount; - - /// - /// Contatore campionamento memoria - /// - protected int sampleMemCount; - - /// - /// contatore lento - /// - protected int slowCount; - - /// - /// contatore sync allarmi - /// - protected int verySlowCount; - - /// - /// Temnpo attesa std in MS - /// - protected int waitRecMSec = 30000; - - #endregion Protected Fields - - #region Public Fields - - /// - /// oggetto logging - /// - public static Logger lg; - - /// - /// Modello macchina - /// - public string curModel = ""; - - /// - /// Vendor macchina - /// - public string curVendor = ""; - - /// - /// configurazione caricata - /// - public IobConfiguration IOBConf; - - /// - /// Oggetto x gestione dell'adapter GENERICO (x poter usare metodi di ognuno...) - /// - public IobGeneric iobObj; - - /// - /// tipo di adapter prescelto... - /// - public tipoAdapter tipoScelto = tipoAdapter.SIMULA; - - #endregion Public Fields - - #region Public Constructors - - /// - /// Avvio MainForm - /// - /// - public AdapterForm(string codIOB) - { - CurrIOB = codIOB; - // continuo avvio... - InitializeComponent(); - myGraphInitForm(); - - checkEditMes2Plc(); - - // inizializzo orologi - firstStart = DateTime.Now; - lastStartTry = DateTime.Now; - - initDatamonitor(); - - waitRecMSec = utils.CRI("waitRecMSec"); - - LogManager.ReconfigExistingLoggers(); - - lg = LogManager.GetCurrentClassLogger(); - displayTaskAndLog("MainForm Starting"); - - // se abilitato autoload conf leggo file corretto... - - if (utils.CRB("autoLoadConf")) - { - try - { - loadIniFile(defConfFilePath); - lgInfo("INI LOADED"); - } - catch (Exception exc) - { - displayTaskAndLog(string.Format("Eccezione in autoLoadConf: {0}", exc)); - } - } - - if (IOBConf == null || !utils.CRB("autoLoadConf")) - { - // definisco e avvio tipo adapter generico - tipoScelto = tipoAdapter.ND; - curVendor = "ACME"; - curModel = "NONE"; - IOBConf = new IobConfiguration(); - loadIobType(); - displayTaskAndLog("Waiting for config file selection"); - } - - // cerco tra i parametri opzionali se ho il parametro di - int timerIntMs = utils.CRI("timerIntMs"); - if (IOBConf.optPar.ContainsKey("timerIntMs")) - { - // recupero - string rawVal = IOBConf.optPar["timerIntMs"]; - if (!string.IsNullOrEmpty(rawVal)) - { - int.TryParse(rawVal, out timerIntMs); - lgInfo($"Impostato timerIntMs da IOB.ini: {timerIntMs}"); - } - } - // Start timer periodico comunicazione - gather.Interval = timerIntMs; - gather.Enabled = true; - displayTaskAndLog(string.Format("Main timer set: {0}ms", gather.Interval)); - - // Start timer periodico interfaccia - displTimer.Interval = utils.CRI("timerIntMs"); - displTimer.Enabled = true; - - displayTaskAndLog("Program Running"); - - // check oggetto not null - if (iobObj != null) - { - try - { - // verifico server online... - if (iobObj.checkServerAlive) - { - // segnalo reboot (programma)... - IobGeneric.callUrl(iobObj.urlReboot, true); - } - else - { - displayTaskAndLog("AdapterForm: Server OFFLINE"); - } - } - catch (Exception exc) - { - lgError(string.Format("AdapterForm: EXCEPTION in fase di chiamata URL di reboot:{0}{1}{2}", iobObj.urlReboot, Environment.NewLine, exc)); - } - } - displayTaskAndLog("Main Form OK"); - } - - #endregion Public Constructors - - #region Private Delegates - - private delegate void SafeCallDelegate(string text); - - #endregion Private Delegates - - #region Protected Properties - - /// - /// Valore protected comunicazione PLC - /// - protected bool _commPlcActive { get; set; } = false; - - /// - /// Valore protetto stato comunicazione - /// - protected int _commSrvActive { get; set; } = 0; - - /// - /// Valore protected semaforo IN - /// - protected Semaforo _sIN { get; set; } = Semaforo.ND; - - /// - /// Valore protected semaforo OUT - /// - protected Semaforo _sOUT { get; set; } = Semaforo.ND; - - /// - /// Codice IOB della macchina cui connettersi (x scegliere corretto file di conf...) - /// - protected string CurrIOB { get; set; } - - protected int delayShowLogMs { get; set; } = utils.CRI("delayShowLogMs"); - - /// - /// Dictionary dei divieti del datamonitor - /// - protected Dictionary dMonDisplVetoVeto { get; set; } = new Dictionary(); - - /// - /// array degli oggetti datamonitor da mostrare - /// - protected Dictionary dMonValues { get; set; } = new Dictionary(); - - /// - /// Veto a NUOVE scritture in COUNTER... - /// - protected DateTime logCounterVeto { get; set; } = DateTime.Now; - - /// - /// Stringa corrente di log... - /// - protected string logWatchString { get; set; } = ""; - - /// - /// Veto a NUOVE scritture in logWatch... - /// - protected DateTime logWatchWriteVeto { get; set; } = DateTime.Now; - - protected int maxAlQueue { get; set; } - - protected int maxEvQueue { get; set; } - - protected int maxFlQueue { get; set; } - - protected int maxMsQueue { get; set; } - - protected int qAlLen { get; set; } - - protected int qEvLen { get; set; } - - protected int qFlLen { get; set; } - - protected int qMsLen { get; set; } - - protected int totQueue - { - get - { - return qEvLen + qFlLen + qAlLen + qMsLen; - } - } - - #endregion Protected Properties - - #region Public Properties - - public int alQueueLen - { - set - { - qAlLen = value; - lblQueueAlarmLen.Text = qAlLen.ToString(); - showQueueData(); - // se supero max precedente, ed è > 10... loggo! - if (qAlLen > maxAlQueue && qAlLen > 10) - { - maxAlQueue = qAlLen; - lgInfo($"[WARN] Coda FLog di {value} record"); - } - else - { - maxAlQueue--; - maxAlQueue = maxAlQueue < qAlLen ? qAlLen : maxAlQueue; - } - } - get - { - return qAlLen; - } - } - - /// - /// Visualizzazione stato di comunicazione attiva con PLC - /// - public bool commPlcActive - { - get - { - return _commPlcActive; - } - set - { - _commPlcActive = value; - // se true --> comunica/verde, altrimenti grigio - lblCNC.ForeColor = value ? Color.SeaGreen : Color.Black; - statusStrip1.Refresh(); - } - } - - /// - /// Visualizzazione stato di comunicazione attiva con PLC: - /// 0 = NO PING - /// 1 = PING OK - /// 2 = IOB enabled - /// - public int commSrvActive - { - get - { - return _commSrvActive; - } - set - { - _commSrvActive = value; - switch (value) - { - case 0: - lblSrvUrl.ForeColor = Color.Red; - break; - - case 1: - lblSrvUrl.ForeColor = Color.OrangeRed; - break; - - case 2: - lblSrvUrl.ForeColor = Color.SeaGreen; - break; - - default: - break; - } - statusStrip1.Refresh(); - } - } - - public string counterIob - { - get - { - return lblPzCountIob.Text; - } - set - { - lblPzCountIob.Text = value; - } - } - - public string counterMac - { - get - { - return lblPzCountMac.Text; - } - set - { - lblPzCountMac.Text = value; - } - } - - /// - /// Stringa dati monitoraggio mostrata (1 SX)... - /// - public string dataMonitor_0 - { - get - { - return dMonValues[0]; - } - set - { - DateTime adesso = DateTime.Now; - // salvo nell'array... - dMonValues[0] = value; - if (dMonDisplVetoVeto[0] < adesso) - { - // se scaduto veto --> display! - lblRawData.Text = value; - // update veto! - dMonDisplVetoVeto[0] = adesso.AddMilliseconds(delayShowLogMs); - } - } - } - - /// - /// Stringa dati monitoraggio mostrata (1 SX)... - /// - public string dataMonitor_1 - { - get - { - return dMonValues[1]; - } - set - { - DateTime adesso = DateTime.Now; - // salvo nell'array... - dMonValues[1] = value; - if (dMonDisplVetoVeto[1] < adesso) - { - // se scaduto veto --> display! - lblOutMessage.Text = value; - // update veto! - dMonDisplVetoVeto[1] = adesso.AddMilliseconds(delayShowLogMs); - } - } - } - - /// - /// Stringa dati monitoraggio mostrata (2 centro)... - /// - public string dataMonitor_2 - { - get - { - return dMonValues[2]; - } - set - { - DateTime adesso = DateTime.Now; - // salvo nell'array... - dMonValues[2] = value; - if (dMonDisplVetoVeto[2] < adesso) - { - // se scaduto veto --> display! - lblOutMessage2.Text = value; - // update veto! - dMonDisplVetoVeto[2] = adesso.AddMilliseconds(delayShowLogMs); - } - } - } - - /// - /// Stringa dati monitoraggio mostrata (3 dx)... - /// - public string dataMonitor_3 - { - get - { - return dMonValues[3]; - } - set - { - DateTime adesso = DateTime.Now; - // salvo nell'array... - dMonValues[3] = value; - if (dMonDisplVetoVeto[3] < adesso) - { - // se scaduto veto --> display! - lblOutMessage3.Text = value; - // update veto! - dMonDisplVetoVeto[3] = adesso.AddMilliseconds(delayShowLogMs); - } - } - } - - /// - /// label del numero di record processati (libera) - /// - public string dataProcLabel - { - get - { - return lblDataProc.Text; - } - set - { - lblDataProc.Text = value; - } - } - - /// - /// File configurazione default - /// - public string defConfFilePath - { - get - { - return string.Format(@"{0}\{1}.ini", utils.confDir, CurrIOB); - } - } - - public bool enableEditMes2Plc { get; set; } - - public int evQueueLen - { - set - { - qEvLen = value; - lblQueueLen.Text = qEvLen.ToString(); - showQueueData(); - // se supero max precedente, ed è > 10... loggo! - if (qEvLen > maxEvQueue && qEvLen > 10) - { - maxEvQueue = qEvLen; - lgInfo($"[WARN] Coda EV di {value} record"); - } - else - { - maxEvQueue--; - maxEvQueue = maxEvQueue < qEvLen ? qEvLen : maxEvQueue; - } - } - get - { - return qEvLen; - } - } - - public int flQueueLen - { - set - { - qFlLen = value; - lblQueueFLogLen.Text = qFlLen.ToString(); - showQueueData(); - // se supero max precedente, ed è > 10... loggo! - if (qFlLen > maxFlQueue && qFlLen > 10) - { - maxFlQueue = qFlLen; - lgInfo($"[WARN] Coda FLog di {value} record"); - } - else - { - maxFlQueue--; - maxFlQueue = maxFlQueue < qFlLen ? qFlLen : maxFlQueue; - } - } - get - { - return qFlLen; - } - } - - /// - /// Log verboso da configurazione (SOLO CHAIVE "verbose"... - /// - public bool isVerboseLog { get; set; } = utils.CRB("verbose"); - - /// - /// Logwatcher (in modalità "accodamento in testa" ultimi messaggi...) - /// - public string logWatcher - { - get - { - return lblLogfile.Text; - } - set - { - try - { - logWatchString = limitLine2show($"{value}{Environment.NewLine}{logWatchString}"); - DateTime adesso = DateTime.Now; - if (logWatchWriteVeto < adesso) - { - this.UIThread(delegate - { - lblLogfile.Text = logWatchString; - lblLogfile.Refresh(); - }); - - logWatchWriteVeto = adesso.AddMilliseconds(delayShowLogMs); - } - } - catch (Exception exc) - { - lgError($"Errore in esecuzione logWatcher{Environment.NewLine}--> {value}"); - if (isVerboseLog) - { - lgError($"{exc}"); - } - } - } - } - - public int msQueueLen - { - set - { - qMsLen = value; - lblQueueMessLen.Text = qMsLen.ToString(); - showQueueData(); - // se supero max precedente, ed è > 10... loggo! - if (qMsLen > maxMsQueue && qMsLen > 10) - { - maxMsQueue = qMsLen; - lgInfo($"[WARN] Coda FLog di {value} record"); - } - else - { - maxMsQueue--; - maxMsQueue = maxMsQueue < qMsLen ? qMsLen : maxMsQueue; - } - } - get - { - return qMsLen; - } - } - - /// - /// Numero max linee da mostrare (da controllo)... - /// - public int nLine2show - { - get - { - int answ = 5; - try - { - Int32.TryParse(nLines.Text, out answ); - } - catch - { } - return answ; - } - set - { - nLines.Text = value.ToString(); - } - } - - /// - /// Imposta COLORE SFONDO x Semaforo IN - /// - public Semaforo sIN - { - get - { - return _sIN; - } - set - { - _sIN = value; - var newColor = decSemaforo(value); - if (newColor != bIN.BackColor) - { - bIN.BackColor = newColor; - bIN.Refresh(); - } - } - } - - /// - /// Imposta COLORE SFONDO x Semaforo OUT - /// - public Semaforo sOUT - { - get - { - return _sOUT; - } - set - { - _sOUT = value; - var newColor = decSemaforo(value); - if (newColor != bOUT.BackColor) - { - bOUT.BackColor = newColor; - bOUT.Refresh(); - } - } - } - - /// - /// Task watcher (in modalità "accodamento in testa" ultimi messaggi...) - /// - public string taskWatcher - { - get - { - return lblTaskLog.Text; - } - set - { - try - { - lblTaskLog.Text = limitLine2show($"{value}{Environment.NewLine}{lblTaskLog.Text}"); - lblTaskLog.Refresh(); - } - catch (Exception exc) - { - lgError($"Errore in esecuzione taskWatcher{Environment.NewLine}--> {value}"); - if (isVerboseLog) - { - lgError($"{exc}"); - } - } - } - } - - #endregion Public Properties - - #region Private Methods - - private void BtnOpenLog_Click(object sender, EventArgs e) - { - try - { - string logPath = $"{System.AppDomain.CurrentDomain.BaseDirectory}logs\\{CurrIOB}\\{DateTime.Today:yyyy-MM-dd}.log"; - Process.Start(logPath); - } - catch (Exception exc) - { - lgError($"Eccezione in show log (MAIN):{Environment.NewLine}{exc}"); - } - } - - private void BtnSendPLC_Click(object sender, EventArgs e) - { - // invia a MES il parametro selezionato (es ART / ODL / PRG NAME, come task2exe..) - Dictionary forcedTask = new Dictionary(); - // guardo i parametri... - if (!string.IsNullOrEmpty(txtValue.Text)) - { - forcedTask.Add(cmbParamValues.SelectedValue.ToString(), txtValue.Text); - } - // chiedo esecuzione task! - iobObj.processTask(forcedTask); - chkEdit.Checked = false; - toggleEditMes2Plc(); - } - - private void checkEditMes2Plc() - { - cmbParamValues.Enabled = enableEditMes2Plc; - txtValue.Enabled = enableEditMes2Plc; - if (enableEditMes2Plc) - { - // aggiorno (se possibile) i parametri selezionabili... - fixComboParameters(); - } - } - - private void checkFastTask() - { - // decremento... - fastCount--; - // se il counter è a zero eseguo... - if (fastCount <= 0) - { - fastCount = utils.CRI("fastCount"); - - // avvio fase raccolta dati e invio con adapter - iobObj.getAndSend(gatherCycle.HF); - } - } - - private void checkNormTask() - { - // decremento... - normCount--; - // se il counter è a zero eseguo... - if (normCount <= 0) - { - normCount = utils.CRI("normCount"); - - // avvio fase raccolta dati e invio con adapter - iobObj.getAndSend(gatherCycle.MF); - } - } - - private void checkSampleMem() - { - // decremento contatore... - sampleMemCount--; - if (sampleMemCount <= 0) - { - sampleMemCount = utils.CRI("sampleMemCount"); - // avvio fase raccolta dati e invio con adapter - iobObj.saveMemDump(dumpType.SAMPLE); - } - } - - private void checkSendTask() - { - // avvio fase invio con adapter (code MST) - iobObj.getAndSend(gatherCycle.VHF); - } - - private void checkSlowTask() - { - slowCount--; - if (slowCount <= 0) - { - slowCount = utils.CRI("slowCount"); - - // avvio fase raccolta dati e invio con adapter - iobObj.getAndSend(gatherCycle.LF); - } - } - - private void checkVerySlowData() - { - verySlowCount--; - if (verySlowCount <= 0) - { - verySlowCount = utils.CRI("verySlowCount"); - // avvio fase raccolta dati e invio con adapter - iobObj.getAndSend(gatherCycle.VLF); - } - } - - private void ChkEdit_CheckedChanged(object sender, EventArgs e) - { - toggleEditMes2Plc(); - } - - /// - /// Chiusura adapter - /// - private void closeAdapter() - { - fermaTutto(true, false, true, false); - } - - private void displTimer_Tick(object sender, EventArgs e) - { - } - - /// - /// Ferma tutti i componenti adapter + update buttons - /// - /// indica se fermare il timer (gather) principale (solo se non si chiude) - /// indica se tentare di riconnettersi - /// indica se sia richeisto di SVUOTARE le code delel info - /// indica se si debba aggiornare la form (no se si sta chiudendo...) - private void fermaTutto(bool stopTimer, bool tryRestart, bool forceDequeue, bool updateForm) - { - iobObj.stopAdapter(tryRestart, forceDequeue); - // salvo! - savePersistLayer(utils.defPersLayerFile); - savePersistLayer(utils.histPersLayerFile); - - stop.Enabled = false; - start.Enabled = true; - restart.Enabled = false; - - if (stopTimer) - { - gather.Enabled = false; - iobObj.tryDisconnect(); - } - - newDisplayData currDispData = new newDisplayData(); - currDispData.semIn = Semaforo.SS; - currDispData.semOut = Semaforo.SS; - if (updateForm) - { - updateFormDisplay(currDispData); - } - } - - private void fixComboParameters() - { - if (iobObj != null) - { - if (iobObj.memMap != null) - { - if (iobObj.memMap.mMapWrite != null) - { - if (iobObj.memMap.mMapWrite.Count > 0) - { - var oldParams = cmbParamValues.DataSource; - List parametri = new List(); - foreach (var item in iobObj.memMap.mMapWrite) - { - parametri.Add(item.Key); - } - // salvo selezione - int oldIdx = cmbParamValues.SelectedIndex; - // riassegno e ri-seleziono - cmbParamValues.DataSource = parametri; - cmbParamValues.SelectedIndex = oldIdx >= 0 ? oldIdx : 0; ; - } - } - } - } - } - - private void gather_Tick(object sender, EventArgs e) - { - bool doLog = false; - if (iobObj != null) - { - if (iobObj.periodicLog) - { - doLog = true; - } - try - { - refreshFormData(); - // check esecuzione SendTask (VHF) COMUNQUE... - checkSendTask(); - // eseguo cicli attivi SOLO se adapter è in EFFETTIVO running... - if (iobObj.adpRunning) - { - if (iobObj.connectionOk) - { - // se richiesto faccio memory DUMP INIZIALE! - if (iobObj.doStartMemDump) - { - lgInfo("Inizio dump memoria"); - iobObj.saveMemDump(dumpType.STARTUP); - // fatto! non ripeto... - iobObj.doStartMemDump = false; - lgInfo("Finito dump memoria"); - } - // controllo se sia abilitato sampleDump della meoria (periodico) - if (iobObj.doSampleMemory) - { - checkSampleMem(); - } - // check esecuzione FastTask - checkFastTask(); - // check esecuzione NormTask - checkNormTask(); - // check esecuzione SlowTask - checkSlowTask(); - // check esecuzione AlarmSync - checkVerySlowData(); - if (utils.CRI("waitEndCycle") > 0) - { - Thread.Sleep(utils.CRI("waitEndCycle")); - } - } - else - { - DateTime dtVeto = lastStartTry.AddMilliseconds(waitRecMSec); - if (iobObj.adpTryRestart && (DateTime.Now > dtVeto)) - { - if (doLog) - { - lgInfo($"Retry Time Elapsed ({waitRecMSec} ms)--> tryConnect"); - } - lastStartTry = DateTime.Now; - iobObj.tryConnect(); - } - } - } - else - { - if (doLog) - { - lgInfo("Adapter stopped"); - } - // verifico SE debba tentare il riavvio, ovvero NON running ma adpTryRestart e non ho riprovato x oltre waitRecMSec - DateTime dtVeto = lastStartTry.AddMilliseconds(waitRecMSec); - if (iobObj.adpTryRestart && (DateTime.Now > dtVeto)) - { - lastStartTry = DateTime.Now; - avviaAdapter(chkForceDequeue.Checked); - } - } - } - catch (Exception exc) - { - lgError(string.Format("Eccezione in fase di gatherTick: {0}{1}", Environment.NewLine, exc)); - } - } - } - - /// - /// Init oggetti datamonitor - /// - private void initDatamonitor() - { - for (int i = 0; i < 4; i++) - { - dMonDisplVetoVeto.Add(i, DateTime.Now); - dMonValues.Add(i, ""); - } - } - - /// - /// GEstione evento refresh - /// - /// - /// - private void IobObj_eh_refreshed(object sender, iobRefreshedEventArgs e) - { - // aggiorno! - updateFormDisplay(e.DisplayDataObject); - } - - /// - /// Carica file ini della configurazione richiesta - /// - /// - private void loadIniFile(string iniConfFile) - { - // out di cosa faccio... - displayTaskAndLog($"[STARTUP] Loading iniConfFile: {iniConfFile}"); - // leggo file - IniFile fIni = new IniFile(iniConfFile); - - // leggo vendor e modello... - curVendor = fIni.ReadString("MACHINE", "VENDOR", "ACME"); - curModel = fIni.ReadString("MACHINE", "MODEL", "NONE"); - // verifico tipo adapter - try - { - tipoScelto = (tipoAdapter)Enum.Parse(typeof(tipoAdapter), fIni.ReadString("IOB", "CNCTYPE", "DEMO")); - } - catch (Exception exc) - { - lgError($"Eccezione in conversione tipo adapter: richiesto un tipo non codificato...{Environment.NewLine}{exc}"); - tipoScelto = tipoAdapter.ND; - } - // carivo vettore parametri opzionai - Dictionary optParRead = new Dictionary(); - string[] optParRows = fIni.ReadSection("OPTPAR"); - if (optParRows.Length > 0) - { - try - { - string[] kvp; - foreach (var item in optParRows) - { - kvp = item.Split('='); - optParRead.Add(kvp[0], kvp[1]); - } - lgInfo($"Caricati {optParRead.Count} parametri opzionali da OPTPAR"); - } - catch (Exception exc) - { - lgError(string.Format("EXCEPTION in fase di lettura OPTPAR: {0}{1}", Environment.NewLine, exc)); - } - } - // inizializzio conf IOB - IOBConf = new IobConfiguration - { - pingMsTimeout = fIni.ReadInteger("IOB", "PING_MS_TIMEOUT", 500), - vendor = curVendor, - model = curModel, - tipoIob = tipoScelto, - optPar = optParRead, - versIOB = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(), - codIOB = CurrIOB, - cncIpAddr = fIni.ReadString("CNC", "IP", "::1"), - cncPort = fIni.ReadString("CNC", "PORT", "0"), - iniFileName = iniConfFile, - cpuType = fIni.ReadString("CNC", "CPUTYPE", ""), - rack = (short)fIni.ReadInteger("CNC", "RACK", 0), - slot = (short)fIni.ReadInteger("CNC", "SLOT", 0), - serverData = new serverMapo(fIni.ReadString("SERVER", "MPIP", "::1"), fIni.ReadString("SERVER", "MPURL", "/"), fIni.ReadString("SERVER", "CMDBASE", "/"), fIni.ReadString("SERVER", "CMDFLOG", "/"), fIni.ReadString("SERVER", "CMDALIVE", "/"), fIni.ReadString("SERVER", "CMDENABLED", "/"), fIni.ReadString("SERVER", "CMDREBO", "/"), fIni.ReadString("SERVER", "CMD_ODL_STARTED", "/IOB/getCurrOdlStart/"), fIni.ReadString("SERVER", "CLI_INST", "SW_CLI"), fIni.ReadString("SERVER", "CMD_FORCLE_SPLIT_ODL", "/IOB/forceSplitOdlFull/")), - MAX_COUNTER_BLINK = Convert.ToInt32(fIni.ReadString("BLINK", "MAX_COUNTER_BLINK", "1")), - BLINK_FILT = Convert.ToInt32(fIni.ReadString("BLINK", "BLINK_FILT", "0")), - TCMaxDelayFactor = Convert.ToDouble(fIni.ReadString("OPTPAR", "TC_MAX_TC_FACTOR", "1.2").Replace(".", ",")), - TCLambda = Convert.ToDouble(fIni.ReadString("OPTPAR", "TC_LAMBDA", "0.5").Replace(".", ",")), - TCMaxIncrPz = Convert.ToDouble(fIni.ReadString("OPTPAR", "TC_MAX_INCR", "5").Replace(".", ",")) - }; - lgInfo($"Creato IOBConf!"); - - // salvo serializzando json... nella folder x Cliente oppure Vendor_Model - string confJson = JsonConvert.SerializeObject(IOBConf, Formatting.Indented); - string path = fileMover.GetExecutingDirectoryName(); // Directory.GetCurrentDirectory(); - string fileName = Path.GetFileName(iniConfFile).Replace(".ini", ".iob"); - string dirPath = $"{path}\\DATA\\{IOBConf.serverData.ClientInstall}"; - string fullPath = $"{dirPath}\\{fileName}"; - // verifica directory - Directory.CreateDirectory(dirPath); - // salvataggio - File.WriteAllText(fullPath, confJson); - - loadIobType(); - // avvio macchina con adapter specificato... - if (utils.CRB("autoStartOnLoad")) - { - displayTaskAndLog("Auto Starting..."); - // avvio! - avviaAdapter(chkForceDequeue.Checked); - displayTaskAndLog("Auto Started!"); - } - try - { - // segnalo reboot (programma)... metto in coda invio... - //iobObj.sendToMoonPro(urlType.FLog, "IOB INI Loaded"); - //iobObj.QueueFLog.Enqueue(iobObj.qEncodeFLog("IOB-STATUS", "IOB INI Loaded")); - } - catch (Exception exc) - { - lgError(string.Format("EXCEPTION in fase di chiamata URL di segnalazione caricamento INI file:{0}{1}", Environment.NewLine, exc)); - } - } - - /// - /// carica IOB richiesto - /// - private void loadIobType() - { - if (IOBConf != null) - { - switch (tipoScelto) - { - case tipoAdapter.SIMULA: - iobObj = new IobSimula(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.FILE_GEN: - iobObj = new IobFile(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.FILE_EUROM63: - iobObj = new IobFileEurom63(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.FANUC: - iobObj = new IobFanuc(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.KAWASAKI: - iobObj = new IobKawasaki(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.MTConnect: - iobObj = new IobMTC(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.OMRON: - iobObj = new IobOmron(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.OpcUa: - iobObj = new IobOpcUa(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.OpcUaEwon: - iobObj = new IobOpcUaEwon(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.OSAI_OPEN: - case tipoAdapter.OSAI_CNDEX: - case tipoAdapter.OSAI_VB6: - // versione CVCncLib - iobObj = new IobOSAI(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.SIEMENS: - iobObj = new IobSiemens(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.SIEMENS_APROCHIM: - iobObj = new IobSiemensAprochim(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.SIEMENS_AT2001: - iobObj = new IobSiemensAt2001(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.SIEMENS_COMUR: - iobObj = new IobSiemensComur(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.SIEMENS_FAPE: - iobObj = new IobSiemensFape(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.SIEMENS_INGENIA: - iobObj = new IobSiemensIngenia(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.SIEMENS_LASCO: - iobObj = new IobSiemensLasco(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.SIEMENS_PRESSOIL_CEI: - iobObj = new IobSiemensPressoilCei(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.SIEMENS_SAET: - iobObj = new IobSiemensSaet(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.SIEMENS_SIMEC: - iobObj = new IobSiemensSimec(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.SIEMENS_TORRI: - iobObj = new IobSiemensTorri(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.WPS: - iobObj = new IobWPS(this, IOBConf); - start.Enabled = true; - break; - - case tipoAdapter.ND: - default: - iobObj = new IobSimula(this, IOBConf); - start.Enabled = false; - break; - } - lblCNC.Text = $"CNC: {IOBConf.tipoIob} [{IOBConf.cncIpAddr}:{IOBConf.cncPort}]"; - lblSrvUrl.Text = $"SRV: {IOBConf.serverData.MPIP} | URL: {IOBConf.serverData.MPURL}{IOBConf.serverData.CMDBASE}"; - - // aggancio evento refresh - iobObj.eh_refreshed += IobObj_eh_refreshed; - - // carico i default values su interfaccia - setDefaults(); - - displayTaskAndLog(string.Format("Caricata conf per adapter {0}", tipoScelto)); - } - } - - /// - /// Fase chiusura Form - /// - /// - /// - private void MainForm_FormClosing(object sender, FormClosingEventArgs e) - { - closeAdapter(); - } - - /// - /// Completato resize form - /// - /// - /// - private void MainForm_Resize(object sender, EventArgs e) - { - } - - /// - /// Mostrata form - /// - /// - /// - private void MainForm_Shown(object sender, EventArgs e) - { - displayTaskAndLog("Main Form SHOWN (Adapter)"); - } - - private void mLoadConf_Click(object sender, EventArgs e) - { - // mostro selettore file x leggere adapter.. - OpenFileDialog openFileDial = new OpenFileDialog(); - - // directory iniziale - openFileDial.InitialDirectory = utils.confDir; // string.Format(@"{0}\{1}", Application.StartupPath, utils.CRS("dataConfPath")); - // Set filter options and filter index. - openFileDial.Filter = "INI Files (.ini)|*.ini|All Files (*.*)|*.*"; - openFileDial.FilterIndex = 1; - // altre opzioni - openFileDial.Multiselect = false; - - // Call the ShowDialog method to show the dialog box. - DialogResult userClickedOK = openFileDial.ShowDialog(); - - // Process input if the user clicked OK. - if (userClickedOK == DialogResult.OK) - { - string iniConfFile = openFileDial.FileName; - loadIniFile(iniConfFile); - lgInfo("INI LOADED"); - } - } - - private void refreshFormData() - { - // aggiorno visualizzazioni varie in form... - evQueueLen = iobObj.QueueIN.Count; - flQueueLen = iobObj.QueueFLog.Count; - alQueueLen = iobObj.QueueAlarm.Count; - msQueueLen = iobObj.QueueMessages.Count; - // aggiorno labels counters... - counterIob = $"pz IOB {iobObj.contapezziIOB}"; - counterMac = $"pz PLC {iobObj.contapezziPLC}"; - // verifico IOB status - IobWinStatus currIobStatus = new IobWinStatus() - { - CodIob = iobObj.cIobConf.codIOB, - queueEvLen = evQueueLen, - queueFlLen = flQueueLen, - queueAlLen = alQueueLen, - queueMsLen = msQueueLen, - counterIOB = iobObj.contapezziIOB, - counterMAC = iobObj.contapezziPLC, - lastUpdate = lastIobStatus.lastUpdate, - online = utils.IOB_Online, - lastDataIn = iobObj.lastReadPLC - }; - // se diverso SALVO! - if (lastIobStatus.online != currIobStatus.online || lastIobStatus.lastDataIn != currIobStatus.lastDataIn || lastIobStatus.counterIOB != currIobStatus.counterIOB || lastIobStatus.counterMAC != currIobStatus.counterMAC || lastIobStatus.queueEvLen != currIobStatus.queueEvLen || lastIobStatus.queueFlLen != currIobStatus.queueFlLen || lastIobStatus.queueAlLen != currIobStatus.queueAlLen || lastIobStatus.queueMsLen != currIobStatus.queueMsLen) - { - // aggiorno data - currIobStatus.lastUpdate = DateTime.Now; - // salvo su redis e in obj corrente - iobObj.redisMan.iobStatus = currIobStatus; - lastIobStatus = currIobStatus; - } - // se diverso SALVO MP IO status - if (lastSrvStatus.online != utils.MPIO_Online) - { - // aggiorno - ServerMpStatus currSrvStatus = iobObj.redisMan.servStatus; - currSrvStatus.online = utils.MPIO_Online; - currSrvStatus.lastUpdate = DateTime.Now; - // salvo su redis e in obj corrente - iobObj.redisMan.servStatus = currSrvStatus; - lastSrvStatus = currSrvStatus; - } - } - - /// - /// Button restart - /// - /// - /// - private void restart_Click(object sender, EventArgs e) - { - string message = "Attenzione: con l'operazione di reset veranno persi (e non inviati) i dati eventualmente accumulati (indipendentemente dalla selezione del checkbox 'svuota coda')."; - string caption = "Conferma Reset Dati IOB"; - MessageBoxButtons buttons = MessageBoxButtons.YesNo; - DialogResult result; - - // verifica con messagebox - result = MessageBox.Show(message, caption, buttons); - // solo se ho conferma da utente - if (result == DialogResult.Yes) - { - // faccio stop... SENZA inviare - fermaAdapter(false, false, true); - displayTaskAndLog("RESTARTING: Adapter Stopped"); - // rileggo INI - loadIniFile(defConfFilePath); - displayTaskAndLog("RESTARTING: Ini File Reloaded"); - // faccio start... CON RESET delel code - avviaAdapter(true); - displayTaskAndLog("RESTARTING: Adapter Started"); - // resetto i data monitor... - dataMonitor_0 = ""; - dataMonitor_1 = ""; - dataMonitor_2 = ""; - dataMonitor_3 = ""; - } - } - - /// - /// impostazione valori defaults - /// - private void setDefaults() - { - stop.Enabled = false; - - evQueueLen = 0; - flQueueLen = 0; - nLine2show = utils.CRI("numRowConsole"); - } - - private void splitContainer1_Panel1_Paint(object sender, PaintEventArgs e) - { - } - - /// - /// Avvio dell'adapter - /// - /// - /// - private void start_Click(object sender, EventArgs e) - { - avviaAdapter(chkForceDequeue.Checked); - // salvo che ho avviato adapter - lgInfo("Completato LOAD Adapter"); - } - - /// - /// fermata dell'adapter - /// - /// - /// - private void stop_Click(object sender, EventArgs e) - { - fermaAdapter(false, chkForceDequeue.Checked, true); - // salvo che ho fermato adapter - lgInfo("UNLOAD Adapter"); - } - - private void TabData_Selected(object sender, TabControlEventArgs e) - { - } - - private void toggleEditMes2Plc() - { - // abilita i campi --> PLC per editing - enableEditMes2Plc = !enableEditMes2Plc; - checkEditMes2Plc(); - } - - #endregion Private Methods - - #region Protected Methods - - protected override void Dispose(bool disposing) - { - if (disposing && (components != null)) - { - components.Dispose(); - } - base.Dispose(disposing); - } - - /// - /// Effettua logging ERROR corretto impostanto anche la variabile IOB prima di scrivere... - /// - /// - protected void lgError(string txt2log) - { - if (!string.IsNullOrEmpty(txt2log)) - { - lg.Factory.Configuration.Variables["codIOB"] = this.CurrIOB; - lg.Error(txt2log); - // salvo anche in logwatcher... SE non si dimostra ricorsivo... - if (!txt2log.Contains("logWatcher")) - { - newDisplayData currDispData = new newDisplayData(); - currDispData.newLiveLogData = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | ERROR | {txt2log}"; - updateFormDisplay(currDispData); - } - } - } - - /// - /// Effettua logging INFO corretto impostanto anche la variabile IOB prima di scrivere... - /// - /// - protected void lgInfo(string txt2log) - { - lg.Factory.Configuration.Variables["codIOB"] = this.CurrIOB; - lg.Info(txt2log); - // salvo anche in logwatcher... - newDisplayData currDispData = new newDisplayData(); - currDispData.newLiveLogData = $"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")} | INFO | {txt2log}"; - updateFormDisplay(currDispData); - } - - /// - /// Init form (grafica) con helper x testi e varie - /// - protected void myGraphInitForm() - { - lblStatus.Text = "Loading"; - - // aggiunta tooltip x send forzato - ToolTip ttForceSend = new ToolTip(); - - // imposto delay. - ttForceSend.AutoPopDelay = 3000; - ttForceSend.InitialDelay = 500; - ttForceSend.ReshowDelay = 500; - // sempre visibile (che sia o meno attiva la form). - ttForceSend.ShowAlways = true; - - // imposto tooltip - ttForceSend.SetToolTip(this.chkForceDequeue, "Forza invio eventi allo stop"); - } - - /// - /// MOstra info su coda complessiva - /// - protected void showQueueData() - { - lblQueueLenTop.Text = totQueue == 0 ? "realtime" : $"ev: {qEvLen} | flog: {qFlLen} | tot: {totQueue}"; - } - - #endregion Protected Methods - - #region Public Methods - - /// - /// Decodifica colore da valore semaforico - /// - /// - /// - public static Color decSemaforo(Semaforo valore) - { - Color colore = Color.LightGray; - switch (valore) - { - case Semaforo.SV: - colore = Color.LightGreen; - break; - - case Semaforo.SG: - colore = Color.LightGoldenrodYellow; - break; - - case Semaforo.SR: - colore = Color.Red; - break; - - case Semaforo.SS: - colore = Color.DarkGray; - break; - - default: - colore = Color.LightGray; - break; - } - return colore; - } - - /// - /// Avvio l'adapter - /// - /// indica se sia richeisto di SVUOTARE le code delel info - public void avviaAdapter(bool resetQueue) - { - displayTaskAndLog("Adapter starting"); - // se NON sta girando... - if (!iobObj.adpRunning) - { - iobObj.startAdapter(resetQueue); - displayTaskAndLog("Adapter started!"); - - // fix buttons start/stop/dump - start.Enabled = false; - stop.Enabled = true; - restart.Enabled = true; - - displayTaskAndLog("Start Timers"); - // inizializzo contatori fast/mid/slow - fastCount = utils.CRI("fastCount"); - normCount = utils.CRI("normCount"); - slowCount = utils.CRI("slowCount"); - verySlowCount = utils.CRI("verySlowCount"); - displayTaskAndLog("Adapter Running..."); - // init max queue - maxEvQueue = 1; - maxFlQueue = 1; - - try - { - // segnalo reboot (programma)... - iobObj.QueueFLog.Enqueue(iobObj.qEncodeFLog("IOB-STATUS", "IOB Started")); - } - catch (Exception exc) - { - lgError(string.Format("EXCEPTION in fase di chiamata URL di segnalazione AVVIO IOB:{0}{1}", Environment.NewLine, exc)); - } - } - else - { - displayTaskAndLog("Adapter STILL Running..."); - } - } - - /// - /// mostra un testo sulla status bar + LOG - /// - /// - public void displayTaskAndLog(string txt2show) - { - lblStatus.Text = txt2show; - lblStatus.Invalidate(); - lgInfo(txt2show); - } - - /// - /// Ferma l'adapter - /// - /// determina se si debba tentare riavvio automatico (per caduta connessione) - /// indica se sia richeisto di SVUOTARE le code delel info - /// indica se aggiornare la form prima di fermare - public void fermaAdapter(bool tryRestart, bool forceDequeue, bool updateForm) - { - fermaTutto(false, tryRestart, forceDequeue, updateForm); - } - - /// - /// Effettua un trim della stringa al numero max di linee da mostrare a video - /// - /// - /// - public string limitLine2show(string newString) - { - if (!string.IsNullOrEmpty(newString)) - { - // se num righe superiore a limite trimmo... - if (newString.Split('\n').Length > nLine2show) - { - //int idx = newString.LastIndexOf('\r'); - int idx = newString.LastIndexOf(Environment.NewLine); - newString = newString.Substring(0, idx); - } - } - return newString; - } - - /// - /// Salva su file l'oggetto di persistenza dati - /// - /// - public void savePersistLayer(string filePath) - { - // in primis check semaforo salvataggio... - if (!iobObj.adpSaving) - { - // alzo semaforo salvataggio - iobObj.adpSaving = true; - // se HO dei dati... - if (iobObj.persistenceLayer != null) - { - try - { - utils.WritePlain(iobObj.persistenceLayer, filePath); - } - catch (Exception exc) - { - lgError(string.Format("Errore salvataggio file{0}{1}", Environment.NewLine, exc)); - } - } - else - { - lgInfo("persistenceLayer null, non salvato..."); - } - // abbasso semaforo salvataggio - iobObj.adpSaving = false; - } - } - - /// - /// Mostra update delle statistiche di comunicazione (numero chiamate, tempo medio...) - /// - /// - public void updateComStats(string txt2show) - { - lblComStats.Text = string.Format("{0} | ", txt2show); - } - - /// - /// Effettua update form una volta ricevuto OBJ che contiene le varie innovazioni... - /// - /// - public void updateFormDisplay(newDisplayData currDispData) - { - // ciclo x ogni oggetto x caricare le innovazioni... - if (currDispData != null && currDispData.hasData) - { - DateTime adesso = DateTime.Now; - // RealTime display - if (!string.IsNullOrWhiteSpace(currDispData.newInData)) - { - dataMonitor_0 = limitLine2show($"{currDispData.newInData}{Environment.NewLine}{dataMonitor_0}"); - } - if (!string.IsNullOrWhiteSpace(currDispData.newSignalData)) - { - dataMonitor_1 = limitLine2show($"{currDispData.newSignalData}{Environment.NewLine}{dataMonitor_1}"); - } - if (!string.IsNullOrWhiteSpace(currDispData.newFLogData)) - { - dataMonitor_3 = limitLine2show($"{currDispData.newFLogData}{Environment.NewLine}{dataMonitor_3}"); - } - if (!string.IsNullOrWhiteSpace(currDispData.newUrlCallData)) - { - dataMonitor_2 = limitLine2show($"{currDispData.newUrlCallData}{Environment.NewLine}{dataMonitor_2}"); - } - - // Bitmap lettura attuale - if (currDispData.counter >= 0) - { - if (logCounterVeto < adesso || lblCounter.Text != $"{currDispData.counter}") - { - lblCounter.Text = $"{currDispData.counter}"; - lblCounter.Refresh(); - logCounterVeto = adesso.AddMilliseconds(delayShowLogMs); - } - } - // Bitmap lettura attuale - if (!string.IsNullOrWhiteSpace(currDispData.currBitmap)) - { - lblBitmap.Text = currDispData.currBitmap; - lblBitmap.Refresh(); - } - // LiveLog - if (!string.IsNullOrWhiteSpace(currDispData.newLiveLogData)) - { - logWatcher = currDispData.newLiveLogData; - } - // semafori - if (currDispData.semOut != Semaforo.ND) - { - // aggiorno SE diverso - if (sOUT != currDispData.semOut) - { - sOUT = currDispData.semOut; - } - } - if (currDispData.semIn != Semaforo.ND) - { - //aggiorno SE diverso - if (sIN != currDispData.semIn) - { - sIN = currDispData.semIn; - } - } - } - } - - public void WriteTextSafe(string text) - { - this.UIThread(delegate - { - lblOutMessage3.Text = text; - }); - - //if (lblOutMessage3.InvokeRequired) - //{ - // var d = new SafeCallDelegate(WriteTextSafe); - // lblOutMessage3.Invoke(d, new object[] { text }); - //} - //else - //{ - //} - } - - #endregion Public Methods - } -} \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/MAIN.ini b/IOB-WIN-NEXT/DATA/CONF/MAIN.ini index 6605c424..c04f13d0 100644 --- a/IOB-WIN-NEXT/DATA/CONF/MAIN.ini +++ b/IOB-WIN-NEXT/DATA/CONF/MAIN.ini @@ -64,7 +64,9 @@ CLI_INST=SteamWareSim ;STARTLIST=TEST ;STARTLIST=SIMUL_01 ;STARTLIST=1032 -STARTLIST=PIZ08 +;STARTLIST=1033 +;STARTLIST=PIZ08 +STARTLIST=PIZ04 ;STARTLIST=OPC_UA MAXCNC=10 \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/PIZ04.ini b/IOB-WIN-NEXT/DATA/CONF/PIZ04.ini new file mode 100644 index 00000000..b2c6e223 --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/PIZ04.ini @@ -0,0 +1,70 @@ +;Configurazione IOB-WIN +[IOB] +;Impianto HAM per Pizzaferri +CNCTYPE=MODBUS_TCP_HAM +PING_MS_TIMEOUT=500 + +[MACHINE] +VENDOR=HAM +MODEL=HAM + +[CNC] +IP=hampizzaferri.dyndns.org +PORT=502 + +[SERVER] +;MPIP=https://localhost:44339 +MPIP=https://gwms.egalware.com +MPURL=/api +CMDBASE=/IOB/input/ +CMDFLOG=/IOB/flog/ +CMDALIVE=/IOB +CMDENABLED=/IOB/enabled/ +CMDADV1=?valore= +CMDREBO=/IOB/sendReboot?idxMacchina= + +[MEMORY] +ADDR_READ=40001 +ADDR_WRITE=40401 +SIZE_READ=34 +;SIZE_READ=5046 +SIZE_WRITE=358 + + +[BLINK] +;MAX_COUNTER_BLINK = 30 +MAX_COUNTER_BLINK = 15 +;bit0 = 0 +;bit1 = 0 +;bit2 = 1 +;bit3 = 1 +;bit4 = 1 +;bit5 = 0 +;bit6 = 0 +;bit7 = 0 +BLINK_FILT=0 +;BLINK_FILT=28 + +[OPTPAR] +;PZCOUNT_MODE=STD.[PAR/MEM].info|BIT.indice +PZCOUNT_MODE=STD.DB85.DBRE16 +DISABLE_PZCOUNT=TRUE +ENABLE_SEND_PZC_BLOCK=TRUE +MIN_SEND_PZC_BLOCK=0 +MAX_SEND_PZC_BLOCK=100 +; GEST DATI DYN +ENABLE_DYN_DATA=TRUE +FORCE_DYN_DATA=TRUE + +; clock base (da 10ms) +timerIntMs=100 + +; conf parametri memoria READ/WRITE +PARAM_CONF=PIZ04.json + +NO_PING=FALSE +; conf aree allarme +ALARM_CONF=PIZ04_alarm.json + +[BRANCH] +NAME=master \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/PIZ04.json b/IOB-WIN-NEXT/DATA/CONF/PIZ04.json new file mode 100644 index 00000000..4889aa31 --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/PIZ04.json @@ -0,0 +1,255 @@ +{ + //"mMapWrite": { + // "setProg": { + // "name": "setProg", + // "description": "Programma", + // "tipoMem": "String", + // "memAddr": "DB6.DBB50", + // "index": 50, + // "size": 50 + // }, + // "setComm": { + // "name": "setComm", + // "description": "Commessa", + // "tipoMem": "String", + // "memAddr": "DB6.DBB0", + // "index": 0, + // "size": 50 + // }, + // "setArt": { + // "name": "setArt", + // "description": "Articolo", + // "tipoMem": "String", + // "memAddr": "DB6.DBB100", + // "index": 100, + // "size": 50 + // }, + // "setPzComm": { + // "name": "setPzComm", + // "description": "Qty", + // "memAddr": "DB30.DBB212", + // "tipoMem": "DInt", + // "index": 212, + // "size": 4 + // } + //}, + "mMapRead": { + "Level": { + "name": "GiacSerb", + "description": "Livello Serbatoio", + "memAddr": "40001", + "tipoMem": "Real", + "index": 1, + "size": 2, + "func": "MAX", + "period": 60, + "factor": 280, + "minVal": 0, + "maxVal": 100 + }, + "MainPress": { + "name": "PressSerb", + "description": "Pressione Serbatoio", + "memAddr": "40003", + "tipoMem": "Real", + "index": 3, + "size": 2, + "func": "MAX", + "period": 60, + "factor": 1, + "minVal": 0, + "maxVal": 25 + }, + "PressBH": { + "name": "PBH", + "description": "Pressione media all’interno dell’accumulo GNC (pacco bombole) di alta pressione", + "memAddr": "40019", + "tipoMem": "Real", + "index": 19, + "size": 2, + "func": "MAX", + "period": 60, + "factor": 1, + "minVal": 0, + "maxVal": 400 + }, + "PressBL": { + "name": "PBM", + "description": "Pressione media all’interno dell’accumulo GNC (pacco bombole) di media pressione", + "memAddr": "40021", + "tipoMem": "Real", + "index": 21, + "size": 2, + "func": "MAX", + "period": 60, + "factor": 1, + "minVal": 0, + "maxVal": 400 + }, + //"TE2A": { + // "name": "TE2A", + // "description": "Temperatura Controllo Tenute Pompa A", + // "memAddr": "DB85.DBB0", + // "tipoMem": "Real", + // "index": 0, + // "size": 4, + // "func": "MAX", + // "period": 60, + // "factor": 1 + //}, + //"TE1A": { + // "name": "TE1A", + // "description": "Temperatura Raffreddamento Pompa A", + // "memAddr": "DB85.DBB4", + // "tipoMem": "Real", + // "index": 4, + // "size": 4, + // "func": "MAX", + // "period": 60, + // "factor": 1 + //}, + //"TE3A": { + // "name": "TE3A", + // "description": "Temperatura Cavitazione Pompa A", + // "memAddr": "DB85.DBB8", + // "tipoMem": "Real", + // "index": 8, + // "size": 4, + // "func": "MAX", + // "period": 60, + // "factor": 1 + //}, + //"Temp01": { + // "name": "TE04", + // "description": "Temperatura Torcia Aria Fredda", + // "memAddr": "DB85.DBB12", + // "tipoMem": "Real", + // "index": 12, + // "size": 4, + // "func": "MAX", + // "period": 60, + // "factor": 1 + //}, + //"Temp02": { + // "name": "TT17", + // "description": "Temperatura Spurgo Torcia Serbatoio", + // "memAddr": "DB85.DBB36", + // "tipoMem": "Real", + // "index": 36, + // "size": 4, + // "func": "MAX", + // "period": 60, + // "factor": 1 + //}, + //"TE06": { + // "name": "TE06", + // "description": "Temperatura Uscita Vaporizzatore", + // "memAddr": "DB85.DBB40", + // "tipoMem": "Real", + // "index": 40, + // "size": 4, + // "func": "MAX", + // "period": 60, + // "factor": 1 + //}, + //"TE05": { + // "name": "TE05", + // "description": "Temperatura Carica Fredda", + // "memAddr": "DB85.DBB60", + // "tipoMem": "Real", + // "index": 60, + // "size": 4, + // "func": "MAX", + // "period": 60, + // "factor": 1 + //}, + //"TE2B ": { + // "name": "TE2B", + // "description": "Temperatura Controllo Tenute Pompa B", + // "memAddr": "DB85.DBB64", + // "tipoMem": "Real", + // "index": 64, + // "size": 4, + // "func": "MAX", + // "period": 60, + // "factor": 1 + //}, + //"TE1B ": { + // "name": "TE1B", + // "description": "Temperatura Raffreddamento Pompa B", + // "memAddr": "DB85.DBB68", + // "tipoMem": "Real", + // "index": 68, + // "size": 4, + // "func": "MAX", + // "period": 60, + // "factor": 1 + //}, + //"TE3B": { + // "name": "TE3B", + // "description": "Temperatura Cavitazione Pompa B", + // "memAddr": "DB85.DBB72", + // "tipoMem": "Real", + // "index": 72, + // "size": 4, + // "func": "MAX", + // "period": 60, + // "factor": 1 + //}, + //"PressH": { + // "name": "PT300A", + // "description": "Alta Pressione", + // "memAddr": "DB85.DBB120", + // "tipoMem": "Real", + // "index": 120, + // "size": 4, + // "func": "MAX", + // "period": 60, + // "factor": 1 + //}, + //"PressM": { + // "name": "PT300M", + // "description": "Media Pressione", + // "memAddr": "DB85.DBB124", + // "tipoMem": "Real", + // "index": 124, + // "size": 4, + // "func": "MAX", + // "period": 60, + // "factor": 1 + //}, + //"LivelloPerc": { + // "name": "LT15%", + // "description": "Livello Serbatorio %", + // "memAddr": "DB85.DBB148", + // "tipoMem": "Real", + // "index": 148, + // "size": 4, + // "func": "MAX", + // "period": 60, + // "factor": 1 + //}, + //"MinTemp01": { + // "name": "MinTempTE04", + // "description": "Minima Temperatura Linea Sfiato Gas TE04", + // "memAddr": "DB85.DBB152", + // "tipoMem": "Real", + // "index": 152, + // "size": 4, + // "func": "MAX", + // "period": 60, + // "factor": 1 + //}, + //"MinTemp02": { + // "name": "MinTempTT17", + // "description": "Minima Temperatura Linea Sfiato Gas Torcia Serbatoio TT17", + // "memAddr": "DB85.DBB156", + // "tipoMem": "Real", + // "index": 156, + // "size": 4, + // "func": "MAX", + // "period": 60, + // "factor": 1 + //} + } +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/PIZ04_alarm.json b/IOB-WIN-NEXT/DATA/CONF/PIZ04_alarm.json new file mode 100644 index 00000000..2b51df57 --- /dev/null +++ b/IOB-WIN-NEXT/DATA/CONF/PIZ04_alarm.json @@ -0,0 +1,125 @@ +[ + //{ + // "description": "Allarmi Impianto", + // "tipoMem": "Boolean", + // "memAddr": "DB85.DBB232", + // "index": 232, + // "size": 6, + // "messages": [ + // "Emergenza Non Ripristinata", + // "Emergenza QE Intervenuta", + // "Emergenza Puls. Dispencer B Invervenuta", + // "Emergenza Puls. Dispencer A Invervenuta", + // "Stato Interruttore Erogatore Liquido B", + // "Allarme Controllo Tensione di Rete", + // "Allarme Controllo Tensione Antincendio", + // "Stato Interruttore Erogatore Liquido A", + // "Stato Sezionatore Generale", + // "Stato Interruttore Protezione SPD", + // "Stato Interruttore Sirena e Rotoalarm", + // "Stato Interruttore Luci Emergenza", + // "Stato Interruttore Pompa PC1A", + // "Stato Interruttore Pompa PC1B", + // "Stato Interruttore Pompa Sommersa C", + // "Stato Termica Boil-Off", + // "##234.0", + // "Preallarme Centralina Metano", + // "Allarme Centralina Metano", + // "Emergenza Puls. Dispencer C Invervenuta", + // "Mancaza Pressione Aria", + // "Minima Temperatura Linea Sfiato Gas TE04", + // "Minima Temperatura Linea Sfiato Gas Torcia Serbatoio TT17", + // "Massima Temperatura Linea Sfiato Gas Torcia Serbatoio TT17", + // "Almeno Un Emergenza Intervenuta", + // "Arresto Operativo da PT1(predisposizione)", + // "Stato Interruttore Alimentazione Punto Zero", + // "##234.11", + // "##234.12", + // "##234.13", + // "##234.14", + // "Configurazione Incongruente", + // "Pulsante Emergenza 2 SB17.3A Premuto", + // "Pulsante Emergenza 1 SB17.3B Premuto", + // "Pulsante Emergenza SB17.3C Premuto", + // "Pulsante Emergenza 3 SB17.5 Premuto", + // "Pulsante Emergenza 4 SB17.7 Premuto", + // "##236.5", + // "##236.6", + // "##236.7", + // "GT_TE2A", + // "GT_TE1A", + // "GT_TE3A", + // "GT_TE04", + // "GT_LT15", + // "GT_PT01", + // "GT_PT300R", + // "GT_PT16" + // ] + //}, + //{ + // "description": "Allarmi Serbatoio", + // "tipoMem": "Boolean", + // "memAddr": "DB85.DBB248", + // "index": 248, + // "size": 2, + // "messages": [ + // "Serbatoio Troppo Pieno", + // "Serbatoio Pieno_HH", + // "Serbatoio Pieno_H", + // "Serbatoio Vuoto_LL", + // "H Pressione Serbatoio", + // "HH Pressione Serbatoio", + // "LL Temperatura Ingresso BoilOff TE08", + // "Minima Pressione Serbatoio per Partenza Pompe", + // "Timeout Apertura Valvola PV1", + // "Timeout Chiusura Valvola PV1", + // "Timeout Apertura Valvola PV70", + // "Timeout Chiusura Valvola PV70", + // "##248.12", + // "##248.13", + // "##248.14", + // "##248.15" + // ] + //}, + //{ + // "description": "Allarmi Pompa Alta Pressione A", + // "tipoMem": "Boolean", + // "memAddr": "DB85.DBB252", + // "index": 252, + // "size": 4, + // "messages": [ + // "Ritardo Avvio Pompa PC1B", + // "##252.1", + // "Temperatura Freddo TE1B NON Raggiunta", + // "HH Temperatura Cavitazione TE3B", + // "Allarme Temperatura Tenute Pompa TE2B", + // "LL Temperatura Ingresso Stoccaggio TE06", + // "Allarme Temperatura Ingresso Stoccaggio TE07", + // "Aumento Pressione PT01", + // "##Max Pressione PT01", + // "##256.9", + // "##256.10", + // "##256.11", + // "##256.12", + // "##256.13", + // "##256.14", + // "##256.15", + // "Timeout Apertura PV3B", + // "Timeout Apertura PV5B", + // "Timeout Apertura PV6B", + // "Timeout Apertura PV7", + // "##258.4", + // "##258.5", + // "##258.6", + // "##258.7", + // "##258.8", + // "##258.9", + // "##258.10", + // "##258.11", + // "##258.12", + // "##258.13", + // "##258.14", + // "##258.15" + // ] + //} +] \ No newline at end of file diff --git a/IOB-WIN-NEXT/DATA/CONF/VL22.ini b/IOB-WIN-NEXT/DATA/CONF/VL22.ini index 567d968e..ea000363 100644 --- a/IOB-WIN-NEXT/DATA/CONF/VL22.ini +++ b/IOB-WIN-NEXT/DATA/CONF/VL22.ini @@ -67,6 +67,8 @@ MAX_SEND_PZC_BLOCK=100 ;GESTIONE DATI DYN ENABLE_DYN_DATA=TRUE FORCE_DYN_DATA=TRUE +; gestione scrittura string/char[]: true = string / false = char[] +WRITE_PRE=TRUE USE_NEW_EXE_TASK=TRUE ; conf parametri memoria READ/WRITE diff --git a/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj b/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj index ffe9e62b..ddcbb005 100644 --- a/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj +++ b/IOB-WIN-NEXT/IOB-WIN-NEXT.csproj @@ -83,12 +83,15 @@ ..\CncLib\ExtLib\CndexLinkDotNet.dll + + ..\packages\EasyModbusTCP.5.6.0\lib\net40\EasyModbus.dll + False ExtLib\krcc.dll - - ..\packages\MapoSDK.6.13.2105.1421\lib\net40\MapoSDK.dll + + ..\packages\MapoSDK.6.14.2109.2809\lib\net40\MapoSDK.dll ..\packages\MTConnect.NET.2.9.1.28314\lib\net40\MTConnect-NET.dll @@ -97,7 +100,7 @@ ..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll - ..\packages\NLog.4.7.9\lib\net45\NLog.dll + ..\packages\NLog.4.7.11\lib\net45\NLog.dll ..\packages\OmronFinsTCP.Net.3.0.0.0\lib\net40\OmronFinsTCP.Net.dll @@ -172,6 +175,8 @@ + + @@ -347,12 +352,21 @@ Always + + Always + + + Always + Always Always + + Always + Always diff --git a/IOB-WIN-NEXT/IobGeneric.cs b/IOB-WIN-NEXT/IobGeneric.cs index 52ed95d7..054dde52 100644 --- a/IOB-WIN-NEXT/IobGeneric.cs +++ b/IOB-WIN-NEXT/IobGeneric.cs @@ -536,8 +536,17 @@ namespace IOB_WIN_NEXT address = IPAddress.Loopback; int maxRetry = maxPingRetry + 1; int numRetry = 1; ; - string ipAdrr = cIobConf.serverData.MPIP.Replace($"{cIobConf.serverData.TRANSP}://", ""); - IPAddress.TryParse(ipAdrr, out address); + string ipAddr = cIobConf.serverData.MPIP.Replace($"{cIobConf.serverData.TRANSP}://", ""); + IPAddress.TryParse(ipAddr, out address); + // se null --> provo DNS... + if (address == null) + { + var rawAddresses = Dns.GetHostAddresses(ipAddr); + if (rawAddresses.Length > 0) + { + address = rawAddresses[0]; + } + } try { // se != null --> uso address... @@ -557,12 +566,12 @@ namespace IOB_WIN_NEXT // se ho timeout riprovo... while (reply.Status != IPStatus.Success && numRetry < maxRetry) { - lgInfo($"Ping KO | reply: {reply.Status} --> retry"); + lgInfo($"Server Ping KO | reply: {reply.Status} --> retry"); reply = pingSender.Send(address, pingServerMsTimeout * numRetry / 2); numRetry++; if (reply.Status == IPStatus.Success) { - lgInfo("PING OK!"); + lgInfo("Server PING OK!"); break; } } @@ -4072,7 +4081,8 @@ namespace IOB_WIN_NEXT { } /// - /// Effettua processing del recupero delle speed (RPM, feedrate) degli assi + /// Effettua processing del recupero dei valori dinamici: + /// es: speed (RPM, feedrate) degli assi, valori pressioni, temeprature /// public void processDynData() { diff --git a/IOB-WIN-NEXT/IobModbusTCP.cs b/IOB-WIN-NEXT/IobModbusTCP.cs new file mode 100644 index 00000000..01ba2870 --- /dev/null +++ b/IOB-WIN-NEXT/IobModbusTCP.cs @@ -0,0 +1,1246 @@ +using EasyModbus; +using IOB_UT_NEXT; +using MapoSDK; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Net.NetworkInformation; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace IOB_WIN_NEXT +{ + /* -------------------------------------------------------------------------------- + * Controlli ModBusTCP COMECA + * - protocollo ModBus TCP + * + * -------------------------------------------------------------------------------- */ + + public class IobModbusTCP : IobGeneric + { + #region Protected Fields + + protected ModbusClient currPLC; + + /// + /// Ultimo controllo ping x evitare ping flood... + /// + protected DateTime lastPingConn = DateTime.Now.AddMinutes(-10); + + /// + /// Esito ultimo ping + /// + protected bool lastPingOk = false; + + /// + /// Setup blocchi memorie read (indirizzo inizio, size) + /// + protected Dictionary memSetR = new Dictionary(); + + /// + /// Setup blocchi memorie write (indirizzo inizio, size) + /// + protected Dictionary memSetW = new Dictionary(); + + /// + /// parametri di connessione + /// + protected connParamModBusTCP parametri; + + /// + /// Oggetto cronometro x test vari... + /// + protected Stopwatch sw = new Stopwatch(); + + #endregion Protected Fields + + #region Public Constructors + + /// Classe base con i metodi x ModBusTCP + /// + /// + /// + public IobModbusTCP(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) + { + lgInfo("NEW IOB ModBus TCP"); + setupMemBlocks(); + memMap = new plcMemMap(); + if (IOBConf != null) + { + // gestione invio ritardato contapezzi + pzCountDelay = utils.CRI("pzCountDelay"); + lastPzCountSend = DateTime.Now; + lastWarnODL = DateTime.Now; + // inizializzo parametri... + parametri = new connParamModBusTCP() + { + ipAdrr = "127.0.0.1", + port = 502, + pingMsTimeout = IOBConf.pingMsTimeout, + memAddrRead = "40001", + memAddrWrite = "41001", + memSizeRead = 0, + memSizeWrite = 0 + }; + setParamPlc(); + + // salvo info su conf IOB... + string iobConfSer = ""; + try + { + iobConfSer = JsonConvert.SerializeObject(IOBConf, Formatting.Indented); + } + catch + { } + // finito! + lgInfo($"Init IOB, con {iobConfSer}"); + } + else + { + lgError("Impossibile avviare, IOBConf nullo/non valido!"); + } + } + + #endregion Public Constructors + + #region Protected Properties + + /// + /// Dizionario delle ultime operazioni di scrittura per OGNI memoria (in modo che fa log ogni x sec...) + /// + protected Dictionary lastMemWrite { get; set; } = new Dictionary(); + + #endregion Protected Properties + + #region Private Methods + + private static int getScaledInt(dataConf currMem) + { + int valInt; + // prima faccio eventuale fattore di scala... + int.TryParse(currMem.value, out valInt); + if (currMem.factor > 1) + { + valInt = valInt * currMem.factor; + } + + return valInt; + } + + private static uint getScaledUInt(dataConf currMem) + { + uint valUInt; + // prima faccio eventuale fattore di scala... + uint.TryParse(currMem.value, out valUInt); + if (currMem.factor > 1) + { + valUInt = valUInt * (uint)currMem.factor; + } + + return valUInt; + } + + /// + /// Verifica SE sia il caso di fare il log della memoria indicata + /// + /// + /// + private void maybeLogWrite(string memAddrWrite, string logValue) + { + bool doWrite = true; + DateTime adesso = DateTime.Now; + if (!lastMemWrite.ContainsKey(memAddrWrite)) + { + lastMemWrite.Add(memAddrWrite, adesso.AddMinutes(-1)); + } + // ora mi leggo valore ultimas crittura e confronto con adesso + try + { + doWrite = (lastMemWrite[memAddrWrite].AddSeconds(vetoSeconds) < adesso); + } + catch (Exception exc) + { + lgError($"Eccezione in maybeLogWrite{Environment.NewLine}{exc}"); + } + // se encessario --> LOG! + if (doWrite) + { + lgInfo(logValue); + lastMemWrite[memAddrWrite] = adesso; + } + } + + #endregion Private Methods + + #region Protected Methods + + /// + /// Decodifica il resto dell'area x i dati accessori (allarmi, ...) + /// + protected virtual void decodeOtherData() + { + } + + /// + /// Effettua decodifica aree memoria alla bitmap usata x MAPO/GWMS + /// - per lo scopo specifico IN REALTA' non conta lo stato macchina.... ma lo inviamo lo stesso + /// + protected virtual void decodeToBaseBitmap() + { + // init a zero... + B_input = 0; + } + + /// + /// Override metodo x scrittura parametri su PLC + /// + /// + protected override void plcWriteParams(ref List updatedPar) + { +#if false + dataConf currMem = null; + int byteSize = 0; + byte[] MemBlock = new byte[1]; + string memAddrWrite = ""; + bool fatto = false; + string serObj = ""; + if (updatedPar != null) + { + // controllo i parametri... ne gestisco 4... + foreach (var item in updatedPar) + { + try + { + memAddrWrite = ""; + int valInt = 0; + uint valUInt = 0; + // cerco in area memMapWrite... + if (memMap.mMapWrite.ContainsKey(item.uid)) + { + // recupero! + currMem = memMap.mMapWrite[item.uid]; + byteSize = currMem.size; + memAddrWrite = currMem.memAddr; + MemBlock = new byte[byteSize]; + // faccio preliminarmente upsertKey... + upsertKey(currMem.name, currMem.value); + serObj = JsonConvert.SerializeObject(item, Formatting.Indented); + lgInfo($"Inizio processing plcWriteParams per {currMem.name} | valore richiesto {currMem.value}{Environment.NewLine}---------------UPDATED PARAM---------------{Environment.NewLine}{serObj}{Environment.NewLine}---------------"); + serObj = JsonConvert.SerializeObject(currMem, Formatting.Indented); + lgInfo($"---------------MEMORY CONTENT---------------{Environment.NewLine}{serObj}{Environment.NewLine}---------------"); + switch (currMem.tipoMem) + { + case plcDataType.Boolean: + break; + + case plcDataType.Int: + valInt = getScaledInt(currMem); + saveIntOnMemBlock(ref MemBlock, 0, valInt.ToString()); + break; + + case plcDataType.DInt: + valInt = getScaledInt(currMem); + saveDIntOnMemBlock(ref MemBlock, 0, valInt.ToString()); + break; + + case plcDataType.Word: + valUInt = getScaledUInt(currMem); + saveWordOnMemBlock(ref MemBlock, 0, valInt.ToString()); + break; + + case plcDataType.DWord: + valUInt = getScaledUInt(currMem); + saveDWordOnMemBlock(ref MemBlock, 0, valInt.ToString()); + break; + + case plcDataType.Real: + saveRealOnMemBlock(ref MemBlock, 0, currMem.value); + break; + + case plcDataType.String: + // se ho writePre --> "allungo" di 2 la dimensione della stringa x MemBlock... + if (writePre) + { + MemBlock = new byte[byteSize + 2]; + } + saveStringOnMemBlock(ref MemBlock, 0, currMem.size, currMem.value); + break; + + default: + break; + } + lgInfo($"---------------MemBlock data---------------{Environment.NewLine}{BitConverter.ToString(MemBlock)}{Environment.NewLine}--------------- END data ---------------"); + if (!string.IsNullOrEmpty(memAddrWrite)) + { + // scrivo su ModBusTCP + fatto = S7WriteBB(ref MemBlock, memAddrWrite); + // se fatto --> aggiorno! + if (fatto) + { + item.value = item.reqValue; + item.reqValue = ""; + item.lastRead = DateTime.Now; + } + // se configurato faccio verifica write... + if (getOptPar("WRITE_CHECK") == "TRUE") + { + byte[] MemBlockRead = new byte[MemBlock.Length]; + S7ReadBB(ref MemBlockRead, memAddrWrite, MemBlock.Length); + // se non corrispondessero loggo! + if (!MemBlock.SequenceEqual(MemBlockRead)) + { + lgError($"Errore: mancata corrispondenza tra dati scritti e letti:{Environment.NewLine}Write: {BitConverter.ToString(MemBlock)}{Environment.NewLine}read: {BitConverter.ToString(MemBlockRead)}"); + } + else + { + lgInfo($"Scrittura corretta: {BitConverter.ToString(MemBlockRead)}"); + } + } + } + else + { + lgInfo($"Errore: memAddrWrite vuoto!"); + } + } + else + { + lgInfo($"Errore uid non trovato in area write memory: {item.uid}, ci sono {memMap.mMapWrite.Count} in area write"); + } + } + catch (Exception exc) + { + lgError($"Eccezione in fase di plcWriteParams per item {item.uid} con valore {item.value}{Environment.NewLine}{exc}"); + } + } + } +#endif + } + + /// + /// Imposto parametri PLC + /// + protected override void setParamPlc() + { + // Creo oggetto connessione NC + parentForm.commPlcActive = true; + lgInfo($"Start init Adapter ModBus TCP all'IP {cIobConf.cncIpAddr} | port: {cIobConf.cncPort} | --> IOB {cIobConf.codIOB}"); + // SE è necessario refresh... + if (needRefresh) + { + lgInfo("Refreshing connection..."); + if (parametri != null) + { + try + { + parametri.ipAdrr = cIobConf.cncIpAddr; + parametri.port = int.Parse(cIobConf.cncPort); + // leggo file init... + lgInfo("Reading ini file..."); + IniFile fIni = new IniFile(cIobConf.iniFileName); + // ora leggo valori speciali + parametri.memAddrRead = fIni.ReadString("MEMORY", "ADDR_READ", ""); + parametri.memAddrWrite = fIni.ReadString("MEMORY", "ADDR_WRITE", ""); + parametri.memSizeRead = fIni.ReadInteger("MEMORY", "SIZE_READ", 0); + parametri.memSizeWrite = fIni.ReadInteger("MEMORY", "SIZE_WRITE", 0); + // salvo vettori memoria... + lgInfo("Set RawInput dimensions..."); + RawInput = new byte[parametri.memSizeRead]; + RawOutput = new byte[parametri.memSizeWrite]; + // salvo parametri conn! + lgInfo(string.Format("Parametri memoria: memAddrRead: {0} | memAddrWrite: {1} | memSizeRead: {2} | memSizeWrite: {3}", parametri.memAddrRead, parametri.memAddrWrite, parametri.memSizeRead, parametri.memSizeWrite)); + } + catch (Exception exc) + { + lgError(exc, "Errore in parse parametri da IOBConf"); + } + // ora tento avvio PLC... SE PING OK... + IPStatus esitoPing = testPingMachine; + if (esitoPing == IPStatus.Success) + { + needRefresh = false; + try + { + //Ip-Address and Port of Modbus-TCP-Server + currPLC = new ModbusClient(parametri.ipAdrr, parametri.port); + + // disconnetto e connetto... + if (isVerboseLog) + { + lgInfo("ModBus TCP: tryDisconnect"); + } + tryDisconnect(); + + // lo ripeto x evitare che ci sia un loop... e tryConnect richiami la procedura corrente... + needRefresh = false; + lgInfo("ModBus TCP: tryConnect"); + tryConnect(); + lgInfo("End init Adapter ModBusTCP"); + if (isVerboseLog) + { + lgInfo("ModBus TCP CONNESSIONE AVVENUTA"); + } + } + catch (Exception exc) + { + lgError(exc, "Errore in INIT ModBusTCP"); + } + } + else + { + lgError($"Errore in ping: esito {esitoPing}"); + } + parentForm.commPlcActive = false; + // carico conf vettore memoria... + loadMemConf(); + bool enableByApp = utils.CRB("enableContapezzi"); + bool enableByIob = (getOptPar("ENABLE_PZCOUNT") == "TRUE"); + bool disableByIob = (getOptPar("DISABLE_PZCOUNT") == "TRUE"); + if ((enableByApp || enableByIob) && !(disableByIob)) + { + lgInfo("ModBus TCP: inizio gestione contapezzi"); + try + { + // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area) + if (cIobConf.optPar.Count > 0 && !string.IsNullOrWhiteSpace(getOptPar("PZCOUNT_MODE"))) + { + if (getOptPar("PZCOUNT_MODE").StartsWith("STD")) + { + lgInfo("Init contapezzi ModBusTCP: pzCntReload(true)"); + pzCntReload(true); + // refresh associazione Macchina - IOB + sendM2IOB(); + // per adesso imposto lettura PLC == contapezzi (poi farà vera lettura...) + contapezziPLC = contapezziIOB; + } + else + { + contapezziIOB = 0; + lgInfo("Contapezzi STD disabilitato: modalità {0}", getOptPar("PZCOUNT_MODE")); + } + } + else + { + contapezziIOB = 0; + lgInfo("Parametro mancante PZCOUNT_MODE"); + } + } + catch (Exception exc) + { + lgError(exc, "Errore in contapezzi ModBusTCP"); + } + } + } + else + { + lgError("Parametri null!"); + } + } + } + + /// + /// effettua il setup dei memblock da gestire (NON leggo intera memoria ma tanti blocchi...) + /// + protected virtual void setupMemBlocks() + { } + + /// + /// Test connessione CNC + /// + /// + protected bool testCncConn() + { + bool answ = currPLC.Connected; + if (!answ) + { + // riduco i controlli ping.. li faccio solo ogni 5 ping period se precedente positivo... + DateTime adesso = DateTime.Now; + if (lastPingOk && adesso.Subtract(lastPingConn).TotalMilliseconds < 5 * parametri.pingMsTimeout) + { + answ = lastPingOk; + } + else + { + IPStatus pingStatus = testPingMachine; + + // se non ok riprovo 1 volta dopo attesa + if (pingStatus != IPStatus.Success) + { + Thread.Sleep(2 * cIobConf.pingMsTimeout); + pingStatus = testPingMachine; + } + // se non passa ancora errore! + if (pingStatus != IPStatus.Success) + { + lgError($"Errore in testCncConn | reply Status {pingStatus} | IP: {parametri.ipAdrr} | T.Out: {parametri.pingMsTimeout}ms"); + } + // se passa il ping faccio il resto... + else + { + if (!currPLC.Connected) + { + currPLC.Connect(); + } + + if (!currPLC.Available(500)) + { + lgError($"PLC ModBus NON disponibile: {currPLC.IPAddress} | {currPLC.Port}"); + } + else + { + if (!currPLC.Connected) + { + lgError($"PLC ModBus NON connesso:{currPLC.IPAddress} | {currPLC.Port}"); + } + else + { + // tutto ok + parentForm.updateComStats("Connection OK"); + answ = true; + } + } + } + // salvo stato ping + lastPingConn = adesso; + } + lastPingOk = answ; + } + + return answ; + } + + #endregion Protected Methods + + #region Public Methods + + /// + /// Metodo dispose x il currPLC contenuto + /// + public void Dispose() + { + currPLC.Disconnect(); + } + + /// + /// Processo i task richiesti e li elimino dalla coda 1:1 + /// + /// + public override Dictionary executeTasks(Dictionary task2exe) + { + lgInfo($"Chiamata executeTasks specifica ModBus TCP: {task2exe.Count} task ricevuti"); + // Verificare il protocollo: dovrebeb togliere SOLO i task eseguiti... + Dictionary taskDone = new Dictionary(); + return taskDone; + } + + /// + /// decodifica tipo indirizzo dal codice + /// + /// + /// + public modBusAddrType getAddrType(string memAddr) + { + modBusAddrType answ = modBusAddrType.Coil; + // leggo prima cifra... + answ = (modBusAddrType)Enum.Parse(typeof(modBusAddrType), memAddr.Substring(0, 1)); + return answ; + } + + /// + /// Recupero dati dinamici... + /// ATTENZIONE factor usato come FONDOSCALA.... quindi 28'000 --> MOLTIPLICO per 28'000 + /// + public override Dictionary getDynData() + { + // valore non presente in vers default... se gestito fare override + Dictionary outVal = new Dictionary(); + if (utils.CRB("enableTSVC")) + { + // processing SOLO SE ho in memoria abbastanza dati... + if (RawInput.Length < parametri.memSizeRead) + { + lgError($"Impossibile processare getDynData x ModBus TCP PLC, vettore memoria troppo piccolo: {RawInput.Length} byte / {parametri.memSizeRead} byte presenti/richiesti)"); + } + else + { + try + { + // processo x ogni valore configurato... + if (memMap.mMapRead.Count > 0) + { + // inizializzo i valori + bool[] listBool = new bool[1]; + int[] listInt = new int[2]; + double valore = 0; + // procedo x ogni valore configurato...... + foreach (var item in memMap.mMapRead) + { + // in primis DEVO determinare di quale TIPO di valore ho bisogno... dalla PRIMA cifra di memAddr... + modBusAddrType memAddrType = getAddrType(item.Value.memAddr); + // in base al tipo leggo array... + switch (memAddrType) + { + case modBusAddrType.Coil: + listBool = readCoil(item.Value.index, item.Value.size); + valore = listBool[0] ? 1 : 0; + break; + + case modBusAddrType.DiscreteInput: + listBool = readDiscrInputs(item.Value.index, item.Value.size); + valore = listBool[0] ? 1 : 0; + break; + + case modBusAddrType.InputRegister: + listInt = readInputReg(item.Value.index, item.Value.size); + //verifico se sia INT o real x convertire... + switch (item.Value.tipoMem) + { + case plcDataType.Real: + if (item.Value.size == 4) + { + valore = ModbusClient.ConvertRegistersToDouble(listInt) * item.Value.factor; + } + else if (item.Value.size == 2) + { + valore = ModbusClient.ConvertRegistersToFloat(listInt) * item.Value.factor; + } + break; + + case plcDataType.Int: + default: + if (item.Value.size == 4) + { + valore = ModbusClient.ConvertRegistersToLong(listInt) * item.Value.factor; + } + else if (item.Value.size == 2) + { + valore = ModbusClient.ConvertRegistersToInt(listInt) * item.Value.factor; + } + break; + } + break; + + case modBusAddrType.HoldingRegister: + listInt = readHoldReg(item.Value.index - 1, item.Value.size); + //verifico se sia INT o real x convertire... + switch (item.Value.tipoMem) + { + case plcDataType.Real: + if (item.Value.size == 4) + { + valore = ModbusClient.ConvertRegistersToDouble(listInt) * item.Value.factor; + } + else if (item.Value.size == 2) + { + valore = ModbusClient.ConvertRegistersToFloat(listInt) * item.Value.factor; + } + break; + + case plcDataType.Int: + default: + if (item.Value.size == 4) + { + valore = ModbusClient.ConvertRegistersToLong(listInt) * item.Value.factor; + } + else if (item.Value.size == 2) + { + valore = ModbusClient.ConvertRegistersToInt(listInt) * item.Value.factor; + } + break; + } + break; + + default: + break; + } + saveValue(ref outVal, valore, item.Key); + } + } + else + { + lgInfo($"getDynData: {memMap.mMapRead.Count} record in mMapRead"); + } + } + catch (Exception exc) + { + lgError(exc, "Errore in getDynData x ModBus TCP PLC"); + } + } + } + else + { + lgInfo($"Non processo getDynData: enableTSVC = false"); + } + if (periodicLog || outVal.Count > 0) + { + lgInfo($"Esito getDynData: {outVal.Count} valori VALIDI in outVal"); + } + return outVal; + } + + /// + /// Lettura valori Coils (1...) + /// + /// + /// + /// + public bool[] readCoil(int startAddr, int qty) + { + bool[] answ = new bool[1]; + if (currPLC.Connected) + { + answ = currPLC.ReadCoils(startAddr, qty); + } + return answ; + } + + /// + /// Lettura valori DiscreteInputs (2...) + /// + /// + /// + /// + public bool[] readDiscrInputs(int startAddr, int qty) + { + bool[] answ = new bool[1]; + if (currPLC.Connected) + { + answ = currPLC.ReadDiscreteInputs(startAddr, qty); + } + return answ; + } + + /// + /// Lettura valori Holding Register (3...) + /// + /// + /// + /// + public int[] readHoldReg(int startAddr, int qty) + { + int[] answ = new int[2]; + if (currPLC.Connected) + { + answ = currPLC.ReadHoldingRegisters(startAddr, qty); + } + return answ; + } + + /// + /// Lettura valori Input Register (4...) + /// + /// + /// + /// + public int[] readInputReg(int startAddr, int qty) + { + int[] answ = new int[2]; + if (currPLC.Connected) + { + answ = currPLC.ReadInputRegisters(startAddr, qty); + } + return answ; + } + + /// + /// Effettua lettura semafori principale + /// Parametri da aggiornare x display in form + /// + public override void readSemafori(ref newDisplayData currDispData) + { + base.readSemafori(ref currDispData); + byte[] MemBlock = new byte[2]; + try + { + currDispData.semIn = Semaforo.SV; + + if (verboseLog) + { + lgInfo("inizio read semafori"); + } + + //// ciclo a leggere TUTTI i blocchi di memoria impostati + //foreach (var item in memSetR) + //{ + // // leggo TUTTI i byte configurati... + // MemBlock = new byte[item.Value]; + // S7ReadBB(ref MemBlock, $"{item.Key}", item.Value); + // Buffer.BlockCopy(MemBlock, 0, RawInput, item.Key, item.Value); + //} + + //// leggo TUTTI i byte configurati... + //MemBlock = new byte[parametri.memSizeRead]; + //bool fatto = S7ReadBB(ref MemBlock); + //Buffer.BlockCopy(MemBlock, 0, RawInput, 0, parametri.memSizeRead); + if (verboseLog) + { + lgInfo(string.Format("RawInput[0]: {0}", utils.binaryForm(RawInput[0]))); + } + + // salvo il solo BYTE dell'input decifrando il semaforo... + decodeToBaseBitmap(); + decodeOtherData(); + // riporto bitmap... + reportRawInput(ref currDispData); + } + catch + { + currDispData.semIn = Semaforo.SR; + } + } + + /// + /// wrapper chiamata LETTURA in blocco MULTI BYTE dell'area read DI DEFAULT... + /// + /// + /// + public bool S7ReadBB(ref byte[] Value) + { + return S7ReadBB(ref Value, parametri.memAddrRead, parametri.memSizeRead); + } + + /// + /// wrapper chiamata LETTURA in blocco MULTI BYTE... + /// + /// MATRICE valori letti + /// Area memoria da leggere... + /// Numero byte da leggere + /// + public bool S7ReadBB(ref byte[] Value, string memAddrRead, int numByte) + { + bool answ = false; + if (Value != null) + { + sw.Restart(); + parentForm.commPlcActive = true; +#if false + if (testCncConn()) + { + // decodifico memoria... + memAreaSiemens memoria = new memAreaSiemens(memAddrRead); + Byte[] memByteRead = currPLC.ReadBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, numByte); + // copio in value, sennò do errore... + if (memByteRead.Length == Value.Length) + { + Value = memByteRead; + } + else + { + lgError($"Mismatch dimensione array memoria: indirizzo: {memAddrRead} | passato array di {Value.Length} byte, letti da S7 {memByteRead.Length} byte"); + } + string titolo = $"READ BLOCK MEM BYTE: {parametri.memAddrRead} --> {numByte} byte"; + if (verboseLog) + { + lgInfo(titolo); + } + + string contenuto = $"Contenuto area memoria acquisita{Environment.NewLine}"; + string byteVal = ""; + for (int i = 0; i < memByteRead.Length; i++) + { + byteVal = Convert.ToString(memByteRead[i], 2).PadLeft(8, '0'); + contenuto += string.Format("B{0:000}: {1} | {2}{3}", i, byteVal, memByteRead[i], Environment.NewLine); + } + // loggo lettura... + if (verboseLog) + { + lgInfo(contenuto); + } + } + else + { + connectionOk = false; + } +#endif + parentForm.commPlcActive = false; + sw.Stop(); + if (utils.CRB("recTime")) + { + TimingData.addResult(cIobConf.codIOB, string.Format("{0}|{1}", parametri.memAddrRead, numByte), sw.ElapsedTicks); + } + } + return answ; + } + + /// + /// wrapper chiamata LETTURA in blocco MULTI BYTE... default size a parametri.memSizeRead + /// + /// + /// Area memoria da leggere... + /// + public bool S7ReadBB(ref byte[] Value, string memAddrRead) + { + bool answ = false; + answ = S7ReadBB(ref Value, memAddrRead, parametri.memSizeRead); + return answ; + } + + /// + /// wrapper chiamata SCRITTURA in blocco MULTI BYTE, DI DEFAULT su area configurata x scrittura CONTINUA... + /// + /// + /// + public bool S7WriteBB(ref byte[] Value) + { + return S7WriteBB(ref Value, parametri.memAddrWrite); + } + + /// + /// Override scrittura in area DBB + /// + /// + /// + /// + public bool S7WriteBB(ref byte[] Value, string memAddrWrite) + { + bool answ = false; + if (Value == null) + { + lgError($"Errore in S7WriteBB: Value è null"); + } + else + { + if (string.IsNullOrEmpty(memAddrWrite)) + { + lgError($"Errore in S7WriteBB: memAddrWrite è vuoto"); + } + else + { + sw.Restart(); +#if false + if (testCncConn()) + { + try + { + // decodifico memoria... + memAreaSiemens memoria = new memAreaSiemens(memAddrWrite); + int numByte = Value.Length; + ErrorCode errorCode = currPLC.WriteBytes(DataType.DataBlock, memoria.DbNum, memoria.indiceMem, Value); + switch (errorCode) + { + case ErrorCode.NoError: + answ = true; + maybeLogWrite(memAddrWrite, $"S7WriteBB-01 Effettuata correttamente scrittura su PLC: MEMORIA {memAddrWrite} | numByte: {Value.Length} | ValOriginale: {Value}"); + break; + + case ErrorCode.WrongCPU_Type: + case ErrorCode.ConnectionError: + case ErrorCode.IPAddressNotAvailable: + case ErrorCode.WrongVarFormat: + case ErrorCode.WrongNumberReceivedBytes: + case ErrorCode.SendData: + case ErrorCode.ReadData: + case ErrorCode.WriteData: + lgError($"Errore in S7WriteBB su {memAddrWrite}: {errorCode.ToString()} | numByte: {Value.Length}| {Value.ValToBinString()}"); + answ = false; + break; + + default: + break; + } + } + catch (Exception exc) + { + lgError($"Eccezione in S7WriteBB | memAddrWrite {memAddrWrite} | numByte: {Value.Length}{Environment.NewLine}{exc}"); + } + } +#endif + sw.Stop(); + } + } + return answ; + } + + /// + /// Override scrittura in area DBB + /// + /// Valore byte[] da scrivere + /// Numero del DB (es 700 per DB700) + /// Indice interno al datablock del byte da cui partire + /// + public bool S7WriteBB(ref byte[] Value, int DbNum, int IndiceMem) + { + bool answ = false; + if (Value == null) + { + lgError($"Errore in S7WriteBB: Value è null"); + } + else + { + if (DbNum < 0 || IndiceMem < 0) + { + lgError($"Errore in S7WriteBB | DbNum: {DbNum} | IndiceMem: {IndiceMem}"); + } + else + { + sw.Restart(); +#if false + if (testCncConn()) + { + try + { + int numByte = Value.Length; + ErrorCode errorCode = currPLC.WriteBytes(DataType.DataBlock, DbNum, IndiceMem, Value); + switch (errorCode) + { + case ErrorCode.NoError: + lgInfo($"S7WriteBB-02 Effettuata correttamente scrittura su PLC: DB {DbNum}.{IndiceMem} | numByte: {Value.Length}| {Value.ValToBinString()}"); + break; + + case ErrorCode.WrongCPU_Type: + case ErrorCode.ConnectionError: + case ErrorCode.IPAddressNotAvailable: + case ErrorCode.WrongVarFormat: + case ErrorCode.WrongNumberReceivedBytes: + case ErrorCode.SendData: + case ErrorCode.ReadData: + case ErrorCode.WriteData: + lgError($"Errore in S7WriteBB su DB {DbNum}.{IndiceMem}: {errorCode.ToString()} | numByte: {Value.Length}| {Value.ValToBinString()}"); + break; + + default: + break; + } + answ = true; + } + catch (Exception exc) + { + lgError($"Eccezione in S7WriteBB: DbNum {DbNum}, IndiceMem: {IndiceMem}, numByte: {Value.Length}{Environment.NewLine}{exc}"); + } + } +#endif + sw.Stop(); + } + } + return answ; + } + + /// + /// Salvo in memblock il valore Int indicato con formattazione ModBus TCP + /// + /// Blocco memoria come byte[] dove scrivere + /// Posizione inizio scrittura + /// valore da scrivere + public void saveIntOnMemBlock(ref byte[] MemBlock, int startPos, string valore) + { + try + { + short valInt = 0; + short.TryParse(valore, out valInt); + byte[] strByte = S7.Net.Types.Int.ToByteArray(valInt); + int byteLen = 2; + Buffer.BlockCopy(strByte, 0, MemBlock, startPos, byteLen); + //var verifica = S7.Net.Types.String.FromByteArray(MemBlock); + } + catch (Exception exc) + { + lgError($"Errore in gestione scrittura INT {valore} alla posizione {startPos} byte{Environment.NewLine}{exc}"); + } + } + + /// + /// Salvo in memblock il valore Int indicato con formattazione ModBus TCP + /// + /// Blocco memoria come byte[] dove scrivere + /// Nome del parametro da recuperare da prodData x scrivere + /// Posizione inizio scrittura + public void saveIntOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos) + { + if (currProdData.ContainsKey(stringKey)) + { + try + { + string valore = currProdData[stringKey]; + saveIntOnMemBlock(ref MemBlock, startPos, valore); + } + catch (Exception exc) + { + lgError($"Errore in gestione scrittura INT {stringKey}{Environment.NewLine}{exc}"); + } + } + } + + /// + /// Salvo in memblock il valore stringa indicato con formattazione ModBus TCP + /// + /// Blocco memoria come byte[] dove scrivere + /// Posizione inizio scrittura + /// Valore scrivere + public void saveRealOnMemBlock(ref byte[] MemBlock, int startPos, string valore) + { + try + { + byte[] stringPar = new byte[2]; + + double valReal = 0; + double.TryParse(valore, out valReal); + byte[] strByte = S7.Net.Types.Double.ToByteArray(valReal); + int byteLen = 4; + Buffer.BlockCopy(strByte, 0, MemBlock, startPos, byteLen); + //var verifica = S7.Net.Types.String.FromByteArray(MemBlock); + } + catch (Exception exc) + { + lgError($"Errore in gestione scrittura REAL {valore} alla posizione {startPos} byte{Environment.NewLine}{exc}"); + } + } + + /// + /// Salvo in memblock il valore stringa indicato con formattazione ModBus TCP + /// + /// Blocco memoria come byte[] dove scrivere + /// Valore scrivere + /// Posizione inizio scrittura + public void saveRealOnMemBlock(ref byte[] MemBlock, string stringKey, int startPos) + { + if (currProdData.ContainsKey(stringKey)) + { + try + { + string valore = currProdData[stringKey]; + saveRealOnMemBlock(ref MemBlock, startPos, valore); + } + catch (Exception exc) + { + lgError($"Errore in gestione scrittura REAL {stringKey}{Environment.NewLine}{exc}"); + } + } + } + + /// + /// Effettua salvataggio in LUT del valore ricevuto (double) + /// + /// + /// + /// + /// + public void saveValue(ref Dictionary outVal, double valore, string chiave) + { + //check obj preliminare + if (outVal == null) + { + outVal = new Dictionary(); + } + bool scaduto = stackVal_TSVC(chiave, valore); + // recupero VC + valore = getVal_TSVC(chiave, scaduto); + if (scaduto) + { + outVal.Add(chiave, $"{valore}"); + } + LastTSVC[chiave] = valore; + } + + /// + /// Override connessione + /// + public override void tryConnect() + { + bool doLog = (verboseLog || periodicLog); + lgInfo("ModBus TCP: tryConnect step 01"); + if (!connectionOk) + { + // SE è necessario refresh... + if (needRefresh) + { + lgInfo("ModBus TCP: tryConnect step 02"); + + // reimporto parametri PLC se necessario... + setParamPlc(); + } + lgInfo("ModBus TCP: tryConnect step 03"); + + // controllo che il ping sia stato tentato almeno pingTestSec fa... + if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec")) + { + if (doLog) + { + lgInfo("ModBus TCP: ConnKO - tryConnect"); + } + lgInfo("ModBus TCP: tryConnect step 04"); + + // in primis salvo data ping... + lastPING = DateTime.Now; + // se passa il ping faccio il resto... + if (testPingMachine == IPStatus.Success) + { + string szStatusConnection = "ND"; + try + { + // ora provo connessione... + parentForm.commPlcActive = true; + currPLC.Connect(); + szStatusConnection = "OPEN"; + parentForm.commPlcActive = false; + connectionOk = currPLC.Connected; + lgInfo($"StatusConnection: {szStatusConnection}"); + // refresh stato allarmi!!! + if (connectionOk) + { + if (adpRunning) + { + lgInfo($"Connessione OK: {connectionOk} | adpRunning: {adpRunning}"); + } + } + else + { + lgError("Impossibile procedere, connessione mancante..."); + } + } + catch (Exception exc) + { + lgFatal($"Errore in TryConnect adapter ModBusTCP | szStatusConnection {szStatusConnection}{Environment.NewLine}{exc}"); + connectionOk = false; + needRefresh = true; + } + } + else + { + // loggo no risposta ping ... + connectionOk = false; + if (doLog) + { + lgInfo($"Attenzione: ModBusTCP controllo PING fallito per IP {cIobConf.cncIpAddr}"); + } + } + } + } + // se non è ancora connesso faccio procesisng memoria caso disconnesso... + if (!connectionOk) + { + // processo semafori ed invio... + processMemoryDiscon(); + } + } + + /// + /// Override disconnessione + /// + public override void tryDisconnect() + { + if (connectionOk) + { + string szStatusConnection = ""; + try + { + currPLC.Disconnect(); + connectionOk = false; + lgInfo(szStatusConnection); + lgInfo("Effettuata disconnessione adapter ModBusTCP!"); + } + catch (Exception exc) + { + lgFatal(exc, "Errore nella disconnessione dall'adapter ModBusTCP"); + } + } + else + { + lgError("IMPOSSIBILE effettuare disconnessione ModBusTCP: Connessione non disponibile..."); + } + } + + #endregion Public Methods + } +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/IobModbusTCPHam.cs b/IOB-WIN-NEXT/IobModbusTCPHam.cs new file mode 100644 index 00000000..f98c9cbb --- /dev/null +++ b/IOB-WIN-NEXT/IobModbusTCPHam.cs @@ -0,0 +1,421 @@ +using EasyModbus; +using IOB_UT_NEXT; +using MapoSDK; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.NetworkInformation; +using System.Text; +using System.Threading.Tasks; + +namespace IOB_WIN_NEXT +{ + /* -------------------------------------------------------------------------------- + * Controlli ModBusTCP COMECA + * - protocollo ModBus TCP HAM + * - specifico comportamento impianti HAM Pizzaferri + * + * STRUTTURA MEMORIA a banchi di byte, convertiti successivamente in bit/int/real: + * lettura: xxx byte, + * scrittura yyy byte + * G:\Drive condivisi\30_Clienti\Pizzaferri\Impianti\HAM + * * + * -------------------------------------------------------------------------------- */ + + public class IobModbusTCPHam : IobModbusTCP + { + #region Public Constructors + + /// Classe base con i metodi x ModBusTCP + /// + /// + /// + public IobModbusTCPHam(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf) + { + lgInfo("NEW IOB ModBus TCP HAM"); + + // provo lettura una prima volta i dati DYN + if (currPLC.Connected) + { + try + { + processDynData(); + } + catch (Exception exc) + { } + } + } + + #endregion Public Constructors + + #region Protected Properties + + protected bool hasAlarms + { + get + { + bool answ = false; +#if false + int numErrors = 0; + uint currStatus = 0; + if (alarmMaps != null) + { + // leggo a ciclo le aree degli allarmi CONFIGURATI, se ne trovo --> segnalo allarme... + foreach (var item in alarmMaps) + { + // in primis decremento eventuali blink... + item.decreaseBlinkCounter(); + // banchi in WORD (2 byte) --> scompongo + for (int i = 0; i < item.size / 2; i++) + { + currStatus = S7.Net.Types.Counter.FromByteArray(RawInput.Skip(item.index + 2 * i).Take(2).ToArray()); + // verifico SE sia variato... + if (item.isChanged(i, currStatus)) + { + numErrors++; + answ = true; + // registro gli allarmi attivi e trasmetto... + if (sendAlarmVariations(item.memAddr, i, item.alarmsState[i], currStatus)) + { + // se inviato --> salvo stato da current... + item.updStatusVal(i, currStatus); + } + } + } + } + } +#endif + + return answ; + } + } + + #endregion Protected Properties + + #region Private Methods + + private void testRead() + { + //Ip-Address and Port of Modbus-TCP-Server + //currPLC = new ModbusClient(cIobConf.cncIpAddr, 502); + ////Connect to Server + //currPLC.Connect(); + //modbusClient.WriteMultipleCoils(4, new bool[] { true, true, true, true, true, true, true, true, true, true }); //Write Coils starting with Address 5 + //bool[] readCoils = modbusClient.ReadCoils(9, 10); //Read 10 Coils from Server, starting with address 10 + //int[] readHoldingRegisters = currPLC.ReadHoldingRegisters(0, 34); //Read 10 Holding Registers from Server, starting with Address 1 + + int[] readHR1000 = currPLC.ReadHoldingRegisters(0, 100); //Read 10 Holding Registers from Server, starting with Address 1 + + //// Console Output + //for (int i = 0; i < readCoils.Length; i++) + // Console.WriteLine("Value of Coil " + (9 + i + 1) + " " + readCoils[i].ToString()); + + for (int i = 0; i < readHR1000.Length / 2; i++) + { + Console.WriteLine($"Value of HoldingRegister {(i)} | {readHR1000[i]} / {readHR1000[i + 1]}"); + int[] thisSet = new int[2]; + Array.Copy(readHR1000, i, thisSet, 0, 2); + Console.WriteLine($"Convert val HoldingRegister {(i)} | {ModbusClient.ConvertRegistersToFloat(thisSet)}"); + } + //Console.Write("Press any key to continue . . . "); + //Console.ReadKey(true); + } + + #endregion Private Methods + + #region Protected Methods + + /// + /// Effettua decodifica aree memoria alla bitmap usata x MAPO/GWMS + /// - per lo scopo specifico IN REALTA' non conta lo stato macchina.... ma lo inviamo lo stesso + /// + protected override void decodeToBaseBitmap() + { + // init a zero... + B_input = 0; + + /* ----------------------------------------------------- + * bitmap MAPO STANDARD + * B0: POWER_ON + * B1: RUN + * B2: pzCount + * B3: allarme + * + ----------------------------------------------------- */ + + var MemInt = new byte[2]; + + int byteSignals = 0; + // bit 0 (poweron) imposto a 1 SE connected... + if (currPLC.Connected) + { + byteSignals += (1 << 0); + } + + // processo dagli stati + gravi... + if (hasAlarms) + { + byteSignals += (1 << 3); + } + else + { + byteSignals += (1 << 1); + } + + // salvo! + B_input = byteSignals; + } + + /// + /// effettua il setup dei memblock da gestire (NON leggo intera memoria ma tanti blocchi...) + /// + protected override void setupMemBlocks() + { + // da calcolare... ora setup cablato... + memSetR.Add(1, 34); + } + + #endregion Protected Methods + + #region Public Methods + + /// + /// Processo i task richiesti e li elimino dalla coda 1:1 + /// + /// + public override Dictionary executeTasks(Dictionary task2exe) + { + lgInfo($"Chiamata executeTasks specifica ModBus TCP HAM: {task2exe.Count} task ricevuti"); + // Verificare il protocollo: dovrebeb togliere SOLO i task eseguiti... + Dictionary taskDone = new Dictionary(); + bool taskOk = false; + string taskVal = ""; + // inizio con 1 byte di default + byte[] MemBlock = new byte[1]; + string memAddrWrite = ""; + if (task2exe != null) + { +#if false + // cerco task specifici + foreach (var item in task2exe) + { + taskOk = false; + taskVal = ""; + // converto richiesta in enum... + taskType tName = taskType.nihil; + Enum.TryParse(item.Key, out tName); + // controllo sulla KEY + switch (tName) + { + case taskType.nihil: + case taskType.fixStopSetup: + case taskType.forceResetPzCount: + case taskType.forceSetPzCount: + case taskType.setProg: + case taskType.sendWatchDogMes2Plc: + taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC"; + break; + + case taskType.setPzComm: + case taskType.setArt: + case taskType.setComm: + saveProdData(item); + int byteSize = 0; + // recupero dati da memMap... altrimenti NULLA + if (memMap.mMapWrite.ContainsKey(item.Key)) + { + dataConf currMem = memMap.mMapWrite[item.Key]; + byteSize = currMem.size; + memAddrWrite = currMem.memAddr; + MemBlock = new byte[byteSize]; + if (currMem.tipoMem == plcDataType.String) + { + saveStringOnMemBlock(ref MemBlock, item.Key, 0, byteSize); + } + else if (currMem.tipoMem == plcDataType.DInt) + { + int valDInt = 0; + int.TryParse(item.Value, out valDInt); + MemBlock = S7.Net.Types.DInt.ToByteArray(valDInt); + } + else if (currMem.tipoMem == plcDataType.Int) + { + short valInt = 0; + short.TryParse(item.Value, out valInt); + MemBlock = S7.Net.Types.Int.ToByteArray(valInt); + } + } + else + { + lgError($"Errore: non trovata chiave write in memMap.mMapWrite per {item.Key}"); + } + taskVal = item.Value; + break; + + case taskType.startSetup: + // processo scrittura BIT su DB6.DBDW216 + MemBlock = new byte[1]; + MemBlock[0] = (byte)1; + memAddrWrite = "DB6.DBDW216"; + break; + + case taskType.stopSetup: + // processo scrittura BIT su DB6.DBDW216 + MemBlock = new byte[1]; + MemBlock[0] = (byte)0; + memAddrWrite = "DB6.DBDW216"; + break; + + case taskType.setParameter: + // richiedo da URL i parametri WRITE da popolare + lgInfo("Chiamata processMemWriteRequests"); + taskVal = processMemWriteRequests(); + // se restituiscce "" faccio altra prova... + if (string.IsNullOrEmpty(taskVal)) + { + // i parametri me li aspetto come stringa composta paramName|paramvalue + if (item.Value.Contains("|")) + { + string[] paramsJob = item.Value.Split('|'); + taskVal = $"REQUEST SET PARAMETERS: {paramsJob[0]} --> {paramsJob[1]}"; + } + else + { + taskVal = $"WRONG REQUEST FOR SET PARAMETERS: {item.Value} doesnt contain pipe for splitting key/value"; + } + } + break; + + default: + taskVal = "SKIPPED | NO EXEC"; + break; + } + // aggiungo task! + taskDone.Add(item.Key, taskVal); + if (!string.IsNullOrEmpty(memAddrWrite)) + { + // scrivo! + taskOk = S7WriteBB(ref MemBlock, memAddrWrite); + } + if (!taskOk) + { + lgError($"Errore in S7WriteBB durante executeTasks: {item.Key} | {item.Value}"); + } + } +#endif + } + return taskDone; + } + + /// + /// Override connessione + /// + public override void tryConnect() + { + bool doLog = (verboseLog || periodicLog); + lgInfo("ModBus TCP HAM: tryConnect step 01"); + if (!connectionOk) + { + // SE è necessario refresh... + if (needRefresh) + { + lgInfo("ModBus TCP HAM: tryConnect step 02"); + + // reimporto parametri PLC se necessario... + setParamPlc(); + } + lgInfo("ModBus TCP HAM: tryConnect step 03"); + + // controllo che il ping sia stato tentato almeno pingTestSec fa... + if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec")) + { + if (doLog) + { + lgInfo("ModBus TCP HAM: ConnKO - tryConnect"); + } + lgInfo("ModBus TCP HAM: tryConnect step 04"); + + // in primis salvo data ping... + lastPING = DateTime.Now; + // se passa il ping faccio il resto... + if (testPingMachine == IPStatus.Success) + { + string szStatusConnection = "ND"; + try + { + // ora provo connessione... + parentForm.commPlcActive = true; + currPLC.Connect(); + szStatusConnection = "OPEN"; + parentForm.commPlcActive = false; + connectionOk = currPLC.Connected; + lgInfo($"StatusConnection: {szStatusConnection}"); + // refresh stato allarmi!!! + if (connectionOk) + { + if (adpRunning) + { + lgInfo($"Connessione OK: {connectionOk} | adpRunning: {adpRunning}"); + } + } + else + { + lgError("Impossibile procedere, connessione mancante..."); + } + } + catch (Exception exc) + { + lgFatal($"Errore in TryConnect adapter ModBusTCP | szStatusConnection {szStatusConnection}{Environment.NewLine}{exc}"); + connectionOk = false; + needRefresh = true; + } + } + else + { + // loggo no risposta ping ... + connectionOk = false; + if (doLog) + { + lgInfo($"Attenzione: ModBusTCP controllo PING fallito per IP {cIobConf.cncIpAddr}"); + } + } + } + } + // se non è ancora connesso faccio procesisng memoria caso disconnesso... + if (!connectionOk) + { + // processo semafori ed invio... + processMemoryDiscon(); + } + } + + /// + /// Override disconnessione + /// + public override void tryDisconnect() + { + if (connectionOk) + { + string szStatusConnection = ""; + try + { + currPLC.Disconnect(); + connectionOk = false; + lgInfo(szStatusConnection); + lgInfo("Effettuata disconnessione adapter ModBusTCP!"); + } + catch (Exception exc) + { + lgFatal(exc, "Errore nella disconnessione dall'adapter ModBusTCP"); + } + } + else + { + lgError("IMPOSSIBILE effettuare disconnessione ModBusTCP: Connessione non disponibile..."); + } + } + + #endregion Public Methods + } +} \ No newline at end of file diff --git a/IOB-WIN-NEXT/IobSiemens.cs b/IOB-WIN-NEXT/IobSiemens.cs index 62a86bfa..20ffab30 100644 --- a/IOB-WIN-NEXT/IobSiemens.cs +++ b/IOB-WIN-NEXT/IobSiemens.cs @@ -129,7 +129,7 @@ namespace IOB_WIN_NEXT #region Protected Properties /// - /// Dizionario delel ultime operazioni dis crittura per OGNI memoria (in modo che fa log ogni x sec...) + /// Dizionario delle ultime operazioni di scrittura per OGNI memoria (in modo che fa log ogni x sec...) /// protected Dictionary lastMemWrite { get; set; } = new Dictionary(); @@ -416,7 +416,7 @@ namespace IOB_WIN_NEXT } /// - /// OVerride metodo x scrittura parametri su PLC + /// Override metodo x scrittura parametri su PLC /// /// protected override void plcWriteParams(ref List updatedPar) diff --git a/IOB-WIN-NEXT/MainForm.cs b/IOB-WIN-NEXT/MainForm.cs index 71aaeec1..216bcc53 100644 --- a/IOB-WIN-NEXT/MainForm.cs +++ b/IOB-WIN-NEXT/MainForm.cs @@ -466,7 +466,10 @@ namespace IOB_WIN_NEXT try { var currForm = (AdapterForm)item; - numAttivi += currForm.iobObj.IobOnline ? 1 : 0; + if (currForm.iobObj != null) + { + numAttivi += currForm.iobObj.IobOnline ? 1 : 0; + } } catch { } diff --git a/IOB-WIN-NEXT/packages.config b/IOB-WIN-NEXT/packages.config index abcb9bfb..5d6bf35d 100644 --- a/IOB-WIN-NEXT/packages.config +++ b/IOB-WIN-NEXT/packages.config @@ -1,12 +1,13 @@  - + + - + diff --git a/IOB-WIN-NEXT/specialConfig.cs b/IOB-WIN-NEXT/specialConfig.cs index 6a867dcf..c85e2f94 100644 --- a/IOB-WIN-NEXT/specialConfig.cs +++ b/IOB-WIN-NEXT/specialConfig.cs @@ -2,6 +2,52 @@ namespace IOB_WIN_NEXT { + /// + /// Implementazione classe connessione ModBus TCP, + /// comprensiva dei parametri delle aree di memoria + /// + public class connParamModBusTCP + { + #region Public Fields + + /// + /// Indirizzo IP del PLC + /// + public string ipAdrr = ""; + + /// + /// Base area x lettura + /// + public string memAddrRead = ""; + + /// + /// Base area x scrittura + /// + public string memAddrWrite = ""; + + /// + /// Size memoria lettura + /// + public int memSizeRead = 0; + + /// + /// Size memoria scrittura + /// + public int memSizeWrite = 0; + + /// + /// Timeout ping + /// + public int pingMsTimeout = 250; + + /// + /// Porta di comunicazione + /// + public int port; + + #endregion Public Fields + } + /// /// Implementazione classe connessione SIEMENS con S7.net, /// comprensiva dei parametri delle aree di memoria