diff --git a/.gitignore b/.gitignore index 144aa92..e455c7f 100644 --- a/.gitignore +++ b/.gitignore @@ -7,8 +7,7 @@ dh.pem /web-action # эти файлы после генерации должны быть перемещены в `/static` -front-generator/main-scpc.html -front-generator/main-tdma.html +front-generator/main-*.html # логи сервера в релизной версии http_server_*.log diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index f0d0ff1..d05e944 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,8 +1,8 @@ stages: - - deploy + - build test for build: - stage: deploy + stage: build image: localhost:5000/cpp-test-universal:latest tags: - cpp-test-universal @@ -13,10 +13,14 @@ test for build: - git submodule update - cmake -DCMAKE_BUILD_TYPE=Debug -DMODEM_TYPE=TDMA -B cmake-build-debug-tdma - cmake -DCMAKE_BUILD_TYPE=Debug -DMODEM_TYPE=SCPC -B cmake-build-debug-scpc + - cmake -DCMAKE_BUILD_TYPE=Debug -DMODEM_TYPE=SHPS -B cmake-build-debug-shps - cmake -DCMAKE_BUILD_TYPE=Release -DMODEM_TYPE=TDMA -B cmake-build-release-tdma - cmake -DCMAKE_BUILD_TYPE=Release -DMODEM_TYPE=SCPC -B cmake-build-release-scpc + - cmake -DCMAKE_BUILD_TYPE=Release -DMODEM_TYPE=SHPS -B cmake-build-release-shps - cmake --build cmake-build-debug-tdma -j 4 - cmake --build cmake-build-debug-scpc -j 4 + - cmake --build cmake-build-debug-shps -j 4 - cmake --build cmake-build-release-tdma -j 4 - cmake --build cmake-build-release-scpc -j 4 + - cmake --build cmake-build-release-shps -j 4 diff --git a/CMakeLists.txt b/CMakeLists.txt index e85af78..c92cea5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,8 +21,11 @@ if("${MODEM_TYPE}" STREQUAL "SCPC") elseif ("${MODEM_TYPE}" STREQUAL "TDMA") add_definitions(-DMODEM_IS_TDMA) message(STATUS "Selected TDMA modem") +elseif ("${MODEM_TYPE}" STREQUAL "SHPS") + add_definitions(-DMODEM_IS_SHPS) + message(STATUS "Selected TDMA modem") else() - message(FATAL_ERROR "You must set `MODEM_TYPE` \"SCPC\" or \"TDMA\"!") + message(FATAL_ERROR "You must set `MODEM_TYPE` \"SCPC\" or \"TDMA\" or \"SHPS\"!") endif() SET(PROJECT_GIT_REVISION "0") @@ -54,6 +57,10 @@ add_subdirectory(dependencies/control_system_client) include_directories(src/) add_executable(terminal-web-server + src/api-driver/proxy.h + src/api-driver/proxy.cpp + src/api-driver/structs.h + src/api-driver/structs.cpp src/server/mime_types.hpp src/server/mime_types.cpp src/server/request_parser.hpp diff --git a/front-generator/render-params.json b/front-generator/render-params.json index 92bf885..38a0163 100644 --- a/front-generator/render-params.json +++ b/front-generator/render-params.json @@ -350,6 +350,128 @@ {"name": "qos", "desc": "QoS"}, {"name": "admin", "desc": "Администрирование"} ] + }, + "shps": { + "modem_name": "ШПС Модем", + "dangerousParamGroups": { + "buclnb": "Применение неправильных настроек может вывести из строя оборудование! Продолжить?", + "network": "Применение этих настроек может сделать модем недоступным! Продолжить?" + }, + "params": { + "rxtx": [ + {"widget": "h2", "label": "Настройки приема/передачи"}, + { + "widget": "flex-container", + "childs": [ + { + "widget": "settings-container", + "childs": [ + {"widget": "h3", "label": "Настройки передатчика"}, + {"widget": "checkbox", "label": "Включить передатчик", "name": "txEn"}, + {"widget": "checkbox", "label": "Автоматический запуск передатчика", "name": "txAutoStart"}, + { + "widget": "select", "label": "Режим работы модулятора", "name": "txModulatorIsTest", + "values": [{"label": "Нормальный", "value": "false"}, {"label": "Тест (CW)", "value": "true"}] + }, + { + "widget": "select", "label": "Входные данные", "name": "txIsTestInput", + "values": [{"label": "Ethernet", "value": "false"}, {"label": "Тест", "value": "true"}] + }, + {"widget": "h3", "label": "Параметры передачи"}, + {"widget": "number", "label": "Центральная частота, КГц", "name": "txCentralFreq", "min": 950000, "max": 6000000, "step": 0.01}, + {"widget": "number", "label": "Символьная скорость, Бод", "name": "txBaudrate", "min": 200000, "max": 54000000}, + { + "widget": "select", "label": "Roll-off", "name": "txRolloff", + "values": [{"label": "0.02", "value": "2"}, {"label": "0.05", "value": "5"}, {"label": "0.10", "value": "10"}, {"label": "0.15", "value": "15"}, {"label": "0.20", "value": "20"}, {"label": "0.25", "value": "25"}] + }, + {"widget": "number", "label": "Коэф. расширения", "name": "txSpreadCoef", "max": 1000, "min": -1000, "step": 0.01}, + { + "widget": "select", "label": "Номер последовательности Голда", "name": "txGoldan", + "values": [{"label": "0", "value": "0"}, {"label": "1", "value": "1"}] + }, + {"widget": "number", "label": "Ослабление, дБ", "name": "txAttenuation", "max": 0, "min": -40, "step": 0.25} + ] + }, + { + "widget": "settings-container", + "childs": [ + {"widget": "h3", "label": "Настройки приемника"}, + { + "widget": "select", "label": "Режим управления усилением", "name": "rxAgcEn", + "values": [{"label": "РРУ", "value": "false"}, {"label": "АРУ", "value": "true"}] + }, + {"widget": "number", "label": "Усиление, дБ", "name": "rxManualGain", "min": -40, "step": 0.01, "max": 40, "v_show": "paramRxtx.rxAgcEn === false"}, + {"widget": "watch-expr", "label": "Текущее усиление", "expr": "paramRxtx.rxManualGain", "v_show": "paramRxtx.rxAgcEn === true"}, + {"widget": "checkbox", "label": "Инверсия спектра", "name": "rxSpectrumInversion"}, + {"widget": "number", "label": "Центральная частота, КГц", "name": "rxCentralFreq", "min": 950000, "max": 6000000, "step": 0.01}, + {"widget": "number", "label": "Символьная скорость, Бод", "name": "rxBaudrate", "min": 200000, "max": 54000000}, + { + "widget": "select", "label": "Roll-off", "name": "rxRolloff", + "values": [{"label": "0.02", "value": "2"}, {"label": "0.05", "value": "5"}, {"label": "0.10", "value": "10"}, {"label": "0.15", "value": "15"}, {"label": "0.20", "value": "20"}, {"label": "0.25", "value": "25"}] + }, + {"widget": "number", "label": "Коэф. расширения", "name": "rxSpreadCoef", "max": 1000, "min": -1000, "step": 0.01}, + { + "widget": "select", "label": "Номер последовательности Голда", "name": "rxGoldan", + "values": [{"label": "0", "value": "0"}, {"label": "1", "value": "1"}] + } + ] + } + ] + } + ], + "buclnb": [ + {"widget": "h2", "label": "Настройки питания и опорного генератора"}, + { + "widget": "flex-container", + "childs": [ + { + "widget": "settings-container", + "childs": [ + {"widget": "h3", "label": "Настройки BUC"}, + {"widget": "checkbox", "label": "Подача опоры 10МГц", "name": "bucRefClk10M"}, + { + "widget": "select", "label": "Питание BUC", "name": "bucPowering", + "values": [ + {"label": "Выкл", "value": "0"}, + {"label": "24В", "value": "24"}, + {"label": "48В", "value": "48"} + ] + } + ] + }, + { + "widget": "settings-container", + "childs": [ + {"widget": "h3", "label": "Настройки LNB"}, + {"widget": "checkbox", "label": "Подача опоры 10МГц", "name": "lnbRefClk10M"}, + { + "widget": "select", "label": "Питание LNB", "name": "lnbPowering", + "values": [ + {"label": "Выкл", "value": "0"}, + {"label": "13В", "value": "13"}, + {"label": "18В", "value": "18"}, + {"label": "24В", "value": "24"} + ] + } + ] + }, + { + "widget": "settings-container", + "childs": [ + {"widget": "h3", "label": "Сервисные настройки"}, + {"widget": "checkbox", "label": "Подача опоры 10МГц на 'Выход 10МГц'", "name": "srvRefClk10M"}, + {"widget": "checkbox", "label": "Автозапуск BUC и LNB при включении", "name": "bucLnbAutoStart"} + ] + } + ] + } + ] + }, + "tabs": [ + {"name": "monitoring", "desc": "Мониторинг"}, + {"name": "setup", "desc": "Настройки"}, + {"name": "admin", "desc": "Администрирование"} + ] } } } \ No newline at end of file diff --git a/src/api-driver/proxy.cpp b/src/api-driver/proxy.cpp new file mode 100644 index 0000000..5ff2d13 --- /dev/null +++ b/src/api-driver/proxy.cpp @@ -0,0 +1 @@ +#include "proxy.h" diff --git a/src/api-driver/proxy.h b/src/api-driver/proxy.h new file mode 100644 index 0000000..97cbd0f --- /dev/null +++ b/src/api-driver/proxy.h @@ -0,0 +1,57 @@ +#ifndef PROXY_H +#define PROXY_H + +#include +#include + + +std::ostream& operator<<(std::ostream& out, CP_Result result); + +namespace api_driver { + /** + * Функция-хелпер для логгирования ошибок всех вызовов API. + * @return то же значение ошибки, что и было передано в качестве параметра + */ + CP_Result logCpApiError(const char* desc, CP_Result err) { + if (err != OK) { + BOOST_LOG_TRIVIAL(error) << "CP API error in " << desc << ": " << err; + } + return err; + } +} + +#define CPAPI_PROXY_CALL(proxy, func, ...) do { auto _res = func(proxy.sid, __VA_ARGS__); if (_res != OK) { BOOST_LOG_TRIVIAL(error) << "CP API error in " #func "(" #__VA_ARGS__ "): " << _res; } } while (0) + +// void foo() { +// api_driver::proxy::CpProxy proxy; +// std::string tmp; +// CPAPI_PROXY_CALL(proxy, CP_GetDmaDebug, "fuck", &tmp); +// } + +namespace api_driver::proxy { + class CpProxy { + public: + TSID sid; + CpProxy(); + CpProxy(TSID s); + + std::string getDmaDebug(TSID sid, const std::string& arg, const char* calledFrom = ""); + + void getModState(TSID sid, modulator_state& dest, const char* calledFrom = ""); + void getModSettings(TSID sid, modulator_settings& dest, const char* calledFrom = ""); + void setModSettings(TSID sid, modulator_settings& dest, const char* calledFrom = ""); + + void getDemodState(TSID sid, demodulator_state& dest, const char* calledFrom = ""); + void getDemodSettings(TSID sid, demodulator_settings& dest, const char* calledFrom = ""); + void setDemodSettings(TSID sid, demodulator_settings& dest, const char* calledFrom = ""); + +#ifdef MODEM_IS_SCPC + void getCincState(TSID sid, demodulator_settings& dest, const char* calledFrom = ""); +#endif + + ~CpProxy(); + }; +} + + +#endif //PROXY_H diff --git a/src/api-driver/structs.cpp b/src/api-driver/structs.cpp new file mode 100644 index 0000000..4ff2b88 --- /dev/null +++ b/src/api-driver/structs.cpp @@ -0,0 +1,206 @@ +#include "api-driver/structs.h" + +#include + +#include "api-driver/proxy.h" + +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(result); + } + return out; +} + +std::string makeTimepointFromMillis(int64_t unix_time_ms) { + // Преобразуем миллисекунды в микросекунды для std::chrono + auto time_point = std::chrono::time_point(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(); +} + + +bool api_driver::obj::CpUpdatebleObject::checkNeedUpdate(int64_t now) const { + if (updatePeriodMs < 0) return false; + // тут нет смысла спать меньше чем на 20мс, поэтому можно разрешить чтение на некоторое время раньше + return now - lastUpdate >= (updatePeriodMs - 20); +} +int64_t api_driver::obj::CpUpdatebleObject::getNextUpdate(int64_t now) const { + if (checkNeedUpdate(now)) { + return 0; + } + auto next = now - lastUpdate; + return next < 0 ? 0 : next; +} +api_driver::obj::CpUpdatebleObject::~CpUpdatebleObject() = default; + + +void api_driver::obj::TerminalState::updateCallback(TSID sid, CP_Result &lastCpError) { + constexpr const char* thisFunc = "api_driver::obj::TerminalState::load()"; + + modulator_state modulator{}; + demodulator_state demodulator{}; +#ifdef MODEM_IS_SCPC + CinC_state cinc{}; +#endif + + proxy::getModState(sid, modulator, thisFunc); + proxy::getDemodState(sid, demodulator, thisFunc); +#ifdef MODEM_IS_TDMA + const auto tmpDevState = proxy::getDmaDebug(sid, "status_init", thisFunc); +#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->mutex); +#ifdef MODEM_IS_TDMA + this->fInitState = tmpDevState; +#endif + this->fTxState = modulator.is_tx_on; + this->fTxModcod = modulator.modcod; + this->fTxSnr = modulator.snr_remote; + this->fTxframeSizeNormal = modulator.snr_remote; + this->fTx = modulator.snr_remote; + this->fTx = modulator.snr_remote; + this->fTx = modulator.snr_remote; +#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, nullptr); + result << ",\"tx.centerFreq\":"; writeDouble(result, modSet.central_freq_in_kGz); + result << ",\"tx.symSpeed\":"; writeDouble(result, (static_cast(modSet.baudrate) / 1000.0)); + } +#endif + + /* + + + result << ",\"tx.speedOnTxKbit\":"; writeDouble(result, static_cast(modulator.speed_in_bytes_tx) / 128.0); + result << ",\"tx.speedOnIifKbit\":"; writeDouble(result, (static_cast(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(demodulator.speed_in_bytes_rx) / 128.0); + result << ",\"rx.speedOnIifKbit\":"; writeDouble(result, static_cast(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); +#ifdef MODEM_IS_TDMA + if (device.cur_image.empty()) { + result << R"(, +"device.upgradeStatus":"Нет обновлений","device.upgradePercent":0,"device.upgradeImage":"")"; + } else { + switch (device.status) { + case NORM_RX_OBJECT_NEW_API: result << ",\n" R"("device.upgradeStatus": "Начало загрузки")"; break; + case NORM_RX_OBJECT_INFO_API: result << ",\n" R"("device.upgradeStatus": "Получено имя образа")"; break; + case NORM_RX_OBJECT_UPDATED_API: result << ",\n" R"("device.upgradeStatus": "Загружается")"; break; + case NORM_RX_OBJECT_COMPLETED_API: result << ",\n" R"("device.upgradeStatus": "Загрузка завершена")"; break; + case NORM_RX_OBJECT_ABORTED_API: result << ",\n" R"("device.upgradeStatus": "Загрузка прервана")"; break; + default: result << ",\n" R"("device.upgradeStatus": "?")"; + + } + result << ",\"device.upgradePercent\":" << device.dwl_percent; + result << ",\"device.upgradeImage\":" << buildEscapedString(device.cur_image); + } + +#endif + + result << "}"; + */ + this->modState = modulator; + this->demodState = demodulator; + +#ifdef MODEM_IS_SCPC + this->cincState = cinc; +#endif + } +} + + +api_driver::obj::TerminalState::~TerminalState() = default; + + + + + diff --git a/src/api-driver/structs.h b/src/api-driver/structs.h new file mode 100644 index 0000000..094146b --- /dev/null +++ b/src/api-driver/structs.h @@ -0,0 +1,279 @@ +#ifndef STRUCTS_H +#define STRUCTS_H +#include +#include +#include +#include +#include + + +namespace api_driver::obj { + /** + * Обертка для объектов, доступных для обновления + * NOTE: перед вызовом функций, требующих `TSID`, необходимо захватить мютекс API. + */ + class CpUpdatebleObject { + public: + int64_t lastUpdate = 0; + int64_t updatePeriodMs = -1; + + virtual void updateCallback(TSID sid, CP_Result& lastCpError) = 0; + + bool checkNeedUpdate(int64_t now) const; + + int64_t getNextUpdate(int64_t now) const; + + virtual ~CpUpdatebleObject(); + }; + + +#ifdef MODEM_IS_SCPC + class api_driver::StatisticsLogger { + public: + StatisticsLogger(): timeStart(TIME_NOW()) {} + + int64_t timeStart; + + bool logEn = false; + std::atomic logPeriodMs = 1000; + std::atomic maxAgeMs = 10000; + + /** + * + * @return {"en": bool, "logPeriodMs": int, "maxAgeMs": 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("en"); + const int newInterval = pt.get("logPeriodMs"); + const int newMaxAgeMs = pt.get("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(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(out.length())); + this->logFile.flush(); + } + } + + // void collectExpiredItems(); + + // void resetLogs() { + // std::lock_guard _lock(mutex); + // logs.clear(); + // } + + ~StatisticsLogger() = default; + private: + // std::pmr::deque logs; + std::fstream logFile{}; + std::shared_mutex mutex; + }; +#endif + +#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 + +#if defined(MODEM_IS_SCPC) + class TerminalNetworkSettings: public CpUpdatebleObject { + public: + std::string managementIp, managementGateway, dataIp, serverName; + bool isL2 = true; + unsigned int dataMtu = 1500; + + TerminalNetworkSettings(); + TerminalNetworkSettings(const TerminalNetworkSettings& src); + TerminalNetworkSettings& operator= (const TerminalNetworkSettings& src); + + void loadDefaults() { + managementIp = "0.0.0.0"; + managementGateway = ""; + isL2 = true; + dataIp = "0.0.0.0"; + dataMtu = 1500; + serverName = DEFAULT_SERVER_NAME; + } + + void updateCallback(TSID sid, CP_Result &lastCpError) override; + void updateFromPt(boost::property_tree::ptree &pt); + void store(TSID sid, CP_Result& lastCpError); + std::string asJson(); + + ~TerminalNetworkSettings() override; + }; +#endif + + class TerminalFirmwareVersion { + public: + std::string version, modemId, modemSn, macMang, macData; + + TerminalFirmwareVersion(); + TerminalFirmwareVersion(const TerminalFirmwareVersion& src); + ~TerminalFirmwareVersion(); + + std::string asJson(); + + TerminalFirmwareVersion& operator= (const TerminalFirmwareVersion& src); + }; + + /** + * Обертка состояния терминала, тут состояние девайса, модулятора/демодулятора, состояние автоматического обновления. + */ + class TerminalState: public CpUpdatebleObject { + public: + std::string fInitState{}; + bool fIsTest = false; // daemon->isTest() + bool fTxState = false; +#ifdef MODEM_IS_SCPC + bool fIsCinC = false; +#endif + + bool fStatRxState; + bool fStatRxSymSyncLock; + bool fStatRxFreqSearchLock; + bool fStatRxAfcLock; + bool fStatRxPktSync; + + float fStatRxSnr; + float fStatRxRssi; + uint16_t fStatRxModcod; + bool fStatRxFrameSizeNormal; + bool fStatRxIsPilots; + + double fStatRxSymError; + double fStatRxFreqErr; + double fStatRxFreqErrAcc; + double fStatRxInputSignalLevel; + double fStatRxPllError; + double fStatRxSpeedOnRxKbit; + double fStatRxSpeedOnIifKbit; + uint32_t fStatRxPacketsOk; + uint32_t fStatRxPacketsBad; + uint32_t fStatRxPacketsDummy; + + bool fStatTxState; + uint16_t fStatTxModcod; + double fStatTxSpeedOnTxKbit; + double fStatTxSpeedOnIifKbit; +#ifdef MODEM_IS_SCPC + float fStatTxSnr; + bool fStatTxFrameSizeNormal; + bool fStatTxIsPilots; + double fStatCincOcc; + bool fStatCincCorrelator; + uint32_t fStatCincCorrelatorFails; + int32_t fStatCincFreqErr; + int32_t fStatCincFreqErrAcc; + float fStatCincChannelDelay; +#endif +#ifdef MODEM_IS_TDMA + fStatTxCenterFreq; + fStatTxSymSpeed; +#endif + + /** + * Обновление основной части статистики, то есть RX/TX и sysinfo + */ + void updateCallback(TSID sid, CP_Result &lastCpError) override; + + void updateFromPt(boost::property_tree::ptree &pt); + void store(TSID sid, CP_Result& lastCpError); + std::string asJson(); + + ~TerminalState() override; + }; + + class TerminalDeviceState: public CpUpdatebleObject { + public: + time_t fStatOsUptime; + double fStatOsLoad1; + double fStatOsLoad5; + double fStatOsLoad15; + int fStatOsTotalram; + int fStatOsFreeram; + int fStatOsProcs; + + double fStatDeviceAdrv; + double fStatDeviceZynq; + double fStatDeviceFpga; +#ifdef MODEM_IS_TDMA + DOWNLOAD_STATUS fStatDeviceUpgradeStatus; + unsigned int fStatDeviceUpgradePercent; + std::string fStatDeviceUpgradeImage; +#endif + + void updateCallback(TSID sid, CP_Result &lastCpError) override; + void updateFromPt(boost::property_tree::ptree &pt); + void store(TSID sid, CP_Result& lastCpError); + std::string asJson(); + + ~TerminalDeviceState() override; + }; +} + +#endif //STRUCTS_H diff --git a/src/terminal_api_driver.h b/src/terminal_api_driver.h index 3b5a255..1bf7040 100644 --- a/src/terminal_api_driver.h +++ b/src/terminal_api_driver.h @@ -1,7 +1,6 @@ #ifndef TERMINAL_API_DRIVER_H #define TERMINAL_API_DRIVER_H -#include #include #include #include diff --git a/static/main-shps.html b/static/main-shps.html new file mode 100644 index 0000000..e1ecd63 --- /dev/null +++ b/static/main-shps.html @@ -0,0 +1,764 @@ + + + + + + ШПС Модем + + + + + + + + + + + \ No newline at end of file