20#include <asio/io_context.hpp>
99 std::atomic<std::chrono::steady_clock::time_point>
lastReceiveTime{std::chrono::steady_clock::now()};
188 virtual void Start(std::unique_ptr<IRawEthernetSocket>
tx =
nullptr, std::unique_ptr<IRawEthernetSocket>
rx =
nullptr) = 0;
226 [[nodiscard]]
virtual std::optional<Bytes>
GetInputData(
int slot,
int subslot,
bool allowBad =
false)
const = 0;
301 std::optional<Bytes>
GetInputData(
int slot,
int subslot,
bool allowBad =
false)
const override;
320 void OnInputStatus(std::function<
void(std::uint16_t slot, std::uint16_t subslot, std::uint8_t iops)> callback);
324 void OnInput(std::function<
void(
int slot,
int subslot,
const Bytes& data)> callback);
332 void OnTimeout(std::function<
void()> callback);
336 void OnError(std::function<
void(
const std::string&)> callback);
346 void Start(std::unique_ptr<IRawEthernetSocket>
tx =
nullptr, std::unique_ptr<IRawEthernetSocket>
rx =
nullptr)
override;
352 void Stop()
override;
389 [[nodiscard]] std::optional<std::uint8_t>
GetInputStatus(std::uint16_t slot, std::uint16_t subslot)
const;
401 [[nodiscard]]
bool IsInputGood(std::uint16_t slot, std::uint16_t subslot)
const;
432 void SendOutputFrame(std::optional<std::uint8_t> dataStatusOverride = std::nullopt);
456 [[nodiscard]]
bool LocalIsInputGood(std::uint16_t slot, std::uint16_t subslot)
const;
460 std::map<std::pair<std::uint16_t, std::uint16_t>, std::uint8_t>
inputStatus;
503 std::unique_ptr<IRawEthernetSocket>
txSock;
506 std::unique_ptr<IRawEthernetSocket>
rxSock;
545 std::function<void(
const std::string&)>
onError;
Abstraction for sending and receiving raw Ethernet frames.
Narrow private-access adapter used only by cyclic controller tests.
RT_CLASS_1 cyclic data exchange controller.
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.
const CyclicStats & Stats() const
Communication statistics for this controller.
bool iocsGood
Tracks the watchdog-driven IOCS state so the RX/timeout paths only rewrite the buffer on transitions ...
void TrackCycleCounter(std::uint16_t rxCounter)
Update cycle-counter tracking stats (gaps/duplicates/reordering) for a received frame.
bool IsRunning() const override
Whether the controller is actively exchanging cyclic data.
std::uint32_t rxCounterStep
Expected cycle-counter increment per received input frame.
rt::CyclicDataBuilder outputBuilder
Double-buffered builder for output cyclic data.
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.
std::uint32_t txCounterStep
Cycle-counter increment applied per sent output frame.
std::mutex callbackMutex
Guards callback setting against concurrent access.
std::string interface
Network interface name.
void SendOutputFrame(std::optional< std::uint8_t > dataStatusOverride=std::nullopt)
Build and send one output frame.
std::unique_ptr< IRawEthernetSocket > rxSock
Raw socket used for receiving input frames.
void TxLoop()
TX thread body: sends output frames at the configured cycle rate.
CyclicController(const CyclicController &)=delete
Not copyable (owns sockets and background threads).
asio::io_context & ioContext
Asio execution context used by the raw Ethernet transports.
std::jthread txThread
Thread sending output frames.
std::mutex inputLock
Guards inputData against concurrent access.
void TxCycle()
Swap the output buffer and transmit one cyclic output frame.
void SendStopFrames()
Send STOP_FRAME_COUNT output frames with ProviderRun cleared.
rt::IOCRConfig outputIocr
Configuration for the output (controller -> device) IOCR.
void OnError(std::function< void(const std::string &)> callback)
Register a callback invoked on TX/RX socket errors.
CyclicState State() const override
The controller's current lifecycle state.
std::function< void(int, int, const std::uint8_t)> onInputStatus
Registered OnInputStatus callback, if any.
void OnStateChange(std::function< void(CyclicState oldState, CyclicState newState)> callback)
Register a callback invoked on every state transition.
void Stop() override
Stop gracefully.
~CyclicController() override
Stop (if running) and release resources.
void OnOutput(std::function< void(int cycleCounter, const Bytes &data)> callback)
Register a callback invoked whenever new output data is send.
std::atomic< bool > running
Whether the TX/RX threads should keep running.
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 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.
std::jthread rxThread
Thread receiving input frames.
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...
void SetOutputData(int slot, int subslot, const Bytes &data) override
Set output data for the next cycle.
std::function< void()> onTimeout
Registered OnTimeout callback, if any.
CyclicController & operator=(const CyclicController &)=delete
Not copyable (owns sockets and background threads).
int maxConsecutiveTimeouts
Consecutive watchdog timeouts before transitioning to Fault.
rt::IOCRConfig inputIocr
Configuration for the input (device -> controller) IOCR.
MacAddress srcMac
This host's MAC address.
void OnTimeout(std::function< void()> callback)
Register a callback invoked on each watchdog timeout.
bool LocalIsInputGood(std::uint16_t slot, std::uint16_t subslot) const
Check whether a submodule has GOOD provider status without locking.
CyclicStatsSnapshot StatsSnapshot() const
std::atomic< CyclicState > state
Current lifecycle state.
bool IsInputGood(std::uint16_t slot, std::uint16_t subslot) const
Check whether the device currently reports GOOD provider status.
std::function< void(CyclicState, CyclicState)> onStateChange
Registered OnStateChange callback, if any.
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.
std::function< void(const std::string &)> onError
Registered OnError callback, if any.
std::uint16_t etherType
Current lifecycle state.
std::unique_ptr< IRawEthernetSocket > txSock
Raw socket used for sending output frames.
std::map< std::pair< int, int >, Bytes > inputData
Latest received data per (slot, subslot).
MacAddress dstMac
The device's MAC address.
std::function< void(int, const Bytes &)> onOutputData
Registered OnOutputData callback, if any.
std::function< void(int, int, const Bytes &)> onInputData
Registered OnInput callback, if any.
void ProcessInputFrame(const Bytes &data)
Parse and process one received input frame.
std::uint16_t cycleCounter
Current TX cycle counter value.
Bytes GetOutputData(int slot, int subslot) const override
Get the current output data for a slot/subslot.
CyclicStats stats
Communication statistics.
void OnInput(std::function< void(int slot, int subslot, const Bytes &data)> callback)
Register a callback invoked whenever new input data is received.
std::optional< std::uint16_t > lastRxCycleCounter
Last received cycle counter, for gap/duplicate/reorder detection.
Abstract interface for controlling cyclic PROFINET communication.
virtual Bytes GetOutputData(int slot, int subslot) const =0
Read the currently configured output data for one slot/subslot.
virtual ~ICyclicController()=default
Virtual destructor.
virtual CyclicState State() const =0
The controller's current lifecycle state.
virtual void Stop()=0
Stops cyclic PROFINET communication.
virtual void Start(std::unique_ptr< IRawEthernetSocket > tx=nullptr, std::unique_ptr< IRawEthernetSocket > rx=nullptr)=0
Starts cyclic PROFINET communication.
virtual std::optional< Bytes > GetInputData(int slot, int subslot, bool allowBad=false) const =0
Get the latest valid input process data.
virtual void SetOutputData(int slot, int subslot, const Bytes &data)=0
Set complete process output data for one slot/subslot.
virtual bool IsRunning() const =0
Whether the controller is actively exchanging cyclic data.
Test fixture for received cyclic input IOPS behavior.
Builds C_SDU payload from IO data objects with double-buffering.
constexpr int DEFAULT_MAX_CONSECUTIVE_TIMEOUTS
Default number of consecutive watchdog timeouts before transitioning to Fault.
std::string ToString(CyclicState state)
Human-readable name for a CyclicState value.
constexpr int MIN_CYCLE_MS
Minimum cycle time (ms) considered reliable.
CyclicState
Lifecycle state of a CyclicController.
@ 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).
constexpr int STOP_FRAME_COUNT
Number of STOP frames sent during a graceful Stop().
constexpr std::uint16_t ETHERTYPE_PROFINET
EtherType used by PROFINET RT frames (0x8892).
std::array< std::uint8_t, macAddressLength > MacAddress
A 6-byte Ethernet MAC address.
std::vector< std::uint8_t > Bytes
Generic byte buffer alias used throughout the library for raw wire data.
Declares PROFINET RT_CLASS_1 cyclic frame and IOCR data structures.
Copyable snapshot of cyclic communication statistics.
std::uint64_t cycleTimeSumUs
std::uint32_t minCycleTimeUs
std::uint32_t maxJitterUs
std::uint64_t framesDuplicate
std::uint64_t framesOutOfOrder
std::uint64_t framesMissed
std::uint64_t framesReceived
std::chrono::steady_clock::time_point lastReceiveTime
std::uint64_t framesInvalid
std::uint32_t lastCycleTimeUs
std::uint64_t AvgCycleTimeUs() const
Compute average TX cycle duration.
std::uint32_t maxCycleTimeUs
Statistics for cyclic communication.
void Reset()
Reset all counters to their initial values.
std::atomic< std::uint32_t > maxJitterUs
Largest observed deviation from the target cycle time, in microseconds.
std::uint64_t AvgCycleTimeUs() const
Compute the average TX cycle duration.
std::atomic< std::uint64_t > framesReceived
Total number of input frames received.
std::atomic< std::uint64_t > framesInvalid
Total number of frames rejected for having an invalid DataStatus.
std::atomic< std::uint64_t > framesOutOfOrder
Total number of frames received out of cycle-counter order.
std::atomic< std::uint32_t > minCycleTimeUs
Smallest observed TX cycle duration, in microseconds.
std::atomic< std::uint64_t > cycleTimeSumUs
Running sum of observed TX cycle durations, in microseconds.
std::atomic< std::uint64_t > framesDuplicate
Total number of duplicate (repeated cycle counter) frames received.
std::atomic< std::uint64_t > framesMissed
Total number of watchdog timeouts (missed input frames).
std::atomic< std::uint32_t > lastCycleTimeUs
Duration of the most recently completed TX cycle, in microseconds.
std::atomic< std::uint64_t > framesSent
Total number of output frames sent.
std::atomic< std::uint64_t > cycleCount
Number of TX cycles included in CycleTimeSumUs.
std::atomic< int > consecutiveTimeouts
Current run of consecutive watchdog timeouts (resets on a good frame).
std::atomic< std::chrono::steady_clock::time_point > lastReceiveTime
Timestamp of the last received input frame (or watchdog check).
std::atomic< std::uint32_t > maxCycleTimeUs
Largest observed TX cycle duration, in microseconds.
IOCR configuration derived from AR setup: timing parameters and IO object mappings needed for cyclic ...
std::unique_ptr< MockRawEthernetSocket > tx
std::unique_ptr< MockRawEthernetSocket > rx
Declares Linux Ethernet, addressing, timing, and utility helpers used by the PROFINET stack.