terminal-web-server/src/terminal_api_driver.cpp

906 lines
37 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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 "../dependencies/control_system/common/protocol_commands.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/0";
managementGateway = "";
mode = "l2";
dataIp = "0.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;
};
/**
* Этот демон нужен для того, чтобы получать статистику из API, а так же корректно сохранять настройки
*/
class api_driver::TerminalApiDaemon {
private:
void updateState() {
modulator_state modulator{};
demodulator_state demodulator{};
device_state device{};
CinC_state cinc{};
std::lock_guard lock(this->cpApiMutex);
CP_GetModulatorState(sid, modulator);
CP_GetDemodulatorState(sid, demodulator);
CP_GetDeviceState(sid, device);
bool isCinC = getIsCinC();
if (isCinC) {
CP_GetCinCState(sid, cinc);
}
{
std::lock_guard lock2(this->stateMutex);
this->modState = modulator;
this->demodState = demodulator;
this->devState = device;
this->cincState = cinc;
}
}
void updateSettings() {
modulator_settings mod{};
// uint32_t modulatorModcod;
// CP_GetModulatorParams(sid, "modcod", &modulatorModcod);
demodulator_settings demod{};
ACM_parameters_serv_ acm{};
DPDI_parmeters dpdi{};
buc_lnb_settings bucLnb{};
std::lock_guard lock(this->cpApiMutex);
CP_GetModulatorSettings(sid, mod);
CP_GetDemodulatorSettings(sid, demod);
CP_GetAcmParams(sid, &acm);
CP_GetDpdiParams(sid, &dpdi);
CP_GetBUC_LNB_settings(sid, bucLnb);
{
std::lock_guard lock2(this->settingsMutex);
this->modSettings = mod;
this->demodSettings = demod;
this->acmSettings = acm;
this->dpdiSettings = dpdi;
this->bucLnbSettings = bucLnb;
}
}
void updateNetworkSettings() {
TerminalNetworkSettings s;
std::string tmp;
std::lock_guard lock(this->cpApiMutex);
CP_GetNetwork(sid, "addr", &tmp);
s.managementIp = tmp + "/";
tmp.clear(); CP_GetNetwork(sid, "mask", &tmp);
s.managementIp += std::to_string(calculateSubnetMask(tmp));
tmp.clear(); CP_GetNetwork(sid, "gateway", &s.managementGateway); s.managementGateway = tmp;
tmp.clear(); CP_GetNetwork(sid, "mode", &tmp);
if (tmp == "tun") {
s.mode = "l3";
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};
CP_GetQoSSettings(this->sid, tmp2, tmp1);
{
std::lock_guard lock2(this->qosSettingsMutex);
this->qosEnabled = tmp1;
this->qosClassesJson = tmp2.empty() ? DEFAULT_QOS_CLASSES : tmp2;
}
}
void run() {
// это демон, который в бесконечном цикле опрашивает API
CP_GetNetwork(sid, "version", &firmware.version);
CP_GetNetwork(sid, "chip_id", &firmware.modemId);
rtrim(firmware.modemId);
CP_GetNetwork(sid, "serial", &firmware.modemSn);
CP_GetNetwork(sid, "mac_eth0", &firmware.macMang);
CP_GetNetwork(sid, "mac_eth1", &firmware.macData);
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) {
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{};
CinC_state cincState{};
std::shared_mutex settingsMutex;
modulator_settings modSettings{};
demodulator_settings demodSettings{};
ACM_parameters_serv_ acmSettings{};
DPDI_parmeters dpdiSettings{};
buc_lnb_settings bucLnbSettings{};
std::shared_mutex networkSettingsMutex;
TerminalNetworkSettings networkSettings;
std::shared_mutex qosSettingsMutex;
bool qosEnabled;
std::string qosClassesJson;
public:
std::mutex cpApiMutex;
TSID sid;
boost::thread daemon;
TerminalFirmwareVersion firmware;
explicit TerminalApiDaemon(TSID sid): qosEnabled(false), sid(sid), daemon([this]() { this->run(); }) {
this->qosClassesJson = DEFAULT_QOS_CLASSES;
}
/**
* Получение статистики, копирует текущие значения в структуры, переданные по указателю. Если передан пустой указатель, копирования не произойдет.
* @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; }
}
}
/**
* Получение настроек, копирует текущие значения в структуры, переданные по указателю. Если передан пустой указатель, копирования не произойдет.
*/
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; }
}
}
bool getIsCinC() {
std::shared_lock lock(this->settingsMutex);
return modSettings.is_cinc;
}
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;
}
void setSettingsRxTx(modulator_settings& mod, demodulator_settings& demod, ACM_parameters_serv_& acm, bool readback = true) {
std::lock_guard lock(this->cpApiMutex);
CP_SetDmaDebug(sid, "begin_save_config", "");
CP_SetModulatorSettings(this->sid, mod);
CP_SetDemodulatorSettings(this->sid, demod);
CP_SetAcmParams(this->sid, acm);
if (readback) {
CP_GetModulatorSettings(this->sid, mod);
CP_GetDemodulatorSettings(this->sid, demod);
CP_GetAcmParams(this->sid, &acm);
{
std::lock_guard lock2{this->settingsMutex};
this->modSettings = mod;
this->demodSettings = demod;
this->acmSettings = acm;
}
}
CP_SetDmaDebug(sid, "save_config", "");
}
void setSettingsCinc(DPDI_parmeters& s, bool readback = true) {
std::lock_guard lock(this->cpApiMutex);
CP_SetDmaDebug(sid, "begin_save_config", "");
CP_SetDpdiParams(sid, s);
if (readback) {
CP_GetDpdiParams(this->sid, &s);
{
std::lock_guard lock2{this->settingsMutex};
this->dpdiSettings = s;
}
}
CP_SetDmaDebug(sid, "save_config", "");
}
void setSettingsBucLnb(buc_lnb_settings& bucLnb, bool readback = true) {
std::lock_guard lock(this->cpApiMutex);
CP_SetDmaDebug(sid, "begin_save_config", "");
CP_SetBUC_LNB_settings(this->sid, bucLnb);
if (readback) {
CP_GetBUC_LNB_settings(this->sid, bucLnb);
{
std::lock_guard lock2{this->settingsMutex};
this->bucLnbSettings = bucLnb;
}
}
CP_SetDmaDebug(sid, "save_config", "");
}
void setQosSettings(bool enabled, const std::string& str, bool readback = true) {
std::lock_guard lock(this->cpApiMutex);
CP_SetDmaDebug(sid, "begin_save_config", "");
CP_SetQoSSettings(this->sid, str, enabled);
if (readback) {
bool tmp1; std::string tmp2;
CP_GetQoSSettings(this->sid, tmp2, tmp1);
{
std::lock_guard lock2(this->qosSettingsMutex);
this->qosEnabled = tmp1;
this->qosClassesJson = tmp2.empty() ? DEFAULT_QOS_CLASSES : tmp2;
}
}
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);
CP_SetDmaDebug(sid, "begin_save_config", "");
CP_SetNetwork(sid, "mode", isL2 ? "tap" : "tun");
CP_SetNetwork(sid, "addr", mang.first.c_str());
CP_SetNetwork(sid, "mask", mang.second.c_str());
CP_SetNetwork(sid, "gateway", s.managementGateway.c_str());
if (!isL2) {
CP_SetNetwork(sid, "data_addr", data.first.c_str());
// TODO маска не устанавливается, потому что в API этого нет
}
// TODO MTU не устанавливается, потому что в API этого нет
if (readback) {
std::string tmp;
s.loadDefaults();
s.managementIp.clear();
CP_GetNetwork(sid, "addr", &s.managementIp);
CP_GetNetwork(sid, "mask", &tmp);
s.managementIp += "/";
s.managementIp += std::to_string(calculateSubnetMask(tmp));
CP_GetNetwork(sid, "gateway", &s.managementGateway);
tmp.clear(); CP_GetNetwork(sid, "mode", &tmp);
if (tmp == "tun") {
s.mode = "l3";
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;
}
}
CP_SetDmaDebug(sid, "save_config", "");
}
void resetPacketStatistics() {
std::string tmp;
std::lock_guard lock(this->cpApiMutex);
CP_GetDmaDebug(sid, "reset_cnt_rx", &tmp);
}
void resetDefaultSettings() {
std::lock_guard lock(this->cpApiMutex);
CP_SetDmaDebug(sid, "begin_save_config", " ");
CP_SetDmaDebug(sid, "default_params", "");
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) {
TSID sid{};
unsigned int access{};
for (int connectAttempt = 0; connectAttempt <= 10; connectAttempt++) {
BOOST_LOG_TRIVIAL(info) << "api_driver::ApiDriver::startDaemon(): Try to connect api (attempt " << connectAttempt << ")...";
auto res = CP_Login("admin", "pass", &sid, &access);
if (res != OK) {
boost::this_thread::sleep_for(boost::chrono::duration(boost::chrono::milliseconds(1000)));
} else {
break;
}
}
CP_GetDmaDebug(sid, "status_init", &deviceInitState);
BOOST_LOG_TRIVIAL(info) << "api_driver::ApiDriver::startDaemon(): Success connect!";
BOOST_LOG_TRIVIAL(info) << "api_driver::ApiDriver::startDaemon(): API status: " << deviceInitState;
daemon = std::make_unique<TerminalApiDaemon>(sid);
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;
}
}
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);
}
std::string api_driver::ApiDriver::loadTerminalState() const {
if (daemon == nullptr) {
return R"({"error": "api daemon not started!"})";
}
std::stringstream result;
result << "{\n\"initState\":" << buildEscapedString(this->deviceInitState);
modulator_state modulator{};
demodulator_state demodulator{};
device_state device{};
CinC_state cinc{};
daemon->getState(&modulator, &demodulator, &device, &cinc);
const bool isCinC = this->daemon->getIsCinC();
result << ",\"isCinC\":" << boolAsStr(isCinC);
// формируем структуру для TX
result << ",\n\"tx.state\":" << boolAsStr(modulator.is_tx_on);
result << ",\"tx.modcod\":" << modulator.modcod;
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)";
}
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;
// формируем структуру для 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)";
}
// структура температур девайса
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();
}
std::string api_driver::ApiDriver::loadSettings() const {
if (daemon == nullptr) {
return R"({"error": "api daemon not started!"})";
}
modulator_settings modSettings{};
demodulator_settings demodSettings{};
ACM_parameters_serv_ acmSettings{};
DPDI_parmeters dpdiSettings{};
buc_lnb_settings bucLnb{};
TerminalNetworkSettings network;
daemon->getSettings(&modSettings, &demodSettings, &acmSettings, &dpdiSettings, &bucLnb);
daemon->getNetworkSettings(network);
std::stringstream result;
result << "{\n\"general.isCinC\":" << boolAsStr(modSettings.is_cinc);
result << ",\"general.txEn\":" << boolAsStr(modSettings.tx_is_on);
result << ",\"general.modulatorMode\":" << (modSettings.is_carrier ? "\"normal\"" : "\"test\"");
result << ",\"general.autoStartTx\":" << boolAsStr(modSettings.is_save_current_state);
result << ",\"general.isTestInputData\":" << boolAsStr(modSettings.is_test_data);
result << ",\n\"tx.attenuation\":"; writeDouble(result, modSettings.attenuation);
result << ",\"tx.rolloff\":" << static_cast<int>(modSettings.rollof * 100);
result << ",\"tx.cymRate\":" << modSettings.baudrate;
result << ",\"tx.centerFreq\":"; writeDouble(result, modSettings.central_freq_in_kGz, 3);
result << ",\"dvbs2.frameSizeNormal\":" << boolAsStr(!(modSettings.modcod_tx & 2));
result << ",\"dvbs2.ccm_modcod\":" << (modSettings.modcod_tx >> 4);
// result << ",\"dvbs2.isPilots\":" << "null";
result << ",\n\"dvbs2.isAcm\":" << 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 << ",\"dvbs2.servicePacketPeriod\":" << 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;
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;
result << "{\n\"fw.version\":" << buildEscapedString(daemon->firmware.version);
result << ",\"fw.modemId\":" << buildEscapedString(daemon->firmware.modemId);
result << ",\"fw.modemSn\":" << buildEscapedString(daemon->firmware.modemSn);
result << ",\"fw.macMang\":" << buildEscapedString(daemon->firmware.macMang);
result << ",\"fw.macData\":" << buildEscapedString(daemon->firmware.macData);
result << "\n}";
return result.str();
}
void api_driver::ApiDriver::setRxTxSettings(boost::property_tree::ptree &pt) {
modulator_settings mod{};
demodulator_settings demod{};
ACM_parameters_serv_ acm{};
// для модулятора
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);
// демодулятор
tmp = pt.get<std::string>(json_path("rx.gainMode", '/'));
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", '/'));
// 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);
}
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", '/'));
this->daemon->setSettingsCinc(s);
}
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;
case 48: s.buc = voltage_buc::_48V; break;
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();
}
}
api_driver::ApiDriver::~ApiDriver() = default;