PROFINET IO Controller Stack 1.0.0
Modern C++ implementation of a PROFINET IO Controller stack
Loading...
Searching...
No Matches
virtual_auma_valve.h
Go to the documentation of this file.
1
10#pragma once
11
12#include <atomic>
13#include <cstdint>
14#include <functional>
15#include <memory>
16#include <mutex>
17#include <optional>
18#include <string>
19#include <string_view>
20#include <thread>
21#include <vector>
22
23#include "profinet/IOSignal.h"
24#include "profinet/gsdml.h"
25#include "profinet/rt.h"
27#include "profinet/util.h"
28
29namespace profinet::sim
30{
31
55
59[[nodiscard]] const char* ToString(VirtualAumaScenario scenario) noexcept;
60
64{
66 std::uint16_t inputSlot = 1;
68 std::uint16_t inputSubslot = 1;
70 std::uint16_t outputSlot = 2;
72 std::uint16_t outputSubslot = 1;
73
75 std::uint16_t initialPosition = 0;
77 double travelUnitsPerSecond = 2500.0;
79 double slowValveMultiplier = 0.25;
80
82 std::string openCommand = "T_ID_CMD_0";
84 std::string closeCommand = "T_ID_CMD_1";
86 std::string stopCommand = "T_ID_CMD_2";
88 std::string positionSetpoint = "T_ID_POSITIONSETPOINT";
90 std::string speedSetpoint = "T_ID_SPEEDSETPOINT";
92 std::string actualPosition = "T_ID_ACTPOS_E2";
94 std::string faultSignal = "T_ID_FAULT1_0";
96 std::string warningSignal = "T_ID_WARNING1_0";
97
99 std::uint16_t alarmSourceReference = 42;
101 std::uint16_t alarmDestinationReference = 1;
105 bool emitRtaError = true;
106
108 std::uint32_t alarmApi = 0;
109
111 std::uint32_t alarmModuleIdent = 0x00008000U;
112
114 std::uint32_t alarmSubmoduleIdent = 0x00002200U;
115};
116
134
148{
149 public:
157 VirtualAumaValve(std::string name,
163
166
169
172 void Start(InMemoryEthernetBus& bus);
173
175 void Stop();
176
180
182 [[nodiscard]] VirtualAumaScenario Scenario() const noexcept;
183
185 [[nodiscard]] std::uint16_t Position() const noexcept;
186
188 [[nodiscard]] std::uint16_t TargetPosition() const noexcept;
189
191 [[nodiscard]] bool FaultActive() const noexcept;
192
194 [[nodiscard]] bool Moving() const noexcept;
195
197 [[nodiscard]] const std::string& Name() const noexcept;
198
200 [[nodiscard]] const MacAddress& DeviceMac() const noexcept;
201
203 [[nodiscard]] std::uint16_t InputSlot() const noexcept;
204
206 [[nodiscard]] std::uint16_t InputSubslot() const noexcept;
207
209 [[nodiscard]] std::uint16_t OutputSlot() const noexcept;
210
212 [[nodiscard]] std::uint16_t OutputSubslot() const noexcept;
213
215 [[nodiscard]] const io::IoSignalCatalog& SignalCatalog() const noexcept;
216
219 void OnFrame(std::function<void(const Bytes&)> callback);
220
223 void OnAlarm(std::function<void(const VirtualAumaAlarmEvent&)> callback);
224
226 [[nodiscard]] Bytes InputProcessData() const;
227
229 [[nodiscard]] Bytes OutputProcessData() const;
230
231 private:
233 void Run();
234
237 void ProcessOutputFrame(const Bytes& frame);
238
241 void UpdateProcessModel(double elapsedSeconds);
242
245 void DecodeCommands(const Bytes& outputData);
246
249
251 void SendInputFrame();
252
257 void SetBitSignal(Bytes& data, std::string_view textId, bool value) const;
258
263 void SetScalarSignal(Bytes& data, std::string_view textId, std::uint64_t value) const;
264
269 [[nodiscard]] bool ReadBitSignal(const Bytes& data, std::string_view textId) const;
270
275 [[nodiscard]] std::uint64_t ReadScalarSignal(const Bytes& data,
276 std::string_view textId) const;
277
279 [[nodiscard]] const io::IoSignal& RequireSignal(std::string_view textId,
280 io::IoSignalDirection direction) const;
281
283 [[nodiscard]] Bytes BuildRtaErrorFrame(std::uint8_t errorCode1,
284 std::uint8_t errorCode2) const;
285
287 [[nodiscard]] Bytes BuildAlarmNotificationBlock(std::uint16_t alarmSpecifier) const;
288
291
293 void NotifyFrame(const Bytes& frame) const;
294
296 void NotifyAlarm(const VirtualAumaAlarmEvent& event) const;
297
298 std::string name;
299 const gsdml::GSDMLDevice& gsdml;
305
306 std::unique_ptr<InMemoryEthernetSocket> socket;
307 std::jthread worker;
308 std::atomic<bool> running{false};
309
310 mutable std::mutex stateMutex;
312 std::uint16_t position = 0;
313 std::uint16_t targetPosition = 0;
314 double commandSpeed = 1.0;
315 bool opening = false;
316 bool closing = false;
317 bool moving = false;
318 bool controllerKnown = false;
320 std::uint16_t rxCycleCounter = 0;
321 std::uint32_t inputFrameNumber = 0;
322 std::uint16_t alarmSequence = 1;
325 std::function<void(const Bytes&)> onFrame;
326 std::function<void(const VirtualAumaAlarmEvent&)> onAlarm;
327};
328
329} // namespace profinet::sim
Defines the GSDML-derived logical process-data signal catalogue.
Builds and owns the logical sensor and actuator signals described by a GSDML device.
Definition IOSignal.h:186
Small virtual Ethernet switch suitable for deterministic tests and demos.
AUMA SGx application model that behaves as a real RTC1 peer in memory.
const MacAddress & DeviceMac() const noexcept
Return the simulated device MAC address.
const gsdml::GSDMLDevice & gsdml
std::uint16_t OutputSubslot() const noexcept
Return the configured output subslot.
Bytes OutputProcessData() const
Return the most recent output process-data object.
const std::string & Name() const noexcept
Return the configured simulator name.
void SetScenario(VirtualAumaScenario scenario)
Set the current simulator scenario.
void SendInputFrame()
Send one device-to-controller RTC1 input frame.
VirtualAumaScenario Scenario() const noexcept
Return the current scenario.
VirtualAumaValve & operator=(const VirtualAumaValve &)=delete
std::uint16_t InputSlot() const noexcept
Return the configured input slot.
void ProcessOutputFrame(const Bytes &frame)
Decode and apply one controller RTC1 output frame.
void SetBitSignal(Bytes &data, std::string_view textId, bool value) const
Set one Boolean input signal.
std::uint64_t ReadScalarSignal(const Bytes &data, std::string_view textId) const
Read a big-endian unsigned output signal.
std::function< void(const Bytes &)> onFrame
VirtualAumaValveConfiguration config
std::function< void(const VirtualAumaAlarmEvent &)> onAlarm
Bytes InputProcessData() const
Return the most recent input process-data object.
void Stop()
Stop cyclic simulation.
void DecodeCommands(const Bytes &outputData)
Decode command bits and optional setpoints from an output object.
void OnAlarm(std::function< void(const VirtualAumaAlarmEvent &)> callback)
Register a callback for generated scenario alarm events.
void Run()
Main worker loop receiving controller outputs and sending device inputs.
void NotifyFrame(const Bytes &frame) const
Invoke the frame callback outside the state mutex.
VirtualAumaValve(const VirtualAumaValve &)=delete
const io::IoSignalCatalog & SignalCatalog() const noexcept
Return the GSDML-derived signal catalogue.
bool FaultActive() const noexcept
Return whether an application or mechanical fault is active.
std::unique_ptr< InMemoryEthernetSocket > socket
Bytes BuildAlarmNotificationBlock(std::uint16_t alarmSpecifier) const
Build a PROFINET AlarmNotification block for a scenario.
std::uint16_t OutputSlot() const noexcept
Return the configured output slot.
bool Moving() const noexcept
Return whether the valve model is moving toward its target.
std::uint16_t InputSubslot() const noexcept
Return the configured input subslot.
Bytes BuildRtaErrorFrame(std::uint8_t errorCode1, std::uint8_t errorCode2) const
Build the raw RTA 0x0F scenario error frame.
const io::IoSignal & RequireSignal(std::string_view textId, io::IoSignalDirection direction) const
Resolve a unique GSDML signal or throw a configuration error.
void UpdateProcessModel(double elapsedSeconds)
Advance the valve application model for one elapsed interval.
bool ReadBitSignal(const Bytes &data, std::string_view textId) const
Read a Boolean output signal.
std::uint16_t TargetPosition() const noexcept
Return the current requested target position.
void BuildInputProcessData()
Rebuild all AUMA input measurement and status signals.
std::uint16_t Position() const noexcept
Return the current simulated position.
void EmitScenarioAlarms(VirtualAumaScenario scenario)
Emit enabled scenario alarms and notify callbacks.
void OnFrame(std::function< void(const Bytes &)> callback)
Register a callback for every Ethernet frame emitted by the device.
void SetScalarSignal(Bytes &data, std::string_view textId, std::uint64_t value) const
Set one big-endian unsigned input signal.
void NotifyAlarm(const VirtualAumaAlarmEvent &event) const
Invoke the alarm callback outside the state mutex.
~VirtualAumaValve()
Stop the simulator and release the virtual transport.
Declares the GSDML parser and PROFINET device-description data model.
Thread-safe in-memory Layer-2 Ethernet switch for PROFINET simulation.
VirtualAumaScenario
Deterministic operating and communication scenarios for a virtual AUMA valve.
@ Fault
Application fault: movement stops, IOPS becomes BAD and alarms are emitted.
@ BadIops
Input frames continue, but the input provider reports BAD IOPS.
@ DuplicateInput
Input frames repeat their previous cycle counter.
@ SlowValve
Valve travels using the configured reduced speed multiplier.
@ OutOfOrderInput
Input frames occasionally move the cycle counter backwards.
@ Normal
Fully healthy operation with normal travel speed.
@ NoInput
Input frames stop completely so the controller watchdog expires.
@ InvalidInput
Input frames remain valid but carry an invalid RTC1 DATA_STATUS.
@ Jammed
Valve accepts commands but the mechanical position does not change.
const char * ToString(VirtualAumaScenario scenario) noexcept
Convert a virtual AUMA scenario into its stable CLI spelling.
std::array< std::uint8_t, macAddressLength > MacAddress
A 6-byte Ethernet MAC address.
Definition util.h:48
std::vector< std::uint8_t > Bytes
Generic byte buffer alias used throughout the library for raw wire data.
Definition protocol.h:55
Declares PROFINET RT_CLASS_1 cyclic frame and IOCR data structures.
Complete parsed GSDML device profile.
Definition gsdml.h:166
IOCR configuration derived from AR setup: timing parameters and IO object mappings needed for cyclic ...
Definition rt.h:137
Captured alarm traffic produced by a virtual AUMA scenario.
Bytes rtaErrorFrame
Complete RTA 0x0F Ethernet frame; empty when disabled.
VirtualAumaScenario scenario
Scenario that caused this event.
std::uint8_t errorCode1
First simulator-defined RTA error code byte.
std::uint16_t alarmSpecifier
AlarmSpecifier placed in the AlarmNotification block.
std::uint8_t errorCode2
Second simulator-defined RTA error code byte.
Bytes alarmNotificationFrame
Complete RTA DATA AlarmNotification Ethernet frame; empty when disabled.
Application-level signal mapping and motion settings for a virtual AUMA SGx.
std::string speedSetpoint
Optional speed setpoint signal, interpreted as 0..100 percent.
std::uint32_t alarmModuleIdent
Module identifier used by the simulated input alarm.
std::string faultSignal
Generic fault indication signal.
std::uint32_t alarmSubmoduleIdent
Submodule identifier used by the simulated input alarm.
std::string positionSetpoint
Optional position setpoint signal.
std::string openCommand
OPEN command bit in the AUMA output process data.
bool emitAlarmNotification
Whether a parseable AlarmNotification is emitted for scenarios.
std::uint16_t alarmSourceReference
Source RTA alarm endpoint reference.
std::string stopCommand
STOP command bit in the AUMA output process data.
bool emitRtaError
Whether an RTA 0x0F error PDU is emitted for scenarios.
std::string actualPosition
Actual position sensor signal.
double slowValveMultiplier
Speed multiplier for the SlowValve scenario.
std::string closeCommand
CLOSE command bit in the AUMA output process data.
std::uint32_t alarmApi
AlarmNotification API used by the simulated device.
double travelUnitsPerSecond
Nominal travel speed in position units per second.
std::uint16_t alarmDestinationReference
Destination RTA alarm endpoint reference.
std::string warningSignal
Generic warning indication signal.
std::uint16_t initialPosition
Initial valve position in the AUMA 0..10000 application range.
std::uint16_t outputSubslot
Output process-data subslot.
std::uint16_t inputSlot
Input process-data slot.
std::uint16_t outputSlot
Output process-data slot.
std::uint16_t inputSubslot
Input process-data subslot.
Bytes frame
Declares Linux Ethernet, addressing, timing, and utility helpers used by the PROFINET stack.