using LB_SmartVisionCommon;
|
using LB_VisionProcesses.Communicators;
|
using LB_VisionProcesses.Communicators.SiemensS7;
|
using LB_VisionProcesses.Communicators.Tcom;
|
using Microsoft.VisualBasic;
|
using OpenVinoSharp.Extensions.model;
|
using ReaLTaiizor.Forms;
|
using RJCP.IO.Ports;
|
using S7.Net;
|
using System.Data;
|
using System.Diagnostics;
|
using System.Linq;
|
using System.Windows.Forms;
|
using YamlDotNet.Core.Tokens;
|
|
namespace LB_SmartVision.Forms.Pages.CommunicatorPage
|
{
|
public delegate void CommunicatorS7Change(BaseCommunicator communicator);
|
public partial class CommunicatorS7Form : Form
|
{
|
BaseCommunicator communicator { get; set; }
|
|
public event CommunicatorS7Change CommunicatorChanged;
|
|
private PlcConfig config;
|
private DataTable signalTable;
|
private BindingSource bindingSource;
|
private string Name;
|
|
private void communicatorChanged(BaseCommunicator communicator)
|
{
|
if (CommunicatorChanged != null)
|
{
|
CommunicatorChanged(communicator);
|
}
|
}
|
|
public CommunicatorS7Form()
|
{
|
InitializeComponent();
|
cmbType.Items.Clear();
|
if (communicator != null && !string.IsNullOrEmpty(communicator.CommunicatorConnections["型号"]?.ToString()))
|
{
|
cmbType.Items.Add(communicator.CommunicatorConnections["型号"]?.ToString());
|
}
|
}
|
|
public CommunicatorS7Form(BaseCommunicator communicator, string name)
|
{
|
InitializeComponent();
|
if (communicator == null)
|
{
|
return;
|
}
|
cmbIP.Enabled = false;
|
txtIP.Enabled = false;
|
txtPort.Enabled = false;
|
|
|
lblType.Visible = false;
|
cmbType.Visible = false;
|
|
Name = name;
|
this.Text = name;
|
if (communicator is SiemensLBS7)
|
{
|
txtIP.Text = communicator.CommunicatorConnections["地址"]?.ToString();
|
txtPort.Text = communicator.CommunicatorConnections["端口"]?.ToString();
|
cmbType.Items.Clear();
|
if (!string.IsNullOrEmpty(communicator.CommunicatorConnections["型号"]?.ToString()))
|
{
|
cmbType.Items.Add(communicator.CommunicatorConnections["型号"]?.ToString());
|
cmbType.Text = communicator.CommunicatorConnections["型号"]?.ToString();
|
}
|
txtIP.Visible = true;
|
cmbIP.Visible = false;
|
lblType.Visible = true;
|
cmbType.Visible = true;
|
|
lblIP.Text = "IP";
|
lblPort.Text = "槽";
|
}
|
|
this.communicator = communicator;
|
//加载回调函数
|
Subscribe();
|
LoadConfigAndSetupGrid();
|
}
|
|
private void CommunicatorForm_FormClosing(object sender, FormClosingEventArgs e) => Unsubscribe();
|
|
public void Unsubscribe()
|
{
|
try
|
{
|
if (communicator == null)
|
{
|
return;
|
}
|
//取消回调函数
|
communicator.MessageReceived -= ShowReceiveMsg;
|
if (communicator != null)
|
{
|
communicatorChanged(communicator);
|
if (GlobalVar.dicCommunicators != null && GlobalVar.dicCommunicators.Keys.Count > 0 && GlobalVar.dicCommunicators.Keys.Contains(communicator.CommunicatorName))
|
{
|
GlobalVar.dicCommunicators[communicator.CommunicatorName] = communicator;
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
// 记录错误信息
|
Debug.WriteLine($"错误: {ex.Message}");
|
}
|
|
}
|
|
public void Subscribe()
|
{
|
try
|
{
|
if (communicator == null)
|
{
|
return;
|
}
|
|
//取消回调函数
|
communicator.MessageReceived -= ShowReceiveMsg;
|
//加载回调函数
|
communicator.MessageReceived += ShowReceiveMsg;
|
}
|
catch (Exception ex)
|
{
|
// 记录错误信息
|
Debug.WriteLine($"错误: {ex.Message}");
|
}
|
}
|
|
/// <summary>
|
/// 通讯回调运行
|
/// </summary>
|
/// <param name="CCDName"></param>
|
/// <param name="image"></param>
|
private void ShowReceiveMsg(string strReceiveMsg)
|
{
|
// 如果当前不是 UI 线程,则通过 Invoke 将操作调度到 UI 线程
|
if (this.InvokeRequired)
|
{
|
this.Invoke(new Action<string>((msg) =>
|
{
|
// 更新 UI 控件,比如显示接收到的消息
|
this.txtReceiveMsg.AppendText(("[接收]" + DateTime.Now.ToString() + ":" + msg));
|
this.txtReceiveMsg.AppendText("\r\n");
|
this.txtReceiveMsg.SelectionStart = this.txtReceiveMsg.Text.Length;
|
this.txtReceiveMsg.ScrollToCaret();
|
}), strReceiveMsg);
|
}
|
else
|
{
|
// 如果已经在 UI 线程上,直接更新 UI
|
this.txtReceiveMsg.AppendText(("[接收]" + DateTime.Now.ToString() + ":" + strReceiveMsg));
|
this.txtReceiveMsg.AppendText("\r\n");
|
this.txtReceiveMsg.SelectionStart = this.txtReceiveMsg.Text.Length;
|
this.txtReceiveMsg.ScrollToCaret();
|
}
|
}
|
|
private void ShowSendMsg(string strSendMsg)
|
{
|
// 如果当前不是 UI 线程,则通过 Invoke 将操作调度到 UI 线程
|
if (this.InvokeRequired)
|
{
|
this.Invoke(new Action<string>((msg) =>
|
{
|
// 更新 UI 控件,比如显示接收到的消息
|
this.txtReceiveMsg.AppendText(("[发送]" + DateTime.Now.ToString() + ":" + msg));
|
this.txtReceiveMsg.AppendText("\r\n");
|
this.txtReceiveMsg.SelectionStart = this.txtReceiveMsg.Text.Length;
|
this.txtReceiveMsg.ScrollToCaret();
|
}), strSendMsg);
|
}
|
else
|
{
|
// 如果已经在 UI 线程上,直接更新 UI
|
this.txtReceiveMsg.AppendText(("[发送]" + DateTime.Now.ToString() + ":" + strSendMsg));
|
this.txtReceiveMsg.AppendText("\r\n");
|
this.txtReceiveMsg.SelectionStart = this.txtReceiveMsg.Text.Length;
|
this.txtReceiveMsg.ScrollToCaret();
|
}
|
}
|
|
private void ShowLogMsg(string msg)
|
{
|
// 如果当前不是 UI 线程,则通过 Invoke 将操作调度到 UI 线程
|
if (this.InvokeRequired)
|
{
|
this.Invoke(new Action<string>((message) =>
|
{
|
this.txtReceiveMsg.AppendText("[" + DateTime.Now.ToString("HH:mm:ss.fff") + "] " + message + "\r\n");
|
this.txtReceiveMsg.ScrollToCaret();
|
}), msg);
|
}
|
else
|
{
|
this.txtReceiveMsg.AppendText("[" + DateTime.Now.ToString("HH:mm:ss.fff") + "] " + msg + "\r\n");
|
this.txtReceiveMsg.ScrollToCaret();
|
}
|
}
|
|
// 批量读取所有信号
|
private void btnReadAll_Click(object sender, EventArgs e)
|
{
|
if (communicator == null || !communicator.bConnected)
|
{
|
MessageBox.Show("请先连接 PLC", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
return;
|
}
|
|
try
|
{
|
for (int i = 0; i < config.Signals.Count; i++)
|
{
|
var signal = config.Signals[i];
|
object value = ((SiemensLBS7)communicator).ReadSignal(signal);
|
config.Signals[i].Value= value?.ToString() ?? "";
|
signalTable.Rows[i]["Value"] = config.Signals[i].Value;
|
ShowLogMsg(signalTable.Rows[i]["Value"] + ":" + value?.ToString() ?? "");
|
}
|
}
|
catch (Exception ex)
|
{
|
MessageBox.Show($"批量读取失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
}
|
}
|
|
// 批量写入:将表格中修改过的值写入 PLC
|
private void btnWriteAll_Click(object sender, EventArgs e)
|
{
|
if (communicator == null || !communicator.bConnected)
|
{
|
MessageBox.Show("请先连接 PLC", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
return;
|
}
|
|
try
|
{
|
int successCount = 0;
|
for (int i = 0; i < config.Signals.Count; i++)
|
{
|
var signal = config.Signals[i];
|
string newValueStr = signalTable.Rows[i]["Value"]?.ToString();
|
if (!string.IsNullOrEmpty(newValueStr))
|
{
|
object convertedValue = ConvertValue(signal.DataType, newValueStr);
|
((SiemensLBS7)communicator).WriteSignal(signal, convertedValue);
|
successCount++;
|
}
|
ShowSendMsg(signalTable.Rows[i]["Value"] + ":" + newValueStr?.ToString() ?? "");
|
}
|
MessageBox.Show($"批量写入完成,成功写入 {successCount} 个信号。", "写入结果", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
}
|
catch (Exception ex)
|
{
|
MessageBox.Show($"批量写入失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
}
|
}
|
|
private void btnConfig_Click(object sender, EventArgs e)
|
{
|
using (var configForm = new ConfigForm(config, GlobalVar.allPlcSettingPath + "\\" + this.Name + ".json"))
|
{
|
if (configForm.ShowDialog() == DialogResult.OK)
|
{
|
config = S7ConfigService.LoadConfig(GlobalVar.allPlcSettingPath);
|
LoadConfigAndSetupGrid();
|
UpdateConnectionStatus();
|
}
|
}
|
}
|
|
|
|
// 数据类型转换辅助方法
|
private object ConvertValue(string dataType, string valueStr)
|
{
|
switch (dataType)
|
{
|
case "Bool":
|
{
|
if (bool.TryParse(valueStr, out bool b)) return b;
|
if (valueStr == "1") return true;
|
if (valueStr == "0") return false;
|
throw new Exception("无效的布尔值");
|
}
|
case "Byte":
|
{
|
return byte.Parse(valueStr);
|
}
|
case "Int":
|
{
|
return short.Parse(valueStr);
|
}
|
case "DInt":
|
{
|
return int.Parse(valueStr);
|
}
|
case "Real":
|
{
|
return float.Parse(valueStr);
|
}
|
case "String":
|
{
|
return valueStr;
|
}
|
default:
|
{
|
throw new NotSupportedException($"不支持的类型: {dataType}");
|
}
|
}
|
}
|
private void LoadConfigAndSetupGrid()
|
{
|
config = S7ConfigService.LoadConfig(GlobalVar.allPlcSettingPath + "\\" + this.Name + ".json");
|
|
if (GlobalVar.allPlcSettings.Keys.Contains(Name))
|
{
|
GlobalVar.allPlcSettings[Name] = config;
|
}
|
else
|
{
|
GlobalVar.allPlcSettings.TryAdd(Name, config);
|
}
|
ConfigManager<Dictionary<string, PlcConfig>>.SaveConfig<Dictionary<string, PlcConfig>>(GlobalVar.allPlcSettings, GlobalVar.allPlcSettingsPath);
|
// 构建 DataTable 用于展示信号(支持编辑值列)
|
signalTable = new DataTable();
|
signalTable.Columns.Add("SignalName", typeof(string));
|
signalTable.Columns.Add("Address", typeof(string));
|
signalTable.Columns.Add("Value", typeof(string));
|
|
foreach (var signal in config.Signals)
|
{
|
string address = $"{signal.Area}";
|
if (signal.Area == "DB")
|
address += $"{signal.DbNumber}.DB";
|
address += $"{signal.ByteOffset}.{signal.BitOffset}";
|
|
signalTable.Rows.Add(signal.SignalName, address, "");
|
}
|
|
bindingSource = new BindingSource();
|
bindingSource.DataSource = signalTable;
|
dgvSignals.DataSource = bindingSource;
|
|
dgvSignals.Columns["SignalName"].HeaderText = "信号名称";
|
dgvSignals.Columns["SignalName"].ReadOnly = true;
|
dgvSignals.Columns["Address"].HeaderText = "PLC 地址";
|
dgvSignals.Columns["Address"].ReadOnly = true;
|
dgvSignals.Columns["Value"].HeaderText = "当前值";
|
dgvSignals.Columns["Value"].ReadOnly = false; // 允许用户编辑
|
|
UpdateConnectionStatus();
|
dgvSignals.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;
|
}
|
|
private void UpdateConnectionStatus()
|
{
|
if (communicator != null && communicator.bConnected)
|
{
|
lblStatus.Text = $"已连接: {config.PlcIpAddress}";
|
lblStatus.ForeColor = Color.Green;
|
}
|
else
|
{
|
lblStatus.Text = "未连接";
|
lblStatus.ForeColor = Color.Red;
|
}
|
}
|
|
// ========== 右键菜单:单信号操作 ==========
|
private SignalConfig GetSelectedSignal()
|
{
|
if (dgvSignals.CurrentRow == null) return null;
|
int index = dgvSignals.CurrentRow.Index;
|
if (index >= 0 && index < config.Signals.Count)
|
return config.Signals[index];
|
return null;
|
}
|
|
private void menuReadSignal_Click(object sender, EventArgs e)
|
{
|
var signal = GetSelectedSignal();
|
if (signal == null) return;
|
|
if (communicator != null && !communicator.bConnected)
|
{
|
MessageBox.Show("请先连接 PLC");
|
return;
|
}
|
|
try
|
{
|
object value = ((SiemensLBS7)communicator).ReadSignal(signal);
|
MessageBox.Show($"信号 [{signal.SignalName}] 当前值: {value}", "读取结果");
|
signalTable.Rows[dgvSignals.CurrentRow.Index]["Value"] = value?.ToString();
|
}
|
catch (Exception ex)
|
{
|
MessageBox.Show($"读取失败: {ex.Message}");
|
}
|
}
|
|
private void menuWriteSignal_Click(object sender, EventArgs e)
|
{
|
var signal = GetSelectedSignal();
|
if (signal == null) return;
|
|
if (communicator != null && !communicator.bConnected)
|
{
|
MessageBox.Show("请先连接 PLC");
|
return;
|
}
|
|
string input = Interaction.InputBox(
|
$"请输入要写入 {signal.SignalName} 的值 ({signal.DataType})",
|
"写入信号", "");
|
if (string.IsNullOrEmpty(input)) return;
|
|
try
|
{
|
object value = ConvertValue(signal.DataType, input);
|
((SiemensLBS7)communicator).WriteSignal(signal, value);
|
MessageBox.Show("写入成功");
|
}
|
catch (Exception ex)
|
{
|
MessageBox.Show($"写入失败: {ex.Message}");
|
}
|
}
|
}
|
}
|