23 const std::vector<RegisterDataList>* requestedRegisters)
27 std::vector<std::pair<std::uint16_t, std::vector<std::pair<int, int>>>> intervals;
29 for (
const auto& registerList : *requestedRegisters)
32 auto frameIntervals = createFrameIntervals(registerList);
33 intervals.push_back({registerList.slaveIndex, frameIntervals});
36 return createEtherCATFrameList(intervals);
42 std::vector<RegisterDataList>* requestedRegisters)
47 auto getRegisterDataForSlave =
48 [&requestedRegisters](std::uint16_t slaveConfiguredIndex) ->
RegisterDataList&
50 std::uint16_t slaveIndex = 0;
51 for (
int i = 1; i <= ec_slavecount; i++)
53 if (ec_slave[i].configadr == slaveConfiguredIndex)
55 slaveIndex =
static_cast<std::uint16_t
>(i);
60 auto it = std::find_if(requestedRegisters->begin(),
61 requestedRegisters->end(),
63 { return list.slaveIndex == slaveIndex; });
67 using RegisterDataIterator =
68 std::map<datatypes::RegisterEnum, datatypes::RegisterEnumTypeContainer>::iterator;
70 auto copyDataFromPduEntryToRegisterDataContainer =
71 [&](
const std::uint8_t* dataPtr, RegisterDataIterator registerDataEntry)
73 std::uint64_t result = 0;
80 result = (*dataPtr) >> subAddress & ((0x1 << bitlength) - 1);
81 registerDataEntry->second =
86 registerDataEntry->second =
91 registerDataEntry->second =
96 registerDataEntry->second =
105 for (
const auto& [frame, metaData] : frameList->list)
107 const uint8_t* frameData =
reinterpret_cast<const uint8_t*
>(&frame);
108 for (
const auto& pdu : metaData.pdus)
112 std::uint16_t wkc = 0;
113 std::memcpy(&wkc, frameData + pdu.workingCounterOffset,
sizeof(uint16_t));
119 RegisterDataIterator registerDataIt =
data.registerData.begin();
121 bool skipped =
false;
122 for (
const auto& [type, offset] : pdu.registerOffsets)
127 while (registerDataIt->first < type)
137 if (registerDataIt->first == type)
140 copyDataFromPduEntryToRegisterDataContainer(frameData + offset,
149 copyDataFromPduEntryToRegisterDataContainer(frameData + offset,
160 unsigned int updatePeriodInMS,
161 std::vector<datatypes::RegisterEnum> registerList) :
162 updatePeriodInMS(updatePeriodInMS)
164 for (std::uint16_t i = 1; i < slaveCount + 1; i++)
168 for (
const auto& type : registerList)
172 registerData.push_back(list);
177 errorRegisterUpdateThread = std::thread(&SlaveRegisterReadingScheduler::updateLoop,
this);
182 errorRegisterUpdateThreadRunning.store(
false);
183 errorRegisterUpdateThread.join();
186 const std::vector<RegisterDataList>&
195 if (readyToReadNextRegisters.load(std::memory_order_relaxed))
197 cv_readNextRegisters.notify_all();
204 return areAllRegistersUpdated.load(std::memory_order_relaxed);
208 SlaveRegisterReadingScheduler::updateLoop()
211 while (errorRegisterUpdateThreadRunning.load() ==
true)
213 std::unique_lock<std::mutex> lock{mutex_readNextRegisters};
214 cv_readNextRegisters.wait(lock);
215 readyToReadNextRegisters.store(
false, std::memory_order_relaxed);
223 frameList, ®isterData);
224 areAllRegistersUpdated.store(
true, std::memory_order_relaxed);
228 areAllRegistersUpdated.store(
false, std::memory_order_relaxed);
234 c.waitForCycleDuration();
237 readyToReadNextRegisters.store(
true, std::memory_order_relaxed);
242 SlaveRegisterReadingScheduler::registerReadMapToAddressList(
const RegisterDataList& toRead)
244 std::vector<int> addressesToRead;
245 for (
const auto& [registerType, _] : toRead.registerData)
249 static constexpr int addressMask = 0xFFFF;
250 static constexpr float byteLength = 8.0;
252 int baseAddress =
static_cast<int>(registerType) & addressMask;
258 addressesToRead.push_back(baseAddress + i);
261 std::sort(addressesToRead.begin(), addressesToRead.end());
263 addressesToRead.erase(std::unique(addressesToRead.begin(), addressesToRead.end()),
264 addressesToRead.end());
266 return addressesToRead;
269 std::vector<std::pair<int, int>>
270 SlaveRegisterReadingScheduler::createFrameIntervals(
const RegisterDataList& toRead)
272 if (toRead.registerData.empty())
277 std::vector<int> addressesToRead(registerReadMapToAddressList(toRead));
279 std::vector<std::pair<int, int>> pduIntervals;
280 int currentIntervalStart = -1;
281 int currentIntervalEnd = 0;
283 for (
int address : addressesToRead)
287 if (currentIntervalStart >= 0 && address - currentIntervalEnd - 1 < pduOverhead &&
288 address + 1 - currentIntervalStart + pduOverhead <
289 static_cast<int>(maxTotalPDULength))
291 currentIntervalEnd = address + 1;
295 if (currentIntervalStart >= 0)
297 pduIntervals.push_back({currentIntervalStart, currentIntervalEnd});
299 currentIntervalStart = address;
300 currentIntervalEnd = address + 1;
303 pduIntervals.push_back({currentIntervalStart, currentIntervalEnd});
308 SlaveRegisterReadingScheduler::createPDUMetaData(std::tuple<uint16_t, int, int> pduInterval,
313 size_t dataLength = std::get<2>(pduInterval) - std::get<1>(pduInterval);
314 result.workingCounterOffset = pduOffset +
sizeof(EtherCATPDU) - 1 + dataLength;
318 for (
int address = std::get<1>(pduInterval); address < std::get<2>(pduInterval); ++address)
323 result.registerOffsets[addressAsEnum] =
324 address - std::get<1>(pduInterval) +
sizeof(EtherCATPDU) - 1 + pduOffset;
330 std::pair<EtherCATFrame, EtherCATFrameMetaData>
331 SlaveRegisterReadingScheduler::createEtherCATFrame(
332 std::vector<std::tuple<uint16_t, int, int>> slaveAssignedPDUIntervals)
334 EtherCATFrame frame{};
335 EtherCATFrameMetaData metaData{};
338 uint8_t* currentLocation =
static_cast<uint8_t*
>(frame.pduArea);
339 for (
auto it = slaveAssignedPDUIntervals.begin(); it != slaveAssignedPDUIntervals.end();
342 uint16_t dataLength = std::get<2>(*it) - std::get<1>(*it);
343 if (currentLocation + dataLength + pduOverhead
344 >=
static_cast<uint8_t*
>(frame.pduArea + maxTotalPDULength))
346 throw std::length_error(
347 "Total PDU length exceeded maximum EtherCAT frame capacity.");
350 EtherCATPDU* pdu =
new (currentLocation) EtherCATPDU;
352 pdu->slaveConfiguredAddress = std::get<0>(*it);
353 pdu->registerAddress = std::get<1>(*it);
355 if (it + 1 != slaveAssignedPDUIntervals.end())
357 static constexpr uint16_t hasNextPDU = 1 << 15;
358 pdu->dataLengthAndNext = dataLength | hasNextPDU;
362 pdu->dataLengthAndNext = dataLength;
365 metaData.pdus.push_back(createPDUMetaData(
366 *it, currentLocation -
reinterpret_cast<uint8_t*
>(&frame)));
368 currentLocation +=
sizeof(EtherCATPDU) - 1 + dataLength +
sizeof(uint16_t);
370 uint16_t frameLength =
371 currentLocation -
static_cast<uint8_t*
>(frame.pduArea) +
sizeof(uint16_t);
372 metaData.lengthOfFrame = frameLength;
374 static constexpr uint16_t frameTypePDUs = 0x1000;
375 frame.lengthAndType = (frameLength - 2) | frameTypePDUs;
377 return {frame, metaData};
381 SlaveRegisterReadingScheduler::createEtherCATFrameList(
382 const std::vector<std::pair<std::uint16_t, std::vector<std::pair<int, int>>>>& pduIntervals)
386 std::vector<std::tuple<std::uint16_t, int, int>> slaveAssignedPDUIntervals;
387 for (
const auto& [slaveIndex, intervals] : pduIntervals)
390 for (
const std::pair<int, int>&
interval : intervals)
392 slaveAssignedPDUIntervals.push_back(
398 EtherCATFrameList* frameList =
new EtherCATFrameList();
399 int frameTotalSize = 0;
400 std::vector<std::tuple<uint16_t, int, int>> nextFrameIntervals;
403 for (
const auto&
interval : slaveAssignedPDUIntervals)
406 if (frameTotalSize + nextIntervalLength + pduOverhead <
407 static_cast<int>(maxTotalPDULength))
409 nextFrameIntervals.push_back(
interval);
410 frameTotalSize += nextIntervalLength + pduOverhead;
414 frameList->list.push_back(createEtherCATFrame(nextFrameIntervals));
415 nextFrameIntervals.clear();
419 frameList->list.push_back(createEtherCATFrame(nextFrameIntervals));
uint16_t slaveConfiguredAddress
This util class helps with keeping a cycle time during a control cycle.
bool readRegisters(std::vector< RegisterDataList > ®isterData)
static Bus & getBus()
This returns the one and only Bus object.
SlaveRegisterReadingScheduler(std::uint16_t slaveCount, unsigned int updatePeriodInMS, std::vector< datatypes::RegisterEnum > registerList)
const std::vector< RegisterDataList > & getRegisterData()
static void updateRegisterDataFromEtherCATFrameList(const EtherCATFrameList *frameList, std::vector< RegisterDataList > *requestedRegisters)
~SlaveRegisterReadingScheduler()
void startReadingNextRegisters()
static EtherCATFrameList * createEtherCATFrameListFromRegisterDataList(const std::vector< RegisterDataList > *requestedRegisters)
bool allRegistersUpdated() const
#define ARMARX_CHECK_LESS_EQUAL(lhs, rhs)
This macro evaluates whether lhs is less or equal (<=) rhs and if it turns out to be false it will th...
#define ARMARX_CHECK_NOT_NULL(ptr)
This macro evaluates whether ptr is not null and if it turns out to be false it will throw an Express...
RegisterEnum
The RegisterEnum enum encodes the slave registers that every slave offers.
std::uint32_t getRegisterAddress(RegisterEnum e)
std::variant< EtherCATDataType::INTEGER8, EtherCATDataType::INTEGER16, EtherCATDataType::INTEGER32, EtherCATDataType::INTEGER64, EtherCATDataType::UNSIGNED8, EtherCATDataType::UNSIGNED16, EtherCATDataType::UNSIGNED32, EtherCATDataType::UNSIGNED64 > RegisterEnumTypeContainer
std::uint8_t getRegisterSubAddress(RegisterEnum e)
const std::unordered_map< RegisterEnum, RegisterInfo > registerMap
Holds additional information on all defined registers.
std::size_t getRegisterByteLength(datatypes::RegisterEnum reg)
Get the length of a register in bytes, rounded up.
Interval< T > interval(T lo, T hi)
constexpr std::size_t find(string_view str, char_type c) noexcept
The EtherCATFrameList struct holds a list of EtherCAT frames that can be scheduled in round-robin-sty...
std::vector< std::pair< EtherCATFrame, EtherCATFrameMetaData > > list
Brief description of struct RegisterDataList.
std::map< datatypes::RegisterEnum, datatypes::RegisterEnumTypeContainer > registerData