PROFINET IO Controller Stack 1.0.0
Modern C++ implementation of a PROFINET IO Controller stack
Loading...
Searching...
No Matches
profinet::cyclic::CyclicController Class Reference

RT_CLASS_1 cyclic data exchange controller. More...

#include <cyclic.h>

+ Inheritance diagram for profinet::cyclic::CyclicController:
+ Collaboration diagram for profinet::cyclic::CyclicController:

Public Member Functions

 CyclicController (asio::io_context &ioContext, std::string interface, MacAddress srcMac, MacAddress dstMac, rt::IOCRConfig inputIocr, rt::IOCRConfig outputIocr, int maxConsecutiveTimeouts=DEFAULT_MAX_CONSECUTIVE_TIMEOUTS, std::uint16_t etherType=rt::ETHERTYPE_PROFINET)
 Construct a controller for the given interface and IOCR configuration.
 
 ~CyclicController () override
 Stop (if running) and release resources.
 
 CyclicController (const CyclicController &)=delete
 Not copyable (owns sockets and background threads).
 
CyclicController & operator= (const CyclicController &)=delete
 Not copyable (owns sockets and background threads).
 
void SetOutputData (int slot, int subslot, const Bytes &data) override
 Set output data for the next cycle.
 
Bytes GetOutputData (int slot, int subslot) const override
 Get the current output data for a slot/subslot.
 
std::optional< Bytes > GetInputData (int slot, int subslot, bool allowBad=false) const override
 Get the latest input data received from the device, if any or IOPS is BAD.
 
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.
 
void OnInput (std::function< void(int slot, int subslot, const Bytes &data)> callback)
 Register a callback invoked whenever new input data is received.
 
void OnOutput (std::function< void(int cycleCounter, const Bytes &data)> callback)
 Register a callback invoked whenever new output data is send.
 
void OnTimeout (std::function< void()> callback)
 Register a callback invoked on each watchdog timeout.
 
void OnError (std::function< void(const std::string &)> callback)
 Register a callback invoked on TX/RX socket errors.
 
void OnStateChange (std::function< void(CyclicState oldState, CyclicState newState)> callback)
 Register a callback invoked on every state transition.
 
void Start (std::unique_ptr< IRawEthernetSocket > tx=nullptr, std::unique_ptr< IRawEthernetSocket > rx=nullptr) override
 Create TX/RX sockets and spawn the TX/RX threads.
 
void Stop () override
 Stop gracefully.
 
bool IsRunning () const override
 Whether the controller is actively exchanging cyclic data.
 
CyclicState State () const override
 The controller's current lifecycle state.
 
const CyclicStats & Stats () const
 Communication statistics for this controller.
 
CyclicStatsSnapshot StatsSnapshot () const
 
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.
 
bool IsInputGood (std::uint16_t slot, std::uint16_t subslot) const
 Check whether the device currently reports GOOD provider status.
 
- Public Member Functions inherited from profinet::cyclic::ICyclicController
virtual ~ICyclicController ()=default
 Virtual destructor.
 

Private Member Functions

void Transition (CyclicState newState)
 Change state and invoke the OnStateChange callback if registered.
 
void CheckCycleTime ()
 Validate the configured cycle time, throwing if it's below 1ms.
 
void TxCycle ()
 Swap the output buffer and transmit one cyclic output frame.
 
void TxLoop ()
 TX thread body: sends output frames at the configured cycle rate.
 
void SendOutputFrame (std::optional< std::uint8_t > dataStatusOverride=std::nullopt)
 Build and send one output frame.
 
void SendStopFrames ()
 Send STOP_FRAME_COUNT output frames with ProviderRun cleared.
 
void RxLoop ()
 RX thread body: receives and processes input frames, checking the watchdog.
 
void HandleWatchdogTimeout ()
 Handle a watchdog timeout: update stats and possibly transition to Fault.
 
void ProcessInputFrame (const Bytes &data)
 Parse and process one received input frame.
 
bool LocalIsInputGood (std::uint16_t slot, std::uint16_t subslot) const
 Check whether a submodule has GOOD provider status without locking.
 
void TrackCycleCounter (std::uint16_t rxCounter)
 Update cycle-counter tracking stats (gaps/duplicates/reordering) for a received frame.
 

Private Attributes

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 the matching IOPS reports GOOD.
 
asio::io_context & ioContext
 Asio execution context used by the raw Ethernet transports.
 
