Skip to content
Start free evaluation

Set up your environment

By the end of this tutorial, you can:

  • Find the headers, native library, .NET assembly and simulator in the SDK bundle.
  • Set the same environment variables in every terminal.
  • Build the C++ and C# tutorial examples from the SDK alone.
  • Connect the two languages to each other and run the headless simulator to confirm the installation.

You need:

  • The PDComm SECS/GEM SDK bundle: a ZIP for Windows x64 or a tar.gz for Linux x64. If you received a macOS (Apple silicon) build, it has the same layout.
  • A C++ compiler:
    • Windows: the Visual Studio 2022 C++ x64 tools. Run cl from x64 Native Tools or Developer PowerShell.
    • Linux: g++ with C++14 or later.
    • macOS: c++ from the Xcode Command Line Tools.
  • The .NET 10 SDK to build the C# examples; the .NET 10 runtime is enough to run them. Follow Microsoft’s instructions for Windows, Linux or macOS. The SDK bundle doesn’t include the .NET SDK.

Extract the bundle into a folder you own. This tutorial uses C:\pdcomm-tutorial on Windows and $HOME/pdcomm-tutorial on Linux and macOS.

터미널 창
Expand-Archive .\pdcomm-secsgem-windows-x64-<version>.zip -DestinationPath C:\pdcomm-tutorial

The extracted folder looks like this. Keep the structure and the license notices together.

  • Directorypdcomm-tutorial/
    • Directorybin/ prebuilt tutorial examples
      • pdcomm-tutorial(.exe) C++ example
      • PDComm.Tutorial.dll C# example
      • PDComm.dll .NET binding
    • Directorysdk/
      • Directoryinclude/ C headers (pdcomm*.h) and C++ wrappers (pdcomm*.hpp)
        • …
      • Directorylib/ native library (pdcomm_ffi.dll with pdcomm_ffi.dll.lib, libpdcomm_ffi.so or libpdcomm_ffi.dylib)
        • …
      • Directorymanaged/
        • PDComm.dll .NET binding
      • Directoryexamples/
        • Directorytutorial/ C++ and C# tutorial sources
          • …
    • Directorysimulator/ GUI, headless and MCP simulators with their libraries
      • …
  • The native library in sdk/lib is the SECS/GEM implementation. C, C++ and C# programs all load it.
  • PDComm.dll is the .NET binding assembly. It doesn’t replace the native library.
  • The capability demos for .NET, the Qt examples and the logging examples ship in a separate examples bundle. These tutorials call the folder where you extract it PDCOMM_EXAMPLES.

Set these variables in every new terminal. All later tutorials use them.

터미널 창
$Root = 'C:\pdcomm-tutorial'
$Sdk = Join-Path $Root 'sdk'
$Native = Join-Path $Sdk 'lib\pdcomm_ffi.dll'
$Simulator = Join-Path $Root 'simulator'
$Examples = 'C:\pdcomm-examples'
$env:PATH = "$Sdk\lib;$env:PATH"
터미널 창
dotnet --info

Under .NET SDK, Version should start with 10, for example Version: 10.0.401. If the command isn’t found, install the .NET SDK and open a new terminal.

Check the C++ compiler with cl on Windows, g++ --version on Linux or c++ --version on macOS.

터미널 창
New-Item -ItemType Directory -Force "$Root\build" | Out-Null
cl /nologo /W4 /WX /EHsc /std:c++14 "/I$Sdk\include" "$Sdk\examples\tutorial\pdcomm_tutorial.cpp" "$Sdk\lib\pdcomm_ffi.dll.lib" "/Fe:$Root\build\pdcomm-tutorial.exe" "/Fo:$Root\build\tutorial.obj"

The build succeeds when it prints no warnings. Because -Werror (/WX on Windows) turns warnings into errors, a mismatch between the headers and your compiler shows up right here.

The C# project takes the SDK folder in the PDCommSdk property and references managed/PDComm.dll from it.

examples/tutorial/PDComm.Tutorial/PDComm.Tutorial.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup><OutputType>Exe</OutputType><TargetFramework>net10.0</TargetFramework><Nullable>enable</Nullable><ImplicitUsings>enable</ImplicitUsings><TreatWarningsAsErrors>true</TreatWarningsAsErrors></PropertyGroup>
<ItemGroup Condition="'$(PDCommSdk)' == ''"><ProjectReference Include="../../../bindings/dotnet/PDComm/PDComm.csproj" /></ItemGroup>
<ItemGroup Condition="'$(PDCommSdk)' != ''"><Reference Include="PDComm"><HintPath>$(PDCommSdk)/managed/PDComm.dll</HintPath></Reference></ItemGroup>
</Project>
터미널 창
dotnet build "$Sdk\examples\tutorial\PDComm.Tutorial\PDComm.Tutorial.csproj" -c Release "-p:PDCommSdk=$Sdk" --artifacts-path "$Root\build\managed"

The build succeeds when the output ends with Build succeeded., 0 Warning(s) and 0 Error(s). The result is build/managed/bin/PDComm.Tutorial/release/PDComm.Tutorial.dll.

All HSMS and GEM options of the C# example live in one file. Replace the timers and limits with the values from the equipment’s interface specification before you connect real equipment.

