You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

246 lines
8.7 KiB
C#

using HighWayIot.Log4net;
using HighWayIot.Plc.PlcHelper;
using HighWayIot.Repository.domain;
using HighWayIot.Repository.service;
using HighWayIot.Rfid;
using HighWayIot.Rfid.Entity;
using HighWayIot.TouchSocket;
using HighWayIot.Winform.Properties;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace HighWayIot.Winform.Business
{
/// <summary>
/// TCP数据工厂类
/// </summary>
public class TCPClientFactory
{
/// <summary>
/// 标签服务类
/// </summary>
private ZxTagSettingService _tagrService = ZxTagSettingService.Instance;
/// <summary>
/// 标签实体类
/// </summary>
private List<ZxTagSettingEntity> _tagSetting;
/// <summary>
/// 读写器服务类
/// </summary>
private ZxReaderSettingService _readerService = ZxReaderSettingService.Instance;
/// <summary>
/// 读写器实体类
/// </summary>
private List<ZxReaderSettingEntity> _readerSetting;
/// <summary>
/// RFID数据分析
/// </summary>
private RfidDataAnalyse _RfidDataAnalyse = new RfidDataAnalyse();
/// <summary>
/// PLC
/// </summary>
private WorkStationHelper _workStationHelper = new WorkStationHelper();
/// <summary>
/// TCP客户端
/// </summary>
private TouchSocketTcpClient _touchSocketTcpClient = TouchSocketTcpClient.Instance;
/// <summary>
/// 心跳检测
/// </summary>
private Dictionary<string, DateTime> _heartBeatRecord = new Dictionary<string, DateTime>();
/// <summary>
/// Timer
/// </summary>
private Timer _heartbeatTimer;
/// <summary>
/// 锁对象
/// </summary>
private static readonly object _heartBeatLocker = new object();
/// <summary>
/// 工位识别历史记录
/// </summary>
public Dictionary<int, int> StationRecord = new Dictionary<int, int>();
public TCPClientFactory()
{
_tagSetting = _tagrService.GetTagInfos();
_readerSetting = _readerService.GetReaderInfos();
_heartbeatTimer = new Timer(new TimerCallback(HeartbeatJudge), null, 0, 10000);
}
/// <summary>
/// 对接收到的数据进行初步解析分发到各个报文类型的解析类中
/// </summary>
public void ReciveDataRoute(byte[] bytes, string ip)
{
BaseReciveDataEntity reciveData = BaseRFIDDataAnalyse.BaseReceiveAnalyse(bytes);
if (reciveData == null)
{
return;
}
switch (reciveData.Code)
{
case 0x02: //盘点结果
ReciveHeartBeatSignal(ip);
Receive02HEntity data02Hentity = _RfidDataAnalyse.Receive02H(reciveData.Data);
if (data02Hentity == null || data02Hentity.Data == null)
{
return;
}
ReciveRFIDSingal(data02Hentity, ip);
break;
case 0xBF: //心跳信号
ReciveHeartBeatSignal(ip);
if (reciveData.Status != 0x00)
{
LogHelper.Instance.Error($"读写器[{ip}]心跳返回异常,异常代码[{reciveData.Status}]");
}
break;
default:
LogHelper.Instance.Error($"接收到未知报文,识别代码[{reciveData.Code.ToString("X2")}]");
return;
}
}
/// <summary>
/// 接收信息的信号
/// </summary>
/// <param name="bytes"></param>
public void ReciveRFIDSingal(Receive02HEntity entity, string ip)
{
//找到读取次数最大的标签EPC
byte[] epcData = entity.Data.Where(x => x.Count == entity.Data.Max(y => y.Count)).First().EPC;
//标签号byte数组转换成字符串
string epcResult = string.Join(" ", epcData.Select(x => x.ToString("X2")));
//根据IP和标签EPC获取工位和对应设备号
string deviceNo = _tagSetting.Where(x => x.RfidEpc == epcResult).FirstOrDefault().DeviceNo;
string workstationNo = _readerSetting.Where(x => x.RfidIp == ip).FirstOrDefault().WorkstationNo;
if (string.IsNullOrEmpty(deviceNo))
{
LogHelper.Instance.Error($"未查询到 [{epcResult}] 标签相关的信息!");
return;
}
if (string.IsNullOrEmpty(workstationNo))
{
LogHelper.Instance.Error($"未查询到 [{ip}] 读写器相关的信息!");
return;
}
try
{
//记录当前配方对应的小车
if (int.Parse(workstationNo) == 1)
{
RecipeSendBusiness.RecipeNeededVehicleNo = int.Parse(deviceNo);
}
//如果对应位置成功写入,记录上次该工位写入的是该小车,如果下次还是,不再写入(防止重复写入)
int stationNo = int.Parse(workstationNo);
int vehicleNo = int.Parse(deviceNo);
//if (StationRecord.ContainsKey(stationNo)) //判断上次是不是写入的该点位
//{
// //上次就写入的该车 就不继续写入了
// if (StationRecord[stationNo] == vehicleNo)
// {
// return;
// }
//}
//写入对应的PLC信号
if (_workStationHelper.WriteStationSingal(stationNo, vehicleNo))
{
////写入成功后记录,上次已写入了该点位,不继续写入
//if (StationRecord.ContainsKey(stationNo))
//{
// StationRecord[stationNo] = vehicleNo;
//}
//else
//{
// StationRecord.Add(stationNo, vehicleNo);
//}
LogHelper.Instance.RfidLog($"{workstationNo}工位, {deviceNo}号车 写入成功[{DateTime.Now.ToString("yy-MM-dd HH:mm:ss:fff")}]");
}
else
{
LogHelper.Instance.Error($"{workstationNo}工位, {deviceNo}号车 信号写入异常(测试阶段日志) [{DateTime.Now.ToString("yy-MM-dd HH:mm:ss:fff")}]");
}
}
catch (Exception ex)
{
LogHelper.Instance.Error("数值转换发生错误", ex);
}
}
/// <summary>
/// 心跳信号接收
/// </summary>
public void ReciveHeartBeatSignal(string ip)
{
try
{
//初次心跳处理
if (!_heartBeatRecord.ContainsKey(ip))
{
LogHelper.Instance.RfidLog($"[{ip}] 初次心跳");
_heartBeatRecord.Add(ip, DateTime.Now);
return;
}
else //不是初次就更新
{
_heartBeatRecord[ip] = DateTime.Now;
}
}
catch (Exception ex)
{
LogHelper.Instance.Error($"心跳信号接收异常 {ex.Message}");
}
}
/// <summary>
/// 心跳识别
/// </summary>
/// <param name="o"></param>
public void HeartbeatJudge(object o)
{
try
{
foreach (var kvp in _heartBeatRecord.ToArray())
{
TimeSpan timeSpan = DateTime.Now - kvp.Value;
if (timeSpan.TotalSeconds > 10)
{
LogHelper.Instance.RfidLog($"[{kvp.Key}] 可能掉线,准备重连");
_heartBeatRecord.Remove(kvp.Key);
_touchSocketTcpClient.DisposeClient(kvp.Key);
_touchSocketTcpClient.CreateTcpClient(kvp.Key, "20108");
_touchSocketTcpClient.Send(kvp.Key, _RfidDataAnalyse.SendBFH(3));
_heartBeatRecord.Remove(kvp.Key);
}
}
}
catch (Exception ex)
{
LogHelper.Instance.Error($"心跳信号监测异常 {ex.Message}");
}
}
}
}