using HH.WCS.EmersonWcs.api;
using HH.WCS.EmersonWcs.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.EmersonWcs.util.Settings;
namespace HH.WCS.EmersonWcs.device
{
///
/// 西门子plc
///
public class S7Helper
{
private static bool debug = true;
private static byte[] Ssxbytes = new byte[0];
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;
}
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.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.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;
}
}
///
/// S7读取byte数组
///
/// 地址
/// DB块
/// 读取起始偏移量
/// 输出byte
///
public static bool PLCRead(string address, int db, int addr, int len, out byte[] bytes)
{
bool result = false;
var plc = new Plc(CpuType.S71500, address, 0, 1);
Link(plc);
string res = string.Empty;
bytes = new byte[len];
try
{
bytes = plc.ReadBytes(DataType.DataBlock, Convert.ToInt16(db), Convert.ToInt16(addr), len);
var r1 = "new byte[] {" + string.Join(",", bytes) + " }";
res = $" B{db} A{addr} L{len} A{r1}";
}
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;
}
///
/// 解析
///
///
///
///
///
///
public static string GetValue(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();
if (varType == VarType.String)
{
adrbyte = adrbyte.Skip(adrbyte.ToList().FindIndex(x => x > 0)).ToArray();
}
var obj = ParseBytes(varType, adrbyte, 1, 0);
return obj.ToString();
}
///
/// 获取输送线数据
///
public static void ReadSsxPLc()
{
#region 测试写入数据
List s7Models = new List();
s7Models.Add(new S7Model() { addr = 0, value = "1", type = "Int", length = 2 });
s7Models.Add(new S7Model() { addr = 2, value = "2", type = "Int", length = 2 });
s7Models.Add(new S7Model() { addr = 4, value = "4", type = "Int", length = 2 });
s7Models.Add(new S7Model() { addr = 18, value = "TP24121108", type = "String", length = 20 });
var plcInfo = Settings.linePlcInfo.Where(a => (a.deviceNo == "2") && a.enable == 1).FirstOrDefault();
Write(s7Models, 100, plcInfo);
#endregion
//获取输送线线体配置文件
var deviceInfos = Settings.ConveyorLinesInfo.Where(a => a.enable == 1).ToList();
if (deviceInfos.Count > 0)
{
var db = new SqlHelper().GetInstance();
var linkplc = Settings.linePlcInfo.Find(a => a.deviceNo == "2");
int len = deviceInfos.Max(a => a.readAddr);
//读取输送线整个偏移量的byte数组 放内存里一起解析,防止过度读取
PLCRead(linkplc.address, 53, 0, len + 38, out Ssxbytes);
foreach (var device in deviceInfos)
{
int targetAddr = int.Parse(GetValue(device.readAddr, VarType.Int, Ssxbytes)); //目标地址
int workMode = int.Parse(GetValue(device.readAddr + 2, VarType.Int, Ssxbytes)); //工作模式
int lightAction = int.Parse(GetValue(device.readAddr + 4, VarType.Int, Ssxbytes)); //是否有货,光电信号
int errorAlarm = int.Parse(GetValue(device.readAddr + 6, VarType.Int, Ssxbytes)); //故障报警
int deviceState = int.Parse(GetValue(device.readAddr + 8, VarType.Int, Ssxbytes)); //设备状态
string TaskNo = GetValue(device.readAddr + 10, VarType.DInt, Ssxbytes); //任务号
int weight = int.Parse(GetValue(device.readAddr + 14, VarType.DInt, Ssxbytes)); // 重量
//string traycoded = GetValue(device.readAddr + 18, VarType.String, Ssxbytes,20); //测试托盘号
////添加修改线体中间表数据
var task = db.Queryable().Where(a => a.DeviceNo == device.code).First();
if (task != null)
{
task.targetAddr = targetAddr;
task.workMode = workMode;
task.lightAction = lightAction;
task.errorAlarm = errorAlarm;
task.deviceState = deviceState;
task.TaskNo = TaskNo;
task.weight = weight;
db.Updateable(task).ExecuteCommand();
}
else
{
db.Insertable(new PlcDeviceTable()
{
targetAddr = targetAddr,
workMode = workMode,
lightAction = lightAction,
errorAlarm = errorAlarm,
deviceState = deviceState,
TaskNo = TaskNo
}).ExecuteCommand();
}
}
}
}
///
/// 批量写入方法
///
/// 写入list
/// 写入db
/// 配置文件
public static void Write(List writemodels, int readdb, LinePlcInfo plcInfo)
{
// var plcInfo = Settings.linePlcInfo.Where(a => (a.deviceNo == "2") && a.enable == 1).FirstOrDefault();
//获取配置文件写入的地址
//List writemodels = Settings.plcValue.Find(a => a.address == plcInfo.address).read;
if (writemodels.Count > 0)
{
byte[] bytes = GetWriteByte(writemodels);
if (PLCWrite(plcInfo, readdb, bytes))
{
Console.WriteLine("写入成功");
//写入成功校验数据
//Read();
//if (Dictvalues[plcInfo.address].Find(a => a.addr == 2).value == "2")
//{
// Console.WriteLine("数据校验成功,修改任务状态");
//}
}
else
{
Console.WriteLine("写入失败");
}
}
// int taskNo = 12100001;
//写入byte数据,杭叉堆垛机默认从偏移量6开始 6,8,10为起点排列层 12 14 16终点排列层 18任务类型以此类推,具体写入byte根据文档调整
// byte[] bytes = new byte[30] {
//0,(byte)int.Parse("2"),
//0,(byte)int.Parse("3"),
//0,(byte)int.Parse("4"),
//0,(byte)int.Parse("5"),
//0,(byte)int.Parse("6"),
//0,(byte)int.Parse("7"),
//0,(byte)1,
//0,1,
//0,0,
//0,0,
//0,0,
//0,0,
//0,0,
//(byte)((uint)(taskNo >> 24) & 0xFFu),
//(byte)((uint)(taskNo >> 16) & 0xFFu),
//(byte)((uint)(taskNo >> 8) & 0xFFu),
//(byte)((uint)taskNo & 0xFFu)
//};
//byte[] bytes = new byte[4] {
// 0,(byte)int.Parse("2"),
//0,(byte)int.Parse("3")
//};
}
///
/// 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;
}
}
///
/// 将要写的数据转换成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;
}
///
/// 批量写入model
///
public class S7Model
{
///
/// 偏移量
///
public int addr { get; set; }
///
/// 类型
///
public string type { get; set; }
///
/// 长度
///
public int length { get; set; }
///
/// 值
///
public string value { get; set; }
}
#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 weight = weight;
}