2017-02-06 update 1 Add AddressHelper and comments, reformat code.

This commit is contained in:
parallelbgls
2017-02-06 17:15:54 +08:00
parent f2ed8ac72b
commit 0d19567038
55 changed files with 2190 additions and 1821 deletions

View File

@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Modbus.Net.Modbus
namespace Modbus.Net.Modbus
{
public class AddressFormaterNA200H : AddressFormater
{

View File

@@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Modbus.Net.Modbus
{
@@ -11,8 +8,8 @@ namespace Modbus.Net.Modbus
/// </summary>
public class AddressTranslatorNA200H : AddressTranslator
{
protected Dictionary<string, int> TransDictionary;
protected Dictionary<string, AreaOutputDef> ReadFunctionCodeDictionary;
protected Dictionary<string, int> TransDictionary;
protected Dictionary<string, AreaOutputDef> WriteFunctionCodeDictionary;
public AddressTranslatorNA200H()
@@ -28,42 +25,134 @@ namespace Modbus.Net.Modbus
{"SW", 5000},
{"MW", 0},
{"QW", 20000},
{"NW", 21000},
{"NW", 21000}
};
ReadFunctionCodeDictionary = new Dictionary<string, AreaOutputDef>
{
{"Q", new AreaOutputDef {Code = (int)ModbusProtocalReadDataFunctionCode.ReadCoilStatus, AreaWidth = 0.125}},
{"M", new AreaOutputDef {Code = (int)ModbusProtocalReadDataFunctionCode.ReadCoilStatus, AreaWidth = 0.125}},
{"N", new AreaOutputDef {Code = (int)ModbusProtocalReadDataFunctionCode.ReadCoilStatus, AreaWidth = 0.125}},
{"I", new AreaOutputDef {Code = (int)ModbusProtocalReadDataFunctionCode.ReadInputStatus, AreaWidth = 0.125}},
{"S", new AreaOutputDef {Code = (int)ModbusProtocalReadDataFunctionCode.ReadInputStatus, AreaWidth = 0.125}},
{"IW", new AreaOutputDef {Code = (int)ModbusProtocalReadDataFunctionCode.ReadInputRegister, AreaWidth = 2}},
{"SW", new AreaOutputDef {Code = (int)ModbusProtocalReadDataFunctionCode.ReadInputRegister, AreaWidth = 2}},
{"MW", new AreaOutputDef {Code = (int)ModbusProtocalReadDataFunctionCode.ReadHoldRegister, AreaWidth = 2}},
{"NW", new AreaOutputDef {Code = (int)ModbusProtocalReadDataFunctionCode.ReadHoldRegister, AreaWidth = 2}},
{"QW", new AreaOutputDef {Code = (int)ModbusProtocalReadDataFunctionCode.ReadHoldRegister, AreaWidth = 2}},
{
"Q",
new AreaOutputDef
{
Code = (int) ModbusProtocalReadDataFunctionCode.ReadCoilStatus,
AreaWidth = 0.125
}
},
{
"M",
new AreaOutputDef
{
Code = (int) ModbusProtocalReadDataFunctionCode.ReadCoilStatus,
AreaWidth = 0.125
}
},
{
"N",
new AreaOutputDef
{
Code = (int) ModbusProtocalReadDataFunctionCode.ReadCoilStatus,
AreaWidth = 0.125
}
},
{
"I",
new AreaOutputDef
{
Code = (int) ModbusProtocalReadDataFunctionCode.ReadInputStatus,
AreaWidth = 0.125
}
},
{
"S",
new AreaOutputDef
{
Code = (int) ModbusProtocalReadDataFunctionCode.ReadInputStatus,
AreaWidth = 0.125
}
},
{
"IW",
new AreaOutputDef {Code = (int) ModbusProtocalReadDataFunctionCode.ReadInputRegister, AreaWidth = 2}
},
{
"SW",
new AreaOutputDef {Code = (int) ModbusProtocalReadDataFunctionCode.ReadInputRegister, AreaWidth = 2}
},
{
"MW",
new AreaOutputDef {Code = (int) ModbusProtocalReadDataFunctionCode.ReadHoldRegister, AreaWidth = 2}
},
{
"NW",
new AreaOutputDef {Code = (int) ModbusProtocalReadDataFunctionCode.ReadHoldRegister, AreaWidth = 2}
},
{
"QW",
new AreaOutputDef {Code = (int) ModbusProtocalReadDataFunctionCode.ReadHoldRegister, AreaWidth = 2}
}
};
WriteFunctionCodeDictionary = new Dictionary<string, AreaOutputDef>
{
{"Q", new AreaOutputDef {Code = (int)ModbusProtocalWriteDataFunctionCode.WriteMultiCoil, AreaWidth = 0.125}},
{"M", new AreaOutputDef {Code = (int)ModbusProtocalWriteDataFunctionCode.WriteMultiCoil, AreaWidth = 0.125}},
{"N", new AreaOutputDef {Code = (int)ModbusProtocalWriteDataFunctionCode.WriteMultiCoil, AreaWidth = 0.125}},
{"MW", new AreaOutputDef {Code = (int)ModbusProtocalWriteDataFunctionCode.WriteMultiRegister, AreaWidth = 2}},
{"NW", new AreaOutputDef {Code = (int)ModbusProtocalWriteDataFunctionCode.WriteMultiRegister, AreaWidth = 2}},
{"QW", new AreaOutputDef {Code = (int)ModbusProtocalWriteDataFunctionCode.WriteMultiRegister, AreaWidth = 2}},
{
"Q",
new AreaOutputDef
{
Code = (int) ModbusProtocalWriteDataFunctionCode.WriteMultiCoil,
AreaWidth = 0.125
}
},
{
"M",
new AreaOutputDef
{
Code = (int) ModbusProtocalWriteDataFunctionCode.WriteMultiCoil,
AreaWidth = 0.125
}
},
{
"N",
new AreaOutputDef
{
Code = (int) ModbusProtocalWriteDataFunctionCode.WriteMultiCoil,
AreaWidth = 0.125
}
},
{
"MW",
new AreaOutputDef
{
Code = (int) ModbusProtocalWriteDataFunctionCode.WriteMultiRegister,
AreaWidth = 2
}
},
{
"NW",
new AreaOutputDef
{
Code = (int) ModbusProtocalWriteDataFunctionCode.WriteMultiRegister,
AreaWidth = 2
}
},
{
"QW",
new AreaOutputDef
{
Code = (int) ModbusProtocalWriteDataFunctionCode.WriteMultiRegister,
AreaWidth = 2
}
}
};
}
public override AddressDef AddressTranslate(string address, bool isRead)
{
address = address.ToUpper();
string[] splitString = address.Split(' ');
string head = splitString[0];
string tail = splitString[1];
var splitString = address.Split(' ');
var head = splitString[0];
var tail = splitString[1];
string sub;
if (tail.Contains('.'))
{
string[] splitString2 = tail.Split('.');
var splitString2 = tail.Split('.');
sub = splitString2[1];
tail = splitString2[0];
}
@@ -72,19 +161,19 @@ namespace Modbus.Net.Modbus
sub = "0";
}
return isRead
? new AddressDef()
? new AddressDef
{
AreaString = head,
Area = ReadFunctionCodeDictionary[head].Code,
Address = TransDictionary[head] + int.Parse(tail) - 1,
SubAddress = int.Parse(sub),
SubAddress = int.Parse(sub)
}
: new AddressDef()
: new AddressDef
{
AreaString = head,
Area = WriteFunctionCodeDictionary[head].Code,
Address = TransDictionary[head] + int.Parse(tail) - 1,
SubAddress = int.Parse(sub),
SubAddress = int.Parse(sub)
};
}
@@ -106,28 +195,62 @@ namespace Modbus.Net.Modbus
{
ReadFunctionCodeDictionary = new Dictionary<string, AreaOutputDef>
{
{"0X", new AreaOutputDef {Code = (int)ModbusProtocalReadDataFunctionCode.ReadCoilStatus, AreaWidth = 0.125}},
{"1X", new AreaOutputDef {Code = (int)ModbusProtocalReadDataFunctionCode.ReadInputStatus, AreaWidth = 0.125}},
{"3X", new AreaOutputDef {Code = (int)ModbusProtocalReadDataFunctionCode.ReadInputRegister, AreaWidth = 2}},
{"4X", new AreaOutputDef {Code = (int)ModbusProtocalReadDataFunctionCode.ReadHoldRegister, AreaWidth = 2}},
{
"0X",
new AreaOutputDef
{
Code = (int) ModbusProtocalReadDataFunctionCode.ReadCoilStatus,
AreaWidth = 0.125
}
},
{
"1X",
new AreaOutputDef
{
Code = (int) ModbusProtocalReadDataFunctionCode.ReadInputStatus,
AreaWidth = 0.125
}
},
{
"3X",
new AreaOutputDef {Code = (int) ModbusProtocalReadDataFunctionCode.ReadInputRegister, AreaWidth = 2}
},
{
"4X",
new AreaOutputDef {Code = (int) ModbusProtocalReadDataFunctionCode.ReadHoldRegister, AreaWidth = 2}
}
};
WriteFunctionCodeDictionary = new Dictionary<string, AreaOutputDef>
{
{"0X", new AreaOutputDef {Code = (int)ModbusProtocalWriteDataFunctionCode.WriteMultiCoil, AreaWidth = 0.125}},
{"4X", new AreaOutputDef {Code = (int)ModbusProtocalWriteDataFunctionCode.WriteMultiRegister, AreaWidth = 2}},
{
"0X",
new AreaOutputDef
{
Code = (int) ModbusProtocalWriteDataFunctionCode.WriteMultiCoil,
AreaWidth = 0.125
}
},
{
"4X",
new AreaOutputDef
{
Code = (int) ModbusProtocalWriteDataFunctionCode.WriteMultiRegister,
AreaWidth = 2
}
}
};
}
public override AddressDef AddressTranslate(string address, bool isRead)
{
address = address.ToUpper();
string[] splitString = address.Split(' ');
string head = splitString[0];
string tail = splitString[1];
var splitString = address.Split(' ');
var head = splitString[0];
var tail = splitString[1];
string sub;
if (tail.Contains('.'))
{
string[] splitString2 = tail.Split('.');
var splitString2 = tail.Split('.');
sub = splitString2[1];
tail = splitString2[0];
}
@@ -136,19 +259,19 @@ namespace Modbus.Net.Modbus
sub = "0";
}
return isRead
? new AddressDef()
? new AddressDef
{
AreaString = head,
Area = ReadFunctionCodeDictionary[head].Code,
Address = int.Parse(tail) - 1,
SubAddress = int.Parse(sub),
SubAddress = int.Parse(sub)
}
: new AddressDef()
: new AddressDef
{
AreaString = head,
Area = WriteFunctionCodeDictionary[head].Code,
Address = int.Parse(tail) - 1,
SubAddress = int.Parse(sub),
SubAddress = int.Parse(sub)
};
}

View File

@@ -1,21 +1,17 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Modbus.Net.Modbus
namespace Modbus.Net.Modbus
{
/// <summary>
/// Modbus/Rtu协议
/// </summary>
public class ModbusAsciiProtocal : ModbusProtocal
{
public ModbusAsciiProtocal(byte belongAddress, byte masterAddress) : this(ConfigurationManager.COM, belongAddress, masterAddress)
public ModbusAsciiProtocal(byte slaveAddress, byte masterAddress)
: this(ConfigurationManager.COM, slaveAddress, masterAddress)
{
}
public ModbusAsciiProtocal(string com, byte belongAddress, byte masterAddress) : base(belongAddress, masterAddress)
public ModbusAsciiProtocal(string com, byte slaveAddress, byte masterAddress)
: base(slaveAddress, masterAddress)
{
ProtocalLinker = new ModbusAsciiProtocalLinker(com);
}

View File

@@ -1,19 +1,19 @@
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.IO.Ports;
using System.Text;
using System.Threading.Tasks;
namespace Modbus.Net.Modbus
{
public class ModbusAsciiProtocalLinker : ComProtocalLinker
{
public ModbusAsciiProtocalLinker(string com) : base(com, 9600, Parity.None, StopBits.One, 8)
{
}
public override bool? CheckRight(byte[] content)
{
if (!base.CheckRight(content).Value) return false;
//CRC校验失败
string contentString = Encoding.ASCII.GetString(content);
var contentString = Encoding.ASCII.GetString(content);
if (!Crc16.GetInstance().LrcEfficacy(contentString))
{
throw new ModbusProtocalErrorException(501);
@@ -25,9 +25,5 @@ namespace Modbus.Net.Modbus
}
return true;
}
public ModbusAsciiProtocalLinker(string com) : base(com, 9600, Parity.None, StopBits.One, 8)
{
}
}
}

View File

@@ -7,7 +7,7 @@ namespace Modbus.Net.Modbus
internal enum ModbusProtocalVariableFunctionCode : byte
{
ReadVariable = 20,
WriteVariable = 21,
WriteVariable = 21
}
/// <summary>
@@ -16,7 +16,7 @@ namespace Modbus.Net.Modbus
public enum ModbusProtocalTimeFunctionCode : byte
{
GetSystemTime = 3,
SetSystemTime = 16,
SetSystemTime = 16
}
/// <summary>
@@ -27,7 +27,7 @@ namespace Modbus.Net.Modbus
ReadCoilStatus = 1,
ReadInputStatus = 2,
ReadHoldRegister = 3,
ReadInputRegister = 4,
ReadInputRegister = 4
}
/// <summary>
@@ -36,11 +36,15 @@ namespace Modbus.Net.Modbus
internal enum ModbusProtocalWriteDataFunctionCode : byte
{
WriteMultiCoil = 15,
WriteMultiRegister = 16,
WriteMultiRegister = 16
}
public abstract class ModbusProtocal : BaseProtocal
{
protected ModbusProtocal(byte slaveAddress, byte masterAddress) : base(slaveAddress, masterAddress)
{
}
public override bool Connect()
{
return ProtocalLinker.Connect();
@@ -50,45 +54,43 @@ namespace Modbus.Net.Modbus
{
return await ProtocalLinker.ConnectAsync();
}
protected ModbusProtocal(byte belongAddress, byte masterAddress) : base(belongAddress, masterAddress)
{
}
}
#region PLC数据
public class ReadDataModbusInputStruct : InputStruct
{
public ReadDataModbusInputStruct(byte belongAddress, string startAddress, ushort getCount, AddressTranslator addressTranslator)
public ReadDataModbusInputStruct(byte slaveAddress, string startAddress, ushort getCount,
AddressTranslator addressTranslator)
{
BelongAddress = belongAddress;
SlaveAddress = slaveAddress;
var translateAddress = addressTranslator.AddressTranslate(startAddress, true);
FunctionCode = (byte) translateAddress.Area;
StartAddress = (ushort) translateAddress.Address;
GetCount = (ushort) Math.Ceiling(getCount/addressTranslator.GetAreaByteLength(translateAddress.AreaString));
}
public byte BelongAddress { get; private set; }
public byte SlaveAddress { get; }
public byte FunctionCode { get; private set; }
public byte FunctionCode { get; }
public ushort StartAddress { get; private set; }
public ushort StartAddress { get; }
public ushort GetCount { get; private set; }
public ushort GetCount { get; }
}
public class ReadDataModbusOutputStruct : OutputStruct
{
public ReadDataModbusOutputStruct(byte belongAddress, byte functionCode,
public ReadDataModbusOutputStruct(byte slaveAddress, byte functionCode,
int dataCount, byte[] dataValue)
{
BelongAddress = belongAddress;
SlaveAddress = slaveAddress;
FunctionCode = functionCode;
DataCount = dataCount;
DataValue = dataValue.Clone() as byte[];
}
public byte BelongAddress { get; private set; }
public byte SlaveAddress { get; private set; }
public byte FunctionCode { get; private set; }
@@ -102,70 +104,73 @@ namespace Modbus.Net.Modbus
public override byte[] Format(InputStruct message)
{
var r_message = (ReadDataModbusInputStruct) message;
return Format(r_message.BelongAddress, r_message.FunctionCode,
return Format(r_message.SlaveAddress, r_message.FunctionCode,
r_message.StartAddress, r_message.GetCount);
}
public override OutputStruct Unformat(byte[] messageBytes, ref int pos)
{
byte belongAddress = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
byte functionCode = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
byte dataCount = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
byte[] dataValue = new byte[dataCount];
var slaveAddress = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
var functionCode = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
var dataCount = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
var dataValue = new byte[dataCount];
Array.Copy(messageBytes, 3, dataValue, 0, dataCount);
if (functionCode == 1 || functionCode == 2)
{
for (int i = 0; i < dataValue.Length; i++)
for (var i = 0; i < dataValue.Length; i++)
{
dataValue[i] = BigEndianValueHelper.Instance.ReverseByte(dataValue[i]);
}
}
return new ReadDataModbusOutputStruct(belongAddress, functionCode, dataCount, dataValue);
return new ReadDataModbusOutputStruct(slaveAddress, functionCode, dataCount, dataValue);
}
}
#endregion
#region PLC数据
public class WriteDataModbusInputStruct : InputStruct
{
public WriteDataModbusInputStruct(byte belongAddress, string startAddress, object[] writeValue, AddressTranslator addressTranslator)
public WriteDataModbusInputStruct(byte slaveAddress, string startAddress, object[] writeValue,
AddressTranslator addressTranslator)
{
BelongAddress = belongAddress;
SlaveAddress = slaveAddress;
var translateAddress = addressTranslator.AddressTranslate(startAddress, false);
FunctionCode = (byte) translateAddress.Area;
StartAddress = (ushort) translateAddress.Address;
var writeByteValue = BigEndianValueHelper.Instance.ObjectArrayToByteArray(writeValue);
WriteCount = (ushort)(writeByteValue.Length / addressTranslator.GetAreaByteLength(translateAddress.AreaString));
WriteCount =
(ushort) (writeByteValue.Length/addressTranslator.GetAreaByteLength(translateAddress.AreaString));
WriteByteCount = (byte) writeByteValue.Length;
WriteValue = writeByteValue;
}
public byte BelongAddress { get; private set; }
public byte SlaveAddress { get; }
public byte FunctionCode { get; private set; }
public byte FunctionCode { get; }
public ushort StartAddress { get; private set; }
public ushort StartAddress { get; }
public ushort WriteCount { get; private set; }
public ushort WriteCount { get; }
public byte WriteByteCount { get; private set; }
public byte WriteByteCount { get; }
public byte[] WriteValue { get; private set; }
public byte[] WriteValue { get; }
}
public class WriteDataModbusOutputStruct : OutputStruct
{
public WriteDataModbusOutputStruct(byte belongAddress, byte functionCode,
public WriteDataModbusOutputStruct(byte slaveAddress, byte functionCode,
ushort startAddress, ushort writeCount)
{
BelongAddress = belongAddress;
SlaveAddress = slaveAddress;
FunctionCode = functionCode;
StartAddress = startAddress;
WriteCount = writeCount;
}
public byte BelongAddress { get; private set; }
public byte SlaveAddress { get; private set; }
public byte FunctionCode { get; private set; }
@@ -183,26 +188,26 @@ namespace Modbus.Net.Modbus
{
var r_message = (WriteDataModbusInputStruct) message;
var functionCode = r_message.FunctionCode;
byte[] dataValue = Format(r_message.WriteValue);
var dataValue = Format(r_message.WriteValue);
if (functionCode == 5 || functionCode == 15)
{
for (int i = 0; i < dataValue.Length; i++)
for (var i = 0; i < dataValue.Length; i++)
{
dataValue[i] = BigEndianValueHelper.Instance.ReverseByte(dataValue[i]);
}
}
byte[] formattingBytes = Format(r_message.BelongAddress, r_message.FunctionCode,
var formattingBytes = Format(r_message.SlaveAddress, r_message.FunctionCode,
r_message.StartAddress, r_message.WriteCount, r_message.WriteByteCount, dataValue);
return formattingBytes;
}
public override OutputStruct Unformat(byte[] messageBytes, ref int flag)
{
byte belongAddress = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
byte functionCode = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
ushort startAddress = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref flag);
ushort writeCount = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref flag);
return new WriteDataModbusOutputStruct(belongAddress, functionCode, startAddress,
var slaveAddress = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
var functionCode = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
var startAddress = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref flag);
var writeCount = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref flag);
return new WriteDataModbusOutputStruct(slaveAddress, functionCode, startAddress,
writeCount);
}
}
@@ -210,38 +215,39 @@ namespace Modbus.Net.Modbus
#endregion
#region PLC时间
public class GetSystemTimeModbusInputStruct : InputStruct
{
public GetSystemTimeModbusInputStruct(byte belongAddress)
public GetSystemTimeModbusInputStruct(byte slaveAddress)
{
BelongAddress = belongAddress;
SlaveAddress = slaveAddress;
FunctionCode = (byte) ModbusProtocalTimeFunctionCode.GetSystemTime;
StartAddress = 30000;
GetCount = 5;
}
public byte BelongAddress { get; private set; }
public byte SlaveAddress { get; }
public byte FunctionCode { get; private set; }
public byte FunctionCode { get; }
public ushort StartAddress { get; private set; }
public ushort StartAddress { get; }
public ushort GetCount { get; private set; }
public ushort GetCount { get; }
}
public class GetSystemTimeModbusOutputStruct : OutputStruct
{
public GetSystemTimeModbusOutputStruct(byte belongAddress, byte functionCode,
public GetSystemTimeModbusOutputStruct(byte slaveAddress, byte functionCode,
byte writeByteCount, ushort year, byte day, byte month, ushort hour, byte second, byte minute,
ushort millisecond)
{
BelongAddress = belongAddress;
SlaveAddress = slaveAddress;
FunctionCode = functionCode;
WriteByteCount = writeByteCount;
Time = new DateTime(year, month, day, hour, minute, second, millisecond);
}
public byte BelongAddress { get; private set; }
public byte SlaveAddress { get; private set; }
public byte FunctionCode { get; private set; }
@@ -258,23 +264,23 @@ namespace Modbus.Net.Modbus
public override byte[] Format(InputStruct message)
{
var r_message = (GetSystemTimeModbusInputStruct) message;
return Format(r_message.BelongAddress, r_message.FunctionCode,
return Format(r_message.SlaveAddress, r_message.FunctionCode,
r_message.StartAddress, r_message.GetCount);
}
public override OutputStruct Unformat(byte[] messageBytes, ref int flag)
{
byte belongAddress = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
byte functionCode = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
byte writeByteCount = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
ushort year = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref flag);
byte day = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
byte month = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
ushort hour = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref flag);
byte second = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
byte minute = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
ushort millisecond = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref flag);
return new GetSystemTimeModbusOutputStruct(belongAddress, functionCode, writeByteCount, year, day,
var slaveAddress = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
var functionCode = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
var writeByteCount = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
var year = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref flag);
var day = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
var month = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
var hour = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref flag);
var second = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
var minute = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
var millisecond = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref flag);
return new GetSystemTimeModbusOutputStruct(slaveAddress, functionCode, writeByteCount, year, day,
month, hour, second, minute, millisecond);
}
}
@@ -282,11 +288,12 @@ namespace Modbus.Net.Modbus
#endregion
#region PLC时间
public class SetSystemTimeModbusInputStruct : InputStruct
{
public SetSystemTimeModbusInputStruct(byte belongAddress, DateTime time)
public SetSystemTimeModbusInputStruct(byte slaveAddress, DateTime time)
{
BelongAddress = belongAddress;
SlaveAddress = slaveAddress;
FunctionCode = (byte) ModbusProtocalTimeFunctionCode.SetSystemTime;
StartAddress = 30000;
WriteCount = 5;
@@ -300,43 +307,43 @@ namespace Modbus.Net.Modbus
Millisecond = (ushort) time.Millisecond;
}
public byte BelongAddress { get; private set; }
public byte SlaveAddress { get; }
public byte FunctionCode { get; private set; }
public byte FunctionCode { get; }
public ushort StartAddress { get; private set; }
public ushort StartAddress { get; }
public ushort WriteCount { get; private set; }
public ushort WriteCount { get; }
public byte WriteByteCount { get; private set; }
public byte WriteByteCount { get; }
public ushort Year { get; private set; }
public ushort Year { get; }
public byte Day { get; private set; }
public byte Day { get; }
public byte Month { get; private set; }
public byte Month { get; }
public ushort Hour { get; private set; }
public ushort Hour { get; }
public byte Second { get; private set; }
public byte Second { get; }
public byte Minute { get; private set; }
public byte Minute { get; }
public ushort Millisecond { get; private set; }
public ushort Millisecond { get; }
}
public class SetSystemTimeModbusOutputStruct : OutputStruct
{
public SetSystemTimeModbusOutputStruct(byte belongAddress, byte functionCode,
public SetSystemTimeModbusOutputStruct(byte slaveAddress, byte functionCode,
ushort startAddress, ushort writeCount)
{
BelongAddress = belongAddress;
SlaveAddress = slaveAddress;
FunctionCode = functionCode;
StartAddress = startAddress;
WriteCount = writeCount;
}
public byte BelongAddress { get; private set; }
public byte SlaveAddress { get; private set; }
public byte FunctionCode { get; private set; }
@@ -353,7 +360,7 @@ namespace Modbus.Net.Modbus
public override byte[] Format(InputStruct message)
{
var r_message = (SetSystemTimeModbusInputStruct) message;
return Format(r_message.BelongAddress, r_message.FunctionCode,
return Format(r_message.SlaveAddress, r_message.FunctionCode,
r_message.StartAddress, r_message.WriteCount, r_message.WriteByteCount, r_message.Year,
r_message.Day,
r_message.Month, r_message.Hour, r_message.Second, r_message.Minute, r_message.Millisecond);
@@ -361,13 +368,14 @@ namespace Modbus.Net.Modbus
public override OutputStruct Unformat(byte[] messageBytes, ref int flag)
{
byte belongAddress = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
byte functionCode = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
ushort startAddress = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref flag);
ushort writeCount = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref flag);
return new SetSystemTimeModbusOutputStruct(belongAddress, functionCode, startAddress, writeCount);
var slaveAddress = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
var functionCode = BigEndianValueHelper.Instance.GetByte(messageBytes, ref flag);
var startAddress = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref flag);
var writeCount = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref flag);
return new SetSystemTimeModbusOutputStruct(slaveAddress, functionCode, startAddress, writeCount);
}
}
#endregion
/// <summary>
@@ -375,8 +383,7 @@ namespace Modbus.Net.Modbus
/// </summary>
public class ModbusProtocalErrorException : ProtocalErrorException
{
public int ErrorMessageNumber { get; private set; }
private static readonly Dictionary<int, string> ProtocalErrorDictionary = new Dictionary<int, string>()
private static readonly Dictionary<int, string> ProtocalErrorDictionary = new Dictionary<int, string>
{
{1, "ILLEGAL_FUNCTION"},
{2, "ILLEGAL_DATA_ACCESS"},
@@ -385,7 +392,7 @@ namespace Modbus.Net.Modbus
{5, "ACKNOWLWDGE"},
{6, "SLAVE_DEVICE_BUSY"},
{500, "TCP_ILLEGAL_LENGTH"},
{501, "RTU_ILLEGAL_CRC"},
{501, "RTU_ILLEGAL_CRC"}
};
public ModbusProtocalErrorException(int messageNumber)
@@ -393,5 +400,7 @@ namespace Modbus.Net.Modbus
{
ErrorMessageNumber = messageNumber;
}
public int ErrorMessageNumber { get; private set; }
}
}

