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,
312 result.slaveConfiguredAddress = std::get<0>(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));