|
|
using CompressorXN_Common;
|
|
|
using CompressorXN_Model.ViewModel.Plc;
|
|
|
using HslCommunication;
|
|
|
using HslCommunication.Profinet.Omron;
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Diagnostics;
|
|
|
using System.Linq;
|
|
|
using System.Text;
|
|
|
|
|
|
namespace CompressorXN_Communication.MyPlc
|
|
|
{
|
|
|
public class OmronCIPHelper
|
|
|
{
|
|
|
private static OmronCipNet omronCipNet = null;
|
|
|
|
|
|
/// <summary>
|
|
|
/// 获取欧姆龙PLC连接对象
|
|
|
/// </summary>
|
|
|
/// <param name="plcIp"></param>
|
|
|
/// <param name="plcPort"></param>
|
|
|
/// <param name="connectTimeOut"></param>
|
|
|
/// <returns></returns>
|
|
|
public static OmronCipNet GetOmronCipNet(string plcIp, int plcPort, int connectTimeOut = 10000)
|
|
|
{
|
|
|
omronCipNet = new OmronCipNet(plcIp, plcPort)
|
|
|
{
|
|
|
ConnectTimeOut = connectTimeOut
|
|
|
};
|
|
|
|
|
|
var connect = omronCipNet.ConnectServer();
|
|
|
|
|
|
isConnected = connect.IsSuccess;
|
|
|
|
|
|
if (connect.IsSuccess)
|
|
|
{
|
|
|
return omronCipNet;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
return null;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 链接状态
|
|
|
/// </summary>
|
|
|
private static bool isConnected = false;
|
|
|
public static bool IsConnected
|
|
|
{
|
|
|
get { return isConnected; }
|
|
|
}
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
/// 获取PLC值--单点位
|
|
|
/// </summary>
|
|
|
/// <param name="pointAddress">点位地址</param>
|
|
|
/// <param name="dataType">数据类型</param>
|
|
|
/// <param name="length">读取长度</param>
|
|
|
/// <returns></returns>
|
|
|
public static (bool ok, string val) SingleReadPlcVal(string pointAddress, string dataType, int length = 1, Encoding encoding = null)
|
|
|
{
|
|
|
var strVal = string.Empty;
|
|
|
try
|
|
|
{
|
|
|
if (!isConnected || omronCipNet == null)
|
|
|
{
|
|
|
return (false, strVal);
|
|
|
}
|
|
|
switch (dataType)
|
|
|
{
|
|
|
case "bool":
|
|
|
var operateBoolResult = omronCipNet.ReadBool(pointAddress);
|
|
|
if (!operateBoolResult.IsSuccess)
|
|
|
{
|
|
|
return (false, strVal);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
var boolVal = operateBoolResult.Content;
|
|
|
strVal = boolVal.ToString();
|
|
|
return (true, strVal);
|
|
|
}
|
|
|
case "int":
|
|
|
var operateIntResult = omronCipNet.ReadInt32(pointAddress);
|
|
|
if (!operateIntResult.IsSuccess)
|
|
|
{
|
|
|
return (false, strVal);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
var intVal = operateIntResult.Content;
|
|
|
strVal = intVal.ToString();
|
|
|
return (true, strVal);
|
|
|
}
|
|
|
case "short":
|
|
|
var operateShortResult = omronCipNet.ReadInt16(pointAddress);
|
|
|
if (!operateShortResult.IsSuccess)
|
|
|
{
|
|
|
return (false, strVal);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
var shortVal = operateShortResult.Content;
|
|
|
strVal = shortVal.ToString();
|
|
|
return (true, strVal);
|
|
|
}
|
|
|
case "ushort":
|
|
|
var operateUshortResult = omronCipNet.ReadUInt16(pointAddress);
|
|
|
if (!operateUshortResult.IsSuccess)
|
|
|
{
|
|
|
return (false, strVal);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
var ushortVal = operateUshortResult.Content;
|
|
|
strVal = ushortVal.ToString();
|
|
|
return (true, strVal);
|
|
|
}
|
|
|
case "float":
|
|
|
var operateFloatResult = omronCipNet.ReadFloat(pointAddress);
|
|
|
if (!operateFloatResult.IsSuccess)
|
|
|
{
|
|
|
return (false, strVal);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
var floatVal = operateFloatResult.Content;
|
|
|
strVal = floatVal.ToString("f3");
|
|
|
return (true, strVal);
|
|
|
}
|
|
|
case "string":
|
|
|
var operateStringResult = omronCipNet.ReadString(pointAddress, (ushort)length, encoding == null ? Encoding.UTF8 : encoding);
|
|
|
if (!operateStringResult.IsSuccess)
|
|
|
{
|
|
|
return (false, strVal);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
strVal = operateStringResult.Content;
|
|
|
return (true, strVal);
|
|
|
}
|
|
|
case "byte":
|
|
|
var operateByteResult = omronCipNet.Read(pointAddress, (ushort)length);
|
|
|
if (!operateByteResult.IsSuccess)
|
|
|
{
|
|
|
return (false, strVal);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (encoding == null)
|
|
|
{
|
|
|
strVal = Encoding.ASCII.GetString(operateByteResult.Content);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
strVal = encoding.GetString(operateByteResult.Content);
|
|
|
}
|
|
|
return (true, strVal);
|
|
|
}
|
|
|
default:
|
|
|
return (false, strVal);
|
|
|
}
|
|
|
}
|
|
|
catch (Exception)
|
|
|
{
|
|
|
return (false, strVal);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 值写入PLC
|
|
|
/// </summary>
|
|
|
/// <param name="pointAddress">点位地址</param>
|
|
|
/// <param name="dataType">数据类型</param>
|
|
|
/// <param name="value">值</param>
|
|
|
/// <param name="len">长度</param>
|
|
|
/// <param name="encoding">编码格式</param>
|
|
|
/// <returns></returns>
|
|
|
public static (bool isOk, string msg) SingleWriteValToPlc(string pointAddress, string dataType, object value, int len = 1, Encoding encoding = null)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
if (!isConnected || omronCipNet == null)
|
|
|
{
|
|
|
return (false, "PLC未连接");
|
|
|
}
|
|
|
OperateResult operateResult = new OperateResult
|
|
|
{
|
|
|
IsSuccess = false
|
|
|
};
|
|
|
switch (dataType)
|
|
|
{
|
|
|
case "bool":
|
|
|
operateResult = omronCipNet.Write(pointAddress, Convert.ToBoolean(value));
|
|
|
break;
|
|
|
case "int":
|
|
|
operateResult = omronCipNet.Write(pointAddress, Convert.ToInt32(value));
|
|
|
break;
|
|
|
case "short":
|
|
|
operateResult = omronCipNet.Write(pointAddress, Convert.ToInt16(value));
|
|
|
break;
|
|
|
case "ushort":
|
|
|
operateResult = omronCipNet.Write(pointAddress, Convert.ToUInt16(value));
|
|
|
break;
|
|
|
case "float":
|
|
|
operateResult = omronCipNet.Write(pointAddress, Convert.ToSingle(value));
|
|
|
break;
|
|
|
case "string":
|
|
|
operateResult = omronCipNet.Write(pointAddress, value.ToString(), len, encoding ?? Encoding.ASCII);
|
|
|
break;
|
|
|
case "byte":
|
|
|
var bytes = Encoding.ASCII.GetBytes(value.ToString());
|
|
|
operateResult = omronCipNet.WriteTag(pointAddress, 0xD1, bytes, len);
|
|
|
break;
|
|
|
}
|
|
|
if (operateResult.IsSuccess)
|
|
|
{
|
|
|
return (operateResult.IsSuccess, "操作成功");
|
|
|
}
|
|
|
return (operateResult.IsSuccess, operateResult.Message);
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
return (false, ex.Message);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//private static Stopwatch stopwatch = new Stopwatch();
|
|
|
|
|
|
/// <summary>
|
|
|
/// 不连续的地址批量读取
|
|
|
/// </summary>
|
|
|
/// <param name="addressArr"></param>
|
|
|
public static (bool isSucess, string msg) ReadPlcBatch(List<Variable> variables, Encoding encoding = null)
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
foreach (var item in variables)
|
|
|
{
|
|
|
switch (item.DataType)
|
|
|
{
|
|
|
case "float":
|
|
|
OperateResult<float> read = omronCipNet.ReadFloat(item.VariableName);
|
|
|
item.ReadVal = read.Content;
|
|
|
break;
|
|
|
}
|
|
|
GlobalVar.deviceInfo.CommGroupList.FirstOrDefault().VariableList.FirstOrDefault(m => m.VariableName == item.VariableName).ReadVal = item.ReadVal;
|
|
|
}
|
|
|
|
|
|
return (true, string.Empty);
|
|
|
//var addressArrTest = new string[1] { "D770" };
|
|
|
//OperateResult<byte[]> readTest = omronCipNet.Read("D770", 4);
|
|
|
//var aa = Encoding.ASCII.GetString(readTest.Content, 0, 4);
|
|
|
|
|
|
//short占2字节,Real占4个字节,bool占2个字节
|
|
|
|
|
|
//stopwatch.Restart();
|
|
|
int readLen = 40;//每次读取40个地址
|
|
|
int plcPointTotalCount = variables.Count;
|
|
|
int readCount = plcPointTotalCount / readLen;//轮询次数
|
|
|
int remainder = plcPointTotalCount % readLen;//余数
|
|
|
readCount = remainder > 0 ? readCount + 1 : readCount;
|
|
|
string[] sourceAddressArr = variables.Select(m => m.VariableName).ToArray();
|
|
|
for (int i = 0; i < readCount; i++)
|
|
|
{
|
|
|
int surplusLen = sourceAddressArr.Length - i * readLen;//剩余长度
|
|
|
int subLen = surplusLen > readLen ? readLen : surplusLen;//应该Take的长度
|
|
|
//本次需要读取的地址数组
|
|
|
var addressArr = sourceAddressArr.Skip(i * readLen).Take(subLen).ToArray();
|
|
|
OperateResult<byte[]> read = omronCipNet.Read(addressArr);
|
|
|
if (!read.IsSuccess)
|
|
|
{
|
|
|
return (read.IsSuccess, read.Message);
|
|
|
}
|
|
|
|
|
|
int startIndex = 0;//起始地址
|
|
|
for (int j = 0; j < addressArr.Length; j++)
|
|
|
{
|
|
|
var item = variables.First(m => m.VariableName == addressArr[j]);
|
|
|
if (j > 0)
|
|
|
{
|
|
|
var lastItem = variables.First(m => m.VariableName == addressArr[j - 1]);
|
|
|
startIndex = j == 0 ? 0 : startIndex + lastItem.Offset;
|
|
|
}
|
|
|
switch (item.DataType)
|
|
|
{
|
|
|
case "string":
|
|
|
item.ReadVal = encoding == null ? Encoding.ASCII.GetString(read.Content, startIndex, item.Offset) : encoding.GetString(read.Content, startIndex, item.Offset);
|
|
|
break;
|
|
|
case "float":
|
|
|
item.ReadVal = omronCipNet.ByteTransform.TransSingle(read.Content, startIndex).ToString("f3");
|
|
|
break;
|
|
|
case "bool":
|
|
|
item.ReadVal = GetBoolFromByte(read.Content, startIndex, item.Offset).ToString();
|
|
|
break;
|
|
|
case "short":
|
|
|
item.ReadVal = omronCipNet.ByteTransform.TransInt16(read.Content, startIndex).ToString();
|
|
|
break;
|
|
|
case "ushort":
|
|
|
item.ReadVal = omronCipNet.ByteTransform.TransUInt16(read.Content, startIndex).ToString();
|
|
|
break;
|
|
|
case "byte":
|
|
|
if (encoding == null)
|
|
|
{
|
|
|
item.ReadVal = Encoding.ASCII.GetString(read.Content, startIndex, item.Offset);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
item.ReadVal = encoding.GetString(read.Content, startIndex, item.Offset);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
GlobalVar.deviceInfo.CommGroupList.FirstOrDefault().VariableList.FirstOrDefault(m => m.VariableName == item.VariableName).ReadVal = item.ReadVal;
|
|
|
}
|
|
|
}
|
|
|
//stopwatch.Stop();
|
|
|
|
|
|
//Console.WriteLine($"读取PLC点位值耗时={stopwatch.ElapsedMilliseconds}ms");
|
|
|
|
|
|
return (true, string.Empty);
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
return (false, $"批量读取异常:{ex.Message}!");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 根据起始索引和长度截取字节数组
|
|
|
/// </summary>
|
|
|
/// <param name="bytes"></param>
|
|
|
/// <param name="startIndex"></param>
|
|
|
/// <param name="len"></param>
|
|
|
/// <returns></returns>
|
|
|
private static bool GetBoolFromByte(byte[] bytes, int startIndex, int len)
|
|
|
{
|
|
|
var getBytes = SubArray(bytes, startIndex, len);
|
|
|
return BitConverter.ToBoolean(getBytes, 0);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// 根据起始索引和截取长度获取新的数组
|
|
|
/// </summary>
|
|
|
/// <typeparam name="T"></typeparam>
|
|
|
/// <param name="data">原始数组</param>
|
|
|
/// <param name="index">起始索引</param>
|
|
|
/// <param name="length">长度</param>
|
|
|
/// <returns></returns>
|
|
|
public static T[] SubArray<T>(T[] data, int index, int length)
|
|
|
{
|
|
|
T[] result = new T[length];
|
|
|
Array.Copy(data, index, result, 0, length);
|
|
|
return result;
|
|
|
}
|
|
|
}
|
|
|
}
|