diff --git a/IOB-UT-NEXT/Config/Base/IobDto.cs b/IOB-UT-NEXT/Config/Base/IobDto.cs
index 3c8ba1ad..394e810b 100644
--- a/IOB-UT-NEXT/Config/Base/IobDto.cs
+++ b/IOB-UT-NEXT/Config/Base/IobDto.cs
@@ -80,7 +80,7 @@ namespace IOB_UT_NEXT.Config.Base
///
/// Soglia massima errori prima della disconnessione automatica in check
///
- public int MaxErroriCheck { get; set; } = 100;
+ public int MaxErroriCheck { get; set; } = 50;
///
/// Max tentativi ping permessi (default: 5)
@@ -107,6 +107,11 @@ namespace IOB_UT_NEXT.Config.Base
///
public bool EnabRedisQue { get; set; } = true;
+ ///
+ /// Forza esecuzione WorkLoopMachine (verso macchina PLC/CNC) in SingleThread (vs ThreadPool)
+ ///
+ public bool MachWLoopSingleThread { get; set; } = true;
+
///
/// Versione software IOB
///
diff --git a/IOB-UT-NEXT/Config/IobConfTree.cs b/IOB-UT-NEXT/Config/IobConfTree.cs
index c3040514..7c50677b 100644
--- a/IOB-UT-NEXT/Config/IobConfTree.cs
+++ b/IOB-UT-NEXT/Config/IobConfTree.cs
@@ -125,6 +125,7 @@ namespace IOB_UT_NEXT.Config
Customer = fIni.ReadString("TAGS", "Customer", "EgalWare"),
EnabelPodlManFull = bool.Parse(fIni.ReadString("OPTPAR", "EnabelPodlManFull", "false")),
EnabRedisQue = bool.Parse(fIni.ReadString("IOB", "EnableRedisQueue", "true")),
+ MachWLoopSingleThread = bool.Parse(fIni.ReadString("OPTPAR", "MachSingleThread", "false")),
MaxErroriCheck = fIni.ReadInteger("OPTPAR", "MAX_ERR_CHECK", maxErrCheck),
MaxPingRetry = fIni.ReadInteger("OPTPAR", "MAX_PING_RETRY", 5),
MinDeltaSec = fIni.ReadInteger("IOB", "MinDeltaSec", 6),
@@ -140,11 +141,11 @@ namespace IOB_UT_NEXT.Config
exclOptPar.Add("DELAY_READ_PZ_COUNT");
exclOptPar.Add("DISABLE_SEND_WDST");
exclOptPar.Add("EnabelPodlManFull");
+ exclOptPar.Add("MachSingleThread");
exclOptPar.Add("MAX_ERR_CHECK");
exclOptPar.Add("MAX_PING_RETRY");
exclOptPar.Add("SEND_ALARM_RESET");
exclOptPar.Add("SEND_MACHINE_CONF");
- exclOptPar.Add("timerIntMs");
exclOptPar.Add("WAIT_REC_MSEC");
exclOptPar.Add("WATCHDOG_PERIOD");
@@ -155,6 +156,7 @@ namespace IOB_UT_NEXT.Config
{
int.TryParse(rawTimer, out uiTimer);
}
+ exclOptPar.Add("timerIntMs");
// ultimo controllo: timer deve essere compreso tra 10 a 500 x evitare task troppo veloci o lenti...
uiTimer = uiTimer < 10 ? 10 : uiTimer;
uiTimer = uiTimer > 500 ? 500 : uiTimer;
@@ -272,7 +274,7 @@ namespace IOB_UT_NEXT.Config
PzTotMode = fIni.ReadString("OPTPAR", "PZGTOT_MODE", ""),
ReadErrorMax = fIni.ReadInteger("OPTPAR", "READ_ERROR_MAX", 20),
ReadErrorSleepTime = fIni.ReadInteger("OPTPAR", "READ_ERROR_SLEEP_TIME", 20000),
- StartupVetoQueueIN = fIni.ReadInteger("OPTPAR", "VETO_QUEUE_IN", 10),
+ StartupVetoQueueIN = fIni.ReadInteger("OPTPAR", "VETO_QUEUE_IN", 6),
Vendor = fIni.ReadString("MACHINE", "VENDOR", "STEAMWARE"),
Connect = new ConnectionDto()
{
diff --git a/IOB-UT-NEXT/IOB-UT-NEXT.csproj b/IOB-UT-NEXT/IOB-UT-NEXT.csproj
index 87a955cc..239e9d06 100644
--- a/IOB-UT-NEXT/IOB-UT-NEXT.csproj
+++ b/IOB-UT-NEXT/IOB-UT-NEXT.csproj
@@ -200,8 +200,11 @@
+
+
+
diff --git a/IOB-UT-NEXT/Iob/BaseObj.cs b/IOB-UT-NEXT/Iob/BaseObj.cs
index 905b8850..39b181ee 100644
--- a/IOB-UT-NEXT/Iob/BaseObj.cs
+++ b/IOB-UT-NEXT/Iob/BaseObj.cs
@@ -238,6 +238,16 @@ namespace IOB_UT_NEXT.Iob
///
public DataQueue QueueRawTransf;// = new DataQueue("000", "QueueRawTransf", false);
+ ///
+ /// Coda delle richieste dal server (Task2Exe)
+ ///
+ public DataQueue QueueSrvReq;
+
+ ///
+ /// Coda delle risposte al server (Task2Exe)
+ ///
+ public DataQueue QueueSrvResp;
+
///
/// Coda valori LOG UTENTE (da non sottocampionare come samples)...
///
@@ -621,16 +631,18 @@ namespace IOB_UT_NEXT.Iob
{
string codIob = IOBConfFull.General.FilenameIOB;
bool useRedis = IOBConfFull.General.EnabRedisQue;
- QueueAlarm = new DataQueue(codIob, "QueueAlarm", false, redisMan);
// valutare se portare di nuovo in redis...
QueueIN = new DataQueue(codIob, "QueueIN", useRedis, redisMan);
+ QueueSrvResp = new DataQueue(codIob, "QueueServResp", useRedis, redisMan);
// fix a NON redis
+ QueueAlarm = new DataQueue(codIob, "QueueAlarm", false, redisMan);
QueueFLog = new DataQueue(codIob, "QueueFLog", false, redisMan);
//QueueFLog = new DataQueue(codIob, "QueueFLog", useRedis, redisMan);
QueueMessages = new DataQueue(codIob, "QueueMessages", false, redisMan);
- QueueRawTransf = new DataQueue(codIob, "QueueRawTransf", false, redisMan);
- QueueULog = new DataQueue(codIob, "QueueULog", false, redisMan);
QueuePing = new DataQueue(codIob, "QueuePing", false, redisMan);
+ QueueRawTransf = new DataQueue(codIob, "QueueRawTransf", false, redisMan);
+ QueueSrvReq = new DataQueue(codIob, "QueueServReq", false, redisMan);
+ QueueULog = new DataQueue(codIob, "QueueULog", false, redisMan);
}
#endregion Protected Methods
diff --git a/IOB-UT-NEXT/JobTask2Exe.cs b/IOB-UT-NEXT/JobTask2Exe.cs
new file mode 100644
index 00000000..da465db4
--- /dev/null
+++ b/IOB-UT-NEXT/JobTask2Exe.cs
@@ -0,0 +1,65 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace IOB_UT_NEXT
+{
+ ///
+ /// Classe per gestione Job Task2Exe x una macchina
+ ///
+ public class JobTaskData
+ {
+ #region Public Constructors
+
+ public JobTaskData(string codTav, string rawData)
+ {
+ CodTav = codTav;
+ RawData = rawData;
+ }
+
+ #endregion Public Constructors
+
+#if false
+ public JobTaskData(string codTav, Dictionary newDict)
+ {
+ CodTav = codTav;
+ RawData = JsonConvert.SerializeObject(newDict);
+ }
+#endif
+
+ #region Public Properties
+
+ ///
+ /// Codice tavola (empty = main)
+ ///
+ public string CodTav { get; private set; } = "";
+
+ ///
+ /// Dizionario in formato raw (da deserializzare
+ ///
+ public string RawData { get; private set; } = "";
+
+ #endregion Public Properties
+
+ #region Public Methods
+
+ ///
+ /// Dizionario dei Task associati
+ ///
+ public static Dictionary TaskDict(string rawData)
+ {
+ var answ = new Dictionary();
+ if (!string.IsNullOrEmpty(rawData))
+ {
+ answ = JsonConvert.DeserializeObject>(rawData) ?? new Dictionary();
+ }
+ return answ;
+ }
+
+ #endregion Public Methods
+ }
+}
\ No newline at end of file
diff --git a/IOB-UT-NEXT/SingleThreadTaskScheduler.cs b/IOB-UT-NEXT/SingleThreadTaskScheduler.cs
new file mode 100644
index 00000000..7c70f915
--- /dev/null
+++ b/IOB-UT-NEXT/SingleThreadTaskScheduler.cs
@@ -0,0 +1,47 @@
+using System;
+using System.Collections.Generic;
+using System.Collections.Concurrent;
+using System.Threading;
+using System.Threading.Tasks;
+
+public class SingleThreadTaskScheduler : TaskScheduler, IDisposable
+{
+ private readonly BlockingCollection _tasks = new BlockingCollection();
+ private readonly Thread _thread;
+ public SynchronizationContext SyncContext { get; private set; }
+
+ public SingleThreadTaskScheduler(string threadName)
+ {
+ var tcs = new TaskCompletionSource();
+ _thread = new Thread(() =>
+ {
+ // Creiamo il contesto di sincronizzazione personalizzato
+ SyncContext = new SingleThreadSynchronizationContext(this);
+ SynchronizationContext.SetSynchronizationContext(SyncContext);
+ tcs.SetResult(true);
+
+ foreach (var task in _tasks.GetConsumingEnumerable())
+ {
+ base.TryExecuteTask(task);
+ }
+ })
+ { IsBackground = true, Name = threadName };
+ _thread.Start();
+ tcs.Task.Wait(); // Aspetta che il thread sia pronto col suo contesto
+ }
+
+ private class SingleThreadSynchronizationContext : SynchronizationContext
+ {
+ private readonly SingleThreadTaskScheduler _sch;
+ public SingleThreadSynchronizationContext(SingleThreadTaskScheduler sch) => _sch = sch;
+ public override void Post(SendOrPostCallback d, object state)
+ => Task.Factory.StartNew(() => d(state), CancellationToken.None, TaskCreationOptions.None, _sch);
+ }
+
+ protected override void QueueTask(Task task) => _tasks.Add(task);
+ protected override bool TryExecuteTaskInline(Task task, bool prev)
+ => Thread.CurrentThread == _thread && base.TryExecuteTask(task);
+ protected override IEnumerable GetScheduledTasks() => _tasks;
+ public override int MaximumConcurrencyLevel => 1;
+ public void Dispose() => _tasks.CompleteAdding();
+}
\ No newline at end of file
diff --git a/IOB-UT-NEXT/TimerMan.cs b/IOB-UT-NEXT/TimerMan.cs
new file mode 100644
index 00000000..d03f3244
--- /dev/null
+++ b/IOB-UT-NEXT/TimerMan.cs
@@ -0,0 +1,64 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace IOB_UT_NEXT
+{
+ ///
+ /// Classe di gestione info Timer per esecuzione ordinata processi secondo priorità
+ ///
+ public class TimerMan
+ {
+ #region Public Constructors
+
+ ///
+ /// Init classe timer
+ ///
+ ///
+ public TimerMan(ContextType contesto)
+ {
+ Contesto = contesto;
+ }
+
+ #endregion Public Constructors
+
+ #region Public Enums
+
+ ///
+ /// Tipologia contesto timer
+ ///
+ public enum ContextType
+ {
+ Machine = 0,
+ Server
+ }
+
+ #endregion Public Enums
+
+ #region Public Properties
+
+ ///
+ /// Contesto del timer
+ ///
+ public ContextType Contesto { get; private set; } = ContextType.Machine;
+
+ ///
+ /// Contatore chiamate timers x debug timing
+ ///
+ public Dictionary CycleCount { get; set; } = new Dictionary();
+
+ ///
+ /// Contatore durata exec x debug timing
+ ///
+ public Dictionary CycleElaps { get; set; } = new Dictionary();
+
+ ///
+ /// Dizionario scadenza timers interni x esecuzione dei vari task a differente frequenza di chiamata
+ ///
+ public Dictionary Veto { get; set; } = new Dictionary();
+
+ #endregion Public Properties
+ }
+}
\ No newline at end of file
diff --git a/IOB-UT-NEXT/baseUtils.cs b/IOB-UT-NEXT/baseUtils.cs
index 7df31da5..159da62a 100644
--- a/IOB-UT-NEXT/baseUtils.cs
+++ b/IOB-UT-NEXT/baseUtils.cs
@@ -351,36 +351,6 @@ namespace IOB_UT_NEXT
}
}
-
-#if false
- ///
- /// Versione async della chiamata ad URL
- ///
- ///
- ///
- public static string callUrlAsync(string URL)
- {
- // Chiamo in modalità task...
- var resp = Task.Run(() => callUrl(URL));
- resp.Wait();
- return resp.Result;
- }
-
- ///
- /// Versione async della chiamata ad URL
- ///
- ///
- ///
- ///
- public static string callUrlAsync(string URL, string payload)
- {
- // Chiamo in modalità task...
- var resp = Task.Run(() => callUrl(URL, payload));
- resp.Wait();
- return resp.Result;
- }
-#endif
-
///
/// Effettua chiamata URL IMMEDIATAMENTE e restituisce risultato
///
@@ -435,7 +405,7 @@ namespace IOB_UT_NEXT
clientPayload = new WebClientWT();
}
clientPayload.Headers.Add("user-agent", $"{CRS("appName")}-PAYLOAD");
- clientPayload.Headers.Add("Content-Type", "application/json");
+ clientPayload.Headers.Add("Content-ContextType", "application/json");
try
{
// problema certificati locali...
@@ -553,20 +523,6 @@ namespace IOB_UT_NEXT
public static string CRS(string key)
{
return ConfigurationManager.AppSettings[key] ?? string.Empty;
-#if false
- string answ = "";
- if (ConfigurationManager.AppSettings.Count > 0)
- {
- try
- {
-
- answ = ConfigurationManager.AppSettings[key].ToString();
- }
- catch
- { }
- }
- return answ;
-#endif
}
///
diff --git a/IOB-WIN-FANUC/App.config b/IOB-WIN-FANUC/App.config
index 2ec47542..83967707 100644
--- a/IOB-WIN-FANUC/App.config
+++ b/IOB-WIN-FANUC/App.config
@@ -25,7 +25,7 @@
-
+
@@ -73,7 +73,7 @@
-
+
diff --git a/IOB-WIN-FANUC/DATA/CONF/3028.ini b/IOB-WIN-FANUC/DATA/CONF/3028.ini
index b92709f3..9e6504a9 100644
--- a/IOB-WIN-FANUC/DATA/CONF/3028.ini
+++ b/IOB-WIN-FANUC/DATA/CONF/3028.ini
@@ -86,6 +86,12 @@ DISABLE_SEND_WDST=TRUE
; bit da scrivere come trace ad ogni check
;MEM_2_TRACE=|BIT3|BIT4|BIT5|
PARAM_CONF=3028.json
+; test timing & errori
+timerIntMs=30
+MachSingleThread=true
+MAX_ERR_CHECK=10
+;WAIT_REC_MSEC=15000
+
[BRANCH]
NAME=master
diff --git a/IOB-WIN-FANUC/DATA/CONF/3029.ini b/IOB-WIN-FANUC/DATA/CONF/3029.ini
index 839a86e0..e144567e 100644
--- a/IOB-WIN-FANUC/DATA/CONF/3029.ini
+++ b/IOB-WIN-FANUC/DATA/CONF/3029.ini
@@ -88,6 +88,10 @@ ENABLE_SEND_PZC_BLOCK=TRUE
MIN_SEND_PZC_BLOCK=0
MAX_SEND_PZC_BLOCK=100
DISABLE_SEND_WDST=TRUE
+; test timing & errori
+;timerIntMs=40
+;MachSingleThread=true
+MAX_ERR_CHECK=10
; bit da scrivere come trace ad ogni check
;MEM_2_TRACE=|BIT3|BIT4|BIT5|
PARAM_CONF=3029.json
diff --git a/IOB-WIN-FANUC/DATA/CONF/FOV106.ini b/IOB-WIN-FANUC/DATA/CONF/FOV106.ini
index ed4fa69c..e0b0a305 100644
--- a/IOB-WIN-FANUC/DATA/CONF/FOV106.ini
+++ b/IOB-WIN-FANUC/DATA/CONF/FOV106.ini
@@ -71,6 +71,7 @@ MIN_SEND_PZC_BLOCK=0
MAX_SEND_PZC_BLOCK=100
; Disabilito conteggio Pezzi come richiesto
DISABLE_PZCOUNT=TRUE
+DISABLE_SEND_WDST=TRUE
[BRANCH]
NAME=master
diff --git a/IOB-WIN-FANUC/DATA/CONF/MAIN.ini b/IOB-WIN-FANUC/DATA/CONF/MAIN.ini
index 7ea30958..6cb43b0d 100644
--- a/IOB-WIN-FANUC/DATA/CONF/MAIN.ini
+++ b/IOB-WIN-FANUC/DATA/CONF/MAIN.ini
@@ -26,10 +26,12 @@ CLI_INST=SteamWareSim
;STARTLIST=3004
;STARTLIST=3002
;STARTLIST=GT575
-;STARTLIST=3029
;STARTLIST=3004,3005
;STARTLIST=SIMUL_01
+;STARTLIST=FOV106
STARTLIST=FOV107
+;STARTLIST=3028
+;STARTLIST=3029
MAXCNC=10
\ No newline at end of file
diff --git a/IOB-WIN-FANUC/IOB-WIN-FANUC.csproj b/IOB-WIN-FANUC/IOB-WIN-FANUC.csproj
index 5a82ef02..25e5d51b 100644
--- a/IOB-WIN-FANUC/IOB-WIN-FANUC.csproj
+++ b/IOB-WIN-FANUC/IOB-WIN-FANUC.csproj
@@ -162,6 +162,7 @@
PreserveNewest
+
Always
@@ -177,6 +178,7 @@
Always
+
Always
@@ -231,7 +233,9 @@
-
+
+ Always
+
Always
diff --git a/IOB-WIN-FANUC/Iob/Fanuc.cs b/IOB-WIN-FANUC/Iob/Fanuc.cs
index 60e192a2..91697079 100644
--- a/IOB-WIN-FANUC/Iob/Fanuc.cs
+++ b/IOB-WIN-FANUC/Iob/Fanuc.cs
@@ -8,17 +8,15 @@ using System;
using System.Collections.Generic;
using System.Net;
using System.Net.NetworkInformation;
+using System.Security.Policy;
+using System.Threading;
using System.Threading.Tasks;
+using static EgwProxy.MultiCncLib.CNC.FANUC;
namespace IOB_WIN_FANUC.Iob
{
public class Fanuc : Iob.GenericNext
{
- ///
- /// Oggetto logger della classe
- ///
- private static Logger _logger = LogManager.GetCurrentClassLogger();
-
#region Public Constructors
///
@@ -61,6 +59,11 @@ namespace IOB_WIN_FANUC.Iob
MemBlockX = new byte[xSize];
MemBlockY = new byte[ySize];
+ // forzo letture single threaded x FANUC!!!
+ IOBConfFull.General.MachWLoopSingleThread = true;
+ // x FANUC riduco num errori std x forzare riavvio rapido
+ maxErroriCheck = maxErroriCheck > 15 ? 15 : maxErroriCheck;
+
// loggo aree di memoria avviate...
lgInfo($"Init area di memoria | MemBlockG: {gSize}b | MemBlockR: {rSize}b | MemBlockX: {xSize}b | MemBlockY: {ySize}b ");
@@ -70,7 +73,6 @@ namespace IOB_WIN_FANUC.Iob
areaX = FormatAreaFanuc("AreaX", "AREAX");
areaY = FormatAreaFanuc("AreaY", "AREAY");
-
lgInfo($"Set Mem | {areaD.areaName}: {areaD.startIdx} +{areaD.arraySize} | {areaR.areaName}: {areaR.startIdx} +{areaR.arraySize} | {areaX.areaName}: {areaX.startIdx} +{areaX.arraySize} | {areaY.areaName}: {areaY.startIdx} +{areaY.arraySize}");
lgInfoStartup($"Start init Adapter FANUC all'IP {IOBConfFull.Device.Connect.IpAddr}:{IOBConfFull.Device.Connect.Port} per IOB {IOBConfFull.General.CodIOB}");
@@ -87,13 +89,10 @@ namespace IOB_WIN_FANUC.Iob
lgInfo("FANUC_ref da EgwProxy.MultiCncLib");
}
- // disconnetto e connetto...
- if (isVerboseLog)
- {
- lgInfo("FANUC: tryDisconnect");
- }
-
+ lgInfo("FANUC: tryDisconnect");
tryDisconnect();
+ Thread.Sleep(200);
+
lgInfo("FANUC: tryConnect");
tryConnect();
if (enablePzCountByApp)
@@ -135,32 +134,6 @@ namespace IOB_WIN_FANUC.Iob
lgInfo("End init Adapter FANUC");
}
- public override async Task InitializeAsync()
- {
- // invio altri dati accessori...
- await SendMachineConfAsync();
- }
-
- ///
- /// Formatta area x memorie Fanuc da conf caricata
- ///
- ///
- ///
- ///
- private memAreaFanuc FormatAreaFanuc(string aName, string mKey)
- {
- var newArea = new memAreaFanuc() { areaName = aName };
- if (IOBConfFull.Special.BankConf.AreaConf.ContainsKey(mKey))
- {
- var thisConf = IOBConfFull.Special.BankConf.AreaConf[mKey];
- newArea.startIdx = thisConf.Start;
- newArea.arraySize = thisConf.Size;
-
- }
-
- return newArea;
- }
-
#endregion Public Constructors
#region Public Methods
@@ -275,7 +248,7 @@ namespace IOB_WIN_FANUC.Iob
{
lgInfo("All OK");
// invio aggiornamento x reset richiesta... test!
- sendOptVal(item.Key, newVal);
+ _ = sendOptVal(item.Key, newVal);
}
else
{
@@ -331,7 +304,7 @@ namespace IOB_WIN_FANUC.Iob
{
lgInfo("All OK");
// invio aggiornamento x reset richiesta... test!
- sendOptVal(item.Key, newVal);
+ _ = sendOptVal(item.Key, newVal);
}
else
{
@@ -438,6 +411,7 @@ namespace IOB_WIN_FANUC.Iob
public bool FanucMemMacroRW(bool bWrite, Int32 memIndex, ref short Value)
{
bool answ = false;
+ string topic = $"FanucMemMacroRW.short.{memIndex}";
if (connectionOk)
{
if (FANUC_ref.Connected)
@@ -451,23 +425,19 @@ namespace IOB_WIN_FANUC.Iob
answ = FANUC_ref.F_RW_Macro_Short(bWrite, memIndex, ref zeroVal);
// ora scrivo vero valore...
answ = FANUC_ref.F_RW_Macro_Short(bWrite, memIndex, ref Value);
- numErroriCheck = numErroriCheck > 0 ? numErroriCheck-- : 0;
+ tryReduceErrorCount(topic);
}
catch (Exception exc)
{
- numErroriCheck++;
- lgError($"Eccezione in FanucMemMacroRW | Short | numErroriCheck: {numErroriCheck}{Environment.NewLine}{exc}");
+ tryIncreaseErrorComm(topic);
+ lgError($"Eccezione in FanucMemMacroRW | Short | MemType: MACRO | memIndex: {memIndex} | numErroriCheck: {numErroriCheck}{Environment.NewLine}{exc}");
}
}
else
{
- numErroriCheck++;
+ connectionOk = false;
}
}
- else
- {
- numErroriCheck++;
- }
parentForm.commPlcActive = false;
return answ;
}
@@ -482,6 +452,7 @@ namespace IOB_WIN_FANUC.Iob
public bool FanucMemMacroRW(bool bWrite, Int32 memIndex, ref double Value)
{
bool answ = false;
+ string topic = $"FanucMemMacroRW.double.{memIndex}";
if (connectionOk)
{
if (FANUC_ref.Connected)
@@ -494,23 +465,19 @@ namespace IOB_WIN_FANUC.Iob
answ = FANUC_ref.F_RW_Macro_Short(bWrite, memIndex, ref zeroVal);
// ora scrivo vero valore...
answ = FANUC_ref.F_RW_Macro_Double(bWrite, memIndex, ref Value);
- numErroriCheck = numErroriCheck > 0 ? numErroriCheck-- : 0;
+ tryReduceErrorCount(topic);
}
catch (Exception exc)
{
- numErroriCheck++;
- lgError($"Eccezione in FanucMemMacroRW | Double | numErroriCheck: {numErroriCheck}{Environment.NewLine}{exc}");
+ tryIncreaseErrorComm(topic);
+ lgError($"Eccezione in FanucMemMacroRW | Double | MemType: MACRO | memIndex: {memIndex} | numErroriCheck: {numErroriCheck}{Environment.NewLine}{exc}");
}
}
else
{
- numErroriCheck++;
+ connectionOk = false;
}
}
- else
- {
- numErroriCheck++;
- }
parentForm.commPlcActive = false;
return answ;
}
@@ -526,6 +493,7 @@ namespace IOB_WIN_FANUC.Iob
public bool FanucMemRW(bool bWrite, FANUC.MemType MemType, Int32 memIndex, ref byte Value)
{
bool answ = false;
+ string topic = $"FanucMemRW.{MemType}.byte.{memIndex}";
if (connectionOk)
{
if (FANUC_ref.Connected)
@@ -534,23 +502,19 @@ namespace IOB_WIN_FANUC.Iob
{
parentForm.commPlcActive = true;
answ = FANUC_ref.F_RW_Byte(bWrite, MemType, memIndex, ref Value);
- numErroriCheck = numErroriCheck > 0 ? numErroriCheck-- : 0;
+ tryReduceErrorCount(topic);
}
catch (Exception exc)
{
- numErroriCheck++;
- lgError($"Eccezione in FanucMemRW | Byte | numErroriCheck: {numErroriCheck}{Environment.NewLine}{exc}");
+ tryIncreaseErrorComm(topic);
+ lgError($"Eccezione in FanucMemRW | Byte | MemType: {MemType} | memIndex: {memIndex} | numErroriCheck: {numErroriCheck}{Environment.NewLine}{exc}");
}
}
else
{
- numErroriCheck++;
+ connectionOk = false;
}
}
- else
- {
- numErroriCheck++;
- }
parentForm.commPlcActive = false;
return answ;
}
@@ -566,6 +530,7 @@ namespace IOB_WIN_FANUC.Iob
public bool FanucMemRW(bool bWrite, FANUC.MemType MemType, Int32 memIndex, ref byte[] Value)
{
bool answ = false;
+ string topic = $"FanucMemRW.{MemType}.byte_array.{memIndex}";
if (connectionOk)
{
if (FANUC_ref.Connected)
@@ -574,23 +539,19 @@ namespace IOB_WIN_FANUC.Iob
{
parentForm.commPlcActive = true;
answ = FANUC_ref.F_RW_Byte(bWrite, MemType, memIndex, ref Value);
- numErroriCheck = numErroriCheck > 0 ? numErroriCheck-- : 0;
+ tryReduceErrorCount(topic);
}
catch (Exception exc)
{
- numErroriCheck++;
- lgError($"Eccezione in FanucMemRW | MultiByte | numErroriCheck: {numErroriCheck}{Environment.NewLine}{exc}");
+ tryIncreaseErrorComm(topic);
+ lgError($"Eccezione in FanucMemRW | MultiByte | MemType: {MemType} | memIndex: {memIndex} | numErroriCheck: {numErroriCheck}{Environment.NewLine}{exc}");
}
}
else
{
- numErroriCheck++;
+ connectionOk = false;
}
}
- else
- {
- numErroriCheck++;
- }
parentForm.commPlcActive = false;
return answ;
}
@@ -601,6 +562,7 @@ namespace IOB_WIN_FANUC.Iob
public override Dictionary getDynData()
{
Dictionary outVal = new Dictionary();
+ string topic = $"FanucMemRW.getDynData";
// processo SOLO SE connected...
if (connectionOk)
{
@@ -635,14 +597,14 @@ namespace IOB_WIN_FANUC.Iob
outVal.Add(string.Format("POS_{0:00}", i), item.ToString());
}
}
+ tryReduceErrorCount(topic);
}
catch (Exception exc)
{
- numErroriCheck++;
+ tryIncreaseErrorComm(topic);
lgError($"Errore in getDynData | numErroriCheck: {numErroriCheck}{Environment.NewLine}{exc}");
}
sw.Stop();
- numErroriCheck = numErroriCheck > 0 ? numErroriCheck-- : 0;
}
}
// se supero soglia errori lettura --> disconnetto e resetto
@@ -654,6 +616,10 @@ namespace IOB_WIN_FANUC.Iob
connectionOk = false;
tryDisconnect();
}
+ if (outVal.Count > 0)
+ {
+ tryReduceErrorCount(topic);
+ }
return outVal;
}
@@ -686,19 +652,22 @@ namespace IOB_WIN_FANUC.Iob
public override string getPrgName()
{
string prgName = "";
+ string topic = $"FanucMemRW.getPrgName";
DateTime adesso = DateTime.Now;
try
{
// recupero nome programma MAIN
- prgName = utils.purgedChar2String(FANUC_ref.getPrgNameMain());
+ var is30 = FANUC_ref.Is30Series;
+ var rawName = FANUC_ref.getPrgNameMain();
+ prgName = utils.purgedChar2String(rawName);
// trimmo path del programma, ovvero "CNCMEMUSERPATH1"
prgName = prgName.Replace(utils.CRS("basePrgMemPath"), "");
lgInfo("Current PROG: {0}", prgName);
- numErroriCheck = numErroriCheck > 0 ? numErroriCheck-- : 0;
+ tryReduceErrorCount(topic);
}
catch (Exception exc)
{
- numErroriCheck++;
+ tryIncreaseErrorComm(topic);
lgError($"Eccezione in recupero PRG NAME MAIN | numErroriCheck: {numErroriCheck}{Environment.NewLine}{exc}");
}
// se supero soglia errori lettura --> disconnetto e resetto
@@ -754,6 +723,12 @@ namespace IOB_WIN_FANUC.Iob
return outVal;
}
+ public override async Task InitializeAsync()
+ {
+ // invio altri dati accessori...
+ await SendMachineConfAsync();
+ }
+
///
/// Effettua vero processing contapezzi:
/// 6711: pezzi lavorati
@@ -762,6 +737,7 @@ namespace IOB_WIN_FANUC.Iob
///
public override void processContapezzi()
{
+ string topic = $"processContapezzi";
if (enablePzCountByApp)
{
// procedo SOLO SE ho connessione...
@@ -775,6 +751,7 @@ namespace IOB_WIN_FANUC.Iob
// verifico quale modalità sia richiesta: STD (6711) oppure BIT
// (Custom, con indicazione area)
string memAddr = IOBConfFull.Device.PzCountMode;
+ topic = $"processContapezzi.{memAddr}";
if (memAddr.StartsWith("STD"))
{
// inizio verifica area memoria/parametro levando prima parte codice
@@ -783,6 +760,7 @@ namespace IOB_WIN_FANUC.Iob
// var di appoggio
int cntAddr = 0;
object outputVal = new object();
+ bool done = false;
// verifico se si tratta di lettura parametro... formato tipo STD.PAR.6711
if (memAddr.StartsWith("PAR."))
{
@@ -794,7 +772,7 @@ namespace IOB_WIN_FANUC.Iob
}
// processo parametro contapezzi (lavorati)
sw.Restart();
- FANUC_ref.F_RW_Param_Integer(false, cntAddr, 3, ref outputVal);
+ done = FANUC_ref.F_RW_Param_Integer(false, cntAddr, 3, ref outputVal);
if (utils.CRB("recTime"))
{
TimingData.addResult(IOBConfFull.General.CodIOB, string.Format("R{0}-PAR", 4), sw.ElapsedTicks);
@@ -813,7 +791,7 @@ namespace IOB_WIN_FANUC.Iob
// processo parametro
sw.Restart();
double macroVal = 0;
- FANUC_ref.F_Read_macro(cntAddr, ref macroVal);
+ done = FANUC_ref.F_Read_macro(cntAddr, ref macroVal);
if (utils.CRB("recTime"))
{
TimingData.addResult(IOBConfFull.General.CodIOB, string.Format("R{0}-MACRO", 5), sw.ElapsedTicks);
@@ -840,19 +818,19 @@ namespace IOB_WIN_FANUC.Iob
{
case "B":
byte valB = 0;
- FANUC_ref.F_RW_Byte(false, areaCounter.mType, areaCounter.mPos, ref valB);
+ done = FANUC_ref.F_RW_Byte(false, areaCounter.mType, areaCounter.mPos, ref valB);
outputVal = valB;
break;
case "D":
ushort valW = 0;
- FANUC_ref.F_RW_Word(false, areaCounter.mType, areaCounter.mPos, ref valW);
+ done = FANUC_ref.F_RW_Word(false, areaCounter.mType, areaCounter.mPos, ref valW);
outputVal = valW;
break;
case "DW":
uint valDW = 0;
- FANUC_ref.F_RW_DWord(false, areaCounter.mType, areaCounter.mPos, ref valDW);
+ done = FANUC_ref.F_RW_DWord(false, areaCounter.mType, areaCounter.mPos, ref valDW);
if (isVerboseLog)
{
lgInfo("[1] valDW contapezzi: {0}", valDW);
@@ -883,12 +861,22 @@ namespace IOB_WIN_FANUC.Iob
//}
}
sw.Stop();
+ tryReduceErrorCount(topic);
}
}
catch (Exception exc)
{
- lgError(exc, "Errore in contapezzi FANUC 02");
+ tryIncreaseErrorComm(topic);
+ lgError($"Eccezione in contapezzi FANUC 02 | numErroriCheck: {numErroriCheck}{Environment.NewLine}{exc}");
+ }
+ // se supero soglia errori lettura --> disconnetto e resetto
+ if (numErroriCheck > maxErroriCheck)
+ {
+ lgError($"numErroriCheck: {numErroriCheck} --> disconnessione adapter con tryDisconnect");
+
+ numErroriCheck = 0;
connectionOk = false;
+ tryDisconnect();
}
}
else
@@ -903,6 +891,7 @@ namespace IOB_WIN_FANUC.Iob
///
public override void processMode()
{
+ string topic = $"FanucMemRW.processMode.G";
// processo SOLO SE connected...
if (connectionOk)
{
@@ -910,13 +899,14 @@ namespace IOB_WIN_FANUC.Iob
{
if (utils.CRB("enableMode") && MemBlockG != null && MemBlockG.Length > 0)
{
+ bool done = false;
try
{
// leggo tutto da 0 a 43...
int memIndex = 0;
// controllo modalità lettura memoria
sw.Restart();
- FanucMemRW(R, FANUC.MemType.G, memIndex, ref MemBlockG);
+ done = FanucMemRW(R, FANUC.MemType.G, memIndex, ref MemBlockG);
if (utils.CRB("recTime"))
{
TimingData.addResult(IOBConfFull.General.CodIOB, string.Format("R{0}-G-AREA", MemBlockG.Length), sw.ElapsedTicks);
@@ -925,6 +915,7 @@ namespace IOB_WIN_FANUC.Iob
sw.Stop();
// verifico modo con valore corrente, se cambia aggiorno...
CNC_MODE newMode = decodeG43(MemBlockG[43]);
+ tryReduceErrorCount(topic);
if (newMode != currMode)
{
// aggiorno!
@@ -943,9 +934,17 @@ namespace IOB_WIN_FANUC.Iob
}
catch (Exception exc)
{
- lgError(exc, string.Format("Errore in process Mode G43: {0}{1}", Environment.NewLine, exc));
+ tryIncreaseErrorComm(topic);
+ lgError($"Errore in process Mode G43 | numErroriCheck: {numErroriCheck}{Environment.NewLine}{exc}");
+ }
+ // se supero soglia errori lettura --> disconnetto e resetto
+ if (numErroriCheck > maxErroriCheck)
+ {
+ lgError($"numErroriCheck: {numErroriCheck} --> disconnessione adapter con tryDisconnect");
+
+ numErroriCheck = 0;
connectionOk = false;
- sw.Stop();
+ tryDisconnect();
}
}
}
@@ -957,74 +956,30 @@ namespace IOB_WIN_FANUC.Iob
///
public override async Task processOtherCounters()
{
- // processo verifica ed invio 1:1
- await checkSendCounter("PzReq", memNamePzReq, memAddrPzReq);
- await checkSendCounter("Articolo", memNameArt, memAddrArt);
- await checkSendCounter("Commessa", memNameCom, memAddrCom);
- // solo SE abilitato contapezzi...
- if (IOBConfFull.Device.EnabPzCount)
+ string topic = $"FanucMemRW.processOtherCounters";
+ try
{
- await checkSendCounter("PzCount", memNamePzCnt, memAddrPzCnt);
- await checkSendCounter("FreeCounter", memNamePzCntFree, memAddrPzCntFree);
- await checkSendCounter("PzCntTOT", memNamePzCntTot, memAddrPzCntTot);
- }
- await checkSendCounter("Cadenza", memNameCaden, memAddrCaden);
- }
- ///
- /// Verifica se effettuare invio (a scadenza) del valore counter richiesto
- ///
- ///
- ///
- ///
- private async Task checkSendCounter(string varName, string currMemName, string currMemAddr)
- {
- // gestione con ricerca in memoria Write / optPar...
- if (string.IsNullOrEmpty(currMemAddr))
- {
- lgTrace($"{varName} disabilitato | NO memConf.Write | NO optPar");
- }
- else
- {
- try
+ // processo verifica ed invio 1:1
+ await checkSendCounter("PzReq", memNamePzReq, memAddrPzReq);
+ await checkSendCounter("Articolo", memNameArt, memAddrArt);
+ await checkSendCounter("Commessa", memNameCom, memAddrCom);
+ // solo SE abilitato contapezzi...
+ if (IOBConfFull.Device.EnabPzCount)
{
- DateTime adesso = DateTime.Now;
- int currPeriod = memPeriod(currMemName);
- // se non ha periodo abilito invio
- bool doSend = currPeriod == 0;
- // altrimenti verifica
- if (!doSend)
- {
- if (VetoCounterSend.ContainsKey(currMemName))
- {
- // verifico scadenza...
- if (VetoCounterSend[currMemName] < adesso)
- {
- VetoCounterSend[currMemName] = adesso.AddSeconds(currPeriod);
- doSend = true;
- lgInfo($"checkSendCounter | set veto for {varName} at {VetoCounterSend[currMemName]:HH:mm:ss}");
- }
- }
- else
- {
- VetoCounterSend.Add(currMemName, adesso.AddSeconds(currPeriod));
- doSend = true;
- lgTrace($"{varName} | Veto still active until {VetoCounterSend[currMemName]:HH:mm:ss}");
- }
- }
- // per il counter verifico SE sia da inviare...
- if (doSend)
- {
- await sendOptVal(currMemName, getValByMemAddr(currMemAddr));
- }
- }
- catch (Exception exc)
- {
- lgError(exc, $"Eccezione | processOtherCounters.checkSendCounter | {varName} | {currMemName} | {currMemAddr}{Environment.NewLine}{exc}");
+ await checkSendCounter("PzCount", memNamePzCnt, memAddrPzCnt);
+ await checkSendCounter("FreeCounter", memNamePzCntFree, memAddrPzCntFree);
+ await checkSendCounter("PzCntTOT", memNamePzCntTot, memAddrPzCntTot);
}
+ await checkSendCounter("Cadenza", memNameCaden, memAddrCaden);
+ tryReduceErrorCount(topic);
+ }
+ catch (Exception exc)
+ {
+ tryIncreaseErrorComm(topic);
+ lgError($"Errore in processOtherCounters: {Environment.NewLine}{exc}");
}
}
-
///
/// Effettua lettura semafori principale Parametri da
/// aggiornare x display in form
@@ -1033,9 +988,16 @@ namespace IOB_WIN_FANUC.Iob
{
DateTime adesso = DateTime.Now;
base.readSemafori(ref currDispData);
+ string topic = $"FanucMemRW.readSemafori";
// verifico non sia in veto invio iniziale...
if (queueInEnabCurr)
{
+ // se ho errori wait proporzionale...
+ if (numErroriCheck > 0)
+ {
+ int sleepTime = rndGen.Next(50, 100) + 10 * numErroriCheck;
+ Thread.Sleep(sleepTime);
+ }
try
{
if (verboseLog)
@@ -1043,13 +1005,14 @@ namespace IOB_WIN_FANUC.Iob
lgInfo("inizio read semafori");
}
+ bool readOk = true;
currDispData.semIn = Semaforo.SV;
// ogni lettura inizia da SUA area inizio controllo area R: se ha dati (> 0
// byte) --> leggo!
if (MemBlockR.Length > 0)
{
sw.Restart();
- FanucMemRW(R, FANUC.MemType.R, areaR.startIdx, ref MemBlockR);
+ readOk = readOk && FanucMemRW(R, FANUC.MemType.R, areaR.startIdx, ref MemBlockR);
if (utils.CRB("recTime"))
{
TimingData.addResult(IOBConfFull.General.CodIOB, string.Format("R{0}-R", MemBlockR.Length), sw.ElapsedTicks);
@@ -1067,7 +1030,7 @@ namespace IOB_WIN_FANUC.Iob
if (MemBlockX.Length > 0)
{
sw.Restart();
- FanucMemRW(R, FANUC.MemType.X, areaX.startIdx, ref MemBlockX);
+ readOk = readOk && FanucMemRW(R, FANUC.MemType.X, areaX.startIdx, ref MemBlockX);
if (utils.CRB("recTime"))
{
TimingData.addResult(IOBConfFull.General.CodIOB, string.Format("R{0}-X", MemBlockX.Length), sw.ElapsedTicks);
@@ -1085,7 +1048,7 @@ namespace IOB_WIN_FANUC.Iob
if (MemBlockY.Length > 0)
{
sw.Restart();
- FanucMemRW(R, FANUC.MemType.Y, areaY.startIdx, ref MemBlockY);
+ readOk = readOk && FanucMemRW(R, FANUC.MemType.Y, areaY.startIdx, ref MemBlockY);
if (utils.CRB("recTime"))
{
TimingData.addResult(IOBConfFull.General.CodIOB, string.Format("R{0}-Y", MemBlockY.Length), sw.ElapsedTicks);
@@ -1103,13 +1066,28 @@ namespace IOB_WIN_FANUC.Iob
// salvo il solo BYTE dell'input decifrando il semaforo...
decodeToBitmap();
reportRawInput(ref currDispData);
+ // se tutte le letture OK decremento
+ if (readOk)
+ {
+ tryReduceErrorCount(topic);
+ }
}
catch (Exception exc)
{
+ tryIncreaseErrorComm(topic);
lgError(string.Format("Eccezione in readSemafori:{0}{1}", Environment.NewLine, exc));
- connectionOk = false;
currDispData.semIn = Semaforo.SR;
}
+
+ // se supero soglia errori lettura --> disconnetto e resetto
+ if (numErroriCheck > maxErroriCheck)
+ {
+ lgError($"numErroriCheck: {numErroriCheck} --> disconnessione adapter con tryDisconnect");
+
+ numErroriCheck = 0;
+ connectionOk = false;
+ tryDisconnect();
+ }
}
else
{
@@ -1125,6 +1103,7 @@ namespace IOB_WIN_FANUC.Iob
public override bool resetContapezziPLC(string codTav)
{
bool answ = false;
+ string topic = $"FanucMemRW.resetContapezziPLC";
// scrivo valore 0 x il contapezzi
try
{
@@ -1134,6 +1113,7 @@ namespace IOB_WIN_FANUC.Iob
// verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con
// indicazione area)
string memAddr = IOBConfFull.Device.PzCountMode;
+ topic = $"FanucMemRW.resetContapezziPLC.{memAddr}";
if (memAddr.StartsWith("STD"))
{
// inizio verifica area memoria/parametro levando prima parte codice
@@ -1156,7 +1136,7 @@ namespace IOB_WIN_FANUC.Iob
// processo RESET contapezzi (lavorati)
sw.Restart();
- FANUC_ref.F_RW_Param_Integer(true, cntAddr, 3, ref newVal);
+ answ = FANUC_ref.F_RW_Param_Integer(true, cntAddr, 3, ref newVal);
if (utils.CRB("recTime"))
{
TimingData.addResult(IOBConfFull.General.CodIOB, string.Format("W{0}-PAR", 4), sw.ElapsedTicks);
@@ -1195,19 +1175,19 @@ namespace IOB_WIN_FANUC.Iob
{
case "B":
byte valB = 0;
- FANUC_ref.F_RW_Byte(true, areaCounter.mType, areaCounter.mPos, ref valB);
+ answ = FANUC_ref.F_RW_Byte(true, areaCounter.mType, areaCounter.mPos, ref valB);
newVal = valB;
break;
case "D":
ushort valW = 0;
- FANUC_ref.F_RW_Word(true, areaCounter.mType, areaCounter.mPos, ref valW);
+ answ = FANUC_ref.F_RW_Word(true, areaCounter.mType, areaCounter.mPos, ref valW);
newVal = valW;
break;
case "DW":
uint valDW = 0;
- FANUC_ref.F_RW_DWord(true, areaCounter.mType, areaCounter.mPos, ref valDW);
+ answ = FANUC_ref.F_RW_DWord(true, areaCounter.mType, areaCounter.mPos, ref valDW);
break;
default:
@@ -1220,13 +1200,24 @@ namespace IOB_WIN_FANUC.Iob
}
sw.Stop();
answ = true;
+ tryReduceErrorCount(topic);
}
}
catch (Exception exc)
{
- lgError(exc, "Errore in RESET contapezzi FANUC");
- connectionOk = false;
+ tryIncreaseErrorComm(topic);
+ lgError($"Errore in RESET contapezzi FANUC | numErroriCheck: {numErroriCheck}{Environment.NewLine}{exc}");
}
+ // se supero soglia errori lettura --> disconnetto e resetto
+ if (numErroriCheck > maxErroriCheck)
+ {
+ lgError($"numErroriCheck: {numErroriCheck} --> disconnessione adapter con tryDisconnect");
+
+ numErroriCheck = 0;
+ connectionOk = false;
+ tryDisconnect();
+ }
+
return answ;
}
@@ -1269,6 +1260,7 @@ namespace IOB_WIN_FANUC.Iob
///
public bool setNumArt(int valReq)
{
+ string topic = $"FanucMemRW.setNumArt";
bool answ = false;
string memAddr = memAddrArt;
lgTrace($"INIT setNumArt | memAddr: {memAddr}");
@@ -1302,11 +1294,21 @@ namespace IOB_WIN_FANUC.Iob
}
}
sw.Stop();
+ tryReduceErrorCount(topic);
}
catch (Exception exc)
{
- lgError(exc, "Errore in setNumArt FANUC");
+ tryIncreaseErrorComm(topic);
+ lgError($"Errore in setNumArtFANUC | numErroriCheck: {numErroriCheck}{Environment.NewLine}{exc}");
+ }
+ // se supero soglia errori lettura --> disconnetto e resetto
+ if (numErroriCheck > maxErroriCheck)
+ {
+ lgError($"numErroriCheck: {numErroriCheck} --> disconnessione adapter con tryDisconnect");
+
+ numErroriCheck = 0;
connectionOk = false;
+ tryDisconnect();
}
}
return answ;
@@ -1319,6 +1321,7 @@ namespace IOB_WIN_FANUC.Iob
public bool setNumCom(int valReq)
{
bool answ = false;
+ string topic = $"FanucMemRW.setNumCom";
// verifico quale modalità sia richiesta
string memAddr = memAddrCom;
lgTrace($"INIT setNumCom | memAddr: {memAddr}");
@@ -1351,141 +1354,21 @@ namespace IOB_WIN_FANUC.Iob
}
}
sw.Stop();
+ tryReduceErrorCount(topic);
}
catch (Exception exc)
{
- lgError(exc, "Errore in setNumCom FANUC");
- connectionOk = false;
+ tryIncreaseErrorComm(topic);
+ lgError($"Errore in setNumCom | numErroriCheck: {numErroriCheck}{Environment.NewLine}{exc}");
}
- answ = true;
- }
- return answ;
- }
-
- protected bool setPzCnt(int pzCnt)
- {
- bool answ = false;
- // ...SE abilitato da conf IOB
- if (IOBConfFull.Counters.EnableSetPzCount)
- {
- // scrivo valore del contapezzi
- try
+ // se supero soglia errori lettura --> disconnetto e resetto
+ if (numErroriCheck > maxErroriCheck)
{
- string memAddr = memAddrPzCnt;
- lgTrace($"INIT setPzCnt | memAddr: {memAddr}");
- // contapezzi ATTUALE
- if (!string.IsNullOrEmpty(memAddr))
- {
- // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con
- // indicazione area)
- if (memAddr.StartsWith("STD"))
- {
- // inizio verifica area memoria/parametro levando prima parte codice
- memAddr = memAddr.Replace("STD.", "");
- }
- // var di appoggio
- int cntAddr = 0;
- // var contapezzi a zero....
- object newVal = new object();
- newVal = pzCnt;
- // verifico se si tratta di lettura parametro... formato tipo STD.PAR.6711
- if (memAddr.StartsWith("PAR."))
- {
- // recupero parametro...
- int.TryParse(memAddr.Replace("PAR.", ""), out cntAddr);
- if (cntAddr == 0)
- {
- cntAddr = 6711;
- }
+ lgError($"numErroriCheck: {numErroriCheck} --> disconnessione adapter con tryDisconnect");
- // processo SET contapezzi (lavorati)
- sw.Restart();
- FANUC_ref.F_RW_Param_Integer(true, cntAddr, 3, ref newVal);
- if (utils.CRB("recTime"))
- {
- TimingData.addResult(IOBConfFull.General.CodIOB, string.Format("W{0}-PAR", 4), sw.ElapsedTicks);
- }
- }
- else if (memAddr.StartsWith("MACRO."))
- {
- // recupero parametro...
- int.TryParse(memAddr.Replace("MACRO.", ""), out cntAddr);
- if (cntAddr == 0)
- {
- cntAddr = 9999;
- }
- lgTrace($"MACRO | Pz Write 01 | memAddr: {memAddr} | idx: {cntAddr}");
- // processo SET contapezzi (lavorati)
- sw.Restart();
- // se > 2^16 scrivo con INT, sennò con double...
- short valTrShr = 0;
- double valTrDbl = 0;
- if (pzCnt < Math.Pow(2, 16))
- {
- valTrShr = (short)pzCnt;
- answ = FanucMemMacroRW(true, cntAddr, ref valTrShr);
- //answ = FANUC_ref.F_RW_Macro_Short(true, cntAddr, ref valTrShr);
- lgTrace($"MACRO | Com Write 02 SHORT | memAddr: {memAddr} | pzCnt: {pzCnt} | valTrShr: {valTrShr}");
- }
- // sennò double!
- else
- {
- valTrDbl = (double)pzCnt;
- answ = FanucMemMacroRW(true, cntAddr, ref valTrDbl);
- //answ = FANUC_ref.F_RW_Macro_Double(true, cntAddr, ref valTrDbl);
- lgTrace($"MACRO | Com Write 02 DOUBLE | memAddr: {memAddr} | pzCnt: {pzCnt} | valTrDbl: {valTrDbl}");
- }
- if (utils.CRB("recTime"))
- {
- TimingData.addResult(IOBConfFull.General.CodIOB, "MACRO-SHORT", sw.ElapsedTicks);
- }
- }
- // altrimenti se legge da area memoria specifica leggo da li... formto tipo STD.D.1604.DW
- else
- {
- memAddressFanuc areaCounter = new memAddressFanuc(memAddr);
-
- if (isVerboseLog)
- {
- lgInfo("setPzComm [0] area memoria: {0}.{1}.{2}", areaCounter.mType, areaCounter.mPos, areaCounter.vType);
- }
- // leggo!
- sw.Restart();
- // switch x tipo dati --> tipo lettura... e salvo ultimo conteggio rilevato
- switch (areaCounter.vType)
- {
- case "B":
- byte valB = (byte)pzCnt;
- FANUC_ref.F_RW_Byte(true, areaCounter.mType, areaCounter.mPos, ref valB);
- newVal = valB;
- break;
-
- case "D":
- ushort valW = (ushort)pzCnt;
- FANUC_ref.F_RW_Word(true, areaCounter.mType, areaCounter.mPos, ref valW);
- newVal = valW;
- break;
-
- case "DW":
- uint valDW = (uint)pzCnt;
- FANUC_ref.F_RW_DWord(true, areaCounter.mType, areaCounter.mPos, ref valDW);
- break;
-
- default:
- break;
- }
- if (utils.CRB("recTime"))
- {
- TimingData.addResult(IOBConfFull.General.CodIOB, string.Format("W-{0}.{1}.{2}", areaCounter.mType, areaCounter.mPos, areaCounter.vType), sw.ElapsedTicks);
- }
- }
- sw.Stop();
- }
- }
- catch (Exception exc)
- {
- lgError($"Errore in SET PzReq Commessa FANUC{Environment.NewLine}{exc}");
+ numErroriCheck = 0;
connectionOk = false;
+ tryDisconnect();
}
answ = true;
}
@@ -1498,6 +1381,7 @@ namespace IOB_WIN_FANUC.Iob
///
public override bool setPzComm(int pzReq)
{
+ string topic = $"FanucMemRW.setPzComm";
bool answ = false;
// ...SE abilitato da conf IOB
if (IOBConfFull.Counters.EnableSetPzReq)
@@ -1534,7 +1418,7 @@ namespace IOB_WIN_FANUC.Iob
// processo SET contapezzi (lavorati)
sw.Restart();
- FANUC_ref.F_RW_Param_Integer(true, cntAddr, 3, ref newVal);
+ answ = FANUC_ref.F_RW_Param_Integer(true, cntAddr, 3, ref newVal);
if (utils.CRB("recTime"))
{
TimingData.addResult(IOBConfFull.General.CodIOB, string.Format("W{0}-PAR", 4), sw.ElapsedTicks);
@@ -1590,19 +1474,19 @@ namespace IOB_WIN_FANUC.Iob
{
case "B":
byte valB = (byte)pzReq;
- FANUC_ref.F_RW_Byte(true, areaCounter.mType, areaCounter.mPos, ref valB);
+ answ = FANUC_ref.F_RW_Byte(true, areaCounter.mType, areaCounter.mPos, ref valB);
newVal = valB;
break;
case "D":
ushort valW = (ushort)pzReq;
- FANUC_ref.F_RW_Word(true, areaCounter.mType, areaCounter.mPos, ref valW);
+ answ = FANUC_ref.F_RW_Word(true, areaCounter.mType, areaCounter.mPos, ref valW);
newVal = valW;
break;
case "DW":
uint valDW = (uint)pzReq;
- FANUC_ref.F_RW_DWord(true, areaCounter.mType, areaCounter.mPos, ref valDW);
+ answ = FANUC_ref.F_RW_DWord(true, areaCounter.mType, areaCounter.mPos, ref valDW);
break;
default:
@@ -1614,12 +1498,22 @@ namespace IOB_WIN_FANUC.Iob
}
}
sw.Stop();
+ tryReduceErrorCount(topic);
}
}
catch (Exception exc)
{
- lgError($"Errore in SET PzReq Commessa FANUC{Environment.NewLine}{exc}");
+ tryIncreaseErrorComm(topic);
+ lgError($"Errore in SET PzReq Commessa | numErroriCheck: {numErroriCheck}{Environment.NewLine}{exc}");
+ }
+ // se supero soglia errori lettura --> disconnetto e resetto
+ if (numErroriCheck > maxErroriCheck)
+ {
+ lgError($"numErroriCheck: {numErroriCheck} --> disconnessione adapter con tryDisconnect");
+
+ numErroriCheck = 0;
connectionOk = false;
+ tryDisconnect();
}
answ = true;
}
@@ -1631,6 +1525,7 @@ namespace IOB_WIN_FANUC.Iob
///
public override void tryConnect()
{
+ lgInfo("++++++++++++ CONNECT ++++++++++++");
if (!connectionOk)
{
// controllo che il ping sia stato tentato almeno pingTestSec fa...
@@ -1671,10 +1566,19 @@ namespace IOB_WIN_FANUC.Iob
{
// ora provo connessione...
parentForm.commPlcActive = true;
+ // se connesso disconnetto...
+ if (FANUC_ref.Connected)
+ {
+ FANUC_ref.Disconnect(ref szStatusConnection);
+ lgInfo($"FANUC_ref preliminary DISCONNECT | connStatus: {FANUC_ref.Connected}| szStatusConnection: {szStatusConnection}");
+ // aspetto
+ Thread.Sleep(500);
+ }
FANUC_ref.Connect(ref szStatusConnection);
parentForm.commPlcActive = false;
- lgInfo("szStatusConnection: " + szStatusConnection);
- connectionOk = true;
+ lgInfo($"FANUC_ref CONNECT | connected: {FANUC_ref.Connected}| szStatusConnection: {szStatusConnection}");
+ connectionOk = FANUC_ref.Connected;
+
// refresh stato allarmi!!!
if (connectionOk)
{
@@ -1721,17 +1625,18 @@ namespace IOB_WIN_FANUC.Iob
///
public override void tryDisconnect()
{
+ lgInfo("----------- DISCONNECT -----------");
if (connectionOk)
{
string szStatusConnection = "";
try
{
FANUC_ref.Disconnect(ref szStatusConnection);
+ Thread.Sleep(500);
connectionOk = false;
// resetto timing!
TimingData.resetData();
- lgInfo(szStatusConnection);
- lgInfo("Effettuata disconnessione adapter FANUC!");
+ lgInfo($"Effettuata disconnessione adapter FANUC! | connectred: {FANUC_ref.Connected} | szStatusConnection: {szStatusConnection}");
}
catch (Exception exc)
{
@@ -1747,7 +1652,7 @@ namespace IOB_WIN_FANUC.Iob
#endregion Public Methods
- #region Internal Fields
+ #region Internal Properties
///
/// LookUpTable di decodifica da CNC a segnali tipo bitmap MAPO
@@ -1757,7 +1662,7 @@ namespace IOB_WIN_FANUC.Iob
get => IOBConfFull.Device.SigLUT;
}
- #endregion Internal Fields
+ #endregion Internal Properties
#region Protected Fields
@@ -1890,8 +1795,158 @@ namespace IOB_WIN_FANUC.Iob
}
}
+ protected bool setPzCnt(int pzCnt)
+ {
+ string topic = $"FanucMemRW.setPzCnt";
+ bool answ = false;
+ // ...SE abilitato da conf IOB
+ if (IOBConfFull.Counters.EnableSetPzCount)
+ {
+ // scrivo valore del contapezzi
+ try
+ {
+ string memAddr = memAddrPzCnt;
+ lgTrace($"INIT setPzCnt | memAddr: {memAddr}");
+ // contapezzi ATTUALE
+ if (!string.IsNullOrEmpty(memAddr))
+ {
+ // verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con
+ // indicazione area)
+ if (memAddr.StartsWith("STD"))
+ {
+ // inizio verifica area memoria/parametro levando prima parte codice
+ memAddr = memAddr.Replace("STD.", "");
+ }
+ // var di appoggio
+ int cntAddr = 0;
+ // var contapezzi a zero....
+ object newVal = new object();
+ newVal = pzCnt;
+ // verifico se si tratta di lettura parametro... formato tipo STD.PAR.6711
+ if (memAddr.StartsWith("PAR."))
+ {
+ // recupero parametro...
+ int.TryParse(memAddr.Replace("PAR.", ""), out cntAddr);
+ if (cntAddr == 0)
+ {
+ cntAddr = 6711;
+ }
+
+ // processo SET contapezzi (lavorati)
+ sw.Restart();
+ FANUC_ref.F_RW_Param_Integer(true, cntAddr, 3, ref newVal);
+ if (utils.CRB("recTime"))
+ {
+ TimingData.addResult(IOBConfFull.General.CodIOB, string.Format("W{0}-PAR", 4), sw.ElapsedTicks);
+ }
+ }
+ else if (memAddr.StartsWith("MACRO."))
+ {
+ // recupero parametro...
+ int.TryParse(memAddr.Replace("MACRO.", ""), out cntAddr);
+ if (cntAddr == 0)
+ {
+ cntAddr = 9999;
+ }
+ lgTrace($"MACRO | Pz Write 01 | memAddr: {memAddr} | idx: {cntAddr}");
+ // processo SET contapezzi (lavorati)
+ sw.Restart();
+ // se > 2^16 scrivo con INT, sennò con double...
+ short valTrShr = 0;
+ double valTrDbl = 0;
+ if (pzCnt < Math.Pow(2, 16))
+ {
+ valTrShr = (short)pzCnt;
+ answ = FanucMemMacroRW(true, cntAddr, ref valTrShr);
+ //answ = FANUC_ref.F_RW_Macro_Short(true, cntAddr, ref valTrShr);
+ lgTrace($"MACRO | Com Write 02 SHORT | memAddr: {memAddr} | pzCnt: {pzCnt} | valTrShr: {valTrShr}");
+ }
+ // sennò double!
+ else
+ {
+ valTrDbl = (double)pzCnt;
+ answ = FanucMemMacroRW(true, cntAddr, ref valTrDbl);
+ //answ = FANUC_ref.F_RW_Macro_Double(true, cntAddr, ref valTrDbl);
+ lgTrace($"MACRO | Com Write 02 DOUBLE | memAddr: {memAddr} | pzCnt: {pzCnt} | valTrDbl: {valTrDbl}");
+ }
+ if (utils.CRB("recTime"))
+ {
+ TimingData.addResult(IOBConfFull.General.CodIOB, "MACRO-SHORT", sw.ElapsedTicks);
+ }
+ }
+ // altrimenti se legge da area memoria specifica leggo da li... formto tipo STD.D.1604.DW
+ else
+ {
+ memAddressFanuc areaCounter = new memAddressFanuc(memAddr);
+
+ if (isVerboseLog)
+ {
+ lgInfo("setPzComm [0] area memoria: {0}.{1}.{2}", areaCounter.mType, areaCounter.mPos, areaCounter.vType);
+ }
+ // leggo!
+ sw.Restart();
+ // switch x tipo dati --> tipo lettura... e salvo ultimo conteggio rilevato
+ switch (areaCounter.vType)
+ {
+ case "B":
+ byte valB = (byte)pzCnt;
+ FANUC_ref.F_RW_Byte(true, areaCounter.mType, areaCounter.mPos, ref valB);
+ newVal = valB;
+ break;
+
+ case "D":
+ ushort valW = (ushort)pzCnt;
+ FANUC_ref.F_RW_Word(true, areaCounter.mType, areaCounter.mPos, ref valW);
+ newVal = valW;
+ break;
+
+ case "DW":
+ uint valDW = (uint)pzCnt;
+ FANUC_ref.F_RW_DWord(true, areaCounter.mType, areaCounter.mPos, ref valDW);
+ break;
+
+ default:
+ break;
+ }
+ if (utils.CRB("recTime"))
+ {
+ TimingData.addResult(IOBConfFull.General.CodIOB, string.Format("W-{0}.{1}.{2}", areaCounter.mType, areaCounter.mPos, areaCounter.vType), sw.ElapsedTicks);
+ }
+ }
+ sw.Stop();
+ tryReduceErrorCount(topic);
+ }
+ }
+ catch (Exception exc)
+ {
+ tryIncreaseErrorComm(topic);
+ lgError($"Errore in SET PzCnt | numErroriCheck: {numErroriCheck}{Environment.NewLine}{exc}");
+ }
+ // se supero soglia errori lettura --> disconnetto e resetto
+ if (numErroriCheck > maxErroriCheck)
+ {
+ lgError($"numErroriCheck: {numErroriCheck} --> disconnessione adapter con tryDisconnect");
+
+ numErroriCheck = 0;
+ connectionOk = false;
+ tryDisconnect();
+ }
+ answ = true;
+ }
+ return answ;
+ }
+
#endregion Protected Methods
+ #region Private Fields
+
+ ///
+ /// Oggetto logger della classe
+ ///
+ private static Logger _logger = LogManager.GetCurrentClassLogger();
+
+ #endregion Private Fields
+
#region Private Properties
///
@@ -2288,6 +2343,207 @@ namespace IOB_WIN_FANUC.Iob
#region Private Methods
+
+ ///
+ /// Calcola il valore bitmap segnale in uscita data la bVal (mem area + bit) + indice i
+ ///
+ /// Conf memoria da signalLUT
+ /// Indice del bit x calcolo out
+ /// Byte completo recuperato
+ /// Indice bit cercato
+ ///
+ private int CalcAreaBitOut(string bVal, int i, ref int byte2check, ref int bitNum)
+ {
+ // OUT valore
+ int outVal = 0;
+ // var accessorie
+ int byteNum = 0;
+ bool invSignal = false;
+ char area;
+ string memArea = "";
+ string[] memIdx;
+ // di norma è segnale normale => 1, altrimenti inverse => 0...
+ // cerco se sia inverse (primo char "!") --> registro e elimino char...
+ invSignal = bVal.StartsWith("!");
+ // tolgo comunque inversione...
+ bVal = bVal.Replace("!", "");
+ // recupero area...
+ area = bVal[0];
+ // altrimenti decodifico area...
+ memArea = bVal.Substring(1, bVal.Length - 1);
+ memIdx = memArea.Split('.');
+ // calcolo bit e byte number...
+ int.TryParse(memIdx[0], out byteNum);
+ if (memIdx.Length > 1)
+ {
+ int.TryParse(memIdx[1], out bitNum);
+ }
+ // in base al nome cerco in una delle aree.. e prendo solo solo quel bit
+ // di quel byte...
+ switch (area)
+ {
+ case 'G':
+ byte2check = MemBlockG[byteNum];
+ break;
+
+ case 'R':
+ byte2check = MemBlockR[byteNum];
+ break;
+
+ case 'X':
+ byte2check = MemBlockX[byteNum];
+ break;
+
+ case 'Y':
+ byte2check = MemBlockY[byteNum];
+ break;
+
+ default:
+ break;
+ }
+ // a secondo che sia segnale normale o inverso...
+ if (invSignal)
+ {
+ // controllo se il bit sia NON attivo (basso)... == 0...
+ if ((byte2check & (1 << bitNum)) == 0)
+ {
+ outVal += 1 << i;
+ }
+ }
+ else
+ {
+ // controllo se il bit sia attivo (alto)... != 0
+ if ((byte2check & (1 << bitNum)) != 0)
+ {
+ outVal += 1 << i;
+ }
+ }
+ return outVal;
+ }
+
+ ///
+ /// Calcola valore bitmap segnale in uscita data condizione programName
+ ///
+ /// Conf search programma: nome e se inizia per % ricerca LIKE
+ /// Indice del bit x calcolo out
+ private int CalProgNameBitOut(string confTest, int i)
+ {
+ // OUT valore
+ int outVal = 0;
+ string prgNameTgt = "";
+ // il valore da cercare è quello inserito dopo il segno pipe...
+ if (confTest.Contains("|"))
+ {
+ var prgData = confTest.Split('|');
+ if (prgData.Length > 1)
+ {
+ prgNameTgt = prgData[1];
+ }
+ }
+ // ora verifico se prog corrente è valido
+ if (!string.IsNullOrEmpty(currPrgName))
+ {
+ // se contiene % allora cerco x like
+ if (prgNameTgt.Contains("%"))
+ {
+ // e se sia uguale al valore tgt senza %
+ if (currPrgName.Contains(prgNameTgt.Replace("%", "")))
+ {
+ // inserisco bit!
+ outVal += 1 << i;
+ }
+ }
+ // altrimenti ricerca puntuale (prima versione)
+ else
+ {
+ // e se sia uguale al valore tgt
+ if (currPrgName == prgNameTgt)
+ {
+ // inserisco bit!
+ outVal += 1 << i;
+ }
+ }
+ }
+ return outVal;
+ }
+
+ ///
+ /// Verifica se effettuare invio (a scadenza) del valore counter richiesto
+ ///
+ ///
+ ///
+ ///
+ private async Task checkSendCounter(string varName, string currMemName, string currMemAddr)
+ {
+ string topic = $"FanucMemRW.checkSendCounter.{currMemName}";
+ // gestione con ricerca in memoria Write / optPar...
+ if (string.IsNullOrEmpty(currMemAddr))
+ {
+ lgTrace($"{varName} disabilitato | currMemAddr vuoto | NO memConf.Read | NO optPar");
+ }
+ else
+ {
+ try
+ {
+ DateTime adesso = DateTime.Now;
+ int currPeriod = memPeriod(currMemName);
+ // se non ha periodo abilito invio
+ bool doSend = currPeriod == 0;
+ string vetoType = "DEFAULT";
+ if (currPeriod == 0)
+ {
+ // ma imposto cmq un poeriodo veto a 15 min...
+ currPeriod = 15 * 60;
+ }
+ else
+ {
+ vetoType = "EXPLICIT";
+ }
+
+ // controllo comunque scadenza...
+ if (VetoCounterSend.ContainsKey(currMemName))
+ {
+ // verifico scadenza...
+ if (VetoCounterSend[currMemName] < adesso)
+ {
+ VetoCounterSend[currMemName] = adesso.AddSeconds(currPeriod);
+ doSend = true;
+ lgInfo($"checkSendCounter | set veto {vetoType} ({currPeriod}) for {varName} at {VetoCounterSend[currMemName]:HH:mm:ss}");
+ }
+ }
+ else
+ {
+ VetoCounterSend.Add(currMemName, adesso.AddSeconds(currPeriod));
+ doSend = true;
+ lgTrace($"{varName} | Veto {vetoType} still active until {VetoCounterSend[currMemName]:HH:mm:ss}");
+ }
+
+ // per il counter verifico SE sia da inviare...
+ if (doSend)
+ {
+ await sendOptVal(currMemName, getValByMemAddr(currMemAddr));
+ tryReduceErrorCount(topic);
+ }
+ }
+ catch (Exception exc)
+ {
+ tryIncreaseErrorComm(topic);
+ lgError($"Eccezione | processOtherCounters.checkSendCounter | {varName} | {currMemName} | {currMemAddr} | numErroriCheck: {numErroriCheck}{Environment.NewLine}{exc}");
+ // attesa 10ms post errore...
+ await Task.Delay(10);
+ }
+ // se supero soglia errori lettura --> disconnetto e resetto
+ if (numErroriCheck > maxErroriCheck)
+ {
+ lgError($"numErroriCheck: {numErroriCheck} --> disconnessione adapter con tryDisconnect");
+
+ numErroriCheck = 0;
+ connectionOk = false;
+ tryDisconnect();
+ }
+ }
+ }
+
///
/// Effettua decodifica aree memoria alla bitmap usata x MAPO
///
@@ -2485,129 +2741,6 @@ namespace IOB_WIN_FANUC.Iob
}
}
- ///
- /// Calcola valore bitmap segnale in uscita data condizione programName
- ///
- /// Conf search programma: nome e se inizia per % ricerca LIKE
- /// Indice del bit x calcolo out
- private int CalProgNameBitOut(string confTest, int i)
- {
- // OUT valore
- int outVal = 0;
- string prgNameTgt = "";
- // il valore da cercare è quello inserito dopo il segno pipe...
- if (confTest.Contains("|"))
- {
- var prgData = confTest.Split('|');
- if (prgData.Length > 1)
- {
- prgNameTgt = prgData[1];
- }
- }
- // ora verifico se prog corrente è valido
- if (!string.IsNullOrEmpty(currPrgName))
- {
- // se contiene % allora cerco x like
- if (prgNameTgt.Contains("%"))
- {
- // e se sia uguale al valore tgt senza %
- if (currPrgName.Contains(prgNameTgt.Replace("%", "")))
- {
- // inserisco bit!
- outVal += 1 << i;
- }
- }
- // altrimenti ricerca puntuale (prima versione)
- else
- {
- // e se sia uguale al valore tgt
- if (currPrgName == prgNameTgt)
- {
- // inserisco bit!
- outVal += 1 << i;
- }
- }
- }
- return outVal;
- }
-
- ///
- /// Calcola il valore bitmap segnale in uscita data la bVal (mem area + bit) + indice i
- ///
- /// Conf memoria da signalLUT
- /// Indice del bit x calcolo out
- /// Byte completo recuperato
- /// Indice bit cercato
- ///
- private int CalcAreaBitOut(string bVal, int i, ref int byte2check, ref int bitNum)
- {
- // OUT valore
- int outVal = 0;
- // var accessorie
- int byteNum = 0;
- bool invSignal = false;
- char area;
- string memArea = "";
- string[] memIdx;
- // di norma è segnale normale => 1, altrimenti inverse => 0...
- // cerco se sia inverse (primo char "!") --> registro e elimino char...
- invSignal = bVal.StartsWith("!");
- // tolgo comunque inversione...
- bVal = bVal.Replace("!", "");
- // recupero area...
- area = bVal[0];
- // altrimenti decodifico area...
- memArea = bVal.Substring(1, bVal.Length - 1);
- memIdx = memArea.Split('.');
- // calcolo bit e byte number...
- int.TryParse(memIdx[0], out byteNum);
- if (memIdx.Length > 1)
- {
- int.TryParse(memIdx[1], out bitNum);
- }
- // in base al nome cerco in una delle aree.. e prendo solo solo quel bit
- // di quel byte...
- switch (area)
- {
- case 'G':
- byte2check = MemBlockG[byteNum];
- break;
-
- case 'R':
- byte2check = MemBlockR[byteNum];
- break;
-
- case 'X':
- byte2check = MemBlockX[byteNum];
- break;
-
- case 'Y':
- byte2check = MemBlockY[byteNum];
- break;
-
- default:
- break;
- }
- // a secondo che sia segnale normale o inverso...
- if (invSignal)
- {
- // controllo se il bit sia NON attivo (basso)... == 0...
- if ((byte2check & (1 << bitNum)) == 0)
- {
- outVal += 1 << i;
- }
- }
- else
- {
- // controllo se il bit sia attivo (alto)... != 0
- if ((byte2check & (1 << bitNum)) != 0)
- {
- outVal += 1 << i;
- }
- }
- return outVal;
- }
-
///
/// Dump area D della memoria
///
@@ -2748,6 +2881,25 @@ namespace IOB_WIN_FANUC.Iob
utils.WritePlain(mappaValori, nomeFile);
}
+ ///
+ /// Formatta area x memorie Fanuc da conf caricata
+ ///
+ ///
+ ///
+ ///
+ private memAreaFanuc FormatAreaFanuc(string aName, string mKey)
+ {
+ var newArea = new memAreaFanuc() { areaName = aName };
+ if (IOBConfFull.Special.BankConf.AreaConf.ContainsKey(mKey))
+ {
+ var thisConf = IOBConfFull.Special.BankConf.AreaConf[mKey];
+ newArea.startIdx = thisConf.Start;
+ newArea.arraySize = thisConf.Size;
+ }
+
+ return newArea;
+ }
+
///
/// Recupera il valore INT dal nome del parametro per successivo processing
///
@@ -2861,6 +3013,24 @@ namespace IOB_WIN_FANUC.Iob
return answ;
}
+ private void tryIncreaseErrorComm(string topic)
+ {
+ lgTrace($"[Thread: {Thread.CurrentThread.ManagedThreadId}] | numErroriCheck: {numErroriCheck}");
+ numErroriCheck++;
+ parentForm.ChangeErrorDelay(topic, numErroriCheck, 5);
+ }
+
+ private void tryReduceErrorCount(string topic)
+ {
+ numErroriCheck -= 1;
+ if (numErroriCheck>=0)
+ {
+ lgTrace($"[Thread: {Thread.CurrentThread.ManagedThreadId}] | numErroriCheck: {numErroriCheck}");
+ }
+ numErroriCheck = numErroriCheck < 0 ? 0 : numErroriCheck;
+ parentForm.ChangeErrorDelay(topic, numErroriCheck, -5);
+ }
+
#endregion Private Methods
}
}
\ No newline at end of file
diff --git a/IOB-WIN-FANUC/postBuildTgt.bat b/IOB-WIN-FANUC/postBuildTgt.bat
index 520cfb94..556d3e50 100644
--- a/IOB-WIN-FANUC/postBuildTgt.bat
+++ b/IOB-WIN-FANUC/postBuildTgt.bat
@@ -48,6 +48,7 @@ REM ROBOCOPY %2 \\192.168.1.133\Steamware\IOB-WIN-FANUC-DEB /MIR
REM ROBOCOPY %2 \\10.51.90.10\Steamware\IOB-WIN-FANUC-DEB /MIR
REM ROBOCOPY %2 \\10.51.90.14\Steamware\IOB-WIN-FANUC-DEB /MIR
REM ROBOCOPY %2 \\10.51.90.13\Steamware\IOB-WIN-FANUC-DEB /MIR
+
ROBOCOPY %2 \\10.51.90.15\Steamware\IOB-WIN-FANUC-DEB /MIR
REM ROBOCOPY %2 \\10.51.90.9\Steamware\IOB-WIN-FANUC-DEB /MIR
diff --git a/IOB-WIN-FORM/AdapterForm.cs b/IOB-WIN-FORM/AdapterForm.cs
index eeba20c4..09919c3f 100644
--- a/IOB-WIN-FORM/AdapterForm.cs
+++ b/IOB-WIN-FORM/AdapterForm.cs
@@ -1,5 +1,6 @@
using IOB_UT_NEXT;
using IOB_UT_NEXT.Config;
+using IOB_UT_NEXT.Config.Base;
using MapoSDK;
using Newtonsoft.Json;
using NLog;
@@ -7,6 +8,7 @@ using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Diagnostics.Eventing.Reader;
using System.Drawing;
using System.IO;
using System.Linq;
@@ -275,7 +277,7 @@ namespace IOB_WIN_FORM
{
// update veto!
dMonDisplVetoVeto[1] = adesso.AddMilliseconds(delayShowLogMs);
-
+
if (!ShouldUpdateUI()) return;
// se scaduto veto --> display!
lblOutMessage.Text = String.Join(Environment.NewLine, dMonValues[1]);
@@ -748,20 +750,36 @@ namespace IOB_WIN_FORM
restart.Enabled = true;
// 2026.01.02 fix timers al restart
gather.Enabled = true;
+
+#if true
// gestione worker
StartWorker();
+#endif
displayTaskAndLog("Start Timers", true);
+
// inizializzo le scadenze dei timers...
+ DateTime adesso = DateTime.Now;
+
+#if false
TimersVeto = new Dictionary();
TimersCycleCount = new Dictionary();
- TimersCycleElaps = new Dictionary();
- DateTime adesso = DateTime.Now;
+ TimersCycleElaps = new Dictionary();
+#endif
foreach (gatherCycle item in Enum.GetValues(typeof(gatherCycle)))
{
- // setup iniziale deterministico
+ // setup iniziale deterministico dei 2 obj gestione
+ TimerMachine.Veto.Add(item, adesso.AddMilliseconds(iobObj.IOBConfFull.TimerMs(item, 0)));
+ TimerMachine.CycleCount.Add(item, 0);
+ TimerMachine.CycleElaps.Add(item, 0);
+
+ TimerServer.Veto.Add(item, adesso.AddMilliseconds(iobObj.IOBConfFull.TimerMs(item, 0)));
+ TimerServer.CycleCount.Add(item, 0);
+ TimerServer.CycleElaps.Add(item, 0);
+#if false
TimersVeto.Add(item, adesso.AddMilliseconds(iobObj.IOBConfFull.TimerMs(item, 0)));
TimersCycleCount.Add(item, 0);
- TimersCycleElaps.Add(item, 0);
+ TimersCycleElaps.Add(item, 0);
+#endif
}
sendStartFLog = utils.CRB("sendStartFLog");
displayTaskAndLog("Adapter Running...", true);
@@ -788,6 +806,31 @@ namespace IOB_WIN_FORM
}
}
+ ///
+ /// Registra variazione error delay in caso di errori o successi
+ ///
+ ///
+ ///
+ ///
+ public void ChangeErrorDelay(string topic, int currCount, int delta)
+ {
+ _errorDelay += delta;
+ // se fosse negativo --> riporto a zero!
+ _errorDelay = _errorDelay < 0 ? 0 : _errorDelay;
+ // registro LOG variazione
+ if (delta > 0)
+ {
+ lgTrace($"[Thread: {Thread.CurrentThread.ManagedThreadId}] | +++ delay {_errorDelay} | {topic} | err: {currCount} | {DateTime.Now:HH:mm:ss.fff}");
+ }
+ else
+ {
+ if (_errorDelay > 0)
+ {
+ lgTrace($"[Thread: {Thread.CurrentThread.ManagedThreadId}] | --- delay {_errorDelay} | {topic} | err: {currCount} | {DateTime.Now:HH:mm:ss.fff}");
+ }
+ }
+ }
+
///
/// mostra un testo sulla status bar + LOG
///
@@ -1084,6 +1127,28 @@ namespace IOB_WIN_FORM
base.Dispose(disposing);
}
+ ///
+ /// Esegue logica di init async x IOB
+ ///
+ ///
+ protected async Task iobInitAsync()
+ {
+ try
+ {
+ this.Cursor = Cursors.WaitCursor;
+ await iobObj.InitializeAsync();
+ this.Cursor = Cursors.Default;
+ }
+ catch (Exception ex)
+ {
+ lgError($"Inizializzazione fallita per {tipoScelto}: {ex.Message}");
+ iobObj = null; // Evitiamo di usare un oggetto malfunzionante
+ return false;
+ }
+
+ return true;
+ }
+
///
/// GEstione evento refresh
///
@@ -1184,28 +1249,6 @@ namespace IOB_WIN_FORM
}
}
- ///
- /// Esegue logica di init async x IOB
- ///
- ///
- protected async Task iobInitAsync()
- {
- try
- {
- this.Cursor = Cursors.WaitCursor;
- await iobObj.InitializeAsync();
- this.Cursor = Cursors.Default;
- }
- catch (Exception ex)
- {
- lgError($"Inizializzazione fallita per {tipoScelto}: {ex.Message}");
- iobObj = null; // Evitiamo di usare un oggetto malfunzionante
- return false;
- }
-
- return true;
- }
-
///
/// Init form (grafica) con helper x testi e varie
///
@@ -1248,25 +1291,6 @@ namespace IOB_WIN_FORM
nLine2show = utils.CRI("numRowConsole");
}
- ///
- /// Indica se debba aggiornare o meno la UI perché minimizzata o meno
- ///
- ///
- private bool ShouldUpdateUI()
- {
- // 1. Controlla se la form stessa è minimizzata
- if (this.WindowState == FormWindowState.Minimized) return false;
-
- // 2. Se è una MDI Child, controlla se il Padre è minimizzato
- if (this.MdiParent != null && this.MdiParent.WindowState == FormWindowState.Minimized)
- return false;
-
- // 3. (Opzionale) Controlla se la form è visibile
- if (!this.Visible) return false;
-
- return true;
- }
-
///
/// MOstra info su coda complessiva
///
@@ -1296,15 +1320,48 @@ namespace IOB_WIN_FORM
#region Private Fields
+ ///
+ /// Task factory single threaded
+ ///
+ private static readonly TaskFactory _singleFactory = new TaskFactory(_singleScheduler);
+
+ ///
+ /// Scheduler single threaded
+ ///
+ private static readonly SingleThreadTaskScheduler _singleScheduler = new SingleThreadTaskScheduler("IOB-SINGLE");
+
private readonly object _lock = new object();
- private CancellationTokenSource _cts;
+ ///
+ /// Usato come semaforo x evitare doppio uso risorse threaded
+ ///
+ private readonly SemaphoreSlim _plcLock = new SemaphoreSlim(1, 1);
+
+ ///
+ /// Cancellation token x processi verso macchina
+ ///
+ private CancellationTokenSource _ctsMachine;
+
+ ///
+ /// Cancellation tocken x processi verso server
+ ///
+ private CancellationTokenSource _ctsServer;
+
+ ///
+ /// Ritardo per errori (extra nei cicli)
+ ///
+ private int _errorDelay = 0;
// Per thread-safety
private bool _isSuspended = false;
+ private FormWindowState _lastState = FormWindowState.Minimized;
+
private Task _workerTask;
+ private bool stopForced = false;
+
+#if false
///
/// Contatore chiamate timers x debug timing
///
@@ -1318,7 +1375,18 @@ namespace IOB_WIN_FORM
///
/// Dizionario scadenza timers interni x esecuzione dei vari task a differente frequenza di chiamata
///
- private Dictionary TimersVeto = new Dictionary();
+ private Dictionary TimersVeto = new Dictionary();
+#endif
+
+ ///
+ /// Obj gestione Timer per esecuzione Task con Machine
+ ///
+ private TimerMan TimerMachine = new TimerMan(TimerMan.ContextType.Machine);
+
+ ///
+ /// Obj gestione Timer per esecuzione Task con Server
+ ///
+ private TimerMan TimerServer = new TimerMan(TimerMan.ContextType.Server);
///
/// Dizionario dei valori bloccati x evitare log eccessivo
@@ -1373,7 +1441,7 @@ namespace IOB_WIN_FORM
if (IOBConfFull == null || !utils.CRB("autoLoadConf"))
{
IOBConfFull = new IobConfTree();
- loadIobType();
+ await loadIobType();
displayTaskAndLog("Waiting for config file selection");
}
@@ -1424,11 +1492,13 @@ namespace IOB_WIN_FORM
lgError($"AdapterForm: EXCEPTION in fase di chiamata URL di reboot:{iobObj.urlReboot}{Environment.NewLine}{exc}");
}
+#if false
// avvio timer secondario x esecuzione (periodo di base: VHF!!!)
StartWorker();
+#endif
displayTaskAndLog($"Main workerTimer set: {IOBConfFull.General.Timers.MsVHF}ms", true);
}
- displayTaskAndLog("Main Form OK", true);
+ displayTaskAndLog("Adapter Form OK", true);
}
private void btnForceAutoOdl_Click(object sender, EventArgs e)
@@ -1509,11 +1579,129 @@ namespace IOB_WIN_FORM
}
}
+ ///
+ /// Verifica scadenza task nell'oggetto Pool
+ ///
+ ///
+ private async Task checkScadPoolAsync()
+ {
+ DateTime adesso = DateTime.Now;
+ bool sendDone = false;
+ // ciclo su tutti i timers enum superiori a VHF
+ var priorities = (gatherCycle[])Enum.GetValues(typeof(gatherCycle));
+ // prendo solo > VHF e ordino discendenti x dare priorità ai più rari...
+ var ordered = priorities.Where(x => x > gatherCycle.VHF).OrderByDescending(x => x);
+ foreach (gatherCycle item in ordered)
+ {
+ if (TimerServer.Veto.ContainsKey(item))
+ {
+ if (TimerServer.Veto[item] <= adesso)
+ {
+ // se non ho già processato a questo giro...
+ if (!sendDone)
+ {
+ TimerServer.CycleCount[item]++;
+
+ Stopwatch sw = Stopwatch.StartNew();
+ await iobObj.doServerTaskAsync(item);
+ sw.Stop();
+
+ sendDone = true;
+ // metto una piccola attesa se ho altre scadenze
+ TimerServer.CycleElaps[item] += sw.Elapsed.TotalMilliseconds;
+ // metto nuova scadenza perturbata 10%
+ TimerServer.Veto[item] = adesso.AddMilliseconds(iobObj.IOBConfFull.TimerMs(item, 0.1));
+ }
+ // log + reset se ho contato ALMENO 100 exec o il tempo totale supera 1000msec
+ int limMs = 10000;
+ double totalMs = TimerServer.CycleElaps.ContainsKey(item) ? TimerServer.CycleElaps[item] : 0;
+ if (TimerServer.CycleCount[item] >= 100 || totalMs > limMs)
+ {
+ int nCount = Math.Max(TimerServer.CycleCount[item], 1);
+ lgDebug($"Timer.{TimerServer.Contesto} | checkScadPoolAsync | {item} | {totalMs / nCount:F1}ms x {nCount}");
+ TimerServer.CycleCount[item] = 0;
+ TimerServer.CycleElaps[item] = 0;
+ }
+ }
+ }
+ else
+ {
+ TimerServer.Veto.Add(item, adesso.AddMilliseconds(iobObj.IOBConfFull.TimerMs(item, 0)));
+ TimerServer.CycleCount.Add(item, 0);
+ if (!TimerServer.CycleElaps.ContainsKey(item))
+ {
+ TimerServer.CycleElaps.Add(item, 0);
+ }
+ }
+ }
+ }
+
+
+ ///
+ /// Verifica scadenza task Machine
+ ///
+ ///
+ private void checkScadMachine()
+ {
+ DateTime adesso = DateTime.Now;
+ bool sendDone = false;
+ // ciclo su tutti i timers enum superiori a VHF
+ var priorities = (gatherCycle[])Enum.GetValues(typeof(gatherCycle));
+ // prendo solo > VHF e ordino discendenti x dare priorità ai più rari...
+ var ordered = priorities.Where(x => x > gatherCycle.VHF).OrderByDescending(x => x);
+ foreach (gatherCycle item in ordered)
+ {
+ if (TimerMachine.Veto.ContainsKey(item))
+ {
+ if (TimerMachine.Veto[item] <= adesso)
+ {
+ // se non ho già processato a questo giro...
+ if (!sendDone)
+ {
+ TimerMachine.CycleCount[item]++;
+ Stopwatch sw = Stopwatch.StartNew();
+
+ iobObj.doMachineTask(item);
+
+ sw.Stop();
+ sendDone = true;
+ // metto una piccola attesa se ho altre scadenze
+ TimerMachine.CycleElaps[item] += sw.Elapsed.TotalMilliseconds;
+ // metto nuova scadenza perturbata 10%
+ TimerMachine.Veto[item] = adesso.AddMilliseconds(iobObj.IOBConfFull.TimerMs(item, 0.1));
+ }
+ // log + reset se ho contato ALMENO 100 exec o il tempo totale supera 1000msec
+ int limMs = 10000;
+ double totalMs = TimerMachine.CycleElaps.ContainsKey(item) ? TimerMachine.CycleElaps[item] : 0;
+ if (TimerMachine.CycleCount[item] >= 100 || totalMs > limMs)
+ {
+ int nCount = Math.Max(TimerMachine.CycleCount[item], 1);
+ lgDebug($"Timer.{TimerMachine.Contesto} | checkScadMachine | {item} | {totalMs / nCount:F1}ms x {nCount}");
+ TimerMachine.CycleCount[item] = 0;
+ TimerMachine.CycleElaps[item] = 0;
+ }
+ }
+ }
+ else
+ {
+ TimerMachine.Veto.Add(item, adesso.AddMilliseconds(iobObj.IOBConfFull.TimerMs(item, 0)));
+ TimerMachine.CycleCount.Add(item, 0);
+ if (!TimerMachine.CycleElaps.ContainsKey(item))
+ {
+ TimerMachine.CycleElaps.Add(item, 0);
+ }
+ }
+ }
+ }
+
+#if false
///
/// Verifica scadenza task
///
- ///
- private async Task checkScad()
+ /// Indica se siano abilitate operazioni Pool (Thread Safe)
+ /// Indica se siano abilitate le operazioni Single Thread
+ ///
+ private async Task checkScad(bool enabPool, bool enabSTID)
{
DateTime adesso = DateTime.Now;
bool sendDone = false;
@@ -1532,10 +1720,13 @@ namespace IOB_WIN_FORM
{
TimersCycleCount[item]++;
Stopwatch sw = Stopwatch.StartNew();
- await iobObj.getAndSendAsync(item);
+
+ // chiamata di processing x frequenza
+ await iobObj.getAndSendAsync(item, enabPool, enabSTID);
sw.Stop();
sendDone = true;
+ // metto una piccola attesa se ho altre scadenze
TimersCycleElaps[item] += sw.Elapsed.TotalMilliseconds;
// metto nuova scadenza perturbata 10%
TimersVeto[item] = adesso.AddMilliseconds(iobObj.IOBConfFull.TimerMs(item, 0.1));
@@ -1559,7 +1750,8 @@ namespace IOB_WIN_FORM
if (!TimersCycleElaps.ContainsKey(item)) TimersCycleElaps.Add(item, 0);
}
}
- }
+ }
+#endif
private void ChkEdit_CheckedChanged(object sender, EventArgs e)
{
@@ -1589,45 +1781,249 @@ namespace IOB_WIN_FORM
{
}
+
///
/// Metodo principale esecuzione task in thread background (no interferenza con UI) x processi IO bound
///
- private async Task DoExecTasks()
+ ///
+ private void DoExecMachineTasks()
{
- bool doLog = false;
- // procedo!
- if (iobObj.periodicLog)
- {
- doLog = true;
- }
+ // Attende il proprio turno. Se un task è già in corso, questo aspetta.
+ _plcLock.Wait();
+ bool doLog = iobObj.periodicLog;
try
{
- // check esecuzione SendTask (MsVHF) COMUNQUE...
- await iobObj.getAndSendAsync(gatherCycle.VHF);
// eseguo cicli attivi SOLO se adapter è in EFFETTIVO running...
if (iobObj.adpRunning)
{
if (iobObj.connectionOk)
{
- // se richiesto faccio memory DUMP INIZIALE!
- if (iobObj.doStartMemDump)
+ DateTime adesso = DateTime.Now;
+ // verifico non ci sia veto comunicazioni lettura...
+ if (iobObj.queueInEnabCurr)
{
- lgInfo("Inizio dump memoria");
- iobObj.saveMemDump(dumpType.STARTUP);
- // fatto! non ripeto...
- iobObj.doStartMemDump = false;
- lgInfo("Finito dump memoria");
+ // 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();
+ }
+
+ // MAIN: controllo TUTTE le scadenze Machine...
+ checkScadMachine();
+
+ // wait opzionale in coda
+ if (utils.CRI("waitEndCycle") > 0)
+ {
+ Thread.Sleep(utils.CRI("waitEndCycle"));
+ }
}
- // controllo se sia abilitato sampleDump della meoria (periodico)
- if (iobObj.doSampleMemory)
+ else
{
- checkSampleMem();
+ lgTrace($"VETO DoExecMachineTasks.queueInEnabCurr | veto attivo | {adesso:yyyy.MM.dd HH:mm:ss}");
+ iobObj.checkVetoQueueIn();
}
- // controllo TUTTE le scadenze...
- checkScad();
- if (utils.CRI("waitEndCycle") > 0)
+ }
+ else
+ {
+ // qui attende meno...
+ DateTime dtVeto = lastStartTry.AddMilliseconds(waitRecMSec / 2);
+ if (iobObj.adpTryRestart && (DateTime.Now > dtVeto))
{
- await Task.Delay(utils.CRI("waitEndCycle"));
+ if (doLog)
+ {
+ lgInfo($"Retry Time Elapsed ({waitRecMSec / 2} ms)--> tryConnect");
+ }
+ lastStartTry = DateTime.Now;
+ iobObj.tryConnect();
+ }
+ }
+ }
+#if false
+ 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);
+ }
+ }
+#endif
+ }
+ catch (Exception exc)
+ {
+ lgError($"Eccezione in fase di DoExecMachineTasks: {Environment.NewLine}{exc}");
+ }
+ finally
+ {
+ _plcLock.Release();
+ }
+ }
+
+
+ ///
+ /// Metodo principale esecuzione task in thread background (no interferenza con UI) x processi IO bound
+ ///
+ /// Richiesta esecuzone su single thread (es FANUC)
+ ///
+ private async Task DoExecServerTasksAsync(bool reqSingle)
+ {
+ // Attende il proprio turno. Se un task è già in corso, questo aspetta.
+ await _plcLock.WaitAsync();
+ bool doLog = iobObj.periodicLog;
+ try
+ {
+ // check esecuzione SendTask (MsVHF) COMUNQUE...
+ await iobObj.doServerTaskAsync(gatherCycle.VHF);
+ // eseguo cicli attivi SOLO se adapter è in EFFETTIVO running...
+ if (iobObj.adpRunning)
+ {
+ if (iobObj.connectionOk)
+ {
+ DateTime adesso = DateTime.Now;
+ // verifico non ci sia veto comunicazioni lettura...
+ if (iobObj.queueInEnabCurr)
+ {
+
+ // MAIN: controllo TUTTE le scadenze Server...
+ await checkScadPoolAsync();
+
+ // wait opzionale in coda
+ if (utils.CRI("waitEndCycle") > 0)
+ {
+ await Task.Delay(utils.CRI("waitEndCycle"));
+ }
+ }
+ else
+ {
+ lgTrace($"VETO DoExecServerTasksAsync.queueInEnabCurr | veto attivo | {adesso:yyyy.MM.dd HH:mm:ss}");
+ iobObj.checkVetoQueueIn();
+ }
+ }
+#if false
+ else
+ {
+ // qui attende meno...
+ DateTime dtVeto = lastStartTry.AddMilliseconds(waitRecMSec / 2);
+ if (iobObj.adpTryRestart && (DateTime.Now > dtVeto))
+ {
+ if (doLog)
+ {
+ lgInfo($"Retry Time Elapsed ({waitRecMSec / 2} ms)--> tryConnect");
+ }
+ lastStartTry = DateTime.Now;
+ iobObj.tryConnect();
+ }
+ }
+#endif
+ }
+ 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($"Eccezione DoExecServerTasksAsync: {Environment.NewLine}{exc}");
+ }
+ finally
+ {
+ _plcLock.Release();
+ }
+ }
+
+#if false
+ ///
+ /// Metodo principale esecuzione task in thread background (no interferenza con UI) x processi IO bound
+ ///
+ /// Richiesta esecuzone su single thread (es FANUC)
+ ///
+ private async Task DoExecTasksAsync(bool reqSingle)
+ {
+ // Attende il proprio turno. Se un task è già in corso, questo aspetta.
+ await _plcLock.WaitAsync();
+ bool doLog = iobObj.periodicLog;
+ try
+ {
+ // imposto variabili x esecuzione separata task Single Thread / Pooled Thread
+ bool reqSTE = iobObj.IOBConfFull.General.MachWLoopSingleThread;
+ bool enabSTID = reqSTE ? reqSingle : true;
+ bool enabPool = !reqSTE;
+
+ if (enabPool)
+ {
+ // check esecuzione SendTask (MsVHF) COMUNQUE...
+ await iobObj.getAndSendAsync(gatherCycle.VHF, enabPool, enabSTID);
+ }
+ // eseguo cicli attivi SOLO se adapter è in EFFETTIVO running...
+ if (iobObj.adpRunning)
+ {
+ if (iobObj.connectionOk)
+ {
+ DateTime adesso = DateTime.Now;
+ // verifico non ci sia veto comunicazioni lettura...
+ if (iobObj.queueInEnabCurr)
+ {
+ if (enabSTID)
+ {
+ // 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");
+ }
+ }
+ if (enabPool)
+ {
+ // controllo se sia abilitato sampleDump della meoria (periodico)
+ if (iobObj.doSampleMemory)
+ {
+ checkSampleMem();
+ }
+ }
+
+ // MAIN: controllo TUTTE le scadenze...
+ await checkScad(enabPool, enabSTID);
+
+ // wait opzionale in coda
+ if (utils.CRI("waitEndCycle") > 0)
+ {
+ await Task.Delay(utils.CRI("waitEndCycle"));
+ }
+ }
+ else
+ {
+ lgTrace($"VETO queueInEnabCurr | veto attivo | {adesso:yyyy.MM.dd HH:mm:ss}");
+ iobObj.checkVetoQueueIn();
}
}
else
@@ -1663,9 +2059,14 @@ namespace IOB_WIN_FORM
}
catch (Exception exc)
{
- lgError(string.Format("Eccezione in fase di gatherTick: {0}{1}", Environment.NewLine, exc));
+ lgError($"Eccezione in fase di DoExecTasksAsync: {Environment.NewLine}{exc}");
}
- }
+ finally
+ {
+ _plcLock.Release();
+ }
+ }
+#endif
///
/// Ferma tutti i componenti adapter + update buttons
@@ -1706,8 +2107,6 @@ namespace IOB_WIN_FORM
lgError($"Errore in fermaTutto |stopTimer: {stopTimer} | tryRestart: {tryRestart} | forceDequeue: {forceDequeue} | updateForm: {updateForm}{Environment.NewLine}{ex.Message}");
}
-
-
newDisplayData currDispData = new newDisplayData();
currDispData.semIn = Semaforo.SS;
currDispData.semOut = Semaforo.SS;
@@ -1812,7 +2211,7 @@ namespace IOB_WIN_FORM
IOBConfFull.SaveYaml(fullPath.Replace("iob", "yaml"));
// carico IOB
- loadIobType();
+ _ = loadIobType();
// invio file di conf!
IOBConfFull.SendConfYaml(iobObj.urlSaveConfYaml);
@@ -1859,7 +2258,7 @@ namespace IOB_WIN_FORM
}
var appVers = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
- loadIobType();
+ _ = loadIobType();
// avvio macchina con adapter specificato...
if (utils.CRB("autoStartOnLoad"))
{
@@ -1922,7 +2321,6 @@ namespace IOB_WIN_FORM
_lastState = this.WindowState;
}
- private FormWindowState _lastState = FormWindowState.Minimized;
///
/// Mostrata form
///
@@ -2117,6 +2515,25 @@ namespace IOB_WIN_FORM
}
}
+ ///
+ /// Indica se debba aggiornare o meno la UI perché minimizzata o meno
+ ///
+ ///
+ private bool ShouldUpdateUI()
+ {
+ // 1. Controlla se la form stessa è minimizzata
+ if (this.WindowState == FormWindowState.Minimized) return false;
+
+ // 2. Se è una MDI Child, controlla se il Padre è minimizzato
+ if (this.MdiParent != null && this.MdiParent.WindowState == FormWindowState.Minimized)
+ return false;
+
+ // 3. (Opzionale) Controlla se la form è visibile
+ if (!this.Visible) return false;
+
+ return true;
+ }
+
private void splitContainer1_Panel1_Paint(object sender, PaintEventArgs e)
{
}
@@ -2139,11 +2556,44 @@ namespace IOB_WIN_FORM
///
private void StartWorker()
{
- // rimozione isSuspended
- _isSuspended = false;
- // per prima cosa disattivo il disabled...
- lock (_lock)
+
+ //// FixMe ToDo !!! togliere o fare alternativa pooled
+ //if (iobObj.IOBConfFull.General.MachWLoopSingleThread || true)
+ //{
+ //}
+ lock (_threadLock)
{
+ // rimozione isSuspended
+ _isSuspended = false;
+
+ // 1. Ferma eventuali worker precedenti
+ if (_ctsMachine != null)
+ {
+ _ctsMachine.Cancel();
+ _ctsMachine.Dispose(); // Libera le risorse del vecchio token
+ }
+
+ // 2. Attendi che il thread precedente sia effettivamente uscito
+ if (_machineThread != null && _machineThread.IsAlive)
+ {
+ // Timeout breve per non freezare la UI, ma necessario per pulizia
+ _machineThread.Join(1000);
+ }
+
+ _ctsMachine = new CancellationTokenSource();
+
+ // 3. Crea un thread NUOVO e DEDICATO
+ _machineThread = new Thread(() => WorkerLoopMachine(_ctsMachine.Token))
+ {
+ IsBackground = true,
+ Name = "Single_Dedicated_Thread",
+ Priority = ThreadPriority.AboveNormal // Opzionale: dà precedenza ai dati PLC
+ };
+
+ _machineThread.Start();
+ lgInfo("--- WORKER MACHINE AVVIATO ---");
+
+ // avvio altro thread comunque...
// 1. Controllo se è già in esecuzione
if (_workerTask != null && !_workerTask.IsCompleted)
{
@@ -2151,12 +2601,23 @@ namespace IOB_WIN_FORM
return;
}
- _cts = new CancellationTokenSource();
- // Assegniamo il Task alla variabile per poterne monitorare lo stato
- _workerTask = Task.Run(() => WorkerLoopAsync(_cts.Token));
+ _ctsServer = new CancellationTokenSource();
+ _workerTask = Task.Run(() => WorkerLoopAsync(_ctsServer.Token));
+ lgInfo("--- WORKER SERVER AVVIATO ---");
}
+
+
}
+
+ private Thread _machineThread;
+ private readonly object _threadLock = new object();
+
+
+#if false
+ private BlockingCollection _workQueue = new BlockingCollection();
+#endif
+
///
/// fermata dell'adapter
///
@@ -2170,14 +2631,12 @@ namespace IOB_WIN_FORM
lgInfo("UNLOAD Adapter");
}
- private bool stopForced = false;
-
// Metodo per fermare tutto (es. nel Form_Closing o Dispose)
private async Task StopWorker()
{
- if (_cts == null) return;
+ if (_ctsMachine == null) return;
- _cts.Cancel();
+ _ctsMachine.Cancel();
try
{
@@ -2190,10 +2649,10 @@ namespace IOB_WIN_FORM
catch (OperationCanceledException) { /* Normale amministrazione */ }
finally
{
- if (_cts != null)
+ if (_ctsMachine != null)
{
- _cts.Dispose();
- _cts = null;
+ _ctsMachine.Dispose();
+ _ctsMachine = null;
}
if (_workerTask != null)
{
@@ -2224,25 +2683,128 @@ namespace IOB_WIN_FORM
checkAssignSize();
}
- private async Task WorkerLoopAsync(CancellationToken ct)
+ ///
+ /// Counter esecuzione WorkerLoopMachine
+ ///
+ private int idxWLM = 0;
+ ///
+ /// Counter esecuzione WorkerLoopServer
+ ///
+ private int idxWLS = 0;
+
+ ///
+ /// Loop di gestione worker comunicazione con la macchina (single threaded)
+ ///
+ ///
+ private void WorkerLoopMachine(CancellationToken ct)
{
+ lgInfo($"[Thread {Thread.CurrentThread.ManagedThreadId} ({idxWLM})] inizio WorkerLoopMachine");
+ int validThread = Thread.CurrentThread.ManagedThreadId;
try
{
while (!ct.IsCancellationRequested)
{
+ // incremento indice x mostrare esecuzione...
+ idxWLM++;
+ idxWLM = idxWLM > 999 ? 0 : idxWLM;
+ //lgTrace($"[Thread: {Thread.CurrentThread.ManagedThreadId} ({idxWLM})] WorkerLoopMachine");
if (!_isSuspended)
{
try
{
- await DoExecTasks();
+ // solo se il thread è valido...
+ if (Thread.CurrentThread.ManagedThreadId == validThread)
+ {
+ // Eseguiamo il lavoro asincrono in modo SINCRONO su questo thread.
+ // .GetAwaiter().GetResult() blocca questo thread finché il task non è finito.
+ //await DoExecMachineTasks();
+ //DoExecMachineTasks().GetAwaiter().GetResult();
+ DoExecMachineTasks();
+ }
+ else
+ {
+ lgTrace($"[Thread: {Thread.CurrentThread.ManagedThreadId} ({idxWLM})] | WorkerLoopMachine | NOT VALID, expecting {validThread}");
+ }
}
catch (Exception ex)
{
- lgError("Errore durante i task: " + ex.Message);
+ lgError($"[Thread: {Thread.CurrentThread.ManagedThreadId} ({idxWLM})] Errore nel task: {ex.Message}");
}
}
else
{
+ lgTrace($"[Thread: {Thread.CurrentThread.ManagedThreadId} ({idxWLM})] WorkerLoopMachine suspended");
+ // se non fosse stop richiesto da utente...
+ if (!stopForced)
+ {
+ DateTime dtVeto = lastStartTry.AddMilliseconds(waitRecMSec / 2);
+ // verifica scadenza controllo SE fosse offline x eseguire test riconnessione...
+ if (iobObj.adpTryRestart && (DateTime.Now > dtVeto) && iobObj.adpRunning && !iobObj.connectionOk)
+ {
+ lgTrace($"[Thread: {Thread.CurrentThread.ManagedThreadId} ({idxWLM})] WorkerLoopMachine sospeso: tentativo riavvio periodico");
+ lastStartTry = DateTime.Now;
+ iobObj.tryConnect();
+ }
+ else
+ {
+ lgTrace($"[Thread: {Thread.CurrentThread.ManagedThreadId} ({idxWLM})] WorkerLoopMachine sospeso: NON esegue task specifici | _isSuspended: {_isSuspended}");
+ }
+ }
+ }
+
+ // Calcolo del delay dinamico tra standard e suspended da Timers.MsVHF
+ int currentDelay = _isSuspended ? 10 * IOBConfFull.General.Timers.MsVHF : IOBConfFull.General.Timers.MsVHF;
+
+ // ATTESA: Non rilascia il thread al pool di .NET
+ // Si interrompe subito se ct viene cancellato
+ bool cancelled = ct.WaitHandle.WaitOne(currentDelay);
+ if (cancelled) break;
+
+ //lgTrace($"[Thread: {Thread.CurrentThread.ManagedThreadId} ({idxWLM})] WorkerLoopMachine | End");
+ }
+ }
+ catch (Exception ex)
+ {
+ lgError($"FATAL: Il thread dedicato {Thread.CurrentThread.ManagedThreadId} ({idxWLM}) è terminato: {ex.Message}");
+ }
+ finally
+ {
+ lgInfo($"[Thread {Thread.CurrentThread.ManagedThreadId} ({idxWLM})] WorkerLoopMachine terminato.");
+ }
+ }
+
+ ///
+ /// Loop di gestione worker
+ ///
+ ///
+ ///
+ private async Task WorkerLoopAsync(CancellationToken ct)
+ {
+ try
+ {
+ lgTrace($"[Thread: {Thread.CurrentThread.ManagedThreadId} ({idxWLS})] Inizio WorkerLoopAsync");
+
+ while (!ct.IsCancellationRequested)
+ {
+ // incremento indice x mostrare esecuzione...
+ idxWLS++;
+ idxWLS = idxWLS > 999 ? 0 : idxWLS;
+ //lgTrace($"[Thread: {Thread.CurrentThread.ManagedThreadId} ({idxWLS})] WorkerLoopAsync");
+ if (!_isSuspended)
+ {
+ try
+ {
+ await DoExecServerTasksAsync(false);
+
+ }
+ catch (Exception ex)
+ {
+ lgError($"[Thread: {Thread.CurrentThread.ManagedThreadId} ({idxWLS})] Errore durante i task: " + ex.Message);
+ }
+ }
+ else
+ {
+ lgTrace($"[Thread: {Thread.CurrentThread.ManagedThreadId} ({idxWLS})] WorkerLoopAsync suspended");
// se non fosse stop richiesto da utente...
if (!stopForced)
{
@@ -2261,20 +2823,31 @@ namespace IOB_WIN_FORM
}
}
- // Calcolo del delay dinamico da Timers.MsVHF
+ // Calcolo del delay dinamico tra standard e suspended da Timers.MsVHF
int currentDelay = _isSuspended ? 10 * IOBConfFull.General.Timers.MsVHF : IOBConfFull.General.Timers.MsVHF;
- // Il Task.Delay accetta il CancellationToken.
- // Se chiudi l'app mentre sta "dormendo", l'attesa si interrompe IMMEDIATAMENTE
- // senza dover aspettare la fine del timer, velocizzando la chiusura.
+ // se ho error delay --> log!
+ if (_errorDelay > 0)
+ {
+ currentDelay += _errorDelay;
+ lgTrace($"[Thread: {Thread.CurrentThread.ManagedThreadId} ({idxWLS})] WorkerLoopAsync | delay: {currentDelay}");
+ }
+
+ // 4. ATTESA INTERROMPIBILE
+ // Il delay asincrono permette al sistema di riutilizzare il thread se necessario,
+ // ma il 'while' garantisce che non inizieremo il prossimo DoExecTasksAsync prematuramente.
+ //await Task.Delay(currentDelay, ct).ConfigureAwait(false);
await Task.Delay(currentDelay, ct);
+
+ // Logga l'ID Thread
+ //lgTrace($"[Thread: {Thread.CurrentThread.ManagedThreadId} ({idxWLS})] WorkerLoopAsync | End");
}
- lgInfo("Worker interrotto per cancellation token.");
+ lgInfo("WorkerLoopAsync interrotto per cancellation token.");
}
catch (OperationCanceledException)
{
// Eccezione normale quando si preme Stop/Cancel
- lgInfo("Worker interrotto correttamente.");
+ lgInfo("WorkerLoopAsync interrotto correttamente.");
}
}
diff --git a/IOB-WIN-FORM/Iob/Generic.Protected.cs b/IOB-WIN-FORM/Iob/Generic.Protected.cs
index 31018f68..d5379f58 100644
--- a/IOB-WIN-FORM/Iob/Generic.Protected.cs
+++ b/IOB-WIN-FORM/Iob/Generic.Protected.cs
@@ -32,6 +32,11 @@ namespace IOB_WIN_FORM.Iob
{
#region Protected Fields
+ ///
+ /// Variabile numero errori vari (in lettura) --> se supera soglia maxErroriCheck --> disconnette
+ ///
+ protected static int numErroriCheck = 0;
+
protected bool _connOk = false;
///
@@ -59,13 +64,6 @@ namespace IOB_WIN_FORM.Iob
///
protected int B_output;
-#if false
- ///
- /// Ultimo valore B_output inviato
- ///
- protected int B_output_sent = -1;
-#endif
-
///
/// Vettore 32 BIT valori precedenti
///
@@ -308,11 +306,6 @@ namespace IOB_WIN_FORM.Iob
///
protected bool numArtCharTrim = false;
- ///
- /// Variabile numero errori vari (in lettura) --> se supera soglia maxErroriCheck --> disconnette
- ///
- protected int numErroriCheck = 0;
-
///
/// Timeout x ping al server
///
@@ -678,16 +671,6 @@ namespace IOB_WIN_FORM.Iob
}
}
- protected bool queueInEnabCurr
- {
- get => qInEnabCurr;
- set
- {
- qInEnabCurr = value;
- lgInfo($"SET queueInEnabCurr: {value} | {DateTime.Now:HHmmss}");
- }
- }
-
///
/// Definizioni x replace in file ricette
///
@@ -1026,13 +1009,6 @@ namespace IOB_WIN_FORM.Iob
{
get => $@"{urlCommandIob("remTask2Exe")}?taskName=";
}
- ///
- /// URL per richiamo task da eseguire...
- ///
- protected string urlRemTask2ExeTav(string codTav)
- {
- return $@"{urlCommandIob("remTask2Exe")}|{codTav}?taskName=";
- }
///
/// URL per salvataggio dati PARAMETRI IOB...
@@ -1139,31 +1115,6 @@ namespace IOB_WIN_FORM.Iob
#region Protected Methods
- ///
- /// Verifico i dynData x validità:
- /// - siano almeno 1
- /// - NON siano tutti identici
- ///
- ///
- ///
- protected bool checkValidDynData(Dictionary currDynData)
- {
- bool answ = false;
- // conto num valori
- int numVal = currDynData.Count;
- bool dataPresent = numVal > 0;
- if (dataPresent)
- {
- // prendo il primo valore..
- string firstVal = currDynData.FirstOrDefault().Value;
- // conto val uguali al primo
- int numEq = currDynData.Where(x => x.Value == firstVal).Count();
- // se solo 1 o almeno 1 è diverso è ok
- answ = numVal == 1 || (numVal > numEq);
- }
- return answ;
- }
-
///
/// Decodifica file MAP (caso .bit)
///
@@ -1226,6 +1177,26 @@ namespace IOB_WIN_FORM.Iob
}
}
+ protected static long GetObjectSize(object genObj, bool isSerializable)
+ {
+ long result = 0;
+ if (isSerializable)
+ {
+ using (var stream = new MemoryStream())
+ {
+ var formatter = new BinaryFormatter();
+ formatter.Serialize(stream, genObj);
+ result = stream.Length;
+ }
+ }
+ else
+ {
+ string rawVal = System.Text.Json.JsonSerializer.Serialize(genObj, options);
+ result = rawVal.Length;
+ }
+ return result;
+ }
+
///
/// Decodifica valore della coda IN nel formato hasVeto[0]=dtEve hasVeto[1]=valore hasVeto[2]=counter
///
@@ -1246,6 +1217,36 @@ namespace IOB_WIN_FORM.Iob
return answ;
}
+ ///
+ /// Accodamento richieste server
+ ///
+ ///
+ ///
+ protected void accodaServReq(string codTav, string newReq)
+ {
+ JobTaskData jobTask = new JobTaskData(codTav, newReq);
+ // accodo richiesta serializzata
+ string serVal = JsonConvert.SerializeObject(jobTask);
+ QueueSrvReq.Enqueue(serVal);
+ // loggo!
+ lgDebug($"[QUEUE] | QueueSrvReq len: {QueueSrvReq.Count}");
+ }
+
+ ///
+ /// Accodamento risposte per il server
+ ///
+ ///
+ ///
+ protected void accodaServResp(string codTav, string rawData)
+ {
+ JobTaskData jobTask = new JobTaskData(codTav, rawData);
+ // accodo richiesta serializzata
+ string serVal = JsonConvert.SerializeObject(jobTask);
+ QueueSrvResp.Enqueue(serVal);
+ // loggo!
+ lgDebug($"[QUEUE] | QueueSrvResp len: {QueueSrvResp.Count}");
+ }
+
///
/// Classe di base implementazione traduzione di una LUT da memoria come valore BIT a valore
/// esplicito x FLog
@@ -1268,11 +1269,28 @@ namespace IOB_WIN_FORM.Iob
}
///
- /// Verifica veto coda QueueIN ed aggiorna abilitazione su variabile
+ /// Verifico i dynData x validità:
+ /// - siano almeno 1
+ /// - NON siano tutti identici
///
- protected void checkVetoQueueIn()
+ ///
+ ///
+ protected bool checkValidDynData(Dictionary currDynData)
{
- queueInEnabCurr = dtVetoQueueIN < DateTime.Now;
+ bool answ = false;
+ // conto num valori
+ int numVal = currDynData.Count;
+ bool dataPresent = numVal > 0;
+ if (dataPresent)
+ {
+ // prendo il primo valore..
+ string firstVal = currDynData.FirstOrDefault().Value;
+ // conto val uguali al primo
+ int numEq = currDynData.Where(x => x.Value == firstVal).Count();
+ // se solo 1 o almeno 1 è diverso è ok
+ answ = numVal == 1 || (numVal > numEq);
+ }
+ return answ;
}
///
@@ -1352,6 +1370,42 @@ namespace IOB_WIN_FORM.Iob
}
}
+ ///
+ /// Verifica se salvare (nel log) info dei FluxLog filtrati
+ /// - per scadenza valore VetoFlushFiltFL
+ /// - per un numero complessivo di eventi superiori a soglia
+ ///
+ /// numero minimo di eventi necessari al salvataggio (come somma complessiva)
+ protected void FiltFluxLogCheckSave(long minCount)
+ {
+ DateTime adesso = DateTime.Now;
+ bool doWrite = VetoFlushFiltFL < adesso;
+ // conteggio valori
+ if (!doWrite)
+ {
+ long numFL = DictFiltFLog.Sum(x => x.Value);
+ doWrite = numFL > minCount;
+ }
+ if (doWrite)
+ {
+ // scrivo log x ogni valore
+ string sep = "------------------------------------------------------------";
+ _logger.Info(sep);
+ _logger.Info("- Paret0 Eventi FluxLog filtrati");
+ _logger.Info(sep);
+ foreach (var item in DictFiltFLog.OrderByDescending(x => x.Value))
+ {
+ // loggo!
+ _logger.Info($"{item.Key}: {item.Value}");
+ }
+ _logger.Info(sep);
+ // reset dizionario
+ DictFiltFLog.Clear();
+ // nuovo veto a 1h
+ VetoFlushFiltFL = adesso.AddHours(1);
+ }
+ }
+
///
/// Imposta eventuali altri valori default
///
@@ -1740,7 +1794,7 @@ namespace IOB_WIN_FORM.Iob
}
answ = await utils.callUrlAsync(url2call);
#if false
- answ = utils.callUrlNow(url2call);
+ answ = utils.callUrlNow(url2call);
#endif
}
return answ;
@@ -3190,28 +3244,28 @@ namespace IOB_WIN_FORM.Iob
url2call = $"{urlRemTask2ExeTav(codTav)}{taskName}";
}
-#if false
-
- try
- {
- Task.Run(async () => answ = await utils.callUrlAsync(url2call))
- .GetAwaiter()
- .GetResult();
- lgInfo($"Task2Exe.remTask2exe | {esitoTask} | chiamata URL {url2call} | answ: {answ}");
- }
- catch (Exception ex)
- {
- lgError("ProcessAutoOdl | Crash nel ponte Sync/Async: " + ex.Message);
- }
-#endif
await utils.callUrlAsync(url2call);
-#if false
- answ = utils.callUrlNow(url2call);
-#endif
}
return answ;
}
+ ///
+ /// Salva nel dizionario il num di valori letti e filtrati/non inviati
+ ///
+ ///
+ protected void SaveFiltFluxLog(string codFlux)
+ {
+ if (DictFiltFLog.ContainsKey(codFlux))
+ {
+ DictFiltFLog[codFlux]++;
+ }
+ else
+ {
+ DictFiltFLog.Add(codFlux, 1);
+ _logger.Info($"FluxLog | veto | {codFlux}");
+ }
+ }
+
///
/// Invio reset allarmi all'avvio per sicurezza...
///
@@ -3335,7 +3389,7 @@ namespace IOB_WIN_FORM.Iob
lgInfo("chiamata URL " + urlSetM2IOB);
await utils.callUrlAsync(urlSetM2IOB);
#if false
- utils.callUrlNow(urlSetM2IOB);
+ utils.callUrlNow(urlSetM2IOB);
#endif
}
}
@@ -3424,7 +3478,7 @@ namespace IOB_WIN_FORM.Iob
lgInfo("chiamata URL " + url2call);
await utils.callUrlAsync(url2call);
#if false
- utils.callUrlNow(url2call);
+ utils.callUrlNow(url2call);
#endif
}
}
@@ -3912,33 +3966,6 @@ namespace IOB_WIN_FORM.Iob
}
}
- protected static long GetObjectSize(object genObj, bool isSerializable)
- {
- long result = 0;
- if (isSerializable)
- {
- using (var stream = new MemoryStream())
- {
-
- var formatter = new BinaryFormatter();
- formatter.Serialize(stream, genObj);
- result = stream.Length;
- }
- }
- else
- {
- string rawVal = System.Text.Json.JsonSerializer.Serialize(genObj, options);
- result = rawVal.Length;
- }
- return result;
- }
-
- private static readonly JsonSerializerOptions options = new JsonSerializerOptions
- {
- ReferenceHandler = ReferenceHandler.IgnoreCycles,
- WriteIndented = false // Optional: set to true for pretty-printing
- };
-
///
/// Traccia in redis l'attività di lettura dati
///
@@ -4123,6 +4150,7 @@ namespace IOB_WIN_FORM.Iob
}
return fatto;
}
+
///
/// Effettua chiamata MP-IO per tentare chiusura ODL specifico
///
@@ -4448,6 +4476,7 @@ namespace IOB_WIN_FORM.Iob
}
raiseRefresh(currDispData);
}
+
///
/// Versione sync chiamata setup PODL
///
@@ -4542,6 +4571,14 @@ namespace IOB_WIN_FORM.Iob
return $@"{urlMesServer}{IOBConfFull.MapoMes.ApiUrl(cmqReq)}{IOBConfFull.General.FilenameIOB}";
}
+ ///
+ /// URL per richiamo task da eseguire...
+ ///
+ protected string urlRemTask2ExeTav(string codTav)
+ {
+ return $@"{urlCommandIob("remTask2Exe")}|{codTav}?taskName=";
+ }
+
///
/// Verifica se il parametro passi il limite della DeadBand (globale o specifica se
/// configurata) Il riferimento è al prec valore currProdData
@@ -4595,6 +4632,12 @@ namespace IOB_WIN_FORM.Iob
#region Private Fields
+ private static readonly JsonSerializerOptions options = new JsonSerializerOptions
+ {
+ ReferenceHandler = ReferenceHandler.IgnoreCycles,
+ WriteIndented = false // Optional: set to true for pretty-printing
+ };
+
///
/// Oggetto logger della classe
///
@@ -4610,64 +4653,6 @@ namespace IOB_WIN_FORM.Iob
///
private Dictionary DictFiltFLog = new Dictionary();
- ///
- /// Valore veto al salvataggio di valori filtrati in FluxLog se NON superato limite chiamate
- ///
- private DateTime VetoFlushFiltFL = DateTime.Now.AddHours(1);
-
- ///
- /// Salva nel dizionario il num di valori letti e filtrati/non inviati
- ///
- ///
- protected void SaveFiltFluxLog(string codFlux)
- {
- if (DictFiltFLog.ContainsKey(codFlux))
- {
- DictFiltFLog[codFlux]++;
- }
- else
- {
- DictFiltFLog.Add(codFlux, 1);
- _logger.Info($"FluxLog | veto | {codFlux}");
- }
- }
-
- ///
- /// Verifica se salvare (nel log) info dei FluxLog filtrati
- /// - per scadenza valore VetoFlushFiltFL
- /// - per un numero complessivo di eventi superiori a soglia
- ///
- /// numero minimo di eventi necessari al salvataggio (come somma complessiva)
- protected void FiltFluxLogCheckSave(long minCount)
- {
- DateTime adesso = DateTime.Now;
- bool doWrite = VetoFlushFiltFL < adesso;
- // conteggio valori
- if (!doWrite)
- {
- long numFL = DictFiltFLog.Sum(x => x.Value);
- doWrite = numFL > minCount;
- }
- if (doWrite)
- {
- // scrivo log x ogni valore
- string sep = "------------------------------------------------------------";
- _logger.Info(sep);
- _logger.Info("- Paret0 Eventi FluxLog filtrati");
- _logger.Info(sep);
- foreach (var item in DictFiltFLog.OrderByDescending(x => x.Value))
- {
- // loggo!
- _logger.Info($"{item.Key}: {item.Value}");
- }
- _logger.Info(sep);
- // reset dizionario
- DictFiltFLog.Clear();
- // nuovo veto a 1h
- VetoFlushFiltFL = adesso.AddHours(1);
- }
- }
-
private string LastDayCurr = "";
///
@@ -4685,6 +4670,17 @@ namespace IOB_WIN_FORM.Iob
private Dictionary TrackDetStatsCount = new Dictionary();
private Dictionary> TrackDetValsCount = new Dictionary>();
+#if false
+ ///
+ /// Ultimo valore B_output inviato
+ ///
+ protected int B_output_sent = -1;
+#endif
+
+ ///
+ /// Valore veto al salvataggio di valori filtrati in FluxLog se NON superato limite chiamate
+ ///
+ private DateTime VetoFlushFiltFL = DateTime.Now.AddHours(1);
///
/// Dizionario dei valori bloccati x evitare log eccessivo
@@ -4720,88 +4716,6 @@ namespace IOB_WIN_FORM.Iob
#region Private Properties
- ///
- /// Verifica se la IOB sia ENABLED (da server o Demo)
- ///
- public async Task CheckIobEnabled()
- {
- // 1. Controllo Veto (Sincrono)
- if (dtVetoCheckIOB >= DateTime.Now)
- return IobOnline;
-
- bool currentAnsw = false;
-
- if (DemoOut)
- {
- currentAnsw = (QueueIN.Count + QueueFLog.Count >= nMaxSend);
- }
- else
- {
- currentAnsw = await ExecuteIobCheckWithRetry(maxRetries: 5);
-#if false
- // 2. Chiamata asincrona con Retry (Ponte Sync/Async)
- currentAnsw = Task.Run(async () => await ExecuteIobCheckWithRetry(maxRetries: 5))
- .GetAwaiter()
- .GetResult();
-#endif
- }
-
- // 3. Gestione Stato e Logica UI
- UpdateIobState(currentAnsw);
-
- return currentAnsw;
- }
-
- private async Task ExecuteIobCheckWithRetry(int maxRetries)
- {
- var rand = new Random();
- for (int i = 0; i <= maxRetries; i++)
- {
- try
- {
- if (i > 0)
- {
- // Al terzo tentativo fallito resetto i client
- if (i == 3) resetWebClients();
-
- int delay = i == 3 ? rand.Next(250, 1000) : rand.Next(250, 500);
- await Task.Delay(delay);
- }
-
- string callResp = await callUrl(urlIobEnabled, i < 3); // true per i primi tentativi
- if (callResp == "OK") return true;
- }
- catch (Exception exc)
- {
- lgError($"Eccez
/// Boolean abilitazione coda eventi IN
///
@@ -4815,98 +4729,6 @@ namespace IOB_WIN_FORM.Iob
get => redisMan.redHash($"IOB:Status:{IOBConfFull.General.FilenameIOB}:CurrProdData");
}
- ///
- /// Test ping all'indirizzo impostato nei parametri
- ///
- ///
- private IPStatus GetPingStatus()
- {
- var pStatus = Task.Run(async () => await GetPingStatusAsync(maxPingRetry + 1))
- .GetAwaiter()
- .GetResult();
-
- return pStatus;
- }
-
- ///
- /// Test ping all'indirizzo impostato nei parametri
- ///
- /// Numero max tentativi (maxPingRetry + 1)
- ///
- private async Task GetPingStatusAsync(int maxAttempts)
- {
- // 1. Check disabilitazione
- if (IOBConfFull.MapoMes.DisabPing) return IPStatus.Success;
-
- // 2. Estrazione Host/IP pulita
- string host = IOBConfFull.MapoMes.IpAddr;
- try
- {
- // Rimuove protocollo (http://, ftp://, etc)
- if (host.Contains("://"))
- host = new Uri(host).Host;
- else if (host.Contains(":"))
- host = host.Split(':')[0];
- }
- catch { /* fallback al valore originale se Uri fallisce */ }
-
- // 3. Risoluzione Indirizzo
- if (!IPAddress.TryParse(host, out IPAddress address))
- {
- try
- {
- var addresses = Dns.GetHostAddresses(host);
- if (addresses.Length > 0) address = addresses[0];
- }
- catch (Exception ex)
- {
- lgError($"Impossibile risolvere DNS per {host}: {ex.Message}");
- return IPStatus.DestinationHostUnreachable;
- }
- }
-
- if (address == null) return IPStatus.Unknown;
-
- // 4. Ciclo di Ping con Retry
- var rand = new Random();
- using (Ping pingSender = new Ping())
- {
- for (int attempt = 1; attempt <= maxAttempts; attempt++)
- {
- try
- {
- // Timeout dinamico come nel tuo originale
- int timeout = (attempt == 1)
- ? rand.Next(200, 400)
- : (pingServerMsTimeout * attempt / 2);
-
- PingReply reply = pingSender.Send(address, timeout);
-
- if (reply.Status == IPStatus.Success)
- {
- if (attempt > 1) lgInfo("Server PING OK dopo retry!");
- return IPStatus.Success;
- }
-
- lgInfo($"Ping tent. {attempt} fallito: {reply.Status} (Timeout: {timeout}ms)");
- }
- catch (Exception ex)
- {
- lgError($"Eccezione durante ping tent. {attempt}: {ex.Message}");
- }
-
- // Attesa prima del prossimo tentativo (se non è l'ultimo)
- if (attempt < maxAttempts)
- {
- await Task.Delay(rand.Next(50, 200));
- }
- }
- }
-
- return IPStatus.TimedOut;
- }
-
-
///
/// URL di base del server MES da contattare
///
@@ -5149,6 +4971,33 @@ namespace IOB_WIN_FORM.Iob
return fatto;
}
+ private async Task ExecuteIobCheckWithRetry(int maxRetries)
+ {
+ var rand = new Random();
+ for (int i = 0; i <= maxRetries; i++)
+ {
+ try
+ {
+ if (i > 0)
+ {
+ // Al terzo tentativo fallito resetto i client
+ if (i == 3) resetWebClients();
+
+ int delay = i == 3 ? rand.Next(250, 1000) : rand.Next(250, 500);
+ await Task.Delay(delay);
+ }
+
+ string callResp = await callUrl(urlIobEnabled, i < 3); // true per i primi tentativi
+ if (callResp == "OK") return true;
+ }
+ catch (Exception exc)
+ {
+ lgError($"Eccez
/// Esegue filtraggio dati x bit blinking!!!
///
@@ -5226,6 +5075,97 @@ namespace IOB_WIN_FORM.Iob
demFactDynData = IOBConfFull.FluxLog.DemFactDynData;
}
+ ///
+ /// Test ping all'indirizzo impostato nei parametri
+ ///
+ ///
+ private IPStatus GetPingStatus()
+ {
+ var pStatus = Task.Run(async () => await GetPingStatusAsync(maxPingRetry + 1))
+ .GetAwaiter()
+ .GetResult();
+
+ return pStatus;
+ }
+
+ ///
+ /// Test ping all'indirizzo impostato nei parametri
+ ///
+ /// Numero max tentativi (maxPingRetry + 1)
+ ///
+ private async Task GetPingStatusAsync(int maxAttempts)
+ {
+ // 1. Check disabilitazione
+ if (IOBConfFull.MapoMes.DisabPing) return IPStatus.Success;
+
+ // 2. Estrazione Host/IP pulita
+ string host = IOBConfFull.MapoMes.IpAddr;
+ try
+ {
+ // Rimuove protocollo (http://, ftp://, etc)
+ if (host.Contains("://"))
+ host = new Uri(host).Host;
+ else if (host.Contains(":"))
+ host = host.Split(':')[0];
+ }
+ catch { /* fallback al valore originale se Uri fallisce */ }
+
+ // 3. Risoluzione Indirizzo
+ if (!IPAddress.TryParse(host, out IPAddress address))
+ {
+ try
+ {
+ var addresses = Dns.GetHostAddresses(host);
+ if (addresses.Length > 0) address = addresses[0];
+ }
+ catch (Exception ex)
+ {
+ lgError($"Impossibile risolvere DNS per {host}: {ex.Message}");
+ return IPStatus.DestinationHostUnreachable;
+ }
+ }
+
+ if (address == null) return IPStatus.Unknown;
+
+ // 4. Ciclo di Ping con Retry
+ var rand = new Random();
+ using (Ping pingSender = new Ping())
+ {
+ for (int attempt = 1; attempt <= maxAttempts; attempt++)
+ {
+ try
+ {
+ // Timeout dinamico come nel tuo originale
+ int timeout = (attempt == 1)
+ ? rand.Next(200, 400)
+ : (pingServerMsTimeout * attempt / 2);
+
+ PingReply reply = pingSender.Send(address, timeout);
+
+ if (reply.Status == IPStatus.Success)
+ {
+ if (attempt > 1) lgInfo("Server PING OK dopo retry!");
+ return IPStatus.Success;
+ }
+
+ lgInfo($"Ping tent. {attempt} fallito: {reply.Status} (Timeout: {timeout}ms)");
+ }
+ catch (Exception ex)
+ {
+ lgError($"Eccezione durante ping tent. {attempt}: {ex.Message}");
+ }
+
+ // Attesa prima del prossimo tentativo (se non è l'ultimo)
+ if (attempt < maxAttempts)
+ {
+ await Task.Delay(rand.Next(50, 200));
+ }
+ }
+ }
+
+ return IPStatus.TimedOut;
+ }
+
///
/// Verifica se il log di un dato errore sia permesso
///
@@ -5632,7 +5572,6 @@ namespace IOB_WIN_FORM.Iob
{
lgError($"Errore in RecipeDoProcessPODL.callUrl: {ex.Message}");
}
-
}
answ = true;
}
@@ -5662,6 +5601,132 @@ namespace IOB_WIN_FORM.Iob
parentForm.dataProcLabel = string.Format("RAW: {0} --> IN: {1} --> OUT: {2}", nReadIN, nReadFilt, nSendOut);
}
+ ///
+ /// Chiamate ritorno task eseguiti al server
+ ///
+ ///
+ ///
+ private async Task SendTaskResult(List listaValori)
+ {
+ foreach (var rawJob in listaValori)
+ {
+ // deserializzo...
+ JobTaskData jobTask = JsonConvert.DeserializeObject(rawJob);
+#if false
+ // loggo tutti i task done...
+ foreach (var item in jobTask.TaskList)
+ {
+ sendToTaskWatch(item.Key, item.Value, jobTask.CodTav);
+ }
+#endif
+ // ora chiamo la cancellazione dei task eseguiti...
+ var taskDict = JobTaskData.TaskDict(jobTask.RawData);
+ foreach (var item in taskDict)
+ {
+ await remTask2exe(item.Key, item.Value, jobTask.CodTav);
+ }
+ }
+ }
+
+ ///
+ /// Effettua ciclo recupero richieste server
+ ///
+ private async Task ServerGetRequestsAsync()
+ {
+ // recupero elenco delle cose da fare
+ string resp = await getTask2exe("");
+ // se ho qualcosa --> creo obj e lo accodo...
+ //if (!string.IsNullOrEmpty(resp))
+ if (!string.IsNullOrEmpty(resp) && resp.Length > 2)
+ {
+ //await ProcessResp(resp, "");
+ accodaServReq("", resp);
+ if (isMulti)
+ {
+ foreach (var item in IOBConfFull.Device.MultiIobList)
+ {
+ resp = await getTask2exe(item);
+ accodaServReq(item, resp);
+ //await ProcessResp(resp, rawJob);
+ }
+ }
+ }
+
+ // vers originale
+#if false
+ // recupero elenco delle cose da fare
+ string resp = await getTask2exe("");
+ await ProcessResp(resp, "");
+ // se fosse multi --> eseguo task per le varie sub (Tavole/Pallet)
+ if (isMulti)
+ {
+ foreach (var item in IOBConfFull.Device.MultiIobList)
+ {
+ resp = await getTask2exe(item);
+ await ProcessResp(resp, item);
+ }
+ }
+#endif
+ }
+
+ ///
+ /// Effettua ciclo invio rispsote (=esito esecuzione richieste) al server
+ ///
+ private async Task ServerPutRespAsync()
+ {
+ // verifico SE la coda abbia dei valori...
+ if (QueueSrvResp.Count > 0)
+ {
+ // invio pacchetto di dati (max da conf)
+ for (int i = 0; i < nMaxSend; i++)
+ {
+ // SE ho qualcosa in coda...
+ if (QueueSrvResp.Count > 0)
+ {
+ string currVal = "";
+ if (MPOnline)
+ {
+ if (IobOnline)
+ {
+ List listaValori = new List();
+ // se ho + di maxJsonData elementi --> invio un set di dati alla volta
+ if (QueueSrvResp.Count > maxJsonData)
+ {
+ // prendoi primi maxJsonDataValori
+ for (int j = 0; j < maxJsonData; j++)
+ {
+ QueueSrvResp.TryDequeue(out currVal);
+ listaValori.Add(currVal);
+ }
+ await SendTaskResult(listaValori);
+ }
+ else
+ {
+ // invio in blocco
+ listaValori = QueueSrvResp.ToList();
+ await SendTaskResult(listaValori);
+ // svuoto!
+ QueueSrvResp = new DataQueue(IOBConfFull.General.FilenameIOB, "QueueServResp", IOBConfFull.General.EnabRedisQue, redisMan);
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+
///
/// Imposto alcuni valori di default
///
@@ -5687,15 +5752,18 @@ namespace IOB_WIN_FORM.Iob
{
string codIob = IOBConfFull.General.FilenameIOB;
bool useRedis = IOBConfFull.General.EnabRedisQue;
- QueueAlarm = new DataQueue(codIob, "QueueAlarm", false, redisMan);
QueueIN.Dispose();
QueueIN = new DataQueue(codIob, "QueueIN", useRedis, redisMan);
+ QueueSrvResp.Dispose();
+ QueueSrvResp = new DataQueue(codIob, "QueueServResp", useRedis, redisMan);
// no coda redis
+ QueueAlarm = new DataQueue(codIob, "QueueAlarm", false, redisMan);
QueueFLog = new DataQueue(codIob, "QueueFLog", false, redisMan);
QueueMessages = new DataQueue(codIob, "QueueMessages", false, redisMan);
- QueueRawTransf = new DataQueue(codIob, "QueueRawTransf", false, redisMan);
- QueueULog = new DataQueue(codIob, "QueueULog", false, redisMan);
QueuePing = new DataQueue(codIob, "QueuePing", false, redisMan);
+ QueueRawTransf = new DataQueue(codIob, "QueueRawTransf", false, redisMan);
+ QueueSrvReq = new DataQueue(codIob, "QueueServReq", false, redisMan);
+ QueueULog = new DataQueue(codIob, "QueueULog", false, redisMan);
}
// imposto contatori blink a zero...
i_counters = new int[32];
@@ -5982,6 +6050,28 @@ namespace IOB_WIN_FORM.Iob
}
}
+ private void UpdateIobState(bool newStatus)
+ {
+ // Log se lo stato è cambiato
+ if (IobOnline != newStatus)
+ {
+ lgInfo(newStatus ? "IOB ONLINE for server MP/IO" : "IOB OFFLINE for server MP/IO");
+ IobOnline = newStatus;
+ if (newStatus)
+ {
+ lastIobOnline = DateTime.Now;
+ parentForm.commSrvActive = 2; // Stato Online
+ }
+ else
+ {
+ parentForm.commSrvActive = 1; // Stato Degradato/Offline
+ }
+ }
+
+ // Imposto il veto per il prossimo controllo
+ dtVetoCheckIOB = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 5);
+ }
+
#endregion Private Methods
}
}
\ No newline at end of file
diff --git a/IOB-WIN-FORM/Iob/Generic.Public.cs b/IOB-WIN-FORM/Iob/Generic.Public.cs
index 9e603b62..499456e9 100644
--- a/IOB-WIN-FORM/Iob/Generic.Public.cs
+++ b/IOB-WIN-FORM/Iob/Generic.Public.cs
@@ -60,7 +60,6 @@ namespace IOB_WIN_FORM.Iob
// initi oggetto TCMan
tcMan = new TCMan(IobConfNew.TCDataConf.Lambda, IobConfNew.TCDataConf.MaxDelayFactor, IobConfNew.TCDataConf.MaxIncrPz);
-
lastConnectTry = DateTime.Now;
lgInfo("Avvio preliminare AdapterGeneric");
@@ -81,7 +80,9 @@ namespace IOB_WIN_FORM.Iob
// imposto veto invio per i prossimi sec
dtVetoQueueIN = DateTime.Now.AddSeconds(vetoQueueIn);
- lgInfoStartup($"Impostato veto QUEUE-IN a {vetoQueueIn}s | fino alle {dtVetoQueueIN:yyyy.MM.dd HH:mm:ss}");
+ string msgVeto = $"Impostato veto QUEUE-IN a {vetoQueueIn}s | fino alle {dtVetoQueueIN:yyyy.MM.dd HH:mm:ss}";
+ lgInfoStartup(msgVeto);
+ lgInfo(msgVeto);
// invio info IOB
SendM2IOB();
@@ -100,16 +101,6 @@ namespace IOB_WIN_FORM.Iob
}
}
- ///
- /// Area init asincrono (fare override async!o)
- ///
- ///
- public virtual Task InitializeAsync()
- {
- // da usare per implementare logiche di init specifiche
- return Task.CompletedTask;
- }
-
#endregion Public Constructors
#region Public Events
@@ -335,6 +326,19 @@ namespace IOB_WIN_FORM.Iob
}
}
+ ///
+ /// Abilitazione coda segnali ingresso
+ ///
+ public bool queueInEnabCurr
+ {
+ get => qInEnabCurr;
+ set
+ {
+ qInEnabCurr = value;
+ lgInfo($"SET queueInEnabCurr: {value} | {DateTime.Now:HHmmss}");
+ }
+ }
+
///
/// Finestra dei byte da mostrare di default x il RawDataInput
///
@@ -432,7 +436,7 @@ namespace IOB_WIN_FORM.Iob
enabled = IOBConfFull.Memory.mMapRead[codFlux].sendEnabled;
if (!enabled)
{
- lgDebug($"accodaFLog : invio bloccato per conf aprametro sendEnabled | codFlux: {codFlux}");
+ lgDebug($"accodaFLog : invio bloccato per conf parametro sendEnabled | codFlux: {codFlux}");
}
else
{
@@ -631,6 +635,32 @@ namespace IOB_WIN_FORM.Iob
}
}
+ ///
+ /// Verifica se la IOB sia ENABLED (da server o Demo)
+ ///
+ public async Task CheckIobEnabled()
+ {
+ // 1. Controllo Veto (Sincrono)
+ if (dtVetoCheckIOB >= DateTime.Now)
+ return IobOnline;
+
+ bool currentAnsw = false;
+
+ if (DemoOut)
+ {
+ currentAnsw = (QueueIN.Count + QueueFLog.Count >= nMaxSend);
+ }
+ else
+ {
+ currentAnsw = await ExecuteIobCheckWithRetry(maxRetries: 5);
+ }
+
+ // 3. Gestione Stato e Logica UI
+ UpdateIobState(currentAnsw);
+
+ return currentAnsw;
+ }
+
///
/// Verifica se il server sia ALIVE (tramite PING)
///
@@ -662,18 +692,8 @@ namespace IOB_WIN_FORM.Iob
if (dtVetoPing >= DateTime.Now) return MPOnline;
if (DemoOut) return true;
-#if false
- // 2. Eseguo la parte asincrona forzando l'attesa
- // Usiamo Task.Run per far girare il codice asincrono su un thread del pool
- // evitando deadlock con il thread della UI
- bool isAlive = Task.Run(async () => await ExecuteApiCheckWithRetryAsync(maxRetries: 7))
- .GetAwaiter()
- .GetResult();
-#endif
-
bool isAlive = await ExecuteApiCheckWithRetryAsync(maxRetries: 7);
-
// 3. Gestione Stato (Sincrono)
UpdateServerState(isAlive);
@@ -681,64 +701,11 @@ namespace IOB_WIN_FORM.Iob
}
///
- /// Test ping + api al server in modalità Async
+ /// Verifica veto coda QueueIN ed aggiorna abilitazione su variabile
///
- ///
- ///
- private async Task ExecuteApiCheckWithRetryAsync(int maxRetries)
+ public void checkVetoQueueIn()
{
- var rand = new Random();
- for (int i = 0; i <= maxRetries; i++)
- {
- try
- {
- // Se non è il primo tentativo, resetta i client e aspetta
- if (i > 0)
- {
- if (i == 4) resetWebClients(); // Reset specifico a metà tentativi
- await Task.Delay(rand.Next(150, 500));
- }
-
- string resp = await callUrl(urlAlive, false);
- if (resp == "OK") return true;
- }
- catch (Exception ex)
- {
- if (i == 0) lgError($"Errore API Check: {ex.Message}");
- }
- }
- return false;
- }
-
- ///
- /// Update stato server
- ///
- ///
- private void UpdateServerState(bool currentAlive)
- {
- if (MPOnline != currentAlive)
- {
- MPOnline = currentAlive;
- parentForm.commSrvActive = currentAlive ? 1 : 0;
-
- if (currentAlive)
- {
- lgInfo("SERVER ONLINE");
- dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 5);
- }
- else
- {
- lgError("SERVER OFFLINE");
- // Veto standard per server offline
- dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 10);
- utils.dtVetoSend = dtVetoPing;
- }
- }
- else
- {
- // Se lo stato è invariato (es. era online e resta online), allunghiamo il prossimo controllo
- dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 20);
- }
+ queueInEnabCurr = dtVetoQueueIN < DateTime.Now;
}
///
@@ -766,6 +733,422 @@ namespace IOB_WIN_FORM.Iob
accodaOtherData(newData);
}
+ ///
+ /// Effettua i task di comunicazione IN/OUT con la macchina
+ ///
+ ///
+ ///
+ public void doMachineTask(gatherCycle ciclo)
+ {
+ // init obj display
+ newDisplayData currDispData = new newDisplayData();
+ // controllo connessione/connettività
+ if (connectionOk)
+ {
+ // controllo non sia già in esecuzione...
+ if (!adpCommAct)
+ {
+ // provo ad avviare
+ try
+ {
+ // imposto flag adapter running..
+ adpCommAct = true;
+ adpStartRun = DateTime.Now;
+ }
+ catch (Exception exc)
+ {
+ string errore = $"Adapter NOT STARTED!!!{Environment.NewLine}{exc}";
+ adpCommAct = false;
+ adpStartRun = DateTime.Now;
+ currDispData.newLiveLogData = errore;
+ }
+ if (adpCommAct)
+ {
+ // try / catch generale altrimenti segno che è disconnesso...
+ try
+ {
+ if (ciclo == gatherCycle.VHF)
+ {
+ //processVHF();
+ }
+ // processing dati memoria (lettura, filtraggio, enqueque)
+ else if (ciclo == gatherCycle.HF)
+ {
+ processWhatchDog();
+ Thread.Sleep(5);
+ processAllMemory();
+ }
+ else if (ciclo == gatherCycle.MF)
+ {
+ processMode();
+ Thread.Sleep(5);
+ ExecServerRequests();
+#if false
+ processServerRequests().GetAwaiter().GetResult();
+#endif
+ Thread.Sleep(5);
+ processCustomTaskMF();
+ Thread.Sleep(5);
+ processOverride();
+ Thread.Sleep(5);
+ processContapezzi();
+ Thread.Sleep(5);
+ processCncAlarms();
+ Thread.Sleep(5);
+ processDynData();
+ Thread.Sleep(5);
+ processMem2Write();
+ //processAllMemory();
+ }
+ else if (ciclo == gatherCycle.LF)
+ {
+ processCustomTaskLF();
+ Thread.Sleep(5);
+ processOtherCounters().GetAwaiter().GetResult(); ;
+ Thread.Sleep(5);
+ processProgram();
+ //// verifico se devo gestire cambio ODL in modo automatico
+ //await ProcessAutoOdlAsync();
+ //// verifico se devo gestire auto generazione dossier quotidiana
+ //ProcessAutoDossier();
+ //// effettua gestione import file se configurato...
+ //await ProcessFileImportAsync();
+ //// effettua process ritorno ricette
+ //await ProcessRecipeFileRetAsync();
+ }
+ else if (ciclo == gatherCycle.VLF)
+ {
+ //if (utils.CRB("enableContapezzi"))
+ //{
+ // // rilettura contapezzi da server...
+ // lgTrace("Ciclo MsVLF: pzCntReload(true)");
+ // if (!isMulti)
+ // {
+ // pzCntReload(true);
+ // }
+ // // refresh associazione Macchina - IOB
+ // await SendM2IobAsync();
+ // // invio altri dati accessori...
+ // await SendMachineConfAsync();
+ //}
+ //// checkLogDir x shrink!
+ //checkShrinkDir();
+ //// eventuale log!
+ //if (utils.CRB("recTime"))
+ //{
+ // try
+ // {
+ // logTimeResults();
+ // }
+ // catch
+ // { }
+ //}
+ //processRecipeSyncArch();
+ // recupero dati SETUP (sysinfo) e li invio/mostro se variati...
+ processSysInfo();
+ if (enableSlowData)
+ {
+ Thread.Sleep(5);
+ processSlowDataRead();
+ }
+ }
+
+ //// mostra eventuali altri dati di processo...
+ //reportDataProc();
+ //if (showDebugData)
+ //{
+ // // verifica se debba salvare e mostrare dati
+ // checkSavePersDataLayer();
+ //}
+ }
+ catch (Exception exc)
+ {
+ // segnalo eccezione e indico disconnesso...
+ lgError($"Exception doMachineTask | {ciclo} | fermo adapter{Environment.NewLine}{exc}");
+ parentForm.fermaAdapter(true, false, true);
+ }
+ // tolgo flag running
+ adpCommAct = false;
+ }
+ else
+ {
+ if (periodicLog)
+ {
+ lgDebug("ADP not running...");
+ }
+ }
+ }
+ else
+ {
+ // log ADP running
+ lgError("Non eseguo chiamata: ADP ancora in running");
+ // se è bloccato da oltre maxSec lo sblocco...
+ if (DateTime.Now.Subtract(adpStartRun).TotalSeconds > utils.CRI("maxAdapterLockSec"))
+ {
+ // tolgo flag running
+ adpCommAct = false;
+ adpStartRun = DateTime.Now;
+ }
+ }
+ }
+ else
+ {
+ //// anche se NON connesso alcuni task di bassa freq li eseguo...
+ //if (ciclo == gatherCycle.LF)
+ //{
+ // // verifico se devo gestire cambio ODL in modo automatico
+ // await ProcessAutoOdlAsync();
+ // // verifico se devo gestire auto generazione dossier quotidiana
+ // ProcessAutoDossier();
+ // // effettua gestione import file se configurato...
+ // await ProcessFileImportAsync();
+ // // effettua process ritorno ricette
+ // await ProcessRecipeFileRetAsync();
+ //}
+ //else if (ciclo == gatherCycle.VLF)
+ //{
+ // processRecipeSyncArch();
+ //}
+
+ // provo a riconnettere SE abilitato tryRestart...
+ if (adpTryRestart && !connectionOk)
+ {
+ // controllo se sia scaduto periodi di veto al tryConnect...
+ int waitRecMSec = utils.CRI("waitRecMSec");
+ // cerco se ci sia un valore in ovverride x il singolo IOB...
+ if (IOBConfFull.General.WaitRecMsec > 0)
+ {
+ waitRecMSec = IOBConfFull.General.WaitRecMsec;
+ }
+ DateTime dtVeto = lastConnectTry.AddMilliseconds(waitRecMSec);
+ if (DateTime.Now > dtVeto)
+ {
+ lgInfo($"Veto Time Elapsed | lastConnectTry: {lastConnectTry} | waitRecMSec {waitRecMSec} ms) | NOW tryConnect");
+ lastConnectTry = DateTime.Now;
+ tryConnect();
+ }
+ }
+ currDispData.semIn = Semaforo.SR;
+ processDisconnectedTask();
+ processMemoryDiscon();
+ }
+ raiseRefresh(currDispData);
+ }
+
+ ///
+ /// Effettua i task di comunicazione IN/OUT con il server MAPO
+ ///
+ ///
+ ///
+ public async Task doServerTaskAsync(gatherCycle ciclo)
+ {
+ // init obj display
+ newDisplayData currDispData = new newDisplayData();
+ // IN OGNI CASO a prima di tutto EFFETTUO GESTIONE INVII dati da code!!!
+ try
+ {
+ await TrySendValuesAsync();
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in gestione svuotamento/invio preliminare code memoria");
+ currDispData.semOut = Semaforo.SR;
+ }
+ // controllo connessione/connettività
+ if (connectionOk)
+ {
+ // try / catch generale altrimenti segno che è disconnesso...
+ try
+ {
+ bool showDebugData = false;
+ if (ciclo == gatherCycle.VHF)
+ {
+ processVHF();
+ }
+ // processing dati memoria (lettura, filtraggio, enqueque)
+ else if (ciclo == gatherCycle.HF)
+ {
+ //processWhatchDog();
+ //processAllMemory();
+
+ // recupera ed invia risposte al server
+ await ServerPutRespAsync();
+ }
+ else if (ciclo == gatherCycle.MF)
+ {
+ //processMode();
+
+ // recupero elenco richieste
+ await ServerGetRequestsAsync();
+
+ //processCustomTaskMF();
+ //processOverride();
+ //processContapezzi();
+ //processCncAlarms();
+ //processDynData();
+ //processMem2Write();
+ //processAllMemory();
+ }
+ else if (ciclo == gatherCycle.LF)
+ {
+ //processCustomTaskLF();
+ //await processOtherCounters();
+ //processProgram();
+
+ // verifico se devo gestire cambio ODL in modo automatico
+ await ProcessAutoOdlAsync();
+ // verifico se devo gestire auto generazione dossier quotidiana
+ ProcessAutoDossier();
+ // effettua gestione import file se configurato...
+ await ProcessFileImportAsync();
+ // effettua process ritorno ricette
+ await ProcessRecipeFileRetAsync();
+ }
+ else if (ciclo == gatherCycle.VLF)
+ {
+ if (utils.CRB("enableContapezzi"))
+ {
+ // rilettura contapezzi da server...
+ lgTrace("Ciclo MsVLF: pzCntReload(true)");
+ if (!isMulti)
+ {
+ pzCntReload(true);
+ }
+ // refresh associazione Macchina - IOB
+ await SendM2IobAsync();
+ // invio altri dati accessori...
+ await SendMachineConfAsync();
+ }
+ // checkLogDir x shrink!
+ checkShrinkDir();
+ // eventuale log!
+ if (utils.CRB("recTime"))
+ {
+ try
+ {
+ logTimeResults();
+ }
+ catch
+ { }
+ }
+ processRecipeSyncArch();
+
+ //// recupero dati SETUP (sysinfo) e li invio/mostro se variati...
+ //processSysInfo();
+ //if (enableSlowData)
+ //{
+ // processSlowDataRead();
+ //}
+ }
+
+ // mostra eventuali altri dati di processo...
+ reportDataProc();
+ if (showDebugData)
+ {
+ // verifica se debba salvare e mostrare dati
+ checkSavePersDataLayer();
+ }
+ }
+ catch (Exception exc)
+ {
+ // segnalo eccezione e indico disconnesso...
+ lgError($"Exception | doServerTaskAsync | {ciclo}{Environment.NewLine}{exc}");
+ }
+ }
+ else
+ {
+ // anche se NON connesso alcuni task di bassa freq li eseguo...
+ if (ciclo == gatherCycle.LF)
+ {
+ // verifico se devo gestire cambio ODL in modo automatico
+ await ProcessAutoOdlAsync();
+ // verifico se devo gestire auto generazione dossier quotidiana
+ ProcessAutoDossier();
+ // effettua gestione import file se configurato...
+ await ProcessFileImportAsync();
+ // effettua process ritorno ricette
+ await ProcessRecipeFileRetAsync();
+ }
+ else if (ciclo == gatherCycle.VLF)
+ {
+ processRecipeSyncArch();
+ }
+
+ //// provo a riconnettere SE abilitato tryRestart...
+ //if (adpTryRestart && !connectionOk)
+ //{
+ // // controllo se sia scaduto periodi di veto al tryConnect...
+ // int waitRecMSec = utils.CRI("waitRecMSec");
+ // // cerco se ci sia un valore in ovverride x il singolo IOB...
+ // if (IOBConfFull.General.WaitRecMsec > 0)
+ // {
+ // waitRecMSec = IOBConfFull.General.WaitRecMsec;
+ // }
+ // DateTime dtVeto = lastConnectTry.AddMilliseconds(waitRecMSec);
+ // if (DateTime.Now > dtVeto)
+ // {
+ // lgInfo($"Veto Time Elapsed | lastConnectTry: {lastConnectTry} | waitRecMSec {waitRecMSec} ms) | NOW tryConnect");
+ // lastConnectTry = DateTime.Now;
+ // tryConnect();
+ // }
+ //}
+ //currDispData.semIn = Semaforo.SR;
+ //processDisconnectedTask();
+ //processMemoryDiscon();
+ }
+ raiseRefresh(currDispData);
+ }
+
+ public void ExecServerRequests()
+ {
+ // verifica se ci siano richieste da eseguire
+ if (QueueSrvReq.Count > 0)
+ {
+ if (MPOnline)
+ {
+ if (IobOnline)
+ {
+ // prendo elenco
+ List listaValori = QueueSrvReq.ToList();
+
+ foreach (var rawJob in listaValori)
+ {
+ // deserializzo...
+ JobTaskData jobTaskReq = JsonConvert.DeserializeObject(rawJob);
+ // processo!
+ var reqDict = JobTaskData.TaskDict(jobTaskReq.RawData);
+ if (reqDict.Count > 0)
+ {
+ var taskDone = ProcessTask(JobTaskData.TaskDict(jobTaskReq.RawData), jobTaskReq.CodTav);
+ // accodo task eseguiti...
+ string serVal = JsonConvert.SerializeObject(taskDone);
+ accodaServResp(jobTaskReq.CodTav, serVal);
+ }
+ }
+
+ // svuoto!
+ QueueSrvReq = new DataQueue(IOBConfFull.General.FilenameIOB, "QueueServResp", IOBConfFull.General.EnabRedisQue, redisMan);
+ }
+ }
+ }
+
+ // versione originale in blocco
+#if false
+ // recupero elenco delle cose da fare
+ string resp = await getTask2exe("");
+ await ProcessResp(resp, "");
+ // se fosse multi --> eseguo task per le varie sub (Tavole/Pallet)
+ if (isMulti)
+ {
+ foreach (var item in IOBConfFull.Device.MultiIobList)
+ {
+ resp = await getTask2exe(item);
+ await ProcessResp(resp, item);
+ }
+ }
+#endif
+ }
+
///
/// Esecuzione dei task richiesti e pulizia coda richieste eseguite
///
@@ -1022,7 +1405,7 @@ namespace IOB_WIN_FORM.Iob
catch (Exception ex)
{
lgError("ProcessOtherInfoAsync | Crash nel ponte Sync/Async: " + ex.Message);
- }
+ }
#endif
break;
@@ -1273,23 +1656,30 @@ namespace IOB_WIN_FORM.Iob
return valTransl;
}
+#if false
///
- /// effettua recupero dati ed invio valori modificati...
+ /// Effettua recupero dati ed invio valori modificati...
///
- ///
- public async Task getAndSendAsync(gatherCycle ciclo)
+ /// Ciclo di freq richiesta
+ /// Indica se siano abilitate operazioni Pool (Thread Safe)
+ /// Indica se siano abilitate le operazioni Single Thread
+ ///
+ public async Task getAndSendAsync(gatherCycle ciclo, bool enabPool, bool enabSTID)
{
// init obj display
newDisplayData currDispData = new newDisplayData();
- // IN OGNI CASO a prima di tutto EFFETTUO GESTIONE INVII dati da code!!!
- try
+ if (enabPool)
{
- await TrySendValuesAsync();
- }
- catch (Exception exc)
- {
- lgError(exc, "Errore in gestione svuotamento/invio preliminare code memoria");
- currDispData.semOut = Semaforo.SR;
+ // IN OGNI CASO a prima di tutto EFFETTUO GESTIONE INVII dati da code!!!
+ try
+ {
+ await TrySendValuesAsync();
+ }
+ catch (Exception exc)
+ {
+ lgError(exc, "Errore in gestione svuotamento/invio preliminare code memoria");
+ currDispData.semOut = Semaforo.SR;
+ }
}
// controllo connessione/connettività
if (connectionOk)
@@ -1319,81 +1709,105 @@ namespace IOB_WIN_FORM.Iob
bool showDebugData = false;
if (ciclo == gatherCycle.VHF)
{
- processVHF();
+ if (enabPool)
+ {
+ processVHF();
+ }
}
// processing dati memoria (lettura, filtraggio, enqueque)
else if (ciclo == gatherCycle.HF)
{
- processWhatchDog();
- processAllMemory();
+ if (enabSTID)
+ {
+ processWhatchDog();
+ processAllMemory();
+ }
}
else if (ciclo == gatherCycle.MF)
{
- processMode();
- await processServerRequests();
- processCustomTaskMF();
- processOverride();
- processContapezzi();
- processCncAlarms();
- processDynData();
- processMem2Write();
- processAllMemory();
+ if (enabSTID)
+ {
+ processMode();
+ await processServerRequests();
+ processCustomTaskMF();
+ processOverride();
+ processContapezzi();
+ processCncAlarms();
+ processDynData();
+ processMem2Write();
+ processAllMemory();
+ }
}
else if (ciclo == gatherCycle.LF)
{
- processCustomTaskLF();
- processOtherCounters();
- processProgram();
- // verifico se devo gestire cambio ODL in modo automatico
- await ProcessAutoOdlAsync();
- // verifico se devo gestire auto generazione dossier quotidiana
- ProcessAutoDossier();
- // effettua gestione import file se configurato...
- await ProcessFileImportAsync();
- // effettua process ritorno ricette
- await ProcessRecipeFileRetAsync();
+ if (enabSTID)
+ {
+ processCustomTaskLF();
+ await processOtherCounters();
+ processProgram();
+ }
+ if (enabPool)
+ {
+ // verifico se devo gestire cambio ODL in modo automatico
+ await ProcessAutoOdlAsync();
+ // verifico se devo gestire auto generazione dossier quotidiana
+ ProcessAutoDossier();
+ // effettua gestione import file se configurato...
+ await ProcessFileImportAsync();
+ // effettua process ritorno ricette
+ await ProcessRecipeFileRetAsync();
+ }
}
else if (ciclo == gatherCycle.VLF)
{
- if (utils.CRB("enableContapezzi"))
+ if (enabPool)
{
- // rilettura contapezzi da server...
- lgTrace("Ciclo MsVLF: pzCntReload(true)");
- if (!isMulti)
+ if (utils.CRB("enableContapezzi"))
{
- pzCntReload(true);
+ // rilettura contapezzi da server...
+ lgTrace("Ciclo MsVLF: pzCntReload(true)");
+ if (!isMulti)
+ {
+ pzCntReload(true);
+ }
+ // refresh associazione Macchina - IOB
+ await SendM2IobAsync();
+ // invio altri dati accessori...
+ await SendMachineConfAsync();
}
- // refresh associazione Macchina - IOB
- await SendM2IobAsync();
- // invio altri dati accessori...
- await SendMachineConfAsync();
- }
- // recupero dati SETUP (sysinfo) e li invio/mostro se variati...
- processSysInfo();
- // checkLogDir x shrink!
- checkShrinkDir();
- // eventuale log!
- if (utils.CRB("recTime"))
- {
- try
+ // checkLogDir x shrink!
+ checkShrinkDir();
+ // eventuale log!
+ if (utils.CRB("recTime"))
{
- logTimeResults();
+ try
+ {
+ logTimeResults();
+ }
+ catch
+ { }
}
- catch
- { }
+ processRecipeSyncArch();
}
- processRecipeSyncArch();
- if (enableSlowData)
+ if (enabSTID)
{
- processSlowDataRead();
+ // recupero dati SETUP (sysinfo) e li invio/mostro se variati...
+ processSysInfo();
+ if (enableSlowData)
+ {
+ processSlowDataRead();
+ }
}
}
- // mostra eventuali altri dati di processo...
- reportDataProc();
- if (showDebugData)
+ if (enabPool)
{
- // verifica se debba salvare e mostrare dati
- checkSavePersDataLayer();
+ // mostra eventuali altri dati di processo...
+ reportDataProc();
+ if (showDebugData)
+ {
+ // verifica se debba salvare e mostrare dati
+ checkSavePersDataLayer();
+ }
}
}
catch (Exception exc)
@@ -1428,28 +1842,31 @@ namespace IOB_WIN_FORM.Iob
}
else
{
- // anche se NON connesso alcuni task di bassa freq li eseguo...
- if (ciclo == gatherCycle.LF)
+ if (enabPool)
{
- // verifico se devo gestire cambio ODL in modo automatico
- await ProcessAutoOdlAsync();
- // verifico se devo gestire auto generazione dossier quotidiana
- ProcessAutoDossier();
- // effettua gestione import file se configurato...
- await ProcessFileImportAsync();
- // effettua process ritorno ricette
- await ProcessRecipeFileRetAsync();
- }
- else if (ciclo == gatherCycle.VLF)
- {
- processRecipeSyncArch();
+ // anche se NON connesso alcuni task di bassa freq li eseguo...
+ if (ciclo == gatherCycle.LF)
+ {
+ // verifico se devo gestire cambio ODL in modo automatico
+ await ProcessAutoOdlAsync();
+ // verifico se devo gestire auto generazione dossier quotidiana
+ ProcessAutoDossier();
+ // effettua gestione import file se configurato...
+ await ProcessFileImportAsync();
+ // effettua process ritorno ricette
+ await ProcessRecipeFileRetAsync();
+ }
+ else if (ciclo == gatherCycle.VLF)
+ {
+ processRecipeSyncArch();
+ }
}
// provo a riconnettere SE abilitato tryRestart...
if (adpTryRestart && !connectionOk)
{
// controllo se sia scaduto periodi di veto al tryConnect...
- int waitRecMSec = utils.CRI("waitRecMSec") * 2;
+ int waitRecMSec = utils.CRI("waitRecMSec");
// cerco se ci sia un valore in ovverride x il singolo IOB...
if (IOBConfFull.General.WaitRecMsec > 0)
{
@@ -1469,6 +1886,7 @@ namespace IOB_WIN_FORM.Iob
}
raiseRefresh(currDispData);
}
+#endif
///
/// Effettua conversione da valore bitmap ai valori configurati
@@ -1672,6 +2090,16 @@ namespace IOB_WIN_FORM.Iob
return answ;
}
+ ///
+ /// Area init asincrono (fare override async!o)
+ ///
+ ///
+ public virtual Task InitializeAsync()
+ {
+ // da usare per implementare logiche di init specifiche
+ return Task.CompletedTask;
+ }
+
///
/// Restituisce un payload in formato json della lista di valori ricevuta
///
@@ -1977,7 +2405,6 @@ namespace IOB_WIN_FORM.Iob
}
}
-
///
/// Verifica e processing x gestione ODL automatica
///
@@ -2202,7 +2629,7 @@ namespace IOB_WIN_FORM.Iob
if (item.Key == "ND" || string.IsNullOrEmpty(item.Key))
{
// log anomalia...
- lgTrace($"Errore in predisposizione FL Allarmi CNC: item.key risulta ND! | item.key: {item.Key} | item.Value: {item.Value}");
+ lgTrace($"Errore in predisposizione FL Allarmi CNC: rawJob.key risulta ND! | rawJob.key: {item.Key} | rawJob.Value: {item.Value}");
}
else
{
@@ -2224,7 +2651,7 @@ namespace IOB_WIN_FORM.Iob
if (item.Key == "ND" || string.IsNullOrEmpty(item.Key))
{
// log anomalia...
- lgTrace($"Errore in predisposizione FL Allarmi NON CNC: item.key risulta ND! | item.key: {item.Key} | item.Value: {item.Value}");
+ lgTrace($"Errore in predisposizione FL Allarmi NON CNC: rawJob.key risulta ND! | rawJob.key: {item.Key} | rawJob.Value: {item.Value}");
}
else
{
@@ -2355,7 +2782,7 @@ namespace IOB_WIN_FORM.Iob
if (item.Key == "ND" || string.IsNullOrEmpty(item.Key))
{
// log anomalia...
- lgTrace($"Errore in processDynData.01: item.key risulta ND! | item.key: {item.Key} | item.Value: {item.Value}");
+ lgTrace($"Errore in processDynData.01: rawJob.key risulta ND! | rawJob.key: {item.Key} | rawJob.Value: {item.Value}");
}
else
{
@@ -2386,7 +2813,7 @@ namespace IOB_WIN_FORM.Iob
if (item.Key == "ND" || string.IsNullOrEmpty(item.Key))
{
// log anomalia...
- lgTrace($"Errore in processDynData.02: item.key risulta ND! | item.key: {item.Key} | item.Value: {item.Value}");
+ lgTrace($"Errore in processDynData.02: rawJob.key risulta ND! | rawJob.key: {item.Key} | rawJob.Value: {item.Value}");
}
else
{
@@ -2426,7 +2853,6 @@ namespace IOB_WIN_FORM.Iob
if (memMap != null && memMap.mMapRead.ContainsKey(item.Key) && !string.IsNullOrEmpty(item.Value))
{
upsertKeyLP(item.Key, item.Value);
-
}
}
}
@@ -2516,7 +2942,7 @@ namespace IOB_WIN_FORM.Iob
if (item.Key == "ND" || string.IsNullOrEmpty(item.Key))
{
// log anomalia...
- lgTrace($"Errore in processOverride: item.key risulta ND! | item.key: {item.Key} | item.Value: {item.Value}");
+ lgTrace($"Errore in processOverride: rawJob.key risulta ND! | rawJob.key: {item.Key} | rawJob.Value: {item.Value}");
}
else
{
@@ -2537,24 +2963,65 @@ namespace IOB_WIN_FORM.Iob
}
///
- /// Effettua ciclo controllo richieste server
+ /// Processa esecuzione task ricevuti
///
- public async Task processServerRequests()
+ ///
+ ///
+ /// Restituisce elenco task svolti --> per accodamento risposta
+ public Dictionary ProcessTask(Dictionary task2exe, string codTav)
{
- // recupero elenco delle cose da fare
- string resp = await getTask2exe("");
- await ProcessResp(resp, "");
- // se fosse multi --> eseguo task per le varie sub (Tavole/Pallet)
- if (isMulti)
+ Dictionary taskDone = new Dictionary();
+ Dictionary task2Add = new Dictionary();
+ // eseguo realmente solo se NON disabilitata questa gestione (caso doppio PLC/HMI)...
+ if (!IOBConfFull.Device.DisabExeTask)
{
- foreach (var item in IOBConfFull.Device.MultiIobList)
+ if (task2exe != null && task2exe.Count > 0)
{
- resp = await getTask2exe(item);
- await ProcessResp(resp, item);
+ string logMsg = $"Task2Exe S01: {task2exe.Count} task ricevuti";
+ if (!string.IsNullOrEmpty(codTav))
+ {
+ logMsg += $" | codTav: {codTav}";
+ }
+ lgInfo(logMsg);
+ int idTask = 0;
+ foreach (var item in task2exe)
+ {
+ idTask++;
+ lgInfo($"[{idTask:00}] - {item.Key} --> {item.Value}");
+ // verifico SE il task abbia un duplo writeLink e nel caso lo aggiungo...
+ var linkVal = getOptWriteLink(item.Key);
+ if (!string.IsNullOrEmpty(linkVal))
+ {
+ // aggiungo a task2add SE manca...
+ if (!task2Add.ContainsKey(linkVal))
+ {
+ task2Add.Add(linkVal, item.Value);
+ }
+ lgInfo($"Aggiunta task linked: {linkVal} -> {item.Value}");
+ }
+ }
+ // se ho task Link da aggiungere li aggiungo!
+ if (task2Add.Count > 0)
+ {
+ foreach (var item in task2Add)
+ {
+ task2exe.Add(item.Key, item.Value);
+ }
+ }
+ // chiamo procedura esecutiva (diversa x ogni IOB)
+ taskDone = executeTasks(task2exe, codTav);
+ lgInfo($"Task2Exe S02: eseguiti {taskDone.Count} task");
+ // loggo tutti i task done...
+ foreach (var item in taskDone)
+ {
+ sendToTaskWatch(item.Key, item.Value, codTav);
+ }
}
}
+ return taskDone;
}
+#if false
///
/// Processa esecuzione task ricevuti
///
@@ -2618,6 +3085,7 @@ namespace IOB_WIN_FORM.Iob
}
return taskDone;
}
+#endif
///
/// Classe fittizia in caso di processing task in MsVHF
@@ -3386,12 +3854,13 @@ namespace IOB_WIN_FORM.Iob
// sistemo altri check avvio
dtVetoQueueIN = DateTime.Now.AddSeconds(vetoQueueIn);
queueInEnabCurr = false;
- lgInfoStartup($"Impostato veto QUEUE-IN a {vetoQueueIn}s | fino alle {dtVetoQueueIN:yyyy.MM.dd HH:mm:ss}");
+ string msgVeto = $"Impostato veto QUEUE-IN a {vetoQueueIn}s | fino alle {dtVetoQueueIN:yyyy.MM.dd HH:mm:ss}";
+ lgInfoStartup(msgVeto);
lgDebug($"startAdapter completed | veto queueIn impostato per {vetoQueueIn}s fino alle {dtVetoQueueIN:yyyy.MM.dd HH:mm:ss}");
}
///
- /// ferma l'adapter...
+ /// Ferma l'adapter...
///
///
/// indica se si debba tentare di riavviare l'adapter (con caduta connessione viene fermato
@@ -3763,6 +4232,37 @@ namespace IOB_WIN_FORM.Iob
#region Private Methods
+ ///
+ /// Test ping + api al server in modalità Async
+ ///
+ ///
+ ///
+ private async Task ExecuteApiCheckWithRetryAsync(int maxRetries)
+ {
+ var rand = new Random();
+ for (int i = 0; i <= maxRetries; i++)
+ {
+ try
+ {
+ // Se non è il primo tentativo, resetta i client e aspetta
+ if (i > 0)
+ {
+ if (i == 4) resetWebClients(); // Reset specifico a metà tentativi
+ await Task.Delay(rand.Next(150, 500));
+ }
+
+ string resp = await callUrl(urlAlive, false);
+ if (resp == "OK") return true;
+ }
+ catch (Exception ex)
+ {
+ if (i == 0) lgError($"Errore API Check: {ex.Message}");
+ }
+ }
+ return false;
+ }
+
+#if false
///
/// Processing di una risposta raw di task2exe
///
@@ -3785,10 +4285,42 @@ namespace IOB_WIN_FORM.Iob
}
catch (Exception exc)
{
- lgError($"Eccezione in processServerRequests.ProcessResp:{Environment.NewLine}{exc}");
+ lgError($"Eccezione in ServerGetRequestsAsync.ProcessResp:{Environment.NewLine}{exc}");
}
}
}
+#endif
+
+ ///
+ /// Update stato server
+ ///
+ ///
+ private void UpdateServerState(bool currentAlive)
+ {
+ if (MPOnline != currentAlive)
+ {
+ MPOnline = currentAlive;
+ parentForm.commSrvActive = currentAlive ? 1 : 0;
+
+ if (currentAlive)
+ {
+ lgInfo("SERVER ONLINE");
+ dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 5);
+ }
+ else
+ {
+ lgError("SERVER OFFLINE");
+ // Veto standard per server offline
+ dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 10);
+ utils.dtVetoSend = dtVetoPing;
+ }
+ }
+ else
+ {
+ // Se lo stato è invariato (es. era online e resta online), allunghiamo il prossimo controllo
+ dtVetoPing = DateTime.Now.AddMilliseconds(baseUtils.nextPauseSendMSec * 20);
+ }
+ }
#endregion Private Methods
}
diff --git a/IOB-WIN-MTC/DATA/CONF/FOV062.json b/IOB-WIN-MTC/DATA/CONF/FOV062.json
index c99e445c..14729269 100644
--- a/IOB-WIN-MTC/DATA/CONF/FOV062.json
+++ b/IOB-WIN-MTC/DATA/CONF/FOV062.json
@@ -17,6 +17,8 @@
}
],
"fluxLogVeto": [
+ "E_nblock1",
+ "E_nline1",
"S_nactS1P1",
"S_nloadS1P1",
"S_nactUP1",