Adaptado UserControl del PLCSim Advanced

This commit is contained in:
Miguel 2024-05-10 22:17:57 +02:00
parent e23e07b2c2
commit 72692cdf8c
12 changed files with 526 additions and 14 deletions

View File

@ -15,4 +15,10 @@
<PackageReference Include="OpenCvSharp4.Windows" Version="4.9.0.20240103" />
</ItemGroup>
<ItemGroup>
<Reference Include="Siemens.Simatic.Simulation.Runtime.Api.x64">
<HintPath>C:\Program Files (x86)\Common Files\Siemens\PLCSIMADV\API\6.0\Siemens.Simatic.Simulation.Runtime.Api.x64.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

View File

@ -14,6 +14,7 @@ using System.Windows.Media.Imaging;
using static System.Runtime.InteropServices.JavaScript.JSType;
using System.Windows.Threading;
using CtrEditor.ObjetosSim;
using CtrEditor.Siemens;
using System.IO;
// using System.Windows.Forms;
using System.Text.Json.Serialization;
@ -32,6 +33,7 @@ namespace CtrEditor
public ObservableCollection<string> listaImagenes { get; private set; } // Publicación de las claves del diccionario
public ObservableCollection<TipoSimulable> ListaOsBase { get; } = new ObservableCollection<TipoSimulable>();
private ObservableCollection<osBase> _objetosSimulables = new ObservableCollection<osBase>();
public PLCViewModel _plcViewModelData;
private SimulationManager simulationManager = new SimulationManager();
@ -52,6 +54,9 @@ namespace CtrEditor
OpenWorkDirectoryCommand = new RelayCommand(OpenWorkDirectory);
datosDeTrabajo = new DatosDeTrabajo();
// Inicializa el PLCViewModel
_plcViewModelData = new PLCViewModel();
InitializeTipoSimulableList();
ItemDoubleClickCommand = new ParameterizedRelayCommand(ExecuteDoubleClick);
@ -62,7 +67,6 @@ namespace CtrEditor
StartSimulationCommand = new RelayCommand(StartSimulation);
StopSimulationCommand = new RelayCommand(StopSimulation);
}
public void LoadInitialData()
@ -161,6 +165,17 @@ namespace CtrEditor
}
}
public PLCViewModel PLCViewModel
{
get { return _plcViewModelData; }
set
{
_plcViewModelData = value;
OnPropertyChanged(nameof(PLCViewModel));
}
}
private string _selectedImage = null;
public string SelectedImage
{
@ -241,7 +256,8 @@ namespace CtrEditor
var dataToSerialize = new SimulationData
{
ObjetosSimulables = ObjetosSimulables,
UnitConverter = PixelToMeter.Instance.calc
UnitConverter = PixelToMeter.Instance.calc,
PLC_ConnectionData = PLCViewModel
};
var serializedData = JsonConvert.SerializeObject(dataToSerialize, settings);
@ -271,9 +287,14 @@ namespace CtrEditor
var simulationData = JsonConvert.DeserializeObject<SimulationData>(jsonString, settings);
if (simulationData != null)
{
ObjetosSimulables = simulationData.ObjetosSimulables;
if (simulationData.ObjetosSimulables is not null)
ObjetosSimulables = simulationData.ObjetosSimulables;
if (simulationData.PLC_ConnectionData is not null)
PLCViewModel = simulationData.PLC_ConnectionData;
else
PLCViewModel = new PLCViewModel();
// Restaura el UnitConverter si es necesario en otra parte de tu código
PixelToMeter.Instance.calc = simulationData.UnitConverter;
// Recorrer la colección de objetos simulables
@ -322,6 +343,7 @@ namespace CtrEditor
{
public ObservableCollection<osBase> ObjetosSimulables { get; set; }
public UnitConverter UnitConverter { get; set; }
public PLCViewModel PLC_ConnectionData { get; set; }
}
public class TipoSimulable

View File

@ -1,9 +1,10 @@
<Window x:Class="CtrEditor.MainWindow"
<Window
xmlns:ctreditor="clr-namespace:CtrEditor"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="450" Width="800"
xmlns:Siemens="clr-namespace:CtrEditor.Siemens" x:Class="CtrEditor.MainWindow"
Height="900" Width="1600"
ResizeMode="CanResize" Title="{Binding directorioTrabajo}">
<Window.DataContext>
@ -33,8 +34,9 @@
<!-- Primera Columna -->
<Grid Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ListBox x:Name="ListaImagenes" Grid.Row="0" Margin="5" ItemsSource="{Binding listaImagenes}" SelectedItem="{Binding SelectedImage}" />
<ListBox x:Name="ListaFunciones" Grid.Row="1" Margin="5" ItemsSource="{Binding ListaOsBase}" DisplayMemberPath="Nombre" SelectedItem="{Binding SelectedItem}">
@ -44,6 +46,7 @@
</i:EventTrigger>
</i:Interaction.Triggers>
</ListBox>
<Siemens:PLCControl x:Name="PLCSim" Grid.Row="2" Margin="5" DataContext="{Binding PLCViewModel}"/>
</Grid>
<!-- GridSplitter -->
<GridSplitter Grid.Column="0" Grid.Row="0" HorizontalAlignment="Right" Width="5" Background="LightGray" />

View File

@ -10,6 +10,7 @@ using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using CtrEditor.ObjetosSim;
using CtrEditor.Siemens;
using static System.Runtime.InteropServices.JavaScript.JSType;
using Binding = System.Windows.Data.Binding;
using Label = System.Windows.Controls.Label;

View File

@ -18,6 +18,8 @@ namespace CtrEditor.ObjetosSim
return new ucTransporteTTop();
if (tipoObjeto == typeof(osGuia))
return new ucGuia();
if (tipoObjeto == typeof(osTransporteGuias))
return new ucTransporteGuias();
// Puedes añadir más condiciones para otros tipos
@ -32,6 +34,8 @@ namespace CtrEditor.ObjetosSim
return new osTransporteTTop();
if (tipoObjeto == typeof(osGuia))
return new osGuia();
if (tipoObjeto == typeof(osTransporteGuias))
return new osTransporteGuias();
// Puedes añadir más condiciones para otros tipos

View File

@ -11,7 +11,7 @@
</UserControl.Resources>
<Canvas>
<Rectangle Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Height="{Binding Alto, Converter={StaticResource MeterToPixelConverter}}" Fill="Blue">
<Rectangle Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Height="{Binding AltoGuia, Converter={StaticResource MeterToPixelConverter}}" Fill="Blue">
<Rectangle.RenderTransform>
<RotateTransform Angle="{Binding Angulo}"/>
</Rectangle.RenderTransform>

View File

@ -54,13 +54,13 @@ namespace CtrEditor.ObjetosSim
OnPropertyChanged(nameof(Ancho));
}
}
public float Alto
public float AltoGuia
{
get => Geometria.Width;
set
{
Geometria.Width = value;
OnPropertyChanged(nameof(Alto));
OnPropertyChanged(nameof(AltoGuia));
}
}
@ -90,7 +90,7 @@ namespace CtrEditor.ObjetosSim
public osGuia()
{
Ancho = 1;
Alto = 0.10f;
AltoGuia = 0.03f;
}
public override void ConnectSimManager(SimulationManager simulationManager)

