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}");
}
}
///
/// 通讯回调运行
///
///
///
private void ShowReceiveMsg(string strReceiveMsg)
{
// 如果当前不是 UI 线程,则通过 Invoke 将操作调度到 UI 线程
if (this.InvokeRequired)
{
this.Invoke(new Action((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((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((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>.SaveConfig>(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}");
}
}
}
}