C00225155-02/C00225155/MegaRobo.C00225155/MegaRobo.C00225155.AppServer/ExecuteWorks/StationServiceBase.cs

357 lines
13 KiB
C#
Raw Permalink Normal View History

2026-04-13 09:12:49 +00:00
using Common;
using Common.Models;
using CommunityToolkit.Mvvm.Messaging;
using MegaRobo.C00225155.DataAccess;
using MegaRobo.C00225155.Entities;
using MegaRobo.C00225155.Entities.Entity_DB;
using MegaRobo.C00225155.Entities.ToWeb;
using MegaRobo.Contract;
using MegaRobo.ControlDevices;
using MegaRobo.ControlDevices.Abstractions;
using MegaRobo.ControlDevices.Models;
using MegaRobo.Entities;
using MegaRobo.Logger;
using MegaRobo.PipetteTool.HamiltonConsole.PipetteDevices.HamiltonDevices;
using MegaRobo.Utility.Files;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows.Controls;
namespace MegaRobo.C00225155.AppServer.ExecuteWorks;
public abstract class StationServiceBase : ModbusWorkServiceBase
{
#region
protected WorkService workService { get; set; }
protected AppConfigService appConfigService;
/// <summary>
/// PLC通讯的ModbusClient
/// </summary>
protected IModbusClientExtend ModbusClient;
/// <summary>
/// PLC 名称
/// </summary>
protected DeviceNames PlcName;
protected IDataAccessService dataAccessService;
protected IDictionary<string, string> PipetteErrorDic = new Dictionary<string, string>();
//protected StationProperty StationProp = new StationProperty();
#endregion
#region Field\Property
/// <summary>
/// 从数据库中加载的所有PLC报警点位
/// </summary>
protected IList<PlcPoint> WarnPointList { get; set; }
/// <summary>
/// 从CSV文件中加载的所有报警点位、报警信息
/// </summary>
protected List<PLCErrorPoint> PLCErrorInfoList { get; set; } = new List<PLCErrorPoint>();
/// <summary>
/// 当前报警信息,触发事件
/// </summary>
protected List<PLCErrorPoint> PLCErrorLists { get; set; } = new List<PLCErrorPoint>();
/// <summary>
///扫描PLC 错误信息集合事件
/// </summary>
public event EventHandler<List<PLCErrorPoint>> OnScanPlcErrorListEvent;
protected bool Runing = false;
protected string stationName = string.Empty;
#endregion
protected StationServiceBase(ICoreService coreService, WorkService workService, DeviceNames plcName, string stationName)
{
this.PlcName = plcName;
this.stationName = stationName;
this.CoreService = coreService;
this.workService = workService;// 关联上级WorkService便于跨工站交互
appConfigService = this.CoreService.GetServiceInstance<AppConfigService>();// 配置服务
dataAccessService = this.CoreService.GetServiceInstance<IDataAccessService>();// 数据访问服务
}
protected override void LoadServices()
{
this.ModbusClient = this.CoreService.GetServiceInstance<IModbusClientExtend>(this.PlcName.ToString());
if (this.ModbusClient is not null)
{
this.ModbusClient.ScannedEvent += this.ModbusClientBaseOnScannedEvent;
this.ModbusClient.PulseTickAction += this.OnPulseTick;
}
}
protected override void LoadDatas()
{
base.LoadDatas();
RegisterPipetteErrorCode();
}
protected override async void RegisterPoints()
{
//转移至 StartupService 统一注册
}
protected void RegisterPipetteErrorCode()
{
PipetteErrorDic = new Dictionary<string, string>()
{
{ "00", "执行成功" },
{ "20", "硬件问题请联系Hamilton"},
{ "30", "未知命令,请参考命令表"},
{ "31", "未知参数,请参考命令表"},
{ "32", "发送的参数值超出预定范围,请参考命令表"},
{ "35", "电源电压超出运行范围,请确保电源电压是48V+-5%"},
{ "36", "关闭紧急停止"},
{ "38", "空液体类型"},
{ "39", "液体类型写保护"},
{ "40", "一次只能发送一个命令"},
{ "50", "Z轴初始化失败,硬件问题请联系Hamilton"},
{ "51", "请初始化泵驱动"},
{ "52", "泵驱动初始化失败,硬件问题请联系Hamilton"},
{ "53", "tip 头容量不够无法吸入ai 值得液体改变ai值或更改tip 头"},
{ "54", "达到泵的最大值"},
{ "55", "吸液体积校验失败吸液量不满足当前Tip头的最小值"},
{ "56", "选择的液体类型要求用导电tip 头请确认液体类型和tip 头类型编号一致"},
{ "57", "确定液体类型一致和tip 头类型编号"},
{ "60", "ZI初始化失败硬件未工作请联系Hamilton"},
{ "61", "Z轴驱动初始化失败"},
{ "62", "Z 轴驱动移动错误 硬件未工作请联系Hamilton"},
{ "63", "移动碰触到试管底部"},
{ "64", "Z 轴驱动达不到gy(要移动到的位置) 值,请检查参数"},
{ "65", "Z 轴驱动达不到te(转移高度)值,请检查参数"},
{ "66", "Z 轴驱动达不到ce(容器底部高度) 值,请检查参数"},
{ "67", "Z 轴驱动达不到cf(液面的高度) 值,请检查参数"},
{ "68", "Z 轴驱动达不到zp(开始探测液面的位置) 值,请检查参数"},
{ "69", "Z 轴驱动达不到tr(丢弃Tip头位置) 值,请检查参数"},
{ "70", "在zp 和ce 两个值之间未检测到液面,请检查参数设置"},
{ "71", "液体不足"},
{ "72", "压力传感器自动校准失效,硬件未工作请联系Hamilton"},
{ "74", "提前检测到液面"},
{ "75", "未取到tip 头"},
{ "76", "tip 头已经取到"},
{ "80", "吸液过程中检测到堵塞"},
{ "81", "吸液过程中检测到吸空"},
{ "82", "吸液过程中检测到气泡"},
{ "83", "分配过程中检测到堵塞"},
{ "84", "分配过程中检测到气泡"},
{ "85", "未与数字电平通信上硬件问题请联系Hamilton"},
};
}
protected override void LoadPlcWarnInfoSetting()
{
base.LoadPlcWarnInfoSetting();
this.PLCErrorInfoList.Clear();
WarnPointList = new List<PlcPoint>();
string filePath = string.Empty;
if (this.PlcName == DeviceNames.Plc1)//投料站
{
filePath = "DataBox\\PlcWarnSetting_Dose.csv";
}
else if (this.PlcName.Equals(DeviceNames.Plc2)) //反应站
{
filePath = "DataBox\\PlcWarnSetting_React.csv";
}
string[] lines = File.ReadAllLines(filePath, System.Text.Encoding.GetEncoding("utf-8"));
foreach (string line in lines)
{
string key = string.Empty;
string[] columns = line.Split(',');
if (columns.Length != 2)
{
continue;
}
key = columns[0].Replace("MX", "");
string value = columns[1];
if (string.IsNullOrEmpty(key) || string.IsNullOrEmpty(value)) continue;
if (!double.TryParse(key, out double _point)) continue;
PLCErrorPoint point = new PLCErrorPoint() { ErrorAddress = key, ErrorInfo = value };
this.PLCErrorInfoList.Add(point);
}
var alladdress = PLCErrorInfoList.Select(x => x.ErrorAddress.Split(".")[0]).Distinct().ToList();
var client = this.CoreService.GetServiceInstance<IModbusClientExtend>("Plc1");
foreach (var addr in alladdress)
{
client.Register<System.Drawing.Point>(ushort.Parse(addr), $"报警点位-{addr}", FunType.ReadHoldingRegisters);
PlcPoint plcPoint = new PlcPoint()
{
Address = ushort.Parse(addr), Descr = $"报警点位-{addr}", FunType = FunType.ReadHoldingRegisters
};
WarnPointList.Add(plcPoint);
}
//this.WarnPointList =
//this.WarnPointList = this.dataAccessService.LoadEntitiesAsync<PlcPoint>(x => x.Name == this.PlcName.ToString() && x.Level == 2).Result;
this.Runing = true;
}
protected string GetMethodName([CallerMemberName] string memberName = "")
{
return memberName;
}
//protected virtual async Task InitPreAsync()
//{
// await Task.Delay(0);
//}
#region PLC读取/
#endregion
private ushort _lastTickValue = 1; //先缓存, 尽量减少通讯次数
protected override void OnPulseTick()
{
var currValue = (ushort)(DateTime.Now.Second % 2); //间隔两秒给一次心跳
if (currValue == 0)
{
//this._lastTickValue = currValue;
this.ModbusClient.Command.WriteValue<ushort>(PlcPoints_MaterialDose.W_PCHeartPluse[(ushort)this.PlcName], 1);
}
}
#region ModBus
protected async void LoadPlcAlarmInfoSetting()
{
//注册提示点位
// this.WarnPointList = await this.DataAccessService.LoadEntitiesAsync<PlcPoint>(x =>
// x.Name == this.PlcName.ToString() && x.Level == 3);
}
//protected IList<PlcPoint> ScanPlcAlarmInfoList(int? takeCount = null)
//{
// return new List<PlcPoint>();
//}
private DateTime lastWarnDateTime = DateTime.Now;
//public Dictionary<ushort, ushort> WarnDictionary = new Dictionary<ushort, ushort>();
protected virtual void ModbusClientBaseOnScannedEvent(object sender, EventArgs e)
{
if (!this.Runing)
return;
DateTime now = DateTime.Now;
if ((now - this.lastWarnDateTime).Seconds >= 5)
{
this.lastWarnDateTime = now;
ScanPLCWarnList();
}
}
public override IList<PlcPoint> ScanPlcWarnInfoList(int? takeCount = null)
{
IList<PlcPoint> warnPointList = new List<PlcPoint>();
try
{
foreach (var plcPoint in this.WarnPointList)
{
//这里的错误报警信息都是1个字2个字节16位
var pointInfo = this.ModbusClient.ReadScannedValue<ushort>(plcPoint.Address);
if (pointInfo.Value != 0)
{
//if (!this.WarnDictionary.ContainsKey(pointInfo.Address) || this.WarnDictionary[pointInfo.Address] != pointInfo.Value)
//{
// this.Logger.LogError($"{this.stationName}异常点位[{pointInfo.Address}]值[{pointInfo.Value}]");
// this.WarnDictionary[pointInfo.Address] = pointInfo.Value;
//}
//pointInfo.LastValue = pointInfo.Value.ToString();
warnPointList.Add(pointInfo);
}
// else
// {
// //复位直接清空 不处理
// if(this.WranDictionary.ContainsKey(pointInfo.Address))
// this.WranDictionary.Remove(pointInfo.Address);
// }
}
}
catch (Exception ex)
{
this.Logger.LogError($"{this.stationName}异常信息[{ex.Message}]");
}
return warnPointList;
}
/// <summary>
/// 扫描PLC报警信息触发事件
/// </summary>
private void ScanPLCWarnList()
{
PLCErrorLists.Clear();
foreach (var plcPoint in WarnPointList)
{
var pointInfo = this.ModbusClient.ReadScannedValue<ushort>(plcPoint.Address);
bool isError = false;
if (pointInfo.Value != 0)
{
for (int i = 0; i < 16; i++)
{
if (((pointInfo.Value >> i) & 1) == 1)
{
var addr = plcPoint.Address.ToString() + "." + i.ToString();
var point = PLCErrorInfoList.FirstOrDefault(p => p.ErrorAddress.Equals(addr));
if (point != null)
{
isError = !point.ErrorInfo.Contains("提示");
PLCErrorLists.Add(point);
}
}
}
if (isError)
{
//给BS那边只需要给报警信息
PLCErrorLists.Add(new PLCErrorPoint() { ErrorAddress = plcPoint.Address.ToString(), ErrorInfo = pointInfo.Value.ToString() }); //这边定义好传给BS的值
}
}
}
if (PLCErrorLists.Count > 0)
{
this.OnScanPlcErrorListEvent?.Invoke(this, PLCErrorLists);
}
}
#endregion
/// <summary>
/// 用于移液枪取运行状态值
/// </summary>
/// <param name="resultString"></param>
/// <returns></returns>
protected string GetPipetteReturnCode(string resultString)
{
try
{
string pattern = @"er(\d{2})";
MatchCollection matches = Regex.Matches(resultString, pattern);
return matches[0].Groups[1].Value;
}
catch (Exception)
{
return resultString;
}
}
}