Files
ThingsGateway/framework/Foundation/ThingsGateway.Foundation.Adapter.Siemens/Siemens/Helper/SiemensHelper.cs
2023-09-30 23:05:53 +08:00

383 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#region copyright
//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://diego2098.gitee.io/thingsgateway-docs/
// QQ群605534569
//------------------------------------------------------------------------------
#endregion
using System.Text;
using ThingsGateway.Foundation.Extension.Generic;
namespace ThingsGateway.Foundation.Adapter.Siemens;
internal partial class SiemensHelper
{
#region
//internal static OperResult<byte[]> AnalysisReadBit(byte[] content)
//{
// int length = 1;
// if (content.Length < 21 || content[20] != 1)
// return new OperResult<byte[]>("数据块长度校验失败");
// byte[] numArray = new byte[length];
// if (content[21] == byte.MaxValue && content[22] == 3)//Bit:3;Byte:4;Counter或者Timer:9
// {
// numArray[0] = content[25];//+4
// }
// else
// {
// return new OperResult<byte[]>((int)content[21] + GetCpuError(content[21]));
// }
// return OperResult.CreateSuccessResult<byte[]>(numArray);
//}
internal static OperResult<byte[]> AnalysisReadByte(byte[] sends, byte[] content)
{
int length = 0;
int itemLen = (sends.Length - 19) / 12;
for (int index = 0; index < itemLen; index++)
{
if (sends[22 + (index * 12)] >= (byte)S7WordLength.Word)
{
length += ((sends[23 + (index * 12)] * 256) + sends[24 + (index * 12)]) * 2;
}
else
{
length += (sends[23 + (index * 12)] * 256) + sends[24 + (index * 12)];
}
}
if (content.Length < 21 || content[20] != itemLen)
{
return new OperResult<byte[]>("数据块长度校验失败");
}
byte[] dataArray = new byte[length];
int index1 = 0;
int dataIndex = 0;
for (int index2 = 21; index2 < content.Length; index2++)
{
if (index2 + 1 < content.Length)
{
int s7len;
if (sends[22 + (index1 * 12)] >= (byte)S7WordLength.Word)
{
s7len = ((sends[23 + (index1 * 12)] * 256) + sends[24 + (index1 * 12)]) * 2;
}
else
{
s7len = (sends[23 + (index1 * 12)] * 256) + sends[24 + (index1 * 12)];
}
if (content[index2] == byte.MaxValue && content[index2 + 1] == 4)//Bit:3;Byte:4;Counter或者Timer:9
{
Array.Copy(content, index2 + 4, dataArray, dataIndex, s7len);
index2 += s7len + 3;
dataIndex += s7len;
index1++;
}
else if (content[index2] == byte.MaxValue && content[index2 + 1] == 9)//Counter或者Timer:9
{
int num = (content[index2 + 2] * 256) + content[index2 + 3];
if (num % 3 == 0)
{
for (int index3 = 0; index3 < num / 3; index3++)
{
Array.Copy(content, index2 + 5 + (3 * index3), dataArray, dataIndex, 2);
dataIndex += 2;
}
}
else
{
for (int index4 = 0; index4 < num / 5; index4++)
{
Array.Copy(content, index2 + 7 + (5 * index4), dataArray, dataIndex, 2);
dataIndex += 2;
}
}
index2 += num + 4;
index1++;
}
else
{
return new OperResult<byte[]>((int)content[index2] + GetCpuError(content[index2]));
}
}
}
return OperResult.CreateSuccessResult(dataArray);
}
internal static OperResult<byte[]> AnalysisWrite(byte[] content)
{
if (content.Length < 22)
{
return new OperResult<byte[]>() { Message = "未知错误" };
}
byte err = content[21];
if (err != byte.MaxValue)
{
return new OperResult<byte[]>((int)content[21] + GetCpuError(content[21]));
}
else
{
return OperResult.CreateSuccessResult(content);
}
}
private static string GetCpuError(ushort Error)
{
return Error switch
{
0x05 => "地址超限",
0x06 => "返回长度无效",
0x07 => "数据大小不匹配",
0x0a or 0xd209 => "数据块不存在",
0x8500 => "超出PDU大小",
0xdc01 => "无效的值",
0x8104 => "功能不可用",
0xd241 => "需要密码",
0xd602 => "无效密码",
0xd604 or 0xd605 => "没有设置密码或已清除",
_ => "未知错误",
};
;
}
#endregion
#region
internal static OperResult<byte[]> GetReadCommand(SiemensAddress[] siemensAddress)
{
if (siemensAddress == null)
{
return new OperResult<byte[]>("地址为null");
}
int len = siemensAddress.Length <= 19 ? siemensAddress.Length : throw new Exception("读取数量大于19!");
int telegramLen = len * 12 + 19;
int parameterLen = len * 12 + 2;
byte[] numArray = new byte[telegramLen];
Array.Copy(S7_MULRW_HEADER, 0, numArray, 0, S7_MULRW_HEADER.Length);
numArray[2] = (byte)(telegramLen / 256);
numArray[3] = (byte)(telegramLen % 256);
numArray[13] = (byte)(parameterLen / 256);
numArray[14] = (byte)(parameterLen % 256);
numArray[18] = (byte)len;
for (int index = 0; index < len; index++)
{
Array.Copy(S7_MULRD_ITEM, 0, numArray, 19 + (index * 12), S7_MULRD_ITEM.Length);
if (siemensAddress[index].DataCode == (byte)S7WordLength.Counter || siemensAddress[index].DataCode == (byte)S7WordLength.Timer)
{
numArray[22 + (index * 12)] = siemensAddress[index].DataCode;
numArray[23 + (index * 12)] = (byte)(siemensAddress[index].Length / 256);
numArray[24 + (index * 12)] = (byte)(siemensAddress[index].Length % 256);
}
else
{
numArray[22 + (index * 12)] = (byte)S7WordLength.Byte;
numArray[23 + (index * 12)] = (byte)(siemensAddress[index].Length / 256);
numArray[24 + (index * 12)] = (byte)(siemensAddress[index].Length % 256);
}
numArray[25 + (index * 12)] = (byte)(siemensAddress[index].DbBlock / 256U);
numArray[26 + (index * 12)] = (byte)(siemensAddress[index].DbBlock % 256U);
numArray[27 + (index * 12)] = siemensAddress[index].DataCode;
numArray[28 + (index * 12)] = (byte)(siemensAddress[index].AddressStart / 256 / 256 % 256);
numArray[29 + (index * 12)] = (byte)(siemensAddress[index].AddressStart / 256 % 256);
numArray[30 + (index * 12)] = (byte)(siemensAddress[index].AddressStart % 256);
}
return OperResult.CreateSuccessResult(numArray);
}
internal static OperResult<byte[]> GetWriteBitCommand(SiemensAddress address, bool data)
{
int len = 1;
int telegramLen = 16 + 19 + len;//最后的1是写入值的byte数量
int parameterLen = 12 + 2;
byte[] numArray = new byte[telegramLen];
Array.Copy(S7_MULRW_HEADER, 0, numArray, 0, S7_MULRW_HEADER.Length);
numArray[2] = (byte)(telegramLen / 256);
numArray[3] = (byte)(telegramLen % 256);
numArray[13] = (byte)(parameterLen / 256);
numArray[14] = (byte)(parameterLen % 256);
numArray[15] = (byte)((4 + len) / 256);
numArray[16] = (byte)((4 + len) % 256);
numArray[17] = 5;
numArray[18] = (byte)1;
//写入Item与读取大致相同
numArray[19] = (byte)18;
numArray[20] = (byte)10;
numArray[21] = (byte)16;
numArray[22] = (byte)S7WordLength.Bit;
numArray[23] = (byte)(len / 256);
numArray[24] = (byte)(len % 256);
numArray[25] = (byte)(address.DbBlock / 256U);
numArray[26] = (byte)(address.DbBlock % 256U);
numArray[27] = (byte)address.DataCode;
numArray[28] = (byte)((address.AddressStart + address.BitCode) / 256 / 256);
numArray[29] = (byte)((address.AddressStart + address.BitCode) / 256);
numArray[30] = (byte)((address.AddressStart + address.BitCode) % 256);
//后面跟的是写入的数据信息
numArray[31] = 0;
numArray[32] = 3;//Bit:3;Byte:4;Counter或者Timer:9
numArray[33] = (byte)(len / 256);
numArray[34] = (byte)(len % 256);
numArray[35] = (byte)(data ? 1 : 0);
return OperResult.CreateSuccessResult(numArray);
}
internal static OperResult<byte[]> GetWriteByteCommand(SiemensAddress address, byte[] data)
{
int len = data.Length;
int telegramLen = 16 + 19 + len;//最后的1是写入值的byte数量
int parameterLen = 12 + 2;
byte[] numArray = new byte[telegramLen];
Array.Copy(S7_MULRW_HEADER, 0, numArray, 0, S7_MULRW_HEADER.Length);
numArray[2] = (byte)(telegramLen / 256);
numArray[3] = (byte)(telegramLen % 256);
numArray[13] = (byte)(parameterLen / 256);
numArray[14] = (byte)(parameterLen % 256);
numArray[15] = (byte)((4 + len) / 256);
numArray[16] = (byte)((4 + len) % 256);
numArray[17] = 5;
numArray[18] = (byte)1;
//写入Item与读取大致相同
numArray[19] = (byte)18;
numArray[20] = (byte)10;
numArray[21] = (byte)16;
numArray[22] = (byte)S7WordLength.Byte;
numArray[23] = (byte)(len / 256);
numArray[24] = (byte)(len % 256);
numArray[25] = (byte)(address.DbBlock / 256U);
numArray[26] = (byte)(address.DbBlock % 256U);
numArray[27] = (byte)address.DataCode;
numArray[28] = (byte)(address.AddressStart / 256 / 256);
numArray[29] = (byte)(address.AddressStart / 256);
numArray[30] = (byte)(address.AddressStart % 256);
//后面跟的是写入的数据信息
numArray[31] = 0;
numArray[32] = 4;//Bit:3;Byte:4;Counter或者Timer:9
numArray[33] = (byte)(len * 8 / 256);
numArray[34] = (byte)(len * 8 % 256);
data.CopyTo(numArray, 35);
return OperResult.CreateSuccessResult(numArray);
}
#endregion
#region
internal static async Task<OperResult<string>> ReadStringAsync(SiemensS7PLC plc, string address, Encoding encoding, CancellationToken cancellationToken)
{
//先读取一次获取长度,再读取实际值
if (plc.CurrentPlc != SiemensEnum.S200Smart)
{
var result1 = await plc.ReadAsync(address, 2, cancellationToken);
if (!result1.IsSuccess)
{
return new(result1);
}
if (result1.Content[0] == (byte)0 || result1.Content[0] == byte.MaxValue)
{
return new OperResult<string>("在PLC中不是字符串类型");
}
var result2 = await plc.ReadAsync(address, 2 + result1.Content[1], cancellationToken);
if (!result2.IsSuccess)
{
return new(result2);
}
else
{
return OperResult.CreateSuccessResult(encoding.GetString(result2.Content, 2, result2.Content.Length - 2));
}
}
else
{
var result1 = await plc.ReadAsync(address, 1, cancellationToken);
if (!result1.IsSuccess)
return new(result1);
var result2 = await plc.ReadAsync(address, 1 + result1.Content[0], cancellationToken);
if (!result2.IsSuccess)
{
return new(result2);
}
else
{
return OperResult.CreateSuccessResult(encoding.GetString(result2.Content, 1, result2.Content.Length - 1));
}
}
}
internal static async Task<OperResult> WriteAsync(SiemensS7PLC plc, string address, string value, Encoding encoding)
{
value ??= string.Empty;
byte[] inBytes = encoding.GetBytes(value);
//if (encoding == Encoding.Unicode)
// inBytes = inBytes.BytesReverseByWord();
if (plc.CurrentPlc != SiemensEnum.S200Smart)
{
OperResult<byte[]> result = await plc.ReadAsync(address, 2);
if (!result.IsSuccess) return result;
if (result.Content[0] == byte.MaxValue) return new OperResult<string>("在PLC中不是字符串类型");
if (result.Content[0] == 0) result.Content[0] = 254;
if (value.Length > result.Content[0]) return new OperResult<string>("写入值长度超限");
return await plc.WriteAsync(
address,
GenericExtensions.SpliceArray(new byte[2] { result.Content[0], (byte)value.Length },
inBytes
));
}
return await plc.WriteAsync(address, GenericExtensions.SpliceArray<byte>(new byte[1]
{
(byte) value.Length
}, inBytes));
}
#endregion
}
/// <summary>
/// <inheritdoc/>
/// </summary>
public enum S7WordLength : byte
{
/// <inheritdoc/>
Bit = 0x01,
/// <inheritdoc/>
Byte = 0x02,
/// <inheritdoc/>
Char = 0x03,
/// <inheritdoc/>
Word = 0x04,
/// <inheritdoc/>
Int = 0x05,
/// <inheritdoc/>
DWord = 0x06,
/// <inheritdoc/>
DInt = 0x07,
/// <inheritdoc/>
Real = 0x08,
/// <inheritdoc/>
Counter = 0x1C,
/// <inheritdoc/>
Timer = 0x1D,
}