View File

@ -5,9 +5,27 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:CtrEditor.ObjetosSim"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<local:MeterToPixelConverter x:Key="MeterToPixelConverter"/>
</UserControl.Resources>
<Grid>
<!-- Contenedor principal -->
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Borde superior -->
<Border Grid.Row="0" Height="5" Width="{Binding Ancho, Converter={StaticResource MeterToPixelConverter}}" Background="Blue"/>
<!-- Contenido central -->
<local:ucTransporteTTop Grid.Row="1"/>
<!-- Borde inferior -->
<Border Grid.Row="2" Height="5" Background="Blue"/>
</Grid>
</UserControl>

View File

@ -18,11 +18,142 @@ namespace CtrEditor.ObjetosSim
/// <summary>
/// Interaction logic for ucTransporteGuias.xaml
/// </summary>
public partial class ucTransporteGuias : UserControl
public class osTransporteGuias : osBase
{
private string _nombre = "Transporte Guias";
private float frictionCoefficient;
private float velMax50hz; // en metros por minuto
private float tiempoRampa;
private bool esMarcha;
private Rectangle Geometria = new Rectangle();
public override float Left
{
get => Geometria.Left;
set
{
Geometria.Left = value;
CanvasSetLeftinMeter(value);
OnPropertyChanged(nameof(Left));
}
}
public override float Top
{
get => Geometria.Top;
set
{
Geometria.Top = value;
CanvasSetTopinMeter(value);
OnPropertyChanged(nameof(Top));
}
}
public float Ancho
{
get => Geometria.Length;
set
{
Geometria.Length = value;
OnPropertyChanged(nameof(Ancho));
}
}
public float Alto
{
get => Geometria.Width;
set
{
Geometria.Width = value;
OnPropertyChanged(nameof(Alto));
}
}
public float Angulo
{
get => Geometria.Angle;
set
{
Geometria.Angle = value;
OnPropertyChanged(nameof(Angulo));
}
}
public float VelocidadActual
{
get => Geometria.Speed;
set
{
Geometria.Speed = value;
OnPropertyChanged(nameof(VelocidadActual));
}
}
public override string Nombre
{
get => _nombre;
set
{
if (_nombre != value)
{
_nombre = value;
OnPropertyChanged(nameof(Nombre));
}
}
}
public float FrictionCoefficient { get => frictionCoefficient; set => frictionCoefficient = value; }
public float VelMax50hz { get => velMax50hz; set => velMax50hz = value; }
public float TiempoRampa { get => tiempoRampa; set => tiempoRampa = value; }
public bool EsMarcha { get => esMarcha; set => esMarcha = value; }
public osTransporteGuias()
{
Ancho = 1;
Alto = 0.10f;
}
public override void ConnectSimManager(SimulationManager simulationManager)
{
simulationManager.rectangles.Add(Geometria);
}
public override void UpdateControl()
{
}
}
public partial class ucTransporteGuias : UserControl, IDataContainer
{
public osBase? Datos { get; set; }
public ucTransporteGuias()
{
InitializeComponent();
}
public void Resize(float width, float height)
{
if (Datos is osTransporteGuias datos)
datos.Ancho = PixelToMeter.Instance.calc.PixelsToMeters(width);
}
public void Move(float LeftPixels, float TopPixels)
{
if (Datos != null)
{
Datos.Left = PixelToMeter.Instance.calc.PixelsToMeters(LeftPixels);
Datos.Top = PixelToMeter.Instance.calc.PixelsToMeters(TopPixels);
}
}
public void Rotate(float Angle)
{
if (Datos != null)
if (Datos is osTransporteGuias datos)
datos.Angulo = Angle;
}
public void Highlight(bool State) { }
public int ZIndex()
{
return 1;
}
}
}

