PLC通讯实现-C#实现AB5000 PLC以太网通讯DTL32(八)
程序员文章站
2024-03-17 12:13:16
...
背景
本人近十年的工作都与工业软件相关、其中工控系统开发过程中有一个必要环节就是跟各大厂商的PLC进行通讯,而对于从互联网行业跨入工业互联网行业的从业人员来说要实现各型号PLC通讯还是需要一个过程的,本人在此对主流型号PLC通讯实现进行总结以便大家参考。
抽象设计
首先我们要进行一下抽象设计,先设计一个抽象类(接口也可以,此处因为还有其他业务使用了抽象类)BaseEquip,对PLC的常规操作进行定义,即Open、Read、Write、Close,业务代码调用BaseEquip进行PLC的读写,然后在实现各型号的Equip类,对Open、Read、Write、Close进行实现,根据配置在业务代码中对BaseEquip进行实例化,这样后期更改PLC型号后,只需修改配置即可,不用修改业务代码。
#AB5000以太网通讯实现DTL32
实现语言C#
抽象基类BaseEquip
public class BaseEquip
{
/// <summary>
/// 打开设备
/// </summary>
/// <returns>成功返回true,失败返回false</returns>
public abstract bool Open();
/// <summary>
/// 读取信息
/// </summary>
/// <param name="block">数据块</param>
/// <param name="start">起始地址</param>
/// <param name="len">长度</param>
/// <param name="buff">读取返回信息</param>
/// <returns>成功返回true,失败返回false</returns>
public abstract bool Read(string block, int start, int len, out object[] buff);
/// <summary>
/// 写入信息
/// </summary>
/// <param name="block">数据块</param>
/// <param name="start">起始地址</param>
/// <param name="buff">要写入的数据</param>
/// <returns>成功返回true,失败返回false</returns>
public abstract bool Write(int block, int start, object[] buff);
/// <summary>
/// 关闭设备
/// </summary>
public abstract void Close();
}
设备实现类Equip实现
using System;
using System.IO;
using Mesnac.Equips;
using Mesnac.Equips.BaseInfo;
using System.Runtime.InteropServices;
namespace Mesnac.Equip.AllenBradley.AB5000.Net
{
public class Equip : BaseEquip
{
private IntPtr structToIntPtr<T>(T[] lst)
{
int nSizeOfT = Marshal.SizeOf(typeof(T));
int nSizeOfIntPtr = Marshal.SizeOf(typeof(IntPtr));
IntPtr Result = Marshal.AllocHGlobal(nSizeOfIntPtr * lst.Length);
for (int i = 0; i < lst.Length; i++)
{
Marshal.StructureToPtr(lst[i], (IntPtr)((UInt32)Result + i * nSizeOfIntPtr), true);
}
return Result;
}
private T[] IntPtrTostruct<T>(IntPtr p, T[] lst)
{
int nSizeOfIntPtr = Marshal.SizeOf(typeof(IntPtr));
for (int i = 0; i < lst.Length; i++)
{
T r = (T)Marshal.PtrToStructure((IntPtr)((UInt32)p + i * nSizeOfIntPtr), typeof(T));
lst[i] = r;
}
return lst;
}
private string getDriveNameFileFullName()
{
return Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Log", "AB5000.DriverName.bin");
}
private void saveDriveName(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return;
}
string path = getDriveNameFileFullName();
FileInfo fi = new FileInfo(path);
if (!fi.Directory.Exists)
{
fi.Directory.Create();
}
if (fi.Exists)
{
fi.Delete();
}
System.IO.StreamWriter sw = new System.IO.StreamWriter(fi.FullName, false);
sw.WriteLine(name);
sw.Close();
}
private string getDriveName()
{
string path = getDriveNameFileFullName();
FileInfo fi = new FileInfo(path);
if (!fi.Directory.Exists)
{
fi.Directory.Create();
}
if (!fi.Exists)
{
return string.Empty;
}
System.IO.StreamReader sw = new System.IO.StreamReader(fi.FullName);
string ss = sw.ReadToEnd();
sw.Close();
return ss;
}
public override bool Open()
{
lock (this)
{
getIP();
this.State = false;
ICSharpCode.Core.LoggingService.Info("DTL_INIT");
int iResult = 0;
uint id = 0;
iResult = DTL32.DTL_INIT(2048);
ICSharpCode.Core.LoggingService.Info("DTL_INIT Result=" + iResult.ToString());
if ((iResult != 0) && (iResult != 39)) // 39已经初始化
{
this.State = false;
return this.State;
}
string driveName = getDriveName();
if (string.IsNullOrWhiteSpace(driveName))
{
ICSharpCode.Core.LoggingService.Info("get szDriverName");
uint drivers = 0;
DTL32.DtlDriver[] dtlDriver = new DTL32.DtlDriver[16];
IntPtr pDriver = structToIntPtr<DTL32.DtlDriver>(dtlDriver);
ICSharpCode.Core.LoggingService.Info("DTL_DRIVER_LIST");
iResult = DTL32.DTL_DRIVER_LIST(pDriver, ref drivers, 1000);
ICSharpCode.Core.LoggingService.Info("DTL_DRIVER_LIST Result=" + iResult.ToString());
dtlDriver = IntPtrTostruct<DTL32.DtlDriver>(pDriver, dtlDriver);
ICSharpCode.Core.LoggingService.Info("IntPtrTostruct");
driveName = new string(dtlDriver[id].szDriverName);
ICSharpCode.Core.LoggingService.Info("szDriverName=" + driveName);
saveDriveName(driveName);
Marshal.FreeHGlobal(pDriver);
ICSharpCode.Core.LoggingService.Info("FreeHGlobal");
if ((iResult != 0))
{
this.State = false;
return this.State;
}
}
iResult = DTL32.DTL_DRIVER_OPEN(id, driveName, 5000);
ICSharpCode.Core.LoggingService.Info("DTL_DRIVER_OPEN Result=" + iResult.ToString());
if ((iResult == 0) || (iResult == 47)) // 47已经连接上
{
this.State = true;
}
return this.State;
}
}
private string getIP()
{
string result = string.Empty;
string ip = ((Mesnac.Equips.Connection.Net.ConnType)this.Main.ConnType).IP;
int iplen = ip.Length;
if (ip.Length % 2 != 0)
{
iplen++;
}
result = iplen.ToString();
foreach (char s in ip)
{
result += "." + Convert.ToInt32(s).ToString();
}
if (ip.Length % 2 != 0)
{
result += ".0";
}
return result;
}
public override bool Read(string block, int start, int len, out object[] buff)
{
lock (this)
{
buff = new object[len];
if (!this.Open())
{
return false;
}
int state = 0;
ushort[] _buff = new ushort[len];
string ss = "$N" + block.ToString() + ":" + start.ToString() + "," +
len.ToString() + ",WORD,READ,AB:CIP,16." + getIP() + ".1.0,PLC5,0";
ICSharpCode.Core.LoggingService.Info("DTL_C_DEFINE=" + ss);
uint id = 0;
int iResult = DTL32.DTL_C_DEFINE(ref id, ss);
ICSharpCode.Core.LoggingService.Info("DTL_C_DEFINE Result=" + iResult.ToString());
if (iResult != 0)
{
return false;
}
iResult = DTL32.DTL_READ_W(id, _buff, ref state, 1000);
ICSharpCode.Core.LoggingService.Info("DTL_READ_W Result=" + iResult.ToString());
DTL32.DTL_UNDEF(id);
if (iResult != 0)
{
return false;
}
for (int i = 0; i < len; i++)
{
int value = _buff[i];
if (value > ushort.MaxValue)
{
value = ushort.MaxValue - value;
}
buff[i] = value;
}
ICSharpCode.Core.LoggingService.Info("Read True");
return true;
}
}
private ushort ToValue(object obj, ushort defaultValue)
{
ushort result = 0;
if (obj != null
&& obj != DBNull.Value
&& ushort.TryParse(obj.ToString(), out result))
{
return result;
}
return defaultValue;
}
public override bool Write(int block, int start, object[] buff)
{
lock (this)
{
if (buff.Length == 0)
{
return true;
}
ICSharpCode.Core.LoggingService.Info("Open");
if (!this.Open())
{
return false;
}
int state = 0;
ushort[] _buff = new ushort[buff.Length];
for (int i = 0; i < buff.Length; i++)
{
_buff[i] = ToValue(buff[i], 0);
}
string ss = "$N" + block.ToString() + ":" + start.ToString() + "," +
buff.Length.ToString() + ",WORD,MODIFY,AB:CIP,16." + getIP() + ".1.0,PLC5,0";
uint id = 0;
int iResult = DTL32.DTL_C_DEFINE(ref id, ss);
if (iResult != 0)
{
return false;
}
iResult = DTL32.DTL_WRITE_W(id, _buff, ref state, 1000);
DTL32.DTL_UNDEF(id);
if (iResult != 0)
{
return false;
}
return true;
}
}
public override void Close()
{
lock (this)
{
try
{
DTL32.DTL_UNINIT(0);
DTL32.DTL_UNDEF(0);
DTL32.DTL_DRIVER_CLOSE(0, 100);
}
catch
{
}
}
}
}
}
DTL32类定义
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
namespace Mesnac.Equip.AllenBradley.AB5000.Net
{
public class DTL32
{
public struct DtlDriver
{
public ushort wType;
public ushort wLength;
public ushort wMfgMask;
public ushort wNetworkType;
public ushort wDriverID;
public ushort wDstDriverID;
public uint dwHandle;
public uint dwStation;
public uint dwMaxStation;
public ushort wCapabilities;
public ushort wMTU;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public char[] szDriverName;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
public char[] szDriverAlias;
public byte bAddrRadix;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] bReserved;
}
private class DllImport
{
[DllImport("DTL32.dll")]
public extern static int DTL_INIT(uint id);
[DllImport("DTL32.dll")]
public extern static int DTL_UNINIT(uint dwError);
[DllImport("DTL32.dll")]
public extern static int DTL_DRIVER_LIST(IntPtr dtlDriver, ref uint drivers, int timeout);
[DllImport("DTL32.dll")]
public extern static int DTL_DRIVER_OPEN(uint id, string name, int timeout);
[DllImport("DTL32.dll")]
public extern static int DTL_DRIVER_CLOSE(uint id, int timeout);
[DllImport("DTL32.dll")]
public extern static int DTL_C_DEFINE(ref uint id, StringBuilder defString);
[DllImport("DTL32.dll")]
public extern static int DTL_UNDEF(uint id);
[DllImport("DTL32.dll")]
public extern static int DTL_READ_W(uint name_id, ushort[] buff, ref int state, int timeout);
[DllImport("DTL32.dll")]
public extern static int DTL_WRITE_W(uint name_id, ushort[] buff, ref int state, int timeout);
}
public static int DTL_INIT(uint tableSize)
{
new UIPermission(UIPermissionWindow.AllWindows).Demand();
return DllImport.DTL_INIT(tableSize);
}
public static int DTL_UNINIT(uint dwError)
{
new UIPermission(UIPermissionWindow.AllWindows).Demand();
return DllImport.DTL_UNINIT(dwError);
}
public static int DTL_DRIVER_LIST(IntPtr dtlDriver, ref uint drivers, int timeout)
{
new UIPermission(UIPermissionWindow.AllWindows).Demand();
return DllImport.DTL_DRIVER_LIST(dtlDriver, ref drivers, timeout);
}
public static int DTL_DRIVER_OPEN(uint id, string name, int timeout)
{
new UIPermission(UIPermissionWindow.AllWindows).Demand();
return DllImport.DTL_DRIVER_OPEN(id, name, timeout);
}
public static int DTL_DRIVER_CLOSE(uint id, int timeout)
{
new UIPermission(UIPermissionWindow.AllWindows).Demand();
return DllImport.DTL_DRIVER_CLOSE(id, timeout);
}
public static int DTL_C_DEFINE(ref uint id, string defString)
{
new UIPermission(UIPermissionWindow.AllWindows).Demand();
StringBuilder def = new StringBuilder();
def.Append(defString);
return DllImport.DTL_C_DEFINE(ref id, def);
}
public static int DTL_UNDEF(uint id)
{
new UIPermission(UIPermissionWindow.AllWindows).Demand();
return DllImport.DTL_UNDEF(id);
}
public static int DTL_READ_W(uint name_id, ushort[] buff, ref int state, int timeout)
{
new UIPermission(UIPermissionWindow.AllWindows).Demand();
return DllImport.DTL_READ_W(name_id, buff, ref state, timeout);
}
public static int DTL_WRITE_W(uint name_id, ushort[] buff, ref int state, int timeout)
{
new UIPermission(UIPermissionWindow.AllWindows).Demand();
return DllImport.DTL_WRITE_W(name_id, buff, ref state, timeout);
}
}
}