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.
808 lines
31 KiB
808 lines
31 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Text;
|
|
using System.Timers;
|
|
using DataService;
|
|
|
|
namespace SiemensPLCDriver
|
|
{
|
|
[Description("S7 以太网协议")]
|
|
public sealed class SiemensTCPReader : IPLCDriver, IMultiReadWrite
|
|
{
|
|
libnodave.daveOSserialType fds;
|
|
libnodave.daveInterface di;
|
|
internal libnodave.daveConnection dc;
|
|
int _rack;
|
|
int _slot;
|
|
string _IP;
|
|
object _async = new object();
|
|
DateTime _closeTime = DateTime.Now;
|
|
|
|
short _id;
|
|
public short ID
|
|
{
|
|
get
|
|
{
|
|
return _id;
|
|
}
|
|
}
|
|
|
|
bool _closed = true;
|
|
public bool IsClosed
|
|
{
|
|
get
|
|
{
|
|
return _closed;
|
|
}
|
|
}
|
|
|
|
public int PDU
|
|
{
|
|
get
|
|
{
|
|
return 220;//240
|
|
}
|
|
}
|
|
|
|
int _timeOut = 1000;
|
|
public int TimeOut
|
|
{
|
|
get
|
|
{
|
|
return _timeOut;
|
|
}
|
|
set
|
|
{
|
|
_timeOut = value;
|
|
}
|
|
}
|
|
|
|
string _name;
|
|
public string Name
|
|
{
|
|
get
|
|
{
|
|
return _name;
|
|
}
|
|
}
|
|
|
|
public string ServerName
|
|
{
|
|
get
|
|
{
|
|
return _IP;
|
|
}
|
|
set
|
|
{
|
|
_IP = value;
|
|
}
|
|
}
|
|
|
|
public int Rack
|
|
{
|
|
get
|
|
{
|
|
return _rack;
|
|
}
|
|
set
|
|
{
|
|
_rack = value;
|
|
}
|
|
}
|
|
|
|
public int Slot
|
|
{
|
|
get
|
|
{
|
|
return _slot;
|
|
}
|
|
set
|
|
{
|
|
_slot = value;
|
|
}
|
|
}
|
|
|
|
public SiemensTCPReader(IDataServer server, short id, string name)
|
|
{
|
|
_id = id;
|
|
_server = server;
|
|
_name = name;
|
|
}
|
|
|
|
List<IGroup> _groups = new List<IGroup>();
|
|
public IEnumerable<IGroup> Groups
|
|
{
|
|
get { return _groups; }
|
|
}
|
|
|
|
IDataServer _server;
|
|
public IDataServer Parent
|
|
{
|
|
get { return _server; }
|
|
}
|
|
|
|
public IGroup AddGroup(string name, short id, int updateRate, float deadBand, bool active)
|
|
{
|
|
NetBytePLCGroup grp = new NetBytePLCGroup(id, name, updateRate, active, this);
|
|
_groups.Add(grp);
|
|
return grp;
|
|
}
|
|
|
|
public bool RemoveGroup(IGroup grp)
|
|
{
|
|
grp.IsActive = false;
|
|
return _groups.Remove(grp);
|
|
}
|
|
|
|
private static readonly Dictionary<char, int> dict = new Dictionary<char, int>(){ {'M',libnodave.daveFlags},
|
|
{'I',libnodave.daveInputs},{'Q',libnodave.daveOutputs}};
|
|
|
|
public string GetAddress(DeviceAddress address)
|
|
{
|
|
string addr = (address.Area == libnodave.daveDB ? string.Concat("DB", address.DBNumber, ",D") :
|
|
address.Area == libnodave.daveFlags ? "M" :
|
|
address.Area == libnodave.daveInputs ? "I" : "Q");
|
|
switch (address.VarType)
|
|
{
|
|
case DataType.BOOL:
|
|
return string.Concat(addr, address.Start, ".", address.Bit);
|
|
case DataType.BYTE:
|
|
return string.Concat(addr, "BB", address.Start);
|
|
case DataType.WORD:
|
|
case DataType.SHORT:
|
|
return string.Concat(addr, "W", address.Start);
|
|
case DataType.FLOAT:
|
|
case DataType.DWORD:
|
|
case DataType.INT:
|
|
return string.Concat(addr, "D", address.Start);
|
|
default:
|
|
return string.Concat(addr, "BB", address.Start);
|
|
}
|
|
}
|
|
|
|
public DeviceAddress GetDeviceAddress(string address)
|
|
{
|
|
DeviceAddress plcAddr = new DeviceAddress();
|
|
if (string.IsNullOrEmpty(address) || address.Length < 2) return plcAddr;
|
|
if (address.Substring(0, 2) == "DB")
|
|
{
|
|
int index = 2;
|
|
for (int i = index; i < address.Length; i++)
|
|
{
|
|
if (!char.IsDigit(address[i]))
|
|
{
|
|
index = i; break;
|
|
}
|
|
}
|
|
plcAddr.Area = libnodave.daveDB;
|
|
plcAddr.DBNumber = ushort.Parse(address.Substring(2, index - 2));
|
|
string str = address.Substring(index + 1);
|
|
if (!char.IsDigit(str[0]))
|
|
{
|
|
for (int i = 1; i < str.Length; i++)
|
|
{
|
|
if (char.IsDigit(str[i]))
|
|
{
|
|
index = i; break;
|
|
}
|
|
}
|
|
if (str[2] == 'W')
|
|
{
|
|
int index1 = str.IndexOf('.');
|
|
if (index1 > 0)
|
|
{
|
|
int start = int.Parse(str.Substring(3, index1 - 3));
|
|
byte bit = byte.Parse(str.RightFrom(index1));
|
|
plcAddr.Start = bit > 8 ? start : start + 1;
|
|
plcAddr.Bit = (byte)(bit > 7 ? bit - 8 : bit);
|
|
return plcAddr;
|
|
}
|
|
}
|
|
str = str.Substring(index);
|
|
}
|
|
index = str.IndexOf('.');
|
|
if (index < 0)
|
|
plcAddr.Start = int.Parse(str);
|
|
else
|
|
{
|
|
plcAddr.Start = int.Parse(str.Substring(0, index));
|
|
plcAddr.Bit = byte.Parse(str.RightFrom(index));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
plcAddr.DBNumber = 0;
|
|
char chr = address[0];
|
|
if (dict.ContainsKey(chr))
|
|
{
|
|
plcAddr.Area = dict[chr];
|
|
int index = address.IndexOf('.');
|
|
if (address[1] == 'W')
|
|
{
|
|
if (index > 0)
|
|
{
|
|
int start = int.Parse(address.Substring(2, index - 2));
|
|
byte bit = byte.Parse(address.RightFrom(index));
|
|
plcAddr.Start = bit > 8 ? start : start + 1;
|
|
plcAddr.Bit = (byte)(bit > 7 ? bit - 8 : bit);
|
|
}
|
|
else
|
|
{
|
|
plcAddr.Start = int.Parse(address.Substring(2));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (index > 0)
|
|
{
|
|
plcAddr.Start = int.Parse(address.Substring(1, index - 1));
|
|
plcAddr.Bit = byte.Parse(address.RightFrom(index));
|
|
}
|
|
else
|
|
{
|
|
plcAddr.Start = int.Parse(address.Substring(1));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return plcAddr;
|
|
}
|
|
|
|
public bool Connect()
|
|
{
|
|
lock (_async)
|
|
{
|
|
if (!_closed) return true;
|
|
double sec = (DateTime.Now - _closeTime).TotalMilliseconds;
|
|
if (sec < 6000)
|
|
System.Threading.Thread.Sleep(6000 - (int)sec);
|
|
fds.rfd = libnodave.openSocket(102, _IP);
|
|
fds.wfd = fds.rfd;
|
|
if (fds.rfd > 0)
|
|
{
|
|
di = new libnodave.daveInterface(fds, "IF1", 0, libnodave.daveProtoISOTCP, libnodave.daveSpeed187k);
|
|
di.setTimeout(TimeOut);
|
|
// res=di.initAdapter(); // does nothing in ISO_TCP. But call it to keep your programs indpendent of protocols
|
|
// if(res==0) {
|
|
dc = new libnodave.daveConnection(di, 0, _rack, _slot);
|
|
if (0 == dc.connectPLC())
|
|
{
|
|
_closed = false;
|
|
return true;
|
|
}
|
|
}
|
|
if (dc != null) dc.disconnectPLC();
|
|
libnodave.closeSocket(fds.rfd);
|
|
}
|
|
_closed = true;
|
|
return false;
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
lock (_async)
|
|
{
|
|
if (dc != null) dc.disconnectPLC();
|
|
libnodave.closeSocket(102);
|
|
foreach (IGroup grp in _groups)
|
|
{
|
|
grp.Dispose();
|
|
}
|
|
_closed = true;
|
|
}
|
|
}
|
|
|
|
string daveStrerror(int code)
|
|
{
|
|
switch (code)
|
|
{
|
|
case 0: return "ok";
|
|
case 6: return "the CPU does not support reading a bit block of length<>1";
|
|
case 10: return "the desired item is not available in the PLC";
|
|
case 3: return "the desired item is not available in the PLC (200 family)";
|
|
case 5: return "the desired address is beyond limit for this PLC";
|
|
case -124: return "the PLC returned a packet with no result data";
|
|
case -125: return "the PLC returned an error code not understood by this library";
|
|
case -126: return "this result contains no data";
|
|
case -127: return "cannot work with an undefined result set";
|
|
case -123: return "cannot evaluate the received PDU";
|
|
case 7: return "Write data size error";
|
|
case 1: return "No data from I/O module";
|
|
case -128: return "Unexpected function code in answer";
|
|
case -129: return "PLC responds with an unknown data type";
|
|
case -1024: return "Short packet from PLC";
|
|
case -1025: return "Timeout when waiting for PLC response";
|
|
case 0x8000: return "function already occupied.";
|
|
case 0x8001: return "not allowed in current operating status.";
|
|
case 0x8101: return "hardware fault.";
|
|
case 0x8103: return "object access not allowed.";
|
|
case 0x8104: return "context is not supported. Step7 says:Function not implemented or error in telgram.";
|
|
case 0x8105: return "invalid address.";
|
|
case 0x8106: return "data type not supported.";
|
|
case 0x8107: return "data type not consistent.";
|
|
case 0x810A: return "object does not exist.";
|
|
case 0x8301: return "insufficient CPU memory ?";
|
|
case 0x8402: return "CPU already in RUN or already in STOP ?";
|
|
case 0x8404: return "severe error ?";
|
|
case 0x8500: return "incorrect PDU size.";
|
|
case 0x8702: return "address invalid."; ;
|
|
case 0xd002: return "Step7:variant of command is illegal.";
|
|
case 0xd004: return "Step7:status for this command is illegal.";
|
|
case 0xd0A1: return "Step7:function is not allowed in the current protection level.";
|
|
case 0xd201: return "block name syntax error.";
|
|
case 0xd202: return "syntax error function parameter.";
|
|
case 0xd203: return "syntax error block type.";
|
|
case 0xd204: return "no linked block in storage medium.";
|
|
case 0xd205: return "object already exists.";
|
|
case 0xd206: return "object already exists.";
|
|
case 0xd207: return "block exists in EPROM.";
|
|
case 0xd209: return "block does not exist/could not be found.";
|
|
case 0xd20e: return "no block present.";
|
|
case 0xd210: return "block number too big.";
|
|
// case 0xd240: return "unfinished block transfer in progress?"; // my guess
|
|
case 0xd240: return "Coordination rules were violated.";
|
|
/* Multiple functions tried to manipulate the same object.
|
|
Example: a block could not be copied,because it is already present in the target system
|
|
and
|
|
*/
|
|
case 0xd241: return "Operation not permitted in current protection level.";
|
|
/**/
|
|
case 0xd242: return "protection violation while processing F-blocks. F-blocks can only be processed after password input.";
|
|
case 0xd401: return "invalid SZL ID.";
|
|
case 0xd402: return "invalid SZL index.";
|
|
case 0xd406: return "diagnosis: info not available.";
|
|
case 0xd409: return "diagnosis: DP error.";
|
|
case 0xdc01: return "invalid BCD code or Invalid time format?";
|
|
default: return "no message defined!";
|
|
}
|
|
}
|
|
|
|
public byte[] ReadBytes(DeviceAddress address, ushort len)//从PLC中读取自己数组
|
|
{
|
|
if (dc != null)
|
|
{
|
|
byte[] buffer = new byte[len];
|
|
int res = -1;
|
|
lock (_async)
|
|
{
|
|
res = dc == null ? -1 : dc.readBytes(address.Area, address.DBNumber, address.Start, len, buffer);
|
|
}
|
|
if (res == 0)
|
|
return buffer;
|
|
_closed = true; dc = null; _closeTime = DateTime.Now;
|
|
if (OnError != null)
|
|
{
|
|
OnError(this, new IOErrorEventArgs(daveStrerror(res))); _closeTime = DateTime.Now;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public ItemData<string> ReadString(DeviceAddress address, ushort size = 0xFF)
|
|
{
|
|
if (dc != null)
|
|
{
|
|
byte[] buffer = new byte[size];
|
|
int res = -1;
|
|
lock (_async)
|
|
{
|
|
res = dc.readBytes(address.Area, address.DBNumber, address.Start, size, buffer);
|
|
}
|
|
if (res == 0)
|
|
return new ItemData<string>(Utility.ConvertToString(buffer), 0, QUALITIES.QUALITY_GOOD);
|
|
_closed = true; dc = null; _closeTime = DateTime.Now;
|
|
if (OnError != null)
|
|
{
|
|
OnError(this, new IOErrorEventArgs(daveStrerror(res)));
|
|
}
|
|
}
|
|
return new ItemData<string>(string.Empty, 0, QUALITIES.QUALITY_NOT_CONNECTED);
|
|
}
|
|
|
|
public ItemData<int> ReadInt32(DeviceAddress address)
|
|
{
|
|
if (dc != null)
|
|
{
|
|
int res = -1;
|
|
lock (_async)
|
|
{
|
|
res = dc.readBytes(address.Area, address.DBNumber, address.Start, 4, null);
|
|
if (res == 0) return new ItemData<int>(dc.getS32(), 0, QUALITIES.QUALITY_GOOD);
|
|
}
|
|
_closed = true; dc = null; _closeTime = DateTime.Now;
|
|
if (OnError != null)
|
|
{
|
|
OnError(this, new IOErrorEventArgs(daveStrerror(res)));
|
|
}
|
|
}
|
|
return new ItemData<int>(0, 0, QUALITIES.QUALITY_NOT_CONNECTED); ;
|
|
}
|
|
|
|
public ItemData<uint> ReadUInt32(DeviceAddress address)
|
|
{
|
|
if (dc != null)
|
|
{
|
|
int res = -1;
|
|
lock (_async)
|
|
{
|
|
res = dc.readBytes(address.Area, address.DBNumber, address.Start, 4, null);
|
|
if (res == 0) return new ItemData<uint>((uint)dc.getS32(), 0, QUALITIES.QUALITY_GOOD);
|
|
}
|
|
_closed = true; dc = null; _closeTime = DateTime.Now;
|
|
if (OnError != null)
|
|
{
|
|
OnError(this, new IOErrorEventArgs(daveStrerror(res)));
|
|
}
|
|
}
|
|
return new ItemData<uint>(0, 0, QUALITIES.QUALITY_NOT_CONNECTED); ;
|
|
}
|
|
|
|
public ItemData<ushort> ReadUInt16(DeviceAddress address)
|
|
{
|
|
if (dc != null)
|
|
{
|
|
int res = -1;
|
|
lock (_async)
|
|
{
|
|
res = dc.readBytes(address.Area, address.DBNumber, address.Start, 2, null);
|
|
if (res == 0) return new ItemData<ushort>((ushort)dc.getS16(), 0, QUALITIES.QUALITY_GOOD);
|
|
}
|
|
_closed = true; dc = null; _closeTime = DateTime.Now;
|
|
if (OnError != null)
|
|
{
|
|
OnError(this, new IOErrorEventArgs(daveStrerror(res)));
|
|
}
|
|
}
|
|
return new ItemData<ushort>(0, 0, QUALITIES.QUALITY_NOT_CONNECTED); ;
|
|
}
|
|
|
|
public ItemData<short> ReadInt16(DeviceAddress address)
|
|
{
|
|
if (dc != null)
|
|
{
|
|
int res = -1;
|
|
lock (_async)
|
|
{
|
|
res = dc.readBytes(address.Area, address.DBNumber, address.Start, 2, null);
|
|
if (res == 0) return new ItemData<short>((short)dc.getS16(), 0, QUALITIES.QUALITY_GOOD);
|
|
}
|
|
_closed = true; dc = null; _closeTime = DateTime.Now;
|
|
if (OnError != null)
|
|
{
|
|
OnError(this, new IOErrorEventArgs(daveStrerror(res)));
|
|
}
|
|
}
|
|
return new ItemData<short>(0, 0, QUALITIES.QUALITY_NOT_CONNECTED); ;
|
|
}
|
|
|
|
public ItemData<byte> ReadByte(DeviceAddress address)
|
|
{
|
|
if (dc != null)
|
|
{
|
|
int res = -1;
|
|
lock (_async)
|
|
{
|
|
res = dc.readBytes(address.Area, address.DBNumber, address.Start, 1, null);
|
|
if (res == 0)
|
|
return new ItemData<byte>((byte)dc.getS8(), 0, QUALITIES.QUALITY_GOOD);
|
|
}
|
|
_closed = true; dc = null; _closeTime = DateTime.Now;
|
|
if (OnError != null)
|
|
{
|
|
OnError(this, new IOErrorEventArgs(daveStrerror(res)));
|
|
}
|
|
}
|
|
return new ItemData<byte>(0, 0, QUALITIES.QUALITY_NOT_CONNECTED); ;
|
|
}
|
|
|
|
public ItemData<bool> ReadBit(DeviceAddress address)
|
|
{
|
|
int res = -1;
|
|
if (dc != null)
|
|
{
|
|
lock (_async)
|
|
{
|
|
res = dc.readBits(address.Area, address.DBNumber, address.Start * 8 + address.Bit, 1, null);//修改了原地址上的Bug
|
|
if (res == 0) return new ItemData<bool>(dc.getS8() != 0, 0, QUALITIES.QUALITY_GOOD);
|
|
}
|
|
_closed = true; dc = null; _closeTime = DateTime.Now;
|
|
if (OnError != null) { OnError(this, new IOErrorEventArgs(daveStrerror(res))); }
|
|
}
|
|
return new ItemData<bool>(false, 0, QUALITIES.QUALITY_NOT_CONNECTED);
|
|
}
|
|
|
|
public ItemData<float> ReadFloat(DeviceAddress address)
|
|
{
|
|
if (dc != null)
|
|
{
|
|
int res = -1;
|
|
lock (_async)
|
|
{
|
|
res = dc.readBytes(address.Area, address.DBNumber, address.Start, 4, null);
|
|
if (res == 0) return new ItemData<float>(dc.getFloat(), 0, QUALITIES.QUALITY_GOOD);
|
|
}
|
|
_closed = true; dc = null; _closeTime = DateTime.Now;
|
|
if (OnError != null)
|
|
{
|
|
OnError(this, new IOErrorEventArgs(daveStrerror(res))); _closeTime = DateTime.Now;
|
|
}
|
|
}
|
|
return new ItemData<float>(0, 0, QUALITIES.QUALITY_NOT_CONNECTED); ;
|
|
}
|
|
|
|
|
|
public ItemData<object> ReadValue(DeviceAddress address)
|
|
{
|
|
return this.ReadValueEx(address);
|
|
}
|
|
|
|
public int WriteBit(DeviceAddress address, bool bit)
|
|
{
|
|
lock (_async)
|
|
{
|
|
return dc == null ? -1 : dc.writeBits(address.Area, address.DBNumber, address.Start * 8 + address.Bit, 1, bit ? new byte[] { 0x1 } : new byte[] { 0x00 });
|
|
}
|
|
}
|
|
|
|
public int WriteBits(DeviceAddress address, byte value)
|
|
{
|
|
lock (_async)
|
|
{
|
|
return dc == null ? -1 : dc.writeBits(address.Area, address.DBNumber, address.Start, 1, new byte[] { value });
|
|
}
|
|
}
|
|
|
|
public int WriteInt16(DeviceAddress address, short value)
|
|
{
|
|
byte[] b = BitConverter.GetBytes(value); Array.Reverse(b);
|
|
lock (_async)
|
|
{
|
|
return dc == null ? -1 : dc.writeBytes(address.Area, address.DBNumber, address.Start, 2, b);
|
|
}
|
|
}
|
|
|
|
public int WriteUInt16(DeviceAddress address, ushort value)
|
|
{
|
|
byte[] b = BitConverter.GetBytes(value); Array.Reverse(b);
|
|
lock (_async)
|
|
{
|
|
return dc == null ? -1 : dc.writeBytes(address.Area, address.DBNumber, address.Start, 2, b);
|
|
}
|
|
}
|
|
|
|
public int WriteUInt32(DeviceAddress address, uint value)
|
|
{
|
|
byte[] b = BitConverter.GetBytes(value); Array.Reverse(b);
|
|
lock (_async)
|
|
{
|
|
return dc == null ? -1 : dc.writeBytes(address.Area, address.DBNumber, address.Start, 4, b);
|
|
}
|
|
}
|
|
|
|
public int WriteInt32(DeviceAddress address, int value)
|
|
{
|
|
byte[] b = BitConverter.GetBytes(value); Array.Reverse(b);
|
|
lock (_async)
|
|
{
|
|
return dc == null ? -1 : dc.writeBytes(address.Area, address.DBNumber, address.Start, 4, b);
|
|
}
|
|
}
|
|
|
|
public int WriteFloat(DeviceAddress address, float value)
|
|
{
|
|
byte[] b = BitConverter.GetBytes(value); Array.Reverse(b);
|
|
lock (_async)
|
|
{
|
|
return dc == null ? -1 : dc.writeBytes(address.Area, address.DBNumber, address.Start, 4, b);
|
|
}
|
|
}
|
|
|
|
public int WriteString(DeviceAddress address, string str)
|
|
{
|
|
lock (_async)
|
|
{
|
|
if (str.Length > address.DataSize)
|
|
str.Remove(address.DataSize - 1);
|
|
var textArr = Encoding.ASCII.GetBytes(str);
|
|
var buffer = new byte[2 + textArr.Length];
|
|
buffer[0] = (byte)address.DataSize;
|
|
buffer[1] = (byte)textArr.Length;
|
|
textArr.CopyTo(buffer, 2);
|
|
return dc == null ? -1 : dc.writeManyBytes(address.Area, address.DBNumber, address.Start,
|
|
buffer.Length, buffer); //1200前置空格
|
|
}
|
|
}
|
|
|
|
public int WriteValue(DeviceAddress address, object value)
|
|
{
|
|
return this.WriteValueEx(address, value);
|
|
}
|
|
|
|
public int WriteBytes(DeviceAddress address, byte[] bit)
|
|
{
|
|
lock (_async)
|
|
{
|
|
return dc == null ? -1 : dc.writeBytes(address.Area, address.DBNumber, address.Start, bit.Length, bit);
|
|
}
|
|
}
|
|
public ItemData<Storage>[] ReadMultiple(DeviceAddress[] addrsArr)
|
|
{
|
|
int len = addrsArr.Length;
|
|
if (len > Limit)
|
|
{
|
|
List<ItemData<Storage>> itemArr = new List<ItemData<Storage>>(len);
|
|
int i = 0;
|
|
while (i < len)
|
|
{
|
|
int cnt = len - i > Limit ? Limit : len - i;
|
|
DeviceAddress[] addr = new DeviceAddress[cnt];
|
|
addrsArr.CopyTo(addr, i);
|
|
itemArr.AddRange(ReadMultipleInternal(addrsArr));
|
|
i += Limit;
|
|
}
|
|
return itemArr.ToArray();
|
|
}
|
|
else
|
|
return ReadMultipleInternal(addrsArr);
|
|
}
|
|
|
|
ItemData<Storage>[] ReadMultipleInternal(DeviceAddress[] addrsArr)
|
|
{
|
|
int len = addrsArr.Length;
|
|
if (len <= Limit)
|
|
{
|
|
lock (_async)
|
|
{
|
|
if (dc == null) return null;
|
|
libnodave.PDU p = dc.prepareReadRequest();
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
DeviceAddress addr = addrsArr[i];
|
|
if (addr.VarType == DataType.BOOL)
|
|
p.addBitVarToReadRequest(addr.Area, addr.DBNumber, addr.Start, addr.DataSize);
|
|
else
|
|
p.addVarToReadRequest(addr.Area, addr.DBNumber, addr.Start, addr.DataSize);
|
|
}
|
|
libnodave.resultSet rs = new libnodave.resultSet();
|
|
int res = dc.execReadRequest(p, rs);
|
|
ItemData<Storage>[] itemArr = new ItemData<Storage>[len];
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
res = dc.useResult(rs, i);
|
|
if (res > 0)
|
|
{
|
|
itemArr[i].Quality = QUALITIES.QUALITY_GOOD;
|
|
switch (addrsArr[i].VarType)
|
|
{
|
|
case DataType.BOOL:
|
|
itemArr[i].Value.Boolean = dc.getU8() > 0;//需测试
|
|
break;
|
|
case DataType.BYTE:
|
|
itemArr[i].Value.Byte = (byte)dc.getU8();
|
|
break;
|
|
case DataType.WORD:
|
|
itemArr[i].Value.Word = (ushort)dc.getS16();
|
|
break;
|
|
case DataType.SHORT:
|
|
itemArr[i].Value.Int16 = (short)dc.getS16();
|
|
break;
|
|
case DataType.DWORD:
|
|
itemArr[i].Value.DWord = (uint)dc.getS32();
|
|
break;
|
|
case DataType.INT:
|
|
itemArr[i].Value.Int32 = dc.getS32();
|
|
break;
|
|
case DataType.FLOAT:
|
|
itemArr[i].Value.Single = dc.getFloat();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return itemArr;
|
|
}
|
|
}
|
|
else
|
|
return this.PLCReadMultiple(new NetByteCacheReader(), addrsArr);
|
|
}
|
|
|
|
public int WriteMultiple(DeviceAddress[] addrArr, object[] buffer)
|
|
{
|
|
int len = addrArr.Length;
|
|
if (len > Limit)
|
|
{
|
|
int ret = 0;
|
|
int i = 0;
|
|
while (i < len)
|
|
{
|
|
int cnt = len - i > Limit ? Limit : len - i;
|
|
DeviceAddress[] addr = new DeviceAddress[cnt];
|
|
Array.Copy(addrArr, i, addr, 0, cnt);
|
|
//addrArr.CopyTo(addr, i);
|
|
object[] values = new object[cnt];
|
|
Array.Copy(buffer, i, values, 0, cnt);
|
|
//buffer.CopyTo(values, i);
|
|
var res = WriteMultipleInternal(addr, values);
|
|
if (res < 0) ret = res;
|
|
i += Limit;
|
|
}
|
|
return ret;
|
|
}
|
|
return WriteMultipleInternal(addrArr, buffer);
|
|
}
|
|
|
|
int WriteMultipleInternal(DeviceAddress[] addrArr, object[] buffer)
|
|
{
|
|
lock (_async)
|
|
{
|
|
if (dc == null) return -1;
|
|
int len = addrArr.Length;
|
|
libnodave.PDU p2 = dc.prepareWriteRequest();
|
|
for (int i = 0; i < len; i++)
|
|
{
|
|
try
|
|
{
|
|
DeviceAddress addr = addrArr[i];
|
|
byte[] b;
|
|
switch (addr.VarType)
|
|
{
|
|
case DataType.BOOL:
|
|
bool bl = Convert.ToBoolean(buffer[i]);
|
|
b = new byte[] { (byte)(bl ? 1 : 0) };
|
|
p2.addBitVarToWriteRequest(addr.Area, addr.DBNumber, addr.Start * 8 + addr.Bit, 1, b);
|
|
break;
|
|
case DataType.BYTE:
|
|
b = BitConverter.GetBytes(Convert.ToByte(buffer[i]));
|
|
p2.addVarToWriteRequest(addr.Area, addr.DBNumber, addr.Start, 1, b);
|
|
break;
|
|
case DataType.WORD:
|
|
b = BitConverter.GetBytes(Convert.ToUInt16(buffer[i])); Array.Reverse(b);
|
|
p2.addVarToWriteRequest(addr.Area, addr.DBNumber, addr.Start, 2, b);
|
|
break;
|
|
case DataType.SHORT:
|
|
b = BitConverter.GetBytes(Convert.ToInt16(buffer[i])); Array.Reverse(b);
|
|
p2.addVarToWriteRequest(addr.Area, addr.DBNumber, addr.Start, 2, b);
|
|
break;
|
|
case DataType.DWORD:
|
|
b = BitConverter.GetBytes(Convert.ToUInt32(buffer[i])); Array.Reverse(b);
|
|
p2.addVarToWriteRequest(addr.Area, addr.DBNumber, addr.Start, 4, b);
|
|
break;
|
|
case DataType.INT:
|
|
b = BitConverter.GetBytes(Convert.ToInt32(buffer[i])); Array.Reverse(b);
|
|
p2.addVarToWriteRequest(addr.Area, addr.DBNumber, addr.Start, 4, b);
|
|
break;
|
|
case DataType.FLOAT:
|
|
b = BitConverter.GetBytes(Convert.ToSingle(buffer[i])); Array.Reverse(b);
|
|
p2.addVarToWriteRequest(addr.Area, addr.DBNumber, addr.Start, 4, b);
|
|
break;
|
|
case DataType.STR:
|
|
{
|
|
b = Encoding.ASCII.GetBytes(buffer[i].ToString());
|
|
var b1 = new byte[2 + b.Length];
|
|
b1[0] = (byte)addrArr[i].DataSize;
|
|
b1[1] = (byte)b.Length;
|
|
b.CopyTo(b1, 2);
|
|
p2.addVarToWriteRequest(addr.Area, addr.DBNumber, addr.Start, addr.DataSize, b1);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
catch (Exception err)
|
|
{
|
|
if (OnError != null) OnError(this, new IOErrorEventArgs(err.Message));//可考虑把相应地址和数值加入
|
|
}
|
|
}
|
|
libnodave.resultSet rs = new libnodave.resultSet();
|
|
return dc.execWriteRequest(p2, rs);
|
|
}
|
|
}
|
|
|
|
public int Limit
|
|
{
|
|
get { return 10; }
|
|
}
|
|
|
|
public event IOErrorEventHandler OnError;
|
|
}
|
|
|
|
}
|
|
|