Files
Mapo-IOB-WIN/IOB-WIN/IobSimula.cs
T
2020-02-04 13:12:16 +01:00

579 lines
17 KiB
C#

using IOB_UT;
using MapoSDK;
using System;
using System.Collections.Generic;
namespace IOB_WIN
{
/// <summary>
/// Configuraizone eventi da simulare
/// </summary>
public class simPar
{
/// <summary>
/// Attesa per evento
/// </summary>
public int wait = 10;
/// <summary>
/// Durata dell'evento
/// </summary>
public int duration = 1;
/// <summary>
/// DateTime ultimo evento
/// </summary>
public DateTime lastEv = DateTime.Now;
}
public class IobSimula : IobGeneric
{
/// <summary>
/// pallet corrente
/// </summary>
protected int cP = 1;
/// <summary>
/// pallet successivo (next)
/// </summary>
protected int nP = 1;
/// <summary>
/// periodo base del simulatore (in secondi)
/// </summary>
protected int periodoMSec = 1000;
/// <summary>
/// BOOL: indica se simulare powerOn/Off (bit 0 e 1) compresi WarmUp e CoolDown
/// </summary>
protected bool simPowerOnOff;
/// <summary>
/// Ora dia ccensione (standard)
/// </summary>
public int tOn = 6;
/// <summary>
/// Ora spegniemnto (standard)
/// </summary>
public int tOff = 22;
/// <summary>
/// Parametri simulazione oscillazione bit 2
/// </summary>
protected simPar bit2;
/// <summary>
/// Parametri simulazione oscillazione bit 3
/// </summary>
protected simPar bit3;
/// <summary>
/// Parametri simulazione oscillazione bit 4
/// </summary>
protected simPar bit4;
/// <summary>
/// Parametri simulazione oscillazione bit 5
/// </summary>
protected simPar bit5;
/// <summary>
/// ultimo controllo decremento eventi
/// </summary>
protected DateTime lastEvCheck;
/// <summary>
/// Durata minima ODL x reset quando pezzi iob > pezzi macchina...
/// </summary>
protected int minDurataODL = 480;
/// <summary>
/// variabile di appoggio x stato segnale contapezzo
/// </summary>
protected bool sigPzCount = false;
/// <summary>
/// Tempo di MINIMO attesa x simulazione parametri
/// </summary>
protected int waitSimPar = utils.CRI("waitSimPar");
/// <summary>
/// Ultimo istante in cui sono stati generati dati di simulazione
/// </summary>
protected DateTime lastSimData;
/// <summary>
/// estende l'init della classe base...
/// </summary>
/// <param name="caller"></param>
/// <param name="adpConf"></param>
public IobSimula(AdapterForm caller, IobConfiguration IOBConf) : base(caller, IOBConf)
{
// gestione invio ritardato contapezzi
pzCountDelay = utils.CRI("pzCountDelay");
DateTime adesso = DateTime.Now;
lastPzCountSend = adesso;
lastWarnODL = adesso;
lastEvCheck = adesso;
lastSimData = adesso;
// sistemo parametri x simulazione...
if (cIobConf.optPar.Count > 0)
{
if (!string.IsNullOrEmpty(getOptPar("PER_BASE")))
{
int.TryParse(getOptPar("PER_BASE"), out periodoMSec);
// aggiungo NOISE... +/- 20%
Random rnd = new Random();
int noise = rnd.Next(1, periodoMSec / 5);
periodoMSec += noise - (periodoMSec / 10);
}
simPowerOnOff = false;
bool.TryParse(getOptPar("SIM_POW_ON_OFF"), out simPowerOnOff);
int.TryParse(getOptPar("T_ON"), out tOn);
int.TryParse(getOptPar("T_OFF"), out tOff);
bit2 = setupSimPar("SIM_PZCNT");
bit3 = setupSimPar("SIM_ALARM");
bit4 = setupSimPar("SIM_MANU");
bit5 = setupSimPar("SIM_SLOW");
int.TryParse(getOptPar("MIN_DURATA_ODL"), out minDurataODL);
}
setParamPlc();
// ricarico da server i dati dei pezzi fatti...
lgInfo("Init contapezzi SIMULA: pzCntReload(true)");
pzCntReload(true);
// imposto pezzi CNC ai pezzi contati da server...
lastCountCNC = contapezzi;
lgInfo($"Impostazione iniziale contatori: contapezzi macchina lastCountCNC: {lastCountCNC} | contapezzi: {contapezzi}");
}
/// <summary>
/// Effettua reset del contapezzi
/// </summary>
/// <returns></returns>
public override bool resetContapezziCNC()
{
bool answ = false;
// ...SE abilitato da conf IOB
if (cIobConf.optPar.Count > 0 && getOptPar("ENABLE_PZ_RESET") == "TRUE")
{
// fingo di aver fatto...
answ = true;
}
return answ;
}
/// <summary>
/// Setup aprametri di simulazione per BIT indicato
/// </summary>
/// <param name="keyName"></param>
private simPar setupSimPar(string keyName)
{
simPar answ = new simPar();
if (cIobConf.optPar.Count > 0)
{
if (cIobConf.optPar.ContainsKey(keyName))
{
string fullVal = getOptPar(keyName);
if (!string.IsNullOrEmpty(fullVal) && fullVal.IndexOf("|") > 0)
{
string[] param = fullVal.Split('|');
int.TryParse(param[0], out answ.wait);
int.TryParse(param[1], out answ.duration);
// aggiongo noise, +/- 40%...
Random rnd = new Random();
int noise = rnd.Next(1, answ.wait * 40 / 100);
answ.wait += noise - (answ.wait * 20 / 100);
}
}
}
return answ;
}
#if false
/// <summary>
/// Setup singolo parametro
/// </summary>
/// <param name="keyName"></param>
/// <returns></returns>
private int setIntSimPar(string keyName)
{
int answ = 1;
int.TryParse(getOptPar(keyName), out answ);
// aggiongo noise, +/- 20%...
Random rnd = new Random();
int noise = rnd.Next(1, answ / 5);
answ += noise - (answ / 10);
return answ;
}
#endif
public override void tryConnect()
{
base.tryConnect();
connectionOk = true;
}
public override void tryDisconnect()
{
base.tryDisconnect();
connectionOk = false;
}
#region Metodi specifici (da verificare/completare in implementazione)
/// <summary>
/// Effettua vero processing contapezzi
/// </summary>
public override void processContapezzi()
{
}
/// <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);
// decodifica e gestione
decodeToBaseBitmap();
decodeOtherData();
reportRawInput(ref currDispData);
}
/// <summary>
/// Processo contatori eventi...
/// </summary>
public override void processVHF()
{
if (lastEvCheck.AddMilliseconds(periodoMSec) < DateTime.Now)
{
// decremento contatore ultimo evento
bit2.wait--;
bit3.wait--;
bit4.wait--;
bit5.wait--;
lastEvCheck = DateTime.Now;
}
}
/// <summary>
/// Effettua decodifica aree memoria alla bitmap usata x MAPO
/// </summary>
private void decodeToBaseBitmap()
{
// init a zero...
B_input = 0;
bool sendContapezzi = false;
/* -----------------------------------------------------
* bitmap MAPO
* B0: POWER_ON
* B1: RUN
* B2: pzCount
* B3: allarme
* B4: manuale
* B5: emergenza - non usato x ora
* B6: pallet 1 (SE doppio pallet)
* B7: pallet 2 (SE doppio pallet)
----------------------------------------------------- */
// di base macchina in RUN
B_input = 3;
/*----------------------------------------
* Simulazione segnali con priorità:
* - Power ON / OFF (bit0/1)
* - ALLARMI
* - SLOW
* - MANUALE
* - contapezzi
*
*----------------------------------------*/
// se simulo PowerOn/Off --> spegnimento con CoolDown e accensione con WarmUp..
if (simPowerOnOff)
{
DateTime adesso = DateTime.Now;
// se l'orario è dopo le tOff (tipicamente 22) --> NO RUN...
if (adesso.Hour >= tOff || adesso.Hour <= tOn)
{
// se prima/ultima mezz'ora è ancora accesa NON in run...
if (adesso.AddMinutes(-30).Hour < tOff || adesso.AddMinutes(30).Hour > tOn)
{
B_input = 1;
}
else
{
B_input = 0;
}
}
}
// in primis verifico SE posso inviare in blocco i pezzi...... SE MP online e SE NON E' MULTI
if (MPOnline && !isMulti)
{
// SE IOB online...
if (IobOnline)
{
// se il contapezzi è OLTRE il valore inviato....
if (lastCountCNC > contapezzi)
{
// invio SOLO SE sono OLTRE i numSim pz e li invio TUTTI in blocco
if ((lastCountCNC - contapezzi) > minSendPzCountBlock)
{
trySendPzCountBlock();
sigPzCount = false;
}
// altrimenti invio 1 segnale
else
{
// se NON STAVA inviando di già...
if (!sigPzCount)
{
// segnalo BIT (1 pz)
B_input += (1 << 2);
sigPzCount = true;
contapezzi++;
// invio conferma contapezzi..
string retVal = utils.callUrl($"{urlSetPzCount}{contapezzi}");
}
else
{
string retVal = utils.callUrl($"{urlSetPzCount}{contapezzi}");
sigPzCount = false;
}
}
lgInfo($"S01: Valori contatori: contapezzi macchina lastCountCNC: {lastCountCNC} | contapezzi: {contapezzi} | lastCountCNC > contapezzi");
}
}
}
// questa parte la processo SOLO SE sono in run --> B_input == 3
if (B_input == 3)
{
if (bit3.wait <= 0)
{
// segnalo BIT
B_input += (1 << 3);
// decremento duration
bit3.duration--;
// controllo se sia scaduta la duration... in quel caso reset...
if (bit3.duration <= 0)
{
bit3 = setupSimPar("SIM_ALARM");
}
}
else if (bit4.wait <= 0)
{
// segnalo BIT
B_input += (1 << 4);
// decremento duration
bit4.duration--;
// controllo se sia scaduta la duration... in quel caso reset...
if (bit4.duration <= 0)
{
bit4 = setupSimPar("SIM_MANU");
}
// in manuale: provo split ODL
trySplitOdl();
}
else if (bit5.wait <= 0)
{
// segnalo BIT
B_input += (1 << 5);
// decremento duration
bit5.duration--;
// controllo se sia scaduta la duration... in quel caso reset...
if (bit5.duration <= 0)
{
bit5 = setupSimPar("SIM_SLOW");
}
}
else if (bit2.wait <= 0)
{
// salvo nuovo contapezziPLC (incremento RAND 0..5)
var rand = new Random();
// se online vero delta altrimenti solo 0..1 50% probabilità
int delta = IobOnline ? rand.Next(1, 5) : rand.Next(0, 2);
if (!isMulti)
{
// solo se MP online...
if (MPOnline)
{
lastCountCNC += delta;
lgInfo($"S01: Valori contatori: contapezzi macchina lastCountCNC: {lastCountCNC} | contapezzi: {contapezzi} | aggiunto delta {delta}");
}
}
// SOLO SE sono online...
if (IobOnline)
{
// se multipallet --> cP a zero!
if (isMulti)
{
cP = 0;
}
// se NON Multi fa contapezzi...
else
{
// SE NON SONO GIA' OLTRE il contapezzi
if (contapezzi < lastCountCNC)
{
// segnalo BIT (1 pz)
B_input += (1 << 2);
}
}
// decremento duration
bit2.duration--;
// controllo se sia scaduta la duration... in quel caso reset...
if (bit2.duration <= 0)
{
bit2 = setupSimPar("SIM_PZCNT");
sendContapezzi = true;
// registro contapezzi
contapezzi++;
lgInfo($"S01: Valori contatori: contapezzi macchina lastCountCNC: {lastCountCNC} | contapezzi: {contapezzi} - incremento contapezzi per bit2.duration <= 0");
}
if (sendContapezzi)
{
// controllo se ALMENO sia pingabile il server
if (checkServerAlive)
{
// invio a server contapezzi (aggiornato)
string retVal = utils.callUrl(urlSetPzCount + contapezzi.ToString());
// verifica se tutto OK
if (retVal != "OK")
{
// errore salvataggio contapezzi
lgInfo(string.Format("Errore salvataggio Contapezzi SIMULAZIONE {0} | Errore salvataggio: {1}", contapezzi, retVal));
}
// resetto timer...
lastPzCountSend = DateTime.Now;
}
}
// provo a fare split ODL SE NON E' multi....
trySplitOdl();
}
}
// se multi gestisco il bit delle tavole...
if (isMulti)
{
// se sono in fase di fronte d'uscita (invio contapezzi) INVERTO nP...
if (sendContapezzi)
{
nP = nP == 1 ? 2 : 1;
// assegno a cP il valore nP...
cP = nP;
lastCountCNC++;
}
// se cP > 0 --> segnalo bit tavola...
if (cP == 1)
{
B_input += (1 << 6);
}
else if (cP == 2)
{
B_input += (1 << 7);
}
}
// init obj display
newDisplayData currDispData = new newDisplayData();
currDispData.counter = contapezzi;
currDispData.semOut = Semaforo.SV;
raiseRefresh(currDispData);
}
}
/// <summary>
/// provo a chaimare split ODL
/// </summary>
private void trySplitOdl()
{
if (!isMulti)
{
// solo se ODL è in lavorazione da ALMENO minDurataODL minuti...
DateTime inizioOdl = DateTime.Now.AddDays(-1);
string rawDataInizio = callUrl(urlInizioOdlIob, false);
DateTime.TryParse(rawDataInizio, out inizioOdl);
if (DateTime.Now.Subtract(inizioOdl).TotalMinutes > minDurataODL)
{
// invio reset ODL...
forceSplitOdl();
}
}
}
/// <summary>
/// Decodifica il resto dell'area x i dati accessori (allarmi, ...)
/// </summary>
private void decodeOtherData()
{
}
/// <summary>
/// Recupero programma in lavorazione
/// </summary>
/// <returns></returns>
public override string getPrgName()
{
// valore non presente in vers default... se gestito fare override
string prgName = string.Format("DEMO_{0:00}", DateTime.Now.Minute);
return prgName;
}
#if false
/// <summary>
/// Genera un valore random POSSIBILMENTE impiegando i valori min/max da conf memoria
/// </summary>
/// <param name="memName"></param>
/// <returns></returns>
protected string getSimVal(string memName)
{
Random rnd = new Random();
int answ = 0;
int minVal = 0;
int maxVal = 100;
if (memMap.mMapRead.ContainsKey(memName))
{
minVal = memMap.mMapRead[memName].minVal;
maxVal = memMap.mMapRead[memName].maxVal;
}
answ = rnd.Next(minVal, maxVal);
return answ.ToString();
}
#endif
/// <summary>
/// Recupero info sistema generiche
/// <returns></returns>
public override Dictionary<string, string> getSysInfo()
{
// valore non presente in vers default... se gestito fare override
Dictionary<string, string> outVal = new Dictionary<string, string>();
outVal.Add("MACHINE", "IOB_SIM");
return outVal;
}
/// <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>();
// verificare periodo SIM parametri... se passato li invio altrimenti NO... FIX a 20 sec
if (lastSimData.AddSeconds(waitSimPar) < DateTime.Now)
{
Random rnd = new Random();
// controllo conf memorie json (se ci sono...)
try
{
if (memMap.mMapWrite.Count > 0)
{
foreach (var item in memMap.mMapWrite)
{
outVal.Add(item.Key, item.Value.value);
}
}
if (memMap.mMapRead.Count > 0)
{
foreach (var item in memMap.mMapRead)
{
// uso factor come valore MAX ammesso
int randVal = rnd.Next(item.Value.minVal, item.Value.maxVal);
outVal.Add(item.Key, randVal.ToString());
}
}
}
catch
{ }
lastSimData = DateTime.Now;
}
return outVal;
}
/// <summary>
/// Recupera e processa allarmi CNC...
/// </summary>
public override Dictionary<string, string> getCncAlarms()
{
Dictionary<string, string> outVal = new Dictionary<string, string>();
return outVal;
}
#endregion
}
}