feat: S7PLC增加WString支持

This commit is contained in:
Diego
2025-07-02 12:49:55 +08:00
parent b06405717d
commit 83736647e7
24 changed files with 347 additions and 154 deletions

View File

@@ -1,8 +1,8 @@
<Project>
<PropertyGroup>
<PluginVersion>10.9.9</PluginVersion>
<ProPluginVersion>10.9.9</ProPluginVersion>
<PluginVersion>10.9.10</PluginVersion>
<ProPluginVersion>10.9.10</ProPluginVersion>
<AuthenticationVersion>2.9.5</AuthenticationVersion>
<SourceGeneratorVersion>10.9.5</SourceGeneratorVersion>
<NET8Version>8.0.17</NET8Version>

View File

@@ -131,7 +131,7 @@ public abstract class DeviceBase : DisposableObject, IDevice
public virtual int RegisterByteLength { get; protected set; } = 1;
/// <inheritdoc/>
public virtual IThingsGatewayBitConverter ThingsGatewayBitConverter { get; protected set; } = new ThingsGatewayBitConverter();
public virtual IThingsGatewayBitConverter ThingsGatewayBitConverter { get; } = new ThingsGatewayBitConverter();
/// <inheritdoc/>
public bool OnLine => Channel.Online;

View File

@@ -325,6 +325,7 @@ public interface IThingsGatewayBitConverter
/// <param name="length">length</param>
/// <returns>decimal对象</returns>
decimal[] ToDecimal(byte[] buffer, int offset, int length);
IThingsGatewayBitConverter GetTransByAddress(string? registerAddress);
#endregion ToValue
}

View File

@@ -14,6 +14,7 @@ using System.Runtime.CompilerServices;
using System.Text;
using ThingsGateway.Foundation.Extension.Generic;
using ThingsGateway.Foundation.Extension.String;
namespace ThingsGateway.Foundation;
@@ -87,6 +88,132 @@ public partial class ThingsGatewayBitConverter : IThingsGatewayBitConverter
/// </summary>
public static readonly ThingsGatewayBitConverter LittleEndian;
public virtual void OtherPropertySet(IThingsGatewayBitConverter thingsGatewayBitConverter, string registerAddress)
{
}
/// <summary>
/// 从设备地址中解析附加信息
/// 这个方法获取<see cref="IThingsGatewayBitConverter"/>
/// 解析步骤将被缓存。
/// </summary>
/// <param name="registerAddress">设备地址</param>
/// <returns><see cref="IThingsGatewayBitConverter"/> 实例</returns>
public virtual IThingsGatewayBitConverter GetTransByAddress(string? registerAddress)
{
if (registerAddress.IsNullOrEmpty()) return this;
var type = this.GetType();
// 尝试从缓存中获取解析结果
//var cacheKey = $"{nameof(ThingsGatewayBitConverterExtension)}_{nameof(GetTransByAddress)}_{type.FullName}_{type.TypeHandle.Value}_{this.ToJsonString()}_{registerAddress}_{this.GetHashCode()}";
//if (MemoryCache.TryGetValue(cacheKey, out IThingsGatewayBitConverter cachedConverter))
//{
// if (cachedConverter.Equals(this))
// {
// return this;
// }
// else
// {
// return (IThingsGatewayBitConverter)cachedConverter.Map(type);
// }
//}
// 去除设备地址两端的空格
registerAddress = registerAddress.Trim();
// 根据分号拆分附加信息
var strs = registerAddress.SplitStringBySemicolon();
DataFormatEnum? dataFormat = null;
Encoding? encoding = null;
bool? wstring = null;
int? stringlength = null;
BcdFormatEnum? bcdFormat = null;
StringBuilder sb = new();
foreach (var str in strs)
{
// 解析 dataFormat
if (str.StartsWith("data=", StringComparison.OrdinalIgnoreCase))
{
var dataFormatName = str.Substring(5);
try { if (Enum.TryParse<DataFormatEnum>(dataFormatName, true, out var dataFormat1)) dataFormat = dataFormat1; } catch { }
}
else if (str.StartsWith("vsl=", StringComparison.OrdinalIgnoreCase))
{
var wstringName = str.Substring(4);
try { if (bool.TryParse(wstringName, out var wstring1)) wstring = wstring1; } catch { }
}
// 解析 encoding
else if (str.StartsWith("encoding=", StringComparison.OrdinalIgnoreCase))
{
var encodingName = str.Substring(9);
try { encoding = Encoding.GetEncoding(encodingName); } catch { }
}
// 解析 length
else if (str.StartsWith("len=", StringComparison.OrdinalIgnoreCase))
{
var lenStr = str.Substring(4);
stringlength = lenStr.IsNullOrEmpty() ? null : Convert.ToUInt16(lenStr);
}
// 解析 bcdFormat
else if (str.StartsWith("bcd=", StringComparison.OrdinalIgnoreCase))
{
var bcdName = str.Substring(4);
try { if (Enum.TryParse<BcdFormatEnum>(bcdName, true, out var bcdFormat1)) bcdFormat = bcdFormat1; } catch { }
}
// 处理其他情况,将未识别的部分拼接回去
else
{
if (sb.Length > 0)
sb.Append($";{str}");
else
sb.Append($"{str}");
}
}
// 更新设备地址为去除附加信息后的地址
registerAddress = sb.ToString();
var converter = (IThingsGatewayBitConverter)this!.Map(type);
// 如果没有解析出任何附加信息,则直接返回默认的数据转换器
if (bcdFormat == null && stringlength == null && encoding == null && dataFormat == null && wstring == null)
{
//MemoryCache.Set(cacheKey, this!, 3600);
return converter;
}
// 根据默认的数据转换器创建新的数据转换器实例
// 更新新的数据转换器实例的属性值
if (encoding != null)
{
converter.Encoding = encoding;
}
if (bcdFormat != null)
{
converter.BcdFormat = bcdFormat.Value;
}
if (wstring != null)
{
converter.IsVariableStringLength = wstring.Value;
}
if (stringlength != null)
{
converter.StringLength = stringlength.Value;
}
if (dataFormat != null)
{
converter.DataFormat = dataFormat.Value;
}
OtherPropertySet(converter, registerAddress);
// 将解析结果添加到缓存中缓存有效期为3600秒
//MemoryCache.Set(cacheKey, converter!, 3600);
return converter;
}
#region GetBytes
/// <inheritdoc/>

