Eliminazione file inutilizzati

This commit is contained in:
Samuele Locatelli
2025-01-22 13:15:02 +01:00
parent 9b180dd6cb
commit f4569d36b2
10 changed files with 0 additions and 7510 deletions
-5
View File
@@ -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
-851
View File
@@ -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 --&gt; num decimale --&gt; HEX --&gt; 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 --&gt; diviso in 1 |
/// 2540 --&gt; 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
}
}
-923
View File
@@ -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 --&gt; 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 --&gt; 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
}
}
-358
View File
@@ -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
}
}
-629
View File
@@ -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: --&gt; sigLog
/// --&gt; 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
}
}
-288
View File
@@ -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
}
}
-523
View File
@@ -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 --&gt; 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
}
}
-686
View File
@@ -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 --&gt; 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
}
}