std::string interface
 Network interface name.
 
MacAddress srcMac
 This host's MAC address.
 
MacAddress dstMac
 The device's MAC address.
 
rt::IOCRConfig inputIocr
 Configuration for the input (device -> controller) IOCR.
 
rt::IOCRConfig outputIocr
 Configuration for the output (controller -> device) IOCR.
 
int maxConsecutiveTimeouts
 Consecutive watchdog timeouts before transitioning to Fault.
 
std::atomic< CyclicState > state {CyclicState::Idle}
 Current lifecycle state.
 
std::uint16_t etherType {rt::ETHERTYPE_PROFINET}
 Current lifecycle state.
 
std::atomic< bool > running {false}
 Whether the TX/RX threads should keep running.
 
std::jthread txThread
 Thread sending output frames.
 
std::jthread rxThread
 Thread receiving input frames.
 
std::unique_ptr< IRawEthernetSocket > txSock
 Raw socket used for sending output frames.
 
std::unique_ptr< IRawEthernetSocket > rxSock
 Raw socket used for receiving input frames.
 
std::uint16_t cycleCounter = 0
 Current TX cycle counter value.
 
rt::CyclicDataBuilder outputBuilder
 Double-buffered builder for output cyclic data.
 
std::mutex inputLock
 Guards inputData against concurrent access.
 
std::mutex callbackMutex
 Guards callback setting against concurrent access.
 
std::map< std::pair< int, int >, Bytes > inputData
 Latest received data per (slot, subslot).
 
std::optional< std::uint16_t > lastRxCycleCounter
 Last received cycle counter, for gap/duplicate/reorder detection.
 
std::uint32_t rxCounterStep
 Expected cycle-counter increment per received input frame.
 
std::uint32_t txCounterStep
 Cycle-counter increment applied per sent output frame.
 
std::function< void(int, int, const std::uint8_t)> onInputStatus
 Registered OnInputStatus callback, if any.
 
std::function< void(int, int, const Bytes &)> onInputData
 Registered OnInput callback, if any.
 
std::function< void(int, const Bytes &)> onOutputData
 Registered OnOutputData callback, if any.
 
std::function< void()> onTimeout
 Registered OnTimeout callback, if any.
 
std::function< void(const std::string &)> onError
 Registered OnError callback, if any.
 
std::function< void(CyclicState, CyclicState)> onStateChange
 Registered OnStateChange callback, if any.
 
CyclicStats stats
 Communication statistics.
 
bool iocsGood
 Tracks the watchdog-driven IOCS state so the RX/timeout paths only rewrite the buffer on transitions (both run on the RX thread).
 

Friends

class CyclicControllerConformanceTest
 
class ReceivedIopsTest
 
class CyclicControllerTestAccess
 
class CyclicTest
 

Detailed Description

RT_CLASS_1 cyclic data exchange controller.

Example:

rt::IOCRConfig input_iocr, output_iocr; // from rt::BuildIocrConfigs
cyclic::CyclicController controller(ifname, my_mac, device_mac,
input_iocr, output_iocr);
controller.OnInput([](int slot, int subslot, const Bytes& data) { ... });
controller.Start();
controller.SetOutputData(1, 1, {0x01, 0x02, 0x03, 0x04});
// ... let it run ...
controller.Stop();
RT_CLASS_1 cyclic data exchange controller.
Definition cyclic.h:248
std::vector< std::uint8_t > Bytes
Generic byte buffer alias used throughout the library for raw wire data.
Definition protocol.h:55
IOCR configuration derived from AR setup: timing parameters and IO object mappings needed for cyclic ...
Definition rt.h:137
std::unique_ptr< cyclic::CyclicController > controller

C++ port has no language-level ceiling, but the constructor still throws below 1ms and still surfaces a warning below 8ms, since the underlying two-thread sleep-based scheduling here is the same design, just compiled – actual achievable jitter depends on the OS scheduler, not the language.

Definition at line 247 of file cyclic.h.

Constructor & Destructor Documentation

◆ CyclicController() [1/2]

profinet::cyclic::CyclicController::CyclicController ( asio::io_context &  ioContext,
std::string  interface,
MacAddress  srcMac,
MacAddress  dstMac,
rt::IOCRConfig  inputIocr,
rt::IOCRConfig  outputIocr,
int  maxConsecutiveTimeouts = DEFAULT_MAX_CONSECUTIVE_TIMEOUTS,
std::uint16_t  etherType = rt::ETHERTYPE_PROFINET 
)