42
Siemens/PLCControl.xaml Normal file
View File

@ -0,0 +1,42 @@
<UserControl x:Class="CtrEditor.Siemens.PLCControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:CtrEditor.Siemens">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions>
<Label Content="IP:" Grid.Row="0" Grid.Column="0" Margin="1" VerticalAlignment="Center"/>
<TextBox Text="{Binding IP, UpdateSourceTrigger=PropertyChanged}"
Grid.Row="0" Grid.Column="1" Margin="1" VerticalAlignment="Center"/>
<Label Content="Name:" Grid.Row="1" Grid.Column="0" Margin="1" VerticalAlignment="Center"/>
<TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"
Grid.Row="1" Grid.Column="1" Margin="1" VerticalAlignment="Center"/>
<Button Content="Connect" Command="{Binding ConnectCommand}"
Grid.Row="2" Grid.Column="0" Margin="1" VerticalAlignment="Center"/>
<Button Content="Disconnect" Command="{Binding DisconnectCommand}"
Grid.Row="2" Grid.Column="1" Margin="1" VerticalAlignment="Center"/>
<Label Content="CPU cycle:" Grid.Row="3" Grid.Column="0" Margin="1" VerticalAlignment="Center"/>
<Label Content="{Binding CpuTime}" Grid.Row="3" Grid.Column="1" Margin="1" VerticalAlignment="Center"/>
<Label Grid.Row="4" Grid.Column="0" Margin="1" VerticalAlignment="Center">
Last Error:
</Label>
<Label Grid.Row="4" Grid.Column="1" Margin="1" VerticalAlignment="Center" HorizontalAlignment="Stretch">
<TextBlock Text="{Binding LastError}" TextWrapping="Wrap" Padding="3"/>
</Label>
</Grid>
</UserControl>

233
Siemens/PLCControl.xaml.cs Normal file
View File

