c4a103ddc5
Bozza struttura file x IobFTP (Sonatest)
338 lines
14 KiB
C#
338 lines
14 KiB
C#
using MapoSDK;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Net.NetworkInformation;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace IOB_WIN_NEXT.IobNet
|
|
{
|
|
/// <summary>
|
|
/// Classe gestione sync via FTP
|
|
/// </summary>
|
|
public class Ftp : Iob.Generic
|
|
{
|
|
#region Public Constructors
|
|
|
|
/// <summary>
|
|
/// Estende l'init della classe base, impiegando il pacchetto EgwCoreLib.Ftp
|
|
/// - gestione dei task da svolgere da configurazione json specifica
|
|
/// - specializzazione da conf e non da codice
|
|
/// </summary>
|
|
/// <param name="caller"></param>
|
|
/// <param name="IOBConf"></param>
|
|
public Ftp(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf)
|
|
{
|
|
lgInfo("Init IobFtp Client");
|
|
|
|
sendKeyRichiesta = true;
|
|
}
|
|
|
|
#endregion Public Constructors
|
|
|
|
#region Public Methods
|
|
|
|
/// <summary>
|
|
/// Processo i task richiesti e li elimino dalla coda 2:2
|
|
/// </summary>
|
|
/// <param name="task2exe"></param>
|
|
public override Dictionary<string, string> executeTasks(Dictionary<string, string> task2exe)
|
|
{
|
|
// uso metodo base x salvare esito scrittura
|
|
var writeResult = base.executeTasks(task2exe);
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* va creata una folder x ogni ODL (una volta LANCIATO da tablet) APERTO
|
|
* - nella folder scriviamo un file con articolo, qta, commessa
|
|
* - la folder sarà usata x salvare OGNI file necessario e di rilevazione
|
|
*---------------------------------------------------------------------------*/
|
|
|
|
// aggiungo comportamento custom: se ho impostato nome ricetta (programma) --> imposto
|
|
// richiesta caricamento se ho richiesto reset o fine lavoro --> imposto azzeramento
|
|
// esco restituendo risutlato scrittura iniziali
|
|
if (task2exe != null)
|
|
{
|
|
// controllo se memMap != null...
|
|
if (memMap != null)
|
|
{
|
|
bool taskOk = false;
|
|
string taskVal = "";
|
|
// cerco task specifici x OMP
|
|
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)
|
|
{
|
|
#if false
|
|
case taskType.setProg:
|
|
// recupero dati da memMap...
|
|
if (memMap != null && memMap.mMapWrite != null)
|
|
{
|
|
if (memMap.mMapWrite.ContainsKey(item.Key))
|
|
{
|
|
dataConf currMem = memMap.mMapWrite[item.Key];
|
|
string addr = currMem.memAddr;
|
|
taskVal = $"SET task: {item.Key} --> {item.Value} | mem: {currMem.memAddr} - {currMem.size} byte";
|
|
// salvo il nuovo valore nella memoria... così prox invio lo trasmetterà
|
|
memMap.mMapWrite[item.Key].value = item.Value;
|
|
}
|
|
else
|
|
{
|
|
taskVal = $"NO DATA MEM, SET task: {item.Key} --> {item.Value}";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
taskVal = $"NO MemMap found, SET task: {item.Key} --> {item.Value}";
|
|
}
|
|
// salvo in currProd..
|
|
saveProdData(new KeyValuePair<string, string>(item.Key, item.Value));
|
|
|
|
break;
|
|
|
|
case taskType.startSetup:
|
|
setFineLotto();
|
|
break;
|
|
|
|
case taskType.stopSetup:
|
|
setInizioProd();
|
|
break;
|
|
|
|
case taskType.syncDbData:
|
|
processDataSync();
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
taskVal = $"taskReq: {tName} | key: {item.Key} | val: {item.Value} | SKIPPED | NO EXEC";
|
|
lgInfo($"Chiamata senza processing: taskOk: {taskOk} | taskVal: {taskVal}");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
lgError($"Attenzione! memMap è nullo, non posso eseguire task2exe!");
|
|
}
|
|
}
|
|
|
|
return writeResult;
|
|
}
|
|
|
|
#endregion Public Methods
|
|
|
|
#region Protected Methods
|
|
|
|
/// <summary>
|
|
/// Effettua decodifica aree memoria alla bitmap usata x MAPO
|
|
/// </summary>
|
|
protected virtual void decodeToBaseBitmap()
|
|
{
|
|
DateTime adesso = DateTime.Now;
|
|
// init a zero...
|
|
B_input = 0;
|
|
|
|
/* -----------------------------------------------------
|
|
* STATE MACHINE 60 STD / SIMULA
|
|
*------------------------------------------------------
|
|
* bitmap MAPO
|
|
* B0: POWER_ON
|
|
* B1: RUN
|
|
* B2: pzCount
|
|
* B3: allarme
|
|
* B4: manuale
|
|
* B5: SlowTC (NON gestito qui)
|
|
* B6: warm-up / cool-down / setup
|
|
* B7: emergenza ARMATA (1=ok, 0 = premuta)
|
|
---------------------------------------------------- */
|
|
|
|
// lo stato è semplicemente
|
|
// - usiamo RunIP (es wifi x Sonatest) x pingare quando accesa --> green se NON risponde
|
|
// ai ping --> GRIGIA nessun altro stato
|
|
|
|
#if false
|
|
// se valido il check ping lo eseguo... altrimenti lo do x buono
|
|
bool checkPing = !opcUaParams.pingAsPowerOn;
|
|
string currRun = "N.A.";
|
|
if (!checkPing)
|
|
{
|
|
checkPing = (testPingMachine == IPStatus.Success);
|
|
}
|
|
// bit 0 (poweron) imposto a 1 SE pingo + PowerOn=="ON"...
|
|
bool powerOnOk = checkPing && hasPowerOn;
|
|
// procedo SOLO SE mi da ping OK...
|
|
if (checkPing)
|
|
{
|
|
B_input = powerOnOk ? 1 : 0;
|
|
|
|
procRunMode(ref currRun);
|
|
|
|
/* -----------------------------------------------------
|
|
* CIMOLAI CUSTOM
|
|
*------------------------------------------------------
|
|
* AUX = 2 --> emergenza armata
|
|
* AUX <> 2 --> emergenza premuta
|
|
* Aux = 2 + InCorso = 0 --> pronto
|
|
* Aux = 2 + LastAct in (2,4,6,8) --> LAVORA
|
|
*
|
|
*
|
|
* PLC/DB231/Attivita
|
|
* 0: Emergenza
|
|
* 1: Avvio registrazione ricetta
|
|
* 2: Inizio comando traslazione
|
|
* 3: Termine comando traslazione
|
|
* 4: Inizio comando di sterzatura
|
|
* 5: Termine comando di sterzatura
|
|
* 6: Inizio comando movimento carrelli
|
|
* 7: Termine comando movimento carrelli
|
|
* 8: Inizio comando sollevamento
|
|
* 9: Termine comando sollevamento
|
|
* 10: richiesta snapshot parametri
|
|
*
|
|
*------------------------------------------------------
|
|
* SEMPLIFICAZIONE POST CERTIFICAZIONE
|
|
*------------------------------------------------------
|
|
*
|
|
* Visto che la rete potrebbe saltare ad intermittenza, conviene gestire in modo semplificato il lavora
|
|
* torno a condizione work base: AUX = 2, marcia = in corso
|
|
*
|
|
*
|
|
---------------------------------------------------- */
|
|
|
|
// controllo emergenza... se zero --> emergenza!
|
|
if (hasEStopArmed)
|
|
{
|
|
B_input += (1 << 7);
|
|
}
|
|
else
|
|
{
|
|
// resetto last act...
|
|
lastAct = 0;
|
|
}
|
|
|
|
// verifico se aggiornare stato LAST ACTION
|
|
if (lastAct != currRunMode && currRunMode != 0)
|
|
{
|
|
// registro solo azioni > 1 e < 10
|
|
if (currRunMode > 1 && currRunMode < 10)
|
|
{
|
|
// escludo le azioni 4 e 5 (che sono anche in concomitanza con 2-3)
|
|
if (currRunMode < 4 || currRunMode > 5)
|
|
{
|
|
lastAct = currRunMode;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Gestione ODL automatica: se abilitata --> qui con start/stop da impianto...
|
|
if (doProcOdl)
|
|
{
|
|
lgTrace($"inizio process verifica presa in carico PODL | isInCorso: {isInCorso} | lastIsInCorso: {lastIsInCorso} | currProgName {currProgName}");
|
|
// se rilevo variazione exe (curr/last)
|
|
// --> registro richiesta attreazzaggio PODL da info commessa
|
|
if (lastIsInCorso != isInCorso)
|
|
{
|
|
// se 0 --> 1 --> registro
|
|
if (isInCorso)
|
|
{
|
|
lgInfo("--------------------------------------------");
|
|
// prendo senza stringa PODL
|
|
string sPODL = currProgName.Replace("PODL", "");
|
|
int idxPODL = 0;
|
|
int.TryParse(sPODL, out idxPODL);
|
|
// chiamo richiesta setup PODL...
|
|
lgInfo($"Inizio trySetupPODL per {idxPODL}");
|
|
trySetupPODL(idxPODL);
|
|
lgInfo("--------------------------------------------");
|
|
}
|
|
else
|
|
{
|
|
lgInfo("--------------------------------------------");
|
|
lgInfo("Inizio tryCloseODL");
|
|
// registro chiusura ODL..
|
|
tryCloseCurrODL();
|
|
lgInfo("--------------------------------------------");
|
|
}
|
|
// registro exe mode
|
|
lastIsInCorso = isInCorso;
|
|
}
|
|
}
|
|
|
|
// salvo running come = working...
|
|
isRunning = isWorkingCimolai;
|
|
|
|
// se ho setup
|
|
if (isWarmUpCoolDown)
|
|
{
|
|
B_input += (1 << 6);
|
|
}
|
|
// se ho almeno 1 allarme E NON SONO IN AUTO --> ALARM!
|
|
if (hasError)
|
|
{
|
|
B_input += (1 << 3);
|
|
}
|
|
if (isWorkingCimolai || isWorking || isInCorso)
|
|
{
|
|
// RUN = LAVORA!
|
|
B_input += (1 << 1);
|
|
}
|
|
else
|
|
{
|
|
if (!isReady || isManualCimolai || isManual)
|
|
{
|
|
// se NON ready --> manual
|
|
B_input += (1 << 4);
|
|
}
|
|
}
|
|
}
|
|
|
|
// controllo se non ho dati buoni da > lastCurrentMaxElapsed sec --> disconnetto
|
|
if (adesso.Subtract(lastCurrent).TotalSeconds > lastCurrentMaxElapsed)
|
|
{
|
|
lgInfo($"Timeout per mancata comunicazione da oltre {lastCurrentMaxElapsed} sec --> disconnessione adapter OpcUa!");
|
|
tryDisconnect();
|
|
}
|
|
|
|
// solo se non ho veto check
|
|
int vFactor = 2;
|
|
if (vetoCheckStatus < adesso)
|
|
{
|
|
lgDebug($"Stato variabili checkPing: {testPingMachine}");
|
|
// imposto veto per vetoSeconds...
|
|
vetoCheckStatus = adesso.AddSeconds(vetoSeconds * vFactor);
|
|
}
|
|
|
|
// log opzionale!
|
|
if (verboseLog)
|
|
{
|
|
lgDebug($"Trasformazione checkPing: {checkPing} | hasPowerOn: {hasPowerOn} | B_input: {B_input} | currRun = {currRun}");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/// <summary>
|
|
/// Effettua sync dati
|
|
/// </summary>
|
|
protected override void processDataSync()
|
|
{
|
|
lgInfo("--------------------------------------------");
|
|
lgInfo($"executeTasks --> syncDbData --> processDataSync");
|
|
lgInfo("--------------------------------------------");
|
|
// effettua sync... recupera cartella MAIN da FTP e replica in locale su folder apposita
|
|
// (in rete?)
|
|
#if false
|
|
var taskGet = iobGetDataFromServer();
|
|
var taskWrite = iobWriteLocalCSV();
|
|
var taskSend = iobSendFTP("");
|
|
#endif
|
|
}
|
|
|
|
#endregion Protected Methods
|
|
}
|
|
} |