Files
2021-12-01 16:47:46 +01:00

324 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Net.NetworkInformation;
using System.Threading;
using TwinCAT;
using TwinCAT.Ads;
using TwinCAT.Ads.TypeSystem;
using System.IO;
using System.Text;
using System.Linq;
using System.Threading.Tasks;
using TwinCAT.TypeSystem;
namespace Test_Beckhoff
{
//var handle = adsClient.AddDeviceNotification("MAIN.boolVal", dataStream, 0, 1,
// AdsTransMode.OnChange, 100, 0, new object() );
// Structure declaration for handles
public enum EnuStates //Stato Macchina
{
Errore = -1,
Ferma = 0,
Automatica = 1,
Manuale = 2,
Emergenza = 3,
AzzeraTavola = 4,
ManualeStazione = 5,
Avviamento = 7,
}
public class ADS
{
public class ComandiADS
{
public TcAdsSymbolInfo Symbol;
public string SymbolName;
public bool ComandoScrittua;
public object Value;
public ManualResetEventSlim Updating;
public bool Error;
public ComandiADS()
{
Updating = new ManualResetEventSlim(false);
}
public ComandiADS(string name)
{
SymbolName = name;
Updating = new ManualResetEventSlim(false);
}
public ComandiADS(TcAdsSymbolInfo info)
{
Symbol = info;
Updating = new ManualResetEventSlim(false);
}
}
/// <summary>
/// Dizionario di conversione da indice a index group e index offset
/// </summary>
private Dictionary<int, Tuple<int, int>> addressList;
public delegate void StatusChangedEventHandler(ADS sender, EnuStates newStatus);
public TcAdsSymbolInfoCollection Symbols;
private TcAdsClient adsClient;
public TcAdsClient Client
{
get { return adsClient; }
}
public TwinCAT.Ads.TcAdsSymbolInfoLoader InfoLoader;
public TwinCAT.TypeSystem.ISymbolLoader SymbolLoaderInstance;
private List<int> addedSignalationList = new List<int>();
private int notifyposition;
private int eventHandle;
private int SegnalazioniADSEventHandle, StatusChangedEventHandle, MessageQueuedEventHandle;
private AdsStream notifyStream;
private AdsStream newNotificationStream;
public bool EnableEvents { get; set; }
private EnuStates _status;
private object lockobj = new object();
//private Action<object> dispatcher;
private System.Threading.Tasks.Task dispatchertask;
public System.Collections.Concurrent.ConcurrentQueue<ComandiADS> CodaComandi;
private CancellationTokenSource cts;
Symbol StatoMacchina;
public event StatusChangedEventHandler StatusChanged;
public ADS(string indirizzo = "local", int porta = 851)
{
notifyStream = new AdsStream();
newNotificationStream = new AdsStream();
addressList = new Dictionary<int, Tuple<int, int>>();
bool ready = false;
while (!ready)
{
try
{
//LETTURA DEL VETTORE DI INIZIALIZZAZIONE
if (adsClient == null) adsClient = new TcAdsClient();
// Connect to local PLC - Runtime 1 - TwinCAT2 Port=801, TwinCAT3 Port=851
if (indirizzo == "")
{
adsClient.Connect(porta);
}
else
{
if (adsClient.IsConnected == false) adsClient.Connect(indirizzo, porta);
}
SymbolLoaderInstance = SymbolLoaderFactory.Create(adsClient, SymbolLoaderSettings.Default);
InfoLoader = adsClient.CreateSymbolInfoLoader();
Symbols = InfoLoader.GetSymbols(true);
ready = true;
}
catch (Exception ex)
{
System.Threading.Thread.Sleep(100);
ready = false;
Debug.Print(ex.Message);
}
}
StatoMacchina = (Symbol)SymbolLoaderInstance.Symbols["VarADS.StatoMacchina"];
StatoMacchina.NotificationSettings = new AdsNotificationSettings(AdsTransMode.OnChange, 100, 100);
StatoMacchina.ValueChanged += StatoMacchina_ValueChanged;
notifyposition = 0;
cts = new CancellationTokenSource();
//adsClient.AdsNotification += new AdsNotificationEventHandler(adsClient_AdsNotification);
CodaComandi = new System.Collections.Concurrent.ConcurrentQueue<ComandiADS>();
cts = new CancellationTokenSource(); //Task require CancellationToken.cancel() to stop
Action<object> Azione = commandDispatcher;
dispatchertask = new Task(Azione, cts.Token, TaskCreationOptions.PreferFairness); //Definisce e Crea un Task di base a priorità favorevole
dispatchertask.Start();
}
private void StatoMacchina_ValueChanged(object sender, TwinCAT.TypeSystem.ValueChangedArgs e)
{
EnuStates newStatus = (EnuStates)e.Value;
if (StatusChanged != null) StatusChanged(this, newStatus);
}
public void dispose()
{
//adsClient.Dispose();
}
public TcAdsSymbolInfo GetSymbolInfo(string nome)
{
try
{
var symbol = InfoLoader.FindSymbol(nome);
return symbol;
}
catch (Exception)
{
throw;
}
}
private void commandDispatcher(object tk)
{
ComandiADS comando;
Thread.CurrentThread.Name = "ADS Command Dispatcher";
CancellationToken chiudi = (CancellationToken)tk;
while (!chiudi.IsCancellationRequested)
{
Thread.Sleep(1);
if (CodaComandi.Count <= 0)
{
Thread.Sleep(1);
continue;
}
if (CodaComandi.Count > 100) Debug.Print("CODA COMANDI! " + CodaComandi.Count.ToString());
if (!CodaComandi.TryDequeue(out comando)) continue;
if (CodaComandi.Count > 1000) continue;
if (comando.ComandoScrittua) //gestione scrittura
{
try
{
if (comando.SymbolName != "")
{
if (comando.Symbol == null) comando.Symbol = GetSymbolInfo(comando.SymbolName);
}
else
{
comando.SymbolName = comando.Symbol.Name;
}
if (comando.Value is int && comando.Symbol.Category == TwinCAT.TypeSystem.DataTypeCategory.Array)
{
var newvalue = new int[comando.Symbol.ArrayInfos[0].Elements];
newvalue[0] = (int)comando.Value;
comando.Value = newvalue;
}
if (comando.Value is double && comando.Symbol.Category == TwinCAT.TypeSystem.DataTypeCategory.Array)
{
var newvalue = new double[comando.Symbol.ArrayInfos[0].Elements];
newvalue[0] = (double)comando.Value;
comando.Value = newvalue;
}
adsClient.WriteSymbol(comando.Symbol, comando.Value);
}
catch (Exception err)
{
comando.Error = true;
Debug.Print(comando.SymbolName + " Scrittura " + err.Message);
}
comando.Updating.Set();
}
else // gestione lettura
{
try
{
if (comando.SymbolName != "")
{
if (comando.Symbol == null) comando.Symbol = GetSymbolInfo(comando.SymbolName);
}
else
{
comando.SymbolName = comando.Symbol.Name;
}
comando.Value = adsClient.ReadSymbol(comando.Symbol);
}
catch (Exception errore)
{
Debug.Print(errore.Message);
comando.Error = true;
Debug.Print("Error reading from ADS: VarName: " + comando.SymbolName);
}
comando.Updating.Set();
}
}
}
public object ReadVariabile(ref TcAdsSymbolInfo variabile)
{
var comando = new ComandiADS { ComandoScrittua = false, Symbol = variabile };
return ReadVariabile(comando);
}
public object ReadVariabile(string symbolName, Type type = null)
{
var comando = new ComandiADS { ComandoScrittua = false, SymbolName = symbolName };
return ReadVariabile(comando);
}
private object ReadVariabile(ComandiADS comando)
{
CodaComandi.Enqueue(comando);
bool test = comando.Updating.Wait(3000);
if (!test) Debug.Print("Errore attesa lettura: " + comando.SymbolName);
if (comando.Value == null) Debug.Print("ADS Variabile non trovata: " + comando.SymbolName);
return comando.Value;
}
public bool WriteVariabile(string symbolName, object value, bool syncronous = false)
{
var comando = new ComandiADS { Value = value, ComandoScrittua = true, SymbolName = symbolName };
return WriteVariabile(comando, syncronous);
}
public bool WriteVariabile(TcAdsSymbolInfo symbol, object value, bool syncronous = false)
{
var comando = new ComandiADS { Value = value, ComandoScrittua = true, Symbol = symbol };
return WriteVariabile(comando, syncronous);
}
private bool WriteVariabile(ComandiADS comando, bool syncronous)
{
bool test = true;
CodaComandi.Enqueue(comando);
if (syncronous) test = comando.Updating.Wait(3000);
if (!test) Debug.Print("Errore attesa lettura: " + comando.SymbolName);
if (comando.Error) Debug.Print("Errore ADS durante la scrittura della variabile: " + comando.SymbolName);
return !comando.Error;
}
public EnuStates Status
{
get
{
var stato = ReadVariabile("VarADS.StatoMacchina");
if (stato != null) _status = (EnuStates)stato;
else
{
throw new Exception("Errore lettura stato");
}
return _status;
}
}
}
}