PROFINET IO Controller Stack 1.0.0
Modern C++ implementation of a PROFINET IO Controller stack
Loading...
Searching...
No Matches
device.h
Go to the documentation of this file.
1
33#pragma once
34
35#include <functional>
36#include <map>
37#include <memory>
38#include <optional>
39#include <string>
40#include <vector>
41
44#include "profinet/alarms.h"
45#include "profinet/blocks.h"
46#include "profinet/cyclic.h"
47#include "profinet/dcp.h"
48#include "profinet/diagnosis.h"
49#include "profinet/protocol.h"
50#include "profinet/rpc.h"
51#include "profinet/rt.h"
52#include "profinet/util.h"
53
55{
56
61std::optional<MacAddress> ParseMac(const std::string& macStr);
62
66bool IsMacAddress(const std::string& identifier);
67
68// =============================================================================
69// Data Classes
70// =============================================================================
71
74{
76 std::uint16_t slot = 0;
77
79 std::uint16_t subslot = 0;
80
82 std::uint16_t index = 0;
83
86
88 std::uint32_t api = 0;
89};
90
95{
97 std::string name;
98
100 std::string ip;
101
103 std::string mac;
104
106 std::uint16_t vendorId = 0;
107
109 std::uint16_t deviceId = 0;
110
112 std::string deviceType;
113
115 std::string netmask;
116
118 std::string gateway;
119
121 std::vector<std::string> deviceRoles;
122
124 std::string vendorName;
125
127 std::optional<PNInM0> im0;
128
130 std::optional<blocks::PDRealData> topology;
131
133 std::string annotation;
134
137 [[nodiscard]] std::string SerialNumber() const;
138
141 [[nodiscard]] std::string OrderId() const;
142
145 [[nodiscard]] std::uint16_t HardwareRevision() const;
146
149 [[nodiscard]] std::string SoftwareRevision() const;
150};
151
152// =============================================================================
153// ProfinetDevice
154// =============================================================================
155
167{
168 public:
180 double timeoutSec = 5.0,
181 std::unique_ptr<rpc::IRPCCon> rpc = nullptr, std::unique_ptr<IAlarmListener> alarmListener = nullptr);
182
185
188
191
193 ProfinetDevice(ProfinetDevice&&) noexcept;
194
197 ProfinetDevice& operator=(ProfinetDevice&&) noexcept;
198
199 // =========================================================================
200 // Discovery factory methods
201 // =========================================================================
202
210 static ProfinetDevice Discover(const std::string& identifier, const std::string& interface,
211 double timeoutSec = 10.0);
212
220 static ProfinetDevice FromIp(const std::string& ip, const std::string& interface, double timeoutSec = 10.0);
221
227 static ProfinetDevice FromDcpInfo(dcp::DCPDeviceDescription info, const std::string& interface,
228 double timeoutSec = 5.0);
229
230 // =========================================================================
231 // Connection management
232 // =========================================================================
233
238 void Connect();
239
242 void Disconnect();
243
246 void Close() noexcept;
247
250 [[nodiscard]] bool IsConnected() const
251 {
252 return connected;
253 }
254
255 // =========================================================================
256 // Device info
257 // =========================================================================
258
261 [[nodiscard]] const std::string& Name() const
262 {
263 return info.name;
264 }
265
268 [[nodiscard]] const std::string& Ip() const
269 {
270 return info.ip;
271 }
272
275 [[nodiscard]] std::string Mac() const
276 {
277 return info.mac;
278 }
279
285 DeviceInfo GetInfo(bool includeTopology = false);
286
287 // =========================================================================
288 // Read/write operations
289 // =========================================================================
290
298 Bytes Read(std::uint16_t slot, std::uint16_t subslot, std::uint16_t index, std::uint32_t api = 0);
299
329 Bytes ReadImplicit(std::uint16_t slot, std::uint16_t subslot, std::uint16_t index, std::uint32_t api = 0);
330
338 void Write(std::uint16_t slot, std::uint16_t subslot, std::uint16_t index, const Bytes& data,
339 std::uint32_t api = 0);
340
344 std::vector<blocks::WriteMultipleResult> WriteMultiple(const std::vector<WriteItem>& writes);
345
346 // =========================================================================
347 // I&M record convenience methods
348 // =========================================================================
349
354 PNInM0 ReadIm0(std::uint16_t slot = 0, std::uint16_t subslot = 1);
355
360 PNInM1 ReadIm1(std::uint16_t slot = 0, std::uint16_t subslot = 1);
361
366 PNInM2 ReadIm2(std::uint16_t slot = 0, std::uint16_t subslot = 1);
367
372 PNInM3 ReadIm3(std::uint16_t slot = 0, std::uint16_t subslot = 1);
373
378 PNInM4 ReadIm4(std::uint16_t slot = 0, std::uint16_t subslot = 1);
379
384 PNInM5 ReadIm5(std::uint16_t slot = 0, std::uint16_t subslot = 1);
385
390 rpc::AllIM ReadAllIm(std::uint16_t slot = 0, std::uint16_t subslot = 1);
391
399 void WriteIm1(const std::string& tagFunction, const std::string& tagLocation, std::uint16_t slot = 0,
400 std::uint16_t subslot = 1);
401
407 void WriteIm2(const std::string& date, std::uint16_t slot = 0, std::uint16_t subslot = 1);
408
414 void WriteIm3(const std::string& descriptor, std::uint16_t slot = 0, std::uint16_t subslot = 1);
415
416 // =========================================================================
417 // Configuration & diagnosis
418 // =========================================================================
419
423
429 diagnosis::DiagnosisData ReadDiagnosis(std::uint16_t slot = 0, std::uint16_t subslot = 0,
430 std::uint16_t index = 0xF000);
431
434 std::map<std::uint16_t, diagnosis::DiagnosisData> ReadAllDiagnosis();
435
438 std::vector<blocks::SlotInfo> DiscoverSlots();
439
443
444 // =========================================================================
445 // Alarm reading
446 // =========================================================================
447
454 std::optional<AlarmNotification> ReadAlarm(std::uint16_t slot = 0, std::uint16_t subslot = 0,
455 std::uint16_t index = 0x800C);
456
461 void OnAlarm(std::function<void(const AlarmNotification&)> callback);
462
470 void StartAlarmListener();
471
474 void StopAlarmListener();
475
478 [[nodiscard]] bool AlarmListenerRunning() const;
479
480 // =========================================================================
481 // Cyclic IO
482 // =========================================================================
483
494 std::unique_ptr<cyclic::ICyclicController> StartCyclic(const rpc::IOCRSetup& iocrSetup,
495 int maxConsecutiveTimeouts = 3,
496 std::unique_ptr<cyclic::ICyclicController> controller = nullptr);
497
498 // =========================================================================
499 // Utility
500 // =========================================================================
501
506 std::map<std::uint16_t, rpc::IndexProbeResult> EnumerateIndices(std::uint16_t slot = 0,
507 std::uint16_t subslot = 1);
508
511 [[nodiscard]] std::string ToString() const;
512
513 private:
517
536 void ReleaseAr(rpc::IRPCCon& releaseRpc);
537
540
542 std::string interface;
543
546
548 double timeout;
549
551 std::unique_ptr<rpc::IRPCCon> rpc;
552
554 bool connected = false;
555
557 std::unique_ptr<IAlarmListener> alarmListener;
558
560 std::vector<std::function<void(const AlarmNotification&)>> alarmCallbacks;
561
563 asio::io_context ioContext{};
564
567};
568
569// =============================================================================
570// Scan
571// =============================================================================
577{
578 public:
579 virtual ~IDcpScanner() = default;
580
586 virtual dcp::ResponseMap Scan(const std::string& interface, double timeoutSec) = 0;
587};
589class DcpScanner final : public IDcpScanner
590{
591 public:
597 dcp::ResponseMap Scan(const std::string& interface, double timeoutSec) override;
598};
599
607std::vector<ProfinetDevice> Scan(const std::string& interface = "eth0", double timeoutSec = 3.0,
608 std::unique_ptr<IDcpScanner> dcpScanner = nullptr, std::unique_ptr<IMacAddressProvider> macAddressProvider = nullptr);
609
617std::map<std::string, DeviceInfo> ScanDict(const std::string& interface = "eth0", double timeoutSec = 3.0,
618 std::unique_ptr<IDcpScanner> dcpScanner = nullptr, std::unique_ptr<IMacAddressProvider> macAddressProvider = nullptr);
619
620} // namespace profinet::device
Runs an Asio I/O context on a dedicated worker thread.
Declares the PROFINET RTA alarm listener and AlarmAck transmission support.
Declares PROFINET alarm, diagnosis, maintenance, and USI payload types and parsers.
Declares PROFINET IO connection-management block structures and wire serialization.
Keeps an Asio I/O context running on a dedicated worker thread.
Parsed PROFINET device information from a DCP response.
Definition dcp.h:268
std::string name
Station name.
Definition dcp.h:282
std::string mac
Device's MAC address, formatted as a string.
Definition dcp.h:276
std::string ip
IPv4 address, or "0.0.0.0" if unset.
Definition dcp.h:285
Production implementation of IDcpScanner using DCP over Ethernet.
Definition device.h:590
dcp::ResponseMap Scan(const std::string &interface, double timeoutSec) override
Discover PROFINET devices using DCP.
Definition device.cpp:786
Interface for PROFINET DCP device discovery.
Definition device.h:577
virtual ~IDcpScanner()=default
virtual dcp::ResponseMap Scan(const std::string &interface, double timeoutSec)=0
Discover PROFINET devices using DCP.
High-level PROFINET device interface.
Definition device.h:167
std::string ToString() const
Human-readable summary of this device, for logging/debugging.
Definition device.cpp:777
PNInM0 ReadIm0(std::uint16_t slot=0, std::uint16_t subslot=1)
Read I&M0 (mandatory identification data).
Definition device.cpp:556
std::string Mac() const
The device's MAC address.
Definition device.h:275
rpc::AllIM ReadAllIm(std::uint16_t slot=0, std::uint16_t subslot=1)
Read all I&M records the device supports.
Definition device.cpp:580
void ReleaseAr(rpc::IRPCCon &releaseRpc)
Release a PROFINET Application Relationship.
Definition device.cpp:406
blocks::ModuleDiffBlock ReadModuleDiff()
Read and parse the device's ModuleDiffBlock.
Definition device.cpp:639
AsioIoContextRunner ioContextRunner
Keeps the Asio execution context running.
Definition device.h:566
~ProfinetDevice()
Close() the connection and release resources.
Definition device.cpp:255
static ProfinetDevice Discover(const std::string &identifier, const std::string &interface, double timeoutSec=10.0)
Discover a device by station name or MAC address.
Definition device.cpp:260
std::map< std::uint16_t, rpc::IndexProbeResult > EnumerateIndices(std::uint16_t slot=0, std::uint16_t subslot=1)
Probe standard indices and report which are readable/empty/erroring.
Definition device.cpp:771
std::vector< blocks::WriteMultipleResult > WriteMultiple(const std::vector< WriteItem > &writes)
Write multiple records atomically.
Definition device.cpp:544
void Close() noexcept
Stop the alarm listener (if running) and fully close the RPC connection.
Definition device.cpp:373
PNInM5 ReadIm5(std::uint16_t slot=0, std::uint16_t subslot=1)
Read I&M5 (free-text annotation).
Definition device.cpp:576
std::string interface
Network interface name in use.
Definition device.h:542
void StopAlarmListener()
Stop the alarm listener.
Definition device.cpp:728
PNInM4 ReadIm4(std::uint16_t slot=0, std::uint16_t subslot=1)
Read I&M4 (PROFIsafe signature).
Definition device.cpp:572
blocks::PDRealData ReadTopology()
Read the device's physical topology.
Definition device.cpp:660
void StartAlarmListener()
Start the background alarm listener.
Definition device.cpp:693
void WriteIm1(const std::string &tagFunction, const std::string &tagLocation, std::uint16_t slot=0, std::uint16_t subslot=1)
Write I&M1 (tag function + location).
Definition device.cpp:585
std::unique_ptr< IAlarmListener > alarmListener
Background alarm listener, created lazily by StartAlarmListener().
Definition device.h:557
void OnAlarm(std::function< void(const AlarmNotification &)> callback)
Register a callback for alarm notifications.
Definition device.cpp:684
void WriteIm3(const std::string &descriptor, std::uint16_t slot=0, std::uint16_t subslot=1)
Write I&M3 (free-text descriptor).
Definition device.cpp:623
void Write(std::uint16_t slot, std::uint16_t subslot, std::uint16_t index, const Bytes &data, std::uint32_t api=0)
Write a raw record.
Definition device.cpp:537
PNInM2 ReadIm2(std::uint16_t slot=0, std::uint16_t subslot=1)
Read I&M2 (installation date).
Definition device.cpp:564
Bytes ReadImplicit(std::uint16_t slot, std::uint16_t subslot, std::uint16_t index, std::uint32_t api=0)
Read a record using the AR-less Read Implicit service.
Definition device.cpp:512
std::unique_ptr< rpc::IRPCCon > rpc
Underlying RPC connection, created lazily on first use.
Definition device.h:551
bool connected
Whether the AR is currently established.
Definition device.h:554
asio::io_context ioContext
Asio execution context.
Definition device.h:563
ProfinetDevice & operator=(const ProfinetDevice &)=delete
Not copyable (owns an RPC connection and alarm listener).
PNInM1 ReadIm1(std::uint16_t slot=0, std::uint16_t subslot=1)
Read I&M1 (tag function/location).
Definition device.cpp:560
diagnosis::DiagnosisData ReadDiagnosis(std::uint16_t slot=0, std::uint16_t subslot=0, std::uint16_t index=0xF000)
Read and parse diagnosis data at the given location/index.
Definition device.cpp:644
void Connect()
Establish the AR.
Definition device.cpp:340
const std::string & Ip() const
The device's IPv4 address.
Definition device.h:268
ProfinetDevice(const ProfinetDevice &)=delete
Not copyable (owns an RPC connection and alarm listener).
Bytes Read(std::uint16_t slot, std::uint16_t subslot, std::uint16_t index, std::uint32_t api=0)
Read a raw record.
Definition device.cpp:495
void WriteIm2(const std::string &date, std::uint16_t slot=0, std::uint16_t subslot=1)
Write I&M2 (installation date).
Definition device.cpp:607
static ProfinetDevice FromDcpInfo(dcp::DCPDeviceDescription info, const std::string &interface, double timeoutSec=5.0)
Wrap an already-discovered DCPDeviceDescription.
Definition device.cpp:332
std::unique_ptr< cyclic::ICyclicController > StartCyclic(const rpc::IOCRSetup &iocrSetup, int maxConsecutiveTimeouts=3, std::unique_ptr< cyclic::ICyclicController > controller=nullptr)
Establish cyclic IO end-to-end.
Definition device.cpp:743
std::vector< blocks::SlotInfo > DiscoverSlots()
List the device's populated slots.
Definition device.cpp:655
PNInM3 ReadIm3(std::uint16_t slot=0, std::uint16_t subslot=1)
Read I&M3 (free-text descriptor).
Definition device.cpp:568
std::optional< AlarmNotification > ReadAlarm(std::uint16_t slot=0, std::uint16_t subslot=0, std::uint16_t index=0x800C)
Attempt to read an alarm notification at the given location.
Definition device.cpp:665
MacAddress srcMac
This host's MAC address.
Definition device.h:545
static ProfinetDevice FromIp(const std::string &ip, const std::string &interface, double timeoutSec=10.0)
Discover a device by IP address.
Definition device.cpp:303
bool IsConnected() const
Whether the AR is currently established.
Definition device.h:250
void Disconnect()
Gracefully disconnect (sends Release).
Definition device.cpp:365
bool AlarmListenerRunning() const
Whether the alarm listener is currently running.
Definition device.cpp:737
double timeout
Default RPC response timeout in seconds.
Definition device.h:548
std::vector< std::function< void(const AlarmNotification &)> > alarmCallbacks
Callbacks registered via OnAlarm(), applied to alarmListener once started.
Definition device.h:560
rpc::IRPCCon & EnsureConnected()
Return the underlying RPCCon, connecting first if necessary.
Definition device.cpp:430
const std::string & Name() const
The device's station name.
Definition device.h:261
DeviceInfo GetInfo(bool includeTopology=false)
Gather a complete device information summary.
Definition device.cpp:439
dcp::DCPDeviceDescription info
DCP-discovered description of this device.
Definition device.h:539
std::map< std::uint16_t, diagnosis::DiagnosisData > ReadAllDiagnosis()
Read diagnosis from all standard diagnosis indices.
Definition device.cpp:650
Test fixture for ProfinetScanner.
Abstract interface for a PROFINET RPC connection.
Definition IRPCCon.h:81
Declares the PROFINET RTC1 cyclic IO controller and process-data exchange API.
PROFINET DCP discovery and device configuration interface.
PROFINET diagnosis data structures, error decoding, and parsers.
std::map< MacAddress, std::map< BlockKey, std::vector< std::uint8_t > > > ResponseMap
Result of ReadResponse(): MAC address -> parsed (option,suboption) -> payload blocks.
Definition dcp.h:483
bool IsMacAddress(const std::string &identifier)
Whether a string parses as a MAC address.
Definition device.cpp:173
std::vector< ProfinetDevice > Scan(const std::string &interface="eth0", double timeoutSec=3.0, std::unique_ptr< IDcpScanner > dcpScanner=nullptr, std::unique_ptr< IMacAddressProvider > macAddressProvider=nullptr)
Scan the network for PROFINET devices via DCP Identify.
Definition device.cpp:799
std::optional< MacAddress > ParseMac(const std::string &macStr)
Parse a MAC address string in any common separator style.
Definition device.cpp:57
std::map< std::string, DeviceInfo > ScanDict(const std::string &interface="eth0", double timeoutSec=3.0, std::unique_ptr< IDcpScanner > dcpScanner=nullptr, std::unique_ptr< IMacAddressProvider > macAddressProvider=nullptr)
Scan the network and return a name -> DeviceInfo map.
Definition device.cpp:837
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
PROFINET protocol wire-format structures and serialization helpers.
PROFINET DCE/RPC protocol structures and IO-Device connection API.
Declares PROFINET RT_CLASS_1 cyclic frame and IOCR data structures.
Complete parsed AlarmNotification PDU: header fields + parsed items.
Definition alarms.h:356
I&M0: mandatory identification data (vendor, order ID, serial number, revisions).
Definition protocol.h:1517
I&M1: user-assigned tag function and location strings.
Definition protocol.h:1624
I&M2: installation date.
Definition protocol.h:1668
I&M3: free-text descriptor.
Definition protocol.h:1709
I&M4: PROFIsafe signature (binary, not text).
Definition protocol.h:1749
I&M5: free-text annotation.
Definition protocol.h:1789
Parsed ModuleDiffBlock (0x8104).
Definition blocks.h:415
Parsed PDRealData (0xF841) structure.
Definition blocks.h:221
Complete device information summary.
Definition device.h:95
std::uint16_t deviceId
PROFINET device ID (from DCP).
Definition device.h:109
std::string name
Station name (from DCP).
Definition device.h:97
std::string deviceType
Device type string (from DCP).
Definition device.h:112
std::string netmask
IPv4 subnet mask (from DCP).
Definition device.h:115
std::string annotation
Device model, if the EPM endpoint advertised one.
Definition device.h:133
std::string mac
MAC address, formatted as a string (from DCP).
Definition device.h:103
std::string SerialNumber() const
Serial number from I&M0, trimmed.
Definition device.cpp:182
std::vector< std::string > deviceRoles
Decoded device role names (from DCP).
Definition device.h:121
std::string vendorName
Human-readable vendor name (from DCP).
Definition device.h:124
std::optional< PNInM0 > im0
I&M0 identification data, if it was read successfully.
Definition device.h:127
std::string gateway
IPv4 default gateway (from DCP).
Definition device.h:118
std::uint16_t vendorId
PROFINET vendor ID (from DCP).
Definition device.h:106
std::uint16_t HardwareRevision() const
Hardware revision from I&M0.
Definition device.cpp:190
std::string OrderId() const
Order ID from I&M0, trimmed.
Definition device.cpp:186
std::string ip
IPv4 address (from DCP).
Definition device.h:100
std::string SoftwareRevision() const
Software revision string from I&M0.
Definition device.cpp:195
std::optional< blocks::PDRealData > topology
Physical topology, if it was read successfully.
Definition device.h:130
A single write operation for ProfinetDevice::WriteMultiple().
Definition device.h:74
std::uint16_t subslot
Subslot number.
Definition device.h:79
std::uint16_t index
Record data index to write.
Definition device.h:82
std::uint32_t api
API number.
Definition device.h:88
Bytes data
Record data to write.
Definition device.h:85
std::uint16_t slot
Slot number.
Definition device.h:76
Complete diagnosis data for one slot/subslot.
Definition diagnosis.h:275
All I&M records a device supports, read in one call.
Definition rpcTypes.h:451
Configuration for establishing cyclic IO alongside an AR.
Definition rpcTypes.h:149
std::unique_ptr< cyclic::CyclicController > controller
Declares Linux Ethernet, addressing, timing, and utility helpers used by the PROFINET stack.