Files
CMS-MTConn/MTC_Sim/MTC_Sim/AdapterFanuc.cs
T
Samuele E. Locatelli 17fcf6e1ba Riorganizzata gestione code M/S/T (codice condiviso)
Aggiunti nuovi strobe x START/STOP/RESET nelle conf
2016-05-13 10:13:22 +02:00

503 lines
19 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CMSCncLib.CNC;
namespace MTC_Sim
{
public class AdapterFanuc : AdapterGeneric
{
protected FANUC FANUC_ref;
/// <summary>
/// estende l'init della classe base...
/// </summary>
/// <param name="caller"></param>
/// <param name="adpConf"></param>
public AdapterFanuc(CMS_MachineSim caller, AdapterConf adpConf) : base(caller, adpConf)
{
Runtime.CreateNC();
FANUC_ref = (FANUC)Runtime.NC;
// disconnetto e connetto...
tryDisconnect();
tryConnect();
}
public override void tryDisconnect()
{
if (connectionOk)
{
string szStatusConnection = "";
try
{
FANUC_ref.Disconnect(ref szStatusConnection);
lg.Info(szStatusConnection);
lg.Info("Effettuata disconnessione adapter FANUC!");
}
catch (Exception exc)
{
lg.Fatal(exc, "Errore nella disconnessione dall'adapter FANUC");
}
}
else
{
lg.Error("IMPOSSIBILE effettuare disconnessione: Connessione non disponibile...");
}
}
public override void tryConnect()
{
if (!connectionOk)
{
string szStatusConnection = "";
try
{
FANUC_ref.Connect(ref szStatusConnection);
lg.Info(szStatusConnection);
// refresh stato allarmi!!!
if (connectionOk)
{
// carico status allarmi (completo)
lg.Info("Inizio refresh completo stato allarmi...");
StFlag32 forceAlarm = (StFlag32)unchecked((int)UInt32.MaxValue);
refreshAlarmState(forceAlarm, false);
lg.Info("Completato refresh completo stato allarmi!");
if (utils.CRB("recTime")) logTimeResults();
}
else
{
lg.Error("Impossibile effettuare refresh completo stato allarmi, connessione mancante...");
}
}
catch (Exception exc)
{
lg.Fatal(exc, "Errore nella connessione all'adapter FANUC", szStatusConnection);
}
}
}
/// <summary>
/// Verifico connessione fanuc...
/// </summary>
/// <returns></returns>
public override bool connectionOk
{
get
{
return FANUC_ref.Connected;
}
}
/// <summary>
/// Effettuo lettura dei 16 byte di strobe/status
/// </summary>
public override void getStrobeAndAckStatus()
{
base.getStrobeAndAckStatus();
if (connectionOk)
{
// leggo TUTTO ack e strobe,
byte[] MemBlock = new byte[Strobes.Length + Acknowl.Length];
int memIndex = 10500;
DateTime inizio = DateTime.Now;
FANUC_ref.F_RW_Byte(R, FANUC.MemType.R, memIndex, ref MemBlock);
if (utils.CRB("recTime")) TimingData.addResult(string.Format("R{0}-STROBES", MemBlock.Length), DateTime.Now.Subtract(inizio).Ticks);
// suddivido!
Buffer.BlockCopy(MemBlock, 0, Acknowl, 0, Acknowl.Length);
Buffer.BlockCopy(MemBlock, Acknowl.Length, Strobes, 0, Strobes.Length);
}
else
{
lg.Error("Errore connessione mancante in getStrobeAndAckStatus");
}
#if false
// hard coded: leggo le 16 word standard dello strobe... R10500--> R10515
FANUC_ref.F_RW_Byte(R, FANUC.MemType.R, 10500, ref Acknowl);
// hard coded: leggo le 16 word standard dello strobe... R10516--> R10532
FANUC_ref.F_RW_Byte(R, FANUC.MemType.R, 10516, ref Strobes);
#endif
}
/// <summary>
/// processing strobe!
/// </summary>
public override void processStrobe()
{
base.processStrobe();
// !!!FARE!!! multipath...
// verifico i vari strobe x recuperare i dati... PER ORA SOLO DW1 per path1 (indice 0)...
int idxPath = 0;
int memIndex = 0;
DateTime inizio = DateTime.Now;
// byte di acknowledge...
byte[] retACK_DW1 = new byte[4];
// controllo TUTTI i flag: se ce ne sono di alzati DEVO processare...
if (STRB_DW1 != StFlag32.NONE)
{
// blocco memoria x lettura TUTTI i dati di buffer M/S/T: 46 byte: 2byte (16bit) x (11+6+6) aree
byte[] MemBlock = new byte[46];
// leggo tutto!!!
memIndex = 10660;
inizio = DateTime.Now;
FANUC_ref.F_RW_Byte(R, FANUC.MemType.R, memIndex, ref MemBlock);
if (utils.CRB("recTime")) TimingData.addResult(string.Format("R{0}-STRB_DW1", MemBlock.Length), DateTime.Now.Subtract(inizio).Ticks);
// check COD_M
gestStrobeCodMST(0, ref retACK_DW1, 0, MemBlock, "M");
// check COD_S
gestStrobeCodMST(1, ref retACK_DW1, 11, MemBlock, "S");
// check COD_T
gestStrobeCodMST(2, ref retACK_DW1, 17, MemBlock, "T");
}
else
{
// se mi sono rimasti degli strobe di lettura allarmi alzati li abbasso
if (ACK_DW1 != StFlag32.NONE)
{
// inizializzo 4 byte a zero!!!
retACK_DW1 = new byte[4];
}
}
memIndex = 10504;
// scrivo update ad ack SE VARIATO!!!
if (ACK_DW1 != (StFlag32)BitConverter.ToUInt32(retACK_DW1, 0))
{
inizio = DateTime.Now;
FANUC_ref.F_RW_Byte(W, FANUC.MemType.R, memIndex, ref retACK_DW1);
if (utils.CRB("recTime")) TimingData.addResult(string.Format("W{0}-DW1", retACK_DW1.Length), DateTime.Now.Subtract(inizio).Ticks);
}
}
/// <summary>
/// Gestione STROBE --> ACK per codici M/S/T
/// </summary>
/// <param name="bitNum">0/1/2</param>
/// <param name="retACK_DW1">vettore da restituire di ACK</param>
/// <param name="memShift">shift memoria x buffer dati da leggere</param>
/// <param name="MemBlock">Vettore completo dei valori + buffer code M/S/T</param>
/// <param name="Coda">Quale coda: M/S/T</param>
private void gestStrobeCodMST(int bitNum, ref byte[] retACK_DW1, int memShift, byte[] MemBlock, string Coda)
{
int numEv = 0;
int codEv = 0;
if (STRB_DW1.HasFlag((StFlag32)Math.Pow(2, bitNum)))
{
// verifico sia > 0 il numero di valori da leggere indice 0 sull'area...
numEv = BitConverter.ToUInt16(MemBlock, 2 * memShift);
if (numEv > 0)
{
// il num ev rappresenta quanti slot 16bit (da 2 byte) sono stati valorizzati, VA FATTO CICLO E LETTI TUTTI
for (int i = 0; i < numEv; i++)
{
// leggo valore Codice
codEv = BitConverter.ToUInt16(MemBlock, 2 * (i + 1 + memShift));
// accodo evento Codice
appendCodeMST(Coda, codEv.ToString());
}
}
// memorizzo allarme nel vettore ack....
retACK_DW1 = utils.setBitOnStFlag(retACK_DW1, 1, bitNum);
}
}
/// <summary>
/// recupera allarmi ed agiorna strobe (privato) degli allarmi
/// </summary>
/// <param name="Alarm2Refresh">32bit mask degli allarmi da aggiornare</param>
/// <param name="giveAck">boolean: se si debba tornare ACK</param>
public override void refreshAlarmState(StFlag32 Alarm2Refresh, bool giveAck)
{
base.refreshAlarmState(Alarm2Refresh, giveAck);
// byte di acknowledge...
byte[] retACK_DW0 = new byte[4];
// inizio impostando una bitmap x ACK che abbia i bit abbassati se lo strobe è disattivo: AND logico tra STR e ACK
retACK_DW0 = BitConverter.GetBytes(Convert.ToUInt32(STRB_DW0 & ACK_DW0));
if (Alarm2Refresh != StFlag32.NONE) lg.Info("Richiesto refresh allarmi x bitmask: {0}", utils.binaryForm((int)Alarm2Refresh));
DateTime inizio = DateTime.Now;
byte[] MemBlock;
// primo blocco memoria allarmi
int memIndex = 10532;
// controllo, SE devo leggere tutto uso un unico accesso ai 128byte, altrimenti leggo a blocchi di 32bit...
if (Alarm2Refresh == (StFlag32)unchecked((int)UInt32.MaxValue))
{
// blocco memoria x lettura dati COMPLETO (4Byte*32 = 128Byte)
MemBlock = new byte[128];
// recupero tutti i 32 bit del blocco
inizio = DateTime.Now;
FANUC_ref.F_RW_Byte(R, FANUC.MemType.R, memIndex, ref MemBlock);
if (utils.CRB("recTime")) TimingData.addResult(string.Format("R{0}-STRB_DW0", MemBlock.Length), DateTime.Now.Subtract(inizio).Ticks);
// aggiorno vettore allarmi x intero!
Buffer.BlockCopy(MemBlock, 0, AlarmFlags, 0, MemBlock.Length);
}
else
{
if (Alarm2Refresh != StFlag32.NONE)
{
// blocco memoria x lettura dati
MemBlock = new byte[4];
// verifico gli allarmi di tutti i bit alzati...
for (int i = 0; i < 32; i++)
{
if (Alarm2Refresh.HasFlag((StFlag32)Math.Pow(2, i)))
{
// recupero tutti i 32 bit del blocco
inizio = DateTime.Now;
FANUC_ref.F_RW_Byte(R, FANUC.MemType.R, memIndex + i * 4, ref MemBlock);
if (utils.CRB("recTime")) TimingData.addResult(string.Format("R{0}-STRB_DW0", MemBlock.Length), DateTime.Now.Subtract(inizio).Ticks);
// da testare metodo copia alternativo !!!FARE!!!
if (true)
{
// aggiorno nel vettore allarmi i byte interessati
for (int j = 0; j < 4; j++)
{
// copy array o byte?!? !!!FARE!!! verifica
AlarmFlags[i * 4 + j] = MemBlock[j];
}
}
else
{
Buffer.BlockCopy(MemBlock, i, AlarmFlags, i, MemBlock.Length);
}
// segnalo allarme letto! memorizzo allarme nel vettore ack....
retACK_DW0 = utils.setBitOnStFlag(retACK_DW0, 1, i);
}
}
// scrivo ack se richiesto!!!
if (giveAck)
{
// mi preparo a scrivere ACK
memIndex = 10500;
// scrivo update ad ack!!!
inizio = DateTime.Now;
FANUC_ref.F_RW_Byte(W, FANUC.MemType.R, memIndex, ref retACK_DW0);
if (utils.CRB("recTime")) TimingData.addResult(string.Format("W{0}-ACK_DW0", retACK_DW0.Length), DateTime.Now.Subtract(inizio).Ticks);
// rileggo strobes...
getStrobeAndAckStatus();
}
}
}
// !!!FARE!!! testare questa modifica
// ultimo controllo: se ho degli ACK sollevati mentre gli strobe sono abbassati li abbasso...
//if ((STRB_DW0 ^ ACK_DW0) != (STRB_DW0 & ACK_DW0))
// se è diverso il vettorei degli ACK in memoria da quello PLC...
if (ACK_DW0 != (StFlag32)BitConverter.ToUInt32(retACK_DW0, 0))
{
memIndex = 10500;
// invio INTERO set ACK_DW0 con bit abbassati...
retACK_DW0 = BitConverter.GetBytes(Convert.ToUInt32(STRB_DW0 & ACK_DW0));
inizio = DateTime.Now;
FANUC_ref.F_RW_Byte(W, FANUC.MemType.R, memIndex, ref retACK_DW0);
if (utils.CRB("recTime")) TimingData.addResult(string.Format("W{0}-ACK_DW0", retACK_DW0.Length), DateTime.Now.Subtract(inizio).Ticks);
}
}
/// <summary>
/// processing strobe degli allarmi
/// </summary>
public override void processAlarm()
{
base.processAlarm();
if (AlarmFlags != null)
{
// variabili helper
StFlag32 AlarmBlock = 0;
allarme currAllarm;
// controllo TUTTI i bit della variabile COMPLETA degli status allarmi: se ce ne sono di alzati DEVO processare...
for (int i = 0; i < AlarmFlags.Length / 4; i++)
{
// leggo 32bit alla volta...
AlarmBlock = (StFlag32)BitConverter.ToUInt32(AlarmFlags, i * 4);
for (int j = 0; j < 32; j++)
{
// converto! e aggiungo allarmi sollevati al corretto controller allarmi...
if (AlarmBlock.HasFlag((StFlag32)Math.Pow(2, j)))
{
// recupero allarme da oggetto in memoria...
currAllarm = elencoAllarmi[i * 32 + j];
// in base al gruppo decido dove assegnare come CONDITION...
switch (currAllarm.gruppo)
{
case "PLC":
mAlarmPLC.Add(MTConnect.Condition.Level.FAULT, currAllarm.descrizione, currAllarm.codNum, "", "");
break;
case "CNC":
default:
mAlarmCNC.Add(MTConnect.Condition.Level.FAULT, currAllarm.descrizione, currAllarm.codNum, "", "");
break;
}
}
}
}
}
}
/// <summary>
/// processing!
/// </summary>
public override void processStatus()
{
base.processStrobe();
// update status da DW2/ DW3
// EMstop: verifico BIT e di conseguenza imposto
if (STRB_DW2.HasFlag(StFlag32.B00))
{
mEStop.Value = "TRIGGERED";
}
else
{
mEStop.Value = "ARMED";
}
// HARD CODE: forzo path 1 (indice 0...)
int idxPath = 0;
// switch su run mode...
if (STRB_DW2.HasFlag(StFlag32.B01))
{
vettPath[idxPath].mPathRunMode.Value = "AUTO";
}
else if (STRB_DW2.HasFlag(StFlag32.B02))
{
vettPath[idxPath].mPathRunMode.Value = "EDIT";
}
else if (STRB_DW2.HasFlag(StFlag32.B03))
{
vettPath[idxPath].mPathRunMode.Value = "MDI";
}
else if (STRB_DW2.HasFlag(StFlag32.B04))
{
vettPath[idxPath].mPathRunMode.Value = "REF";
}
else if (STRB_DW2.HasFlag(StFlag32.B05))
{
vettPath[idxPath].mPathRunMode.Value = "JOG";
}
else if (STRB_DW2.HasFlag(StFlag32.B07))
{
vettPath[idxPath].mPathRunMode.Value = "JOGINC";
}
else if (STRB_DW2.HasFlag(StFlag32.B07))
{
vettPath[idxPath].mPathRunMode.Value = "HANDLE";
}
// switch su EXE mode...
if (STRB_DW2.HasFlag(StFlag32.B08))
{
vettPath[idxPath].mPathExeMode.Value = "RUN";
}
else if (STRB_DW2.HasFlag(StFlag32.B09))
{
vettPath[idxPath].mPathExeMode.Value = "READY";
}
else if (STRB_DW2.HasFlag(StFlag32.B10))
{
vettPath[idxPath].mPathExeMode.Value = "HOLD";
}
else if (STRB_DW2.HasFlag(StFlag32.B11))
{
vettPath[idxPath].mPathExeMode.Value = "FEEDHOLD";
}
// verifico tipo path...
if (STRB_DW2.HasFlag(StFlag32.B12))
{
vettPath[idxPath].mPathType.Value = "LAVORO";
}
else
{
vettPath[idxPath].mPathType.Value = "ASSERV";
}
// verifico sulla STRB_DW3 i submode che POTREBBERO tutti sovrapposti...
// devo aver già in memoria come allarmi la lista dei SUBMODE (32)
// leggo come allarmi i BIT attivi
// per ogni BIT attivo aggiungo nell'event del PATH (forzato a 1) l'elenco separato da spazio dei submode attivi
#if false
// IPOTESI DA VERIFICARE!!!
// leggo primo byte, i cui bit indicano run mode (3450.0 --> 3450.7)
RunStatus = (StFlag8)status[0];
// leggo primo byte, i cui bit indicano run mode (3451.0 --> 3451.7)
ExeStatus = (StFlag8)status[1];
// se devo prendere sotto insiemi di byte --> BitConverter
//BitConverter.ToUInt32
// check bit 0... SE è presente
Status8.Has(StFlag8.B0);
// check bit 0... SE è SOLO QUELLO
Status8.Is(StFlag8.B0);
// check bit 18...
Status8.Has(StFlag32.B18);
#endif
}
public override void getConfigParam()
{
base.getConfigParam();
}
public override void getSlowChangingData()
{
base.getSlowChangingData();
// !!!FARE!!! recuperare davvero dai dati del CNC e sostituire NA
mOperator.Value = "NA";
// recupero SEMPRE dati ulteriori: status ON/OFF, clock, ...
mStatus.Value = "NA";
mAccTime.Value = "NA";
mClock.Value = DateTime.Now.Date.ToFileTimeUtc();
mPower.Value = "NA";
}
public override void getUnOp()
{
base.getUnOp();
}
public override void getPath()
{
base.getPath();
}
public override void getAxis()
{
base.getAxis();
}
}
}