Construct a controller for the given interface and IOCR configuration.

Parameters
ioContextAsio execution context.
interfaceNetwork interface name to bind to, e.g. "eth0".
srcMacThis host's MAC address.
dstMacThe device's MAC address.
inputIocrConfiguration for the input (device -> controller) IOCR.
outputIocrConfiguration for the output (controller -> device) IOCR.
maxConsecutiveTimeoutsConsecutive watchdog timeouts before transitioning to Fault.
etherTypeBind protocol. 0 binds ALL so VLAN-tagged frames are delivered too.

Definition at line 62 of file cyclic.cpp.

References CheckCycleTime(), profinet::rt::IOXS_GOOD, outputBuilder, profinet::rt::IOCRConfig::reductionRatio, rxCounterStep, profinet::rt::IOCRConfig::sendClockFactor, profinet::rt::CyclicDataBuilder::SetAllIocs(), profinet::rt::CyclicDataBuilder::SetAllIops(), and txCounterStep.

+ Here is the call graph for this function:

◆ ~CyclicController()

profinet::cyclic::CyclicController::~CyclicController ( )
override

Stop (if running) and release resources.

Definition at line 95 of file cyclic.cpp.

References running, and Stop().

+ Here is the call graph for this function:

◆ CyclicController() [2/2]

profinet::cyclic::CyclicController::CyclicController ( const CyclicController &  )
delete

Not copyable (owns sockets and background threads).

Member Function Documentation

◆ CheckCycleTime()

void profinet::cyclic::CyclicController::CheckCycleTime ( )
private

Validate the configured cycle time, throwing if it's below 1ms.

Definition at line 103 of file cyclic.cpp.

References profinet::rt::IOCRConfig::CycleTimeMs(), and outputIocr.

Referenced by CyclicController().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ GetInputData()

std::optional< Bytes > profinet::cyclic::CyclicController::GetInputData ( int  slot,
int  subslot,
bool  allowBad = false 
) const
overridevirtual

Get the latest input data received from the device, if any or IOPS is BAD.

Data whose IOPS is BAD must not be used by the application: the device is telling us the payload is not valid (module pulled, sensor faulted), and the bytes it keeps sending are stale. Such data is withheld unless allowBad is set. Use GetInputStatus() to inspect the raw IOPS.

Parameters
slotSlot number of the object to read.
subslotSubslot number of the object to read.
allowBadReturn the payload even when the device marked IOPS BAD.
Returns
The object's latest data, or std::nullopt if none received yet.

Thread-safe.

Implements profinet::cyclic::ICyclicController.

Definition at line 152 of file cyclic.cpp.

References inputData, inputLock, and LocalIsInputGood().

+ Here is the call graph for this function:

◆ GetInputStatus()

std::optional< std::uint8_t > profinet::cyclic::CyclicController::GetInputStatus ( std::uint16_t  slot,
std::uint16_t  subslot 
) const

Get the last provider status (IOPS) received for a submodule.

Returns the raw IOPS byte reported by the PROFINET device for the specified slot and subslot. The access is protected by the input status mutex.

A value of 0x80 indicates GOOD provider status.

Parameters
slotSlot number.
subslotSubslot number.
Returns
The last received raw IOPS byte, or std::nullopt if no provider status has been received yet.

Definition at line 163 of file cyclic.cpp.

References inputLock, and inputStatus.

◆ GetOutputData()

Bytes profinet::cyclic::CyclicController::GetOutputData ( int  slot,
int  subslot 
) const
overridevirtual

Get the current output data for a slot/subslot.

Parameters
slotSlot number.
subslotSubslot number.
Returns
Current output data from the application/write buffer.

Implements profinet::cyclic::ICyclicController.

Definition at line 147 of file cyclic.cpp.

References profinet::rt::CyclicDataBuilder::GetData(), and outputBuilder.

+ Here is the call graph for this function:

◆ HandleWatchdogTimeout()

void profinet::cyclic::CyclicController::HandleWatchdogTimeout ( )
private

Handle a watchdog timeout: update stats and possibly transition to Fault.

Definition at line 557 of file cyclic.cpp.

