607 lines
20 KiB
C#
607 lines
20 KiB
C#
using System;
|
|
using System.Drawing;
|
|
using System.Windows.Forms;
|
|
|
|
namespace B24SiemensEmulator
|
|
{
|
|
public partial class MainForm : Form
|
|
{
|
|
private GroupBox inputGroupBox;
|
|
private GroupBox outputGroupBox;
|
|
private GroupBox controlGroupBox;
|
|
private GroupBox statusGroupBox;
|
|
|
|
// Input controls
|
|
private CheckBox lifebitCheckBox;
|
|
private CheckBox kameraStartCheckBox;
|
|
private NumericUpDown materialnummerNumeric;
|
|
private NumericUpDown artikelnummerBallNumeric;
|
|
private NumericUpDown materialnummerFoilNumeric;
|
|
private TextBox chargennummerTextBox;
|
|
|
|
// Output controls (read-only)
|
|
private Label lifebitResponseLabel;
|
|
private Label kameraStartResponseLabel;
|
|
private Label materialnummerResponseLabel;
|
|
private Label artikelnummerBallResponseLabel;
|
|
private Label materialnummerFoilResponseLabel;
|
|
private Label chargennummerResponseLabel;
|
|
|
|
// Control buttons
|
|
private Button startStopButton;
|
|
private Button saveConfigButton;
|
|
private Button loadConfigButton;
|
|
private Button applyButton;
|
|
|
|
// Status controls
|
|
private Label connectionStatusLabel;
|
|
private Label errorMessageLabel;
|
|
|
|
private bool isRunning = false;
|
|
private SiemensTcpClient? tcpClient;
|
|
private PLCPacket currentPacket = new PLCPacket();
|
|
|
|
public MainForm()
|
|
{
|
|
InitializeComponent();
|
|
InitializeTcpClient();
|
|
WireUpEventHandlers();
|
|
|
|
// Initialize current packet with form default values
|
|
currentPacket = GetInputPacket();
|
|
}
|
|
|
|
private void InitializeTcpClient()
|
|
{
|
|
tcpClient = new SiemensTcpClient();
|
|
tcpClient.GetPacketToSend = GetCurrentPacket;
|
|
tcpClient.ConnectionStatusChanged += OnConnectionStatusChanged;
|
|
tcpClient.ResponseReceived += OnResponseReceived;
|
|
tcpClient.ErrorOccurred += OnErrorOccurred;
|
|
}
|
|
|
|
private void WireUpEventHandlers()
|
|
{
|
|
startStopButton.Click += OnStartStopButtonClick;
|
|
saveConfigButton.Click += OnSaveConfigButtonClick;
|
|
loadConfigButton.Click += OnLoadConfigButtonClick;
|
|
applyButton.Click += OnApplyButtonClick;
|
|
|
|
// Form closing event
|
|
this.FormClosing += OnFormClosing;
|
|
}
|
|
|
|
private async void OnStartStopButtonClick(object? sender, EventArgs e)
|
|
{
|
|
if (tcpClient == null) return;
|
|
|
|
if (!isRunning)
|
|
{
|
|
// Start
|
|
var connected = await tcpClient.ConnectAsync();
|
|
if (connected)
|
|
{
|
|
tcpClient.StartSending();
|
|
SetRunningState(true);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Stop
|
|
tcpClient.StopSending();
|
|
await tcpClient.DisconnectAsync();
|
|
SetRunningState(false);
|
|
}
|
|
}
|
|
|
|
private void OnSaveConfigButtonClick(object? sender, EventArgs e)
|
|
{
|
|
var config = PacketConfiguration.FromPLCPacket(currentPacket);
|
|
|
|
bool saved = ConfigurationManager.SaveConfiguration(config);
|
|
if (saved)
|
|
{
|
|
MessageBox.Show("Current applied configuration saved successfully.", "Save Complete",
|
|
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
}
|
|
|
|
private void OnLoadConfigButtonClick(object? sender, EventArgs e)
|
|
{
|
|
var config = ConfigurationManager.LoadConfiguration();
|
|
if (config != null)
|
|
{
|
|
LoadConfigurationToForm(config);
|
|
MessageBox.Show("Configuration loaded successfully. Click Apply to use the loaded values.", "Load Complete",
|
|
MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
}
|
|
}
|
|
|
|
private void OnApplyButtonClick(object? sender, EventArgs e)
|
|
{
|
|
currentPacket = GetInputPacket();
|
|
|
|
// Provide visual feedback by briefly changing the button text
|
|
applyButton.Text = "Applied!";
|
|
applyButton.BackColor = Color.LightGreen;
|
|
|
|
var timer = new System.Windows.Forms.Timer();
|
|
timer.Interval = 1000; // 1 second
|
|
timer.Tick += (s, args) =>
|
|
{
|
|
applyButton.Text = "Apply";
|
|
applyButton.BackColor = SystemColors.Control;
|
|
timer.Stop();
|
|
timer.Dispose();
|
|
};
|
|
timer.Start();
|
|
}
|
|
|
|
private void LoadConfigurationToForm(PacketConfiguration config)
|
|
{
|
|
lifebitCheckBox.Checked = config.Lifebit;
|
|
kameraStartCheckBox.Checked = config.KameraStart;
|
|
materialnummerNumeric.Value = config.Materialnummer;
|
|
artikelnummerBallNumeric.Value = config.ArtikelnummerBall;
|
|
materialnummerFoilNumeric.Value = config.MaterialnummerFoil;
|
|
chargennummerTextBox.Text = config.Chargennummer;
|
|
}
|
|
|
|
private void OnConnectionStatusChanged(bool connected)
|
|
{
|
|
UpdateConnectionStatus(connected);
|
|
if (connected)
|
|
{
|
|
HideErrorMessage();
|
|
}
|
|
}
|
|
|
|
private void OnResponseReceived(PLCPacket packet)
|
|
{
|
|
UpdateResponseDisplay(packet);
|
|
}
|
|
|
|
private void OnErrorOccurred(string error)
|
|
{
|
|
ShowErrorMessage(error);
|
|
}
|
|
|
|
private void OnFormClosing(object? sender, FormClosingEventArgs e)
|
|
{
|
|
tcpClient?.Dispose();
|
|
}
|
|
|
|
private void InitializeComponent()
|
|
{
|
|
this.SuspendLayout();
|
|
|
|
// Form properties
|
|
this.Text = "B24 Siemens PLC Emulator";
|
|
this.Size = new Size(800, 640);
|
|
this.FormBorderStyle = FormBorderStyle.FixedSingle;
|
|
this.MaximizeBox = false;
|
|
this.StartPosition = FormStartPosition.CenterScreen;
|
|
|
|
// Status Group Box (Top)
|
|
statusGroupBox = new GroupBox
|
|
{
|
|
Text = "Status",
|
|
Location = new Point(12, 12),
|
|
Size = new Size(760, 80)
|
|
};
|
|
|
|
connectionStatusLabel = new Label
|
|
{
|
|
Text = "Disconnected",
|
|
Location = new Point(15, 25),
|
|
Size = new Size(200, 20),
|
|
Font = new Font("Microsoft Sans Serif", 9F, FontStyle.Bold)
|
|
};
|
|
|
|
errorMessageLabel = new Label
|
|
{
|
|
Text = "",
|
|
Location = new Point(15, 50),
|
|
Size = new Size(720, 20),
|
|
ForeColor = Color.Red,
|
|
Font = new Font("Microsoft Sans Serif", 8.25F)
|
|
};
|
|
|
|
statusGroupBox.Controls.Add(connectionStatusLabel);
|
|
statusGroupBox.Controls.Add(errorMessageLabel);
|
|
|
|
// Control Group Box
|
|
controlGroupBox = new GroupBox
|
|
{
|
|
Text = "Controls",
|
|
Location = new Point(12, 100),
|
|
Size = new Size(760, 60)
|
|
};
|
|
|
|
startStopButton = new Button
|
|
{
|
|
Text = "Start",
|
|
Location = new Point(15, 25),
|
|
Size = new Size(100, 30),
|
|
UseVisualStyleBackColor = true
|
|
};
|
|
|
|
saveConfigButton = new Button
|
|
{
|
|
Text = "Save Config",
|
|
Location = new Point(130, 25),
|
|
Size = new Size(100, 30),
|
|
UseVisualStyleBackColor = true
|
|
};
|
|
|
|
loadConfigButton = new Button
|
|
{
|
|
Text = "Load Config",
|
|
Location = new Point(245, 25),
|
|
Size = new Size(100, 30),
|
|
UseVisualStyleBackColor = true
|
|
};
|
|
|
|
controlGroupBox.Controls.Add(startStopButton);
|
|
controlGroupBox.Controls.Add(saveConfigButton);
|
|
controlGroupBox.Controls.Add(loadConfigButton);
|
|
|
|
// Input Group Box (Left Panel)
|
|
inputGroupBox = new GroupBox
|
|
{
|
|
Text = "Input Packet",
|
|
Location = new Point(12, 180),
|
|
Size = new Size(370, 390)
|
|
};
|
|
|
|
// Output Group Box (Right Panel)
|
|
outputGroupBox = new GroupBox
|
|
{
|
|
Text = "Response Packet",
|
|
Location = new Point(400, 180),
|
|
Size = new Size(370, 390)
|
|
};
|
|
|
|
CreateInputControls();
|
|
CreateOutputControls();
|
|
|
|
// Add all controls to form
|
|
this.Controls.Add(statusGroupBox);
|
|
this.Controls.Add(controlGroupBox);
|
|
this.Controls.Add(inputGroupBox);
|
|
this.Controls.Add(outputGroupBox);
|
|
|
|
this.ResumeLayout();
|
|
}
|
|
|
|
private void CreateInputControls()
|
|
{
|
|
int yPos = 30;
|
|
int spacing = 45;
|
|
|
|
// Lifebit
|
|
var lifebitLabel = new Label
|
|
{
|
|
Text = "Lifebit:",
|
|
Location = new Point(15, yPos),
|
|
Size = new Size(80, 20)
|
|
};
|
|
lifebitCheckBox = new CheckBox
|
|
{
|
|
Location = new Point(120, yPos),
|
|
Size = new Size(20, 20)
|
|
};
|
|
inputGroupBox.Controls.Add(lifebitLabel);
|
|
inputGroupBox.Controls.Add(lifebitCheckBox);
|
|
|
|
yPos += spacing;
|
|
|
|
// KameraStart
|
|
var kameraStartLabel = new Label
|
|
{
|
|
Text = "KameraStart:",
|
|
Location = new Point(15, yPos),
|
|
Size = new Size(80, 20)
|
|
};
|
|
kameraStartCheckBox = new CheckBox
|
|
{
|
|
Location = new Point(120, yPos),
|
|
Size = new Size(20, 20)
|
|
};
|
|
inputGroupBox.Controls.Add(kameraStartLabel);
|
|
inputGroupBox.Controls.Add(kameraStartCheckBox);
|
|
|
|
yPos += spacing;
|
|
|
|
// Materialnummer
|
|
var materialnummerLabel = new Label
|
|
{
|
|
Text = "Materialnummer:",
|
|
Location = new Point(15, yPos),
|
|
Size = new Size(100, 20)
|
|
};
|
|
materialnummerNumeric = new NumericUpDown
|
|
{
|
|
Location = new Point(120, yPos),
|
|
Size = new Size(120, 20),
|
|
Minimum = int.MinValue,
|
|
Maximum = int.MaxValue
|
|
};
|
|
inputGroupBox.Controls.Add(materialnummerLabel);
|
|
inputGroupBox.Controls.Add(materialnummerNumeric);
|
|
|
|
yPos += spacing;
|
|
|
|
// ArtikelnummerBall
|
|
var artikelnummerBallLabel = new Label
|
|
{
|
|
Text = "ArtikelnummerBall:",
|
|
Location = new Point(15, yPos),
|
|
Size = new Size(100, 20)
|
|
};
|
|
artikelnummerBallNumeric = new NumericUpDown
|
|
{
|
|
Location = new Point(120, yPos),
|
|
Size = new Size(120, 20),
|
|
Minimum = int.MinValue,
|
|
Maximum = int.MaxValue
|
|
};
|
|
inputGroupBox.Controls.Add(artikelnummerBallLabel);
|
|
inputGroupBox.Controls.Add(artikelnummerBallNumeric);
|
|
|
|
yPos += spacing;
|
|
|
|
// MaterialnummerFoil
|
|
var materialnummerFoilLabel = new Label
|
|
{
|
|
Text = "MaterialnummerFoil:",
|
|
Location = new Point(15, yPos),
|
|
Size = new Size(100, 20)
|
|
};
|
|
materialnummerFoilNumeric = new NumericUpDown
|
|
{
|
|
Location = new Point(120, yPos),
|
|
Size = new Size(120, 20),
|
|
Minimum = int.MinValue,
|
|
Maximum = int.MaxValue
|
|
};
|
|
inputGroupBox.Controls.Add(materialnummerFoilLabel);
|
|
inputGroupBox.Controls.Add(materialnummerFoilNumeric);
|
|
|
|
yPos += spacing;
|
|
|
|
// Chargennummer
|
|
var chargennummerLabel = new Label
|
|
{
|
|
Text = "Chargennummer:",
|
|
Location = new Point(15, yPos),
|
|
Size = new Size(100, 20)
|
|
};
|
|
chargennummerTextBox = new TextBox
|
|
{
|
|
Location = new Point(120, yPos),
|
|
Size = new Size(120, 20),
|
|
MaxLength = 5
|
|
};
|
|
inputGroupBox.Controls.Add(chargennummerLabel);
|
|
inputGroupBox.Controls.Add(chargennummerTextBox);
|
|
|
|
yPos += spacing;
|
|
|
|
// Apply button
|
|
applyButton = new Button
|
|
{
|
|
Text = "Apply",
|
|
Location = new Point(120, yPos),
|
|
Size = new Size(120, 30),
|
|
UseVisualStyleBackColor = true,
|
|
Font = new Font("Microsoft Sans Serif", 8.25F, FontStyle.Bold)
|
|
};
|
|
inputGroupBox.Controls.Add(applyButton);
|
|
}
|
|
|
|
private void CreateOutputControls()
|
|
{
|
|
int yPos = 30;
|
|
int spacing = 45;
|
|
|
|
// Lifebit Response
|
|
var lifebitResponseTitle = new Label
|
|
{
|
|
Text = "Lifebit:",
|
|
Location = new Point(15, yPos),
|
|
Size = new Size(80, 20)
|
|
};
|
|
lifebitResponseLabel = new Label
|
|
{
|
|
Text = "False",
|
|
Location = new Point(120, yPos),
|
|
Size = new Size(100, 20),
|
|
BorderStyle = BorderStyle.FixedSingle,
|
|
BackColor = SystemColors.Control
|
|
};
|
|
outputGroupBox.Controls.Add(lifebitResponseTitle);
|
|
outputGroupBox.Controls.Add(lifebitResponseLabel);
|
|
|
|
yPos += spacing;
|
|
|
|
// KameraStart Response
|
|
var kameraStartResponseTitle = new Label
|
|
{
|
|
Text = "KameraStart:",
|
|
Location = new Point(15, yPos),
|
|
Size = new Size(80, 20)
|
|
};
|
|
kameraStartResponseLabel = new Label
|
|
{
|
|
Text = "False",
|
|
Location = new Point(120, yPos),
|
|
Size = new Size(100, 20),
|
|
BorderStyle = BorderStyle.FixedSingle,
|
|
BackColor = SystemColors.Control
|
|
};
|
|
outputGroupBox.Controls.Add(kameraStartResponseTitle);
|
|
outputGroupBox.Controls.Add(kameraStartResponseLabel);
|
|
|
|
yPos += spacing;
|
|
|
|
// Materialnummer Response
|
|
var materialnummerResponseTitle = new Label
|
|
{
|
|
Text = "Materialnummer:",
|
|
Location = new Point(15, yPos),
|
|
Size = new Size(100, 20)
|
|
};
|
|
materialnummerResponseLabel = new Label
|
|
{
|
|
Text = "0",
|
|
Location = new Point(120, yPos),
|
|
Size = new Size(120, 20),
|
|
BorderStyle = BorderStyle.FixedSingle,
|
|
BackColor = SystemColors.Control
|
|
};
|
|
outputGroupBox.Controls.Add(materialnummerResponseTitle);
|
|
outputGroupBox.Controls.Add(materialnummerResponseLabel);
|
|
|
|
yPos += spacing;
|
|
|
|
// ArtikelnummerBall Response
|
|
var artikelnummerBallResponseTitle = new Label
|
|
{
|
|
Text = "ArtikelnummerBall:",
|
|
Location = new Point(15, yPos),
|
|
Size = new Size(100, 20)
|
|
};
|
|
artikelnummerBallResponseLabel = new Label
|
|
{
|
|
Text = "0",
|
|
Location = new Point(120, yPos),
|
|
Size = new Size(120, 20),
|
|
BorderStyle = BorderStyle.FixedSingle,
|
|
BackColor = SystemColors.Control
|
|
};
|
|
outputGroupBox.Controls.Add(artikelnummerBallResponseTitle);
|
|
outputGroupBox.Controls.Add(artikelnummerBallResponseLabel);
|
|
|
|
yPos += spacing;
|
|
|
|
// MaterialnummerFoil Response
|
|
var materialnummerFoilResponseTitle = new Label
|
|
{
|
|
Text = "MaterialnummerFoil:",
|
|
Location = new Point(15, yPos),
|
|
Size = new Size(100, 20)
|
|
};
|
|
materialnummerFoilResponseLabel = new Label
|
|
{
|
|
Text = "0",
|
|
Location = new Point(120, yPos),
|
|
Size = new Size(120, 20),
|
|
BorderStyle = BorderStyle.FixedSingle,
|
|
BackColor = SystemColors.Control
|
|
};
|
|
outputGroupBox.Controls.Add(materialnummerFoilResponseTitle);
|
|
outputGroupBox.Controls.Add(materialnummerFoilResponseLabel);
|
|
|
|
yPos += spacing;
|
|
|
|
// Chargennummer Response
|
|
var chargennummerResponseTitle = new Label
|
|
{
|
|
Text = "Chargennummer:",
|
|
Location = new Point(15, yPos),
|
|
Size = new Size(100, 20)
|
|
};
|
|
chargennummerResponseLabel = new Label
|
|
{
|
|
Text = "",
|
|
Location = new Point(120, yPos),
|
|
Size = new Size(120, 20),
|
|
BorderStyle = BorderStyle.FixedSingle,
|
|
BackColor = SystemColors.Control
|
|
};
|
|
outputGroupBox.Controls.Add(chargennummerResponseTitle);
|
|
outputGroupBox.Controls.Add(chargennummerResponseLabel);
|
|
}
|
|
|
|
public PLCPacket GetInputPacket()
|
|
{
|
|
return new PLCPacket
|
|
{
|
|
Lifebit = lifebitCheckBox.Checked,
|
|
KameraStart = kameraStartCheckBox.Checked,
|
|
Materialnummer = (int)materialnummerNumeric.Value,
|
|
ArtikelnummerBall = (int)artikelnummerBallNumeric.Value,
|
|
MaterialnummerFoil = (int)materialnummerFoilNumeric.Value,
|
|
Chargennummer = chargennummerTextBox.Text
|
|
};
|
|
}
|
|
|
|
public PLCPacket GetCurrentPacket()
|
|
{
|
|
return currentPacket;
|
|
}
|
|
|
|
public void UpdateResponseDisplay(PLCPacket packet)
|
|
{
|
|
if (InvokeRequired)
|
|
{
|
|
Invoke(new Action<PLCPacket>(UpdateResponseDisplay), packet);
|
|
return;
|
|
}
|
|
|
|
lifebitResponseLabel.Text = packet.Lifebit.ToString();
|
|
kameraStartResponseLabel.Text = packet.KameraStart.ToString();
|
|
materialnummerResponseLabel.Text = packet.Materialnummer.ToString();
|
|
artikelnummerBallResponseLabel.Text = packet.ArtikelnummerBall.ToString();
|
|
materialnummerFoilResponseLabel.Text = packet.MaterialnummerFoil.ToString();
|
|
chargennummerResponseLabel.Text = packet.Chargennummer;
|
|
}
|
|
|
|
public void UpdateConnectionStatus(bool connected)
|
|
{
|
|
if (InvokeRequired)
|
|
{
|
|
Invoke(new Action<bool>(UpdateConnectionStatus), connected);
|
|
return;
|
|
}
|
|
|
|
connectionStatusLabel.Text = connected ? "Connected" : "Disconnected";
|
|
connectionStatusLabel.ForeColor = connected ? Color.Green : Color.Red;
|
|
}
|
|
|
|
public void ShowErrorMessage(string message)
|
|
{
|
|
if (InvokeRequired)
|
|
{
|
|
Invoke(new Action<string>(ShowErrorMessage), message);
|
|
return;
|
|
}
|
|
|
|
errorMessageLabel.Text = message;
|
|
}
|
|
|
|
public void HideErrorMessage()
|
|
{
|
|
if (InvokeRequired)
|
|
{
|
|
Invoke(new Action(HideErrorMessage));
|
|
return;
|
|
}
|
|
|
|
errorMessageLabel.Text = "";
|
|
}
|
|
|
|
// Event handlers will be wired up later
|
|
public Button StartStopButton => startStopButton;
|
|
public Button SaveConfigButton => saveConfigButton;
|
|
public Button LoadConfigButton => loadConfigButton;
|
|
public bool IsRunning => isRunning;
|
|
|
|
public void SetRunningState(bool running)
|
|
{
|
|
isRunning = running;
|
|
startStopButton.Text = running ? "Stop" : "Start";
|
|
}
|
|
}
|
|
} |