View File

@@ -13,9 +13,9 @@ namespace Modbus.Net.Modbus
public override byte[] BytesExtend(byte[] content)
{
//Modbus/Tcp协议扩张前面加6个字节前面4个为0后面两个为协议整体内容的长度
byte[] newFormat = new byte[6 + content.Length];
int tag = 0;
ushort leng = (ushort)content.Length;
var newFormat = new byte[6 + content.Length];
var tag = 0;
var leng = (ushort) content.Length;
Array.Copy(BigEndianValueHelper.Instance.GetBytes(tag), 0, newFormat, 0, 4);
Array.Copy(BigEndianValueHelper.Instance.GetBytes(leng), 0, newFormat, 4, 2);
Array.Copy(content, 0, newFormat, 6, content.Length);
@@ -25,7 +25,7 @@ namespace Modbus.Net.Modbus
public override byte[] BytesDecact(byte[] content)
{
//Modbus/Tcp协议收缩抛弃前面6个字节的内容
byte[] newContent = new byte[content.Length - 6];
var newContent = new byte[content.Length - 6];
Array.Copy(content, 6, newContent, 0, newContent.Length);
return newContent;
}
@@ -35,9 +35,9 @@ namespace Modbus.Net.Modbus
{
public override byte[] BytesExtend(byte[] content)
{
byte[] crc = new byte[2];
var crc = new byte[2];
//Modbus/Rtu协议扩张增加CRC校验
byte[] newFormat = new byte[content.Length + 2];
var newFormat = new byte[content.Length + 2];
Crc16.GetInstance().GetCRC(content, ref crc);
Array.Copy(content, 0, newFormat, 0, content.Length);
Array.Copy(crc, 0, newFormat, newFormat.Length - 2, crc.Length);
@@ -47,7 +47,7 @@ namespace Modbus.Net.Modbus
public override byte[] BytesDecact(byte[] content)
{
//Modbus/Rtu协议收缩抛弃后面2个字节的内容
byte[] newContent = new byte[content.Length - 2];
var newContent = new byte[content.Length - 2];
Array.Copy(content, 0, newContent, 0, newContent.Length);
return newContent;
}
@@ -57,7 +57,7 @@ namespace Modbus.Net.Modbus
{
public override byte[] BytesExtend(byte[] content)
{
List<byte> newContent = new List<byte>();
var newContent = new List<byte>();
newContent.AddRange(Encoding.ASCII.GetBytes(":"));
foreach (var number in content)
{
@@ -71,11 +71,11 @@ namespace Modbus.Net.Modbus
public override byte[] BytesDecact(byte[] content)
{
List<byte> newContent = new List<byte>();
string ans = Encoding.ASCII.GetString(content);
var newContent = new List<byte>();
var ans = Encoding.ASCII.GetString(content);
var index = ans.IndexOf(Environment.NewLine);
ans = ans.Substring(1, index - 1);
for (int i = 0; i < ans.Length; i += 2)
for (var i = 0; i < ans.Length; i += 2)
{
var number = byte.Parse(ans.Substring(i, 2), NumberStyles.HexNumber);
newContent.Add(number);

View File

@@ -5,11 +5,13 @@
/// </summary>
public class ModbusRtuProtocal : ModbusProtocal
{
public ModbusRtuProtocal(byte belongAddress, byte masterAddress) : this(ConfigurationManager.COM, belongAddress, masterAddress)
public ModbusRtuProtocal(byte slaveAddress, byte masterAddress)
: this(ConfigurationManager.COM, slaveAddress, masterAddress)
{
}
public ModbusRtuProtocal(string com, byte belongAddress, byte masterAddress) : base(belongAddress, masterAddress)
public ModbusRtuProtocal(string com, byte slaveAddress, byte masterAddress)
: base(slaveAddress, masterAddress)
{
ProtocalLinker = new ModbusRtuProtocalLinker(com);
}

View File

@@ -2,8 +2,12 @@
namespace Modbus.Net.Modbus
{
class ModbusRtuProtocalLinker : ComProtocalLinker
public class ModbusRtuProtocalLinker : ComProtocalLinker
{
public ModbusRtuProtocalLinker(string com) : base(com, 9600, Parity.None, StopBits.One, 8)
{
}
public override bool? CheckRight(byte[] content)
{
if (!base.CheckRight(content).Value) return false;
@@ -19,10 +23,5 @@ namespace Modbus.Net.Modbus
}
return true;
}
public ModbusRtuProtocalLinker(string com) : base(com, 9600, Parity.None, StopBits.One, 8)
{
}
}
}

View File

@@ -5,16 +5,18 @@
/// </summary>
public class ModbusTcpProtocal : ModbusProtocal
{
public ModbusTcpProtocal(byte belongAddress, byte masterAddress) : this(ConfigurationManager.IP, belongAddress, masterAddress)
public ModbusTcpProtocal(byte slaveAddress, byte masterAddress)
: this(ConfigurationManager.IP, slaveAddress, masterAddress)
{
}
public ModbusTcpProtocal(string ip, byte belongAddress, byte masterAddress) : base(belongAddress, masterAddress)
public ModbusTcpProtocal(string ip, byte slaveAddress, byte masterAddress) : base(slaveAddress, masterAddress)
{
ProtocalLinker = new ModbusTcpProtocalLinker(ip);
}
public ModbusTcpProtocal(string ip, int port, byte belongAddress, byte masterAddress) : base(belongAddress, masterAddress)
public ModbusTcpProtocal(string ip, int port, byte slaveAddress, byte masterAddress)
: base(slaveAddress, masterAddress)
{
ProtocalLinker = new ModbusTcpProtocalLinker(ip, port);
}

View File

@@ -2,6 +2,14 @@
{
public class ModbusTcpProtocalLinker : TcpProtocalLinker
{
public ModbusTcpProtocalLinker(string ip) : base(ip, int.Parse(ConfigurationManager.ModbusPort))
{
}
public ModbusTcpProtocalLinker(string ip, int port) : base(ip, port)
{
}
public override bool? CheckRight(byte[] content)
{
if (!base.CheckRight(content).Value) return false;
@@ -17,15 +25,5 @@
}
return true;
}
public ModbusTcpProtocalLinker(string ip) : base(ip, int.Parse(ConfigurationManager.ModbusPort))
{
}
public ModbusTcpProtocalLinker(string ip, int port) : base(ip, port)
{
}
}
}

View File

@@ -1,5 +1,4 @@
using System;
using System.Threading.Tasks;
using System.Threading.Tasks;
namespace Modbus.Net.Modbus
{
@@ -12,20 +11,38 @@ namespace Modbus.Net.Modbus
/// Rtu连接
/// </summary>
Rtu = 0,
/// <summary>
/// Tcp连接
/// </summary>
Tcp = 1,
/// <summary>
/// Ascii连接
/// </summary>
Ascii = 2,
Ascii = 2
}
public class ModbusUtility : BaseUtility
{
private ModbusType _modbusType;
public ModbusUtility(int connectionType, byte slaveAddress, byte masterAddress)
: base(slaveAddress, masterAddress)
{
ConnectionString = null;
ModbusType = (ModbusType) connectionType;
AddressTranslator = new AddressTranslatorModbus();
}
public ModbusUtility(ModbusType connectionType, string connectionString, byte slaveAddress, byte masterAddress)
: base(slaveAddress, masterAddress)
{
ConnectionString = connectionString;
ModbusType = connectionType;
AddressTranslator = new AddressTranslatorModbus();
}
public override bool GetLittleEndian => Wrapper[typeof (ReadDataModbusProtocal)].IsLittleEndian;
public override bool SetLittleEndian => Wrapper[typeof (WriteDataModbusProtocal)].IsLittleEndian;
@@ -53,16 +70,12 @@ namespace Modbus.Net.Modbus
{
return null;
}
}
}
public ModbusType ModbusType
{
get
{
return _modbusType;
}
get { return _modbusType; }
set
{
_modbusType = value;
@@ -70,37 +83,32 @@ namespace Modbus.Net.Modbus
{
case ModbusType.Rtu:
{
Wrapper = ConnectionString == null ? new ModbusRtuProtocal(BelongAddress, MasterAddress) : new ModbusRtuProtocal(ConnectionString, BelongAddress, MasterAddress);
Wrapper = ConnectionString == null
? new ModbusRtuProtocal(SlaveAddress, MasterAddress)
: new ModbusRtuProtocal(ConnectionString, SlaveAddress, MasterAddress);
break;
}
case ModbusType.Tcp:
{
Wrapper = ConnectionString == null ? new ModbusTcpProtocal(BelongAddress, MasterAddress) : (ConnectionStringPort == null ? new ModbusTcpProtocal(ConnectionString, BelongAddress, MasterAddress) : new ModbusTcpProtocal(ConnectionStringIp,ConnectionStringPort.Value, BelongAddress, MasterAddress));
Wrapper = ConnectionString == null
? new ModbusTcpProtocal(SlaveAddress, MasterAddress)
: (ConnectionStringPort == null
? new ModbusTcpProtocal(ConnectionString, SlaveAddress, MasterAddress)
: new ModbusTcpProtocal(ConnectionStringIp, ConnectionStringPort.Value, SlaveAddress,
MasterAddress));
break;
}
case ModbusType.Ascii:
{
Wrapper = ConnectionString == null ? new ModbusAsciiProtocal(BelongAddress, MasterAddress) : new ModbusAsciiProtocal(ConnectionString, BelongAddress, MasterAddress);
Wrapper = ConnectionString == null
? new ModbusAsciiProtocal(SlaveAddress, MasterAddress)
: new ModbusAsciiProtocal(ConnectionString, SlaveAddress, MasterAddress);
break;
}
}
}
}
public ModbusUtility(int connectionType, byte belongAddress, byte masterAddress) : base(belongAddress, masterAddress)
{
ConnectionString = null;
ModbusType = (ModbusType)connectionType;
AddressTranslator = new AddressTranslatorModbus();
}
public ModbusUtility(ModbusType connectionType, string connectionString, byte belongAddress, byte masterAddress) : base(belongAddress, masterAddress)
{
ConnectionString = connectionString;
ModbusType = connectionType;
AddressTranslator = new AddressTranslatorModbus();
}
public override void SetConnectionType(int connectionType)
{
ModbusType = (ModbusType) connectionType;
@@ -110,7 +118,7 @@ namespace Modbus.Net.Modbus
{
try
{
var inputStruct = new ReadDataModbusInputStruct(BelongAddress, startAddress,
var inputStruct = new ReadDataModbusInputStruct(SlaveAddress, startAddress,
(ushort) getByteCount, AddressTranslator);
var outputStruct = await
Wrapper.SendReceiveAsync(Wrapper[typeof (ReadDataModbusProtocal)], inputStruct) as
@@ -127,7 +135,7 @@ namespace Modbus.Net.Modbus
{
try
{
var inputStruct = new WriteDataModbusInputStruct(BelongAddress, startAddress, setContents,
var inputStruct = new WriteDataModbusInputStruct(SlaveAddress, startAddress, setContents,
AddressTranslator);
var outputStruct = await
Wrapper.SendReceiveAsync(Wrapper[typeof (WriteDataModbusProtocal)], inputStruct) as
@@ -145,7 +153,7 @@ namespace Modbus.Net.Modbus
{
try
{
var inputStruct = new GetSystemTimeModbusInputStruct(BelongAddress);
var inputStruct = new GetSystemTimeModbusInputStruct(SlaveAddress);
var outputStruct =
Wrapper.SendReceive(Wrapper[typeof(GetSystemTimeModbusProtocal)], inputStruct) as
GetSystemTimeModbusOutputStruct;
@@ -161,7 +169,7 @@ namespace Modbus.Net.Modbus
{
try
{
var inputStruct = new SetSystemTimeModbusInputStruct(BelongAddress, setTime);
var inputStruct = new SetSystemTimeModbusInputStruct(SlaveAddress, setTime);
var outputStruct =
Wrapper.SendReceive(Wrapper[typeof(SetSystemTimeModbusProtocal)], inputStruct) as
SetSystemTimeModbusOutputStruct;

View File

@@ -1,33 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Modbus.Net.OPC
{
public class AddressFormaterOpc : AddressFormater
{
public BaseMachine Machine { get; set; }
protected Func<BaseMachine, AddressUnit, string[]> TagGeter { get; set; }
protected char Seperator { get; set; }
public AddressFormaterOpc(Func<BaseMachine, AddressUnit, string[]> tagGeter, BaseMachine machine, char seperator = '/')
public AddressFormaterOpc(Func<BaseMachine, AddressUnit, string[]> tagGeter, BaseMachine machine,
char seperator = '/')
{
Machine = machine;
TagGeter = tagGeter;
Seperator = seperator;
}
public BaseMachine Machine { get; set; }
protected Func<BaseMachine, AddressUnit, string[]> TagGeter { get; set; }
protected char Seperator { get; set; }
public override string FormatAddress(string area, int address)
{
var findAddress = Machine?.GetAddresses.FirstOrDefault(p => p.Area == area && p.Address == address);
if (findAddress == null) return null;
var strings = TagGeter(Machine, findAddress);
var ans = "";
for (int i = 0; i < strings.Length; i++)
for (var i = 0; i < strings.Length; i++)
{
ans += strings[i].Trim().Replace(" ", "") + Seperator;
}

View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Modbus.Net.OPC
{

View File

@@ -7,7 +7,6 @@ using Opc.Da;
namespace Modbus.Net.OPC
{
/// <summary>
/// Read value full result
/// </summary>
@@ -20,17 +19,23 @@ namespace Modbus.Net.OPC
public class MyDaClient : DaClient
{
public MyDaClient(Uri serverUrl) : base(serverUrl)
{
}
/// <summary>
/// Write a value on the specified opc tag
/// </summary>
/// <param name="tag">The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name.
/// E.g: the tag `foo.bar` writes on the tag `bar` on the folder `foo`</param>
/// <param name="tag">
/// The fully-qualified identifier of the tag. You can specify a subfolder by using a comma delimited name.
/// E.g: the tag `foo.bar` writes on the tag `bar` on the folder `foo`
/// </param>
public OpcValueResult Read(string tag)
{
var item = new Item {ItemName = tag};
var result = Server.Read(new[] {item})[0];
CheckResult(result, tag);
return new OpcValueResult()
return new OpcValueResult
{
Value = result.Value,
Timestamp = result.Timestamp,
@@ -46,16 +51,14 @@ namespace Modbus.Net.OPC
return Task.Run(() => Read(tag));
}
public MyDaClient(Uri serverUrl) : base(serverUrl)
{
}
private static void CheckResult(IResult result, string tag)
{
if (result == null)
throw new OpcException("The server replied with an empty response");
if (result.ResultID.ToString() != "S_OK")
throw new OpcException(string.Format("Invalid response from the server. (Response Status: {0}, Opc Tag: {1})", result.ResultID, tag));
throw new OpcException(
string.Format("Invalid response from the server. (Response Status: {0}, Opc Tag: {1})",
result.ResultID, tag));
}
}
}

View File

@@ -1,22 +1,15 @@
using System;
using System.Collections.Generic;
using System.Diagnostics.Eventing.Reader;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Hylasoft.Opc.Common;
using Hylasoft.Opc.Da;
namespace Modbus.Net.OPC
{
public class OpcDaConnector : BaseConnector
{
public override string ConnectionToken { get; }
protected static Dictionary<string, OpcDaConnector> _instances = new Dictionary<string, OpcDaConnector>();
protected bool _connect;
public override bool IsConnected => _connect;
protected static Dictionary<string, OpcDaConnector> _instances = new Dictionary<string, OpcDaConnector>();
protected MyDaClient _daClient;
protected OpcDaConnector(string host)
@@ -24,6 +17,9 @@ namespace Modbus.Net.OPC
ConnectionToken = host;
}
public override string ConnectionToken { get; }
public override bool IsConnected => _connect;
public static OpcDaConnector Instance(string host)
{
if (!_instances.ContainsKey(host))
@@ -99,23 +95,20 @@ namespace Modbus.Net.OPC
var protocal = BigEndianValueHelper.Instance.GetByte(message, ref pos);
if (protocal == 0)
{
byte[] tagBytes = new byte[message.Length - 1];
var tagBytes = new byte[message.Length - 1];
Array.Copy(message, 1, tagBytes, 0, tagBytes.Length);
string tag = Encoding.UTF8.GetString(tagBytes);
var tag = Encoding.UTF8.GetString(tagBytes);
var result = await _daClient.ReadAsync(tag);
if (result.QualityGood)
{
return BigEndianValueHelper.Instance.GetBytes(result.Value, result.Value.GetType());
}
else
{
return Encoding.ASCII.GetBytes("NoData");
}
}
else
{
int index = 0;
for (int i = 1; i < message.Length - 3; i++)
var index = 0;
for (var i = 1; i < message.Length - 3; i++)
{
if (message[i] == 0x00 && message[i + 1] == 0xff && message[i + 2] == 0xff &&
message[i + 3] == 0x00)
@@ -125,8 +118,8 @@ namespace Modbus.Net.OPC
}
}
int index2 = 0;
for (int i = index + 4; i < message.Length - 3; i++)
var index2 = 0;
for (var i = index + 4; i < message.Length - 3; i++)
{
if (message[i] == 0x00 && message[i + 1] == 0xff && message[i + 2] == 0xff &&
message[i + 3] == 0x00)
@@ -135,16 +128,16 @@ namespace Modbus.Net.OPC
break;
}
}
byte[] tagBytes = new byte[index - 1];
var tagBytes = new byte[index - 1];
Array.Copy(message, 1, tagBytes, 0, tagBytes.Length);
string tag = Encoding.UTF8.GetString(tagBytes);
byte[] typeBytes = new byte[index2 - index - 4];
var tag = Encoding.UTF8.GetString(tagBytes);
var typeBytes = new byte[index2 - index - 4];
Array.Copy(message, index + 4, typeBytes, 0, typeBytes.Length);
Type type = Type.GetType(Encoding.UTF8.GetString(typeBytes));
byte[] valueBytes = new byte[message.Length - index2 - 4];
var type = Type.GetType(Encoding.UTF8.GetString(typeBytes));
var valueBytes = new byte[message.Length - index2 - 4];
Array.Copy(message, index2 + 4, valueBytes, 0, valueBytes.Length);
int mainpos = 0, subpos = 0;
object value = BigEndianValueHelper.Instance.GetValue(valueBytes, ref mainpos, ref subpos, type);
var value = BigEndianValueHelper.Instance.GetValue(valueBytes, ref mainpos, ref subpos, type);
await _daClient.WriteAsync(tag, value);
return new byte[] {1};
}

View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections.Generic;
namespace Modbus.Net.OPC
{

View File

@@ -1,16 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading.Tasks;
namespace Modbus.Net.OPC
{
public class OpcDaProtocal : OpcProtocal
{
private int _connectTryCount;
private readonly string _host;
private int _connectTryCount;
public OpcDaProtocal(string host)
{

View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text;
namespace Modbus.Net.OPC
{
@@ -10,12 +6,11 @@ namespace Modbus.Net.OPC
{
public OpcDaProtocalLinker() : this(ConfigurationManager.OpcDaHost)
{
}
public OpcDaProtocalLinker(string host)
{
_baseConnector = OpcDaConnector.Instance(host);
BaseConnector = OpcDaConnector.Instance(host);
}
public override bool? CheckRight(byte[] content)

View File

@@ -1,16 +1,10 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Modbus.Net.OPC
{
public class OpcDaUtility : BaseUtility
{
public override bool GetLittleEndian => Wrapper[typeof (ReadRequestOpcProtocal)].IsLittleEndian;
public override bool SetLittleEndian => Wrapper[typeof (WriteRequestOpcProtocal)].IsLittleEndian;
public OpcDaUtility(string connectionString) : base(0, 0)
{
ConnectionString = connectionString;
@@ -18,6 +12,9 @@ namespace Modbus.Net.OPC
Wrapper = new OpcDaProtocal(ConnectionString);
}
public override bool GetLittleEndian => Wrapper[typeof (ReadRequestOpcProtocal)].IsLittleEndian;
public override bool SetLittleEndian => Wrapper[typeof (WriteRequestOpcProtocal)].IsLittleEndian;
public override void SetConnectionType(int connectionType)
{
}
@@ -29,7 +26,8 @@ namespace Modbus.Net.OPC
var readRequestOpcInputStruct = new ReadRequestOpcInputStruct(startAddress);
var readRequestOpcOutputStruct =
await
Wrapper.SendReceiveAsync(Wrapper[typeof(ReadRequestOpcProtocal)], readRequestOpcInputStruct) as ReadRequestOpcOutputStruct;
Wrapper.SendReceiveAsync(Wrapper[typeof (ReadRequestOpcProtocal)], readRequestOpcInputStruct) as
ReadRequestOpcOutputStruct;
return readRequestOpcOutputStruct?.GetValue;
}
catch (Exception)
@@ -45,7 +43,8 @@ namespace Modbus.Net.OPC
var writeRequestOpcInputStruct = new WriteRequestOpcInputStruct(startAddress, setContents[0]);
var writeRequestOpcOutputStruct =
await
Wrapper.SendReceiveAsync(Wrapper[typeof(WriteRequestOpcProtocal)], writeRequestOpcInputStruct) as WriteRequestOpcOutputStruct;
Wrapper.SendReceiveAsync(Wrapper[typeof (WriteRequestOpcProtocal)], writeRequestOpcInputStruct)
as WriteRequestOpcOutputStruct;
return writeRequestOpcOutputStruct?.WriteResult == true;
}
catch (Exception e)

View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Text;
namespace Modbus.Net.OPC
{
@@ -20,7 +16,7 @@ namespace Modbus.Net.OPC
Tag = tag;
}
public string Tag { get; private set; }
public string Tag { get; }
}
public class ReadRequestOpcOutputStruct : OutputStruct
@@ -55,8 +51,8 @@ namespace Modbus.Net.OPC
SetValue = setValue;
}
public string Tag { get; private set; }
public object SetValue { get; private set; }
public string Tag { get; }
public object SetValue { get; }
}
public class WriteRequestOpcOutputStruct : OutputStruct
@@ -67,7 +63,6 @@ namespace Modbus.Net.OPC
}
public bool WriteResult { get; private set; }
}
public class WriteRequestOpcProtocal : SpecialProtocalUnit
@@ -75,9 +70,9 @@ namespace Modbus.Net.OPC
public override byte[] Format(InputStruct message)
{
var r_message = (WriteRequestOpcInputStruct) message;
byte[] tag = Encoding.UTF8.GetBytes(r_message.Tag);
byte[] fullName = Encoding.UTF8.GetBytes(r_message.SetValue.GetType().FullName);
return Format((byte)0x01, tag, (int)0x00ffff00, fullName, (int)0x00ffff00, r_message.SetValue);
var tag = Encoding.UTF8.GetBytes(r_message.Tag);
var fullName = Encoding.UTF8.GetBytes(r_message.SetValue.GetType().FullName);
return Format((byte) 0x01, tag, 0x00ffff00, fullName, 0x00ffff00, r_message.SetValue);
}
public override OutputStruct Unformat(byte[] messageBytes, ref int pos)

View File

@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Modbus.Net.Siemens
namespace Modbus.Net.Siemens
{
public class AddressFormaterSiemens : AddressFormater
{

View File

@@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
namespace Modbus.Net.Siemens
@@ -23,20 +22,20 @@ namespace Modbus.Net.Siemens
{"Q", 0x82},
{"M", 0x83},
{"DB", 0x84},
{"V", 0x184},
{"V", 0x184}
};
}
public override AddressDef AddressTranslate(string address, bool isRead)
{
address = address.ToUpper();
string[] splitString = address.Split(' ');
string head = splitString[0];
string tail = splitString[1];
var splitString = address.Split(' ');
var head = splitString[0];
var tail = splitString[1];
string sub;
if (tail.Contains('.'))
{
string[] splitString2 = tail.Split('.');
var splitString2 = tail.Split('.');
sub = splitString2[1];
tail = splitString2[0];
}
@@ -47,21 +46,21 @@ namespace Modbus.Net.Siemens
if (head.Length > 1 && head.Substring(0, 2) == "DB")
{
head = head.Substring(2);
return new AddressDef()
return new AddressDef
{
AreaString = "DB" + head,
Area = int.Parse(head)*256 + AreaCodeDictionary["DB"],
Address = int.Parse(tail),
SubAddress = int.Parse(sub),
SubAddress = int.Parse(sub)
};
}
return
new AddressDef()
new AddressDef
{
AreaString = head,
Area = AreaCodeDictionary[head],
Address = int.Parse(tail),
SubAddress = int.Parse(sub),
SubAddress = int.Parse(sub)
};
}

View File

@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading.Tasks;
namespace Modbus.Net.Siemens
{
@@ -10,11 +6,13 @@ namespace Modbus.Net.Siemens
{
private readonly string _com;
public SiemensPpiProtocal(byte belongAddress, byte masterAddress) : this( ConfigurationManager.COM, belongAddress, masterAddress)
public SiemensPpiProtocal(byte slaveAddress, byte masterAddress)
: this(ConfigurationManager.COM, slaveAddress, masterAddress)
{
}
public SiemensPpiProtocal(string com, byte belongAddress, byte masterAddress) : base(belongAddress, masterAddress)
public SiemensPpiProtocal(string com, byte slaveAddress, byte masterAddress)
: base(slaveAddress, masterAddress)
{
_com = com;
}
@@ -46,7 +44,7 @@ namespace Modbus.Net.Siemens
public override async Task<bool> ConnectAsync()
{
ProtocalLinker = new SiemensPpiProtocalLinker(_com);
var inputStruct = new ComCreateReferenceSiemensInputStruct(BelongAddress, MasterAddress);
var inputStruct = new ComCreateReferenceSiemensInputStruct(SlaveAddress, MasterAddress);
var outputStruct =
await await
ForceSendReceiveAsync(this[typeof (ComCreateReferenceSiemensProtocal)],
@@ -54,7 +52,7 @@ namespace Modbus.Net.Siemens
ContinueWith(async answer =>
{
if (!ProtocalLinker.IsConnected) return false;
var inputStruct2 = new ComConfirmMessageSiemensInputStruct(BelongAddress, MasterAddress);
var inputStruct2 = new ComConfirmMessageSiemensInputStruct(SlaveAddress, MasterAddress);
var outputStruct2 =
(ComConfirmMessageSiemensOutputStruct)
await
@@ -62,7 +60,7 @@ namespace Modbus.Net.Siemens
inputStruct2);
return outputStruct2 != null;
});
return outputStruct != null;
return outputStruct;
}
}
}

View File

@@ -1,9 +1,4 @@
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.IO.Ports;
using System.Threading;
using System.Threading.Tasks;
@@ -11,9 +6,14 @@ namespace Modbus.Net.Siemens
{
public class SiemensPpiProtocalLinker : ComProtocalLinker
{
public SiemensPpiProtocalLinker(string com)
: base(com, 9600, Parity.Even, StopBits.One, 8)
{
}
public override async Task<byte[]> SendReceiveAsync(byte[] content)
{
byte[] extBytes = BytesExtend(content);
var extBytes = BytesExtend(content);
if (extBytes[6] == 0x7c)
{
var inputStruct2 = new ComConfirmMessageSiemensInputStruct(content[4], content[5]);
@@ -60,13 +60,13 @@ namespace Modbus.Net.Siemens
public override bool? CheckRight(byte[] content)
{
if (!base.CheckRight(content).Value) return false;
int fcsCheck = 0;
var fcsCheck = 0;
if (content.Length == 1 && content[0] == 0xe5)
{
return true;
}
if (content.Length == 6 && content[3] == 0) return true;
for (int i = 4; i < content.Length - 2; i++)
for (var i = 4; i < content.Length - 2; i++)
{
fcsCheck += content[i];
}
@@ -76,10 +76,5 @@ namespace Modbus.Net.Siemens
if (content[1] != content.Length - 6) return false;
return true;
}
public SiemensPpiProtocalLinker(string com)
: base(com, 9600, Parity.Even, StopBits.One, 8)
{
}
}
}

View File

@@ -12,8 +12,8 @@ namespace Modbus.Net.Siemens
DWord = 0x04,
C = 0x1E,
T = 0x1F,
HC = 0x20,
};
HC = 0x20
}
public enum SiemensAccessResult : byte
{
@@ -22,47 +22,47 @@ namespace Modbus.Net.Siemens
IllegalObjectAccess = 0x03,
InvalidAddress = 0x05,
DataTypeNotSupport = 0x06,
ObjNotExistOrLengthError = 0x0A,
};
ObjNotExistOrLengthError = 0x0A
}
public enum SiemensDataType : byte
{
Error = 0x00,
BitAccess = 0x03,
OtherAccess = 0x04
};
}
public abstract class SiemensProtocal : BaseProtocal
{
protected SiemensProtocal(byte belongAddress, byte masterAddress) : base(belongAddress, masterAddress)
protected SiemensProtocal(byte slaveAddress, byte masterAddress) : base(slaveAddress, masterAddress)
{
}
}
internal class ComCreateReferenceSiemensInputStruct : InputStruct
{
public byte BelongAddress { get; set; }
public byte MasterAddress { get; set; }
public ComCreateReferenceSiemensInputStruct(byte belongAddress, byte masterAddress)
public ComCreateReferenceSiemensInputStruct(byte slaveAddress, byte masterAddress)
{
BelongAddress = belongAddress;
SlaveAddress = slaveAddress;
MasterAddress = masterAddress;
}
public byte SlaveAddress { get; set; }
public byte MasterAddress { get; set; }
}
internal class ComCreateReferenceSiemensOutputStruct : OutputStruct
{
public byte BelongAddress { get; set; }
public byte MasterAddress { get; set; }
public byte ConfirmMessage { get; set; }
public ComCreateReferenceSiemensOutputStruct(byte belongAddress, byte masterAddress, byte confirmMessage)
public ComCreateReferenceSiemensOutputStruct(byte slaveAddress, byte masterAddress, byte confirmMessage)
{
BelongAddress = belongAddress;
SlaveAddress = slaveAddress;
MasterAddress = masterAddress;
ConfirmMessage = confirmMessage;
}
public byte SlaveAddress { get; set; }
public byte MasterAddress { get; set; }
public byte ConfirmMessage { get; set; }
}
internal class ComCreateReferenceSiemensProtocal : SpecialProtocalUnit
@@ -70,34 +70,35 @@ namespace Modbus.Net.Siemens
public override byte[] Format(InputStruct message)
{
var r_message = (ComCreateReferenceSiemensInputStruct) message;
var crc = (r_message.BelongAddress + r_message.MasterAddress + 0x49)%256;
return Format((byte)0x10, r_message.BelongAddress, r_message.MasterAddress, (byte)0x49, (byte)crc, (byte)0x16);
var crc = (r_message.SlaveAddress + r_message.MasterAddress + 0x49)%256;
return Format((byte) 0x10, r_message.SlaveAddress, r_message.MasterAddress, (byte) 0x49, (byte) crc,
(byte) 0x16);
}
public override OutputStruct Unformat(byte[] messageBytes, ref int pos)
{
pos = 1;
var masterAddress = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
var belongAddress = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
var slaveAddress = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
var confirmMessage = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
return new ComCreateReferenceSiemensOutputStruct(belongAddress, masterAddress, confirmMessage);
return new ComCreateReferenceSiemensOutputStruct(slaveAddress, masterAddress, confirmMessage);
}
}
internal class CreateReferenceSiemensInputStruct : InputStruct
{
public byte TdpuSize;
public ushort TsapDst;
public ushort TsapSrc;
public CreateReferenceSiemensInputStruct(byte tdpuSize, ushort srcTsap, ushort dstTsap)
{
TdpuSize = tdpuSize;
TsapSrc = srcTsap;
TsapDst = dstTsap;
}
public byte TdpuSize;
public ushort TsapSrc;
public ushort TsapDst;
}
internal class CreateReferenceSiemensOutputStruct : OutputStruct
@@ -127,11 +128,11 @@ namespace Modbus.Net.Siemens
const ushort srcRef = 0x000c;
const byte reserved = 0x00;
const ushort tdpuSizeCode = 0xc001;
byte tdpuSizeContent = r_message.TdpuSize;
var tdpuSizeContent = r_message.TdpuSize;
const ushort srcTsapCode = 0xc102;
ushort srcTsapContent = r_message.TsapSrc;
var srcTsapContent = r_message.TsapSrc;
const ushort dstTsapCode = 0xc202;
ushort dstTsapContent = r_message.TsapDst;
var dstTsapContent = r_message.TsapDst;
return Format(head, len, contentLen, typeCode, dstRef, srcRef, reserved, tdpuSizeCode, tdpuSizeContent,
srcTsapCode, srcTsapContent, dstTsapCode, dstTsapContent);
}
@@ -168,14 +169,14 @@ namespace Modbus.Net.Siemens
public class ComConfirmMessageSiemensInputStruct : InputStruct
{
public byte BelongAddress { get; set; }
public byte MasterAddress { get; set; }
public ComConfirmMessageSiemensInputStruct(byte belongAddress, byte masterAddress)
public ComConfirmMessageSiemensInputStruct(byte slaveAddress, byte masterAddress)
{
BelongAddress = belongAddress;
SlaveAddress = slaveAddress;
MasterAddress = masterAddress;
}
public byte SlaveAddress { get; set; }
public byte MasterAddress { get; set; }
}
public class ComConfirmMessageSiemensOutputStruct : OutputStruct
@@ -193,8 +194,9 @@ namespace Modbus.Net.Siemens
public override byte[] Format(InputStruct message)
{
var r_message = (ComConfirmMessageSiemensInputStruct) message;
var crc = r_message.BelongAddress + r_message.MasterAddress + 0x5c%256;
return Format((byte)0x10, r_message.BelongAddress, r_message.MasterAddress, (byte)0x5c, (byte)crc, (byte)0x16);
var crc = r_message.SlaveAddress + r_message.MasterAddress + 0x5c%256;
return Format((byte) 0x10, r_message.SlaveAddress, r_message.MasterAddress, (byte) 0x5c, (byte) crc,
(byte) 0x16);
}
public override OutputStruct Unformat(byte[] messageBytes, ref int pos)
@@ -214,10 +216,10 @@ namespace Modbus.Net.Siemens
MaxPdu = maxPdu;
}
public ushort PduRef { get; private set; }
public ushort MaxCalling { get; private set; }
public ushort MaxCalled { get; private set; }
public ushort MaxPdu { get; private set; }
public ushort PduRef { get; }
public ushort MaxCalling { get; }
public ushort MaxCalled { get; }
public ushort MaxPdu { get; }
}
internal class EstablishAssociationSiemensOutputStruct : OutputStruct
@@ -244,14 +246,14 @@ namespace Modbus.Net.Siemens
const byte protoId = 0x32;
const byte rosctr = 0x01;
const ushort redId = 0x0000;
ushort pduRef = r_message.PduRef;
var pduRef = r_message.PduRef;
const ushort parLg = 0x0008;
const ushort datLg = 0x0000;
const byte serviceId = 0xf0;
const byte reserved = 0x00;
ushort maxCalling = r_message.MaxCalling;
ushort maxCalled = r_message.MaxCalled;
ushort maxPdu = r_message.MaxPdu;
var maxCalling = r_message.MaxCalling;
var maxCalled = r_message.MaxCalled;
var maxPdu = r_message.MaxPdu;
return Format(new byte[7], protoId, rosctr, redId, pduRef, parLg, datLg, serviceId, reserved, maxCalling,
maxCalled, maxPdu);
}
@@ -259,44 +261,46 @@ namespace Modbus.Net.Siemens
public override OutputStruct Unformat(byte[] messageBytes, ref int pos)
{
pos = 4;
ushort pduRef = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
var pduRef = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
pos = 14;
ushort maxCalling = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
ushort maxCalled = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
ushort maxPdu = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
var maxCalling = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
var maxCalled = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
var maxPdu = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
return new EstablishAssociationSiemensOutputStruct(pduRef, maxCalling, maxCalled, maxPdu);
}
}
public class ReadRequestSiemensInputStruct : InputStruct
{
public ReadRequestSiemensInputStruct(byte belongAddress, byte masterAddress, ushort pduRef, SiemensTypeCode getType, string startAddress, ushort getCount, AddressTranslator addressTranslator)
public ReadRequestSiemensInputStruct(byte slaveAddress, byte masterAddress, ushort pduRef,
SiemensTypeCode getType, string startAddress, ushort getCount, AddressTranslator addressTranslator)
{
BelongAddress = belongAddress;
SlaveAddress = slaveAddress;
MasterAddress = masterAddress;
PduRef = pduRef;
TypeCode = (byte) getType;
var address = addressTranslator.AddressTranslate(startAddress, true);
Offset = address.Address;
int area = address.Area;
var area = address.Area;
Area = (byte) (area%256);
DbBlock = Area == 0x84 ? (ushort) (area/256) : (ushort) 0;
NumberOfElements = getCount;
}
public byte BelongAddress { get; set; }
public byte SlaveAddress { get; set; }
public byte MasterAddress { get; set; }
public ushort PduRef { get; private set; }
public byte TypeCode { get; private set; }
public ushort NumberOfElements { get; private set; }
public ushort DbBlock { get; private set; }
public byte Area { get; private set; }
public int Offset { get; private set; }
public ushort PduRef { get; }
public byte TypeCode { get; }
public ushort NumberOfElements { get; }
public ushort DbBlock { get; }
public byte Area { get; }
public int Offset { get; }
}
public class ReadRequestSiemensOutputStruct : OutputStruct
{
public ReadRequestSiemensOutputStruct(ushort pduRef, SiemensAccessResult accessResult, SiemensDataType dataType, ushort getLength, byte[] value)
public ReadRequestSiemensOutputStruct(ushort pduRef, SiemensAccessResult accessResult, SiemensDataType dataType,
ushort getLength, byte[] value)
{
PduRef = pduRef;
AccessResult = accessResult;
@@ -317,12 +321,12 @@ namespace Modbus.Net.Siemens
public override byte[] Format(InputStruct message)
{
var r_message = (ReadRequestSiemensInputStruct) message;
byte belongAddress = r_message.BelongAddress;
byte masterAddress = r_message.MasterAddress;
var slaveAddress = r_message.SlaveAddress;
var masterAddress = r_message.MasterAddress;
const byte protoId = 0x32;
const byte rosctr = 0x01;
const ushort redId = 0x0000;
ushort pduRef = r_message.PduRef;
var pduRef = r_message.PduRef;
const ushort parLg = 14; // 参数字节数2+12的倍数目前仅为14
const ushort datLg = 0; // 数据字节数
const byte serviceId = 0x04;
@@ -330,13 +334,14 @@ namespace Modbus.Net.Siemens
const byte variableSpec = 0x12;
const byte vAddrLg = 0x0A;
const byte syntaxId = 0x10;
byte type = r_message.TypeCode;
ushort numberOfElements = r_message.NumberOfElements;
ushort dbBlock = r_message.DbBlock;
byte area = r_message.Area;
int offsetBit = r_message.Offset*8;
byte[] offsetBitBytes = BigEndianValueHelper.Instance.GetBytes(offsetBit);
return Format(new byte[4], belongAddress, masterAddress, (byte)0x6c, protoId, rosctr, redId, pduRef, parLg, datLg, serviceId, numberOfVariables
var type = r_message.TypeCode;
var numberOfElements = r_message.NumberOfElements;
var dbBlock = r_message.DbBlock;
var area = r_message.Area;
var offsetBit = r_message.Offset*8;
var offsetBitBytes = BigEndianValueHelper.Instance.GetBytes(offsetBit);
return Format(new byte[4], slaveAddress, masterAddress, (byte) 0x6c, protoId, rosctr, redId, pduRef, parLg,
datLg, serviceId, numberOfVariables
, variableSpec, vAddrLg, syntaxId, type, numberOfElements, dbBlock, area,
offsetBitBytes.Skip(1).ToArray());
}
@@ -344,13 +349,13 @@ namespace Modbus.Net.Siemens
public override OutputStruct Unformat(byte[] messageBytes, ref int pos)
{
pos = 4;
ushort pduRef = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
var pduRef = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
pos = 14;
byte accessResult = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
byte dataType = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
ushort length = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
int byteLength = length/8;
var values = new Byte[byteLength];
var accessResult = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
var dataType = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
var length = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
var byteLength = length/8;
var values = new byte[byteLength];
Array.Copy(messageBytes, pos, values, 0, byteLength);
return new ReadRequestSiemensOutputStruct(pduRef, (SiemensAccessResult) accessResult,
(SiemensDataType) dataType, length, values);
@@ -359,26 +364,27 @@ namespace Modbus.Net.Siemens
public class WriteRequestSiemensInputStruct : InputStruct
{
public WriteRequestSiemensInputStruct(byte belongAddress, byte masterAddress, ushort pduRef, string startAddress, object[] writeValue, AddressTranslator addressTranslator)
public WriteRequestSiemensInputStruct(byte slaveAddress, byte masterAddress, ushort pduRef, string startAddress,
object[] writeValue, AddressTranslator addressTranslator)
{
BelongAddress = belongAddress;
SlaveAddress = slaveAddress;
MasterAddress = masterAddress;
PduRef = pduRef;
var address = addressTranslator.AddressTranslate(startAddress, true);
Offset = address.Address;
int area = address.Area;
var area = address.Area;
Area = (byte) (area%256);
DbBlock = Area == 0x84 ? (ushort) (area/256) : (ushort) 0;
WriteValue = writeValue;
}
public byte BelongAddress { get; set; }
public byte SlaveAddress { get; set; }
public byte MasterAddress { get; set; }
public ushort PduRef { get; private set; }
public ushort DbBlock { get; private set; }
public byte Area { get; private set; }
public int Offset { get; private set; }
public object[] WriteValue { get; private set; }
public ushort PduRef { get; }
public ushort DbBlock { get; }
public byte Area { get; }
public int Offset { get; }
public object[] WriteValue { get; }
}
public class WriteRequestSiemensOutputStruct : OutputStruct
@@ -391,7 +397,6 @@ namespace Modbus.Net.Siemens
public ushort PduRef { get; private set; }
public SiemensAccessResult AccessResult { get; private set; }
}
public class WriteRequestSiemensProtocal : ProtocalUnit
@@ -399,30 +404,31 @@ namespace Modbus.Net.Siemens
public override byte[] Format(InputStruct message)
{
var r_message = (WriteRequestSiemensInputStruct) message;
byte[] valueBytes = BigEndianValueHelper.Instance.ObjectArrayToByteArray(r_message.WriteValue);
byte belongAddress = r_message.BelongAddress;
byte masterAddress = r_message.MasterAddress;
var valueBytes = BigEndianValueHelper.Instance.ObjectArrayToByteArray(r_message.WriteValue);
var slaveAddress = r_message.SlaveAddress;
var masterAddress = r_message.MasterAddress;
const byte protoId = 0x32;
const byte rosctr = 0x01;
const ushort redId = 0x0000;
ushort pduRef = r_message.PduRef;
var pduRef = r_message.PduRef;
const ushort parLg = 14; // 参数字节数2+12的倍数目前仅为14
ushort datLg = (ushort)(4+valueBytes.Length); // 数据字节数
var datLg = (ushort) (4 + valueBytes.Length); // 数据字节数
const byte serviceId = 0x05;
const byte numberOfVariables = 1;
const byte variableSpec = 0x12;
const byte vAddrLg = 0x0A;
const byte syntaxId = 0x10;
const byte typeR = (byte) SiemensTypeCode.Byte;
ushort numberOfElements = (ushort)valueBytes.Length;
ushort dbBlock = r_message.DbBlock;
byte area = r_message.Area;
int offsetBit = r_message.Offset * 8;
byte[] offsetBitBytes = BigEndianValueHelper.Instance.GetBytes(offsetBit);
var numberOfElements = (ushort) valueBytes.Length;
var dbBlock = r_message.DbBlock;
var area = r_message.Area;
var offsetBit = r_message.Offset*8;
var offsetBitBytes = BigEndianValueHelper.Instance.GetBytes(offsetBit);
const byte reserved = 0x00;
const byte type = (byte) SiemensDataType.OtherAccess;
ushort numberOfWriteBits = (ushort)(valueBytes.Length*8);
return Format(new byte[4], belongAddress, masterAddress, (byte)0x7c, protoId, rosctr, redId, pduRef, parLg, datLg, serviceId, numberOfVariables
var numberOfWriteBits = (ushort) (valueBytes.Length*8);
return Format(new byte[4], slaveAddress, masterAddress, (byte) 0x7c, protoId, rosctr, redId, pduRef, parLg,
datLg, serviceId, numberOfVariables
, variableSpec, vAddrLg, syntaxId, typeR, numberOfElements, dbBlock, area,
offsetBitBytes.Skip(1).ToArray(), reserved, type, numberOfWriteBits, valueBytes);
}
@@ -431,15 +437,16 @@ namespace Modbus.Net.Siemens
{
if (messageBytes.Length == 1)
{
byte accessResult = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
return new WriteRequestSiemensOutputStruct(0, accessResult == 0xe5 ? SiemensAccessResult.NoError : SiemensAccessResult.InvalidAddress);
var accessResult = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
return new WriteRequestSiemensOutputStruct(0,
accessResult == 0xe5 ? SiemensAccessResult.NoError : SiemensAccessResult.InvalidAddress);
}
else
{
pos = 4;
ushort pduRef = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
var pduRef = BigEndianValueHelper.Instance.GetUShort(messageBytes, ref pos);
pos = 14;
byte accessResult = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
var accessResult = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
return new WriteRequestSiemensOutputStruct(pduRef, (SiemensAccessResult) accessResult);
}
}
@@ -525,9 +532,7 @@ namespace Modbus.Net.Siemens
public class SiemensProtocalErrorException : ProtocalErrorException
{
public int ErrorClass { get; private set; }
public int ErrorCode { get; private set; }
private static readonly Dictionary<int, string> ProtocalErrorDictionary = new Dictionary<int, string>()
private static readonly Dictionary<int, string> ProtocalErrorDictionary = new Dictionary<int, string>
{
{0x00, "No Error"},
{0x81, "Error in the application Id of the request"},
@@ -540,7 +545,7 @@ namespace Modbus.Net.Siemens
{0xD4, "Diagnostic error"},
{0xD6, "Protection system error"},
{0xD8, "BuB error"},
{0xEF, "Layer 2 specific error"},
{0xEF, "Layer 2 specific error"}
};
public SiemensProtocalErrorException(int errCls, int errCod)
@@ -549,5 +554,8 @@ namespace Modbus.Net.Siemens
ErrorClass = errCls;
ErrorCode = errCod;
}
public int ErrorClass { get; private set; }
public int ErrorCode { get; private set; }
}
}

View File

@@ -13,7 +13,7 @@ namespace Modbus.Net.Siemens
public override byte[] BytesDecact(byte[] content)
{
byte[] newContent = new byte[content.Length - 7];
var newContent = new byte[content.Length - 7];
Array.Copy(content, 7, newContent, 0, newContent.Length);
return newContent;
}
@@ -23,11 +23,12 @@ namespace Modbus.Net.Siemens
{
public override byte[] BytesExtend(byte[] content)
{
byte[] newContent = new byte[content.Length + 2];
var newContent = new byte[content.Length + 2];
Array.Copy(content, 0, newContent, 0, content.Length);
Array.Copy(new byte[] { 0x68, (byte)(content.Length - 4), (byte)(content.Length - 4), 0x68 }, 0, newContent, 0, 4);
int check = 0;
for (int i = 4; i < newContent.Length - 2; i++)
Array.Copy(new byte[] {0x68, (byte) (content.Length - 4), (byte) (content.Length - 4), 0x68}, 0, newContent,
0, 4);
var check = 0;
for (var i = 4; i < newContent.Length - 2; i++)
{
check += newContent[i];
}
@@ -39,7 +40,7 @@ namespace Modbus.Net.Siemens
public override byte[] BytesDecact(byte[] content)
{
byte[] newContent = new byte[content.Length - 9];
var newContent = new byte[content.Length - 9];
Array.Copy(content, 7, newContent, 0, newContent.Length);
return newContent;
}

View File

@@ -89,3 +89,4 @@
}
}
*/

View File

@@ -15,17 +15,18 @@ namespace Modbus.Net.Siemens
private readonly int _port;
private int _connectTryCount;
public SiemensTcpProtocal(byte tdpuSize, ushort tsapSrc, ushort tsapDst, ushort maxCalling, ushort maxCalled, ushort maxPdu) : this(tdpuSize, tsapSrc, tsapDst, maxCalling, maxCalled, maxPdu, ConfigurationManager.IP)
public SiemensTcpProtocal(byte tdpuSize, ushort tsapSrc, ushort tsapDst, ushort maxCalling, ushort maxCalled,
ushort maxPdu) : this(tdpuSize, tsapSrc, tsapDst, maxCalling, maxCalled, maxPdu, ConfigurationManager.IP)
{
}
public SiemensTcpProtocal(byte tdpuSize, ushort tsapSrc, ushort tsapDst, ushort maxCalling, ushort maxCalled,
ushort maxPdu, string ip) : this(tdpuSize, tsapSrc, tsapDst, maxCalling, maxCalled, maxPdu, ip, 0)
{
}
public SiemensTcpProtocal(byte tdpuSize, ushort tsapSrc, ushort tsapDst, ushort maxCalling, ushort maxCalled, ushort maxPdu, string ip, int port) : base (0, 0)
public SiemensTcpProtocal(byte tdpuSize, ushort tsapSrc, ushort tsapDst, ushort maxCalling, ushort maxCalled,
ushort maxPdu, string ip, int port) : base(0, 0)
{
_taspSrc = tsapSrc;
_tsapDst = tsapDst;
@@ -61,7 +62,11 @@ namespace Modbus.Net.Siemens
{
if (ProtocalLinker != null && ProtocalLinker.IsConnected) return await base.SendReceiveAsync(unit, content);
if (_connectTryCount > 10) return null;
return await await ConnectAsync().ContinueWith(answer => answer.Result ? base.SendReceiveAsync(unit, content) : null);
return
await
await
ConnectAsync()
.ContinueWith(answer => answer.Result ? base.SendReceiveAsync(unit, content) : null);
}
private async Task<OutputStruct> ForceSendReceiveAsync(ProtocalUnit unit, InputStruct content)

View File

@@ -4,6 +4,16 @@ namespace Modbus.Net.Siemens
{
public class SiemensTcpProtocalLinker : TcpProtocalLinker
{
public SiemensTcpProtocalLinker(string ip)
: base(ip, int.Parse(ConfigurationManager.SiemensPort))
{
}
public SiemensTcpProtocalLinker(string ip, int port)
: base(ip, port)
{
}
public override bool? CheckRight(byte[] content)
{
if (!base.CheckRight(content).Value) return false;
@@ -27,17 +37,5 @@ namespace Modbus.Net.Siemens
throw new FormatException();
}
}
public SiemensTcpProtocalLinker(string ip)
: base(ip, int.Parse(ConfigurationManager.SiemensPort))
{
}
public SiemensTcpProtocalLinker(string ip, int port)
: base(ip, port)
{
}
}
}

View File

@@ -8,7 +8,7 @@ namespace Modbus.Net.Siemens
Ppi = 0,
Mpi = 1,
Tcp = 2
};
}
public enum SiemensMachineModel
{
@@ -18,7 +18,7 @@ namespace Modbus.Net.Siemens
S7_400 = 3,
S7_1200 = 4,
S7_1500 = 5
};
}
public class SiemensUtility : BaseUtility
@@ -30,69 +30,10 @@ namespace Modbus.Net.Siemens
private readonly ushort _maxCalled;
private readonly ushort _maxPdu;
public override bool GetLittleEndian => Wrapper[typeof (ReadRequestSiemensProtocal)].IsLittleEndian;
public override bool SetLittleEndian => Wrapper[typeof (WriteRequestSiemensProtocal)].IsLittleEndian;
protected string ConnectionStringIp
{
get
{
if (ConnectionString == null) return null;
return ConnectionString.Contains(":") ? ConnectionString.Split(':')[0] : ConnectionString;
}
}
protected int? ConnectionStringPort
{
get
{
if (ConnectionString == null) return null;
if (!ConnectionString.Contains(":")) return null;
var connectionStringSplit = ConnectionString.Split(':');
try
{
return connectionStringSplit.Length < 2 ? (int?)null : int.Parse(connectionStringSplit[1]);
}
catch
{
return null;
}
}
}
private SiemensType _siemensType;
public SiemensType ConnectionType
{
get
{
return _siemensType;
}
set
{
_siemensType = value;
switch (_siemensType)
{
case SiemensType.Ppi:
{
Wrapper = ConnectionString == null ? new SiemensPpiProtocal(BelongAddress, MasterAddress) : new SiemensPpiProtocal(ConnectionString, BelongAddress, MasterAddress);
break;
}
//case SiemensType.Mpi:
// {
// throw new NotImplementedException();
// }
case SiemensType.Tcp:
{
Wrapper = ConnectionString == null ? new SiemensTcpProtocal(_tdpuSize, _taspSrc, _tsapDst, _maxCalling, _maxCalled, _maxPdu) : (ConnectionStringPort == null ? new SiemensTcpProtocal(_tdpuSize, _taspSrc, _tsapDst, _maxCalling, _maxCalled, _maxPdu, ConnectionString) : new SiemensTcpProtocal(_tdpuSize, _taspSrc, _tsapDst, _maxCalling, _maxCalled, _maxPdu, ConnectionStringIp, ConnectionStringPort.Value));
break;
}
}
}
}
public SiemensUtility(SiemensType connectionType, string connectionString, SiemensMachineModel model,
byte belongAddress, byte masterAddress) : base(belongAddress, masterAddress)
byte slaveAddress, byte masterAddress) : base(slaveAddress, masterAddress)
{
ConnectionString = connectionString;
switch (model)
@@ -148,6 +89,70 @@ namespace Modbus.Net.Siemens
AddressTranslator = new AddressTranslatorSiemens();
}
public override bool GetLittleEndian => Wrapper[typeof (ReadRequestSiemensProtocal)].IsLittleEndian;
public override bool SetLittleEndian => Wrapper[typeof (WriteRequestSiemensProtocal)].IsLittleEndian;
protected string ConnectionStringIp
{
get
{
if (ConnectionString == null) return null;
return ConnectionString.Contains(":") ? ConnectionString.Split(':')[0] : ConnectionString;
}
}
protected int? ConnectionStringPort
{
get
{
if (ConnectionString == null) return null;
if (!ConnectionString.Contains(":")) return null;
var connectionStringSplit = ConnectionString.Split(':');
try
{
return connectionStringSplit.Length < 2 ? (int?) null : int.Parse(connectionStringSplit[1]);
}
catch
{
return null;
}
}
}
public SiemensType ConnectionType
{
get { return _siemensType; }
set
{
_siemensType = value;
switch (_siemensType)
{
case SiemensType.Ppi:
{
Wrapper = ConnectionString == null
? new SiemensPpiProtocal(SlaveAddress, MasterAddress)
: new SiemensPpiProtocal(ConnectionString, SlaveAddress, MasterAddress);
break;
}
//case SiemensType.Mpi:
// {
// throw new NotImplementedException();
// }
case SiemensType.Tcp:
{
Wrapper = ConnectionString == null
? new SiemensTcpProtocal(_tdpuSize, _taspSrc, _tsapDst, _maxCalling, _maxCalled, _maxPdu)
: (ConnectionStringPort == null
? new SiemensTcpProtocal(_tdpuSize, _taspSrc, _tsapDst, _maxCalling, _maxCalled, _maxPdu,
ConnectionString)
: new SiemensTcpProtocal(_tdpuSize, _taspSrc, _tsapDst, _maxCalling, _maxCalled, _maxPdu,
ConnectionStringIp, ConnectionStringPort.Value));
break;
}
}
}
}
public override void SetConnectionType(int connectionType)
{
ConnectionType = (SiemensType) connectionType;
@@ -157,7 +162,8 @@ namespace Modbus.Net.Siemens
{
try
{
var readRequestSiemensInputStruct = new ReadRequestSiemensInputStruct(BelongAddress, MasterAddress, 0xd3c7, SiemensTypeCode.Byte, startAddress, (ushort)getByteCount, AddressTranslator);
var readRequestSiemensInputStruct = new ReadRequestSiemensInputStruct(SlaveAddress, MasterAddress,
0xd3c7, SiemensTypeCode.Byte, startAddress, (ushort) getByteCount, AddressTranslator);
var readRequestSiemensOutputStruct =
await
Wrapper.SendReceiveAsync(Wrapper[typeof (ReadRequestSiemensProtocal)],
@@ -174,7 +180,8 @@ namespace Modbus.Net.Siemens
{
try
{
var writeRequestSiemensInputStruct = new WriteRequestSiemensInputStruct(BelongAddress, MasterAddress, 0xd3c8, startAddress, setContents, AddressTranslator);
var writeRequestSiemensInputStruct = new WriteRequestSiemensInputStruct(SlaveAddress, MasterAddress,
0xd3c8, startAddress, setContents, AddressTranslator);
var writeRequestSiemensOutputStruct =
await
Wrapper.SendReceiveAsync(Wrapper[typeof (WriteRequestSiemensProtocal)],
@@ -188,12 +195,12 @@ namespace Modbus.Net.Siemens
}
/*
public override DateTime GetTime(byte belongAddress)
public override DateTime GetTime(byte slaveAddress)
{
throw new NotImplementedException();
}
public override bool SetTime(byte belongAddress, DateTime setTime)
public override bool SetTime(byte slaveAddress, DateTime setTime)
{
throw new NotImplementedException();
}

View File

@@ -22,68 +22,94 @@ namespace Modbus.Net
/// </summary>
public class AddressCombinerContinus : AddressCombiner
{
public AddressCombinerContinus(AddressTranslator addressTranslator)
{
AddressTranslator = addressTranslator;
}
protected AddressTranslator AddressTranslator { get; set; }
public override IEnumerable<CommunicationUnit> Combine(IEnumerable<AddressUnit> addresses)
{
//按从小到大的顺序对地址进行排序
var groupedAddresses = from address in addresses
orderby address.Address + address.SubAddress * (0.125 / AddressTranslator.GetAreaByteLength(address.Area))
orderby
AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress,
AddressTranslator.GetAreaByteLength(address.Area))
group address by address.Area
into grouped
select grouped;
var ans = new List<CommunicationUnit>();
foreach (var groupedAddress in groupedAddresses)
{
string area = groupedAddress.Key;
var area = groupedAddress.Key;
//初始地址
double initNum = -1;
//上一个地址
double preNum = -1;
//上一个地址类型
Type preType = null;
List<AddressUnit> originalAddresses = new List<AddressUnit>();
//记录一个地址组合当中的所有原始地址
var originalAddresses = new List<AddressUnit>();
//对组合内地址从小到大进行排序
var orderedAddresses =
groupedAddress.OrderBy(
address =>
address.Address +
address.SubAddress*(0.125/AddressTranslator.GetAreaByteLength(address.Area)));
AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress,
AddressTranslator.GetAreaByteLength(address.Area)));
foreach (var address in orderedAddresses)
{
//第一次进入时直接压入地址
if (initNum < 0)
{
initNum = address.Address + address.SubAddress * (0.125 / AddressTranslator.GetAreaByteLength(address.Area));
initNum = AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress,
AddressTranslator.GetAreaByteLength(address.Area));
originalAddresses.Add(address);
}
else
{
if (address.Address +
address.SubAddress*(0.125/AddressTranslator.GetAreaByteLength(address.Area)) <
preNum +
BigEndianValueHelper.Instance.ByteLength[preType.FullName]/
AddressTranslator.GetAreaByteLength(address.Area))
//如果当前地址小于已经记录的地址域,表示这个地址的开始已经记录过了
if (AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress,
AddressTranslator.GetAreaByteLength(address.Area)) <
AddressHelper.GetProtocalCoordinateNextPosition(preNum,
preType,
AddressTranslator.GetAreaByteLength(address.Area)))
{
originalAddresses.Add(address);
if (address.Address +
address.SubAddress*(0.125/AddressTranslator.GetAreaByteLength(address.Area)) +
BigEndianValueHelper.Instance.ByteLength[address.DataType.FullName]/
AddressTranslator.GetAreaByteLength(address.Area) <=
preNum +
BigEndianValueHelper.Instance.ByteLength[preType.FullName]/
AddressTranslator.GetAreaByteLength(address.Area))
//如果当前地址的末尾被记录,表示地址被记录的地址域覆盖,这个地址没有记录的必要
if (AddressHelper.GetProtocalCoordinateNextPosition(
AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress,
AddressTranslator.GetAreaByteLength(address.Area)),
address.DataType,
AddressTranslator.GetAreaByteLength(address.Area)) <=
AddressHelper.GetProtocalCoordinateNextPosition(preNum,
preType,
AddressTranslator.GetAreaByteLength(address.Area)))
{
continue;
}
}
else if (address.Address +
address.SubAddress*(0.125/AddressTranslator.GetAreaByteLength(address.Area)) >
preNum +
BigEndianValueHelper.Instance.ByteLength[preType.FullName]/
AddressTranslator.GetAreaByteLength(address.Area))
//如果当前地址大于记录的地址域的开头,则表示地址已经不连续了
else if (AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress,
AddressTranslator.GetAreaByteLength(address.Area)) >
AddressHelper.GetProtocalCoordinateNextPosition(preNum,
preType,
AddressTranslator.GetAreaByteLength(address.Area)))
{
ans.Add(new CommunicationUnit()
//上一个地址域压入返回结果,并把当前记录的结果清空。
ans.Add(new CommunicationUnit
{
Area = area,
Address = (int) Math.Floor(initNum),
GetCount = (int)Math.Ceiling((preNum - (int)Math.Floor(initNum)) * AddressTranslator.GetAreaByteLength(address.Area) + BigEndianValueHelper.Instance.ByteLength[preType.FullName]),
GetCount =
(int)
Math.Ceiling(
AddressHelper.MapProtocalGetCountToAbstractByteCount(
preNum - (int) Math.Floor(initNum),
AddressTranslator.GetAreaByteLength(address.Area),
BigEndianValueHelper.Instance.ByteLength[preType.FullName])),
DataType = typeof (byte),
OriginalAddresses = originalAddresses.ToList(),
OriginalAddresses = originalAddresses.ToList()
});
initNum = address.Address;
originalAddresses.Clear();
@@ -91,30 +117,37 @@ namespace Modbus.Net
}
else
{
//地址连续,压入当前记录的结果
originalAddresses.Add(address);
}
}
preNum = address.Address + address.SubAddress * (0.125 / AddressTranslator.GetAreaByteLength(address.Area));
//把当前地址变为上一个地址
preNum = AddressHelper.GetProtocalCoordinate(address.Address, address.SubAddress,
AddressTranslator.GetAreaByteLength(address.Area));
preType = address.DataType;
}
ans.Add(new CommunicationUnit()
//最后一个地址域压入返回结果
ans.Add(new CommunicationUnit
{
Area = area,
Address = (int) Math.Floor(initNum),
GetCount = (int)Math.Ceiling((preNum - (int)Math.Floor(initNum)) * AddressTranslator.GetAreaByteLength(area) + BigEndianValueHelper.Instance.ByteLength[preType.FullName]),
GetCount =
(int)
Math.Ceiling(
AddressHelper.MapProtocalGetCountToAbstractByteCount(
preNum - (int) Math.Floor(initNum), AddressTranslator.GetAreaByteLength(area),
BigEndianValueHelper.Instance.ByteLength[preType.FullName])),
DataType = typeof (byte),
OriginalAddresses = originalAddresses.ToList()
});
}
return ans;
}
public AddressCombinerContinus(AddressTranslator addressTranslator)
{
AddressTranslator = addressTranslator;
}
}
/// <summary>
/// 单个地址变为一组,每一个地址都进行一次查询
/// </summary>
public class AddressCombinerSingle : AddressCombiner
{
public override IEnumerable<CommunicationUnit> Combine(IEnumerable<AddressUnit> addresses)
@@ -122,37 +155,44 @@ namespace Modbus.Net
return
addresses.Select(
address =>
new CommunicationUnit()
new CommunicationUnit
{
Area = address.Area,
Address = address.Address,
SubAddress = address.SubAddress,
DataType = address.DataType,
GetCount = 1,
OriginalAddresses = new List<AddressUnit>() {address}
OriginalAddresses = new List<AddressUnit> {address}
}).ToList();
}
}
class CommunicationUnitGap
/// <summary>
/// 两个CommunicationUnit之间的间隔
/// </summary>
internal class CommunicationUnitGap
{
public CommunicationUnit EndUnit { get; set; }
public int GapNumber { get; set; }
}
/// <summary>
/// 可以调过多少数量的地址,把两个地址段变为一组通讯
/// </summary>
public class AddressCombinerNumericJump : AddressCombinerContinus
{
private int JumpNumber { get; }
public AddressCombinerNumericJump(int jumpByteCount, AddressTranslator addressTranslator) : base(addressTranslator)
public AddressCombinerNumericJump(int jumpByteCount, AddressTranslator addressTranslator)
: base(addressTranslator)
{
JumpNumber = jumpByteCount;
}
private int JumpNumber { get; }
public override IEnumerable<CommunicationUnit> Combine(IEnumerable<AddressUnit> addresses)
{
var continusAddresses = base.Combine(addresses).ToList();
List<CommunicationUnitGap> addressesGaps = new List<CommunicationUnitGap>();
var addressesGaps = new List<CommunicationUnitGap>();
CommunicationUnit preCommunicationUnit = null;
foreach (var continusAddress in continusAddresses)
{
@@ -163,17 +203,26 @@ namespace Modbus.Net
}
if (continusAddress.Area == preCommunicationUnit.Area)
{
var gap = new CommunicationUnitGap()
//计算间隔
var gap = new CommunicationUnitGap
{
EndUnit = continusAddress,
GapNumber = (int)Math.Ceiling((continusAddress.Address - preCommunicationUnit.Address) * AddressTranslator.GetAreaByteLength(continusAddress.Area) - preCommunicationUnit.GetCount * BigEndianValueHelper.Instance.ByteLength[preCommunicationUnit.DataType.FullName])
GapNumber =
(int)
Math.Ceiling(AddressHelper.MapProtocalCoordinateToAbstractCoordinate(
continusAddress.Address, preCommunicationUnit.Address,
AddressTranslator.GetAreaByteLength(continusAddress.Area)) -
preCommunicationUnit.GetCount*
BigEndianValueHelper.Instance.ByteLength[
preCommunicationUnit.DataType.FullName])
};
addressesGaps.Add(gap);
}
preCommunicationUnit = continusAddress;
}
//减去间隔
var orderedGaps = addressesGaps.OrderBy(p => p.GapNumber);
int jumpNumberInner = JumpNumber;
var jumpNumberInner = JumpNumber;
foreach (var orderedGap in orderedGaps)
{
jumpNumberInner -= orderedGap.GapNumber;
@@ -184,7 +233,8 @@ namespace Modbus.Net
var preAddress = continusAddresses[index];
continusAddresses.RemoveAt(index);
continusAddresses.RemoveAt(index);
var newAddress = new CommunicationUnit()
//变为新的地址段
var newAddress = new CommunicationUnit
{
Area = nowAddress.Area,
Address = preAddress.Address,
@@ -203,21 +253,26 @@ namespace Modbus.Net
}
}
/// <summary>
/// 可以调过多少百分比的地址,把两个地址段变为一个
/// </summary>
public class AddressCombinerPercentageJump : AddressCombinerContinus
{
private double Percentage { get; }
public AddressCombinerPercentageJump(double percentage, AddressTranslator addressTranslator) :base (addressTranslator)
public AddressCombinerPercentageJump(double percentage, AddressTranslator addressTranslator)
: base(addressTranslator)
{
if (percentage < 0) percentage = 0;
Percentage = percentage;
}
private double Percentage { get; }
public override IEnumerable<CommunicationUnit> Combine(IEnumerable<AddressUnit> addresses)
{
var addressUnits = addresses as IList<AddressUnit> ?? addresses.ToList();
double count = addressUnits.Sum(address => BigEndianValueHelper.Instance.ByteLength[address.DataType.FullName]);
return new AddressCombinerNumericJump((int)(count * Percentage / 100.0), AddressTranslator).Combine(addressUnits);
var count = addressUnits.Sum(address => BigEndianValueHelper.Instance.ByteLength[address.DataType.FullName]);
return
new AddressCombinerNumericJump((int) (count*Percentage/100.0), AddressTranslator).Combine(addressUnits);
}
}
}

View File

@@ -1,6 +1,4 @@
using System;
namespace Modbus.Net
namespace Modbus.Net
{
/// <summary>
/// 地址编码器
@@ -8,6 +6,7 @@ namespace Modbus.Net
public abstract class AddressFormater
{
public abstract string FormatAddress(string area, int address);
/// <summary>
/// 编码地址
/// </summary>

View File

@@ -0,0 +1,98 @@
using System;
namespace Modbus.Net
{
/// <summary>
/// 地址辅助类
/// </summary>
public static class AddressHelper
{
/// <summary>
/// 将字节坐标变为协议坐标
/// </summary>
/// <param name="abstractAddress">字节坐标地址</param>
/// <param name="startAddress">起始地址</param>
/// <param name="byteLength">协议坐标单个地址的字节长度</param>
/// <returns></returns>
public static double MapAbstractCoordinateToProtocalCoordinate(double abstractAddress, int startAddress,
double byteLength)
{
return abstractAddress/byteLength + startAddress;
}
/// <summary>
/// 将协议坐标变为字节坐标
/// </summary>
/// <param name="protocalAddress">协议坐标地址</param>
/// <param name="startAddress">起始地址</param>
/// <param name="byteLength">协议坐标单个地址的字节长度</param>
/// <returns></returns>
public static double MapProtocalCoordinateToAbstractCoordinate(double protocalAddress, int startAddress,
double byteLength)
{
return (protocalAddress - startAddress)*byteLength;
}
/// <summary>
/// 将协议获取数变为字节获取数
/// </summary>
/// <param name="protocalGetCount">协议坐标获取个数</param>
/// <param name="areaLength">协议坐标区域与字节之间的防缩倍数</param>
/// <param name="byteLength">协议坐标单个地址的字节长度</param>
/// <returns></returns>
public static double MapProtocalGetCountToAbstractByteCount(double protocalGetCount, double areaLength,
double byteLength)
{
return protocalGetCount*areaLength + byteLength;
}
/// <summary>
/// 获取协议坐标
/// </summary>
/// <param name="address">主地址</param>
/// <param name="subAddress">子地址</param>
/// <param name="byteLength">协议坐标单个地址的字节长度</param>
/// <returns></returns>
public static double GetProtocalCoordinate(int address, int subAddress, double byteLength)
{
return address + subAddress*(0.125/byteLength);
}
/// <summary>
/// 获取字节坐标
/// </summary>
/// <param name="address">主地址</param>
/// <param name="subAddress">子地址</param>
/// <returns></returns>
public static double GetAbstractCoordinate(int address, int subAddress)
{
return address + subAddress*0.125;
}
/// <summary>
/// 获取协议坐标下一个数据的位置
/// </summary>
/// <param name="protocalAddress">协议坐标地址</param>
/// <param name="nextPositionBetweenType">间隔的数据类型</param>
/// <param name="byteLength">协议坐标单个地址的字节长度</param>
/// <returns></returns>
public static double GetProtocalCoordinateNextPosition(double protocalAddress, Type nextPositionBetweenType,
double byteLength)
{
return protocalAddress +
BigEndianValueHelper.Instance.ByteLength[nextPositionBetweenType.FullName]/byteLength;
}
/// <summary>
/// 获取字节坐标下一个数据的位置
/// </summary>
/// <param name="abstractAddress">字节坐标地址</param>
/// <param name="nextPositionBetweenType">间隔的数据类型</param>
/// <returns></returns>
public static double GetAbstractCoordinateNextPosition(double abstractAddress, Type nextPositionBetweenType)
{
return abstractAddress +
BigEndianValueHelper.Instance.ByteLength[nextPositionBetweenType.FullName];
}
}
}

View File

@@ -1,8 +1,10 @@
using System;
using System.Collections.Generic;
namespace Modbus.Net
{
/// <summary>
/// 地址定义类
/// </summary>
public class AddressDef
{
public string AreaString { get; set; }
@@ -11,6 +13,9 @@ namespace Modbus.Net
public int SubAddress { get; set; }
}
/// <summary>
/// 区域数据定义类
/// </summary>
public class AreaOutputDef
{
public int Code { get; set; }
@@ -30,6 +35,11 @@ namespace Modbus.Net
/// <returns>Key为转换后的地址Value为辅助码</returns>
public abstract AddressDef AddressTranslate(string address, bool isRead);
/// <summary>
/// 获取区域中的单个地址占用的字节长度
/// </summary>
/// <param name="area">区域名称</param>
/// <returns>字节长度</returns>
public abstract double GetAreaByteLength(string area);
}
@@ -41,12 +51,12 @@ namespace Modbus.Net
public override AddressDef AddressTranslate(string address, bool isRead)
{
int num1, num2, num3;
string[] split = address.Split(':');
var split = address.Split(':');
if (split.Length == 2)
{
if (int.TryParse(split[0], out num1) && int.TryParse(split[1], out num2))
{
return new AddressDef()
return new AddressDef
{
Area = num1,
Address = num2
@@ -55,13 +65,14 @@ namespace Modbus.Net
}
else if (split.Length == 3)
{
if (int.TryParse(split[0], out num1) && int.TryParse(split[1], out num2) && int.TryParse(split[3], out num3))
if (int.TryParse(split[0], out num1) && int.TryParse(split[1], out num2) &&
int.TryParse(split[3], out num3))
{
return new AddressDef()
return new AddressDef
{
Area = num1,
Address = num2,
SubAddress = num3,
SubAddress = num3
};
}
}

View File

@@ -1,4 +1,9 @@
using System;
/* AsyncHelper 注释
* -- AsyncHelper来自于AsyncEx为了引用方便直接拷贝了代码。Modbus.Net的作者不保留对AsyncHeloper类的版权。
* -- AsyncHelper copied from AsyncEx. The author of "Modbus.Net" <b>donnot</b> obtain the copyright of AsyncHelper(Only).
*/
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
@@ -21,9 +26,9 @@ namespace Modbus.Net
/// <returns>Return value</returns>
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
{
return AsyncHelper._myTaskFactory
.StartNew<Task<TResult>>(func)
.Unwrap<TResult>()
return _myTaskFactory
.StartNew(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
@@ -34,8 +39,8 @@ namespace Modbus.Net
/// <param name="func">Async method</param>
public static void RunSync(Func<Task> func)
{
AsyncHelper._myTaskFactory
.StartNew<Task>(func)
_myTaskFactory
.StartNew(func)
.Unwrap()
.GetAwaiter()
.GetResult();
@@ -65,8 +70,8 @@ namespace Modbus.Net
/// </summary>
public class AsyncLock
{
private readonly AsyncSemaphore _semaphore;
private readonly Task<Releaser> _releaser;
private readonly AsyncSemaphore _semaphore;
public AsyncLock()
{
@@ -113,7 +118,7 @@ namespace Modbus.Net
/// </summary>
public class AsyncSemaphore
{
private readonly static Task _completed = Task.FromResult(true);
private static readonly Task _completed = Task.FromResult(true);
private readonly Queue<TaskCompletionSource<bool>> _waiters = new Queue<TaskCompletionSource<bool>>();
private int _currentCount;
@@ -135,14 +140,11 @@ namespace Modbus.Net
_currentCount--;
return _completed;
}
else
{
var waiter = new TaskCompletionSource<bool>();
_waiters.Enqueue(waiter);
return waiter.Task;
}
}
}
public void Release()
{

View File

@@ -1,51 +1,61 @@
using System;
using System.Threading.Tasks;
using System.Threading.Tasks;
namespace Modbus.Net
{
/// <summary>
/// 基础的协议连接类
/// </summary>
public abstract class BaseConnector
{
/// <summary>
/// 标识Connector的连接关键字
/// </summary>
public abstract string ConnectionToken { get; }
/// <summary>
/// 是否处于连接状态
/// </summary>
public abstract bool IsConnected { get; }
/// <summary>
/// 连接PLC
/// </summary>
/// <returns>是否连接成功</returns>
public abstract bool Connect();
/// <summary>
/// 连接PLC异步
/// </summary>
/// <returns>是否连接成功</returns>
public abstract Task<bool> ConnectAsync();
/// <summary>
/// 断开PLC
/// </summary>
/// <returns>是否断开成功</returns>
public abstract bool Disconnect();
/// <summary>
/// 无返回发送数据
/// </summary>
/// <param name="message">需要发送的数据</param>
/// <returns>是否发送成功</returns>
public abstract bool SendMsgWithoutReturn(byte[] message);
/// <summary>
/// 无返回发送数据
/// </summary>
/// <param name="message">需要发送的数据</param>
/// <returns>是否发送成功</returns>
public abstract Task<bool> SendMsgWithoutReturnAsync(byte[] message);
/// <summary>
/// 带返回发送数据
/// </summary>
/// <param name="message">需要发送的数据</param>
/// <returns>是否发送成功</returns>
public abstract byte[] SendMsg(byte[] message);
/// <summary>
/// 带返回发送数据
/// </summary>

View File

@@ -14,6 +14,7 @@ namespace Modbus.Net
/// 地址
/// </summary>
Address,
/// <summary>
/// 通讯标识
/// </summary>
@@ -29,6 +30,7 @@ namespace Modbus.Net
/// 地址
/// </summary>
Address,
/// <summary>
/// 通讯标识
/// </summary>
@@ -37,87 +39,7 @@ namespace Modbus.Net
public abstract class BaseMachine : IMachineProperty
{
private int ErrorCount { get; set; } = 0;
private int _maxErrorCount = 3;
/// <summary>
/// 设备的Id
/// </summary>
public string Id { get; set; }
/// <summary>
/// 设备所在工程的名称
/// </summary>
public string ProjectName { get; set; }
/// <summary>
/// 设备的名称
/// </summary>
public string MachineName { get; set; }
/// <summary>
/// 是否处于连接状态
/// </summary>
public bool IsConnected => BaseUtility.IsConnected;
/// <summary>
/// 标识设备的连接关键字
/// </summary>
public string ConnectionToken => BaseUtility.ConnectionToken;
/// <summary>
/// 地址编码器
/// </summary>
public AddressFormater AddressFormater { get; set; }
/// <summary>
/// 获取地址组合器
/// </summary>
public AddressCombiner AddressCombiner { get; set; }
/// <summary>
/// 写入地址组合器
/// </summary>
public AddressCombiner AddressCombinerSet { get; set; }
/// <summary>
/// 地址转换器
/// </summary>
public AddressTranslator AddressTranslator
{
get { return BaseUtility.AddressTranslator; }
set { BaseUtility.AddressTranslator = value; }
}
/// <summary>
/// 与设备实际通讯的连续地址
/// </summary>
protected IEnumerable<CommunicationUnit> CommunicateAddresses => GetAddresses != null ? AddressCombiner.Combine(GetAddresses) : null;
/// <summary>
/// 描述需要与设备通讯的地址
/// </summary>
public IEnumerable<AddressUnit> GetAddresses { get; set; }
/// <summary>
/// 是否保持连接
/// </summary>
public bool KeepConnect { get; set; }
/// <summary>
/// 从站号
/// </summary>
public byte SlaveAddress { get; set; } = 2;
/// <summary>
/// 主站号
/// </summary>
public byte MasterAddress { get; set; } = 0;
/// <summary>
/// 设备的连接器
/// </summary>
protected BaseUtility BaseUtility { get; set; }
private readonly int _maxErrorCount = 3;
/// <summary>
/// 构造器
@@ -146,12 +68,95 @@ namespace Modbus.Net
/// <param name="keepConnect">是否保持连接</param>
/// <param name="slaveAddress">从站地址</param>
/// <param name="masterAddress">主站地址</param>
protected BaseMachine(IEnumerable<AddressUnit> getAddresses, bool keepConnect, byte slaveAddress, byte masterAddress) : this(getAddresses, keepConnect)
protected BaseMachine(IEnumerable<AddressUnit> getAddresses, bool keepConnect, byte slaveAddress,
byte masterAddress) : this(getAddresses, keepConnect)
{
SlaveAddress = slaveAddress;
MasterAddress = masterAddress;
}
private int ErrorCount { get; set; }
/// <summary>
/// 是否处于连接状态
/// </summary>
public bool IsConnected => BaseUtility.IsConnected;
/// <summary>
/// 地址编码器
/// </summary>
public AddressFormater AddressFormater { get; set; }
/// <summary>
/// 获取地址组合器
/// </summary>
public AddressCombiner AddressCombiner { get; set; }
/// <summary>
/// 写入地址组合器
/// </summary>
public AddressCombiner AddressCombinerSet { get; set; }
/// <summary>
/// 地址转换器
/// </summary>
public AddressTranslator AddressTranslator
{
get { return BaseUtility.AddressTranslator; }
set { BaseUtility.AddressTranslator = value; }
}
/// <summary>
/// 与设备实际通讯的连续地址
/// </summary>
protected IEnumerable<CommunicationUnit> CommunicateAddresses
=> GetAddresses != null ? AddressCombiner.Combine(GetAddresses) : null;
/// <summary>
/// 描述需要与设备通讯的地址
/// </summary>
public IEnumerable<AddressUnit> GetAddresses { get; set; }
/// <summary>
/// 是否保持连接
/// </summary>
public bool KeepConnect { get; set; }
/// <summary>
/// 从站号
/// </summary>
public byte SlaveAddress { get; set; } = 2;
/// <summary>
/// 主站号
/// </summary>
public byte MasterAddress { get; set; }
/// <summary>
/// 设备的连接器
/// </summary>
protected BaseUtility BaseUtility { get; set; }
/// <summary>
/// 设备的Id
/// </summary>
public string Id { get; set; }
/// <summary>
/// 设备所在工程的名称
/// </summary>
public string ProjectName { get; set; }
/// <summary>
/// 设备的名称
/// </summary>
public string MachineName { get; set; }
/// <summary>
/// 标识设备的连接关键字
/// </summary>
public string ConnectionToken => BaseUtility.ConnectionToken;
/// <summary>
/// 读取数据
/// </summary>
@@ -162,7 +167,6 @@ namespace Modbus.Net
}
/// <summary>
/// 读取数据
/// </summary>
@@ -171,7 +175,7 @@ namespace Modbus.Net
{
try
{
Dictionary<string, ReturnUnit> ans = new Dictionary<string, ReturnUnit>();
var ans = new Dictionary<string, ReturnUnit>();
//检测并连接设备
if (!BaseUtility.IsConnected)
{
@@ -186,7 +190,8 @@ namespace Modbus.Net
var datas =
await
BaseUtility.GetDatasAsync(
AddressFormater.FormatAddress(communicateAddress.Area, communicateAddress.Address, communicateAddress.SubAddress),
AddressFormater.FormatAddress(communicateAddress.Area, communicateAddress.Address,
communicateAddress.SubAddress),
(int)
Math.Ceiling(communicateAddress.GetCount*
BigEndianValueHelper.Instance.ByteLength[
@@ -204,12 +209,17 @@ namespace Modbus.Net
foreach (var address in communicateAddress.OriginalAddresses)
{
var localPos = (address.Address - communicateAddress.Address)*
AddressTranslator.GetAreaByteLength(communicateAddress.Area) +
address.SubAddress/8.0;
//字节坐标的位置
var localPos = AddressHelper.MapProtocalCoordinateToAbstractCoordinate(address.Address,
communicateAddress.Address,
AddressTranslator.GetAreaByteLength(communicateAddress.Area)) +
address.SubAddress*0.125;
//字节坐标的主地址位置
var localMainPos = (int) localPos;
//字节坐标的子地址位置
var localSubPos = (int) ((localPos - localMainPos)*8);
//根据类型选择返回结果的键是通讯标识还是地址
string key;
switch (getDataType)
{
@@ -230,6 +240,7 @@ namespace Modbus.Net
}
}
//如果没有数据返回空
if (datas.Length == 0)
{
ans.Add(key, new ReturnUnit
@@ -308,7 +319,7 @@ namespace Modbus.Net
}
//如果设备无法连接,终止
if (!BaseUtility.IsConnected) return false;
List<AddressUnit> addresses = new List<AddressUnit>();
var addresses = new List<AddressUnit>();
//遍历每个要设置的值
foreach (var value in values)
{
@@ -333,14 +344,17 @@ namespace Modbus.Net
break;
}
}
//地址为空报错
if (address == null)
{
Console.WriteLine($"Machine {ConnectionToken} Address {value.Key} doesn't exist.");
continue;
}
//不能写报错
if (!address.CanWrite)
{
Console.WriteLine($"Machine {ConnectionToken} Address {value.Key} cannot write.");
continue;
}
addresses.Add(address);
}
@@ -376,27 +390,35 @@ namespace Modbus.Net
foreach (var addressUnit in communicateAddress.OriginalAddresses)
{
var byteCount = (addressUnit.Address - communicateAddress.Address +
//字节坐标地址
var byteCount =
AddressHelper.MapProtocalGetCountToAbstractByteCount(
addressUnit.Address - communicateAddress.Address +
addressUnit.SubAddress*0.125/
AddressTranslator.GetAreaByteLength(communicateAddress.Area)) *
AddressTranslator.GetAreaByteLength(communicateAddress.Area);
AddressTranslator.GetAreaByteLength(communicateAddress.Area),
AddressTranslator.GetAreaByteLength(communicateAddress.Area), 0);
//字节坐标主地址
var mainByteCount = (int) byteCount;
//字节坐标自地址
var localByteCount = (int) ((byteCount - (int) byteCount)*8);
//协议坐标地址
var localPos = byteCount/AddressTranslator.GetAreaByteLength(communicateAddress.Area);
//编码当前地址
//协议坐标子地址
var subPos =
(int)
((localPos - (int) localPos)/
(0.125/AddressTranslator.GetAreaByteLength(communicateAddress.Area)));
//协议主地址字符串
var address = AddressFormater.FormatAddress(communicateAddress.Area,
communicateAddress.Address + (int) localPos, subPos);
//协议完整地址字符串
var address2 = subPos != 0
? null
: AddressFormater.FormatAddress(communicateAddress.Area,
communicateAddress.Address + (int) localPos);
//获取写入类型
Type dataType = addressUnit.DataType;
var dataType = addressUnit.DataType;
switch (setDataType)
{
case MachineSetDataType.Address:
@@ -492,22 +514,27 @@ namespace Modbus.Net
/// 区域
/// </summary>
public string Area { get; set; }
/// <summary>
/// 地址
/// </summary>
public int Address { get; set; }
/// <summary>
/// 子地址
/// </summary>
public int SubAddress { get; set; } = 0;
/// <summary>
/// 获取个数
/// </summary>
public int GetCount { get; set; }
/// <summary>
/// 数据类型
/// </summary>
public Type DataType { get; set; }
/// <summary>
/// 原始的地址
/// </summary>
@@ -519,7 +546,6 @@ namespace Modbus.Net
/// </summary>
public class UnitExtend
{
}
/// <summary>
@@ -531,6 +557,7 @@ namespace Modbus.Net
/// 返回的数据
/// </summary>
public double? PlcValue { get; set; }
/// <summary>
/// 数据的扩展
/// </summary>
@@ -543,52 +570,66 @@ namespace Modbus.Net
/// 数据单元Id
/// </summary>
public string Id { get; set; }
/// <summary>
/// 数据所属的区域
/// </summary>
public string Area { get; set; }
/// <summary>
/// 地址
/// </summary>
public int Address { get; set; }
/// <summary>
/// bit位地址
/// </summary>
public int SubAddress { get; set; } = 0;
/// <summary>
/// 数据类型
/// </summary>
public Type DataType { get; set; }
/// <summary>
/// 放缩比例
/// </summary>
public double Zoom { get; set; } = 1;
/// <summary>
/// 小数位数
/// </summary>
public int DecimalPos { get; set; }
/// <summary>
/// 通讯标识名称
/// </summary>
public string CommunicationTag { get; set; }
/// <summary>
/// 名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 单位
/// </summary>
public string Unit { get; set; }
/// <summary>
/// 是否可写,默认可写
/// </summary>
public bool CanWrite { get; set; } = true;
/// <summary>
/// 扩展
/// </summary>
public UnitExtend UnitExtend { get; set; }
}
/// <summary>
/// AddressUnit大小比较
/// </summary>
public struct AddressUnitEqualityComparer : IEqualityComparer<AddressUnit>
{
public bool Equals(AddressUnit x, AddressUnit y)
@@ -611,14 +652,17 @@ namespace Modbus.Net
/// Id
/// </summary>
string Id { get; set; }
/// <summary>
/// 工程名
/// </summary>
string ProjectName { get; set; }
/// <summary>
/// 设备名
/// </summary>
string MachineName { get; set; }
/// <summary>
/// 标识设备的连接关键字
/// </summary>

View File

@@ -1,24 +1,26 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Modbus.Net
{
/// <summary>
/// BaseMachine扩展类
/// </summary>
public static class BaseMachineExtend
{
/// <summary>
/// 将获取的数据转换成可以向设备写入的数据格式
/// 注意转换无法变更读写类型
/// </summary>
/// <param name="getValues">获取的数据</param>
/// <returns>写入的数据</returns>
/// <returns>应该写入的数据</returns>
public static Dictionary<string, double> MapGetValuesToSetValues(this Dictionary<string, ReturnUnit> getValues)
{
if (getValues == null) return null;
return (from getValue in getValues
where getValue.Value.PlcValue != null
select new KeyValuePair<string, double>(getValue.Key, getValue.Value.PlcValue.Value)).ToDictionary(p => p.Key, p => p.Value);
select new KeyValuePair<string, double>(getValue.Key, getValue.Value.PlcValue.Value)).ToDictionary(
p => p.Key, p => p.Value);
}
}
}

View File

@@ -10,7 +10,17 @@ namespace Modbus.Net
/// </summary>
public abstract class BaseProtocal
{
public byte BelongAddress { get; set; }
/// <summary>
/// 构造器
/// </summary>
protected BaseProtocal(byte slaveAddress, byte masterAddress)
{
Protocals = new Dictionary<string, ProtocalUnit>();
SlaveAddress = slaveAddress;
MasterAddress = masterAddress;
}
public byte SlaveAddress { get; set; }
public byte MasterAddress { get; set; }
/// <summary>
@@ -18,16 +28,6 @@ namespace Modbus.Net
/// </summary>
public ProtocalLinker ProtocalLinker { get; protected set; }
/// <summary>
/// 构造器
/// </summary>
protected BaseProtocal(byte belongAddress, byte masterAddress)
{
Protocals = new Dictionary<string, ProtocalUnit>();
BelongAddress = belongAddress;
MasterAddress = masterAddress;
}
/// <summary>
/// 协议索引器,这是一个懒加载协议,当字典中不存在协议时自动加载协议,否则调用已经加载的协议
/// </summary>
@@ -37,7 +37,7 @@ namespace Modbus.Net
{
get
{
string protocalName = type.FullName;
var protocalName = type.FullName;
if (Protocals.ContainsKey(protocalName))
{
return Protocals[protocalName];
@@ -93,11 +93,8 @@ namespace Modbus.Net
{
return await ProtocalLinker.SendReceiveAsync(ProtocalUnit.TranslateContent(isLittleEndian, content));
}
else
{
return null;
}
}
/// <summary>
/// 发送协议,通过传入需要使用的协议内容和输入结构
@@ -118,7 +115,7 @@ namespace Modbus.Net
/// <returns>输出信息的结构化描述</returns>
public virtual async Task<OutputStruct> SendReceiveAsync(ProtocalUnit unit, InputStruct content)
{
int t = 0;
var t = 0;
var formatContent = unit.Format(content);
if (formatContent != null)
{

View File

@@ -11,15 +11,27 @@ namespace Modbus.Net
/// 协议收发主体
/// </summary>
protected BaseProtocal Wrapper;
/// <summary>
/// 构造器
/// </summary>
protected BaseUtility(byte slaveAddress, byte masterAddress)
{
SlaveAddress = slaveAddress;
MasterAddress = masterAddress;
AddressTranslator = new AddressTranslatorBase();
}
protected string ConnectionString { get; set; }
public byte BelongAddress { get; set; }
public byte SlaveAddress { get; set; }
public byte MasterAddress { get; set; }
/// <summary>
/// 获取协议是否遵循小端格式
/// </summary>
public abstract bool GetLittleEndian { get; }
/// <summary>
/// 设置协议是否遵循小端格式
/// </summary>
@@ -40,16 +52,6 @@ namespace Modbus.Net
/// </summary>
public AddressTranslator AddressTranslator { get; set; }
/// <summary>
/// 构造器
/// </summary>
protected BaseUtility(byte belongAddress, byte masterAddress)
{
BelongAddress = belongAddress;
MasterAddress = masterAddress;
AddressTranslator = new AddressTranslatorBase();
}
/// <summary>
/// 设置连接类型
/// </summary>
@@ -78,8 +80,6 @@ namespace Modbus.Net
/// <summary>
/// 获取数据
/// </summary>
/// <param name="belongAddress">从站地址</param>
/// <param name="masterAddress">主站地址</param>
/// <param name="startAddress">开始地址</param>
/// <param name="getTypeAndCount">获取类型和个数</param>
/// <returns>接收到的对应的类型和数据</returns>
@@ -92,8 +92,6 @@ namespace Modbus.Net
/// <summary>
/// 获取数据
/// </summary>
/// <param name="belongAddress">从站地址</param>
/// <param name="masterAddress">主站地址</param>
/// <param name="startAddress">开始地址</param>
/// <param name="getTypeAndCount">获取类型和个数</param>
/// <returns>接收到的对应的类型和数据</returns>
@@ -102,8 +100,8 @@ namespace Modbus.Net
{
try
{
string typeName = getTypeAndCount.Key.FullName;
double bCount = BigEndianValueHelper.Instance.ByteLength[typeName];
var typeName = getTypeAndCount.Key.FullName;
var bCount = BigEndianValueHelper.Instance.ByteLength[typeName];
var getReturnValue = await GetDatasAsync(startAddress,
(int) Math.Ceiling(bCount*getTypeAndCount.Value));
var getBytes = getReturnValue;
@@ -121,8 +119,6 @@ namespace Modbus.Net
/// 获取数据
/// </summary>
/// <typeparam name="T">需要接收的类型</typeparam>
/// <param name="belongAddress">从站地址</param>
/// <param name="masterAddress">主站地址</param>
/// <param name="startAddress">开始地址</param>
/// <param name="getByteCount">获取字节数个数</param>
/// <returns>接收到的对应的类型和数据</returns>
@@ -136,8 +132,6 @@ namespace Modbus.Net
/// 获取数据
/// </summary>
/// <typeparam name="T">需要接收的类型</typeparam>
/// <param name="belongAddress">从站地址</param>
/// <param name="masterAddress">主站地址</param>
/// <param name="startAddress">开始地址</param>
/// <param name="getByteCount">获取字节数个数</param>
/// <returns>接收到的对应的类型和数据</returns>
@@ -181,13 +175,13 @@ namespace Modbus.Net
{
var translateTypeAndCount = getTypeAndCountList as IList<KeyValuePair<Type, int>> ??
getTypeAndCountList.ToList();
int bAllCount = (
var bAllCount = (
from getTypeAndCount in translateTypeAndCount
let typeName = getTypeAndCount.Key.FullName
let bCount = BigEndianValueHelper.Instance.ByteLength[typeName]
select (int) Math.Ceiling(bCount*getTypeAndCount.Value)).Sum();
var getReturnValue = await GetDatasAsync(startAddress, bAllCount);
byte[] getBytes = getReturnValue;
var getBytes = getReturnValue;
return GetLittleEndian
? ValueHelper.Instance.ByteArrayToObjectArray(getBytes, translateTypeAndCount)
: BigEndianValueHelper.Instance.ByteArrayToObjectArray(getBytes, translateTypeAndCount);
@@ -258,6 +252,5 @@ namespace Modbus.Net
{
return Wrapper.Disconnect();
}
}
}

View File

@@ -1,16 +1,21 @@
using System;
/*
* Crc16来自于多个网络上的代码Modbus.Net的作者不保留对Crc16类的版权。
* Crc16 class comes from mutiple websites, the author of "Modbus.Net" <b>donnot</b> obtain the copyright of Crc16(only).
*/
using System;
namespace Modbus.Net
{
public class Crc16
{
private static Crc16 _crc16;
/// <summary>
/// CRC验证表
/// </summary>
public byte[] crc_table = new byte[512];
private static Crc16 _crc16 = null;
public static Crc16 GetInstance()
{
if (_crc16 == null)
@@ -31,7 +36,7 @@ namespace Modbus.Net
public short GetCRC(byte[] message, ref byte[] Rcvbuf)
{
int IX, IY, CRC;
int Len = message.Length;
var Len = message.Length;
CRC = 0xFFFF;
//set all 1
if (Len <= 0)
@@ -41,7 +46,7 @@ namespace Modbus.Net
Len--;
for (IX = 0; IX <= Len; IX++)
{
CRC=CRC^(message[IX]);
CRC = CRC ^ message[IX];
for (IY = 0; IY <= 7; IY++)
{
if ((CRC & 1) != 0)
@@ -70,19 +75,16 @@ namespace Modbus.Net
/// <returns>十六进制数</returns>
public bool CrcEfficacy(byte[] byteframe)
{
byte[] recvbuff = new byte[2];
byte[] byteArr = new byte[byteframe.Length - 2];
var recvbuff = new byte[2];
var byteArr = new byte[byteframe.Length - 2];
Array.Copy(byteframe, 0, byteArr, 0, byteArr.Length);
GetCRC(byteArr, ref recvbuff);
if (recvbuff[0] == byteframe[byteframe.Length - 2] && recvbuff[1] == byteframe[byteframe.Length - 1])
{
return true;
}
else
{
return false;
}
}
#endregion
@@ -97,18 +99,18 @@ namespace Modbus.Net
var index = message.IndexOf(Environment.NewLine, StringComparison.InvariantCulture);
var writeUncheck = message.Substring(1, index - 2);
var checkString = message.Substring(index - 2, 2);
char[] hexArray = new char[writeUncheck.Length];
var hexArray = new char[writeUncheck.Length];
hexArray = writeUncheck.ToCharArray();
int decNum = 0, decNumMSB = 0, decNumLSB = 0;
int decByte, decByteTotal = 0;
bool msb = true;
var msb = true;
for (int t = 0; t <= hexArray.GetUpperBound(0); t++)
for (var t = 0; t <= hexArray.GetUpperBound(0); t++)
{
if ((hexArray[t] >= 48) && (hexArray[t] <= 57))
decNum = (hexArray[t] - 48);
decNum = hexArray[t] - 48;
else if ((hexArray[t] >= 65) & (hexArray[t] <= 70))
decNum = 10 + (hexArray[t] - 65);
@@ -130,7 +132,7 @@ namespace Modbus.Net
}
}
decByteTotal = (255 - decByteTotal) + 1;
decByteTotal = 255 - decByteTotal + 1;
decByteTotal = decByteTotal & 255;
int a, b = 0;
@@ -169,7 +171,7 @@ namespace Modbus.Net
break;
}
}
hexTotal = String.Concat(hexByte, hexTotal);
hexTotal = string.Concat(hexByte, hexTotal);
}
return hexTotal == checkString;
}
@@ -177,12 +179,12 @@ namespace Modbus.Net
public string GetLRC(byte[] code)
{
byte sum = 0;
foreach (byte b in code)
foreach (var b in code)
{
sum += b;
}
sum = (byte) (~sum + 1); //取反+1
string lrc = sum.ToString("X2");
var lrc = sum.ToString("X2");
return lrc;
}
}

View File

@@ -1,4 +1,5 @@
using System;
using System.Globalization;
using System.IO.Ports;
using System.Text;
using System.Threading;
@@ -6,12 +7,45 @@ using System.Threading.Tasks;
namespace Modbus.Net
{
/// <summary>
/// 串口通讯类
/// </summary>
public class ComConnector : BaseConnector, IDisposable
{
public override string ConnectionToken => _com;
public delegate byte[] GetDate(byte[] bts);
private readonly int _baudRate;
//private GetDate mygetDate;
private readonly string _com;
private readonly int _dataBits;
private readonly Parity _parity;
private readonly StopBits _stopBits;
private readonly int _timeoutTime;
private SerialPort _serialPort1;
private bool m_disposed = true;
public ComConnector(string com, int baudRate, Parity parity, StopBits stopBits, int dataBits, int timeoutTime)
{
_com = com;
_timeoutTime = timeoutTime;
_baudRate = baudRate;
_parity = parity;
_stopBits = stopBits;
_dataBits = dataBits;
//端口号
//读超时
//比特率
//奇偶校验
//停止位
//数据位
}
public override string ConnectionToken => _com;
private SerialPort SerialPort1
{
get
@@ -25,38 +59,222 @@ namespace Modbus.Net
Parity = _parity,
StopBits = _stopBits,
DataBits = _dataBits,
ReadTimeout = _timeoutTime,
ReadTimeout = _timeoutTime
};
}
return _serialPort1;
}
}
public delegate byte[] GetDate(byte[] bts);
//private GetDate mygetDate;
private readonly string _com;
private readonly int _timeoutTime;
private readonly int _baudRate;
private readonly Parity _parity;
private readonly StopBits _stopBits;
private readonly int _dataBits;
public ComConnector(string com, int baudRate, Parity parity, StopBits stopBits, int dataBits, int timeoutTime)
/// <summary>
/// 实现IDisposable接口
/// </summary>
public void Dispose()
{
_com = com;
_timeoutTime = timeoutTime;
_baudRate = baudRate;
_parity = parity;
_stopBits = stopBits;
_dataBits = dataBits;
Dispose(true);
//.NET Framework 类库
// GC..::.SuppressFinalize 方法
//请求系统不要调用指定对象的终结器。
GC.SuppressFinalize(this);
}
//端口号
//比特率
//奇偶校验
//停止位
//读超时即在1000内未读到数据就引起超时异常
/// <summary>
/// 串口读(非阻塞方式读串口,直到串口缓冲区中没有数据
/// </summary>
/// <param name="readBuf">串口数据缓冲 </param>
/// <param name="bufRoom">串口数据缓冲空间大小 </param>
/// <param name="HowTime">设置串口读放弃时间 </param>
/// <param name="ByteTime">字节间隔最大时间 </param>
/// <returns>串口实际读入数据个数 </returns>
public int ReadComm(out byte[] readBuf, int bufRoom, int HowTime, int ByteTime)
{
//throw new System.NotImplementedException();
readBuf = new byte[1023];
Array.Clear(readBuf, 0, readBuf.Length);
int nReadLen, nBytelen;
if (SerialPort1.IsOpen == false)
return -1;
nBytelen = 0;
SerialPort1.ReadTimeout = HowTime;
try
{
while (SerialPort1.BytesToRead > 0)
{
readBuf[nBytelen] = (byte) SerialPort1.ReadByte();
var bTmp = new byte[bufRoom];
Array.Clear(bTmp, 0, bTmp.Length);
nReadLen = ReadBlock(bTmp, bufRoom, ByteTime);
if (nReadLen > 0)
{
Array.Copy(bTmp, 0, readBuf, nBytelen + 1, nReadLen);
nBytelen += 1 + nReadLen;
}
else if (nReadLen == 0)
nBytelen += 1;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return nBytelen;
}
/// <summary>
/// 串口同步读(阻塞方式读串口,直到串口缓冲区中没有数据,靠字符间间隔超时确定没有数据)
/// </summary>
/// <param name="ReadBuf">串口数据缓冲 </param>
/// <param name="ReadRoom">串口数据缓冲空间大小 </param>
/// <param name="ByteTime">字节间隔最大时间 </param>
/// <returns>从串口实际读入的字节个数 </returns>
public int ReadBlock(byte[] ReadBuf, int ReadRoom, int ByteTime)
{
sbyte nBytelen;
//long nByteRead;
if (SerialPort1.IsOpen == false)
return 0;
nBytelen = 0;
SerialPort1.ReadTimeout = ByteTime;
while (nBytelen < ReadRoom - 1 && SerialPort1.BytesToRead > 0)
{
try
{
ReadBuf[nBytelen] = (byte) SerialPort1.ReadByte();
nBytelen++; // add one
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
ReadBuf[nBytelen] = 0x00;
return nBytelen;
}
/// <summary>
/// 字符数组转字符串16进制
/// </summary>
/// <param name="InBytes"> 二进制字节 </param>
/// <returns>类似"01 02 0F" </returns>
public static string ByteToString(byte[] InBytes)
{
var StringOut = "";
foreach (var InByte in InBytes)
{
StringOut = StringOut + string.Format("{0:X2}", InByte) + " ";
}
return StringOut.Trim();
}
/// <summary>
/// strhex 转字节数组
/// </summary>
/// <param name="InString">类似"01 02 0F" 用空格分开的 </param>
/// <returns> </returns>
public static byte[] StringToByte(string InString)
{
string[] ByteStrings;
ByteStrings = InString.Split(" ".ToCharArray());
byte[] ByteOut;
ByteOut = new byte[ByteStrings.Length];
for (var i = 0; i <= ByteStrings.Length - 1; i++)
{
ByteOut[i] = byte.Parse(ByteStrings[i], NumberStyles.HexNumber);
}
return ByteOut;
}
/// <summary>
/// strhex 转字节数组
/// </summary>
/// <param name="InString">类似"01 02 0F" 中间无空格 </param>
/// <returns> </returns>
public static byte[] StringToByte_2(string InString)
{
byte[] ByteOut;
InString = InString.Replace(" ", "");
try
{
var ByteStrings = new string[InString.Length/2];
var j = 0;
for (var i = 0; i < ByteStrings.Length; i++)
{
ByteStrings[i] = InString.Substring(j, 2);
j += 2;
}
ByteOut = new byte[ByteStrings.Length];
for (var i = 0; i <= ByteStrings.Length - 1; i++)
{
ByteOut[i] = byte.Parse(ByteStrings[i], NumberStyles.HexNumber);
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return ByteOut;
}
/// <summary>
/// 字符串 转16进制字符串
/// </summary>
/// <param name="InString">unico </param>
/// <returns>类似“01 0f” </returns>
public static string Str_To_0X(string InString)
{
return ByteToString(Encoding.Default.GetBytes(InString));
}
/// <summary>
/// 虚方法,可供子类重写
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
if (!m_disposed)
{
if (disposing)
{
// Release managed resources
}
// Release unmanaged resources
if (_serialPort1 != null)
{
try
{
_serialPort1.Close();
}
catch (Exception)
{
//ignore
}
_serialPort1.Dispose();
_serialPort1 = null;
}
m_disposed = true;
}
}
/// <summary>
/// 析构函数
/// 当客户端没有显示调用Dispose()时由GC完成资源回收功能
/// </summary>
~ComConnector()
{
Dispose(false);
}
#region
@@ -111,10 +329,9 @@ namespace Modbus.Net
public void SendMsg(string senStr)
{
byte[] myByte = StringToByte_2(senStr);
var myByte = StringToByte_2(senStr);
SendMsg(myByte);
}
public override Task<bool> SendMsgWithoutReturnAsync(byte[] message)
@@ -164,18 +381,16 @@ namespace Modbus.Net
{
return false;
}
}
public string ReadMsgStr()
{
string rd = "";
var rd = "";
byte[] data = ReadMsg();
var data = ReadMsg();
rd = ByteToString(data);
return rd;
}
public byte[] ReadMsg()
@@ -189,8 +404,8 @@ namespace Modbus.Net
byte[] data;
Thread.Sleep(100);
int i = ReadComm(out data, 10, 5000, 1000);
byte[] returndata = new byte[i];
var i = ReadComm(out data, 10, 5000, 1000);
var returndata = new byte[i];
Array.Copy(data, 0, returndata, 0, i);
return returndata;
}
@@ -202,221 +417,5 @@ namespace Modbus.Net
}
#endregion
/// <summary>
/// 串口读(非阻塞方式读串口,直到串口缓冲区中没有数据
/// </summary>
/// <param name="readBuf">串口数据缓冲 </param>
/// <param name="bufRoom">串口数据缓冲空间大小 </param>
/// <param name="HowTime">设置串口读放弃时间 </param>
/// <param name="ByteTime">字节间隔最大时间 </param>
/// <returns>串口实际读入数据个数 </returns>
public int ReadComm(out Byte[] readBuf, int bufRoom, int HowTime, int ByteTime)
{
//throw new System.NotImplementedException();
readBuf = new Byte[1023];
Array.Clear(readBuf, 0, readBuf.Length);
int nReadLen, nBytelen;
if (SerialPort1.IsOpen == false)
return -1;
nBytelen = 0;
SerialPort1.ReadTimeout = HowTime;
try
{
while (SerialPort1.BytesToRead > 0)
{
readBuf[nBytelen] = (byte) SerialPort1.ReadByte();
byte[] bTmp = new byte[bufRoom];
Array.Clear(bTmp, 0, bTmp.Length);
nReadLen = ReadBlock(bTmp, bufRoom, ByteTime);
if (nReadLen > 0)
{
Array.Copy(bTmp, 0, readBuf, nBytelen + 1, nReadLen);
nBytelen += 1 + nReadLen;
}
else if (nReadLen == 0)
nBytelen += 1;
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return nBytelen;
}
/// <summary>
/// 串口同步读(阻塞方式读串口,直到串口缓冲区中没有数据,靠字符间间隔超时确定没有数据)
/// </summary>
/// <param name="ReadBuf">串口数据缓冲 </param>
/// <param name="ReadRoom">串口数据缓冲空间大小 </param>
/// <param name="ByteTime">字节间隔最大时间 </param>
/// <returns>从串口实际读入的字节个数 </returns>
public int ReadBlock(byte[] ReadBuf, int ReadRoom, int ByteTime)
{
sbyte nBytelen;
//long nByteRead;
if (SerialPort1.IsOpen == false)
return 0;
nBytelen = 0;
SerialPort1.ReadTimeout = ByteTime;
while (nBytelen < ReadRoom - 1 && SerialPort1.BytesToRead > 0)
{
try
{
ReadBuf[nBytelen] = (byte) SerialPort1.ReadByte();
nBytelen++; // add one
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
ReadBuf[nBytelen] = 0x00;
return nBytelen;
}
/// <summary>
/// 字符数组转字符串16进制
/// </summary>
/// <param name="InBytes"> 二进制字节 </param>
/// <returns>类似"01 02 0F" </returns>
public static string ByteToString(byte[] InBytes)
{
string StringOut = "";
foreach (byte InByte in InBytes)
{
StringOut = StringOut + String.Format("{0:X2}", InByte) + " ";
}
return StringOut.Trim();
}
/// <summary>
/// strhex 转字节数组
/// </summary>
/// <param name="InString">类似"01 02 0F" 用空格分开的 </param>
/// <returns> </returns>
public static byte[] StringToByte(string InString)
{
string[] ByteStrings;
ByteStrings = InString.Split(" ".ToCharArray());
byte[] ByteOut;
ByteOut = new byte[ByteStrings.Length];
for (int i = 0; i <= ByteStrings.Length - 1; i++)
{
ByteOut[i] = byte.Parse(ByteStrings[i], System.Globalization.NumberStyles.HexNumber);
}
return ByteOut;
}
/// <summary>
/// strhex 转字节数组
/// </summary>
/// <param name="InString">类似"01 02 0F" 中间无空格 </param>
/// <returns> </returns>
public static byte[] StringToByte_2(string InString)
{
byte[] ByteOut;
InString = InString.Replace(" ", "");
try
{
string[] ByteStrings = new string[InString.Length/2];
int j = 0;
for (int i = 0; i < ByteStrings.Length; i++)
{
ByteStrings[i] = InString.Substring(j, 2);
j += 2;
}
ByteOut = new byte[ByteStrings.Length];
for (int i = 0; i <= ByteStrings.Length - 1; i++)
{
ByteOut[i] = byte.Parse(ByteStrings[i], System.Globalization.NumberStyles.HexNumber);
}
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
return ByteOut;
}
/// <summary>
/// 字符串 转16进制字符串
/// </summary>
/// <param name="InString">unico </param>
/// <returns>类似“01 0f” </returns>
public static string Str_To_0X(string InString)
{
return ByteToString(UnicodeEncoding.Default.GetBytes(InString));
}
/// <summary>
    /// 实现IDisposable接口
    /// </summary>
public void Dispose()
{
Dispose(true);
//.NET Framework 类库
// GC..::.SuppressFinalize 方法
//请求系统不要调用指定对象的终结器。
GC.SuppressFinalize(this);
}
private bool m_disposed = true;
/// <summary>
/// 虚方法,可供子类重写
/// </summary>
/// <param name="disposing"></param>
protected virtual void Dispose(bool disposing)
{
if (!m_disposed)
{
if (disposing)
{
// Release managed resources
}
// Release unmanaged resources
if (_serialPort1 != null)
{
try
{
_serialPort1.Close();
}
catch (Exception)
{
//ignore
}
_serialPort1.Dispose();
_serialPort1 = null;
}
m_disposed = true;
}
}
/// <summary>
/// 析构函数
/// 当客户端没有显示调用Dispose()时由GC完成资源回收功能
/// </summary>
~ComConnector()
{
Dispose(false);
}
}
}

View File

@@ -1,18 +1,21 @@
using System;
using System.IO.Ports;
using System.IO.Ports;
namespace Modbus.Net
{
/// <summary>
/// 串口连接对象
/// </summary>
public abstract class ComProtocalLinker : ProtocalLinker
{
protected ComProtocalLinker(int baudRate, Parity parity, StopBits stopBits, int dataBits) : this(ConfigurationManager.COM, baudRate, parity, stopBits, dataBits)
protected ComProtocalLinker(int baudRate, Parity parity, StopBits stopBits, int dataBits)
: this(ConfigurationManager.COM, baudRate, parity, stopBits, dataBits)
{
}
protected ComProtocalLinker(string com, int baudRate, Parity parity, StopBits stopBits, int dataBits)
{
//初始化连对象
_baseConnector = new ComConnector(com, baudRate, parity, stopBits, dataBits, 30000);
BaseConnector = new ComConnector(com, baudRate, parity, stopBits, dataBits, 30000);
}
}
}

View File

@@ -53,6 +53,7 @@
<Compile Include="AddressCombiner.cs" />
<Compile Include="AddressFormater.cs" />
<Compile Include="AddressTranslator.cs" />
<Compile Include="AddressHelper.cs" />
<Compile Include="AsyncHelper.cs" />
<Compile Include="BaseMachineExtend.cs" />
<Compile Include="BaseProtocal.cs" />

View File

@@ -1,5 +1,4 @@
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
namespace Modbus.Net
@@ -9,14 +8,14 @@ namespace Modbus.Net
/// </summary>
public abstract class ProtocalLinker
{
protected BaseConnector _baseConnector;
protected BaseConnector BaseConnector;
public string ConnectionToken => _baseConnector.ConnectionToken;
public string ConnectionToken => BaseConnector.ConnectionToken;
/// <summary>
/// 设备是否连接
/// </summary>
public bool IsConnected => _baseConnector != null && _baseConnector.IsConnected;
public bool IsConnected => BaseConnector != null && BaseConnector.IsConnected;
/// <summary>
/// 连接设备
@@ -24,7 +23,7 @@ namespace Modbus.Net
/// <returns>设备是否连接成功</returns>
public bool Connect()
{
return _baseConnector.Connect();
return BaseConnector.Connect();
}
/// <summary>
@@ -33,7 +32,7 @@ namespace Modbus.Net
/// <returns>设备是否连接成功</returns>
public async Task<bool> ConnectAsync()
{
return await _baseConnector.ConnectAsync();
return await BaseConnector.ConnectAsync();
}
/// <summary>
@@ -42,7 +41,7 @@ namespace Modbus.Net
/// <returns>设备是否断开成功</returns>
public bool Disconnect()
{
return _baseConnector.Disconnect();
return BaseConnector.Disconnect();
}
/// <summary>
@@ -62,8 +61,8 @@ namespace Modbus.Net
/// <returns>接收协议的内容</returns>
public virtual async Task<byte[]> SendReceiveAsync(byte[] content)
{
byte[] extBytes = BytesExtend(content);
byte[] receiveBytes = await SendReceiveWithoutExtAndDecAsync(extBytes);
var extBytes = BytesExtend(content);
var receiveBytes = await SendReceiveWithoutExtAndDecAsync(extBytes);
return receiveBytes == null ? null : receiveBytes.Length == 0 ? receiveBytes : BytesDecact(receiveBytes);
}
@@ -85,7 +84,7 @@ namespace Modbus.Net
public virtual async Task<byte[]> SendReceiveWithoutExtAndDecAsync(byte[] content)
{
//发送数据
byte[] receiveBytes = await _baseConnector.SendMsgAsync(content);
var receiveBytes = await BaseConnector.SendMsgAsync(content);
//容错处理
var checkRight = CheckRight(receiveBytes);
return checkRight == null ? new byte[0] : (!checkRight.Value ? null : receiveBytes);
@@ -112,8 +111,8 @@ namespace Modbus.Net
public byte[] BytesExtend(byte[] content)
{
//自动查找相应的协议放缩类,命令规则为——当前的实际类名(注意是继承后的)+"BytesExtend"。
ProtocalLinkerBytesExtend bytesExtend =
Assembly.Load(this.GetType().Assembly.FullName).CreateInstance(this.GetType().FullName + "BytesExtend") as
var bytesExtend =
Assembly.Load(GetType().Assembly.FullName).CreateInstance(GetType().FullName + "BytesExtend") as
ProtocalLinkerBytesExtend;
return bytesExtend?.BytesExtend(content);
}
@@ -126,8 +125,8 @@ namespace Modbus.Net
public byte[] BytesDecact(byte[] content)
{
//自动查找相应的协议放缩类,命令规则为——当前的实际类名(注意是继承后的)+"BytesExtend"。
ProtocalLinkerBytesExtend bytesExtend =
Assembly.Load(this.GetType().Assembly.GetName().Name).CreateInstance(this.GetType().FullName + "BytesExtend") as
var bytesExtend =
Assembly.Load(GetType().Assembly.GetName().Name).CreateInstance(GetType().FullName + "BytesExtend") as
ProtocalLinkerBytesExtend;
return bytesExtend?.BytesDecact(content);
}

View File

@@ -1,6 +1,4 @@
using System;
namespace Modbus.Net
namespace Modbus.Net
{
/// <summary>
/// 协议字节伸缩

View File

@@ -2,8 +2,14 @@
namespace Modbus.Net
{
/// <summary>
/// 协议单元
/// </summary>
public abstract class ProtocalUnit : IProtocalFormatting
{
/// <summary>
/// 是否为小端格式
/// </summary>
public bool IsLittleEndian { get; protected set; } = false;
/// <summary>
@@ -45,6 +51,9 @@ namespace Modbus.Net
}
}
/// <summary>
/// 特殊协议单元继承这个类的协议不会执行BytesExtend和BytesDecact
/// </summary>
public abstract class SpecialProtocalUnit : ProtocalUnit
{
}
@@ -71,7 +80,6 @@ namespace Modbus.Net
public ProtocalErrorException(string message)
: base(message)
{
}
}
}

View File

@@ -380,17 +380,17 @@ public class ReadDataModbusProtocal : ProtocalUnit
public override byte[] Format(InputStruct message)
{
var r_message = (ReadDataModbusInputStruct)message;
return Format(r_message.BelongAddress, r_message.FunctionCode, r_message.StartAddress, r_message.GetCount);
return Format(r_message.SlaveAddress, r_message.FunctionCode, r_message.StartAddress, r_message.GetCount);
}
public override OutputStruct Unformat(byte[] messageBytes, ref int pos)
{
byte belongAddress = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
byte slaveAddress = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
byte functionCode = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
byte dataCount = BigEndianValueHelper.Instance.GetByte(messageBytes, ref pos);
byte[] dataValue = new byte[dataCount];
Array.Copy(messageBytes, 3, dataValue, 0, dataCount);
return new ReadDataModbusOutputStruct(belongAddress, functionCode, dataCount, dataValue);
return new ReadDataModbusOutputStruct(slaveAddress, functionCode, dataCount, dataValue);
}
}
```
@@ -453,14 +453,14 @@ Implement low level api for Modbus.
You need to implement three functions.
```C#
public override void SetConnectionType(int connectionType)
protected override async Task<byte[]> GetDatasAsync(byte belongAddress, byte masterAddress, string startAddress, int getByteCount)
public override async Task<bool> SetDatasAsync(byte belongAddress, byte masterAddress, string startAddress, object[] setContents)
protected override async Task<byte[]> GetDatasAsync(byte slaveAddress, byte masterAddress, string startAddress, int getByteCount)
public override async Task<bool> SetDatasAsync(byte slaveAddress, byte masterAddress, string startAddress, object[] setContents)
public override bool GetLittleEndian
public override bool SetLittleEndian
```
And don't remember set default AddressTranslator, belongAddress, masterAddress and Protocal.
And don't remember set default AddressTranslator, slaveAddress, masterAddress and Protocal.
```C#
public ModbusUtility(int connectionType, byte belongAddress, byte masterAddress) : base(belongAddress, masterAddress)
public ModbusUtility(int connectionType, byte slaveAddress, byte masterAddress) : base(slaveAddress, masterAddress)
{
ConnectionString = null;
ModbusType = (ModbusType)connectionType;
@@ -552,8 +552,8 @@ Remember subpos system cannot cross a byte in current version. If you want to cr
###Version 1.2.2
* Address Utility (In Road)
* Move SlaveAddress parameter to GetData and SetData. (In Road)
* More functions in TaskManager. (In Road)
* More functions in TaskManager (In Road)
* More interfaces (In Road)
###Version 1.2.3
* OPC UA Support (In Road)

View File

@@ -1,4 +1,9 @@
using System;
/*
* LimitedConcurrencyLevelTaskScheduler类来自于MSDN官方样例Modbus.Net的作者不保留对这个类的版权。
* LimitedConcurrencyLevelTaskScheduler class comes from offical samples of MSDN, the author of "Modbus.Net" "donnot" obtain the copyright of LimitedConcurrencyLevelTaskScheduler(only).
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
@@ -6,18 +11,27 @@ using System.Threading.Tasks;
namespace Modbus.Net
{
/// <summary>
/// 设备的读写方式
/// </summary>
public enum MachineDataType
{
Address,
CommunicationTag,
CommunicationTag
}
/// <summary>
/// 返回结果的定义类
/// </summary>
public class TaskReturnDef
{
public string MachineId { get; set; }
public Dictionary<string, ReturnUnit> ReturnValues { get; set; }
}
/// <summary>
/// 时间定义
/// </summary>
public static class TimeRestore
{
public static int Restore = 0;
@@ -28,20 +42,22 @@ namespace Modbus.Net
/// <summary>
/// Whether the current thread is processing work items.
/// </summary>
[ThreadStatic]
private static bool _currentThreadIsProcessingItems;
/// <summary>
/// The list of tasks to be executed.
/// </summary>
private readonly LinkedList<Task> _tasks = new LinkedList<Task>(); // protected by lock(_tasks)
[ThreadStatic] private static bool _currentThreadIsProcessingItems;
/// <summary>
/// The maximum concurrency level allowed by this scheduler.
/// </summary>
private readonly int _maxDegreeOfParallelism;
/// <summary>
/// The list of tasks to be executed.
/// </summary>
private readonly LinkedList<Task> _tasks = new LinkedList<Task>(); // protected by lock(_tasks)
/// <summary>
/// Whether the scheduler is currently processing work items.
/// </summary>
private int _delegatesQueuedOrRunning = 0; // protected by lock(_tasks)
private int _delegatesQueuedOrRunning; // protected by lock(_tasks)
/// <summary>
/// Initializes an instance of the LimitedConcurrencyLevelTaskScheduler class with the
@@ -56,6 +72,14 @@ namespace Modbus.Net
_maxDegreeOfParallelism = maxDegreeOfParallelism;
}
/// <summary>
/// Gets the maximum concurrency level supported by this scheduler.
/// </summary>
public sealed override int MaximumConcurrencyLevel
{
get { return _maxDegreeOfParallelism; }
}
/// <summary>
/// Queues a task to the scheduler.
/// </summary>
@@ -109,11 +133,14 @@ namespace Modbus.Net
}
// Execute the task we pulled out of the queue
base.TryExecuteTask(item);
TryExecuteTask(item);
}
}
// We're done processing items on the current thread
finally { _currentThreadIsProcessingItems = false; }
finally
{
_currentThreadIsProcessingItems = false;
}
}, null);
}
@@ -130,7 +157,7 @@ namespace Modbus.Net
if (taskWasPreviouslyQueued) TryDequeue(task);
// Try to run the task.
return base.TryExecuteTask(task);
return TryExecuteTask(task);
}
/// <summary>
@@ -147,11 +174,6 @@ namespace Modbus.Net
lock (_tasks) return _tasks.Remove(task);
}
/// <summary>
/// Gets the maximum concurrency level supported by this scheduler.
/// </summary>
public sealed override int MaximumConcurrencyLevel { get { return _maxDegreeOfParallelism; } }
/// <summary>
/// Gets an enumerable of the tasks currently scheduled on this scheduler.
/// </summary>
@@ -160,7 +182,7 @@ namespace Modbus.Net
/// </returns>
protected sealed override IEnumerable<Task> GetScheduledTasks()
{
bool lockTaken = false;
var lockTaken = false;
try
{
Monitor.TryEnter(_tasks, ref lockTaken);
@@ -176,32 +198,71 @@ namespace Modbus.Net
public class TaskManager
{
/// <summary>
/// 返回数据代理
/// </summary>
/// <param name="returnValue"></param>
public delegate void ReturnValuesDelegate(TaskReturnDef returnValue);
/// <summary>
/// 正在运行的设备
/// </summary>
private HashSet<BaseMachine> _machines;
private readonly HashSet<BaseMachine> _machines;
/// <summary>
/// 不在运行的设备
/// </summary>
private HashSet<BaseMachine> _unlinkedMachines;
private readonly HashSet<BaseMachine> _unlinkedMachines;
private TaskFactory _tasks;
private TaskScheduler _scheduler;
private CancellationTokenSource _cts;
/// <summary>
/// 获取间隔
/// </summary>
private int _getCycle;
/// <summary>
/// 保持连接
/// </summary>
private bool _keepConnect;
/// <summary>
/// 任务调度
/// </summary>
private TaskScheduler _scheduler;
/// <summary>
/// 任务工厂
/// </summary>
private TaskFactory _tasks;
/// <summary>
/// 正常读取的计时器
/// </summary>
private Timer _timer;
/// <summary>
/// 重连计时器
/// </summary>
private Timer _timer2;
/// <summary>
/// 保持连接
/// 构造一个TaskManager
/// </summary>
private bool _keepConnect;
/// <param name="maxRunningTask">同时可以运行的任务数</param>
/// <param name="getCycle">读取数据的时间间隔(秒)</param>
/// <param name="keepConnect">读取数据后是否保持连接</param>
/// <param name="dataType">获取与设置数据的方式</param>
public TaskManager(int maxRunningTask, int getCycle, bool keepConnect,
MachineDataType dataType = MachineDataType.CommunicationTag)
{
_scheduler = new LimitedConcurrencyLevelTaskScheduler(maxRunningTask);
_machines = new HashSet<BaseMachine>(new BaseMachineEqualityComparer());
_unlinkedMachines = new HashSet<BaseMachine>(new BaseMachineEqualityComparer());
_getCycle = getCycle;
KeepConnect = keepConnect;
MachineDataType = dataType;
}
/// <summary>
/// 保持连接
@@ -223,22 +284,6 @@ namespace Modbus.Net
}
}
/// <summary>
/// 返回数据代理
/// </summary>
/// <param name="returnValue"></param>
public delegate void ReturnValuesDelegate(TaskReturnDef returnValue);
/// <summary>
/// 返回数据事件
/// </summary>
public event ReturnValuesDelegate ReturnValues;
/// <summary>
/// 获取间隔
/// </summary>
private int _getCycle;
/// <summary>
/// 获取间隔,毫秒
/// </summary>
@@ -310,6 +355,9 @@ namespace Modbus.Net
public MachineGetDataType GetDataType { get; set; }
public MachineSetDataType SetDataType { get; set; }
/// <summary>
/// 最大可执行任务数
/// </summary>
public int MaxRunningTasks
{
get { return _scheduler.MaximumConcurrencyLevel; }
@@ -321,21 +369,9 @@ namespace Modbus.Net
}
/// <summary>
/// 构造一个TaskManager
/// 返回数据事件
/// </summary>
/// <param name="maxRunningTask">同时可以运行的任务数</param>
/// <param name="getCycle">读取数据的时间间隔(秒)</param>
/// <param name="keepConnect">读取数据后是否保持连接</param>
/// <param name="dataType">获取与设置数据的方式</param>
public TaskManager(int maxRunningTask, int getCycle, bool keepConnect, MachineDataType dataType = MachineDataType.CommunicationTag)
{
_scheduler = new LimitedConcurrencyLevelTaskScheduler(maxRunningTask);
_machines = new HashSet<BaseMachine>(new BaseMachineEqualityComparer());
_unlinkedMachines = new HashSet<BaseMachine>(new BaseMachineEqualityComparer());
_getCycle = getCycle;
KeepConnect = keepConnect;
MachineDataType = dataType;
}
public event ReturnValuesDelegate ReturnValues;
/// <summary>
/// 添加一台设备
@@ -484,7 +520,7 @@ namespace Modbus.Net
try
{
var tasks = new List<Task>();
HashSet<BaseMachine> saveMachines = new HashSet<BaseMachine>();
var saveMachines = new HashSet<BaseMachine>();
IEnumerable<BaseMachine> saveMachinesEnum;
lock (_machines)
{
@@ -493,16 +529,16 @@ namespace Modbus.Net
}
foreach (var machine in saveMachinesEnum)
{
CancellationTokenSource cts = new CancellationTokenSource();
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(_getCycle*10));
var task = _tasks.StartNew(() => RunTask(machine).WithCancellation(cts.Token));
tasks.Add(task);
}
await Task.WhenAll(tasks);
}
catch
catch(Exception)
{
return;
//ignore
}
}
@@ -515,23 +551,23 @@ namespace Modbus.Net
try
{
var tasks = new List<Task>();
HashSet<BaseMachine> saveMachines = new HashSet<BaseMachine>();
var saveMachines = new HashSet<BaseMachine>();
lock (_unlinkedMachines)
{
saveMachines.UnionWith(_unlinkedMachines);
}
foreach (var machine in saveMachines)
{
CancellationTokenSource cts = new CancellationTokenSource();
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeSpan.FromSeconds(_getCycle*10));
var task = _tasks.StartNew(() => RunTask(machine).WithCancellation(cts.Token));
tasks.Add(task);
}
await Task.WhenAll(tasks);
}
catch
catch(Exception)
{
return;
//ignore
}
}
@@ -572,10 +608,7 @@ namespace Modbus.Net
lock (_machines)
{
GetCycle = Timeout.Infinite;
if (_cts != null)
{
_cts.Cancel();
}
_cts?.Cancel();
if (_machines != null)
{
foreach (var machine in _machines)
@@ -599,7 +632,7 @@ namespace Modbus.Net
//调试代码,调试时取消下面一下代码的注释,会同步调用获取数据。
//var ans = machine.GetDatas();
//设置Cancellation Token
CancellationTokenSource cts = new CancellationTokenSource();
var cts = new CancellationTokenSource();
//超时后取消任务
cts.CancelAfter(TimeSpan.FromSeconds(_getCycle));
//读取数据
@@ -612,7 +645,7 @@ namespace Modbus.Net
{
MoveMachineToLinked(machine.Id);
}
ReturnValues?.Invoke(new TaskReturnDef()
ReturnValues?.Invoke(new TaskReturnDef
{
MachineId = machine.Id,
ReturnValues = ans
@@ -624,7 +657,7 @@ namespace Modbus.Net
{
MoveMachineToUnlinked(machine.Id);
}
ReturnValues?.Invoke(new TaskReturnDef()
ReturnValues?.Invoke(new TaskReturnDef
{
MachineId = machine.Id,
ReturnValues = null

View File

@@ -1,5 +1,4 @@
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
@@ -25,21 +24,30 @@ namespace Modbus.Net
/// </summary>
public class TcpConnector : BaseConnector, IDisposable
{
public override string ConnectionToken => _host;
private readonly string _host;
private int _sendCount;
private int _receiveCount;
private int _errorCount;
private readonly int _port;
// 2MB 的接收缓冲区,目的是一次接收完服务器发回的消息
private readonly byte[] _receiveBuffer = new byte[1024];
private readonly int _port;
private int _errorCount;
private int _receiveCount;
private int _sendCount;
private TcpClient _socketClient;
private int _timeoutTime;
private bool m_disposed;
public TcpConnector(string ipaddress, int port, int timeoutTime)
{
_host = ipaddress;
_port = port;
TimeoutTime = timeoutTime;
}
public override string ConnectionToken => _host;
public int TimeoutTime
{
get { return _timeoutTime; }
@@ -53,18 +61,11 @@ namespace Modbus.Net
}
}
public TcpConnector(string ipaddress, int port, int timeoutTime)
{
_host = ipaddress;
_port = port;
TimeoutTime = timeoutTime;
}
public override bool IsConnected => _socketClient?.Client != null && _socketClient.Connected;
/// <summary>
    /// 实现IDisposable接口
    /// </summary>
/// 实现IDisposable接口
/// </summary>
public void Dispose()
{
Dispose(true);
@@ -74,8 +75,6 @@ namespace Modbus.Net
GC.SuppressFinalize(this);
}
private bool m_disposed = false;
/// <summary>
/// 虚方法,可供子类重写
/// </summary>
@@ -128,7 +127,7 @@ namespace Modbus.Net
try
{
CancellationTokenSource cts = new CancellationTokenSource();
var cts = new CancellationTokenSource();
cts.CancelAfter(TimeoutTime);
await _socketClient.ConnectAsync(_host, _port).WithCancellation(cts.Token);
}
@@ -192,7 +191,7 @@ namespace Modbus.Net
/// <returns>是否发送成功</returns>
public override async Task<bool> SendMsgWithoutReturnAsync(byte[] message)
{
byte[] datagram = message;
var datagram = message;
try
{
@@ -228,7 +227,7 @@ namespace Modbus.Net
/// <returns>是否发送成功</returns>
public override async Task<byte[]> SendMsgAsync(byte[] message)
{
byte[] datagram = message;
var datagram = message;
try
{
@@ -257,7 +256,7 @@ namespace Modbus.Net
{
try
{
int len = await stream.ReadAsync(_receiveBuffer, 0, _receiveBuffer.Length);
var len = await stream.ReadAsync(_receiveBuffer, 0, _receiveBuffer.Length);
stream.Flush();
// 异步接收回答
if (len > 0)

View File

@@ -1,21 +1,18 @@
using System;
namespace Modbus.Net
namespace Modbus.Net
{
/// <summary>
/// Tcp连接对象
/// </summary>
public abstract class TcpProtocalLinker : ProtocalLinker
{
protected TcpProtocalLinker() : this(ConfigurationManager.IP, int.Parse(ConfigurationManager.ModbusPort))
{
}
protected TcpProtocalLinker(string ip, int port)
{
_baseConnector = new TcpConnector(ip, port, int.Parse(ConfigurationManager.IPConnectionTimeout));
//初始化连接对象
BaseConnector = new TcpConnector(ip, port, int.Parse(ConfigurationManager.IPConnectionTimeout));
}
}
}

View File

@@ -1,7 +1,6 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
@@ -9,11 +8,10 @@ namespace Modbus.Net
{
/// <summary>
/// 值与字节数组之间转换的辅助类这是一个Singleton类
/// 作者罗圣Chris L.
/// </summary>
public class ValueHelper
{
public Dictionary<string, double> ByteLength = new Dictionary<string, double>()
public Dictionary<string, double> ByteLength = new Dictionary<string, double>
{
{"System.Boolean", 0.125},
{"System.Byte", 1},
@@ -36,25 +34,12 @@ namespace Modbus.Net
/// </summary>
public static bool LittleEndian => true;
#region Factory
private static ValueHelper _instance;
protected virtual ValueHelper _Instance => _instance;
/// <summary>
/// ValueHelper单例的实例
/// </summary>
public static ValueHelper Instance => _instance ?? (_instance = new ValueHelper());
#endregion
/// <summary>
/// 将一个byte数字转换为一个byte元素的数组。
/// </summary>
/// <param name="value">byte数字</param>
/// <returns>byte数组</returns>
public Byte[] GetBytes(byte value)
public byte[] GetBytes(byte value)
{
return new[] {value};
}
@@ -64,7 +49,7 @@ namespace Modbus.Net
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public virtual Byte[] GetBytes(short value)
public virtual byte[] GetBytes(short value)
{
return BitConverter.GetBytes(value);
}
@@ -74,7 +59,7 @@ namespace Modbus.Net
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public virtual Byte[] GetBytes(int value)
public virtual byte[] GetBytes(int value)
{
return BitConverter.GetBytes(value);
}
@@ -84,7 +69,7 @@ namespace Modbus.Net
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public virtual Byte[] GetBytes(long value)
public virtual byte[] GetBytes(long value)
{
return BitConverter.GetBytes(value);
}
@@ -94,7 +79,7 @@ namespace Modbus.Net
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public virtual Byte[] GetBytes(ushort value)
public virtual byte[] GetBytes(ushort value)
{
return BitConverter.GetBytes(value);
}
@@ -104,7 +89,7 @@ namespace Modbus.Net
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public virtual Byte[] GetBytes(uint value)
public virtual byte[] GetBytes(uint value)
{
return BitConverter.GetBytes(value);
}
@@ -114,7 +99,7 @@ namespace Modbus.Net
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public virtual Byte[] GetBytes(ulong value)
public virtual byte[] GetBytes(ulong value)
{
return BitConverter.GetBytes(value);
}
@@ -124,7 +109,7 @@ namespace Modbus.Net
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public virtual Byte[] GetBytes(float value)
public virtual byte[] GetBytes(float value)
{
return BitConverter.GetBytes(value);
}
@@ -134,7 +119,7 @@ namespace Modbus.Net
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public virtual Byte[] GetBytes(double value)
public virtual byte[] GetBytes(double value)
{
return BitConverter.GetBytes(value);
}
@@ -145,53 +130,53 @@ namespace Modbus.Net
/// <param name="value"></param>
/// <param name="type"></param>
/// <returns></returns>
public virtual Byte[] GetBytes(object value, Type type)
public virtual byte[] GetBytes(object value, Type type)
{
switch (type.FullName)
{
case "System.Int16":
{
byte[] bytes = _Instance.GetBytes((short) value);
var bytes = _Instance.GetBytes((short) value);
return bytes;
}
case "System.Int32":
{
byte[] bytes = _Instance.GetBytes((int) value);
var bytes = _Instance.GetBytes((int) value);
return bytes;
}
case "System.Int64":
{
byte[] bytes = _Instance.GetBytes((long) value);
var bytes = _Instance.GetBytes((long) value);
return bytes;
}
case "System.UInt16":
{
byte[] bytes = _Instance.GetBytes((ushort) value);
var bytes = _Instance.GetBytes((ushort) value);
return bytes;
}
case "System.UInt32":
{
byte[] bytes = _Instance.GetBytes((uint) value);
var bytes = _Instance.GetBytes((uint) value);
return bytes;
}
case "System.UInt64":
{
byte[] bytes = _Instance.GetBytes((ulong) value);
var bytes = _Instance.GetBytes((ulong) value);
return bytes;
}
case "System.Single":
{
byte[] bytes = _Instance.GetBytes((float) value);
var bytes = _Instance.GetBytes((float) value);
return bytes;
}
case "System.Double":
{
byte[] bytes = _Instance.GetBytes((double) value);
var bytes = _Instance.GetBytes((double) value);
return bytes;
}
case "System.Byte":
{
byte[] bytes = _Instance.GetBytes((byte) value);
var bytes = _Instance.GetBytes((byte) value);
return bytes;
}
default:
@@ -215,52 +200,52 @@ namespace Modbus.Net
{
case "System.Int16":
{
short value = _Instance.GetShort(data, ref pos);
var value = _Instance.GetShort(data, ref pos);
return value;
}
case "System.Int32":
{
int value = _Instance.GetInt(data, ref pos);
var value = _Instance.GetInt(data, ref pos);
return value;
}
case "System.Int64":
{
long value = _Instance.GetLong(data, ref pos);
var value = _Instance.GetLong(data, ref pos);
return value;
}
case "System.UInt16":
{
ushort value = _Instance.GetUShort(data, ref pos);
var value = _Instance.GetUShort(data, ref pos);
return value;
}
case "System.UInt32":
{
uint value = _Instance.GetUInt(data, ref pos);
var value = _Instance.GetUInt(data, ref pos);
return value;
}
case "System.UInt64":
{
ulong value = _Instance.GetULong(data, ref pos);
var value = _Instance.GetULong(data, ref pos);
return value;
}
case "System.Single":
{
float value = _Instance.GetFloat(data, ref pos);
var value = _Instance.GetFloat(data, ref pos);
return value;
}
case "System.Double":
{
double value = _Instance.GetDouble(data, ref pos);
var value = _Instance.GetDouble(data, ref pos);
return value;
}
case "System.Byte":
{
byte value = _Instance.GetByte(data, ref pos);
var value = _Instance.GetByte(data, ref pos);
return value;
}
case "System.Boolean":
{
bool value = _Instance.GetBit(data, ref pos, ref subPos);
var value = _Instance.GetBit(data, ref pos, ref subPos);
return value;
}
default:
@@ -278,7 +263,7 @@ namespace Modbus.Net
/// <returns></returns>
public virtual byte GetByte(byte[] data, ref int pos)
{
byte t = data[pos];
var t = data[pos];
pos += 1;
return t;
}
@@ -291,7 +276,7 @@ namespace Modbus.Net
/// <returns></returns>
public virtual short GetShort(byte[] data, ref int pos)
{
short t = BitConverter.ToInt16(data, pos);
var t = BitConverter.ToInt16(data, pos);
pos += 2;
return t;
}
@@ -304,7 +289,7 @@ namespace Modbus.Net
/// <returns></returns>
public virtual int GetInt(byte[] data, ref int pos)
{
int t = BitConverter.ToInt32(data, pos);
var t = BitConverter.ToInt32(data, pos);
pos += 4;
return t;
}
@@ -317,7 +302,7 @@ namespace Modbus.Net
/// <returns></returns>
public virtual long GetLong(byte[] data, ref int pos)
{
long t = BitConverter.ToInt64(data, pos);
var t = BitConverter.ToInt64(data, pos);
pos += 8;
return t;
}
@@ -330,7 +315,7 @@ namespace Modbus.Net
/// <returns></returns>
public virtual ushort GetUShort(byte[] data, ref int pos)
{
ushort t = BitConverter.ToUInt16(data, pos);
var t = BitConverter.ToUInt16(data, pos);
pos += 2;
return t;
}
@@ -343,7 +328,7 @@ namespace Modbus.Net
/// <returns></returns>
public virtual uint GetUInt(byte[] data, ref int pos)
{
uint t = BitConverter.ToUInt32(data, pos);
var t = BitConverter.ToUInt32(data, pos);
pos += 4;
return t;
}
@@ -356,7 +341,7 @@ namespace Modbus.Net
/// <returns></returns>
public virtual ulong GetULong(byte[] data, ref int pos)
{
ulong t = BitConverter.ToUInt64(data, pos);
var t = BitConverter.ToUInt64(data, pos);
pos += 8;
return t;
}
@@ -369,7 +354,7 @@ namespace Modbus.Net
/// <returns></returns>
public virtual float GetFloat(byte[] data, ref int pos)
{
float t = BitConverter.ToSingle(data, pos);
var t = BitConverter.ToSingle(data, pos);
pos += 4;
return t;
}
@@ -382,7 +367,7 @@ namespace Modbus.Net
/// <returns></returns>
public virtual double GetDouble(byte[] data, ref int pos)
{
double t = BitConverter.ToDouble(data, pos);
var t = BitConverter.ToDouble(data, pos);
pos += 8;
return t;
}
@@ -397,7 +382,7 @@ namespace Modbus.Net
/// <returns></returns>
public virtual string GetString(byte[] data, int count, ref int pos, Encoding encoding)
{
string t = encoding.GetString(data, pos, count);
var t = encoding.GetString(data, pos, count);
pos += count;
return t;
}
@@ -410,9 +395,9 @@ namespace Modbus.Net
/// <returns></returns>
public virtual bool[] GetBits(byte[] data, ref int pos)
{
bool[] t = new bool[8];
byte temp = data[pos];
for (int i = 0; i < 8; i++)
var t = new bool[8];
var temp = data[pos];
for (var i = 0; i < 8; i++)
{
t[i] = temp%2 > 0;
temp /= 2;
@@ -431,8 +416,8 @@ namespace Modbus.Net
public bool GetBit(byte number, ref int pos, ref int subPos)
{
if (subPos < 0 && subPos >= 8) throw new IndexOutOfRangeException();
int ans = number % 2;
int i = 0;
var ans = number%2;
var i = 0;
while (i <= subPos)
{
ans = number%2;
@@ -448,15 +433,27 @@ namespace Modbus.Net
return ans > 0;
}
/// <summary>
/// 获取一个字节数组中某个Bit位的数据
/// </summary>
/// <param name="number"></param>
/// <param name="pos"></param>
/// <param name="subPos"></param>
/// <returns></returns>
public virtual bool GetBit(byte[] number, ref int pos, ref int subPos)
{
return GetBit(number[pos], ref pos, ref subPos);
}
/// <summary>
/// 反转一个字节的8个Bit位
/// </summary>
/// <param name="originalByte"></param>
/// <returns></returns>
public virtual byte ReverseByte(byte originalByte)
{
byte result = 0;
for (int i = 0; i < 8; i++)
for (var i = 0; i < 8; i++)
{
result <<= 1;
result |= (byte) (originalByte & 1);
@@ -472,17 +469,17 @@ namespace Modbus.Net
/// <returns></returns>
public virtual byte[] ObjectArrayToByteArray(object[] contents)
{
bool b = false;
var b = false;
//先查找传入的结构中有没有数组,有的话将其打开
var newContentsList = new List<object>();
foreach (object content in contents)
foreach (var content in contents)
{
string t = content.GetType().ToString();
var t = content.GetType().ToString();
if (t.Substring(t.Length - 2, 2) == "[]")
{
b = true;
//自动将目标数组中内含的子数组展开,是所有包含在子数组拼接为一个数组
IEnumerable<object> contentArray =
var contentArray =
ArrayList.Adapter((Array) content).ToArray(typeof (object)).OfType<object>();
newContentsList.AddRange(contentArray);
}
@@ -496,12 +493,12 @@ namespace Modbus.Net
//把参数一个一个翻译为相对应的字节,然后拼成一个队列
var translateTarget = new List<byte>();
//将bool类型拼装为byte类型时按照8个一组不满8个时补false为原则进行
bool lastIsBool = false;
var lastIsBool = false;
byte boolToByteTemp = 0;
int boolToByteCount = 0;
foreach (object content in contents)
var boolToByteCount = 0;
foreach (var content in contents)
{
string t = content.GetType().ToString();
var t = content.GetType().ToString();
if (t == "System.Boolean")
{
if (boolToByteCount >= 8)
@@ -601,9 +598,16 @@ namespace Modbus.Net
/// <returns>object数组</returns>
public virtual object[] ByteArrayToObjectArray(byte[] contents, KeyValuePair<Type, int> translateTypeAndCount)
{
return ByteArrayToObjectArray(contents, new List<KeyValuePair<Type, int>>() {translateTypeAndCount});
return ByteArrayToObjectArray(contents, new List<KeyValuePair<Type, int>> {translateTypeAndCount});
}
/// <summary>
/// 将一个byte数组转换成用户指定类型的数组使用模板参数确定需要转换的类型
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="contents"></param>
/// <param name="getCount"></param>
/// <returns></returns>
public virtual T[] ByteArrayToDestinationArray<T>(byte[] contents, int getCount)
{
var objectArray = _Instance.ByteArrayToObjectArray(contents,
@@ -615,16 +619,19 @@ namespace Modbus.Net
/// 将byte数组转换为用户指定类型的数组通过object数组的方式返回用户需要再把object转换为自己需要的类型或调用ObjectArrayToDestinationArray返回单一类型的目标数组。
/// </summary>
/// <param name="contents">byte数组</param>
/// <param name="translateTypeAndCount">一连串类型和需要转换的个数的键值对该方法会依次转换每一个需要转的目标数据类型。比如typeof(int),5; typeof(short),3 会转换出8个元素当然前提是byte数组足够长的时候5个int和3个short然后全部变为object类型返回。</param>
/// <param name="translateTypeAndCount">
/// 一连串类型和需要转换的个数的键值对该方法会依次转换每一个需要转的目标数据类型。比如typeof(int),5; typeof(short),3
/// 会转换出8个元素当然前提是byte数组足够长的时候5个int和3个short然后全部变为object类型返回。
/// </param>
/// <returns>object数组</returns>
public virtual object[] ByteArrayToObjectArray(byte[] contents,
IEnumerable<KeyValuePair<Type, int>> translateTypeAndCount)
{
List<object> translation = new List<object>();
int count = 0;
var translation = new List<object>();
var count = 0;
foreach (var translateUnit in translateTypeAndCount)
{
for (int i = 0; i < translateUnit.Value; i++)
for (var i = 0; i < translateUnit.Value; i++)
{
if (count >= contents.Length) break;
try
@@ -633,64 +640,63 @@ namespace Modbus.Net
{
case "System.Int16":
{
short value = _Instance.GetShort(contents, ref count);
var value = _Instance.GetShort(contents, ref count);
translation.Add(value);
break;
}
case "System.Int32":
{
int value = _Instance.GetInt(contents, ref count);
var value = _Instance.GetInt(contents, ref count);
translation.Add(value);
break;
}
case "System.Int64":
{
long value = _Instance.GetLong(contents, ref count);
var value = _Instance.GetLong(contents, ref count);
translation.Add(value);
break;
}
case "System.UInt16":
{
ushort value = _Instance.GetUShort(contents, ref count);
var value = _Instance.GetUShort(contents, ref count);
translation.Add(value);
break;
}
case "System.UInt32":
{
uint value = _Instance.GetUInt(contents, ref count);
var value = _Instance.GetUInt(contents, ref count);
translation.Add(value);
break;
}
case "System.UInt64":
{
ulong value = _Instance.GetULong(contents, ref count);
var value = _Instance.GetULong(contents, ref count);
translation.Add(value);
break;
}
case "System.Single":
{
float value = _Instance.GetFloat(contents, ref count);
var value = _Instance.GetFloat(contents, ref count);
translation.Add(value);
break;
}
case "System.Double":
{
double value = _Instance.GetDouble(contents, ref count);
var value = _Instance.GetDouble(contents, ref count);
translation.Add(value);
break;
}
case "System.Byte":
{
byte value = _Instance.GetByte(contents, ref count);
var value = _Instance.GetByte(contents, ref count);
translation.Add(value);
break;
}
case "System.Boolean":
{
bool[] value = _Instance.GetBits(contents, ref count);
int k = translateUnit.Value - i < 8 ? translateUnit.Value - i : 8;
for (int j = 0; j < k; j++)
var value = _Instance.GetBits(contents, ref count);
var k = translateUnit.Value - i < 8 ? translateUnit.Value - i : 8;
for (var j = 0; j < k; j++)
{
translation.Add(value[j]);
}
@@ -720,7 +726,7 @@ namespace Modbus.Net
/// <returns>目标数组</returns>
public T[] ObjectArrayToDestinationArray<T>(object[] contents)
{
T[] array = new T[contents.Length];
var array = new T[contents.Length];
Array.Copy(contents, array, contents.Length);
return array;
}
@@ -733,52 +739,52 @@ namespace Modbus.Net
{
case "System.Int16":
{
bool success = _Instance.SetValue(contents, setPos, (short)setValue);
var success = _Instance.SetValue(contents, setPos, (short) setValue);
return success;
}
case "System.Int32":
{
bool success = _Instance.SetValue(contents, setPos, (int) setValue);
var success = _Instance.SetValue(contents, setPos, (int) setValue);
return success;
}
case "System.Int64":
{
bool success = _Instance.SetValue(contents, setPos, (long) setValue);
var success = _Instance.SetValue(contents, setPos, (long) setValue);
return success;
}
case "System.UInt16":
{
bool success = _Instance.SetValue(contents, setPos, (ushort) setValue);
var success = _Instance.SetValue(contents, setPos, (ushort) setValue);
return success;
}
case "System.UInt32":
{
bool success = _Instance.SetValue(contents, setPos, (uint) setValue);
var success = _Instance.SetValue(contents, setPos, (uint) setValue);
return success;
}
case "System.UInt64":
{
bool success = _Instance.SetValue(contents, setPos, (ulong) setValue);
var success = _Instance.SetValue(contents, setPos, (ulong) setValue);
return success;
}
case "System.Single":
{
bool success = _Instance.SetValue(contents, setPos, (float) setValue);
var success = _Instance.SetValue(contents, setPos, (float) setValue);
return success;
}
case "System.Double":
{
bool success = _Instance.SetValue(contents, setPos, (double) setValue);
var success = _Instance.SetValue(contents, setPos, (double) setValue);
return success;
}
case "System.Byte":
{
bool success = _Instance.SetValue(contents, setPos, (byte) setValue);
var success = _Instance.SetValue(contents, setPos, (byte) setValue);
return success;
}
case "System.Boolean":
{
bool success = _Instance.SetBit(contents, setPos, subPos, (bool) setValue);
var success = _Instance.SetBit(contents, setPos, subPos, (bool) setValue);
return success;
}
default:
@@ -799,7 +805,7 @@ namespace Modbus.Net
{
try
{
byte[] datas = _Instance.GetBytes(setValue, setValue.GetType());
var datas = _Instance.GetBytes(setValue, setValue.GetType());
Array.Copy(datas, 0, contents, pos, datas.Length);
return true;
}
@@ -818,26 +824,23 @@ namespace Modbus.Net
/// <returns></returns>
public byte SetBit(byte number, int subPos, bool setBit)
{
int creation = 0;
var creation = 0;
if (setBit)
{
for (int i = 7; i >= 0; i--)
for (var i = 7; i >= 0; i--)
{
creation *= 2;
if (i == subPos) creation++;
}
return (byte) (number | creation);
}
else
{
for (int i = 7; i >= 0; i--)
for (var i = 7; i >= 0; i--)
{
creation *= 2;
if (i != subPos) creation++;
}
return (byte) (number & creation);
}
}
/// <summary>
/// 设置一组数据中的一个bit
@@ -859,59 +862,72 @@ namespace Modbus.Net
return false;
}
}
#region Factory
private static ValueHelper _instance;
protected virtual ValueHelper _Instance => _instance;
/// <summary>
/// ValueHelper单例的实例
/// </summary>
public static ValueHelper Instance => _instance ?? (_instance = new ValueHelper());
#endregion
}
public class BigEndianValueHelper : ValueHelper
{
private static BigEndianValueHelper _bigEndianInstance;
protected override ValueHelper _Instance => _bigEndianInstance;
protected BigEndianValueHelper()
{
}
protected override ValueHelper _Instance => _bigEndianInstance;
protected new bool LittleEndian => false;
public new static BigEndianValueHelper Instance => _bigEndianInstance ?? (_bigEndianInstance = new BigEndianValueHelper());
public new static BigEndianValueHelper Instance
=> _bigEndianInstance ?? (_bigEndianInstance = new BigEndianValueHelper());
public override Byte[] GetBytes(short value)
public override byte[] GetBytes(short value)
{
return Reverse(BitConverter.GetBytes(value));
}
public override Byte[] GetBytes(int value)
public override byte[] GetBytes(int value)
{
return Reverse(BitConverter.GetBytes(value));
}
public override Byte[] GetBytes(long value)
public override byte[] GetBytes(long value)
{
return Reverse(BitConverter.GetBytes(value));
}
public override Byte[] GetBytes(ushort value)
public override byte[] GetBytes(ushort value)
{
return Reverse(BitConverter.GetBytes(value));
}
public override Byte[] GetBytes(uint value)
public override byte[] GetBytes(uint value)
{
return Reverse(BitConverter.GetBytes(value));
}
public override Byte[] GetBytes(ulong value)
public override byte[] GetBytes(ulong value)
{
return Reverse(BitConverter.GetBytes(value));
}
public override Byte[] GetBytes(float value)
public override byte[] GetBytes(float value)
{
return Reverse(BitConverter.GetBytes(value));
}
public override Byte[] GetBytes(double value)
public override byte[] GetBytes(double value)
{
return Reverse(BitConverter.GetBytes(value));
}
@@ -919,7 +935,7 @@ namespace Modbus.Net
public override short GetShort(byte[] data, ref int pos)
{
Array.Reverse(data, pos, 2);
short t = BitConverter.ToInt16(data, pos);
var t = BitConverter.ToInt16(data, pos);
Array.Reverse(data, pos, 2);
pos += 2;
return t;
@@ -928,7 +944,7 @@ namespace Modbus.Net
public override int GetInt(byte[] data, ref int pos)
{
Array.Reverse(data, pos, 4);
int t = BitConverter.ToInt32(data, pos);
var t = BitConverter.ToInt32(data, pos);
Array.Reverse(data, pos, 4);
pos += 4;
return t;
@@ -937,7 +953,7 @@ namespace Modbus.Net
public override long GetLong(byte[] data, ref int pos)
{
Array.Reverse(data, pos, 8);
long t = BitConverter.ToInt64(data, pos);
var t = BitConverter.ToInt64(data, pos);
Array.Reverse(data, pos, 8);
pos += 8;
return t;
@@ -946,7 +962,7 @@ namespace Modbus.Net
public override ushort GetUShort(byte[] data, ref int pos)
{
Array.Reverse(data, pos, 2);
ushort t = BitConverter.ToUInt16(data, pos);
var t = BitConverter.ToUInt16(data, pos);
Array.Reverse(data, pos, 2);
pos += 2;
return t;
@@ -955,7 +971,7 @@ namespace Modbus.Net
public override uint GetUInt(byte[] data, ref int pos)
{
Array.Reverse(data, pos, 4);
uint t = BitConverter.ToUInt32(data, pos);
var t = BitConverter.ToUInt32(data, pos);
Array.Reverse(data, pos, 4);
pos += 4;
return t;
@@ -964,7 +980,7 @@ namespace Modbus.Net
public override ulong GetULong(byte[] data, ref int pos)
{
Array.Reverse(data, pos, 8);
ulong t = BitConverter.ToUInt64(data, pos);
var t = BitConverter.ToUInt64(data, pos);
Array.Reverse(data, pos, 8);
pos += 8;
return t;
@@ -973,7 +989,7 @@ namespace Modbus.Net
public override float GetFloat(byte[] data, ref int pos)
{
Array.Reverse(data, pos, 4);
float t = BitConverter.ToSingle(data, pos);
var t = BitConverter.ToSingle(data, pos);
Array.Reverse(data, pos, 4);
pos += 4;
return t;
@@ -982,7 +998,7 @@ namespace Modbus.Net
public override double GetDouble(byte[] data, ref int pos)
{
Array.Reverse(data, pos, 8);
double t = BitConverter.ToDouble(data, pos);
var t = BitConverter.ToDouble(data, pos);
Array.Reverse(data, pos, 8);
pos += 8;
return t;
@@ -1005,9 +1021,9 @@ namespace Modbus.Net
public override bool[] GetBits(byte[] data, ref int pos)
{
bool[] t = new bool[8];
byte temp = data[pos];
for (int i = 0; i < 8; i++)
var t = new bool[8];
var temp = data[pos];
for (var i = 0; i < 8; i++)
{
t[7 - i] = temp%2 > 0;
temp /= 2;
@@ -1021,7 +1037,7 @@ namespace Modbus.Net
return base.SetBit(number, pos, 7 - subPos, setBit);
}
private Byte[] Reverse(Byte[] data)
private byte[] Reverse(byte[] data)
{
Array.Reverse(data);
return data;