examples/tutorial/PDComm.Tutorial/TutorialOptions.cs
using PDComm;
internal static class TutorialOptions
{
internal static readonly SecsLimits Limits = new(8192,4096,512,24);
internal static GemFormattedProgramConfiguration Configuration() => new(
new(4, 128, 512, 8, 8, 16, 32), new(4, 4, 8, 1024, 8, 8, 16, 32),
new(4, 4, 8, 1024, 8, 2048, 8, 8, 16, 32), new(4, 4, 8, 1024, 8, 8, 16, 32),
new(4, 32, 4, 8, 4, 32, 1024, 4096, 8, 8, 16, 32), new(4, 128, 512, 8, 8, 8, 16, 32));
internal static GemFormattedProgramCapabilityCommand Capability() => new("RUN", "Run", true, 0, [], [], [], 0, [], [], []);
internal static HsmsOptions Transport(HsmsMode mode) => new()
{ Mode = mode, SessionId = 7, InitialSystemBytes = 1, T3Milliseconds = 2000, T5Milliseconds = 20,
T6Milliseconds = 2000, T7Milliseconds = 5000, T8Milliseconds = 2000, ConnectTimeoutMilliseconds = 100,
ShutdownTimeoutMilliseconds = 1000, WriteTimeoutMilliseconds = 2000, MaxFrameBytes = 8206,
MaxEvents = 128, MaxQueuedBytes = 65536, MaxWriteFrames = 64, MaxWriteBytes = 65536,
MaxIoChunk = 4096, MaxApplicationEvents = 128, MaxApplicationBytes = 65536, PollBudget = 32, ItemLimits = Limits };
internal static GemHostOptions HostOptions() => new() { MaxPendingIds = 64, ItemLimits = Limits };
internal static GemEquipmentOptions EquipmentOptions() => new()
{ Model = "PDComm", SoftwareRevision = "0.1.0", InitialControl = GemControlState.HostOffline,
OnlineMode = GemOnlineMode.Remote, MaxVariables = 8, MaxMetadataBytes = 1024, MaxValueBytes = 8192, ItemLimits = Limits };
internal static HsmsWorkerOptions WorkerOptions() => new()
{ CommandCapacity = 32, MaxCommandBytes = 65536, EventCapacity = 32, MaxEventBytes = 131072,
PollIntervalMilliseconds = 1, ShutdownTimeoutMilliseconds = 2000 };
}

Run the C++ equipment against the C# host in automatic mode to confirm that the SDK, the native library and the .NET binding work together. Start the equipment in the first terminal:

터미널 창
"$PDCOMM_ROOT/build/pdcomm-tutorial" equipment passive 127.0.0.1:5000 --auto

Start the C# host in the second terminal:

터미널 창
dotnet "$PDCOMM_ROOT/build/managed/bin/PDComm.Tutorial/release/PDComm.Tutorial.dll" "$PDCOMM_NATIVE" host active 127.0.0.1:5000 --auto

On Windows, use & "$Root\build\pdcomm-tutorial.exe" ... and dotnet "$Root\build\managed\bin\PDComm.Tutorial\release\PDComm.Tutorial.dll" "$Native" ....

The C# host prints each result with its numeric codes and their names:

RESULT kind=2 request=1 outcome=2 status=CommunicationEstablished
SECS-II 0102210100010241065044436F6D6D4105302E312E30
RESULT kind=2 request=2 outcome=4 status=EquipmentIdentity
SECS-II 010241065044436F6D6D4105302E312E30
RESULT kind=2 request=3 outcome=5 status=ValuesReceived
SECS-II 0102910441AC000041074C4F542D303031
PASS tutorial host active

The equipment’s last line is PASS tutorial equipment passive. Both programs exit with code 0.

The headless simulator runs a scenario with an internal host and equipment pair and no GUI. Run the smoke scenario to check the installation:

터미널 창
& "$Simulator\pdcomm-simulator-headless.exe" --scenario smoke
$LASTEXITCODE

It prints one JSON object per line and ends with a summary:

{"schema":1,"sequence":1,"scenario":"smoke","scope":"pair","kind":"start","detail":"scenario-started","truncated":false}
...
{"schema":1,"sequence":6,"scenario":"smoke","scope":"pair","kind":"summary","outcome":"passed","exit_code":0,"elapsed_ms":10,"records_emitted":6,"max_records":128,"truncated":false,"status_names":0,"status_values":0}

Your setup is complete when the summary shows "outcome":"passed" and "exit_code":0, and the process exit code is also 0. The elapsed_ms value differs on every run.

Symptom Cause and fix
Windows reports that VCRUNTIME140.dll or MSVCP140.dll is missing. The x64 Visual C++ Redistributable isn’t installed. Install it and try again.
Linux reports error while loading shared libraries: libpdcomm_ffi.so. LD_LIBRARY_PATH isn’t set in this terminal. Repeat step 2.
macOS reports Library not loaded: @rpath/libpdcomm_ffi.dylib. You built without -Wl,-rpath. Rebuild with the macOS command from step 4.
C# throws System.DllNotFoundException: Unable to load shared library .... The native library path in the first argument is wrong. Check that PDCOMM_NATIVE points to an existing file built for your OS and CPU architecture.
C# throws NotSupportedException. PDComm.dll and the native library come from different versions. Use both files from the same bundle.
The program prints Usage: PDComm.Tutorial <absolute-library-path> ... and exits with code 2. An argument is missing or wrong. The role is host or equipment and the mode is active or passive.
The simulator can’t find a Qt platform plugin. The simulator folder wasn’t copied as a whole, or QT_PLUGIN_PATH points to another Qt installation. Keep the folder intact and clear that variable.

Automatic mode exits on its own. Delete the build folder if you no longer need the build output.

In First communication, you change the communication state step by step with interactive commands and connect to the simulator GUI.