mirror of
https://gitee.com/ThingsGateway/ThingsGateway.git
synced 2025-10-22 19:43:07 +08:00
383 lines
14 KiB
C#
383 lines
14 KiB
C#
#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,
|
||
} |