| | |
| | | using LB_VisionProcesses.Communicators; |
| | | 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 |
| | | { |
| | |
| | | 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) |
| | | { |
| | |
| | | cmbIP.Enabled = false; |
| | | txtIP.Enabled = false; |
| | | txtPort.Enabled = false; |
| | | cmbDataType.Enabled = false; |
| | | |
| | | |
| | | lblType.Visible = false; |
| | | lblAddress.Visible = false; |
| | | cmbType.Visible = false; |
| | | txtAddress.Visible = false; |
| | | lblDataType.Visible = false; |
| | | cmbDataType.Visible = false; |
| | | |
| | | |
| | | Name = name; |
| | | this.Text = name; |
| | | if (communicator is UARTPort) |
| | | { |
| | | //统计可用端口 |
| | | SerialPortStream temp = new SerialPortStream(); |
| | | string[] ArryPort = temp.GetPortNames(); |
| | | for (int i = 0; i < ArryPort.Length; i++) |
| | | { |
| | | cmbIP.Items.Add(ArryPort[i]); |
| | | } |
| | | cmbIP.Text = communicator.CommunicatorConnections["地址"]?.ToString(); |
| | | txtPort.Text = communicator.CommunicatorConnections["端口"]?.ToString(); |
| | | txtIP.Visible = false; |
| | | cmbIP.Visible = true; |
| | | this.btnRuleSend.Visible = true; |
| | | lblType.Visible = false; |
| | | lblAddress.Visible = false; |
| | | cmbType.Visible = false; |
| | | txtAddress.Visible = false; |
| | | lblDataType.Visible = false; |
| | | cmbDataType.Visible = false; |
| | | |
| | | lblIP.Text = "COM口"; |
| | | lblPort.Text = "波特率"; |
| | | } |
| | | else if (communicator is TCPClient || communicator is TCPServer) |
| | | { |
| | | txtIP.Text = communicator.CommunicatorConnections["地址"]?.ToString(); |
| | | txtPort.Text = communicator.CommunicatorConnections["端口"]?.ToString(); |
| | | txtIP.Visible = true; |
| | | cmbIP.Visible = false; |
| | | this.btnRuleSend.Visible = false; |
| | | lblType.Visible = false; |
| | | lblAddress.Visible = false; |
| | | cmbType.Visible = false; |
| | | txtAddress.Visible = false; |
| | | lblDataType.Visible = false; |
| | | cmbDataType.Visible = false; |
| | | |
| | | lblIP.Text = "地址"; |
| | | lblPort.Text = "端口"; |
| | | } |
| | | else if (communicator is SiemensLBS7) |
| | | if (communicator is SiemensLBS7) |
| | | { |
| | | txtIP.Text = communicator.CommunicatorConnections["地址"]?.ToString(); |
| | | txtPort.Text = communicator.CommunicatorConnections["端口"]?.ToString(); |
| | |
| | | cmbType.Items.Add(communicator.CommunicatorConnections["型号"]?.ToString()); |
| | | cmbType.Text = communicator.CommunicatorConnections["型号"]?.ToString(); |
| | | } |
| | | if (!string.IsNullOrEmpty(communicator.CommunicatorConnections["变量地址"]?.ToString())) |
| | | { |
| | | txtAddress.Text = communicator.CommunicatorConnections["变量地址"]?.ToString(); |
| | | } |
| | | |
| | | // 初始化数据类型 |
| | | cmbDataType.Items.Clear(); |
| | | cmbDataType.Items.AddRange(new string[] { "String", "Bool", "Byte", "Int", "DInt", "Real", "Double", "Word", "DWord" }); |
| | | if (communicator.CommunicatorConnections.Contains("数据类型")) |
| | | { |
| | | cmbDataType.Text = communicator.CommunicatorConnections["数据类型"].ToString(); |
| | | } |
| | | else |
| | | { |
| | | cmbDataType.Text = "String"; |
| | | } |
| | | |
| | | txtIP.Visible = true; |
| | | cmbIP.Visible = false; |
| | | this.btnRuleSend.Visible = false; |
| | | lblType.Visible = true; |
| | | lblAddress.Visible = true; |
| | | cmbType.Visible = true; |
| | | txtAddress.Visible = true; |
| | | lblDataType.Visible = true; |
| | | cmbDataType.Visible = true; |
| | | cmbDataType.Enabled = true; // 启用数据类型选择 |
| | | |
| | | lblIP.Text = "IP"; |
| | | lblPort.Text = "槽"; |
| | |
| | | this.communicator = communicator; |
| | | //加载回调函数 |
| | | Subscribe(); |
| | | } |
| | | |
| | | private void cmbDataType_SelectedIndexChanged(object sender, EventArgs e) |
| | | { |
| | | if (communicator != null) |
| | | { |
| | | communicator.CommunicatorConnections.Add("数据类型", cmbDataType.Text); |
| | | communicatorChanged(communicator); |
| | | } |
| | | LoadConfigAndSetupGrid(); |
| | | } |
| | | |
| | | private void CommunicatorForm_FormClosing(object sender, FormClosingEventArgs e) => Unsubscribe(); |
| | |
| | | } |
| | | } |
| | | |
| | | private void btnSend_Click(object sender, EventArgs e) |
| | | // 批量读取所有信号 |
| | | private void btnReadAll_Click(object sender, EventArgs e) |
| | | { |
| | | if (communicator == null) |
| | | if (communicator == null || !communicator.bConnected) |
| | | { |
| | | MessageBox.Show("请先连接 PLC", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); |
| | | return; |
| | | } |
| | | |
| | | if (communicator.SendMessage(txtSendMsg.Text)) |
| | | try |
| | | { |
| | | ShowSendMsg(txtSendMsg.Text); |
| | | 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() ?? ""); |
| | | } |
| | | } |
| | | else |
| | | catch (Exception ex) |
| | | { |
| | | ShowLogMsg(communicator.Msg); |
| | | MessageBox.Show($"批量读取失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); |
| | | } |
| | | } |
| | | |
| | | private void btnRuleSend_Click(object sender, EventArgs e) |
| | | // 批量写入:将表格中修改过的值写入 PLC |
| | | private void btnWriteAll_Click(object sender, EventArgs e) |
| | | { |
| | | if (communicator == null) |
| | | if (communicator == null || !communicator.bConnected) |
| | | { |
| | | MessageBox.Show("请先连接 PLC", "提示", MessageBoxButtons.OK, MessageBoxIcon.Warning); |
| | | return; |
| | | } |
| | | |
| | | string SendMsg = txtSendMsg.Text; |
| | | |
| | | //byte[] HexByte = BaseCommunicator.strToHexByte(SendMsg); |
| | | |
| | | byte[] HexByte = SendMsg.Split(' ', StringSplitOptions.RemoveEmptyEntries) |
| | | .Select(hex => Convert.ToByte(hex, 16)) |
| | | .ToArray(); |
| | | ushort crcHexByte = BaseCommunicator.CRC16Calculate(HexByte, HexByte.Length); |
| | | |
| | | string crcString = crcHexByte.ToString("X4"); |
| | | crcString = crcString.Insert(2, " "); |
| | | HexByte = BaseCommunicator.strToHexByte(SendMsg + " " + crcString); |
| | | |
| | | if (communicator.SendMessage(HexByte)) |
| | | try |
| | | { |
| | | ShowSendMsg(SendMsg + " " + crcString); |
| | | 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); |
| | | } |
| | | else |
| | | catch (Exception ex) |
| | | { |
| | | ShowLogMsg(communicator.Msg); |
| | | MessageBox.Show($"批量写入失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error); |
| | | } |
| | | } |
| | | |
| | | private void txtAddress_TextChanged(object sender, EventArgs e) |
| | | private void btnConfig_Click(object sender, EventArgs e) |
| | | { |
| | | if (communicator != null) |
| | | using (var configForm = new ConfigForm(config, GlobalVar.allPlcSettingPath + "\\" + this.Name + ".json")) |
| | | { |
| | | communicator.CommunicatorConnections.Add("变量地址", txtAddress.Text); |
| | | communicatorChanged(communicator); |
| | | 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}"); |
| | | } |
| | | } |
| | | } |