using HH.WCS.Mobox3.FJJT.api;
using HH.WCS.Mobox3.FJJT.util;
using Newtonsoft.Json.Linq;
using S7.Net;
using S7.Net.Types;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Services.Description;
using static HH.WCS.Mobox3.FJJT.util.Settings;
namespace HH.WCS.Mobox3.FJJT.device
{
///
/// 西门子plc
///
public class S7Helper
{
private static bool debug = true;
private static S7.Net.Plc plc = null;
static S7Helper()
{
Init();
}
private static Dictionary plcDic = new Dictionary();
private static void Init()
{
//配置文件读取所有的plc进行初始化
try
{
var plc1 = new Plc(CpuType.S71500, "", 0, 1);
plcDic.Add("plc1", plc1);
Link(plc1);
}
catch (Exception ex)
{
Console.WriteLine("S7Helper Init err=" + ex.Message);
}
}
private static Plc GetPlc(string plc)
{
if (plcDic.ContainsKey(plc))
{
return plcDic[plc];
}
else
{
return null;
}
}
public static Dictionary s7TestData = new Dictionary();
private static void Link(Plc plc)
{
try
{
//if (!plc.IsConnected) {
plc.Close();
plc.Open();
if (plc.IsConnected)
{
Console.WriteLine($"已连接到plc{plc.IP}");
}
else
{
Console.WriteLine($"plc{plc.IP}连接失败");
LogHelper.Info($"plc{plc.IP}连接失败", "Plc");
}
//}
}
catch (Exception ex)
{
Console.WriteLine($"plc{plc.IP}连接失败,err={ex.Message}");
LogHelper.Info($"plc{plc.IP}连接失败,err={ex.Message}");
//Init();
}
}
//https://www.ad.siemens.com.cn/productportal/Prods/S7-1200_PLC_EASY_PLUS/SmartSMS/060.html
//https://www.ad.siemens.com.cn/productportal/Prods/S7-1200_PLC_EASY_PLUS/07-Program/02-basic/01-Data_Type/09-String.html
internal static short[] ReadInt(string device, int db, int byteAddr, int count)
{
short[] result = null;
try
{
if (debug)
{
var s7Key = $"int_{db}_{byteAddr}_{count}";
if (s7TestData.ContainsKey(s7Key))
{
var data = s7TestData[s7Key].Split(',');
if (data.Length == count)
{
result = Array.ConvertAll(data, s => short.Parse(s));
}
else
{
result = new short[count];
s7TestData[s7Key] = string.Join(",", result);
}
Console.WriteLine($"读取plc {device}信息成功, addr={byteAddr} data={string.Join(",", result)}");
}
}
else
{
var plc = GetPlc(device);
if (plc != null)
{
if (plc.IsConnected)
{
result = (short[])plc.Read(DataType.DataBlock, db, byteAddr, VarType.Int, count, 0);
Console.WriteLine($"读取plc {device}信息成功,ip={plc.IP} addr={byteAddr} data={string.Join(",", result)}");
if (result.Length == 0)
{
Console.WriteLine($"plc {device}准备重新连接");
Link(plc);
}
}
else
{
Console.WriteLine($"准备连接plc {device}");
Link(plc);
}
}
else
{
Console.WriteLine($"plc {device}不存在");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"ReadInt,device={device} addr={byteAddr} count={count} err={ex.Message}");
LogHelper.Error($"ReadInt,device={device} addr={byteAddr} count={count} err={ex.Message}", ex);
}
return result;
}
///
///
///
///
///
///
///
internal static bool WriteInt(int db, int byteAddr, short data)
{
var result = false;
try
{
if (plc.IsConnected)
{
plc.Write(DataType.DataBlock, db, byteAddr, data);
Console.WriteLine($"写入plc信息,ip={plc.IP} addr={byteAddr} data={data} ");
LogHelper.Info($"写入plc信息,ip={plc.IP} addr={byteAddr} data={data} ");
if (result)
{
//写完再读一次确认
var readData = (short)plc.Read(DataType.DataBlock, db, byteAddr, VarType.Int, 1, 0);
Console.WriteLine($"读取plc信息,ip={plc.IP} addr={byteAddr} data={data} res={string.Join(", ", readData)}");
LogHelper.Info($"读取plc信息,ip={plc.IP} addr={byteAddr} data={data} res={string.Join(", ", readData)}", "PLC");
result = readData == data;
}
}
else
{
Console.WriteLine("准备连接plc1");
Link(plc);
}
}
catch (Exception ex)
{
LogHelper.Error($"写入plc1信息失败,ip={plc.IP} addr={byteAddr} data={data} err={ex.Message}", ex);
}
return result;
}
public static object ReadBit(string device, int db, int byteAddr, byte bitAddr)
{
object result = null;
try
{
if (debug)
{
var s7Key = $"bit_{db}_{byteAddr}_{bitAddr}";
if (s7TestData.ContainsKey(s7Key))
{
var data = s7TestData[s7Key];
if (data == "1")
{
result = true;
}
else { result = false; }
Console.WriteLine($"读取plc {device}信息成功, addr={byteAddr} data={result.ToString()}");
}
}
else
{
var plc = GetPlc(device);
if (plc != null)
{
if (plc.IsConnected)
{
result = plc.Read(DataType.DataBlock, db, byteAddr, VarType.Int, 1, bitAddr);
Console.WriteLine($"读取plc {device}信息成功,ip={plc.IP} addr={byteAddr} data={result.ToString()}");
}
else
{
Console.WriteLine($"准备连接plc {device}");
Link(plc);
}
}
else
{
Console.WriteLine($"plc {device}不存在");
}
}
}
catch (Exception ex)
{
Console.WriteLine($"ReadBit,device={device} addr={byteAddr} bit={bitAddr} err={ex.Message}");
LogHelper.Error($"ReadBit,device={device} addr={byteAddr} bit={bitAddr} err={ex.Message}", ex);
}
return result;
}
public static string ReadStr(string device, int db, int byteAddr, int count)
{
string result = string.Empty;
try
{
if (debug)
{
var s7Key = $"str_{db}_{byteAddr}_{count}";
if (s7TestData.ContainsKey(s7Key))
{
var data = s7TestData[s7Key];
if (data.Length == count)
{
result = data;
Console.WriteLine($"ReadStr 成功, addr={byteAddr} res={result}");
}
}
}
else
{
if (plc.IsConnected)
{
result = plc.Read(DataType.DataBlock, 100, byteAddr, VarType.String, count, 0).ToString();
Console.WriteLine($"ReadStr 成功,ip={plc.IP} addr={byteAddr} res={result}");
if (result.Length == 0)
{
Link(plc);
}
}
else
{
Console.WriteLine("准备连接plc");
Link(plc);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"ReadStr,device={device} addr={byteAddr} count={count} err={ex.Message}");
LogHelper.Error($"ReadStr,device={device} addr={byteAddr} count={count} err={ex.Message}", ex);
}
return result;
}
#region 批量写入 读取
///
/// s7写入取值方法
///
public static void Write()
{
var plcInfo = Settings.linePlcInfo.Where(a => (a.deviceNo == "1") && a.enable == 1).FirstOrDefault();
//获取配置文件写入的地址
List writemodels = Settings.plcValue.Find(a => a.address == plcInfo.address).read;
if (writemodels.Count > 0)
{
writemodels.Find(a => a.addr == 0).value = "1";
writemodels.Find(a => a.addr == 2).value = "2";
writemodels.Find(a => a.addr == 4).value = "4";
writemodels.Find(a => a.addr == 18).value = "TP24121108";
byte[] bytes = GetWriteByte(writemodels);
if (PLCWrite(plcInfo, 100, bytes))
{
Console.WriteLine("写入成功");
//写入成功校验数据
Read();
if (Dictvalues[plcInfo.address].Find(a => a.addr == 2).value == "2")
{
Console.WriteLine("数据校验成功,修改任务状态");
}
}
else
{
Console.WriteLine("写入失败");
}
}
}
///
/// 将要写的数据转换成byte
///
///
///
public static byte[] GetWriteByte(List writemodels)
{
var model = writemodels.OrderByDescending(a => a.addr).First();
var readlen = model.addr + model.length;
byte[] bytes = new byte[readlen];
foreach (var item in writemodels)
{
if (!string.IsNullOrEmpty(item.value))
{
//转换byte
switch (item.type)
{
case "Int":
case "Bit":
bytes[item.addr] = (byte)((uint)(int.Parse(item.value) >> 8) & 0xFFu);
bytes[item.addr + 1] = (byte)((uint)(int.Parse(item.value) >> 0) & 0xFFu);
break;
case "DInt":
case "Real":
bytes[item.addr] = (byte)((uint)(int.Parse(item.value) >> 24) & 0xFFu);
bytes[item.addr + 1] = (byte)((uint)(int.Parse(item.value) >> 16) & 0xFFu);
bytes[item.addr + 2] = (byte)((uint)(int.Parse(item.value) >> 8) & 0xFFu);
bytes[item.addr + 3] = (byte)((uint)(int.Parse(item.value) >> 0) & 0xFFu);
break;
case "String":
case "Byte":
var bytevalue = Encoding.UTF8.GetBytes(item.value);
if (bytevalue.Count() <= item.length)
{
for (int i = 0; i < bytevalue.Count(); i++)
{
bytes[item.addr + item.length - bytevalue.Count() + i] = bytevalue[i];
}
}
break;
}
}
}
return bytes;
}
public static Dictionary> Dictvalues = new Dictionary>();
///
/// s7读取方法
///
public static void Read()
{
var plcInfo = Settings.linePlcInfo.Where(a => (a.deviceNo == "1") && a.enable == 1).FirstOrDefault();
var bytes = new byte[0];
//获取配置文件读取的地址
List readmodels = Settings.plcValue.Find(a => a.address == plcInfo.address).read;
if (readmodels.Count > 0)
{
//获取读取长度
var model = readmodels.OrderByDescending(a => a.addr).First();
var readlen = model.addr + model.length;
PLCRead(plcInfo, 100, 0, readlen, out bytes);
//将配置文件配置的偏移量转换存放到字典里
// List s7Values = new List();
foreach (var item in readmodels)
{
//解析数据
string value = "";
switch (item.type)
{
case "Int":
value = GetInt(bytes, item.addr, VarType.Int).ToString();
break;
case "DInt":
value = GetInt(bytes, item.addr, VarType.DInt).ToString();
break;
case "Real":
value = GetInt(bytes, item.addr, VarType.Real).ToString();
break;
case "String":
value = GetString(bytes, item.addr, VarType.String, item.length).ToString();
break;
//case "Byte":
// value = S7Help.GetInt(bytes, item.addr, VarType.Byte,item.length).ToString();
// break;
}
item.value = value;
// s7Values.Add(new S7Value { addr = item.addr, type = item.type, value = value });
}
//数据存入字典
if (Dictvalues.Keys.Contains(plcInfo.address))
{
Dictvalues[plcInfo.address] = readmodels;
}
else
{
Dictvalues.Add(plcInfo.address, readmodels);
}
}
}
///
/// S7写入byte数组
///
/// 配置文件
/// DB块
///
///
public static bool PLCWrite(Settings.LinePlcInfo plcInfo, int db, byte[] bytes)
{
bool result = false;
var plc = new Plc(CpuType.S71500, plcInfo.address, 0, 1);
Link(plc);
try
{
result = plc.WriteBytes(DataType.DataBlock, Convert.ToInt16(db), Convert.ToInt16(plcInfo.writeAddr), bytes) == ErrorCode.NoError;
return result;
}
catch (Exception ex)
{
throw ex;
}
}
///
/// S7读取byte数组
///
/// 配置文件
/// DB块
/// 读取起始偏移量
/// 输出byte
///
public static bool PLCRead(Settings.LinePlcInfo plcInfo, int db, int addr, int len, out byte[] bytes)
{
bool result = false;
var plc = new Plc(CpuType.S71500, plcInfo.address, 0, 1);
Link(plc);
string res = string.Empty;
bytes = new byte[len];
try
{
if (plcInfo != null)
{
bytes = plc.ReadBytes(DataType.DataBlock, Convert.ToInt16(db), Convert.ToInt16(plcInfo.readAddr + addr), len);
var r1 = "new byte[] {" + string.Join(",", bytes) + " }";
res = $" B{db} A{addr} L{len} A{r1}";
}
else
{
res = " 没设备。";
}
}
catch (Exception ex)
{
res = "Err" + ex.Message + ex.StackTrace;
}
// result = plc.WriteBytes(DataType.DataBlock, Convert.ToInt16(1000), Convert.ToInt16(linePlcInfo.writeAddr + 6), bytes) == ErrorCode.NoError;
return result;
}
///
/// 解析堆垛机byte数组int类型
///
/// 偏移量
/// 类型
/// 解析失败调取方法单个读取
///
public static int GetInt(byte[] bytes, int adr, VarType varType, Func action = null)
{
var b = -1;
byte[] by = new byte[0];
by = bytes;
if (by.Count() > 0)
{
b = GetInt(adr, varType, by);
}
if (b == -1 && action != null)
{
b = action();
}
return b;
}
public static int GetInt(int adr, VarType varType, byte[] d, int length = 1)
{
//计算类型长度,string类型为可变长度用配置文件定义的长度
var vlen = VarTypeToByteLength(varType);
if (varType == VarType.String)
{
vlen = length;
}
if (adr + vlen > d.Length)
{
return -1;
}
var adrbyte = d.Skip(adr).Take(vlen).ToArray();
var obj = ParseBytes(varType, adrbyte, 1, 0);
return Convert.ToInt32(obj);
}
///
/// 解析string类型
///
///
///
///
///
///
///
public static string GetString(byte[] bytes, int adr, VarType varType, int count, Func action = null)
{
string b = null;
byte[] by = new byte[0];
by = bytes;
if (by.Count() > 0)
{
b = GetString(adr, varType, by, count);
}
if (string.IsNullOrEmpty(b) && action != null)
{
b = action().ToString();
}
return b;
}
public static string GetString(int adr, VarType varType, byte[] d, int length = 1)
{
//计算类型长度,string类型为可变长度用配置文件定义的长度
var vlen = VarTypeToByteLength(varType);
if (varType == VarType.String)
{
vlen = length;
}
if (adr + vlen > d.Length)
{
return "";
}
var adrbyte = d.Skip(adr).Take(vlen).ToArray();
adrbyte = adrbyte.Skip(adrbyte.ToList().FindIndex(x => x > 0)).ToArray();
var obj = ParseBytes(varType, adrbyte, 1, 0);
return obj.ToString();
}
private static int VarTypeToByteLength(VarType varType, int varCount = 1)
{
switch (varType)
{
case VarType.Bit:
return varCount;
case VarType.Byte:
if (varCount >= 1)
{
return varCount;
}
return 1;
case VarType.String:
return varCount;
case VarType.StringEx:
return varCount + 2;
case VarType.Word:
case VarType.Int:
case VarType.Timer:
case VarType.Counter:
return varCount * 2;
case VarType.DWord:
case VarType.DInt:
case VarType.Real:
return varCount * 4;
default:
return 0;
}
}
private static object ParseBytes(VarType varType, byte[] bytes, int varCount, byte bitAdr = 0)
{
if (bytes == null)
{
return null;
}
switch (varType)
{
case VarType.Byte:
if (varCount == 1)
{
return bytes[0];
}
return bytes;
case VarType.Word:
if (varCount == 1)
{
return Word.FromByteArray(bytes);
}
return Word.ToArray(bytes);
case VarType.Int:
if (varCount == 1)
{
return Int.FromByteArray(bytes);
}
return Int.ToArray(bytes);
case VarType.DWord:
if (varCount == 1)
{
return DWord.FromByteArray(bytes);
}
return DWord.ToArray(bytes);
case VarType.DInt:
if (varCount == 1)
{
return DInt.FromByteArray(bytes);
}
return DInt.ToArray(bytes);
case VarType.Real:
if (varCount == 1)
{
return S7.Net.Types.Double.FromByteArray(bytes);
}
return S7.Net.Types.Double.ToArray(bytes);
case VarType.String:
return S7.Net.Types.String.FromByteArray(bytes);
case VarType.StringEx:
return StringEx.FromByteArray(bytes);
case VarType.Timer:
if (varCount == 1)
{
return S7.Net.Types.Timer.FromByteArray(bytes);
}
return S7.Net.Types.Timer.ToArray(bytes);
case VarType.Counter:
if (varCount == 1)
{
return Counter.FromByteArray(bytes);
}
return Counter.ToArray(bytes);
case VarType.Bit:
if (varCount == 1)
{
if (bitAdr > 7)
{
return null;
}
return Bit.FromByte(bytes[0], bitAdr);
}
return Bit.ToBitArray(bytes);
default:
return null;
}
}
#endregion
#region 用于模拟测试
///
/// short类型,一个占2个byte
///
public class DBWModel
{
public int db { get; set; }
public int byteAddr { get; set; }
///
/// int类型需要用逗号分开,string不需要
///
public string value { get; set; }
}
///
/// 字符串类型,一个占1个byte
///
public class DBBModel
{
public int db { get; set; }
public int byteAddr { get; set; }
public string value { get; set; }
}
public class DBXModel
{
public int db { get; set; }
public int byteAddr { get; set; }
public int bitAddr { get; set; }
///
/// 1:true 0:false
///
public int value { get; set; }
}
public static void s7SetInt(DBWModel model)
{
var data = model.value.Replace(",", "");
var s7Key = $"int_{model.db}_{model.byteAddr}_{data.Length}";
if (s7TestData.ContainsKey(s7Key))
{
s7TestData[s7Key] = model.value;
}
else
{
s7TestData.Add(s7Key, model.value);
}
}
internal static void s7SetBit(DBXModel model)
{
var s7Key = $"bit_{model.db}_{model.byteAddr}_{model.bitAddr}";
var value = model.value == 1 ? "1" : "0";
if (s7TestData.ContainsKey(s7Key))
{
s7TestData[s7Key] = value;
}
else
{
s7TestData.Add(s7Key, value);
}
}
internal static void s7SetStr(DBBModel model)
{
var s7Key = $"str_{model.db}_{model.byteAddr}_{model.value.Length}";
if (s7TestData.ContainsKey(s7Key))
{
s7TestData[s7Key] = model.value;
}
else
{
s7TestData.Add(s7Key, model.value);
}
}
}
#endregion
}