diff --git a/NA200H/ModBus.Net/ModBus.Net.csproj b/NA200H/ModBus.Net/ModBus.Net.csproj index d67e0f3..e05fee2 100644 --- a/NA200H/ModBus.Net/ModBus.Net.csproj +++ b/NA200H/ModBus.Net/ModBus.Net.csproj @@ -50,6 +50,7 @@ + diff --git a/NA200H/ModBus.Net/ModbusTCPProtocal.cs b/NA200H/ModBus.Net/ModbusTCPProtocal.cs index 238e88b..d98a113 100644 --- a/NA200H/ModBus.Net/ModbusTCPProtocal.cs +++ b/NA200H/ModBus.Net/ModbusTCPProtocal.cs @@ -12,5 +12,10 @@ namespace ModBus.Net { _protocalLinker = new ModbusTcpProtocalLinker(); } + + public ModbusTcpProtocal(string IP) + { + _protocalLinker = new ModbusTcpProtocalLinker(IP); + } } } \ No newline at end of file diff --git a/NA200H/ModBus.Net/ModbusTcpProtocalLinker.cs b/NA200H/ModBus.Net/ModbusTcpProtocalLinker.cs index a0cca7a..b8ebe32 100644 --- a/NA200H/ModBus.Net/ModbusTcpProtocalLinker.cs +++ b/NA200H/ModBus.Net/ModbusTcpProtocalLinker.cs @@ -6,7 +6,7 @@ using System.Threading.Tasks; namespace ModBus.Net { - class ModbusTcpProtocalLinker : TcpProtocalLinker + public class ModbusTcpProtocalLinker : TcpProtocalLinker { public override bool CheckRight(byte[] content) { @@ -16,5 +16,15 @@ namespace ModBus.Net } return true; } + + public ModbusTcpProtocalLinker() : base() + { + + } + + public ModbusTcpProtocalLinker(string IP) : base(IP) + { + + } } } diff --git a/NA200H/ModBus.Net/Prodave/ProdavePackLv1.cs b/NA200H/ModBus.Net/Prodave/ProdavePackLv1.cs new file mode 100644 index 0000000..e1d811d --- /dev/null +++ b/NA200H/ModBus.Net/Prodave/ProdavePackLv1.cs @@ -0,0 +1,286 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; + +namespace ModBus.Net.Prodave +{ + public class Prodave6 + { + #region 常值定义(用于极限值) + + public const int MAX_CONNECTIONS = 64; // 64 is default in PRODAVE + public const int MAX_DEVNAME_LEN = 128; // e.g. "S7ONLINE" + public const int MAX_BUFFERS = 64; // 64 for blk_read() and blk_write() + public const int MAX_BUFFER = 65536; // Transfer buffer for error text) + + #endregion + + #region 结构体定义 + + public struct CON_TABLE_TYPE //待连接plc地址属性表 + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] //public CON_ADR_TYPE Adr; // connection address + public byte[] Adr; // connection address + + // MPI/PB station address (2) + // IP address (192.168.0.1) + // MAC address (08-00-06-01-AA-BB) + public byte AdrType; // Type of address: MPI/PB (1), IP (2), MAC (3) + public byte SlotNr; // Slot number + public byte RackNr; // Rack number + } + + public enum DatType : byte //PLC数据类型 + { + + BYTE = 0x02, + WORD = 0x04, + DWORD = 0x06, + } + + public enum FieldType : byte //PLC区域类型 + { + //Value types as ASCII characters区域类型对应的ASCII字符 + //data byte (d/D) + d = 100, + D = 68, + //input byte (e/E) + e = 101, + E = 69, + //output byte (a/A) + a = 97, + A = 65, + //memory byte (m/M) + m = 109, + M = 77, + //timer word (t/T), + t = 116, + T = 84, + //counter word (z/Z), + z = 122, + Z = 90, + //virable storage type (v/V), + v = 118, + V = 86, + } + + #endregion + + #region PLC基本函数 + + [DllImport("Prodave6.dll")] //连接PLC操作 + //参数:连接号(0-63)、常值"S7ONLINE"、待连接plc地址属性表长度(字节为单位,常值9)、待连接plc地址属性表 + public static extern int LoadConnection_ex6(int ConNr, string pAccessPoint, int ConTableLen, + ref CON_TABLE_TYPE pConTable); + + [DllImport("Prodave6.dll")] //断开PLC操作 + //参数:连接号(0-63) + public static extern int UnloadConnection_ex6(UInt16 ConNr); + + [DllImport("Prodave6.dll")] //激活PLC连接操作 + //参数:连接号(0-63) + public static extern int SetActiveConnection_ex6(UInt16 ConNr); + + [DllImport("Prodave6.dll")] //PLC db区读取操作 + //参数:data block号、要读取的数据类型、起始地址号、需要读取类型的数量、缓冲区长度(字节为单位)、缓冲区、缓冲区数据交互的长度 + public static extern int db_read_ex6(UInt16 BlkNr, DatType DType, UInt16 StartNr, ref UInt32 pAmount, + UInt32 BufLen, + byte[] pBuffer, ref UInt32 pDatLen); + + [DllImport("Prodave6.dll")] //PLC db区写入操作 + //参数:data block号、要写入的数据类型、起始地址号、需要写入类型的数量、缓冲区长度(字节为单位)、缓冲区 + public static extern int db_write_ex6(UInt16 BlkNr, DatType Type, UInt16 StartNr, ref UInt32 pAmount, + UInt32 BufLen, + byte[] pBuffer); + + [DllImport("Prodave6.dll")] //PLC 任意区读取操作 + //参数:要读取的区类型、data block号(DB区特有,默认为0)、起始地址号、需要读取类型的数量、 + //缓冲区长度(字节为单位)、缓冲区、缓冲区数据交互的长度 + public static extern int field_read_ex6(FieldType FType, UInt16 BlkNr, UInt16 StartNr, UInt32 pAmount, + UInt32 BufLen, + byte[] pBuffer, ref UInt32 pDatLen); + + [DllImport("Prodave6.dll")] //PLC 任意区写入操作 + //参数:要写入的区类型、data block号(DB区特有,默认为0)、起始地址号、需要写入类型的数量、 + //缓冲区长度(字节为单位)、缓冲区 + public static extern int field_write_ex6(FieldType FType, UInt16 BlkNr, UInt16 StartNr, UInt32 pAmount, + UInt32 BufLen, + byte[] pBuffer); + + [DllImport("Prodave6.dll")] //PLC M区某字节的某位读取操作 + //参数:M区字节号、位号、当前的值(0/1) + public static extern int mb_bittest_ex6(UInt16 MbNr, UInt16 BitNr, ref int pValue); + + [DllImport("Prodave6.dll")] //PLC M区某字节的某位写入操作 + //参数:M区字节号、位号、要写入的值(0/1) + public static extern int mb_setbit_ex6(UInt16 MbNr, UInt16 BitNr, byte Value); + + #endregion + + #region PLC200用数据传输函数 + + [DllImport("Prodave6.dll")] //200系列PLC 任意区读取操作 + //参数:要读取的区类型、data block号(DB区特有,默认为0)、起始地址号、需要读取类型的数量、 + //缓冲区长度(字节为单位)、缓冲区、缓冲区数据交互的长度 + public static extern int as200_field_read_ex6(FieldType FType, UInt16 BlkNr, UInt16 StartNr, UInt32 pAmount, + UInt32 BufLen, + byte[] pBuffer, ref UInt32 pDatLen); + + [DllImport("Prodave6.dll")] //200系列PLC 任意区写入操作 + //参数:要写入的区类型、data block号(DB区特有,默认为0)、起始地址号、需要写入类型的数量、 + //缓冲区长度(字节为单位)、缓冲区 + public static extern int as200_field_write_ex6(FieldType FType, UInt16 BlkNr, UInt16 StartNr, UInt32 pAmount, + UInt32 BufLen, + byte[] pBuffer); + + [DllImport("Prodave6.dll")] //200系列PLC M区某字节的某位读取操作 + //参数:M区字节号、位号、当前的值(0/1) + public static extern int as200_mb_bittest_ex6(UInt16 MbNr, UInt16 BitNr, ref int pValue); + + [DllImport("Prodave6.dll")] //200系列PLC M区某字节的某位写入操作 + //参数:M区字节号、位号、要写入的值(0/1) + public static extern int as200_mb_setbit_ex6(UInt16 MbNr, UInt16 BitNr, byte Value); + + #endregion + + #region PLC数据转换函数 + + [DllImport("Prodave6.dll")] //诊断错误信息操作 + //参数:错误代号、缓冲区大小(字节为单位)、缓冲区 + public static extern int GetErrorMessage_ex6(int ErrorNr, UInt32 BufLen, + byte[] pBuffer); + + [DllImport("Prodave6.dll")] //S7浮点数转换成PC浮点数 + //参数:S7浮点数、PC浮点数 + public static extern int gp_2_float_ex6(UInt32 gp, ref float pieee); + + [DllImport("Prodave6.dll")] //PC浮点数转换成S7浮点数 + //参数:PC浮点数、S7浮点数 + public static extern int float_2_gp_ex6(float ieee, ref UInt32 pgp); + + [DllImport("Prodave6.dll")] //检测某字节的某位的值是0或1 + //参数:字节值、位号 + public static extern int testbit_ex6(byte Value, int BitNr); + + [DllImport("Prodave6.dll")] //检测某字节的byte值转换成int数组 + //参数:byte值、int数组(长度为8) + public static extern void byte_2_bool_ex6(byte Value, int[] pBuffer); + + + [DllImport("Prodave6.dll")] //检测某字节的int数组转换成byte值 + //参数:int数组(长度为8) + public static extern byte bool_2_byte_ex6(int[] pBuffer); + + [DllImport("Prodave6.dll")] //交换数据的高低字节——16位数据 + //参数:待交换的数据 + public static extern UInt16 kf_2_integer_ex6(UInt16 wValue); //16位数据——WORD + + [DllImport("Prodave6.dll")] //交换数据的高低字节——32位数据 + //参数:待交换的数据 + public static extern UInt32 kf_2_long_ex6(UInt32 dwValue); //32位数据——DWORD + + [DllImport("Prodave6.dll")] //交换数据缓冲区的的高低字节区,例如pBuffer[0]与pBuffer[1],pBuffer[2]与pBuffer[3]交换 + //参数:待交换的数据缓冲区,要交换的字节数,如Amount=pBuffer.Length,则交换全部缓冲 + public static extern void swab_buffer_ex6(byte[] pBuffer, UInt32 Amount); + + [DllImport("Prodave6.dll")] //复制数据缓冲区 + //参数:目的数据缓冲区,源数据缓冲区,要复制的数量(字节为单位) + public static extern void copy_buffer_ex6(byte[] pTargetBuffer, byte[] pSourceBuffer, UInt32 Amount); + + [DllImport("Prodave6.dll")] //把二进制数组传换成BCD码的数组——16位数据 + //参数:要处理的数组,要处理的字节数,转换前是否先交换高低字节,转换后是否要交换高低字节 + //InBytechange为1则转换BCD码之前,先交换高低字节 + //OutBytechange为1则转换BCD码之后,再交换高低字节 + //如果InBytechange和OutBytechange都没有置1,则不发生高低位的交换 + //16位数据BCD码值的许可范围是:+999 —— -999 + public static extern void ushort_2_bcd_ex6(UInt16[] pwValues, UInt32 Amount, int InBytechange, int OutBytechange); //16位数据——WORD + + [DllImport("Prodave6.dll")] //把二进制数组传换成BCD码的数组——32位数据 + //参数:要处理的数组,要处理的字节数,转换前是否先交换高低字节,转换后是否要交换高低字节 + //InBytechange为1则转换BCD码之前,先交换高低字节 + //OutBytechange为1则转换BCD码之后,再交换高低字节 + //如果InBytechange和OutBytechange都没有置1,则不发生高低位的交换 + //32位数据BCD码值的许可范围是:+9 999 999 —— -9 999 999 + public static extern void ulong_2_bcd_ex6(UInt32[] pdwValues, UInt32 Amount, int InBytechange, int OutBytechange); //32位数据——DWORD + + [DllImport("Prodave6.dll")] //把BCD码的数组传换成二进制数组——16位数据 + //参数:要处理的数组,要处理的字节数,转换前是否先交换高低字节,转换后是否要交换高低字节 + //InBytechange为1则转换BCD码之前,先交换高低字节 + //OutBytechange为1则转换BCD码之后,再交换高低字节 + //如果InBytechange和OutBytechange都没有置1,则不发生高低位的交换 + //16位数据BCD码值的许可范围是:+999 —— -999 + public static extern void bcd_2_ushort_ex6(UInt16[] pwValues, UInt32 Amount, int InBytechange, int OutBytechange); //16位数据——WORD + + [DllImport("Prodave6.dll")] //把BCD码的数组传换成二进制数组——32位数据 + //参数:要处理的数组,要处理的字节数,转换前是否先交换高低字节,转换后是否要交换高低字节 + //InBytechange为1则转换BCD码之前,先交换高低字节 + //OutBytechange为1则转换BCD码之后,再交换高低字节 + //如果InBytechange和OutBytechange都没有置1,则不发生高低位的交换 + //32位数据BCD码值的许可范围是:+9 999 999 —— -9 999 999 + public static extern void bcd_2_ulong_ex6(UInt32[] pdwValues, UInt32 Amount, int InBytechange, int OutBytechange); //32位数据——DWORD + + [DllImport("Prodave6.dll")] //查看64个连接中哪些被占用,哪些已经建立 + //参数:传输缓冲的字节长度,64位长度的数组(0或1) + public static extern void GetLoadedConnections_ex6(UInt32 BufLen, int[] pBuffer); + + #endregion + + #region 自定义辅助函数 + + public static UInt16 bytes_2_word(byte dbb0, byte dbb1) //将高低2个byte转换成1个word + { + UInt16 dbw0; + dbw0 = (UInt16) (dbb0*256 + dbb1); + return dbw0; + } + + public static UInt32 bytes_2_dword(byte dbb0, byte dbb1, byte dbb2, byte dbb3) //将高低4个byte转换成1个dword + { + UInt32 dbd0; + dbd0 = (UInt32) (dbb0*16777216 + dbb1*65536 + dbb2*256 + dbb3); + return dbd0; + } + + public static UInt32 words_2_dword(UInt16 dbw0, UInt16 dbw2) //将高低2个word转换成1个dword + { + UInt32 dbd0; + dbd0 = (UInt32) (dbw0*65536 + dbw2); + return dbd0; + } + + public static byte[] word_2_bytes(UInt16 dbw0) //将word拆分为2个byte + { + byte[] bytes = new byte[2]; + bytes[0] = (byte) (dbw0/256); + bytes[1] = (byte) (dbw0%256); + return bytes; + } + + public static byte[] dword_2_bytes(UInt32 dbd0) //将dword拆分为4个byte + { + byte[] bytes = new byte[4]; + bytes[0] = (byte) (dbd0/16777216); + dbd0 = dbd0%16777216; + bytes[1] = (byte) (dbd0/65536); + dbd0 = dbd0%65536; + bytes[2] = (byte) (dbd0/256); + bytes[3] = (byte) (dbd0%256); + return bytes; + } + + public static UInt16[] dword_2_words(UInt32 dbd0) //将dword拆分为2个word + { + UInt16[] words = new UInt16[2]; + words[0] = (UInt16) (dbd0/65536); + words[1] = (UInt16) (dbd0%65536); + return words; + } + + #endregion + + } + +} diff --git a/NA200H/ModBus.Net/TCPProtocalLinker.cs b/NA200H/ModBus.Net/TCPProtocalLinker.cs index dfbae9c..3230d97 100644 --- a/NA200H/ModBus.Net/TCPProtocalLinker.cs +++ b/NA200H/ModBus.Net/TCPProtocalLinker.cs @@ -17,6 +17,11 @@ namespace ModBus.Net _socket = new TcpSocket(ConfigurationManager.IP, int.Parse(ConfigurationManager.Port), false); } + protected TcpProtocalLinker(string IP) + { + _socket = new TcpSocket(IP, int.Parse(ConfigurationManager.Port), false); + } + public override byte[] SendReceive(byte[] content) { //接收数据 diff --git a/NA200H/NA200H.UI.Console/Program.cs b/NA200H/NA200H.UI.Console/Program.cs index b3d275b..31fdf64 100644 --- a/NA200H/NA200H.UI.Console/Program.cs +++ b/NA200H/NA200H.UI.Console/Program.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading.Tasks; using ModBus.Net; using System.Reflection; +using ModBus.Net.Prodave; namespace NA200H.UI.ConsoleApp { @@ -12,8 +13,64 @@ namespace NA200H.UI.ConsoleApp { static void Main(string[] args) { + /* + string ip = "192.168.4.247"; + try + { + BaseProtocal wrapper = new ModbusTcpProtocal(ip); + Console.WriteLine("link ip is {0}",ip); + //第一步:先生成一个输入信息的object数组 + object[] inputObjects = new object[] {(byte) 0x11, (byte) 0x01, (short) 0x13, (short) 0x25}; + //第二步:向仪器发送这个信息,并接收信息 + byte[] outputBytes = wrapper.SendReceive(inputObjects); + //第三步:输出信息 + for (int i = 0; i < outputBytes.Length; i++) + { + Console.WriteLine(outputBytes[i]); + } + Console.WriteLine("modbus link success"); + } + catch (Exception) + { + Console.WriteLine("modbus link failed"); + } + Console.Read(); + */ + + + string ip = "192.168.3.246"; + try + { + Console.WriteLine("link ip is {0}",ip); + short ConNr = 63; // First connection;(0 63);(max. 64 connections). + string AccessPoint = "S7ONLINE"; // Default access point——S7ONLINE + Prodave6.CON_TABLE_TYPE ConTable; // Connection table + int ConTableLen = System.Runtime.InteropServices.Marshal.SizeOf(typeof (Prodave6.CON_TABLE_TYPE)); + // Length of the connection table + int RetValue; + string[] splitip = ip.Split('.'); + ConTable.Adr = new byte[] {byte.Parse(splitip[0]), byte.Parse(splitip[1]), byte.Parse(splitip[2]), byte.Parse(splitip[3]), 0, 0}; + ConTable.AdrType = 2; // Type of address: MPI/PB (1), IP (2), MAC (3) + ConTable.SlotNr = 2; // 插槽号 + ConTable.RackNr = 0; // 机架号 + RetValue = Prodave6.LoadConnection_ex6(ConNr, AccessPoint, ConTableLen, ref ConTable); + if (RetValue > 0) throw new Exception(); + //以下测试SetActiveConnection_ex6 + UInt16 UConNr = (UInt16) ConNr; + RetValue = Prodave6.SetActiveConnection_ex6(UConNr); + if (RetValue > 0) throw new Exception(); + Console.WriteLine("prodave link success"); + } + catch (Exception) + { + Console.WriteLine("prodave link failed"); + } + Console.Read(); + + + //先初始化一个协议转换器,这里构造Modbus/Tcp协议。 - BaseProtocal wrapper = new ModbusTcpProtocal(); + /*BaseProtocal wrapper = new ModbusTcpProtocal(); //调用方法一:手动构造 //第一步:先生成一个输入信息的object数组 @@ -53,7 +110,7 @@ namespace NA200H.UI.ConsoleApp Console.Read(); Console.Read(); - ReadHoldRegisterModbusProtocal.ReadHoldRegisterInputStruct readHoldRegisterInputStruct = new ReadHoldRegisterModbusProtocal.ReadHoldRegisterInputStruct(0x11, "MW1", 8); + ReadHoldRegisterModbusProtocal.ReadHoldRegisterInputStruct readHoldRegisterInputStruct = new ReadHoldRegisterModbusProtocal.ReadHoldRegisterInputStruct(0x11, "0", 8); ReadHoldRegisterModbusProtocal.ReadHoldRegisterOutputStruct readHoldRegisterOutputStruct = (ReadHoldRegisterModbusProtocal.ReadHoldRegisterOutputStruct)wrapper.SendReceive(wrapper["ReadHoldRegisterModbusProtocal"], readHoldRegisterInputStruct); for (int i = 0; i < readHoldRegisterOutputStruct.HoldRegisterStatus.Length; i++) { @@ -124,7 +181,60 @@ namespace NA200H.UI.ConsoleApp Console.WriteLine(setSystemTimeOutputStruct.StartAddress); Console.WriteLine(setSystemTimeOutputStruct.WriteCount); Console.Read(); - Console.Read(); + Console.Read();*/ + + /*short ConNr = 63; // First connection;(0 63);(max. 64 connections). + string AccessPoint = "S7ONLINE"; // Default access point——S7ONLINE + Prodave6.CON_TABLE_TYPE ConTable;// Connection table + int ConTableLen = System.Runtime.InteropServices.Marshal.SizeOf(typeof(Prodave6.CON_TABLE_TYPE));// Length of the connection table + int RetValue; + //ConTable.Adr = new byte[] { 115, 238, 36, 68, 0, 0 }; + ConTable.Adr = new byte[] { 192, 168, 3, 246, 0, 0 }; + ConTable.AdrType = 2; // Type of address: MPI/PB (1), IP (2), MAC (3) + ConTable.SlotNr = 2; // 插槽号 + ConTable.RackNr = 0; // 机架号 + RetValue = Prodave6.LoadConnection_ex6(ConNr, AccessPoint, ConTableLen, ref ConTable); + + //以下测试SetActiveConnection_ex6 + UInt16 UConNr = (UInt16)ConNr; + RetValue = Prodave6.SetActiveConnection_ex6(UConNr); + + //以下测试db_write_ex6 + UInt16 BlkNr = 1;//data block号 + Prodave6.DatType DType = Prodave6.DatType.BYTE;//要读取的数据类型 + UInt16 StartNr = 0;//起始地址号 + UInt32 pAmount = 20;//需要读取类型的数量 + UInt32 BufLen = 200;//缓冲区长度(字节为单位) + //参数:data block号、要写入的数据类型、起始地址号、需要写入类型的数量、缓冲区长度(字节为单位)、缓冲区 + byte[] pWriteBuffer = new byte[5]; + for (int i = 0; i < pWriteBuffer.Length; i++) + pWriteBuffer[i] = (byte)(1); + //RetValue = Prodave6.db_write_ex6(BlkNr, DType, StartNr, ref pAmount, BufLen, pWriteBuffer); + + //以下测试db_read_ex6 + //参数:data block号、要读取的数据类型、起始地址号、需要读取类型的数量、缓冲区长度(字节为单位)、 + //缓冲区、缓冲区数据交互的长度 + byte[] pReadBuffer = new byte[200]; + UInt32 pDatLen = 0; + //RetValue = Prodave6.as200_field_read_ex6(Prodave6.FieldType.V, BlkNr, StartNr, pAmount, BufLen, pReadBuffer, + // ref pDatLen); + RetValue = Prodave6.db_read_ex6(BlkNr, DType, StartNr, ref pAmount, BufLen, pReadBuffer, ref pDatLen); + //pBuffer = new byte[300]; + //RetValue = Prodave6.GetErrorMessage_ex6(RetValue, 300, pBuffer); + //s = Encoding.ASCII.GetString(pBuffer); + //以下测试field_read_ex6(测试DB区) + //参数:data block号、要读取的数据类型、起始地址号、需要读取类型的数量、缓冲区长度(字节为单位)、 + //缓冲区、缓冲区数据交互的长度 + Prodave6.FieldType FType = Prodave6.FieldType.E; + for (int i = 0; i < pWriteBuffer.Length; i++) + pWriteBuffer[i] = (byte)(1); + + RetValue = Prodave6.field_read_ex6(FType, BlkNr, StartNr, pAmount, BufLen, pReadBuffer, ref pDatLen); + + RetValue = Prodave6.field_write_ex6(FType, BlkNr, StartNr, pAmount, BufLen, pWriteBuffer); + + RetValue = Prodave6.field_read_ex6(FType, BlkNr, StartNr, pAmount, BufLen, pReadBuffer, ref pDatLen);*/ + } } }