References profinet::cyclic::CyclicStats::consecutiveTimeouts, profinet::cyclic::Fault, profinet::cyclic::CyclicStats::framesMissed, iocsGood, profinet::rt::IOXS_BAD, maxConsecutiveTimeouts, onError, onTimeout, outputBuilder, profinet::cyclic::Running, profinet::rt::CyclicDataBuilder::SetAllIocs(), state, stats, and Transition().

Referenced by RxLoop().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ IsInputGood()

bool profinet::cyclic::CyclicController::IsInputGood ( std::uint16_t  slot,
std::uint16_t  subslot 
) const

Check whether the device currently reports GOOD provider status.

Checks the last IOPS value received for the specified submodule. The access is protected by the input status mutex.

Parameters
slotSlot number.
subslotSubslot number.
Returns
true if the last received IOPS contains the GOOD data-state bit, otherwise false. Returns false if no IOPS has been received yet.

Definition at line 177 of file cyclic.cpp.

References inputLock, and LocalIsInputGood().

+ Here is the call graph for this function:

◆ IsRunning()

bool profinet::cyclic::CyclicController::IsRunning ( ) const
inlineoverridevirtual

Whether the controller is actively exchanging cyclic data.

Returns
True if State() == CyclicState::Running.

Implements profinet::cyclic::ICyclicController.

Definition at line 356 of file cyclic.h.

References profinet::cyclic::Running, and state.

Referenced by profinet::cyclic::TEST_F().

+ Here is the caller graph for this function:

◆ LocalIsInputGood()

bool profinet::cyclic::CyclicController::LocalIsInputGood ( std::uint16_t  slot,
std::uint16_t  subslot 
) const
private

Check whether a submodule has GOOD provider status without locking.

This is the internal implementation of IsInputGood(). The caller must already hold m_inputStatusMutex.

Parameters
slotSlot number.
subslotSubslot number.
Returns
true if the last received IOPS contains the GOOD data-state bit, otherwise false.

Definition at line 184 of file cyclic.cpp.

References inputStatus, and profinet::rt::IOXS_DATA_STATE_GOOD.

Referenced by GetInputData(), IsInputGood(), and ProcessInputFrame().

+ Here is the caller graph for this function:

◆ OnError()

void profinet::cyclic::CyclicController::OnError ( std::function< void(const std::string &)>  callback)

Register a callback invoked on TX/RX socket errors.

Parameters
callbackFunction called with a human-readable error message.

Definition at line 218 of file cyclic.cpp.

References callbackMutex, and onError.

◆ OnInput()

void profinet::cyclic::CyclicController::OnInput ( std::function< void(int slot, int subslot, const Bytes &data)>  callback)

Register a callback invoked whenever new input data is received.

Parameters
callbackFunction called with (slot, subslot, data) for each updated object.

Definition at line 202 of file cyclic.cpp.

References callbackMutex, and onInputData.

◆ OnInputStatus()

void profinet::cyclic::CyclicController::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.

The callback is invoked by the RX thread whenever the provider status (IOPS) of a submodule transitions between GOOD and BAD.

A device can use an IOPS transition to indicate that its input data has become invalid, for example when a module is removed or a sensor fault occurs, without terminating the Application Relationship (AR). In this situation cyclic frames may continue to arrive with stale payload data, making the IOPS transition the relevant notification available to the application.

The callback receives the slot number, subslot number, and raw IOPS byte reported by the device.

Parameters
callbackFunction invoked as callback(slot, subslot, iops). Passing an empty std::function disables the callback.

Definition at line 196 of file cyclic.cpp.

References callbackMutex, and onInputStatus.

◆ OnOutput()

void profinet::cyclic::CyclicController::OnOutput ( std::function< void(int cycleCounter, const Bytes &data)>  callback)

Register a callback invoked whenever new output data is send.

Parameters
callbackFunction called with (cycleCounter, data) for each updated object.

Definition at line 208 of file cyclic.cpp.

References callbackMutex, and onOutputData.

◆ OnStateChange()

void profinet::cyclic::CyclicController::OnStateChange ( std::function< void(CyclicState oldState, CyclicState newState)>  callback)

Register a callback invoked on every state transition.

Parameters
callbackFunction called with (old_state, new_state).

Definition at line 223 of file cyclic.cpp.

References callbackMutex, and onStateChange.

◆ OnTimeout()

void profinet::cyclic::CyclicController::OnTimeout ( std::function< void()>  callback)

Register a callback invoked on each watchdog timeout.

Parameters
callbackFunction called with no arguments.

Definition at line 213 of file cyclic.cpp.