View File

@@ -10,10 +10,6 @@
using Newtonsoft.Json.Linq;
using System.Text;
using ThingsGateway.Foundation.Extension.String;
namespace ThingsGateway.Foundation;
/// <summary>
@@ -23,126 +19,6 @@ public static class ThingsGatewayBitConverterExtension
{
//private static MemoryCache MemoryCache = new() { Capacity = 10000000 };
/// <summary>
/// 从设备地址中解析附加信息
/// 这个方法获取<see cref="IThingsGatewayBitConverter"/>
/// 解析步骤将被缓存。
/// </summary>
/// <param name="registerAddress">设备地址</param>
/// <param name="defaultBitConverter">默认的数据转换器</param>
/// <returns><see cref="IThingsGatewayBitConverter"/> 实例</returns>
public static IThingsGatewayBitConverter GetTransByAddress(this IThingsGatewayBitConverter defaultBitConverter, string? registerAddress)
{
if (registerAddress.IsNullOrEmpty()) return defaultBitConverter;
var type = defaultBitConverter.GetType();
// 尝试从缓存中获取解析结果
//var cacheKey = $"{nameof(ThingsGatewayBitConverterExtension)}_{nameof(GetTransByAddress)}_{type.FullName}_{type.TypeHandle.Value}_{defaultBitConverter.ToJsonString()}_{registerAddress}_{defaultBitConverter.GetHashCode()}";
//if (MemoryCache.TryGetValue(cacheKey, out IThingsGatewayBitConverter cachedConverter))
//{
// if (cachedConverter.Equals(defaultBitConverter))
// {
// return defaultBitConverter;
// }
// else
// {
// return (IThingsGatewayBitConverter)cachedConverter.Map(type);
// }
//}
// 去除设备地址两端的空格
registerAddress = registerAddress.Trim();
// 根据分号拆分附加信息
var strs = registerAddress.SplitStringBySemicolon();
DataFormatEnum? dataFormat = null;
Encoding? encoding = null;
bool? wstring = null;
int? stringlength = null;
BcdFormatEnum? bcdFormat = null;
StringBuilder sb = new();
foreach (var str in strs)
{
// 解析 dataFormat
if (str.StartsWith("data=", StringComparison.OrdinalIgnoreCase))
{
var dataFormatName = str.Substring(5);
try { if (Enum.TryParse<DataFormatEnum>(dataFormatName, true, out var dataFormat1)) dataFormat = dataFormat1; } catch { }
}
else if (str.StartsWith("vsl=", StringComparison.OrdinalIgnoreCase))
{
var wstringName = str.Substring(4);
try { if (bool.TryParse(wstringName, out var wstring1)) wstring = wstring1; } catch { }
}
// 解析 encoding
else if (str.StartsWith("encoding=", StringComparison.OrdinalIgnoreCase))
{
var encodingName = str.Substring(9);
try { encoding = Encoding.GetEncoding(encodingName); } catch { }
}
// 解析 length
else if (str.StartsWith("len=", StringComparison.OrdinalIgnoreCase))
{
var lenStr = str.Substring(4);
stringlength = lenStr.IsNullOrEmpty() ? null : Convert.ToUInt16(lenStr);
}
// 解析 bcdFormat
else if (str.StartsWith("bcd=", StringComparison.OrdinalIgnoreCase))
{
var bcdName = str.Substring(4);
try { if (Enum.TryParse<BcdFormatEnum>(bcdName, true, out var bcdFormat1)) bcdFormat = bcdFormat1; } catch { }
}
// 处理其他情况,将未识别的部分拼接回去
else
{
if (sb.Length > 0)
sb.Append($";{str}");
else
sb.Append($"{str}");
}
}
// 更新设备地址为去除附加信息后的地址
registerAddress = sb.ToString();
// 如果没有解析出任何附加信息,则直接返回默认的数据转换器
if (bcdFormat == null && stringlength == null && encoding == null && dataFormat == null && wstring == null)
{
//MemoryCache.Set(cacheKey, defaultBitConverter!, 3600);
return defaultBitConverter;
}
// 根据默认的数据转换器创建新的数据转换器实例
var converter = (IThingsGatewayBitConverter)defaultBitConverter!.Map(type);
// 更新新的数据转换器实例的属性值
if (encoding != null)
{
converter.Encoding = encoding;
}
if (bcdFormat != null)
{
converter.BcdFormat = bcdFormat.Value;
}
if (wstring != null)
{
converter.IsVariableStringLength = wstring.Value;
}
if (stringlength != null)
{
converter.StringLength = stringlength.Value;
}
if (dataFormat != null)
{
converter.DataFormat = dataFormat.Value;
}
// 将解析结果添加到缓存中缓存有效期为3600秒
//MemoryCache.Set(cacheKey, converter!, 3600);
return converter;
}
#region

View File

@@ -128,6 +128,7 @@ public class Variable : BaseDataEntity, IValidatableObject
[IgnoreExcel]
[Required]
[NotNull]
[MinValue(1)]
public virtual long DeviceId { get => deviceId; set => deviceId = value; }
/// <summary>

View File

@@ -18,6 +18,7 @@ namespace ThingsGateway.Gateway.Application
{
Task<bool> BatchEditAsync(IEnumerable<Variable> models, Variable oldModel, Variable model, bool restart, CancellationToken cancellationToken);
Task<bool> DeleteVariableAsync(IEnumerable<long> ids, bool restart, CancellationToken cancellationToken);
Task<bool> ClearVariableAsync(bool restart, CancellationToken cancellationToken);
Task<Dictionary<string, object>> ExportVariableAsync(ExportFilter exportFilter);
Task ImportVariableAsync(Dictionary<string, ImportPreviewOutputBase> input, bool restart, CancellationToken cancellationToken);

View File

@@ -106,13 +106,14 @@ public class VariableRuntimeService : IVariableRuntimeService
var result = await GlobalData.VariableService.DeleteVariableAsync(variableIds).ConfigureAwait(false);
ConcurrentHashSet<IDriver> changedDriver = new();
RuntimeServiceHelper.AddBusinessChangedDriver(variableIds, changedDriver);
RuntimeServiceHelper.VariableRuntimesDispose(variableIds);
if (restart)
{
ConcurrentHashSet<IDriver> changedDriver = new();
RuntimeServiceHelper.AddBusinessChangedDriver(variableIds, changedDriver);
RuntimeServiceHelper.VariableRuntimesDispose(variableIds);
await RuntimeServiceHelper.ChangedDriverAsync(changedDriver, _logger, cancellationToken).ConfigureAwait(false);
}
@@ -125,6 +126,38 @@ public class VariableRuntimeService : IVariableRuntimeService
}
public async Task<bool> ClearVariableAsync(bool restart, CancellationToken cancellationToken)
{
try
{
// await WaitLock.WaitAsync().ConfigureAwait(false);
var result = await GlobalData.VariableService.DeleteVariableAsync(null).ConfigureAwait(false);
if (restart)
{
ConcurrentHashSet<IDriver> changedDriver = new();
var variableIds = GlobalData.IdVariables.Select(a => a.Key).ToHashSet();
RuntimeServiceHelper.AddBusinessChangedDriver(variableIds, changedDriver);
RuntimeServiceHelper.VariableRuntimesDispose(variableIds);
await RuntimeServiceHelper.ChangedDriverAsync(changedDriver, _logger, cancellationToken).ConfigureAwait(false);
}
return true;
}
finally
{
//WaitLock.Release();
}
}
public Task<Dictionary<string, object>> ExportVariableAsync(ExportFilter exportFilter) => GlobalData.VariableService.ExportVariableAsync(exportFilter);
public async Task ImportVariableAsync(Dictionary<string, ImportPreviewOutputBase> input, bool restart, CancellationToken cancellationToken)

View File

@@ -335,8 +335,8 @@ internal sealed class VariableService : BaseService<Variable>, IVariableService
{
using var db = GetDB();
var dataScope = await GlobalData.SysUserService.GetCurrentUserDataScopeAsync().ConfigureAwait(false);
var ids = input.ToList();
var result = (await db.Deleteable<Variable>().Where(a => ids.Contains(a.Id))
var ids = input?.ToList();
var result = (await db.Deleteable<Variable>().WhereIF(input != null, a => ids.Contains(a.Id))
.WhereIF(dataScope != null && dataScope?.Count > 0, u => dataScope.Contains(u.CreateOrgId))//在指定机构列表查询
.WhereIF(dataScope?.Count == 0, u => u.CreateUserId == UserManager.UserId)
.ExecuteCommandAsync().ConfigureAwait(false)) > 0;

View File

@@ -424,7 +424,7 @@ finally
await Task.Run(async () =>
{
await GlobalData.VariableRuntimeService.DeleteVariableAsync(Items.Select(a => a.Id), AutoRestartThread, default);
await GlobalData.VariableRuntimeService.ClearVariableAsync(AutoRestartThread, default);
await InvokeAsync(async () =>
{
await ToastService.Default();

View File

@@ -24,7 +24,7 @@ public class Dlt645_2007Master : DtuServiceDeviceBase
RegisterByteLength = 2;
channel.MaxSign = ushort.MaxValue;
}
public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get; protected set; } = new Dlt645_2007BitConverter(EndianType.Big) { };
public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get; } = new Dlt645_2007BitConverter(EndianType.Big) { };
/// <inheritdoc/>
public string FEHead { get; set; } = "FEFEFEFE";

View File

@@ -30,7 +30,7 @@ public partial class ModbusMaster : DtuServiceDeviceBase, IModbusAddress
}
}
public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get; protected set; } = new ThingsGatewayBitConverter(EndianType.Big) { };
public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get; } = new ThingsGatewayBitConverter(EndianType.Big) { };
/// <summary>
/// Modbus类型在initChannelAsync之前设置

