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

357 lines
13 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.

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;
}
}
}