References callbackMutex, and onTimeout.

◆ operator=()

CyclicController & profinet::cyclic::CyclicController::operator= ( const CyclicController &  )
delete

Not copyable (owns sockets and background threads).

◆ ProcessInputFrame()

void profinet::cyclic::CyclicController::ProcessInputFrame ( const Bytes &  data)
private

◆ RxLoop()

void profinet::cyclic::CyclicController::RxLoop ( )
private

RX thread body: receives and processes input frames, checking the watchdog.

Definition at line 516 of file cyclic.cpp.

References HandleWatchdogTimeout(), inputIocr, profinet::cyclic::CyclicStats::lastReceiveTime, onError, ProcessInputFrame(), running, rxSock, stats, and profinet::rt::IOCRConfig::WatchdogTimeUs().

Referenced by Start().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ SendOutputFrame()

void profinet::cyclic::CyclicController::SendOutputFrame ( std::optional< std::uint8_t >  dataStatusOverride = std::nullopt)
private

Build and send one output frame.

Parameters
dataStatusOverrideIf set, overrides the computed DataStatus (used for STOP frames).

Definition at line 444 of file cyclic.cpp.

References profinet::rt::CyclicDataBuilder::Build(), profinet::rt::BuildEthernetFrame(), cycleCounter, profinet::rt::DATA_STATUS_PROVIDER_RUN, profinet::rt::DATA_STATUS_STATE, profinet::rt::DATA_STATUS_STATION_OK, profinet::rt::DATA_STATUS_VALID, dstMac, frame, profinet::rt::IOCRConfig::frameId, profinet::rt::RTFrame::frameId, onError, onOutputData, outputBuilder, outputIocr, payload, srcMac, txCounterStep, and txSock.

Referenced by SendStopFrames(), and TxCycle().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ SendStopFrames()

void profinet::cyclic::CyclicController::SendStopFrames ( )
private

Send STOP_FRAME_COUNT output frames with ProviderRun cleared.

Definition at line 486 of file cyclic.cpp.

References profinet::rt::IOCRConfig::CycleTimeUs(), profinet::rt::DATA_STATUS_STATE, profinet::rt::DATA_STATUS_STATION_OK, profinet::rt::DATA_STATUS_VALID, profinet::cyclic::CyclicStats::framesSent, outputBuilder, outputIocr, SendOutputFrame(), stats, profinet::cyclic::STOP_FRAME_COUNT, profinet::rt::CyclicDataBuilder::Swap(), and txSock.

Referenced by Stop().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ SetOutputData()

void profinet::cyclic::CyclicController::SetOutputData ( int  slot,
int  subslot,
const Bytes &  data 
)
overridevirtual

Set output data for the next cycle.

Parameters
slotSlot number of the object to update.
subslotSubslot number of the object to update.
dataNew data for the object.

Thread-safe. Throws std::runtime_error if in Fault or Stopped state.

Implements profinet::cyclic::ICyclicController.

Definition at line 137 of file cyclic.cpp.

References profinet::cyclic::Fault, profinet::rt::IOXS_GOOD, outputBuilder, profinet::rt::CyclicDataBuilder::SetData(), profinet::rt::CyclicDataBuilder::SetIops(), state, profinet::cyclic::Stopped, and profinet::cyclic::ToString().

+ Here is the call graph for this function:

◆ Start()

void profinet::cyclic::CyclicController::Start ( std::unique_ptr< IRawEthernetSocket >  tx = nullptr,
std::unique_ptr< IRawEthernetSocket >  rx = nullptr 
)
overridevirtual

Create TX/RX sockets and spawn the TX/RX threads.

Throws std::runtime_error if not in Idle/Stopped/Fault state, or if CycleTimeMs() < 1ms (not achievable). Throws PermissionDeniedError if raw sockets need elevated privilege.

Implements profinet::cyclic::ICyclicController.

Definition at line 229 of file cyclic.cpp.

References etherType, profinet::cyclic::Fault, profinet::cyclic::Idle, interface, ioContext, lastRxCycleCounter, outputBuilder, profinet::cyclic::CyclicStats::Reset(), profinet::cyclic::Running, running, rx, RxLoop(), rxSock, rxThread, profinet::cyclic::Starting, state, stats, profinet::cyclic::Stopped, profinet::rt::CyclicDataBuilder::Swap(), profinet::cyclic::ToString(), Transition(), tx, TxLoop(), txSock, and txThread.

