Skip to content

Commit

Permalink
PLCsim script should discover its local dll version and load it dynam…
Browse files Browse the repository at this point in the history
…ically (#51)

* Check if the plcsim instance is already registered using dynamic loading dll

* dll dynamically loaded

* Create draft PR for #50

* cleanup

* all code moved into axopen.simple.tools

* Just one tool project for create unit so as for starting plcsim advanced using dynamic loading of the dll

* cleanup

---------

Co-authored-by: TK <61820360+TomKovac@users.noreply.github.com>
  • Loading branch information
IX-BOT and TomKovac authored Dec 9, 2024
1 parent 252769a commit f25081c
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 192 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ VisualStudioVersion = 17.12.35521.163
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AXOpen.Simple.Tools", "AXOpen.Simple.Tools\AXOpen.Simple.Tools.csproj", "{2085A8F9-6645-4BF6-AAC5-18D7DA651689}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlcSimAdvancedStarter", "PlcSimAdvancedStarter\PlcSimAdvancedStarter.csproj", "{24B14AC4-4623-41FB-94C7-5E0E67576940}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand All @@ -17,10 +15,6 @@ Global
{2085A8F9-6645-4BF6-AAC5-18D7DA651689}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2085A8F9-6645-4BF6-AAC5-18D7DA651689}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2085A8F9-6645-4BF6-AAC5-18D7DA651689}.Release|Any CPU.Build.0 = Release|Any CPU
{24B14AC4-4623-41FB-94C7-5E0E67576940}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{24B14AC4-4623-41FB-94C7-5E0E67576940}.Debug|Any CPU.Build.0 = Debug|Any CPU
{24B14AC4-4623-41FB-94C7-5E0E67576940}.Release|Any CPU.ActiveCfg = Release|Any CPU
{24B14AC4-4623-41FB-94C7-5E0E67576940}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,6 @@
<PackageReference Include="Cocona" Version="2.2.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\PlcSimAdvancedStarter\PlcSimAdvancedStarter.csproj" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\PlcSimAdvancedStarter\PlcSimAdvancedStarter.csproj" />
</ItemGroup>

<ItemGroup>
<Reference Include="AX.ST.Compiler.PluginAbstractions">
<HintPath>.apax\.apax\packages\@ax\stc-win-x64\bin\AX.ST.Compiler.PluginAbstractions.dll</HintPath>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ public Task StartPlcSim( [Option('x',Description = "PlcSim instance name")] str
// This is a workaround to get the local dll for the PlcSimAdvanced API
var entry = new FileInfo(Assembly.GetEntryAssembly().Location);
var folder = entry.Directory.FullName;
File.Copy(dllPath, Path.Combine(folder, "Siemens.Simatic.Simulation.Runtime.Api.x64.dll"), true);

// Check if PlcSim is already running
if (Process.GetProcesses().Where(p => p.ProcessName.Equals("Siemens.Simatic.PlcSim.Advanced.UserInterface")).Count() > 0)
Expand All @@ -36,10 +35,117 @@ public Task StartPlcSim( [Option('x',Description = "PlcSim instance name")] str
Console.WriteLine("PlcSimAdvanced started.");
}

exePath = Path.Combine(folder, "PlcSimAdvancedStarter.exe");
Process.Start(new ProcessStartInfo(exePath) { Arguments = $"-x {PlcSimInstanceName} -n {PlcName} -t {PlcIpAddress}" });
}
var plcSimAdvancedApiDll = Assembly.LoadFrom(dllPath);

var simulationRuntimeManager = plcSimAdvancedApiDll.GetType("Siemens.Simatic.Simulation.Runtime.SimulationRuntimeManager");
var networkModeProperty = simulationRuntimeManager.GetRuntimeProperty("NetworkMode");
var eNetworkModeType = plcSimAdvancedApiDll.GetType("Siemens.Simatic.Simulation.Runtime.ENetworkMode");
var tcpipSingleAdapterValue = Enum.Parse(eNetworkModeType, "TCPIPSingleAdapter");
networkModeProperty.SetValue(null, tcpipSingleAdapterValue);

// Check if PlcSimInstanceName is already registered
bool instanceAlreadyRegistered = false;


var iInstanceType = plcSimAdvancedApiDll.GetType("Siemens.Simatic.Simulation.Runtime.IInstance");
object plcSimInstance = null;

