Files
2025-05-29 17:32:41 +02:00

787 lines
31 KiB
C#

using CndexLinkDotNet;
using EgwProxy.OsaiCncLib;
using IOB_UT_NEXT;
using IOB_UT_NEXT.Config;
using MapoSDK;
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.NetworkInformation;
namespace IOB_WIN_OSAI.Iob
{
public class OSAI : Iob.GenericNext
{
#region Public Fields
/// <summary>
/// Vettore degli allarmi CNC attivi
/// </summary>
public Dictionary<string, string> allarmiCNC = new Dictionary<string, string>();
/// <summary>
/// Stato corrente (da classe ENUM)
/// </summary>
public CNC_STATUS_OSAI currStatus;
#endregion Public Fields
#region Public Constructors
/// <summary>
/// estende l'init della classe base...
/// </summary>
/// <param name="caller">Form chiamante</param>
/// <param name="IobConfNew">Configurazione (v 4.x)</param>
public OSAI(AdapterFormNext caller, IobConfTree IobConfNew) : base(caller, IobConfNew)
{
// gestione invio ritardato contapezzi
lastPzCountSend = DateTime.Now;
lastWarnODL = DateTime.Now;
if (IOBConfFull != null)
{
signLUT = IOBConfFull.Device.SigLUT;
#if false
// inizializzo correttamente aree memoria secondo CONF - iniFileName
if (!string.IsNullOrEmpty(IOBConf.iniFileName))
{
IniFile fIni = new IniFile(IOBConf.iniFileName);
// fix enable prgName
enablePrgName = fIni.ReadBoolean("CNC", "GETPRGNAME", true);
// effettuo lettura della conf sigLUT... cercando 1:1 i bit...
string currBit = "";
string memArea = "";
for (int i = 0; i < 8; i++)
{
currBit = string.Format("BIT{0}", i);
memArea = fIni.ReadString("MEMORY", currBit, "");
// se trovo un valore...
if (!string.IsNullOrEmpty(memArea))
{
signLUT.Add(currBit, memArea);
}
}
}
#endif
}
// è little endian (NON serve conversione)
hasBigEndian = false;
lgInfoStartup($"Start init Adapter OSAI, tipo all'IP/NOME {IOBConfFull.Device.Connect.IpAddr}, variante {IOBConfFull.General.IobType} per IOB {IOBConfFull.General.CodIOB}");
// Creo oggetto x gestione connessione/comunicazione NC: secondo il tipo creo CNDEX o OPEN
parentForm.commPlcActive = true;
if (IOBConfFull.General.IobType == tipoAdapter.OSAI_OPEN)
{
OSAI_ref = new Open_Series(IOBConfFull.Device.Connect.IpAddr, false);
}
else if (IobConfNew.General.IobType == tipoAdapter.OSAI_VB6)
{
OSAI_ref = new ComCNOSAIVB6(IOBConfFull.Device.Connect.IpAddr, false);
}
else
{
OSAI_ref = new ComCNOsai(IOBConfFull.Device.Connect.IpAddr, false);
}
parentForm.commPlcActive = false;
if (isVerboseLog)
{
lgInfo($"INIT OSAI_ref da EgwProxy.MultiCncLib come {IOBConfFull.General.IobType}");
}
// disconnetto e connetto...
if (isVerboseLog)
{
lgInfo("OSAI: tryDisconnect");
}
tryDisconnect();
lgInfo("OSAI: tryConnect");
tryConnect();
// recupero machine status e mode da cui decodificare info sul PLC...
byte machineStatus = OSAI_ref.GetMachineStatus();
byte modeSelected = OSAI_ref.GetModeSelected();
lgInfo(string.Format("Lettura preliminare: machineStatus={0} | modeSelected={1}", machineStatus, modeSelected));
// possiamo leggere tutto da qui che contiene status, mode e last_nc_error
oData = new Cndex.GETINFO1DATA();
var ncInfo = OSAI_ref.NcInfo1(ref oData);
lgInfo(string.Format("Lettura START completa NCINFO1DATA{0} lastNcError={1}{0}status={2}{0}substatus={9}{0}mode_select={3}{0}main_progr_name={4}{0}speed_ov={5}{0}progr_speed={6}{0}real_speed={7}{0}real_feed={8}{0}", Environment.NewLine, oData.last_nc_error, oData.status, oData.mode_select, oData.main_progr_name, oData.speed_ov, oData.progr_speed, oData.real_speed, oData.real_feed, oData.substatus));
// inizio il calcolo dello status semaforico
short bitStatus = 0;
if (OSAI_ref.Connected)
{
bitStatus += 1;
}
if (utils.CRB("enableContapezzi"))
{
lgInfo("OSAI: inizio gestione contapezzi");
try
{
// verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con
// indicazione area)
if (IobConfNew.OptPar.Count > 0 && !string.IsNullOrEmpty(IOBConfFull.Device.PzCountMode))
{
if (IOBConfFull.Device.PzCountMode.StartsWith("OVAR"))
{
lgInfo("Init contapezzi OSAI: pzCntReload(true)");
pzCntReload(true);
// refresh associazione Macchina - IOB
SendM2IOB();
// invio altri dati accessori...
SendMachineConf();
// per adesso imposto lettura dal CNC == contapezzi (poi farà vera lettura...)
contapezziPLC = contapezziIOB;
}
else
{
contapezziIOB = 0;
lgInfo("Contapezzi STD disabilitato: modalità {0}", IOBConfFull.Device.PzCountMode);
}
}
else
{
contapezziIOB = 0;
lgInfo("Parametro mancante PZCOUNT_MODE");
}
}
catch (Exception exc)
{
lgError(exc, "Errore in contapezzi OSAI");
}
}
// finisco INIT ADAPTER
lgInfo("End init Adapter OSAI");
}
#endregion Public Constructors
#region Public Methods
/// <summary>
/// Recupera e processa allarmi CNC...
/// </summary>
public override Dictionary<string, string> getCncAlarms()
{
Dictionary<string, string> outVal = new Dictionary<string, string>();
// se ho allarmi li accodo...
if (oData.last_nc_error != 0)
{
try
{
outVal.Add("CNC_ALARM", (oData.last_nc_error).ToString());
}
catch (Exception exc)
{
lgError(exc, "Eccezione in getCncAlarms");
}
}
return outVal;
}
/// <summary>
/// Recupero dati dinamici...
/// </summary>
public override Dictionary<string, string> getDynData()
{
Dictionary<string, string> outVal = new Dictionary<string, string>();
sw.Restart();
try
{
string actf = oData.real_feed.ToString();
string acts = oData.real_speed.ToString();
outVal.Add("DYNDATA", string.Format("FEED {0}#SPEED_RPM {1}", actf, acts));
if (utils.CRB("SendFeedSpeed"))
{
outVal.Add("FEED", actf);
outVal.Add("SPEED_RPM", acts);
//outVal.Add("NUM_ALARM", numAlarm);
outVal.Add("ACT_TOOL", oData.actual_tool.ToString());
}
if (utils.CRB("SendAxPos"))
{
// salvo info assi...
outVal.Add("AX_SEL", oData.ax_sel.ToString());
outVal.Add("NUM_AX_SEL", oData.num_ax_sel.ToString());
}
}
catch (Exception exc)
{
lgError(exc, "Errore in getDynData");
}
sw.Stop();
return outVal;
}
/// <summary>
/// Recupero dati override (da area G che è già stata letta...)
/// </summary>
/// <returns></returns>
public override Dictionary<string, string> getOverrides()
{
Dictionary<string, string> outVal = new Dictionary<string, string>();
outVal.Add("FEED_OVER", (oData.feed_ov).ToString());
outVal.Add("RAPID_OVER", (oData.rapid_override).ToString());
return outVal;
}
/// <summary>
/// Recupero programma in lavorazione
/// </summary>
/// <returns></returns>
public override string getPrgName()
{
string prgName = "";
// recupero NUOVO prgName...
try
{
// recupero nome programma MAIN
prgName = System.Text.Encoding.Default.GetString(oData.main_progr_name);
// trimmo path del programma, ovvero "CNCMEMUSERPATH1"
prgName = prgName.Replace(utils.CRS("basePrgMemPath"), "");
lgInfo("Current PROG: {0}", prgName);
}
catch (Exception exc)
{
lgError(string.Format("Eccezione in recupero PRG NAME MAIN:{0}{1}", Environment.NewLine, exc));
connectionOk = false;
}
return prgName;
}
/// <summary>
/// Effettua vero processing contapezzi appoggiato ad area specifica da CONF
/// </summary>
public override void processContapezzi()
{
if (utils.CRB("enableContapezzi"))
{
try
{
// verifico quale modalità sia richiesta: STD (6711) oppure BIT (Custom, con
// indicazione area)
if (IOBConfFull.OptPar.Count > 0 && !string.IsNullOrEmpty(IOBConfFull.Device.PzCountMode))
{
string memAddr = IOBConfFull.Device.PzCountMode;
if (memAddr.StartsWith("STD"))
{
// inizio verifica area memoria/parametro levando prima parte codice
memAddr = memAddr.Replace("STD.", "");
// var di appoggio
int cntAddr = 0;
// verifico se si tratta di lettura MEMORIA... formato tipo STD.MEM.6711
if (memAddr.StartsWith("MEM."))
{
// recupero parametro...
int.TryParse(memAddr.Replace("MEM.", ""), out cntAddr);
if (cntAddr == 0)
{
cntAddr = 29;
}
// processo parametro contapezzi (lavorati)
sw.Restart();
// vera lettura area memoria...
int resVal = 0;
// lettura variabili (es contapezzi)
resVal = (int)OSAI_ref.ReadVarSN((short)cntAddr);
if (utils.CRB("recTime"))
{
TimingData.addResult(IOBConfFull.General.CodIOB, string.Format("R{0}-MEM", 2), sw.ElapsedTicks);
}
// aggiungo in visualizzazione SE variata...
if (resVal != contapezziPLC)
{
string mCount = string.Format("MEM{0}", cntAddr);
string sVal = string.Format("[PZCOUNT]{0}|{1}", mCount, resVal);
// chiamo accodamento...
bool sent = accodaFLog(mCount, sVal, qEncodeFLog(mCount, $"{resVal}"));
if (sent)
{ // traccio valore DynData x analisi
trackDynData(mCount, $"{resVal}");
}
}
// salvo ultimo conteggio rilevato
contapezziPLC = resVal;
}
sw.Stop();
}
}
}
catch (Exception exc)
{
lgError(exc, "Errore in contapezzi CNC");
connectionOk = false;
}
}
}
/// <summary>
/// Esegue processing MODE (e nel contempo recupera altri dati dell'area G)
/// </summary>
public override void processMode()
{
if (utils.CRB("enableMode"))
{
try
{
// verifico modo con valore corrente, se cambia aggiorno...
CNC_MODE newMode = decodeModeOsai(oData.mode_select);
if (newMode != currMode)
{
// aggiorno!
currMode = newMode;
// conversione NUM MODE in descrizione da ENUM
string descrMode = Enum.GetName(typeof(CNC_MODE), currMode);
// accodo x invio
string sVal = string.Format("[CNC_MODE]{0}", descrMode);
// chiamo accodamento...
bool sent = accodaFLog("CNC_MODE", sVal, qEncodeFLog("CNC_MODE", descrMode));
if (sent)
{ // traccio valore DynData x analisi
trackDynData("CNC_MODE", descrMode);
}
}
}
catch (Exception exc)
{
lgError(exc, string.Format("Errore in process Mode OSAI: {0}{1}", Environment.NewLine, exc));
connectionOk = false;
sw.Stop();
}
}
// lo status lo processo SEMPRE
try
{
// verifico modo con valore corrente, se cambia aggiorno...
CNC_STATUS_OSAI newStatus = (CNC_STATUS_OSAI)(oData.status);
if (newStatus != currStatus)
{
// aggiorno!
currStatus = newStatus;
// accodo x invio
string sVal = string.Format("[CNC_STATUS]{0}", $"{currStatus}");
// chiamo accodamento...
bool sent = accodaFLog("CNC_STATUS", sVal, qEncodeFLog("CNC_STATUS", $"{currStatus}"));
if (sent)
{ // traccio valore DynData x analisi
trackDynData("CNC_STATUS", $"{currStatus}");
}
}
}
catch (Exception exc)
{
lgError(exc, string.Format("Errore in process Mode OSAI: {0}{1}", Environment.NewLine, exc));
connectionOk = false;
sw.Stop();
}
}
/// <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;
sw.Restart();
// possiamo leggere tutto da qui che contiene tutto: status, mode, last_nc_error
var ncInfo = OSAI_ref.NcInfo1(ref oData);
// time rec
if (utils.CRB("recTime"))
{
TimingData.addResult(IOBConfFull.General.CodIOB, "GETINFO1DATA", sw.ElapsedTicks);
}
sw.Stop();
// salvo il solo BYTE dell'input decifrando il semaforo...
decodeToBitmap();
}
catch (Exception exc)
{
lgError(string.Format("Eccezione in readSemafori:{0}{1}", Environment.NewLine, exc));
connectionOk = false;
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("OSAI: ConnKO - tryConnect");
}
// PING SOLO x OPEN!!!
bool needPing = (IOBConfFull.General.IobType == tipoAdapter.OSAI_OPEN);
bool pingOk = false;
Ping pingSender = new Ping();
PingReply reply = pingSender.Send("127.0.0.1", 100);
// se serve PING...
if (needPing)
{
// in primis salvo data ping...
lastPING = DateTime.Now;
// ora PING!!!
IPAddress address = IPAddress.Loopback;
IPAddress.TryParse(IOBConfFull.Device.Connect.PingIpAddr, out address);
try
{
// se != null --> uso address...
if (address != null)
{
reply = pingSender.Send(address, 100);
}
else
{
reply = pingSender.Send(IOBConfFull.Device.Connect.IpAddr, 100);
}
}
catch
{
reply = pingSender.Send(IPAddress.Loopback, 100);
}
pingOk = reply.Status == IPStatus.Success;
}
// se passa il ping faccio il resto...
if (pingOk || !needPing)
{
string szStatusConnection = "";
try
{
// ora provo connessione...
parentForm.commPlcActive = true;
bool fatto = OSAI_ref.OpenSession();
if (!fatto)
{
// log errore!
lgInfo("Impossibile effettuare apertura sessione: " + OSAI_ref.ErrMsg);
}
parentForm.commPlcActive = false;
lgInfo("szStatusConnection: " + szStatusConnection);
connectionOk = true;
// refresh stato allarmi!!!
if (connectionOk)
{
dtAvvioAdp = DateTime.Now;
queueInEnabCurr = true;
if (adpRunning)
{
lgInfo("Connessione OK");
}
}
else
{
lgError("Impossibile procedere, connessione mancante...");
}
}
catch (Exception exc)
{
lgFatal($"Errore nella connessione all'adapter OSAI: {szStatusConnection}{Environment.NewLine}{exc}");
connectionOk = false;
lgInfo($"Eccezione in TryConnect, Adapter NON running, pausa di {utils.CRI("waitRecMSec")} msec prima di ulteriori tentativi di riconnessione");
}
}
else
{
// loggo no risposta ping ...
connectionOk = false;
if (needPing)
{
if (verboseLog || periodicLog)
{
lgInfo($"Attenzione: controllo PING fallito per IP {IOBConfFull.Device.Connect.PingIpAddr} - {reply.Status}");
}
}
}
}
}
// 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
{
OSAI_ref.CloseSession();
connectionOk = false;
// resetto timing!
TimingData.resetData();
lgInfo(szStatusConnection);
lgInfo("Effettuata disconnessione adapter OSAI!");
}
catch (Exception exc)
{
lgFatal(exc, "Errore nella disconnessione dall'adapter OSAI");
}
}
else
{
lgError("IMPOSSIBILE effettuare disconnessione: Connessione non disponibile...");
}
queueInEnabCurr = false;
}
#endregion Public Methods
#region Protected Fields
/// <summary>
/// Struttura dati principale in continuo update...
/// </summary>
protected Cndex.GETINFO1DATA oData;
/// <summary>
/// Oggetto MAIN x connessione OSAI
/// </summary>
protected ComCNOsai OSAI_ref;
#endregion Protected Fields
#region Protected Methods
/// <summary>
/// Decodifica del MODE selezionato
/// </summary>
/// <param name="mode"></param>
/// <returns></returns>
protected static CNC_MODE decodeModeOsai(int mode)
{
CNC_MODE answ = CNC_MODE.ND;
switch (mode)
{
case 1:
answ = CNC_MODE.MDI;
break;
case 2:
answ = CNC_MODE.AUTO;
break;
case 3:
answ = CNC_MODE.SEMI;
break;
case 4:
answ = CNC_MODE.JOG_MAN;
break;
case 5:
answ = CNC_MODE.JOG_INC;
break;
case 6:
answ = CNC_MODE.PROFILE;
break;
case 7:
answ = CNC_MODE.HOME;
break;
case 8:
answ = CNC_MODE.HANDLE_INC;
break;
default:
break;
}
return answ;
}
#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 decodeToBitmap()
{
// init a zero...
B_input = 0;
// SE SI E' CONNESSO al CNC allora è 1=powerON...
if (OSAI_ref.Connected)
{
B_input += 1 << 0;
}
// decodifico impiegando dictionary... cercando il TIPO di memoria & co...
string bKey = "";
string bVal = "";
for (int i = 0; i < 8; i++)
{
bKey = string.Format("BIT{0}", i);
// cerco se ci sia in LUT
if (signLUT.ContainsKey(bKey))
{
// recupero nome variabile...
bVal = signLUT[bKey];
// se l'area è PZCOUNT... processo PUNTUALMENTE il CONTAPEZZI...
if (bVal.StartsWith("PZCOUNT"))
{
// 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("Osai | Lettura ODL andata a vuoto: currODL: {0}", currODL));
}
}
else
{
lgInfo(string.Format("Osai | 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($"OSAI | Lettura ODL non effettuata: IobOnline: {IobOnline} | currODL impostato a vuoto");
}
}
if (!string.IsNullOrEmpty(currODL) && currODL != "0")
{
// controllo se è passato intervallo minimo tra 2 controlli/elaborazioni
// x distanziare invio e ridurre letture
if (DateTime.Now >= lastPzCountSend.AddMilliseconds(pzCountDelay))
{
// se sono differenti MOSTRO...
if (contapezziPLC != contapezziIOB)
{
// registro contapezzi
lgInfo($"Differenza Contapezzi: contapezziPLC: {contapezziPLC} | contapezziIOB {contapezziIOB}");
}
// verifico se variato contapezzi in area STD PAR6711... e se
// passato ritardo minimo...
if (contapezziPLC > contapezziIOB)
{
// salvo nuovo contapezzi (incremento di 1...) + richiesta
// refresh conteggio
contapezziIOB++;
needRefreshPzCount = true;
// salvo in semaforo!
B_input += 1 << 2;
// registro contapezzi
lgInfo($"contapezziPLC OSAI: {contapezziPLC} | contapezziIOB {contapezziIOB}");
}
// invio a server contapezzi (aggiornato)
string retVal = utils.callUrl(urlSetPzCount + contapezziIOB.ToString());
// verifica se tutto OK
if (retVal != contapezziIOB.ToString())
{
// errore salvataggio contapezzi
lgInfo($"Errore salvataggio Contapezzi OSAI: contapezziPLC {contapezziPLC} | contapezziIOB {contapezziIOB} | risposta: {retVal}");
// rileggo il counter pezzi da server
pzCntReload(true);
}
// resetto timer...
lastPzCountSend = DateTime.Now;
}
}
else
{
if (DateTime.Now >= lastPzCountSend.AddMilliseconds(pzCountDelay))
{
lgInfo($"Attenzione: mancanza ODL non procedo con gestione contapezzi. contapezziPLC OSAI: {contapezziPLC} | contapezziIOB {contapezziIOB}");
// resetto timer...
lastPzCountSend = DateTime.Now;
}
}
}
// controllo le condizioni x costruire il bit1 RUN!
if (oData.mode_select == 2 && oData.status == 2)
{
B_input += 1 << 1;
}
// errore su bit3
if (oData.mode_select == 6)
{
B_input += 1 << 3;
}
// auto su bit4
if (oData.mode_select != 2)
{
B_input += 1 << 4;
}
// emergenza su bit5
if (oData.mode_select == 9)
{
B_input += 1 << 5;
}
}
}
// log opzionale!
if (verboseLog)
{
lgInfo(string.Format("Trasformazione B_input: {0}", B_input));
}
}
#endregion Private Methods
}
}