Files
CMS-MTConn/MTC_Sim/MTC_Sim/AdapterFanuc.cs
T
2016-05-17 13:58:14 +02:00

619 lines
26 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CMSCncLib.CNC;
using System.Runtime.InteropServices;
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)
{
if (utils.CRB("verbose")) lg.Info("Start init Adapter FANUC");
Runtime.CreateNC(utils.CRS("ipFanuc"));
FANUC_ref = (FANUC)Runtime.NC;
if (utils.CRB("verbose")) lg.Info("FANUC_ref da CMSCncLib");
// disconnetto e connetto...
if (utils.CRB("verbose")) lg.Info("FANUC: tryDisconnect");
tryDisconnect();
if (utils.CRB("verbose")) lg.Info("FANUC: tryConnect");
tryConnect();
if (utils.CRB("verbose")) lg.Info("End init Adapter FANUC");
}
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;
int bitNum = 0;
DateTime inizio = DateTime.Now;
// byte di acknowledge...
byte[] retACK_DW1 = new byte[4];
// inizializzo userAction
string UserAction = "";
string TestingData = "";
// 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
bitNum = 0;
gestStrobeCodMST(bitNum, ref retACK_DW1, 0, MemBlock, "M");
// check COD_S
bitNum = 1;
gestStrobeCodMST(bitNum, ref retACK_DW1, 11, MemBlock, "S");
// check COD_T
bitNum = 2;
gestStrobeCodMST(bitNum, ref retACK_DW1, 17, MemBlock, "T");
// check FILE DATI MODIFICATO: ricaricare...
bitNum = 3;
if (STRB_DW1.HasFlag((StFlag32)Math.Pow(2, bitNum)))
{
// reload dati da file...
reloadDataFromFile();
// memorizzo allarme nel vettore ack....
retACK_DW1 = utils.setBitOnStFlag(retACK_DW1, true, bitNum);
}
// AREA strobe USER ACTION
// chiamato Start...
bitNum = 4;
gestStrobeUserAction(bitNum, ref retACK_DW1, ref UserAction, "# START # ");
// chiamato Stop...
bitNum = 5;
gestStrobeUserAction(bitNum, ref retACK_DW1, ref UserAction, "# STOP # ");
// chiamato Reset...
bitNum = 6;
gestStrobeUserAction(bitNum, ref retACK_DW1, ref UserAction, "# RESET # ");
// AREA strobe x TEST
// INIZIO TEST...
bitNum = 30;
if (STRB_DW1.HasFlag((StFlag32)Math.Pow(2, bitNum)))
{
// formatto stringa risultato
TestingData = string.Format("START TEST{0}", getTestData(utils.CRS("testCharSep")));
// memorizzo allarme nel vettore ack....
retACK_DW1 = utils.setBitOnStFlag(retACK_DW1, true, bitNum);
}
// FINE TEST...
bitNum = 31;
if (STRB_DW1.HasFlag((StFlag32)Math.Pow(2, bitNum)))
{
// formatto stringa risultato
TestingData = string.Format("STOP TEST{0}", getTestData(utils.CRS("testCharSep")));
// memorizzo allarme nel vettore ack....
retACK_DW1 = utils.setBitOnStFlag(retACK_DW1, true, bitNum);
}
}
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];
}
}
// INVIO COMUNQUE vettore azioni (0 o +)...
mUserAction.Value = UserAction.Trim();
// INVIO COMUNQUE stato test...
mTestingData.Value = TestingData.Trim();
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>
/// Recupero info su test: numero + elenco parametri IN/OUT
/// </summary>
/// <param name="charSep"></param>
/// <returns></returns>
private string getTestData(string charSep)
{
string answ = "";
// Area di memoria x test... 64 byte
byte[] MemBlockTestData = new byte[64];
// variabili numero test e num parametri impiegati
int testNum = 0;
int numPar = 0;
// variabile dove parcheggiare conversione codici dei parametri del test (IN o OUT)
UInt32 testParam = 0;
// leggo tutto!!!
int memIndex = 11000;
DateTime inizio = DateTime.Now;
FANUC_ref.F_RW_Byte(R, FANUC.MemType.R, memIndex, ref MemBlockTestData);
if (utils.CRB("recTime")) TimingData.addResult(string.Format("R{0}-TEST_DATA_DW1", MemBlockTestData.Length), DateTime.Now.Subtract(inizio).Ticks);
// recupero cod univoco test e numero parametri impiegati
testNum = BitConverter.ToUInt16(MemBlockTestData, 0);
numPar = BitConverter.ToUInt16(MemBlockTestData, 2);
// riporto separatore + numero test + num parametri
answ = string.Format("{0}TN:{1}{0}NP:{2}", charSep, testNum, numPar);
// se ci sono parametri da accodare li recupero!
if (numPar > 0)
{
for (int i = 0; i < numPar; i++)
{
testParam = BitConverter.ToUInt32(MemBlockTestData, 4 * (1 + i));
answ += string.Format("{0}{1}", charSep, testParam);
}
}
return answ;
}
/// <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, true, bitNum);
}
}
/// <summary>
/// Ricarica dati da file di scambio con CMSConnect
/// </summary>
private void reloadDataFromFile()
{
// !!!FARE!!! da definire cosa ci sarà e come leggerlo...
}
/// <summary>
/// Gestione strobe UserAction: salva dati e gestione ACK
/// </summary>
/// <param name="bitNum"></param>
/// <param name="retACK_DW1"></param>
/// <param name="UserAction"></param>
/// <param name="azione"></param>
private void gestStrobeUserAction(int bitNum, ref byte[] retACK_DW1, ref string UserAction, string azione)
{
if (STRB_DW1.HasFlag((StFlag32)Math.Pow(2, bitNum)))
{
// salvo evento UserAction in variabile...
UserAction += azione;
// memorizzo allarme nel vettore ack....
retACK_DW1 = utils.setBitOnStFlag(retACK_DW1, true, bitNum);
}
}
/// <summary>
/// recupera allarmi ed aggiorna 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);
bool ackReturned = false;
// 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));
// log bitmap se verboso attivo + ho allarmi da refreshare
if ((Alarm2Refresh != StFlag32.NONE) && utils.CRB("verbose"))
{
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, true, 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);
ackReturned = true;
// !!!FARE!!! tolto, verificare sia ok così...
#if false
// rileggo strobes...
getStrobeAndAckStatus();
#endif
}
}
}
// !!!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 non ho già tornato un ACK...
if (!ackReturned)
{
// se è diverso il vettori 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();
//}
/// <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";
}
// inizializzo SEMPRE a vuoto...
string SubMode = "";
// verifico sulla STRB_DW3 i submode che POTREBBERO tutti sovrapposti...
if (STRB_DW3 != StFlag32.NONE)
{
// cerco i bit alzati --> aggiungo relativo submode!
for (int i = 0; i < 32; i++)
{
// converto! e aggiungo allarmi sollevati al corretto controller allarmi...
if (STRB_DW3.HasFlag((StFlag32)Math.Pow(2, i)))
{
SubMode += string.Format("# {0} #", elencoSubMode[i.ToString()]);
}
}
}
// INVIO SEMBRE (x prendere il reset/fronte discesa)...
vettPath[idxPath].mPathSubMode.Value = SubMode.Trim();
}
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()
{
DateTime inizio = DateTime.Now;
CMSCncLib.Focas1.ODBPOS posAssi = FANUC_ref.getAllAxisPos();
if (utils.CRB("recTime")) TimingData.addResult("R-AXIS_POS", DateTime.Now.Subtract(inizio).Ticks);
inizio = DateTime.Now;
CMSCncLib.Focas1.ODBSPEED speedAssi = FANUC_ref.getAllAxisSpeed();
if (utils.CRB("recTime")) TimingData.addResult("R-AXIS_SPEED", DateTime.Now.Subtract(inizio).Ticks);
// fare: salvataggio assi...
StringBuilder sb = new StringBuilder();
sb.AppendLine(string.Format("Asse {0}: PosAct:{1:N3}, ToGo:{2:N3}{3}", posAssi.p1.abs.name, (double)(posAssi.p1.abs.data) / Math.Pow(10, posAssi.p1.abs.dec), posAssi.p1.dist.name, (double)(posAssi.p1.dist.data) / Math.Pow(10, posAssi.p1.dist.dec), Environment.NewLine));
sb.AppendLine(string.Format("Asse {0}: PosAct:{1:N3}, ToGo:{2:N3}{3}", posAssi.p2.abs.name, (double)(posAssi.p2.abs.data) / Math.Pow(10, posAssi.p2.abs.dec), posAssi.p2.dist.name, (double)(posAssi.p2.dist.data) / Math.Pow(10, posAssi.p2.dist.dec), Environment.NewLine));
sb.AppendLine(string.Format("Asse {0}: PosAct:{1:N3}, ToGo:{2:N3}{3}", posAssi.p3.abs.name, (double)(posAssi.p3.abs.data) / Math.Pow(10, posAssi.p3.abs.dec), posAssi.p3.dist.name, (double)(posAssi.p3.dist.data) / Math.Pow(10, posAssi.p3.dist.dec), Environment.NewLine));
sb.AppendLine(string.Format("Asse {0}: PosAct:{1:N3}, ToGo:{2:N3}{3}", posAssi.p4.abs.name, (double)(posAssi.p4.abs.data) / Math.Pow(10, posAssi.p4.abs.dec), posAssi.p4.dist.name, (double)(posAssi.p4.dist.data) / Math.Pow(10, posAssi.p4.dist.dec), Environment.NewLine));
sb.AppendLine(string.Format("Asse {0}: PosAct:{1:N3}, ToGo:{2:N3}{3}", posAssi.p5.abs.name, (double)(posAssi.p5.abs.data) / Math.Pow(10, posAssi.p5.abs.dec), posAssi.p5.dist.name, (double)(posAssi.p5.dist.data) / Math.Pow(10, posAssi.p5.dist.dec), Environment.NewLine));
sb.AppendLine(string.Format("Asse {0}: PosAct:{1:N3}, ToGo:{2:N3}{3}", posAssi.p6.abs.name, (double)(posAssi.p6.abs.data) / Math.Pow(10, posAssi.p6.abs.dec), posAssi.p6.dist.name, (double)(posAssi.p6.dist.data) / Math.Pow(10, posAssi.p6.dist.dec), Environment.NewLine));
sb.AppendLine(string.Format("{0} {1}", speedAssi.actf.name, speedAssi.actf.data));
sb.AppendLine(string.Format("{0} {1}", speedAssi.acts.name, speedAssi.acts.data));
parentForm.showMessage(sb.ToString());
}
}
}