1376 lines
58 KiB
C++
1376 lines
58 KiB
C++
#include "terminal_api_driver.h"
|
||
|
||
#include <cmath>
|
||
#include "terminal_api/ControlProtoCInterface.h"
|
||
#include <sstream>
|
||
#include <iomanip>
|
||
#include <shared_mutex>
|
||
#include <boost/thread.hpp>
|
||
#include <boost/log/trivial.hpp>
|
||
#include <boost/property_tree/json_parser.hpp>
|
||
#include <sys/sysinfo.h>
|
||
|
||
#define TIME_NOW() std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count()
|
||
|
||
typedef boost::property_tree::ptree::path_type json_path;
|
||
|
||
static constexpr const char* DEFAULT_QOS_CLASSES = R"({"rt1":[],"rt2":[],"rt3":[],"cd":[]})";
|
||
|
||
// static int calculateSubnetMask(const std::string& subnet_mask) {
|
||
// int mask = 0;
|
||
// std::istringstream iss(subnet_mask);
|
||
// std::string octet;
|
||
// while (std::getline(iss, octet, '.')) {
|
||
// int octet_value = std::stoi(octet);
|
||
// for (int i = 7; i >= 0; i--) {
|
||
// if (octet_value & (1 << i)) {
|
||
// mask++;
|
||
// }
|
||
// }
|
||
// }
|
||
// return mask;
|
||
// }
|
||
|
||
/**
|
||
* Преобразует строку вида `1.2.3.4/24` в пару строк вида `1.2.3.4` `255.255.255.0`
|
||
*/
|
||
// std::pair<std::string, std::string> splitIpAndMask(const std::string& input) {
|
||
// auto pos = input.find('/');
|
||
// if (pos == std::string::npos) {
|
||
// // Обработка ошибки: нет символа '/'
|
||
// throw std::runtime_error("address not contains mask");
|
||
// }
|
||
// std::string ip = input.substr(0, pos);
|
||
// const unsigned int mask_int = std::stoul(input.substr(pos + 1));
|
||
//
|
||
// if (mask_int > 32) {
|
||
// throw std::runtime_error("invalid mask");
|
||
// }
|
||
//
|
||
// std::string mask_binary = std::string(mask_int, '1') + std::string(32 - mask_int, '0');
|
||
// std::string mask_str;
|
||
//
|
||
// for (unsigned int i = 0; i < 4; ++i) {
|
||
// std::string octet = mask_binary.substr(i * 8u, 8);
|
||
// int octet_value = std::stoi(octet, nullptr, 2);
|
||
// mask_str += std::to_string(octet_value) + (i < 3 ? "." : "");
|
||
// }
|
||
//
|
||
// return std::make_pair(ip, mask_str);
|
||
// }
|
||
|
||
static inline void rtrim(std::string &s) {
|
||
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
|
||
return !std::isspace(ch);
|
||
}).base(), s.end());
|
||
}
|
||
static const char* boolAsStr(bool value) {
|
||
return value ? "true" : "false";
|
||
}
|
||
|
||
class TerminalNetworkSettings {
|
||
public:
|
||
std::string managementIp, managementGateway, dataIp, serverName;
|
||
bool isL2 = true;
|
||
unsigned int dataMtu = 1500;
|
||
|
||
#ifdef MODEM_IS_SCPC
|
||
static constexpr const char* DEFAULT_SERVER_NAME = "RCSM-101";
|
||
#endif
|
||
#ifdef MODEM_IS_TDMA
|
||
static constexpr const char* DEFAULT_SERVER_NAME = "RCSM-101 TDMA";
|
||
#endif
|
||
|
||
TerminalNetworkSettings() = default;
|
||
TerminalNetworkSettings(const TerminalNetworkSettings& src) = default;
|
||
~TerminalNetworkSettings() = default;
|
||
|
||
TerminalNetworkSettings& operator= (const TerminalNetworkSettings& src) = default;
|
||
|
||
void loadDefaults() {
|
||
managementIp = "0.0.0.0";
|
||
managementGateway = "";
|
||
isL2 = true;
|
||
dataIp = "0.0.0.0";
|
||
dataMtu = 1500;
|
||
serverName = DEFAULT_SERVER_NAME;
|
||
}
|
||
};
|
||
|
||
class TerminalFirmwareVersion {
|
||
public:
|
||
std::string version, modemId, modemSn, macMang, macData;
|
||
|
||
TerminalFirmwareVersion() = default;
|
||
TerminalFirmwareVersion(const TerminalFirmwareVersion& src) = default;
|
||
~TerminalFirmwareVersion() = default;
|
||
|
||
TerminalFirmwareVersion& operator= (const TerminalFirmwareVersion& src) = default;
|
||
};
|
||
|
||
static std::ostream& operator<<(std::ostream& out, CP_Result result) {
|
||
switch (result) {
|
||
case OK: out << "OK"; break;
|
||
case TIMEOUT: out << "TIMEOUT"; break;
|
||
case ERROR: out << "ERROR"; break;
|
||
case ABORT: out << "ABORT"; break;
|
||
case BUSY: out << "BUSY"; break;
|
||
default:
|
||
out << static_cast<int>(result);
|
||
}
|
||
return out;
|
||
}
|
||
|
||
std::string makeTimepointFromMillis(int64_t unix_time_ms) {
|
||
// Преобразуем миллисекунды в микросекунды для std::chrono
|
||
auto time_point = std::chrono::time_point<std::chrono::system_clock,
|
||
std::chrono::microseconds>(std::chrono::microseconds(unix_time_ms * 1000));
|
||
|
||
auto tp = std::chrono::system_clock::to_time_t(time_point);
|
||
tm* t = std::localtime(&tp);
|
||
|
||
std::stringstream ss;
|
||
ss << std::put_time(t, "%Y-%m-%d %H:%M:%S");
|
||
auto ms = (unix_time_ms % 1000);
|
||
ss << '.' << std::setw(3) << std::setfill('0') << ms;
|
||
return ss.str();
|
||
}
|
||
|
||
class api_driver::StatisticsLogger {
|
||
public:
|
||
StatisticsLogger(): timeStart(TIME_NOW()) {}
|
||
|
||
int64_t timeStart;
|
||
|
||
bool logEn = false;
|
||
std::atomic<int> logPeriodMs = 1000;
|
||
std::atomic<int> maxAgeMs = 10000;
|
||
|
||
/**
|
||
*
|
||
* @return {"en": bool, "logPeriodMs": int, ""}
|
||
*/
|
||
std::string getSettings() {
|
||
std::lock_guard _lock(mutex);
|
||
std::stringstream res;
|
||
res << "{\"en\":" << boolAsStr(this->logEn);
|
||
res << ",\"logPeriodMs\":" << logPeriodMs;
|
||
res << ",\"maxAgeMs\":" << maxAgeMs;
|
||
res << '}';
|
||
return res.str();
|
||
}
|
||
void setSettings(boost::property_tree::ptree &pt) {
|
||
const bool newEn = pt.get<bool>("en");
|
||
const int newInterval = pt.get<int>("logPeriodMs");
|
||
const int newMaxAgeMs = pt.get<int>("maxAgeMs");
|
||
|
||
std::lock_guard _lock(this->mutex);
|
||
this->logPeriodMs = newInterval;
|
||
this->maxAgeMs = newMaxAgeMs;
|
||
|
||
if (newEn != this->logEn) {
|
||
if (newEn) {
|
||
this->logFile.open("/tmp/weblog-statistics.csv", std::ios::out);
|
||
if (this->logFile.is_open()) {
|
||
const auto* header = "timestamp\tcnt ok\tcnt bad\tfine freq dem\tcrs freq dem\tcrs freq compensator\tcrs time est\tfine time est\tmax level corr\tcurrent delay\tSNR\tcurrent modcod\tfine freq compensator\tind freq grb\tind freq tochn\tind filt adapt\tfilter corr cinc\tcorr cnt\tRSS\tcor erl\tcor lat\tgc gain\tpower pl rx\n";
|
||
this->logFile.write(header, static_cast<std::streamsize>(strlen(header)));
|
||
this->logEn = true;
|
||
this->timeStart = TIME_NOW();
|
||
}
|
||
} else {
|
||
if (this->logFile.is_open()) {
|
||
this->logFile.close();
|
||
}
|
||
this->logEn = false;
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Записать значение в "базу данных". Метку при этом вставлять не нужно, она будет вставлена автоматически.
|
||
* @param item
|
||
*/
|
||
void putItem(const debug_metrics& item) {
|
||
std::lock_guard _lock(this->mutex);
|
||
if (!logEn) return;
|
||
if (this->logFile.is_open()) {
|
||
std::stringstream res;
|
||
res << makeTimepointFromMillis(TIME_NOW()) << '\t';
|
||
res << item.cnt_ok << '\t';
|
||
res << item.cnt_bad << '\t';
|
||
res << item.fine_freq_dem << '\t';
|
||
res << item.crs_freq_dem << '\t';
|
||
res << item.crs_freq_compensator << '\t';
|
||
res << item.crs_time_est << '\t';
|
||
res << item.fine_time_est << '\t';
|
||
res << item.max_level_corr << '\t';
|
||
res << item.current_delay << '\t';
|
||
res << item.SNR << '\t';
|
||
res << item.current_modcod << '\t';
|
||
res << item.fine_freq_compensator << '\t';
|
||
res << item.ind_freq_grb << '\t';
|
||
res << item.ind_freq_tochn << '\t';
|
||
res << item.ind_filt_adapt << '\t';
|
||
res << item.filter_corr_cinc << '\t';
|
||
res << item.corr_cnt << '\t';
|
||
res << item.RSS << '\t';
|
||
res << item.cor_erl << '\t';
|
||
res << item.cor_lat << '\t';
|
||
res << item.gc_gain << '\t';
|
||
res << item.power_pl_rx << '\n';
|
||
|
||
const auto out = res.str();
|
||
this->logFile.write(out.c_str(), static_cast<std::streamsize>(out.length()));
|
||
this->logFile.flush();
|
||
}
|
||
}
|
||
|
||
// void collectExpiredItems();
|
||
|
||
// void resetLogs() {
|
||
// std::lock_guard _lock(mutex);
|
||
// logs.clear();
|
||
// }
|
||
|
||
~StatisticsLogger() = default;
|
||
private:
|
||
// std::pmr::deque<LogItem> logs;
|
||
std::fstream logFile{};
|
||
std::shared_mutex mutex;
|
||
};
|
||
|
||
/**
|
||
* Этот демон нужен для того, чтобы получать статистику из API, а так же корректно сохранять настройки
|
||
*/
|
||
class api_driver::TerminalApiDaemon {
|
||
private:
|
||
CP_Result lastCpError = OK;
|
||
void logCpApiError(const char* desc, CP_Result err) {
|
||
if (err != OK) {
|
||
BOOST_LOG_TRIVIAL(error) << "CP API error in " << desc << ": " << err;
|
||
this->lastCpError = err;
|
||
}
|
||
}
|
||
|
||
void updateState() {
|
||
modulator_state modulator{};
|
||
demodulator_state demodulator{};
|
||
device_state device{};
|
||
#ifdef MODEM_IS_SCPC
|
||
CinC_state cinc{};
|
||
#endif
|
||
|
||
std::lock_guard lock(this->cpApiMutex);
|
||
logCpApiError("api_driver::TerminalApiDaemon::updateState()->CP_GetModulatorState()", CP_GetModulatorState(sid, modulator));
|
||
logCpApiError("api_driver::TerminalApiDaemon::updateState()->CP_GetDemodulatorState()", CP_GetDemodulatorState(sid, demodulator));
|
||
logCpApiError("api_driver::TerminalApiDaemon::updateState()->CP_GetDeviceState()", CP_GetDeviceState(sid, device));
|
||
#ifdef MODEM_IS_TDMA
|
||
std::string tmpDevState;
|
||
logCpApiError("api_driver::TerminalApiDaemon::updateState()->CP_GetDmaDebug(status_init)", CP_GetDmaDebug(sid, "status_init", &tmpDevState));
|
||
#endif
|
||
#ifdef MODEM_IS_SCPC
|
||
logCpApiError("api_driver::TerminalApiDaemon::updateState()->CP_GetDebugMetrics()", CP_GetDebugMetrics(sid, debugMetrics));
|
||
|
||
bool isCinC = getIsCinC();
|
||
if (isCinC) {
|
||
logCpApiError("api_driver::TerminalApiDaemon::updateState()->CP_GetCinCState()", CP_GetCinCState(sid, cinc));
|
||
}
|
||
#endif
|
||
|
||
{
|
||
std::lock_guard lock2(this->stateMutex);
|
||
this->modState = modulator;
|
||
this->demodState = demodulator;
|
||
this->devState = device;
|
||
#ifdef MODEM_IS_TDMA
|
||
this->deviceInitState = tmpDevState;
|
||
#endif
|
||
#ifdef MODEM_IS_SCPC
|
||
this->cincState = cinc;
|
||
#endif
|
||
}
|
||
}
|
||
|
||
void updateSettings() {
|
||
modulator_settings mod{};
|
||
// uint32_t modulatorModcod;
|
||
// CP_GetModulatorParams(sid, "modcod", &modulatorModcod);
|
||
demodulator_settings demod{};
|
||
#ifdef MODEM_IS_SCPC
|
||
ACM_parameters_serv_ acm{};
|
||
DPDI_parmeters dpdi{};
|
||
#endif
|
||
buc_lnb_settings bucLnb{};
|
||
|
||
std::lock_guard lock(this->cpApiMutex);
|
||
logCpApiError("api_driver::TerminalApiDaemon::updateSettings()->CP_GetModulatorSettings()", CP_GetModulatorSettings(sid, mod));
|
||
logCpApiError("api_driver::TerminalApiDaemon::updateSettings()->CP_GetDemodulatorSettings()", CP_GetDemodulatorSettings(sid, demod));
|
||
#ifdef MODEM_IS_SCPC
|
||
logCpApiError("api_driver::TerminalApiDaemon::updateSettings()->CP_GetAcmParams()", CP_GetAcmParams(sid, &acm));
|
||
logCpApiError("api_driver::TerminalApiDaemon::updateSettings()->CP_GetDpdiParams()", CP_GetDpdiParams(sid, &dpdi));
|
||
#endif
|
||
logCpApiError("api_driver::TerminalApiDaemon::updateSettings()->CP_GetBUC_LNB_settings()", CP_GetBUC_LNB_settings(sid, bucLnb));
|
||
|
||
{
|
||
std::lock_guard lock2(this->settingsMutex);
|
||
this->modSettings = mod;
|
||
this->demodSettings = demod;
|
||
#ifdef MODEM_IS_SCPC
|
||
this->acmSettings = acm;
|
||
this->dpdiSettings = dpdi;
|
||
#endif
|
||
this->bucLnbSettings = bucLnb;
|
||
}
|
||
}
|
||
|
||
void unsafeLoadNetworkSettings(TerminalNetworkSettings& s) {
|
||
s.loadDefaults();
|
||
logCpApiError("api_driver::TerminalApiDaemon::unsafeLoadNetworkSettings()->CP_GetNetwork(addr)", CP_GetNetwork(sid, "addr", &s.managementIp));
|
||
// logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(mask)", CP_GetNetwork(sid, "mask", &tmp));
|
||
// s.managementIp += "/";
|
||
// s.managementIp += std::to_string(calculateSubnetMask(tmp));
|
||
logCpApiError("api_driver::TerminalApiDaemon::unsafeLoadNetworkSettings()->CP_GetNetwork(gateway)", CP_GetNetwork(sid, "gateway", &s.managementGateway));
|
||
std::string nm; logCpApiError("api_driver::TerminalApiDaemon::unsafeLoadNetworkSettings()->CP_GetNetwork(mode)", CP_GetNetwork(sid, "mode", &nm));
|
||
if (nm == "tun") {
|
||
s.isL2 = false;
|
||
logCpApiError("api_driver::TerminalApiDaemon::unsafeLoadNetworkSettings()->CP_GetNetwork(addr_data)", CP_GetNetwork(sid, "addr_data", &s.dataIp));
|
||
} else {
|
||
s.isL2 = true;
|
||
}
|
||
s.dataMtu = 1500;
|
||
logCpApiError("api_driver::TerminalApiDaemon::unsafeLoadNetworkSettings()->CP_GetNetwork(name_serv)", CP_GetNetwork(sid, "name_serv", &s.serverName));
|
||
if (s.serverName.empty()) {
|
||
s.serverName = TerminalNetworkSettings::DEFAULT_SERVER_NAME;
|
||
}
|
||
}
|
||
void unsafStoreNetworkSettings(TerminalNetworkSettings& s) {
|
||
logCpApiError("api_driver::TerminalApiDaemon::unsafStoreNetworkSettings()->CP_SetNetwork(mode)", CP_SetNetwork(sid, "mode", s.isL2 ? "tap" : "tun"));
|
||
logCpApiError("api_driver::TerminalApiDaemon::unsafStoreNetworkSettings()->CP_SetNetwork(addr)", CP_SetNetwork(sid, "addr", s.managementIp.c_str()));
|
||
if (!s.isL2) {
|
||
logCpApiError("api_driver::TerminalApiDaemon::unsafStoreNetworkSettings()->CP_SetNetwork(addr_data)", CP_SetNetwork(sid, "addr_data", s.dataIp.c_str()));
|
||
// TODO маска не устанавливается, потому что в API этого нет
|
||
}
|
||
logCpApiError("api_driver::TerminalApiDaemon::unsafStoreNetworkSettings()->CP_SetNetwork(mask)", CP_SetNetwork(sid, "mask", "255.255.255.0"));
|
||
logCpApiError("api_driver::TerminalApiDaemon::unsafStoreNetworkSettings()->CP_SetNetwork(gateway)", CP_SetNetwork(sid, "gateway", s.managementGateway.c_str()));
|
||
|
||
// TODO MTU не устанавливается, потому что в API этого нет
|
||
|
||
logCpApiError("api_driver::TerminalApiDaemon::unsafeLoadNetworkSettings()->CP_SetNetwork(name_serv)", CP_SetNetwork(sid, "name_serv", s.serverName.c_str()));
|
||
}
|
||
|
||
void updateNetworkSettings() {
|
||
TerminalNetworkSettings s;
|
||
|
||
std::lock_guard lock(this->cpApiMutex);
|
||
unsafeLoadNetworkSettings(s);
|
||
|
||
{
|
||
std::lock_guard lock2(this->networkSettingsMutex);
|
||
this->networkSettings = s;
|
||
}
|
||
}
|
||
|
||
void updateQos() {
|
||
bool tmp1; std::string tmp2;
|
||
std::scoped_lock lock{this->cpApiMutex};
|
||
logCpApiError("api_driver::TerminalApiDaemon::updateQos()->CP_GetQoSSettings()", CP_GetQoSSettings(this->sid, tmp2, tmp1));
|
||
{
|
||
std::lock_guard lock2(this->qosSettingsMutex);
|
||
this->qosEnabled = tmp1;
|
||
this->qosClassesJson = tmp2.empty() ? DEFAULT_QOS_CLASSES : tmp2;
|
||
}
|
||
}
|
||
|
||
void connectToApi() {
|
||
{
|
||
std::lock_guard _lock(this->stateMutex);
|
||
this->deviceInitState = "Not connected to API";
|
||
this->networkSettings.loadDefaults();
|
||
}
|
||
|
||
unsigned int access{};
|
||
for (int connectAttempt = 0;; connectAttempt++) {
|
||
BOOST_LOG_TRIVIAL(info) << "api_driver::TerminalApiDaemon::connectToApi(): Try to connect api (attempt " << connectAttempt << ")...";
|
||
auto res = CP_Login("admin", "pass", &sid, &access);
|
||
logCpApiError(R"(api_driver::TerminalApiDaemon::connectToApi()->CP_Login("admin", "pass"))", res);
|
||
if (res != OK) {
|
||
boost::this_thread::sleep_for(boost::chrono::duration(boost::chrono::milliseconds(1000)));
|
||
} else {
|
||
break;
|
||
}
|
||
}
|
||
|
||
std::string tmp;
|
||
logCpApiError("api_driver::TerminalApiDaemon::run()->CP_GetDmaDebug(status_init)", CP_GetDmaDebug(sid, "status_init", &tmp));
|
||
{
|
||
std::lock_guard _lock(this->stateMutex);
|
||
this->deviceInitState = tmp;
|
||
}
|
||
BOOST_LOG_TRIVIAL(info) << "api_driver::TerminalApiDaemon::connectToApi(): Success connect!";
|
||
BOOST_LOG_TRIVIAL(info) << "api_driver::TerminalApiDaemon::connectToApi(): API status: " << tmp;
|
||
|
||
TerminalFirmwareVersion f;
|
||
logCpApiError("api_driver::TerminalApiDaemon::connectToApi()->CP_GetNetwork(version)", CP_GetNetwork(sid, "version", &f.version));
|
||
logCpApiError("api_driver::TerminalApiDaemon::connectToApi()->CP_GetNetwork(chip_id)", CP_GetNetwork(sid, "chip_id", &f.modemId));
|
||
rtrim(f.modemId);
|
||
logCpApiError("api_driver::TerminalApiDaemon::connectToApi()->CP_GetNetwork(serial)", CP_GetNetwork(sid, "serial", &f.modemSn));
|
||
logCpApiError("api_driver::TerminalApiDaemon::connectToApi()->CP_GetNetwork(mac_eth0)", CP_GetNetwork(sid, "mac_eth0", &f.macMang));
|
||
logCpApiError("api_driver::TerminalApiDaemon::connectToApi()->CP_GetNetwork(mac_eth1)", CP_GetNetwork(sid, "mac_eth1", &f.macData));
|
||
|
||
{
|
||
std::lock_guard _lock(this->firmwareMutex);
|
||
this->firmware = f;
|
||
}
|
||
|
||
this->lastCpError = OK;
|
||
}
|
||
|
||
void run() {
|
||
// это демон, который в бесконечном цикле опрашивает API
|
||
this->connectToApi();
|
||
|
||
struct IntervalUpdate_t {
|
||
int64_t lastUpdate;
|
||
int64_t periodMs;
|
||
|
||
std::function<void()> callback;
|
||
|
||
bool checkNeedUpdate(int64_t now) const {
|
||
// тут нет смысла спать меньше чем на 20мс, поэтому можно разрешить чтение на некоторое время раньше
|
||
return now - lastUpdate >= (periodMs - 20);
|
||
}
|
||
|
||
int64_t getNextUpdate(int64_t now) const {
|
||
if (checkNeedUpdate(now)) {
|
||
return 0;
|
||
}
|
||
auto next = now - lastUpdate;
|
||
return next < 0 ? 0 : next;
|
||
}
|
||
};
|
||
|
||
IntervalUpdate_t updaters[] = {
|
||
// обновление статистики
|
||
{.lastUpdate = 0, .periodMs = CACHE_STATISTICS_UPDATE_MS, .callback = [this]() {
|
||
try {
|
||
this->updateState();
|
||
BOOST_LOG_TRIVIAL(debug) << "api_driver::TerminalApiDaemon::updateState(): success update!";
|
||
} catch (std::exception& e) {
|
||
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::updateState(): " << e.what();
|
||
}
|
||
|
||
// запись статистики в лог, если нужно
|
||
try {
|
||
static int uc = 0;
|
||
if (uc == 0) {
|
||
this->statsLogs.putItem(debugMetrics);
|
||
|
||
BOOST_LOG_TRIVIAL(debug) << "api_driver::TerminalApiDaemon::updateState(): success write statistics state to log!";
|
||
}
|
||
uc++;
|
||
if (uc * CACHE_STATISTICS_UPDATE_MS >= this->statsLogs.logPeriodMs) {
|
||
uc = 0;
|
||
}
|
||
} catch (std::exception& e) {
|
||
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::updateState() failed to log: " << e.what();
|
||
}
|
||
}},
|
||
// обновление кеша настроек
|
||
{.lastUpdate = 0, .periodMs = CACHE_SETTINGS_UPDATE_MS, .callback = [this]() {
|
||
try {
|
||
this->updateSettings();
|
||
BOOST_LOG_TRIVIAL(debug) << "api_driver::TerminalApiDaemon::updateSettings(): success update!";
|
||
} catch (std::exception& e) {
|
||
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::updateSettings(): " << e.what();
|
||
}
|
||
}},
|
||
// обновление кеша настроек сети (делается отдельно)
|
||
{.lastUpdate = 0, .periodMs = CACHE_SETTINGS_UPDATE_MS, .callback = [this]() {
|
||
try {
|
||
this->updateNetworkSettings();
|
||
BOOST_LOG_TRIVIAL(debug) << "api_driver::TerminalApiDaemon::updateNetworkSettings(): success update!";
|
||
} catch (std::exception& e) {
|
||
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::updateNetworkSettings(): " << e.what();
|
||
}
|
||
}},
|
||
// обновление кеша QoS
|
||
{.lastUpdate = 0, .periodMs = CACHE_QOS_UPDATE_MS, .callback = [this]() {
|
||
try {
|
||
this->updateQos();
|
||
BOOST_LOG_TRIVIAL(debug) << "api_driver::TerminalApiDaemon::updateQos(): success update!";
|
||
} catch (std::exception& e) {
|
||
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::updateQos(): " << e.what();
|
||
}
|
||
}}
|
||
};
|
||
|
||
while (true) {
|
||
if (this->lastCpError == ERROR || this->lastCpError == TIMEOUT) {
|
||
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::run(): close current daemon session caused error " << this->lastCpError;
|
||
CP_Logout(this->sid);
|
||
this->connectToApi();
|
||
}
|
||
|
||
int64_t sleepTime = 60000; // минута по-умолчанию
|
||
auto now = TIME_NOW();
|
||
for (auto& u: updaters) {
|
||
if (u.checkNeedUpdate(now)) {
|
||
u.lastUpdate = now;
|
||
u.callback();
|
||
now = TIME_NOW();
|
||
}
|
||
|
||
sleepTime = std::min(sleepTime, u.getNextUpdate(now));
|
||
}
|
||
|
||
if (sleepTime > 0) {
|
||
boost::this_thread::sleep_for(boost::chrono::duration(boost::chrono::milliseconds(sleepTime)));
|
||
}
|
||
}
|
||
}
|
||
|
||
std::shared_mutex stateMutex;
|
||
modulator_state modState{};
|
||
demodulator_state demodState{};
|
||
device_state devState{};
|
||
std::string deviceInitState;
|
||
debug_metrics debugMetrics{};
|
||
#ifdef MODEM_IS_SCPC
|
||
CinC_state cincState{};
|
||
#endif
|
||
|
||
std::shared_mutex settingsMutex;
|
||
modulator_settings modSettings{};
|
||
demodulator_settings demodSettings{};
|
||
#ifdef MODEM_IS_SCPC
|
||
ACM_parameters_serv_ acmSettings{};
|
||
DPDI_parmeters dpdiSettings{};
|
||
#endif
|
||
buc_lnb_settings bucLnbSettings{};
|
||
|
||
std::shared_mutex networkSettingsMutex;
|
||
TerminalNetworkSettings networkSettings;
|
||
|
||
std::shared_mutex qosSettingsMutex;
|
||
bool qosEnabled;
|
||
std::string qosClassesJson;
|
||
|
||
std::shared_mutex firmwareMutex;
|
||
TerminalFirmwareVersion firmware;
|
||
|
||
public:
|
||
StatisticsLogger statsLogs;
|
||
|
||
std::mutex cpApiMutex;
|
||
TSID sid;
|
||
boost::thread daemon;
|
||
|
||
explicit TerminalApiDaemon(): deviceInitState("Not connected to API"), qosEnabled(false), sid(0), daemon([this]() { this->run(); }) {
|
||
this->qosClassesJson = DEFAULT_QOS_CLASSES;
|
||
}
|
||
|
||
std::string getDeviceInitState() {
|
||
std::shared_lock lock(this->stateMutex);
|
||
return this->deviceInitState;
|
||
}
|
||
|
||
#ifdef MODEM_IS_SCPC
|
||
/**
|
||
* Получение статистики, копирует текущие значения в структуры, переданные по указателю. Если передан пустой указатель, копирования не произойдет.
|
||
* @param mod статистика модулятра
|
||
* @param demod статистика демодулятора
|
||
* @param dev статистика устройства (температуры)
|
||
* @param cinc статистика CinC (актуальна только для режима CinC, но в любом случае будет перезаписана)
|
||
*/
|
||
void getState(modulator_state* mod, demodulator_state* demod, device_state* dev, CinC_state* cinc) {
|
||
if (mod != nullptr || demod != nullptr || dev != nullptr) {
|
||
std::shared_lock lock(this->stateMutex);
|
||
if (mod) { *mod = this->modState; }
|
||
if (demod) { *demod = this->demodState; }
|
||
if (dev) { *dev = this->devState; }
|
||
if (cinc) { *cinc = this->cincState; }
|
||
}
|
||
}
|
||
#else
|
||
/**
|
||
* Получение статистики, копирует текущие значения в структуры, переданные по указателю. Если передан пустой указатель, копирования не произойдет.
|
||
* @param mod статистика модулятра
|
||
* @param demod статистика демодулятора
|
||
* @param dev статистика устройства (температуры)
|
||
*/
|
||
void getState(modulator_state* mod, demodulator_state* demod, device_state* dev) {
|
||
if (mod != nullptr || demod != nullptr || dev != nullptr) {
|
||
std::shared_lock lock(this->stateMutex);
|
||
if (mod) { *mod = this->modState; }
|
||
if (demod) { *demod = this->demodState; }
|
||
if (dev) { *dev = this->devState; }
|
||
}
|
||
}
|
||
#endif
|
||
|
||
/**
|
||
* Получение настроек, копирует текущие значения в структуры, переданные по указателю. Если передан пустой указатель, копирования не произойдет.
|
||
*/
|
||
#ifdef MODEM_IS_SCPC
|
||
void getSettings(modulator_settings* mod, demodulator_settings* demod, ACM_parameters_serv_* acm, DPDI_parmeters* dpdi, buc_lnb_settings* bucLnb) {
|
||
if (mod || demod || acm || dpdi || bucLnb) {
|
||
std::shared_lock lock(this->settingsMutex);
|
||
if (mod) { *mod = this->modSettings; }
|
||
if (demod) { *demod = this->demodSettings; }
|
||
if (acm) { *acm = this->acmSettings; }
|
||
if (dpdi) { *dpdi = this->dpdiSettings; }
|
||
if (bucLnb) { *bucLnb = this->bucLnbSettings; }
|
||
}
|
||
}
|
||
#else
|
||
void getSettings(modulator_settings* mod, demodulator_settings* demod, buc_lnb_settings* bucLnb) {
|
||
if (mod || demod || bucLnb) {
|
||
std::shared_lock lock(this->settingsMutex);
|
||
if (mod) { *mod = this->modSettings; }
|
||
if (demod) { *demod = this->demodSettings; }
|
||
if (bucLnb) { *bucLnb = this->bucLnbSettings; }
|
||
}
|
||
}
|
||
#endif
|
||
|
||
#ifdef MODEM_IS_SCPC
|
||
bool getIsCinC() {
|
||
std::shared_lock lock(this->settingsMutex);
|
||
return modSettings.is_cinc;
|
||
}
|
||
#endif
|
||
|
||
bool isTest() {
|
||
std::shared_lock lock(this->settingsMutex);
|
||
return modSettings.tx_is_on && (!modSettings.is_carrier
|
||
#ifdef MODEM_IS_SCPC
|
||
|| this->modSettings.is_test_data
|
||
#endif
|
||
);
|
||
}
|
||
|
||
void getNetworkSettings(TerminalNetworkSettings& dest) {
|
||
std::shared_lock lock(this->networkSettingsMutex);
|
||
dest = this->networkSettings;
|
||
}
|
||
|
||
void getQosSettings(bool& isEnabled, std::string& json) {
|
||
std::shared_lock lock(this->qosSettingsMutex);
|
||
isEnabled = this->qosEnabled;
|
||
json = this->qosClassesJson;
|
||
}
|
||
|
||
#ifdef MODEM_IS_SCPC
|
||
void setSettingsRxTx(modulator_settings& mod, demodulator_settings& demod, ACM_parameters_serv_& acm, bool readback = true) {
|
||
std::lock_guard lock(this->cpApiMutex);
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_SetDmaDebug(begin_save_config)", CP_SetDmaDebug(sid, "begin_save_config", ""));
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_SetModulatorSettings()", CP_SetModulatorSettings(this->sid, mod));
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_SetDemodulatorSettings()", CP_SetDemodulatorSettings(this->sid, demod));
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_SetAcmParams()", CP_SetAcmParams(this->sid, acm));
|
||
if (readback) {
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_GetModulatorSettings()", CP_GetModulatorSettings(this->sid, mod));
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_GetDemodulatorSettings()", CP_GetDemodulatorSettings(this->sid, demod));
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_GetAcmParams()", CP_GetAcmParams(this->sid, &acm));
|
||
{
|
||
std::lock_guard lock2{this->settingsMutex};
|
||
this->modSettings = mod;
|
||
this->demodSettings = demod;
|
||
this->acmSettings = acm;
|
||
}
|
||
}
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_SetDmaDebug(save_config)", CP_SetDmaDebug(sid, "save_config", ""));
|
||
}
|
||
#else
|
||
void setSettingsRxTx(modulator_settings& mod, demodulator_settings& demod, bool readback = true) {
|
||
std::lock_guard lock(this->cpApiMutex);
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_SetDmaDebug(begin_save_config)", CP_SetDmaDebug(sid, "begin_save_config", ""));
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_SetModulatorSettings()", CP_SetModulatorSettings(this->sid, mod));
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_SetDemodulatorSettings()", CP_SetDemodulatorSettings(this->sid, demod));
|
||
if (readback) {
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_GetModulatorSettings()", CP_GetModulatorSettings(this->sid, mod));
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_GetDemodulatorSettings()", CP_GetDemodulatorSettings(this->sid, demod));
|
||
{
|
||
std::lock_guard lock2{this->settingsMutex};
|
||
this->modSettings = mod;
|
||
this->demodSettings = demod;
|
||
}
|
||
}
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_SetDmaDebug(save_config)", CP_SetDmaDebug(sid, "save_config", ""));
|
||
}
|
||
#endif
|
||
|
||
#ifdef MODEM_IS_SCPC
|
||
void setSettingsCinc(DPDI_parmeters& s, bool readback = true) {
|
||
std::lock_guard lock(this->cpApiMutex);
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsCinc()->CP_SetDmaDebug(begin_save_config)", CP_SetDmaDebug(sid, "begin_save_config", ""));
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsCinc()->CP_SetDpdiParams()", CP_SetDpdiParams(sid, s));
|
||
if (readback) {
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsCinc()->CP_GetDpdiParams()", CP_GetDpdiParams(this->sid, &s));
|
||
{
|
||
std::lock_guard lock2{this->settingsMutex};
|
||
this->dpdiSettings = s;
|
||
}
|
||
}
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsCinc()->CP_SetDmaDebug(save_config)", CP_SetDmaDebug(sid, "save_config", ""));
|
||
}
|
||
#endif
|
||
|
||
void setSettingsBucLnb(buc_lnb_settings& bucLnb, bool readback = true) {
|
||
std::lock_guard lock(this->cpApiMutex);
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsBucLnb()->CP_SetDmaDebug(begin_save_config)", CP_SetDmaDebug(sid, "begin_save_config", ""));
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsBucLnb()->CP_SetBUC_LNB_settings()", CP_SetBUC_LNB_settings(this->sid, bucLnb));
|
||
if (readback) {
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsBucLnb()->CP_GetBUC_LNB_settings()", CP_GetBUC_LNB_settings(this->sid, bucLnb));
|
||
{
|
||
std::lock_guard lock2{this->settingsMutex};
|
||
this->bucLnbSettings = bucLnb;
|
||
}
|
||
}
|
||
logCpApiError("api_driver::TerminalApiDaemon::setSettingsBucLnb()->CP_SetDmaDebug(save_config)", CP_SetDmaDebug(sid, "save_config", ""));
|
||
}
|
||
|
||
void setQosSettings(bool enabled, const std::string& str, bool readback = true) {
|
||
std::lock_guard lock(this->cpApiMutex);
|
||
logCpApiError("api_driver::TerminalApiDaemon::setQosSettings()->CP_SetDmaDebug(begin_save_config)", CP_SetDmaDebug(sid, "begin_save_config", ""));
|
||
logCpApiError("api_driver::TerminalApiDaemon::setQosSettings()->CP_SetQoSSettings()", CP_SetQoSSettings(this->sid, str, enabled));
|
||
if (readback) {
|
||
bool tmp1; std::string tmp2;
|
||
logCpApiError("api_driver::TerminalApiDaemon::setQosSettings()->CP_GetQoSSettings()", CP_GetQoSSettings(this->sid, tmp2, tmp1));
|
||
{
|
||
std::lock_guard lock2(this->qosSettingsMutex);
|
||
this->qosEnabled = tmp1;
|
||
this->qosClassesJson = tmp2.empty() ? DEFAULT_QOS_CLASSES : tmp2;
|
||
}
|
||
}
|
||
logCpApiError("api_driver::TerminalApiDaemon::setQosSettings()->CP_SetDmaDebug(save_config)", CP_SetDmaDebug(sid, "save_config", ""));
|
||
}
|
||
|
||
void setNetworkSettings(TerminalNetworkSettings& s, bool readback = true) {
|
||
// const auto mang = splitIpAndMask();
|
||
// std::pair<std::string, std::string> data;
|
||
// if (!s.isL2) {
|
||
// data = splitIpAndMask(s.dataIp);
|
||
// }
|
||
|
||
std::lock_guard lock(this->cpApiMutex);
|
||
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetDmaDebug(begin_save_config)", CP_SetDmaDebug(sid, "begin_save_config", ""));
|
||
unsafStoreNetworkSettings(s);
|
||
|
||
if (readback) {
|
||
unsafeLoadNetworkSettings(s);
|
||
{
|
||
std::lock_guard lock2(this->networkSettingsMutex);
|
||
this->networkSettings = s;
|
||
}
|
||
}
|
||
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetDmaDebug(save_config)", CP_SetDmaDebug(sid, "save_config", ""));
|
||
}
|
||
|
||
TerminalFirmwareVersion getFirmware() {
|
||
std::shared_lock lock(this->firmwareMutex);
|
||
return firmware;
|
||
}
|
||
|
||
void resetPacketStatistics() {
|
||
std::string tmp;
|
||
std::lock_guard lock(this->cpApiMutex);
|
||
logCpApiError("api_driver::TerminalApiDaemon::resetPacketStatistics()->CP_GetDmaDebug(reset_cnt_rx)", CP_GetDmaDebug(sid, "reset_cnt_rx", &tmp));
|
||
}
|
||
|
||
void resetDefaultSettings() {
|
||
std::lock_guard lock(this->cpApiMutex);
|
||
logCpApiError("api_driver::TerminalApiDaemon::resetDefaultSettings()->CP_SetDmaDebug(begin_save_config)", CP_SetDmaDebug(sid, "begin_save_config", ""));
|
||
logCpApiError("api_driver::TerminalApiDaemon::resetDefaultSettings()->CP_SetDmaDebug(default_params)", CP_SetDmaDebug(sid, "default_params", ""));
|
||
logCpApiError("api_driver::TerminalApiDaemon::resetDefaultSettings()->CP_SetDmaDebug(save_config)", CP_SetDmaDebug(sid, "save_config", ""));
|
||
}
|
||
|
||
~TerminalApiDaemon() {
|
||
try {
|
||
daemon.interrupt();
|
||
daemon.try_join_for(boost::chrono::seconds(2));
|
||
} catch (std::exception& e) {
|
||
BOOST_LOG_TRIVIAL(error) << "api_driver::~TerminalApiDaemon(): " << e.what();
|
||
}
|
||
}
|
||
};
|
||
|
||
|
||
api_driver::ApiDriver::ApiDriver() = default;
|
||
|
||
void api_driver::ApiDriver::startDaemon() {
|
||
if (daemon == nullptr) {
|
||
daemon = std::make_unique<TerminalApiDaemon>();
|
||
BOOST_LOG_TRIVIAL(info) << "api_driver::ApiDriver::startDaemon(): API daemon succes started!";
|
||
}
|
||
}
|
||
|
||
std::string api_driver::buildEscapedString(const std::string& source) {
|
||
std::string str(source);
|
||
size_t start_pos = 0;
|
||
while((start_pos = str.find('\"', start_pos)) != std::string::npos) {
|
||
str.replace(start_pos, 1, "\\\"");
|
||
start_pos += 2;
|
||
}
|
||
for (start_pos = 0; start_pos < str.size() && (str[start_pos] == ' ' || str[start_pos] == '\n' || str[start_pos] == '\t'); start_pos++) {}
|
||
size_t end_pos = str.size() - 1;
|
||
for (; end_pos > start_pos && end_pos != 0 && (str[end_pos] == ' ' || str[end_pos] == '\n' || str[end_pos] == '\t'); end_pos--) {}
|
||
return "\"" + str.substr(start_pos, end_pos - start_pos + 1) + "\"";
|
||
}
|
||
|
||
static void writeDouble(std::ostream& out, double value, int prec = 2) {
|
||
if (std::isnan(value) || std::isinf(value)) {
|
||
out << "\"nan\"";
|
||
} else {
|
||
out << std::fixed << std::setprecision(prec) << value;
|
||
}
|
||
}
|
||
#ifdef MODEM_IS_SCPC
|
||
double translateCoordinates(uint8_t deg, uint8_t min) {
|
||
return static_cast<double>(deg) + static_cast<double>(min) / 60;
|
||
}
|
||
|
||
std::tuple<uint8_t, uint8_t> translateCoordinates(double abs) {
|
||
auto deg = static_cast<uint8_t>(abs);
|
||
double min_double = (abs - deg) * 60;
|
||
auto min = static_cast<uint8_t>(min_double);
|
||
return std::make_tuple(deg, min);
|
||
}
|
||
#endif
|
||
|
||
|
||
std::string api_driver::ApiDriver::loadTerminalState() const {
|
||
if (daemon == nullptr) {
|
||
return R"({"error": "api daemon not started!"})";
|
||
}
|
||
std::stringstream result;
|
||
|
||
result << "{\n\"initState\":" << buildEscapedString(daemon->getDeviceInitState());
|
||
result << ",\n\"testState\":" << boolAsStr(daemon->isTest());
|
||
|
||
modulator_state modulator{};
|
||
demodulator_state demodulator{};
|
||
device_state device{};
|
||
#ifdef MODEM_IS_SCPC
|
||
CinC_state cinc{};
|
||
daemon->getState(&modulator, &demodulator, &device, &cinc);
|
||
const bool isCinC = this->daemon->getIsCinC();
|
||
#else
|
||
daemon->getState(&modulator, &demodulator, &device);
|
||
#endif
|
||
|
||
#ifdef MODEM_IS_SCPC
|
||
result << ",\"isCinC\":" << boolAsStr(isCinC);
|
||
#endif
|
||
|
||
// формируем структуру для TX
|
||
result << ",\n\"tx.state\":" << boolAsStr(modulator.is_tx_on);
|
||
result << ",\"tx.modcod\":" << modulator.modcod;
|
||
#ifdef MODEM_IS_SCPC
|
||
result << ",\"tx.snr\":"; writeDouble(result, modulator.snr_remote);
|
||
|
||
if (modulator.is_short) { result << R"(,"tx.frameSizeNormal":false)"; }
|
||
else { result << R"(,"tx.frameSizeNormal":true)"; }
|
||
|
||
if (modulator.is_pilots) { result << R"(,"tx.isPilots":true)"; }
|
||
else { result << R"(,"tx.isPilots":false)"; }
|
||
#else
|
||
{
|
||
modulator_settings modSet{};
|
||
daemon->getSettings(&modSet, nullptr, nullptr);
|
||
result << ",\"tx.centerFreq\":"; writeDouble(result, modSet.central_freq_in_kGz);
|
||
result << ",\"tx.symSpeed\":"; writeDouble(result, (static_cast<double>(modSet.baudrate) / 1000.0));
|
||
}
|
||
#endif
|
||
result << ",\"tx.speedOnTxKbit\":"; writeDouble(result, static_cast<double>(modulator.speed_in_bytes_tx) / 128.0);
|
||
result << ",\"tx.speedOnIifKbit\":"; writeDouble(result, (static_cast<double>(modulator.speed_in_bytes_tx_iface) / 128.0));
|
||
|
||
// формируем структуру для RX
|
||
result << ",\n\"rx.state\":" << boolAsStr(demodulator.locks.sym_sync_lock && demodulator.locks.freq_lock && demodulator.locks.afc_lock && demodulator.locks.pkt_sync);
|
||
result << ",\"rx.sym_sync_lock\":" << boolAsStr(demodulator.locks.sym_sync_lock);
|
||
result << ",\"rx.freq_search_lock\":" << boolAsStr(demodulator.locks.freq_lock);
|
||
result << ",\"rx.afc_lock\":" << boolAsStr(demodulator.locks.afc_lock);
|
||
result << ",\"rx.pkt_sync\":" << boolAsStr(demodulator.locks.pkt_sync);
|
||
|
||
result << ",\"rx.snr\":"; writeDouble(result, demodulator.snr);
|
||
result << ",\"rx.rssi\":"; writeDouble(result, demodulator.rssi);
|
||
result << ",\"rx.modcod\":" << demodulator.modcod;
|
||
|
||
if (demodulator.is_short) {
|
||
result << R"(,"rx.frameSizeNormal":false)";
|
||
} else {
|
||
result << R"(,"rx.frameSizeNormal":true)";
|
||
}
|
||
|
||
if (demodulator.is_pilots) {
|
||
result << R"(,"rx.isPilots":true)";
|
||
} else {
|
||
result << R"(,"rx.isPilots":false)";
|
||
}
|
||
|
||
result << ",\n\"rx.symError\":"; writeDouble(result, demodulator.sym_err);
|
||
result << ",\"rx.freqErr\":"; writeDouble(result, demodulator.crs_freq_err);
|
||
result << ",\"rx.freqErrAcc\":"; writeDouble(result, demodulator.fine_freq_err);
|
||
result << ",\"rx.inputSignalLevel\":"; writeDouble(result, demodulator.if_overload);
|
||
result << ",\"rx.pllError\":"; writeDouble(result, demodulator.afc_err);
|
||
result << ",\"rx.speedOnRxKbit\":"; writeDouble(result, static_cast<double>(demodulator.speed_in_bytes_rx) / 128.0);
|
||
result << ",\"rx.speedOnIifKbit\":"; writeDouble(result, static_cast<double>(demodulator.speed_in_bytes_rx_iface) / 128.0);
|
||
result << ",\"rx.packetsOk\":" << demodulator.packet_ok_cnt;
|
||
result << ",\"rx.packetsBad\":" << demodulator.packet_bad_cnt;
|
||
result << ",\"rx.packetsDummy\":" << demodulator.dummy_cnt;
|
||
|
||
#ifdef MODEM_IS_SCPC
|
||
// формируем структуру для CinC
|
||
if (isCinC) {
|
||
if (modulator.is_tx_on) {
|
||
if (cinc.carrier_lock) {
|
||
result << R"(,"cinc.correlator":true)";
|
||
} else {
|
||
result << R"(,"cinc.correlator":false)";
|
||
}
|
||
} else {
|
||
result << R"(,"cinc.correlator":null)";
|
||
}
|
||
|
||
result << ",\n\"cinc.occ\":"; writeDouble(result, cinc.ratio_signal_signal, 3);
|
||
result << ",\"cinc.correlatorFails\":" << cinc.cnt_bad_lock;
|
||
result << ",\"cinc.freqErr\":" << cinc.freq_error_offset;
|
||
result << ",\"cinc.freqErrAcc\":" << cinc.freq_fine_estimate;
|
||
result << ",\"cinc.channelDelay\":" << cinc.delay_dpdi;
|
||
} else {
|
||
result << R"(,"cinc.correlator":null)";
|
||
}
|
||
#endif
|
||
|
||
// структура температур девайса
|
||
result << ",\n\"device.adrv\":"; writeDouble(result, device.adrv_temp, 1);
|
||
result << ",\"device.fpga\":"; writeDouble(result, device.pl_temp, 1);
|
||
result << ",\"device.zynq\":"; writeDouble(result, device.zynq_temp, 1);
|
||
|
||
result << "}";
|
||
|
||
return result.str();
|
||
}
|
||
|
||
|
||
void api_driver::ApiDriver::resetPacketStatistics() const {
|
||
this->daemon->resetPacketStatistics();
|
||
}
|
||
|
||
#ifdef MODEM_IS_SCPC
|
||
struct ModcodDef_t {const char* modulation; const char* speed;};
|
||
const static ModcodDef_t ModcodDefs[] = {
|
||
{.modulation = "dummy", .speed = "0"},
|
||
{.modulation = "qpsk", .speed = "1/4"},
|
||
{.modulation = "qpsk", .speed = "1/3"},
|
||
{.modulation = "qpsk", .speed = "2/5"},
|
||
{.modulation = "qpsk", .speed = "1/2"},
|
||
{.modulation = "qpsk", .speed = "3/5"},
|
||
{.modulation = "qpsk", .speed = "2/3"},
|
||
{.modulation = "qpsk", .speed = "3/4"},
|
||
{.modulation = "qpsk", .speed = "4/5"},
|
||
{.modulation = "qpsk", .speed = "5/6"},
|
||
{.modulation = "qpsk", .speed = "8/9"},
|
||
{.modulation = "qpsk", .speed = "9/10"},
|
||
{.modulation = "8psk", .speed = "3/5"},
|
||
{.modulation = "8psk", .speed = "2/3"},
|
||
{.modulation = "8psk", .speed = "3/4"},
|
||
{.modulation = "8psk", .speed = "5/6"},
|
||
{.modulation = "8psk", .speed = "8/9"},
|
||
{.modulation = "8psk", .speed = "9/10"},
|
||
{.modulation = "16apsk", .speed = "2/3"},
|
||
{.modulation = "16apsk", .speed = "3/4"},
|
||
{.modulation = "16apsk", .speed = "4/5"},
|
||
{.modulation = "16apsk", .speed = "5/6"},
|
||
{.modulation = "16apsk", .speed = "8/9"},
|
||
{.modulation = "16apsk", .speed = "9/10"},
|
||
{.modulation = "32apsk", .speed = "3/4"},
|
||
{.modulation = "32apsk", .speed = "4/5"},
|
||
{.modulation = "32apsk", .speed = "5/6"},
|
||
{.modulation = "32apsk", .speed = "8/9"},
|
||
{.modulation = "32apsk", .speed = "9/10"},
|
||
};
|
||
|
||
static const char* extractModcodModulation(uint32_t modcod, bool defaultQpsk1_4 = true) {
|
||
modcod >>= 2;
|
||
const auto* d = defaultQpsk1_4 ? ModcodDefs : ModcodDefs + 1;
|
||
if (modcod < (sizeof(ModcodDefs) / sizeof(ModcodDef_t))) {
|
||
d = ModcodDefs + modcod;
|
||
}
|
||
return d->modulation;
|
||
}
|
||
|
||
static const char* extractModcodSpeed(uint32_t modcod, bool defaultQpsk1_4 = true) {
|
||
modcod >>= 2;
|
||
const auto* d = defaultQpsk1_4 ? ModcodDefs : ModcodDefs + 1;
|
||
if (modcod < (sizeof(ModcodDefs) / sizeof(ModcodDef_t))) {
|
||
d = ModcodDefs + modcod;
|
||
}
|
||
return d->speed;
|
||
}
|
||
#endif
|
||
|
||
std::string api_driver::ApiDriver::loadSettings() const {
|
||
if (daemon == nullptr) {
|
||
return R"({"error": "api daemon not started!"})";
|
||
}
|
||
|
||
modulator_settings modSettings{};
|
||
demodulator_settings demodSettings{};
|
||
buc_lnb_settings bucLnb{};
|
||
TerminalNetworkSettings network;
|
||
#ifdef MODEM_IS_SCPC
|
||
ACM_parameters_serv_ acmSettings{};
|
||
DPDI_parmeters dpdiSettings{};
|
||
daemon->getSettings(&modSettings, &demodSettings, &acmSettings, &dpdiSettings, &bucLnb);
|
||
#else
|
||
daemon->getSettings(&modSettings, &demodSettings, &bucLnb);
|
||
#endif
|
||
daemon->getNetworkSettings(network);
|
||
|
||
std::stringstream result;
|
||
result << "{\n\"txAutoStart\":" << boolAsStr(modSettings.is_save_current_state);
|
||
result << ",\"txEn\":" << boolAsStr(modSettings.tx_is_on);
|
||
#ifdef MODEM_IS_SCPC
|
||
result << ",\"txIsTestInput\":" << boolAsStr(modSettings.is_test_data);
|
||
#endif
|
||
result << ",\"txModulatorIsTest\":" << boolAsStr(!modSettings.is_carrier);
|
||
result << ",\"txCentralFreq\":"; writeDouble(result, modSettings.central_freq_in_kGz);
|
||
#ifdef MODEM_IS_SCPC
|
||
result << ",\"txBaudrate\":" << modSettings.baudrate;
|
||
result << ",\"txRolloff\":" << static_cast<int>(modSettings.rollof);
|
||
result << ",\"txGoldan\":" << static_cast<int>(modSettings.gold_seq_is_active);
|
||
#endif
|
||
result << ",\"txAttenuation\":"; writeDouble(result, modSettings.attenuation);
|
||
|
||
#ifdef MODEM_IS_SCPC
|
||
result << ",\n\"isCinC\":" << boolAsStr(modSettings.is_cinc);
|
||
result << ",\n\"dvbServicePacketPeriod\":" << acmSettings.period_pack_acm;
|
||
result << ",\"dvbIsAcm\":" << boolAsStr(acmSettings.enable_acm);
|
||
result << ",\"txFrameSizeNormal\":" << boolAsStr((modSettings.modcod_tx & 2) == 0);
|
||
|
||
result << R"(,"dvbCcmModulation":")" << extractModcodModulation(modSettings.modcod_tx) << "\"";
|
||
result << R"(,"dvbCcmSpeed":")" << extractModcodSpeed(modSettings.modcod_tx) << "\"";
|
||
result << R"(,"dvbAcmMinModulation":")" << extractModcodModulation(acmSettings.min_modcod_acm) << "\"";
|
||
result << R"(,"dvbAcmMinSpeed":")" << extractModcodSpeed(acmSettings.min_modcod_acm) << "\"";
|
||
result << R"(,"dvbAcmMaxModulation":")" << extractModcodModulation(acmSettings.max_modcod_acm) << "\"";
|
||
result << R"(,"dvbAcmMaxSpeed":")" << extractModcodSpeed(acmSettings.max_modcod_acm) << "\"";
|
||
result << ",\"dvbSnrReserve\":"; writeDouble(result, acmSettings.snr_threashold_acm);
|
||
|
||
result << ",\n\"aupcEn\":" << boolAsStr(acmSettings.enable_aupc);
|
||
result << ",\"aupcMinAttenuation\":"; writeDouble(result, acmSettings.min_attenuation_aupc);
|
||
result << ",\"aupcMaxAttenuation\":"; writeDouble(result, acmSettings.max_attenuation_aupc);
|
||
result << ",\"aupcRequiredSnr\":"; writeDouble(result, acmSettings.snr_threashold_aupc);
|
||
|
||
result << ",\n\"cincIsPositional\":" << boolAsStr(!dpdiSettings.is_delay_window);
|
||
result << ",\"cincSearchBandwidth\":" << dpdiSettings.freq_offset; // полоса поиска в кГц
|
||
result << ",\"cincPositionStationLatitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.latitude_station_grad, dpdiSettings.latitude_station_minute), 6);
|
||
result << ",\"cincPositionStationLongitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.longitude_station_grad, dpdiSettings.longitude_station_minute), 6);
|
||
result << ",\"cincPositionSatelliteLongitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.longitude_sattelite_grad, dpdiSettings.longitude_sattelite_minute), 6);
|
||
result << ",\"cincDelayMin\":" << dpdiSettings.min_delay;
|
||
result << ",\"cincDelayMax\":" << dpdiSettings.max_delay;
|
||
#endif
|
||
|
||
#ifdef MODEM_IS_TDMA
|
||
result << ",\n\"rxTxSatDelay\":" << static_cast<int>(demodSettings.delay_ms);
|
||
#endif
|
||
|
||
result << ",\n\"rxAgcEn\":" << boolAsStr(demodSettings.is_aru_on);
|
||
result << ",\"rxSpectrumInversion\":" << boolAsStr(demodSettings.is_rvt_iq);
|
||
result << ",\"rxManualGain\":"; writeDouble(result, demodSettings.gain);
|
||
result << ",\"rxCentralFreq\":"; writeDouble(result, demodSettings.central_freq_in_kGz);
|
||
result << ",\"rxBaudrate\":" << demodSettings.baudrate;
|
||
result << ",\"rxRolloff\":" << static_cast<int>(demodSettings.rollof);
|
||
#ifdef MODEM_IS_SCPC
|
||
result << ",\"rxGoldan\":" << static_cast<int>(demodSettings.gold_seq_is_active);
|
||
#endif
|
||
|
||
// BUC LNB
|
||
result << ",\n\"bucRefClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_buc);
|
||
switch (bucLnb.buc) {
|
||
case voltage_buc::_24V: result << ",\"bucPowering\":24"; break;
|
||
#ifdef MODEM_IS_SCPC
|
||
case voltage_buc::_48V: result << ",\"bucPowering\":48"; break;
|
||
#endif
|
||
case voltage_buc::DISABLE:
|
||
default: result << ",\"bucPowering\":0";
|
||
}
|
||
|
||
result << ",\"lnbRefClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_lnb);
|
||
switch (bucLnb.lnb) {
|
||
case voltage_lnb::_13V: result << ",\"lnbPowering\":13"; break;
|
||
case voltage_lnb::_18V: result << ",\"lnbPowering\":18"; break;
|
||
case voltage_lnb::_24V: result << ",\"lnbPowering\":24"; break;
|
||
case voltage_lnb::DISABLE:
|
||
default: result << ",\"lnbPowering\":0";
|
||
}
|
||
|
||
result << ",\"srvRefClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_output);
|
||
result << ",\"bucLnbAutoStart\":" << boolAsStr(bucLnb.is_save_current_state);
|
||
|
||
// QoS
|
||
bool qosEnabled = false; std::string qosClasses;
|
||
daemon->getQosSettings(qosEnabled, qosClasses);
|
||
result << ",\n\"qosEnabled\":" << boolAsStr(qosEnabled);
|
||
result << ",\"qosProfile\":" << qosClasses;
|
||
|
||
// сеть
|
||
result << "\n,\"netManagementIp\":" << buildEscapedString(network.managementIp);
|
||
result << ",\"netIsL2\":" << boolAsStr(network.isL2);
|
||
result << ",\"netManagementGateway\":" << buildEscapedString(network.managementGateway);
|
||
result << ",\"netDataIp\":" << buildEscapedString(network.dataIp);
|
||
result << ",\"netDataMtu\":" << network.dataMtu;
|
||
result << ",\"netServerName\":" << buildEscapedString(network.serverName);
|
||
|
||
result << "}";
|
||
return result.str();
|
||
}
|
||
|
||
std::string api_driver::ApiDriver::loadFirmwareVersion() const {
|
||
if (daemon == nullptr) {
|
||
return R"({"error": "api daemon not started!"})";
|
||
}
|
||
|
||
std::stringstream result;
|
||
auto firmware = daemon->getFirmware();
|
||
result << "{\n\"fw.version\":" << buildEscapedString(firmware.version);
|
||
result << ",\"fw.modemId\":" << buildEscapedString(firmware.modemId);
|
||
result << ",\"fw.modemSn\":" << buildEscapedString(firmware.modemSn);
|
||
result << ",\"fw.macMang\":" << buildEscapedString(firmware.macMang);
|
||
result << ",\"fw.macData\":" << buildEscapedString(firmware.macData);
|
||
result << "\n}";
|
||
return result.str();
|
||
}
|
||
|
||
#ifdef MODEM_IS_SCPC
|
||
static uint32_t buildModcodFromPt(const boost::property_tree::ptree& pt, const std::string& name, bool isShortFrame) {
|
||
uint32_t modcod = 0;
|
||
const auto mod = pt.get<std::string>(name + "Modulation");
|
||
const auto speed = pt.get<std::string>(name + "Speed");
|
||
uint32_t _index = 0;
|
||
for (const auto& m: ModcodDefs) {
|
||
if (mod == m.modulation) {
|
||
if (modcod == 0) modcod = _index;
|
||
if (speed == m.speed) {
|
||
modcod = _index;
|
||
break;
|
||
}
|
||
}
|
||
_index++;
|
||
}
|
||
return (modcod << 2) | (isShortFrame ? 2 : 0);
|
||
}
|
||
#endif
|
||
|
||
void api_driver::ApiDriver::setRxTxSettings(boost::property_tree::ptree &pt) {
|
||
modulator_settings mod{};
|
||
demodulator_settings demod{};
|
||
#ifdef MODEM_IS_SCPC
|
||
ACM_parameters_serv_ acm{};
|
||
daemon->getSettings(&mod, &demod, &acm, nullptr, nullptr);
|
||
#else
|
||
daemon->getSettings(&mod, &demod, nullptr);
|
||
#endif
|
||
|
||
// для модулятора
|
||
#ifdef MODEM_IS_SCPC
|
||
mod.is_cinc = pt.get<bool>("isCinC");
|
||
#endif
|
||
mod.tx_is_on = pt.get<bool>("txEn");
|
||
#ifdef MODEM_IS_SCPC
|
||
mod.is_save_current_state = pt.get<bool>("txAutoStart");
|
||
mod.is_test_data = pt.get<bool>("txIsTestInput");
|
||
#endif
|
||
mod.is_carrier = !pt.get<bool>("txModulatorIsTest");
|
||
mod.central_freq_in_kGz = pt.get<double>("txCentralFreq");
|
||
#ifdef MODEM_IS_SCPC
|
||
mod.baudrate = pt.get<uint32_t>("txBaudrate");
|
||
mod.rollof = pt.get<unsigned int>("txRolloff");
|
||
mod.gold_seq_is_active = pt.get<unsigned int>("txGoldan");
|
||
#endif
|
||
mod.attenuation = pt.get<double>("txAttenuation");
|
||
|
||
#ifdef MODEM_IS_SCPC
|
||
const bool acmIsShortFrame = !pt.get<bool>("txFrameSizeNormal");
|
||
mod.modcod_tx = buildModcodFromPt(pt, "dvbCcm", acmIsShortFrame);
|
||
#endif
|
||
|
||
// демодулятор
|
||
demod.is_aru_on = pt.get<bool>("rxAgcEn");
|
||
demod.gain = pt.get<double>("rxManualGain");
|
||
demod.is_rvt_iq = pt.get<bool>("rxSpectrumInversion");
|
||
demod.central_freq_in_kGz = pt.get<double>("rxCentralFreq");
|
||
demod.baudrate = pt.get<uint32_t>("rxBaudrate");
|
||
demod.rollof = pt.get<unsigned int>("rxRolloff");
|
||
#ifdef MODEM_IS_SCPC
|
||
demod.gold_seq_is_active = pt.get<unsigned int>("rxGoldan");
|
||
#endif
|
||
|
||
#ifdef MODEM_IS_TDMA
|
||
demod.delay_ms = pt.get<unsigned int>("rxTxSatDelay");
|
||
#endif
|
||
|
||
#ifdef MODEM_IS_SCPC
|
||
// ACM
|
||
acm.period_pack_acm = pt.get<uint32_t>("dvbServicePacketPeriod");
|
||
acm.enable_acm = pt.get<bool>("dvbIsAcm");
|
||
acm.min_modcod_acm = buildModcodFromPt(pt, "dvbAcmMin", acmIsShortFrame);
|
||
acm.max_modcod_acm = buildModcodFromPt(pt, "dvbAcmMax", acmIsShortFrame);
|
||
acm.snr_threashold_acm = pt.get<double>("dvbSnrReserve"); // запас ОСШ
|
||
acm.enable_aupc = pt.get<bool>(json_path("aupcEn", '/'));
|
||
acm.min_attenuation_aupc = pt.get<int>("aupcMinAttenuation");
|
||
acm.max_attenuation_aupc = pt.get<int>("aupcMaxAttenuation");
|
||
acm.snr_threashold_aupc= pt.get<double>("aupcRequiredSnr");
|
||
|
||
daemon->setSettingsRxTx(mod, demod, acm);
|
||
#else
|
||
daemon->setSettingsRxTx(mod, demod);
|
||
#endif
|
||
}
|
||
|
||
#ifdef MODEM_IS_SCPC
|
||
void api_driver::ApiDriver::setCincSettings(boost::property_tree::ptree &pt) {
|
||
DPDI_parmeters s{};
|
||
|
||
s.is_delay_window = !pt.get<bool>("cincIsPositional");
|
||
s.freq_offset = pt.get<uint32_t>("cincSearchBandwidth");
|
||
|
||
auto ctmp = translateCoordinates(pt.get<double>("cincPositionStationLatitude"));
|
||
s.latitude_station_grad = std::get<0>(ctmp);
|
||
s.latitude_station_minute = std::get<1>(ctmp);
|
||
|
||
ctmp = translateCoordinates(pt.get<double>("cincPositionStationLongitude"));
|
||
s.longitude_station_grad = std::get<0>(ctmp);
|
||
s.longitude_station_minute = std::get<1>(ctmp);
|
||
|
||
ctmp = translateCoordinates(pt.get<double>("cincPositionSatelliteLongitude"));
|
||
s.longitude_sattelite_grad = std::get<0>(ctmp);
|
||
s.longitude_sattelite_minute = std::get<1>(ctmp);
|
||
|
||
s.min_delay = pt.get<uint32_t>("cincDelayMin");
|
||
s.max_delay = pt.get<uint32_t>("cincDelayMax");
|
||
|
||
this->daemon->setSettingsCinc(s);
|
||
}
|
||
#endif
|
||
|
||
void api_driver::ApiDriver::setBucLnbSettings(boost::property_tree::ptree &pt) {
|
||
buc_lnb_settings s{};
|
||
#ifdef MODEM_IS_SCPC
|
||
daemon->getSettings(nullptr, nullptr, nullptr, nullptr, &s);
|
||
#else
|
||
daemon->getSettings(nullptr, nullptr, &s);
|
||
#endif
|
||
|
||
auto tmp = pt.get<int>("bucPowering");
|
||
switch (tmp) {
|
||
case 24: s.buc = voltage_buc::_24V; break;
|
||
#ifdef MODEM_IS_SCPC
|
||
case 48: s.buc = voltage_buc::_48V; break;
|
||
#endif
|
||
case 0:
|
||
default:
|
||
s.lnb = voltage_lnb::DISABLE;
|
||
}
|
||
s.is_ref_10MHz_buc = pt.get<bool>("bucRefClk10M");
|
||
|
||
tmp = pt.get<int>("lnbPowering");
|
||
switch (tmp) {
|
||
case 13: s.lnb = voltage_lnb::_13V; break;
|
||
case 18: s.lnb = voltage_lnb::_18V; break;
|
||
case 24: s.lnb = voltage_lnb::_24V; break;
|
||
case 0:
|
||
default:
|
||
s.lnb = voltage_lnb::DISABLE;
|
||
}
|
||
s.is_ref_10MHz_lnb = pt.get<bool>("lnbRefClk10M");
|
||
|
||
s.is_ref_10MHz_output = pt.get<bool>("srvRefClk10M");
|
||
s.is_save_current_state = pt.get<bool>("bucLnbAutoStart");
|
||
|
||
this->daemon->setSettingsBucLnb(s);
|
||
}
|
||
|
||
void api_driver::ApiDriver::setQosSettings(boost::property_tree::ptree &pt) {
|
||
bool enabled = pt.get<bool>("en");
|
||
pt.erase("en");
|
||
|
||
std::ostringstream oss;
|
||
write_json(oss, pt);
|
||
|
||
this->daemon->setQosSettings(enabled, oss.str());
|
||
}
|
||
|
||
void api_driver::ApiDriver::setNetworkSettings(boost::property_tree::ptree &pt) {
|
||
TerminalNetworkSettings s;
|
||
daemon->getNetworkSettings(s);
|
||
|
||
s.managementIp = pt.get<std::string>("netManagementIp");
|
||
// s.managementGateway = pt.get<std::string>(json_path("network.managementGateway", '/'));
|
||
s.isL2 = pt.get<bool>("netIsL2");
|
||
s.dataIp = pt.get<std::string>("netDataIp");
|
||
s.dataMtu = pt.get<unsigned int>("netDataMtu");
|
||
s.serverName = pt.get<std::string>("netServerName");
|
||
|
||
daemon->setNetworkSettings(s);
|
||
}
|
||
|
||
void api_driver::ApiDriver::resetDefaultSettings() {
|
||
daemon->resetDefaultSettings();
|
||
}
|
||
|
||
void api_driver::ApiDriver::executeInApi(const std::function<void(TSID sid)>& callback) {
|
||
try {
|
||
std::lock_guard lock(this->daemon->cpApiMutex);
|
||
callback(this->daemon->sid);
|
||
} catch (std::exception& e) {
|
||
BOOST_LOG_TRIVIAL(error) << "ApiDriver::executeInApi(): failed to exec with error: " << e.what();
|
||
}
|
||
}
|
||
|
||
std::string api_driver::ApiDriver::getLoggingStatisticsSettings() {
|
||
return this->daemon->statsLogs.getSettings();
|
||
}
|
||
|
||
void api_driver::ApiDriver::setLoggingStatisticsSettings(boost::property_tree::ptree &pt) {
|
||
this->daemon->statsLogs.setSettings(pt);
|
||
}
|
||
|
||
std::string api_driver::ApiDriver::loadSysInfo() {
|
||
std::stringstream result;
|
||
struct sysinfo info{};
|
||
sysinfo(&info);
|
||
|
||
// struct sysinfo {
|
||
// long uptime; /* Seconds since boot */
|
||
// unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
|
||
// unsigned long totalram; /* Total usable main memory size */
|
||
// unsigned long freeram; /* Available memory size */
|
||
// unsigned long sharedram; /* Amount of shared memory */
|
||
// unsigned long bufferram; /* Memory used by buffers */
|
||
// unsigned long totalswap; /* Total swap space size */
|
||
// unsigned long freeswap; /* Swap space still available */
|
||
// unsigned short procs; /* Number of current processes */
|
||
// unsigned long totalhigh; /* Total high memory size */
|
||
// unsigned long freehigh; /* Available high memory size */
|
||
// unsigned int mem_unit; /* Memory unit size in bytes */
|
||
// };
|
||
|
||
const double f_load = 100.0 / ((1 << SI_LOAD_SHIFT) * get_nprocs());
|
||
|
||
result << "{\n\"uptime\":" << info.uptime;
|
||
result << ",\"load1min\":"; writeDouble(result, f_load * static_cast<double>(info.loads[0]), 2);
|
||
result << ",\"load5min\":"; writeDouble(result, f_load * static_cast<double>(info.loads[1]), 2);
|
||
result << ",\"load15min\":"; writeDouble(result, f_load * static_cast<double>(info.loads[2]), 2);
|
||
result << ",\"totalram\":" << ((info.totalram * info.mem_unit) >> 20); // Mb
|
||
result << ",\"freeram\":" << ((info.freeram * info.mem_unit) >> 20); // Mb
|
||
// result << ",\"sharedram\":" << ((info.sharedram * info.mem_unit) >> 20); // Mb
|
||
// result << ",\"bufferram\":" << ((info.bufferram * info.mem_unit) >> 20); // Mb
|
||
// result << ",\"totalswap\":" << info.totalswap * info.mem_unit;
|
||
// result << ",\"freeswap\":" << info.freeswap * info.mem_unit;
|
||
result << ",\"procs\":" << static_cast<long>(info.procs);
|
||
result << "\n}";
|
||
return result.str();
|
||
}
|
||
|
||
api_driver::ApiDriver::~ApiDriver() = default;
|