EtherCATFrame.h
Go to the documentation of this file.
1#pragma once
3/*!
4 * Copied from https://gitlab.com/h2t/student-projects/pse-ws2021/etherkitten/-/tree/master/reader/src/etherkitten/reader
5 *
6 * !!!
7 * Needs correct license message!!!!
8 * !!!
9 */
11#include <array>
12#include <cstdint>
13#include <unordered_map>
14#include <utility>
15#include <vector>
16
17#include "SlaveRegisters.h"
18
20{
21 /*!
22 * \brief The maximum length of an Ethernet frame as defined by the standard.
23 */
24 static constexpr size_t ethernetFrameMaxLength = 1518;
25
26 /*!
27 * \brief The size of an Ethernet frame header as defined by the standard.
28 */
29 static constexpr size_t ethernetHeaderSize = 14;
30
31 /*!
32 * \brief The maximum space that a series of PDUs is allowed to have in an EtherCAT frame.
33 *
34 * (Max. length of eth.) - (eth. header size) - (ecat header size) - (CRC checksum size)
35 */
36 static constexpr size_t maxTotalPDULength =
37 ethernetFrameMaxLength - ethernetHeaderSize - sizeof(uint16_t) - sizeof(uint32_t);
38
39 /*!
40 * \brief The EtherCATFrame struct represents an EtherCAT frame according to the EtherCAT spec.
41 *
42 * See the EtherCAT standard, part 4, page 30
43 */
45 {
46 uint16_t lengthAndType{};
47 uint8_t pduArea[maxTotalPDULength]{}; // NOLINT
48 };
49
50 static constexpr uint8_t fprdCommandType = 0x04; /*!< The type specifier for an FPRD PDU */
51
52 /*!
53 * \brief This is a placeholder index - SOEM uses the index field of the first PDU to sort
54 * frames, so we have to set this in the SOEM-interacting code where we know which index we
55 * need.
56 */
57 static constexpr uint8_t invalidIndex = 0xff;
58
59 /*!
60 * \brief The EtherCATPDU struct represents an EtherCAT PDU according to the EtherCAT spec.
61 *
62 * See the EtherCAT standard, part 4, page 32 (we only use FPRD PDUs here)
63 */
65 {
66 uint8_t commandType = fprdCommandType;
67 uint8_t index = invalidIndex;
69 uint16_t registerAddress = 0;
70 uint16_t dataLengthAndNext = 0;
71 uint16_t externalEvent = 0;
72
73 /* This is a workaround since C++ doesn't have flexible array members like C.
74 * EtherCATPDUs are only ever placement-constructed inside an EtherCATFrame,
75 * so this doesn't create problems with memory allocation. */
76 uint8_t data[1] = {0}; // NOLINT
77 } __attribute__((packed));
78
79 /*!
80 * \brief The overhead that a PDU has = its size without the data section.
81 *
82 * We use this to decide where to set PDU boundaries to save space in an EtherCAT frame.
83 *
84 * (Size of the PDU struct) - (That annoying workaround byte) + (The working counter at the end)
85 */
86 static constexpr int pduOverhead = sizeof(EtherCATPDU) - sizeof(uint8_t) + sizeof(uint16_t);
87
88 /*!
89 * \brief The PDUMetaData struct holds information about the structure of a PDU.
90 *
91 * We need this if we don't want to reparse the frames once we receive to get the data out.
92 */
94 {
96
97 /*!
98 * \brief The offsets of the registers that are written into this PDU by the slave
99 * relative to the start of the EtherCAT frame.
100 */
101 std::map<datatypes::RegisterEnum, size_t> registerOffsets;
102
103 /*!
104 * \brief The offset of the working counter for this PDU relative to the start of
105 * the EtherCAT frame.
106 */
108 };
109
110 /*!
111 * \brief The EtherCATFrameMetaData struct holds information about the structure of an
112 * EtherCAT frame.
113 */
115 {
117 std::vector<PDUMetaData> pdus;
118 };
119
120 /*!
121 * \brief The EtherCATFrameList struct holds a list of EtherCAT frames that can be
122 * scheduled in round-robin-style.
123 */
125 {
126 size_t nextIndex = 0; /*!< The next frame in the RR scheduler */
127 std::vector<std::pair<EtherCATFrame, EtherCATFrameMetaData>> list;
128 };
129
130 /*!
131 * \brief The EtherCATFrameIterator class iterates over a set range of EtherCAT frames
132 * once.
133 */
135 {
136 public:
137 /*!
138 * \brief Construct a new EtherCATFrameIterator that iterates over the given
139 * range of EtherCAT frames.
140 *
141 * If `startIndex + count > list->list.size()`, the iterator will wrap around
142 * to the start fo the list.
143 * \param list the list to iterate over
144 * \param startIndex the index to start iterating on
145 * \param count the number of frames to iterate over (including the first)
146 */
147 EtherCATFrameIterator(EtherCATFrameList* list, size_t startIndex, size_t count);
148
149 /*!
150 * \brief Get the EtherCAT frame this iterator is on with metadata.
151 * \return an EtherCATFrame along with its metadata
152 */
153 std::pair<EtherCATFrame*, EtherCATFrameMetaData*> operator*() const;
154
155 /*!
156 * \brief Check if this iterator points to the first available register frame.
157 *
158 * This indicates that all registers have been read by sequential iterators.
159 * \retval true iff this iterator points to the first register frame
160 * \retval false iff this iterator does not point to the first register frame
161 * \exception
162 */
163 bool hasCompletedLoop() const;
164
165 /*!
166 * \brief Move this iterator to the next EtherCAT frame.
167 *
168 * Does nothing if this iterator is at the end of its range.
169 * \return a reference to this iterator
170 */
172
173 /*!
174 * \brief Check if this iterator has stepped over its range.
175 * \retval true iff this iterator can no longer be dereferenced or advanced
176 * \retval false iff this iterator can still be dereferenced and advanced
177 */
178 bool atEnd() const;
179
180 size_t getCurrentIndex() const;
181
182 private:
183 EtherCATFrameList* list;
184 size_t nextIndex;
185 size_t remaining;
186 };
187
188} // namespace armarx::control::ethercat
EtherCATFrameIterator & operator++()
Move this iterator to the next EtherCAT frame.
bool atEnd() const
Check if this iterator has stepped over its range.
bool hasCompletedLoop() const
Check if this iterator points to the first available register frame.
EtherCATFrameIterator(EtherCATFrameList *list, size_t startIndex, size_t count)
Construct a new EtherCATFrameIterator that iterates over the given range of EtherCAT frames.
std::pair< EtherCATFrame *, EtherCATFrameMetaData * > operator*() const
Get the EtherCAT frame this iterator is on with metadata.
struct armarx::control::ethercat::PDUMetaData __attribute__
The EtherCATFrameList struct holds a list of EtherCAT frames that can be scheduled in round-robin-sty...
std::vector< std::pair< EtherCATFrame, EtherCATFrameMetaData > > list
The EtherCATFrameMetaData struct holds information about the structure of an EtherCAT frame.
The EtherCATFrame struct represents an EtherCAT frame according to the EtherCAT spec.
uint8_t pduArea[maxTotalPDULength]
The EtherCATPDU struct represents an EtherCAT PDU according to the EtherCAT spec.
The PDUMetaData struct holds information about the structure of a PDU.
size_t workingCounterOffset
The offset of the working counter for this PDU relative to the start of the EtherCAT frame.
std::map< datatypes::RegisterEnum, size_t > registerOffsets
The offsets of the registers that are written into this PDU by the slave relative to the start of the...