View File

@@ -51,7 +51,7 @@ public class ModbusSlave : DeviceBase, IModbusAddress
RegisterByteLength = 2;
channel.MaxSign = ushort.MaxValue;
}
public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get; protected set; } = new ThingsGatewayBitConverter(EndianType.Big) { };
public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get; } = new ThingsGatewayBitConverter(EndianType.Big) { };
public override bool SupportMultipleDevice()
{

View File

@@ -3,7 +3,8 @@
"AddressStart": "AddressStart",
"BitCode": "BitBitCode",
"DataCode": "DataCode",
"DbBlock": "DbBlock"
"DbBlock": "DbBlock",
"WStringEnable": "WString"
},
"ThingsGateway.Foundation.SiemensS7.SiemensS7Master": {
"LocalTSAP": "LocalTSAP",

View File

@@ -3,7 +3,8 @@
"AddressStart": "起始地址",
"BitCode": "Bit地址",
"DataCode": "寄存器区",
"DbBlock": "DB块"
"DbBlock": "DB块",
"WStringEnable": "WString"
},
"ThingsGateway.Foundation.SiemensS7.SiemensS7Master": {
"LocalTSAP": "本地TSAP",

View File

@@ -24,18 +24,44 @@ public class S7BitConverter : ThingsGatewayBitConverter
public S7BitConverter(EndianType endianType) : base(endianType)
{
}
public bool SMART200 { get; set; } = false;
public bool WStringEnable { get; set; } = false;
public override int? StringLength { get; set; } = 100;
/// <inheritdoc/>
public override string ToString(byte[] buffer, int offset, int length)
{
if (!IsVariableStringLength)
if (WStringEnable)
{
return base.ToString(buffer, offset, length);
if (!SMART200)
return base.ToString(buffer, offset, this.ToUInt16(buffer, offset - 2) * 2);
else
return base.ToString(buffer, offset, buffer[offset - 1] * 2);
}
else if (IsVariableStringLength)
{
if (!SMART200)
return base.ToString(buffer, offset, buffer[offset - 1]);
else
return base.ToString(buffer, offset, buffer[offset - 1]);
}
else
{
return base.ToString(buffer, offset, buffer[offset - 1]);
return base.ToString(buffer, offset, length);
}
}
public override void OtherPropertySet(IThingsGatewayBitConverter thingsGatewayBitConverter, string registerAddress)
{
if (thingsGatewayBitConverter is not S7BitConverter s7BitConverter)
{
return;
}
var sAddress = SiemensS7Address.ParseFrom(registerAddress);
s7BitConverter.WStringEnable = sAddress.WStringEnable;
base.OtherPropertySet(thingsGatewayBitConverter, registerAddress);
}
}

