|
|
using HslCommunication.Core;
|
|
|
using HslCommunication.Core.IMessage;
|
|
|
using HslCommunication.Core.Net;
|
|
|
using System;
|
|
|
using System.Collections;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Linq;
|
|
|
using System.Text;
|
|
|
using HslCommunication.BasicFramework;
|
|
|
|
|
|
namespace HslCommunication.Profinet.LSIS
|
|
|
{
|
|
|
/// <summary>
|
|
|
/// XGB Fast Enet I/F module supports open Ethernet. It provides network configuration that is to connect LSIS and other company PLC, PC on network
|
|
|
/// </summary>
|
|
|
/// <remarks>
|
|
|
/// Address example likes the follow
|
|
|
/// [welcome to finish]
|
|
|
/// </remarks>
|
|
|
public class XGBFastEnet : NetworkDeviceBase<LsisFastEnetMessage, RegularByteTransform>
|
|
|
{
|
|
|
#region Constractor
|
|
|
|
|
|
/// <summary>
|
|
|
/// Instantiate a Default object
|
|
|
/// </summary>
|
|
|
public XGBFastEnet()
|
|
|
{
|
|
|
WordLength = 2;
|
|
|
IpAddress = string.Empty;
|
|
|
Port = 2004;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// Instantiate a object by ipaddress and port
|
|
|
/// </summary>
|
|
|
/// <param name="ipAddress">the ip address of the plc</param>
|
|
|
/// <param name="port">the port of the plc, default is 2004</param>
|
|
|
public XGBFastEnet(string ipAddress, int port)
|
|
|
{
|
|
|
WordLength = 2;
|
|
|
IpAddress = ipAddress;
|
|
|
Port = port;
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region Public Properties
|
|
|
|
|
|
/// <summary>
|
|
|
/// CPU TYPE
|
|
|
/// </summary>
|
|
|
public string CpuType { get; private set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// Cpu is error
|
|
|
/// </summary>
|
|
|
public bool CpuError { get; private set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// RUN, STOP, ERROR, DEBUG
|
|
|
/// </summary>
|
|
|
public LSCpuStatus LSCpuStatus { get; private set; }
|
|
|
|
|
|
/// <summary>
|
|
|
/// FEnet I/F module’s Base No.
|
|
|
/// </summary>
|
|
|
public byte BaseNo
|
|
|
{
|
|
|
get => baseNo;
|
|
|
set => baseNo = value;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// FEnet I/F module’s Slot No.
|
|
|
/// </summary>
|
|
|
public byte SlotNo
|
|
|
{
|
|
|
get => slotNo;
|
|
|
set => slotNo = value;
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region Read Write
|
|
|
|
|
|
/// <summary>
|
|
|
/// Read Bytes from plc, you should specify address
|
|
|
/// </summary>
|
|
|
/// <param name="address">Start Address, for example: M100</param>
|
|
|
/// <param name="length">Array of data Lengths</param>
|
|
|
/// <returns>Whether to read the successful result object</returns>
|
|
|
/// <exception cref="NullReferenceException"></exception>
|
|
|
/// <remarks>
|
|
|
/// </remarks>
|
|
|
/// <example>
|
|
|
/// </example>
|
|
|
public override OperateResult<byte[]> Read(string address, ushort length)
|
|
|
{
|
|
|
// build read command
|
|
|
OperateResult<byte[]> coreResult = BuildReadByteCommand(address, length);
|
|
|
if (!coreResult.IsSuccess) return coreResult;
|
|
|
|
|
|
// communication
|
|
|
var read = ReadFromCoreServer(PackCommand(coreResult.Content));
|
|
|
if (!read.IsSuccess) return OperateResult.CreateFailedResult<byte[]>(read);
|
|
|
|
|
|
// analysis read result
|
|
|
return ExtractActualData(read.Content);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// Write bytes to plc, you should specify bytes, can't be null
|
|
|
/// </summary>
|
|
|
/// <param name="address">Start Address, for example: M100</param>
|
|
|
/// <param name="value">source dara</param>
|
|
|
/// <returns>Whether to write the successful result object</returns>
|
|
|
/// <exception cref="NullReferenceException"></exception>
|
|
|
public override OperateResult Write(string address, byte[] value)
|
|
|
{
|
|
|
// build write command
|
|
|
OperateResult<byte[]> coreResult = BuildWriteByteCommand(address, value);
|
|
|
if (!coreResult.IsSuccess) return coreResult;
|
|
|
|
|
|
// communication
|
|
|
var read = ReadFromCoreServer(PackCommand(coreResult.Content));
|
|
|
if (!read.IsSuccess) return OperateResult.CreateFailedResult<byte[]>(read);
|
|
|
|
|
|
// analysis read result
|
|
|
return ExtractActualData(read.Content);
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region Read Write Byte
|
|
|
|
|
|
/// <summary>
|
|
|
/// Read single byte value from plc
|
|
|
/// </summary>
|
|
|
/// <param name="address">Start address</param>
|
|
|
/// <returns>result</returns>
|
|
|
public OperateResult<byte> ReadByte(string address)
|
|
|
{
|
|
|
var read = Read(address, 1);
|
|
|
if (!read.IsSuccess) return OperateResult.CreateFailedResult<byte>(read);
|
|
|
|
|
|
return OperateResult.CreateSuccessResult(read.Content[0]);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// Write single byte value to plc
|
|
|
/// </summary>
|
|
|
/// <param name="address">Start address</param>
|
|
|
/// <param name="value">value</param>
|
|
|
/// <returns>Whether to write the successful</returns>
|
|
|
public OperateResult Write(string address, byte value)
|
|
|
{
|
|
|
return Write(address, new byte[] { value });
|
|
|
}
|
|
|
/// <summary>
|
|
|
/// WriteCoil
|
|
|
/// </summary>
|
|
|
/// <param name="address"></param>
|
|
|
/// <param name="value"></param>
|
|
|
/// <returns></returns>
|
|
|
public OperateResult WriteCoil(string address, bool value)
|
|
|
{
|
|
|
|
|
|
return Write(address, new byte[] { (byte)(value == true ? 0x01 : 0x00), 0x00 });
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
#region Private Member
|
|
|
|
|
|
private byte[] PackCommand(byte[] coreCommand)
|
|
|
{
|
|
|
byte[] command = new byte[coreCommand.Length + 20];
|
|
|
Encoding.ASCII.GetBytes(CompanyID1).CopyTo(command, 0);
|
|
|
switch (cpuInfo)
|
|
|
{
|
|
|
case LSCpuInfo.XGK: command[12] = 0xA0; break;
|
|
|
case LSCpuInfo.XGI: command[12] = 0xA4; break;
|
|
|
case LSCpuInfo.XGR: command[12] = 0xA8; break;
|
|
|
case LSCpuInfo.XGB_MK: command[12] = 0xB0; break;
|
|
|
case LSCpuInfo.XGB_IEC: command[12] = 0xB4; break;
|
|
|
default: break;
|
|
|
}
|
|
|
command[13] = 0x33;
|
|
|
BitConverter.GetBytes((short)coreCommand.Length).CopyTo(command, 16);
|
|
|
command[18] = (byte)(baseNo * 16 + slotNo);
|
|
|
|
|
|
int count = 0;
|
|
|
for (int i = 0; i < 19; i++)
|
|
|
{
|
|
|
count += command[i];
|
|
|
}
|
|
|
command[19] = (byte)count;
|
|
|
|
|
|
coreCommand.CopyTo(command, 20);
|
|
|
|
|
|
string hex = SoftBasic.ByteToHexString(command, ' ');
|
|
|
return command;
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region Const Value
|
|
|
|
|
|
private const string CompanyID1 = "LSIS-XGT";
|
|
|
private const string CompanyID2 = "LGIS-GLOGA";
|
|
|
private LSCpuInfo cpuInfo = LSCpuInfo.XGK;
|
|
|
private byte baseNo = 0;
|
|
|
private byte slotNo = 3;
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region Static Helper
|
|
|
|
|
|
/// <summary>
|
|
|
/// AnalysisAddress
|
|
|
/// </summary>
|
|
|
/// <param name="address"></param>
|
|
|
/// <param name="isRead"></param>
|
|
|
/// <returns></returns>
|
|
|
public static OperateResult<string> AnalysisAddress(string address, bool isRead)
|
|
|
{
|
|
|
// P,M,L,K,F,T
|
|
|
// P,M,L,K,F,T,C,D,S
|
|
|
StringBuilder sb = new StringBuilder();
|
|
|
try
|
|
|
{
|
|
|
sb.Append("%");
|
|
|
char[] types = new char[] { 'P', 'M', 'L', 'K', 'F', 'T', 'C', 'D', 'S', 'Q', 'I', 'N', 'U', 'Z', 'R' };
|
|
|
bool exsist = false;
|
|
|
int baseAddress;
|
|
|
int LsBaseNumber = 0;
|
|
|
int LsSlotNumber = 0;
|
|
|
string fullAddress = address;
|
|
|
if (isRead)
|
|
|
{
|
|
|
for (int i = 0; i < types.Length; i++)
|
|
|
{
|
|
|
if (types[i] == address[0])
|
|
|
{
|
|
|
sb.Append(types[i]);
|
|
|
sb.Append("B");
|
|
|
|
|
|
if (address[1] == 'X')//Bit
|
|
|
{
|
|
|
|
|
|
if (address.IndexOf(".") > 1) //MX0.0
|
|
|
{
|
|
|
string[] list = address.Split('.');
|
|
|
baseAddress = ((int.Parse($"{list[2]}") >= 16) ? (int.Parse($"{list[2]}") / 16) : 0) * 2;
|
|
|
sb.Append(baseAddress);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
sb.Append(int.Parse($"{address[2]}"));
|
|
|
}
|
|
|
}
|
|
|
else if (address[1] == 'B')//BitOnByte
|
|
|
{
|
|
|
|
|
|
|
|
|
if (address.IndexOf(".") > 0)
|
|
|
{
|
|
|
string[] list = address.Split('.');
|
|
|
for (int y = 0; y < list.Length; y++)
|
|
|
{
|
|
|
if (list[y][0] == 'I' || list[y][0] == 'Q' || list[y][0] == 'U') //IB0.0.0.1
|
|
|
{
|
|
|
baseAddress = ((int.Parse($"{list[3]}") >= 2) ? (int.Parse($"{list[3]}") / 2) : 0) * 2;
|
|
|
sb.Append(baseAddress);
|
|
|
break;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
|
|
|
sb.Append(int.Parse($"{list[1]}")); //MB0.0
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
sb.Append(int.Parse($"{address[2]}"));
|
|
|
}
|
|
|
|
|
|
}
|
|
|
else if (address[1] == 'W')
|
|
|
{
|
|
|
if (address.IndexOf(".") > 0)//BitOnWord
|
|
|
{
|
|
|
string[] list = address.Split('.');
|
|
|
for (int y = 0; y < list.Length; y++)
|
|
|
{
|
|
|
if (list[y][0] == 'I' || list[y][0] == 'Q' || list[y][0] == 'U')//IW0.0.0.1
|
|
|
{
|
|
|
baseAddress = ((int.Parse($"{list[3]}") >= 2) ? (int.Parse($"{list[3]}") / 2) : 0) * 2;
|
|
|
sb.Append(baseAddress);
|
|
|
break;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
|
|
|
sb.Append(int.Parse($"{list[1]}") * 2);//MW0.0
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
sb.Append(int.Parse($"{address[2]}") * 2);//MW0
|
|
|
}
|
|
|
|
|
|
}
|
|
|
else if (address[1] == 'D')
|
|
|
{
|
|
|
sb.Append(int.Parse($"{address[2]}") * 4);
|
|
|
}
|
|
|
else if (address[1] == 'L')
|
|
|
{
|
|
|
sb.Append(int.Parse($"{address[2]}") * 8);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
sb.Append(int.Parse($"{address[1]}"));
|
|
|
}
|
|
|
|
|
|
exsist = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
if (address.Length >= 3 || address.Length >= 5)
|
|
|
{
|
|
|
for (int i = 0; i < types.Length; i++)
|
|
|
{
|
|
|
if (types[i] == address[0])
|
|
|
{
|
|
|
|
|
|
|
|
|
if (address[1] == 'B')
|
|
|
{
|
|
|
if (address.IndexOf(".") > 0)//BitOnByte
|
|
|
{
|
|
|
string text3 = address.Substring(0, 1);
|
|
|
address.Substring(1, 1);
|
|
|
string text4 = address.Remove(0, 2);
|
|
|
|
|
|
switch (text3)
|
|
|
{
|
|
|
case "I":
|
|
|
case "Q":
|
|
|
case "U":
|
|
|
{
|
|
|
string[] array4 = text4.Split(new char[1]
|
|
|
{
|
|
|
'.'
|
|
|
}, 4);
|
|
|
fullAddress = text3 + "B" + array4[0] + "." + array4[1] + ".";
|
|
|
LsBaseNumber = int.Parse(array4[2]);
|
|
|
LsSlotNumber = int.Parse(array4[3]);
|
|
|
break;
|
|
|
}
|
|
|
default:
|
|
|
{
|
|
|
string[] array3 = text4.Split(new char[1]
|
|
|
{
|
|
|
'.'
|
|
|
}, 2);
|
|
|
fullAddress = text3 + "B";
|
|
|
LsBaseNumber = int.Parse(array3[0]);
|
|
|
LsSlotNumber = int.Parse(array3[1]);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
fullAddress = $"{fullAddress}{(LsBaseNumber * 8 + LsSlotNumber) / 8}.{LsSlotNumber % 8}";
|
|
|
sb.Append(fullAddress);
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
sb.Append(address);
|
|
|
}
|
|
|
|
|
|
exsist = true;
|
|
|
break;
|
|
|
}
|
|
|
else if (address[1] == 'W')
|
|
|
{
|
|
|
if (address.IndexOf(".") > 0)//BitOnWord
|
|
|
{
|
|
|
|
|
|
string text = address.Substring(0, 1);
|
|
|
address.Substring(1, 1);
|
|
|
string text2 = address.Remove(0, 2);
|
|
|
|
|
|
|
|
|
switch (text)
|
|
|
{
|
|
|
case "I":
|
|
|
case "Q":
|
|
|
case "U":
|
|
|
{
|
|
|
string[] array2 = text2.Split(new char[1]
|
|
|
{
|
|
|
'.'
|
|
|
}, 4);
|
|
|
fullAddress = text + "B" + array2[0] + "." + array2[1] + ".";
|
|
|
LsBaseNumber = int.Parse(array2[2]);
|
|
|
LsSlotNumber = int.Parse(array2[3]);
|
|
|
break;
|
|
|
}
|
|
|
default:
|
|
|
{
|
|
|
string[] array = text2.Split(new char[1]
|
|
|
{
|
|
|
'.'
|
|
|
}, 2);
|
|
|
fullAddress = text + "B";
|
|
|
LsBaseNumber = int.Parse(array[0]);
|
|
|
LsSlotNumber = int.Parse(array[1]);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
fullAddress = $"{fullAddress}{(LsBaseNumber * 16 + LsSlotNumber) / 8}.{LsSlotNumber % 8}";
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
sb.Append(fullAddress);
|
|
|
}
|
|
|
|
|
|
exsist = true;
|
|
|
break;
|
|
|
}
|
|
|
else if (address[1] == 'D')
|
|
|
{
|
|
|
sb.Append(address);
|
|
|
exsist = true;
|
|
|
break;
|
|
|
}
|
|
|
else if (address[1] == 'X')
|
|
|
{
|
|
|
sb.Append(address);
|
|
|
exsist = true;
|
|
|
break;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
exsist = false;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
}
|
|
|
if (!exsist) throw new Exception(StringResources.Language.NotSupportedDataType);
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
return new OperateResult<string>(ex.Message);
|
|
|
}
|
|
|
|
|
|
return OperateResult.CreateSuccessResult(sb.ToString());
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// Get DataType to Address
|
|
|
/// </summary>
|
|
|
/// <param name="address"></param>
|
|
|
/// <returns></returns>
|
|
|
public static OperateResult<string> GetDataTypeToAddress(string address)
|
|
|
{
|
|
|
string lSDataType = string.Empty; ;
|
|
|
try
|
|
|
{
|
|
|
|
|
|
char[] types = new char[] { 'P', 'M', 'L', 'K', 'F', 'T', 'C', 'D', 'S', 'Q', 'I', 'R' };
|
|
|
bool exsist = false;
|
|
|
|
|
|
for (int i = 0; i < types.Length; i++)
|
|
|
{
|
|
|
if (types[i] == address[0])
|
|
|
{
|
|
|
|
|
|
if (address[1] == 'W')
|
|
|
{
|
|
|
lSDataType = "Word";
|
|
|
}
|
|
|
else if (address[1] == 'D')
|
|
|
{
|
|
|
lSDataType = "DWord";
|
|
|
}
|
|
|
else if (address[1] == 'L')
|
|
|
{
|
|
|
lSDataType = "LWord";
|
|
|
}
|
|
|
else if (address[1] == 'B')
|
|
|
{
|
|
|
lSDataType = "Byte";
|
|
|
}
|
|
|
else if (address[1] == 'X')
|
|
|
{
|
|
|
lSDataType = "Bit";
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
exsist = false;
|
|
|
break;
|
|
|
}
|
|
|
exsist = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (!exsist) throw new Exception(StringResources.Language.NotSupportedDataType);
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
return new OperateResult<string>(ex.Message);
|
|
|
}
|
|
|
|
|
|
return OperateResult.CreateSuccessResult(lSDataType);
|
|
|
|
|
|
|
|
|
}
|
|
|
private static OperateResult<byte[]> BuildReadByteCommand(string address, ushort length)
|
|
|
{
|
|
|
var analysisResult = AnalysisAddress(address, true);
|
|
|
if (!analysisResult.IsSuccess) return OperateResult.CreateFailedResult<byte[]>(analysisResult);
|
|
|
|
|
|
byte[] command = new byte[12 + analysisResult.Content.Length];
|
|
|
command[0] = 0x54; // read
|
|
|
command[1] = 0x00;
|
|
|
command[2] = 0x14; // continuous reading
|
|
|
command[3] = 0x00;
|
|
|
command[4] = 0x00; // Reserved
|
|
|
command[5] = 0x00;
|
|
|
command[6] = 0x01; // Block No ?? i don't know what is the meaning
|
|
|
command[7] = 0x00;
|
|
|
command[8] = (byte)analysisResult.Content.Length; // Variable Length
|
|
|
command[9] = 0x00;
|
|
|
|
|
|
Encoding.ASCII.GetBytes(analysisResult.Content).CopyTo(command, 10);
|
|
|
BitConverter.GetBytes(length).CopyTo(command, command.Length - 2);
|
|
|
|
|
|
return OperateResult.CreateSuccessResult(command);
|
|
|
}
|
|
|
|
|
|
private static OperateResult<byte[]> BuildWriteByteCommand(string address, byte[] data)
|
|
|
{
|
|
|
var analysisResult = AnalysisAddress(address, false);
|
|
|
if (!analysisResult.IsSuccess) return OperateResult.CreateFailedResult<byte[]>(analysisResult);
|
|
|
var DataTypeResult = GetDataTypeToAddress(address);
|
|
|
if (!DataTypeResult.IsSuccess) return OperateResult.CreateFailedResult<byte[]>(DataTypeResult);
|
|
|
|
|
|
byte[] command = new byte[12 + analysisResult.Content.Length + data.Length];
|
|
|
|
|
|
switch (DataTypeResult.Content)
|
|
|
{
|
|
|
case "Bit":
|
|
|
command[2] = 0x00; break;
|
|
|
case "Byte":
|
|
|
command[2] = 0x01; break;
|
|
|
case "Word":
|
|
|
command[2] = 0x02; break;
|
|
|
case "DWord": command[2] = 0x03; break;
|
|
|
case "LWord": command[2] = 0x04; break;
|
|
|
case "Continuous": command[2] = 0x14; break;
|
|
|
default: break;
|
|
|
}
|
|
|
command[0] = 0x58; // write
|
|
|
command[1] = 0x00;
|
|
|
//command[2] = 0x14; // continuous reading
|
|
|
command[3] = 0x00;
|
|
|
command[4] = 0x00; // Reserved
|
|
|
command[5] = 0x00;
|
|
|
command[6] = 0x01; // Block No ?? i don't know what is the meaning
|
|
|
command[7] = 0x00;
|
|
|
command[8] = (byte)analysisResult.Content.Length; // Variable Length
|
|
|
command[9] = 0x00;
|
|
|
|
|
|
Encoding.ASCII.GetBytes(analysisResult.Content).CopyTo(command, 10);
|
|
|
BitConverter.GetBytes(data.Length).CopyTo(command, command.Length - 2 - data.Length);
|
|
|
data.CopyTo(command, command.Length - data.Length);
|
|
|
|
|
|
return OperateResult.CreateSuccessResult(command);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// Returns true data content, supports read and write returns
|
|
|
/// </summary>
|
|
|
/// <param name="response">response data</param>
|
|
|
/// <returns>real data</returns>
|
|
|
public OperateResult<byte[]> ExtractActualData(byte[] response)
|
|
|
{
|
|
|
if (response.Length < 20) return new OperateResult<byte[]>("Length is less than 20:" + SoftBasic.ByteToHexString(response));
|
|
|
|
|
|
ushort plcInfo = BitConverter.ToUInt16(response, 10);
|
|
|
BitArray array_plcInfo = new BitArray(BitConverter.GetBytes(plcInfo));
|
|
|
|
|
|
switch (plcInfo % 32)
|
|
|
{
|
|
|
case 1: CpuType = "XGK/R-CPUH"; break;
|
|
|
case 2: CpuType = "XGK-CPUS"; break;
|
|
|
case 5: CpuType = "XGK/R-CPUH"; break;
|
|
|
}
|
|
|
|
|
|
CpuError = array_plcInfo[7];
|
|
|
if (array_plcInfo[8]) LSCpuStatus = LSCpuStatus.RUN;
|
|
|
if (array_plcInfo[9]) LSCpuStatus = LSCpuStatus.STOP;
|
|
|
if (array_plcInfo[10]) LSCpuStatus = LSCpuStatus.ERROR;
|
|
|
if (array_plcInfo[11]) LSCpuStatus = LSCpuStatus.DEBUG;
|
|
|
|
|
|
if (response.Length < 28) return new OperateResult<byte[]>("Length is less than 28:" + SoftBasic.ByteToHexString(response));
|
|
|
ushort error = BitConverter.ToUInt16(response, 26);
|
|
|
if (error > 0) return new OperateResult<byte[]>(response[28], "Error:" + GetErrorDesciption(response[28]));
|
|
|
|
|
|
if (response[20] == 0x59) return OperateResult.CreateSuccessResult(new byte[0]); // write
|
|
|
|
|
|
if (response[20] == 0x55) // read
|
|
|
{
|
|
|
try
|
|
|
{
|
|
|
ushort length = BitConverter.ToUInt16(response, 30);
|
|
|
byte[] content = new byte[length];
|
|
|
Array.Copy(response, 32, content, 0, length);
|
|
|
return OperateResult.CreateSuccessResult(content);
|
|
|
}
|
|
|
catch (Exception ex)
|
|
|
{
|
|
|
return new OperateResult<byte[]>(ex.Message);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return new OperateResult<byte[]>(StringResources.Language.NotSupportedFunction);
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
|
/// get the description of the error code meanning
|
|
|
/// </summary>
|
|
|
/// <param name="code">code value</param>
|
|
|
/// <returns>string information</returns>
|
|
|
public static string GetErrorDesciption(byte code)
|
|
|
{
|
|
|
switch (code)
|
|
|
{
|
|
|
case 0: return "Normal";
|
|
|
case 1: return "Physical layer error (TX, RX unavailable)";
|
|
|
case 3: return "There is no identifier of Function Block to receive in communication channel";
|
|
|
case 4: return "Mismatch of data type";
|
|
|
case 5: return "Reset is received from partner station";
|
|
|
case 6: return "Communication instruction of partner station is not ready status";
|
|
|
case 7: return "Device status of remote station is not desirable status";
|
|
|
case 8: return "Access to some target is not available";
|
|
|
case 9: return "Can’ t deal with communication instruction of partner station by too many reception";
|
|
|
case 10: return "Time Out error";
|
|
|
case 11: return "Structure error";
|
|
|
case 12: return "Abort";
|
|
|
case 13: return "Reject(local/remote)";
|
|
|
case 14: return "Communication channel establishment error (Connect/Disconnect)";
|
|
|
case 15: return "High speed communication and connection service error";
|
|
|
case 33: return "Can’t find variable identifier";
|
|
|
case 34: return "Address error";
|
|
|
case 50: return "Response error";
|
|
|
case 113: return "Object Access Unsupported";
|
|
|
case 187: return "Unknown error code (communication code of other company) is received";
|
|
|
default: return "Unknown error";
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
#region Override
|
|
|
|
|
|
/// <summary>
|
|
|
/// Returns a string representing the current object
|
|
|
/// </summary>
|
|
|
/// <returns>字符串</returns>
|
|
|
public override string ToString()
|
|
|
{
|
|
|
return $"XGBFastEnet[{IpAddress}:{Port}]";
|
|
|
}
|
|
|
|
|
|
#endregion
|
|
|
}
|
|
|
}
|