+ Here is the call graph for this function:

◆ State()

CyclicState profinet::cyclic::CyclicController::State ( ) const
inlineoverridevirtual

The controller's current lifecycle state.

Returns
The current CyclicState.

Implements profinet::cyclic::ICyclicController.

Definition at line 363 of file cyclic.h.

References state.

Referenced by profinet::cyclic::TEST_F().

+ Here is the caller graph for this function:

◆ Stats()

const CyclicStats & profinet::cyclic::CyclicController::Stats ( ) const
inline

Communication statistics for this controller.

Returns
A const reference to the live statistics.

Definition at line 370 of file cyclic.h.

References stats.

◆ StatsSnapshot()

CyclicStatsSnapshot profinet::cyclic::CyclicController::StatsSnapshot ( ) const

◆ Stop()

void profinet::cyclic::CyclicController::Stop ( )
overridevirtual

Stop gracefully.

Signals threads to exit, joins the TX thread, sends STOP frames (ProviderRun cleared), closes the RX socket, joins the RX thread, then closes the TX socket.

Implements profinet::cyclic::ICyclicController.

Definition at line 289 of file cyclic.cpp.

References running, rxSock, rxThread, SendStopFrames(), profinet::cyclic::Stopped, profinet::cyclic::Stopping, Transition(), txSock, and txThread.

Referenced by ~CyclicController().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ TrackCycleCounter()

void profinet::cyclic::CyclicController::TrackCycleCounter ( std::uint16_t  rxCounter)
private

Update cycle-counter tracking stats (gaps/duplicates/reordering) for a received frame.

Parameters
rxCounterCycle counter from the received frame.

Definition at line 796 of file cyclic.cpp.

References profinet::cyclic::CyclicStats::framesDuplicate, profinet::cyclic::CyclicStats::framesMissed, profinet::cyclic::CyclicStats::framesOutOfOrder, lastRxCycleCounter, rxCounterStep, and stats.

Referenced by ProcessInputFrame().

+ Here is the caller graph for this function:

◆ Transition()

void profinet::cyclic::CyclicController::Transition ( CyclicState  newState)
private

Change state and invoke the OnStateChange callback if registered.

Parameters
newStateState to transition to.

Definition at line 118 of file cyclic.cpp.

References onStateChange, and state.

Referenced by HandleWatchdogTimeout(), ProcessInputFrame(), Start(), and Stop().

+ Here is the caller graph for this function:

◆ TxCycle()

void profinet::cyclic::CyclicController::TxCycle ( )
private

Swap the output buffer and transmit one cyclic output frame.

Executes one PROFINET cyclic output transmission cycle.

The output buffer is swapped before transmission so that the frame contains the latest prepared output data. A frame must continue to be transmitted even while the controller is in FAULT state. Stopping cyclic transmission would cause the device's Data Hold Timer to expire, which would terminate the Application Relationship (AR) and prevent the input stream from resuming during FAULT recovery.

IOCS is already reported as BAD while the controller is in FAULT, so cyclic transmission can safely continue while the controller is in that state.

Definition at line 361 of file cyclic.cpp.

References profinet::cyclic::CyclicStats::framesSent, outputBuilder, SendOutputFrame(), stats, and profinet::rt::CyclicDataBuilder::Swap().

Referenced by TxLoop().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ TxLoop()

void profinet::cyclic::CyclicController::TxLoop ( )
private

TX thread body: sends output frames at the configured cycle rate.

Definition at line 370 of file cyclic.cpp.

References profinet::cyclic::CyclicStats::cycleCount, profinet::cyclic::CyclicStats::cycleTimeSumUs, profinet::rt::IOCRConfig::CycleTimeUs(), profinet::cyclic::CyclicStats::lastCycleTimeUs, profinet::cyclic::CyclicStats::maxCycleTimeUs, profinet::cyclic::CyclicStats::maxJitterUs, profinet::cyclic::CyclicStats::minCycleTimeUs, outputIocr, running, stats, and TxCycle().

Referenced by Start().

+ Here is the call graph for this function:
+ Here is the caller graph for this function:

Friends And Related Symbol Documentation

◆ CyclicControllerConformanceTest

friend class CyclicControllerConformanceTest
friend

Definition at line 250 of file cyclic.h.

◆ CyclicControllerTestAccess

friend class CyclicControllerTestAccess
friend

Definition at line 252 of file cyclic.h.

