PROFINET IO Controller Stack 1.0.0
Modern C++ implementation of a PROFINET IO Controller stack
Loading...
Searching...
No Matches
cyclic.h
Go to the documentation of this file.
1
18#pragma once
19
20#include <atomic>
21#include <chrono>
22#include <cstdint>
23#include <functional>
24#include <map>
25#include <mutex>
26#include <optional>
27#include <string>
28#include <thread>
29#include <utility>
30
31#include "profinet/rt.h"
32#include "profinet/util.h"
33
35{
36
38enum class CyclicState
39{
41 Idle,
45 Running,
49 Stopped,
51 Fault,
52};
53
57std::string ToString(CyclicState state);
58
65{
67 std::atomic<std::uint64_t> framesSent{0};
68
70 std::atomic<std::uint64_t> framesReceived{0};
71
73 std::atomic<std::uint64_t> framesMissed{0};
74
76 std::atomic<std::uint64_t> framesInvalid{0};
77
79 std::atomic<std::uint64_t> framesDuplicate{0};
80
82 std::atomic<std::uint64_t> framesOutOfOrder{0};
83
85 std::atomic<std::uint32_t> lastCycleTimeUs{0};
86
88 std::atomic<std::uint32_t> maxJitterUs{0};
89
91 std::atomic<std::uint32_t> minCycleTimeUs{0x7FFFFFFF};
92
94 std::atomic<std::uint32_t> maxCycleTimeUs{0};
95
97 std::atomic<std::chrono::steady_clock::time_point> lastReceiveTime{std::chrono::steady_clock::now()};
98
100 std::atomic<int> consecutiveTimeouts{0};
101
103 std::atomic<std::uint64_t> cycleTimeSumUs{0};
104
106 std::atomic<std::uint64_t> cycleCount{0};
107
110 [[nodiscard]] std::uint64_t AvgCycleTimeUs() const
111 {
112 return (cycleCount != 0U) ? cycleTimeSumUs / cycleCount : 0;
113 }
114
116 void Reset();
117};
118
121{
122 std::uint64_t framesSent{};
123 std::uint64_t framesReceived{};
124 std::uint64_t framesMissed{};
125 std::uint64_t framesInvalid{};
126 std::uint64_t framesDuplicate{};
127 std::uint64_t framesOutOfOrder{};
128
129 std::uint32_t lastCycleTimeUs{};
130 std::uint32_t maxJitterUs{};
131 std::uint32_t minCycleTimeUs{};
132 std::uint32_t maxCycleTimeUs{};
133
134 std::chrono::steady_clock::time_point lastReceiveTime;
135
137
138 std::uint64_t cycleTimeSumUs{};
139 std::uint64_t cycleCount{};
140
143 [[nodiscard]] std::uint64_t AvgCycleTimeUs() const
144 {
145 return (cycleCount != 0U) ? cycleTimeSumUs / cycleCount : 0;
146 }
147};
148
149// NOLINTBEGIN(readability-identifier-naming)
151inline constexpr int MIN_CYCLE_MS = 8;
153inline constexpr int RECOMMENDED_CYCLE_MS = 32;
155inline constexpr int DEFAULT_MAX_CONSECUTIVE_TIMEOUTS = 3;
157inline constexpr int STOP_FRAME_COUNT = 3;
158// NOLINTEND(readability-identifier-naming)
170{
171 public:
177 virtual ~ICyclicController() = default;
178
186 virtual void Start() = 0;
187
197 virtual void Stop() = 0;
198};
199
220{
221 public:
223 friend class ReceivedIopsTest;
224
235 std::uint16_t etherType = rt::ETHERTYPE_PROFINET);
236
238 ~CyclicController() override;
239
242
245
251 void SetOutputData(int slot, int subslot, const Bytes& data);
252
263 std::optional<Bytes> GetInputData(int slot, int subslot, bool allowBad = false) const;
264
282 void OnInputStatus(std::function<void(std::uint16_t slot, std::uint16_t subslot, std::uint8_t iops)> callback);
283
286 void OnInput(std::function<void(int slot, int subslot, const Bytes& data)> callback);
287
290 void OnTimeout(std::function<void()> callback);
291
294 void OnError(std::function<void(const std::string&)> callback);
295
298 void OnStateChange(std::function<void(CyclicState oldState, CyclicState newState)> callback);
299
304 void Start() override;
305
310 void Stop() override;
311
314 bool IsRunning() const
315 {
316 return state == CyclicState::Running;
317 }
318
322 {
323 return state;
324 }
325
328 const CyclicStats& Stats() const
329 {
330 return stats;
331 }
332
333 [[nodiscard]] CyclicStatsSnapshot StatsSnapshot() const;
334
347 [[nodiscard]] std::optional<std::uint8_t> GetInputStatus(std::uint16_t slot, std::uint16_t subslot) const;
348
359 [[nodiscard]] bool IsInputGood(std::uint16_t slot, std::uint16_t subslot) const;
360
361 private:
364 void Transition(CyclicState newState);
365
367 void CheckCycleTime();
368
383 void TxCycle();
384
386 void TxLoop();
387
390 void SendOutputFrame(std::optional<std::uint8_t> dataStatusOverride = std::nullopt);
391
393 void SendStopFrames();
394
396 void RxLoop();
397
400
403 void ProcessInputFrame(const Bytes& data);
404
414 [[nodiscard]] bool LocalIsInputGood(std::uint16_t slot, std::uint16_t subslot) const;
415
418 std::map<std::pair<std::uint16_t, std::uint16_t>, std::uint8_t> inputStatus;
419
422 void TrackCycleCounter(std::uint16_t rxCounter);
423
425 std::string interface;
426
429
432
435
438
441
443 std::atomic<CyclicState> state{CyclicState::Idle};
444
447
449 std::atomic<bool> running{false};
450
452 std::thread txThread;
453
455 std::thread rxThread;
456
458 std::optional<EthernetSocket> txSock;
459
461 std::optional<EthernetSocket> rxSock;
462
464 std::uint16_t cycleCounter = 0;
465
468
470 mutable std::mutex inputLock;
471
473 std::map<std::pair<int, int>, Bytes> inputData;
474
476 std::optional<std::uint16_t> lastRxCycleCounter;
477
479 std::uint32_t rxCounterStep;
480
482 std::uint32_t txCounterStep;
483
485 std::function<void(int, int, const std::uint8_t)> onInputStatus;
486
488 std::function<void(int, int, const Bytes&)> onInputData;
489
491 std::function<void()> onTimeout;
492
494 std::function<void(const std::string&)> onError;
495
497 std::function<void(CyclicState, CyclicState)> onStateChange;
498
501
505};
506
507} // namespace profinet::cyclic
RT_CLASS_1 cyclic data exchange controller.
Definition cyclic.h:220
void OnInputStatus(std::function< void(std::uint16_t slot, std::uint16_t subslot, std::uint8_t iops)> callback)
Register a callback for PROFINET provider status (IOPS) changes.
Definition cyclic.cpp:192
const CyclicStats & Stats() const
Communication statistics for this controller.
Definition cyclic.h:328
bool iocsGood
Tracks the watchdog-driven IOCS state so the RX/timeout paths only rewrite the buffer on transitions ...
Definition cyclic.h:504
void TrackCycleCounter(std::uint16_t rxCounter)
Update cycle-counter tracking stats (gaps/duplicates/reordering) for a received frame.
Definition cyclic.cpp:732
bool IsRunning() const
Whether the controller is actively exchanging cyclic data.
Definition cyclic.h:314
std::uint32_t rxCounterStep
Expected cycle-counter increment per received input frame.
Definition cyclic.h:479
rt::CyclicDataBuilder outputBuilder
Double-buffered builder for output cyclic data.
Definition cyclic.h:467
void SetOutputData(int slot, int subslot, const Bytes &data)
Set output data for the next cycle.
Definition cyclic.cpp:137
std::uint32_t txCounterStep
Cycle-counter increment applied per sent output frame.
Definition cyclic.h:482
std::string interface
Network interface name.
Definition cyclic.h:425
void SendOutputFrame(std::optional< std::uint8_t > dataStatusOverride=std::nullopt)
Build and send one output frame.
Definition cyclic.cpp:396
void TxLoop()
TX thread body: sends output frames at the configured cycle rate.
Definition cyclic.cpp:322
CyclicController(const CyclicController &)=delete
Not copyable (owns sockets and background threads).
std::mutex inputLock
Guards inputData against concurrent access.
Definition cyclic.h:470
void TxCycle()
Swap the output buffer and transmit one cyclic output frame.
Definition cyclic.cpp:313
std::thread txThread
Thread sending output frames.
Definition cyclic.h:452
void SendStopFrames()
Send STOP_FRAME_COUNT output frames with ProviderRun cleared.
Definition cyclic.cpp:434
rt::IOCRConfig outputIocr
Configuration for the output (controller -> device) IOCR.
Definition cyclic.h:437
void OnError(std::function< void(const std::string &)> callback)
Register a callback invoked on TX/RX socket errors.
Definition cyclic.cpp:205
std::function< void(int, int, const std::uint8_t)> onInputStatus
Registered OnInputStatus callback, if any.
Definition cyclic.h:485
void OnStateChange(std::function< void(CyclicState oldState, CyclicState newState)> callback)
Register a callback invoked on every state transition.
Definition cyclic.cpp:209
void Stop() override
Stop gracefully.
Definition cyclic.cpp:244
~CyclicController() override
Stop (if running) and release resources.
Definition cyclic.cpp:92
std::atomic< bool > running
Whether the TX/RX threads should keep running.
Definition cyclic.h:449
void Transition(CyclicState newState)
Change state and invoke the OnStateChange callback if registered.
Definition cyclic.cpp:118
void CheckCycleTime()
Validate the configured cycle time, throwing if it's below 1ms.
Definition cyclic.cpp:100
void RxLoop()
RX thread body: receives and processes input frames, checking the watchdog.
Definition cyclic.cpp:464
std::optional< Bytes > GetInputData(int slot, int subslot, bool allowBad=false) const
Get the latest input data received from the device, if any or IOPS is BAD.
Definition cyclic.cpp:148
void HandleWatchdogTimeout()
Handle a watchdog timeout: update stats and possibly transition to Fault.
Definition cyclic.cpp:505
std::map< std::pair< std::uint16_t, std::uint16_t >, std::uint8_t > inputStatus
Last provider status (IOPS) the device sent per submodule. Payload bytes are only meaningful while th...
Definition cyclic.h:418
CyclicState State() const
The controller's current lifecycle state.
Definition cyclic.h:321
std::function< void()> onTimeout
Registered OnTimeout callback, if any.
Definition cyclic.h:491
CyclicController & operator=(const CyclicController &)=delete
Not copyable (owns sockets and background threads).
int maxConsecutiveTimeouts
Consecutive watchdog timeouts before transitioning to Fault.
Definition cyclic.h:440
rt::IOCRConfig inputIocr
Configuration for the input (device -> controller) IOCR.
Definition cyclic.h:434
std::optional< EthernetSocket > rxSock
Raw socket used for receiving input frames.
Definition cyclic.h:461
MacAddress srcMac
This host's MAC address.
Definition cyclic.h:428
void OnTimeout(std::function< void()> callback)
Register a callback invoked on each watchdog timeout.
Definition cyclic.cpp:201
bool LocalIsInputGood(std::uint16_t slot, std::uint16_t subslot) const
Check whether a submodule has GOOD provider status without locking.
Definition cyclic.cpp:180
CyclicStatsSnapshot StatsSnapshot() const
Definition cyclic.cpp:278
std::atomic< CyclicState > state
Current lifecycle state.
Definition cyclic.h:443
bool IsInputGood(std::uint16_t slot, std::uint16_t subslot) const
Check whether the device currently reports GOOD provider status.
Definition cyclic.cpp:173
std::function< void(CyclicState, CyclicState)> onStateChange
Registered OnStateChange callback, if any.
Definition cyclic.h:497
std::optional< std::uint8_t > GetInputStatus(std::uint16_t slot, std::uint16_t subslot) const
Get the last provider status (IOPS) received for a submodule.
Definition cyclic.cpp:159
std::function< void(const std::string &)> onError
Registered OnError callback, if any.
Definition cyclic.h:494
std::uint16_t etherType
Current lifecycle state.
Definition cyclic.h:446
std::optional< EthernetSocket > txSock
Raw socket used for sending output frames.
Definition cyclic.h:458
std::map< std::pair< int, int >, Bytes > inputData
Latest received data per (slot, subslot).
Definition cyclic.h:473
friend class CyclicControllerConformanceTest
Definition cyclic.h:222
std::thread rxThread
Thread receiving input frames.
Definition cyclic.h:455
MacAddress dstMac
The device's MAC address.
Definition cyclic.h:431
std::function< void(int, int, const Bytes &)> onInputData
Registered OnInput callback, if any.
Definition cyclic.h:488
void ProcessInputFrame(const Bytes &data)
Parse and process one received input frame.
Definition cyclic.cpp:543
void Start() override
Create TX/RX sockets and spawn the TX/RX threads.
Definition cyclic.cpp:214
std::uint16_t cycleCounter
Current TX cycle counter value.
Definition cyclic.h:464
CyclicStats stats
Communication statistics.
Definition cyclic.h:500
void OnInput(std::function< void(int slot, int subslot, const Bytes &data)> callback)
Register a callback invoked whenever new input data is received.
Definition cyclic.cpp:197
std::optional< std::uint16_t > lastRxCycleCounter
Last received cycle counter, for gap/duplicate/reorder detection.
Definition cyclic.h:476
Abstract interface for controlling cyclic PROFINET communication.
Definition cyclic.h:170
virtual void Start()=0
Starts cyclic PROFINET communication.
virtual ~ICyclicController()=default
Virtual destructor.
virtual void Stop()=0
Stops cyclic PROFINET communication.
Builds C_SDU payload from IO data objects with double-buffering.
Definition rt.h:277
constexpr int DEFAULT_MAX_CONSECUTIVE_TIMEOUTS
Default number of consecutive watchdog timeouts before transitioning to Fault.
Definition cyclic.h:155
std::string ToString(CyclicState state)
Human-readable name for a CyclicState value.
Definition cyclic.cpp:22
constexpr int MIN_CYCLE_MS
Minimum cycle time (ms) considered reliable.
Definition cyclic.h:151
CyclicState
Lifecycle state of a CyclicController.
Definition cyclic.h:39
@ Fault
Communication failure (e.g. consecutive watchdog timeouts).
@ Running
Active cyclic data exchange.
@ Stopping
Graceful shutdown in progress (sending STOP frames).
@ Stopped
Fully stopped, threads joined.
@ Starting
Sockets created, threads launching.
@ Idle
Initial state, not yet started.
constexpr int RECOMMENDED_CYCLE_MS
Recommended cycle time (ms).
Definition cyclic.h:153
constexpr int STOP_FRAME_COUNT
Number of STOP frames sent during a graceful Stop().
Definition cyclic.h:157
constexpr std::uint16_t ETHERTYPE_PROFINET
EtherType used by PROFINET RT frames (0x8892).
Definition rt.h:34
std::array< std::uint8_t, macAddressLength > MacAddress
A 6-byte Ethernet MAC address.
Definition util.h:67
std::vector< std::uint8_t > Bytes
Generic byte buffer alias used throughout the library for raw wire data.
Definition protocol.h:52
Declares PROFINET RT_CLASS_1 cyclic frame and IOCR data structures.
Copyable snapshot of cyclic communication statistics.
Definition cyclic.h:121
std::chrono::steady_clock::time_point lastReceiveTime
Definition cyclic.h:134
std::uint64_t AvgCycleTimeUs() const
Compute average TX cycle duration.
Definition cyclic.h:143
Statistics for cyclic communication.
Definition cyclic.h:65
void Reset()
Reset all counters to their initial values.
Definition cyclic.cpp:42
std::atomic< std::uint32_t > maxJitterUs
Largest observed deviation from the target cycle time, in microseconds.
Definition cyclic.h:88
std::uint64_t AvgCycleTimeUs() const
Compute the average TX cycle duration.
Definition cyclic.h:110
std::atomic< std::uint64_t > framesReceived
Total number of input frames received.
Definition cyclic.h:70
std::atomic< std::uint64_t > framesInvalid
Total number of frames rejected for having an invalid DataStatus.
Definition cyclic.h:76
std::atomic< std::uint64_t > framesOutOfOrder
Total number of frames received out of cycle-counter order.
Definition cyclic.h:82
std::atomic< std::uint32_t > minCycleTimeUs
Smallest observed TX cycle duration, in microseconds.
Definition cyclic.h:91
std::atomic< std::uint64_t > cycleTimeSumUs
Running sum of observed TX cycle durations, in microseconds.
Definition cyclic.h:103
std::atomic< std::uint64_t > framesDuplicate
Total number of duplicate (repeated cycle counter) frames received.
Definition cyclic.h:79
std::atomic< std::uint64_t > framesMissed
Total number of watchdog timeouts (missed input frames).
Definition cyclic.h:73
std::atomic< std::uint32_t > lastCycleTimeUs
Duration of the most recently completed TX cycle, in microseconds.
Definition cyclic.h:85
std::atomic< std::uint64_t > framesSent
Total number of output frames sent.
Definition cyclic.h:67
std::atomic< std::uint64_t > cycleCount
Number of TX cycles included in CycleTimeSumUs.
Definition cyclic.h:106
std::atomic< int > consecutiveTimeouts
Current run of consecutive watchdog timeouts (resets on a good frame).
Definition cyclic.h:100
std::atomic< std::chrono::steady_clock::time_point > lastReceiveTime
Timestamp of the last received input frame (or watchdog check).
Definition cyclic.h:97
std::atomic< std::uint32_t > maxCycleTimeUs
Largest observed TX cycle duration, in microseconds.
Definition cyclic.h:94
IOCR configuration derived from AR setup: timing parameters and IO object mappings needed for cyclic ...
Definition rt.h:126
Declares Linux Ethernet, addressing, timing, and utility helpers used by the PROFINET stack.