using HH.WCS.Mobox3.DSZSH.api;
|
using Newtonsoft.Json.Linq;
|
using S7.Net;
|
using S7.Net.Types;
|
using System;
|
using System.Collections;
|
using System.Collections.Generic;
|
using System.Linq;
|
using System.Text;
|
using System.Threading.Tasks;
|
using System.Web.Services.Description;
|
|
namespace HH.WCS.Mobox3.DSZSH.device
|
{
|
|
/// <summary>
|
/// 西门子plc
|
/// </summary>
|
public class S7Helper
|
{
|
public static Dictionary<string, Plc> ip_Plc = new Dictionary<string, Plc>();//内存,连接上的PLC通讯对象
|
|
public S7Helper(string ip, short rack, short slot)
|
{
|
Init(new S7ConfigModel() { Ip = ip, Rack = rack, Slot = slot, CpuType = CpuType.S71500 });
|
}
|
|
/// <summary>
|
/// S7启动初始化
|
/// </summary>
|
public static void Init(S7ConfigModel s7ConfigInfo)
|
{
|
//配置文件读取所有的plc进行初始化
|
try
|
{
|
if (s7ConfigInfo == null)
|
{
|
//读取配置信息失败
|
return;
|
}
|
|
var plc = new Plc(s7ConfigInfo.CpuType, s7ConfigInfo.Ip, s7ConfigInfo.Rack, s7ConfigInfo.Slot);
|
ip_Plc.Add(s7ConfigInfo.Ip, plc);
|
Link(plc);
|
}
|
catch (Exception ex)
|
{
|
LogHelper.Info($"{ex.Message}\r\n{ex.StackTrace}");
|
}
|
}
|
|
/// <summary>
|
/// 重连
|
/// </summary>
|
public static void RestLink()
|
{
|
if (ip_Plc.Count>0)
|
{
|
foreach (var item in ip_Plc)
|
{
|
if(!item.Value.IsConnected)
|
{
|
Link(item.Value);
|
}
|
}
|
}
|
}
|
|
|
/// <summary>
|
/// 连接PLC
|
/// </summary>
|
/// <param name="plc"></param>
|
private static void Link(Plc plc)
|
{
|
try
|
{
|
plc.Close();
|
plc.Open();
|
if (plc.IsConnected)
|
{
|
LogHelper.Info($"连接上{plc.IP}");//连接上
|
}
|
else
|
{
|
LogHelper.Info($"没连上{plc.IP}");//没连上
|
}
|
}
|
catch (Exception ex)
|
{
|
LogHelper.Info($"{ex.Message}\r\n{ex.StackTrace}");
|
}
|
}
|
|
/// <summary>
|
/// 批量读取或单独读取DB块数据(8位byte),并转换成字符串形式
|
/// </summary>
|
/// <param name="deviceIp">plc设备通讯地址</param>
|
/// <param name="dbNo">DB块号</param>
|
/// <param name="startByteAdr">起始byte地址,最小值0,1=8位=1个Block</param>
|
/// <param name="count">读取的个数,1个=8位十六进制数</param>
|
/// <returns></returns>
|
public static string ReadString(string deviceIp, int dbNo, int startByteAdr, int count)
|
{
|
string result = "";
|
try
|
{
|
var plc = GetPlc(deviceIp);
|
if (plc != null)
|
{
|
if (plc.IsConnected)
|
{
|
var data = plc.ReadBytes(DataType.DataBlock, dbNo, startByteAdr, count);
|
result = System.Text.Encoding.UTF8.GetString(data).TrimEnd('\0').TrimEnd('\n').TrimEnd('\r'); ;//此方法可以把byte数组转换成字符串,但是会造成\0\u结束符不显示,需要下位机正确的数据
|
if (result == string.Empty)
|
{
|
Link(plc);//设备发送的数据为空,重连
|
}
|
}
|
else
|
{
|
Link(plc);//设备未连接,重连
|
}
|
}
|
else
|
{
|
LogHelper.Info($"不存在的设备。配置文件中是否包含其设备。");//不存在的设备。配置文件中是否包含其设备。
|
}
|
|
}
|
catch (Exception ex)
|
{
|
LogHelper.Info($"{ex.Message}\r\n{ex.StackTrace}");
|
}
|
return result;
|
}
|
|
/// <summary>
|
/// 批量写入或单独写入DB块数据(8位byte),以字符串转换byte形式写入
|
/// </summary>
|
/// <param name="deviceIp">plc设备通讯地址</param>
|
/// <param name="dbNo">DB块号</param>
|
/// <param name="startByteAdr">起始byte地址,最小值0,1=8位=1个Block</param>
|
/// <param name="data">要写入的数据</param>
|
/// <returns></returns>
|
public static bool WriteString(string deviceIp, int dbNo, int startByteAdr, string data)
|
{
|
var result = false;
|
try
|
{
|
var plc = GetPlc(deviceIp);
|
if (plc != null)
|
{
|
if (plc.IsConnected)
|
{
|
byte[] bytes = System.Text.Encoding.UTF8.GetBytes(data);
|
plc.WriteBytes(DataType.DataBlock, dbNo, startByteAdr, bytes);
|
|
if (!result)
|
{
|
//写完再读一次确认
|
var readData = ReadString(deviceIp, dbNo, startByteAdr, data.Length);
|
result = readData == data;
|
}
|
}
|
else
|
{
|
Link(plc);//设备未连接,重连
|
}
|
}
|
else
|
{
|
//不存在的设备。配置文件中是否包含其设备。
|
}
|
|
}
|
catch (Exception ex)
|
{
|
LogHelper.Info($"{ex.Message}\r\n{ex.StackTrace}");
|
}
|
return result;
|
}
|
|
/// <summary>
|
/// 批量读取或单独读取DB块数据(8位byte)
|
/// </summary>
|
/// <param name="deviceIp">plc设备通讯地址</param>
|
/// <param name="dbNo">DB块号</param>
|
/// <param name="startByteAdr">起始byte地址,最小值0,1=8位=1个Block</param>
|
/// <param name="count">读取的个数,1个=8位十六进制数</param>
|
/// <returns></returns>
|
public static byte[] ReadBytes(string deviceIp, int dbNo, int startByteAdr, int count)
|
{
|
byte[] result = null;
|
try
|
{
|
var plc = GetPlc(deviceIp);
|
if (plc != null)
|
{
|
if (plc.IsConnected)
|
{
|
result = plc.ReadBytes(DataType.DataBlock, dbNo, startByteAdr, count);
|
|
if (result.Length == 0)
|
{
|
Link(plc);//设备发送的数据为空,重连
|
}
|
}
|
else
|
{
|
Link(plc);//设备未连接,重连
|
}
|
}
|
else
|
{
|
LogHelper.Info($"不存在的设备。配置文件中是否包含其设备。");//不存在的设备。配置文件中是否包含其设备。
|
}
|
|
}
|
catch (Exception ex)
|
{
|
LogHelper.Info($"{ex.Message}\r\n{ex.StackTrace}");
|
}
|
return result;
|
}
|
|
/// <summary>
|
/// 批量写入或单独写入DB块数据(8位byte)
|
/// </summary>
|
/// <param name="deviceIp">plc设备通讯地址</param>
|
/// <param name="dbNo">DB块号</param>
|
/// <param name="startByteAdr">起始byte地址,最小值0,1=8位=1个Block</param>
|
/// <param name="data">要写入的数据</param>
|
/// <returns></returns>
|
public static bool WriteBytes(string deviceIp, int dbNo, int startByteAdr, byte[] data)
|
{
|
var result = false;
|
try
|
{
|
var plc = GetPlc(deviceIp);
|
if (plc != null)
|
{
|
if (plc.IsConnected)
|
{
|
plc.WriteBytes(DataType.DataBlock, dbNo, startByteAdr, data);
|
|
if (!result)
|
{
|
//写完再读一次确认
|
var readData = ReadBytes(deviceIp, dbNo, startByteAdr, data.Length);
|
result = readData.SequenceEqual(data);
|
}
|
}
|
else
|
{
|
Link(plc);//设备未连接,重连
|
}
|
}
|
else
|
{
|
LogHelper.Info($"不存在的设备。配置文件中是否包含其设备。");//不存在的设备。配置文件中是否包含其设备。
|
}
|
|
}
|
catch (Exception ex)
|
{
|
LogHelper.Info($"{ex.Message}\r\n{ex.StackTrace}");
|
}
|
return result;
|
}
|
|
/// <summary>
|
/// 批量读取或单独读取DB块数据(1位bit)
|
/// </summary>
|
/// <param name="deviceIp">plc设备通讯地址</param>
|
/// <param name="dbNo">DB块号</param>
|
/// <param name="startByteAdr">起始byte地址,最小值0,1=8位=1个Block</param>
|
/// <param name="count">要读取多少位</param>
|
/// <param name="bitAdr">从第几位开始读取</param>
|
/// <returns></returns>
|
public static BitArray ReadBits(string deviceIp, int dbNo, int startByteAdr, int count, byte bitAdr = 0)
|
{
|
BitArray result = null;
|
try
|
{
|
var plc = GetPlc(deviceIp);
|
if (plc != null)
|
{
|
if (plc.IsConnected)
|
{
|
var data = plc.Read(DataType.DataBlock, dbNo, startByteAdr, VarType.Bit, count, bitAdr);
|
if (count == 1)
|
{
|
result = new BitArray(new bool[] { (bool)data });
|
}
|
else
|
{
|
result = (BitArray)data;
|
}
|
if (result.Length == 0)
|
{
|
Link(plc);//设备发送的数据为空,重连
|
}
|
}
|
else
|
{
|
Link(plc);//设备未连接,重连
|
}
|
}
|
else
|
{
|
LogHelper.Info($"不存在的设备。配置文件中是否包含其设备。");//不存在的设备。配置文件中是否包含其设备。
|
}
|
|
}
|
catch (Exception ex)
|
{
|
LogHelper.Info($"{ex.Message}\r\n{ex.StackTrace}");
|
}
|
return result;
|
}
|
|
/// <summary>
|
/// 批量写入或单独写入DB块数据(1位bit)
|
/// </summary>
|
/// <param name="deviceIp">plc设备通讯地址</param>
|
/// <param name="dbNo">DB块号</param>
|
/// <param name="startByteAdr">起始byte地址,最小值0,1=8位=1个Block</param>
|
/// <param name="biteAdr">起始bit地址,从第几位开始写k</param>
|
/// <param name="bitValue">要写入的数据</param>
|
/// <returns></returns>
|
public static bool WriteBits(string deviceIp, int dbNo, int startByteAdr, byte biteAdr, BitArray bitValue)
|
{
|
var result = false;
|
try
|
{
|
var plc = GetPlc(deviceIp);
|
if (plc != null)
|
{
|
if (plc.IsConnected)
|
{
|
for (int i = 0; i < bitValue.Length; i++)
|
{
|
plc.WriteBit(DataType.DataBlock, dbNo, startByteAdr, biteAdr + i, bitValue[i]);
|
}
|
|
if (!result)
|
{
|
//写完再读一次确认
|
var readData = ReadBits(deviceIp, dbNo, startByteAdr, bitValue.Length, biteAdr);
|
result = CompareBitArray(readData, bitValue);
|
}
|
}
|
else
|
{
|
Link(plc);//设备未连接,重连
|
}
|
}
|
else
|
{
|
LogHelper.Info($"不存在的设备。配置文件中是否包含其设备。");//不存在的设备。配置文件中是否包含其设备。
|
}
|
|
}
|
catch (Exception ex)
|
{
|
LogHelper.Info($"{ex.Message}\r\n{ex.StackTrace}");
|
}
|
return result;
|
}
|
|
/// <summary>
|
/// 获取PLC读写对象
|
/// </summary>
|
/// <param name="plc"></param>
|
/// <returns></returns>
|
private static Plc GetPlc(string plc)
|
{
|
if (ip_Plc.ContainsKey(plc))
|
{
|
return ip_Plc[plc];
|
}
|
else
|
{
|
return null;
|
}
|
}
|
|
/// <summary>
|
/// 比较两个二进制的数值是否相同
|
/// </summary>
|
/// <param name="b1"></param>
|
/// <param name="b2"></param>
|
/// <returns></returns>
|
private static bool CompareBitArray(BitArray b1, BitArray b2)
|
{
|
bool result = true;
|
b1.Xor(b2).Not();//异或操作 然后 非操作
|
|
foreach (var item in b1)
|
{
|
if (!(bool)item)
|
{
|
result = false;
|
break;
|
}
|
}
|
return result;
|
}
|
|
/// <summary>
|
/// 通过S7协议连接下位机时需要的model,应该放在model层,这里我懒了
|
/// </summary>
|
public class S7ConfigModel
|
{
|
public CpuType CpuType { set; get; }//协议类型
|
public string Ip { set; get; }//IP地址
|
public short Rack { set; get; }//架子号
|
public short Slot { set; get; }//插槽号
|
}
|
|
}
|
}
|