122 lines
4.2 KiB
C++
122 lines
4.2 KiB
C++
// SPDX-License-Identifier: MIT
|
|
/**
|
|
Copyright (c) 2021 - 2022 Beckhoff Automation GmbH & Co. KG
|
|
*/
|
|
|
|
#include "RTimeAccess.h"
|
|
#include "AdsLib.h"
|
|
#include "Log.h"
|
|
#include <iostream>
|
|
#include <limits>
|
|
|
|
namespace Beckhoff
|
|
{
|
|
namespace Ads
|
|
{
|
|
static std::ostream& operator<<(std::ostream& os, const RTimeCpuLatency& info)
|
|
{
|
|
return os << std::dec << info.current << " " << info.maximum << " " << info.limit;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& os, const RTimeCpuSettings& info)
|
|
{
|
|
return os << std::dec <<
|
|
"nWinCPUs: " << info.nWinCPUs << '\n' <<
|
|
"nNonWinCPUs: " << info.nNonWinCPUs << '\n' <<
|
|
"dwAffinityMask: 0x" << std::hex << info.affinityMask << '\n' <<
|
|
"nRtCpus: " << std::dec << info.nRtCpus << '\n' <<
|
|
"nCpuType: 0x" << std::hex << info.nCpuType << '\n' <<
|
|
"nCpuFamily: 0x" << info.nCpuFamily << '\n' <<
|
|
"nCpuFreq: " << std::dec << info.nCpuFreq << '\n'
|
|
;
|
|
}
|
|
|
|
RTimeAccess::RTimeAccess(const std::string& gw, const AmsNetId netid, const uint16_t port)
|
|
: device(gw, netid, port ? port : 200)
|
|
{}
|
|
|
|
RTimeCpuSettings RTimeAccess::ReadCpuSettings() const
|
|
{
|
|
struct RTimeCpuSettings settings;
|
|
uint32_t bytesRead;
|
|
|
|
const auto status = device.ReadReqEx2(ADSSRVID_READDEVICEINFO,
|
|
RTIME_CPU_SETTINGS,
|
|
sizeof(settings),
|
|
&settings,
|
|
&bytesRead);
|
|
if (ADSERR_NOERR != status) {
|
|
LOG_ERROR(__FUNCTION__ << "(): failed with: 0x" << std::hex << status << '\n');
|
|
throw AdsException(status);
|
|
}
|
|
return settings;
|
|
}
|
|
|
|
long RTimeAccess::SetSharedCores(const uint32_t sharedCores) const
|
|
{
|
|
const auto oldSettings = ReadCpuSettings();
|
|
|
|
if (sharedCores == std::numeric_limits<uint32_t>::max()) {
|
|
// 0xffffffff means RESET -> no isolated cores, all shared.
|
|
if (0 == oldSettings.nNonWinCPUs) {
|
|
std::cout << "Requested shared core configuration already active, no change applied.\n";
|
|
return ADSERR_DEVICE_EXISTS;
|
|
}
|
|
} else {
|
|
// All other values mean limit the number of shared cores -> use remaining cores as isolated.
|
|
if (sharedCores == oldSettings.nWinCPUs) {
|
|
std::cout << "Requested shared core configuration already active, no change applied.\n";
|
|
return ADSERR_DEVICE_EXISTS;
|
|
}
|
|
}
|
|
// We have to apply changes to the current core configuration. For this we
|
|
// have to talk to a different AdsDevice, the system service. Now, it is handy
|
|
// that ADS doesn't really implement "connections" so we can just use the AMS
|
|
// port of our RTimeAccess object, but adust the target AmsPort.
|
|
const AmsAddr systemService { device.m_Addr.netId, 10000 };
|
|
return AdsSyncWriteReqEx(device.GetLocalPort(),
|
|
&systemService,
|
|
SYSTEMSERVICE_SETNUMPROC,
|
|
0,
|
|
sizeof(sharedCores),
|
|
&sharedCores);
|
|
}
|
|
|
|
long RTimeAccess::ShowLatency(const uint32_t indexOffset, const uint32_t cpuId) const
|
|
{
|
|
struct RTimeCpuLatency info;
|
|
uint32_t bytesRead;
|
|
|
|
const auto status = device.ReadWriteReqEx2(
|
|
ADSSRVID_READDEVICEINFO,
|
|
indexOffset,
|
|
sizeof(info), &info,
|
|
sizeof(cpuId), &cpuId,
|
|
&bytesRead
|
|
);
|
|
|
|
if (ADSERR_NOERR != status) {
|
|
LOG_ERROR(__FUNCTION__ << "(" << std::dec << cpuId << "): failed with: 0x" << std::hex << status << '\n');
|
|
return status;
|
|
}
|
|
std::cout << std::dec << cpuId << ": " << info << '\n';
|
|
return 0;
|
|
}
|
|
|
|
long RTimeAccess::ShowLatency(const uint32_t indexOffset) const
|
|
{
|
|
const auto info = ReadCpuSettings();
|
|
|
|
std::cout << "RTimeCpuSettings:\n" << info;
|
|
for (uint8_t cpuId = 0; cpuId < 8 * sizeof(info.affinityMask); ++cpuId) {
|
|
static_assert((8 * sizeof(info.affinityMask) < std::numeric_limits<decltype(cpuId)>::max()),
|
|
"cpuId is to small for affinityMask");
|
|
if (info.affinityMask & (1ULL << cpuId)) {
|
|
ShowLatency(indexOffset, cpuId);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
}
|