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
{
///
/// 西门子plc
///
public class S7Helper
{
public static Dictionary ip_Plc = new Dictionary();//内存,连接上的PLC通讯对象
public S7Helper(string ip, short rack, short slot)
{
Init(new S7ConfigModel() { Ip = ip, Rack = rack, Slot = slot, CpuType = CpuType.S71500 });
}
///
/// S7启动初始化
///
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}");
}
}
///
/// 重连
///
public static void RestLink()
{
if (ip_Plc.Count>0)
{
foreach (var item in ip_Plc)
{
if(!item.Value.IsConnected)
{
Link(item.Value);
}
}
}
}
///
/// 连接PLC
///
///
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}");
}
}
///
/// 批量读取或单独读取DB块数据(8位byte),并转换成字符串形式
///
/// plc设备通讯地址
/// DB块号
/// 起始byte地址,最小值0,1=8位=1个Block
/// 读取的个数,1个=8位十六进制数
///
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;
}
///
/// 批量写入或单独写入DB块数据(8位byte),以字符串转换byte形式写入
///
/// plc设备通讯地址
/// DB块号
/// 起始byte地址,最小值0,1=8位=1个Block
/// 要写入的数据
///
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;
}
///
/// 批量读取或单独读取DB块数据(8位byte)
///
/// plc设备通讯地址
/// DB块号
/// 起始byte地址,最小值0,1=8位=1个Block
/// 读取的个数,1个=8位十六进制数
///
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;
}
///
/// 批量写入或单独写入DB块数据(8位byte)
///
/// plc设备通讯地址
/// DB块号
/// 起始byte地址,最小值0,1=8位=1个Block
/// 要写入的数据
///
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;
}
///
/// 批量读取或单独读取DB块数据(1位bit)
///
/// plc设备通讯地址
/// DB块号
/// 起始byte地址,最小值0,1=8位=1个Block
/// 要读取多少位
/// 从第几位开始读取
///
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;
}
///
/// 批量写入或单独写入DB块数据(1位bit)
///
/// plc设备通讯地址
/// DB块号
/// 起始byte地址,最小值0,1=8位=1个Block
/// 起始bit地址,从第几位开始写k
/// 要写入的数据
///
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;
}
///
/// 获取PLC读写对象
///
///
///
private static Plc GetPlc(string plc)
{
if (ip_Plc.ContainsKey(plc))
{
return ip_Plc[plc];
}
else
{
return null;
}
}
///
/// 比较两个二进制的数值是否相同
///
///
///
///
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;
}
///
/// 通过S7协议连接下位机时需要的model,应该放在model层,这里我懒了
///
public class S7ConfigModel
{
public CpuType CpuType { set; get; }//协议类型
public string Ip { set; get; }//IP地址
public short Rack { set; get; }//架子号
public short Slot { set; get; }//插槽号
}
}
}