◆ CyclicTest

friend class CyclicTest
friend

Definition at line 253 of file cyclic.h.

◆ ReceivedIopsTest

friend class ReceivedIopsTest
friend

Definition at line 251 of file cyclic.h.

Member Data Documentation

◆ callbackMutex

std::mutex profinet::cyclic::CyclicController::callbackMutex
mutableprivate

Guards callback setting against concurrent access.

Definition at line 518 of file cyclic.h.

Referenced by OnError(), OnInput(), OnInputStatus(), OnOutput(), OnStateChange(), and OnTimeout().

◆ cycleCounter

std::uint16_t profinet::cyclic::CyclicController::cycleCounter = 0
private

Current TX cycle counter value.

Definition at line 509 of file cyclic.h.

Referenced by SendOutputFrame().

◆ dstMac

MacAddress profinet::cyclic::CyclicController::dstMac
private

The device's MAC address.

Definition at line 476 of file cyclic.h.

Referenced by ProcessInputFrame(), and SendOutputFrame().

◆ etherType

std::uint16_t profinet::cyclic::CyclicController::etherType {rt::ETHERTYPE_PROFINET}
private

Current lifecycle state.

Definition at line 491 of file cyclic.h.

Referenced by Start().

◆ inputData

std::map<std::pair<int, int>, Bytes> profinet::cyclic::CyclicController::inputData
private

Latest received data per (slot, subslot).

Definition at line 521 of file cyclic.h.

Referenced by GetInputData(), and ProcessInputFrame().

◆ inputIocr

rt::IOCRConfig profinet::cyclic::CyclicController::inputIocr
private

Configuration for the input (device -> controller) IOCR.

Definition at line 479 of file cyclic.h.

Referenced by ProcessInputFrame(), and RxLoop().

◆ inputLock

std::mutex profinet::cyclic::CyclicController::inputLock
mutableprivate

Guards inputData against concurrent access.

Definition at line 515 of file cyclic.h.

Referenced by GetInputData(), GetInputStatus(), IsInputGood(), and ProcessInputFrame().

◆ inputStatus

std::map<std::pair<std::uint16_t, std::uint16_t>, std::uint8_t> profinet::cyclic::CyclicController::inputStatus
private

Last provider status (IOPS) the device sent per submodule. Payload bytes are only meaningful while the matching IOPS reports GOOD.

Definition at line 460 of file cyclic.h.

Referenced by GetInputStatus(), LocalIsInputGood(), and ProcessInputFrame().

◆ interface

std::string profinet::cyclic::CyclicController::interface
private

Network interface name.

Definition at line 470 of file cyclic.h.

Referenced by Start().

◆ ioContext

asio::io_context& profinet::cyclic::CyclicController::ioContext
private

Asio execution context used by the raw Ethernet transports.

Definition at line 467 of file cyclic.h.

Referenced by Start().

◆ iocsGood

bool profinet::cyclic::CyclicController::iocsGood
private

Tracks the watchdog-driven IOCS state so the RX/timeout paths only rewrite the buffer on transitions (both run on the RX thread).

Definition at line 555 of file cyclic.h.

Referenced by HandleWatchdogTimeout(), and ProcessInputFrame().

◆ lastRxCycleCounter

std::optional<std::uint16_t> profinet::cyclic::CyclicController::lastRxCycleCounter
private

Last received cycle counter, for gap/duplicate/reorder detection.

Definition at line 524 of file cyclic.h.

Referenced by Start(), and TrackCycleCounter().

◆ maxConsecutiveTimeouts

int profinet::cyclic::CyclicController::maxConsecutiveTimeouts
private

Consecutive watchdog timeouts before transitioning to Fault.

Definition at line 485 of file cyclic.h.

Referenced by HandleWatchdogTimeout().

◆ onError

std::function<void(const std::string&)> profinet::cyclic::CyclicController::onError
private

Registered OnError callback, if any.

Definition at line 545 of file cyclic.h.

Referenced by HandleWatchdogTimeout(), OnError(), ProcessInputFrame(), RxLoop(), and SendOutputFrame().

◆ onInputData

std::function<void(int, int, const Bytes&)> profinet::cyclic::CyclicController::onInputData
private

Registered OnInput callback, if any.

Definition at line 536 of file cyclic.h.

Referenced by OnInput(), and ProcessInputFrame().

◆ onInputStatus

