485 lines
17 KiB
C#
485 lines
17 KiB
C#
|
|
using Aitex.Core.RT.IOCore;
|
|||
|
|
using Aitex.Core.RT.Log;
|
|||
|
|
using Aitex.Core.Util;
|
|||
|
|
using MECF.Framework.Common.PLC;
|
|||
|
|
using MECF.Framework.RT.Core.IoProviders;
|
|||
|
|
using System;
|
|||
|
|
using System.Diagnostics;
|
|||
|
|
using System.Xml;
|
|||
|
|
|
|||
|
|
namespace Aitex.Core.RT.Device.Devices
|
|||
|
|
{
|
|||
|
|
public partial class SiemensIoProvider : IoProvider
|
|||
|
|
{
|
|||
|
|
protected readonly DOAccessor _doShutDown;
|
|||
|
|
|
|||
|
|
private IAdsPlc _ads;
|
|||
|
|
private static object _locker = new object();
|
|||
|
|
|
|||
|
|
private R_TRIG _trigConnected = new R_TRIG();
|
|||
|
|
protected override void SetParameter(XmlElement nodeParameter)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
private bool MonitorAdsConnection()
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
//if (_SiemensClient == null)
|
|||
|
|
//{
|
|||
|
|
// _SiemensClient = DEVICE.GetDevice<PMModule>(Module + "." + Module)?.Siemens;
|
|||
|
|
//}
|
|||
|
|
//if (_SiemensClient != null) return _SiemensClient.IsTrue;
|
|||
|
|
//return false;
|
|||
|
|
|
|||
|
|
if (_ads == null)
|
|||
|
|
{
|
|||
|
|
_ads = DEVICE.GetOptionDevice($"{Module}.MainPLC", typeof(SicAds)) as IAdsPlc;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return _ads != null && _ads.CheckIsConnected();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
//public bool IsCommunicationError
|
|||
|
|
//{
|
|||
|
|
// get { return _ads.IsCommunicationError; }
|
|||
|
|
//}
|
|||
|
|
protected override void Close()
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
protected override void Open()
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override bool OnTimer()
|
|||
|
|
{
|
|||
|
|
_trigConnected.CLK = MonitorAdsConnection();
|
|||
|
|
|
|||
|
|
if (!_trigConnected.M)
|
|||
|
|
return true;
|
|||
|
|
|
|||
|
|
lock (_locker)
|
|||
|
|
{
|
|||
|
|
// PLC数据以32位二级制存储,软件读取的值与DINT相同
|
|||
|
|
// 如果是DINT类型数据,直接使用,无需转换;
|
|||
|
|
// 如果是REAL类型数据,先使用BitConverter.GetBytes获取有4个元素的字节数组,再使用BitConverter.ToSingle,得到float类型值;
|
|||
|
|
// 如果是DWORD类型数据,先使用BitConverter.GetBytes获取有4个元素的字节数组,再进行位运算,得到每位的值
|
|||
|
|
|
|||
|
|
//int[] input = ReadInput();
|
|||
|
|
//Console.WriteLine(input[0]);
|
|||
|
|
//byte[] byteArr = BitConverter.GetBytes(input[0]);
|
|||
|
|
//float fValve = BitConverter.ToSingle(byteArr, 0);
|
|||
|
|
|
|||
|
|
foreach (var key in DiVariables.Keys)
|
|||
|
|
{
|
|||
|
|
var ioVar = DiVariables[key];
|
|||
|
|
var diData = ReadDIn(ioVar.Name, (ushort)ioVar.Length);
|
|||
|
|
if (diData != null)
|
|||
|
|
{
|
|||
|
|
var diBuffer = ParseDI(key, diData);
|
|||
|
|
if (diBuffer != null)
|
|||
|
|
{
|
|||
|
|
_buffer.SetDiBuffer(_source, ioVar.Block.Index, diBuffer);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
foreach (var key in DoVariables.Keys)
|
|||
|
|
{
|
|||
|
|
var ioVar = DoVariables[key];
|
|||
|
|
var doData = ReadDOut(ioVar.Name, (ushort)ioVar.Length);
|
|||
|
|
if (doData != null)
|
|||
|
|
{
|
|||
|
|
var doBuffer = ParseDO(key, doData);
|
|||
|
|
if (doBuffer != null)
|
|||
|
|
{
|
|||
|
|
_buffer.SetDoBuffer(_source, ioVar.Block.Index, doBuffer);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
foreach (var key in AiVariables.Keys)
|
|||
|
|
{
|
|||
|
|
var ioVar = AiVariables[key];
|
|||
|
|
var aiData = ReadAIn(ioVar.Name, (ushort)ioVar.Length);
|
|||
|
|
if (aiData != null)
|
|||
|
|
{
|
|||
|
|
var aiBuffer = ParseAI(key, aiData);
|
|||
|
|
if (aiBuffer != null)
|
|||
|
|
{
|
|||
|
|
_buffer.SetAiBuffer(_source, ioVar.Block.Index, aiBuffer);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
foreach (var key in AoVariables.Keys)
|
|||
|
|
{
|
|||
|
|
var ioVar = AoVariables[key];
|
|||
|
|
var aoData = ReadAOut(ioVar.Name, (ushort)ioVar.Length);
|
|||
|
|
if (aoData != null)
|
|||
|
|
{
|
|||
|
|
var aoBuffer = ParseAO(key, aoData);
|
|||
|
|
if (aoBuffer != null)
|
|||
|
|
{
|
|||
|
|
_buffer.SetAoBuffer(_source, ioVar.Block.Index, aoBuffer);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private bool CommunicationError()
|
|||
|
|
{
|
|||
|
|
//_buffer.SetDiBuffer(_source, 0, new bool[1000]);
|
|||
|
|
//_buffer.SetDoBuffer(_source, 0, new bool[1000]);
|
|||
|
|
//_buffer.SetAiBufferFloat(_source, 0, new float[1000]);
|
|||
|
|
//_buffer.SetAoBufferFloat(_source, 0, new float[1000]);
|
|||
|
|
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected byte[] ReadDIn(string variable, ushort len)
|
|||
|
|
{
|
|||
|
|
if (!_trigConnected.M)
|
|||
|
|
return null;
|
|||
|
|
|
|||
|
|
if (_ads.BulkReadRenderResult(variable, len, out var data))
|
|||
|
|
return data;
|
|||
|
|
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
private byte[] ReadDOut(string variable, ushort len)
|
|||
|
|
{
|
|||
|
|
if (!_trigConnected.M)
|
|||
|
|
return null;
|
|||
|
|
|
|||
|
|
if (_ads.BulkReadRenderResult(variable, len, out var data))
|
|||
|
|
return (byte[])data;
|
|||
|
|
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected byte[] ReadAIn(string variable, ushort len)
|
|||
|
|
{
|
|||
|
|
if (!_trigConnected.M)
|
|||
|
|
return null;
|
|||
|
|
|
|||
|
|
if (_ads.BulkReadRenderResult(variable, len, out var data))
|
|||
|
|
return data;
|
|||
|
|
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
private byte[] ReadAOut(string variable, ushort len)
|
|||
|
|
{
|
|||
|
|
if (!_trigConnected.M)
|
|||
|
|
return null;
|
|||
|
|
|
|||
|
|
if (_ads.BulkReadRenderResult(variable, len, out var data))
|
|||
|
|
return (byte[])data;
|
|||
|
|
|
|||
|
|
return null;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private bool[] ParseDI(int blockIndex, byte[] inputValue)
|
|||
|
|
{
|
|||
|
|
var dataCount = inputValue.Length * 8;
|
|||
|
|
var result = new bool[dataCount];
|
|||
|
|
for (var i = 0; i < dataCount; i++)
|
|||
|
|
{
|
|||
|
|
var whichBit = i % 8;
|
|||
|
|
var whichByte = i % 8 == 0 ? i / 8 : (i - i % 8) / 8;
|
|||
|
|
|
|||
|
|
result[i] = ((inputValue[whichByte] >> whichBit) & 0x1) == 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
private bool[] ParseDO(int blockIndex, byte[] outputValue)
|
|||
|
|
{
|
|||
|
|
var dataCount = outputValue.Length * 8;
|
|||
|
|
var result = new bool[dataCount];
|
|||
|
|
for (var i = 0; i < dataCount; i++)
|
|||
|
|
{
|
|||
|
|
var whichBit = i % 8;
|
|||
|
|
var whichByte = i % 8 == 0 ? i / 8 : (i - i % 8) / 8;
|
|||
|
|
|
|||
|
|
result[i] = ((outputValue[whichByte] >> whichBit) & 0x1) == 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
private float[] ParseAI(int blockIndex, byte[] inputValue)
|
|||
|
|
{
|
|||
|
|
Debug.Assert(inputValue.Length % 4 == 0, "The length of 'inputValue' must be 4-byte align");
|
|||
|
|
|
|||
|
|
var dataCount = inputValue.Length / 4;
|
|||
|
|
var result = new float[dataCount];
|
|||
|
|
for (var i = 0; i < dataCount; i++)
|
|||
|
|
{
|
|||
|
|
if (blockIndex == 0)
|
|||
|
|
{
|
|||
|
|
var index = i;
|
|||
|
|
if (index <= 71 || index >= 108 && index <= 117 || index >= 181 || index == 119 || index == 123 || index == 124 || index == 125)
|
|||
|
|
{
|
|||
|
|
if (index >= 181)
|
|||
|
|
index += 181; // 跳过181个AO
|
|||
|
|
|
|||
|
|
result[i] = BitConverter.ToSingle([inputValue[index * 4 + 3], inputValue[index * 4 + 2], inputValue[index * 4 + 1], inputValue[index * 4]
|
|||
|
|
], 0);
|
|||
|
|
}
|
|||
|
|
else if (index >= 72 && index <= 103)
|
|||
|
|
{
|
|||
|
|
result[i] = BitConverter.ToSingle([inputValue[index * 4 + 3], inputValue[index * 4 + 2], inputValue[index * 4 + 1], inputValue[index * 4]
|
|||
|
|
], 0);
|
|||
|
|
}
|
|||
|
|
else if (index >= 104 && index <= 107 || index >= 118 && index <= 128)
|
|||
|
|
{
|
|||
|
|
result[i] = BitConverter.ToUInt32([inputValue[index * 4 + 3], inputValue[index * 4 + 2], inputValue[index * 4 + 1], inputValue[index * 4]
|
|||
|
|
], 0);
|
|||
|
|
}
|
|||
|
|
else if (index == 129)
|
|||
|
|
{
|
|||
|
|
result[i] = BitConverter.ToSingle([inputValue[index * 4 + 3], inputValue[index * 4 + 2], inputValue[index * 4 + 1], inputValue[index * 4]
|
|||
|
|
], 0);
|
|||
|
|
}
|
|||
|
|
else if (index >= 130 && index <= 180)
|
|||
|
|
{
|
|||
|
|
result[i] = BitConverter.ToInt32([inputValue[index * 4 + 3], inputValue[index * 4 + 2], inputValue[index * 4 + 1], inputValue[index * 4]
|
|||
|
|
], 0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
result[i] = BitConverter.ToSingle([
|
|||
|
|
inputValue[i * 4 + 3],
|
|||
|
|
inputValue[i * 4 + 2],
|
|||
|
|
inputValue[i * 4 + 1],
|
|||
|
|
inputValue[i * 4]
|
|||
|
|
], 0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
|
|||
|
|
/* var aiList = Singleton<IoManager>.Instance.GetAIList($"{Module}.io").Where(x=>x.BlockIndex == blockIndex);
|
|||
|
|
var result = new float[500];
|
|||
|
|
foreach (var aiAccessor in aiList)
|
|||
|
|
{
|
|||
|
|
var addr = aiAccessor.Addr;
|
|||
|
|
if (int.TryParse(addr, out var index))
|
|||
|
|
{
|
|||
|
|
var valve = BitConverter.ToSingle([
|
|||
|
|
inputValue[index * 4 + 3],
|
|||
|
|
inputValue[index * 4 + 2],
|
|||
|
|
inputValue[index * 4 + 1],
|
|||
|
|
inputValue[index * 4]
|
|||
|
|
], 0);
|
|||
|
|
result[aiAccessor.Index] = valve;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
return result;*/
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
private float[] ParseAO(int blockIndex, byte[] outputValue)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
Debug.Assert(outputValue.Length % 4 == 0, "The length of 'outputValue' must be 4-byte align");
|
|||
|
|
|
|||
|
|
var dataCount = outputValue.Length / 4;
|
|||
|
|
var result = new float[dataCount];
|
|||
|
|
for (var i = 0; i < dataCount; i++)
|
|||
|
|
{
|
|||
|
|
if (blockIndex == 0)
|
|||
|
|
{
|
|||
|
|
var index = i;
|
|||
|
|
var valve = 0.0f;
|
|||
|
|
|
|||
|
|
if (index >= 92 && index <= 103)
|
|||
|
|
{
|
|||
|
|
valve = BitConverter.ToSingle([outputValue[index * 4 + 3], outputValue[index * 4 + 2], outputValue[index * 4 + 1], outputValue[index * 4]
|
|||
|
|
], 0);
|
|||
|
|
}
|
|||
|
|
else if (index >= 104 && index <= 107)
|
|||
|
|
{
|
|||
|
|
valve = BitConverter.ToSingle([outputValue[index * 4 + 3], outputValue[index * 4 + 2], outputValue[index * 4 + 1], outputValue[index * 4]
|
|||
|
|
], 0);
|
|||
|
|
}
|
|||
|
|
else if (index <= 117 || index >= 181 || index == 129 || index == 122 || index == 123 || index == 124 || index == 125)
|
|||
|
|
{
|
|||
|
|
if (index >= 181)
|
|||
|
|
index += 100; // 跳过100个AI
|
|||
|
|
|
|||
|
|
valve = BitConverter.ToSingle([outputValue[index * 4 + 3], outputValue[index * 4 + 2], outputValue[index * 4 + 1], outputValue[index * 4]
|
|||
|
|
], 0);
|
|||
|
|
}
|
|||
|
|
else if (index >= 118 && index <= 128 && index != 119)
|
|||
|
|
{
|
|||
|
|
valve = BitConverter.ToUInt32([outputValue[index * 4 + 3], outputValue[index * 4 + 2], outputValue[index * 4 + 1], outputValue[index * 4]
|
|||
|
|
], 0);
|
|||
|
|
}
|
|||
|
|
else if (index >= 130 && index <= 180)
|
|||
|
|
{
|
|||
|
|
valve = BitConverter.ToInt32([outputValue[index * 4 + 3], outputValue[index * 4 + 2], outputValue[index * 4 + 1], outputValue[index * 4]
|
|||
|
|
], 0);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
result[i] = valve;
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
result[i] = BitConverter.ToSingle([
|
|||
|
|
outputValue[i * 4 + 3],
|
|||
|
|
outputValue[i * 4 + 2],
|
|||
|
|
outputValue[i * 4 + 1],
|
|||
|
|
outputValue[i * 4]
|
|||
|
|
], 0);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return result;
|
|||
|
|
}
|
|||
|
|
protected override short[] ReadAi(int offset, int size)
|
|||
|
|
{
|
|||
|
|
throw new NotImplementedException();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override bool[] ReadDi(int offset, int size)
|
|||
|
|
{
|
|||
|
|
throw new NotImplementedException();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
protected override void WriteAo(int offset, short[] buffer)
|
|||
|
|
{
|
|||
|
|
throw new NotImplementedException();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override void ReadDo(int offset, bool[] buffer)
|
|||
|
|
{
|
|||
|
|
throw new NotImplementedException();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override short[] ReadAo(int offset, int size)
|
|||
|
|
{
|
|||
|
|
throw new NotImplementedException();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected override void WriteDo(int offset, bool[] buffer)
|
|||
|
|
{
|
|||
|
|
throw new NotImplementedException();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
public override bool SetValue(AOAccessor aoItem, float value)
|
|||
|
|
{
|
|||
|
|
if (!_trigConnected.M)
|
|||
|
|
return false;
|
|||
|
|
|
|||
|
|
lock (_locker)
|
|||
|
|
{
|
|||
|
|
var data = new byte[4];
|
|||
|
|
|
|||
|
|
//// 获取下标,转换成Byte数组,然后写下去
|
|||
|
|
var addr = aoItem.Addr;
|
|||
|
|
var index = int.Parse(addr);
|
|||
|
|
var ioVar = AoVariables[aoItem.BlockIndex];
|
|||
|
|
|
|||
|
|
// Address: DB100.DBDxxx
|
|||
|
|
// target: xxx +index
|
|||
|
|
var stringSeparators = new string[] { "DBD" };
|
|||
|
|
var result = ioVar.Name.Split(stringSeparators, StringSplitOptions.None);
|
|||
|
|
int.TryParse(result[1], out var startIndex);
|
|||
|
|
var finalIndex = startIndex + index * sizeof(float); // 4 bytes per data
|
|||
|
|
var address = $"{result[0]}DBD{finalIndex}";
|
|||
|
|
|
|||
|
|
if (aoItem.BlockIndex == 0)
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
if (index >= 92 && index <= 103)
|
|||
|
|
{
|
|||
|
|
data = BitConverter.GetBytes(value);
|
|||
|
|
}
|
|||
|
|
else if (index <= 117 || index >= 181 || index == 129 || index == 119 || index == 122 || index == 123 || index == 124 || index == 125)
|
|||
|
|
{
|
|||
|
|
data = BitConverter.GetBytes(value);
|
|||
|
|
}
|
|||
|
|
else if (index >= 118 && index <= 128)
|
|||
|
|
{
|
|||
|
|
data = BitConverter.GetBytes((uint)value);
|
|||
|
|
}
|
|||
|
|
else if (index >= 130 && index <= 180)
|
|||
|
|
{
|
|||
|
|
data = BitConverter.GetBytes((int)value);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
data = BitConverter.GetBytes(value);
|
|||
|
|
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Array.Reverse(data);
|
|||
|
|
return _ads.BulkWriteByteRenderResult(address, data);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public override bool SetValue(DOAccessor doItem, bool value)
|
|||
|
|
{
|
|||
|
|
if (!_trigConnected.M)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!IO.CanSetDO(doItem.Name, value, out var reason))
|
|||
|
|
{
|
|||
|
|
LOG.Write(reason);
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
lock (_locker)
|
|||
|
|
{
|
|||
|
|
var ioVar = DoVariables[doItem.BlockIndex];
|
|||
|
|
|
|||
|
|
////获取单个DWORD数据,修改其中一位,然后整个Byte写下去
|
|||
|
|
var addr = doItem.Addr;
|
|||
|
|
var add = int.Parse(addr);
|
|||
|
|
var indexByte = add % 8;
|
|||
|
|
var index = add % 8 == 0 ? add / 8 : (add - add % 8) / 8;
|
|||
|
|
var val = 1 << indexByte;
|
|||
|
|
var output = ReadDOut(ioVar.Name, (ushort)ioVar.Length);
|
|||
|
|
if (output == null)
|
|||
|
|
{
|
|||
|
|
LOG.Write("ReadDOut = null , in SetValue()");
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
output[index] = value
|
|||
|
|
? Convert.ToByte(Convert.ToUInt16(output[index]) | val)
|
|||
|
|
: Convert.ToByte((Convert.ToUInt16(output[index]) & ~val));
|
|||
|
|
|
|||
|
|
|
|||
|
|
var stringSeparators = new string[] { "DBB" };
|
|||
|
|
var result = ioVar.Name.Split(stringSeparators, StringSplitOptions.None);
|
|||
|
|
int.TryParse(result[1], out var startIndex);
|
|||
|
|
var finalIndex = startIndex + index;
|
|||
|
|
var address = $"{result[0]}DBB{finalIndex}";
|
|||
|
|
var data = new byte[] { output[index] };
|
|||
|
|
|
|||
|
|
return _ads.BulkWriteByteRenderResult(address, data);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|