var registeredInstanceInfoProperty = simulationRuntimeManager.GetProperty("RegisteredInstanceInfo", BindingFlags.Static | BindingFlags.Public);
var instanceInfos = registeredInstanceInfoProperty.GetValue(null) as Array;
if (instanceInfos != null)
{
foreach (var instanceInfo in instanceInfos)
{
string instanceName = instanceInfo.GetType().GetField("Name", BindingFlags.Public | BindingFlags.Instance).GetValue(instanceInfo)?.ToString();

if (instanceName.Equals(PlcSimInstanceName))
{
Console.WriteLine($"Instance {PlcSimInstanceName} already registered.");
var createInterfaceMethod = simulationRuntimeManager.GetMethod("CreateInterface", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(string) }, null);
plcSimInstance = createInterfaceMethod.Invoke(null, new object[] {PlcSimInstanceName });
instanceAlreadyRegistered = true;
break;
}
}
}


// Register PlcSimInstanceName
if (!instanceAlreadyRegistered)
{
var registerInstanceMethod = simulationRuntimeManager.GetMethod("RegisterInstance", BindingFlags.Static | BindingFlags.Public, null, new Type[] { typeof(string) }, null);
plcSimInstance = registerInstanceMethod.Invoke(null, new object[] { PlcSimInstanceName });
Console.WriteLine($"Instance {PlcSimInstanceName} registered.");
}

// Power On
var eOperatingStateType = plcSimAdvancedApiDll.GetType("Siemens.Simatic.Simulation.Runtime.EOperatingState");
string operatingStateTypeOffValue = Enum.Parse(eOperatingStateType, "Off").ToString();
string operatingStateValue = plcSimInstance.GetType().GetRuntimeProperty("OperatingState").GetValue(plcSimInstance).ToString();

if (operatingStateValue.Equals(operatingStateTypeOffValue))
{
var powerOnMethod = plcSimInstance.GetType().GetMethod("PowerOn", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(uint) }, null);
uint timeout = 6000;
powerOnMethod.Invoke(plcSimInstance, new object[] { timeout });
Console.WriteLine($"Instance {PlcSimInstanceName} powered on.");
}
else
{
Console.WriteLine($"Instance {PlcSimInstanceName} already powered.");
}

// Set Ip address
var sipSuiteType = plcSimInstance.GetType().Assembly.GetType("Siemens.Simatic.Simulation.Runtime.SIPSuite4");

if (sipSuiteType != null)
{
var setIpSuiteMethod = plcSimInstance.GetType().GetMethod("SetIPSuite", BindingFlags.Public | BindingFlags.Instance);
if (setIpSuiteMethod != null)
{
var sipSuiteInstance = Activator.CreateInstance(sipSuiteType, new object[] { PlcIpAddress, "255.255.255.0", "0.0.0.0" });
if (sipSuiteInstance != null)
{
setIpSuiteMethod.Invoke(plcSimInstance, new object[] { (UInt32)0, sipSuiteInstance, true });
}
else
{
Console.WriteLine("Failed to create SIPSuite4 instance.");
return Task.CompletedTask;
}
}
else
{
Console.WriteLine("SetIPSuite method not found.");
return Task.CompletedTask;
}
}
else
{
Console.WriteLine("SIPSuite4 type not found.");
return Task.CompletedTask;
}

// Run
string operatingStateTypeStopValue = Enum.Parse(eOperatingStateType, "Stop").ToString();
operatingStateValue = plcSimInstance.GetType().GetRuntimeProperty("OperatingState").GetValue(plcSimInstance).ToString();

if (operatingStateValue.Equals(operatingStateTypeStopValue))
{
try
{
var runMethod = plcSimInstance.GetType().GetMethod("Run", BindingFlags.Public | BindingFlags.Instance, null, new Type[] { typeof(uint) }, null);
uint timeout = 6000;
runMethod.Invoke(plcSimInstance, new object[] { timeout });
Console.WriteLine($"PLC set to RUN mode.");
}
catch (Exception ex)
{
Console.WriteLine($"Unable to set the PLC into the RUN mode. {ex.Message}");

}
}
}
return Task.CompletedTask;
}
}
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Binary file not shown.

0 comments on commit f25081c

Please sign in to comment.