View File

@@ -21,6 +21,8 @@ namespace ThingsGateway.Foundation.SiemensS7;
/// </summary>
public class SiemensS7Address : S7Request
{
public bool WStringEnable { get; set; }
public SiemensS7Address()
{
}
@@ -42,6 +44,7 @@ public class SiemensS7Address : S7Request
public override string ToString()
{
StringBuilder stringBuilder = Pool.StringBuilder.Get();
stringBuilder.Append($"W={WStringEnable};");
if (DataCode == S7Area.TM)
{
stringBuilder.Append($"T{AddressStart}");
@@ -273,6 +276,10 @@ public class SiemensS7Address : S7Request
throw new Exception(string.Format(AppResource.AddressError, address));
}
}
else if (strArr[index].StartsWith("W=", StringComparison.OrdinalIgnoreCase))
{
s7AddressData.WStringEnable = strArr[index].Substring(2).ToBoolean(false);
}
}
//if (isCache)

View File

@@ -8,6 +8,8 @@
// QQ群605534569
//------------------------------------------------------------------------------
using System.Text;
namespace ThingsGateway.Foundation.SiemensS7;
internal static class PackHelper
@@ -49,6 +51,13 @@ internal static class PackHelper
{
// 解析SiemensS7Address对象
var s7Address = SiemensS7Address.ParseFrom(it.RegisterAddress);
// 根据地址获取转换参数
if (it.ThingsGatewayBitConverter is S7BitConverter s7BitConverter)
{
s7BitConverter.WStringEnable = s7Address.WStringEnable;
}
int lastLen = it.DataType.GetByteLength();
// 处理特殊情况下的长度
@@ -76,10 +85,23 @@ internal static class PackHelper
{
lastLen = it.ThingsGatewayBitConverter.StringLength.Value;
}
if (s7Address.WStringEnable)
{
it.ThingsGatewayBitConverter.Encoding = Encoding.Unicode;
}
}
else
{
if (it.ThingsGatewayBitConverter.IsVariableStringLength)
if (s7Address.WStringEnable)
{
// 字符串在S7中前四个字节不属于实际内容
it.Index += 4;
lastLen = it.ThingsGatewayBitConverter.StringLength.Value + 4;
it.ThingsGatewayBitConverter.Encoding = Encoding.BigEndianUnicode;
}
else if (it.ThingsGatewayBitConverter.IsVariableStringLength)
{
// 字符串在S7中前两个字节不属于实际内容
it.Index += 2;

View File

@@ -106,7 +106,7 @@ internal sealed partial class SiemensHelper
}
}
internal static async ValueTask<OperResult> WriteAsync(SiemensS7Master plc, string address, string value, Encoding encoding, CancellationToken cancellationToken = default)
internal static async ValueTask<OperResult> WriteStringAsync(SiemensS7Master plc, string address, string value, Encoding encoding, CancellationToken cancellationToken = default)
{
value ??= string.Empty;
byte[] inBytes = encoding.GetBytes(value);
@@ -125,4 +125,71 @@ internal sealed partial class SiemensHelper
}
return await plc.WriteAsync(address, DataTransUtil.SpliceArray([(byte)value.Length], inBytes), DataTypeEnum.String, cancellationToken).ConfigureAwait(false);
}
internal static async ValueTask<OperResult<string>> ReadWStringAsync(SiemensS7Master plc, string address, CancellationToken cancellationToken)
{
//先读取一次获取长度,再读取实际值
if (plc.SiemensS7Type != SiemensTypeEnum.S200Smart)
{
var encoding = Encoding.BigEndianUnicode;
var result1 = await plc.ReadAsync(address, 4, cancellationToken).ConfigureAwait(false);
if (!result1.IsSuccess)
{
return new OperResult<string>(result1);
}
if (result1.Content[0] == 0 || result1.Content[0] == byte.MaxValue)
{
return new OperResult<string>(AppResource.NotString);
}
var result2 = await plc.ReadAsync(address, 4 + (plc.ThingsGatewayBitConverter.ToUInt16(result1.Content, 2) * 2), cancellationToken).ConfigureAwait(false);
if (!result2.IsSuccess)
{
return new OperResult<string>(result2);
}
else
{
return OperResult.CreateSuccessResult(encoding.GetString(result2.Content, 4, result2.Content.Length - 4));
}
}
else
{
var encoding = Encoding.Unicode;
var result1 = await plc.ReadAsync(address, 1, cancellationToken).ConfigureAwait(false);
if (!result1.IsSuccess)
return new OperResult<string>(result1);
var result2 = await plc.ReadAsync(address, 1 + (result1.Content[0] * 2), cancellationToken).ConfigureAwait(false);
if (!result2.IsSuccess)
{
return new OperResult<string>(result2);
}
else
{
return OperResult.CreateSuccessResult(encoding.GetString(result2.Content, 1, result2.Content.Length - 1));
}
}
}
internal static async ValueTask<OperResult> WriteWStringAsync(SiemensS7Master plc, string address, string value, CancellationToken cancellationToken = default)
{
value ??= string.Empty;
if (plc.SiemensS7Type != SiemensTypeEnum.S200Smart)
{
byte[] inBytes1 = Encoding.BigEndianUnicode.GetBytes(value);
var result = await plc.ReadAsync(address, 4, cancellationToken).ConfigureAwait(false);
if (!result.IsSuccess) return result;
var num = plc.ThingsGatewayBitConverter.ToUInt16(result.Content, 0);
if (num == 0)
num = 254;
if (value.Length > num) return new OperResult<string>(AppResource.WriteDataLengthMore);
return await plc.WriteAsync(
address,
DataTransUtil.SpliceArray(plc.ThingsGatewayBitConverter.GetBytes(num), plc.ThingsGatewayBitConverter.GetBytes((ushort)value.Length),
inBytes1
), DataTypeEnum.String, cancellationToken).ConfigureAwait(false);
}
byte[] inBytes2 = Encoding.Unicode.GetBytes(value);
return await plc.WriteAsync(address, DataTransUtil.SpliceArray([(byte)value.Length], inBytes2), DataTypeEnum.String, cancellationToken).ConfigureAwait(false);
}
}

