1174 lines
52 KiB
C++
1174 lines
52 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>
|
||
|
||
|
||
|
||
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());
|
||
}
|
||
|
||
class TerminalNetworkSettings {
|
||
public:
|
||
std::string managementIp, managementGateway, mode, dataIp;
|
||
unsigned int dataMtu = 1500;
|
||
|
||
TerminalNetworkSettings() = default;
|
||
TerminalNetworkSettings(const TerminalNetworkSettings& src) = default;
|
||
~TerminalNetworkSettings() = default;
|
||
|
||
TerminalNetworkSettings& operator= (const TerminalNetworkSettings& src) = default;
|
||
|
||
void loadDefaults() {
|
||
managementIp = "0.0.0.0";
|
||
managementGateway = "";
|
||
mode = "l2";
|
||
dataIp = "0.0.0.0";
|
||
dataMtu = 1500;
|
||
}
|
||
};
|
||
|
||
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;
|
||
}
|
||
|
||
/**
|
||
* Этот демон нужен для того, чтобы получать статистику из 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
|
||
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 updateNetworkSettings() {
|
||
TerminalNetworkSettings s;
|
||
std::string tmp;
|
||
std::lock_guard lock(this->cpApiMutex);
|
||
logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(addr)", CP_GetNetwork(sid, "addr", &tmp));
|
||
s.managementIp = tmp + "/";
|
||
tmp.clear(); logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(mask)", CP_GetNetwork(sid, "mask", &tmp));
|
||
s.managementIp += std::to_string(calculateSubnetMask(tmp));
|
||
tmp.clear(); logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(gateway)", CP_GetNetwork(sid, "gateway", &s.managementGateway)); s.managementGateway = tmp;
|
||
tmp.clear(); logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(mode)", CP_GetNetwork(sid, "mode", &tmp));
|
||
if (tmp == "tun") {
|
||
s.mode = "l3";
|
||
logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(addr_data)", CP_GetNetwork(sid, "addr_data", &s.dataIp));
|
||
s.dataIp += "/24";
|
||
} else {
|
||
s.mode = "l2";
|
||
s.dataIp = "0.0.0.0/24";
|
||
}
|
||
s.dataMtu = 1500;
|
||
|
||
{
|
||
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";
|
||
}
|
||
|
||
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();
|
||
}
|
||
}},
|
||
// обновление кеша настроек
|
||
{.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 = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
|
||
for (auto& u: updaters) {
|
||
if (u.checkNeedUpdate(now)) {
|
||
u.lastUpdate = now;
|
||
u.callback();
|
||
now = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
|
||
}
|
||
|
||
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;
|
||
#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:
|
||
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
|
||
|
||
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(s.managementIp);
|
||
std::pair<std::string, std::string> data;
|
||
bool isL2;
|
||
if (s.mode == "l2") { isL2 = true; }
|
||
else if (s.mode == "l3") { isL2 = false; data = splitIpAndMask(s.dataIp); }
|
||
else { throw std::runtime_error("invalid mode"); }
|
||
|
||
std::lock_guard lock(this->cpApiMutex);
|
||
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetDmaDebug(begin_save_config)", CP_SetDmaDebug(sid, "begin_save_config", ""));
|
||
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(mode)", CP_SetNetwork(sid, "mode", isL2 ? "tap" : "tun"));
|
||
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(addr)", CP_SetNetwork(sid, "addr", mang.first.c_str()));
|
||
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(mask)", CP_SetNetwork(sid, "mask", mang.second.c_str()));
|
||
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(gateway)", CP_SetNetwork(sid, "gateway", s.managementGateway.c_str()));
|
||
if (!isL2) {
|
||
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(data_addr)", CP_SetNetwork(sid, "data_addr", data.first.c_str()));
|
||
// TODO маска не устанавливается, потому что в API этого нет
|
||
}
|
||
// TODO MTU не устанавливается, потому что в API этого нет
|
||
|
||
if (readback) {
|
||
std::string tmp;
|
||
s.loadDefaults();
|
||
s.managementIp.clear();
|
||
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->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::setNetworkSettings()->CP_GetNetwork(gateway)", CP_GetNetwork(sid, "gateway", &s.managementGateway));
|
||
tmp.clear(); logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(mode)", CP_GetNetwork(sid, "mode", &tmp));
|
||
if (tmp == "tun") {
|
||
s.mode = "l3";
|
||
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(addr_data)", CP_GetNetwork(sid, "addr_data", &s.dataIp));
|
||
} else {
|
||
s.mode = "l2";
|
||
s.dataIp = "0.0.0.0/24";
|
||
}
|
||
s.dataMtu = 1500;
|
||
{
|
||
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!";
|
||
}
|
||
}
|
||
|
||
static const char* boolAsStr(bool value) {
|
||
return value ? "true" : "false";
|
||
}
|
||
|
||
static std::string 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;
|
||
}
|
||
return "\"" + str + "\"";
|
||
}
|
||
|
||
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());
|
||
|
||
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();
|
||
}
|
||
|
||
static void generateModcode(std::ostream& out, const char* paramName, uint32_t modcod) {
|
||
struct _modcodDef {const char* modulation; const char* speed;};
|
||
const static _modcodDef defs[] = {
|
||
{.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"},
|
||
};
|
||
const _modcodDef* d = defs;
|
||
if (modcod < 28) {
|
||
d = defs + modcod;
|
||
}
|
||
|
||
}
|
||
|
||
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;
|
||
#ifdef MODEM_IS_SCPC
|
||
result << "{\n\"isCinC\":" << boolAsStr(modSettings.is_cinc);
|
||
result << ",\"txEn\":" << boolAsStr(modSettings.tx_is_on);
|
||
result << ",\"txModulatorIsTest\":" << boolAsStr(!modSettings.is_carrier);
|
||
result << ",\"txAutoStart\":" << boolAsStr(modSettings.is_save_current_state);
|
||
result << ",\"txIsTestInput\":" << boolAsStr(modSettings.is_test_data);
|
||
result << ",\n\"txAttenuation\":"; writeDouble(result, modSettings.attenuation);
|
||
result << ",\"txRolloff\":" << static_cast<int>(modSettings.rollof * 100);
|
||
result << ",\"txBaudrate\":" << modSettings.baudrate;
|
||
result << ",\"txCentralFreq\":"; writeDouble(result, modSettings.central_freq_in_kGz, 3);
|
||
result << ",\"dvbs2.frameSizeNormal\":" << boolAsStr(!(modSettings.modcod_tx & 2));
|
||
result << ",\"dvbs2.ccm_modcod\":" << (modSettings.modcod_tx >> 2);
|
||
|
||
// result << ",\"dvbs2.isPilots\":" << "null";
|
||
result << ",\n\"dvbIsAcm\":" << boolAsStr(acmSettings.enable);
|
||
result << ",\"dvbs2.acm_maxModcod\":" << (acmSettings.max_modcod >> 2);
|
||
result << ",\"dvbs2.acm_minModcod\":" << (acmSettings.min_modcod >> 2);
|
||
result << ",\"dvbs2.snrReserve\":"; writeDouble(result, acmSettings.snr_treashold_acm);
|
||
result << ",\"dvbServicePacketPeriod\":" << acmSettings.period_pack;
|
||
|
||
result << ",\n\"acm.en\":" << boolAsStr(acmSettings.enable_auto_atten);
|
||
result << ",\"acm.maxAttenuation\":"; writeDouble(result, acmSettings.max_attenuation);
|
||
result << ",\"acm.minAttenuation\":"; writeDouble(result, acmSettings.min_attenuation);
|
||
result << ",\"acm.requiredSnr\":"; writeDouble(result, acmSettings.snr_treashold);
|
||
|
||
result << ",\n\"rx.gainMode\":" << (demodSettings.is_aru_on ? "\"auto\"" : "\"manual\"");
|
||
result << ",\"rx.manualGain\":"; writeDouble(result, demodSettings.gain);
|
||
result << ",\"rx.spectrumInversion\":" << boolAsStr(demodSettings.is_rvt_iq);
|
||
result << ",\"rx.rolloff\":" << static_cast<int>(demodSettings.rollof * 100);
|
||
result << ",\"rx.cymRate\":" << demodSettings.baudrate;
|
||
result << ",\"rx.centerFreq\":"; writeDouble(result, demodSettings.central_freq_in_kGz);
|
||
|
||
result << ",\n\"cinc.mode\":" << (dpdiSettings.is_delay_window ? "\"delay\"" : "\"positional\"");
|
||
result << ",\"cinc.searchBandwidth\":" << dpdiSettings.freq_offset; // полоса поиска в кГц
|
||
result << ",\"cinc.position.station.latitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.latitude_station_grad, dpdiSettings.latitude_station_minute), 6);
|
||
result << ",\"cinc.position.station.longitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.longitude_station_grad, dpdiSettings.longitude_station_minute), 6);
|
||
result << ",\"cinc.position.satelliteLongitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.longitude_sattelite_grad, dpdiSettings.longitude_sattelite_minute), 6);
|
||
result << ",\"cinc.delayMin\":" << dpdiSettings.min_delay;
|
||
result << ",\"cinc.delayMax\":" << dpdiSettings.max_delay;
|
||
#else
|
||
result << "{\n\"tx.txEn\":" << boolAsStr(modSettings.tx_is_on);
|
||
result << ",\"tx.isTestInputData\":" << boolAsStr(modSettings.is_test_data);
|
||
result << ",\"tx.cymRate\":" << modSettings.baudrate;
|
||
result << ",\"tx.centerFreq\":"; writeDouble(result, modSettings.central_freq_in_kGz, 3);
|
||
result << ",\"tx.attenuation\":"; writeDouble(result, modSettings.attenuation);
|
||
|
||
result << ",\n\"rx.gainMode\":" << (demodSettings.is_aru_on ? "\"auto\"" : "\"manual\"");
|
||
result << ",\"rx.manualGain\":"; writeDouble(result, demodSettings.gain);
|
||
result << ",\"rx.spectrumInversion\":" << boolAsStr(demodSettings.is_rvt_iq);
|
||
result << ",\"rx.rolloff\":" << static_cast<int>(demodSettings.rollof * 100);
|
||
result << ",\"rx.cymRate\":" << demodSettings.baudrate;
|
||
result << ",\"rx.centerFreq\":"; writeDouble(result, demodSettings.central_freq_in_kGz);
|
||
#endif
|
||
|
||
result << ",\n\"buc.refClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_buc);
|
||
switch (bucLnb.buc) {
|
||
case voltage_buc::_24V: result << ",\"buc.powering\":24"; break;
|
||
case voltage_buc::_48V: result << ",\"buc.powering\":48"; break;
|
||
case voltage_buc::DISABLE:
|
||
default: result << ",\"buc.powering\":0";
|
||
}
|
||
|
||
result << ",\n\"lnb.refClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_lnb);
|
||
switch (bucLnb.lnb) {
|
||
case voltage_lnb::_13V: result << ",\"lnb.powering\":13"; break;
|
||
case voltage_lnb::_18V: result << ",\"lnb.powering\":18"; break;
|
||
case voltage_lnb::_24V: result << ",\"lnb.powering\":24"; break;
|
||
case voltage_lnb::DISABLE:
|
||
default: result << ",\"lnb.powering\":0";
|
||
}
|
||
|
||
result << ",\n\"serviceSettings.refClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_output);
|
||
result << ",\"serviceSettings.autoStart\":" << boolAsStr(bucLnb.is_save_current_state);
|
||
|
||
bool qosEnabled = false; std::string qosClasses;
|
||
daemon->getQosSettings(qosEnabled, qosClasses);
|
||
result << ",\n\"qos.enabled\":" << boolAsStr(qosEnabled);
|
||
result << ",\"qos.profile\":" << qosClasses;
|
||
|
||
// сеть
|
||
result << ",\"network.managementIp\":\n" << buildEscapedString(network.managementIp);
|
||
result << ",\"network.managementGateway\":\n" << buildEscapedString(network.managementGateway);
|
||
result << ",\"network.mode\":\n" << buildEscapedString(network.mode);
|
||
result << ",\"network.dataIp\":\n" << buildEscapedString(network.dataIp);
|
||
result << ",\"network.dataMtu\":\n" << network.dataMtu;
|
||
|
||
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();
|
||
}
|
||
|
||
void api_driver::ApiDriver::setRxTxSettings(boost::property_tree::ptree &pt) {
|
||
modulator_settings mod{};
|
||
demodulator_settings demod{};
|
||
#ifdef MODEM_IS_SCPC
|
||
ACM_parameters_serv_ acm{};
|
||
#endif
|
||
|
||
// для модулятора
|
||
#ifdef MODEM_IS_SCPC
|
||
mod.is_cinc = pt.get<bool>(json_path("general.isCinC", '/'));
|
||
mod.tx_is_on = pt.get<bool>(json_path("general.txEn", '/'));
|
||
auto tmp = pt.get<std::string>(json_path("general.modulatorMode", '/'));
|
||
if (tmp == "normal") { mod.is_carrier = true; }
|
||
else if (tmp == "test") { mod.is_carrier = false; }
|
||
else { throw std::runtime_error("api_driver::ApiDriver::setRxTxSettings(): Wrong carrier mode: " + tmp); }
|
||
mod.is_save_current_state = pt.get<bool>(json_path("general.autoStartTx", '/'));
|
||
mod.is_test_data = pt.get<bool>(json_path("general.isTestInputData", '/'));
|
||
mod.attenuation = pt.get<double>(json_path("tx.attenuation", '/'));
|
||
mod.rollof = pt.get<double>(json_path("tx.rolloff", '/')) / 100.0;
|
||
mod.baudrate = pt.get<uint32_t>(json_path("tx.cymRate", '/'));
|
||
mod.central_freq_in_kGz = pt.get<double>(json_path("tx.centerFreq", '/'));
|
||
|
||
const bool acmIsShortFrame = !pt.get<bool>(json_path("dvbs2.frameSizeNormal", '/'));
|
||
mod.modcod_tx = (pt.get<uint32_t>(json_path("dvbs2.ccm_modcod", '/')) << 2) | (acmIsShortFrame ? 2 : 0);
|
||
#else
|
||
mod.tx_is_on = pt.get<bool>(json_path("tx.txEn", '/'));
|
||
mod.is_test_data = pt.get<bool>(json_path("tx.isTestInputData", '/'));
|
||
mod.central_freq_in_kGz = pt.get<double>(json_path("tx.centerFreq", '/'));
|
||
mod.baudrate = pt.get<uint32_t>(json_path("tx.cymRate", '/'));
|
||
mod.attenuation = pt.get<double>(json_path("tx.attenuation", '/'));
|
||
#endif
|
||
|
||
// демодулятор
|
||
#ifdef MODEM_IS_SCPC
|
||
tmp = pt.get<std::string>(json_path("rx.gainMode", '/'));
|
||
#else
|
||
auto tmp = pt.get<std::string>(json_path("rx.gainMode", '/'));
|
||
#endif
|
||
if (tmp == "auto") { demod.is_aru_on = true; }
|
||
else if (tmp == "manual") { demod.is_aru_on = false; }
|
||
else { throw std::runtime_error("api_driver::ApiDriver::setRxTxSettings(): Wrong gain mode: " + tmp); }
|
||
demod.gain = pt.get<double>(json_path("rx.manualGain", '/'));
|
||
demod.baudrate = pt.get<uint32_t>(json_path("rx.cymRate", '/'));
|
||
demod.is_rvt_iq = pt.get<bool>(json_path("rx.spectrumInversion", '/'));
|
||
demod.rollof = pt.get<double>(json_path("rx.rolloff", '/')) / 100.0;
|
||
demod.central_freq_in_kGz = pt.get<double>(json_path("rx.centerFreq", '/'));
|
||
|
||
#ifdef MODEM_IS_SCPC
|
||
// ACM
|
||
acm.enable = pt.get<bool>(json_path("dvbs2.isAcm", '/'));
|
||
acm.max_modcod = (pt.get<uint32_t>(json_path("dvbs2.acm_maxModcod", '/')) << 2) | (acmIsShortFrame ? 2 : 0);
|
||
acm.min_modcod = (pt.get<uint32_t>(json_path("dvbs2.acm_minModcod", '/')) << 2) | (acmIsShortFrame ? 2 : 0);
|
||
acm.snr_treashold_acm = pt.get<double>(json_path("dvbs2.snrReserve", '/')); // запас ОСШ
|
||
acm.period_pack = pt.get<uint32_t>(json_path("dvbs2.servicePacketPeriod", '/'));
|
||
acm.enable_auto_atten = pt.get<bool>(json_path("acm.en", '/'));
|
||
acm.max_attenuation = pt.get<double>(json_path("acm.maxAttenuation", '/'));
|
||
acm.min_attenuation = pt.get<double>(json_path("acm.minAttenuation", '/'));
|
||
acm.snr_treashold = pt.get<double>(json_path("acm.requiredSnr", '/')); // требуемый ОСШ
|
||
|
||
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{};
|
||
|
||
//result << ",\n\"cinc.mode\":" << (dpdiSettings.is_delay_window ? "\"delay\"" : "\"positional\"");
|
||
auto tmp = pt.get<std::string>(json_path("cinc.mode", '/'));
|
||
if (tmp == "delay") { s.is_delay_window = true; }
|
||
else if (tmp == "positional") { s.is_delay_window = false; }
|
||
else {
|
||
throw std::runtime_error("Wrong CinC mode: " + tmp);
|
||
}
|
||
|
||
auto ctmp = translateCoordinates(pt.get<double>(json_path("cinc.position.station.latitude", '/')));
|
||
s.latitude_station_grad = std::get<0>(ctmp);
|
||
s.latitude_station_minute = std::get<1>(ctmp);
|
||
|
||
ctmp = translateCoordinates(pt.get<double>(json_path("cinc.position.station.longitude", '/')));
|
||
s.longitude_station_grad = std::get<0>(ctmp);
|
||
s.longitude_station_minute = std::get<1>(ctmp);
|
||
|
||
ctmp = translateCoordinates(pt.get<double>(json_path("cinc.position.satelliteLongitude", '/')));
|
||
s.longitude_sattelite_grad = std::get<0>(ctmp);
|
||
s.longitude_sattelite_minute = std::get<1>(ctmp);
|
||
|
||
s.max_delay = pt.get<uint32_t>(json_path("cinc.delayMax", '/'));
|
||
s.min_delay = pt.get<uint32_t>(json_path("cinc.delayMin", '/'));
|
||
|
||
s.freq_offset = pt.get<uint32_t>(json_path("cinc.searchBandwidth", '/'));
|
||
|
||
this->daemon->setSettingsCinc(s);
|
||
}
|
||
#endif
|
||
|
||
void api_driver::ApiDriver::setBucLnbSettings(boost::property_tree::ptree &pt) {
|
||
buc_lnb_settings s{};
|
||
|
||
auto tmp = pt.get<int>(json_path("lnb.powering", '/'));
|
||
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>(json_path("lnb.refClk10M", '/'));
|
||
|
||
tmp = pt.get<int>(json_path("buc.powering", '/'));
|
||
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>(json_path("buc.refClk10M", '/'));
|
||
|
||
s.is_ref_10MHz_output = pt.get<bool>(json_path("serviceSettings.refClk10M", '/'));
|
||
s.is_save_current_state = pt.get<bool>(json_path("serviceSettings.autoStart", '/'));
|
||
|
||
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;
|
||
s.managementIp = pt.get<std::string>(json_path("network.managementIp", '/'));
|
||
s.managementGateway = pt.get<std::string>(json_path("network.managementGateway", '/'));
|
||
s.mode = pt.get<std::string>(json_path("network.mode", '/'));
|
||
s.dataIp = pt.get<std::string>(json_path("network.dataIp", '/'));
|
||
s.dataMtu = pt.get<unsigned int>(json_path("network.dataMtu", '/'));
|
||
|
||
daemon->setNetworkSettings(s);
|
||
}
|
||
|
||
void api_driver::ApiDriver::setDebugSendSettings(boost::property_tree::ptree &pt) {
|
||
boost::ignore_unused(pt);
|
||
}
|
||
|
||
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::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 */
|
||
// };
|
||
|
||
double f_load = 1.0 / (1 << SI_LOAD_SHIFT);
|
||
|
||
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;
|