Eliminazione file inutilizzati
This commit is contained in:
@@ -379,17 +379,14 @@
|
||||
<Compile Include="AdapterFormNext.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Iob\Mitsubishi.cs" />
|
||||
<Compile Include="MainFormNext.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="TcAdsClient.cs" />
|
||||
<Compile Include="GlobalSuppressions.cs" />
|
||||
<Compile Include="IobBeckhoff\BeckhoffCpa.cs" />
|
||||
<Compile Include="Iob\Omron.cs" />
|
||||
<Compile Include="IobBeckhoff\Beckhoff.cs" />
|
||||
<Compile Include="Iob\OSAI.cs" />
|
||||
<Compile Include="Iob\Kawasaki.cs" />
|
||||
<Compile Include="Output.cs" />
|
||||
<Compile Include="Iob\GenericNext.cs" />
|
||||
<Compile Include="Program.cs" />
|
||||
@@ -587,8 +584,6 @@
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Folder Include="IobFile\" />
|
||||
<Folder Include="IobSql\" />
|
||||
<Folder Include="prog\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,851 +0,0 @@
|
||||
using IOB_UT_NEXT;
|
||||
using MapoSDK;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
|
||||
namespace IOB_WIN_NEXT.Iob
|
||||
{
|
||||
public class Omron : Iob.GenericNext
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
/// estende l'init della classe base...
|
||||
/// </summary>
|
||||
/// <param name="caller"></param>
|
||||
/// <param name="adpConf"></param>
|
||||
public Omron(AdapterFormNext caller, IobConfiguration IOBConf) : base(caller, IOBConf)
|
||||
{
|
||||
// gestione invio ritardato contapezzi
|
||||
pzCountDelay = utils.CRI("pzCountDelay");
|
||||
lastPzCountSend = DateTime.Now;
|
||||
lastWarnODL = DateTime.Now;
|
||||
|
||||
// imposto i parametri PLC
|
||||
setParamPlc();
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Processo i task richiesti e li elimino dalla coda 1:1
|
||||
/// </summary>
|
||||
/// <param name="task2exe"></param>
|
||||
public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe)
|
||||
{
|
||||
// uso metodo base x ora
|
||||
return base.executeTasks(task2exe);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupero dati dinamici...
|
||||
/// </summary>
|
||||
public override Dictionary<string, string> getDynData()
|
||||
{
|
||||
// valore non presente in vers default... se gestito fare override
|
||||
Dictionary<string, string> outVal = new Dictionary<string, string>();
|
||||
outVal.Add("kgAct", pesoRilevato.ToString());
|
||||
outVal.Add("kgImp", pesoRichiesto.ToString());
|
||||
return outVal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua vero processing contapezzi
|
||||
/// </summary>
|
||||
public override void processContapezzi()
|
||||
{
|
||||
if (utils.CRB("enableContapezzi"))
|
||||
{
|
||||
#if false
|
||||
try
|
||||
{
|
||||
// hard coded... !!!FARE!!! rivedere megio conf
|
||||
contapezziPLC = pzCounter;
|
||||
// verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con indicazione area)
|
||||
if (cIobConf.optPar.Count > 0 && getOptPar("PZCOUNT_MODE") != "")
|
||||
{
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgError(exc, "Errore in contapezzi OMRON");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua lettura semafori principale <paramref name="currDispData">Parametri da
|
||||
/// aggiornare x display in form</paramref>
|
||||
/// </summary>
|
||||
public override void readSemafori(ref newDisplayData currDispData)
|
||||
{
|
||||
base.readSemafori(ref currDispData);
|
||||
try
|
||||
{
|
||||
if (verboseLog)
|
||||
{
|
||||
lgInfo("inizio read semafori");
|
||||
}
|
||||
|
||||
currDispData.semIn = Semaforo.SV;
|
||||
|
||||
// effettuo TUTTE le letture
|
||||
OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.CIO, 0, 60, out memReadCIO_IN);
|
||||
OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.CIO, 100, 10, out memReadCIO_OUT);
|
||||
//OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.DM, 0, 8, out memReadDM);
|
||||
//OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.WR, 0, 8, out memReadWR);
|
||||
|
||||
contapezziPLC = pesoRilevato;
|
||||
// decodifica e gestione
|
||||
decodeToBaseBitmap();
|
||||
reportRawInput(ref currDispData);
|
||||
}
|
||||
catch
|
||||
{
|
||||
currDispData.semIn = Semaforo.SR;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua reset del contapezzi, in questo caso il conteggio dei KG
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override bool resetContapezziPLC()
|
||||
{
|
||||
bool answ = false;
|
||||
#if false
|
||||
// ...SE abilitato da conf IOB
|
||||
if (cIobConf.optPar.Count > 0 && getOptPar("ENABLE_PZ_RESET") == "TRUE")
|
||||
{
|
||||
// scrivo valore 0 x il contapezzi
|
||||
try
|
||||
{
|
||||
pzCounter = 0;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgError(exc, "Errore in RESET contapezzi OMRON");
|
||||
connectionOk = false;
|
||||
}
|
||||
answ = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
lgError("Impossibile effettuare RESET contapezzi OMRON, mancanza parametro OPT:ENABLE_PZ_RESET");
|
||||
}
|
||||
#endif
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua IMPOSTAZIONE FORZATA del contapezzi, in questo caso il conteggio dei KG
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override bool setcontapezziPLC(int newPzCount)
|
||||
{
|
||||
bool answ = false;
|
||||
#if false
|
||||
// ...SE abilitato da conf IOB
|
||||
if (cIobConf.optPar.Count > 0 && getOptPar("ENABLE_PZ_RESET") == "TRUE")
|
||||
{
|
||||
// scrivo valore 0 x il contapezzi
|
||||
try
|
||||
{
|
||||
pzCounter = newPzCount;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgError(exc, "Errore in SET contapezzi OMRON");
|
||||
connectionOk = false;
|
||||
}
|
||||
answ = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
lgError("Impossibile effettuare SET contapezzi OMRON, mancanza parametro OPT:ENABLE_PZ_RESET");
|
||||
}
|
||||
#endif
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override connessione
|
||||
/// </summary>
|
||||
public override void tryConnect()
|
||||
{
|
||||
if (!connectionOk)
|
||||
{
|
||||
// controllo che il ping sia stato tentato almeno pingTestSec fa...
|
||||
if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec"))
|
||||
{
|
||||
if (verboseLog || periodicLog)
|
||||
{
|
||||
lgInfo("OMRON: ConnKO - tryConnect");
|
||||
}
|
||||
// in primis salvo data ping...
|
||||
lastPING = DateTime.Now;
|
||||
// se passa il ping faccio il resto...
|
||||
if (testPingMachine == IPStatus.Success)
|
||||
{
|
||||
string szStatusConnection = "";
|
||||
try
|
||||
{
|
||||
// ora provo connessione...
|
||||
parentForm.commPlcActive = true;
|
||||
short esitoLink = doConnect();
|
||||
lgInfo($"szStatusConnection OMRON, esitoLink: {esitoLink}");
|
||||
parentForm.commPlcActive = false;
|
||||
// imposto i parametri...
|
||||
setParamPlc();
|
||||
connectionOk = true;
|
||||
// refresh stato connessione!!!
|
||||
if (connectionOk)
|
||||
{
|
||||
queueInEnabCurr = true;
|
||||
if (adpRunning)
|
||||
{
|
||||
lgInfo("Connessione OK");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lgError("Impossibile procedere, connessione mancante...");
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgFatal($"Errore nella connessione all'adapter OMRON: {szStatusConnection}{Environment.NewLine}{exc}");
|
||||
connectionOk = false;
|
||||
lgInfo($"Eccezione in TryConnect, Adapter OMRON NON running, pausa di {utils.CRI("waitRecMSec")} msec prima di ulteriori tentativi di riconnessione");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// loggo no risposta ping ...
|
||||
connectionOk = false;
|
||||
if (verboseLog || periodicLog)
|
||||
{
|
||||
lgInfo($"Attenzione: OMRON controllo PING fallito per IP {cIobConf.cncPingAddr}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
needRefresh = true;
|
||||
}
|
||||
// se non è ancora connesso faccio procesisng memoria caso disconnesso...
|
||||
if (!connectionOk)
|
||||
{
|
||||
// processo semafori ed invio...
|
||||
processMemoryDiscon();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override disconnessione
|
||||
/// </summary>
|
||||
public override void tryDisconnect()
|
||||
{
|
||||
if (connectionOk)
|
||||
{
|
||||
string szStatusConnection = "";
|
||||
try
|
||||
{
|
||||
OMRON_ref.Close();
|
||||
connectionOk = false;
|
||||
lgInfo(szStatusConnection);
|
||||
lgInfo("Effettuata disconnessione adapter OMRON!");
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgFatal(exc, "Errore nella disconnessione dall'adapter OMRON");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lgError("IMPOSSIBILE effettuare disconnessione OMRON: Connessione non disponibile...");
|
||||
}
|
||||
queueInEnabCurr = false;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
/// <summary>
|
||||
/// Array valori letti da memoria CIO INGRESSI
|
||||
/// </summary>
|
||||
protected short[] memReadCIO_IN;
|
||||
|
||||
/// <summary>
|
||||
/// Array valori letti da memoria CIO USCITE
|
||||
/// </summary>
|
||||
protected short[] memReadCIO_OUT;
|
||||
|
||||
/// <summary>
|
||||
/// Array valori letti da memoria DM
|
||||
/// </summary>
|
||||
protected short[] memReadDM;
|
||||
|
||||
/// <summary>
|
||||
/// Array valori letti da memoria WR
|
||||
/// </summary>
|
||||
protected short[] memReadWR;
|
||||
|
||||
/// <summary>
|
||||
/// Array valori SCRITTI su memoria CIO
|
||||
/// </summary>
|
||||
protected short[] memWriteCIO;
|
||||
|
||||
/// <summary>
|
||||
/// Array valori SCRITTI su memoria DM
|
||||
/// </summary>
|
||||
protected short[] memWriteDM;
|
||||
|
||||
/// <summary>
|
||||
/// Array valori SCRITTI su memoria WR
|
||||
/// </summary>
|
||||
protected short[] memWriteWR;
|
||||
|
||||
/// <summary>
|
||||
/// Oggetto MAIN x connessione OMRON
|
||||
/// </summary>
|
||||
protected OmronFinsTCP.Net.EtherNetPLC OMRON_ref;
|
||||
|
||||
/// <summary>
|
||||
/// Array delle risposte dal controllo OMRON
|
||||
/// </summary>
|
||||
protected System.Collections.ArrayList resDataArray;
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
/// <summary>
|
||||
/// Lettura scrittura commessa da OMRON (come array di coppie di byte)
|
||||
/// </summary>
|
||||
protected string commessa
|
||||
{
|
||||
get
|
||||
{
|
||||
string answ = "";
|
||||
short[] response;
|
||||
byte[] byteData = new byte[20];
|
||||
try
|
||||
{
|
||||
// leggo
|
||||
OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.WR, 0, 10, out response);
|
||||
// copio come byte...
|
||||
Buffer.BlockCopy(response, 0, byteData, 0, response.Length);
|
||||
answ = Encoding.ASCII.GetString(byteData);
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
return answ;
|
||||
}
|
||||
set
|
||||
{
|
||||
// converto in byte la mia stringa
|
||||
byte[] valByte = Encoding.ASCII.GetBytes(value);
|
||||
// limite 20 char... imposto a 20!
|
||||
int maxChar = valByte.Length < 20 ? valByte.Length : 20;
|
||||
// creao un array di 10 short MAX
|
||||
short[] valoriWord = new short[10];
|
||||
// copio i valori
|
||||
Buffer.BlockCopy(valByte, 0, valoriWord, 0, maxChar);
|
||||
// scrivo su OMRON!
|
||||
OMRON_ref.WriteWords(OmronFinsTCP.Net.PlcMemory.WR, 0, 10, valoriWord);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifico se abbia ALMENO un errore...
|
||||
/// </summary>
|
||||
protected bool hasError
|
||||
{
|
||||
get
|
||||
{
|
||||
bool answ = false;
|
||||
if (memReadCIO_OUT != null)
|
||||
{
|
||||
answ = ((memReadCIO_OUT[4] & (1 << 7)) != 0);
|
||||
}
|
||||
#if false
|
||||
bool answ = false;
|
||||
// controllo primi errori, parto dal primo e poi OR
|
||||
answ = answ || ((memReadCIO[0] & (1 << 7)) == 1);
|
||||
answ = answ || ((memReadCIO[1] & (1 << 0)) == 1);
|
||||
answ = answ || ((memReadCIO[1] & (1 << 1)) == 1);
|
||||
answ = answ || ((memReadCIO[1] & (1 << 3)) == 1);
|
||||
answ = answ || (memReadCIO[2] > 0);
|
||||
answ = answ || ((memReadCIO[3] & (1 << 0)) == 1);
|
||||
answ = answ || ((memReadCIO[3] & (1 << 1)) == 1);
|
||||
#endif
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Oggetto get/set per lettura (DM22-23) /scrittura (DM26-27) PESO RICHIESTO
|
||||
/// </summary>
|
||||
protected int pesoRichiesto
|
||||
{
|
||||
get
|
||||
{
|
||||
int answ = 0;
|
||||
try
|
||||
{
|
||||
short[] valDM;
|
||||
OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.DM, 22, 2, out valDM);
|
||||
answ = convDHD(valDM[0]) + 10000 * convDHD(valDM[1]);
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
return answ;
|
||||
}
|
||||
set
|
||||
{
|
||||
short[] valDM = intToShort(value);
|
||||
OMRON_ref.WriteWords(OmronFinsTCP.Net.PlcMemory.DM, 26, 2, valDM);
|
||||
// ora devo "comandare scrittura" su OMRON...
|
||||
|
||||
// sollevo bit 65.0 x azzeramento
|
||||
OMRON_ref.WriteWord(OmronFinsTCP.Net.PlcMemory.CIO, 65, 1);
|
||||
Thread.Sleep(500);
|
||||
// ora sollevo bit e 65.1 x indicare nuovo valore...
|
||||
OMRON_ref.WriteWord(OmronFinsTCP.Net.PlcMemory.CIO, 65, 2);
|
||||
// ora attendo ed abbasso tutti i bit
|
||||
Thread.Sleep(500);
|
||||
OMRON_ref.WriteWord(OmronFinsTCP.Net.PlcMemory.CIO, 65, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Oggetto per lettura PESO rilevato (DM20-21)
|
||||
/// </summary>
|
||||
protected int pesoRilevato
|
||||
{
|
||||
get
|
||||
{
|
||||
int answ = 0;
|
||||
try
|
||||
{
|
||||
short[] valDM;
|
||||
OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.DM, 20, 2, out valDM);
|
||||
// legge delle coppie di valori INT, vanno trasformati in HEX e POI accodati,
|
||||
// dove il primo è x 1 e il secondo x 10000 (in pratica va in testa) esempio
|
||||
// 12540 --> diviso in 1 | 2540 --> in HEX diventa 1 | 9472, ma il 9472 va su
|
||||
// byte[0] e 1 su byte[1]
|
||||
answ = convDHD(valDM[0]) + 10000 * convDHD(valDM[1]);
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
return answ;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Oggetto get/set x portata
|
||||
/// </summary>
|
||||
protected int portata
|
||||
{
|
||||
get
|
||||
{
|
||||
int answ = 0;
|
||||
try
|
||||
{
|
||||
short valDM;
|
||||
OMRON_ref.ReadWord(OmronFinsTCP.Net.PlcMemory.DM, 50, out valDM);
|
||||
answ = convDHD(valDM);
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
return answ;
|
||||
}
|
||||
set
|
||||
{
|
||||
// scrivo portata su memoria DM50...
|
||||
short portata = (short)convHD("0x" + value.ToString("0000"));
|
||||
OMRON_ref.WriteWord(OmronFinsTCP.Net.PlcMemory.DM, 50, portata);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Oggetto get/set x quantità richiesta LOTTO
|
||||
/// </summary>
|
||||
protected int quantitaLotto
|
||||
{
|
||||
get
|
||||
{
|
||||
int answ = 0;
|
||||
try
|
||||
{
|
||||
short[] valDM;
|
||||
OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.DM, 52, 2, out valDM);
|
||||
answ = convDHD(valDM[0]) + 10000 * convDHD(valDM[1]);
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
return answ;
|
||||
}
|
||||
set
|
||||
{
|
||||
short[] valDM = intToShort(value);
|
||||
OMRON_ref.WriteWords(OmronFinsTCP.Net.PlcMemory.DM, 52, 2, valDM);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Protected Properties
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Calcola la conversione da byte --> num decimale --> HEX --> conversione come
|
||||
/// stringa in INT
|
||||
/// </summary>
|
||||
/// <param name="valore"></param>
|
||||
/// <returns></returns>
|
||||
protected static int convDHD(short valore)
|
||||
{
|
||||
// legge delle coppie di valori INT, vanno trasformati in HEX e POI accodati, dove il
|
||||
// primo è x 1 e il secondo x 10000 (in pratica va in testa) esempio 12540 --> diviso in
|
||||
// 1 | 2540 --> in HEX diventa 1 | 9472, ma il 9472 va su byte[0] e 1 su byte[1]
|
||||
int answ = 0;
|
||||
string hexVal = valore.ToString("x");
|
||||
int.TryParse(hexVal, out answ);
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converte un valore di 2 short in un unico numero accostato:
|
||||
/// es: legge delle coppie di valori INT, vanno trasformati in HEX e POI accodati, dove il
|
||||
/// primo è x 1 e il secondo x 10000 (in pratica va in testa) 12540 --> diviso in 1 |
|
||||
/// 2540 --> in HEX diventa 1 | 9472, ma il 9472 va su byte[0] e 1 su byte[1]
|
||||
/// </summary>
|
||||
/// <param name="valori"></param>
|
||||
/// <returns></returns>
|
||||
protected static int convFromHex(short[] valori)
|
||||
{
|
||||
int answ = 0;
|
||||
string fullVal = $"{convDHD(valori[1]).ToString("D4")}{convDHD(valori[0]).ToString("D4")}";
|
||||
int.TryParse(fullVal, out answ);
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calcola la conversione da INTERO a intero HEX x OMRON
|
||||
/// </summary>
|
||||
/// <param name="valore"></param>
|
||||
/// <returns></returns>
|
||||
protected static int convHD(string hexVal)
|
||||
{
|
||||
int answ = 0;
|
||||
if (!string.IsNullOrEmpty(hexVal))
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!hexVal.StartsWith("0x"))
|
||||
{
|
||||
hexVal = "0x" + hexVal;
|
||||
}
|
||||
answ = Convert.ToInt32(hexVal, 16);
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converte un valore INT in un array di due SHORT valido x scrivere su OMRON
|
||||
/// </summary>
|
||||
/// <param name="value"></param>
|
||||
/// <returns></returns>
|
||||
protected static short[] intToShort(int value)
|
||||
{
|
||||
short[] valDM = new short[2];
|
||||
short highVal = (short)(value / 10000);
|
||||
short lowVal = (short)(value - highVal * 10000);
|
||||
valDM[0] = (short)convHD("0x" + lowVal.ToString("0000"));
|
||||
valDM[1] = (short)convHD("0x" + highVal.ToString("0000"));
|
||||
return valDM;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OVerride metodo x scrittura parametri su PLC
|
||||
/// </summary>
|
||||
/// <param name="updatedPar"></param>
|
||||
protected override void plcWriteParams(ref List<objItem> updatedPar)
|
||||
{
|
||||
int valInt = 0;
|
||||
if (updatedPar != null)
|
||||
{
|
||||
// controllo i parametri... ne gestisco 4...
|
||||
foreach (var item in updatedPar)
|
||||
{
|
||||
lgInfo($"Richiesti processing plcWriteParams per {item.name} | valore richiesto {item.reqValue} | valore attuale {item.value}");
|
||||
string readBackVal = "";
|
||||
switch (item.uid)
|
||||
{
|
||||
case "kgRich":
|
||||
// 2023.09.19 value --> reqValue
|
||||
int.TryParse(item.reqValue, out valInt);
|
||||
pesoRichiesto = valInt;
|
||||
readBackVal = pesoRichiesto.ToString();
|
||||
break;
|
||||
|
||||
case "kgLotto":
|
||||
// 2023.09.19 value --> reqValue
|
||||
int.TryParse(item.reqValue, out valInt);
|
||||
quantitaLotto = valInt;
|
||||
readBackVal = quantitaLotto.ToString();
|
||||
break;
|
||||
|
||||
case "portata":
|
||||
// 2023.09.19 value --> reqValue
|
||||
int.TryParse(item.reqValue, out valInt);
|
||||
portata = valInt;
|
||||
readBackVal = portata.ToString();
|
||||
break;
|
||||
|
||||
case "setComm":
|
||||
// 2023.09.19 value --> reqValue
|
||||
commessa = item.reqValue;
|
||||
readBackVal = commessa;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
// SE non corrispondessero LOGGO ERRORE...
|
||||
if (item.value != readBackVal)
|
||||
{
|
||||
lgError($"Errore in plcWriteParams: uid {item.uid} | Wrote {item.value} | ReadBack {readBackVal}");
|
||||
}
|
||||
// 2023.09.19 resetto richiesta
|
||||
else
|
||||
{
|
||||
item.reqValue = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
#region Private Fields
|
||||
|
||||
/// <summary>
|
||||
/// LookUpTable di decodifica da CNC a segnali tipo bitmap MAPO
|
||||
/// </summary>
|
||||
private Dictionary<string, string> signLUT = new Dictionary<string, string>();
|
||||
|
||||
#endregion Private Fields
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Effettua decodifica aree memoria alla bitmap usata x MAPO
|
||||
/// </summary>
|
||||
private void decodeToBaseBitmap()
|
||||
{
|
||||
// init a zero...
|
||||
B_input = 0;
|
||||
|
||||
/* -----------------------------------------------------
|
||||
* bitmap MAPO
|
||||
* B0: POWER_ON
|
||||
* B1: RUN
|
||||
* B2: pzCount -- non usato
|
||||
* B3: allarme
|
||||
* B4: manuale -- non usato
|
||||
* B5: carico SILOS
|
||||
* B6: carico AUTOBOTTE
|
||||
----------------------------------------------------- */
|
||||
|
||||
// in primis test ping!
|
||||
bool pingOk = testPingMachine == IPStatus.Success;
|
||||
if (pingOk)
|
||||
{
|
||||
// versione pre 2023: controllo SOLO ping...
|
||||
//// bit 0 (poweron) imposto a 1 SE pingo...
|
||||
//B_input = testPingMachine == IPStatus.Success ? 1 : 0;
|
||||
|
||||
// recupero i bit! check poweron = aux inseriti
|
||||
bool runAux = ((memReadCIO_IN[0] & (1 << 0)) != 0);
|
||||
// check lavora = filtro ON (DEVE ANDARE ma VIENE RILEVATO DOPO, POTREBBE andare da
|
||||
// solo x scaricare...)
|
||||
bool runFiltro = ((memReadCIO_IN[0] & (1 << 1)) != 0);
|
||||
// check carico silos/autobotte
|
||||
bool caricoSilos = ((memReadCIO_IN[55] & (1 << 2)) != 0);
|
||||
bool caricoAutobotte = ((memReadCIO_IN[50] & (1 << 2)) != 0);
|
||||
|
||||
// Costruzione HEX B_input
|
||||
|
||||
// RUN se CIO_bit 0.00 è POWER ON...
|
||||
B_input = runAux ? 1 : 0;
|
||||
// RUN se CIO_bit 0.01 è RUN FILTRO...
|
||||
if (runFiltro || caricoAutobotte || caricoSilos)
|
||||
{
|
||||
// SE HO carico silos OPPURE carico autobotte --> RUN
|
||||
B_input += (1 << 1);
|
||||
}
|
||||
// ERROR generale (CORREGGERE!)
|
||||
if (hasError)
|
||||
{
|
||||
B_input += (1 << 3);
|
||||
}
|
||||
|
||||
// carico SILOS
|
||||
if (caricoSilos)
|
||||
{
|
||||
B_input += (1 << 5);
|
||||
}
|
||||
// carico AUTOBOTTE
|
||||
if (caricoAutobotte)
|
||||
{
|
||||
B_input += (1 << 6);
|
||||
}
|
||||
|
||||
// procedo SOLO SE è enabled IOB
|
||||
if (IobOnline)
|
||||
{
|
||||
try
|
||||
{
|
||||
currODL = utils.callUrl(urlGetCurrODL);
|
||||
// solo SE HO un ODL...
|
||||
if (string.IsNullOrEmpty(currODL) || currODL == "0")
|
||||
{
|
||||
if (periodicLog)
|
||||
{
|
||||
lgInfo(string.Format("OMRON | Lettura ODL andata a vuoto: currODL: {0}", currODL));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// se variato o scaduto timeout log...
|
||||
if (periodicLog || (currIdxODL.ToString() != currODL))
|
||||
{
|
||||
lgInfo(string.Format("OMRON | Lettura ODL, currODL: {0} --> currIdxODL prec: {1}", currODL, currIdxODL));
|
||||
}
|
||||
// provo a salvare nuovo ODL
|
||||
int.TryParse(currODL, out currIdxODL);
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
if (DateTime.Now.Subtract(lastWarnODL).TotalSeconds > 15)
|
||||
{
|
||||
lgError(exc, "Errore in fase di chiamata URL x ODL corrente | URL chiamato: {0}", urlGetCurrODL);
|
||||
lastWarnODL = DateTime.Now;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// imposto currODL a vuoto!
|
||||
currODL = "";
|
||||
if (periodicLog)
|
||||
{
|
||||
lgInfo($"Omron | Lettura ODL non effettuata: IobOnline: {IobOnline} | currODL impostato a vuoto");
|
||||
}
|
||||
}
|
||||
// log opzionale!
|
||||
if (verboseLog)
|
||||
{
|
||||
lgInfo(string.Format("Trasformazione B_input: {0}", B_input));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Vera connessione ad OMRON
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private short doConnect()
|
||||
{
|
||||
// avvio un oggetto di comunicazione OMRON
|
||||
OMRON_ref = new OmronFinsTCP.Net.EtherNetPLC();
|
||||
short port = 9600;
|
||||
short.TryParse(cIobConf.cncPort, out port);
|
||||
lgInfo($"Chiamata apertura OMRON FINS: {cIobConf.cncIpAddr}:{port}");
|
||||
short esitoLink = OMRON_ref.Link(cIobConf.cncIpAddr, port, 500);
|
||||
return esitoLink;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test completo funzioni OMRON
|
||||
/// </summary>
|
||||
private void omronWriteTest()
|
||||
{
|
||||
commessa = "OMRON EDF TEST";
|
||||
|
||||
// scrivo portata
|
||||
portata = 444;
|
||||
|
||||
// scrivo pesatura richiesta
|
||||
pesoRichiesto = 22222;
|
||||
|
||||
// scrivo DM 52-53 del lotto richiesto
|
||||
quantitaLotto = 66666;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Lettura e log valori x debug
|
||||
/// </summary>
|
||||
private void readAndLog()
|
||||
{
|
||||
OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.CIO, 0, 8, out memReadCIO_IN);
|
||||
OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.CIO, 100, 8, out memReadCIO_OUT);
|
||||
OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.DM, 0, 8, out memReadDM);
|
||||
OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.WR, 0, 8, out memReadWR);
|
||||
|
||||
if (isVerboseLog)
|
||||
{
|
||||
lgInfo("Effettuata lettura dati CIO");
|
||||
foreach (var item in memReadCIO_IN)
|
||||
{
|
||||
lgInfo($"Valori: {item} --> {baseUtils.binaryForm(item)}");
|
||||
}
|
||||
lgInfo("Effettuata lettura dati DM");
|
||||
foreach (var item in memReadDM)
|
||||
{
|
||||
lgInfo($"Valori: {item} --> {baseUtils.binaryForm(item)}");
|
||||
}
|
||||
lgInfo("Effettuata lettura dati WR");
|
||||
foreach (var item in memReadWR)
|
||||
{
|
||||
lgInfo($"Valori: {item} --> {baseUtils.binaryForm(item)}");
|
||||
}
|
||||
}
|
||||
short[] respDM20;
|
||||
short[] respDM22;
|
||||
OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.DM, 20, 2, out respDM20);
|
||||
OMRON_ref.ReadWords(OmronFinsTCP.Net.PlcMemory.DM, 22, 2, out respDM22);
|
||||
if (isVerboseLog)
|
||||
{
|
||||
// legge delle coppie di valori INT, vanno trasformati in HEX e POI accodati, dove
|
||||
// il primo è x 1 e il secondo x 10000 (in pratica va in testa)
|
||||
lgInfo("Effettuata lettura dati respDM20");
|
||||
foreach (var item in respDM20)
|
||||
{
|
||||
lgInfo($"Valori: {item} --> {baseUtils.binaryForm(item)}");
|
||||
}
|
||||
lgInfo("Effettuata lettura dati respDM22");
|
||||
foreach (var item in respDM22)
|
||||
{
|
||||
lgInfo($"Valori: {item} --> {baseUtils.binaryForm(item)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
@@ -1,923 +0,0 @@
|
||||
using IOB_UT_NEXT;
|
||||
using MapoSDK;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace IOB_WIN_NEXT.IobFile
|
||||
{
|
||||
public class FileEurom63 : IobFile.FileGen
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Estende l'init della classe base...
|
||||
/// </summary>
|
||||
/// <param name="caller"></param>
|
||||
/// <param name="adpConf"></param>
|
||||
public FileEurom63(AdapterFormNext caller, IobConfiguration IOBConf) : base(caller, IOBConf)
|
||||
{
|
||||
lgInfo("INIT IobFileEurom63");
|
||||
appPath = Path.GetDirectoryName(Application.ExecutablePath);
|
||||
|
||||
string MAX_DELAY_SEC = getOptPar("MAX_DELAY_SEC");
|
||||
string CACHE_MULT = getOptPar("CACHE_MULT");
|
||||
int.TryParse(MAX_DELAY_SEC, out maxDelaySec);
|
||||
int.TryParse(CACHE_MULT, out cacheMult);
|
||||
|
||||
#if DEBUG
|
||||
maxDelaySec = 60 * 60 * 24;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Effettua vero processing contapezzi
|
||||
/// </summary>
|
||||
public override void processContapezzi()
|
||||
{
|
||||
if (utils.CRB("enableContapezzi"))
|
||||
{
|
||||
try
|
||||
{
|
||||
// controllo se sono in sampling della produzione
|
||||
if (actLevel >= Eurom63.ComLevel.ProdRequested)
|
||||
{
|
||||
/************************************************************
|
||||
*
|
||||
* EXAMPLE
|
||||
* DATE, TIME, ActCntCyc, ActTimCyc, ActTimFill, @OutXhour, SetDescJob
|
||||
* 20201007, 21:29:52, 5302, 8.61, 0.50, 10058, Nr. 1000987654.01
|
||||
*
|
||||
* devo prendere il 3° valore
|
||||
*
|
||||
*
|
||||
************************************************************/
|
||||
|
||||
// leggo il file della produzione HARD CODED...
|
||||
var sessProd = confE63.ActiveSessions[5];
|
||||
string currPzCount = "";
|
||||
if (sessProd != null)
|
||||
{
|
||||
if (sessProd.Active)
|
||||
{
|
||||
// nome file...
|
||||
string fileName = $"{BaseDir}\\{sessProd.SessionName}.DAT";
|
||||
if (File.Exists(fileName))
|
||||
{
|
||||
string rawData = "";
|
||||
using (var fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
using (var textReader = new StreamReader(fileStream))
|
||||
{
|
||||
rawData = textReader.ReadToEnd();
|
||||
}
|
||||
// ora splitto in linee
|
||||
string[] rawLines = Regex.Split(rawData, "\r\n|\r|\n");
|
||||
int numRow = rawLines.Length;
|
||||
|
||||
// devo avere almeno 2 righe...
|
||||
if (numRow >= 2)
|
||||
{
|
||||
string[] statusData = rawLines[1].Split(',');
|
||||
currPzCount = statusData[2].Trim();
|
||||
// salvo se valido
|
||||
if (!string.IsNullOrEmpty(currPzCount))
|
||||
{
|
||||
int newVal = -1;
|
||||
Int32.TryParse(currPzCount, out newVal);
|
||||
// verifico SE il contapezzi vada moltiplicato x il
|
||||
// fattore pzPallet...
|
||||
if (confE63.PzPallet > 1)
|
||||
{
|
||||
newVal = newVal * confE63.PzPallet;
|
||||
}
|
||||
// aggiorno contapezzi
|
||||
contapezziPLC = newVal > -1 ? newVal : contapezziPLC;
|
||||
}
|
||||
// ora verifico SE siano validi anche le dataora dei valori
|
||||
// letti (< 20 sec ritardo da ora...)
|
||||
string data = statusData[0].Trim();
|
||||
string ora = statusData[1].Trim();
|
||||
DateTime adesso = DateTime.Now;
|
||||
DateTime lastPub = adesso.AddMinutes(-1);
|
||||
CultureInfo provider = CultureInfo.InvariantCulture;
|
||||
try
|
||||
{
|
||||
lastPub = DateTime.ParseExact($"{data} {ora}", "yyyyMMdd HH:mm:ss", provider);
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
if (Math.Abs(lastPub.Subtract(adesso).TotalSeconds) > maxDelaySec)
|
||||
{
|
||||
sessProd.SessionValidUntil = adesso;
|
||||
// elimino file RSP...
|
||||
cleanupResp(sessProd.SessionName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
actLevel = Eurom63.ComLevel.StatusRequested;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
actLevel = Eurom63.ComLevel.StatusRequested;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgError($"Eccezione in processContapezzi:{Environment.NewLine}{exc}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua lettura semafori principale <paramref name="currDispData">Parametri da
|
||||
/// aggiornare x display in form</paramref>
|
||||
/// </summary>
|
||||
public override void readSemafori(ref newDisplayData currDispData)
|
||||
{
|
||||
base.readSemafori(ref currDispData);
|
||||
// in primis controllo status...
|
||||
checkCommStatus();
|
||||
|
||||
// init a zero...
|
||||
B_input = 0;
|
||||
string currStatus = "99999";
|
||||
bool readDone = false;
|
||||
DateTime adesso = DateTime.Now;
|
||||
// leggo il file dela produzione HARD CODED...
|
||||
var sessStatus = confE63.ActiveSessions[4];
|
||||
// ciclo!
|
||||
try
|
||||
{
|
||||
// controllo se sono in sampling dello stato
|
||||
if (actLevel >= Eurom63.ComLevel.StatusRequested)
|
||||
{
|
||||
/* -----------------------------------------------------
|
||||
* bitmap MAPO
|
||||
* B0: POWER_ON
|
||||
* B1: RUN
|
||||
* B2: pzCount
|
||||
* B3: allarme
|
||||
* B4: manuale
|
||||
* B5: allarme TCiclo (SLOW)
|
||||
* B6: avvio/spegnimento
|
||||
* B7: Emergenza armata (1= pronto, 0 = emergenza) --> DA INVIARE!!!
|
||||
----------------------------------------------------- */
|
||||
|
||||
/******************************************************************
|
||||
*
|
||||
* EXAMPLE file content
|
||||
* DATE, TIME, ActStsMach
|
||||
* 20201007, 21:28:10, 0A000
|
||||
*
|
||||
* Configurazione array status: 5 char status decoding
|
||||
*
|
||||
* Pos1: (status)
|
||||
* 0: poweron
|
||||
* 1: poweroff
|
||||
*
|
||||
* Pos2: (mode)
|
||||
* A: AUTO
|
||||
* S: SEMI auto
|
||||
* M: Manual
|
||||
* U: Setup
|
||||
* H: Hord
|
||||
* C: Maintenance
|
||||
* 0: Unknown
|
||||
* I: Idle
|
||||
*
|
||||
* Pos3: (assist call)
|
||||
* 0: No assistance
|
||||
* 2: Assistance required
|
||||
*
|
||||
* Pos4: (Bad part)
|
||||
* 0: last cycle not bad
|
||||
* 1: last cycle bad
|
||||
*
|
||||
* Pos5: Active Alarm
|
||||
* 0: No alarm
|
||||
* 1: Alarm
|
||||
*
|
||||
*
|
||||
*
|
||||
*******************************************************************/
|
||||
|
||||
if (sessStatus != null)
|
||||
{
|
||||
if (sessStatus.Active)
|
||||
{
|
||||
// nome file...
|
||||
string fileName = $"{BaseDir}\\{sessStatus.SessionName}.DAT";
|
||||
if (File.Exists(fileName))
|
||||
{
|
||||
string rawData = "";
|
||||
using (var fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
using (var textReader = new StreamReader(fileStream))
|
||||
{
|
||||
rawData = textReader.ReadToEnd();
|
||||
}
|
||||
if (!string.IsNullOrEmpty(rawData))
|
||||
{
|
||||
// ora splitto in linee
|
||||
string[] rawLines = Regex.Split(rawData, "\r\n|\r|\n");
|
||||
int numRow = rawLines.Length;
|
||||
|
||||
// devo avere almeno 2 righe...
|
||||
if (numRow >= 2)
|
||||
{
|
||||
string[] statusData = rawLines[1].Split(',');
|
||||
if (statusData.Length >= 3)
|
||||
{
|
||||
currStatus = statusData[2].Trim();
|
||||
if (!string.IsNullOrEmpty(currStatus))
|
||||
{
|
||||
currDispData.semIn = Semaforo.SV;
|
||||
}
|
||||
// salvo in cache!
|
||||
Last_CurrStatus.Value = currStatus;
|
||||
Last_CurrStatus.ValidUntil = DateTime.Now.AddSeconds(maxDelaySec * cacheMult);
|
||||
|
||||
// ora verifico SE siano validi anche le dataora dei
|
||||
// valori letti (< 20 sec ritardo da ora...)
|
||||
string data = statusData[0].Trim();
|
||||
string ora = statusData[1].Trim();
|
||||
DateTime lastPub = adesso.AddMinutes(-1);
|
||||
CultureInfo provider = CultureInfo.InvariantCulture;
|
||||
try
|
||||
{
|
||||
lastPub = DateTime.ParseExact($"{data} {ora}", "yyyyMMdd HH:mm:ss", provider);
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
if (Math.Abs(lastPub.Subtract(adesso).TotalSeconds) > maxDelaySec)
|
||||
{
|
||||
sessStatus.SessionValidUntil = adesso;
|
||||
// elimino file RSP...
|
||||
cleanupResp(sessStatus.SessionName);
|
||||
}
|
||||
readDone = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
lgError($"Decodifica StatusData in errore: trovati {statusData.Length} campi in {rawLines}");
|
||||
// se valido RILEGGO ultimo curr status
|
||||
if (Last_CurrStatus.ValidUntil > adesso)
|
||||
{
|
||||
currStatus = Last_CurrStatus.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lgError($"Lettura file stato in errore: trovate {numRow} linee");
|
||||
}
|
||||
}
|
||||
// se valido RILEGGO ultimo curr status
|
||||
if (Last_CurrStatus.ValidUntil > adesso)
|
||||
{
|
||||
currStatus = Last_CurrStatus.Value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// se valido RILEGGO ultimo curr status
|
||||
if (Last_CurrStatus.ValidUntil > adesso)
|
||||
{
|
||||
currStatus = Last_CurrStatus.Value;
|
||||
}
|
||||
// abbasso status...
|
||||
actLevel--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// se valido RILEGGO ultimo curr status
|
||||
if (Last_CurrStatus.ValidUntil > adesso)
|
||||
{
|
||||
currStatus = Last_CurrStatus.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// se valido RILEGGO ultimo curr status
|
||||
if (Last_CurrStatus.ValidUntil > adesso)
|
||||
{
|
||||
currStatus = Last_CurrStatus.Value;
|
||||
}
|
||||
}
|
||||
|
||||
// processo il currentStatus... parto da poweron
|
||||
B_input = currStatus[0] == '1' ? 0 : 1;
|
||||
|
||||
// aggiungo il bit NON emergenza
|
||||
B_input += (1 << 7);
|
||||
|
||||
// ora MODE
|
||||
switch (currStatus[1])
|
||||
{
|
||||
case 'A':
|
||||
B_input += (1 << 1);
|
||||
break;
|
||||
|
||||
case 'S':
|
||||
case 'M':
|
||||
case 'U':
|
||||
B_input += (1 << 4);
|
||||
break;
|
||||
|
||||
default:
|
||||
// loggo cosa trovo (CREDO
|
||||
break;
|
||||
}
|
||||
// ora cerco allarmi
|
||||
if (currStatus[4] == '1')
|
||||
{
|
||||
B_input += (1 << 3);
|
||||
}
|
||||
// controllo se diverso faccio log!
|
||||
if (!B_input.Equals(Last_B_Input.Value))
|
||||
{
|
||||
lgInfo($"B_Input variato: {Last_B_Input.Value} --> {B_input} | currStatus: {currStatus}");
|
||||
}
|
||||
// salvo B_Input in cache!
|
||||
Last_B_Input.Value = B_input;
|
||||
Last_B_Input.ValidUntil = DateTime.Now.AddSeconds(maxDelaySec * cacheMult);
|
||||
}
|
||||
// se disponibile riporto B_Input precedente
|
||||
else
|
||||
{
|
||||
if (Last_B_Input.ValidUntil > adesso)
|
||||
{
|
||||
B_input = Last_B_Input.Value;
|
||||
}
|
||||
}
|
||||
// riporto bitmap...
|
||||
reportRawInput(ref currDispData);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgError(exc, "Errore in readSemafori x IOB FILE");
|
||||
if (currDispData != null)
|
||||
currDispData.semIn = Semaforo.SR;
|
||||
}
|
||||
|
||||
// ultimo controllo...
|
||||
if (!readDone)
|
||||
{
|
||||
// se valido RILEGGO ultimo B_INPUT
|
||||
if (Last_B_Input.ValidUntil > adesso)
|
||||
{
|
||||
B_input = Last_B_Input.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua reset del contapezzi, NON PERMESSO per EM63 (read only)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override bool resetContapezziPLC()
|
||||
{
|
||||
bool answ = false;
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua IMPOSTAZIONE FORZATA del contapezzi, NON PERMESSO per EM63 (read only)
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override bool setcontapezziPLC(int newPzCount)
|
||||
{
|
||||
bool answ = false;
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connessione
|
||||
/// </summary>
|
||||
public override void tryConnect()
|
||||
{
|
||||
var nextLevel = Eurom63.ComLevel.IsConnected;
|
||||
var connectSession = confE63.ActiveSessions[0];
|
||||
processSession(nextLevel, ref connectSession);
|
||||
queueInEnabCurr = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnessione
|
||||
/// </summary>
|
||||
public override void tryDisconnect()
|
||||
{
|
||||
connectionOk = false;
|
||||
queueInEnabCurr = false;
|
||||
try
|
||||
{
|
||||
abortPrevJob();
|
||||
cleanupFolder();
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgError(exc, "Eccezione in tryDisconnect");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Internal Methods
|
||||
|
||||
/// <summary>
|
||||
/// Metodi preliminari x comunicazione:
|
||||
/// - richiesta connessione
|
||||
/// - richiesta stato attivo
|
||||
/// </summary>
|
||||
internal void checkCommStatus()
|
||||
{
|
||||
// init obj display
|
||||
newDisplayData currDispData = new newDisplayData();
|
||||
currDispData.semIn = Semaforo.ND;
|
||||
|
||||
switch (actLevel)
|
||||
{
|
||||
case Eurom63.ComLevel.None:
|
||||
tryConnect();
|
||||
currDispData.semIn = Semaforo.SS;
|
||||
break;
|
||||
|
||||
case Eurom63.ComLevel.IsConnected:
|
||||
requestInfo();
|
||||
currDispData.semIn = Semaforo.SS;
|
||||
break;
|
||||
|
||||
case Eurom63.ComLevel.HasInfo:
|
||||
setMachineTime();
|
||||
currDispData.semIn = Semaforo.SS;
|
||||
break;
|
||||
|
||||
case Eurom63.ComLevel.TimeSet:
|
||||
abortPrevJob();
|
||||
currDispData.semIn = Semaforo.SG;
|
||||
break;
|
||||
|
||||
case Eurom63.ComLevel.ChannelOk:
|
||||
requestStatusData();
|
||||
currDispData.semIn = Semaforo.SG;
|
||||
break;
|
||||
|
||||
case Eurom63.ComLevel.StatusRequested:
|
||||
requestProdData();
|
||||
currDispData.semIn = Semaforo.SV;
|
||||
break;
|
||||
|
||||
case Eurom63.ComLevel.ProdRequested:
|
||||
checkSampling();
|
||||
currDispData.semIn = Semaforo.SV;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (utils.CRB("verbose"))
|
||||
{
|
||||
lgInfo($"DONE checkCommStatus | actLevel {actLevel}");
|
||||
}
|
||||
raiseRefresh(currDispData);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pulizia preliminare folder comunicazione
|
||||
/// </summary>
|
||||
internal override void cleanupFolder()
|
||||
{
|
||||
// elimino OGNI file per tipo configurato
|
||||
foreach (var cleanExt in confE63.cleanupExt)
|
||||
{
|
||||
string[] file2del = Directory.GetFiles(BaseDir, cleanExt);
|
||||
foreach (var file in file2del)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pulizia folder dai file RSP della sessione
|
||||
/// </summary>
|
||||
internal void cleanupResp(string sessionName)
|
||||
{
|
||||
string[] file2del = Directory.GetFiles(BaseDir, $"{sessionName}.RSP");
|
||||
foreach (var file in file2del)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ricarica conf adapter...
|
||||
/// </summary>
|
||||
internal override void reloadAdapterConf()
|
||||
{
|
||||
// init obj display
|
||||
newDisplayData currDispData = new newDisplayData();
|
||||
lgInfo("BEGIN reloadAdapterConf");
|
||||
// inizializzo LUT decodifica
|
||||
string jsonConf = getOptPar("LUT_CONF");
|
||||
if (!string.IsNullOrEmpty(jsonConf))
|
||||
{
|
||||
string jsonFullPath = $"{Application.StartupPath}/DATA/CONF/{jsonConf}";
|
||||
lgInfo($"Apertura file {jsonFullPath}");
|
||||
StreamReader reader = new StreamReader(jsonFullPath);
|
||||
string jsonData = reader.ReadToEnd();
|
||||
if (!string.IsNullOrEmpty(jsonData))
|
||||
{
|
||||
try
|
||||
{
|
||||
confE63 = JsonConvert.DeserializeObject<Eurom63.ProtoConf>(jsonData);
|
||||
|
||||
// salvo baseUri
|
||||
BaseDir = confE63.BaseDir;
|
||||
lgInfo($"baseDir = {BaseDir}");
|
||||
// imposto a zero la bitmap x riavvio!
|
||||
B_input = 0;
|
||||
// FORZO invio dati...
|
||||
accodaSigIN(ref currDispData);
|
||||
// loggo!
|
||||
lgInfo($"init input bitmap to zero: {B_input}");
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgError(exc, "Eccezione in decodifica conf json");
|
||||
}
|
||||
}
|
||||
reader.Dispose();
|
||||
}
|
||||
lgInfo("DONE reloadAdapterConf");
|
||||
raiseRefresh(currDispData);
|
||||
}
|
||||
|
||||
#endregion Internal Methods
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
protected static DateTime lastStatusDecr = DateTime.Now;
|
||||
|
||||
/// <summary>
|
||||
/// step di comunicazione attivo
|
||||
/// </summary>
|
||||
protected Eurom63.ComLevel actLevel = Eurom63.ComLevel.None;
|
||||
|
||||
/// <summary>
|
||||
/// DIrectory eseguibile corrente
|
||||
/// </summary>
|
||||
protected string appPath = Directory.GetCurrentDirectory();
|
||||
|
||||
/// <summary>
|
||||
/// Moltiplicatore durata cache
|
||||
/// </summary>
|
||||
protected int cacheMult = 4;
|
||||
|
||||
/// <summary>
|
||||
/// Oggetti decodificati da pagina
|
||||
/// </summary>
|
||||
protected Eurom63.ProtoConf confE63;
|
||||
|
||||
/// <summary>
|
||||
/// Valore currStatus validato (per gestione "disconnessioni")
|
||||
/// </summary>
|
||||
protected CachedInt Last_B_Input = new CachedInt() { Value = 0 };
|
||||
|
||||
/// <summary>
|
||||
/// Valore currStatus validato (per gestione "disconnessioni")
|
||||
/// </summary>
|
||||
protected CachedString Last_CurrStatus = new CachedString() { Value = "00000" };
|
||||
|
||||
/// <summary>
|
||||
/// Massimo delay lettura dati prima di considerarli scaduti (30 sec, ma x test 1 gg)
|
||||
/// </summary>
|
||||
protected int maxDelaySec = 30;
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
protected void abortPrevJob()
|
||||
{
|
||||
var nextLevel = Eurom63.ComLevel.ChannelOk;
|
||||
var connectSession = confE63.ActiveSessions[3];
|
||||
processSession(nextLevel, ref connectSession);
|
||||
#if false
|
||||
// qui per sicurezza PULISCE TUTTO
|
||||
cleanupFolder();
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifica una sessione configurata (ovvero la comunicazione su TUTTI i file associati)
|
||||
/// </summary>
|
||||
/// <param name="session"></param>
|
||||
/// <returns></returns>
|
||||
protected bool checkRequest(Eurom63.Session session)
|
||||
{
|
||||
bool answ = false;
|
||||
string fileName = "";
|
||||
if (session != null)
|
||||
{
|
||||
fileName = $"{BaseDir}\\{session.SessionName}.REQ";
|
||||
answ = File.Exists(fileName);
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifica se ci sia una risposta POSITIVA
|
||||
/// </summary>
|
||||
/// <param name="session"></param>
|
||||
/// <returns></returns>
|
||||
protected bool checkResp(Eurom63.Session session)
|
||||
{
|
||||
bool answ = false;
|
||||
string fileName = "";
|
||||
if (session != null)
|
||||
{
|
||||
fileName = $"{BaseDir}\\{session.SessionName}.RSP";
|
||||
if (File.Exists(fileName))
|
||||
{
|
||||
// verifico contenuto
|
||||
//string rawData = File.ReadAllText(fileName);
|
||||
string rawData = "";
|
||||
// lettura in modo NON esclusivo...
|
||||
using (var fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
|
||||
using (var textReader = new StreamReader(fileStream))
|
||||
{
|
||||
rawData = textReader.ReadToEnd();
|
||||
}
|
||||
// se la stringa session.RespOk contiene | significa ci sono + valori ammessi e
|
||||
// li controlla tutti
|
||||
if (session.RespOk.Contains("|"))
|
||||
{
|
||||
// splitto e testo tutti...
|
||||
string[] validRespOk = session.RespOk.Split('|');
|
||||
foreach (var item in validRespOk)
|
||||
{
|
||||
answ = answ || rawData.Contains(item);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
answ = rawData.Contains(session.RespOk);
|
||||
}
|
||||
}
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// verifica periodica dei campionamenti:
|
||||
/// - i due jobs devono essere attivi e non scaduti
|
||||
/// - non devo aver già resettato...
|
||||
/// </summary>
|
||||
protected void checkSampling()
|
||||
{
|
||||
var currSession = confE63.ActiveSessions[4];
|
||||
checkSessionActive(currSession, Eurom63.ComLevel.ChannelOk);
|
||||
|
||||
currSession = confE63.ActiveSessions[5];
|
||||
checkSessionActive(currSession, Eurom63.ComLevel.ChannelOk);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Elimina i file della sessione indicata (SE è un task ciclico --> solo RSP)
|
||||
/// </summary>
|
||||
/// <param name="session"></param>
|
||||
/// <returns></returns>
|
||||
protected bool cleanupSession(Eurom63.Session session)
|
||||
{
|
||||
bool answ = false;
|
||||
if (session != null)
|
||||
{
|
||||
// solo se scaduta validità...
|
||||
if (session.SessionValidUntil < DateTime.Now)
|
||||
{
|
||||
string searchPattern = $"{session.SessionName}.*";
|
||||
// task ciclico?
|
||||
if (session.Cycle)
|
||||
{
|
||||
// solo risposta!
|
||||
searchPattern = $"{session.SessionName}.RSP";
|
||||
}
|
||||
string[] file2del = Directory.GetFiles(BaseDir, searchPattern);
|
||||
foreach (var file in file2del)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(file);
|
||||
}
|
||||
catch
|
||||
{ }
|
||||
}
|
||||
}
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processa una sessione
|
||||
/// - andando a verificare l'esistenza della REQ + se esito positivo pulizia
|
||||
/// - andando a richeidere di nuovo risposta
|
||||
/// </summary>
|
||||
/// <param name="nextLevel"></param>
|
||||
/// <param name="connectSession"></param>
|
||||
protected void processSession(Eurom63.ComLevel nextLevel, ref Eurom63.Session connectSession)
|
||||
{
|
||||
if (connectSession != null)
|
||||
{
|
||||
// controllo esistenza directory --> segno connected...
|
||||
connectionOk = Directory.Exists(BaseDir);
|
||||
DateTime adesso = DateTime.Now;
|
||||
if (connectionOk)
|
||||
{
|
||||
// verifico se ci sia risp CONNECT
|
||||
if (checkResp(connectSession))
|
||||
{
|
||||
// aggiorno livello
|
||||
actLevel = nextLevel;
|
||||
parentForm.displayTaskAndLog($"Adp Level: {nextLevel}");
|
||||
// elimino file sessione
|
||||
cleanupSession(connectSession);
|
||||
connectSession.Active = connectSession.Cycle;
|
||||
connectSession.Passed = true;
|
||||
}
|
||||
// verifico SE ci sia la richiesta sennò la chiedo...
|
||||
else if (!checkRequest(connectSession))
|
||||
{
|
||||
copyRequestFiles(connectSession, adesso);
|
||||
}
|
||||
// richiedo SE non ci fosse i dati CONNECT...
|
||||
else
|
||||
{
|
||||
// evito di richiedere SE non fosse già scaduta richiesta...
|
||||
if (adesso > connectSession.RetryVeto || !checkRequest(connectSession))
|
||||
{
|
||||
// pulisco eventuali risp vecchie
|
||||
cleanupResp(connectSession.SessionName);
|
||||
copyRequestFiles(connectSession, adesso);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// aspetto prima di riprovare...
|
||||
Thread.Sleep(50);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// aspetto prima di riprovare...
|
||||
Thread.Sleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Processa i file della sessione indicata (copy + transform)
|
||||
/// </summary>
|
||||
/// <param name="session"></param>
|
||||
/// <returns></returns>
|
||||
protected bool processSessionFile(Eurom63.Session session)
|
||||
{
|
||||
bool answ = false;
|
||||
if (session != null)
|
||||
{
|
||||
string fileFrom = "";
|
||||
string fileTo = "";
|
||||
// processo OGNI file sessione x farne copia
|
||||
foreach (var file2Proc in session.FileList)
|
||||
{
|
||||
fileFrom = $"{appPath}\\{file2Proc.Path}";
|
||||
fileTo = $"{BaseDir}\\{Path.GetFileName(file2Proc.Path)}";
|
||||
string rawData = File.ReadAllText(fileFrom);
|
||||
|
||||
if (file2Proc.OprReq == Eurom63.FileOpr.Copy)
|
||||
{
|
||||
// scrivo!
|
||||
File.WriteAllText(fileTo, rawData);
|
||||
}
|
||||
else
|
||||
{
|
||||
// leggo file originale... e processo sostituzioni
|
||||
rawData = rawData.Replace("{DTNow}", DateTime.Now.ToString("HHmmssyyyyMMdd"));
|
||||
// ora in posizione definitiva
|
||||
File.WriteAllText(fileTo, rawData);
|
||||
}
|
||||
}
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua richiesta info x macchina (validare startup process)
|
||||
/// </summary>
|
||||
protected void requestInfo()
|
||||
{
|
||||
var nextLevel = Eurom63.ComLevel.HasInfo;
|
||||
var connectSession = confE63.ActiveSessions[1];
|
||||
processSession(nextLevel, ref connectSession);
|
||||
}
|
||||
|
||||
protected void requestProdData()
|
||||
{
|
||||
var nextLevel = Eurom63.ComLevel.ProdRequested;
|
||||
var connectSession = confE63.ActiveSessions[5];
|
||||
processSession(nextLevel, ref connectSession);
|
||||
}
|
||||
|
||||
protected void requestStatusData()
|
||||
{
|
||||
var nextLevel = Eurom63.ComLevel.StatusRequested;
|
||||
var connectSession = confE63.ActiveSessions[4];
|
||||
processSession(nextLevel, ref connectSession);
|
||||
}
|
||||
|
||||
protected void setMachineTime()
|
||||
{
|
||||
var nextLevel = Eurom63.ComLevel.TimeSet;
|
||||
var connectSession = confE63.ActiveSessions[2];
|
||||
processSession(nextLevel, ref connectSession);
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Se la sessione fosse scaduta o non attiva --> torna al livello indicato
|
||||
/// </summary>
|
||||
/// <param name="currSession"></param>
|
||||
private void checkSessionActive(Eurom63.Session currSession, Eurom63.ComLevel nextLevel)
|
||||
{
|
||||
// SOLO SE ha senso che controllo (sono in sampling...)
|
||||
if (actLevel > Eurom63.ComLevel.HasInfo)
|
||||
{
|
||||
DateTime adesso = DateTime.Now;
|
||||
// devono essere ATTIVE le sessioni di campionamento... e NON scadute
|
||||
if (!currSession.Active || currSession.SessionValidUntil < adesso)
|
||||
{
|
||||
// controllo ultimo downgrade status
|
||||
if (lastStatusDecr.AddSeconds(3) < adesso)
|
||||
{
|
||||
// elimino TUTTE le risposte...
|
||||
cleanupResp(currSession.SessionName);
|
||||
// registro downgrade status...
|
||||
lastStatusDecr = adesso;
|
||||
// imposto livellotornando indietro di 1 alla volta... senza andare in negativoS
|
||||
actLevel = actLevel - 1;
|
||||
actLevel = actLevel > 0 ? actLevel : 0;
|
||||
lgInfo($"Sessione inattiva, {actLevel + 1} --> {actLevel}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua copia file richeiste + update timing
|
||||
/// </summary>
|
||||
/// <param name="connectSession"></param>
|
||||
/// <param name="adesso"></param>
|
||||
private void copyRequestFiles(Eurom63.Session connectSession, DateTime adesso)
|
||||
{
|
||||
// processo richiesta
|
||||
processSessionFile(connectSession);
|
||||
if (adesso > connectSession.SessionValidUntil)
|
||||
{
|
||||
connectSession.Active = !connectSession.Cycle;
|
||||
}
|
||||
connectSession.Passed = false;
|
||||
connectSession.SessionStarted = adesso;
|
||||
connectSession.SessionValidUntil = adesso.AddMinutes(connectSession.ValidityMinutes);
|
||||
connectSession.RetryVeto = adesso.AddSeconds(connectSession.RetrySec);
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
@@ -1,358 +0,0 @@
|
||||
using IOB_UT_NEXT;
|
||||
using MapoSDK;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
|
||||
namespace IOB_WIN_NEXT.IobFile
|
||||
{
|
||||
/// <summary>
|
||||
/// Generica classe per implementare IOB basato su scambio FILE
|
||||
/// </summary>
|
||||
public class FileGen : Iob.GenericNext, IDisposable
|
||||
{
|
||||
/* --------------------------------------------------------------------------------
|
||||
* Controlli dotati di GENERICA funzionalità scambio info tramite file
|
||||
*
|
||||
* -------------------------------------------------------------------------------- */
|
||||
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Estende l'init della classe base...
|
||||
/// </summary>
|
||||
/// <param name="caller"></param>
|
||||
/// <param name="adpConf"></param>
|
||||
public FileGen(AdapterFormNext caller, IobConfiguration IOBConf) : base(caller, IOBConf)
|
||||
{
|
||||
lgInfo("INIT FileGen");
|
||||
//reloadAdapterConf();
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupero dati dinamici in formato dictionary
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public override Dictionary<string, string> getDynData()
|
||||
{
|
||||
lgInfo("Chiamata getDynData x IOB FILE!");
|
||||
Dictionary<string, string> outVal = new Dictionary<string, string>();
|
||||
#if false
|
||||
try
|
||||
{
|
||||
/* ----------------------------------------------------------
|
||||
* Recupero dalla TUTTE le chiavi richieste...
|
||||
* */
|
||||
|
||||
string cKey = "";
|
||||
string cVal = "";
|
||||
// processo tutti i DynData...
|
||||
foreach (var item in monitoredItems.DynData)
|
||||
{
|
||||
// cerco elemento indicato
|
||||
element = driver.FindElement(By.Id(item.val));
|
||||
cVal = element.Text;
|
||||
// verifico nome o key...
|
||||
if (!string.IsNullOrEmpty(item.name))
|
||||
{
|
||||
cKey = item.name;
|
||||
}
|
||||
else
|
||||
{
|
||||
element = driver.FindElement(By.Id(item.key));
|
||||
cKey = element.Text;
|
||||
}
|
||||
// controllo se devo inviare (per tipo di dato, x scadenza)
|
||||
if (monItem2Send(cVal, item))
|
||||
{
|
||||
item.actVal = cVal;
|
||||
item.DTScad = DateTime.Now.AddSeconds(item.sPeriod);
|
||||
// accodo!
|
||||
outVal.Add(cKey, cVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgError(exc, "Errore in getDynData x IOB FILE");
|
||||
}
|
||||
#endif
|
||||
return outVal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua processing del recupero delle OVERRIDE (spindle, feedrate, rapid)
|
||||
/// </summary>
|
||||
public override void processOverride()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua lettura semafori principale
|
||||
/// <paramref name="currDispData">Parametri da aggiornare x display in form</paramref>
|
||||
/// </summary>
|
||||
public override void readSemafori(ref newDisplayData currDispData)
|
||||
{
|
||||
base.readSemafori(ref currDispData);
|
||||
// init a zero...
|
||||
B_input = 0;
|
||||
// ciclo!
|
||||
try
|
||||
{
|
||||
#if false
|
||||
// controllo SE il driver SIA attivo...
|
||||
if (driver != null)
|
||||
{
|
||||
string cKey = "";
|
||||
string cVal = "";
|
||||
// IPOTESI: un UNICO oggetto decodifica status
|
||||
if (monitoredItems.Status.Count == 1)
|
||||
{
|
||||
var item = monitoredItems.Status[0];
|
||||
// cerco elemento indicato
|
||||
element = driver.FindElement(By.Id(item.val));
|
||||
cKey = element.Text;
|
||||
// verifico se mancasse il mapping...
|
||||
if (!item.codeMapping.ContainsKey(cKey))
|
||||
{
|
||||
processUnknStatus(cKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
// ora decodifico da variabile status a valore secondo impostazione "codeMapping"
|
||||
cVal = item.codeMapping[cKey];
|
||||
B_input = int.Parse(cVal, System.Globalization.NumberStyles.HexNumber);
|
||||
if (currDispData != null)
|
||||
{
|
||||
currDispData.semIn = Semaforo.SV;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lgError("Errore: driver non pronto (null)");
|
||||
}
|
||||
#endif
|
||||
// riporto bitmap...
|
||||
reportRawInput(ref currDispData);
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgError(exc, "Errore in readSemafori x IOB FILE");
|
||||
if (currDispData != null)
|
||||
currDispData.semIn = Semaforo.SR;
|
||||
}
|
||||
}
|
||||
|
||||
public override void startAdapter(bool resetQueue)
|
||||
{
|
||||
// in primis RICARICO conf specifica...
|
||||
reloadAdapterConf();
|
||||
// pulizia preliminare folder
|
||||
cleanupFolder();
|
||||
// continuo con start...
|
||||
base.startAdapter(resetQueue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override x chiusura driver...
|
||||
/// </summary>
|
||||
/// <param name="tryRestart"></param>
|
||||
/// <param name="forceDequeue"></param>
|
||||
public override void stopAdapter(bool tryRestart, bool forceDequeue)
|
||||
{
|
||||
try
|
||||
{
|
||||
#if false
|
||||
// in primis chiudo driver...
|
||||
if (driver != null)
|
||||
{
|
||||
driver.Quit();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgError(exc, "Eccezione in tryDisconnect");
|
||||
}
|
||||
// continuo
|
||||
base.stopAdapter(tryRestart, forceDequeue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connessione
|
||||
/// </summary>
|
||||
public override void tryConnect()
|
||||
{
|
||||
// controllo ping --> segno connected...
|
||||
connectionOk = Directory.Exists(BaseDir);
|
||||
if (connectionOk)
|
||||
{
|
||||
queueInEnabCurr = true;
|
||||
#if false
|
||||
try
|
||||
{
|
||||
// modalità sincrona
|
||||
startDriver();
|
||||
lgInfo("Completato start driver");
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgError(exc, "Eccezione in tryConnect");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// aspetto prima di riprovare...
|
||||
Thread.Sleep(200);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Disconnessione
|
||||
/// </summary>
|
||||
public override void tryDisconnect()
|
||||
{
|
||||
connectionOk = false;
|
||||
queueInEnabCurr = false;
|
||||
try
|
||||
{
|
||||
#if false
|
||||
// in primis chiudo driver...
|
||||
if (driver != null)
|
||||
//if (driver != null && driver.WindowHandles.Count > 0)
|
||||
{
|
||||
driver.Quit();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgError(exc, "Eccezione in tryDisconnect");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Internal Methods
|
||||
|
||||
/// <summary>
|
||||
/// Pulizia preliminare folder comunicazione
|
||||
/// </summary>
|
||||
internal virtual void cleanupFolder()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ricarica conf adapter...
|
||||
/// </summary>
|
||||
internal virtual void reloadAdapterConf()
|
||||
{
|
||||
#if false
|
||||
// init obj display
|
||||
newDisplayData currDispData = new newDisplayData();
|
||||
lgInfo("BEGIN reloadAdapterConf");
|
||||
// inizializzo LUT decodifica
|
||||
string jsonConf = getOptPar("LUT_CONF");
|
||||
if (!string.IsNullOrEmpty(jsonConf))
|
||||
{
|
||||
string jsonFullPath = $"{Application.StartupPath}/DATA/CONF/{jsonConf}";
|
||||
lgInfo($"Apertura file {jsonFullPath}");
|
||||
StreamReader reader = new StreamReader(jsonFullPath);
|
||||
string jsonData = reader.ReadToEnd();
|
||||
if (!string.IsNullOrEmpty(jsonData))
|
||||
{
|
||||
try
|
||||
{
|
||||
monitoredItems = JsonConvert.DeserializeObject<MonitoredItemsConf>(jsonData);
|
||||
// salvo baseUri
|
||||
baseDir = monitoredItems.SrvData.baseUri;
|
||||
lgInfo($"baseUri = {baseDir}");
|
||||
// imposto a zero la bitmap x riavvio!
|
||||
B_input = 0;
|
||||
// FORZO invio dati...
|
||||
accodaSigIN(ref currDispData);
|
||||
// loggo!
|
||||
lgInfo($"init input bitmap to zero: {B_input}");
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgError(exc, "Eccezione in decodifica conf json");
|
||||
}
|
||||
}
|
||||
reader.Dispose();
|
||||
}
|
||||
lgInfo("DONE reloadAdapterConf");
|
||||
raiseRefresh(currDispData);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endregion Internal Methods
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
/// <summary>
|
||||
/// Cartella di base per interscambio
|
||||
/// </summary>
|
||||
protected string BaseDir = @"C:\Steamware";
|
||||
|
||||
/// <summary>
|
||||
/// Array di configurazione degli oggetti da cercare x decodifica e recupero info
|
||||
/// </summary>
|
||||
protected Dictionary<string, string> dataLocatorLUT;
|
||||
|
||||
/// <summary>
|
||||
/// Vettore della frequenza di ogni status trovato... invio ogni 100 rilevazioni (modulo
|
||||
/// 100, resto == 1)
|
||||
/// </summary>
|
||||
protected Dictionary<string, int> freqUnknStatus = new Dictionary<string, int>();
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Processo stati unknown...
|
||||
/// </summary>
|
||||
/// <param name="cKey"></param>
|
||||
private void processUnknStatus(string cKey)
|
||||
{
|
||||
// cerco se avevo già una key nella dictionary...
|
||||
if (freqUnknStatus.ContainsKey(cKey))
|
||||
{
|
||||
freqUnknStatus[cKey]++;
|
||||
// se è 1 ogni 100 (%100, resto ==1) --> loggo...
|
||||
if (freqUnknStatus[cKey] % 100 == 1)
|
||||
{
|
||||
lgInfo($"Errore in decodifica status: MAPPING non trovato per {cKey} | freq: {freqUnknStatus[cKey]}");
|
||||
// accodo come invio di tipo FLOG...
|
||||
string sVal = string.Format("[UnknStatus] {0}, freq: {1}", cKey, freqUnknStatus);
|
||||
// chiamo accodamento...
|
||||
accodaFLog(sVal, qEncodeFLog("UnknStatus", sVal));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// creo chiave con freq = 1
|
||||
freqUnknStatus.Add(cKey, 1);
|
||||
// log iniziale
|
||||
lgInfo($"Errore in decodifica status: MAPPING non trovato per {cKey}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
@@ -1,629 +0,0 @@
|
||||
#if false
|
||||
using EgwProxy.SqlDb.DbModels;
|
||||
#endif
|
||||
using IOB_UT_NEXT;
|
||||
using MapoSDK;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using static IOB_UT_NEXT.CustomObj;
|
||||
|
||||
namespace IOB_WIN_NEXT.IobFile
|
||||
{
|
||||
/// <summary>
|
||||
/// Adapter specializzato per SOITAAB x la SOLA lettura stato macchina da log, da accoppiare a
|
||||
/// adapter x IOB LANTEK x scrittura PODL
|
||||
/// - IN: LOGFile macchina diretto
|
||||
/// - OUT: --> sigLog
|
||||
/// --> fluxLog
|
||||
/// </summary>
|
||||
|
||||
public class IobFileSoitaab : Iob.GenericNext
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Costruttore dell'IOB FileBased SOITAAB
|
||||
/// </summary>
|
||||
/// <param name="caller">AdapterForm chiamante</param>
|
||||
/// <param name="IOBConf">Configurazione IOB per avvio</param>
|
||||
public IobFileSoitaab(AdapterFormNext caller, IobConfiguration IOBConf) : base(caller, IOBConf)
|
||||
{
|
||||
DateTime adesso = DateTime.Now;
|
||||
string VetoReadSec = getOptPar("VetoReadSec");
|
||||
|
||||
setupSpecialParams();
|
||||
if (pathList.ContainsKey("path-remBase"))
|
||||
{
|
||||
logDirPath = pathList["path-remBase"];
|
||||
}
|
||||
// fix parametri veto
|
||||
if (!string.IsNullOrEmpty(VetoReadSec))
|
||||
{
|
||||
int.TryParse(VetoReadSec, out vetoReadFileSec);
|
||||
}
|
||||
|
||||
string sFluxOnRead = getOptPar("sendFluxOnRead");
|
||||
if (!string.IsNullOrEmpty("sendFluxOnRead"))
|
||||
{
|
||||
bool.TryParse(sFluxOnRead, out sendFluxOnRead);
|
||||
}
|
||||
|
||||
// init a zero....
|
||||
B_input = 0;
|
||||
|
||||
// provo prima lettura logfile
|
||||
try
|
||||
{
|
||||
// eseguo subito un ciclo acquisizione log + processing
|
||||
bool acquireLog = getRemoteLog();
|
||||
if (acquireLog)
|
||||
{
|
||||
bool sentSignLog = processSignLogTable(adesso);
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgError($"Eccezione in IobFileSoitaab{Environment.NewLine}{exc}");
|
||||
}
|
||||
|
||||
lastPING = DateTime.Now.AddHours(-1);
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Implementazione custom esecuzione task specifici
|
||||
/// </summary>
|
||||
/// <param name="task2exe"></param>
|
||||
/// <returns></returns>
|
||||
public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe)
|
||||
{
|
||||
DateTime adesso = DateTime.Now;
|
||||
// NON fa nulla... anche se non dovrebbe richiamarlo
|
||||
Dictionary<string, string> taskDone = new Dictionary<string, string>();
|
||||
lastReadPLC = DateTime.Now;
|
||||
return taskDone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupero dati dinamici...
|
||||
/// </summary>
|
||||
public override Dictionary<string, string> getDynData()
|
||||
{
|
||||
DateTime adesso = DateTime.Now;
|
||||
// dizionario vuoto / faccio direttamente accodamento in FluxLog
|
||||
Dictionary<string, string> outVal = new Dictionary<string, string>();
|
||||
// processo ed accodo!
|
||||
processFluxLogTable(adesso);
|
||||
lastReadPLC = DateTime.Now;
|
||||
return outVal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua lettura semafori principale <paramref name="currDispData">Parametri da
|
||||
/// aggiornare x display in form</paramref>
|
||||
/// </summary>
|
||||
public override void readSemafori(ref newDisplayData currDispData)
|
||||
{
|
||||
DateTime adesso = DateTime.Now;
|
||||
if (connectionOk)
|
||||
{
|
||||
// controllo veto checkDB
|
||||
if (adesso > vetoDataRead)
|
||||
{
|
||||
// predispongo prox veto...
|
||||
vetoDataRead = adesso.AddSeconds(vetoReadFileSec);
|
||||
// semaforo
|
||||
currDispData.semIn = Semaforo.SV;
|
||||
// verifico SignLog e processo
|
||||
bool acquireLog = getRemoteLog();
|
||||
bool sentSignLog = processSignLogTable(adesso);
|
||||
// verifico ProdData e processo
|
||||
bool sentProdData = processProdDataTable(adesso);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
B_input = 0;
|
||||
currDispData.semIn = Semaforo.SR;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override connessione
|
||||
/// </summary>
|
||||
public override void tryConnect()
|
||||
{
|
||||
if (!connectionOk)
|
||||
{
|
||||
// controllo che il ping sia stato tentato almeno pingTestSec fa...
|
||||
if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec"))
|
||||
{
|
||||
if (verboseLog || periodicLog)
|
||||
{
|
||||
lgInfo("FileSoitaab: ConnKO - tryConnect");
|
||||
}
|
||||
// in primis salvo data ping...
|
||||
lastPING = DateTime.Now;
|
||||
// se passa il ping faccio il resto...
|
||||
if (testPingMachine == IPStatus.Success)
|
||||
{
|
||||
string szStatusConnection = "";
|
||||
try
|
||||
{
|
||||
// ora provo connessione...
|
||||
parentForm.commPlcActive = true;
|
||||
|
||||
// connessione OK se oltre al PING riesco a leggere la folder di base
|
||||
if (Directory.Exists(logDirPath))
|
||||
{
|
||||
parentForm.commPlcActive = false;
|
||||
connectionOk = true;
|
||||
}
|
||||
// refresh stato connessione!!!
|
||||
if (connectionOk)
|
||||
{
|
||||
queueInEnabCurr = true;
|
||||
if (adpRunning)
|
||||
{
|
||||
lgInfo($"Connessione OK alla folder {logDirPath}");
|
||||
lastReadPLC = DateTime.Now;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lgError("Impossibile procedere, connessione mancante...");
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgFatal($"Errore nella connessione all'adapter IobFileSoitaab: {szStatusConnection}{Environment.NewLine}{exc}");
|
||||
connectionOk = false;
|
||||
lgInfo($"Eccezione in TryConnect, Adapter IobFileSoitaab NON running, pausa di {utils.CRI("waitRecMSec")} msec prima di ulteriori tentativi di riconnessione");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// loggo no risposta ping ...
|
||||
connectionOk = false;
|
||||
B_input = 0;
|
||||
if (verboseLog || periodicLog)
|
||||
{
|
||||
lgInfo($"Attenzione: IobFileSoitaab controllo PING fallito per IP {cIobConf.cncPingAddr}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
needRefresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void tryDisconnect()
|
||||
{
|
||||
// registro solo che è disconnesso
|
||||
connectionOk = false;
|
||||
queueInEnabCurr = false;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
protected bool sendFluxOnRead = false;
|
||||
protected int vetoReadFileSec = 3;
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
#if false
|
||||
/// <summary>
|
||||
/// Stato di sync delle tab gestite
|
||||
/// </summary>
|
||||
protected List<SyncStateModel> elencoSyncState { get; set; } = new List<SyncStateModel>();
|
||||
#endif
|
||||
|
||||
#endregion Protected Properties
|
||||
|
||||
#region Protected Methods
|
||||
|
||||
/// <summary>
|
||||
/// Conversione string row in log generico
|
||||
/// </summary>
|
||||
/// <param name="dailyLog"></param>
|
||||
/// <returns></returns>
|
||||
protected override GenLogRow convertToMachineLog(string dailyLog)
|
||||
{
|
||||
GenLogRow answ = new GenLogRow();
|
||||
if (!string.IsNullOrEmpty(dailyLog))
|
||||
{
|
||||
// preventivamente: doppio ";;" --> ";"
|
||||
dailyLog = dailyLog.Replace(";;", ";");
|
||||
var sSplit = dailyLog.Split(';');
|
||||
answ.dtRif = DateTime.ParseExact($"{sSplit[0]} {sSplit[1]}", "yyyy-M-d HH:mm:ss", null);
|
||||
answ.valString = $"{sSplit[2]};{sSplit[3]}";
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupera file log da analizzare
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected override bool getRemoteLog()
|
||||
{
|
||||
bool answ = false;
|
||||
bool pingOk = testPingMachine == IPStatus.Success;
|
||||
if (pingOk && Directory.Exists(logDirPath))
|
||||
{
|
||||
string filePath = Path.Combine(logDirPath, $"Report-{DateTime.Today.Day}.txt");
|
||||
bool hasDaily = File.Exists(filePath);
|
||||
// cerco file quotidiano...
|
||||
if (!hasDaily)
|
||||
{
|
||||
var fileList = Directory.GetFiles(logDirPath, "Report-*.txt");
|
||||
DateTime lastMod = DateTime.Today.AddYears(-1);
|
||||
foreach (var cFile in fileList)
|
||||
{
|
||||
var tempFile = Path.Combine(logDirPath, cFile);
|
||||
var lwTime = File.GetLastWriteTime(tempFile);
|
||||
if (lwTime >= lastMod)
|
||||
{
|
||||
lastMod = lwTime;
|
||||
filePath = tempFile;
|
||||
}
|
||||
}
|
||||
}
|
||||
// leggo file
|
||||
string rawVal = File.ReadAllText(Path.Combine(logDirPath, filePath));
|
||||
if (!string.IsNullOrEmpty(rawVal))
|
||||
{
|
||||
// salvo in redis
|
||||
string redKey = redisMan.redHash($"IOB:CurrData:{cIobConf.codIOB}:LogFile:Act");
|
||||
redisMan.setRSV(redKey, rawVal);
|
||||
answ = true;
|
||||
}
|
||||
}
|
||||
return answ;
|
||||
}
|
||||
|
||||
#endregion Protected Methods
|
||||
|
||||
#region Private Properties
|
||||
|
||||
private string logDirPath { get; set; } = "\\\\ecs900\\Logs";
|
||||
|
||||
#endregion Private Properties
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private static int decodeSoitaabLog(string val2test)
|
||||
{
|
||||
// di default NON EMERGENZA...
|
||||
int valInt = 128;
|
||||
switch (val2test)
|
||||
{
|
||||
case "START;1":
|
||||
valInt = 1 + 2 + 128;
|
||||
break;
|
||||
|
||||
case "END;1":
|
||||
valInt = 1 + 128;
|
||||
break;
|
||||
|
||||
case "START;0":
|
||||
case "END;0":
|
||||
case "HOLD;":
|
||||
valInt = 1 + 16 + 128;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return valInt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue processing + invio dati tab SignLog
|
||||
/// </summary>
|
||||
/// <param name="adesso"></param>
|
||||
/// <returns></returns>
|
||||
private bool processFluxLogTable(DateTime adesso)
|
||||
{
|
||||
bool fatto = false;
|
||||
// leggo eventuali dati di fluxlog ed invio...
|
||||
if (fluxLogData != null && fluxLogData.Count > 0)
|
||||
{
|
||||
string sVal = "";
|
||||
foreach (var fLog2send in fluxLogData)
|
||||
{
|
||||
var kvpFlux = fLog2send.valString.Split(';');
|
||||
if (kvpFlux.Count() > 1)
|
||||
{
|
||||
sVal = $"[DYNDATA] |{fLog2send.dtRif:yyyy-MM-dd HH:mm:ss}|{kvpFlux[0]}|{kvpFlux[1]}";
|
||||
// chiamo accodamento con dataora corretta...
|
||||
accodaFLog(sVal, qEncodeFLog(fLog2send.dtRif, kvpFlux[0], kvpFlux[1]));
|
||||
}
|
||||
}
|
||||
// svuoto coda invio fluxlog...
|
||||
fluxLogData = new List<GenLogRow>();
|
||||
// fatto!
|
||||
fatto = true;
|
||||
}
|
||||
return fatto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue processing + invio dati tab ProdData
|
||||
/// </summary>
|
||||
/// <param name="adesso"></param>
|
||||
/// <returns></returns>
|
||||
private bool processProdDataTable(DateTime adesso)
|
||||
{
|
||||
bool fatto = false;
|
||||
return fatto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue processing + invio dati tab SignLog
|
||||
/// </summary>
|
||||
/// <param name="adesso"></param>
|
||||
/// <returns></returns>
|
||||
private bool processSignLogTable(DateTime adesso)
|
||||
{
|
||||
bool fatto = false;
|
||||
// init oggetto x processing
|
||||
Dictionary<DateTime, int> sigLogFromFile = new Dictionary<DateTime, int>();
|
||||
// recupero i dati dai logs files, attuale e nuovo...
|
||||
string fileAct = redisMan.getRSV(redKeyLogfileAct);
|
||||
string fileLast = redisMan.getRSV(redKeyLogfileLast);
|
||||
// confronto con i dati dell'ultimo LOG FILE processato
|
||||
int lenghtAct = fileAct != null ? fileAct.Length : 0;
|
||||
int lenghtLast = fileLast != null ? fileLast.Length : 0;
|
||||
//if (lenghtAct > 0 && lenghtAct != lenghtLast)
|
||||
if (lenghtAct > 0)
|
||||
{
|
||||
List<GenLogRow> logNew = new List<GenLogRow>();
|
||||
List<GenLogRow> sigLogData = new List<GenLogRow>();
|
||||
List<GenLogRow> logLast = getGenLogFromMachineLog(fileLast);
|
||||
List<GenLogRow> logAct = getGenLogFromMachineLog(fileAct);
|
||||
// SE c'è prendo ultima riga inviata x confronto...
|
||||
var fileLastEnd = logLast.LastOrDefault();
|
||||
if (fileLastEnd != null)
|
||||
{
|
||||
// ora prendo SOLAMENTE le righe nuove
|
||||
logNew = logAct
|
||||
.Where(x => x.dtRif > fileLastEnd.dtRif)
|
||||
.OrderBy(x => x.dtRif)
|
||||
.ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
logNew = logAct;
|
||||
}
|
||||
// solo SE ho nuovi dati....
|
||||
if (logNew.Count > 0)
|
||||
{
|
||||
// processo le righe nuove e le accodo in redis come elenco FluxLog da inviare
|
||||
// (appoggio in redis)... andando ad accodarle...
|
||||
var currFLD = fluxLogData;
|
||||
currFLD.AddRange(logNew);
|
||||
fluxLogData = currFLD;
|
||||
|
||||
// estraggo solo info x sig log
|
||||
sigLogData = logNew
|
||||
.Where(x => x.valString.StartsWith("START") || x.valString.StartsWith("HOLD") || x.valString.StartsWith("END"))
|
||||
.OrderBy(x => x.dtRif)
|
||||
.ToList();
|
||||
|
||||
// processo le righe nuove trasformando al volo SOLO eventi...
|
||||
foreach (var sLog2send in sigLogData)
|
||||
{
|
||||
/* -----------------------------------------------------
|
||||
* bitmap MAPO STANDARD 60
|
||||
* B0: 001 POWER_ON
|
||||
* B1: 002 RUN
|
||||
* B2: 004 pzCount
|
||||
* B3: 008 allarme
|
||||
* B4: 016 manuale
|
||||
* B5: 032 slowTC
|
||||
* B6: 064 WarmUpCoolDown
|
||||
* B7: 128 EmergArmata
|
||||
*
|
||||
----------------------------------------------------- */
|
||||
|
||||
int valInt = decodeSoitaabLog(sLog2send.valString);
|
||||
|
||||
string currVal = getEncodSigLog(sLog2send.dtRif, valInt, counterSigIN);
|
||||
// verifico non sia in veto invio iniziale...
|
||||
if (queueInEnabCurr)
|
||||
{
|
||||
// --> accodo (valore già formattato)!
|
||||
QueueIN.Enqueue(currVal);
|
||||
// loggo!
|
||||
lgTrace(string.Format("[QUEUE-IN] {0}", currVal));
|
||||
counterSigIN++;
|
||||
if (counterSigIN > 9999)
|
||||
{
|
||||
counterSigIN = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lgDebug($"[VETO FOR QUEUE-IN] | {currVal} - MESSAGE NOT SENT | {adesso:yyyyMMdd_HHmmss}");
|
||||
checkVetoQueueIn();
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------------------------------------------------------
|
||||
* processo righe x costruire una lista di eventi produzione:
|
||||
* - elenco di eventi contapezzi
|
||||
* - lista xODL come articolo + quantità prodotta (_1, _2, ...)
|
||||
* - eventuale ultimo xODL che resta aperto
|
||||
*
|
||||
* successivamente processing + invio info raccolte
|
||||
* - recupero PODL aperti
|
||||
* - apertura/chiusura PODL esistenti
|
||||
* - creazione PODL mancanti
|
||||
* - dichiarazione contapezzi
|
||||
*
|
||||
* ---------------------------------------------------------- */
|
||||
|
||||
string sVal = "";
|
||||
string descrArt = "";
|
||||
List<ProdBatchData> elencoProdBatch = new List<ProdBatchData>();
|
||||
ProdBatchData lastProdBatch = new ProdBatchData();
|
||||
|
||||
// ora processo TUTTO x il generico caso fluxLog......
|
||||
foreach (var fLog2send in logNew)
|
||||
{
|
||||
// separo per ";"
|
||||
var currData = fLog2send.valString.Split(';');
|
||||
if (currData.Length > 1)
|
||||
{
|
||||
if (sendFluxOnRead)
|
||||
{
|
||||
// per prima cosa fluxLog a prescindere...
|
||||
sVal = $"[LOGFILE]{currData[0]}|{currData[1]}";
|
||||
// ...e chiamo accodamento
|
||||
accodaFLog(sVal, qEncodeFLog(fLog2send.dtRif, currData[0], currData[1]));
|
||||
}
|
||||
|
||||
switch (currData[0])
|
||||
{
|
||||
case "END":
|
||||
// se è un end --> è comunque NON + runnning
|
||||
isRunningState = false; // chiudo batch precedente + in elenco (SE era valido...)
|
||||
if (!string.IsNullOrEmpty(lastProdBatch.codArt))
|
||||
{
|
||||
lastProdBatch.dtEnd = fLog2send.dtRif;
|
||||
elencoProdBatch.Add(lastProdBatch);
|
||||
}
|
||||
// reset articolo..
|
||||
lastArtDescr = "";
|
||||
// nuovo batch VUOTO
|
||||
lastProdBatch = new ProdBatchData();
|
||||
contapezziPLC = 0;
|
||||
break;
|
||||
|
||||
case "START":
|
||||
isRunningState = currData[1] == "1";
|
||||
break;
|
||||
|
||||
case "PARTCODE":
|
||||
// inizio confronto articolo con precedente x capire se sia NUOVO
|
||||
descrArt = currData[1];
|
||||
// devo scartare i "doppi percorsi"
|
||||
if (descrArt != lastArtDescr)
|
||||
{
|
||||
// verifico se sia DAVVERO cambiato articolo... prendo
|
||||
// articolo senza indice (_1, _2, _3, ...)
|
||||
var artDataLast = lastArtDescr.Split('_');
|
||||
var artDataNew = descrArt.Split('_');
|
||||
// nuovo articolo (NON vuoto)
|
||||
if (!string.IsNullOrEmpty(artDataNew[0]) && artDataLast[0] != artDataNew[0])
|
||||
{
|
||||
// chiudo batch precedente + in elenco (SE era valido...)
|
||||
if (!string.IsNullOrEmpty(lastProdBatch.codArt))
|
||||
{
|
||||
// chiudo prod
|
||||
lastProdBatch.dtEnd = fLog2send.dtRif;
|
||||
elencoProdBatch.Add(lastProdBatch);
|
||||
}
|
||||
// nuovo batch
|
||||
lastProdBatch = new ProdBatchData()
|
||||
{
|
||||
codArt = artDataNew[0],
|
||||
dtStart = fLog2send.dtRif,
|
||||
numPz = 1
|
||||
};
|
||||
}
|
||||
// solo nuova copia articolo
|
||||
else
|
||||
{
|
||||
// aumento numPezzi batch
|
||||
lastProdBatch.numPz++;
|
||||
}
|
||||
|
||||
// salvo nuovo art processato
|
||||
lastArtDescr = descrArt;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// recupero elenco PODL corrente...
|
||||
List<PODLModel> reqPOdlList = MachineNextPodl();
|
||||
// adesso processo tutti i prodBatch collezionati x invio
|
||||
foreach (var item in elencoProdBatch)
|
||||
{
|
||||
int currIdxPOdl = 0;
|
||||
// cerco se articolo sia in elenco PODL
|
||||
var listPOdl = reqPOdlList
|
||||
.Where(x => x.CodArticolo.Equals(item.codArt, StringComparison.InvariantCultureIgnoreCase))
|
||||
.ToList();
|
||||
|
||||
// se trovato --> invio start/stop PODL
|
||||
if (listPOdl != null && listPOdl.Count > 0)
|
||||
{
|
||||
var currPodl = listPOdl.FirstOrDefault();
|
||||
if (currPodl != null)
|
||||
{
|
||||
currIdxPOdl = currPodl.IdxPromessa;
|
||||
// elimino da elenco PODL
|
||||
reqPOdlList.Remove(currPodl);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// se NON trovato --> creo PODL, poi avvio/chiudo
|
||||
currIdxPOdl = TryCreatePodl(item.codArt, CodGruppoIob, item.numPz);
|
||||
}
|
||||
// se idxPOdl valido
|
||||
if (currIdxPOdl > 0)
|
||||
{
|
||||
// mando apertura PODL
|
||||
SendStartPodl(currIdxPOdl, item.dtStart);
|
||||
// chiudo PODL...
|
||||
if (item.dtEnd != null)
|
||||
{
|
||||
// invio pezzi 3 sec prima di chiusura
|
||||
SendPzIncrAtDate(item.numPz, ((DateTime)item.dtEnd).AddSeconds(-3));
|
||||
// chiudo
|
||||
SendClosePOdl(currIdxPOdl, (DateTime)item.dtEnd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// salvo in last il valore di act...
|
||||
redisMan.setRSV(redKeyLogfileLast, fileAct);
|
||||
|
||||
// calcolo B_input valido
|
||||
var lastRec = sigLogData.LastOrDefault();
|
||||
if (lastRec != null)
|
||||
{
|
||||
// salvo in B_input ultimo valore letto...
|
||||
int lastValInt = decodeSoitaabLog(lastRec.valString);
|
||||
B_input = lastValInt;
|
||||
}
|
||||
}
|
||||
fatto = true;
|
||||
}
|
||||
return fatto;
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
@@ -1,288 +0,0 @@
|
||||
using EgwProxy.Icoel;
|
||||
using IOB_UT_NEXT;
|
||||
using MapoSDK;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Net.NetworkInformation;
|
||||
|
||||
namespace IOB_WIN_NEXT.IobSql
|
||||
{
|
||||
/// <summary>
|
||||
/// Adapter specializzato per ICOEL e le chiamate tramite DB per i dati
|
||||
/// - accettazione lotti prodotto (frontiera / entrata ciliegie)
|
||||
/// - export (totale per prodotti)
|
||||
/// - tracciabilità (confezioni
|
||||
/// </summary>
|
||||
|
||||
public class IcoelDb : Iob.GenericNext
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Costruttore dell'IOB Icoel DB
|
||||
/// </summary>
|
||||
/// <param name="caller">AdapterForm chiamante</param>
|
||||
/// <param name="IOBConf">Configurazione IOB per avvio</param>
|
||||
public IcoelDb(AdapterFormNext caller, IobConfiguration IOBConf) : base(caller, IOBConf)
|
||||
{
|
||||
/* --------------------------------------
|
||||
* todo's
|
||||
* --------------------------------------
|
||||
* - init obj comunicazione da conf e nuget
|
||||
* - lanciare sync e verifica stato sync
|
||||
*/
|
||||
|
||||
string SyncStateServer = getOptPar("SyncStateServer");
|
||||
string SyncStateDb = getOptPar("SyncStateDb");
|
||||
string SyncStateUser = getOptPar("SyncStateUser");
|
||||
string SyncStatePwd = getOptPar("SyncStatePwd");
|
||||
string SyncStateCTout = getOptPar("SyncStateCTout");
|
||||
|
||||
string connSyncState = $"data source={SyncStateServer};initial catalog={SyncStateDb};persist security info=True;user id={SyncStateUser};password={SyncStatePwd};MultipleActiveResultSets=True;App=IOB-WIN-NEXT";
|
||||
|
||||
// gestione command timeout da https://erikej.github.io/sqlclient/2020/10/26/sqlclient-commandtimeout-preview.html
|
||||
if (!string.IsNullOrEmpty(SyncStateCTout))
|
||||
{
|
||||
connSyncState = $"{connSyncState};Command Timeout={SyncStateCTout}";
|
||||
}
|
||||
|
||||
// eccezione: NON TROVA EntityFramework 6.0.0 o successivo... why?!?
|
||||
dbProxy = new DbProxy(connSyncState);
|
||||
|
||||
lastPING = DateTime.Now.AddHours(-1);
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Implementazione custom esecuzione task specifici
|
||||
/// </summary>
|
||||
/// <param name="task2exe"></param>
|
||||
/// <returns></returns>
|
||||
public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe)
|
||||
{
|
||||
// unico task ammissibile: fare un SYNC forzato...
|
||||
Dictionary<string, string> taskDone = new Dictionary<string, string>();
|
||||
if (task2exe != null)
|
||||
{
|
||||
// controllo se memMap != null...
|
||||
if (memMap != null)
|
||||
{
|
||||
bool taskOk = false;
|
||||
string taskVal = "";
|
||||
// cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4
|
||||
foreach (var item in task2exe)
|
||||
{
|
||||
taskOk = false;
|
||||
taskVal = "";
|
||||
// converto richiesta in enum...
|
||||
taskType tName = taskType.nihil;
|
||||
Enum.TryParse(item.Key, out tName);
|
||||
// controllo sulla KEY...
|
||||
switch (tName)
|
||||
{
|
||||
case taskType.syncDbData:
|
||||
lgInfo($"executeTasks --> syncDbData");
|
||||
// effettua sync
|
||||
refreshElencoStati();
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
taskVal = $"IobIcoelDb | taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
|
||||
lgInfo($"IobIcoelDb | chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
lastReadPLC = DateTime.Now;
|
||||
return taskDone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupero dati dinamici...
|
||||
/// </summary>
|
||||
public override Dictionary<string, string> getDynData()
|
||||
{
|
||||
// valore non presente in vers default... se gestito fare override
|
||||
Dictionary<string, string> outVal = new Dictionary<string, string>();
|
||||
// recupero da DB locale stato sync attuale
|
||||
var elencoSyncStateCurr = dbProxy.DataController.SyncStateGetAll();
|
||||
foreach (var item in elencoSyncStateCurr)
|
||||
{
|
||||
saveValue(ref outVal, $"{item.TableName}_NumRec", item.NumRec);
|
||||
saveValue(ref outVal, $"{item.TableName}_NumRecIn", item.NumRecIn);
|
||||
saveValue(ref outVal, $"{item.TableName}_LastIdx", item.LastIdx);
|
||||
saveValue(ref outVal, $"{item.TableName}_LastIdxIn", item.LastIdxIn);
|
||||
}
|
||||
|
||||
// aggiungo anche i campi currData
|
||||
var currData = dbProxy.DataController.CurrDataGetAll();
|
||||
foreach (var item in currData)
|
||||
{
|
||||
saveValue(ref outVal, item.Topic, (double)item.CurrVal);
|
||||
}
|
||||
|
||||
lastReadPLC = DateTime.Now;
|
||||
return outVal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua processing CUSTOM x Icoel:
|
||||
/// - recupera elenco batch delle 2 linee
|
||||
/// - invia al sistema
|
||||
/// </summary>
|
||||
public override void processCustomTaskLF()
|
||||
{
|
||||
lgInfo($"Richiesto processCustomTaskLF");
|
||||
// effettua sync
|
||||
refreshElencoStati();
|
||||
lastReadPLC = DateTime.Now;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua lettura semafori principale <paramref name="currDispData">Parametri da
|
||||
/// aggiornare x display in form</paramref>
|
||||
/// </summary>
|
||||
public override void readSemafori(ref newDisplayData currDispData)
|
||||
{
|
||||
if (connectionOk)
|
||||
{
|
||||
B_input = 1;
|
||||
currDispData.semIn = Semaforo.SV;
|
||||
|
||||
if (dbProxy != null && elencoSyncState != null && elencoSyncState.Count > 0)
|
||||
{
|
||||
B_input += (1 << 1);
|
||||
}
|
||||
|
||||
// accodo NON emergenza
|
||||
B_input += (1 << 7);
|
||||
}
|
||||
else
|
||||
{
|
||||
B_input = 0;
|
||||
currDispData.semIn = Semaforo.SR;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override connessione
|
||||
/// </summary>
|
||||
public override void tryConnect()
|
||||
{
|
||||
if (!connectionOk)
|
||||
{
|
||||
// controllo che il ping sia stato tentato almeno pingTestSec fa...
|
||||
if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec"))
|
||||
{
|
||||
if (verboseLog || periodicLog)
|
||||
{
|
||||
lgInfo("IcoelSoap: ConnKO - tryConnect");
|
||||
}
|
||||
// in primis salvo data ping...
|
||||
lastPING = DateTime.Now;
|
||||
// se passa il ping faccio il resto...
|
||||
if (testPingMachine == IPStatus.Success)
|
||||
{
|
||||
string szStatusConnection = "";
|
||||
try
|
||||
{
|
||||
// ora provo connessione...
|
||||
parentForm.commPlcActive = true;
|
||||
if (dbProxy != null)
|
||||
{
|
||||
elencoSyncState = dbProxy.DataController.SyncStateDoImportAll();
|
||||
|
||||
if (elencoSyncState != null && elencoSyncState.Count > 0)
|
||||
{
|
||||
parentForm.commPlcActive = false;
|
||||
connectionOk = true;
|
||||
}
|
||||
}
|
||||
// refresh stato connessione!!!
|
||||
if (connectionOk)
|
||||
{
|
||||
queueInEnabCurr = true;
|
||||
if (adpRunning)
|
||||
{
|
||||
lgInfo("Connessione OK");
|
||||
lastReadPLC = DateTime.Now;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lgError("Impossibile procedere, connessione mancante...");
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgFatal($"Errore nella connessione all'adapter IcoelSoap: {szStatusConnection}{Environment.NewLine}{exc}");
|
||||
connectionOk = false;
|
||||
lgInfo($"Eccezione in TryConnect, Adapter IcoelSoap NON running, pausa di {utils.CRI("waitRecMSec")} msec prima di ulteriori tentativi di riconnessione");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// loggo no risposta ping ...
|
||||
connectionOk = false;
|
||||
if (verboseLog || periodicLog)
|
||||
{
|
||||
lgInfo($"Attenzione: IcoelSoap controllo PING fallito per IP {cIobConf.cncPingAddr}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
needRefresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void tryDisconnect()
|
||||
{
|
||||
// registro solo che è disconnesso
|
||||
connectionOk = false;
|
||||
queueInEnabCurr = false;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
protected EgwProxy.Icoel.DbProxy dbProxy { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Stato di sync delle tab gestite
|
||||
/// </summary>
|
||||
protected List<EgwProxy.Icoel.DataLayer.DatabaseModels.SyncStateModel> elencoSyncState { get; set; } = new List<EgwProxy.Icoel.DataLayer.DatabaseModels.SyncStateModel>();
|
||||
|
||||
#endregion Protected Properties
|
||||
|
||||
#region Private Methods
|
||||
|
||||
private void refreshElencoStati()
|
||||
{
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
elencoSyncState = dbProxy.DataController.SyncStateDoImportAll();
|
||||
sw.Stop();
|
||||
lastReadPLC = DateTime.Now;
|
||||
lgInfo($"DB: esecuzione task dbProxy.DataController.SyncStateGetAll() in {sw.ElapsedMilliseconds} ms");
|
||||
|
||||
if (elencoSyncState != null)
|
||||
{
|
||||
foreach (var item in elencoSyncState)
|
||||
{
|
||||
lgTrace($"TAB: {item.TableName} | IdxIN / IdxLocal {item.LastIdxIn} / {item.LastIdx} | NumIn / NumLocal {item.NumRecIn} / {item.NumRec}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
@@ -1,523 +0,0 @@
|
||||
using EgwProxy.SqlDb.Controllers;
|
||||
using EgwProxy.SqlDb.DbModels;
|
||||
using IOB_UT_NEXT;
|
||||
using MapoSDK;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using static IOB_UT_NEXT.CustomObj;
|
||||
|
||||
namespace IOB_WIN_NEXT.IobSql
|
||||
{
|
||||
/// <summary>
|
||||
/// Adapter specializzato per LANTEK e le chiamate tramite DB per i dati
|
||||
/// - PODL (ordini MES --> MACCHINA)
|
||||
/// - ProdLog (da NestingDaLantek + RigheNestingDaLantek)
|
||||
/// </summary>
|
||||
|
||||
public class SqlServLantek : Iob.GenericNext
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Costruttore dell'IOB DB LANTEK
|
||||
/// </summary>
|
||||
/// <param name="caller">AdapterForm chiamante</param>
|
||||
/// <param name="IOBConf">Configurazione IOB per avvio</param>
|
||||
public SqlServLantek(AdapterFormNext caller, IobConfiguration IOBConf) : base(caller, IOBConf)
|
||||
{
|
||||
DateTime adesso = DateTime.Now;
|
||||
string SyncStateServ = getOptPar("SyncStateServer");
|
||||
string SyncStateDb = getOptPar("SyncStateDb");
|
||||
string SyncStateUser = getOptPar("SyncStateUser");
|
||||
string SyncStatePwd = getOptPar("SyncStatePwd");
|
||||
string SyncStateCTout = getOptPar("SyncStateCTout");
|
||||
string VetoReadSec = getOptPar("VetoReadSec");
|
||||
string VetoSyncSec = getOptPar("VetoSyncSec");
|
||||
string sFullPodlUrl = getOptPar("FullPodlUrl");
|
||||
|
||||
setupSpecialParams();
|
||||
|
||||
string connSyncState = $"data source={SyncStateServ};initial catalog={SyncStateDb};persist security info=True;user id={SyncStateUser};password={SyncStatePwd};MultipleActiveResultSets=True;App=IOB-WIN-NEXT";
|
||||
|
||||
// gestione command timeout da https://erikej.github.io/sqlclient/2020/10/26/sqlclient-commandtimeout-preview.html
|
||||
if (!string.IsNullOrEmpty(SyncStateCTout))
|
||||
{
|
||||
connSyncState = $"{connSyncState};Command Timeout={SyncStateCTout}";
|
||||
}
|
||||
if (!string.IsNullOrEmpty(VetoReadSec))
|
||||
{
|
||||
int.TryParse(VetoReadSec, out vetoReadDbSec);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(VetoSyncSec))
|
||||
{
|
||||
int.TryParse(VetoSyncSec, out VetoSyncDbSec);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(sFullPodlUrl))
|
||||
{
|
||||
bool.TryParse(sFullPodlUrl, out FullPodlUrl);
|
||||
}
|
||||
|
||||
// avvio DB controller
|
||||
dbProxy = new DbController(connSyncState);
|
||||
|
||||
lastPING = DateTime.Now.AddHours(-1);
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Implementazione custom esecuzione task specifici
|
||||
/// </summary>
|
||||
/// <param name="task2exe"></param>
|
||||
/// <returns></returns>
|
||||
public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe)
|
||||
{
|
||||
DateTime adesso = DateTime.Now;
|
||||
// unico task ammissibile: fare un SYNC forzato...
|
||||
Dictionary<string, string> taskDone = new Dictionary<string, string>();
|
||||
if (task2exe != null)
|
||||
{
|
||||
// controllo se memMap != null...
|
||||
if (memMap != null)
|
||||
{
|
||||
bool taskOk = false;
|
||||
string taskVal = "";
|
||||
// cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4
|
||||
foreach (var item in task2exe)
|
||||
{
|
||||
taskOk = false;
|
||||
taskVal = "";
|
||||
// converto richiesta in enum...
|
||||
taskType tName = taskType.nihil;
|
||||
Enum.TryParse(item.Key, out tName);
|
||||
// controllo sulla KEY...
|
||||
switch (tName)
|
||||
{
|
||||
case taskType.setComm:
|
||||
case taskType.syncDbData:
|
||||
lgInfo($"executeTasks --> {tName}");
|
||||
// per prima cosa recupero elenco PODL attivi x la macchina
|
||||
List<PODLModel> listaPODL = new List<PODLModel>();
|
||||
bool okPodl = false;
|
||||
var rawListPODL = callUrl(urlGetCurrPODL, false);
|
||||
if (!string.IsNullOrEmpty(rawListPODL))
|
||||
{
|
||||
try
|
||||
{
|
||||
listaPODL = JsonConvert.DeserializeObject<List<PODLModel>>(rawListPODL);
|
||||
okPodl = listaPODL.Count > 0;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lg.Error($"Errore: chiamata elenco PODL ha restituito errore{Environment.NewLine}{exc}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lg.Error($"Errore: chiamata elenco PODL ({urlGetCurrPODL}) ha restituito valore vuoto");
|
||||
}
|
||||
if (okPodl)
|
||||
{
|
||||
//mando elenco PODL...
|
||||
List<MesPODLReqModel> CurrPodlReq = listaPODL
|
||||
.Select(x => new MesPODLReqModel()
|
||||
{
|
||||
Attivabile = x.Attivabile,
|
||||
CodArticolo = x.CodArticolo,
|
||||
CodCli = x.CodCli,
|
||||
CodGruppo = x.CodGruppo,
|
||||
DueDate = x.DueDate ?? DateTime.Now,
|
||||
IdxMacchina = x.IdxMacchina,
|
||||
IdxODL = x.IdxOdl,
|
||||
IdxPromessa = x.IdxPromessa,
|
||||
InsertDate = x.InsertDate,
|
||||
KeyBCode = x.KeyBCode,
|
||||
KeyRichiesta = x.KeyRichiesta,
|
||||
Note = x.Note,
|
||||
NumPezzi = x.NumPezzi,
|
||||
Priorita = x.Priorita,
|
||||
PzPallet = x.PzPallet,
|
||||
TCAssegnato = x.Tcassegnato
|
||||
})
|
||||
.ToList();
|
||||
// scrivo i record richiesti
|
||||
bool fatto = dbProxy.MesPodlWriteReq(CurrPodlReq);
|
||||
if (fatto)
|
||||
{
|
||||
taskVal = $"EXECUTED task: {item.Key} / {item.Value}";
|
||||
// registro evento chiamata scrittura in syncState...
|
||||
string tabName = item.Key;
|
||||
var currSyncState = elencoSyncState.FirstOrDefault(x => x.TableName == tabName);
|
||||
// verifico x registrare azione
|
||||
if (currSyncState == null)
|
||||
{
|
||||
currSyncState = new SyncStateModel()
|
||||
{
|
||||
LastIdx = 0,
|
||||
LastUpdate = adesso,
|
||||
TableName = tabName,
|
||||
Note = "Init"
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
var lastRec = CurrPodlReq.OrderBy(x => x.IdxPromessa).LastOrDefault();
|
||||
currSyncState.LastIdx = lastRec != null ? lastRec.IdxPromessa : -1;
|
||||
currSyncState.Note = $"Esecuzione {tabName} per {CurrPodlReq.Count} rec | last code: {currSyncState.LastIdx}";
|
||||
currSyncState.LastUpdate = adesso;
|
||||
}
|
||||
// salvo sync...
|
||||
dbProxy.SyncStateUpsert(currSyncState);
|
||||
}
|
||||
|
||||
// effettua sync scrivendo i dati in export (PODL)
|
||||
execExportAll();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
taskVal = $"IobSqlServLantek | taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
|
||||
lgInfo($"IobSqlServLantek | chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}");
|
||||
break;
|
||||
}
|
||||
// aggiungo task!
|
||||
taskDone.Add(item.Key, taskVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
lastReadPLC = DateTime.Now;
|
||||
return taskDone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupero dati dinamici... FAKE!
|
||||
/// </summary>
|
||||
public override Dictionary<string, string> getDynData()
|
||||
{
|
||||
DateTime adesso = DateTime.Now;
|
||||
|
||||
// dizionario vuoto / gestito da altro adapter file-based
|
||||
Dictionary<string, string> outVal = new Dictionary<string, string>();
|
||||
|
||||
lastReadPLC = DateTime.Now;
|
||||
return outVal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua processing CUSTOM:
|
||||
/// - esegue tutti gli import
|
||||
/// </summary>
|
||||
public override void processCustomTaskLF()
|
||||
{
|
||||
lgInfo($"Richiesto processCustomTaskLF");
|
||||
// effettua sync
|
||||
execExportAll();
|
||||
execImportAll();
|
||||
lastReadPLC = DateTime.Now;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua lettura semafori principale <paramref name="currDispData">Parametri da
|
||||
/// aggiornare x display in form</paramref>
|
||||
/// </summary>
|
||||
public override void readSemafori(ref newDisplayData currDispData)
|
||||
{
|
||||
DateTime adesso = DateTime.Now;
|
||||
if (connectionOk)
|
||||
{
|
||||
// controllo veto checkDB
|
||||
if (adesso > vetoDataRead)
|
||||
{
|
||||
// predispongo prox veto...
|
||||
vetoDataRead = adesso.AddSeconds(vetoReadDbSec);
|
||||
if (adesso > vetoDataSync)
|
||||
{
|
||||
// effettua sync
|
||||
execImportAll();
|
||||
vetoDataSync = adesso.AddSeconds(VetoSyncDbSec);
|
||||
}
|
||||
|
||||
// semaforo
|
||||
currDispData.semIn = Semaforo.SV;
|
||||
// recupero syncState
|
||||
elencoSyncState = dbProxy.SyncStateGetAll();
|
||||
// verifico ProdData e processo
|
||||
bool sentProdData = processProdDataTable(adesso);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
B_input = 0;
|
||||
currDispData.semIn = Semaforo.SR;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override connessione
|
||||
/// </summary>
|
||||
public override void tryConnect()
|
||||
{
|
||||
if (!connectionOk)
|
||||
{
|
||||
// controllo che il ping sia stato tentato almeno pingTestSec fa...
|
||||
if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec"))
|
||||
{
|
||||
if (verboseLog || periodicLog)
|
||||
{
|
||||
lgInfo("SqlDb LANTEK: ConnKO - tryConnect");
|
||||
}
|
||||
// in primis salvo data ping...
|
||||
lastPING = DateTime.Now;
|
||||
// se passa il ping faccio il resto...
|
||||
if (testPingMachine == IPStatus.Success)
|
||||
{
|
||||
string szStatusConnection = "";
|
||||
try
|
||||
{
|
||||
// ora provo connessione...
|
||||
parentForm.commPlcActive = true;
|
||||
if (dbProxy != null)
|
||||
{
|
||||
elencoSyncState = dbProxy.SyncStateDoImportAll();
|
||||
|
||||
if (elencoSyncState != null && elencoSyncState.Count > 0)
|
||||
{
|
||||
parentForm.commPlcActive = false;
|
||||
connectionOk = true;
|
||||
}
|
||||
}
|
||||
// refresh stato connessione!!!
|
||||
if (connectionOk)
|
||||
{
|
||||
queueInEnabCurr = true;
|
||||
if (adpRunning)
|
||||
{
|
||||
lgInfo("Connessione OK");
|
||||
lastReadPLC = DateTime.Now;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lgError("Impossibile procedere, connessione mancante...");
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgFatal($"Errore nella connessione all'adapter SqlDb LANTEK: {szStatusConnection}{Environment.NewLine}{exc}");
|
||||
connectionOk = false;
|
||||
lgInfo($"Eccezione in TryConnect, Adapter SqlDb LANTEK NON running, pausa di {utils.CRI("waitRecMSec")} msec prima di ulteriori tentativi di riconnessione");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// loggo no risposta ping ...
|
||||
connectionOk = false;
|
||||
if (verboseLog || periodicLog)
|
||||
{
|
||||
lgInfo($"Attenzione: SqlDb LANTEK controllo PING fallito per IP {cIobConf.cncPingAddr}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
needRefresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void tryDisconnect()
|
||||
{
|
||||
// registro solo che è disconnesso
|
||||
connectionOk = false;
|
||||
queueInEnabCurr = false;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
protected bool FullPodlUrl = false;
|
||||
protected int vetoReadDbSec = 3;
|
||||
|
||||
protected int VetoSyncDbSec = 20;
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
protected DbController dbProxy { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Stato di sync delle tab gestite
|
||||
/// </summary>
|
||||
protected List<SyncStateModel> elencoSyncState { get; set; } = new List<SyncStateModel>();
|
||||
|
||||
#endregion Protected Properties
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Esegue task EXPORT (MES PODL to MACHINE)
|
||||
/// </summary>
|
||||
private void execExportAll()
|
||||
{
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
elencoSyncState = dbProxy.SyncStateDoExportAll();
|
||||
sw.Stop();
|
||||
DateTime adesso = DateTime.Now;
|
||||
lastReadPLC = adesso;
|
||||
lgInfo($"DB: esecuzione task dbProxy.SyncStateDoExportAll() in {sw.ElapsedMilliseconds} ms");
|
||||
|
||||
if (elencoSyncState != null)
|
||||
{
|
||||
// registro evento chiamata scrittura in syncState...
|
||||
string tabName = "ExportAll";
|
||||
var currSyncState = elencoSyncState.FirstOrDefault(x => x.TableName == tabName);
|
||||
// verifico x registrare azione
|
||||
if (currSyncState == null)
|
||||
{
|
||||
currSyncState = new SyncStateModel()
|
||||
{
|
||||
LastIdx = 0,
|
||||
LastUpdate = adesso,
|
||||
TableName = tabName,
|
||||
Note = "Init"
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
// calcolo lastIDX valore da datetime
|
||||
int valInt = -1;
|
||||
var nowString = $"{adesso:HHmmss}";
|
||||
int.TryParse(nowString, out valInt);
|
||||
currSyncState.LastIdx = valInt;
|
||||
currSyncState.Note = $"Esecuzione {tabName} | DT code: {currSyncState.LastIdx}";
|
||||
currSyncState.LastUpdate = adesso;
|
||||
}
|
||||
// salvo sync...
|
||||
dbProxy.SyncStateUpsert(currSyncState);
|
||||
foreach (var item in elencoSyncState)
|
||||
{
|
||||
lgTrace($"TAB {item.TableName} | LastIdx {item.LastIdx} | Note {item.Note} | Last Upd {item.LastUpdate}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue task IMPORT (MES PODL to MACHINE)
|
||||
/// </summary>
|
||||
private void execImportAll()
|
||||
{
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
elencoSyncState = dbProxy.SyncStateDoImportAll();
|
||||
sw.Stop();
|
||||
lastReadPLC = DateTime.Now;
|
||||
lgInfo($"DB: esecuzione task dbProxy.SyncStateDoImportAll() in {sw.ElapsedMilliseconds} ms");
|
||||
|
||||
if (elencoSyncState != null)
|
||||
{
|
||||
foreach (var item in elencoSyncState)
|
||||
{
|
||||
lgTrace($"TAB {item.TableName} | LastIdx {item.LastIdx} | Note {item.Note} | Last Upd {item.LastUpdate}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue processing + invio dati tab ProdData
|
||||
/// </summary>
|
||||
/// <param name="adesso"></param>
|
||||
/// <returns></returns>
|
||||
private bool processProdDataTable(DateTime adesso)
|
||||
{
|
||||
bool fatto = false;
|
||||
string tabNameIn = "ProdData";
|
||||
string tabNameOut = "ProdDataToMes";
|
||||
// cerco info sui SignLog (ToMes e letti)
|
||||
var currSignLogRead = elencoSyncState.FirstOrDefault(x => x.TableName == tabNameIn);
|
||||
// se nullo inizializzo
|
||||
if (currSignLogRead == null)
|
||||
{
|
||||
currSignLogRead = new SyncStateModel()
|
||||
{
|
||||
LastIdx = 0,
|
||||
LastUpdate = adesso,
|
||||
TableName = tabNameIn,
|
||||
Note = "Init"
|
||||
};
|
||||
}
|
||||
var currSignLogSent = elencoSyncState.FirstOrDefault(x => x.TableName == tabNameOut);
|
||||
// se nullo inizializzo
|
||||
if (currSignLogSent == null)
|
||||
{
|
||||
currSignLogSent = new SyncStateModel()
|
||||
{
|
||||
LastIdx = 0,
|
||||
LastUpdate = adesso,
|
||||
TableName = tabNameOut,
|
||||
Note = "Init"
|
||||
};
|
||||
}
|
||||
// verifica se ci siano dati da trasmettere (sui valori LastIdx)
|
||||
if (currSignLogRead.LastIdx > currSignLogSent.LastIdx)
|
||||
{
|
||||
// recupero i dati dal DB...
|
||||
var data2send = dbProxy.MachProdDataGetNew(currSignLogSent.LastIdx);
|
||||
// se ho dati preparo invio
|
||||
if (data2send != null && data2send.Count > 0)
|
||||
{
|
||||
foreach (var sLog2send in data2send)
|
||||
{
|
||||
if (sLog2send.Action == "StartOrd")
|
||||
{
|
||||
if (FullPodlUrl)
|
||||
{
|
||||
// se il record è apertura PODL chiamo apertura
|
||||
trySetupPODL(sLog2send.IdxPodl, true, sLog2send.DtEve, DateTime.Now);
|
||||
}
|
||||
else
|
||||
{
|
||||
trySetupPODL(0);
|
||||
}
|
||||
}
|
||||
else if (sLog2send.Action == "EndOrd")
|
||||
{
|
||||
// se il record è chiusura PODL chiamo chiusura... DOPO aver cercato
|
||||
// PODL --> ODL
|
||||
if (FullPodlUrl)
|
||||
{
|
||||
tryClosePODL(sLog2send.IdxPodl, sLog2send.DtEve, DateTime.Now);
|
||||
}
|
||||
else
|
||||
{
|
||||
tryClosePODL(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// aggiorno idx inviato...
|
||||
currSignLogSent.Note = $"Updated from {currSignLogRead.LastIdx}";
|
||||
currSignLogSent.LastUpdate = adesso;
|
||||
currSignLogSent.LastIdx = currSignLogRead.LastIdx;
|
||||
fatto = true;
|
||||
}
|
||||
|
||||
// alla fine aggiorno i dati inviati!
|
||||
dbProxy.SyncStateUpsert(currSignLogSent);
|
||||
|
||||
return fatto;
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
@@ -1,686 +0,0 @@
|
||||
using EgwProxy.SqlDb.Controllers;
|
||||
using EgwProxy.SqlDb.DbModels;
|
||||
using IOB_UT_NEXT;
|
||||
using MapoSDK;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using static IOB_UT_NEXT.CustomObj;
|
||||
|
||||
namespace IOB_WIN_NEXT.IobSql
|
||||
{
|
||||
/// <summary>
|
||||
/// Adapter specializzato per PAMA e le chiamate tramite DB per i dati
|
||||
/// - PODL (ordini MES --> MACCHINA)
|
||||
/// - SignLog (da stato macchina)
|
||||
/// - FluxLog (da stato macchina)
|
||||
/// - ProdLog (da stato Prod)
|
||||
/// </summary>
|
||||
public class SqlServPama : Iob.GenericNext
|
||||
{
|
||||
#region Public Constructors
|
||||
|
||||
/// <summary>
|
||||
/// Costruttore dell'IOB DB PAMA
|
||||
/// </summary>
|
||||
/// <param name="caller">AdapterForm chiamante</param>
|
||||
/// <param name="IOBConf">Configurazione IOB per avvio</param>
|
||||
public SqlServPama(AdapterFormNext caller, IobConfiguration IOBConf) : base(caller, IOBConf)
|
||||
{
|
||||
string SyncStateServ = getOptPar("SyncStateServer");
|
||||
string SyncStateDb = getOptPar("SyncStateDb");
|
||||
string SyncStateUser = getOptPar("SyncStateUser");
|
||||
string SyncStatePwd = getOptPar("SyncStatePwd");
|
||||
string SyncStateCTout = getOptPar("SyncStateCTout");
|
||||
string VetoReadSec = getOptPar("VetoReadSec");
|
||||
string VetoSyncSec = getOptPar("VetoSyncSec");
|
||||
string sFullPodlUrl = getOptPar("FullPodlUrl");
|
||||
|
||||
string connSyncState = $"data source={SyncStateServ};initial catalog={SyncStateDb};persist security info=True;user id={SyncStateUser};password={SyncStatePwd};MultipleActiveResultSets=True;App=IOB-WIN-NEXT";
|
||||
|
||||
// gestione command timeout da https://erikej.github.io/sqlclient/2020/10/26/sqlclient-commandtimeout-preview.html
|
||||
if (!string.IsNullOrEmpty(SyncStateCTout))
|
||||
{
|
||||
connSyncState = $"{connSyncState};Command Timeout={SyncStateCTout}";
|
||||
}
|
||||
if (!string.IsNullOrEmpty(VetoReadSec))
|
||||
{
|
||||
int.TryParse(VetoReadSec, out vetoReadDbSec);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(VetoSyncSec))
|
||||
{
|
||||
int.TryParse(VetoSyncSec, out VetoSyncDbSec);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(sFullPodlUrl))
|
||||
{
|
||||
bool.TryParse(sFullPodlUrl, out FullPodlUrl);
|
||||
}
|
||||
|
||||
// eccezione: NON TROVA EntityFramework 6.0.0 o successivo... why?!?
|
||||
dbProxy = new DbController(connSyncState);
|
||||
|
||||
lastPING = DateTime.Now.AddHours(-1);
|
||||
}
|
||||
|
||||
#endregion Public Constructors
|
||||
|
||||
#region Public Methods
|
||||
|
||||
/// <summary>
|
||||
/// Implementazione custom esecuzione task specifici
|
||||
/// </summary>
|
||||
/// <param name="task2exe"></param>
|
||||
/// <returns></returns>
|
||||
public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe)
|
||||
{
|
||||
DateTime adesso = DateTime.Now;
|
||||
// unico task ammissibile: fare un SYNC forzato...
|
||||
Dictionary<string, string> taskDone = new Dictionary<string, string>();
|
||||
if (task2exe != null)
|
||||
{
|
||||
// controllo se memMap != null...
|
||||
if (memMap != null)
|
||||
{
|
||||
bool taskOk = false;
|
||||
string taskVal = "";
|
||||
// cerco task specifici: se ho startSetup --> imposto bit DBB701.DBB0.4
|
||||
foreach (var item in task2exe)
|
||||
{
|
||||
taskOk = false;
|
||||
taskVal = "";
|
||||
// converto richiesta in enum...
|
||||
taskType tName = taskType.nihil;
|
||||
Enum.TryParse(item.Key, out tName);
|
||||
// controllo sulla KEY...
|
||||
switch (tName)
|
||||
{
|
||||
case taskType.setComm:
|
||||
case taskType.syncDbData:
|
||||
lgInfo($"executeTasks --> {tName}");
|
||||
// per prima cosa recupero elenco PODL attivi x la macchina
|
||||
List<PODLModel> listaPODL = new List<PODLModel>();
|
||||
bool okPodl = false;
|
||||
var rawListPODL = callUrl(urlGetCurrPODL, false);
|
||||
if (!string.IsNullOrEmpty(rawListPODL))
|
||||
{
|
||||
try
|
||||
{
|
||||
listaPODL = JsonConvert.DeserializeObject<List<PODLModel>>(rawListPODL);
|
||||
okPodl = listaPODL.Count > 0;
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lg.Error($"Errore: chiamata elenco PODL ha restituito errore{Environment.NewLine}{exc}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lg.Error($"Errore: chiamata elenco PODL ({urlGetCurrPODL}) ha restituito valore vuoto");
|
||||
}
|
||||
if (okPodl)
|
||||
{
|
||||
//mando elenco PODL...
|
||||
List<MesPODLReqModel> CurrPodlReq = listaPODL
|
||||
.Select(x => new MesPODLReqModel()
|
||||
{
|
||||
Attivabile = x.Attivabile,
|
||||
CodArticolo = x.CodArticolo,
|
||||
CodCli = x.CodCli,
|
||||
CodGruppo = x.CodGruppo,
|
||||
DueDate = x.DueDate ?? DateTime.Now,
|
||||
IdxMacchina = x.IdxMacchina,
|
||||
IdxODL = x.IdxOdl,
|
||||
IdxPromessa = x.IdxPromessa,
|
||||
InsertDate = x.InsertDate,
|
||||
KeyBCode = x.KeyBCode,
|
||||
KeyRichiesta = x.KeyRichiesta,
|
||||
Note = x.Note,
|
||||
NumPezzi = x.NumPezzi,
|
||||
Priorita = x.Priorita,
|
||||
PzPallet = x.PzPallet,
|
||||
TCAssegnato = x.Tcassegnato
|
||||
})
|
||||
.ToList();
|
||||
// scrivo i record richiesti
|
||||
bool fatto = dbProxy.MesPodlWriteReq(CurrPodlReq);
|
||||
if (fatto)
|
||||
{
|
||||
taskVal = $"EXECUTED task: {item.Key} / {item.Value}";
|
||||
// registro evento chiamata scrittura in syncState...
|
||||
string tabName = item.Key;
|
||||
var currSyncState = elencoSyncState.FirstOrDefault(x => x.TableName == tabName);
|
||||
// verifico x registrare azione
|
||||
if (currSyncState == null)
|
||||
{
|
||||
currSyncState = new SyncStateModel()
|
||||
{
|
||||
LastIdx = 0,
|
||||
LastUpdate = adesso,
|
||||
TableName = tabName,
|
||||
Note = "Init"
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
var lastRec = CurrPodlReq.OrderBy(x => x.IdxPromessa).LastOrDefault();
|
||||
currSyncState.LastIdx = lastRec != null ? lastRec.IdxPromessa : -1;
|
||||
currSyncState.Note = $"Esecuzione {tabName} per {CurrPodlReq.Count} rec | last code: {currSyncState.LastIdx}";
|
||||
currSyncState.LastUpdate = adesso;
|
||||
}
|
||||
// salvo sync...
|
||||
dbProxy.SyncStateUpsert(currSyncState);
|
||||
}
|
||||
|
||||
// effettua sync scrivendo i dati in export (PODL)
|
||||
execExportAll();
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
taskVal = $"IobSqlServPama | taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
|
||||
lgInfo($"IobSqlServPama | chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}");
|
||||
break;
|
||||
}
|
||||
// aggiungo task!
|
||||
taskDone.Add(item.Key, taskVal);
|
||||
}
|
||||
}
|
||||
}
|
||||
lastReadPLC = DateTime.Now;
|
||||
return taskDone;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Recupero dati dinamici...
|
||||
/// </summary>
|
||||
public override Dictionary<string, string> getDynData()
|
||||
{
|
||||
DateTime adesso = DateTime.Now;
|
||||
|
||||
// dizionario vuoto / faccio direttamente accodamento in FluxLog
|
||||
Dictionary<string, string> outVal = new Dictionary<string, string>();
|
||||
|
||||
// processo ed accodo!
|
||||
processFluxLogTable(adesso);
|
||||
|
||||
lastReadPLC = DateTime.Now;
|
||||
return outVal;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua processing CUSTOM:
|
||||
/// - esegue tutti gli import
|
||||
/// </summary>
|
||||
public override void processCustomTaskLF()
|
||||
{
|
||||
lgInfo($"Richiesto processCustomTaskLF");
|
||||
// effettua sync
|
||||
execImportAll();
|
||||
lastReadPLC = DateTime.Now;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Effettua lettura semafori principale <paramref name="currDispData">Parametri da
|
||||
/// aggiornare x display in form</paramref>
|
||||
/// </summary>
|
||||
public override void readSemafori(ref newDisplayData currDispData)
|
||||
{
|
||||
DateTime adesso = DateTime.Now;
|
||||
if (connectionOk)
|
||||
{
|
||||
// controllo veto checkDB
|
||||
if (adesso > vetoDataRead)
|
||||
{
|
||||
// predispongo prox veto...
|
||||
vetoDataRead = adesso.AddSeconds(vetoReadDbSec);
|
||||
if (adesso > vetoDataSync)
|
||||
{
|
||||
// effettua sync
|
||||
execImportAll();
|
||||
vetoDataSync = adesso.AddSeconds(VetoSyncDbSec);
|
||||
}
|
||||
|
||||
// semaforo
|
||||
currDispData.semIn = Semaforo.SV;
|
||||
// recupero syncState
|
||||
elencoSyncState = dbProxy.SyncStateGetAll();
|
||||
// verifico SignLog e processo
|
||||
bool sentSignLog = processSignLogTable(adesso);
|
||||
// verifico ProdData e processo
|
||||
bool sentProdData = processProdDataTable(adesso);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
B_input = 0;
|
||||
currDispData.semIn = Semaforo.SR;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override connessione
|
||||
/// </summary>
|
||||
public override void tryConnect()
|
||||
{
|
||||
if (!connectionOk)
|
||||
{
|
||||
// controllo che il ping sia stato tentato almeno pingTestSec fa...
|
||||
if (DateTime.Now.Subtract(lastPING).TotalSeconds > utils.CRI("pingTestSec"))
|
||||
{
|
||||
if (verboseLog || periodicLog)
|
||||
{
|
||||
lgInfo("SqlDb PAMA: ConnKO - tryConnect");
|
||||
}
|
||||
// in primis salvo data ping...
|
||||
lastPING = DateTime.Now;
|
||||
// se passa il ping faccio il resto...
|
||||
if (testPingMachine == IPStatus.Success)
|
||||
{
|
||||
string szStatusConnection = "";
|
||||
try
|
||||
{
|
||||
// ora provo connessione...
|
||||
parentForm.commPlcActive = true;
|
||||
if (dbProxy != null)
|
||||
{
|
||||
elencoSyncState = dbProxy.SyncStateDoImportAll();
|
||||
|
||||
if (elencoSyncState != null && elencoSyncState.Count > 0)
|
||||
{
|
||||
parentForm.commPlcActive = false;
|
||||
connectionOk = true;
|
||||
}
|
||||
}
|
||||
// refresh stato connessione!!!
|
||||
if (connectionOk)
|
||||
{
|
||||
queueInEnabCurr = true;
|
||||
if (adpRunning)
|
||||
{
|
||||
lgInfo("Connessione OK");
|
||||
lastReadPLC = DateTime.Now;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lgError("Impossibile procedere, connessione mancante...");
|
||||
}
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
lgFatal($"Errore nella connessione all'adapter SqlDb PAMA: {szStatusConnection}{Environment.NewLine}{exc}");
|
||||
connectionOk = false;
|
||||
lgInfo($"Eccezione in TryConnect, Adapter SqlDb PAMA NON running, pausa di {utils.CRI("waitRecMSec")} msec prima di ulteriori tentativi di riconnessione");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// loggo no risposta ping ...
|
||||
connectionOk = false;
|
||||
if (verboseLog || periodicLog)
|
||||
{
|
||||
lgInfo($"Attenzione: SqlDb PAMA controllo PING fallito per IP {cIobConf.cncPingAddr}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
needRefresh = true;
|
||||
}
|
||||
}
|
||||
|
||||
public override void tryDisconnect()
|
||||
{
|
||||
// registro solo che è disconnesso
|
||||
connectionOk = false;
|
||||
queueInEnabCurr = false;
|
||||
}
|
||||
|
||||
#endregion Public Methods
|
||||
|
||||
#region Protected Fields
|
||||
|
||||
protected bool FullPodlUrl = false;
|
||||
protected int vetoReadDbSec = 3;
|
||||
|
||||
protected int VetoSyncDbSec = 20;
|
||||
|
||||
#endregion Protected Fields
|
||||
|
||||
#region Protected Properties
|
||||
|
||||
protected DbController dbProxy { get; set; } = null;
|
||||
|
||||
/// <summary>
|
||||
/// Stato di sync delle tab gestite
|
||||
/// </summary>
|
||||
protected List<SyncStateModel> elencoSyncState { get; set; } = new List<SyncStateModel>();
|
||||
|
||||
#endregion Protected Properties
|
||||
|
||||
#region Private Methods
|
||||
|
||||
/// <summary>
|
||||
/// Esegue task EXPORT (MES PODL to MACHINE)
|
||||
/// </summary>
|
||||
private void execExportAll()
|
||||
{
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
elencoSyncState = dbProxy.SyncStateDoExportAll();
|
||||
sw.Stop();
|
||||
DateTime adesso = DateTime.Now;
|
||||
lastReadPLC = adesso;
|
||||
lgInfo($"DB: esecuzione task dbProxy.SyncStateDoExportAll() in {sw.ElapsedMilliseconds} ms");
|
||||
|
||||
if (elencoSyncState != null)
|
||||
{
|
||||
// registro evento chiamata scrittura in syncState...
|
||||
string tabName = "ExportAll";
|
||||
var currSyncState = elencoSyncState.FirstOrDefault(x => x.TableName == tabName);
|
||||
// verifico x registrare azione
|
||||
if (currSyncState == null)
|
||||
{
|
||||
currSyncState = new SyncStateModel()
|
||||
{
|
||||
LastIdx = 0,
|
||||
LastUpdate = adesso,
|
||||
TableName = tabName,
|
||||
Note = "Init"
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
// calcolo lastIDX valore da datetime
|
||||
int valInt = -1;
|
||||
var nowString = $"{adesso:HHmmss}";
|
||||
int.TryParse(nowString, out valInt);
|
||||
currSyncState.LastIdx = valInt;
|
||||
currSyncState.Note = $"Esecuzione {tabName} | DT code: {currSyncState.LastIdx}";
|
||||
currSyncState.LastUpdate = adesso;
|
||||
}
|
||||
// salvo sync...
|
||||
dbProxy.SyncStateUpsert(currSyncState);
|
||||
foreach (var item in elencoSyncState)
|
||||
{
|
||||
lgTrace($"TAB {item.TableName} | LastIdx {item.LastIdx} | Note {item.Note} | Last Upd {item.LastUpdate}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue task IMPORT (MES PODL to MACHINE)
|
||||
/// </summary>
|
||||
private void execImportAll()
|
||||
{
|
||||
Stopwatch sw = new Stopwatch();
|
||||
sw.Start();
|
||||
elencoSyncState = dbProxy.SyncStateDoImportAll();
|
||||
sw.Stop();
|
||||
lastReadPLC = DateTime.Now;
|
||||
lgInfo($"DB: esecuzione task dbProxy.SyncStateDoImportAll() in {sw.ElapsedMilliseconds} ms");
|
||||
|
||||
if (elencoSyncState != null)
|
||||
{
|
||||
foreach (var item in elencoSyncState)
|
||||
{
|
||||
lgTrace($"TAB {item.TableName} | LastIdx {item.LastIdx} | Note {item.Note} | Last Upd {item.LastUpdate}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue processing + invio dati tab SignLog
|
||||
/// </summary>
|
||||
/// <param name="adesso"></param>
|
||||
/// <returns></returns>
|
||||
private bool processFluxLogTable(DateTime adesso)
|
||||
{
|
||||
bool fatto = false;
|
||||
string tabNameIn = "FluxLog";
|
||||
string tabNameOut = "FluxLogToMes";
|
||||
// cerco info sui FluxLog (ToMes e letti)
|
||||
var currFluxLogRead = elencoSyncState.FirstOrDefault(x => x.TableName == tabNameIn);
|
||||
// se nullo inizializzo
|
||||
if (currFluxLogRead == null)
|
||||
{
|
||||
currFluxLogRead = new SyncStateModel()
|
||||
{
|
||||
LastIdx = 0,
|
||||
LastUpdate = adesso,
|
||||
TableName = tabNameIn,
|
||||
Note = "Init"
|
||||
};
|
||||
}
|
||||
var currFluxLogSent = elencoSyncState.FirstOrDefault(x => x.TableName == tabNameOut);
|
||||
// se nullo inizializzo
|
||||
if (currFluxLogSent == null)
|
||||
{
|
||||
currFluxLogSent = new SyncStateModel()
|
||||
{
|
||||
LastIdx = 0,
|
||||
LastUpdate = adesso,
|
||||
TableName = tabNameOut,
|
||||
Note = "Init"
|
||||
};
|
||||
}
|
||||
// verifica se ci siano dati da trasmettere (sui valori LastIdx)
|
||||
if (currFluxLogRead.LastIdx > currFluxLogSent.LastIdx)
|
||||
{
|
||||
// recupero i dati dal DB...
|
||||
var data2send = dbProxy.MachFluxLogGetNew(currFluxLogSent.LastIdx);
|
||||
// se ho dati preparo invio
|
||||
if (data2send != null && data2send.Count > 0)
|
||||
{
|
||||
string sVal = "";
|
||||
foreach (var fLog2send in data2send)
|
||||
{
|
||||
sVal = $"[DYNDATA] |{fLog2send.DtEvento:yyyy-MM-dd HH:mm:ss}|{fLog2send.CodFlux}|{fLog2send.Valore}";
|
||||
// chiamo accodamento con dataora corretta...
|
||||
accodaFLog(sVal, qEncodeFLog(fLog2send.DtEvento, fLog2send.CodFlux, fLog2send.Valore));
|
||||
}
|
||||
fatto = true;
|
||||
}
|
||||
|
||||
// aggiorno idx inviato...
|
||||
currFluxLogSent.Note = $"Updated from {currFluxLogRead.LastIdx}";
|
||||
currFluxLogSent.LastUpdate = adesso;
|
||||
currFluxLogSent.LastIdx = currFluxLogRead.LastIdx;
|
||||
}
|
||||
|
||||
// alla fine aggiorno i dati inviati!
|
||||
dbProxy.SyncStateUpsert(currFluxLogSent);
|
||||
|
||||
return fatto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue processing + invio dati tab ProdData
|
||||
/// </summary>
|
||||
/// <param name="adesso"></param>
|
||||
/// <returns></returns>
|
||||
private bool processProdDataTable(DateTime adesso)
|
||||
{
|
||||
bool fatto = false;
|
||||
string tabNameIn = "ProdData";
|
||||
string tabNameOut = "ProdDataToMes";
|
||||
// cerco info sui SignLog (ToMes e letti)
|
||||
var currSignLogRead = elencoSyncState.FirstOrDefault(x => x.TableName == tabNameIn);
|
||||
// se nullo inizializzo
|
||||
if (currSignLogRead == null)
|
||||
{
|
||||
currSignLogRead = new SyncStateModel()
|
||||
{
|
||||
LastIdx = 0,
|
||||
LastUpdate = adesso,
|
||||
TableName = tabNameIn,
|
||||
Note = "Init"
|
||||
};
|
||||
}
|
||||
var currSignLogSent = elencoSyncState.FirstOrDefault(x => x.TableName == tabNameOut);
|
||||
// se nullo inizializzo
|
||||
if (currSignLogSent == null)
|
||||
{
|
||||
currSignLogSent = new SyncStateModel()
|
||||
{
|
||||
LastIdx = 0,
|
||||
LastUpdate = adesso,
|
||||
TableName = tabNameOut,
|
||||
Note = "Init"
|
||||
};
|
||||
}
|
||||
// verifica se ci siano dati da trasmettere (sui valori LastIdx)
|
||||
if (currSignLogRead.LastIdx > currSignLogSent.LastIdx)
|
||||
{
|
||||
// recupero i dati dal DB...
|
||||
var data2send = dbProxy.MachProdDataGetNew(currSignLogSent.LastIdx);
|
||||
// se ho dati preparo invio
|
||||
if (data2send != null && data2send.Count > 0)
|
||||
{
|
||||
foreach (var sLog2send in data2send)
|
||||
{
|
||||
if (sLog2send.Action == "StartOrd")
|
||||
{
|
||||
if (FullPodlUrl)
|
||||
{
|
||||
// se il record è apertura PODL chiamo apertura
|
||||
trySetupPODL(sLog2send.IdxPodl);
|
||||
//trySetupPODL(sLog2send.IdxPodl, true, sLog2send.DtEve, DateTime.Now);
|
||||
}
|
||||
else
|
||||
{
|
||||
trySetupPODL(0);
|
||||
}
|
||||
}
|
||||
else if (sLog2send.Action == "EndOrd")
|
||||
{
|
||||
// se il record è chiusura PODL chiamo chiusura... DOPO aver cercato
|
||||
// PODL --> ODL
|
||||
if (FullPodlUrl)
|
||||
{
|
||||
tryClosePODL(sLog2send.IdxPodl);
|
||||
//tryClosePODL(sLog2send.IdxPodl, sLog2send.DtEve, DateTime.Now);
|
||||
}
|
||||
else
|
||||
{
|
||||
tryClosePODL(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// aggiorno idx inviato...
|
||||
currSignLogSent.Note = $"Updated from {currSignLogRead.LastIdx}";
|
||||
currSignLogSent.LastUpdate = adesso;
|
||||
currSignLogSent.LastIdx = currSignLogRead.LastIdx;
|
||||
#if false
|
||||
var lastRec = data2send.LastOrDefault();
|
||||
if (lastRec != null)
|
||||
{
|
||||
// salvo in B_input ultimo valore letto...
|
||||
B_input = lastRec.ValInt;
|
||||
}
|
||||
#endif
|
||||
fatto = true;
|
||||
}
|
||||
|
||||
// alla fine aggiorno i dati inviati!
|
||||
dbProxy.SyncStateUpsert(currSignLogSent);
|
||||
|
||||
return fatto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Esegue processing + invio dati tab SignLog
|
||||
/// </summary>
|
||||
/// <param name="adesso"></param>
|
||||
/// <returns></returns>
|
||||
private bool processSignLogTable(DateTime adesso)
|
||||
{
|
||||
bool fatto = false;
|
||||
string tabNameIn = "SignLog";
|
||||
string tabNameOut = "SignLogToMes";
|
||||
// cerco info sui SignLog (ToMes e letti)
|
||||
var currSignLogRead = elencoSyncState.FirstOrDefault(x => x.TableName == tabNameIn);
|
||||
// se nullo inizializzo
|
||||
if (currSignLogRead == null)
|
||||
{
|
||||
currSignLogRead = new SyncStateModel()
|
||||
{
|
||||
LastIdx = 0,
|
||||
LastUpdate = adesso,
|
||||
TableName = tabNameIn,
|
||||
Note = "Init"
|
||||
};
|
||||
}
|
||||
var currSignLogSent = elencoSyncState.FirstOrDefault(x => x.TableName == tabNameOut);
|
||||
// se nullo inizializzo
|
||||
if (currSignLogSent == null)
|
||||
{
|
||||
currSignLogSent = new SyncStateModel()
|
||||
{
|
||||
LastIdx = 0,
|
||||
LastUpdate = adesso,
|
||||
TableName = tabNameOut,
|
||||
Note = "Init"
|
||||
};
|
||||
}
|
||||
// verifica se ci siano dati da trasmettere (sui valori LastIdx)
|
||||
if (currSignLogRead.LastIdx > currSignLogSent.LastIdx)
|
||||
{
|
||||
// recupero i dati dal DB...
|
||||
List<MachSigLogModel> data2send = dbProxy.MachSigLogGetNew(currSignLogSent.LastIdx);
|
||||
// se ho dati preparo invio
|
||||
if (data2send != null && data2send.Count > 0)
|
||||
{
|
||||
foreach (var sLog2send in data2send)
|
||||
{
|
||||
string currVal = getEncodSigLog(sLog2send.DtEve, sLog2send.ValInt, counterSigIN);
|
||||
// verifico non sia in veto invio iniziale...
|
||||
if (queueInEnabCurr)
|
||||
{
|
||||
// --> accodo (valore già formattato)!
|
||||
QueueIN.Enqueue(currVal);
|
||||
// loggo!
|
||||
lgTrace(string.Format("[QUEUE-IN] {0}", currVal));
|
||||
counterSigIN++;
|
||||
if (counterSigIN > 9999)
|
||||
{
|
||||
counterSigIN = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
lgDebug($"[VETO FOR QUEUE-IN] | {currVal} - MESSAGE NOT SENT | {adesso:yyyyMMdd_HHmmss}");
|
||||
checkVetoQueueIn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// aggiorno idx inviato...
|
||||
currSignLogSent.Note = $"Updated from {currSignLogRead.LastIdx}";
|
||||
currSignLogSent.LastUpdate = adesso;
|
||||
currSignLogSent.LastIdx = currSignLogRead.LastIdx;
|
||||
var lastRec = data2send.LastOrDefault();
|
||||
if (lastRec != null)
|
||||
{
|
||||
// salvo in B_input ultimo valore letto...
|
||||
B_input = lastRec.ValInt;
|
||||
}
|
||||
fatto = true;
|
||||
}
|
||||
|
||||
// alla fine aggiorno i dati inviati!
|
||||
dbProxy.SyncStateUpsert(currSignLogSent);
|
||||
|
||||
return fatto;
|
||||
}
|
||||
|
||||
#endregion Private Methods
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user