View File

@@ -32,8 +32,8 @@ public partial class SiemensS7Master : DeviceBase
{
}
public override IThingsGatewayBitConverter ThingsGatewayBitConverter { get; protected set; } = new S7BitConverter(EndianType.Big) { };
public override IThingsGatewayBitConverter ThingsGatewayBitConverter => s7BitConverter;
private S7BitConverter s7BitConverter = new S7BitConverter(EndianType.Big) { };
/// <summary>
/// PduLength
/// </summary>
@@ -54,7 +54,14 @@ public partial class SiemensS7Master : DeviceBase
/// <summary>
/// S7类型
/// </summary>
public SiemensTypeEnum SiemensS7Type { get; set; }
public SiemensTypeEnum SiemensS7Type
{
get => siemensS7Type; set
{
siemensS7Type = value;
s7BitConverter.SMART200 = value == SiemensTypeEnum.S200Smart;
}
}
/// <summary>
/// 槽号,需重新连接
@@ -371,6 +378,8 @@ public partial class SiemensS7Master : DeviceBase
#region
private WaitLock ChannelStartedWaitLock = new();
private SiemensTypeEnum siemensS7Type;
/// <inheritdoc/>
protected override async ValueTask<bool> ChannelStarted(IClientChannel channel, bool last)
{
@@ -553,7 +562,24 @@ public partial class SiemensS7Master : DeviceBase
public override async ValueTask<OperResult<string[]>> ReadStringAsync(string address, int length, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
if (bitConverter.IsVariableStringLength)
if (((S7BitConverter)bitConverter)?.WStringEnable == true)
{
if (length > 1)
{
return new OperResult<string[]>(AppResource.StringLengthReadError);
}
var result = await SiemensHelper.ReadWStringAsync(this, address, cancellationToken).ConfigureAwait(false);
if (result.IsSuccess)
{
return OperResult.CreateSuccessResult(new string[] { result.Content });
}
else
{
return new OperResult<string[]>(result);
}
}
else if (bitConverter.IsVariableStringLength)
{
if (length > 1)
{
@@ -579,9 +605,14 @@ public partial class SiemensS7Master : DeviceBase
public override ValueTask<OperResult> WriteAsync(string address, string value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
if (((S7BitConverter)bitConverter)?.WStringEnable == true)
{
return SiemensHelper.WriteWStringAsync(this, address, value, cancellationToken);
}
if (bitConverter.IsVariableStringLength)
{
return SiemensHelper.WriteAsync(this, address, value, bitConverter.Encoding, cancellationToken);
return SiemensHelper.WriteStringAsync(this, address, value, bitConverter.Encoding, cancellationToken);
}
else
{

View File

@@ -95,11 +95,11 @@
<div class="col-12 col-md-12 min-height-500">
<BootstrapLabel Value=@Localizer["BigTextScriptRpc"] ShowLabelTooltip="true" />
<CodeEditor ShowLineNo @bind-Value=@clientProperty.BigTextScriptRpc Language="csharp" Theme="vs-dark" IsReadonly=@(!CanWrite) />
<div class="ms-2 d-flex justify-content-center align-items-center">
@* <div class="ms-2 d-flex justify-content-center align-items-center">
<Button IsDisabled=@(!CanWrite) OnClick=@(() => PropertyComponent.CheckScript(clientProperty, nameof(clientProperty.BigTextScriptRpc), Localizer["check"], this, DialogService))>
@Localizer["Check"]
</Button>
</div>
</div> *@
</div>
</EditTemplate>

View File

@@ -14,8 +14,6 @@ using BootstrapBlazor.Components;
using Microsoft.AspNetCore.Components;
using Microsoft.Extensions.Localization;
using ThingsGateway.Gateway.Razor;
using ThingsGateway.NewLife.Json.Extension;
using ThingsGateway.Razor;
namespace ThingsGateway.Plugin.Mqtt

View File

@@ -15,6 +15,7 @@
<EditorItem @bind-Field=context.BitCode />
<EditorItem @bind-Field=context.DataCode />
<EditorItem @bind-Field=context.DbBlock />
<EditorItem @bind-Field=context.WStringEnable />
</FieldItems>
</EditorFormObject>

View File

@@ -1,6 +1,6 @@
<Project>
<PropertyGroup>
<Version>10.9.9</Version>
<Version>10.9.10</Version>
</PropertyGroup>
<ItemGroup>