chore: 初始化平芝126KV总装线 WebApi
This commit is contained in:
82
Tighten/Helpers/TightenHelpers.cs
Normal file
82
Tighten/Helpers/TightenHelpers.cs
Normal file
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WebApi.Tighten
|
||||
{
|
||||
public class TightenHelpers
|
||||
{
|
||||
public static bool Send(TcpClient tcpClient, string command,out string errMsg)
|
||||
{
|
||||
bool send = false;
|
||||
errMsg = "";
|
||||
try
|
||||
{
|
||||
var sendstr = command.Replace(" ", "");
|
||||
byte[] commandbyte = Encoding.Default.GetBytes(sendstr);
|
||||
tcpClient.Client.Send(commandbyte, SocketFlags.None);
|
||||
send = true;
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
errMsg = err.Message;
|
||||
send = false;
|
||||
}
|
||||
return send;
|
||||
}
|
||||
|
||||
public static string Read(TcpClient tcpClient, out string errMsg)
|
||||
{
|
||||
errMsg = "";
|
||||
string command = "";
|
||||
if (tcpClient != null && tcpClient.Connected)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] byteCommand = new byte[1024];
|
||||
int icommand = tcpClient.Client.Receive(byteCommand);
|
||||
command = System.Text.Encoding.ASCII.GetString(byteCommand, 0, icommand);
|
||||
}
|
||||
catch(Exception ex) {
|
||||
errMsg = ex.Message;
|
||||
}
|
||||
}
|
||||
return command;
|
||||
}
|
||||
|
||||
public static void ParseTorqueData(string input, out double minTorque, out double maxTorque, out double targetTorque, out double actualTorque)
|
||||
{
|
||||
// 初始化默认值
|
||||
minTorque = maxTorque = targetTorque = actualTorque = 0;
|
||||
|
||||
// 检查输入长度是否足够(至少需要146字符)
|
||||
if (input == null || input.Length < 146)
|
||||
{
|
||||
throw new ArgumentException("输入字符串长度不足");
|
||||
}
|
||||
|
||||
// 解析扭矩最小值(字节117-122,索引116-121)
|
||||
string torqueMinStr = input.Substring(116, 6);
|
||||
if (int.TryParse(torqueMinStr, out int torqueMinInt))
|
||||
minTorque = torqueMinInt / 100.0;
|
||||
|
||||
// 解析扭矩最大值(字节125-130,索引124-129)
|
||||
string torqueMaxStr = input.Substring(124, 6);
|
||||
if (int.TryParse(torqueMaxStr, out int torqueMaxInt))
|
||||
maxTorque = torqueMaxInt / 100.0;
|
||||
|
||||
// 解析扭矩目标值(字节133-138,索引132-137)
|
||||
string torqueTargetStr = input.Substring(132, 6);
|
||||
if (int.TryParse(torqueTargetStr, out int torqueTargetInt))
|
||||
targetTorque = torqueTargetInt / 100.0;
|
||||
|
||||
// 解析实际扭矩值(字节141-146,索引140-145)
|
||||
string torqueActualStr = input.Substring(140, 6);
|
||||
if (int.TryParse(torqueActualStr, out int torqueActualInt))
|
||||
actualTorque = torqueActualInt / 100.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
63
Tighten/Models/TightenTool.cs
Normal file
63
Tighten/Models/TightenTool.cs
Normal file
@@ -0,0 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace WebApi.Models
|
||||
{
|
||||
public class TightenTool
|
||||
{
|
||||
public readonly object TcpClientLock = new object();
|
||||
/// <summary>
|
||||
/// 工位号
|
||||
/// </summary>
|
||||
public string OpName
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
/// <summary>
|
||||
/// 拧紧枪名称
|
||||
/// </summary>
|
||||
public string Name
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
/// <summary>
|
||||
/// IP
|
||||
/// </summary>
|
||||
public string IP
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
/// <summary>
|
||||
/// 端口号
|
||||
/// </summary>
|
||||
public string Port
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// TPC客户端
|
||||
/// </summary>
|
||||
public TcpClient TcpClient
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 安全判断TcpClient是否已连接
|
||||
/// </summary>
|
||||
public bool IsConnected
|
||||
{
|
||||
get { return TcpClient != null && TcpClient.Connected; }
|
||||
}
|
||||
}
|
||||
}
|
||||
256
Tighten/TightenServer.cs
Normal file
256
Tighten/TightenServer.cs
Normal file
@@ -0,0 +1,256 @@
|
||||
using Logger;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Sockets;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Remoting.Contexts;
|
||||
using System.Security.Cryptography;
|
||||
using System.Security.Policy;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using WebApi.Helpers;
|
||||
using WebApi.Models;
|
||||
|
||||
namespace WebApi.Tighten
|
||||
{
|
||||
public class TightenServer
|
||||
{
|
||||
Dictionary<string,string> SendCode = new Dictionary<string,string>
|
||||
{
|
||||
{ "connect", "0020 0001 0050 0001 0000" }, // 建立通讯
|
||||
{ "heart", "00209999001000010000" }, // 心跳
|
||||
{ "curve", "00200900000000000000" }, // 曲线
|
||||
{ "result", "00200060001000010000" }, // 订阅结果
|
||||
{ "tightenOk", "00200062001000000000" } // 确认收到结果
|
||||
};
|
||||
public static event Action<string> ShowMsg; // 记录日志事件
|
||||
|
||||
private bool _heartbeatRunning = false;
|
||||
|
||||
public void InitTightenList()
|
||||
{
|
||||
RedTightenList();
|
||||
//Connect();
|
||||
StartHeartbeatLoop();
|
||||
StartReadData();
|
||||
}
|
||||
|
||||
public void Connect()
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (KeyValuePair<string, TightenTool> kvp in Gl.TightenList)
|
||||
{
|
||||
if (!kvp.Value.IsConnected)
|
||||
{
|
||||
kvp.Value.TcpClient.Connect(kvp.Value.IP, Convert.ToInt32(kvp.Value.Port));
|
||||
if (kvp.Value.IsConnected)
|
||||
{
|
||||
string ErrMsg;
|
||||
// 创建工具连接
|
||||
if (!TightenHelpers.Send(kvp.Value.TcpClient, SendCode["connect"], out ErrMsg))
|
||||
{
|
||||
Log.Error(kvp.Value.IP + ":" + ErrMsg);
|
||||
return;
|
||||
}
|
||||
// 心跳
|
||||
if (!TightenHelpers.Send(kvp.Value.TcpClient, SendCode["heart"], out ErrMsg))
|
||||
{
|
||||
Log.Error(kvp.Value.IP + ":" + ErrMsg);
|
||||
return;
|
||||
}
|
||||
// 订阅结果
|
||||
if (!TightenHelpers.Send(kvp.Value.TcpClient, SendCode["result"], out ErrMsg))
|
||||
{
|
||||
Log.Error(kvp.Value.IP + ":" + ErrMsg);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
Log.FunError(ex, MethodBase.GetCurrentMethod().Name);
|
||||
}
|
||||
}
|
||||
|
||||
private void RedTightenList()
|
||||
{
|
||||
SqlServer.ExecuteSql("SELECT * FROM PTCHV_基础表_拧紧枪", out DataTable dt, out string err);
|
||||
if (dt.Rows.Count > 0)
|
||||
{
|
||||
foreach (DataRow dr in dt.Rows) {
|
||||
var tool = new TightenTool();
|
||||
tool.OpName = dr["OpName"].ToString();
|
||||
tool.Name = dr["Name"].ToString();
|
||||
tool.IP = dr["IP"].ToString();
|
||||
tool.Port = dr["Port"].ToString();
|
||||
tool.TcpClient = new System.Net.Sockets.TcpClient();
|
||||
Gl.TightenList.TryAdd(tool.IP, tool);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool SaveTightenData(string opName,string toolName,string max,string min,string OkValue,string value)
|
||||
{
|
||||
bool isOk = false;
|
||||
var param = new Dictionary<string, Object>{
|
||||
{ "工位号", opName },
|
||||
{ "拧紧枪名称", toolName },
|
||||
{ "上限值", max },
|
||||
{ "下限值", min },
|
||||
{ "标准值", OkValue },
|
||||
{ "值", value }
|
||||
};
|
||||
SqlServer.ExecuteProcedure("PTCHV_质量数据_增加", param, out DataTable dt, out string err);
|
||||
if (dt.Rows.Count > 0)
|
||||
{
|
||||
if(dt.Rows[0]["result"].ToString() == "1")
|
||||
{
|
||||
isOk = true;
|
||||
}
|
||||
}
|
||||
return isOk;
|
||||
}
|
||||
|
||||
// 开启心跳轮询 同时监听数据
|
||||
public void StartHeartbeatLoop()
|
||||
{
|
||||
foreach (var kvp in Gl.TightenList)
|
||||
{
|
||||
var tool = kvp.Value;
|
||||
Task.Run(async () =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (tool.TcpClient == null)
|
||||
tool.TcpClient = new TcpClient();
|
||||
|
||||
if (!tool.IsConnected)
|
||||
{
|
||||
try
|
||||
{
|
||||
tool.TcpClient.Close();
|
||||
}
|
||||
catch { }
|
||||
tool.TcpClient = new TcpClient();
|
||||
// 连接加超时
|
||||
var connectTask = tool.TcpClient.ConnectAsync(tool.IP, Convert.ToInt32(tool.Port));
|
||||
if (await Task.WhenAny(connectTask, Task.Delay(3000)) == connectTask)
|
||||
{
|
||||
// 连接成功
|
||||
string errMsg;
|
||||
TightenHelpers.Send(tool.TcpClient, SendCode["connect"], out errMsg);
|
||||
TightenHelpers.Send(tool.TcpClient, SendCode["heart"], out errMsg);
|
||||
TightenHelpers.Send(tool.TcpClient, SendCode["result"], out errMsg);
|
||||
if(errMsg == "")
|
||||
{
|
||||
Log.Info($"拧紧枪【{tool.Name}】 连接成功!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Log.Error($"{tool.IP} 连接超时");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
string errMsg;
|
||||
TightenHelpers.Send(tool.TcpClient, SendCode["heart"], out errMsg);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.FunError(ex, "HeartbeatLoop");
|
||||
}
|
||||
await Task.Delay(10000);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void StartReadData()
|
||||
{
|
||||
foreach (var kvp in Gl.TightenList)
|
||||
{
|
||||
Task.Run(async () =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var tool = kvp.Value;
|
||||
string ErrMsg = "";
|
||||
try
|
||||
{
|
||||
var client = tool.TcpClient;
|
||||
bool isConnected = false;
|
||||
try
|
||||
{
|
||||
isConnected = client?.Client?.Connected ?? false;
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
isConnected = false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.Error($"检查连接状态时发生意外错误 for {tool.IP}: {ex.Message}");
|
||||
isConnected = false;
|
||||
}
|
||||
|
||||
if (isConnected)
|
||||
{
|
||||
string command = "";
|
||||
try
|
||||
{
|
||||
if(client != null)
|
||||
command = TightenHelpers.Read(client, out ErrMsg);
|
||||
else
|
||||
continue;
|
||||
|
||||
if(ErrMsg != "")
|
||||
{
|
||||
Log.Error("【ReadErr】"+kvp.Value.IP + ":" + ErrMsg);
|
||||
}
|
||||
|
||||
if (command.Length == 232)
|
||||
{
|
||||
TightenHelpers.ParseTorqueData(command, out double min, out double max, out double target, out double actual);
|
||||
ShowMsg?.Invoke($"【{tool.OpName}{tool.Name} 拧紧数据】最小扭矩: {min}, 最大扭矩: {max}, 目标扭矩: {target}, 实际扭矩: {actual}");
|
||||
SaveTightenData(tool.OpName, tool.Name, max.ToString(), min.ToString(), target.ToString(), actual.ToString());
|
||||
await MqttServer.SendMqttMessageToOp(tool.OpName, "TightenOk", "1");
|
||||
// 发送确认前再次检查连接状态
|
||||
bool canSend = false;
|
||||
try
|
||||
{
|
||||
canSend = client?.Client?.Connected ?? false;
|
||||
} catch { /* ignore */ }
|
||||
|
||||
if (canSend)
|
||||
{
|
||||
TightenHelpers.Send(client, SendCode["tightenOk"], out ErrMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception readSendEx) // 捕获读取或发送过程中的异常
|
||||
{
|
||||
Log.Error($"读取或发送数据时出错 for {tool.IP}: {readSendEx.Message}");
|
||||
try { client?.Close(); } catch { }
|
||||
tool.TcpClient = null; // 标记以便下次循环重建
|
||||
}
|
||||
}
|
||||
} catch (Exception outerEx) {
|
||||
Log.FunError(outerEx, MethodBase.GetCurrentMethod().Name);
|
||||
}
|
||||
await Task.Delay(50);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user