@ -0,0 +1,233 @@
using Siemens.Simatic.Simulation.Runtime;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace CtrEditor.Siemens
{
/// <summary>
/// Interaction logic for PLCControl.xaml
/// </summary>
public class PLCViewModel : INotifyPropertyChanged
{
private readonly PLCModel _plcModel;
private readonly DispatcherTimer _timer;
private string _cpuTime;
private string _connectionStatus = "offline";
private string _ip = "10.1.30.11";
private string _name = "PLC";
private string lastError;
public event PropertyChangedEventHandler PropertyChanged;
public PLCViewModel()
{
_plcModel = new PLCModel();
_timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(1000) };
_timer.Tick += (s, e) => Refresh();
ConnectCommand = new RelayCommand(Connect, () => true);
DisconnectCommand = new RelayCommand(Disconnect, () => true);
}
public string IP
{
get => _ip;
set
{
_ip = value;
OnPropertyChanged();
}
}
public string Name
{
get => _name;
set
{
_name = value;
OnPropertyChanged();
}
}
public string CpuTime
{
get => _cpuTime;
set
{
_cpuTime = value;
OnPropertyChanged();
}
}
public string ConnectionStatus
{
get => _connectionStatus;
set
{
_connectionStatus = value;
OnPropertyChanged();
}
}
public ICommand ConnectCommand { get; }
public ICommand DisconnectCommand { get; }
public string LastError
{
get => lastError;
set
{
lastError = value;
OnPropertyChanged();
}
}
private void Connect()
{
// Implementa la conexión utilizando PLCModel
_plcModel.Instance = SimulationRuntimeManager.CreateInterface(Name);
_plcModel.Instance.OnSoftwareConfigurationChanged += Instance_OnSoftwareConfigurationChanged;
//_plcModel.Instance.CommunicationInterface = ECommunicationInterface.Softbus;
if (_plcModel.Instance != null)
{
_plcModel.UpdateTagList();
_timer.Start();
ConnectionStatus = "connected";
}
}
private void Instance_OnSoftwareConfigurationChanged(IInstance instance, SOnSoftwareConfigChangedParameter event_param)
{
_plcModel.UpdateTagList();
}
private void Disconnect()
{
_timer.Stop();
ConnectionStatus = "offline";
_plcModel.Instance = null;
}
private void Refresh()
{
if (_plcModel.Instance != null)
{
CpuTime = _plcModel.LeerInt16("\"DB HMI\".CPU_Scan_Time")?.ToString() ?? "N/A";
LastError = _plcModel.LastError;
}
}
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class PLCModel
{
public IInstance Instance { get; set; }
public bool IsConfigured { get; set; }
public string LastError { get; set; }
public void UpdateTagList()
{
IsConfigured = false;
try
{
Instance?.UpdateTagList( ETagListDetails.IO | ETagListDetails.DB);
IsConfigured = true;
}
catch (Exception ex)
{
LastError = ex.Message;
}
}
public bool LeerSalidaBool(byte pByte, int pBit)
{
try
{
return Instance?.OutputArea.ReadBit(pByte, (byte)pBit) ?? false;
}
catch (Exception ex)
{
LastError = ex.Message;
return false;
}
}
public void EscribirInputBool(byte pByte, int pBit, bool pValue)
{
try
{
Instance?.InputArea.WriteBit(pByte, (byte)pBit, pValue);
}
catch (Exception ex)
{
LastError = ex.Message;
}
}
public void EscribirTagBool(string pTag, bool pValue)
{
try
{
Instance?.WriteBool(pTag, pValue);
}
catch (Exception ex)
{
LastError = pTag + ":" + ex.Message;
}
}
public bool LeerTagBool(string pTag)
{
try
{
return Instance?.ReadBool(pTag) ?? false;
}
catch (Exception ex)
{
LastError = pTag + ":" + ex.Message;
return false;
}
}
public int? LeerInt16(string pTag)
{
try
{
return Instance?.ReadInt16(pTag);
}
catch (Exception ex)
{
LastError = pTag + ":" + ex.Message;
return 0;
}
}
}
public partial class PLCControl : UserControl
{
public PLCControl()
{
InitializeComponent();
}
}
}

52
Siemens/PLCSim.cs Normal file
View File

@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Siemens.Simatic;
using Siemens.Simatic.Simulation.Runtime;
namespace CtrEditor.Siemens
{
internal class PLCSim
{
SIPSuite4 plcIP;
}
public class PLCConnector
{
// Propiedades
public IInstance Instance { get; set; }
private bool IsConfigured { get; set; } = false;
private SIPSuite4 InstanceIP;
// Constructor
public PLCConnector(string instanceName, string pIP4)
{
InstanceIP = new SIPSuite4(pIP4, "255.255.255.0", "0.0.0.0");
Instance = SimulationRuntimeManager.CreateInterface(instanceName);
}
// Métodos Públicos
public void PowerOnPLCInstance()
{
Instance.PowerOn(60000);
Instance.SetIPSuite(0, InstanceIP, true);
}
public void PowerOffPLCInstance()
{
Instance.PowerOff(6000);
}
public void RunPLCInstance()
{
Instance.Run(6000);
}
public void StopPLCInstance()
{
Instance.Stop(6000);
}
}
}