C# SCADA
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1405 lines
48 KiB

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO.Ports;
using System.Linq;
using System.Net;
using System.Text;
using System.Timers;
using DataService;
using HslCommunication.Profinet.Melsec;
namespace MelsecDriver
{
[Description("三菱Fx系列串口")]
//ModbusRTUReader : IPLCDriver IPLCDriver : IDriver, IReaderWriter IDriver : IDisposable
public sealed class FxSerialReader : IPLCDriver
{
#region : IDisposable
public void Dispose()
{
foreach (IGroup grp in _grps)
{
grp.Dispose();
}
_grps.Clear();
_fxSerial.Close();
}
#endregion
//从站地址
short _id;
public short ID
{
get { return _id; }
}
string _name;
public string Name
{
get { return _name; }
}
private string _serverName = "unknown";
public string ServerName
{
get { return _serverName; }
set { _serverName = value; }
}
public bool IsClosed
{
get { return _fxSerial == null || _fxSerial.IsOpen == false; }
}
IDataServer _server;
public IDataServer Parent
{
get { return _server; }
}
private string _port = "COM1";
[Category("串口设置"), Description("串口号")]
public string PortName
{
get { return _port; }
set { _port = value; }
}
private int _timeOut = 3000;
[Category("串口设置"), Description("通迅超时时间")]
public int TimeOut
{
get { return _timeOut; }
set { _timeOut = value; }
}
private int _baudRate = 9600;
[Category("串口设置"), Description("波特率")]
public int BaudRate
{
get { return _baudRate; }
set { _baudRate = value; }
}
private int _dataBits = 8;
[Category("串口设置"), Description("数据位")]
public int DataBits
{
get { return _dataBits; }
set { _dataBits = value; }
}
private StopBits _stopBits = StopBits.One;
[Category("串口设置"), Description("停止位")]
public StopBits StopBits
{
get { return _stopBits; }
set { _stopBits = value; }
}
private Parity _parity = Parity.None;
[Category("串口设置"), Description("奇偶校验")]
public Parity Parity
{
get { return _parity; }
set { _parity = value; }
}
private MelsecFxSerial _fxSerial;
public bool Connect()
{
_fxSerial = new MelsecFxSerial();
try
{
_fxSerial.SerialPortInni(sp =>
{
sp.PortName = _port;
sp.BaudRate = _baudRate;
sp.DataBits = _dataBits;
sp.StopBits = _stopBits;
sp.Parity = _parity;
});
_fxSerial.Open();
return true;
}
catch (Exception ex)
{
if (OnError != null)
OnError(this, new IOErrorEventArgs(ex.Message));
return false;
}
}
List<IGroup> _grps = new List<IGroup>();
public event IOErrorEventHandler OnError;
public IEnumerable<IGroup> Groups
{
get { return _grps; }
}
public IGroup AddGroup(string name, short id, int updateRate, float deadBand = 0, bool active = false)
{
FxShortGroup grp = new FxShortGroup(id, name, updateRate, active, this);
_grps.Add(grp);
return grp;
}
public bool RemoveGroup(IGroup grp)
{
grp.IsActive = false;
return _grps.Remove(grp);
}
//自定义构造函数3
public FxSerialReader(IDataServer server, short id, string name)
{
_id = id;
_name = name;
_server = server;
}
object _async = new object();
public byte[] ReadBytes(DeviceAddress address, ushort size)
{
string addr;
addr = GetAddress(address);
try
{
lock (_async)
{
if (address.DBNumber < 3)
{
var read = _fxSerial.ReadBool(addr, (ushort) (size * 16));
if (read.IsSuccess)
{
byte[] retBytes = new byte[size * 2];
Buffer.BlockCopy(read.Content,0,retBytes,0,size * 2);
return retBytes;
}
else
{
if (OnError != null)
OnError(this, new IOErrorEventArgs(read.Message));
return null;
}
}
else
{
var read = _fxSerial.Read(addr, size);
if (read.IsSuccess)
{
return read.Content;
}
else
{
if (OnError != null)
OnError(this, new IOErrorEventArgs(read.Message));
return null;
}
}
}
}
catch (Exception e)
{
if (OnError != null)
OnError(this, new IOErrorEventArgs(e.Message));
return null;
}
}
public ItemData<uint> ReadUInt32(DeviceAddress address)
{
byte[] bit = ReadBytes(address, 2);
return bit == null ? new ItemData<uint>(0, 0, QUALITIES.QUALITY_BAD) :
new ItemData<uint>(BitConverter.ToUInt32(bit, 0), 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<int> ReadInt32(DeviceAddress address)
{
byte[] bit = ReadBytes(address, 2);
return bit == null ? new ItemData<int>(0, 0, QUALITIES.QUALITY_BAD) :
new ItemData<int>(BitConverter.ToInt32(bit, 0), 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<ushort> ReadUInt16(DeviceAddress address)
{
byte[] bit = ReadBytes(address, 1);
return bit == null ? new ItemData<ushort>(0, 0, QUALITIES.QUALITY_BAD) :
new ItemData<ushort>(BitConverter.ToUInt16(bit, 0), 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<short> ReadInt16(DeviceAddress address)
{
byte[] bit = ReadBytes(address, 1);
return bit == null ? new ItemData<short>(0, 0, QUALITIES.QUALITY_BAD) :
new ItemData<short>(BitConverter.ToInt16(bit, 0), 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<byte> ReadByte(DeviceAddress address)
{
byte[] bit = ReadBytes(address, 1);
return bit == null ? new ItemData<byte>(0, 0, QUALITIES.QUALITY_BAD) :
new ItemData<byte>(bit[0], 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<string> ReadString(DeviceAddress address, ushort size)
{
byte[] bit = ReadBytes(address, size);
return bit == null ? new ItemData<string>(string.Empty, 0, QUALITIES.QUALITY_BAD) :
new ItemData<string>(Encoding.ASCII.GetString(bit), 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<float> ReadFloat(DeviceAddress address)
{
byte[] bit = ReadBytes(address, 2);
return bit == null ? new ItemData<float>(0f, 0, QUALITIES.QUALITY_BAD) :
new ItemData<float>(BitConverter.ToSingle(bit, 0), 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<bool> ReadBit(DeviceAddress address)
{
byte[] bit = ReadBytes(address, 1);
return bit == null ? new ItemData<bool>(false, 0, QUALITIES.QUALITY_BAD) :
new ItemData<bool>((bit[0] & (1 << (address.Bit))) > 0, 0, QUALITIES.QUALITY_GOOD);
}
public ItemData<object> ReadValue(DeviceAddress address)
{
return this.ReadValueEx(address);
}
public int WriteBytes(DeviceAddress address, byte[] bit)
{
return Writes(address, bit);
}
public int WriteBit(DeviceAddress address, bool bit)
{
try
{
lock (_async)
{
string addr = GetAddress(address);
var ret = _fxSerial.Write(addr, bit);
if (ret.IsSuccess)
{
return 0;
}
else
{
if (OnError != null)
{
OnError(this, new IOErrorEventArgs(ret.Message));
}
return -1;
}
}
}
catch (Exception e)
{
if (OnError != null)
{
OnError(this, new IOErrorEventArgs(e.Message));
}
return -1;
}
}
public int WriteBits(DeviceAddress address, byte bits)
{
return Writes(address, new byte[] {bits});
}
public int WriteInt16(DeviceAddress address, short value)
{
return Writes(address, BitConverter.GetBytes(value));
}
public int WriteUInt16(DeviceAddress address, ushort value)
{
return Writes(address, BitConverter.GetBytes(value));
}
public int WriteInt32(DeviceAddress address, int value)
{
return Writes(address, BitConverter.GetBytes(value));
}
public int WriteUInt32(DeviceAddress address, uint value)
{
return Writes(address, BitConverter.GetBytes(value));
}
public int WriteFloat(DeviceAddress address, float value)
{
return Writes(address, BitConverter.GetBytes(value));
}
public int WriteString(DeviceAddress address, string str)
{
return Writes(address, Encoding.ASCII.GetBytes(str));
}
private int Writes(DeviceAddress address, byte[] bytes)
{
try
{
lock (_async)
{
string addr = GetAddress(address);
var ret = _fxSerial.Write(addr, bytes);
if (ret.IsSuccess)
{
return 0;
}
else
{
if (OnError != null)
{
OnError(this, new IOErrorEventArgs(ret.Message));
}
return -1;
}
}
}
catch (Exception e)
{
if (OnError != null)
{
OnError(this, new IOErrorEventArgs(e.Message));
}
return -1;
}
}
public int WriteValue(DeviceAddress address, object value)
{
return this.WriteValueEx(address, value);
}
public int PDU { get; }
//将三菱PLC的地址解析为modbus地址格式,参考bcnet的地址解析方式
//T/C暂存器分为bool类型和word类型,采用地址的第二码区分,第二码A表示bool,第二码为B表示word, 默认则为读取word值
private string ParseAddress(TagMetaData meta)
{
string address = meta.Address;
int m, n;
string newaddress = "";
switch (address[0])
{
case 'Y':
case 'y':
int.TryParse(address.Substring(1, address.Length - 2), out m);
int.TryParse(address.Substring(address.Length - 1), out n);
newaddress = '0' + (m * 8 + n).ToString().PadLeft(5, '0');
break;
case 'M':
case 'm':
int.TryParse(address.Substring(1, address.Length - 1), out m);
if (m >= 8000)
{
newaddress = '0' + (5001 + (m - 8000)).ToString().PadLeft(5, '0');
}
else
{
newaddress = '0' + (10001 + m).ToString().PadLeft(5, '0');
}
break;
case 'T':
case 't':
if (meta.DataType == DataType.BOOL)
{
int.TryParse(address.Substring(1, address.Length - 1), out m);
newaddress = '0' + (6001 + m).ToString().PadLeft(5, '0');
}
else
{
int.TryParse(address.Substring(1, address.Length - 1), out m);
newaddress = '4' + (1 + m).ToString().PadLeft(5, '0');
}
break;
case 'C':
case 'c':
if (meta.DataType == DataType.BOOL)
{
int.TryParse(address.Substring(1, address.Length - 1), out m);
newaddress = '0' + (7001 + m).ToString().PadLeft(5, '0');
}
else
{
int.TryParse(address.Substring(1, address.Length - 1), out m);
newaddress = '4' + (1001 + m).ToString().PadLeft(5, '0');
}
break;
case 'S':
case 's':
int.TryParse(address.Substring(1, address.Length - 1), out m);
newaddress = '0' + (30001 + m).ToString().PadLeft(5, '0');
break;
case 'X':
case 'x':
int.TryParse(address.Substring(1, address.Length - 2), out m);
int.TryParse(address.Substring(address.Length - 1), out n);
newaddress = '1' + (1 + m * 8 + n).ToString().PadLeft(5, '0');
break;
case 'D':
case 'd':
int.TryParse(address.Substring(1, address.Length - 1), out m);
if (m >= 8000)
{
newaddress = '4' + (1301 + m - 8000).ToString().PadLeft(5, '0');
}
else
{
newaddress = '4' + (2001 + m).ToString().PadLeft(5, '0');
}
break;
}
return newaddress;
}
public DeviceAddress GetDeviceAddress(string address)
{
DeviceAddress dv = DeviceAddress.Empty;
if (string.IsNullOrEmpty(address))
return dv;
if (string.IsNullOrEmpty(address))
return dv;
switch (address[0])
{
case '0':
{
dv.DBNumber = Fx.fctReadCoil;
int st;
int.TryParse(address, out st);
st--;
dv.Bit = (byte)(st % 16);
st /= 16;
dv.Start = st;
//dv.Bit--;
}
break;
case '1':
{
dv.DBNumber = Fx.fctReadDiscreteInputs;
int st;
int.TryParse(address.Substring(1), out st);
st--;
dv.Bit = (byte)(st % 16);
st /= 16;
dv.Start = st;
//dv.Bit--;
}
break;
case '4':
{
int index = address.IndexOf('.');
dv.DBNumber = Fx.fctReadHoldingRegister;
if (index > 0)
{
dv.Start = int.Parse(address.Substring(1, index - 1));
dv.Bit = byte.Parse(address.Substring(index + 1));
}
else
dv.Start = int.Parse(address.Substring(1));
dv.Start--;
dv.Bit--;
dv.ByteOrder = ByteOrder.BigEndian;
}
break;
case '3':
break;
}
return dv;
}
public DeviceAddress GetDeviceAddress(TagMetaData meta)
{
string newaddress = ParseAddress(meta);
return GetDeviceAddress(newaddress);
}
public string GetAddress(DeviceAddress dv)
{
string address = "", newaddress = "";
int addr;
switch (dv.DBNumber)
{
case Fx.fctReadCoil:
address = '0' + (dv.Start * 16 + dv.Bit + 1).ToString().PadLeft(5, '0');
int.TryParse(address, out addr);
if (addr >= 30001)
{
newaddress = "S" + (addr - 30001).ToString();
}
else if (addr >= 10001)
{
newaddress = "M" + (addr - 10001).ToString();
}
else if (addr >= 7001)
{
newaddress = "C" + (addr - 7001).ToString();
}
else if (addr >= 6001)
{
newaddress = "T" + (addr - 6001).ToString();
}
else if (addr >= 5001)
{
newaddress = "M8" + (addr - 5001).ToString().PadLeft(3, '0');
}
else
{
newaddress = "Y" + Convert.ToString(addr - 1, 8);
}
break;
case Fx.fctReadDiscreteInputs:
address = "1" + (dv.Start * 16 + dv.Bit + 1).ToString().PadLeft(5, '0');
int.TryParse(address, out addr);
newaddress = "X" + Convert.ToString(addr - 100001, 8);
break;
case Fx.fctReadHoldingRegister:
address = "4" + (dv.Start * 16 + 1).ToString().PadLeft(5, '0');
int.TryParse(address, out addr);
if (addr >= 420001)
{
newaddress = "R" + (addr - 420001).ToString();
}
else if (addr >= 402001)
{
newaddress = "D" + (addr - 402001).ToString();
}
else if (addr >= 401301)
{
newaddress = "D8" + (addr - 401301).ToString().PadLeft(3, '0');
}
else if (addr >= 401001)
{
newaddress = "C" + (addr - 401001).ToString();
}
else if (addr >= 400001)
{
newaddress = "T" + (addr - 400001).ToString();
}
break;
case Fx.fctReadInputRegister:
break;
}
return newaddress;
}
}
public sealed class Fx
{
public const byte fctReadCoil = 1;
public const byte fctReadDiscreteInputs = 2;
public const byte fctReadHoldingRegister = 3;
public const byte fctReadInputRegister = 4;
public const byte fctWriteSingleCoil = 5;
public const byte fctWriteSingleRegister = 6;
public const byte fctWriteMultipleCoils = 15;
public const byte fctWriteMultipleRegister = 16;
public const byte fctReadWriteMultipleRegister = 23;
}
public class FxShortGroup : IGroup
{
protected Timer _timer;
protected bool _isActive;
public virtual bool IsActive
{
get
{
return _isActive;
}
set
{
_isActive = value;
if (value)
{
if (_updateRate <= 0) _updateRate = 100;
_timer.Interval = _updateRate;
_timer.Elapsed += new ElapsedEventHandler(timer_Timer);
_timer.Start();
}
else
{
_timer.Elapsed -= new ElapsedEventHandler(timer_Timer);
_timer.Stop();
}
}
}
protected short _id;
public short ID
{
get
{
return _id;
}
}
protected int _updateRate;
public int UpdateRate
{
get
{
return _updateRate;
}
set
{
_updateRate = value;
}
}
protected string _name;
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
protected float _deadband;
public float DeadBand
{
get
{
return _deadband;
}
set
{
_deadband = value;
}
}
protected ICache _cacheReader;
protected IPLCDriver _plcReader;
public IDriver Parent
{
get
{
return _plcReader;
}
}
protected List<int> _changedList;
public List<int> ChangedList
{
get
{
return _changedList;
}
}
protected List<ITag> _items;
public IEnumerable<ITag> Items
{
get { return _items; }
}
protected IDataServer _server;
public IDataServer Server
{
get
{
return _server;
}
}
protected List<PDUArea> _rangeList = new List<PDUArea>();
protected FxShortGroup()
{
}
public FxShortGroup(short id, string name, int updateRate, bool active, IPLCDriver plcReader)
{
this._id = id;
this._name = name;
this._updateRate = updateRate;
this._isActive = active;
this._plcReader = plcReader;
this._server = _plcReader.Parent;
this._timer = new Timer();
this._changedList = new List<int>();
this._cacheReader = new ShortCacheReader();
}
public bool AddItems(IList<TagMetaData> items)
{
FxSerialReader fxReader = _plcReader as FxSerialReader;
if (fxReader == null) return false;
int count = items.Count;
if (_items == null) _items = new List<ITag>(count);
lock (_server.SyncRoot)
{
for (int i = 0; i < count; i++)
{
ITag dataItem = null;
TagMetaData meta = items[i];
if (meta.GroupID == this._id)
{
DeviceAddress addr = fxReader.GetDeviceAddress(meta);
if (addr.DataSize == 0) addr.DataSize = meta.Size;
if (addr.VarType == DataType.NONE) addr.VarType = meta.DataType;
if (addr.VarType != DataType.BOOL) addr.Bit = 0;
switch (meta.DataType)
{
case DataType.BOOL:
dataItem = new BoolTag(meta.ID, addr, this);
break;
case DataType.BYTE:
dataItem = new ByteTag(meta.ID, addr, this);
break;
case DataType.WORD:
dataItem = new UShortTag(meta.ID, addr, this);
break;
case DataType.SHORT:
dataItem = new ShortTag(meta.ID, addr, this);
break;
case DataType.DWORD:
dataItem = new UIntTag(meta.ID, addr, this);
break;
case DataType.INT:
dataItem = new IntTag(meta.ID, addr, this);
break;
case DataType.FLOAT:
dataItem = new FloatTag(meta.ID, addr, this);
break;
case DataType.STR:
dataItem = new StringTag(meta.ID, addr, this);
break;
}
if (dataItem != null)
{
//dataItem.Active = meta.Active;
_items.Add(dataItem);
_server.AddItemIndex(meta.Name, dataItem);
}
}
}
}
_items.TrimExcess();
_items.Sort((x, y) => x.Address.CompareTo(y.Address));
UpdatePDUArea();
return true;
}
public bool AddTags(IEnumerable<ITag> tags)
{
if (_items == null)
{
_items = new List<ITag>();
}
foreach (ITag tag in tags)
{
if (tag != null)
{
_items.Add(tag);
}
}
_items.TrimExcess();
_items.Sort((x, y) => x.Address.CompareTo(y.Address));
UpdatePDUArea();
return true;
}
public bool RemoveItems(params ITag[] items)
{
foreach (var item in items)
{
_server.RemoveItemIndex(item.GetTagName());
_items.Remove(item);
}
UpdatePDUArea();
return true;
}
protected void UpdatePDUArea()
{
int count = _items.Count;
if (count > 0)
{
DeviceAddress _start = _items[0].Address;
_start.Bit = 0;
int bitCount = _cacheReader.ByteCount;
if (count > 1)
{
int cacheLength = 0;//缓冲区的大小
int cacheIndexStart = 0;
int startIndex = 0;
DeviceAddress segmentEnd = DeviceAddress.Empty;
DeviceAddress tagAddress = DeviceAddress.Empty;
DeviceAddress segmentStart = _start;
for (int j = 1, i = 1; i < count; i++, j++)
{
tagAddress = _items[i].Address;//当前变量地址
int offset1 = _cacheReader.GetOffset(tagAddress, segmentStart);
if (offset1 > (_plcReader.PDU - tagAddress.DataSize) / bitCount)
{
segmentEnd = _items[i - 1].Address;
int len = _cacheReader.GetOffset(segmentEnd, segmentStart);
len += segmentEnd.DataSize <= bitCount ? 1 : segmentEnd.DataSize / bitCount;
tagAddress.CacheIndex = (ushort)(cacheIndexStart + len);
_items[i].Address = tagAddress;
_rangeList.Add(new PDUArea(segmentStart, len, startIndex, j));
startIndex += j; j = 0;
cacheLength += len;//更新缓存长度
cacheIndexStart = cacheLength;
segmentStart = tagAddress;//更新数据片段的起始地址
}
else
{
tagAddress.CacheIndex = (ushort)(cacheIndexStart + offset1);
_items[i].Address = tagAddress;
}
if (i == count - 1)
{
segmentEnd = _items[i].Address;
int segmentLength = _cacheReader.GetOffset(segmentEnd, segmentStart);
if (segmentLength > (_plcReader.PDU - segmentEnd.DataSize) / bitCount)
{
segmentEnd = _items[i - 1].Address;
segmentLength = segmentEnd.DataSize <= bitCount ? 1 : segmentEnd.DataSize / bitCount;
}
tagAddress.CacheIndex = (ushort)(cacheIndexStart + segmentLength);
_items[i].Address = tagAddress;
segmentLength += segmentEnd.DataSize <= bitCount ? 1 : segmentEnd.DataSize / bitCount;
_rangeList.Add(new PDUArea(segmentStart, segmentLength, startIndex, j + 1));
cacheLength += segmentLength;
}
}
_cacheReader.Size = cacheLength;
}
else
{
var size = _start.DataSize <= bitCount ? 1 : _start.DataSize / bitCount;
_rangeList.Add(new PDUArea(_start, size, 0, 1));
_cacheReader.Size = size;//改变Cache的Size属性值将创建Cache的内存区域
}
}
}
public ITag FindItemByAddress(DeviceAddress addr)
{
int index = _items.BinarySearch(new BoolTag(0, addr, null));
return index < 0 ? null : _items[index];
}
public bool SetActiveState(bool active, params short[] items)
{
return false;
}
object sync = new object();
public void Flush()
{
lock (sync)
{
_changedList.Clear();
Poll();
if (_changedList.Count > 0)
Update();
}
}
protected void timer_Timer(object sender, EventArgs e)
{
//Modified Kevin
if (_isActive && !_plcReader.IsClosed)
{
lock (sync)
{
_changedList.Clear();
Poll();
if (_changedList.Count > 0)
Update();
}
}
else
return;
}
protected virtual unsafe void Poll()
{
short[] cache = (short[])_cacheReader.Cache;
int k = 0;
foreach (PDUArea area in _rangeList)
{
byte[] rcvBytes = _plcReader.ReadBytes(area.Start, (ushort)area.Len);//从PLC读取数据
if (rcvBytes == null)
{
k += (area.Len + 1) / 2;
continue;
}
else
{
int len = rcvBytes.Length / 2;
fixed (byte* p1 = rcvBytes)
{
short* prcv = (short*)p1;
int index = area.StartIndex;//index指向_items中的Tag元数据
int count = index + area.Count;
while (index < count)
{
DeviceAddress addr = _items[index].Address;
int iShort = addr.CacheIndex;
int iShort1 = iShort - k;
if (addr.VarType == DataType.BOOL)
{
int tmp = prcv[iShort1] ^ cache[iShort];
DeviceAddress next = addr;
if (tmp != 0)
{
while (addr.Start == next.Start)
{
if ((tmp & (1 << next.Bit)) > 0) _changedList.Add(index);
if (++index < count)
next = _items[index].Address;
else
break;
}
}
else
{
while (addr.Start == next.Start && ++index < count)
{
next = _items[index].Address;
}
}
}
else
{
if (addr.ByteOrder.HasFlag(ByteOrder.BigEndian))
{
for (int i = 0; i < addr.DataSize / 2; i++)
{
prcv[iShort1 + i] = IPAddress.HostToNetworkOrder(prcv[iShort1 + i]);
}
}
if (addr.DataSize <= 2)
{
if (prcv[iShort1] != cache[iShort]) _changedList.Add(index);
}
else
{
int size = addr.DataSize / 2;
for (int i = 0; i < size; i++)
{
if (prcv[iShort1 + i] != cache[iShort + i])
{
_changedList.Add(index);
break;
}
}
}
index++;
}
}
short[] prcvShorts = new short[len];
for (int i = 0; i < len; i++)
{
prcvShorts[i] = prcv[i];
}
//改成Array.Copy 由于线程安全的问题
Array.Copy(prcvShorts, 0, cache, k, len);
/*
for (int j = 0; j < len; j++)
{
cache[j + offset] = prcv[j];
}//将PLC读取的数据写入到CacheReader中
*/
}
k += len;
}
}
}
protected void Update()
{
DateTime dt = DateTime.Now;
if (DataChange != null)
{
HistoryData[] values = new HistoryData[_changedList.Count];
int i = 0;
foreach (int index in _changedList)
{
ITag item = _items[index];
var itemData = item.Read();
if (item.Active)
item.Update(itemData, dt, QUALITIES.QUALITY_GOOD);
if (_deadband == 0 || (item.Address.VarType == DataType.FLOAT &&
(Math.Abs(itemData.Single / item.Value.Single - 1) > _deadband)))
{
values[i].ID = item.ID;
values[i].Quality = item.Quality;
values[i].Value = itemData;
values[i].TimeStamp = item.TimeStamp;
i++;
}
}
foreach (DataChangeEventHandler deleg in DataChange.GetInvocationList())
{
deleg.BeginInvoke(this, new DataChangeEventArgs(1, values), null, null);
}
}
else
{
foreach (int index in _changedList)
{
ITag item = _items[index];
if (item.Active)
item.Update(item.Read(), dt, QUALITIES.QUALITY_GOOD);
}
}
}
public void Dispose()
{
if (_timer != null)
_timer.Dispose();
//if (_items != null)
// _items.Clear();
}
public virtual HistoryData[] BatchRead(DataSource source, bool isSync, params ITag[] itemArray)
{
int len = itemArray.Length;
HistoryData[] values = new HistoryData[len];
if (source == DataSource.Device)
{
IMultiReadWrite multi = _plcReader as IMultiReadWrite;
if (multi != null)
{
Array.Sort(itemArray);
var itemArr = multi.ReadMultiple(Array.ConvertAll(itemArray, x => x.Address));
for (int i = 0; i < len; i++)
{
values[i].ID = itemArray[i].ID;
values[i].Value = itemArr[i].Value;
values[i].TimeStamp = itemArr[i].TimeStamp.ToDateTime();
itemArray[i].Update(itemArr[i].Value, values[i].TimeStamp, itemArr[i].Quality);
}
}
else
{
for (int i = 0; i < len; i++)
{
itemArray[i].Refresh(source);
values[i].ID = itemArray[i].ID;
values[i].Value = itemArray[i].Value;
values[i].Quality = itemArray[i].Quality;
values[i].TimeStamp = itemArray[i].TimeStamp;
}
}
}
else
{
for (int i = 0; i < len; i++)
{
values[i].ID = itemArray[i].ID;
values[i].Value = itemArray[i].Value;
values[i].Quality = itemArray[i].Quality;
values[i].TimeStamp = itemArray[i].TimeStamp;
}
}
return values;
}
public virtual int BatchWrite(SortedDictionary<ITag, object> items, bool isSync = true)
{
int len = items.Count;
int rev = 0;
IMultiReadWrite multi = _plcReader as IMultiReadWrite;
if (multi != null)
{
DeviceAddress[] addrs = new DeviceAddress[len];
object[] objs = new object[len];
int i = 0;
foreach (var item in items)
{
addrs[i] = item.Key.Address;
objs[i] = item.Value;
i++;
}
rev = multi.WriteMultiple(addrs, objs);
}
else
{
foreach (var tag in items)
{
if (tag.Key.Write(tag.Value) < 0)
rev = -1;
}
}
if (DataChange != null && rev >= 0)
{
HistoryData[] data = new HistoryData[len];
int i = 0;
foreach (var item in items)
{
ITag tag = item.Key;
data[i].ID = tag.ID;
data[i].TimeStamp = tag.TimeStamp;
data[i].Quality = tag.Quality;
data[i].Value = item.Key.ToStorage(item.Value);
i++;
}
foreach (DataChangeEventHandler deleg in DataChange.GetInvocationList())
{
deleg.BeginInvoke(this, new DataChangeEventArgs(1, data), null, null);
}
}
return rev;
}
public ItemData<int> ReadInt32(DeviceAddress address, DataSource source = DataSource.Cache)
{
return source == DataSource.Cache ? _cacheReader.ReadInt32(address) : _plcReader.ReadInt32(address);
}
public ItemData<uint> ReadUInt32(DeviceAddress address, DataSource source = DataSource.Cache)
{
return source == DataSource.Cache ? _cacheReader.ReadUInt32(address) : _plcReader.ReadUInt32(address);
}
public ItemData<ushort> ReadUInt16(DeviceAddress address, DataSource source = DataSource.Cache)
{
return source == DataSource.Cache ? _cacheReader.ReadUInt16(address) : _plcReader.ReadUInt16(address);
}
public ItemData<short> ReadInt16(DeviceAddress address, DataSource source = DataSource.Cache)
{
return source == DataSource.Cache ? _cacheReader.ReadInt16(address) : _plcReader.ReadInt16(address);
}
public ItemData<byte> ReadByte(DeviceAddress address, DataSource source = DataSource.Cache)
{
return source == DataSource.Cache ? _cacheReader.ReadByte(address) : _plcReader.ReadByte(address);
}
public ItemData<float> ReadFloat(DeviceAddress address, DataSource source = DataSource.Cache)
{
return source == DataSource.Cache ? _cacheReader.ReadFloat(address) : _plcReader.ReadFloat(address);
}
public ItemData<bool> ReadBool(DeviceAddress address, DataSource source = DataSource.Cache)
{
return source == DataSource.Cache ? _cacheReader.ReadBit(address) : _plcReader.ReadBit(address);
}
public ItemData<string> ReadString(DeviceAddress address, DataSource source = DataSource.Cache)
{
ushort siz = address.DataSize;
return source == DataSource.Cache ? _cacheReader.ReadString(address, siz) :
_plcReader.ReadString(address, siz);
}
public int WriteInt32(DeviceAddress address, int value)
{
int rs = _plcReader.WriteInt32(address, value);
if (rs >= 0)
{
if (DataChange != null)
{
ITag tag = GetTagByAddress(address);
if (tag != null)
DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
{
new HistoryData(tag.ID,QUALITIES.QUALITY_GOOD,new Storage{Int32=value}, DateTime.Now)
}));
}
}
return rs;
}
public int WriteUInt32(DeviceAddress address, uint value)
{
int rs = _plcReader.WriteUInt32(address, value);
if (rs >= 0)
{
if (DataChange != null)
{
ITag tag = GetTagByAddress(address);
if (tag != null)
DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
{
new HistoryData(tag.ID,QUALITIES.QUALITY_GOOD,new Storage{DWord=value}, DateTime.Now)
}));
}
}
return rs;
}
public int WriteUInt16(DeviceAddress address, ushort value)
{
int rs = _plcReader.WriteUInt16(address, value);
if (rs >= 0)
{
if (DataChange != null)
{
ITag tag = GetTagByAddress(address);
if (tag != null)
DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
{
new HistoryData(tag.ID,QUALITIES.QUALITY_GOOD,new Storage{Word=value}, DateTime.Now)
}));
}
}
return rs;
}
public int WriteInt16(DeviceAddress address, short value)
{
int rs = _plcReader.WriteInt16(address, value);
if (rs >= 0)
{
if (DataChange != null)
{
ITag tag = GetTagByAddress(address);
if (tag != null)
DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
{
new HistoryData(tag.ID,QUALITIES.QUALITY_GOOD,new Storage{Int16=value}, DateTime.Now)
}));
}
}
return rs;
}
public int WriteFloat(DeviceAddress address, float value)
{
int rs = _plcReader.WriteFloat(address, value);
if (rs >= 0)
{
if (DataChange != null)
{
ITag tag = GetTagByAddress(address);
if (tag != null)
DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
{
new HistoryData(tag.ID,QUALITIES.QUALITY_GOOD,new Storage{Single=value}, DateTime.Now)
}));
}
}
return rs;
}
public int WriteString(DeviceAddress address, string value)
{
int rs = _plcReader.WriteString(address, value);
if (rs >= 0)
{
if (DataChange != null)
{
ITag tag = GetTagByAddress(address);
if (tag != null)
DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
{
new HistoryData(tag.ID,QUALITIES.QUALITY_GOOD,Storage.Empty, DateTime.Now)
}));
}
}
return rs;
}
public int WriteBit(DeviceAddress address, bool value)
{
int rs = _plcReader.WriteBit(address, value);
if (rs >= 0)
{
if (DataChange != null)
{
ITag tag = GetTagByAddress(address);
if (tag != null)
DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
{
new HistoryData(tag.ID,QUALITIES.QUALITY_GOOD,new Storage{Boolean=value}, DateTime.Now)
}));
}
}
return rs;
}
public int WriteBits(DeviceAddress address, byte value)
{
int rs = _plcReader.WriteBits(address, value);
if (rs >= 0)
{
if (DataChange != null)
{
ITag tag = GetTagByAddress(address);
if (tag != null)
DataChange(this, new DataChangeEventArgs(1, new HistoryData[1]
{
new HistoryData(tag.ID,QUALITIES.QUALITY_GOOD,new Storage{Byte=value}, DateTime.Now)
}));
}
}
return rs;
}
private ITag GetTagByAddress(DeviceAddress addr)
{
int index = _items.BinarySearch(new BoolTag(0, addr, null));
return index < 0 ? null : _items[index];
}
public event DataChangeEventHandler DataChange;
}
}