std::function<void(int, int, const std::uint8_t)> profinet::cyclic::CyclicController::onInputStatus
private

Registered OnInputStatus callback, if any.

Definition at line 533 of file cyclic.h.

Referenced by OnInputStatus(), and ProcessInputFrame().

◆ onOutputData

std::function<void(int, const Bytes&)> profinet::cyclic::CyclicController::onOutputData
private

Registered OnOutputData callback, if any.

Definition at line 539 of file cyclic.h.

Referenced by OnOutput(), and SendOutputFrame().

◆ onStateChange

std::function<void(CyclicState, CyclicState)> profinet::cyclic::CyclicController::onStateChange
private

Registered OnStateChange callback, if any.

Definition at line 548 of file cyclic.h.

Referenced by OnStateChange(), and Transition().

◆ onTimeout

std::function<void()> profinet::cyclic::CyclicController::onTimeout
private

Registered OnTimeout callback, if any.

Definition at line 542 of file cyclic.h.

Referenced by HandleWatchdogTimeout(), and OnTimeout().

◆ outputBuilder

rt::CyclicDataBuilder profinet::cyclic::CyclicController::outputBuilder
private

Double-buffered builder for output cyclic data.

Definition at line 512 of file cyclic.h.

Referenced by CyclicController(), GetOutputData(), HandleWatchdogTimeout(), ProcessInputFrame(), SendOutputFrame(), SendStopFrames(), SetOutputData(), Start(), and TxCycle().

◆ outputIocr

rt::IOCRConfig profinet::cyclic::CyclicController::outputIocr
private

Configuration for the output (controller -> device) IOCR.

Definition at line 482 of file cyclic.h.

Referenced by CheckCycleTime(), SendOutputFrame(), SendStopFrames(), and TxLoop().

◆ running

std::atomic<bool> profinet::cyclic::CyclicController::running {false}
private

Whether the TX/RX threads should keep running.

Definition at line 494 of file cyclic.h.

Referenced by ~CyclicController(), RxLoop(), Start(), Stop(), and TxLoop().

◆ rxCounterStep

std::uint32_t profinet::cyclic::CyclicController::rxCounterStep
private

Expected cycle-counter increment per received input frame.

Definition at line 527 of file cyclic.h.

Referenced by CyclicController(), and TrackCycleCounter().

◆ rxSock

std::unique_ptr<IRawEthernetSocket> profinet::cyclic::CyclicController::rxSock
private

Raw socket used for receiving input frames.

Definition at line 506 of file cyclic.h.

Referenced by RxLoop(), Start(), and Stop().

◆ rxThread

std::jthread profinet::cyclic::CyclicController::rxThread
private

Thread receiving input frames.

Definition at line 500 of file cyclic.h.

Referenced by Start(), and Stop().

◆ srcMac

MacAddress profinet::cyclic::CyclicController::srcMac
private

This host's MAC address.

Definition at line 473 of file cyclic.h.

Referenced by SendOutputFrame().

◆ state

std::atomic<CyclicState> profinet::cyclic::CyclicController::state {CyclicState::Idle}
private

Current lifecycle state.

Definition at line 488 of file cyclic.h.

Referenced by HandleWatchdogTimeout(), IsRunning(), ProcessInputFrame(), SetOutputData(), Start(), State(), and Transition().

◆ stats

CyclicStats profinet::cyclic::CyclicController::stats
private

Communication statistics.

Definition at line 551 of file cyclic.h.

Referenced by HandleWatchdogTimeout(), ProcessInputFrame(), RxLoop(), SendStopFrames(), Start(), Stats(), StatsSnapshot(), TrackCycleCounter(), TxCycle(), and TxLoop().

◆ txCounterStep

std::uint32_t profinet::cyclic::CyclicController::txCounterStep
private

Cycle-counter increment applied per sent output frame.

Definition at line 530 of file cyclic.h.

Referenced by CyclicController(), and SendOutputFrame().

◆ txSock

std::unique_ptr<IRawEthernetSocket> profinet::cyclic::CyclicController::txSock
private

Raw socket used for sending output frames.

Definition at line 503 of file cyclic.h.

Referenced by SendOutputFrame(), SendStopFrames(), Start(), and Stop().

◆ txThread

std::jthread profinet::cyclic::CyclicController::txThread
private

Thread sending output frames.

Definition at line 497 of file cyclic.h.

Referenced by Start(), and Stop().


The documentation for this class was generated from the following files: