21 const std::vector<RegisterDataList>* requestedRegisters)
25 std::vector<std::pair<std::uint16_t, std::vector<std::pair<int, int>>>> intervals;
27 for (
const auto& registerList : *requestedRegisters)
30 auto frameIntervals = createFrameIntervals(registerList);
31 intervals.push_back({registerList.slaveIndex, frameIntervals});
34 return createEtherCATFrameList(intervals);
40 std::vector<RegisterDataList>* requestedRegisters)
45 auto getRegisterDataForSlave =
46 [&requestedRegisters](std::uint16_t slaveConfiguredIndex) ->
RegisterDataList&
48 std::uint16_t slaveIndex = 0;
49 for (
int i = 1; i <= ec_slavecount; i++)
51 if (ec_slave[i].configadr == slaveConfiguredIndex)
53 slaveIndex =
static_cast<std::uint16_t
>(i);
58 auto it = std::find_if(requestedRegisters->begin(),
59 requestedRegisters->end(),
61 { return list.slaveIndex == slaveIndex; });
65 using RegisterDataIterator =
66 std::map<datatypes::RegisterEnum, datatypes::RegisterEnumTypeContainer>::iterator;
68 auto copyDataFromPduEntryToRegisterDataContainer =
69 [&](
const std::uint8_t* dataPtr, RegisterDataIterator registerDataEntry)
71 std::uint64_t result = 0;
78 result = (*dataPtr) >> subAddress & ((0x1 << bitlength) - 1);
79 registerDataEntry->second =
84 registerDataEntry->second =
89 registerDataEntry->second =
94 registerDataEntry->second =
103 for (
const auto& [frame, metaData] : frameList->
list)
105 const uint8_t* frameData =
reinterpret_cast<const uint8_t*
>(&frame);
106 for (
const auto& pdu : metaData.pdus)
110 std::uint16_t wkc = 0;
111 std::memcpy(&wkc, frameData + pdu.workingCounterOffset,
sizeof(uint16_t));
117 RegisterDataIterator registerDataIt =
data.registerData.begin();
119 bool skipped =
false;
120 for (
const auto& [type, offset] : pdu.registerOffsets)
125 while (registerDataIt->first < type)
135 if (registerDataIt->first == type)
138 copyDataFromPduEntryToRegisterDataContainer(frameData + offset,
147 copyDataFromPduEntryToRegisterDataContainer(frameData + offset,
159 unsigned int updatePeriodInMS,
160 std::vector<datatypes::RegisterEnum> registerList) :
161 updatePeriodInMS(updatePeriodInMS)
163 for (std::uint16_t i = 1; i < slaveCount + 1; i++)
167 for (
const auto& type : registerList)
171 registerData.push_back(
list);
176 errorRegisterUpdateThread = std::thread(&SlaveRegisterReadingScheduler::updateLoop,
this);
181 errorRegisterUpdateThreadRunning.store(
false);
182 errorRegisterUpdateThread.join();
185 const std::vector<RegisterDataList>&
194 if (readyToReadNextRegisters.load(std::memory_order_relaxed))
196 cv_readNextRegisters.notify_all();
203 return areAllRegistersUpdated.load(std::memory_order_relaxed);
207 SlaveRegisterReadingScheduler::updateLoop()
210 while (errorRegisterUpdateThreadRunning.load() ==
true)
212 std::unique_lock<std::mutex> lock{mutex_readNextRegisters};
213 cv_readNextRegisters.wait(lock);
214 readyToReadNextRegisters.store(
false, std::memory_order_relaxed);
222 frameList, ®isterData);
223 areAllRegistersUpdated.store(
true, std::memory_order_relaxed);
227 areAllRegistersUpdated.store(
false, std::memory_order_relaxed);
233 c.waitForCycleDuration();
236 readyToReadNextRegisters.store(
true, std::memory_order_relaxed);
241 SlaveRegisterReadingScheduler::registerReadMapToAddressList(
const RegisterDataList& toRead)
243 std::vector<int> addressesToRead;
244 for (
const auto& [registerType, _] : toRead.registerData)
248 static constexpr
int addressMask = 0xFFFF;
249 static constexpr
float byteLength = 8.0;
251 int baseAddress =
static_cast<int>(registerType) & addressMask;
257 addressesToRead.push_back(baseAddress + i);
260 std::sort(addressesToRead.begin(), addressesToRead.end());
262 addressesToRead.erase(std::unique(addressesToRead.begin(), addressesToRead.end()),
263 addressesToRead.end());
265 return addressesToRead;
268 std::vector<std::pair<int, int>>
269 SlaveRegisterReadingScheduler::createFrameIntervals(
const RegisterDataList& toRead)
271 if (toRead.registerData.empty())
276 std::vector<int> addressesToRead(registerReadMapToAddressList(toRead));
278 std::vector<std::pair<int, int>> pduIntervals;
279 int currentIntervalStart = -1;
280 int currentIntervalEnd = 0;
282 for (
int address : addressesToRead)
286 if (currentIntervalStart >= 0 && address - currentIntervalEnd - 1 < pduOverhead &&
287 address + 1 - currentIntervalStart + pduOverhead <
288 static_cast<int>(maxTotalPDULength))
290 currentIntervalEnd = address + 1;
294 if (currentIntervalStart >= 0)
296 pduIntervals.push_back({currentIntervalStart, currentIntervalEnd});
298 currentIntervalStart = address;
299 currentIntervalEnd = address + 1;
302 pduIntervals.push_back({currentIntervalStart, currentIntervalEnd});
307 SlaveRegisterReadingScheduler::createPDUMetaData(std::tuple<uint16_t, int, int> pduInterval,
311 result.slaveConfiguredAddress = std::get<0>(pduInterval);
312 size_t dataLength = std::get<2>(pduInterval) - std::get<1>(pduInterval);
313 result.workingCounterOffset = pduOffset +
sizeof(EtherCATPDU) - 1 + dataLength;
317 for (
int address = std::get<1>(pduInterval); address < std::get<2>(pduInterval); ++address)
322 result.registerOffsets[addressAsEnum] =
323 address - std::get<1>(pduInterval) +
sizeof(EtherCATPDU) - 1 + pduOffset;
329 std::pair<EtherCATFrame, EtherCATFrameMetaData>
330 SlaveRegisterReadingScheduler::createEtherCATFrame(
331 std::vector<std::tuple<uint16_t, int, int>> slaveAssignedPDUIntervals)
333 EtherCATFrame frame{};
334 EtherCATFrameMetaData metaData{};
337 uint8_t* currentLocation =
static_cast<uint8_t*
>(frame.pduArea);
338 for (
auto it = slaveAssignedPDUIntervals.begin(); it != slaveAssignedPDUIntervals.end();
341 uint16_t dataLength = std::get<2>(*it) - std::get<1>(*it);
342 if (currentLocation + dataLength + pduOverhead
343 >=
static_cast<uint8_t*
>(frame.pduArea + maxTotalPDULength))
345 throw std::length_error(
346 "Total PDU length exceeded maximum EtherCAT frame capacity.");
349 EtherCATPDU* pdu =
new (currentLocation) EtherCATPDU;
351 pdu->slaveConfiguredAddress = std::get<0>(*it);
352 pdu->registerAddress = std::get<1>(*it);
354 if (it + 1 != slaveAssignedPDUIntervals.end())
356 static constexpr uint16_t hasNextPDU = 1 << 15;
357 pdu->dataLengthAndNext = dataLength | hasNextPDU;
361 pdu->dataLengthAndNext = dataLength;
364 metaData.pdus.push_back(createPDUMetaData(
365 *it, currentLocation -
reinterpret_cast<uint8_t*
>(&frame)));
367 currentLocation +=
sizeof(EtherCATPDU) - 1 + dataLength +
sizeof(uint16_t);
369 uint16_t frameLength =
370 currentLocation -
static_cast<uint8_t*
>(frame.pduArea) +
sizeof(uint16_t);
371 metaData.lengthOfFrame = frameLength;
373 static constexpr uint16_t frameTypePDUs = 0x1000;
374 frame.lengthAndType = (frameLength - 2) | frameTypePDUs;
376 return {frame, metaData};
380 SlaveRegisterReadingScheduler::createEtherCATFrameList(
381 const std::vector<std::pair<std::uint16_t, std::vector<std::pair<int, int>>>>& pduIntervals)
385 std::vector<std::tuple<std::uint16_t, int, int>> slaveAssignedPDUIntervals;
386 for (
const auto& [slaveIndex, intervals] : pduIntervals)
389 for (
const std::pair<int, int>&
interval : intervals)
391 slaveAssignedPDUIntervals.push_back(
397 EtherCATFrameList* frameList =
new EtherCATFrameList();
398 int frameTotalSize = 0;
399 std::vector<std::tuple<uint16_t, int, int>> nextFrameIntervals;
402 for (
const auto&
interval : slaveAssignedPDUIntervals)
405 if (frameTotalSize + nextIntervalLength + pduOverhead <
406 static_cast<int>(maxTotalPDULength))
408 nextFrameIntervals.push_back(
interval);
409 frameTotalSize += nextIntervalLength + pduOverhead;
413 frameList->list.push_back(createEtherCATFrame(nextFrameIntervals));
414 nextFrameIntervals.clear();
418 frameList->list.push_back(createEtherCATFrame(nextFrameIntervals));