532 lines
20 KiB
C#
532 lines
20 KiB
C#
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using System.Text;
|
||
using System.Threading.Tasks;
|
||
using SCMCncLib;
|
||
using XSimGph;
|
||
using System.Windows.Forms;
|
||
using System.Threading;
|
||
using System.IO;
|
||
|
||
namespace MTC_Adapter
|
||
{
|
||
public class AdapterESA : AdapterGeneric
|
||
{
|
||
/// <summary>
|
||
/// oggetto onnessione ESA
|
||
/// </summary>
|
||
protected thdNcEsaGvKvara ncDevice;
|
||
/// <summary>
|
||
/// thread del processo comunicazione esa
|
||
/// </summary>
|
||
protected Thread thdDevice;
|
||
|
||
/// <summary>
|
||
/// estende l'init della classe base...
|
||
/// </summary>
|
||
/// <param name="caller"></param>
|
||
/// <param name="adpConf"></param>
|
||
public AdapterESA(MainForm caller, AdapterConf adpConf) : base(caller, adpConf)
|
||
{
|
||
string iniPath = string.Format(@"{0}\{1}\{2}", Application.StartupPath, utils.CRS("adapterConfPath"), utils.CRS("defaultEsaFile"));
|
||
|
||
if (utils.CRB("verbose")) lg.Info("Start init Adapter ESA dal file {0}", iniPath);
|
||
|
||
IniFiles.IniFile EsaIni = new IniFiles.IniFile(iniPath);
|
||
ncDevice = new thdNcEsaGvKvara(EsaIni);
|
||
|
||
// inizializzo posizioni assi...
|
||
prevPosAxis = new double[adpConf.nAxis];
|
||
prevDirAxis = new int[adpConf.nAxis];
|
||
|
||
// verifica avvio...
|
||
if (utils.CRB("verbose")) lg.Info("ESA: tryConnect");
|
||
tryConnect();
|
||
|
||
#if false
|
||
// avvio il thread...
|
||
if (utils.CRB("verbose")) lg.Info("ESA: try avvio thread");
|
||
// !!! 2016.05.25 verificare funzionamento thread... eventualmente portare entro metodo questo thread con suoi timing...
|
||
thdDevice = new Thread(ncDevice.Execute);
|
||
#endif
|
||
|
||
if (utils.CRB("verbose")) lg.Info("End init Adapter ESA");
|
||
}
|
||
|
||
public override void tryDisconnect()
|
||
{
|
||
base.tryDisconnect();
|
||
// disconnetto
|
||
ncDevice.Disconnect();
|
||
}
|
||
|
||
public override void tryConnect()
|
||
{
|
||
base.tryConnect();
|
||
|
||
// se non già connesso provo a connettermi...
|
||
if (!ncDevice.Connected)
|
||
{
|
||
// provo a collegarmi
|
||
if (!ncDevice.Connect())
|
||
{
|
||
//altrimenti disconnette...
|
||
ncDevice.Disconnect();
|
||
}
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Verifico connessione ESA...
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public override bool connectionOk
|
||
{
|
||
get
|
||
{
|
||
return ncDevice.Connected;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Effettuo lettura memorie strobe/status
|
||
/// </summary>
|
||
public override void getStrobeAndAckStatus()
|
||
{
|
||
base.getStrobeAndAckStatus();
|
||
}
|
||
|
||
public override void getGlobalData()
|
||
{
|
||
base.getGlobalData();
|
||
|
||
// accodo dati path in DataMonitor......
|
||
StringBuilder sb = new StringBuilder();
|
||
|
||
if (connectionOk)
|
||
{
|
||
// leggo TUTTO il blocco di memoria
|
||
inizio = DateTime.Now;
|
||
ncDevice.ReadBuffer();
|
||
if (utils.CRB("recTime")) TimingData.addResult(string.Format("R-PLC_FullMemoryRead", ncDevice.PLC_MemoryRead.Length), DateTime.Now.Subtract(inizio).Ticks);
|
||
}
|
||
else
|
||
{
|
||
lg.Error("Errore connessione mancante in getStrobeAndAckStatus");
|
||
}
|
||
|
||
// dati override feed/speed...
|
||
Byte v82 = ncDevice.PLC_MemoryAreaV[14];
|
||
Byte v83 = ncDevice.PLC_MemoryAreaV[15];
|
||
// 2 byte x speed da copiare...
|
||
byte[] tmpByte = new byte[2];
|
||
Buffer.BlockCopy(ncDevice.PLC_MemoryAreaV, 16, tmpByte, 0, 2);
|
||
short v84 = BitConverter.ToInt16(tmpByte, 0);
|
||
// lista allarmi PLC/CNC
|
||
Byte v87 = ncDevice.PLC_MemoryAreaV[19]; // Allarme CN (almeno 1?!?)
|
||
|
||
// -------------------------------------------
|
||
// recupero dati Feed/Speed/override
|
||
// FeedOver: 100% = 213 (il pannello è 0-120 --> 0-255, quindi 100% è 100/120*255=213)
|
||
FeedRateOver = Convert.ToInt16((decimal)(v82 * 100) / 213);
|
||
sb.AppendLine(string.Format("FeedRateOver: {0} %", FeedRateOver));
|
||
// SpeedOver: 50% = 128
|
||
SpeedRateOver = Convert.ToInt16((decimal)(v83 * 100) / 255);
|
||
sb.AppendLine(string.Format("SpeedRateOver: {0} %", SpeedRateOver));
|
||
// Speed S5000 OK!!!
|
||
SpeedRate = v84;
|
||
sb.AppendLine(string.Format("SpeedRate: {0} rpm", SpeedRate));
|
||
// -------------------------------------------
|
||
|
||
// da recuperare da qualche parte?!?
|
||
UnOpLoad = 0;
|
||
sb.AppendLine(string.Format("Load: {0}", UnOpLoad));
|
||
|
||
// -------------------------------------------
|
||
// recupero dati dai contatori EOK
|
||
bool needSave = false;
|
||
|
||
// ore totali accensione
|
||
int MinMaccOn = (int)ncDevice.PLC_MemoryAreaEOK[0];
|
||
int OreMaccOn = (int)ncDevice.PLC_MemoryAreaEOK[1];
|
||
istOreMaccOn = OreMaccOn + (double)MinMaccOn / 60;
|
||
needSave = procOreMaccOn(needSave);
|
||
|
||
// ore totali lavoro
|
||
int MinMaccLav = (int)ncDevice.PLC_MemoryAreaEOK[2];
|
||
int OreMaccLav = (int)ncDevice.PLC_MemoryAreaEOK[3];
|
||
istOreMaccLav = OreMaccLav + (double)MinMaccLav / 60;
|
||
needSave = procOreMaccLav(needSave);
|
||
|
||
// giri totali degli elettromandrini!
|
||
for (int i = 0; i < currAdpConf.nUnOp; i++)
|
||
{
|
||
istGiriElettrom[i] = (uint)ncDevice.PLC_MemoryAreaEOK[4 + i];
|
||
}
|
||
needSave = procGiriTotUnOp(needSave);
|
||
needSave = procNumCU(needSave);
|
||
|
||
// spostamento totale assi!
|
||
for (int i = 0; i < 3; i++)
|
||
{
|
||
// primo è metri, secondo km (moltiplico x 1000)
|
||
istDistMovAssi[i] = ncDevice.PLC_MemoryAreaEOK[8 + 2 * i] + ncDevice.PLC_MemoryAreaEOK[9 + 2 * i] * 1000;
|
||
}
|
||
needSave = procMovTotAssi(needSave);
|
||
|
||
needSave = procPartId(needSave);
|
||
needSave = procPzProd(needSave);
|
||
needSave = procNumInvAssi(needSave);
|
||
needSave = procVacPump(needSave);
|
||
needSave = procVacAct(needSave);
|
||
needSave = procLubro(needSave);
|
||
|
||
|
||
|
||
// salvo se necessario!
|
||
if (needSave) parentForm.persistXmlData();
|
||
// -------------------------------------------
|
||
|
||
|
||
// copio allarmi in vettore generale AlarFlags (dove lo gestisce)...
|
||
Buffer.BlockCopy(ncDevice.PLC_MemAreaAlarm_tmp, 0, AlarmFlags, 0, ncDevice.PLC_MemAreaAlarm_tmp.Length);
|
||
|
||
parentForm.dataMonitor = sb.ToString();
|
||
}
|
||
/// <summary>
|
||
/// Path percorso file prod
|
||
/// </summary>
|
||
protected string ScmProdFileName
|
||
{
|
||
get
|
||
{
|
||
return string.Format(@"{0}\{1}", Application.StartupPath, utils.CRS("ScmProdFile"));
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// Oggetto elenco dati produzione
|
||
/// </summary>
|
||
public datiProdSCM[] elencoDatiProd;
|
||
|
||
/// <summary>
|
||
/// leggo altri file:
|
||
/// - dati produzione
|
||
/// </summary>
|
||
public override void getSlowChangingData()
|
||
{
|
||
base.getSlowChangingData();
|
||
|
||
// carico dati x Maintenance
|
||
if (utils.CRB("verbose")) lg.Info(string.Format("Inizio caricamento file dati produzione ({0})", ScmProdFileName));
|
||
int totRighe = 0;
|
||
string linea;
|
||
// controllo se file esista, altrimenti loggo errore!
|
||
if (!File.Exists(ScmProdFileName))
|
||
{
|
||
lg.Error(string.Format("ATTENZIONE! file dati produzione ({0}) non trovato!", ScmProdFileName));
|
||
}
|
||
else
|
||
{
|
||
totRighe = File.ReadLines(ScmProdFileName).Count();
|
||
// creo un vettore della dimensione corretta... conta anche commenti tanto poi riduco...
|
||
datiProdSCM[] elencoDatiProdNew = new datiProdSCM[File.ReadLines(ScmProdFileName).Count()];
|
||
// carica da file...
|
||
System.IO.StreamReader file = new System.IO.StreamReader(ScmProdFileName);
|
||
// leggo 1 linea alla volta...
|
||
int rumRiga = 0;
|
||
while ((linea = file.ReadLine()) != null)
|
||
{
|
||
// SE non è un valore totale... lungh > 50 e 22 virgole (23 valori)
|
||
if (linea.Length > 50)
|
||
{
|
||
// comma separated!
|
||
elencoDatiProdNew[rumRiga] = decodeScmProdLine(linea, ',');
|
||
// se !=null conto!
|
||
if (elencoDatiProdNew != null) rumRiga++;
|
||
}
|
||
}
|
||
// chiudo file
|
||
file.Close();
|
||
// ora trimmo vettore al solo numero VERO degli allarmi caricati...
|
||
Array.Resize<datiProdSCM>(ref elencoDatiProdNew, rumRiga);
|
||
|
||
/*--------------------------------------------------
|
||
* Gestione verifica dati prod (naive)
|
||
* - se file curr vuoto --> inizio a popolare
|
||
* - se i 2 file hannos tessa lunghezza --> verifico +update last row
|
||
* - se nNew > nCurr --> accodo
|
||
* - se nCurr > nNew e nNew ==0 --> aggiorno last row giorno prec
|
||
* - se nCurr > nNew e nNew > 0 --> svuoto file curr e riparto
|
||
*--------------------------------------------------*/
|
||
|
||
|
||
// verifica preliminare dati da lung vettori
|
||
int nRecCur = 0;
|
||
int nRecIst = 0;
|
||
if (elencoDatiProd != null)
|
||
{
|
||
try
|
||
{
|
||
nRecCur = elencoDatiProd.Length;
|
||
}
|
||
catch
|
||
{ }
|
||
}
|
||
if (elencoDatiProdNew != null)
|
||
{
|
||
try
|
||
{
|
||
nRecIst = elencoDatiProdNew.Length;
|
||
}
|
||
catch
|
||
{ }
|
||
}
|
||
|
||
// uso un INT x delta qta da sommare...
|
||
int deltaQta = 0;
|
||
// in primis devo verificare che sia > 0 num oggetti su entrambi i vettori
|
||
if (nRecCur + nRecIst > 0)
|
||
{
|
||
// verifico se ho meno valori CURR e quindi devo accodare
|
||
if (nRecCur < nRecIst)
|
||
{
|
||
// resize vettore!
|
||
Array.Resize<datiProdSCM>(ref elencoDatiProd, nRecCur + 1);
|
||
// carico nuovo record
|
||
elencoDatiProd[nRecCur] = elencoDatiProdNew[nRecCur];
|
||
deltaQta = elencoDatiProd[nRecCur].qta;
|
||
nRecCur++;
|
||
}
|
||
else if (nRecCur == nRecIst)
|
||
{
|
||
// devo confrontare ULTIMO record Curr con equivalente record NEW x verificare se sia variato.. verifico PRG + start
|
||
bool checkName = elencoDatiProd[nRecCur - 1].fileName == elencoDatiProdNew[nRecCur - 1].fileName;
|
||
bool checkStart = elencoDatiProd[nRecCur - 1].start == elencoDatiProdNew[nRecCur - 1].start;
|
||
if (checkName && checkStart)
|
||
{
|
||
// salvo se variata quantità...
|
||
deltaQta = elencoDatiProdNew[nRecCur - 1].qta - elencoDatiProd[nRecCur - 1].qta;
|
||
elencoDatiProd[nRecCur - 1] = elencoDatiProdNew[nRecCur - 1];
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// inizio svuotando elenco eventi CURR (migliorabile leggendo da data prec?!?)
|
||
elencoDatiProd = null;
|
||
nRecCur = 0;
|
||
}
|
||
|
||
// riporto comunque ultima riga del vettore CURR (sia perché variato sia perché aggiunto)
|
||
if (nRecCur > 0)
|
||
{
|
||
string prgName = elencoDatiProd[nRecCur - 1].fileName;
|
||
prgName = prgName.Substring(prgName.LastIndexOf(@"\") + 1);
|
||
// se il mio articolo NON cambia...
|
||
if (istPathPartId[0] == prgName)
|
||
{
|
||
istPathPartCount[0] += (uint)deltaQta;
|
||
}
|
||
else
|
||
{
|
||
istPathPartId[0] = prgName;
|
||
istPathPartCount[0] = Convert.ToUInt32(elencoDatiProd[nRecCur - 1].qta);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// Processo stti macchina...
|
||
/// </summary>
|
||
public override void processStatus()
|
||
{
|
||
|
||
// HARD CODE: forzo path 1 (indice 0...)
|
||
int idxPath = 0;
|
||
|
||
// verifica macchina accesa...
|
||
Byte V73 = ncDevice.PLC_MemoryAreaV[5];
|
||
if (((StFlag8)V73).HasFlag(StFlag8.B2))
|
||
{
|
||
mPower.Value = "ON";
|
||
}
|
||
else
|
||
{
|
||
mPower.Value = "OFF";
|
||
}
|
||
|
||
// switch su EXE mode...
|
||
/*
|
||
* MODO_X V[70/71] --> byte (2-3)
|
||
* V70.2 = Modo RUN
|
||
* V70.3 = Modo FeedHold
|
||
* V71.5 = Ready
|
||
* */
|
||
Byte V70 = ncDevice.PLC_MemoryAreaV[2];
|
||
Byte V71 = ncDevice.PLC_MemoryAreaV[3];
|
||
if (((StFlag8)V70).HasFlag(StFlag8.B3))
|
||
{
|
||
vettPath[idxPath].mPathExeMode.Value = "FEEDHOLD";
|
||
}
|
||
else if (((StFlag8)V70).HasFlag(StFlag8.B2))
|
||
{
|
||
vettPath[idxPath].mPathExeMode.Value = "RUN";
|
||
}
|
||
else if (((StFlag8)V71).HasFlag(StFlag8.B5))
|
||
{
|
||
vettPath[idxPath].mPathExeMode.Value = "READY";
|
||
}
|
||
|
||
// switch su run mode...
|
||
/*
|
||
* MODO_X V[74].W --> byte (6)
|
||
* 0 = Modo NESSUNO
|
||
* 1 = Modo MANUALE
|
||
* 2 = Modo AUTOMATICO
|
||
* 3 = Modo POM
|
||
* 4 = Modo MDI
|
||
* 5 = Modo SEMIAUTOMATICO
|
||
* 6 = Modo RAP
|
||
* 7 = Modo TES
|
||
* */
|
||
uint V74 = ncDevice.PLC_MemoryAreaV[6];
|
||
switch (V74)
|
||
{
|
||
case 1:
|
||
vettPath[idxPath].mPathRunMode.Value = "EDIT";
|
||
break;
|
||
case 2:
|
||
vettPath[idxPath].mPathRunMode.Value = "AUTO";
|
||
break;
|
||
case 3:
|
||
vettPath[idxPath].mPathRunMode.Value = "REF";
|
||
break;
|
||
case 4:
|
||
vettPath[idxPath].mPathRunMode.Value = "MDI";
|
||
break;
|
||
case 5:
|
||
vettPath[idxPath].mPathRunMode.Value = "SEMIAUTO"; // JOG/JOGINC/HANDLE ?
|
||
break;
|
||
case 6:
|
||
vettPath[idxPath].mPathRunMode.Value = "RAP"; // JOG/JOGINC/HANDLE ?
|
||
break;
|
||
case 7:
|
||
vettPath[idxPath].mPathRunMode.Value = "TES"; // JOG/JOGINC/HANDLE ?
|
||
break;
|
||
case 0:
|
||
default:
|
||
vettPath[idxPath].mPathRunMode.Value = "ND"; // JOG/JOGINC/HANDLE ?
|
||
break;
|
||
}
|
||
}
|
||
|
||
public override void getUnOp()
|
||
{
|
||
base.getUnOp();
|
||
|
||
// cicl su UnOp
|
||
for (int i = 0; i < currAdpConf.nUnOp; i++)
|
||
{
|
||
vettUnOp[i].mUnOpToolId.Value = (int)ncDevice.PLC_MemoryAreaEOK[31];
|
||
}
|
||
}
|
||
|
||
public override void getPath()
|
||
{
|
||
base.getPath();
|
||
}
|
||
|
||
public override void getAxis()
|
||
{
|
||
base.getAxis();
|
||
|
||
// mostro assi in DataMonitor......
|
||
StringBuilder sb = new StringBuilder();
|
||
|
||
// nuova posizione (per calcoli)
|
||
double newPos = 0;
|
||
double distPerc = 0;
|
||
int newDir = 0;
|
||
|
||
// leggo in modo "cablato" i dati dei vari assi...
|
||
for (int i = 0; i < currAdpConf.nAxis; i++)
|
||
{
|
||
|
||
// in base a indice scelgo valore posizione e load
|
||
switch (i)
|
||
{
|
||
case 0:
|
||
newPos = (double)BitConverter.ToInt32(BitConverter.GetBytes(ncDevice.PLC_MemoryRead[240]), 0);
|
||
break;
|
||
case 1:
|
||
newPos = (double)BitConverter.ToInt32(BitConverter.GetBytes(ncDevice.PLC_MemoryRead[241]), 0);
|
||
break;
|
||
case 2:
|
||
newPos = (double)BitConverter.ToInt32(BitConverter.GetBytes(ncDevice.PLC_MemoryRead[242]), 0);
|
||
break;
|
||
case 3:
|
||
newPos = (double)BitConverter.ToInt32(BitConverter.GetBytes(ncDevice.PLC_MemoryRead[243]), 0);
|
||
break;
|
||
case 4:
|
||
newPos = (double)BitConverter.ToInt32(BitConverter.GetBytes(ncDevice.PLC_MemoryRead[244]), 0);
|
||
break;
|
||
case 5:
|
||
newPos = (double)BitConverter.ToInt32(BitConverter.GetBytes(ncDevice.PLC_MemoryRead[245]), 0);
|
||
break;
|
||
default:
|
||
// valPos = posAssi.p1;
|
||
// valLoad = loadAssi.svload1;
|
||
break;
|
||
}
|
||
|
||
// popolo valori...
|
||
//vettAxis[i].mAxLoad.Value = (double)(valLoad.data) / Math.Pow(10, valLoad.dec);
|
||
vettAxis[i].mAxPosAct.Value = newPos;
|
||
//vettAxis[i].mAxPosTgt.Value = newPos + (double)(valPos.dist.data) / Math.Pow(10, valPos.dist.dec);
|
||
|
||
if (utils.CRB("verbose"))
|
||
{
|
||
sb.AppendLine(string.Format("Asse {0}: PosAct:{1:N3}, ToGo:{2:N3}{3}", i, (double)(newPos) / utils.CRI("fattdecimale"), i, 0));
|
||
}
|
||
|
||
vettAxis[i].mAxFeedAct.Value = FeedRate;
|
||
|
||
// calcolo distanza e salvo valore...
|
||
distPerc = newPos - prevPosAxis[i];
|
||
|
||
// sistemo direzione +/- (POS/NEG se lineari, CCW/CW se rotativi)
|
||
if (distPerc != 0)
|
||
{
|
||
newDir = Convert.ToInt32(distPerc / Math.Abs(distPerc));
|
||
}
|
||
else
|
||
{
|
||
newDir = prevDirAxis[i];
|
||
}
|
||
vettAxis[i].mAxDir.Value = newDir;
|
||
|
||
// se la direzione è variata salvo il cambio direzione...
|
||
if (newDir != prevDirAxis[i])
|
||
{
|
||
// salvo "+1" come cambi direzione
|
||
istNumInvAssi[i]++;
|
||
}
|
||
|
||
// salvo valori vettore prec...
|
||
prevPosAxis[i] = newPos;
|
||
prevDirAxis[i] = newDir;
|
||
|
||
//vettAxis[i].mAxMainProc.Value = AxData.AxisMainProc;
|
||
//vettAxis[i].mAxIsMaster.Value = AxData.AxisIsMaster;
|
||
//vettAxis[i].mAxMastId.Value = AxData.AxisMastId;
|
||
//vettAxis[i].mAxFeedOver.Value = AxData.AxisFeedOver;
|
||
//vettAxis[i].mAxAccelAct.Value = AxData.AxisAccel;
|
||
//vettAxis[i].mAxBattery.Value = AxData.AxisBattery;
|
||
}
|
||
|
||
parentForm.dataMonitor += sb.ToString();
|
||
}
|
||
}
|
||
}
|