Files
ThingsGateway/src/Foundation/ThingsGateway.Foundation/Device/DeviceBase.cs
2025-05-07 22:08:54 +08:00

1006 lines
42 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.

//------------------------------------------------------------------------------
// 此代码版权声明为全文件覆盖,如有原作者特别声明,会在下方手动补充
// 此代码版权除特别声明外的代码归作者本人Diego所有
// 源代码使用协议遵循本仓库的开源协议及附加协议
// Gitee源代码仓库https://gitee.com/diego2098/ThingsGateway
// Github源代码仓库https://github.com/kimdiego2098/ThingsGateway
// 使用文档https://thingsgateway.cn/
// QQ群605534569
//------------------------------------------------------------------------------
using Newtonsoft.Json.Linq;
using System.Net;
using ThingsGateway.Foundation.Extension.Generic;
using ThingsGateway.Foundation.Extension.String;
using ThingsGateway.NewLife;
using ThingsGateway.NewLife.Extension;
namespace ThingsGateway.Foundation;
/// <summary>
/// 协议基类
/// </summary>
public abstract class DeviceBase : DisposableObject, IDevice
{
/// <inheritdoc/>
public IChannel Channel { get; private set; }
public virtual bool SupportMultipleDevice()
{
return true;
}
/// <inheritdoc/>
public virtual void InitChannel(IChannel channel, ILog? deviceLog = default)
{
if (channel == null) throw new ArgumentNullException(nameof(channel));
if (channel.Collects.Contains(this))
return;
Channel = channel;
_deviceLogger = deviceLog;
lock (channel)
{
if (channel.Collects.Contains(this))
return;
if (channel.Collects.Count > 0)
{
//var device = channel.Collects.First();
//if (device.GetType() != GetType())
// throw new InvalidOperationException("The channel already exists in the device of another type");
if (!SupportMultipleDevice())
throw new InvalidOperationException("The proactive response device does not support multiple devices");
}
if (channel.Collects.Count == 0)
{
channel.Config.ConfigurePlugins(ConfigurePlugins(channel.Config));
if (Channel is IClientChannel clientChannel)
{
if (clientChannel.ChannelType == ChannelTypeEnum.UdpSession)
{
channel.Config.SetUdpDataHandlingAdapter(() =>
{
var adapter = GetDataAdapter() as UdpDataHandlingAdapter;
return adapter;
});
}
else
{
channel.Config.SetTcpDataHandlingAdapter(() =>
{
var adapter = GetDataAdapter() as SingleStreamDataHandlingAdapter;
return adapter;
});
}
clientChannel.SetDataHandlingAdapter(GetDataAdapter());
}
else if (Channel is ITcpServiceChannel serviceChannel)
{
channel.Config.SetTcpDataHandlingAdapter(() =>
{
var adapter = GetDataAdapter() as SingleStreamDataHandlingAdapter;
return adapter;
});
}
}
channel.Collects.Add(this);
Channel.Starting.Add(ChannelStarting);
Channel.Stoped.Add(ChannelStoped);
Channel.Stoping.Add(ChannelStoping);
Channel.Started.Add(ChannelStarted);
Channel.ChannelReceived.Add(ChannelReceived);
SetChannel();
}
}
protected virtual void SetChannel()
{
Channel.ChannelOptions.MaxConcurrentCount = 1;
}
/// <inheritdoc/>
~DeviceBase()
{
this.SafeDispose();
}
#region
/// <inheritdoc/>
public virtual int SendDelayTime { get; set; }
/// <inheritdoc/>
public virtual int Timeout { get; set; } = 3000;
private ILog? _deviceLogger;
/// <inheritdoc/>
public virtual ILog? Logger
{
get
{
return _deviceLogger ?? Channel?.Logger;
}
}
/// <inheritdoc/>
public virtual int RegisterByteLength { get; protected set; } = 1;
/// <inheritdoc/>
public virtual IThingsGatewayBitConverter ThingsGatewayBitConverter { get; protected set; } = new ThingsGatewayBitConverter();
/// <inheritdoc/>
public bool OnLine => Channel.Online;
/// <summary>
/// <inheritdoc cref="IThingsGatewayBitConverter.IsStringReverseByteWord"/>
/// </summary>
public bool IsStringReverseByteWord
{
get
{
return ThingsGatewayBitConverter.IsStringReverseByteWord;
}
set
{
ThingsGatewayBitConverter.IsStringReverseByteWord = value;
}
}
/// <inheritdoc/>
public virtual DataFormatEnum DataFormat
{
get => ThingsGatewayBitConverter.DataFormat;
set => ThingsGatewayBitConverter.DataFormat = value;
}
#endregion
#region
/// <inheritdoc/>
public abstract DataHandlingAdapter GetDataAdapter();
/// <summary>
/// 通道连接成功时如果通道存在其他设备并且不希望其他设备处理时返回true
/// </summary>
protected virtual ValueTask<bool> ChannelStarted(IClientChannel channel, bool last)
{
return EasyValueTask.FromResult(true);
}
/// <summary>
/// 通道断开连接前如果通道存在其他设备并且不希望其他设备处理时返回true
/// </summary>
protected virtual ValueTask<bool> ChannelStoping(IClientChannel channel, bool last)
{
return EasyValueTask.FromResult(true);
}
/// <summary>
/// 通道断开连接后如果通道存在其他设备并且不希望其他设备处理时返回true
/// </summary>
protected ValueTask<bool> ChannelStoped(IClientChannel channel, bool last)
{
try
{
channel.WaitHandlePool.CancelAll();
}
catch
{
}
return EasyValueTask.FromResult(true);
}
/// <summary>
/// 通道即将连接成功时会设置适配器如果通道存在其他设备并且不希望其他设备处理时返回true
/// </summary>
protected virtual ValueTask<bool> ChannelStarting(IClientChannel channel, bool last)
{
if (channel.ReadOnlyDataHandlingAdapter != null)
{
channel.ReadOnlyDataHandlingAdapter.Logger = Logger;
}
return EasyValueTask.FromResult(true);
}
/// <summary>
/// 设置适配器
/// </summary>
protected virtual void SetDataAdapter(IClientChannel clientChannel)
{
var adapter = clientChannel.ReadOnlyDataHandlingAdapter;
if (adapter == null)
{
var dataHandlingAdapter = GetDataAdapter();
clientChannel.SetDataHandlingAdapter(dataHandlingAdapter);
}
else
{
if (Channel?.Collects?.Count > 1)
{
var dataHandlingAdapter = GetDataAdapter();
if (adapter.GetType() != dataHandlingAdapter.GetType())
{
clientChannel.SetDataHandlingAdapter(dataHandlingAdapter);
}
}
}
}
#endregion
#region
/// <inheritdoc/>
public abstract List<T> LoadSourceRead<T>(IEnumerable<IVariable> deviceVariables, int maxPack, string defaultIntervalTime) where T : IVariableSource, new();
/// <inheritdoc/>
public virtual string GetAddressDescription()
{
return DefaultResource.Localizer["DefaultAddressDes"];
}
/// <summary>
/// 获取bit偏移量
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
public int GetBitOffsetDefault(string address)
{
return GetBitOffset(address) ?? 0;
}
/// <summary>
/// 获取bit偏移量
/// </summary>
/// <param name="address"></param>
/// <returns></returns>
public virtual int? GetBitOffset(string address)
{
int? bitIndex = null;
if (address?.IndexOf('.') > 0)
bitIndex = address.SplitStringByDelimiter().Last().ToInt();
return bitIndex;
}
/// <inheritdoc/>
public virtual bool BitReverse(string address)
{
return address?.IndexOf('.') > 0;
}
/// <inheritdoc/>
public virtual int GetLength(string address, int length, int typeLength, bool isBool = false)
{
var result = Math.Ceiling((double)length * typeLength / RegisterByteLength);
if (isBool && GetBitOffset(address) != null)
{
var data = Math.Ceiling((double)length / RegisterByteLength / 8);
return (int)data;
}
else
{
return (int)result;
}
}
#endregion
#region
/// <summary>
/// 日志输出16进制
/// </summary>
public virtual bool IsHexLog { get; init; } = true;
/// <summary>
/// 接收,非主动发送的情况,重写实现非主从并发通讯协议,如果通道存在其他设备并且不希望其他设备处理时,设置<see cref="TouchSocketEventArgs.Handled"/> 为true
/// </summary>
protected virtual Task ChannelReceived(IClientChannel client, ReceivedDataEventArgs e, bool last)
{
if (e.RequestInfo is MessageBase response)
{
try
{
if (client.WaitHandlePool.SetRun(response))
{
e.Handled = true;
}
}
catch (Exception ex)
{
Logger?.LogWarning(ex, $"Response {response.Sign}");
}
}
return EasyTask.CompletedTask;
}
protected volatile bool AutoConnect = true;
/// <inheritdoc/>
private async ValueTask<OperResult> SendAsync(ISendMessage sendMessage, IClientChannel channel = default, EndPoint endPoint = default, CancellationToken token = default)
{
try
{
if (channel == default)
{
if (Channel is not IClientChannel clientChannel) { throw new ArgumentNullException(nameof(channel)); }
channel = clientChannel;
}
if (SendDelayTime != 0)
await Task.Delay(SendDelayTime, token).ConfigureAwait(false);
if (channel is IDtuUdpSessionChannel udpSession)
{
await udpSession.SendAsync(endPoint, sendMessage).ConfigureAwait(false);
}
else
{
await channel.SendAsync(sendMessage).ConfigureAwait(false);
}
return OperResult.Success;
}
catch (Exception ex)
{
return new(ex);
}
}
private async ValueTask BefortSendAsync(IClientChannel channel, CancellationToken token)
{
SetDataAdapter(channel);
try
{
if (AutoConnect && !Channel.Online)
await Channel.ConnectAsync(Channel.ChannelOptions.ConnectTimeout, token).ConfigureAwait(false);
}
catch (Exception ex)
{
await Task.Delay(1000, token).ConfigureAwait(false);
throw ex;
}
if (token.IsCancellationRequested)
throw new OperationCanceledException();
}
/// <inheritdoc/>
public virtual async ValueTask<OperResult> SendAsync(ISendMessage sendMessage, CancellationToken cancellationToken)
{
try
{
var dtuId = this is IDtu dtu1 ? dtu1.DtuId : null;
var channelResult = await GetChannelAsync(dtuId).ConfigureAwait(false);
if (!channelResult.IsSuccess) return new OperResult<byte[]>(channelResult);
WaitLock? waitLock = null;
EndPoint? endPoint = GetUdpEndpoint(dtuId);
waitLock = GetWaitLock(channelResult.Content, waitLock, dtuId);
try
{
await BefortSendAsync(channelResult.Content, cancellationToken).ConfigureAwait(false);
await waitLock.WaitAsync(cancellationToken).ConfigureAwait(false);
if (channelResult.Content.ReadOnlyDataHandlingAdapter != null)
channelResult.Content.ReadOnlyDataHandlingAdapter.Logger = Logger;
return await SendAsync(sendMessage, channelResult.Content, endPoint, cancellationToken).ConfigureAwait(false);
}
finally
{
waitLock.Release();
}
}
catch (Exception ex)
{
return new(ex);
}
}
/// <inheritdoc/>
public virtual async ValueTask<OperResult<IClientChannel>> GetChannelAsync(string socketId)
{
if (string.IsNullOrWhiteSpace(socketId))
return new OperResult<IClientChannel>() { Content = (IClientChannel)Channel };
if (Channel is ITcpServiceChannel serviceChannel)
{
if (serviceChannel.TryGetClient($"ID={socketId}", out var client))
{
return new OperResult<IClientChannel>() { Content = client };
}
else
{
await Task.Delay(1000).ConfigureAwait(false);
if (serviceChannel.TryGetClient($"ID={socketId}", out var client1))
{
return new OperResult<IClientChannel>() { Content = client1 };
}
return (new OperResult<IClientChannel>(DefaultResource.Localizer["DtuNoConnectedWaining", socketId]));
}
}
else
return new OperResult<IClientChannel>() { Content = (IClientChannel)Channel };
}
/// <inheritdoc/>
public virtual EndPoint GetUdpEndpoint(string socketId)
{
if (Channel is IDtuUdpSessionChannel udpSessionChannel)
{
if (string.IsNullOrWhiteSpace(socketId))
return udpSessionChannel.DefaultEndpoint;
{
if (udpSessionChannel.TryGetEndPoint($"ID={socketId}", out var endPoint))
{
return endPoint;
}
else
{
if (udpSessionChannel.TryGetEndPoint($"ID={socketId}", out var endPoint1))
{
return endPoint1;
}
throw new Exception(DefaultResource.Localizer["DtuNoConnectedWaining", socketId]);
}
}
}
return null;
}
/// <inheritdoc/>
public virtual async ValueTask<OperResult<byte[]>> SendThenReturnAsync(ISendMessage sendMessage, CancellationToken cancellationToken = default)
{
var channelResult = await GetChannelAsync(this is IDtu dtu ? dtu.DtuId : null).ConfigureAwait(false);
if (!channelResult.IsSuccess) return new OperResult<byte[]>(channelResult);
return await SendThenReturnAsync(sendMessage, channelResult.Content, cancellationToken).ConfigureAwait(false);
}
/// <inheritdoc/>
protected virtual async ValueTask<MessageBase> SendThenReturnMessageAsync(ISendMessage sendMessage, CancellationToken cancellationToken = default)
{
var channelResult = await GetChannelAsync(this is IDtu dtu ? dtu.DtuId : null).ConfigureAwait(false);
if (!channelResult.IsSuccess) return new MessageBase(channelResult);
return await SendThenReturnMessageBaseAsync(sendMessage, channelResult.Content, cancellationToken).ConfigureAwait(false);
}
/// <inheritdoc/>
public virtual async ValueTask<OperResult<byte[]>> SendThenReturnAsync(ISendMessage sendMessage, IClientChannel channel, CancellationToken cancellationToken = default)
{
try
{
var result = await SendThenReturnMessageBaseAsync(sendMessage, channel, cancellationToken).ConfigureAwait(false);
return new OperResult<byte[]>(result) { Content = result.Content };
}
catch (Exception ex)
{
return new(ex);
}
}
/// <inheritdoc/>
protected virtual async ValueTask<MessageBase> SendThenReturnMessageBaseAsync(ISendMessage command, IClientChannel clientChannel = default, CancellationToken cancellationToken = default)
{
try
{
return await GetResponsedDataAsync(command, clientChannel, Timeout, cancellationToken).ConfigureAwait(false);
}
catch (Exception ex)
{
return new(ex);
}
}
/// <summary>
/// 发送并等待数据
/// </summary>
protected async ValueTask<MessageBase> GetResponsedDataAsync(ISendMessage command, IClientChannel clientChannel, int timeout = 3000, CancellationToken cancellationToken = default)
{
var waitData = clientChannel.WaitHandlePool.GetWaitDataAsync(out var sign);
command.Sign = sign;
WaitLock? waitLock = null;
var dtuId = this is IDtu dtu1 ? dtu1.DtuId : null;
EndPoint? endPoint = GetUdpEndpoint(dtuId);
try
{
waitLock = GetWaitLock(clientChannel, waitLock, dtuId);
await BefortSendAsync(clientChannel, cancellationToken).ConfigureAwait(false);
await waitLock.WaitAsync(cancellationToken).ConfigureAwait(false);
if (clientChannel.ReadOnlyDataHandlingAdapter != null)
clientChannel.ReadOnlyDataHandlingAdapter.Logger = Logger;
waitData.SetCancellationToken(cancellationToken);
Channel.ChannelReceivedWaitDict.TryAdd(sign, ChannelReceived);
var sendOperResult = await SendAsync(command, clientChannel, endPoint, cancellationToken).ConfigureAwait(false);
if (!sendOperResult.IsSuccess)
throw sendOperResult.Exception ?? new(sendOperResult.ErrorMessage);
await waitData.WaitAsync(timeout).ConfigureAwait(false);
var result = waitData.Check();
if (result.IsSuccess)
{
var response = waitData.WaitResult;
return response;
}
else
{
throw result.Exception ?? new(result.ErrorMessage);
}
}
finally
{
waitLock.Release();
if (waitData.WaitResult != null)
{
if (waitData.WaitResult.Sign != sign)
{
waitData.WaitResult.Sign = sign;
}
}
else
{
waitData.SetResult(new MessageBase() { Sign = sign });
}
clientChannel.WaitHandlePool.Destroy(waitData);
Channel.ChannelReceivedWaitDict.TryRemove(sign, out _);
}
}
private static WaitLock GetWaitLock(IClientChannel clientChannel, WaitLock? waitLock, string dtuId)
{
if (clientChannel is IDtuUdpSessionChannel udpSessionChannel)
{
waitLock = udpSessionChannel.GetLock(dtuId);
}
waitLock ??= clientChannel.GetLock(null);
return waitLock;
}
#endregion
#region
/// <inheritdoc/>
public virtual async ValueTask<IOperResult<Array>> ReadAsync(string address, int length, DataTypeEnum dataType, CancellationToken cancellationToken = default)
{
return dataType switch
{
DataTypeEnum.String => await ReadStringAsync(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
DataTypeEnum.Boolean => await ReadBooleanAsync(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
DataTypeEnum.Byte => await ReadAsync(address, length, cancellationToken).ConfigureAwait(false),
DataTypeEnum.Int16 => await ReadInt16Async(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
DataTypeEnum.UInt16 => await ReadUInt16Async(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
DataTypeEnum.Int32 => await ReadInt32Async(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
DataTypeEnum.UInt32 => await ReadUInt32Async(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
DataTypeEnum.Int64 => await ReadInt64Async(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
DataTypeEnum.UInt64 => await ReadUInt64Async(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
DataTypeEnum.Single => await ReadSingleAsync(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
DataTypeEnum.Double => await ReadDoubleAsync(address, length, cancellationToken: cancellationToken).ConfigureAwait(false),
_ => new OperResult<Array>(DefaultResource.Localizer["DataTypeNotSupported", dataType]),
};
}
/// <inheritdoc/>
public virtual async ValueTask<OperResult> WriteAsync(string address, JToken value, DataTypeEnum dataType, CancellationToken cancellationToken = default)
{
try
{
var bitConverter = ThingsGatewayBitConverter.GetTransByAddress(address);
if (value is JArray jArray)
{
return dataType switch
{
DataTypeEnum.String => await WriteAsync(address, jArray.ToObject<String[]>(), cancellationToken: cancellationToken).ConfigureAwait(false),
DataTypeEnum.Boolean => await WriteAsync(address, jArray.ToObject<Boolean[]>(), cancellationToken).ConfigureAwait(false),
DataTypeEnum.Byte => await WriteAsync(address, jArray.ToObject<Byte[]>(), dataType, cancellationToken).ConfigureAwait(false),
DataTypeEnum.Int16 => await WriteAsync(address, jArray.ToObject<Int16[]>(), cancellationToken: cancellationToken).ConfigureAwait(false),
DataTypeEnum.UInt16 => await WriteAsync(address, jArray.ToObject<UInt16[]>(), cancellationToken: cancellationToken).ConfigureAwait(false),
DataTypeEnum.Int32 => await WriteAsync(address, jArray.ToObject<Int32[]>(), cancellationToken: cancellationToken).ConfigureAwait(false),
DataTypeEnum.UInt32 => await WriteAsync(address, jArray.ToObject<UInt32[]>(), cancellationToken: cancellationToken).ConfigureAwait(false),
DataTypeEnum.Int64 => await WriteAsync(address, jArray.ToObject<Int64[]>(), cancellationToken: cancellationToken).ConfigureAwait(false),
DataTypeEnum.UInt64 => await WriteAsync(address, jArray.ToObject<UInt64[]>(), cancellationToken: cancellationToken).ConfigureAwait(false),
DataTypeEnum.Single => await WriteAsync(address, jArray.ToObject<Single[]>(), cancellationToken: cancellationToken).ConfigureAwait(false),
DataTypeEnum.Double => await WriteAsync(address, jArray.ToObject<Double[]>(), cancellationToken: cancellationToken).ConfigureAwait(false),
_ => new OperResult(DefaultResource.Localizer["DataTypeNotSupported", dataType]),
};
}
else
{
return dataType switch
{
DataTypeEnum.String => await WriteAsync(address, value.ToObject<String>(), bitConverter, cancellationToken).ConfigureAwait(false),
DataTypeEnum.Boolean => await WriteAsync(address, value.ToObject<Boolean>(), bitConverter, cancellationToken).ConfigureAwait(false),
DataTypeEnum.Byte => await WriteAsync(address, value.ToObject<Byte>(), bitConverter, cancellationToken).ConfigureAwait(false),
DataTypeEnum.Int16 => await WriteAsync(address, value.ToObject<Int16>(), bitConverter, cancellationToken).ConfigureAwait(false),
DataTypeEnum.UInt16 => await WriteAsync(address, value.ToObject<UInt16>(), bitConverter, cancellationToken).ConfigureAwait(false),
DataTypeEnum.Int32 => await WriteAsync(address, value.ToObject<Int32>(), bitConverter, cancellationToken).ConfigureAwait(false),
DataTypeEnum.UInt32 => await WriteAsync(address, value.ToObject<UInt32>(), bitConverter, cancellationToken).ConfigureAwait(false),
DataTypeEnum.Int64 => await WriteAsync(address, value.ToObject<Int64>(), bitConverter, cancellationToken).ConfigureAwait(false),
DataTypeEnum.UInt64 => await WriteAsync(address, value.ToObject<UInt64>(), bitConverter, cancellationToken).ConfigureAwait(false),
DataTypeEnum.Single => await WriteAsync(address, value.ToObject<Single>(), bitConverter, cancellationToken).ConfigureAwait(false),
DataTypeEnum.Double => await WriteAsync(address, value.ToObject<Double>(), bitConverter, cancellationToken).ConfigureAwait(false),
_ => new OperResult(DefaultResource.Localizer["DataTypeNotSupported", dataType]),
};
}
}
catch (Exception ex)
{
return new OperResult(ex);
}
}
#endregion
#region
/// <inheritdoc/>
public abstract ValueTask<OperResult<byte[]>> ReadAsync(string address, int length, CancellationToken cancellationToken = default);
/// <inheritdoc/>
public virtual async ValueTask<OperResult<Boolean[]>> ReadBooleanAsync(string address, int length, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
var result = await ReadAsync(address, GetLength(address, length, RegisterByteLength, true), cancellationToken).ConfigureAwait(false);
return result.OperResultFrom(() => bitConverter.ToBoolean(result.Content, GetBitOffsetDefault(address), length, BitReverse(address)));
}
/// <inheritdoc/>
public virtual async ValueTask<OperResult<Int16[]>> ReadInt16Async(string address, int length, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
var result = await ReadAsync(address, GetLength(address, length, 2), cancellationToken).ConfigureAwait(false);
return result.OperResultFrom(() => bitConverter.ToInt16(result.Content, 0, length));
}
/// <inheritdoc/>
public virtual async ValueTask<OperResult<UInt16[]>> ReadUInt16Async(string address, int length, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
var result = await ReadAsync(address, GetLength(address, length, 2), cancellationToken).ConfigureAwait(false);
return result.OperResultFrom(() => bitConverter.ToUInt16(result.Content, 0, length));
}
/// <inheritdoc/>
public virtual async ValueTask<OperResult<Int32[]>> ReadInt32Async(string address, int length, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
var result = await ReadAsync(address, GetLength(address, length, 4), cancellationToken).ConfigureAwait(false);
return result.OperResultFrom(() => bitConverter.ToInt32(result.Content, 0, length));
}
/// <inheritdoc/>
public virtual async ValueTask<OperResult<UInt32[]>> ReadUInt32Async(string address, int length, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
var result = await ReadAsync(address, GetLength(address, length, 4), cancellationToken).ConfigureAwait(false);
return result.OperResultFrom(() => bitConverter.ToUInt32(result.Content, 0, length));
}
/// <inheritdoc/>
public virtual async ValueTask<OperResult<Int64[]>> ReadInt64Async(string address, int length, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
var result = await ReadAsync(address, GetLength(address, length, 8), cancellationToken).ConfigureAwait(false);
return result.OperResultFrom(() => bitConverter.ToInt64(result.Content, 0, length));
}
/// <inheritdoc/>
public virtual async ValueTask<OperResult<UInt64[]>> ReadUInt64Async(string address, int length, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
var result = await ReadAsync(address, GetLength(address, length, 8), cancellationToken).ConfigureAwait(false);
return result.OperResultFrom(() => bitConverter.ToUInt64(result.Content, 0, length));
}
/// <inheritdoc/>
public virtual async ValueTask<OperResult<Single[]>> ReadSingleAsync(string address, int length, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
var result = await ReadAsync(address, GetLength(address, length, 4), cancellationToken).ConfigureAwait(false);
return result.OperResultFrom(() => bitConverter.ToSingle(result.Content, 0, length));
}
/// <inheritdoc/>
public virtual async ValueTask<OperResult<Double[]>> ReadDoubleAsync(string address, int length, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
var result = await ReadAsync(address, GetLength(address, length, 8), cancellationToken).ConfigureAwait(false);
return result.OperResultFrom(() => bitConverter.ToDouble(result.Content, 0, length));
}
/// <inheritdoc/>
public virtual async ValueTask<OperResult<String[]>> ReadStringAsync(string address, int length, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
if (bitConverter.StringLength == null) return new OperResult<String[]>(DefaultResource.Localizer["StringAddressError"]);
var len = bitConverter.StringLength * length;
var result = await ReadAsync(address, GetLength(address, len.Value, 1), cancellationToken).ConfigureAwait(false);
return result.OperResultFrom(() =>
{
List<String> strings = new();
for (int i = 0; i < length; i++)
{
var data = bitConverter.ToString(result.Content, i * bitConverter.StringLength.Value, bitConverter.StringLength.Value);
strings.Add(data);
}
return strings.ToArray();
}
);
}
#endregion
#region
/// <inheritdoc/>
public abstract ValueTask<OperResult> WriteAsync(string address, byte[] value, DataTypeEnum dataType, CancellationToken cancellationToken = default);
/// <inheritdoc/>
public abstract ValueTask<OperResult> WriteAsync(string address, bool[] value, CancellationToken cancellationToken = default);
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, bool value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
return WriteAsync(address, new bool[1] { value }, cancellationToken);
}
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, byte value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
return WriteAsync(address, new byte[] { value }, DataTypeEnum.Byte, cancellationToken);
}
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, short value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
return WriteAsync(address, bitConverter.GetBytes(value), DataTypeEnum.Int16, cancellationToken);
}
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, ushort value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
return WriteAsync(address, bitConverter.GetBytes(value), DataTypeEnum.UInt16, cancellationToken);
}
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, int value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
return WriteAsync(address, bitConverter.GetBytes(value), DataTypeEnum.Int32, cancellationToken);
}
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, uint value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
return WriteAsync(address, bitConverter.GetBytes(value), DataTypeEnum.UInt32, cancellationToken);
}
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, long value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
return WriteAsync(address, bitConverter.GetBytes(value), DataTypeEnum.Int64, cancellationToken);
}
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, ulong value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
return WriteAsync(address, bitConverter.GetBytes(value), DataTypeEnum.UInt64, cancellationToken);
}
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, float value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
return WriteAsync(address, bitConverter.GetBytes(value), DataTypeEnum.Single, cancellationToken);
}
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, double value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
return WriteAsync(address, bitConverter.GetBytes(value), DataTypeEnum.Double, cancellationToken);
}
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, string value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
var data = bitConverter.GetBytes(value);
return WriteAsync(address, data.ArrayExpandToLength(bitConverter.StringLength ?? data.Length), DataTypeEnum.String, cancellationToken);
}
#endregion
#region
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, short[] value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
return WriteAsync(address, bitConverter.GetBytes(value), DataTypeEnum.Int16, cancellationToken);
}
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, ushort[] value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
return WriteAsync(address, bitConverter.GetBytes(value), DataTypeEnum.UInt16, cancellationToken);
}
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, int[] value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
return WriteAsync(address, bitConverter.GetBytes(value), DataTypeEnum.Int32, cancellationToken);
}
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, uint[] value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
return WriteAsync(address, bitConverter.GetBytes(value), DataTypeEnum.UInt32, cancellationToken);
}
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, long[] value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
return WriteAsync(address, bitConverter.GetBytes(value), DataTypeEnum.Int64, cancellationToken);
}
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, ulong[] value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
return WriteAsync(address, bitConverter.GetBytes(value), DataTypeEnum.UInt64, cancellationToken);
}
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, float[] value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
return WriteAsync(address, bitConverter.GetBytes(value), DataTypeEnum.Single, cancellationToken);
}
/// <inheritdoc/>
public virtual ValueTask<OperResult> WriteAsync(string address, double[] value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
return WriteAsync(address, bitConverter.GetBytes(value), DataTypeEnum.Double, cancellationToken);
}
/// <inheritdoc/>
public virtual async ValueTask<OperResult> WriteAsync(string address, string[] value, IThingsGatewayBitConverter bitConverter = null, CancellationToken cancellationToken = default)
{
bitConverter ??= ThingsGatewayBitConverter.GetTransByAddress(address);
if (bitConverter.StringLength == null) return new OperResult(DefaultResource.Localizer["StringAddressError"]);
List<byte> bytes = new();
foreach (var a in value)
{
var data = bitConverter.GetBytes(a);
bytes.AddRange(data.ArrayExpandToLength(bitConverter.StringLength ?? data.Length));
}
return await WriteAsync(address, bytes.ToArray(), DataTypeEnum.String, cancellationToken).ConfigureAwait(false);
}
#endregion
/// <inheritdoc/>
protected override void Dispose(bool disposing)
{
if (Channel != null)
{
lock (Channel)
{
Channel.Starting.Remove(ChannelStarting);
Channel.Stoped.Remove(ChannelStoped);
Channel.Started.Remove(ChannelStarted);
Channel.Stoping.Remove(ChannelStoping);
Channel.ChannelReceived.Remove(ChannelReceived);
if (Channel.Collects.Count == 1)
{
if (Channel is ITcpServiceChannel tcpServiceChannel)
{
tcpServiceChannel.Clients.ForEach(a =>
{
a.WaitHandlePool.SafeDispose();
});
}
try
{
//只关闭,不释放
_ = Channel.CloseAsync();
if (Channel is IClientChannel client)
{
client.WaitHandlePool.SafeDispose();
}
}
catch (Exception ex)
{
Logger?.LogWarning(ex);
}
}
else
{
if (Channel is ITcpServiceChannel tcpServiceChannel && this is IDtu dtu)
{
if (tcpServiceChannel.TryGetClient($"ID={dtu.DtuId}", out var client))
{
client.WaitHandlePool?.SafeDispose();
client.Close();
}
}
}
Channel.Collects.Remove(this);
}
}
_deviceLogger?.TryDispose();
base.Dispose(disposing);
}
/// <inheritdoc/>
public virtual Action<IPluginManager> ConfigurePlugins(TouchSocketConfig config)
{
switch (Channel.ChannelType)
{
case ChannelTypeEnum.TcpService:
{
if (Channel.ChannelOptions.DtuSeviceType == DtuSeviceType.Default)
return PluginUtil.GetDtuPlugin(Channel.ChannelOptions);
else
return PluginUtil.GetTcpServicePlugin(Channel.ChannelOptions);
}
}
return a => { };
}
}