using System; using System.Collections.Generic; using System.Net.Sockets; using System.Net; using System.Text; using System.Diagnostics; namespace DataService { public class ModbusTCPReader : IPLCDevice { 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; /// Constant for exception illegal function. public const byte excIllegalFunction = 1; /// Constant for exception illegal data address. public const byte excIllegalDataAdr = 2; /// Constant for exception illegal data value. public const byte excIllegalDataVal = 3; /// Constant for exception slave device failure. public const byte excSlaveDeviceFailure = 4; /// Constant for exception acknowledge. public const byte excAck = 5; /// Constant for exception slave is busy/booting up. public const byte excSlaveIsBusy = 6; /// Constant for exception gate path unavailable. public const byte excGatePathUnavailable = 10; /// Constant for exception not connected. public const byte excExceptionNotConnected = 253; /// Constant for exception connection lost. public const byte excExceptionConnectionLost = 254; /// Constant for exception response timeout. public const byte excExceptionTimeout = 255; /// Constant for exception wrong offset. private const byte excExceptionOffset = 128; /// Constant for exception send failt. private const byte excSendFailt = 100; private static int _timeout; private Socket tcpSynCl; private byte[] tcpSynClBuffer = new byte[256]; /// Response data event. This event is called when new data arrives public delegate void ResponseData(ushort id, byte function, byte[] data); /// Exception data event. This event is called when the data is incorrect public delegate void ExceptionData(int id, byte function, byte exception); /// Exception data event. This event is called when the data is incorrect short _id; public short ID { get { return _id; } } string _ip; public string ServerName { get { return _ip; } set { _ip = value; } } public bool IsClosed { get { return tcpSynCl == null || tcpSynCl.Connected == false; } } public int TimeOut { get { return _timeout; } set{ _timeout = value; } } public DeviceDriver Driver { get { return DeviceDriver.ModbusTcp; } } List _grps = new List(20); public IEnumerable Groups { get { return _grps; } } IDataServer _server; public IDataServer Parent { get { return _server; } } public ModbusTCPReader(IDataServer server,short id, string ip, int timeOut = 500) { _id = id; _server = server; _ip = ip; _timeout = timeOut; } public bool Connect() { try { int port = 502; //IPAddress ip = IPAddress.Parse(_ip); // ---------------------------------------------------------------- // Connect synchronous client tcpSynCl = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); tcpSynCl.Connect(_ip, port); tcpSynCl.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, _timeout); tcpSynCl.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, _timeout); tcpSynCl.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.NoDelay, 1); return true; } catch (SocketException error) { if (OnClose != null) OnClose(this, new ShutdownRequestEventArgs(error.Message)); return false; } } private byte[] CreateReadHeader(int id, int startAddress, ushort length, byte function) { byte[] data = new byte[12]; byte[] _id = BitConverter.GetBytes((short)id); data[0] = _id[0]; // Slave id high byte data[1] = _id[1]; // Slave id low byte data[5] = 6; // Message size data[6] = 0; // Slave address data[7] = function; // Function code byte[] _adr = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)startAddress)); data[8] = _adr[0]; // Start address data[9] = _adr[1]; // Start address byte[] _length = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)length)); data[10] = _length[0]; // Number of data to read data[11] = _length[1]; // Number of data to read return data; } private byte[] CreateWriteHeader(int id, int startAddress, ushort numData, ushort numBytes, byte function) { byte[] data = new byte[numBytes + 11]; byte[] _id = BitConverter.GetBytes(id); data[0] = _id[0]; // Slave id high byte data[1] = _id[1]; // Slave id low byte+ byte[] _size = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)(5 + numBytes))); data[4] = _size[0]; // Complete message size in bytes data[5] = _size[1]; // Complete message size in bytes data[6] = 0; // Slave address data[7] = function; // Function code byte[] _adr = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)startAddress)); data[8] = _adr[0]; // Start address data[9] = _adr[1]; // Start address if (function >= fctWriteMultipleCoils) { byte[] _cnt = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((short)numData)); data[10] = _cnt[0]; // Number of bytes data[11] = _cnt[1]; // Number of bytes data[12] = (byte)(numBytes - 2); } return data; } private byte[] WriteSyncData(byte[] write_data) { short id = BitConverter.ToInt16(write_data, 0); if (IsClosed) CallException(id, write_data[7], excExceptionConnectionLost); else { try { tcpSynCl.Send(write_data, 0, write_data.Length, SocketFlags.None); int result = tcpSynCl.Receive(tcpSynClBuffer, 0, tcpSynClBuffer.Length, SocketFlags.None); byte function = tcpSynClBuffer[7]; byte[] data; if (result == 0) CallException(id, write_data[7], excExceptionConnectionLost); // ------------------------------------------------------------ // Response data is slave exception if (function > excExceptionOffset) { function -= excExceptionOffset; CallException(id, function, tcpSynClBuffer[8]); return null; } // ------------------------------------------------------------ // Write response data else if ((function >= fctWriteSingleCoil) && (function != fctReadWriteMultipleRegister)) { data = new byte[2]; Array.Copy(tcpSynClBuffer, 10, data, 0, 2); } // ------------------------------------------------------------ // Read response data else { data = new byte[tcpSynClBuffer[8]]; Array.Copy(tcpSynClBuffer, 9, data, 0, tcpSynClBuffer[8]); } return data; } catch (SocketException) { CallException(id, write_data[7], excExceptionConnectionLost); } } return null; } public byte[] WriteSingleCoils(int id, int startAddress, bool OnOff) { byte[] data; data = CreateWriteHeader(id, startAddress, 1, 1, fctWriteSingleCoil); if (OnOff == true) data[10] = 255; else data[10] = 0; return WriteSyncData(data); } public byte[] WriteMultipleCoils(int id, int startAddress, ushort numBits, byte[] values) { byte numBytes = Convert.ToByte(values.Length); byte[] data; data = CreateWriteHeader(id, startAddress, numBits, (byte)(numBytes + 2), fctWriteMultipleCoils); Array.Copy(values, 0, data, 13, numBytes); return WriteSyncData(data); } public byte[] WriteSingleRegister(int id, int startAddress, byte[] values) { byte[] data; data = CreateWriteHeader(id, startAddress, 1, 1, fctWriteSingleRegister); data[10] = values[0]; data[11] = values[1]; return WriteSyncData(data); } public byte[] WriteMultipleRegister(int id, int startAddress, byte[] values) { ushort numBytes = Convert.ToUInt16(values.Length); if (numBytes % 2 > 0) numBytes++; byte[] data; data = CreateWriteHeader(id, startAddress, Convert.ToUInt16(numBytes / 2), Convert.ToUInt16(numBytes + 2), fctWriteMultipleRegister); Array.Copy(values, 0, data, 13, values.Length); return WriteSyncData(data); } public int PDU { get { return 256; } } public int GetBlockSize(int area) { return area > 2 ? PDU / 2 : PDU; } public DeviceAddress GetDeviceAddress(string address) { DeviceAddress dv = DeviceAddress.Empty; if (address == null || address.Length < 3) return dv; else { int index = address.IndexOf('.'); switch (address[0]) { case '0': dv.Area = fctReadCoil; if (index > 0) { dv.Start = 64 * int.Parse(address.Substring(1, index - 1)); dv.Bit = byte.Parse(address.Substring(index + 1)); } break; case '1': dv.Area = fctReadDiscreteInputs; if (index > 0) { dv.Start = 64 * int.Parse(address.Substring(1, index - 1)); dv.Bit = byte.Parse(address.Substring(index + 1)); } break; case '4': dv.Area = 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.Mid(1)); break; case '3': dv.Area = fctReadInputRegister; 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.Mid(1)); break; } } return dv; } public string GetAddress(DeviceAddress address) { return string.Empty; } public IGroup AddGroup(string name, short id, int updateRate, float deadBand = 0f, bool active = false) { ModbusGroup grp = new ModbusGroup(id, name, updateRate, active, this); _grps.Add(grp); return grp; } public bool RemoveGroup(IGroup grp) { grp.IsActive = false; return _grps.Remove(grp); } public void Dispose() { if (tcpSynCl != null) { if (tcpSynCl.Connected) { try { tcpSynCl.Shutdown(SocketShutdown.Both); } catch { } tcpSynCl.Close(); } tcpSynCl = null; } foreach (IGroup grp in _grps) { grp.Dispose(); } _grps.Clear(); } internal string GetErrorString(byte exception) { switch (exception) { case excIllegalFunction: return "Constant for exception illegal function."; case excIllegalDataAdr: return "Constant for exception illegal data address."; case excIllegalDataVal: return "Constant for exception illegal data value."; case excSlaveDeviceFailure: return "Constant for exception slave device failure."; case excAck: return "Constant for exception acknowledge."; case excSlaveIsBusy: return "Constant for exception slave is busy/booting up."; case excGatePathUnavailable: return "Constant for exception gate path unavailable."; case excExceptionNotConnected: return "Constant for exception not connected."; case excExceptionConnectionLost: return "Constant for exception connection lost."; case excExceptionTimeout: return "Constant for exception response timeout."; case excExceptionOffset: return "Constant for exception wrong offset."; case excSendFailt: return "Constant for exception send failt."; } return string.Empty; } internal void CallException(int id, byte function, byte exception) { if (tcpSynCl == null) return; if (exception == excExceptionConnectionLost && IsClosed == false) { if (OnClose != null) OnClose(this, new ShutdownRequestEventArgs(GetErrorString(exception))); } } public byte[] ReadBytes(DeviceAddress address, ushort size) { return WriteSyncData(CreateReadHeader(address.Area, address.Start, size, (byte)address.Area)); } public ItemData ReadInt32(DeviceAddress address) { byte[] data = WriteSyncData(CreateReadHeader(address.Area, address.Start, 4, (byte)address.Area)); if (data == null) return new ItemData(0, 0, QUALITIES.QUALITY_BAD); else return new ItemData(IPAddress.HostToNetworkOrder(BitConverter.ToInt32(data, 0)), 0, QUALITIES.QUALITY_GOOD); } public ItemData ReadInt16(DeviceAddress address) { byte[] data = WriteSyncData(CreateReadHeader(address.Area, address.Start, 2, (byte)address.Area)); if (data == null) return new ItemData(0, 0, QUALITIES.QUALITY_BAD); else return new ItemData(IPAddress.HostToNetworkOrder(BitConverter.ToInt16(data, 0)), 0, QUALITIES.QUALITY_GOOD); } public ItemData ReadByte(DeviceAddress address) { byte[] data = WriteSyncData(CreateReadHeader(address.Area, address.Start, 1, (byte)address.Area)); if (data == null) return new ItemData(0, 0, QUALITIES.QUALITY_BAD); else return new ItemData(data[0], 0, QUALITIES.QUALITY_GOOD); } public ItemData ReadString(DeviceAddress address, ushort size) { byte[] data = WriteSyncData(CreateReadHeader(address.Area, address.Start, size, (byte)address.Area)); if (data == null) return new ItemData(string.Empty, 0, QUALITIES.QUALITY_BAD); else return new ItemData(Encoding.Default.GetString(data, 0, size), 0, QUALITIES.QUALITY_GOOD);//是否考虑字节序问题? } public unsafe ItemData ReadFloat(DeviceAddress address) { byte[] data = WriteSyncData(CreateReadHeader(address.Area, address.Start, 4, (byte)address.Area)); if (data == null) return new ItemData(0.0f, 0, QUALITIES.QUALITY_BAD); else { int value = IPAddress.HostToNetworkOrder(BitConverter.ToInt32(data, 0)); return new ItemData(*(((float*)&value)), 0, QUALITIES.QUALITY_GOOD); } } public unsafe ItemData ReadBit(DeviceAddress address) { byte[] data = WriteSyncData(CreateReadHeader(address.Area, address.Start, 1, (byte)address.Area)); if (data == null) return new ItemData(false, 0, QUALITIES.QUALITY_BAD); else { fixed (byte* p = data) { int* p1 = (int*)p; return new ItemData((*p1 & (1 << (address.Bit < 8 ? address.Bit + 8 : address.Bit - 8))) != 0, 0, QUALITIES.QUALITY_GOOD); } } } public ItemData ReadValue(DeviceAddress address) { throw new NotImplementedException(); } public int WriteBytes(DeviceAddress address, byte[] bit) { var data = WriteMultipleRegister(address.Area, address.Start, bit); return data == null ? -1 : 0; } public int WriteBit(DeviceAddress address, bool bit) { var data = WriteSingleCoils(address.Area, address.Start + address.Bit, bit); return data == null ? -1 : 0; } public int WriteBits(DeviceAddress address, byte bits) { var data = WriteSingleRegister(address.Area, address.Start, new byte[] { bits }); return data == null ? -1 : 0; } public int WriteInt16(DeviceAddress address, short value) { var data = WriteSingleRegister(address.Area, address.Start, BitConverter.GetBytes(value)); return data == null ? -1 : 0; } public int WriteInt32(DeviceAddress address, int value) { var data = WriteSingleRegister(address.Area, address.Start, BitConverter.GetBytes(value)); return data == null ? -1 : 0; } public int WriteFloat(DeviceAddress address, float value) { var data = WriteSingleRegister(address.Area, address.Start, BitConverter.GetBytes(value)); return data == null ? -1 : 0; } public int WriteString(DeviceAddress address, string str) { var data = WriteSingleRegister(address.Area, address.Start, Encoding.ASCII.GetBytes(str)); return data == null ? -1 : 0; } public int WriteValue(DeviceAddress address, object value) { throw new NotImplementedException(); } public override string ToString() { return "MODBUS以太网"; } public event ShutdownRequestEventHandler OnClose; } public class ModbusGroup : PLCGroup { public ModbusGroup(short id, string name, int updateRate, bool active, IPLCDevice plcReader) { this._id = id; this._name = name; this._updateRate = updateRate; this._isActive = active; this._plcReader = plcReader; this._server = _plcReader.Parent; this._timer = new MMTimer(); this._changedList = new List(100); this._cacheReader = new ModbusCacheReader(); } protected override unsafe int StartScan(DeviceAddress start, ushort len) { if (_start.Area > 2) { byte[] b1 = _plcReader.ReadBytes(start, len); if (b1 == null) return -1; fixed (byte* p3 = b1) { short* p2 = (short*)p3; int address = start.Start; fixed (byte* numPtr = _cacheReader.Cache) { short* p1 = (short*)numPtr + address - _start.Start; int i = 0; ITag other = new BoolTag(0, DeviceAddress.Empty, null); while (i < len) { //start.Start += i; p2[i] = IPAddress.HostToNetworkOrder(p2[i]); if (p2[i] != p1[i]) { start.Start = address + i; other.Address = start; int index = _items.BinarySearch(other); if (index >= 0) { ITag item1 = _items[index]; int size = item1.Address.DataSize; if (size >= 16) { _changedList.Add(index); i += (size / 16); } else { DeviceAddress addr = _items[index].Address; int tmp = p2[i] ^ p1[i]; while (addr.Start == start.Start) { if ((tmp & (1 << addr.Bit)) > 0) _changedList.Add(index); if (++index < _items.Count) addr = _items[index].Address; else break; } i++; } } else { index = ~index; if (index < _items.Count) { DeviceAddress addr = _items[index].Address; if (addr.Start == start.Start) { int tmp = p2[i] ^ p1[i]; while (addr.Start == start.Start) { if ((tmp & (1 << addr.Bit)) > 0) _changedList.Add(index); if (++index < _items.Count) addr = _items[index].Address; else break; } } else { if (addr.Start > start.Start && index > 0) addr = _items[--index].Address; int size = addr.DataSize / 16; if (size > start.Start - addr.Start) { _changedList.Add(index); i += size + addr.Start - start.Start; continue; } } } i++; } } else i++; } for (int j = 0; j < len; j++) { *(p1++) = p2[j]; } return 1; } } } else { byte[] b1 = _plcReader.ReadBytes(start, len); if (b1 == null || _cacheReader.Size < 1) return -1; fixed (byte* p3 = b1) { long* p2 = (long*)p3; int address = start.Start; fixed (byte* numPtr = _cacheReader.Cache) { long* p1 = (long*)numPtr + address - _start.Start; int i = 0; len <<= 3; ITag other = new BoolTag(0, DeviceAddress.Empty, null); while (i < len) { p2[i] = IPAddress.HostToNetworkOrder(p2[i]); if (p2[i] != p1[i]) { start.Start = address + i << 6; other.Address = start; int index = _items.BinarySearch(other); if (index > 0) { DeviceAddress addr = _items[index].Address; long tmp = p2[i] ^ p1[i]; while (addr.Start == start.Start) { if ((tmp & (1 << addr.Bit)) > 0) _changedList.Add(index); if (++index < _items.Count) addr = _items[index].Address; else break; } } else { index = ~index; if (index < _items.Count) { DeviceAddress addr = _items[index].Address; if (addr.Start == start.Start) { long tmp = p2[i] ^ p1[i]; while (addr.Start == start.Start) { if ((tmp & (1 << addr.Bit)) > 0) _changedList.Add(index); if (++index < _items.Count) addr = _items[index].Address; else break; } } } } p1[i] = p2[i]; i++; } else i++; } return 1; } } } } } } using System; using System.Net; using System.Text; namespace DataService { public unsafe class CacheReader : ICache { byte[] _cache; public byte[] Cache { get { return _cache; } } DeviceAddress _start; public DeviceAddress Start { get { return _start; } set { _start = value; } } int _size; public int Size { get { return _size; } set { _size = value; this._cache = new byte[_size]; } } public CacheReader() { } public CacheReader(DeviceAddress start, int size) { this.Start = start; this.Size = size; } public int GetOffset(DeviceAddress start, DeviceAddress end) { return start.Start - end.Start; } public ItemData ReadInt32(DeviceAddress address) { return new ItemData(BitConverter.ToInt32(_cache, address.Start - _start.Start), 0, QUALITIES.QUALITY_GOOD); } public ItemData ReadBit(DeviceAddress address) { //byte b = _cache[address.Start - _start.Start]; fixed (byte* p = _cache) { int* p1 = (int*)(p + address.Start - _start.Start); return new ItemData((*p1 & (1 << address.Bit)) != 0, 0, QUALITIES.QUALITY_GOOD); } } public ItemData ReadInt16(DeviceAddress address) { return new ItemData(BitConverter.ToInt16(_cache, address.Start - _start.Start), 0, QUALITIES.QUALITY_GOOD); } public ItemData ReadByte(DeviceAddress address) { return new ItemData(_cache[address.Start - _start.Start], 0, QUALITIES.QUALITY_GOOD); } public ItemData ReadString(DeviceAddress address, ushort size = 64) { return new ItemData(BitConverter.ToString(_cache, address.Start - _start.Start, size), 0, QUALITIES.QUALITY_GOOD); } public ItemData ReadFloat(DeviceAddress address) { return new ItemData(BitConverter.ToSingle(_cache, address.Start - _start.Start), 0, QUALITIES.QUALITY_GOOD); } public ItemData ReadValue(DeviceAddress address) { throw new NotImplementedException(); } public int WriteBit(DeviceAddress address, bool bit) { byte b = _cache[address.Start - _start.Start]; b |= (byte)(1 << address.Bit); return 0; } public int WriteBits(DeviceAddress address, byte bits) { _cache[address.Start - _start.Start] = bits; return 0; } public int WriteInt16(DeviceAddress address, short value) { int index = address.Start - _start.Start; fixed (byte* p1 = _cache) { byte* numPtr = p1 + index; if ((((int)numPtr) & 1) == 0) { *((short*)numPtr) = value; } else { byte* numPtr2 = (byte*)&value; numPtr[0] = numPtr2[0]; numPtr[1] = numPtr2[1]; } } return 0; } public int WriteInt32(DeviceAddress address, int value) { int index = address.Start - _start.Start; fixed (byte* p1 = _cache) { byte* numPtr = p1 + index; if ((((int)numPtr) & 3) == 0) { *((int*)numPtr) = value; } else { byte* numPtr2 = (byte*)&value; numPtr[0] = numPtr2[0]; numPtr[1] = numPtr2[1]; numPtr[2] = numPtr2[2]; numPtr[3] = numPtr2[3]; } } return 0; } public int WriteFloat(DeviceAddress address, float value) { return 0; } public int WriteString(DeviceAddress address, string str) { byte[] b = System.Text.Encoding.Default.GetBytes(str); int index = address.Start - _start.Start; Array.Copy(_cache, index, b, 0, 64); return 0; } public int WriteValue(DeviceAddress address, object value) { throw new NotImplementedException(); } public byte[] ReadBytes(DeviceAddress address, ushort size) { byte[] bytes = new byte[size]; Array.Copy(_cache, address.Start - _start.Start, bytes, 0, size); return bytes; } public int WriteBytes(DeviceAddress address, byte[] bit) { if (bit != null && bit.Length > 0) { Array.Copy(bit, 0, _cache, address.Start - _start.Start, bit.Length); return 1; } return -1; } } public unsafe class ModbusCacheReader : ICache { byte[] _cache; public byte[] Cache { get { return _cache; } } DeviceAddress _start; public DeviceAddress Start { get { return _start; } set { _start = value; } } int _size; public int Size { get { return _size; } set { _size = value; this._cache = new byte[_start.Area > 2 ? 2 * _size : _size]; } } public ModbusCacheReader() { } public ModbusCacheReader(DeviceAddress start, int size) { this.Start = start; this.Size = size; } public int GetOffset(DeviceAddress start, DeviceAddress end) { return start.Area > 2 ? (start.Start - end.Start) << 1 : start.Start - end.Start; } public ItemData ReadInt32(DeviceAddress address) { return new ItemData(BitConverter.ToInt32(_cache, GetOffset(address, _start)) , 0, QUALITIES.QUALITY_GOOD); } public ItemData ReadBit(DeviceAddress address) { fixed (byte* p = _cache) { int* p1 = (int*)(p + GetOffset(address, _start)); return new ItemData((*p1 & (1 << address.Bit)) != 0, 0, QUALITIES.QUALITY_GOOD); } } public ItemData ReadInt16(DeviceAddress address) { return new ItemData(BitConverter.ToInt16(_cache, GetOffset(address, _start)), 0, QUALITIES.QUALITY_GOOD); } public ItemData ReadByte(DeviceAddress address) { return new ItemData(_cache[GetOffset(address, _start)], 0, QUALITIES.QUALITY_GOOD); } public ItemData ReadString(DeviceAddress address, ushort size = 64) { return new ItemData(BitConverter.ToString(_cache, GetOffset(address, _start), size), 0, QUALITIES.QUALITY_GOOD); } public ItemData ReadFloat(DeviceAddress address) { int value = BitConverter.ToInt32(_cache, GetOffset(address, _start)); //value = IPAddress.HostToNetworkOrder(value); return new ItemData(*(((float*)&value)), 0, QUALITIES.QUALITY_GOOD); } public ItemData ReadValue(DeviceAddress address) { throw new NotImplementedException(); } public int WriteBit(DeviceAddress address, bool bit) { throw new NotImplementedException(); } public int WriteBits(DeviceAddress address, byte bits) { throw new NotImplementedException(); } public int WriteInt16(DeviceAddress address, short value) { throw new NotImplementedException(); } public int WriteInt32(DeviceAddress address, int value) { throw new NotImplementedException(); } public int WriteFloat(DeviceAddress address, float value) { throw new NotImplementedException(); } public int WriteString(DeviceAddress address, string str) { throw new NotImplementedException(); } public int WriteValue(DeviceAddress address, object value) { throw new NotImplementedException(); } public byte[] ReadBytes(DeviceAddress address, ushort size) { throw new NotImplementedException(); } public int WriteBytes(DeviceAddress address, byte[] bit) { throw new NotImplementedException(); } } public unsafe class MXCacheReader : ICache { byte[] _cache; public byte[] Cache { get { return _cache; } } DeviceAddress _start; public DeviceAddress Start { get { return _start; } set { _start = value; } } int _size; public int Size { get { return _size; } set { _size = value; this._cache = new byte[_size]; } } public MXCacheReader() { } public MXCacheReader(DeviceAddress start, int size) { this.Start = start; this.Size = size; } static int GetOffset(DeviceAddress addr1) { switch (addr1.Area) { case MX_AREA.T: case MX_AREA.D: return addr1.Area + 2 * addr1.Start; case MX_AREA.S: case MX_AREA.M: case MX_AREA.X: case MX_AREA.Y: return addr1.Area + (addr1.Start >> 3); default: return 0; } } public int GetOffset(DeviceAddress start, DeviceAddress end) { return GetOffset(start) - GetOffset(end); } public ItemData ReadInt32(DeviceAddress address) { return new ItemData(BitConverter.ToInt32(_cache, GetOffset(address, _start)), 0, QUALITIES.QUALITY_GOOD); } public ItemData ReadBit(DeviceAddress address) { //if (address.Area == MX_AREA.D || address.Area == MX_AREA.T) // return new ItemData(false, 0, QUALITIES.QUALITY_BAD); fixed (byte* p = _cache) { short* p1 = (short*)(p + GetOffset(address, _start)); return new ItemData((*p1 & (1 << address.Bit)) != 0, 0, QUALITIES.QUALITY_GOOD); } } public ItemData ReadInt16(DeviceAddress address) { return new ItemData(BitConverter.ToInt16(_cache, GetOffset(address, _start)), 0, QUALITIES.QUALITY_GOOD); } public ItemData ReadByte(DeviceAddress address) { return new ItemData(_cache[GetOffset(address, _start)], 0, QUALITIES.QUALITY_GOOD); } public ItemData ReadString(DeviceAddress address, ushort size = 64) { byte[] bytes = new byte[size]; Array.Copy(_cache, GetOffset(address, _start), bytes, 0, size); return new ItemData(Encoding.Default.GetString(bytes).Trim((char)0), 0, QUALITIES.QUALITY_GOOD); //return new ItemData(BitConverter.ToString(_cache, GetOffset(address, _start), size>>3), 0, QUALITIES.QUALITY_GOOD); } public ItemData ReadFloat(DeviceAddress address) { return new ItemData(BitConverter.ToSingle(_cache, GetOffset(address, _start)), 0, QUALITIES.QUALITY_GOOD); } public ItemData ReadValue(DeviceAddress address) { throw new NotImplementedException(); } public int WriteBit(DeviceAddress address, bool bit) { throw new NotImplementedException(); } public int WriteBits(DeviceAddress address, byte bits) { throw new NotImplementedException(); } public int WriteInt16(DeviceAddress address, short value) { throw new NotImplementedException(); } public int WriteInt32(DeviceAddress address, int value) { throw new NotImplementedException(); } public int WriteFloat(DeviceAddress address, float value) { throw new NotImplementedException(); } public int WriteString(DeviceAddress address, string str) { throw new NotImplementedException(); } public int WriteValue(DeviceAddress address, object value) { throw new NotImplementedException(); } public byte[] ReadBytes(DeviceAddress address, ushort size) { throw new NotImplementedException(); } public int WriteBytes(DeviceAddress address, byte[] bit) { throw new NotImplementedException(); } } }