#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 Furion;
using Microsoft.Extensions.Logging;
using SqlSugar;
using System.Collections.Concurrent;
using ThingsGateway.Foundation.Adapter.Modbus;
using ThingsGateway.Foundation.Extension;
using ThingsGateway.Foundation.Extension.ConcurrentQueue;
using ThingsGateway.Foundation.Extension.String;
namespace ThingsGateway.Plugin.Modbus;
///
///
///
public class ModbusSerialServer : UpLoadBase
{
private readonly ModbusSerialServerProperty driverPropertys = new();
private readonly ModbusSerialServerVariableProperty variablePropertys = new();
private Dictionary _ModbusTags;
private ThingsGateway.Foundation.Adapter.Modbus.ModbusSerialServer _plc;
private ConcurrentQueue<(string, DeviceVariableRunTime)> Values = new();
///
public override Type DriverDebugUIType => typeof(ModbusSerialServerDebugPage);
///
public override UpDriverPropertyBase DriverPropertys => driverPropertys;
///
public override List UploadVariables => _ModbusTags?.Values.ToList();
///
public override VariablePropertyBase VariablePropertys => variablePropertys;
RpcSingletonService RpcCore { get; set; }
///
///
///
///
public override Task AfterStopAsync()
{
return Task.CompletedTask;
}
///
public override Task BeforStartAsync(CancellationToken cancellationToken)
{
return _plc?.ConnectAsync(cancellationToken);
}
///
public override async Task ExecuteAsync(CancellationToken cancellationToken)
{
var list = Values.ToListWithDequeue();
foreach (var item in list)
{
if (cancellationToken.IsCancellationRequested)
break;
var type = GetPropertyValue(item.Item2, nameof(ModbusSerialServerVariableProperty.ModbusType));
if (Enum.TryParse(type, out DataTypeEnum result))
{
await _plc.WriteAsync(item.Item1, item.Item2.Value?.ToString(), 1, result, cancellationToken);
}
else
{
await _plc.WriteAsync(item.Item1, item.Item2.Value?.ToString(), 1, item.Item2.DataTypeEnum, cancellationToken);
}
}
if (driverPropertys.CycleInterval > UploadDeviceThread.CycleInterval + 50)
{
try
{
await Task.Delay(driverPropertys.CycleInterval - UploadDeviceThread.CycleInterval, cancellationToken);
}
catch
{
}
}
else
{
}
}
///
public override bool IsConnected()
{
return _plc?.SerialSession?.CanSend == true;
}
///
protected override void Dispose(bool disposing)
{
_ModbusTags?.Values?.ToList()?.ForEach(a => a.VariableValueChange -= VariableValueChange);
if (_plc != null)
_plc.WriteData -= WriteData;
_plc?.Disconnect();
_plc?.SafeDispose();
_ModbusTags?.Clear();
_ModbusTags = null;
Values?.Clear();
Values = null;
base.Dispose(disposing);
}
///
protected override void Init(UploadDeviceRunTime device)
{
var service = new SerialSession();
FoundataionConfig.SetSerialProperty(new()
{
PortName = driverPropertys.PortName,
BaudRate = driverPropertys.BaudRate,
DataBits = driverPropertys.DataBits,
Parity = driverPropertys.Parity,
StopBits = driverPropertys.StopBits,
})
;
service = new SerialSession();
((SerialSession)service).Setup(FoundataionConfig);
//载入配置
_plc = new(service)
{
DataFormat = driverPropertys.DataFormat,
Station = driverPropertys.Station,
CacheTimeout = driverPropertys.CacheTimeout,
MulStation = driverPropertys.MulStation
};
var _globalDeviceData = App.GetService();
var tags = _globalDeviceData.AllVariables.Where(a => a.VariablePropertys.ContainsKey(device.Id))
.Where(b => !string.IsNullOrEmpty(GetPropertyValue(b, nameof(variablePropertys.ServiceAddress))))
.ToList();
tags.ForEach(a =>
{
a.VariableValueChange += VariableValueChange;
VariableValueChange(a);
});
_plc.WriteData += WriteData;
try
{
_ModbusTags = tags.ToDictionary(a =>
{
ModbusAddress address = ModbusAddress.ParseFrom(
GetPropertyValue(a, nameof(variablePropertys.ServiceAddress))
, driverPropertys.Station);
return address;
});
}
catch (Exception ex)
{
LogMessage?.LogWarning(ex);
tags.ForEach(a =>
{
a.VariableValueChange -= VariableValueChange;
});
_plc.WriteData -= WriteData;
}
RpcCore = App.GetService();
}
///
private void VariableValueChange(DeviceVariableRunTime collectVariableRunTime)
{
var address = GetPropertyValue(collectVariableRunTime, nameof(variablePropertys.ServiceAddress));
if (address != null && collectVariableRunTime.Value != null)
{
Values?.Enqueue((address, collectVariableRunTime));
}
}
///
/// RPC写入
///
///
///
///
///
///
private async Task WriteData(ModbusAddress address, byte[] bytes, IThingsGatewayBitConverter thingsGatewayBitConverter, SerialSession client)
{
try
{
var tag = _ModbusTags.FirstOrDefault(a => a.Key?.AddressStart == address.AddressStart && a.Key?.Station == address.Station && a.Key?.ReadFunction == address.ReadFunction);
if (tag.Value == null) return OperResult.CreateSuccessResult();
var enable =
GetPropertyValue(tag.Value, nameof(variablePropertys.VariableRpcEnable)).ToBoolean()
&& driverPropertys.DeviceRpcEnable;
if (!enable) return new OperResult("不允许写入");
var type = GetPropertyValue(tag.Value, nameof(ModbusSerialServerVariableProperty.ModbusType));
var addressStr = GetPropertyValue(tag.Value, nameof(ModbusSerialServerVariableProperty.ServiceAddress));
if (Enum.TryParse(type, out DataTypeEnum result))
{
var result1 = await RpcCore.InvokeDeviceMethodAsync($"{nameof(ModbusSerialServer)}-{CurrentDevice.Name}",
new Dictionary
{
{
tag.Value.Name,
thingsGatewayBitConverter.GetDataFormBytes(addressStr , bytes,result).ToString()
},
}
);
return result1.FirstOrDefault().Value;
}
else
{
var result1 = await RpcCore.InvokeDeviceMethodAsync($"{nameof(ModbusSerialServer)}-{CurrentDevice.Name}",
new Dictionary
{
{
tag.Value.Name,
thingsGatewayBitConverter.GetDataFormBytes(addressStr , bytes,result).ToString()
},
}
);
return result1.FirstOrDefault().Value;
}
}
catch (Exception ex)
{
return new OperResult(ex);
}
}
}