using Aitex.Core.RT.IOCore;
using Aitex.Core.RT.Log;
using Aitex.Core.Util;
using DocumentFormat.OpenXml.Wordprocessing;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using TwinCAT.Ads;
using Venus_Core;
namespace MECF.Framework.Common.Twincat
{
///
/// 变量数值发生变化委托声明
///
///
///
public delegate void OnUpdateModuleVariableValue(string variableName, object value);
///
/// Twicat Ado通信
///
public class TwincatAdoManager
{
#region 内部变量
///
/// IO长度字典(key-变量名称,value-变量数据长度)
///
private ConcurrentDictionary _ioLengthDic = new ConcurrentDictionary();
///
/// 输出变量集合
///
private ConcurrentBag _outputBag = new ConcurrentBag();
///
/// 主动读取变量集合
///
private ConcurrentBag _inputBag = new ConcurrentBag();
///
/// Twincat 对象
///
private TcAdsClient _adsClient = null;
///
/// 地址
///
private string _ipAddress = "";
///
/// 端口号
///
private int _port = 851;
///
/// 句柄变量名称字典(key-创建句柄,value-变量名称)
///
private Dictionary _notificationHandleNameDic = new Dictionary();
///
/// 模块变量更新委托字典(key-模块.变量,value-变量委托事件
///
private Dictionary _moduleVariableActionDic = new Dictionary();
///
/// 写变更名称句柄字典(key-变量名称,value-创建句柄)
///
private Dictionary _writeNameHandleDic = new Dictionary();
///
/// 主动读取名称字典(key-变量名称,value-创建句柄)
///
private Dictionary _readNameHandleDic = new Dictionary();
private AdsStream _adsStream;
private BinaryReader _reader;
///
/// 连接状态
///
private bool _isConnected;
#endregion
///
/// 订阅变量
///
///
///
public void Subscribe(string itemName,int itemLength, OnUpdateModuleVariableValue onUpdateModuleVariableValue)
{
_ioLengthDic[itemName] = itemLength;
_moduleVariableActionDic[itemName] = onUpdateModuleVariableValue;
}
///
/// 订阅输出变量名称
///
///
public void SubscribeOutput(string itemName)
{
_outputBag.Add(itemName);
}
///
/// 订阅主动读取变量名称
///
///
public void SubscribeInput(string itemName)
{
_inputBag.Add(itemName);
}
///
/// 初始化
///
///
///
public void Initialize(string ipAddress,int port)
{
_ipAddress = ipAddress;
_port = port;
}
///
/// 获取所有数据长度
///
///
private int GetAllSize()
{
int size = 0;
foreach(string item in _ioLengthDic.Keys)
{
size+= _ioLengthDic[item];
}
return size;
}
///
/// ADO变量变化通知,twincat->上位机
///
///
///
private void AdsClient_AdsNotification(object sender, AdsNotificationEventArgs e)
{
try
{
if (_notificationHandleNameDic.ContainsKey(e.NotificationHandle))
{
string item = _notificationHandleNameDic[e.NotificationHandle];
if(!_ioLengthDic.ContainsKey(item))
{
LOG.Write(eEvent.ERR_TWINCAT, "System", $"{item} not in twincat io list");
return;
}
int size = _ioLengthDic[item];
e.DataStream.Position = e.Offset;
if(size==1)
{
bool boolValue = _reader.ReadBoolean();
if(_moduleVariableActionDic.ContainsKey(item))
{
_moduleVariableActionDic[item].Invoke(item, boolValue);
}
}
else if(size==4)
{
float floatValue= _reader.ReadSingle();
if (_moduleVariableActionDic.ContainsKey(item))
{
_moduleVariableActionDic[item].Invoke(item, floatValue);
}
}
else
{
byte[] byt = new byte[size];
var value = _reader.Read(byt, 0, byt.Length);
if (_moduleVariableActionDic.ContainsKey(item))
{
_moduleVariableActionDic[item].Invoke(item, byt);
}
//LOG.Write(eEvent.ERR_TWINCAT, "System", $"{item} size is invalid");
}
}
}
catch (Exception ex)
{
LOG.Write(eEvent.ERR_TWINCAT, "System", ex.Message);
}
}
///
/// 连接状态变化
///
///
///
private void AdsClient_ConnectionStateChanged(object sender, TwinCAT.ConnectionStateChangedEventArgs e)
{
if (e.NewState == TwinCAT.ConnectionState.Connected)
{
try
{
StateInfo stateInfo = _adsClient.ReadState();
CreateWriteHandle();
CreateReadHandle();
SubscribeNotification();
_isConnected = true;
}
catch (Exception ex)
{
_isConnected = false;
LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat connect{_ipAddress}:{_port} error");
return;
}
}
else
{
_isConnected = false;
LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat connect{_ipAddress}:{_port} error");
}
}
///
/// 启动
///
public void Start()
{
_adsClient = new TcAdsClient();
_adsClient.ConnectionStateChanged += AdsClient_ConnectionStateChanged;
_adsClient.AdsNotification += AdsClient_AdsNotification;
_adsStream = new AdsStream(GetAllSize());
_reader = new BinaryReader(_adsStream);
try
{
_adsClient.Connect(_ipAddress, _port);
}
catch
{
LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat connect{_ipAddress}:{_port} error");
}
}
///
/// 创建写入句柄
///
private void CreateWriteHandle()
{
_writeNameHandleDic.Clear();
foreach (string item in _outputBag)
{
try
{
int handle = _adsClient.CreateVariableHandle(item);
_writeNameHandleDic[item] = handle;
}
catch
{
LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat create variable handle {item} error");
}
}
}
///
/// 创建主动读取句柄
///
private void CreateReadHandle()
{
_readNameHandleDic.Clear();
foreach (string item in _inputBag)
{
try
{
int handle = _adsClient.CreateVariableHandle(item);
_readNameHandleDic[item] = handle;
}
catch
{
LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat create variable handle {item} error");
}
}
}
///
/// 订阅变量
///
private void SubscribeNotification()
{
_notificationHandleNameDic.Clear();
int count = 0;
foreach (string item in _ioLengthDic.Keys)
{
int size = _ioLengthDic[item];
try
{
int handle = _adsClient.AddDeviceNotification(item, _adsStream, count, size, AdsTransMode.OnChange, 0, 0, null);
_notificationHandleNameDic[handle] = item;
count += size;
}
catch
{
LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat add variable {item} error");
}
}
}
///
/// 写入数值
///
///
///
///
public (bool success,int status) WriteValue(string name, object value)
{
if (_writeNameHandleDic.ContainsKey(name))
{
if (!_isConnected)
{
LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat connected failed, write variable {name} error");
return (false,0);
}
try
{
int handle = _writeNameHandleDic[name];
_adsClient.WriteAny(handle, value);
if (value.ToString() == "System.Byte[]")
{
byte[] result = ((byte[])value).Where(b => b != 0).ToArray();
string _value = System.Text.Encoding.UTF8.GetString(result);
LOG.Write(eEvent.EV_TWINCAT, "System", $"Twincat write variable {name} value {_value}");
}
else
{
LOG.Write(eEvent.EV_TWINCAT, "System", $"Twincat write variable {name} value {value}");
}
return (true,0);
}
catch (Exception ex)
{
LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat write variable {name} error {ex.Message}");
return (false,1);
}
}
else
{
LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat doesnot has {name} variable");
return (false, 0);
}
}
///
/// 主动读取
///
///
///
///
public (bool success,object obj) ReadValue(string name,Type type)
{
if (_readNameHandleDic.ContainsKey(name))
{
if (!_isConnected)
{
LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat connected failed, read variable {name} error");
return (false, null);
}
try
{
int handle = _readNameHandleDic[name];
return (true, _adsClient.ReadAny(handle,type));
}
catch (Exception ex)
{
LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat write variable {name} error {ex.Message}");
return (false, null);
}
}
else
{
LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat doesnot has {name} variable");
return (false, null);
}
}
#region 支持写入结构体
/* T必须字段必须为连续地址,
* [StructLayout(LayoutKind.Sequential)]
public class Tag
{
[MarshalAs(UnmanagedType.I1)]
public bool DO_PVN21;
[MarshalAs(UnmanagedType.I1)]
public bool DO_PV11;
[MarshalAs(UnmanagedType.R4)]
public float AI_Chamber_Pressure_10t;
}
* */
///
/// 写入类
///
///
///
///
///
public (bool success,int status) WriteStruct(string name,T data)
{
if (_writeNameHandleDic.ContainsKey(name))
{
if (!_isConnected)
{
LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat connected failed, write variable {name} error");
return (false, 0);
}
try
{
int handle = _writeNameHandleDic[name];
_adsClient.WriteAny(handle, data);
LOG.Write(eEvent.EV_TWINCAT, "System", $"Twincat write variable {name} value {data}");
return (true, 0);
}
catch (Exception ex)
{
LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat write variable {name} error {ex.Message}");
return (false, 1);
}
}
else
{
LOG.Write(eEvent.ERR_TWINCAT, "System", $"Twincat doesnot has {name} variable");
return (false, 0);
}
}
#endregion
}
}