Compare commits

..

30 Commits

Author SHA1 Message Date
483c174cd5 обновление TDMA вебки: добавил лимит ослабления 2025-09-09 13:56:16 +03:00
eb1e4609bb обновление ШПС вебки: исправил порог коррелятора по просьбе @hernayo, обновление control system api 2025-09-08 11:27:35 +03:00
00a9692b3d обновление ШПС вебки: исправил порог коррелятора по просьбе @hernayo 2025-09-06 12:12:09 +03:00
89004bcf31 обновление ШПС вебки: исправление полей для ввода частоты 2025-09-05 17:48:35 +03:00
b580ac6b37 обновление ШПС вебки: добавление новых полей, удаление полей из мониторинга и обновление страницы настроек 2025-09-05 16:09:37 +03:00
7cd096a269 feature: добавил поле для ввода пароля входа в сеть ЦЗС 2025-08-13 11:16:14 +03:00
beca00ff70 fix: восстановил чтение статуса обновление с предупреждением, что в этом месте API зависает 2025-07-18 16:32:05 +03:00
ed6694b99d CI: установка переменной GIT_SUBMODULE_STRATEGY=recursive 2025-07-14 13:31:46 +03:00
305a8c54fa Merge remote-tracking branch 'origin/tdma-lo-feature' 2025-07-14 11:38:43 +03:00
297e681b75 привет, зоопарк веток control_system_client! зато теперь вебка должна собираться для всех модемов из одной ветки 2025-07-14 11:37:40 +03:00
32720ca365 fix: scpc некорректный максимальный модкод для ACM 2025-07-10 11:26:42 +03:00
33bbdafc3d fix: tdma временное отключение мониторинга статуса обновления и фикс установки настроек DPDI 2025-07-05 15:10:09 +03:00
bfcdc88da9 fix: tdma+scpc не читались и не применялись настройки DPDI 2025-07-05 14:38:04 +03:00
760a6858ee feature: LO freq для BUC и LNB 2025-07-05 13:54:21 +03:00
e9ff1d099a fix: set ACM settings 2025-07-02 15:33:06 +03:00
11e4561551 fix: aupcRequiredSnr - изменена граница допустимых значений 2025-07-02 14:52:17 +03:00
081ef1b84f fix: большие числа в мониторинге параметров (2) 2025-07-02 13:20:30 +03:00
bb90a3fec2 unlock: установил нижний предел частот 100MHz вместо 950MHz 2025-06-17 13:08:00 +03:00
9fbe88b64d фича: маска для сети управления + исправление багов на странице для разработчиков 2025-06-05 17:07:27 +03:00
996e711436 фича: бекап параметров и восстановление через вебку 2025-06-05 15:21:18 +03:00
57ba61da41 фикс огромных чисел на странице мониторинга 2025-06-05 11:22:34 +03:00
b9a25e8734 фикс roll-off, фикс нечитающихся настроек сети, фикс значений на странице мониторинга, добавил авто-регулировку мощности в ШПС 2025-06-05 11:15:13 +03:00
1e185a987d мелкие косметические изменения, добавил в вебку ШПС настройки сети 2025-06-05 10:29:58 +03:00
4c555d5400 bugfix: исправление ошибки, из-за которой не показываются сведения о ПО и системе 2025-06-04 16:54:40 +03:00
38a00173a2 отладочная версия веб-сервера, работает со статистикой и настройкой. Не показывает параметры прошивки 2025-06-04 13:23:27 +03:00
e5e6878351 компилируемая версия веб-сервера, находится на стадии отладки 2025-06-04 11:04:51 +03:00
55fc322c13 исправления методов-заглушек, часть 1 2025-06-03 18:32:28 +03:00
f30e1adb49 компилируемая версия для всех версий модемов, пока без CP Proxy 2025-06-03 16:16:41 +03:00
50f82483fd исправления для TDMA 2025-06-01 15:59:42 +03:00
c2dd4b13e8 условно компилируемый проект после рефактора, еще нет настроек rxtx 2025-06-01 15:49:31 +03:00
29 changed files with 27613 additions and 2226 deletions

View File

@@ -8,9 +8,9 @@ test for build:
- cpp-test-universal - cpp-test-universal
only: only:
- master - master
variables:
GIT_SUBMODULE_STRATEGY: recursive
script: script:
- git submodule init
- git submodule update
- cmake -DCMAKE_BUILD_TYPE=Debug -DMODEM_TYPE=TDMA -B cmake-build-debug-tdma - 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=SCPC -B cmake-build-debug-scpc
- cmake -DCMAKE_BUILD_TYPE=Debug -DMODEM_TYPE=SHPS -B cmake-build-debug-shps - cmake -DCMAKE_BUILD_TYPE=Debug -DMODEM_TYPE=SHPS -B cmake-build-debug-shps

6
.gitmodules vendored
View File

@@ -1,3 +1,9 @@
[submodule "dependencies/control_system_client"] [submodule "dependencies/control_system_client"]
path = dependencies/control_system_client path = dependencies/control_system_client
url = http://gitlab.devrss.vg/mf-tdma/protocol_processing/control_system_client.git url = http://gitlab.devrss.vg/mf-tdma/protocol_processing/control_system_client.git
[submodule "dependencies/control_system_client_tdma"]
path = dependencies/control_system_client_tdma
url = http://gitlab.devrss.vg/mf-tdma/protocol_processing/control_system_client.git
[submodule "dependencies/control_system_client_shps"]
path = dependencies/control_system_client_shps
url = http://gitlab.devrss.vg/mf-tdma/protocol_processing/control_system_client.git

View File

@@ -18,12 +18,15 @@ endif()
if("${MODEM_TYPE}" STREQUAL "SCPC") if("${MODEM_TYPE}" STREQUAL "SCPC")
add_definitions(-DMODEM_IS_SCPC) add_definitions(-DMODEM_IS_SCPC)
message(STATUS "Selected SCPC modem") message(STATUS "Selected SCPC modem")
add_subdirectory(dependencies/control_system_client) # подключение правильного control system client SCPC, ветка main
elseif ("${MODEM_TYPE}" STREQUAL "TDMA") elseif ("${MODEM_TYPE}" STREQUAL "TDMA")
add_definitions(-DMODEM_IS_TDMA) add_definitions(-DMODEM_IS_TDMA)
message(STATUS "Selected TDMA modem") message(STATUS "Selected TDMA modem")
add_subdirectory(dependencies/control_system_client_tdma) # подключение правильного control system client TDMA, ветка terminal-tdma
elseif ("${MODEM_TYPE}" STREQUAL "SHPS") elseif ("${MODEM_TYPE}" STREQUAL "SHPS")
add_definitions(-DMODEM_IS_SHPS) add_definitions(-DMODEM_IS_SHPS)
message(STATUS "Selected TDMA modem") message(STATUS "Selected SHPS modem")
add_subdirectory(dependencies/control_system_client_shps) # подключение правильного control system client SHPS, ветка shps
else() else()
message(FATAL_ERROR "You must set `MODEM_TYPE` \"SCPC\" or \"TDMA\" or \"SHPS\"!") message(FATAL_ERROR "You must set `MODEM_TYPE` \"SCPC\" or \"TDMA\" or \"SHPS\"!")
endif() endif()
@@ -52,7 +55,6 @@ add_compile_options(-Wall -Wextra -Wsign-conversion -DPROJECT_GIT_REVISION="${PR
# максимальный размер тела запроса 200mb # максимальный размер тела запроса 200mb
add_definitions(-DHTTP_MAX_PAYLOAD=200000000) add_definitions(-DHTTP_MAX_PAYLOAD=200000000)
add_subdirectory(dependencies/control_system_client)
include_directories(src/) include_directories(src/)
@@ -63,6 +65,7 @@ add_executable(terminal-web-server
src/api-driver/proxy.cpp src/api-driver/proxy.cpp
src/api-driver/structs.h src/api-driver/structs.h
src/api-driver/structs.cpp src/api-driver/structs.cpp
src/common/nlohmann/json.hpp
src/server/mime_types.hpp src/server/mime_types.hpp
src/server/mime_types.cpp src/server/mime_types.cpp
src/server/request_parser.hpp src/server/request_parser.hpp

View File

@@ -44,6 +44,25 @@ def cp_get_dma_debug(base_url, param_name):
return res.content.decode('utf-8') return res.content.decode('utf-8')
def cp_set_network(base_url, param_name, value):
session = do_login(base_url)
res = session.post(f"{base_url}/dev/cpapicall", params={
"f": "SetDmaDebug",
"param": param_name,
"value": value
})
return res.content.decode('utf-8')
def cp_get_network(base_url, param_name):
session = do_login(base_url)
res = session.post(f"{base_url}/dev/cpapicall", params={
"f": "GetDmaDebug",
"param": param_name
})
return res.content.decode('utf-8')
def set_logging(base_url, value): def set_logging(base_url, value):
print(cp_set_dma_debug(base_url, "log_bool", value)) print(cp_set_dma_debug(base_url, "log_bool", value))
@@ -53,6 +72,8 @@ if __name__ == '__main__':
print(f"Usage: {sys.argv[0]} http(s)://terminal-url logging on|off") print(f"Usage: {sys.argv[0]} http(s)://terminal-url logging on|off")
print(f" set_dma_debug <param_name> <value>") print(f" set_dma_debug <param_name> <value>")
print(f" get_dma_debug <param_name>") print(f" get_dma_debug <param_name>")
print(f" set_network <param_name> <value>")
print(f" get_network <param_name>")
exit(1) exit(1)
if sys.argv[2] == "logging": if sys.argv[2] == "logging":
@@ -67,7 +88,17 @@ if __name__ == '__main__':
print(cp_set_dma_debug(sys.argv[1], sys.argv[3], sys.argv[4])) print(cp_set_dma_debug(sys.argv[1], sys.argv[3], sys.argv[4]))
elif sys.argv[2] == "get_dma_debug": elif sys.argv[2] == "get_dma_debug":
if len(sys.argv) != 4: if len(sys.argv) != 4:
print("Wrong set dma debug usage!") print("Wrong get dma debug usage!")
else:
print(cp_get_dma_debug(sys.argv[1], sys.argv[3]))
elif sys.argv[2] == "set_network":
if len(sys.argv) != 5:
print("Wrong set network usage!")
else:
print(cp_set_dma_debug(sys.argv[1], sys.argv[3], sys.argv[4]))
elif sys.argv[2] == "get_network":
if len(sys.argv) != 4:
print("Wrong get dma debug usage!")
else: else:
print(cp_get_dma_debug(sys.argv[1], sys.argv[3])) print(cp_get_dma_debug(sys.argv[1], sys.argv[3]))
else: else:

View File

@@ -22,7 +22,8 @@
"values": [{"label": "Нормальный", "value": "false"}, {"label": "Тест (CW)", "value": "true"}] "values": [{"label": "Нормальный", "value": "false"}, {"label": "Тест (CW)", "value": "true"}]
}, },
{"widget": "number-int", "label": "Центральная частота, КГц", "name": "txCentralFreq", "min": 900000, "step": 0.01, "v_show": "paramRxtx.txModulatorIsTest"}, {"widget": "number-int", "label": "Центральная частота, КГц", "name": "txCentralFreq", "min": 900000, "step": 0.01, "v_show": "paramRxtx.txModulatorIsTest"},
{"widget": "number", "label": "Ослабление, дБ", "name": "txAttenuation", "max": 0, "min": -90, "step": 1} {"widget": "number", "label": "Ослабление, дБ", "name": "txAttenuation", "max": 0, "min": -90, "step": 1},
{"widget": "number", "label": "Ограничение ослабления", "name": "txAttenuationLimit", "max": 0, "min": -40, "step": 0.25}
] ]
}, },
{ {
@@ -42,7 +43,7 @@
{"widget": "number-int", "label": "Символьная скорость, Бод", "name": "rxBaudrate", "min": 200000, "max": 54000000, "step": 1}, {"widget": "number-int", "label": "Символьная скорость, Бод", "name": "rxBaudrate", "min": 200000, "max": 54000000, "step": 1},
{ {
"widget": "select", "label": "Roll-off", "name": "rxRolloff", "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"}] "values": [{"label": "0.02", "value": "20"}, {"label": "0.05", "value": "50"}, {"label": "0.10", "value": "100"}, {"label": "0.15", "value": "150"}, {"label": "0.20", "value": "200"}, {"label": "0.25", "value": "250"}]
} }
] ]
} }
@@ -65,7 +66,8 @@
{"label": "Выкл", "value": "0"}, {"label": "Выкл", "value": "0"},
{"label": "24В", "value": "24"} {"label": "24В", "value": "24"}
] ]
} },
{"widget": "number-int", "label": "Частота LO, кГц", "name": "bucLoKhz", "min": 0, "max": 40000000, "step": 1}
] ]
}, },
{ {
@@ -81,7 +83,8 @@
{"label": "18В", "value": "18"}, {"label": "18В", "value": "18"},
{"label": "24В", "value": "24"} {"label": "24В", "value": "24"}
] ]
} },
{"widget": "number-int", "label": "Частота LO, кГц", "name": "lnbLoKhz", "min": 0, "max": 40000000, "step": 1}
] ]
}, },
{ {
@@ -101,17 +104,17 @@
"widget": "settings-container", "widget": "settings-container",
"childs": [ "childs": [
{ {
"widget": "select", "label": "Метод расчета задержки", "name": "dpdiIsPositional", "widget": "select", "label": "Метод расчета задержки", "name": "isPositional",
"values": [ "values": [
{"label": "Позиционированием", "value": "true"}, {"label": "Позиционированием", "value": "true"},
{"label": "Окном задержки", "value": "false"} {"label": "Окном задержки", "value": "false"}
] ]
}, },
{"widget": "h2", "label": "Настройки позиционирования", "v_show": "paramDpdi.dpdiIsPositional === true"}, {"widget": "h2", "label": "Настройки позиционирования", "v_show": "paramDpdi.isPositional === true"},
{"widget": "number", "label": "Широта станции", "name": "dpdiPositionStationLatitude", "v_show": "paramDpdi.dpdiIsPositional === true", "min": -180, "step": 0.000001, "max": 180}, {"widget": "number", "label": "Широта станции", "name": "positionStationLatitude", "v_show": "paramDpdi.isPositional === true", "min": -180, "step": 0.000001, "max": 180},
{"widget": "number", "label": "Долгота станции", "name": "dpdiPositionStationLongitude", "v_show": "paramDpdi.dpdiIsPositional === true", "min": -180, "step": 0.000001, "max": 180}, {"widget": "number", "label": "Долгота станции", "name": "positionStationLongitude", "v_show": "paramDpdi.isPositional === true", "min": -180, "step": 0.000001, "max": 180},
{"widget": "number", "label": "Подспутниковая точка", "name": "dpdiPositionSatelliteLongitude", "v_show": "paramDpdi.dpdiIsPositional === true", "min": -180, "step": 0.000001, "max": 180}, {"widget": "number", "label": "Подспутниковая точка", "name": "positionSatelliteLongitude", "v_show": "paramDpdi.isPositional === true", "min": -180, "step": 0.000001, "max": 180},
{"widget": "number", "label": "Задержка до спутника, мс", "name": "dpdiDelay", "v_show": "paramDpdi.dpdiIsPositional === false", "min": 0, "step": 0.1, "max": 400}] {"widget": "number", "label": "Задержка до спутника, мс", "name": "delay", "v_show": "paramDpdi.isPositional === false", "min": 0, "step": 0.1, "max": 400}]
}, },
{"widget": "submit"} {"widget": "submit"}
], ],
@@ -120,10 +123,9 @@
{ {
"widget": "settings-container", "widget": "settings-container",
"childs": [ "childs": [
{"widget": "text", "label": "Пароль для входа в сеть ЦЗС", "name": "netCesPassword"},
{"widget": "h3", "label": "Настройки интерфейса управления"}, {"widget": "h3", "label": "Настройки интерфейса управления"},
{"widget": "ip-address", "label": "IP Интерфейса управления (/24)", "name": "netManagementIp"}, {"widget": "ip-address-mask", "label": "Интерфейс управления (a.d.d.r/mask)", "name": "managementIp"},
{"widget": "text", "label": "Имя веб-сервера", "name": "netServerName"} {"widget": "text", "label": "Имя веб-сервера", "name": "serverName"}
] ]
} }
] ]
@@ -170,11 +172,11 @@
"values": [{"label": "Ethernet", "value": "false"}, {"label": "Тест", "value": "true"}] "values": [{"label": "Ethernet", "value": "false"}, {"label": "Тест", "value": "true"}]
}, },
{"widget": "h3", "label": "Параметры передачи"}, {"widget": "h3", "label": "Параметры передачи"},
{"widget": "number-int", "label": "Центральная частота, КГц", "name": "txCentralFreq", "min": 950000, "max": 6000000, "step": 0.01}, {"widget": "number-int", "label": "Центральная частота, КГц", "name": "txCentralFreq", "min": 100000, "max": 6000000, "step": 0.01},
{"widget": "number-int", "label": "Символьная скорость, Бод", "name": "txBaudrate", "min": 200000, "max": 54000000}, {"widget": "number-int", "label": "Символьная скорость, Бод", "name": "txBaudrate", "min": 200000, "max": 54000000},
{ {
"widget": "select", "label": "Roll-off", "name": "txRolloff", "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"}] "values": [{"label": "0.02", "value": "20"}, {"label": "0.05", "value": "50"}, {"label": "0.10", "value": "100"}, {"label": "0.15", "value": "150"}, {"label": "0.20", "value": "200"}, {"label": "0.25", "value": "250"}]
}, },
{ {
"widget": "select", "label": "Номер последовательности Голда", "name": "txGoldan", "widget": "select", "label": "Номер последовательности Голда", "name": "txGoldan",
@@ -217,7 +219,7 @@
{"widget": "checkbox", "label": "Авто-регулировка мощности", "name": "aupcEn"}, {"widget": "checkbox", "label": "Авто-регулировка мощности", "name": "aupcEn"},
{"widget": "number", "label": "Минимальное ослабление, дБ", "name": "aupcMinAttenuation", "min": 0, "step": 0.1, "max": 10}, {"widget": "number", "label": "Минимальное ослабление, дБ", "name": "aupcMinAttenuation", "min": 0, "step": 0.1, "max": 10},
{"widget": "number", "label": "Максимальное ослабление, дБ", "name": "aupcMaxAttenuation", "min": 0, "step": 0.1, "max": 10}, {"widget": "number", "label": "Максимальное ослабление, дБ", "name": "aupcMaxAttenuation", "min": 0, "step": 0.1, "max": 10},
{"widget": "number", "label": "Требуемое ОСШ", "name": "aupcRequiredSnr", "min": 0, "step": 0.01, "max": 10} {"widget": "number", "label": "Требуемое ОСШ", "name": "aupcRequiredSnr", "min": 0, "step": 0.01, "max": 30}
] ]
}, },
{ {
@@ -231,11 +233,11 @@
{"widget": "number", "label": "Усиление, дБ", "name": "rxManualGain", "min": -40, "step": 0.01, "max": 40, "v_show": "paramRxtx.rxAgcEn === false"}, {"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": "watch-expr", "label": "Текущее усиление", "expr": "paramRxtx.rxManualGain", "v_show": "paramRxtx.rxAgcEn === true"},
{"widget": "checkbox", "label": "Инверсия спектра", "name": "rxSpectrumInversion"}, {"widget": "checkbox", "label": "Инверсия спектра", "name": "rxSpectrumInversion"},
{"widget": "number-int", "label": "Центральная частота, КГц", "name": "rxCentralFreq", "min": 950000, "max": 6000000, "step": 0.01}, {"widget": "number-int", "label": "Центральная частота, КГц", "name": "rxCentralFreq", "min": 100000, "max": 6000000, "step": 0.01},
{"widget": "number-int", "label": "Символьная скорость, Бод", "name": "rxBaudrate", "min": 200000, "max": 54000000}, {"widget": "number-int", "label": "Символьная скорость, Бод", "name": "rxBaudrate", "min": 200000, "max": 54000000},
{ {
"widget": "select", "label": "Roll-off", "name": "rxRolloff", "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"}] "values": [{"label": "0.02", "value": "20"}, {"label": "0.05", "value": "50"}, {"label": "0.10", "value": "100"}, {"label": "0.15", "value": "150"}, {"label": "0.20", "value": "200"}, {"label": "0.25", "value": "250"}]
}, },
{ {
"widget": "select", "label": "Номер последовательности Голда", "name": "rxGoldan", "widget": "select", "label": "Номер последовательности Голда", "name": "rxGoldan",
@@ -252,20 +254,20 @@
"widget": "settings-container", "v_show": "paramRxtx.isCinC", "widget": "settings-container", "v_show": "paramRxtx.isCinC",
"childs": [ "childs": [
{ {
"widget": "select", "label": "Метод расчета задержки", "name": "dpdiIsPositional", "widget": "select", "label": "Метод расчета задержки", "name": "isPositional",
"values": [ "values": [
{"label": "Позиционированием", "value": "true"}, {"label": "Позиционированием", "value": "true"},
{"label": "Окном задержки", "value": "false"} {"label": "Окном задержки", "value": "false"}
] ]
}, },
{"widget": "number", "label": "Полоса поиска, КГц ±", "name": "dpdiSearchBandwidth", "min": 0, "step": 1, "max": 100}, {"widget": "number", "label": "Полоса поиска, КГц ±", "name": "searchBandwidth", "min": 0, "step": 1, "max": 100},
{"widget": "h2", "label": "Настройки позиционирования", "v_show": "paramDpdi.dpdiIsPositional === true"}, {"widget": "h2", "label": "Настройки позиционирования", "v_show": "paramDpdi.isPositional === true"},
{"widget": "number", "label": "Широта станции", "name": "dpdiPositionStationLatitude", "v_show": "paramDpdi.dpdiIsPositional === true", "min": -180, "step": 0.000001, "max": 180}, {"widget": "number", "label": "Широта станции", "name": "positionStationLatitude", "v_show": "paramDpdi.isPositional === true", "min": -180, "step": 0.000001, "max": 180},
{"widget": "number", "label": "Долгота станции", "name": "dpdiPositionStationLongitude", "v_show": "paramDpdi.dpdiIsPositional === true", "min": -180, "step": 0.000001, "max": 180}, {"widget": "number", "label": "Долгота станции", "name": "positionStationLongitude", "v_show": "paramDpdi.isPositional === true", "min": -180, "step": 0.000001, "max": 180},
{"widget": "number", "label": "Подспутниковая точка", "name": "dpdiPositionSatelliteLongitude", "v_show": "paramDpdi.dpdiIsPositional === true", "min": -180, "step": 0.000001, "max": 180}, {"widget": "number", "label": "Подспутниковая точка", "name": "positionSatelliteLongitude", "v_show": "paramDpdi.isPositional === true", "min": -180, "step": 0.000001, "max": 180},
{"widget": "h2", "label": "Задержка до спутника", "v_show": "paramDpdi.dpdiIsPositional === false"}, {"widget": "h2", "label": "Задержка до спутника", "v_show": "paramDpdi.isPositional === false"},
{"widget": "number", "label": "от, мс", "name": "dpdiDelayMin", "v_show": "paramDpdi.dpdiIsPositional === false", "min": 0, "step": 0.1, "max": 400}, {"widget": "number", "label": "от, мс", "name": "delayMin", "v_show": "paramDpdi.isPositional === false", "min": 0, "step": 0.1, "max": 400},
{"widget": "number", "label": "до, мс", "name": "dpdiDelayMax", "v_show": "paramDpdi.dpdiIsPositional === false", "min": 0, "step": 0.1, "max": 400}] {"widget": "number", "label": "до, мс", "name": "delayMax", "v_show": "paramDpdi.isPositional === false", "min": 0, "step": 0.1, "max": 400}]
}, },
{"widget": "submit", "v_show": "paramRxtx.isCinC"} {"widget": "submit", "v_show": "paramRxtx.isCinC"}
], ],
@@ -316,30 +318,20 @@
] ]
} }
], ],
"tcpaccel": [
{"widget": "h2", "label": "Настройки TCP-акселерации"},
{
"widget": "settings-container",
"childs": [
{"widget": "checkbox", "label": "Активировать акселерацию", "name": "accelEn"},
{"widget": "number", "label": "Максимальное количество соединений", "name": "accelMaxConnections", "min": 0, "step": 1, "max": 4000}
]
}
],
"network": [ "network": [
{"widget": "h2", "label": "Настройки сети"}, {"widget": "h2", "label": "Настройки сети"},
{ {
"widget": "settings-container", "widget": "settings-container",
"childs": [ "childs": [
{"widget": "h3", "label": "Настройки интерфейса управления"}, {"widget": "h3", "label": "Настройки интерфейса управления"},
{"widget": "ip-address", "label": "Интерфейс управления (/24)", "name": "netManagementIp"}, {"widget": "ip-address-mask", "label": "Интерфейс управления (a.d.d.r/mask)", "name": "managementIp"},
{ {
"widget": "select", "label": "Режим сети", "name": "netIsL2", "widget": "select", "label": "Режим сети", "name": "isL2",
"values": [{"label": "Маршрутизатор", "value": "false"}, {"label": "Коммутатор", "value": "true"}] "values": [{"label": "Маршрутизатор", "value": "false"}, {"label": "Коммутатор", "value": "true"}]
}, },
{"widget": "ip-address", "label": "Интерфейс данных (/24)", "name": "netDataIp", "v_show": "paramNetwork.netIsL2 === false"}, {"widget": "ip-address", "label": "Интерфейс данных (/24)", "name": "dataIp", "v_show": "paramNetwork.isL2 === false"},
{"widget": "number", "label": "MTU интерфейса данных", "name": "netDataMtu", "min": 1500, "step": 1, "max": 2000}, {"widget": "number", "label": "MTU интерфейса данных", "name": "dataMtu", "min": 1500, "step": 1, "max": 2000},
{"widget": "text", "label": "Имя веб-сервера", "name": "netServerName"} {"widget": "text", "label": "Имя веб-сервера", "name": "serverName"}
] ]
} }
] ]
@@ -373,23 +365,30 @@
"widget": "select", "label": "Режим работы модулятора", "name": "txModulatorIsTest", "widget": "select", "label": "Режим работы модулятора", "name": "txModulatorIsTest",
"values": [{"label": "Нормальный", "value": "false"}, {"label": "Тест (CW)", "value": "true"}] "values": [{"label": "Нормальный", "value": "false"}, {"label": "Тест (CW)", "value": "true"}]
}, },
{"widget": "number", "label": "Ослабление, дБ", "name": "txAttenuation", "max": 0, "min": -40, "step": 0.25},
{ {
"widget": "select", "label": "Входные данные", "name": "txIsTestInput", "widget": "select", "label": "Входные данные", "name": "txIsTestInput",
"values": [{"label": "Ethernet", "value": "false"}, {"label": "Тест", "value": "true"}] "values": [{"label": "Ethernet", "value": "false"}, {"label": "Тест", "value": "true"}]
}, },
{"widget": "h3", "label": "Параметры передачи"}, {"widget": "h3", "label": "Параметры передачи"},
{"widget": "number", "label": "Центральная частота, КГц", "name": "txCentralFreq", "min": 950000, "max": 6000000, "step": 0.01}, {"widget": "number-int", "label": "Центральная частота, КГц", "name": "txCentralFreq", "min": 70000, "max": 6000000, "step": 100},
{"widget": "number", "label": "Символьная скорость, Бод", "name": "txBaudrate", "min": 200000, "max": 54000000}, {"widget": "number-int", "label": "Символьная скорость, Бод", "name": "txBaudrate", "min": 128000, "max": 30000000},
{ {
"widget": "select", "label": "Roll-off", "name": "txRolloff", "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"}] "values": [{"label": "0.02", "value": "20"}, {"label": "0.05", "value": "50"}, {"label": "0.10", "value": "100"}, {"label": "0.15", "value": "150"}, {"label": "0.20", "value": "200"}, {"label": "0.25", "value": "250"}, {"label": "0.30", "value": "300"}, {"label": "0.35", "value": "350"}]
},
{"widget": "number", "label": "Коэф. расширения", "name": "txSpreadCoef", "max": 1024, "min": 8, "step": 2},
{"widget": "number", "label": "Кол-во пакетов на преамбулу", "name": "txFieldsDataPreamble", "max": 255, "min": 1, "step": 1}
]
}, },
{"widget": "number", "label": "Коэф. расширения", "name": "txSpreadCoef", "max": 1000, "min": -1000, "step": 0.01},
{ {
"widget": "select", "label": "Номер последовательности Голда", "name": "txGoldan", "widget": "settings-container",
"values": [{"label": "0", "value": "0"}, {"label": "1", "value": "1"}] "childs": [
}, {"widget": "h3", "label": "Авто-регулировка мощности"},
{"widget": "number", "label": "Ослабление, дБ", "name": "txAttenuation", "max": 0, "min": -40, "step": 0.25} {"widget": "checkbox", "label": "Авто-регулировка мощности", "name": "aupcEn"},
{"widget": "number", "label": "Минимальное ослабление, дБ", "name": "aupcMinAttenuation", "min": 0, "step": 0.1, "max": 10},
{"widget": "number", "label": "Максимальное ослабление, дБ", "name": "aupcMaxAttenuation", "min": 0, "step": 0.1, "max": 10},
{"widget": "number", "label": "Требуемое ОСШ", "name": "aupcRequiredSnr", "min": 0, "step": 0.01, "max": 30}
] ]
}, },
{ {
@@ -403,17 +402,15 @@
{"widget": "number", "label": "Усиление, дБ", "name": "rxManualGain", "min": -40, "step": 0.01, "max": 40, "v_show": "paramRxtx.rxAgcEn === false"}, {"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": "watch-expr", "label": "Текущее усиление", "expr": "paramRxtx.rxManualGain", "v_show": "paramRxtx.rxAgcEn === true"},
{"widget": "checkbox", "label": "Инверсия спектра", "name": "rxSpectrumInversion"}, {"widget": "checkbox", "label": "Инверсия спектра", "name": "rxSpectrumInversion"},
{"widget": "number", "label": "Центральная частота, КГц", "name": "rxCentralFreq", "min": 950000, "max": 6000000, "step": 0.01}, {"widget": "number-int", "label": "Центральная частота, КГц", "name": "rxCentralFreq", "min": 70000, "max": 6000000, "step": 100},
{"widget": "number", "label": "Символьная скорость, Бод", "name": "rxBaudrate", "min": 200000, "max": 54000000}, {"widget": "number-int", "label": "Символьная скорость, Бод", "name": "rxBaudrate", "min": 128000, "max": 30000000},
{ {
"widget": "select", "label": "Roll-off", "name": "rxRolloff", "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"}] "values": [{"label": "0.02", "value": "20"}, {"label": "0.05", "value": "50"}, {"label": "0.10", "value": "100"}, {"label": "0.15", "value": "150"}, {"label": "0.20", "value": "200"}, {"label": "0.25", "value": "250"}, {"label": "0.30", "value": "300"}, {"label": "0.35", "value": "350"}]
}, },
{"widget": "number", "label": "Коэф. расширения", "name": "rxSpreadCoef", "max": 1000, "min": -1000, "step": 0.01}, {"widget": "number", "label": "Коэф. расширения", "name": "rxSpreadCoef", "max": 1024, "min": 8, "step": 2},
{ {"widget": "number", "label": "Порог коррелятора", "name": "rxFftShift", "max": 10, "min": 1, "step": 0.125},
"widget": "select", "label": "Номер последовательности Голда", "name": "rxGoldan", {"widget": "number", "label": "Кол-во пакетов на преамбулу", "name": "rxFieldsDataPreamble", "max": 255, "min": 1, "step": 1}
"values": [{"label": "0", "value": "0"}, {"label": "1", "value": "1"}]
}
] ]
} }
] ]
@@ -465,6 +462,23 @@
} }
] ]
} }
],
"network": [
{"widget": "h2", "label": "Настройки сети"},
{
"widget": "settings-container",
"childs": [
{"widget": "h3", "label": "Настройки интерфейса управления"},
{"widget": "ip-address-mask", "label": "Интерфейс управления (a.d.d.r/mask)", "name": "managementIp"},
{
"widget": "select", "label": "Режим сети", "name": "isL2",
"values": [{"label": "Маршрутизатор", "value": "false"}, {"label": "Коммутатор", "value": "true"}]
},
{"widget": "ip-address", "label": "Интерфейс данных (/24)", "name": "dataIp", "v_show": "paramNetwork.isL2 === false"},
{"widget": "number", "label": "MTU интерфейса данных", "name": "dataMtu", "min": 1500, "step": 1, "max": 2000},
{"widget": "text", "label": "Имя веб-сервера", "name": "serverName"}
]
}
] ]
}, },
"tabs": [ "tabs": [

View File

@@ -63,6 +63,22 @@
} }
this.submitStatus.firmwareUpgradeOta = false this.submitStatus.firmwareUpgradeOta = false
}, },
async settingsPerformSetCesPassword() {
if (this.submitStatus.cesPassword) { return }
this.submitStatus.cesPassword = true
try {
await fetch('/api/set/cesPassword', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({'password': this.cesPasswordValue})
})
} catch (e) {
console.log("failed to perform set CES password: ", e)
}
this.submitStatus.cesPassword = false
},
{% endif %} {% endif %}
doModemReboot() { doModemReboot() {
@@ -72,3 +88,130 @@
this.submitStatus.modemReboot = 30 this.submitStatus.modemReboot = 30
fetch('/api/reboot', { method: 'POST' }).then((r) => {}) fetch('/api/reboot', { method: 'POST' }).then((r) => {})
}, },
async restoreAllSettings() {
// Порядок применения настроек
const settingsApplyOrder = ['qos', 'tcpaccel', 'dpdi', 'rxtx', 'buclnb', 'network'];
// 1. Чтение JSON-файла, выбранного пользователем
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = '.json';
const filePromise = new Promise((resolve, reject) => {
fileInput.onchange = e => {
const file = e.target.files[0];
if (!file) {
reject(new Error('Файл не выбран'));
return;
}
const reader = new FileReader();
reader.onload = event => {
try {
const jsonData = JSON.parse(event.target.result);
resolve(jsonData);
} catch (error) {
reject(new Error('Ошибка парсинга JSON'));
}
};
reader.onerror = () => reject(new Error('Ошибка чтения файла'));
reader.readAsText(file);
};
fileInput.click();
});
try {
const settingsToApply = await filePromise;
const errors = [];
// 2. Перебор групп параметров в заданном порядке
for (const groupName of settingsApplyOrder) {
if (!settingsToApply.hasOwnProperty(groupName)) {
continue; // Пропускаем группы, которых нет в файле
}
const groupSettings = settingsToApply[groupName];
if (typeof groupSettings !== 'object' || groupSettings === null) {
continue;
}
try {
// 2.1. POST-запрос для применения группы параметров
const postResponse = await fetch(`/api/set/${groupName}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(groupSettings)
});
if (!postResponse.ok) {
throw new Error(`HTTP error ${postResponse.status}`);
}
const postResult = await postResponse.json();
if (postResult.status !== 'ok') {
throw new Error(`API error: ${postResult.message || 'unknown error'}`);
}
// 2.2. Проверка примененных параметров
const getResponse = await fetch('/api/get/settings', { method: 'GET' });
if (!getResponse.ok) {
throw new Error(`HTTP error ${getResponse.status}`);
}
const fetchSettingsResult = await getResponse.json();
if (fetchSettingsResult.status !== 'ok') {
throw new Error('Не удалось получить текущие настройки');
}
// Проверка соответствия параметров
const appliedGroup = fetchSettingsResult.settings[groupName] || {};
const failedSettings = [];
for (const [key, value] of Object.entries(groupSettings)) {
if (appliedGroup[key] !== value) {
failedSettings.push(`${key} (ожидалось: ${value}, получено: ${appliedGroup[key]})`);
}
}
if (failedSettings.length > 0) {
throw new Error(`Не совпадают параметры: ${failedSettings.join(', ')}`);
}
} catch (groupError) {
errors.push(`Группа ${groupName}: ${groupError.message}`);
}
}
// 3. Показ ошибок, если они есть
if (errors.length > 0) {
const errorMessage = errors.join('\n\n') +
'\n\nНекоторые настройки могли примениться некорректно.\nСтраница будет перезагружена.';
alert(errorMessage);
}
} catch (error) {
alert(`Ошибка при восстановлении настроек: ${error.message}`);
return;
}
// 4. Перезагрузка страницы
location.reload();
},
async dumpAllSettings() {
function downloadAsFile(data, filename) {
let a = document.createElement("a");
let file = new Blob([data], {type: 'application/json'});
a.href = URL.createObjectURL(file);
a.download = filename;
a.click();
}
const response = await fetch('/api/get/settings', { method: 'GET' })
if (response.ok) {
const jres = await response.json()
if (jres["status"] === "ok") {
downloadAsFile(JSON.stringify(jres["settings"], null, 4), "backup-" + this.about.firmwareVersion + "-" + this.about.modemSn + ".json")
}
}
},

View File

@@ -21,7 +21,18 @@
<div> <div>
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button> <button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
</div> </div>
</div> <button class="action-button" @click="dumpAllSettings()">Сохранить бекап конфигурации</button>
<button class="dangerous-button" @click="restoreAllSettings()">Восстановить бекап конфигурации</button>
</div>{% endraw %}{% if modem == 'tdma' %}
<h2>Вход в сеть ЦЗС</h2>
<div class="settings-set-container statistics-container">
<label>
<span>Хеш-строка пароля (выдается оператором NMS)</span>
<input v-model="cesPasswordValue" type="text">
</label>
<button class="action-button" @click="settingsPerformSetCesPassword()">Установить пароль<span class="submit-spinner" v-show="submitStatus.cesPassword"></span></button>
</div>{% endif %}{% raw %}
<h2>Обновление ПО</h2> <h2>Обновление ПО</h2>
<div class="settings-set-container statistics-container"> <div class="settings-set-container statistics-container">

View File

@@ -24,7 +24,7 @@
update{{ g['group'] | title }}Settings(vals) { update{{ g['group'] | title }}Settings(vals) {
this.submitStatus.{{ g['group'] }} = false this.submitStatus.{{ g['group'] }} = false
{% for p in g['params'] %} {% for p in g['params'] %}
{{ build_setter_js(g['group'], p, "vals[\"settings\"][\"" ~ p['name'] ~ "\"]") }} {{ build_setter_js(g['group'], p, "vals[\"settings\"][\"" ~ g['group'] ~ "\"][\"" ~ p['name'] ~ "\"]") }}
{% endfor %} {% endfor %}
}, },
{% endfor %} {% endfor %}

View File

@@ -18,69 +18,68 @@
} }
this.lastUpdateTime = new Date(); this.lastUpdateTime = new Date();
this.initState = vals["mainState"]["initState"] this.initState = vals["state"]["initState"]
this.testState = vals["state"]["testState"]
{% if modem == 'scpc' %} {% if modem == 'scpc' %}
this.isCinC = vals["mainState"]["isCinC"] this.isCinC = vals["state"]["isCinC"]
{% endif %} {% endif %}
this.statRx.state = vals["mainState"]["rx.state"] this.statRx.state = vals["state"]["rx"]["state"]
this.statRx.sym_sync_lock = vals["mainState"]["rx.sym_sync_lock"] this.statRx.sym_sync_lock = vals["state"]["rx"]["sym_sync_lock"]
this.statRx.freq_search_lock = vals["mainState"]["rx.freq_search_lock"] this.statRx.freq_search_lock = vals["state"]["rx"]["freq_search_lock"]
this.statRx.afc_lock = vals["mainState"]["rx.afc_lock"] this.statRx.afc_lock = vals["state"]["rx"]["afc_lock"]
this.statRx.pkt_sync = vals["mainState"]["rx.pkt_sync"] this.statRx.pkt_sync = vals["state"]["rx"]["pkt_sync"]
this.statRx.snr = vals["mainState"]["rx.snr"] this.statRx.snr = Math.round(vals["state"]["rx"]["snr"] * 10) / 10
this.statRx.rssi = vals["mainState"]["rx.rssi"] this.statRx.rssi = Math.round(vals["state"]["rx"]["rssi"] * 10) / 10
this.statRx.modcod = modcodToStr(vals["mainState"]["rx.modcod"]) this.statRx.modcod = modcodToStr(vals["state"]["rx"]["modcod"])
this.statRx.frameSizeNormal = vals["mainState"]["rx.frameSizeNormal"] this.statRx.frameSizeNormal = vals["state"]["rx"]["frameSizeNormal"]
this.statRx.isPilots = vals["mainState"]["rx.isPilots"] this.statRx.isPilots = vals["state"]["rx"]["isPilots"]
this.statRx.symError = vals["mainState"]["rx.symError"] this.statRx.symError = vals["state"]["rx"]["symError"]
this.statRx.freqErr = vals["mainState"]["rx.freqErr"] this.statRx.freqErr = Math.round(vals["state"]["rx"]["freqErr"] * 100) / 100
this.statRx.freqErrAcc = vals["mainState"]["rx.freqErrAcc"] this.statRx.freqErrAcc = Math.round(vals["state"]["rx"]["freqErrAcc"] * 100) / 100
this.statRx.inputSignalLevel = vals["mainState"]["rx.inputSignalLevel"] this.statRx.inputSignalLevel = vals["state"]["rx"]["inputSignalLevel"]
this.statRx.pllError = vals["mainState"]["rx.pllError"] this.statRx.pllError = Math.round(vals["state"]["rx"]["pllError"] * 100) / 100
this.statRx.speedOnRxKbit = vals["mainState"]["rx.speedOnRxKbit"] this.statRx.speedOnRxKbit = Math.round(vals["state"]["rx"]["speedOnRxKbit"] * 100) / 100
this.statRx.speedOnIifKbit = vals["mainState"]["rx.speedOnIifKbit"] this.statRx.speedOnIifKbit = Math.round(vals["state"]["rx"]["speedOnIifKbit"] * 100) / 100
this.statRx.packetsOk = vals["mainState"]["rx.packetsOk"] this.statRx.packetsOk = vals["state"]["rx"]["packetsOk"]
this.statRx.packetsBad = vals["mainState"]["rx.packetsBad"] this.statRx.packetsBad = vals["state"]["rx"]["packetsBad"]
this.statRx.packetsDummy = vals["mainState"]["rx.packetsDummy"] this.statRx.packetsDummy = vals["state"]["rx"]["packetsDummy"]
{% if modem == 'scpc' %} {% if modem == 'scpc' %}
this.statTx.state = vals["mainState"]["tx.state"] this.statTx.state = vals["state"]["tx"]["state"]
this.statTx.snr = vals["mainState"]["tx.snr"] this.statTx.snr = Math.round(vals["state"]["tx"]["snr"] * 100) / 100
this.statTx.modcod = modcodToStr(vals["mainState"]["tx.modcod"]) this.statTx.modcod = modcodToStr(vals["state"]["tx"]["modcod"])
this.statTx.frameSizeNormal = vals["mainState"]["tx.frameSizeNormal"] this.statTx.frameSizeNormal = vals["state"]["tx"]["frameSizeNormal"]
this.statTx.isPilots = vals["mainState"]["tx.isPilots"] this.statTx.isPilots = vals["state"]["tx"]["isPilots"]
this.statTx.speedOnTxKbit = vals["mainState"]["tx.speedOnTxKbit"] this.statTx.speedOnTxKbit = Math.round(vals["state"]["tx"]["speedOnTxKbit"] * 100) / 100
this.statTx.speedOnIifKbit = vals["mainState"]["tx.speedOnIifKbit"] this.statTx.speedOnIifKbit = Math.round(vals["state"]["tx"]["speedOnIifKbit"] * 100) / 100
this.statCinc.occ = vals["mainState"]["cinc.occ"] this.statCinc.occ = vals["state"]["cinc"]["occ"]
this.statCinc.correlator = vals["mainState"]["cinc.correlator"] this.statCinc.correlator = vals["state"]["cinc"]["correlator"]
this.statCinc.correlatorFails = vals["mainState"]["cinc.correlatorFails"] this.statCinc.correlatorFails = vals["state"]["cinc"]["correlatorFails"]
this.statCinc.freqErr = vals["mainState"]["cinc.freqErr"] this.statCinc.freqErr = Math.round(vals["state"]["cinc"]["freqErr"] * 100) / 100
this.statCinc.freqErrAcc = vals["mainState"]["cinc.freqErrAcc"] this.statCinc.freqErrAcc = Math.round(vals["state"]["cinc"]["freqErrAcc"] * 100) / 100
this.statCinc.channelDelay = vals["mainState"]["cinc.channelDelay"] this.statCinc.channelDelay = vals["state"]["cinc"]["channelDelay"]
{% else %} {% else %}
this.statTx.state = vals["mainState"]["tx.state"] this.statTx.state = vals["state"]["tx"]["state"]
this.statTx.modcod = modcodToStr(vals["mainState"]["tx.modcod"]) this.statTx.modcod = modcodToStr(vals["state"]["tx"]["modcod"])
this.statTx.speedOnTxKbit = vals["mainState"]["tx.speedOnTxKbit"] this.statTx.speedOnTxKbit = Math.round(vals["state"]["tx"]["speedOnTxKbit"] * 100) / 100
this.statTx.speedOnIifKbit = vals["mainState"]["tx.speedOnIifKbit"] this.statTx.speedOnIifKbit = Math.round(vals["state"]["tx"]["speedOnIifKbit"] * 100) / 100
this.statTx.centerFreq = vals["mainState"]["tx.centerFreq"] this.statTx.centerFreq = vals["state"]["tx"]["centerFreq"]
this.statTx.symSpeed = vals["mainState"]["tx.symSpeed"] this.statTx.symSpeed = vals["state"]["tx"]["symSpeed"]
{% endif %} {% endif %}
this.statDevice.adrv = vals["mainState"]["device.adrv"] this.statDevice.adrv = vals["state"]["device"]["adrv"]
this.statDevice.zynq = vals["mainState"]["device.zynq"] this.statDevice.zynq = vals["state"]["device"]["zynq"]
this.statDevice.fpga = vals["mainState"]["device.fpga"] this.statDevice.fpga = vals["state"]["device"]["fpga"]
{% if modem == 'tdma' %} {% if modem == 'tdma' %}
this.statDevice.upgradeStatus = vals["mainState"]["device.upgradeStatus"] this.statDevice.upgradeStatus = vals["state"]["device"]["upgradeStatus"]
this.statDevice.upgradePercent = vals["mainState"]["device.upgradePercent"] this.statDevice.upgradePercent = vals["state"]["device"]["upgradePercent"]
this.statDevice.upgradeImage = vals["mainState"]["device.upgradeImage"] this.statDevice.upgradeImage = vals["state"]["device"]["upgradeImage"]
{% endif %} {% endif %}
this.testState = vals["mainState"]["testState"]
// аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид // аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид
let uptime = vals["sysinfo"]["uptime"] let uptime = vals["state"]["device"]["uptime"]
if (uptime) { if (uptime) {
let secs = uptime % 60; uptime = Math.floor(uptime / 60) let secs = uptime % 60; uptime = Math.floor(uptime / 60)
let mins = uptime % 60; uptime = Math.floor(uptime / 60) let mins = uptime % 60; uptime = Math.floor(uptime / 60)
@@ -92,11 +91,11 @@
} else { } else {
this.statOs.uptime = '?' this.statOs.uptime = '?'
} }
this.statOs.load1 = vals["sysinfo"]["load1min"] this.statOs.load1 = Math.round(vals["state"]["device"]["load1min"] * 100) / 100
this.statOs.load5 = vals["sysinfo"]["load5min"] this.statOs.load5 = Math.round(vals["state"]["device"]["load5min"] * 100) / 100
this.statOs.load15 = vals["sysinfo"]["load15min"] this.statOs.load15 = Math.round(vals["state"]["device"]["load15min"] * 100) / 100
this.statOs.totalram = vals["sysinfo"]["totalram"] this.statOs.totalram = vals["state"]["device"]["totalram"]
this.statOs.freeram = vals["sysinfo"]["freeram"] this.statOs.freeram = vals["state"]["device"]["freeram"]
}, },
resetPacketsStatistics() { resetPacketsStatistics() {

View File

@@ -3,7 +3,7 @@
<div class="settings-set-container statistics-container"> <div class="settings-set-container statistics-container">
<h2>Статистика приема</h2> <h2>Статистика приема</h2>
<table> <table>
<tbody> <tbody>{% endraw %}{% if modem != 'shps' %}{% raw %}
<tr><th>Прием</th><td><span :class="{ indicator_bad: statRx.state === false, indicator_good: statRx.state === true, indicator: true }"></span></td></tr> <tr><th>Прием</th><td><span :class="{ indicator_bad: statRx.state === false, indicator_good: statRx.state === true, indicator: true }"></span></td></tr>
<tr><th>Захват символьной</th><td><span :class="{ indicator_bad: statRx.sym_sync_lock === false, indicator_good: statRx.sym_sync_lock === true, indicator: true }"></span></td></tr> <tr><th>Захват символьной</th><td><span :class="{ indicator_bad: statRx.sym_sync_lock === false, indicator_good: statRx.sym_sync_lock === true, indicator: true }"></span></td></tr>
<tr><th>Захват ФАПЧ</th><td><span :class="{ indicator_bad: statRx.afc_lock === false, indicator_good: statRx.afc_lock === true, indicator: true }"></span></td></tr> <tr><th>Захват ФАПЧ</th><td><span :class="{ indicator_bad: statRx.afc_lock === false, indicator_good: statRx.afc_lock === true, indicator: true }"></span></td></tr>
@@ -22,7 +22,17 @@
<tr><td colspan="2" style="padding-top: 1em; text-align: center">Статистика пакетов</td></tr> <tr><td colspan="2" style="padding-top: 1em; text-align: center">Статистика пакетов</td></tr>
<tr><th>Качественных пакетов</th><td>{{ statRx.packetsOk }}</td></tr> <tr><th>Качественных пакетов</th><td>{{ statRx.packetsOk }}</td></tr>
<tr><th>Поврежденных пакетов</th><td>{{ statRx.packetsBad }}</td></tr> <tr><th>Поврежденных пакетов</th><td>{{ statRx.packetsBad }}</td></tr>
<tr><th>DUMMY</th><td>{{ statRx.packetsDummy }}</td></tr> <tr><th>DUMMY</th><td>{{ statRx.packetsDummy }}</td></tr>{% endraw %}{% else %}{% raw %}
<tr><th>Прием</th><td><span :class="{ indicator_bad: statRx.state === false, indicator_good: statRx.state === true, indicator: true }"></span></td></tr>
<tr><th>ОСШ/RSSI</th><td>{{ statRx.snr }} / {{ statRx.rssi }}</td></tr>
<tr><th>Частотная ошибка, Гц</th><td>{{ statRx.freqErrAcc }}</td></tr>
<tr><th>Ур. входного сигнала</th><td>{{ statRx.inputSignalLevel }}</td></tr>
<tr><th>Ошибка ФАПЧ</th><td>{{ statRx.pllError }}</td></tr>
<tr><th>Инф. скорость на приеме</th><td>{{ statRx.speedOnRxKbit }} кбит/с</td></tr>
<tr><th>Инф. скорость на интерфейсе</th><td>{{ statRx.speedOnIifKbit }} кбит/с</td></tr>
<tr><td colspan="2" style="padding-top: 1em; text-align: center">Статистика пакетов</td></tr>
<tr><th>Качественных пакетов</th><td>{{ statRx.packetsOk }}</td></tr>
<tr><th>Поврежденных пакетов</th><td>{{ statRx.packetsBad }}</td></tr>{% endraw %}{% endif %}{% raw %}
</tbody> </tbody>
</table> </table>
<button class="action-button" @click="resetPacketsStatistics()"> Сброс статистики </button> <button class="action-button" @click="resetPacketsStatistics()"> Сброс статистики </button>
@@ -39,7 +49,7 @@
<tr><th>Инф. скорость на передаче</th><td>{{ statTx.speedOnTxKbit }} кбит/с</td></tr> <tr><th>Инф. скорость на передаче</th><td>{{ statTx.speedOnTxKbit }} кбит/с</td></tr>
<tr><th>Инф. скорость на интерфейсе</th><td>{{ statTx.speedOnIifKbit }} кбит/с</td></tr> <tr><th>Инф. скорость на интерфейсе</th><td>{{ statTx.speedOnIifKbit }} кбит/с</td></tr>
</tbody> </tbody>
</table>{% endraw %}{% else %}{% raw %} </table>{% endraw %}{% elif modem == 'tdma' %}{% raw %}
<table> <table>
<tbody> <tbody>
<tr><th>Передача</th><td><span :class="{ indicator_bad: statTx.state === false, indicator_good: statTx.state === true, indicator: true }"></span></td></tr> <tr><th>Передача</th><td><span :class="{ indicator_bad: statTx.state === false, indicator_good: statTx.state === true, indicator: true }"></span></td></tr>
@@ -49,6 +59,15 @@
<tr><th>Центральная частота</th><td>{{ statTx.centerFreq }} кГц</td></tr> <tr><th>Центральная частота</th><td>{{ statTx.centerFreq }} кГц</td></tr>
<tr><th>Символьная скорость</th><td>{{ statTx.symSpeed }} ksymb</td></tr> <tr><th>Символьная скорость</th><td>{{ statTx.symSpeed }} ksymb</td></tr>
</tbody> </tbody>
</table>{% endraw %}{% elif modem == 'shps' %}{% raw %}
<table>
<tbody>
<tr><th>Передача</th><td><span :class="{ indicator_bad: statTx.state === false, indicator_good: statTx.state === true, indicator: true }"></span></td></tr>
<tr><th>Инф. скорость на передаче</th><td>{{ statTx.speedOnTxKbit }} кбит/с</td></tr>
<tr><th>Инф. скорость на интерфейсе</th><td>{{ statTx.speedOnIifKbit }} кбит/с</td></tr>
<tr><th>Центральная частота</th><td>{{ statTx.centerFreq }} кГц</td></tr>
<tr><th>Символьная скорость</th><td>{{ statTx.symSpeed }} ksymb</td></tr>
</tbody>
</table>{% endraw %}{% endif %}{% raw %} </table>{% endraw %}{% endif %}{% raw %}
</div>{% endraw %}{% if modem == 'scpc' %}{% raw %} </div>{% endraw %}{% if modem == 'scpc' %}{% raw %}
<div class="settings-set-container statistics-container" v-if="paramRxtx.isCinC === true"> <div class="settings-set-container statistics-container" v-if="paramRxtx.isCinC === true">

View File

@@ -44,15 +44,17 @@
} }
let query = { let query = {
"en": this.paramQos.en, "en": this.paramQos.en,
"profile": {
"rt1": [], "rt1": [],
"rt2": [], "rt2": [],
"rt3": [], "rt3": [],
"cd": [] "cd": []
} }
for (let i = 0; i < this.paramQos.rt1.length; i++) { query.rt1.push(_translateQosClass('rt', this.paramQos.rt1[i])) } }
for (let i = 0; i < this.paramQos.rt2.length; i++) { query.rt2.push(_translateQosClass('rt', this.paramQos.rt2[i])) } for (let i = 0; i < this.paramQos.rt1.length; i++) { query.profile.rt1.push(_translateQosClass('rt', this.paramQos.rt1[i])) }
for (let i = 0; i < this.paramQos.rt3.length; i++) { query.rt3.push(_translateQosClass('rt', this.paramQos.rt3[i])) } for (let i = 0; i < this.paramQos.rt2.length; i++) { query.profile.rt2.push(_translateQosClass('rt', this.paramQos.rt2[i])) }
for (let i = 0; i < this.paramQos.cd.length; i++) { query.cd.push(_translateQosClass('rt', this.paramQos.cd[i])) } for (let i = 0; i < this.paramQos.rt3.length; i++) { query.profile.rt3.push(_translateQosClass('rt', this.paramQos.rt3[i])) }
for (let i = 0; i < this.paramQos.cd.length; i++) { query.profile.cd.push(_translateQosClass('rt', this.paramQos.cd[i])) }
//console.log(query) //console.log(query)
fetch('/api/set/qos', { fetch('/api/set/qos', {
@@ -73,9 +75,9 @@
updateQosSettings(vals) { updateQosSettings(vals) {
this.submitStatusQos = false this.submitStatusQos = false
this.paramQos.en = vals["settings"]["qosEnabled"] this.paramQos.en = vals["settings"]["qos"]["en"]
const qosProfile = vals["settings"]["qosProfile"] const qosProfile = vals["settings"]["qos"]["profile"]
if (qosProfile !== null && qosProfile !== undefined) { if (qosProfile !== null && qosProfile !== undefined) {
this.paramQos.rt1 = [] // .splice(0, this.paramQos.rt1.length) this.paramQos.rt1 = [] // .splice(0, this.paramQos.rt1.length)
this.paramQos.rt2 = [] // .splice(0, this.paramQos.rt2.length) this.paramQos.rt2 = [] // .splice(0, this.paramQos.rt2.length)

View File

@@ -58,6 +58,10 @@
<span>{{ widget.label }}</span> <span>{{ widget.label }}</span>
<input v-model="param{{ param_group | title }}.{{ widget.name }}" required type="text" pattern="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"> <input v-model="param{{ param_group | title }}.{{ widget.name }}" required type="text" pattern="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$">
</label>{% endmacro %} </label>{% endmacro %}
{% macro build_widget_ip_address_mask(param_group, widget) %}<label{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>
<span>{{ widget.label }}</span>
<input v-model="param{{ param_group | title }}.{{ widget.name }}" required type="text" pattern="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\/([0-9]|[1-2][0-9]|3[0-2])$">
</label>{% endmacro %}
{% macro build_widget_text(param_group, widget) %}<label{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}> {% macro build_widget_text(param_group, widget) %}<label{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>
<span>{{ widget.label }}</span> <span>{{ widget.label }}</span>
@@ -78,22 +82,23 @@
{% elif widget.widget == 'modulation-modcod' %}{{ build_widget_modulation_modcod(param_group, widget) }} {% elif widget.widget == 'modulation-modcod' %}{{ build_widget_modulation_modcod(param_group, widget) }}
{% elif widget.widget == 'modulation-speed' %}{{ build_widget_modulation_speed(param_group, widget) }} {% elif widget.widget == 'modulation-speed' %}{{ build_widget_modulation_speed(param_group, widget) }}
{% elif widget.widget == 'ip-address' %}{{ build_widget_ip_address(param_group, widget) }} {% elif widget.widget == 'ip-address' %}{{ build_widget_ip_address(param_group, widget) }}
{% elif widget.widget == 'ip-address-mask' %}{{ build_widget_ip_address_mask(param_group, widget) }}
{% elif widget.widget == 'text' %}{{ build_widget_text(param_group, widget) }} {% elif widget.widget == 'text' %}{{ build_widget_text(param_group, widget) }}
{% else %}<p>Widget '{{ widget.widget }}' not defined!</p><p>{{ widget }}</p> {% else %}<p>Widget '{{ widget.widget }}' not defined!</p><p>{{ widget }}</p>
{% endif %} {% endif %}
{% endmacro %} {% endmacro %}
{% macro build_getter_js(param_group, widget) %}{% if widget.widget in ['flex-container', 'settings-container', 'h2', 'h3', 'submit', 'watch', 'watch-expr'] %}null{% {% macro build_getter_js(param_group, widget) %}{% if widget.widget in ['flex-container', 'settings-container', 'h2', 'h3', 'submit', 'watch', 'watch-expr'] %}null{%
elif widget.widget in ['checkbox', 'number', 'select', 'ip-address', 'modulation-modcod', 'modulation-speed', 'text'] %}this.param{{ param_group | title }}.{{ widget.name }}{% elif widget.widget in ['checkbox', 'number', 'select', 'ip-address', 'ip-address-mask', 'modulation-modcod', 'modulation-speed', 'text'] %}this.param{{ param_group | title }}.{{ widget.name }}{%
elif widget.widget == 'number-int' %}parseFloat(this.param{{ param_group | title }}.{{ widget.name }}.replace(/[^0-9,.]/g, '').replace(',', '.')){% elif widget.widget == 'number-int' %}parseFloat(this.param{{ param_group | title }}.{{ widget.name }}.replace(/[^0-9,.]/g, '').replace(',', '.')){%
else %}<p>Widget '{{ widget.widget }}' not defined!</p><p>{{ widget }}</p>{% endif %}{% endmacro %} else %}<p>Widget '{{ widget.widget }}' not defined!</p><p>{{ widget }}</p>{% endif %}{% endmacro %}
{% macro build_setter_js(param_group, widget, expr) %}{% if widget.widget in ['flex-container', 'settings-container', 'h2', 'h3', 'submit', 'watch', 'watch-expr'] %}null{% {% macro build_setter_js(param_group, widget, expr) %}{% if widget.widget in ['flex-container', 'settings-container', 'h2', 'h3', 'submit', 'watch', 'watch-expr'] %}null{%
elif widget.widget in ['checkbox', 'number', 'select', 'ip-address', 'modulation-modcod', 'modulation-speed', 'text'] %}this.param{{ param_group | title }}.{{ widget.name }} = {{ expr }}{% elif widget.widget in ['checkbox', 'number', 'select', 'ip-address', 'ip-address-mask', 'modulation-modcod', 'modulation-speed', 'text'] %}this.param{{ param_group | title }}.{{ widget.name }} = {{ expr }}{%
elif widget.widget == 'number-int' %}this.param{{ param_group | title }}.{{ widget.name }} = this.inputFormatNumber({{ expr }}, {{ js_build_number_number_validator(widget) }}){% elif widget.widget == 'number-int' %}this.param{{ param_group | title }}.{{ widget.name }} = this.inputFormatNumber({{ expr }}, {{ js_build_number_number_validator(widget) }}){%
else %}<p>Widget '{{ widget.widget }}' not defined!</p><p>{{ widget }}</p>{% endif %}{% endmacro %} else %}<p>Widget '{{ widget.widget }}' not defined!</p><p>{{ widget }}</p>{% endif %}{% endmacro %}
{% macro build_setter(param_group, widget, expr) %}{% if widget.widget in ['flex-container', 'settings-container', 'h2', 'h3', 'submit', 'watch', 'watch-expr'] %}null{% {% macro build_setter(param_group, widget, expr) %}{% if widget.widget in ['flex-container', 'settings-container', 'h2', 'h3', 'submit', 'watch', 'watch-expr'] %}null{%
elif widget.widget in ['checkbox', 'number', 'select', 'ip-address', 'modulation-modcod', 'modulation-speed', 'text'] %}param{{ param_group | title }}.{{ widget.name }} = {{ expr }}{% elif widget.widget in ['checkbox', 'number', 'select', 'ip-address', 'ip-address-mask', 'modulation-modcod', 'modulation-speed', 'text'] %}param{{ param_group | title }}.{{ widget.name }} = {{ expr }}{%
elif widget.widget == 'number-int' %}param{{ param_group | title }}.{{ widget.name }} = inputFormatNumber({{ expr }}, {{ js_build_number_number_validator(widget) }}){% elif widget.widget == 'number-int' %}param{{ param_group | title }}.{{ widget.name }} = inputFormatNumber({{ expr }}, {{ js_build_number_number_validator(widget) }}){%
else %}<p>Widget '{{ widget.widget }}' not defined!</p><p>{{ widget }}</p>{% endif %}{% endmacro %} else %}<p>Widget '{{ widget.widget }}' not defined!</p><p>{{ widget }}</p>{% endif %}{% endmacro %}

View File

@@ -99,10 +99,14 @@
firmwareUpgrade: false, firmwareUpgrade: false,
{% if modem == 'tdma' %} {% if modem == 'tdma' %}
firmwareUpgradeOta: false, firmwareUpgradeOta: false,
cesPassword: false,
{% endif %} {% endif %}
// когда модем перезагружается, тут должен быть счетчик. Направление счета - к нулю // когда модем перезагружается, тут должен быть счетчик. Направление счета - к нулю
modemReboot: null modemReboot: null
}, },
{% if modem == 'tdma' %}
cesPasswordValue: '',
{% endif %}
// ========== include from 'common/all-params-data.js.j2' // ========== include from 'common/all-params-data.js.j2'
{% include 'common/all-params-data.js.j2' %} {% include 'common/all-params-data.js.j2' %}
@@ -235,11 +239,11 @@
try { try {
const fr = await fetch("/api/get/aboutFirmware") const fr = await fetch("/api/get/aboutFirmware")
const d = await fr.json() const d = await fr.json()
this.about.firmwareVersion = d["fw.version"] this.about.firmwareVersion = d["firmware"]["version"]
this.about.modemUid = d["fw.modemId"] this.about.modemUid = d["firmware"]["modemId"]
this.about.modemSn = d["fw.modemSn"] this.about.modemSn = d["firmware"]["modemSn"]
this.about.macManagement = d["fw.macMang"] this.about.macManagement = d["firmware"]["macMang"]
this.about.macData = d["fw.macData"] this.about.macData = d["firmware"]["macData"]
} catch (e) { } catch (e) {
console.log('Ошибка загрузки версии ПО', e) console.log('Ошибка загрузки версии ПО', e)
} }

View File

@@ -1,10 +1,50 @@
//
// Created by vlad on 03.04.2025.
//
#include "daemon.h" #include "daemon.h"
#include <utility>
#include <boost/thread/pthread/thread_data.hpp> #include "terminal_api_driver.h"
// минимальный порог для сна в цикле событий демона
static constexpr int64_t SLEEP_THRESHOLD = 10;
int64_t api_driver::TimeNow() {
return std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count();
}
namespace api_driver {
/**
* Обертка для объектов, доступных для обновления
* NOTE: перед вызовом функций, требующих `TSID`, необходимо захватить мютекс API.
*/
class CpUpdatebleObject {
public:
int64_t lastUpdate = 0;
int64_t updatePeriodMs = -1;
/**
* Функция для обновления (загрузки) объекта из CP API.
*/
std::function<void ()> updateCallback;
explicit CpUpdatebleObject(std::function<void ()> callback, int64_t period = -1): updatePeriodMs(period), updateCallback(std::move(callback)) {}
bool checkNeedUpdate(int64_t now) const {
if (updatePeriodMs < 0) return false;
// тут нет смысла спать меньше чем на 20мс, поэтому можно разрешить чтение на некоторое время раньше
return now - lastUpdate >= (updatePeriodMs - 20);
}
int64_t getNextUpdate(int64_t now) const {
if (checkNeedUpdate(now)) {
return 0;
}
auto next = now - lastUpdate;
return next < 0 ? 0 : next;
}
~CpUpdatebleObject() = default;
};
}
void api_driver::TerminalApiDaemon::connectToApi() { void api_driver::TerminalApiDaemon::connectToApi() {
@@ -12,7 +52,7 @@ void api_driver::TerminalApiDaemon::connectToApi() {
std::lock_guard _lock(this->stateMutex); std::lock_guard _lock(this->stateMutex);
this->state.fInitState = "Not connected to API"; this->state.fInitState = "Not connected to API";
} }
#if defined(MODEM_IS_SCPC) || defined(MODEM_IS_TDMA) #ifdef API_OBJECT_NETWORK_SETTINGS_ENABLE
{ {
std::lock_guard _lock(this->settingsMutex); std::lock_guard _lock(this->settingsMutex);
this->settingsNetwork.loadDefaults(); this->settingsNetwork.loadDefaults();
@@ -54,89 +94,97 @@ void api_driver::TerminalApiDaemon::run() {
this->connectToApi(); this->connectToApi();
struct { struct {
obj::CpUpdatebleObject* u; CpUpdatebleObject uo;
std::function<void ()> c; std::string updaterName;
} updaters[] = { } updaters[] = {
#if API_OBJECT_NETWORK_SETTINGS_ENABLE #ifdef API_OBJECT_DEBUG_METRICS_ENABLE
// обновление логов // обновление логов
{.u = &statsLogs, .c = [this]() { {.uo = CpUpdatebleObject([this]() {
try {
{
std::lock_guard _alock(this->cpApiMutex);
this->statsLogs.updateCallback(cp); this->statsLogs.updateCallback(cp);
} }), .updaterName = "updateDebugMetrics"},
BOOST_LOG_TRIVIAL(debug) << "api_driver::TerminalApiDaemon->statsLogs.putItem(): success write statistics state to log!";
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon->statsLogs.putItem() failed to log: " << e.what();
}
}},
#endif #endif
// обновление статистики // обновление статистики
{.u = state, .c = [this]() { {.uo = CpUpdatebleObject([this]() {
try {
std::lock_guard _alock(this->cpApiMutex); obj::TerminalState tmp;
std::lock_guard _slock(this->stateMutex); {
state.updateCallback(cp); std::shared_lock _slock1(this->settingsMutex);
stateDev.updateCallback(cp); tmp = state;
BOOST_LOG_TRIVIAL(debug) << "api_driver::TerminalApiDaemon::updateState(): success update!";
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::updateState(): " << e.what();
} }
}},
tmp.updateCallback(cp);
std::lock_guard _slock2(this->settingsMutex);
state = tmp;
}, CACHE_STATISTICS_UPDATE_MS), .updaterName = "updateStatistics"},
{.uo = CpUpdatebleObject([this]() {
obj::TerminalDeviceState tmp(stateDev);
tmp.updateCallback(cp);
std::lock_guard _slock2(this->settingsMutex);
stateDev = tmp;
}, CACHE_STATISTICS_UPDATE_MS), .updaterName = "updateDeviceState"},
// обновление кеша настроек // обновление кеша настроек
{.lastUpdate = 0, .periodMs = CACHE_SETTINGS_UPDATE_MS, .c = [this]() { {.uo = CpUpdatebleObject([this]() {
try { obj::TerminalRxTxSettings rxtx;
this->updateSettings(); rxtx.updateCallback(cp);
BOOST_LOG_TRIVIAL(debug) << "api_driver::TerminalApiDaemon::updateSettings(): success update!"; std::lock_guard _slock2(this->settingsMutex);
} catch (std::exception& e) { settingsRxTx = rxtx;
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::updateSettings(): " << e.what(); }, CACHE_SETTINGS_UPDATE_MS), .updaterName = "updateRxTxSettings"},
#ifdef API_OBJECT_NETWORK_SETTINGS_ENABLE
{.uo = CpUpdatebleObject([this]() {
obj::TerminalNetworkSettings net;
{
std::shared_lock _slock1(this->settingsMutex);
net = settingsNetwork;
} }
}},
// обновление кеша настроек сети (делается отдельно) net.updateCallback(cp);
{.lastUpdate = 0, .periodMs = CACHE_SETTINGS_UPDATE_MS, .c = [this]() { std::lock_guard _slock2(this->settingsMutex);
try { settingsNetwork = net;
this->updateNetworkSettings(); }, CACHE_SETTINGS_UPDATE_MS), .updaterName = "updateNetworkSettings"},
BOOST_LOG_TRIVIAL(debug) << "api_driver::TerminalApiDaemon::updateNetworkSettings(): success update!"; #endif
} catch (std::exception& e) { #ifdef API_OBJECT_QOS_SETTINGS_ENABLE
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::updateNetworkSettings(): " << e.what();
}
}},
// обновление кеша QoS // обновление кеша QoS
{.lastUpdate = 0, .periodMs = CACHE_QOS_UPDATE_MS, .c = [this]() { {.uo = CpUpdatebleObject([this]() {
try { obj::TerminalQosSettings qos;
this->updateQos(); qos.updateCallback(cp);
BOOST_LOG_TRIVIAL(debug) << "api_driver::TerminalApiDaemon::updateQos(): success update!"; std::lock_guard _slock(this->settingsMutex);
} catch (std::exception& e) { settingsQos = qos;
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::updateQos(): " << e.what(); }, CACHE_SETTINGS_UPDATE_MS), .updaterName = "updateQosSettings"},
} #endif
}}
}; };
while (true) { while (true) {
if (this->lastCpError == ERROR || this->lastCpError == TIMEOUT) { if (this->cp.lastCpError == ERROR || this->cp.lastCpError == TIMEOUT) {
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::run(): close current daemon session caused error " << this->lastCpError; BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::run(): close current daemon session caused error " << this->cp.lastCpError;
CP_Logout(this->sid); cp.disconnect();
this->connectToApi(); this->connectToApi();
} }
#ifdef MODEM_IS_SCPC #ifdef API_OBJECT_DEBUG_METRICS_ENABLE
updaters[0].periodMs = this->statsLogs.logEn ? this->statsLogs.logPeriodMs.load() : -1; updaters[0].uo.updatePeriodMs = this->statsLogs.logEn ? this->statsLogs.logPeriodMs.load() : -1;
#endif #endif
int64_t sleepTime = 60000; // минута по-умолчанию int64_t sleepTime = 60000; // минута по-умолчанию
auto now = TIME_NOW(); auto now = TimeNow();
for (auto& u: updaters) { for (auto& u: updaters) {
if (u.checkNeedUpdate(now)) { if (u.uo.checkNeedUpdate(now)) {
auto targetTime = u.lastUpdate + u.periodMs; auto targetTime = u.uo.lastUpdate + u.uo.updatePeriodMs;
if (targetTime + SLEEP_THRESHOLD <= now && targetTime - SLEEP_THRESHOLD >= now) { if (targetTime + SLEEP_THRESHOLD <= now && targetTime - SLEEP_THRESHOLD >= now) {
u.lastUpdate = targetTime; u.uo.lastUpdate = targetTime;
} else { } else {
u.lastUpdate = now; u.uo.lastUpdate = now;
} }
u.callback(); try {
now = TIME_NOW(); std::lock_guard _lock(this->cpApiMutex);
u.uo.updateCallback();
BOOST_LOG_TRIVIAL(debug) << "api_driver::TerminalApiDaemon::run()->" << u.updaterName << "(): success update!";
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::run()->" << u.updaterName << "(): error " << e.what();
} }
if (u.periodMs >= 0) {
sleepTime = std::min(sleepTime, u.getNextUpdate(now)); now = TimeNow();
}
if (u.uo.updatePeriodMs >= 0) {
sleepTime = std::min(sleepTime, u.uo.getNextUpdate(now));
} }
} }
@@ -149,46 +197,80 @@ void api_driver::TerminalApiDaemon::run() {
api_driver::TerminalApiDaemon::TerminalApiDaemon(): daemon([this]() { this->run(); }) {} api_driver::TerminalApiDaemon::TerminalApiDaemon(): daemon([this]() { this->run(); }) {}
void api_driver::TerminalApiDaemon::getState(obj::TerminalState &dest) { void api_driver::TerminalApiDaemon::getState(obj::TerminalState &dest) {
std::shared_lock _lock(state); std::shared_lock _lock(stateMutex);
dest = state; dest = state;
} }
void api_driver::TerminalApiDaemon::getDeviceState(obj::TerminalDeviceState &dest) { void api_driver::TerminalApiDaemon::getDeviceState(obj::TerminalDeviceState &dest) {
std::shared_lock _lock(state); std::shared_lock _lock(stateMutex);
dest = stateDev; dest = stateDev;
} }
void api_driver::TerminalApiDaemon::getSettingsRxTx(obj::TerminalRxTxSettings &dest) { api_driver::obj::TerminalRxTxSettings api_driver::TerminalApiDaemon::getSettingsRxTx() {
obj::TerminalRxTxSettings s;
{
std::shared_lock _olock(this->settingsMutex);
s = settingsRxTx;
}
return s;
} }
void api_driver::TerminalApiDaemon::getNetworkSettings(obj::TerminalNetworkSettings &dest) { void api_driver::TerminalApiDaemon::setSettingsRxTx(obj::TerminalRxTxSettings &s) {
std::lock_guard _olock(settingsMutex);
settingsRxTx = s;
} }
void api_driver::TerminalApiDaemon::getQosSettings(bool &isEnabled, std::string &json) { #ifdef API_OBJECT_NETWORK_SETTINGS_ENABLE
api_driver::obj::TerminalNetworkSettings api_driver::TerminalApiDaemon::getNetworkSettings() {
obj::TerminalNetworkSettings s;
{
std::shared_lock _olock(this->settingsMutex);
s = settingsNetwork;
}
return s;
} }
void api_driver::TerminalApiDaemon::setSettingsRxTx(obj::TerminalRxTxSettings &s, bool readback) { void api_driver::TerminalApiDaemon::setNetworkSettings(obj::TerminalNetworkSettings &s) {
std::lock_guard _olock(settingsMutex);
settingsNetwork = s;
}
#endif
#ifdef API_OBJECT_QOS_SETTINGS_ENABLE
api_driver::obj::TerminalQosSettings api_driver::TerminalApiDaemon::getQosSettings() {
obj::TerminalQosSettings s;
{
std::shared_lock _olock(this->settingsMutex);
s = settingsQos;
}
return s;
} }
void api_driver::TerminalApiDaemon::setSettingsDpdi(DPDI_parmeters &s, bool readback) { void api_driver::TerminalApiDaemon::setQosSettings(obj::TerminalQosSettings &s) {
} std::lock_guard _olock(settingsMutex);
settingsQos = s;
void api_driver::TerminalApiDaemon::setSettingsBucLnb(buc_lnb_settings &bucLnb, bool readback) {
}
void api_driver::TerminalApiDaemon::setQosSettings(bool enabled, const std::string &str, bool readback) {
}
void api_driver::TerminalApiDaemon::setNetworkSettings(obj::TerminalNetworkSettings &s, bool readback) {
} }
#endif
api_driver::obj::TerminalFirmwareVersion api_driver::TerminalApiDaemon::getFirmware() { api_driver::obj::TerminalFirmwareVersion api_driver::TerminalApiDaemon::getFirmware() {
obj::TerminalFirmwareVersion res;
{
std::shared_lock _olock(firmwareMutex);
res = firmware;
}
return res;
} }
void api_driver::TerminalApiDaemon::resetPacketStatistics() { void api_driver::TerminalApiDaemon::resetPacketStatistics() {
std::lock_guard lock(this->cpApiMutex);
cp.getDmaDebug("reset_cnt_rx");
} }
void api_driver::TerminalApiDaemon::resetDefaultSettings() { void api_driver::TerminalApiDaemon::resetDefaultSettings() {
std::lock_guard lock(this->cpApiMutex);
cp.setDmaDebug("begin_save_config", "");
cp.setDmaDebug("default_params", "");
cp.setDmaDebug("save_config", "");
} }
api_driver::TerminalApiDaemon::~TerminalApiDaemon() { api_driver::TerminalApiDaemon::~TerminalApiDaemon() {
@@ -199,274 +281,3 @@ api_driver::TerminalApiDaemon::~TerminalApiDaemon() {
BOOST_LOG_TRIVIAL(error) << "api_driver::~TerminalApiDaemon(): " << e.what(); BOOST_LOG_TRIVIAL(error) << "api_driver::~TerminalApiDaemon(): " << e.what();
} }
} }
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
* Этот демон нужен для того, чтобы получать статистику из API, а так же корректно сохранять настройки
*/
class api_driver::TerminalApiDaemon {
void updateState() {
obj::TerminalDeviceState s;
std::lock_guard lock(this->cpApiMutex);
try {
s.updateCallback(cp);
}
{
std::lock_guard lock2(this->stateMutex);
this->state = s;
#ifdef MODEM_IS_TDMA
this->state.fInitState = tmpDevState;
#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{};
#endif
DPDI_parmeters dpdi{};
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));
#endif
logCpApiError("api_driver::TerminalApiDaemon::updateSettings()->CP_GetDpdiParams()", CP_GetDpdiParams(sid, &dpdi));
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;
#endif
this->dpdiSettings = dpdi;
this->bucLnbSettings = bucLnb;
}
}
void updateNetworkSettings() {
obj::TerminalNetworkSettings s;
std::lock_guard lock(this->cpApiMutex);
unsafeLoadNetworkSettings(s);
{
std::lock_guard lock2(this->networkSettingsMutex);
this->networkSettings = s;
}
}
void updateQos() {
bool tmp1; std::string tmp2;
std::scoped_lock lock{this->cpApiMutex};
logCpApiError("api_driver::TerminalApiDaemon::updateQos()->CP_GetQoSSettings()", CP_GetQoSSettings(this->sid, tmp2, tmp1));
{
std::lock_guard lock2(this->qosSettingsMutex);
this->qosEnabled = tmp1;
this->qosClassesJson = tmp2.empty() ? DEFAULT_QOS_CLASSES : tmp2;
}
}
public:
/**
* Получение статистики, копирует текущие значения в структуры, переданные по указателю. Если передан пустой указатель, копирования не произойдет.
*/
TerminalDeviceState getState() {
TerminalDeviceState s;
{
std::shared_lock lock(this->stateMutex);
s = this->state;
}
return s;
}
/**
* Получение настроек, копирует текущие значения в структуры, переданные по указателю. Если передан пустой указатель, копирования не произойдет.
*/
void getSettings(
modulator_settings* mod, demodulator_settings* demod,
#ifdef MODEM_IS_SCPC
ACM_parameters_serv_* acm,
#endif
DPDI_parmeters* dpdi, buc_lnb_settings* bucLnb) {
if (mod || demod ||
#ifdef MODEM_IS_SCPC
acm ||
#endif
dpdi || bucLnb) {
std::shared_lock lock(this->settingsMutex);
if (mod) { *mod = this->modSettings; }
if (demod) { *demod = this->demodSettings; }
#ifdef MODEM_IS_SCPC
if (acm) { *acm = this->acmSettings; }
#endif
if (dpdi) { *dpdi = this->dpdiSettings; }
if (bucLnb) { *bucLnb = this->bucLnbSettings; }
}
}
#ifdef MODEM_IS_SCPC
bool getIsCinC() {
std::shared_lock lock(this->settingsMutex);
return modSettings.is_cinc;
}
#endif
bool isTest() {
std::shared_lock lock(this->settingsMutex);
return modSettings.tx_is_on && (!modSettings.is_carrier
#ifdef MODEM_IS_SCPC
|| this->modSettings.is_test_data
#endif
);
}
void getNetworkSettings(TerminalNetworkSettings& dest) {
std::shared_lock lock(this->networkSettingsMutex);
dest = this->networkSettings;
}
void getQosSettings(bool& isEnabled, std::string& json) {
std::shared_lock lock(this->qosSettingsMutex);
isEnabled = this->qosEnabled;
json = this->qosClassesJson;
}
#ifdef MODEM_IS_SCPC
void setSettingsRxTx(modulator_settings& mod, demodulator_settings& demod, ACM_parameters_serv_& acm, bool readback = true) {
std::lock_guard lock(this->cpApiMutex);
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_SetDmaDebug(begin_save_config)", CP_SetDmaDebug(sid, "begin_save_config", ""));
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_SetModulatorSettings()", CP_SetModulatorSettings(this->sid, mod));
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_SetDemodulatorSettings()", CP_SetDemodulatorSettings(this->sid, demod));
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_SetAcmParams()", CP_SetAcmParams(this->sid, acm));
if (readback) {
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_GetModulatorSettings()", CP_GetModulatorSettings(this->sid, mod));
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_GetDemodulatorSettings()", CP_GetDemodulatorSettings(this->sid, demod));
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_GetAcmParams()", CP_GetAcmParams(this->sid, &acm));
{
std::lock_guard lock2{this->settingsMutex};
this->modSettings = mod;
this->demodSettings = demod;
this->acmSettings = acm;
}
}
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_SetDmaDebug(save_config)", CP_SetDmaDebug(sid, "save_config", ""));
}
#else
void setSettingsRxTx(modulator_settings& mod, demodulator_settings& demod, bool readback = true) {
std::lock_guard lock(this->cpApiMutex);
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_SetDmaDebug(begin_save_config)", CP_SetDmaDebug(sid, "begin_save_config", ""));
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_SetModulatorSettings()", CP_SetModulatorSettings(this->sid, mod));
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_SetDemodulatorSettings()", CP_SetDemodulatorSettings(this->sid, demod));
if (readback) {
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_GetModulatorSettings()", CP_GetModulatorSettings(this->sid, mod));
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_GetDemodulatorSettings()", CP_GetDemodulatorSettings(this->sid, demod));
{
std::lock_guard lock2{this->settingsMutex};
this->modSettings = mod;
this->demodSettings = demod;
}
}
logCpApiError("api_driver::TerminalApiDaemon::setSettingsRxTx()->CP_SetDmaDebug(save_config)", CP_SetDmaDebug(sid, "save_config", ""));
}
#endif
void setSettingsDpdi(DPDI_parmeters& s, bool readback = true) {
std::lock_guard lock(this->cpApiMutex);
logCpApiError("api_driver::TerminalApiDaemon::setSettingsDpdi()->CP_SetDmaDebug(begin_save_config)", CP_SetDmaDebug(sid, "begin_save_config", ""));
logCpApiError("api_driver::TerminalApiDaemon::setSettingsDpdi()->CP_SetDpdiParams()", CP_SetDpdiParams(sid, s));
if (readback) {
logCpApiError("api_driver::TerminalApiDaemon::setSettingsDpdi()->CP_GetDpdiParams()", CP_GetDpdiParams(this->sid, &s));
{
std::lock_guard lock2{this->settingsMutex};
this->dpdiSettings = s;
}
}
logCpApiError("api_driver::TerminalApiDaemon::setSettingsDpdi()->CP_SetDmaDebug(save_config)", CP_SetDmaDebug(sid, "save_config", ""));
}
void setSettingsBucLnb(buc_lnb_settings& bucLnb, bool readback = true) {
std::lock_guard lock(this->cpApiMutex);
logCpApiError("api_driver::TerminalApiDaemon::setSettingsBucLnb()->CP_SetDmaDebug(begin_save_config)", CP_SetDmaDebug(sid, "begin_save_config", ""));
logCpApiError("api_driver::TerminalApiDaemon::setSettingsBucLnb()->CP_SetBUC_LNB_settings()", CP_SetBUC_LNB_settings(this->sid, bucLnb));
if (readback) {
logCpApiError("api_driver::TerminalApiDaemon::setSettingsBucLnb()->CP_GetBUC_LNB_settings()", CP_GetBUC_LNB_settings(this->sid, bucLnb));
{
std::lock_guard lock2{this->settingsMutex};
this->bucLnbSettings = bucLnb;
}
}
logCpApiError("api_driver::TerminalApiDaemon::setSettingsBucLnb()->CP_SetDmaDebug(save_config)", CP_SetDmaDebug(sid, "save_config", ""));
}
void setQosSettings(bool enabled, const std::string& str, bool readback = true) {
std::lock_guard lock(this->cpApiMutex);
logCpApiError("api_driver::TerminalApiDaemon::setQosSettings()->CP_SetDmaDebug(begin_save_config)", CP_SetDmaDebug(sid, "begin_save_config", ""));
logCpApiError("api_driver::TerminalApiDaemon::setQosSettings()->CP_SetQoSSettings()", CP_SetQoSSettings(this->sid, str, enabled));
if (readback) {
bool tmp1; std::string tmp2;
logCpApiError("api_driver::TerminalApiDaemon::setQosSettings()->CP_GetQoSSettings()", CP_GetQoSSettings(this->sid, tmp2, tmp1));
{
std::lock_guard lock2(this->qosSettingsMutex);
this->qosEnabled = tmp1;
this->qosClassesJson = tmp2.empty() ? DEFAULT_QOS_CLASSES : tmp2;
}
}
logCpApiError("api_driver::TerminalApiDaemon::setQosSettings()->CP_SetDmaDebug(save_config)", CP_SetDmaDebug(sid, "save_config", ""));
}
void setNetworkSettings(TerminalNetworkSettings& s, bool readback = true) {
// const auto mang = splitIpAndMask();
// std::pair<std::string, std::string> data;
// if (!s.isL2) {
// data = splitIpAndMask(s.dataIp);
// }
std::lock_guard lock(this->cpApiMutex);
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetDmaDebug(begin_save_config)", CP_SetDmaDebug(sid, "begin_save_config", ""));
unsafStoreNetworkSettings(s);
if (readback) {
unsafeLoadNetworkSettings(s);
{
std::lock_guard lock2(this->networkSettingsMutex);
this->networkSettings = s;
}
}
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetDmaDebug(save_config)", CP_SetDmaDebug(sid, "save_config", ""));
}
TerminalFirmwareVersion getFirmware() {
std::shared_lock lock(this->firmwareMutex);
return firmware;
}
void resetPacketStatistics() {
std::string tmp;
std::lock_guard lock(this->cpApiMutex);
logCpApiError("api_driver::TerminalApiDaemon::resetPacketStatistics()->CP_GetDmaDebug(reset_cnt_rx)", CP_GetDmaDebug(sid, "reset_cnt_rx", &tmp));
}
void resetDefaultSettings() {
std::lock_guard lock(this->cpApiMutex);
logCpApiError("api_driver::TerminalApiDaemon::resetDefaultSettings()->CP_SetDmaDebug(begin_save_config)", CP_SetDmaDebug(sid, "begin_save_config", ""));
logCpApiError("api_driver::TerminalApiDaemon::resetDefaultSettings()->CP_SetDmaDebug(default_params)", CP_SetDmaDebug(sid, "default_params", ""));
logCpApiError("api_driver::TerminalApiDaemon::resetDefaultSettings()->CP_SetDmaDebug(save_config)", CP_SetDmaDebug(sid, "save_config", ""));
}
};

View File

@@ -1,16 +1,15 @@
#ifndef DAEMON_H #ifndef API_DRIVER_DAEMON_H
#define DAEMON_H #define API_DRIVER_DAEMON_H
#include <boost/thread/detail/thread.hpp>
#include "proxy.h" #include "proxy.h"
#include "api-driver/structs.h" #include "api-driver/structs.h"
#include <boost/thread/thread.hpp>
namespace api_driver { namespace api_driver {
int64_t TimeNow();
class TerminalApiDaemon { class TerminalApiDaemon {
std::mutex cpApiMutex;
boost::thread daemon; boost::thread daemon;
proxy::CpProxy cp;
void connectToApi(); void connectToApi();
@@ -22,49 +21,49 @@ namespace api_driver {
std::shared_mutex settingsMutex; std::shared_mutex settingsMutex;
obj::TerminalRxTxSettings settingsRxTx; obj::TerminalRxTxSettings settingsRxTx;
#if API_OBJECT_NETWORK_SETTINGS_ENABLE #ifdef API_OBJECT_NETWORK_SETTINGS_ENABLE
obj::TerminalNetworkSettings settingsNetwork; obj::TerminalNetworkSettings settingsNetwork;
#endif #endif
#if API_OBJECT_QOS_SETTINGS_ENABLE #ifdef API_OBJECT_QOS_SETTINGS_ENABLE
obj::TerminalQosSettings settingsQos; obj::TerminalQosSettings settingsQos;
#endif #endif
std::shared_mutex firmwareMutex; std::shared_mutex firmwareMutex;
obj::TerminalFirmwareVersion firmware; obj::TerminalFirmwareVersion firmware;
public: public:
#if API_OBJECT_STATISTICS_ENABLE std::mutex cpApiMutex;
proxy::CpProxy cp;
#ifdef API_OBJECT_DEBUG_METRICS_ENABLE
obj::StatisticsLogger statsLogs; obj::StatisticsLogger statsLogs;
#endif #endif
explicit TerminalApiDaemon(); explicit TerminalApiDaemon();
std::string getDeviceInitState();
/** /**
* Получение статистики, копирует текущие значения в структуры, переданные по указателю. Если передан пустой указатель, копирования не произойдет. * Получение статистики, копирует текущие значения в структуры, переданные по указателю. Если передан пустой указатель, копирования не произойдет.
*/ */
void getState(obj::TerminalState& dest); void getState(obj::TerminalState &dest);
void getDeviceState(obj::TerminalDeviceState& dest);
void getDeviceState(obj::TerminalDeviceState &dest);
// /** // /**
// * Получение настроек, копирует текущие значения в структуры, переданные по указателю. Если передан пустой указатель, копирования не произойдет. // * Получение настроек, копирует текущие значения в структуры, переданные по указателю. Если передан пустой указатель, копирования не произойдет.
// * Установка настроек просто копирует настройки и устанавливает их текущими
// */ // */
void getSettingsRxTx(obj::TerminalRxTxSettings& dest); obj::TerminalRxTxSettings getSettingsRxTx();
void setSettingsRxTx(obj::TerminalRxTxSettings &s);
void getNetworkSettings(obj::TerminalNetworkSettings& dest); #ifdef API_OBJECT_NETWORK_SETTINGS_ENABLE
obj::TerminalNetworkSettings getNetworkSettings();
void setNetworkSettings(obj::TerminalNetworkSettings &s);
#endif
void getQosSettings(bool& isEnabled, std::string& json); #ifdef API_OBJECT_QOS_SETTINGS_ENABLE
obj::TerminalQosSettings getQosSettings();
void setSettingsRxTx(obj::TerminalRxTxSettings& s, bool readback = true); void setQosSettings(obj::TerminalQosSettings &s);
#endif
void setSettingsDpdi(DPDI_parmeters& s, bool readback = true);
void setSettingsBucLnb(buc_lnb_settings& bucLnb, bool readback = true);
void setQosSettings(bool enabled, const std::string& str, bool readback = true);
void setNetworkSettings(obj::TerminalNetworkSettings& s, bool readback = true);
obj::TerminalFirmwareVersion getFirmware(); obj::TerminalFirmwareVersion getFirmware();
@@ -77,4 +76,4 @@ namespace api_driver {
} }
#endif //DAEMON_H #endif //API_DRIVER_DAEMON_H

View File

@@ -1,10 +1,137 @@
#include "proxy.h" #include "proxy.h"
#include "sstream"
//#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) #define CPAPI_PROXY_CALL_HELPER(callfrom, func, funcArgs, throwArgs) do { lastCpError = func funcArgs; if (lastCpError != OK) { \
// void foo() { std::stringstream err; err << callfrom ": CP Api error " #func "("; err << throwArgs; err << "): " << lastCpError;\
// api_driver::proxy::CpProxy proxy; throw std::runtime_error(err.str());\
// std::string tmp; } } while (0)
// CPAPI_PROXY_CALL(proxy, CP_GetDmaDebug, "fuck", &tmp);
// }
api_driver::proxy::CpProxy::CpProxy() = default;
api_driver::proxy::CpProxy::CpProxy(TSID s): sid(s) {}
void api_driver::proxy::CpProxy::connect() {
unsigned int access{};
CPAPI_PROXY_CALL_HELPER("CpProxy::connect", CP_Login, ("admin", "pass", &sid, &access), R"("admin", "pass", &sid, &access)");
}
void api_driver::proxy::CpProxy::disconnect() {
if (sid != 0) {
lastCpError = CP_Logout(sid);
sid = 0;
}
}
std::string api_driver::proxy::CpProxy::getDmaDebug(const std::string &arg) {
std::string result;
CPAPI_PROXY_CALL_HELPER("CpProxy::getDmaDebug", CP_GetDmaDebug, (sid, arg.c_str(), &result), arg);
return result;
}
void api_driver::proxy::CpProxy::setDmaDebug(const std::string &arg, const std::string &value) {
CPAPI_PROXY_CALL_HELPER("CpProxy::setDmaDebug", CP_SetDmaDebug, (sid, arg.c_str(), value), arg << ", \"" << value << "\"");
}
std::string api_driver::proxy::CpProxy::getNetwork(const std::string &param) {
std::string result;
CPAPI_PROXY_CALL_HELPER("CpProxy::getNetwork", CP_GetNetwork, (sid, param.c_str(), &result), param);
return result;
}
void api_driver::proxy::CpProxy::setNetwork(const std::string &param, const std::string &value) {
CPAPI_PROXY_CALL_HELPER("CpProxy::setNetwork", CP_SetNetwork, (sid, param.c_str(), value.c_str()), param << ", \"" << value << "\"");
}
void api_driver::proxy::CpProxy::getModState(modulator_state &dest) {
CPAPI_PROXY_CALL_HELPER("CpProxy::getModState", CP_GetModulatorState, (sid, dest), "");
}
void api_driver::proxy::CpProxy::getModSettings(modulator_settings &dest) {
CPAPI_PROXY_CALL_HELPER("CpProxy::getModSettings", CP_GetModulatorSettings, (sid, dest), "");
}
void api_driver::proxy::CpProxy::setModSettings(modulator_settings &dest) {
CPAPI_PROXY_CALL_HELPER("CpProxy::setModSettings", CP_SetModulatorSettings, (sid, dest), "struct {...}");
}
void api_driver::proxy::CpProxy::getDemodState(demodulator_state &dest) {
CPAPI_PROXY_CALL_HELPER("CpProxy::getDemodState", CP_GetDemodulatorState, (sid, dest), "");
}
void api_driver::proxy::CpProxy::getDemodSettings(demodulator_settings &dest) {
CPAPI_PROXY_CALL_HELPER("CpProxy::getDemodSettings", CP_GetDemodulatorSettings, (sid, dest), "");
}
void api_driver::proxy::CpProxy::setDemodSettings(demodulator_settings &dest) {
CPAPI_PROXY_CALL_HELPER("CpProxy::setDemodSettings", CP_SetDemodulatorSettings, (sid, dest), "struct {...}");
}
#ifdef API_STRUCT_ACM_ENABLE
void api_driver::proxy::CpProxy::getAcmSettings(ACM_parameters_serv_ &dest) {
CPAPI_PROXY_CALL_HELPER("CpProxy::getAcmSettings", CP_GetAcmParams, (sid, &dest), "");
}
void api_driver::proxy::CpProxy::setAcmSettings(ACM_parameters_serv_ &dest) {
CPAPI_PROXY_CALL_HELPER("CpProxy::setAcmSettings", CP_SetAcmParams, (sid, dest), "struct {...}");
}
#endif
void api_driver::proxy::CpProxy::getDeviceState(device_state &dest) {
CPAPI_PROXY_CALL_HELPER("CpProxy::getDeviceState", CP_GetDeviceState, (sid, dest), "");
}
#ifdef API_OBJECT_QOS_SETTINGS_ENABLE
std::tuple<std::string, bool> api_driver::proxy::CpProxy::getQosSettings() {
std::string rules;
bool en;
CPAPI_PROXY_CALL_HELPER("CpProxy::getQosSettings", CP_GetQoSSettings, (sid, rules, en), "");
return {rules, en};
}
void api_driver::proxy::CpProxy::setQosSettings(const std::string &rules, bool enable) {
CPAPI_PROXY_CALL_HELPER("CpProxy::setQosSettings", CP_SetQoSSettings, (sid, rules, enable), "`" << rules << "`, " << (enable ? "true" : "false"));
}
#endif
#ifdef API_OBJECT_DPDI_SETTINGS_ENABLE
void api_driver::proxy::CpProxy::getDpdiSettings(DPDI_parmeters &dest) {
CPAPI_PROXY_CALL_HELPER("CpProxy::getDpdiSettings", CP_GetDpdiParams, (sid, &dest), "");
}
void api_driver::proxy::CpProxy::setDpdiSettings(DPDI_parmeters &dest) {
CPAPI_PROXY_CALL_HELPER("CpProxy::setDpdiSettings", CP_SetDpdiParams, (sid, dest), "struct {...}");
}
#endif
#ifdef API_OBJECT_BUCLNB_SETTINGS_ENABLE
void api_driver::proxy::CpProxy::getBuclnbSettings(buc_lnb_settings &dest) {
CPAPI_PROXY_CALL_HELPER("CpProxy::getBuclnbSettings", CP_GetBUC_LNB_settings, (sid, dest), "");
}
void api_driver::proxy::CpProxy::setBuclnbSettings(buc_lnb_settings &dest) {
CPAPI_PROXY_CALL_HELPER("CpProxy::setBuclnbSettings", CP_SetBUC_LNB_settings, (sid, dest), "struct {...}");
}
#endif
#ifdef MODEM_IS_SCPC
void api_driver::proxy::CpProxy::getCincState(CinC_state &dest) {
CPAPI_PROXY_CALL_HELPER("CpProxy::getCincState", CP_GetCinCState, (sid, dest), "");
}
#endif
#ifdef API_OBJECT_DEBUG_METRICS_ENABLE
void api_driver::proxy::CpProxy::getDebugMetrics(debug_metrics &dest) {
CPAPI_PROXY_CALL_HELPER("CpProxy::getDebugMetrics", CP_GetDebugMetrics, (sid, dest), "");
}
#endif
#ifdef MODEM_IS_TDMA
void api_driver::proxy::CpProxy::getUpdateStatus(progress_msg &dest) {
CPAPI_PROXY_CALL_HELPER("CpProxy::getUpdateStatus", CP_GetUpdateStatus, (sid, dest), "");
}
#endif
api_driver::proxy::CpProxy::~CpProxy() {
disconnect();
}

View File

@@ -8,7 +8,6 @@
std::ostream& operator<<(std::ostream& out, CP_Result result); std::ostream& operator<<(std::ostream& out, CP_Result result);
namespace api_driver::proxy { namespace api_driver::proxy {
class CpProxy { class CpProxy {
public: public:
@@ -28,6 +27,7 @@ namespace api_driver::proxy {
void disconnect(); void disconnect();
std::string getDmaDebug(const std::string& arg); std::string getDmaDebug(const std::string& arg);
void setDmaDebug(const std::string& arg, const std::string& value);
std::string getNetwork(const std::string& param); std::string getNetwork(const std::string& param);
void setNetwork(const std::string& param, const std::string& value); void setNetwork(const std::string& param, const std::string& value);
@@ -40,15 +40,39 @@ namespace api_driver::proxy {
void getDemodSettings(demodulator_settings& dest); void getDemodSettings(demodulator_settings& dest);
void setDemodSettings(demodulator_settings& dest); void setDemodSettings(demodulator_settings& dest);
#ifdef API_STRUCT_ACM_ENABLE
void getAcmSettings(ACM_parameters_serv_& dest);
void setAcmSettings(ACM_parameters_serv_& dest);
#endif
void getDeviceState(device_state& dest); void getDeviceState(device_state& dest);
#ifdef MODEM_IS_SCPC #ifdef API_OBJECT_QOS_SETTINGS_ENABLE
void getCincState(CinC_state& dest); std::tuple<std::string, bool> getQosSettings();
#endif void setQosSettings(const std::string& rules, bool enable);
#endif
#if API_OBJECT_STATISTICS_ENABLE #ifdef API_OBJECT_DPDI_SETTINGS_ENABLE
void getDpdiSettings(DPDI_parmeters& dest);
void setDpdiSettings(DPDI_parmeters& dest);
#endif
#ifdef API_OBJECT_BUCLNB_SETTINGS_ENABLE
void getBuclnbSettings(buc_lnb_settings& dest);
void setBuclnbSettings(buc_lnb_settings& dest);
#endif
#ifdef MODEM_IS_SCPC
void getCincState(CinC_state& dest);
#endif
#ifdef API_OBJECT_DEBUG_METRICS_ENABLE
void getDebugMetrics(debug_metrics& dest); void getDebugMetrics(debug_metrics& dest);
#endif #endif
#ifdef MODEM_IS_TDMA
void getUpdateStatus(progress_msg& dest);
#endif
~CpProxy(); ~CpProxy();
}; };

View File

@@ -1,8 +1,30 @@
#ifndef API_DRIVER_STRICTS_ENABLE_H #ifndef API_DRIVER_STRICTS_ENABLE_H
#define API_DRIVER_STRICTS_ENABLE_H #define API_DRIVER_STRICTS_ENABLE_H
#define API_OBJECT_STATISTICS_ENABLE defined(MODEM_IS_SCPC)
#define API_OBJECT_NETWORK_SETTINGS_ENABLE defined(MODEM_IS_SCPC) || defined(MODEM_IS_TDMA) #if defined(MODEM_IS_SCPC)
#define API_OBJECT_QOS_SETTINGS_ENABLE defined(MODEM_IS_SCPC) || defined(MODEM_IS_TDMA) #define API_OBJECT_DEBUG_METRICS_ENABLE
#endif
#if defined(MODEM_IS_SCPC) || defined(MODEM_IS_SHPS)
#define API_STRUCT_ACM_ENABLE
#endif
#if defined(MODEM_IS_SCPC) || defined(MODEM_IS_TDMA) || defined(MODEM_IS_SHPS)
#define API_OBJECT_NETWORK_SETTINGS_ENABLE
#endif
#if defined(MODEM_IS_SCPC) || defined(MODEM_IS_TDMA)
#define API_OBJECT_QOS_SETTINGS_ENABLE
#endif
#if defined(MODEM_IS_SCPC) || defined(MODEM_IS_TDMA)
#define API_OBJECT_DPDI_SETTINGS_ENABLE
#endif
#if defined(MODEM_IS_SCPC) || defined(MODEM_IS_TDMA) || defined(MODEM_IS_SHPS)
#define API_OBJECT_BUCLNB_SETTINGS_ENABLE
#endif
#endif //API_DRIVER_STRICTS_ENABLE_H #endif //API_DRIVER_STRICTS_ENABLE_H

File diff suppressed because it is too large Load Diff

View File

@@ -7,36 +7,12 @@
#include <fstream> #include <fstream>
#include <shared_mutex> #include <shared_mutex>
#include <string> #include <string>
#include <boost/log/trivial.hpp> #include "common/nlohmann/json.hpp"
#include <boost/property_tree/ptree_fwd.hpp>
namespace api_driver::obj { namespace api_driver::obj {
/** #ifdef API_OBJECT_DEBUG_METRICS_ENABLE
* Обертка для объектов, доступных для обновления class StatisticsLogger {
* NOTE: перед вызовом функций, требующих `TSID`, необходимо захватить мютекс API.
*/
class CpUpdatebleObject {
public:
int64_t lastUpdate = 0;
int64_t updatePeriodMs = -1;
/**
* Функция для обновления (загрузки) объекта из CP API.
*/
virtual void updateCallback(proxy::CpProxy& cp) = 0;
bool checkNeedUpdate(int64_t now) const;
int64_t getNextUpdate(int64_t now) const;
virtual ~CpUpdatebleObject();
};
#if API_OBJECT_STATISTICS_ENABLE
class StatisticsLogger: public CpUpdatebleObject {
public: public:
StatisticsLogger(); StatisticsLogger();
@@ -52,10 +28,10 @@ namespace api_driver::obj {
* *
* @return {"en": bool, "logPeriodMs": int, "maxAgeMs": int} * @return {"en": bool, "logPeriodMs": int, "maxAgeMs": int}
*/ */
std::string getSettings(); nlohmann::json getSettings();
void setSettings(boost::property_tree::ptree &pt); void setSettings(const nlohmann::json& data);
void updateCallback(proxy::CpProxy& cp) override; void updateCallback(proxy::CpProxy& cp);
/** /**
* Записать значение в "базу данных". Метку при этом вставлять не нужно, она будет вставлена автоматически. * Записать значение в "базу данных". Метку при этом вставлять не нужно, она будет вставлена автоматически.
* @param item * @param item
@@ -69,7 +45,7 @@ namespace api_driver::obj {
// logs.clear(); // logs.clear();
// } // }
~StatisticsLogger() override; ~StatisticsLogger();
private: private:
// std::pmr::deque<LogItem> logs; // std::pmr::deque<LogItem> logs;
std::fstream logFile{}; std::fstream logFile{};
@@ -81,14 +57,14 @@ namespace api_driver::obj {
static constexpr const char* DEFAULT_SERVER_NAME = "RSCM-101"; static constexpr const char* DEFAULT_SERVER_NAME = "RSCM-101";
#elif defined(MODEM_IS_TDMA) #elif defined(MODEM_IS_TDMA)
static constexpr const char* DEFAULT_SERVER_NAME = "TDMA Abonent"; static constexpr const char* DEFAULT_SERVER_NAME = "TDMA Abonent";
#elif defined(MODEM_IS_SHPC) #elif defined(MODEM_IS_SHPS)
static constexpr const char* DEFAULT_SERVER_NAME = "SHPS Terminal"; static constexpr const char* DEFAULT_SERVER_NAME = "SHPS Terminal";
#else #else
#error "Selected modem type not supported!" #error "Selected modem type not supported!"
#endif #endif
#if API_OBJECT_NETWORK_SETTINGS_ENABLE #ifdef API_OBJECT_NETWORK_SETTINGS_ENABLE
class TerminalNetworkSettings: public CpUpdatebleObject { class TerminalNetworkSettings {
public: public:
std::string managementIp, managementGateway, dataIp, serverName; std::string managementIp, managementGateway, dataIp, serverName;
bool isL2 = true; bool isL2 = true;
@@ -100,20 +76,20 @@ namespace api_driver::obj {
void loadDefaults(); void loadDefaults();
void updateCallback(proxy::CpProxy& cp) override; void updateCallback(proxy::CpProxy& cp);
void updateFromPt(boost::property_tree::ptree &pt); void updateFromJson(const nlohmann::json& data);
void store(proxy::CpProxy& cp); void store(proxy::CpProxy& cp);
std::string asJson(); nlohmann::json asJson();
~TerminalNetworkSettings() override; ~TerminalNetworkSettings();
}; };
#endif #endif
#if API_OBJECT_QOS_SETTINGS_ENABLE #ifdef API_OBJECT_QOS_SETTINGS_ENABLE
class TerminalQosSettings: public CpUpdatebleObject { class TerminalQosSettings {
public: public:
static constexpr const char* DEFAULT_QOS_CLASSES = R"({"rt1":[],"rt2":[],"rt3":[],"cd":[]})"; static constexpr const char* DEFAULT_QOS_CLASSES = R"({"rt1":[],"rt2":[],"rt3":[],"cd":[]})";
std::string qosSettingsJson; nlohmann::json qosSettingsJson;
bool qosEnabled = false; bool qosEnabled = false;
TerminalQosSettings(); TerminalQosSettings();
@@ -122,12 +98,12 @@ namespace api_driver::obj {
void loadDefaults(); void loadDefaults();
void updateCallback(proxy::CpProxy& cp) override; void updateCallback(proxy::CpProxy& cp);
void updateFromPt(boost::property_tree::ptree &pt); void updateFromJson(const nlohmann::json& data);
void store(proxy::CpProxy& cp); void store(proxy::CpProxy& cp);
std::string asJson(); nlohmann::json asJson();
~TerminalQosSettings() override; ~TerminalQosSettings();
}; };
#endif #endif
@@ -137,24 +113,18 @@ namespace api_driver::obj {
TerminalFirmwareVersion(); TerminalFirmwareVersion();
TerminalFirmwareVersion(const TerminalFirmwareVersion& src); TerminalFirmwareVersion(const TerminalFirmwareVersion& src);
~TerminalFirmwareVersion();
// 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));
void load(proxy::CpProxy& cp);
std::string asJson();
TerminalFirmwareVersion& operator= (const TerminalFirmwareVersion& src); TerminalFirmwareVersion& operator= (const TerminalFirmwareVersion& src);
void load(proxy::CpProxy& cp);
nlohmann::json asJson();
~TerminalFirmwareVersion();
}; };
/** /**
* Обертка состояния терминала, тут состояние девайса, модулятора/демодулятора, состояние автоматического обновления. * Обертка состояния терминала, тут состояние девайса, модулятора/демодулятора, состояние автоматического обновления.
*/ */
class TerminalState: public CpUpdatebleObject { class TerminalState {
public: public:
std::string fInitState{}; std::string fInitState{};
bool fIsTest = false; // daemon->isTest() bool fIsTest = false; // daemon->isTest()
@@ -163,62 +133,62 @@ namespace api_driver::obj {
bool fIsCinC = false; bool fIsCinC = false;
#endif #endif
bool fStatRxState; bool fRxState{};
bool fStatRxSymSyncLock; #ifndef MODEM_IS_SHPS
bool fStatRxFreqSearchLock; bool fRxSymSyncLock{};
bool fStatRxAfcLock; bool fRxFreqSearchLock{};
bool fStatRxPktSync; bool fRxAfcLock{};
bool fRxPktSync{};
#endif
float fStatRxSnr; float fRxSnr{};
float fStatRxRssi; float fRxRssi{};
uint16_t fStatRxModcod; #ifndef MODEM_IS_SHPS
bool fStatRxFrameSizeNormal; uint16_t fRxModcod{};
bool fStatRxIsPilots; bool fRxFrameSizeNormal{};
bool fRxIsPilots{};
double fStatRxSymError; double fRxSymError{};
double fStatRxFreqErr; double fRxFreqErr{};
double fStatRxFreqErrAcc; #endif
double fStatRxInputSignalLevel; double fRxFreqErrAcc{};
double fStatRxPllError; double fRxInputSignalLevel{};
double fStatRxSpeedOnRxKbit; double fRxPllError{};
double fStatRxSpeedOnIifKbit; double fRxSpeedOnRxKbit{};
uint32_t fStatRxPacketsOk; double fRxSpeedOnIifKbit{};
uint32_t fStatRxPacketsBad; uint32_t fRxPacketsOk{};
uint32_t fStatRxPacketsDummy; uint32_t fRxPacketsBad{};
#ifndef MODEM_IS_SHPS
bool fStatTxState; uint32_t fRxPacketsDummy{};
uint16_t fStatTxModcod; uint16_t fTxModcod{};
double fStatTxSpeedOnTxKbit; #endif
double fStatTxSpeedOnIifKbit; double fTxSpeedOnTxKbit{};
double fTxSpeedOnIifKbit{};
#ifdef MODEM_IS_SCPC #ifdef MODEM_IS_SCPC
float fStatTxSnr; float fTxSnr{};
bool fStatTxFrameSizeNormal; bool fTxFrameSizeNormal{};
bool fStatTxIsPilots; bool fTxIsPilots{};
double fStatCincOcc; double fCincOcc{};
bool fStatCincCorrelator; bool fCincCorrelator{};
uint32_t fStatCincCorrelatorFails; uint32_t fCincCorrelatorFails{};
int32_t fStatCincFreqErr; int32_t fCincFreqErr{};
int32_t fStatCincFreqErrAcc; int32_t fCincFreqErrAcc{};
float fStatCincChannelDelay; float fCincChannelDelay{};
#endif
#ifdef MODEM_IS_TDMA
fStatTxCenterFreq;
fStatTxSymSpeed;
#endif #endif
double fTxCenterFreq;
double fTxSymSpeed;
TerminalState();
/** /**
* Обновление основной части статистики, то есть RX/TX и sysinfo * Обновление основной части статистики, то есть RX/TX и sysinfo
*/ */
void updateCallback(proxy::CpProxy& cp) override; void updateCallback(proxy::CpProxy& cp);
nlohmann::json asJson();
void updateFromPt(boost::property_tree::ptree &pt); ~TerminalState();
void store(TSID sid, CP_Result& lastCpError);
std::string asJson();
~TerminalState() override;
}; };
class TerminalDeviceState: public CpUpdatebleObject { class TerminalDeviceState {
public: public:
time_t fOsUptime{}; time_t fOsUptime{};
double fOsLoad1{}; double fOsLoad1{};
@@ -241,23 +211,49 @@ namespace api_driver::obj {
TerminalDeviceState(const TerminalDeviceState& src); TerminalDeviceState(const TerminalDeviceState& src);
TerminalDeviceState& operator= (const TerminalDeviceState& src); TerminalDeviceState& operator= (const TerminalDeviceState& src);
void updateCallback(proxy::CpProxy& cp) override; void updateCallback(proxy::CpProxy& cp);
std::string asJson() const; nlohmann::json asJson() const;
~TerminalDeviceState() override; ~TerminalDeviceState();
}; };
class TerminalRxTxSettings: public CpUpdatebleObject { class TerminalRxTxSettings {
modulator_settings mod{};
demodulator_settings dem{};
#ifdef API_STRUCT_ACM_ENABLE
ACM_parameters_serv_ acm{};
#endif
#ifdef API_OBJECT_DPDI_SETTINGS_ENABLE
DPDI_parmeters dpdi{};
#endif
#ifdef API_OBJECT_BUCLNB_SETTINGS_ENABLE
buc_lnb_settings buclnb{};
#endif
public: public:
// TODO описать все параметры для всех терминалов TerminalRxTxSettings();
TerminalRxTxSettings(const TerminalRxTxSettings& src);
TerminalRxTxSettings& operator= (const TerminalRxTxSettings& src);
void updateCallback(proxy::CpProxy& cp) override; void updateCallback(proxy::CpProxy& cp);
void updateFromPt(boost::property_tree::ptree &pt);
void store(proxy::CpProxy& cp);
std::string asJson();
~TerminalRxTxSettings() override; void updateMainSettings(const nlohmann::json& data);
void storeMainSettings(proxy::CpProxy& cp);
#ifdef API_OBJECT_DPDI_SETTINGS_ENABLE
void updateDpdiSettings(const nlohmann::json& data);
void storeDpdiSettings(proxy::CpProxy& cp);
#endif
#ifdef API_OBJECT_BUCLNB_SETTINGS_ENABLE
void updateBuclnbSettings(const nlohmann::json& data);
void storeBuclnbSettings(proxy::CpProxy& cp);
#endif
void storeAll(proxy::CpProxy& cp);
nlohmann::json asJson() const;
~TerminalRxTxSettings();
}; };
} }

24765
src/common/nlohmann/json.hpp Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -11,7 +11,6 @@
#include <boost/log/utility/setup/formatter_parser.hpp> #include <boost/log/utility/setup/formatter_parser.hpp>
#include <boost/asio/buffer.hpp> #include <boost/asio/buffer.hpp>
#include <boost/asio/ssl/context.hpp> #include <boost/asio/ssl/context.hpp>
#include <boost/property_tree/json_parser.hpp>
#include <cstddef> #include <cstddef>
#include <memory> #include <memory>
#include <fstream> #include <fstream>
@@ -21,6 +20,7 @@
#include "auth/resources.h" #include "auth/resources.h"
#include "auth/jwt.h" #include "auth/jwt.h"
#include "auth/utils.h" #include "auth/utils.h"
#include "common/nlohmann/json.hpp"
namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.hpp> namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.hpp>
@@ -76,25 +76,25 @@ class ServerResources {
} }
void doTerminalUpgrade() const { void doTerminalUpgrade() const {
api->executeInApi([](TSID sid) { api->executeInApi([](api_driver::proxy::CpProxy& cp) {
CP_SetDmaDebug(sid, "begin_save_config", ""); cp.setDmaDebug("begin_save_config", "");
std::string cmd(UPGRADE_COMMAND); std::string cmd(UPGRADE_COMMAND);
cmd += " "; cmd += " ";
cmd += FIRMWARE_LOCATION; cmd += FIRMWARE_LOCATION;
system(cmd.c_str()); system(cmd.c_str());
CP_SetDmaDebug(sid, "save_config", ""); cp.setDmaDebug("save_config", "");
}); });
} }
#ifdef MODEM_IS_TDMA #ifdef MODEM_IS_TDMA
void doTerminalUpgradeOta() const { void doTerminalUpgradeOta() const {
api->executeInApi([&](TSID sid) { api->executeInApi([&](auto& cp) {
CP_SetDmaDebug(sid, "begin_save_config", ""); cp.setDmaDebug("begin_save_config", "");
std::string cmd(UPGRADE_COMMAND); std::string cmd(UPGRADE_COMMAND);
cmd += " "; cmd += " ";
cmd += api->getOtaFileLocation(); cmd += api->getOtaFileLocation();
system(cmd.c_str()); system(cmd.c_str());
CP_SetDmaDebug(sid, "save_config", ""); cp.setDmaDebug("save_config", "");
}); });
} }
#endif #endif
@@ -104,6 +104,8 @@ public:
static constexpr const char* INDEX_HTML = "/main-tdma.html"; static constexpr const char* INDEX_HTML = "/main-tdma.html";
#elif defined(MODEM_IS_SCPC) #elif defined(MODEM_IS_SCPC)
static constexpr const char* INDEX_HTML = "/main-scpc.html"; static constexpr const char* INDEX_HTML = "/main-scpc.html";
#elif defined(MODEM_IS_SHPS)
static constexpr const char* INDEX_HTML = "/main-shps.html";
#else #else
#error "Modem type not defined!" #error "Modem type not defined!"
#endif #endif
@@ -177,11 +179,9 @@ public:
rep.headers.clear(); rep.headers.clear();
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
try { try {
std::istringstream is(std::string(req.payload.data(), req.payload.size())); auto reqJson = nlohmann::json::parse(std::string(req.payload.begin(), req.payload.end()));
boost::property_tree::ptree pt;
read_json(is, pt);
auto u = auth.doAuth(pt.get<std::string>("username"), pt.get<std::string>("password"), req, rep); auto u = auth.doAuth(reqJson["username"], reqJson["password"], req, rep);
if (u == nullptr) { if (u == nullptr) {
throw std::runtime_error("invalid session"); throw std::runtime_error("invalid session");
} }
@@ -219,14 +219,21 @@ public:
http::server::stockReply(http::server::bad_request, rep); http::server::stockReply(http::server::bad_request, rep);
return; return;
} }
rep.status = http::server::ok; rep.status = http::server::ok;
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
std::string result = R"({"mainState":)"; nlohmann::json resultJson;
result += api->loadTerminalState();
result += R"(,"sysinfo":)"; try {
result += api->loadSysInfo(); resultJson["status"] = "ok";
result += "}"; resultJson["state"] = api->loadTerminalState();
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/get/statistics): Can't get terminal state: " << e.what();
resultJson.clear();
resultJson["status"] = "error";
resultJson["error"] = e.what();
}
auto result = resultJson.dump();
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
})); }));
@@ -235,12 +242,22 @@ public:
http::server::stockReply(http::server::bad_request, rep); http::server::stockReply(http::server::bad_request, rep);
return; return;
} }
rep.status = http::server::ok; rep.status = http::server::ok;
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
std::string result = R"({"settings":)"; nlohmann::json resultJson;
result += api->loadSettings();
result += "}"; try {
resultJson["status"] = "ok";
resultJson["settings"] = api->loadSettings();
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/get/settings): Can't get object: " << e.what();
resultJson.clear();
rep.status = http::server::internal_server_error;
resultJson["status"] = "error";
resultJson["error"] = e.what();
}
auto result = resultJson.dump();
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
})); }));
@@ -252,7 +269,20 @@ public:
rep.status = http::server::ok; rep.status = http::server::ok;
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
const auto result = api->loadFirmwareVersion(); nlohmann::json resultJson;
try {
resultJson["status"] = "ok";
resultJson["firmware"] = api->loadFirmwareVersion();
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/get/aboutFirmware): Can't get object: " << e.what();
resultJson.clear();
rep.status = http::server::internal_server_error;
resultJson["status"] = "error";
resultJson["error"] = e.what();
}
auto result = resultJson.dump();
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
})); }));
@@ -269,6 +299,7 @@ public:
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
})); }));
#ifdef API_OBJECT_QOS_SETTINGS_ENABLE
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/qos", this->auth, http::auth::User::SETUP_QOS, [this](const auto& req, auto& rep) { s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/qos", this->auth, http::auth::User::SETUP_QOS, [this](const auto& req, auto& rep) {
if (req.method != "POST") { if (req.method != "POST") {
http::server::stockReply(http::server::bad_request, rep); http::server::stockReply(http::server::bad_request, rep);
@@ -277,26 +308,26 @@ public:
rep.status = http::server::ok; rep.status = http::server::ok;
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
nlohmann::json resultJson;
try { try {
std::stringstream ss; auto reqJson = nlohmann::json::parse(std::string(req.payload.begin(), req.payload.end()));
ss.str(std::string(req.payload.begin(), req.payload.end())); api->setQosSettings(reqJson);
boost::property_tree::ptree pt; resultJson["status"] = "ok";
read_json(ss, pt); resultJson["settings"] = api->loadSettings();
api->setQosSettings(pt);
std::string result = R"({"status":"ok","settings":)";
result += api->loadSettings();
result += "}";
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
} catch (std::exception& e) { } catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/qos): Can't set QoS settings: " << e.what(); BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/qos): Can't set QoS settings: " << e.what();
const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}"; resultJson.clear();
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); resultJson["status"] = "error";
resultJson["error"] = e.what();
} }
}));
auto result = resultJson.dump();
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
}));
#endif
#ifdef API_OBJECT_BUCLNB_SETTINGS_ENABLE
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/buclnb", this->auth, http::auth::User::EDIT_SETTINGS, [this](const auto& req, auto& rep) { s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/buclnb", this->auth, http::auth::User::EDIT_SETTINGS, [this](const auto& req, auto& rep) {
if (req.method != "POST") { if (req.method != "POST") {
http::server::stockReply(http::server::bad_request, rep); http::server::stockReply(http::server::bad_request, rep);
@@ -306,25 +337,26 @@ public:
rep.status = http::server::ok; rep.status = http::server::ok;
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
nlohmann::json resultJson;
try { try {
std::stringstream ss; auto reqJson = nlohmann::json::parse(std::string(req.payload.begin(), req.payload.end()));
ss.str(std::string(req.payload.begin(), req.payload.end())); api->setBucLnbSettings(reqJson);
boost::property_tree::ptree pt; resultJson["status"] = "ok";
read_json(ss, pt); resultJson["settings"] = api->loadSettings();
api->setBucLnbSettings(pt);
std::string result = R"({"status":"ok","settings":)";
result += api->loadSettings();
result += "}";
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
} catch (std::exception& e) { } catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/buclnb): Can't set BUC LNB settings: " << e.what(); BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/buclnb): Can't set BUC LNB settings: " << e.what();
const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}"; resultJson.clear();
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); resultJson["status"] = "error";
resultJson["error"] = e.what();
} }
}));
auto result = resultJson.dump();
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
}));
#endif
#ifdef API_OBJECT_DPDI_SETTINGS_ENABLE
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/dpdi", this->auth, http::auth::User::EDIT_SETTINGS, [this](const auto& req, auto& rep) { s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/dpdi", this->auth, http::auth::User::EDIT_SETTINGS, [this](const auto& req, auto& rep) {
if (req.method != "POST") { if (req.method != "POST") {
http::server::stockReply(http::server::bad_request, rep); http::server::stockReply(http::server::bad_request, rep);
@@ -333,25 +365,24 @@ public:
rep.status = http::server::ok; rep.status = http::server::ok;
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
nlohmann::json resultJson;
try { try {
std::stringstream ss; auto reqJson = nlohmann::json::parse(std::string(req.payload.begin(), req.payload.end()));
ss.str(std::string(req.payload.begin(), req.payload.end())); api->setDpdiSettings(reqJson);
boost::property_tree::ptree pt; resultJson["status"] = "ok";
read_json(ss, pt); resultJson["settings"] = api->loadSettings();
api->setDpdiSettings(pt);
std::string result = R"({"status":"ok","settings":)";
result += api->loadSettings();
result += "}";
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
} catch (std::exception& e) { } catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/dpdi): Can't set DPDI settings: " << e.what(); BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/dpdi): Can't set DPDI settings: " << e.what();
const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}"; resultJson.clear();
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); resultJson["status"] = "error";
resultJson["error"] = e.what();
} }
auto result = resultJson.dump();
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
})); }));
#endif
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/rxtx", this->auth, http::auth::User::EDIT_SETTINGS, [this](const auto& req, auto& rep) { s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/rxtx", this->auth, http::auth::User::EDIT_SETTINGS, [this](const auto& req, auto& rep) {
if (req.method != "POST") { if (req.method != "POST") {
@@ -361,26 +392,25 @@ public:
rep.status = http::server::ok; rep.status = http::server::ok;
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
nlohmann::json resultJson;
try { try {
std::stringstream ss; auto reqJson = nlohmann::json::parse(std::string(req.payload.begin(), req.payload.end()));
ss.str(std::string(req.payload.begin(), req.payload.end())); api->setRxTxSettings(reqJson);
boost::property_tree::ptree pt; resultJson["status"] = "ok";
read_json(ss, pt); resultJson["settings"] = api->loadSettings();
api->setRxTxSettings(pt);
std::string result = R"({"status":"ok","settings":)";
result += api->loadSettings();
result += "}";
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
} catch (std::exception& e) { } catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/rxtx): Can't set RX/TX settings: " << e.what(); BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/rxtx): Can't set RX/TX settings: " << e.what();
const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}"; resultJson.clear();
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); resultJson["status"] = "error";
resultJson["error"] = e.what();
} }
auto result = resultJson.dump();
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
})); }));
#ifdef API_OBJECT_NETWORK_SETTINGS_ENABLE
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/network", this->auth, http::auth::User::EDIT_SETTINGS, [this](const auto& req, auto& rep) { s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/network", this->auth, http::auth::User::EDIT_SETTINGS, [this](const auto& req, auto& rep) {
if (req.method != "POST") { if (req.method != "POST") {
http::server::stockReply(http::server::bad_request, rep); http::server::stockReply(http::server::bad_request, rep);
@@ -389,25 +419,54 @@ public:
rep.status = http::server::ok; rep.status = http::server::ok;
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
nlohmann::json resultJson;
try { try {
std::stringstream ss; auto reqJson = nlohmann::json::parse(std::string(req.payload.begin(), req.payload.end()));
ss.str(std::string(req.payload.begin(), req.payload.end())); api->setNetworkSettings(reqJson);
boost::property_tree::ptree pt; resultJson["status"] = "ok";
read_json(ss, pt); resultJson["settings"] = api->loadSettings();
api->setNetworkSettings(pt);
std::string result = R"({"status":"ok","settings":)";
result += api->loadSettings();
result += "}";
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
} catch (std::exception& e) { } catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/network): Can't set network settings: " << e.what(); BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/network): Can't set network settings: " << e.what();
const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}"; resultJson.clear();
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); resultJson["status"] = "error";
resultJson["error"] = e.what();
} }
auto result = resultJson.dump();
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
})); }));
#ifdef MODEM_IS_TDMA
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/cesPassword", this->auth, http::auth::User::EDIT_SETTINGS, [this](const http::server::Request& req, auto& rep) {
if (req.method != "POST") {
http::server::stockReply(http::server::bad_request, rep);
return;
}
rep.status = http::server::ok;
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
nlohmann::json resultJson;
try {
auto reqJson = nlohmann::json::parse(std::string(req.payload.begin(), req.payload.end()));
auto password = reqJson["password"].get<std::string>();
this->api->executeInApi([&password](auto& cp) {
cp.setNetwork("ces_password", password);
});
resultJson["status"] = "ok";
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/cesPassword): Can't set CES password: " << e.what();
resultJson.clear();
resultJson["status"] = "error";
resultJson["error"] = e.what();
}
auto result = resultJson.dump();
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
}));
#endif
#endif
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/reboot", this->auth, 0, [this](const auto& req, auto& rep) { s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/reboot", this->auth, 0, [this](const auto& req, auto& rep) {
if (req.method != "POST") { if (req.method != "POST") {
@@ -458,6 +517,12 @@ public:
http::server::stockReply(http::server::bad_request, rep); http::server::stockReply(http::server::bad_request, rep);
return; return;
} }
rep.status = http::server::ok;
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
nlohmann::json resultJson;
try {
this->upgradeOrRebootRunning = true; this->upgradeOrRebootRunning = true;
#ifdef MODEM_IS_TDMA #ifdef MODEM_IS_TDMA
if (req.url->params.find("ota") != req.url->params.end()) { if (req.url->params.find("ota") != req.url->params.end()) {
@@ -468,10 +533,15 @@ public:
#else #else
doTerminalUpgrade(); doTerminalUpgrade();
#endif #endif
rep.status = http::server::ok; resultJson["status"] = "ok";
rep.headers.clear(); } catch (std::exception& e) {
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/doFirmwareUpgrade): Error: " << e.what();
const auto result = api->loadFirmwareVersion(); resultJson.clear();
resultJson["status"] = "error";
resultJson["error"] = e.what();
}
auto result = resultJson.dump();
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
})); }));
@@ -490,59 +560,103 @@ public:
return; return;
} }
const auto func = req.url->params["f"]; const auto func = req.url->params["f"];
std::string result = R"({"status":"ok"})"; rep.status = http::server::ok;
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
nlohmann::json resultJson;
try {
resultJson["status"] = "error";
if (func == "SetDmaDebug") { if (func == "SetDmaDebug") {
if (req.url->params.find("param") == req.url->params.end()) { http::server::stockReply(http::server::bad_request, rep); return; } if (req.url->params.find("param") == req.url->params.end()) {
if (req.url->params.find("value") == req.url->params.end()) { http::server::stockReply(http::server::bad_request, rep); return; } rep.status = http::server::bad_request;
this->api->executeInApi([&](auto sid) { resultJson["error"] = "missing required adgument: `param`";
CP_SetDmaDebug(sid, req.url->params["param"].c_str(), req.url->params["value"]); } else if (req.url->params.find("value") == req.url->params.end()) {
rep.status = http::server::bad_request;
resultJson["error"] = "missing required adgument: `value`";
} else {
this->api->executeInApi([&](auto& cp) {
cp.setDmaDebug(req.url->params["param"], req.url->params["value"]);
}); });
}
} else if (func == "GetDmaDebug") { } else if (func == "GetDmaDebug") {
if (req.url->params.find("param") == req.url->params.end()) { http::server::stockReply(http::server::bad_request, rep); return; } if (req.url->params.find("param") == req.url->params.end()) {
this->api->executeInApi([&](auto sid) { rep.status = http::server::bad_request;
std::string tmp{}; resultJson["error"] = "missing required adgument: `param`";
CP_GetDmaDebug(sid, req.url->params["param"].c_str(), &tmp); } else {
result = R"({"status":"ok","result":)"; this->api->executeInApi([&](auto& cp) {
result += api_driver::buildEscapedString(tmp); resultJson["status"] = "ok";
result += "}"; resultJson["result"] = cp.getDmaDebug(req.url->params["param"]);
}); });
}
} else if (func == "SetNetwork") {
if (req.url->params.find("param") == req.url->params.end()) {
rep.status = http::server::bad_request;
resultJson["error"] = "missing required adgument: `param`";
} else if (req.url->params.find("value") == req.url->params.end()) {
rep.status = http::server::bad_request;
resultJson["error"] = "missing required adgument: `value`";
} else { } else {
http::server::stockReply(http::server::not_implemented, rep); this->api->executeInApi([&](auto& cp) {
return; cp.setNetwork(req.url->params["param"], req.url->params["value"]);
});
}
} else if (func == "GetNetwork") {
if (req.url->params.find("param") == req.url->params.end()) {
rep.status = http::server::bad_request;
resultJson["error"] = "missing required adgument: `param`";
} else {
this->api->executeInApi([&](auto& cp) {
resultJson["status"] = "ok";
resultJson["result"] = cp.getNetwork(req.url->params["param"]);
});
}
} else {
resultJson["error"] = "function not supported";
}
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/qos): Can't set QoS settings: " << e.what();
resultJson.clear();
resultJson["status"] = "error";
resultJson["error"] = e.what();
} }
rep.status = http::server::ok; auto result = resultJson.dump();
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
})); }));
#ifdef MODEM_IS_SCPC #ifdef API_OBJECT_DEBUG_METRICS_ENABLE
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/dev/settings", this->auth, http::auth::User::DEVELOPER, [this](const auto& req, auto& rep) { s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/dev/settings", this->auth, http::auth::User::DEVELOPER, [this](const auto& req, auto& rep) {
std::string result; rep.status = http::server::ok;
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::text_plain)});
nlohmann::json resultJson;
try {
if (req.method == "GET") { if (req.method == "GET") {
result = R"({"status":"ok","logstat":)"; resultJson["status"] = "ok";
result += this->api->getLoggingStatisticsSettings(); resultJson["logstat"] = api->getLoggingStatisticsSettings();
result += "}";
} else if (req.method == "POST") { } else if (req.method == "POST") {
std::stringstream ss; auto reqJson = nlohmann::json::parse(std::string(req.payload.begin(), req.payload.end()));
ss.str(std::string(req.payload.begin(), req.payload.end())); api->setLoggingStatisticsSettings(reqJson);
boost::property_tree::ptree pt;
read_json(ss, pt);
api->setLoggingStatisticsSettings(pt); resultJson["status"] = "ok";
resultJson["logstat"] = api->getLoggingStatisticsSettings();
result = R"({"status":"ok","logstat":)";
result += this->api->getLoggingStatisticsSettings();
result += "}";
} else { } else {
http::server::stockReply(http::server::bad_request, rep); rep.status = http::server::bad_request;
return; resultJson["status"] = "error";
resultJson["error"] = "unsupported request type";
}
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/qos): Can't set QoS settings: " << e.what();
resultJson.clear();
resultJson["status"] = "error";
resultJson["error"] = e.what();
} }
rep.status = http::server::ok; auto result = resultJson.dump();
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
})); }));
#endif
#ifdef API_OBJECT_DEBUG_METRICS_ENABLE
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/dev/logs.csv", this->auth, http::auth::User::DEVELOPER, [this](const auto& req, auto& rep) { s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/dev/logs.csv", this->auth, http::auth::User::DEVELOPER, [this](const auto& req, auto& rep) {
if (req.method != "GET") { if (req.method != "GET") {
http::server::stockReply(http::server::bad_request, rep); http::server::stockReply(http::server::bad_request, rep);

View File

@@ -1,7 +1,6 @@
#include "terminal_api_driver.h" #include "terminal_api_driver.h"
#include <cmath> #include <cmath>
#include "terminal_api/ControlProtoCInterface.h"
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include <shared_mutex> #include <shared_mutex>
@@ -9,215 +8,11 @@
#include <boost/log/trivial.hpp> #include <boost/log/trivial.hpp>
#include <boost/property_tree/json_parser.hpp> #include <boost/property_tree/json_parser.hpp>
#include <sys/sysinfo.h> #include <sys/sysinfo.h>
#include "common/nlohmann/json.hpp"
#define TIME_NOW() std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count() #include "api-driver/daemon.h"
typedef boost::property_tree::ptree::path_type json_path; typedef boost::property_tree::ptree::path_type json_path;
// пороговое значение сна
static constexpr int64_t SLEEP_THRESHOLD = 10;
static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch);
}).base(), s.end());
}
static inline const char* boolAsStr(bool value) {
return value ? "true" : "false";
}
class TerminalNetworkSettings {
public:
std::string managementIp, managementGateway, dataIp, serverName;
bool isL2 = true;
unsigned int dataMtu = 1500;
#ifdef MODEM_IS_SCPC
static constexpr const char* DEFAULT_SERVER_NAME = "RCSM-101";
#endif
#ifdef MODEM_IS_TDMA
static constexpr const char* DEFAULT_SERVER_NAME = "RCSM-101 TDMA";
#endif
TerminalNetworkSettings() = default;
TerminalNetworkSettings(const TerminalNetworkSettings& src) = default;
~TerminalNetworkSettings() = default;
TerminalNetworkSettings& operator= (const TerminalNetworkSettings& src) = default;
void loadDefaults() {
managementIp = "0.0.0.0";
managementGateway = "";
isL2 = true;
dataIp = "0.0.0.0";
dataMtu = 1500;
serverName = DEFAULT_SERVER_NAME;
}
};
class TerminalDeviceState {
public:
double adrv_temp{}, pl_temp{}, zynq_temp{};
#ifdef MODEM_IS_TDMA
DOWNLOAD_STATUS otaStatus{}; // Downloading Status
unsigned int otaPercent{}; // % downloaded data
std::string otaImage{}; // Name of downloading image file
#endif
modulator_state mod{};
demodulator_state demod{};
#ifdef MODEM_IS_SCPC
debug_metrics debug{};
CinC_state cinc{};
#endif
};
class TerminalFirmwareVersion {
public:
std::string version, modemId, modemSn, macMang, macData;
TerminalFirmwareVersion() = default;
TerminalFirmwareVersion(const TerminalFirmwareVersion& src) = default;
~TerminalFirmwareVersion() = default;
TerminalFirmwareVersion& operator= (const TerminalFirmwareVersion& src) = default;
};
static std::ostream& operator<<(std::ostream& out, CP_Result result) {
switch (result) {
case OK: out << "OK"; break;
case TIMEOUT: out << "TIMEOUT"; break;
case ERROR: out << "ERROR"; break;
case ABORT: out << "ABORT"; break;
case BUSY: out << "BUSY"; break;
default:
out << static_cast<int>(result);
}
return out;
}
std::string makeTimepointFromMillis(int64_t unix_time_ms) {
// Преобразуем миллисекунды в микросекунды для std::chrono
auto time_point = std::chrono::time_point<std::chrono::system_clock,
std::chrono::microseconds>(std::chrono::microseconds(unix_time_ms * 1000));
auto tp = std::chrono::system_clock::to_time_t(time_point);
tm* t = std::localtime(&tp);
std::stringstream ss;
ss << std::put_time(t, "%Y-%m-%d %H:%M:%S");
auto ms = (unix_time_ms % 1000);
ss << '.' << std::setw(3) << std::setfill('0') << ms;
return ss.str();
}
#ifdef MODEM_IS_SCPC
class api_driver::StatisticsLogger {
public:
StatisticsLogger(): timeStart(TIME_NOW()) {}
int64_t timeStart;
bool logEn = false;
std::atomic<int> logPeriodMs = 1000;
std::atomic<int> maxAgeMs = 10000;
/**
*
* @return {"en": bool, "logPeriodMs": int, ""}
*/
std::string getSettings() {
std::lock_guard _lock(mutex);
std::stringstream res;
res << "{\"en\":" << boolAsStr(this->logEn);
res << ",\"logPeriodMs\":" << logPeriodMs;
res << ",\"maxAgeMs\":" << maxAgeMs;
res << '}';
return res.str();
}
void setSettings(boost::property_tree::ptree &pt) {
const bool newEn = pt.get<bool>("en");
const int newInterval = pt.get<int>("logPeriodMs");
const int newMaxAgeMs = pt.get<int>("maxAgeMs");
std::lock_guard _lock(this->mutex);
this->logPeriodMs = newInterval;
this->maxAgeMs = newMaxAgeMs;
if (newEn != this->logEn) {
if (newEn) {
this->logFile.open("/tmp/weblog-statistics.csv", std::ios::out);
if (this->logFile.is_open()) {
const auto* header = "timestamp\tcnt ok\tcnt bad\tfine freq dem\tcrs freq dem\tcrs freq compensator\tcrs time est\tfine time est\tmax level corr\tcurrent delay\tSNR\tcurrent modcod\tfine freq compensator\tind freq grb\tind freq tochn\tind filt adapt\tfilter corr cinc\tcorr cnt\tRSS\tcor erl\tcor lat\tgc gain\tpower pl rx\n";
this->logFile.write(header, static_cast<std::streamsize>(strlen(header)));
this->logEn = true;
this->timeStart = TIME_NOW();
}
} else {
if (this->logFile.is_open()) {
this->logFile.close();
}
this->logEn = false;
}
}
}
/**
* Записать значение в "базу данных". Метку при этом вставлять не нужно, она будет вставлена автоматически.
* @param item
*/
void putItem(const debug_metrics& item) {
std::lock_guard _lock(this->mutex);
if (!logEn) return;
if (this->logFile.is_open()) {
std::stringstream res;
res << makeTimepointFromMillis(TIME_NOW()) << '\t';
res << item.cnt_ok << '\t';
res << item.cnt_bad << '\t';
res << item.fine_freq_dem << '\t';
res << item.crs_freq_dem << '\t';
res << item.crs_freq_compensator << '\t';
res << item.crs_time_est << '\t';
res << item.fine_time_est << '\t';
res << item.max_level_corr << '\t';
res << item.current_delay << '\t';
res << item.SNR << '\t';
res << item.current_modcod << '\t';
res << item.fine_freq_compensator << '\t';
res << item.ind_freq_grb << '\t';
res << item.ind_freq_tochn << '\t';
res << item.ind_filt_adapt << '\t';
res << item.filter_corr_cinc << '\t';
res << item.corr_cnt << '\t';
res << item.RSS << '\t';
res << item.cor_erl << '\t';
res << item.cor_lat << '\t';
res << item.gc_gain << '\t';
res << item.power_pl_rx << '\n';
const auto out = res.str();
this->logFile.write(out.c_str(), static_cast<std::streamsize>(out.length()));
this->logFile.flush();
}
}
// void collectExpiredItems();
// void resetLogs() {
// std::lock_guard _lock(mutex);
// logs.clear();
// }
~StatisticsLogger() = default;
private:
// std::pmr::deque<LogItem> logs;
std::fstream logFile{};
std::shared_mutex mutex;
};
#endif
api_driver::ApiDriver::ApiDriver() = default; api_driver::ApiDriver::ApiDriver() = default;
@@ -241,18 +36,6 @@ std::string api_driver::buildEscapedString(const std::string& source) {
return "\"" + str.substr(start_pos, end_pos - start_pos + 1) + "\""; return "\"" + str.substr(start_pos, end_pos - start_pos + 1) + "\"";
} }
static void writeDouble(std::ostream& out, double value, int prec = 2) {
if (std::isnan(value) || std::isinf(value)) {
out << "\"nan\"";
} else {
out << std::fixed << std::setprecision(prec) << value;
}
}
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) { std::tuple<uint8_t, uint8_t> translateCoordinates(double abs) {
auto deg = static_cast<uint8_t>(abs); auto deg = static_cast<uint8_t>(abs);
double min_double = (abs - deg) * 60; double min_double = (abs - deg) * 60;
@@ -261,130 +44,19 @@ std::tuple<uint8_t, uint8_t> translateCoordinates(double abs) {
} }
std::string api_driver::ApiDriver::loadTerminalState() const { nlohmann::json api_driver::ApiDriver::loadTerminalState() const {
if (daemon == nullptr) { if (daemon == nullptr) {
return R"({"error": "api daemon not started!"})"; return R"({"error": "api daemon not started!"})";
} }
std::stringstream result;
result << "{\n\"initState\":" << buildEscapedString(daemon->getDeviceInitState()); obj::TerminalState state;
result << ",\n\"testState\":" << boolAsStr(daemon->isTest()); daemon->getState(state);
obj::TerminalDeviceState devState;
daemon->getDeviceState(devState);
auto state = daemon->getState(); auto res = state.asJson();
#ifdef MODEM_IS_SCPC res["device"] = devState.asJson();
const bool isCinC = this->daemon->getIsCinC(); return res;
#endif
#ifdef MODEM_IS_SCPC
result << ",\"isCinC\":" << boolAsStr(isCinC);
#endif
// формируем структуру для TX
result << ",\n\"tx.state\":" << boolAsStr(state.mod.is_tx_on);
result << ",\"tx.modcod\":" << state.mod.modcod;
#ifdef MODEM_IS_SCPC
result << ",\"tx.snr\":"; writeDouble(result, state.mod.snr_remote);
if (state.mod.is_short) { result << R"(,"tx.frameSizeNormal":false)"; }
else { result << R"(,"tx.frameSizeNormal":true)"; }
if (state.mod.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<double>(modSet.baudrate) / 1000.0));
}
#endif
result << ",\"tx.speedOnTxKbit\":"; writeDouble(result, static_cast<double>(state.mod.speed_in_bytes_tx) / 128.0);
result << ",\"tx.speedOnIifKbit\":"; writeDouble(result, (static_cast<double>(state.mod.speed_in_bytes_tx_iface) / 128.0));
// формируем структуру для RX
result << ",\n\"rx.state\":" << boolAsStr(state.demod.locks.sym_sync_lock && state.demod.locks.freq_lock && state.demod.locks.afc_lock && state.demod.locks.pkt_sync);
result << ",\"rx.sym_sync_lock\":" << boolAsStr(state.demod.locks.sym_sync_lock);
result << ",\"rx.freq_search_lock\":" << boolAsStr(state.demod.locks.freq_lock);
result << ",\"rx.afc_lock\":" << boolAsStr(state.demod.locks.afc_lock);
result << ",\"rx.pkt_sync\":" << boolAsStr(state.demod.locks.pkt_sync);
result << ",\"rx.snr\":"; writeDouble(result, state.demod.snr);
result << ",\"rx.rssi\":"; writeDouble(result, state.demod.rssi);
result << ",\"rx.modcod\":" << state.demod.modcod;
if (state.demod.is_short) {
result << R"(,"rx.frameSizeNormal":false)";
} else {
result << R"(,"rx.frameSizeNormal":true)";
}
if (state.demod.is_pilots) {
result << R"(,"rx.isPilots":true)";
} else {
result << R"(,"rx.isPilots":false)";
}
result << ",\n\"rx.symError\":"; writeDouble(result, state.demod.sym_err);
result << ",\"rx.freqErr\":"; writeDouble(result, state.demod.crs_freq_err);
result << ",\"rx.freqErrAcc\":"; writeDouble(result, state.demod.fine_freq_err);
result << ",\"rx.inputSignalLevel\":"; writeDouble(result, state.demod.if_overload);
result << ",\"rx.pllError\":"; writeDouble(result, state.demod.afc_err);
result << ",\"rx.speedOnRxKbit\":"; writeDouble(result, static_cast<double>(state.demod.speed_in_bytes_rx) / 128.0);
result << ",\"rx.speedOnIifKbit\":"; writeDouble(result, static_cast<double>(state.demod.speed_in_bytes_rx_iface) / 128.0);
result << ",\"rx.packetsOk\":" << state.demod.packet_ok_cnt;
result << ",\"rx.packetsBad\":" << state.demod.packet_bad_cnt;
result << ",\"rx.packetsDummy\":" << state.demod.dummy_cnt;
#ifdef MODEM_IS_SCPC
// формируем структуру для CinC
if (isCinC) {
if (state.mod.is_tx_on) {
if (state.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, state.cinc.ratio_signal_signal, 3);
result << ",\"cinc.correlatorFails\":" << state.cinc.cnt_bad_lock;
result << ",\"cinc.freqErr\":" << state.cinc.freq_error_offset;
result << ",\"cinc.freqErrAcc\":" << state.cinc.freq_fine_estimate;
result << ",\"cinc.channelDelay\":" << state.cinc.delay_dpdi;
} else {
result << R"(,"cinc.correlator":null)";
}
#endif
// структура температур девайса
result << ",\n\"device.adrv\":"; writeDouble(result, state.adrv_temp, 1);
result << ",\"device.fpga\":"; writeDouble(result, state.pl_temp, 1);
result << ",\"device.zynq\":"; writeDouble(result, state.zynq_temp, 1);
#ifdef MODEM_IS_TDMA
if (state.otaImage.empty()) {
result << R"(,
"device.upgradeStatus":"Нет обновлений","device.upgradePercent":0,"device.upgradeImage":"")";
} else {
switch (state.otaStatus) {
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\":" << state.otaPercent;
result << ",\"device.upgradeImage\":" << buildEscapedString(state.otaImage);
}
#endif
result << "}";
return result.str();
} }
@@ -392,387 +64,114 @@ void api_driver::ApiDriver::resetPacketStatistics() const {
this->daemon->resetPacketStatistics(); this->daemon->resetPacketStatistics();
} }
#ifdef MODEM_IS_SCPC nlohmann::json api_driver::ApiDriver::loadSettings() const {
struct ModcodDef_t {const char* modulation; const char* speed;};
const static ModcodDef_t ModcodDefs[] = {
{.modulation = "dummy", .speed = "0"},
{.modulation = "qpsk", .speed = "1/4"},
{.modulation = "qpsk", .speed = "1/3"},
{.modulation = "qpsk", .speed = "2/5"},
{.modulation = "qpsk", .speed = "1/2"},
{.modulation = "qpsk", .speed = "3/5"},
{.modulation = "qpsk", .speed = "2/3"},
{.modulation = "qpsk", .speed = "3/4"},
{.modulation = "qpsk", .speed = "4/5"},
{.modulation = "qpsk", .speed = "5/6"},
{.modulation = "qpsk", .speed = "8/9"},
{.modulation = "qpsk", .speed = "9/10"},
{.modulation = "8psk", .speed = "3/5"},
{.modulation = "8psk", .speed = "2/3"},
{.modulation = "8psk", .speed = "3/4"},
{.modulation = "8psk", .speed = "5/6"},
{.modulation = "8psk", .speed = "8/9"},
{.modulation = "8psk", .speed = "9/10"},
{.modulation = "16apsk", .speed = "2/3"},
{.modulation = "16apsk", .speed = "3/4"},
{.modulation = "16apsk", .speed = "4/5"},
{.modulation = "16apsk", .speed = "5/6"},
{.modulation = "16apsk", .speed = "8/9"},
{.modulation = "16apsk", .speed = "9/10"},
{.modulation = "32apsk", .speed = "3/4"},
{.modulation = "32apsk", .speed = "4/5"},
{.modulation = "32apsk", .speed = "5/6"},
{.modulation = "32apsk", .speed = "8/9"},
{.modulation = "32apsk", .speed = "9/10"},
};
static const char* extractModcodModulation(uint32_t modcod, bool defaultQpsk1_4 = true) {
modcod >>= 2;
const auto* d = defaultQpsk1_4 ? ModcodDefs : ModcodDefs + 1;
if (modcod < (sizeof(ModcodDefs) / sizeof(ModcodDef_t))) {
d = ModcodDefs + modcod;
}
return d->modulation;
}
static const char* extractModcodSpeed(uint32_t modcod, bool defaultQpsk1_4 = true) {
modcod >>= 2;
const auto* d = defaultQpsk1_4 ? ModcodDefs : ModcodDefs + 1;
if (modcod < (sizeof(ModcodDefs) / sizeof(ModcodDef_t))) {
d = ModcodDefs + modcod;
}
return d->speed;
}
#endif
std::string api_driver::ApiDriver::loadSettings() const {
if (daemon == nullptr) { if (daemon == nullptr) {
return R"({"error": "api daemon not started!"})"; return R"({"error": "api daemon not started!"})";
} }
modulator_settings modSettings{}; nlohmann::json res = daemon->getSettingsRxTx().asJson();
demodulator_settings demodSettings{}; #ifdef API_OBJECT_QOS_SETTINGS_ENABLE
buc_lnb_settings bucLnb{}; res["qos"] = (daemon->getQosSettings().asJson());
TerminalNetworkSettings network;
DPDI_parmeters dpdiSettings{};
#ifdef MODEM_IS_SCPC
ACM_parameters_serv_ acmSettings{};
daemon->getSettings(&modSettings, &demodSettings, &acmSettings, &dpdiSettings, &bucLnb);
#else
daemon->getSettings(&modSettings, &demodSettings, &dpdiSettings, &bucLnb);
#endif #endif
daemon->getNetworkSettings(network); #ifdef API_OBJECT_NETWORK_SETTINGS_ENABLE
res["network"] = (daemon->getNetworkSettings().asJson());
std::stringstream result;
result << "{\n\"txAutoStart\":" << boolAsStr(modSettings.is_save_current_state);
result << ",\"txEn\":" << boolAsStr(modSettings.tx_is_on);
#ifdef MODEM_IS_SCPC
result << ",\"txIsTestInput\":" << boolAsStr(modSettings.is_test_data);
#endif #endif
result << ",\"txModulatorIsTest\":" << boolAsStr(!modSettings.is_carrier); return res;
result << ",\"txCentralFreq\":"; writeDouble(result, modSettings.central_freq_in_kGz);
#ifdef MODEM_IS_SCPC
result << ",\"txBaudrate\":" << modSettings.baudrate;
result << ",\"txRolloff\":" << static_cast<int>(modSettings.rollof);
result << ",\"txGoldan\":" << static_cast<int>(modSettings.gold_seq_is_active);
#endif
result << ",\"txAttenuation\":"; writeDouble(result, modSettings.attenuation);
#ifdef MODEM_IS_SCPC
result << ",\n\"isCinC\":" << boolAsStr(modSettings.is_cinc);
result << ",\n\"dvbServicePacketPeriod\":" << acmSettings.period_pack_acm;
result << ",\"dvbIsAcm\":" << boolAsStr(acmSettings.enable_acm);
result << ",\"txFrameSizeNormal\":" << boolAsStr((modSettings.modcod_tx & 2) == 0);
result << ",\"txIsPilots\":" << boolAsStr((modSettings.modcod_tx & 1) != 0);
result << R"(,"dvbCcmModulation":")" << extractModcodModulation(modSettings.modcod_tx) << "\"";
result << R"(,"dvbCcmSpeed":")" << extractModcodSpeed(modSettings.modcod_tx) << "\"";
result << R"(,"dvbAcmMinModulation":")" << extractModcodModulation(acmSettings.min_modcod_acm) << "\"";
result << R"(,"dvbAcmMinSpeed":")" << extractModcodSpeed(acmSettings.min_modcod_acm) << "\"";
result << R"(,"dvbAcmMaxModulation":")" << extractModcodModulation(acmSettings.max_modcod_acm) << "\"";
result << R"(,"dvbAcmMaxSpeed":")" << extractModcodSpeed(acmSettings.max_modcod_acm) << "\"";
result << ",\"dvbSnrReserve\":"; writeDouble(result, acmSettings.snr_threashold_acm);
result << ",\n\"aupcEn\":" << boolAsStr(acmSettings.enable_aupc);
result << ",\"aupcMinAttenuation\":"; writeDouble(result, acmSettings.min_attenuation_aupc);
result << ",\"aupcMaxAttenuation\":"; writeDouble(result, acmSettings.max_attenuation_aupc);
result << ",\"aupcRequiredSnr\":"; writeDouble(result, acmSettings.snr_threashold_aupc);
#endif
result << ",\n\"dpdiIsPositional\":" << boolAsStr(!dpdiSettings.is_delay_window);
#ifdef MODEM_IS_SCPC
result << ",\"dpdiSearchBandwidth\":" << dpdiSettings.freq_offset; // полоса поиска в кГц
#endif
result << ",\"dpdiPositionStationLatitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.latitude_station_grad, dpdiSettings.latitude_station_minute), 6);
result << ",\"dpdiPositionStationLongitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.longitude_station_grad, dpdiSettings.longitude_station_minute), 6);
result << ",\"dpdiPositionSatelliteLongitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.longitude_sattelite_grad, dpdiSettings.longitude_sattelite_minute), 6);
#ifdef MODEM_IS_SCPC
result << ",\"dpdiDelayMin\":" << dpdiSettings.min_delay;
result << ",\"dpdiDelayMax\":" << dpdiSettings.max_delay;
#else
result << ",\"dpdiDelay\":" << dpdiSettings.max_delay;
#endif
result << ",\n\"rxAgcEn\":" << boolAsStr(demodSettings.is_aru_on);
result << ",\"rxSpectrumInversion\":" << boolAsStr(demodSettings.is_rvt_iq);
result << ",\"rxManualGain\":"; writeDouble(result, demodSettings.gain);
result << ",\"rxCentralFreq\":"; writeDouble(result, demodSettings.central_freq_in_kGz);
result << ",\"rxBaudrate\":" << demodSettings.baudrate;
result << ",\"rxRolloff\":" << static_cast<int>(demodSettings.rollof);
#ifdef MODEM_IS_SCPC
result << ",\"rxGoldan\":" << static_cast<int>(demodSettings.gold_seq_is_active);
#endif
// BUC LNB
result << ",\n\"bucRefClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_buc);
switch (bucLnb.buc) {
case voltage_buc::_24V: result << ",\"bucPowering\":24"; break;
#ifdef MODEM_IS_SCPC
case voltage_buc::_48V: result << ",\"bucPowering\":48"; break;
#endif
case voltage_buc::DISABLE:
default: result << ",\"bucPowering\":0";
}
result << ",\"lnbRefClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_lnb);
switch (bucLnb.lnb) {
case voltage_lnb::_13V: result << ",\"lnbPowering\":13"; break;
case voltage_lnb::_18V: result << ",\"lnbPowering\":18"; break;
case voltage_lnb::_24V: result << ",\"lnbPowering\":24"; break;
case voltage_lnb::DISABLE:
default: result << ",\"lnbPowering\":0";
}
result << ",\"srvRefClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_output);
result << ",\"bucLnbAutoStart\":" << boolAsStr(bucLnb.is_save_current_state);
// QoS
bool qosEnabled = false; std::string qosClasses;
daemon->getQosSettings(qosEnabled, qosClasses);
result << ",\n\"qosEnabled\":" << boolAsStr(qosEnabled);
result << ",\"qosProfile\":" << qosClasses;
// сеть
result << "\n,\"netManagementIp\":" << buildEscapedString(network.managementIp);
result << ",\"netIsL2\":" << boolAsStr(network.isL2);
result << ",\"netManagementGateway\":" << buildEscapedString(network.managementGateway);
result << ",\"netDataIp\":" << buildEscapedString(network.dataIp);
result << ",\"netDataMtu\":" << network.dataMtu;
result << ",\"netServerName\":" << buildEscapedString(network.serverName);
result << "}";
return result.str();
} }
std::string api_driver::ApiDriver::loadFirmwareVersion() const { nlohmann::json api_driver::ApiDriver::loadFirmwareVersion() const {
if (daemon == nullptr) { if (daemon == nullptr) {
return R"({"error": "api daemon not started!"})"; return R"({"error": "api daemon not started!"})";
} }
return daemon->getFirmware().asJson();
std::stringstream result;
auto firmware = daemon->getFirmware();
result << "{\n\"fw.version\":" << buildEscapedString(firmware.version);
result << ",\"fw.modemId\":" << buildEscapedString(firmware.modemId);
result << ",\"fw.modemSn\":" << buildEscapedString(firmware.modemSn);
result << ",\"fw.macMang\":" << buildEscapedString(firmware.macMang);
result << ",\"fw.macData\":" << buildEscapedString(firmware.macData);
result << "\n}";
return result.str();
} }
#ifdef MODEM_IS_SCPC void api_driver::ApiDriver::setRxTxSettings(const nlohmann::json& data) {
static uint32_t buildModcodFromPt(const boost::property_tree::ptree& pt, const std::string& name, bool isShortFrame, bool isPilots = false) { auto rxtx = daemon->getSettingsRxTx();
uint32_t modcod = 0; rxtx.updateMainSettings(data);
const auto mod = pt.get<std::string>(name + "Modulation");
const auto speed = pt.get<std::string>(name + "Speed"); std::lock_guard _lapi(this->daemon->cpApiMutex);
uint32_t _index = 0; this->daemon->cp.setDmaDebug("begin_save_config", "");
for (const auto& m: ModcodDefs) { rxtx.storeMainSettings(this->daemon->cp);
if (mod == m.modulation) { this->daemon->cp.setDmaDebug("save_config", "");
if (modcod == 0) modcod = _index; rxtx.updateCallback(this->daemon->cp);
if (speed == m.speed) { {
modcod = _index; daemon->setSettingsRxTx(rxtx);
break;
} }
}
#ifdef API_OBJECT_DPDI_SETTINGS_ENABLE
void api_driver::ApiDriver::setDpdiSettings(const nlohmann::json& data) {
auto rxtx = daemon->getSettingsRxTx();
rxtx.updateDpdiSettings(data);
std::lock_guard _lapi(this->daemon->cpApiMutex);
this->daemon->cp.setDmaDebug("begin_save_config", "");
rxtx.storeDpdiSettings(this->daemon->cp);
this->daemon->cp.setDmaDebug("save_config", "");
rxtx.updateCallback(this->daemon->cp);
{
daemon->setSettingsRxTx(rxtx);
} }
_index++; }
#endif
#ifdef API_OBJECT_BUCLNB_SETTINGS_ENABLE
void api_driver::ApiDriver::setBucLnbSettings(const nlohmann::json& data) {
auto rxtx = daemon->getSettingsRxTx();
rxtx.updateBuclnbSettings(data);
std::lock_guard _lapi(this->daemon->cpApiMutex);
this->daemon->cp.setDmaDebug("begin_save_config", "");
rxtx.storeBuclnbSettings(this->daemon->cp);
this->daemon->cp.setDmaDebug("save_config", "");
rxtx.updateCallback(this->daemon->cp);
{
daemon->setSettingsRxTx(rxtx);
} }
return (modcod << 2)| (isShortFrame ? 2 : 0) | (isPilots ? 1 : 0);
} }
#endif #endif
void api_driver::ApiDriver::setRxTxSettings(boost::property_tree::ptree &pt) { #ifdef API_OBJECT_QOS_SETTINGS_ENABLE
modulator_settings mod{}; void api_driver::ApiDriver::setQosSettings(const nlohmann::json& data) {
demodulator_settings demod{}; auto qos = daemon->getQosSettings();
#ifdef MODEM_IS_SCPC qos.updateFromJson(data);
ACM_parameters_serv_ acm{};
daemon->getSettings(&mod, &demod, &acm, nullptr, nullptr);
#else
daemon->getSettings(&mod, &demod, nullptr, nullptr);
#endif
// для модулятора std::lock_guard _lapi(this->daemon->cpApiMutex);
#ifdef MODEM_IS_SCPC this->daemon->cp.setDmaDebug("begin_save_config", "");
mod.is_cinc = pt.get<bool>("isCinC"); qos.store(this->daemon->cp);
#endif this->daemon->cp.setDmaDebug("save_config", "");
mod.tx_is_on = pt.get<bool>("txEn"); qos.updateCallback(this->daemon->cp);
#ifdef MODEM_IS_SCPC {
mod.is_save_current_state = pt.get<bool>("txAutoStart"); daemon->setQosSettings(qos);
mod.is_test_data = pt.get<bool>("txIsTestInput");
#endif
mod.is_carrier = !pt.get<bool>("txModulatorIsTest");
mod.central_freq_in_kGz = pt.get<double>("txCentralFreq");
#ifdef MODEM_IS_SCPC
mod.baudrate = pt.get<uint32_t>("txBaudrate");
mod.rollof = pt.get<unsigned int>("txRolloff");
mod.gold_seq_is_active = pt.get<unsigned int>("txGoldan");
#endif
mod.attenuation = pt.get<double>("txAttenuation");
#ifdef MODEM_IS_SCPC
const bool acmIsShortFrame = !pt.get<bool>("txFrameSizeNormal");
const bool acmIsPilots = pt.get<bool>("txIsPilots");
mod.modcod_tx = buildModcodFromPt(pt, "dvbCcm", acmIsShortFrame, acmIsPilots);
#endif
// демодулятор
demod.is_aru_on = pt.get<bool>("rxAgcEn");
demod.gain = pt.get<double>("rxManualGain");
demod.is_rvt_iq = pt.get<bool>("rxSpectrumInversion");
demod.central_freq_in_kGz = pt.get<double>("rxCentralFreq");
demod.baudrate = pt.get<uint32_t>("rxBaudrate");
demod.rollof = pt.get<unsigned int>("rxRolloff");
#ifdef MODEM_IS_SCPC
demod.gold_seq_is_active = pt.get<unsigned int>("rxGoldan");
#endif
#ifdef MODEM_IS_SCPC
// ACM
acm.period_pack_acm = pt.get<uint32_t>("dvbServicePacketPeriod");
acm.enable_acm = pt.get<bool>("dvbIsAcm");
#ifdef MODEM_IS_SCPC
acm.min_modcod_acm = buildModcodFromPt(pt, "dvbAcmMin", acmIsShortFrame, acmIsPilots);
acm.max_modcod_acm = buildModcodFromPt(pt, "dvbAcmMax", acmIsShortFrame, acmIsPilots);
#else
acm.min_modcod_acm = buildModcodFromPt(pt, "dvbAcmMin", acmIsShortFrame);
acm.max_modcod_acm = buildModcodFromPt(pt, "dvbAcmMax", acmIsShortFrame);
#endif
acm.snr_threashold_acm = pt.get<double>("dvbSnrReserve"); // запас ОСШ
acm.enable_aupc = pt.get<bool>(json_path("aupcEn", '/'));
acm.min_attenuation_aupc = pt.get<int>("aupcMinAttenuation");
acm.max_attenuation_aupc = pt.get<int>("aupcMaxAttenuation");
acm.snr_threashold_aupc= pt.get<double>("aupcRequiredSnr");
daemon->setSettingsRxTx(mod, demod, acm);
#else
daemon->setSettingsRxTx(mod, demod);
#endif
}
void api_driver::ApiDriver::setDpdiSettings(boost::property_tree::ptree &pt) {
DPDI_parmeters s{};
#ifdef MODEM_IS_SCPC
this->daemon->getSettings(nullptr, nullptr, nullptr, &s, nullptr);
#else
this->daemon->getSettings(nullptr, nullptr, &s, nullptr);
#endif
s.is_delay_window = !pt.get<bool>("dpdiIsPositional");
#ifdef MODEM_IS_SCPC
s.freq_offset = pt.get<uint32_t>("dpdiSearchBandwidth");
#endif
auto ctmp = translateCoordinates(pt.get<double>("dpdiPositionStationLatitude"));
s.latitude_station_grad = std::get<0>(ctmp);
s.latitude_station_minute = std::get<1>(ctmp);
ctmp = translateCoordinates(pt.get<double>("dpdiPositionStationLongitude"));
s.longitude_station_grad = std::get<0>(ctmp);
s.longitude_station_minute = std::get<1>(ctmp);
ctmp = translateCoordinates(pt.get<double>("dpdiPositionSatelliteLongitude"));
s.longitude_sattelite_grad = std::get<0>(ctmp);
s.longitude_sattelite_minute = std::get<1>(ctmp);
#ifdef MODEM_IS_SCPC
s.min_delay = pt.get<uint32_t>("dpdiDelayMin");
s.max_delay = pt.get<uint32_t>("dpdiDelayMax");
#else
s.min_delay = 0;
s.max_delay = pt.get<uint32_t>("dpdiDelay");
#endif
this->daemon->setSettingsDpdi(s);
}
void api_driver::ApiDriver::setBucLnbSettings(boost::property_tree::ptree &pt) {
buc_lnb_settings s{};
#ifdef MODEM_IS_SCPC
daemon->getSettings(nullptr, nullptr, nullptr, nullptr, &s);
#else
daemon->getSettings(nullptr, nullptr, nullptr, &s);
#endif
auto tmp = pt.get<int>("bucPowering");
switch (tmp) {
case 24: s.buc = voltage_buc::_24V; break;
#ifdef MODEM_IS_SCPC
case 48: s.buc = voltage_buc::_48V; break;
#endif
case 0:
default:
s.buc = voltage_buc::DISABLE;
} }
s.is_ref_10MHz_buc = pt.get<bool>("bucRefClk10M"); }
#endif
tmp = pt.get<int>("lnbPowering"); #ifdef API_OBJECT_NETWORK_SETTINGS_ENABLE
switch (tmp) { void api_driver::ApiDriver::setNetworkSettings(const nlohmann::json& data) {
case 13: s.lnb = voltage_lnb::_13V; break; auto net = daemon->getNetworkSettings();
case 18: s.lnb = voltage_lnb::_18V; break; net.updateFromJson(data);
case 24: s.lnb = voltage_lnb::_24V; break;
case 0: std::lock_guard _lapi(this->daemon->cpApiMutex);
default: this->daemon->cp.setDmaDebug("begin_save_config", "");
s.lnb = voltage_lnb::DISABLE; net.store(this->daemon->cp);
this->daemon->cp.setDmaDebug("save_config", "");
net.updateCallback(this->daemon->cp);
{
daemon->setNetworkSettings(net);
} }
s.is_ref_10MHz_lnb = pt.get<bool>("lnbRefClk10M");
s.is_ref_10MHz_output = pt.get<bool>("srvRefClk10M");
s.is_save_current_state = pt.get<bool>("bucLnbAutoStart");
this->daemon->setSettingsBucLnb(s);
}
void api_driver::ApiDriver::setQosSettings(boost::property_tree::ptree &pt) {
bool enabled = pt.get<bool>("en");
pt.erase("en");
std::ostringstream oss;
write_json(oss, pt);
this->daemon->setQosSettings(enabled, oss.str());
}
void api_driver::ApiDriver::setNetworkSettings(boost::property_tree::ptree &pt) {
TerminalNetworkSettings s;
daemon->getNetworkSettings(s);
s.managementIp = pt.get<std::string>("netManagementIp");
// s.managementGateway = pt.get<std::string>(json_path("network.managementGateway", '/'));
s.isL2 = pt.get<bool>("netIsL2");
s.dataIp = pt.get<std::string>("netDataIp");
s.dataMtu = pt.get<unsigned int>("netDataMtu");
s.serverName = pt.get<std::string>("netServerName");
daemon->setNetworkSettings(s);
} }
#endif
void api_driver::ApiDriver::resetDefaultSettings() { void api_driver::ApiDriver::resetDefaultSettings() {
daemon->resetDefaultSettings(); daemon->resetDefaultSettings();
} }
void api_driver::ApiDriver::executeInApi(const std::function<void(TSID sid)>& callback) { void api_driver::ApiDriver::executeInApi(const std::function<void(proxy::CpProxy&)>& callback) {
try { try {
std::lock_guard lock(this->daemon->cpApiMutex); std::lock_guard lock(this->daemon->cpApiMutex);
callback(this->daemon->sid); callback(this->daemon->cp);
} catch (std::exception& e) { } catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "ApiDriver::executeInApi(): failed to exec with error: " << e.what(); BOOST_LOG_TRIVIAL(error) << "ApiDriver::executeInApi(): failed to exec with error: " << e.what();
} }
@@ -780,17 +179,19 @@ void api_driver::ApiDriver::executeInApi(const std::function<void(TSID sid)>& ca
#ifdef MODEM_IS_TDMA #ifdef MODEM_IS_TDMA
std::string api_driver::ApiDriver::getOtaFileLocation() const { std::string api_driver::ApiDriver::getOtaFileLocation() const {
return daemon->getState().otaImage; obj::TerminalDeviceState ds;
daemon->getDeviceState(ds);
return ds.fUpgradeImage;
} }
#endif #endif
#ifdef MODEM_IS_SCPC #ifdef MODEM_IS_SCPC
std::string api_driver::ApiDriver::getLoggingStatisticsSettings() { nlohmann::json api_driver::ApiDriver::getLoggingStatisticsSettings() {
return this->daemon->statsLogs.getSettings(); return this->daemon->statsLogs.getSettings();
} }
void api_driver::ApiDriver::setLoggingStatisticsSettings(boost::property_tree::ptree &pt) { void api_driver::ApiDriver::setLoggingStatisticsSettings(const nlohmann::json& data) {
this->daemon->statsLogs.setSettings(pt); this->daemon->statsLogs.setSettings(data);
} }
#endif #endif

View File

@@ -1,11 +1,12 @@
#ifndef TERMINAL_API_DRIVER_H #ifndef TERMINAL_API_DRIVER_H
#define TERMINAL_API_DRIVER_H #define TERMINAL_API_DRIVER_H
#include "api-driver/stricts-enable.h"
#include "api-driver/proxy.h"
#include <memory> #include <memory>
#include <string> #include <string>
#include <boost/property_tree/ptree.hpp>
#include <terminal_api/ControlProtoCInterface.h>
#include "common/nlohmann/json.hpp"
namespace api_driver { namespace api_driver {
constexpr int CACHE_STATISTICS_UPDATE_MS = 500; ///< время обновления кеша статистики модулятора/демодулятора constexpr int CACHE_STATISTICS_UPDATE_MS = 500; ///< время обновления кеша статистики модулятора/демодулятора
@@ -13,7 +14,6 @@ namespace api_driver {
constexpr int CACHE_SETTINGS_UPDATE_MS = 5000; constexpr int CACHE_SETTINGS_UPDATE_MS = 5000;
constexpr int CACHE_QOS_UPDATE_MS = 5000; constexpr int CACHE_QOS_UPDATE_MS = 5000;
class StatisticsLogger;
class TerminalApiDaemon; class TerminalApiDaemon;
/** /**
@@ -30,50 +30,56 @@ namespace api_driver {
/** /**
* Запросить общее состояние терминала * Запросить общее состояние терминала
* @return {"txState":false,"rxState":false,"rx.sym_sync_lock":false,"rx.freq_search_lock":false,"rx.afc_lock":false,"rx.pkt_sync":false}
*/ */
std::string loadTerminalState() const; nlohmann::json loadTerminalState() const;
/** /**
* Сбросить статистику пакетов * Сбросить статистику пакетов
*/ */
void resetPacketStatistics() const; void resetPacketStatistics() const;
std::string loadSettings() const; nlohmann::json loadSettings() const;
std::string loadFirmwareVersion() const; nlohmann::json loadFirmwareVersion() const;
/** /**
* Установить настройки RX/TX, readback можно получить используя loadTerminalState * Установить настройки RX/TX, readback можно получить используя loadTerminalState
*/ */
void setRxTxSettings(boost::property_tree::ptree &pt); void setRxTxSettings(const nlohmann::json& data);
#ifdef API_OBJECT_DPDI_SETTINGS_ENABLE
/** /**
* Установить настройки DPDI, readback можно получить используя loadTerminalState. * Установить настройки DPDI, readback можно получить используя loadTerminalState.
* @note Для TDMA и SCPC модемов эти настройки доступны * @note Для TDMA и SCPC модемов эти настройки доступны
*/ */
void setDpdiSettings(boost::property_tree::ptree &pt); void setDpdiSettings(const nlohmann::json& data);
#endif
#ifdef API_OBJECT_BUCLNB_SETTINGS_ENABLE
/** /**
* Установить настройки BUC и LNB, readback можно получить используя loadTerminalState. * Установить настройки BUC и LNB, readback можно получить используя loadTerminalState.
*/ */
void setBucLnbSettings(boost::property_tree::ptree &pt); void setBucLnbSettings(const nlohmann::json& data);
#endif
#ifdef API_OBJECT_QOS_SETTINGS_ENABLE
/** /**
* Установить настройки QoS, readback можно получить используя loadTerminalState. * Установить настройки QoS, readback можно получить используя loadTerminalState.
*/ */
void setQosSettings(boost::property_tree::ptree &pt); void setQosSettings(const nlohmann::json& data);
#endif
void setNetworkSettings(boost::property_tree::ptree &pt); #ifdef API_OBJECT_NETWORK_SETTINGS_ENABLE
void setNetworkSettings(const nlohmann::json& data);
#endif
void resetDefaultSettings(); void resetDefaultSettings();
void executeInApi(const std::function<void(TSID sid)> &callback); void executeInApi(const std::function<void(proxy::CpProxy&)> &callback);
#ifdef MODEM_IS_SCPC #ifdef API_OBJECT_DEBUG_METRICS_ENABLE
std::string getLoggingStatisticsSettings(); nlohmann::json getLoggingStatisticsSettings();
void setLoggingStatisticsSettings(boost::property_tree::ptree &pt); void setLoggingStatisticsSettings(const nlohmann::json& data);
/** /**
* Получить статистику в формате json. Выход будет дописан в вектор * Получить статистику в формате json. Выход будет дописан в вектор
@@ -90,8 +96,6 @@ namespace api_driver {
std::string getOtaFileLocation() const; std::string getOtaFileLocation() const;
#endif #endif
static std::string loadSysInfo();
~ApiDriver(); ~ApiDriver();
private: private:

View File

@@ -160,7 +160,7 @@
<h3>Параметры передачи</h3> <h3>Параметры передачи</h3>
<label> <label>
<span>Центральная частота, КГц</span> <span>Центральная частота, КГц</span>
<input type="text" v-model.lazy="paramRxtx.txCentralFreq" @change="e => paramRxtx.txCentralFreq = inputFormatNumber(inputFormatNumber(e.target.value, {min:950000,max:6000000,step:0.01}), {min:950000,max:6000000,step:0.01})"/> <input type="text" v-model.lazy="paramRxtx.txCentralFreq" @change="e => paramRxtx.txCentralFreq = inputFormatNumber(inputFormatNumber(e.target.value, {min:100000,max:6000000,step:0.01}), {min:100000,max:6000000,step:0.01})"/>
</label> </label>
<label> <label>
<span>Символьная скорость, Бод</span> <span>Символьная скорость, Бод</span>
@@ -169,12 +169,12 @@
<label> <label>
<span>Roll-off</span> <span>Roll-off</span>
<select v-model="paramRxtx.txRolloff"> <select v-model="paramRxtx.txRolloff">
<option :value="2">0.02</option> <option :value="20">0.02</option>
<option :value="5">0.05</option> <option :value="50">0.05</option>
<option :value="10">0.10</option> <option :value="100">0.10</option>
<option :value="15">0.15</option> <option :value="150">0.15</option>
<option :value="20">0.20</option> <option :value="200">0.20</option>
<option :value="25">0.25</option> <option :value="250">0.25</option>
</select> </select>
</label> </label>
<label> <label>
@@ -274,7 +274,7 @@
</label> </label>
<label><span>Минимальное ослабление, дБ</span><input type="number" v-model="paramRxtx.aupcMinAttenuation" max="10" step="0.1"/></label> <label><span>Минимальное ослабление, дБ</span><input type="number" v-model="paramRxtx.aupcMinAttenuation" max="10" step="0.1"/></label>
<label><span>Максимальное ослабление, дБ</span><input type="number" v-model="paramRxtx.aupcMaxAttenuation" max="10" step="0.1"/></label> <label><span>Максимальное ослабление, дБ</span><input type="number" v-model="paramRxtx.aupcMaxAttenuation" max="10" step="0.1"/></label>
<label><span>Требуемое ОСШ</span><input type="number" v-model="paramRxtx.aupcRequiredSnr" max="10" step="0.01"/></label> <label><span>Требуемое ОСШ</span><input type="number" v-model="paramRxtx.aupcRequiredSnr" max="30" step="0.01"/></label>
</div> </div>
<div class="settings-set-container"> <div class="settings-set-container">
<h3>Настройки приемника</h3> <h3>Настройки приемника</h3>
@@ -295,7 +295,7 @@
</label> </label>
<label> <label>
<span>Центральная частота, КГц</span> <span>Центральная частота, КГц</span>
<input type="text" v-model.lazy="paramRxtx.rxCentralFreq" @change="e => paramRxtx.rxCentralFreq = inputFormatNumber(inputFormatNumber(e.target.value, {min:950000,max:6000000,step:0.01}), {min:950000,max:6000000,step:0.01})"/> <input type="text" v-model.lazy="paramRxtx.rxCentralFreq" @change="e => paramRxtx.rxCentralFreq = inputFormatNumber(inputFormatNumber(e.target.value, {min:100000,max:6000000,step:0.01}), {min:100000,max:6000000,step:0.01})"/>
</label> </label>
<label> <label>
<span>Символьная скорость, Бод</span> <span>Символьная скорость, Бод</span>
@@ -304,12 +304,12 @@
<label> <label>
<span>Roll-off</span> <span>Roll-off</span>
<select v-model="paramRxtx.rxRolloff"> <select v-model="paramRxtx.rxRolloff">
<option :value="2">0.02</option> <option :value="20">0.02</option>
<option :value="5">0.05</option> <option :value="50">0.05</option>
<option :value="10">0.10</option> <option :value="100">0.10</option>
<option :value="15">0.15</option> <option :value="150">0.15</option>
<option :value="20">0.20</option> <option :value="200">0.20</option>
<option :value="25">0.25</option> <option :value="250">0.25</option>
</select> </select>
</label> </label>
<label> <label>
@@ -326,19 +326,19 @@
<div class="settings-set-container" v-show="paramRxtx.isCinC"> <div class="settings-set-container" v-show="paramRxtx.isCinC">
<label> <label>
<span>Метод расчета задержки</span> <span>Метод расчета задержки</span>
<select v-model="paramDpdi.dpdiIsPositional"> <select v-model="paramDpdi.isPositional">
<option :value="true">Позиционированием</option> <option :value="true">Позиционированием</option>
<option :value="false">Окном задержки</option> <option :value="false">Окном задержки</option>
</select> </select>
</label> </label>
<label><span>Полоса поиска, КГц ±</span><input type="number" v-model="paramDpdi.dpdiSearchBandwidth" max="100" step="1"/></label> <label><span>Полоса поиска, КГц ±</span><input type="number" v-model="paramDpdi.searchBandwidth" max="100" step="1"/></label>
<h2 v-show="paramDpdi.dpdiIsPositional === true">Настройки позиционирования</h2> <h2 v-show="paramDpdi.isPositional === true">Настройки позиционирования</h2>
<label v-show="paramDpdi.dpdiIsPositional === true"><span>Широта станции</span><input type="number" v-model="paramDpdi.dpdiPositionStationLatitude" min="-180" max="180" step="1e-06"/></label> <label v-show="paramDpdi.isPositional === true"><span>Широта станции</span><input type="number" v-model="paramDpdi.positionStationLatitude" min="-180" max="180" step="1e-06"/></label>
<label v-show="paramDpdi.dpdiIsPositional === true"><span>Долгота станции</span><input type="number" v-model="paramDpdi.dpdiPositionStationLongitude" min="-180" max="180" step="1e-06"/></label> <label v-show="paramDpdi.isPositional === true"><span>Долгота станции</span><input type="number" v-model="paramDpdi.positionStationLongitude" min="-180" max="180" step="1e-06"/></label>
<label v-show="paramDpdi.dpdiIsPositional === true"><span>Подспутниковая точка</span><input type="number" v-model="paramDpdi.dpdiPositionSatelliteLongitude" min="-180" max="180" step="1e-06"/></label> <label v-show="paramDpdi.isPositional === true"><span>Подспутниковая точка</span><input type="number" v-model="paramDpdi.positionSatelliteLongitude" min="-180" max="180" step="1e-06"/></label>
<h2 v-show="paramDpdi.dpdiIsPositional === false">Задержка до спутника</h2> <h2 v-show="paramDpdi.isPositional === false">Задержка до спутника</h2>
<label v-show="paramDpdi.dpdiIsPositional === false"><span>от, мс</span><input type="number" v-model="paramDpdi.dpdiDelayMin" max="400" step="0.1"/></label> <label v-show="paramDpdi.isPositional === false"><span>от, мс</span><input type="number" v-model="paramDpdi.delayMin" max="400" step="0.1"/></label>
<label v-show="paramDpdi.dpdiIsPositional === false"><span>до, мс</span><input type="number" v-model="paramDpdi.dpdiDelayMax" max="400" step="0.1"/></label> <label v-show="paramDpdi.isPositional === false"><span>до, мс</span><input type="number" v-model="paramDpdi.delayMax" max="400" step="0.1"/></label>
</div> </div>
<button class="action-button" @click="settingsSubmitDpdi()" v-show="paramRxtx.isCinC">Сохранить <span class="submit-spinner" v-show="submitStatus.dpdi"></span></button> <button class="action-button" @click="settingsSubmitDpdi()" v-show="paramRxtx.isCinC">Сохранить <span class="submit-spinner" v-show="submitStatus.dpdi"></span></button>
<h2>Настройки питания и опорного генератора</h2> <h2>Настройки питания и опорного генератора</h2>
@@ -489,38 +489,29 @@
</div> </div>
<button class="action-button" @click="settingsSubmitQoS()">Применить <span class="submit-spinner" v-show="submitStatusQos"></span></button> <button class="action-button" @click="settingsSubmitQoS()">Применить <span class="submit-spinner" v-show="submitStatusQos"></span></button>
<h2>Настройки TCP-акселерации</h2>
<div class="settings-set-container">
<label>
<span>Активировать акселерацию</span>
<span class="toggle-input"><input type="checkbox" v-model="paramTcpaccel.accelEn" /><span class="slider"></span></span>
</label>
<label><span>Максимальное количество соединений</span><input type="number" v-model="paramTcpaccel.accelMaxConnections" max="4000" step="1"/></label>
</div>
<button class="action-button" @click="settingsSubmitTcpaccel()">Сохранить <span class="submit-spinner" v-show="submitStatus.tcpaccel"></span></button>
</div> <div class="tabs-body-item" v-if="activeTab === 'admin' && settingFetchComplete"> </div> <div class="tabs-body-item" v-if="activeTab === 'admin' && settingFetchComplete">
<h2>Настройки сети</h2> <h2>Настройки сети</h2>
<div class="settings-set-container"> <div class="settings-set-container">
<h3>Настройки интерфейса управления</h3> <h3>Настройки интерфейса управления</h3>
<label> <label>
<span>Интерфейс управления (/24)</span> <span>Интерфейс управления (a.d.d.r/mask)</span>
<input v-model="paramNetwork.netManagementIp" required type="text" pattern="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"> <input v-model="paramNetwork.managementIp" required type="text" pattern="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\/([0-9]|[1-2][0-9]|3[0-2])$">
</label> </label>
<label> <label>
<span>Режим сети</span> <span>Режим сети</span>
<select v-model="paramNetwork.netIsL2"> <select v-model="paramNetwork.isL2">
<option :value="false">Маршрутизатор</option> <option :value="false">Маршрутизатор</option>
<option :value="true">Коммутатор</option> <option :value="true">Коммутатор</option>
</select> </select>
</label> </label>
<label v-show="paramNetwork.netIsL2 === false"> <label v-show="paramNetwork.isL2 === false">
<span>Интерфейс данных (/24)</span> <span>Интерфейс данных (/24)</span>
<input v-model="paramNetwork.netDataIp" required type="text" pattern="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"> <input v-model="paramNetwork.dataIp" required type="text" pattern="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$">
</label> </label>
<label><span>MTU интерфейса данных</span><input type="number" v-model="paramNetwork.netDataMtu" min="1500" max="2000" step="1"/></label> <label><span>MTU интерфейса данных</span><input type="number" v-model="paramNetwork.dataMtu" min="1500" max="2000" step="1"/></label>
<label> <label>
<span>Имя веб-сервера</span> <span>Имя веб-сервера</span>
<input v-model="paramNetwork.netServerName" type="text"> <input v-model="paramNetwork.serverName" type="text">
</label> </label>
</div> </div>
<button class="action-button" @click="settingsSubmitNetwork()">Сохранить <span class="submit-spinner" v-show="submitStatus.network"></span></button> <button class="action-button" @click="settingsSubmitNetwork()">Сохранить <span class="submit-spinner" v-show="submitStatus.network"></span></button>
@@ -542,6 +533,8 @@
<div> <div>
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button> <button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
</div> </div>
<button class="action-button" @click="dumpAllSettings()">Сохранить бекап конфигурации</button>
<button class="dangerous-button" @click="restoreAllSettings()">Восстановить бекап конфигурации</button>
</div> </div>
<h2>Обновление ПО</h2> <h2>Обновление ПО</h2>
@@ -595,7 +588,6 @@
rxtx: false, rxtx: false,
dpdi: false, dpdi: false,
buclnb: false, buclnb: false,
tcpaccel: false,
network: false, network: false,
firmwareUpload: false, firmwareUpload: false,
firmwareUpgrade: false, firmwareUpgrade: false,
@@ -612,7 +604,7 @@
txIsTestInput: false, txIsTestInput: false,
txCentralFreq: 0, txCentralFreq: 0,
txBaudrate: 0, txBaudrate: 0,
txRolloff: 2, txRolloff: 20,
txGoldan: 0, txGoldan: 0,
txAttenuation: -40, txAttenuation: -40,
dvbServicePacketPeriod: 0, dvbServicePacketPeriod: 0,
@@ -635,17 +627,17 @@
rxSpectrumInversion: false, rxSpectrumInversion: false,
rxCentralFreq: 0, rxCentralFreq: 0,
rxBaudrate: 0, rxBaudrate: 0,
rxRolloff: 2, rxRolloff: 20,
rxGoldan: 0, rxGoldan: 0,
}, },
paramDpdi: { paramDpdi: {
dpdiIsPositional: true, isPositional: true,
dpdiSearchBandwidth: 0, searchBandwidth: 0,
dpdiPositionStationLatitude: -180, positionStationLatitude: -180,
dpdiPositionStationLongitude: -180, positionStationLongitude: -180,
dpdiPositionSatelliteLongitude: -180, positionSatelliteLongitude: -180,
dpdiDelayMin: 0, delayMin: 0,
dpdiDelayMax: 0, delayMax: 0,
}, },
paramBuclnb: { paramBuclnb: {
bucRefClk10M: false, bucRefClk10M: false,
@@ -655,16 +647,12 @@
srvRefClk10M: false, srvRefClk10M: false,
bucLnbAutoStart: false, bucLnbAutoStart: false,
}, },
paramTcpaccel: {
accelEn: false,
accelMaxConnections: 0,
},
paramNetwork: { paramNetwork: {
netManagementIp: null, managementIp: null,
netIsL2: false, isL2: false,
netDataIp: null, dataIp: null,
netDataMtu: 1500, dataMtu: 1500,
netServerName: null, serverName: null,
}, },
// ========== include end from 'common/all-params-data.js.j2' // ========== include end from 'common/all-params-data.js.j2'
@@ -841,13 +829,13 @@
if (this.submitStatus.dpdi) { return } if (this.submitStatus.dpdi) { return }
let query = { let query = {
"dpdiIsPositional": this.paramDpdi.dpdiIsPositional, "isPositional": this.paramDpdi.isPositional,
"dpdiSearchBandwidth": this.paramDpdi.dpdiSearchBandwidth, "searchBandwidth": this.paramDpdi.searchBandwidth,
"dpdiPositionStationLatitude": this.paramDpdi.dpdiPositionStationLatitude, "positionStationLatitude": this.paramDpdi.positionStationLatitude,
"dpdiPositionStationLongitude": this.paramDpdi.dpdiPositionStationLongitude, "positionStationLongitude": this.paramDpdi.positionStationLongitude,
"dpdiPositionSatelliteLongitude": this.paramDpdi.dpdiPositionSatelliteLongitude, "positionSatelliteLongitude": this.paramDpdi.positionSatelliteLongitude,
"dpdiDelayMin": this.paramDpdi.dpdiDelayMin, "delayMin": this.paramDpdi.delayMin,
"dpdiDelayMax": this.paramDpdi.dpdiDelayMax, "delayMax": this.paramDpdi.delayMax,
} }
this.submitStatus.dpdi = true this.submitStatus.dpdi = true
@@ -875,30 +863,16 @@
.catch((reason) => { alert(`Ошибка при применении настроек: ${reason}`) }) .catch((reason) => { alert(`Ошибка при применении настроек: ${reason}`) })
.finally(() => { this.submitStatus.buclnb = false }) .finally(() => { this.submitStatus.buclnb = false })
}, },
settingsSubmitTcpaccel() {
if (this.submitStatus.tcpaccel) { return }
let query = {
"accelEn": this.paramTcpaccel.accelEn,
"accelMaxConnections": this.paramTcpaccel.accelMaxConnections,
}
this.submitStatus.tcpaccel = true
fetch('/api/set/tcpaccel', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(query), credentials: 'same-origin' })
.then(async (resp) => { let vals = await resp.json(); if (vals['status'] !== 'ok') { throw new Error(vals['error'] ? vals['error'] : "Server returns undefined error") } this.updateTcpaccelSettings(vals) })
.catch((reason) => { alert(`Ошибка при применении настроек: ${reason}`) })
.finally(() => { this.submitStatus.tcpaccel = false })
},
settingsSubmitNetwork() { settingsSubmitNetwork() {
if (this.submitStatus.network) { return } if (this.submitStatus.network) { return }
{ if (!confirm("Применение этих настроек может сделать модем недоступным! Продолжить?")) return } { if (!confirm("Применение этих настроек может сделать модем недоступным! Продолжить?")) return }
let query = { let query = {
"netManagementIp": this.paramNetwork.netManagementIp, "managementIp": this.paramNetwork.managementIp,
"netIsL2": this.paramNetwork.netIsL2, "isL2": this.paramNetwork.isL2,
"netDataIp": this.paramNetwork.netDataIp, "dataIp": this.paramNetwork.dataIp,
"netDataMtu": this.paramNetwork.netDataMtu, "dataMtu": this.paramNetwork.dataMtu,
"netServerName": this.paramNetwork.netServerName, "serverName": this.paramNetwork.serverName,
} }
this.submitStatus.network = true this.submitStatus.network = true
@@ -910,70 +884,65 @@
updateRxtxSettings(vals) { updateRxtxSettings(vals) {
this.submitStatus.rxtx = false this.submitStatus.rxtx = false
this.paramRxtx.isCinC = vals["settings"]["isCinC"] this.paramRxtx.isCinC = vals["settings"]["rxtx"]["isCinC"]
this.paramRxtx.txEn = vals["settings"]["txEn"] this.paramRxtx.txEn = vals["settings"]["rxtx"]["txEn"]
this.paramRxtx.txAutoStart = vals["settings"]["txAutoStart"] this.paramRxtx.txAutoStart = vals["settings"]["rxtx"]["txAutoStart"]
this.paramRxtx.txModulatorIsTest = vals["settings"]["txModulatorIsTest"] this.paramRxtx.txModulatorIsTest = vals["settings"]["rxtx"]["txModulatorIsTest"]
this.paramRxtx.txIsTestInput = vals["settings"]["txIsTestInput"] this.paramRxtx.txIsTestInput = vals["settings"]["rxtx"]["txIsTestInput"]
this.paramRxtx.txCentralFreq = this.inputFormatNumber(vals["settings"]["txCentralFreq"], {min:950000,max:6000000,step:0.01}) this.paramRxtx.txCentralFreq = this.inputFormatNumber(vals["settings"]["rxtx"]["txCentralFreq"], {min:100000,max:6000000,step:0.01})
this.paramRxtx.txBaudrate = this.inputFormatNumber(vals["settings"]["txBaudrate"], {min:200000,max:54000000,}) this.paramRxtx.txBaudrate = this.inputFormatNumber(vals["settings"]["rxtx"]["txBaudrate"], {min:200000,max:54000000,})
this.paramRxtx.txRolloff = vals["settings"]["txRolloff"] this.paramRxtx.txRolloff = vals["settings"]["rxtx"]["txRolloff"]
this.paramRxtx.txGoldan = vals["settings"]["txGoldan"] this.paramRxtx.txGoldan = vals["settings"]["rxtx"]["txGoldan"]
this.paramRxtx.txAttenuation = vals["settings"]["txAttenuation"] this.paramRxtx.txAttenuation = vals["settings"]["rxtx"]["txAttenuation"]
this.paramRxtx.dvbServicePacketPeriod = vals["settings"]["dvbServicePacketPeriod"] this.paramRxtx.dvbServicePacketPeriod = vals["settings"]["rxtx"]["dvbServicePacketPeriod"]
this.paramRxtx.dvbIsAcm = vals["settings"]["dvbIsAcm"] this.paramRxtx.dvbIsAcm = vals["settings"]["rxtx"]["dvbIsAcm"]
this.paramRxtx.txFrameSizeNormal = vals["settings"]["txFrameSizeNormal"] this.paramRxtx.txFrameSizeNormal = vals["settings"]["rxtx"]["txFrameSizeNormal"]
this.paramRxtx.txIsPilots = vals["settings"]["txIsPilots"] this.paramRxtx.txIsPilots = vals["settings"]["rxtx"]["txIsPilots"]
this.paramRxtx.dvbCcmModulation = vals["settings"]["dvbCcmModulation"] this.paramRxtx.dvbCcmModulation = vals["settings"]["rxtx"]["dvbCcmModulation"]
this.paramRxtx.dvbCcmSpeed = vals["settings"]["dvbCcmSpeed"] this.paramRxtx.dvbCcmSpeed = vals["settings"]["rxtx"]["dvbCcmSpeed"]
this.paramRxtx.dvbAcmMinModulation = vals["settings"]["dvbAcmMinModulation"] this.paramRxtx.dvbAcmMinModulation = vals["settings"]["rxtx"]["dvbAcmMinModulation"]
this.paramRxtx.dvbAcmMinSpeed = vals["settings"]["dvbAcmMinSpeed"] this.paramRxtx.dvbAcmMinSpeed = vals["settings"]["rxtx"]["dvbAcmMinSpeed"]
this.paramRxtx.dvbAcmMaxModulation = vals["settings"]["dvbAcmMaxModulation"] this.paramRxtx.dvbAcmMaxModulation = vals["settings"]["rxtx"]["dvbAcmMaxModulation"]
this.paramRxtx.dvbAcmMaxSpeed = vals["settings"]["dvbAcmMaxSpeed"] this.paramRxtx.dvbAcmMaxSpeed = vals["settings"]["rxtx"]["dvbAcmMaxSpeed"]
this.paramRxtx.dvbSnrReserve = vals["settings"]["dvbSnrReserve"] this.paramRxtx.dvbSnrReserve = vals["settings"]["rxtx"]["dvbSnrReserve"]
this.paramRxtx.aupcEn = vals["settings"]["aupcEn"] this.paramRxtx.aupcEn = vals["settings"]["rxtx"]["aupcEn"]
this.paramRxtx.aupcMinAttenuation = vals["settings"]["aupcMinAttenuation"] this.paramRxtx.aupcMinAttenuation = vals["settings"]["rxtx"]["aupcMinAttenuation"]
this.paramRxtx.aupcMaxAttenuation = vals["settings"]["aupcMaxAttenuation"] this.paramRxtx.aupcMaxAttenuation = vals["settings"]["rxtx"]["aupcMaxAttenuation"]
this.paramRxtx.aupcRequiredSnr = vals["settings"]["aupcRequiredSnr"] this.paramRxtx.aupcRequiredSnr = vals["settings"]["rxtx"]["aupcRequiredSnr"]
this.paramRxtx.rxAgcEn = vals["settings"]["rxAgcEn"] this.paramRxtx.rxAgcEn = vals["settings"]["rxtx"]["rxAgcEn"]
this.paramRxtx.rxManualGain = vals["settings"]["rxManualGain"] this.paramRxtx.rxManualGain = vals["settings"]["rxtx"]["rxManualGain"]
this.paramRxtx.rxSpectrumInversion = vals["settings"]["rxSpectrumInversion"] this.paramRxtx.rxSpectrumInversion = vals["settings"]["rxtx"]["rxSpectrumInversion"]
this.paramRxtx.rxCentralFreq = this.inputFormatNumber(vals["settings"]["rxCentralFreq"], {min:950000,max:6000000,step:0.01}) this.paramRxtx.rxCentralFreq = this.inputFormatNumber(vals["settings"]["rxtx"]["rxCentralFreq"], {min:100000,max:6000000,step:0.01})
this.paramRxtx.rxBaudrate = this.inputFormatNumber(vals["settings"]["rxBaudrate"], {min:200000,max:54000000,}) this.paramRxtx.rxBaudrate = this.inputFormatNumber(vals["settings"]["rxtx"]["rxBaudrate"], {min:200000,max:54000000,})
this.paramRxtx.rxRolloff = vals["settings"]["rxRolloff"] this.paramRxtx.rxRolloff = vals["settings"]["rxtx"]["rxRolloff"]
this.paramRxtx.rxGoldan = vals["settings"]["rxGoldan"] this.paramRxtx.rxGoldan = vals["settings"]["rxtx"]["rxGoldan"]
}, },
updateDpdiSettings(vals) { updateDpdiSettings(vals) {
this.submitStatus.dpdi = false this.submitStatus.dpdi = false
this.paramDpdi.dpdiIsPositional = vals["settings"]["dpdiIsPositional"] this.paramDpdi.isPositional = vals["settings"]["dpdi"]["isPositional"]
this.paramDpdi.dpdiSearchBandwidth = vals["settings"]["dpdiSearchBandwidth"] this.paramDpdi.searchBandwidth = vals["settings"]["dpdi"]["searchBandwidth"]
this.paramDpdi.dpdiPositionStationLatitude = vals["settings"]["dpdiPositionStationLatitude"] this.paramDpdi.positionStationLatitude = vals["settings"]["dpdi"]["positionStationLatitude"]
this.paramDpdi.dpdiPositionStationLongitude = vals["settings"]["dpdiPositionStationLongitude"] this.paramDpdi.positionStationLongitude = vals["settings"]["dpdi"]["positionStationLongitude"]
this.paramDpdi.dpdiPositionSatelliteLongitude = vals["settings"]["dpdiPositionSatelliteLongitude"] this.paramDpdi.positionSatelliteLongitude = vals["settings"]["dpdi"]["positionSatelliteLongitude"]
this.paramDpdi.dpdiDelayMin = vals["settings"]["dpdiDelayMin"] this.paramDpdi.delayMin = vals["settings"]["dpdi"]["delayMin"]
this.paramDpdi.dpdiDelayMax = vals["settings"]["dpdiDelayMax"] this.paramDpdi.delayMax = vals["settings"]["dpdi"]["delayMax"]
}, },
updateBuclnbSettings(vals) { updateBuclnbSettings(vals) {
this.submitStatus.buclnb = false this.submitStatus.buclnb = false
this.paramBuclnb.bucRefClk10M = vals["settings"]["bucRefClk10M"] this.paramBuclnb.bucRefClk10M = vals["settings"]["buclnb"]["bucRefClk10M"]
this.paramBuclnb.bucPowering = vals["settings"]["bucPowering"] this.paramBuclnb.bucPowering = vals["settings"]["buclnb"]["bucPowering"]
this.paramBuclnb.lnbRefClk10M = vals["settings"]["lnbRefClk10M"] this.paramBuclnb.lnbRefClk10M = vals["settings"]["buclnb"]["lnbRefClk10M"]
this.paramBuclnb.lnbPowering = vals["settings"]["lnbPowering"] this.paramBuclnb.lnbPowering = vals["settings"]["buclnb"]["lnbPowering"]
this.paramBuclnb.srvRefClk10M = vals["settings"]["srvRefClk10M"] this.paramBuclnb.srvRefClk10M = vals["settings"]["buclnb"]["srvRefClk10M"]
this.paramBuclnb.bucLnbAutoStart = vals["settings"]["bucLnbAutoStart"] this.paramBuclnb.bucLnbAutoStart = vals["settings"]["buclnb"]["bucLnbAutoStart"]
},
updateTcpaccelSettings(vals) {
this.submitStatus.tcpaccel = false
this.paramTcpaccel.accelEn = vals["settings"]["accelEn"]
this.paramTcpaccel.accelMaxConnections = vals["settings"]["accelMaxConnections"]
}, },
updateNetworkSettings(vals) { updateNetworkSettings(vals) {
this.submitStatus.network = false this.submitStatus.network = false
this.paramNetwork.netManagementIp = vals["settings"]["netManagementIp"] this.paramNetwork.managementIp = vals["settings"]["network"]["managementIp"]
this.paramNetwork.netIsL2 = vals["settings"]["netIsL2"] this.paramNetwork.isL2 = vals["settings"]["network"]["isL2"]
this.paramNetwork.netDataIp = vals["settings"]["netDataIp"] this.paramNetwork.dataIp = vals["settings"]["network"]["dataIp"]
this.paramNetwork.netDataMtu = vals["settings"]["netDataMtu"] this.paramNetwork.dataMtu = vals["settings"]["network"]["dataMtu"]
this.paramNetwork.netServerName = vals["settings"]["netServerName"] this.paramNetwork.serverName = vals["settings"]["network"]["serverName"]
}, },
// ========== include end from 'common/all-params-methods.js.j2' // ========== include end from 'common/all-params-methods.js.j2'
@@ -998,53 +967,52 @@
} }
this.lastUpdateTime = new Date(); this.lastUpdateTime = new Date();
this.initState = vals["mainState"]["initState"] this.initState = vals["state"]["initState"]
this.isCinC = vals["mainState"]["isCinC"] this.testState = vals["state"]["testState"]
this.isCinC = vals["state"]["isCinC"]
this.statRx.state = vals["mainState"]["rx.state"] this.statRx.state = vals["state"]["rx"]["state"]
this.statRx.sym_sync_lock = vals["mainState"]["rx.sym_sync_lock"] this.statRx.sym_sync_lock = vals["state"]["rx"]["sym_sync_lock"]
this.statRx.freq_search_lock = vals["mainState"]["rx.freq_search_lock"] this.statRx.freq_search_lock = vals["state"]["rx"]["freq_search_lock"]
this.statRx.afc_lock = vals["mainState"]["rx.afc_lock"] this.statRx.afc_lock = vals["state"]["rx"]["afc_lock"]
this.statRx.pkt_sync = vals["mainState"]["rx.pkt_sync"] this.statRx.pkt_sync = vals["state"]["rx"]["pkt_sync"]
this.statRx.snr = vals["mainState"]["rx.snr"] this.statRx.snr = Math.round(vals["state"]["rx"]["snr"] * 10) / 10
this.statRx.rssi = vals["mainState"]["rx.rssi"] this.statRx.rssi = Math.round(vals["state"]["rx"]["rssi"] * 10) / 10
this.statRx.modcod = modcodToStr(vals["mainState"]["rx.modcod"]) this.statRx.modcod = modcodToStr(vals["state"]["rx"]["modcod"])
this.statRx.frameSizeNormal = vals["mainState"]["rx.frameSizeNormal"] this.statRx.frameSizeNormal = vals["state"]["rx"]["frameSizeNormal"]
this.statRx.isPilots = vals["mainState"]["rx.isPilots"] this.statRx.isPilots = vals["state"]["rx"]["isPilots"]
this.statRx.symError = vals["mainState"]["rx.symError"] this.statRx.symError = vals["state"]["rx"]["symError"]
this.statRx.freqErr = vals["mainState"]["rx.freqErr"] this.statRx.freqErr = Math.round(vals["state"]["rx"]["freqErr"] * 100) / 100
this.statRx.freqErrAcc = vals["mainState"]["rx.freqErrAcc"] this.statRx.freqErrAcc = Math.round(vals["state"]["rx"]["freqErrAcc"] * 100) / 100
this.statRx.inputSignalLevel = vals["mainState"]["rx.inputSignalLevel"] this.statRx.inputSignalLevel = vals["state"]["rx"]["inputSignalLevel"]
this.statRx.pllError = vals["mainState"]["rx.pllError"] this.statRx.pllError = Math.round(vals["state"]["rx"]["pllError"] * 100) / 100
this.statRx.speedOnRxKbit = vals["mainState"]["rx.speedOnRxKbit"] this.statRx.speedOnRxKbit = Math.round(vals["state"]["rx"]["speedOnRxKbit"] * 100) / 100
this.statRx.speedOnIifKbit = vals["mainState"]["rx.speedOnIifKbit"] this.statRx.speedOnIifKbit = Math.round(vals["state"]["rx"]["speedOnIifKbit"] * 100) / 100
this.statRx.packetsOk = vals["mainState"]["rx.packetsOk"] this.statRx.packetsOk = vals["state"]["rx"]["packetsOk"]
this.statRx.packetsBad = vals["mainState"]["rx.packetsBad"] this.statRx.packetsBad = vals["state"]["rx"]["packetsBad"]
this.statRx.packetsDummy = vals["mainState"]["rx.packetsDummy"] this.statRx.packetsDummy = vals["state"]["rx"]["packetsDummy"]
this.statTx.state = vals["mainState"]["tx.state"] this.statTx.state = vals["state"]["tx"]["state"]
this.statTx.snr = vals["mainState"]["tx.snr"] this.statTx.snr = Math.round(vals["state"]["tx"]["snr"] * 100) / 100
this.statTx.modcod = modcodToStr(vals["mainState"]["tx.modcod"]) this.statTx.modcod = modcodToStr(vals["state"]["tx"]["modcod"])
this.statTx.frameSizeNormal = vals["mainState"]["tx.frameSizeNormal"] this.statTx.frameSizeNormal = vals["state"]["tx"]["frameSizeNormal"]
this.statTx.isPilots = vals["mainState"]["tx.isPilots"] this.statTx.isPilots = vals["state"]["tx"]["isPilots"]
this.statTx.speedOnTxKbit = vals["mainState"]["tx.speedOnTxKbit"] this.statTx.speedOnTxKbit = Math.round(vals["state"]["tx"]["speedOnTxKbit"] * 100) / 100
this.statTx.speedOnIifKbit = vals["mainState"]["tx.speedOnIifKbit"] this.statTx.speedOnIifKbit = Math.round(vals["state"]["tx"]["speedOnIifKbit"] * 100) / 100
this.statCinc.occ = vals["mainState"]["cinc.occ"] this.statCinc.occ = vals["state"]["cinc"]["occ"]
this.statCinc.correlator = vals["mainState"]["cinc.correlator"] this.statCinc.correlator = vals["state"]["cinc"]["correlator"]
this.statCinc.correlatorFails = vals["mainState"]["cinc.correlatorFails"] this.statCinc.correlatorFails = vals["state"]["cinc"]["correlatorFails"]
this.statCinc.freqErr = vals["mainState"]["cinc.freqErr"] this.statCinc.freqErr = Math.round(vals["state"]["cinc"]["freqErr"] * 100) / 100
this.statCinc.freqErrAcc = vals["mainState"]["cinc.freqErrAcc"] this.statCinc.freqErrAcc = Math.round(vals["state"]["cinc"]["freqErrAcc"] * 100) / 100
this.statCinc.channelDelay = vals["mainState"]["cinc.channelDelay"] this.statCinc.channelDelay = vals["state"]["cinc"]["channelDelay"]
this.statDevice.adrv = vals["mainState"]["device.adrv"] this.statDevice.adrv = vals["state"]["device"]["adrv"]
this.statDevice.zynq = vals["mainState"]["device.zynq"] this.statDevice.zynq = vals["state"]["device"]["zynq"]
this.statDevice.fpga = vals["mainState"]["device.fpga"] this.statDevice.fpga = vals["state"]["device"]["fpga"]
this.testState = vals["mainState"]["testState"]
// аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид // аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид
let uptime = vals["sysinfo"]["uptime"] let uptime = vals["state"]["device"]["uptime"]
if (uptime) { if (uptime) {
let secs = uptime % 60; uptime = Math.floor(uptime / 60) let secs = uptime % 60; uptime = Math.floor(uptime / 60)
let mins = uptime % 60; uptime = Math.floor(uptime / 60) let mins = uptime % 60; uptime = Math.floor(uptime / 60)
@@ -1056,11 +1024,11 @@
} else { } else {
this.statOs.uptime = '?' this.statOs.uptime = '?'
} }
this.statOs.load1 = vals["sysinfo"]["load1min"] this.statOs.load1 = Math.round(vals["state"]["device"]["load1min"] * 100) / 100
this.statOs.load5 = vals["sysinfo"]["load5min"] this.statOs.load5 = Math.round(vals["state"]["device"]["load5min"] * 100) / 100
this.statOs.load15 = vals["sysinfo"]["load15min"] this.statOs.load15 = Math.round(vals["state"]["device"]["load15min"] * 100) / 100
this.statOs.totalram = vals["sysinfo"]["totalram"] this.statOs.totalram = vals["state"]["device"]["totalram"]
this.statOs.freeram = vals["sysinfo"]["freeram"] this.statOs.freeram = vals["state"]["device"]["freeram"]
}, },
resetPacketsStatistics() { resetPacketsStatistics() {
@@ -1156,15 +1124,17 @@
} }
let query = { let query = {
"en": this.paramQos.en, "en": this.paramQos.en,
"profile": {
"rt1": [], "rt1": [],
"rt2": [], "rt2": [],
"rt3": [], "rt3": [],
"cd": [] "cd": []
} }
for (let i = 0; i < this.paramQos.rt1.length; i++) { query.rt1.push(_translateQosClass('rt', this.paramQos.rt1[i])) } }
for (let i = 0; i < this.paramQos.rt2.length; i++) { query.rt2.push(_translateQosClass('rt', this.paramQos.rt2[i])) } for (let i = 0; i < this.paramQos.rt1.length; i++) { query.profile.rt1.push(_translateQosClass('rt', this.paramQos.rt1[i])) }
for (let i = 0; i < this.paramQos.rt3.length; i++) { query.rt3.push(_translateQosClass('rt', this.paramQos.rt3[i])) } for (let i = 0; i < this.paramQos.rt2.length; i++) { query.profile.rt2.push(_translateQosClass('rt', this.paramQos.rt2[i])) }
for (let i = 0; i < this.paramQos.cd.length; i++) { query.cd.push(_translateQosClass('rt', this.paramQos.cd[i])) } for (let i = 0; i < this.paramQos.rt3.length; i++) { query.profile.rt3.push(_translateQosClass('rt', this.paramQos.rt3[i])) }
for (let i = 0; i < this.paramQos.cd.length; i++) { query.profile.cd.push(_translateQosClass('rt', this.paramQos.cd[i])) }
//console.log(query) //console.log(query)
fetch('/api/set/qos', { fetch('/api/set/qos', {
@@ -1185,9 +1155,9 @@
updateQosSettings(vals) { updateQosSettings(vals) {
this.submitStatusQos = false this.submitStatusQos = false
this.paramQos.en = vals["settings"]["qosEnabled"] this.paramQos.en = vals["settings"]["qos"]["en"]
const qosProfile = vals["settings"]["qosProfile"] const qosProfile = vals["settings"]["qos"]["profile"]
if (qosProfile !== null && qosProfile !== undefined) { if (qosProfile !== null && qosProfile !== undefined) {
this.paramQos.rt1 = [] // .splice(0, this.paramQos.rt1.length) this.paramQos.rt1 = [] // .splice(0, this.paramQos.rt1.length)
this.paramQos.rt2 = [] // .splice(0, this.paramQos.rt2.length) this.paramQos.rt2 = [] // .splice(0, this.paramQos.rt2.length)
@@ -1395,6 +1365,133 @@
} }
this.submitStatus.modemReboot = 30 this.submitStatus.modemReboot = 30
fetch('/api/reboot', { method: 'POST' }).then((r) => {}) fetch('/api/reboot', { method: 'POST' }).then((r) => {})
},
async restoreAllSettings() {
// Порядок применения настроек
const settingsApplyOrder = ['qos', 'tcpaccel', 'dpdi', 'rxtx', 'buclnb', 'network'];
// 1. Чтение JSON-файла, выбранного пользователем
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = '.json';
const filePromise = new Promise((resolve, reject) => {
fileInput.onchange = e => {
const file = e.target.files[0];
if (!file) {
reject(new Error('Файл не выбран'));
return;
}
const reader = new FileReader();
reader.onload = event => {
try {
const jsonData = JSON.parse(event.target.result);
resolve(jsonData);
} catch (error) {
reject(new Error('Ошибка парсинга JSON'));
}
};
reader.onerror = () => reject(new Error('Ошибка чтения файла'));
reader.readAsText(file);
};
fileInput.click();
});
try {
const settingsToApply = await filePromise;
const errors = [];
// 2. Перебор групп параметров в заданном порядке
for (const groupName of settingsApplyOrder) {
if (!settingsToApply.hasOwnProperty(groupName)) {
continue; // Пропускаем группы, которых нет в файле
}
const groupSettings = settingsToApply[groupName];
if (typeof groupSettings !== 'object' || groupSettings === null) {
continue;
}
try {
// 2.1. POST-запрос для применения группы параметров
const postResponse = await fetch(`/api/set/${groupName}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(groupSettings)
});
if (!postResponse.ok) {
throw new Error(`HTTP error ${postResponse.status}`);
}
const postResult = await postResponse.json();
if (postResult.status !== 'ok') {
throw new Error(`API error: ${postResult.message || 'unknown error'}`);
}
// 2.2. Проверка примененных параметров
const getResponse = await fetch('/api/get/settings', { method: 'GET' });
if (!getResponse.ok) {
throw new Error(`HTTP error ${getResponse.status}`);
}
const fetchSettingsResult = await getResponse.json();
if (fetchSettingsResult.status !== 'ok') {
throw new Error('Не удалось получить текущие настройки');
}
// Проверка соответствия параметров
const appliedGroup = fetchSettingsResult.settings[groupName] || {};
const failedSettings = [];
for (const [key, value] of Object.entries(groupSettings)) {
if (appliedGroup[key] !== value) {
failedSettings.push(`${key} (ожидалось: ${value}, получено: ${appliedGroup[key]})`);
}
}
if (failedSettings.length > 0) {
throw new Error(`Не совпадают параметры: ${failedSettings.join(', ')}`);
}
} catch (groupError) {
errors.push(`Группа ${groupName}: ${groupError.message}`);
}
}
// 3. Показ ошибок, если они есть
if (errors.length > 0) {
const errorMessage = errors.join('\n\n') +
'\n\nНекоторые настройки могли примениться некорректно.\nСтраница будет перезагружена.';
alert(errorMessage);
}
} catch (error) {
alert(`Ошибка при восстановлении настроек: ${error.message}`);
return;
}
// 4. Перезагрузка страницы
location.reload();
},
async dumpAllSettings() {
function downloadAsFile(data, filename) {
let a = document.createElement("a");
let file = new Blob([data], {type: 'application/json'});
a.href = URL.createObjectURL(file);
a.download = filename;
a.click();
}
const response = await fetch('/api/get/settings', { method: 'GET' })
if (response.ok) {
const jres = await response.json()
if (jres["status"] === "ok") {
downloadAsFile(JSON.stringify(jres["settings"], null, 4), "backup-" + this.about.firmwareVersion + "-" + this.about.modemSn + ".json")
}
}
}, // ========== include end from 'common/admin-methods.js.j2' }, // ========== include end from 'common/admin-methods.js.j2'
@@ -1406,7 +1503,6 @@
this.updateRxtxSettings(vals) this.updateRxtxSettings(vals)
this.updateDpdiSettings(vals) this.updateDpdiSettings(vals)
this.updateBuclnbSettings(vals) this.updateBuclnbSettings(vals)
this.updateTcpaccelSettings(vals)
this.updateNetworkSettings(vals) this.updateNetworkSettings(vals)
this.updateQosSettings(vals) this.updateQosSettings(vals)
@@ -1443,11 +1539,11 @@
try { try {
const fr = await fetch("/api/get/aboutFirmware") const fr = await fetch("/api/get/aboutFirmware")
const d = await fr.json() const d = await fr.json()
this.about.firmwareVersion = d["fw.version"] this.about.firmwareVersion = d["firmware"]["version"]
this.about.modemUid = d["fw.modemId"] this.about.modemUid = d["firmware"]["modemId"]
this.about.modemSn = d["fw.modemSn"] this.about.modemSn = d["firmware"]["modemSn"]
this.about.macManagement = d["fw.macMang"] this.about.macManagement = d["firmware"]["macMang"]
this.about.macData = d["fw.macData"] this.about.macData = d["firmware"]["macData"]
} catch (e) { } catch (e) {
console.log('Ошибка загрузки версии ПО', e) console.log('Ошибка загрузки версии ПО', e)
} }

View File

@@ -58,16 +58,8 @@
<table> <table>
<tbody> <tbody>
<tr><th>Прием</th><td><span :class="{ indicator_bad: statRx.state === false, indicator_good: statRx.state === true, indicator: true }"></span></td></tr> <tr><th>Прием</th><td><span :class="{ indicator_bad: statRx.state === false, indicator_good: statRx.state === true, indicator: true }"></span></td></tr>
<tr><th>Захват символьной</th><td><span :class="{ indicator_bad: statRx.sym_sync_lock === false, indicator_good: statRx.sym_sync_lock === true, indicator: true }"></span></td></tr>
<tr><th>Захват ФАПЧ</th><td><span :class="{ indicator_bad: statRx.afc_lock === false, indicator_good: statRx.afc_lock === true, indicator: true }"></span></td></tr>
<tr><th>Захват поиска по частоте</th><td><span :class="{ indicator_bad: statRx.freq_search_lock === false, indicator_good: statRx.freq_search_lock === true, indicator: true }"></span></td></tr>
<tr><th>Захват пакетной синхр.</th><td><span :class="{ indicator_bad: statRx.pkt_sync === false, indicator_good: statRx.pkt_sync === true, indicator: true }"></span></td></tr>
<tr><th>ОСШ/RSSI</th><td>{{ statRx.snr }} / {{ statRx.rssi }}</td></tr> <tr><th>ОСШ/RSSI</th><td>{{ statRx.snr }} / {{ statRx.rssi }}</td></tr>
<tr><th>Modcod</th><td>{{ statRx.modcod }}</td></tr> <tr><th>Частотная ошибка, Гц</th><td>{{ statRx.freqErrAcc }}</td></tr>
<tr><th>Размер кадра</th><td>{{ statRx.frameSizeNormal ? 'normal' : 'short' }}</td></tr>
<tr><th>Пилот-символы</th><td>{{ statRx.isPilots ? 'pilots' : 'no pilots' }}</td></tr>
<tr><th>Символьная ошибка</th><td>{{ statRx.symError }}</td></tr>
<tr><th>Грубая/точная част. ошибка, Гц</th><td>{{ statRx.freqErr }} / {{ statRx.freqErrAcc }}</td></tr>
<tr><th>Ур. входного сигнала</th><td>{{ statRx.inputSignalLevel }}</td></tr> <tr><th>Ур. входного сигнала</th><td>{{ statRx.inputSignalLevel }}</td></tr>
<tr><th>Ошибка ФАПЧ</th><td>{{ statRx.pllError }}</td></tr> <tr><th>Ошибка ФАПЧ</th><td>{{ statRx.pllError }}</td></tr>
<tr><th>Инф. скорость на приеме</th><td>{{ statRx.speedOnRxKbit }} кбит/с</td></tr> <tr><th>Инф. скорость на приеме</th><td>{{ statRx.speedOnRxKbit }} кбит/с</td></tr>
@@ -75,7 +67,6 @@
<tr><td colspan="2" style="padding-top: 1em; text-align: center">Статистика пакетов</td></tr> <tr><td colspan="2" style="padding-top: 1em; text-align: center">Статистика пакетов</td></tr>
<tr><th>Качественных пакетов</th><td>{{ statRx.packetsOk }}</td></tr> <tr><th>Качественных пакетов</th><td>{{ statRx.packetsOk }}</td></tr>
<tr><th>Поврежденных пакетов</th><td>{{ statRx.packetsBad }}</td></tr> <tr><th>Поврежденных пакетов</th><td>{{ statRx.packetsBad }}</td></tr>
<tr><th>DUMMY</th><td>{{ statRx.packetsDummy }}</td></tr>
</tbody> </tbody>
</table> </table>
<button class="action-button" @click="resetPacketsStatistics()"> Сброс статистики </button> <button class="action-button" @click="resetPacketsStatistics()"> Сброс статистики </button>
@@ -85,7 +76,6 @@
<table> <table>
<tbody> <tbody>
<tr><th>Передача</th><td><span :class="{ indicator_bad: statTx.state === false, indicator_good: statTx.state === true, indicator: true }"></span></td></tr> <tr><th>Передача</th><td><span :class="{ indicator_bad: statTx.state === false, indicator_good: statTx.state === true, indicator: true }"></span></td></tr>
<tr><th>Modcod</th><td>{{ statTx.modcod }}</td></tr>
<tr><th>Инф. скорость на передаче</th><td>{{ statTx.speedOnTxKbit }} кбит/с</td></tr> <tr><th>Инф. скорость на передаче</th><td>{{ statTx.speedOnTxKbit }} кбит/с</td></tr>
<tr><th>Инф. скорость на интерфейсе</th><td>{{ statTx.speedOnIifKbit }} кбит/с</td></tr> <tr><th>Инф. скорость на интерфейсе</th><td>{{ statTx.speedOnIifKbit }} кбит/с</td></tr>
<tr><th>Центральная частота</th><td>{{ statTx.centerFreq }} кГц</td></tr> <tr><th>Центральная частота</th><td>{{ statTx.centerFreq }} кГц</td></tr>
@@ -127,6 +117,7 @@
<option :value="true">Тест (CW)</option> <option :value="true">Тест (CW)</option>
</select> </select>
</label> </label>
<label><span>Ослабление, дБ</span><input type="number" v-model="paramRxtx.txAttenuation" min="-40" step="0.25"/></label>
<label> <label>
<span>Входные данные</span> <span>Входные данные</span>
<select v-model="paramRxtx.txIsTestInput"> <select v-model="paramRxtx.txIsTestInput">
@@ -135,28 +126,39 @@
</select> </select>
</label> </label>
<h3>Параметры передачи</h3> <h3>Параметры передачи</h3>
<label><span>Центральная частота, КГц</span><input type="number" v-model="paramRxtx.txCentralFreq" min="950000" max="6000000" step="0.01"/></label> <label>
<label><span>Символьная скорость, Бод</span><input type="number" v-model="paramRxtx.txBaudrate" min="200000" max="54000000"/></label> <span>Центральная частота, КГц</span>
<input type="text" v-model.lazy="paramRxtx.txCentralFreq" @change="e => paramRxtx.txCentralFreq = inputFormatNumber(inputFormatNumber(e.target.value, {min:70000,max:6000000,step:100}), {min:70000,max:6000000,step:100})"/>
</label>
<label>
<span>Символьная скорость, Бод</span>
<input type="text" v-model.lazy="paramRxtx.txBaudrate" @change="e => paramRxtx.txBaudrate = inputFormatNumber(inputFormatNumber(e.target.value, {min:128000,max:30000000,}), {min:128000,max:30000000,})"/>
</label>
<label> <label>
<span>Roll-off</span> <span>Roll-off</span>
<select v-model="paramRxtx.txRolloff"> <select v-model="paramRxtx.txRolloff">
<option :value="2">0.02</option> <option :value="20">0.02</option>
<option :value="5">0.05</option> <option :value="50">0.05</option>
<option :value="10">0.10</option> <option :value="100">0.10</option>
<option :value="15">0.15</option> <option :value="150">0.15</option>
<option :value="20">0.20</option> <option :value="200">0.20</option>
<option :value="25">0.25</option> <option :value="250">0.25</option>
<option :value="300">0.30</option>
<option :value="350">0.35</option>
</select> </select>
</label> </label>
<label><span>Коэф. расширения</span><input type="number" v-model="paramRxtx.txSpreadCoef" min="-1000" max="1000" step="0.01"/></label> <label><span>Коэф. расширения</span><input type="number" v-model="paramRxtx.txSpreadCoef" min="8" max="1024" step="2"/></label>
<label><span>Кол-во пакетов на преамбулу</span><input type="number" v-model="paramRxtx.txFieldsDataPreamble" min="1" max="255" step="1"/></label>
</div>
<div class="settings-set-container">
<h3>Авто-регулировка мощности</h3>
<label> <label>
<span>Номер последовательности Голда</span> <span>Авто-регулировка мощности</span>
<select v-model="paramRxtx.txGoldan"> <span class="toggle-input"><input type="checkbox" v-model="paramRxtx.aupcEn" /><span class="slider"></span></span>
<option :value="0">0</option>
<option :value="1">1</option>
</select>
</label> </label>
<label><span>Ослабление, дБ</span><input type="number" v-model="paramRxtx.txAttenuation" min="-40" step="0.25"/></label> <label><span>Минимальное ослабление, дБ</span><input type="number" v-model="paramRxtx.aupcMinAttenuation" max="10" step="0.1"/></label>
<label><span>Максимальное ослабление, дБ</span><input type="number" v-model="paramRxtx.aupcMaxAttenuation" max="10" step="0.1"/></label>
<label><span>Требуемое ОСШ</span><input type="number" v-model="paramRxtx.aupcRequiredSnr" max="30" step="0.01"/></label>
</div> </div>
<div class="settings-set-container"> <div class="settings-set-container">
<h3>Настройки приемника</h3> <h3>Настройки приемника</h3>
@@ -175,27 +177,30 @@
<span>Инверсия спектра</span> <span>Инверсия спектра</span>
<span class="toggle-input"><input type="checkbox" v-model="paramRxtx.rxSpectrumInversion" /><span class="slider"></span></span> <span class="toggle-input"><input type="checkbox" v-model="paramRxtx.rxSpectrumInversion" /><span class="slider"></span></span>
</label> </label>
<label><span>Центральная частота, КГц</span><input type="number" v-model="paramRxtx.rxCentralFreq" min="950000" max="6000000" step="0.01"/></label> <label>
<label><span>Символьная скорость, Бод</span><input type="number" v-model="paramRxtx.rxBaudrate" min="200000" max="54000000"/></label> <span>Центральная частота, КГц</span>
<input type="text" v-model.lazy="paramRxtx.rxCentralFreq" @change="e => paramRxtx.rxCentralFreq = inputFormatNumber(inputFormatNumber(e.target.value, {min:70000,max:6000000,step:100}), {min:70000,max:6000000,step:100})"/>
</label>
<label>
<span>Символьная скорость, Бод</span>
<input type="text" v-model.lazy="paramRxtx.rxBaudrate" @change="e => paramRxtx.rxBaudrate = inputFormatNumber(inputFormatNumber(e.target.value, {min:128000,max:30000000,}), {min:128000,max:30000000,})"/>
</label>
<label> <label>
<span>Roll-off</span> <span>Roll-off</span>
<select v-model="paramRxtx.rxRolloff"> <select v-model="paramRxtx.rxRolloff">
<option :value="2">0.02</option> <option :value="20">0.02</option>
<option :value="5">0.05</option> <option :value="50">0.05</option>
<option :value="10">0.10</option> <option :value="100">0.10</option>
<option :value="15">0.15</option> <option :value="150">0.15</option>
<option :value="20">0.20</option> <option :value="200">0.20</option>
<option :value="25">0.25</option> <option :value="250">0.25</option>
</select> <option :value="300">0.30</option>
</label> <option :value="350">0.35</option>
<label><span>Коэф. расширения</span><input type="number" v-model="paramRxtx.rxSpreadCoef" min="-1000" max="1000" step="0.01"/></label>
<label>
<span>Номер последовательности Голда</span>
<select v-model="paramRxtx.rxGoldan">
<option :value="0">0</option>
<option :value="1">1</option>
</select> </select>
</label> </label>
<label><span>Коэф. расширения</span><input type="number" v-model="paramRxtx.rxSpreadCoef" min="8" max="1024" step="2"/></label>
<label><span>Порог коррелятора</span><input type="number" v-model="paramRxtx.rxFftShift" min="1" max="10" step="0.125"/></label>
<label><span>Кол-во пакетов на преамбулу</span><input type="number" v-model="paramRxtx.rxFieldsDataPreamble" min="1" max="255" step="1"/></label>
</div> </div>
</div> </div>
<button class="action-button" @click="settingsSubmitRxtx()">Сохранить <span class="submit-spinner" v-show="submitStatus.rxtx"></span></button> <button class="action-button" @click="settingsSubmitRxtx()">Сохранить <span class="submit-spinner" v-show="submitStatus.rxtx"></span></button>
@@ -246,6 +251,31 @@
</div> </div>
<button class="action-button" @click="settingsSubmitBuclnb()">Сохранить <span class="submit-spinner" v-show="submitStatus.buclnb"></span></button> <button class="action-button" @click="settingsSubmitBuclnb()">Сохранить <span class="submit-spinner" v-show="submitStatus.buclnb"></span></button>
</div> <div class="tabs-body-item" v-if="activeTab === 'admin' && settingFetchComplete"> </div> <div class="tabs-body-item" v-if="activeTab === 'admin' && settingFetchComplete">
<h2>Настройки сети</h2>
<div class="settings-set-container">
<h3>Настройки интерфейса управления</h3>
<label>
<span>Интерфейс управления (a.d.d.r/mask)</span>
<input v-model="paramNetwork.managementIp" required type="text" pattern="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\/([0-9]|[1-2][0-9]|3[0-2])$">
</label>
<label>
<span>Режим сети</span>
<select v-model="paramNetwork.isL2">
<option :value="false">Маршрутизатор</option>
<option :value="true">Коммутатор</option>
</select>
</label>
<label v-show="paramNetwork.isL2 === false">
<span>Интерфейс данных (/24)</span>
<input v-model="paramNetwork.dataIp" required type="text" pattern="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$">
</label>
<label><span>MTU интерфейса данных</span><input type="number" v-model="paramNetwork.dataMtu" min="1500" max="2000" step="1"/></label>
<label>
<span>Имя веб-сервера</span>
<input v-model="paramNetwork.serverName" type="text">
</label>
</div>
<button class="action-button" @click="settingsSubmitNetwork()">Сохранить <span class="submit-spinner" v-show="submitStatus.network"></span></button>
<h2>Система</h2> <h2>Система</h2>
<div class="settings-set-container statistics-container"> <div class="settings-set-container statistics-container">
@@ -264,6 +294,8 @@
<div> <div>
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button> <button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
</div> </div>
<button class="action-button" @click="dumpAllSettings()">Сохранить бекап конфигурации</button>
<button class="dangerous-button" @click="restoreAllSettings()">Восстановить бекап конфигурации</button>
</div> </div>
<h2>Обновление ПО</h2> <h2>Обновление ПО</h2>
@@ -316,6 +348,7 @@
submitStatus: { submitStatus: {
rxtx: false, rxtx: false,
buclnb: false, buclnb: false,
network: false,
firmwareUpload: false, firmwareUpload: false,
firmwareUpgrade: false, firmwareUpgrade: false,
// когда модем перезагружается, тут должен быть счетчик. Направление счета - к нулю // когда модем перезагружается, тут должен быть счетчик. Направление счета - к нулю
@@ -327,21 +360,26 @@
txEn: false, txEn: false,
txAutoStart: false, txAutoStart: false,
txModulatorIsTest: false, txModulatorIsTest: false,
txIsTestInput: false,
txCentralFreq: 950000,
txBaudrate: 200000,
txRolloff: 2,
txSpreadCoef: -1000,
txGoldan: 0,
txAttenuation: -40, txAttenuation: -40,
txIsTestInput: false,
txCentralFreq: 0,
txBaudrate: 0,
txRolloff: 20,
txSpreadCoef: 8,
txFieldsDataPreamble: 1,
aupcEn: false,
aupcMinAttenuation: 0,
aupcMaxAttenuation: 0,
aupcRequiredSnr: 0,
rxAgcEn: false, rxAgcEn: false,
rxManualGain: -40, rxManualGain: -40,
rxSpectrumInversion: false, rxSpectrumInversion: false,
rxCentralFreq: 950000, rxCentralFreq: 0,
rxBaudrate: 200000, rxBaudrate: 0,
rxRolloff: 2, rxRolloff: 20,
rxSpreadCoef: -1000, rxSpreadCoef: 8,
rxGoldan: 0, rxFftShift: 1,
rxFieldsDataPreamble: 1,
}, },
paramBuclnb: { paramBuclnb: {
bucRefClk10M: false, bucRefClk10M: false,
@@ -351,6 +389,13 @@
srvRefClk10M: false, srvRefClk10M: false,
bucLnbAutoStart: false, bucLnbAutoStart: false,
}, },
paramNetwork: {
managementIp: null,
isL2: false,
dataIp: null,
dataMtu: 1500,
serverName: null,
},
// ========== include end from 'common/all-params-data.js.j2' // ========== include end from 'common/all-params-data.js.j2'
// ========== include from 'common/monitoring-data.js.j2' // ========== include from 'common/monitoring-data.js.j2'
@@ -468,21 +513,26 @@
"txEn": this.paramRxtx.txEn, "txEn": this.paramRxtx.txEn,
"txAutoStart": this.paramRxtx.txAutoStart, "txAutoStart": this.paramRxtx.txAutoStart,
"txModulatorIsTest": this.paramRxtx.txModulatorIsTest, "txModulatorIsTest": this.paramRxtx.txModulatorIsTest,
"txAttenuation": this.paramRxtx.txAttenuation,
"txIsTestInput": this.paramRxtx.txIsTestInput, "txIsTestInput": this.paramRxtx.txIsTestInput,
"txCentralFreq": this.paramRxtx.txCentralFreq, "txCentralFreq": parseFloat(this.paramRxtx.txCentralFreq.replace(/[^0-9,.]/g, '').replace(',', '.')),
"txBaudrate": this.paramRxtx.txBaudrate, "txBaudrate": parseFloat(this.paramRxtx.txBaudrate.replace(/[^0-9,.]/g, '').replace(',', '.')),
"txRolloff": this.paramRxtx.txRolloff, "txRolloff": this.paramRxtx.txRolloff,
"txSpreadCoef": this.paramRxtx.txSpreadCoef, "txSpreadCoef": this.paramRxtx.txSpreadCoef,
"txGoldan": this.paramRxtx.txGoldan, "txFieldsDataPreamble": this.paramRxtx.txFieldsDataPreamble,
"txAttenuation": this.paramRxtx.txAttenuation, "aupcEn": this.paramRxtx.aupcEn,
"aupcMinAttenuation": this.paramRxtx.aupcMinAttenuation,
"aupcMaxAttenuation": this.paramRxtx.aupcMaxAttenuation,
"aupcRequiredSnr": this.paramRxtx.aupcRequiredSnr,
"rxAgcEn": this.paramRxtx.rxAgcEn, "rxAgcEn": this.paramRxtx.rxAgcEn,
"rxManualGain": this.paramRxtx.rxManualGain, "rxManualGain": this.paramRxtx.rxManualGain,
"rxSpectrumInversion": this.paramRxtx.rxSpectrumInversion, "rxSpectrumInversion": this.paramRxtx.rxSpectrumInversion,
"rxCentralFreq": this.paramRxtx.rxCentralFreq, "rxCentralFreq": parseFloat(this.paramRxtx.rxCentralFreq.replace(/[^0-9,.]/g, '').replace(',', '.')),
"rxBaudrate": this.paramRxtx.rxBaudrate, "rxBaudrate": parseFloat(this.paramRxtx.rxBaudrate.replace(/[^0-9,.]/g, '').replace(',', '.')),
"rxRolloff": this.paramRxtx.rxRolloff, "rxRolloff": this.paramRxtx.rxRolloff,
"rxSpreadCoef": this.paramRxtx.rxSpreadCoef, "rxSpreadCoef": this.paramRxtx.rxSpreadCoef,
"rxGoldan": this.paramRxtx.rxGoldan, "rxFftShift": this.paramRxtx.rxFftShift,
"rxFieldsDataPreamble": this.paramRxtx.rxFieldsDataPreamble,
} }
this.submitStatus.rxtx = true this.submitStatus.rxtx = true
@@ -510,36 +560,67 @@
.catch((reason) => { alert(`Ошибка при применении настроек: ${reason}`) }) .catch((reason) => { alert(`Ошибка при применении настроек: ${reason}`) })
.finally(() => { this.submitStatus.buclnb = false }) .finally(() => { this.submitStatus.buclnb = false })
}, },
settingsSubmitNetwork() {
if (this.submitStatus.network) { return }
{ if (!confirm("Применение этих настроек может сделать модем недоступным! Продолжить?")) return }
let query = {
"managementIp": this.paramNetwork.managementIp,
"isL2": this.paramNetwork.isL2,
"dataIp": this.paramNetwork.dataIp,
"dataMtu": this.paramNetwork.dataMtu,
"serverName": this.paramNetwork.serverName,
}
this.submitStatus.network = true
fetch('/api/set/network', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(query), credentials: 'same-origin' })
.then(async (resp) => { let vals = await resp.json(); if (vals['status'] !== 'ok') { throw new Error(vals['error'] ? vals['error'] : "Server returns undefined error") } this.updateNetworkSettings(vals) })
.catch((reason) => { alert(`Ошибка при применении настроек: ${reason}`) })
.finally(() => { this.submitStatus.network = false })
},
updateRxtxSettings(vals) { updateRxtxSettings(vals) {
this.submitStatus.rxtx = false this.submitStatus.rxtx = false
this.paramRxtx.txEn = vals["settings"]["txEn"] this.paramRxtx.txEn = vals["settings"]["rxtx"]["txEn"]
this.paramRxtx.txAutoStart = vals["settings"]["txAutoStart"] this.paramRxtx.txAutoStart = vals["settings"]["rxtx"]["txAutoStart"]
this.paramRxtx.txModulatorIsTest = vals["settings"]["txModulatorIsTest"] this.paramRxtx.txModulatorIsTest = vals["settings"]["rxtx"]["txModulatorIsTest"]
this.paramRxtx.txIsTestInput = vals["settings"]["txIsTestInput"] this.paramRxtx.txAttenuation = vals["settings"]["rxtx"]["txAttenuation"]
this.paramRxtx.txCentralFreq = vals["settings"]["txCentralFreq"] this.paramRxtx.txIsTestInput = vals["settings"]["rxtx"]["txIsTestInput"]
this.paramRxtx.txBaudrate = vals["settings"]["txBaudrate"] this.paramRxtx.txCentralFreq = this.inputFormatNumber(vals["settings"]["rxtx"]["txCentralFreq"], {min:70000,max:6000000,step:100})
this.paramRxtx.txRolloff = vals["settings"]["txRolloff"] this.paramRxtx.txBaudrate = this.inputFormatNumber(vals["settings"]["rxtx"]["txBaudrate"], {min:128000,max:30000000,})
this.paramRxtx.txSpreadCoef = vals["settings"]["txSpreadCoef"] this.paramRxtx.txRolloff = vals["settings"]["rxtx"]["txRolloff"]
this.paramRxtx.txGoldan = vals["settings"]["txGoldan"] this.paramRxtx.txSpreadCoef = vals["settings"]["rxtx"]["txSpreadCoef"]
this.paramRxtx.txAttenuation = vals["settings"]["txAttenuation"] this.paramRxtx.txFieldsDataPreamble = vals["settings"]["rxtx"]["txFieldsDataPreamble"]
this.paramRxtx.rxAgcEn = vals["settings"]["rxAgcEn"] this.paramRxtx.aupcEn = vals["settings"]["rxtx"]["aupcEn"]
this.paramRxtx.rxManualGain = vals["settings"]["rxManualGain"] this.paramRxtx.aupcMinAttenuation = vals["settings"]["rxtx"]["aupcMinAttenuation"]
this.paramRxtx.rxSpectrumInversion = vals["settings"]["rxSpectrumInversion"] this.paramRxtx.aupcMaxAttenuation = vals["settings"]["rxtx"]["aupcMaxAttenuation"]
this.paramRxtx.rxCentralFreq = vals["settings"]["rxCentralFreq"] this.paramRxtx.aupcRequiredSnr = vals["settings"]["rxtx"]["aupcRequiredSnr"]
this.paramRxtx.rxBaudrate = vals["settings"]["rxBaudrate"] this.paramRxtx.rxAgcEn = vals["settings"]["rxtx"]["rxAgcEn"]
this.paramRxtx.rxRolloff = vals["settings"]["rxRolloff"] this.paramRxtx.rxManualGain = vals["settings"]["rxtx"]["rxManualGain"]
this.paramRxtx.rxSpreadCoef = vals["settings"]["rxSpreadCoef"] this.paramRxtx.rxSpectrumInversion = vals["settings"]["rxtx"]["rxSpectrumInversion"]
this.paramRxtx.rxGoldan = vals["settings"]["rxGoldan"] this.paramRxtx.rxCentralFreq = this.inputFormatNumber(vals["settings"]["rxtx"]["rxCentralFreq"], {min:70000,max:6000000,step:100})
this.paramRxtx.rxBaudrate = this.inputFormatNumber(vals["settings"]["rxtx"]["rxBaudrate"], {min:128000,max:30000000,})
this.paramRxtx.rxRolloff = vals["settings"]["rxtx"]["rxRolloff"]
this.paramRxtx.rxSpreadCoef = vals["settings"]["rxtx"]["rxSpreadCoef"]
this.paramRxtx.rxFftShift = vals["settings"]["rxtx"]["rxFftShift"]
this.paramRxtx.rxFieldsDataPreamble = vals["settings"]["rxtx"]["rxFieldsDataPreamble"]
}, },
updateBuclnbSettings(vals) { updateBuclnbSettings(vals) {
this.submitStatus.buclnb = false this.submitStatus.buclnb = false
this.paramBuclnb.bucRefClk10M = vals["settings"]["bucRefClk10M"] this.paramBuclnb.bucRefClk10M = vals["settings"]["buclnb"]["bucRefClk10M"]
this.paramBuclnb.bucPowering = vals["settings"]["bucPowering"] this.paramBuclnb.bucPowering = vals["settings"]["buclnb"]["bucPowering"]
this.paramBuclnb.lnbRefClk10M = vals["settings"]["lnbRefClk10M"] this.paramBuclnb.lnbRefClk10M = vals["settings"]["buclnb"]["lnbRefClk10M"]
this.paramBuclnb.lnbPowering = vals["settings"]["lnbPowering"] this.paramBuclnb.lnbPowering = vals["settings"]["buclnb"]["lnbPowering"]
this.paramBuclnb.srvRefClk10M = vals["settings"]["srvRefClk10M"] this.paramBuclnb.srvRefClk10M = vals["settings"]["buclnb"]["srvRefClk10M"]
this.paramBuclnb.bucLnbAutoStart = vals["settings"]["bucLnbAutoStart"] this.paramBuclnb.bucLnbAutoStart = vals["settings"]["buclnb"]["bucLnbAutoStart"]
},
updateNetworkSettings(vals) {
this.submitStatus.network = false
this.paramNetwork.managementIp = vals["settings"]["network"]["managementIp"]
this.paramNetwork.isL2 = vals["settings"]["network"]["isL2"]
this.paramNetwork.dataIp = vals["settings"]["network"]["dataIp"]
this.paramNetwork.dataMtu = vals["settings"]["network"]["dataMtu"]
this.paramNetwork.serverName = vals["settings"]["network"]["serverName"]
}, },
// ========== include end from 'common/all-params-methods.js.j2' // ========== include end from 'common/all-params-methods.js.j2'
@@ -564,44 +645,43 @@
} }
this.lastUpdateTime = new Date(); this.lastUpdateTime = new Date();
this.initState = vals["mainState"]["initState"] this.initState = vals["state"]["initState"]
this.testState = vals["state"]["testState"]
this.statRx.state = vals["mainState"]["rx.state"] this.statRx.state = vals["state"]["rx"]["state"]
this.statRx.sym_sync_lock = vals["mainState"]["rx.sym_sync_lock"] this.statRx.sym_sync_lock = vals["state"]["rx"]["sym_sync_lock"]
this.statRx.freq_search_lock = vals["mainState"]["rx.freq_search_lock"] this.statRx.freq_search_lock = vals["state"]["rx"]["freq_search_lock"]
this.statRx.afc_lock = vals["mainState"]["rx.afc_lock"] this.statRx.afc_lock = vals["state"]["rx"]["afc_lock"]
this.statRx.pkt_sync = vals["mainState"]["rx.pkt_sync"] this.statRx.pkt_sync = vals["state"]["rx"]["pkt_sync"]
this.statRx.snr = vals["mainState"]["rx.snr"] this.statRx.snr = Math.round(vals["state"]["rx"]["snr"] * 10) / 10
this.statRx.rssi = vals["mainState"]["rx.rssi"] this.statRx.rssi = Math.round(vals["state"]["rx"]["rssi"] * 10) / 10
this.statRx.modcod = modcodToStr(vals["mainState"]["rx.modcod"]) this.statRx.modcod = modcodToStr(vals["state"]["rx"]["modcod"])
this.statRx.frameSizeNormal = vals["mainState"]["rx.frameSizeNormal"] this.statRx.frameSizeNormal = vals["state"]["rx"]["frameSizeNormal"]
this.statRx.isPilots = vals["mainState"]["rx.isPilots"] this.statRx.isPilots = vals["state"]["rx"]["isPilots"]
this.statRx.symError = vals["mainState"]["rx.symError"] this.statRx.symError = vals["state"]["rx"]["symError"]
this.statRx.freqErr = vals["mainState"]["rx.freqErr"] this.statRx.freqErr = Math.round(vals["state"]["rx"]["freqErr"] * 100) / 100
this.statRx.freqErrAcc = vals["mainState"]["rx.freqErrAcc"] this.statRx.freqErrAcc = Math.round(vals["state"]["rx"]["freqErrAcc"] * 100) / 100
this.statRx.inputSignalLevel = vals["mainState"]["rx.inputSignalLevel"] this.statRx.inputSignalLevel = vals["state"]["rx"]["inputSignalLevel"]
this.statRx.pllError = vals["mainState"]["rx.pllError"] this.statRx.pllError = Math.round(vals["state"]["rx"]["pllError"] * 100) / 100
this.statRx.speedOnRxKbit = vals["mainState"]["rx.speedOnRxKbit"] this.statRx.speedOnRxKbit = Math.round(vals["state"]["rx"]["speedOnRxKbit"] * 100) / 100
this.statRx.speedOnIifKbit = vals["mainState"]["rx.speedOnIifKbit"] this.statRx.speedOnIifKbit = Math.round(vals["state"]["rx"]["speedOnIifKbit"] * 100) / 100
this.statRx.packetsOk = vals["mainState"]["rx.packetsOk"] this.statRx.packetsOk = vals["state"]["rx"]["packetsOk"]
this.statRx.packetsBad = vals["mainState"]["rx.packetsBad"] this.statRx.packetsBad = vals["state"]["rx"]["packetsBad"]
this.statRx.packetsDummy = vals["mainState"]["rx.packetsDummy"] this.statRx.packetsDummy = vals["state"]["rx"]["packetsDummy"]
this.statTx.state = vals["mainState"]["tx.state"] this.statTx.state = vals["state"]["tx"]["state"]
this.statTx.modcod = modcodToStr(vals["mainState"]["tx.modcod"]) this.statTx.modcod = modcodToStr(vals["state"]["tx"]["modcod"])
this.statTx.speedOnTxKbit = vals["mainState"]["tx.speedOnTxKbit"] this.statTx.speedOnTxKbit = Math.round(vals["state"]["tx"]["speedOnTxKbit"] * 100) / 100
this.statTx.speedOnIifKbit = vals["mainState"]["tx.speedOnIifKbit"] this.statTx.speedOnIifKbit = Math.round(vals["state"]["tx"]["speedOnIifKbit"] * 100) / 100
this.statTx.centerFreq = vals["mainState"]["tx.centerFreq"] this.statTx.centerFreq = vals["state"]["tx"]["centerFreq"]
this.statTx.symSpeed = vals["mainState"]["tx.symSpeed"] this.statTx.symSpeed = vals["state"]["tx"]["symSpeed"]
this.statDevice.adrv = vals["mainState"]["device.adrv"] this.statDevice.adrv = vals["state"]["device"]["adrv"]
this.statDevice.zynq = vals["mainState"]["device.zynq"] this.statDevice.zynq = vals["state"]["device"]["zynq"]
this.statDevice.fpga = vals["mainState"]["device.fpga"] this.statDevice.fpga = vals["state"]["device"]["fpga"]
this.testState = vals["mainState"]["testState"]
// аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид // аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид
let uptime = vals["sysinfo"]["uptime"] let uptime = vals["state"]["device"]["uptime"]
if (uptime) { if (uptime) {
let secs = uptime % 60; uptime = Math.floor(uptime / 60) let secs = uptime % 60; uptime = Math.floor(uptime / 60)
let mins = uptime % 60; uptime = Math.floor(uptime / 60) let mins = uptime % 60; uptime = Math.floor(uptime / 60)
@@ -613,11 +693,11 @@
} else { } else {
this.statOs.uptime = '?' this.statOs.uptime = '?'
} }
this.statOs.load1 = vals["sysinfo"]["load1min"] this.statOs.load1 = Math.round(vals["state"]["device"]["load1min"] * 100) / 100
this.statOs.load5 = vals["sysinfo"]["load5min"] this.statOs.load5 = Math.round(vals["state"]["device"]["load5min"] * 100) / 100
this.statOs.load15 = vals["sysinfo"]["load15min"] this.statOs.load15 = Math.round(vals["state"]["device"]["load15min"] * 100) / 100
this.statOs.totalram = vals["sysinfo"]["totalram"] this.statOs.totalram = vals["state"]["device"]["totalram"]
this.statOs.freeram = vals["sysinfo"]["freeram"] this.statOs.freeram = vals["state"]["device"]["freeram"]
}, },
resetPacketsStatistics() { resetPacketsStatistics() {
@@ -696,6 +776,133 @@
} }
this.submitStatus.modemReboot = 30 this.submitStatus.modemReboot = 30
fetch('/api/reboot', { method: 'POST' }).then((r) => {}) fetch('/api/reboot', { method: 'POST' }).then((r) => {})
},
async restoreAllSettings() {
// Порядок применения настроек
const settingsApplyOrder = ['qos', 'tcpaccel', 'dpdi', 'rxtx', 'buclnb', 'network'];
// 1. Чтение JSON-файла, выбранного пользователем
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = '.json';
const filePromise = new Promise((resolve, reject) => {
fileInput.onchange = e => {
const file = e.target.files[0];
if (!file) {
reject(new Error('Файл не выбран'));
return;
}
const reader = new FileReader();
reader.onload = event => {
try {
const jsonData = JSON.parse(event.target.result);
resolve(jsonData);
} catch (error) {
reject(new Error('Ошибка парсинга JSON'));
}
};
reader.onerror = () => reject(new Error('Ошибка чтения файла'));
reader.readAsText(file);
};
fileInput.click();
});
try {
const settingsToApply = await filePromise;
const errors = [];
// 2. Перебор групп параметров в заданном порядке
for (const groupName of settingsApplyOrder) {
if (!settingsToApply.hasOwnProperty(groupName)) {
continue; // Пропускаем группы, которых нет в файле
}
const groupSettings = settingsToApply[groupName];
if (typeof groupSettings !== 'object' || groupSettings === null) {
continue;
}
try {
// 2.1. POST-запрос для применения группы параметров
const postResponse = await fetch(`/api/set/${groupName}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(groupSettings)
});
if (!postResponse.ok) {
throw new Error(`HTTP error ${postResponse.status}`);
}
const postResult = await postResponse.json();
if (postResult.status !== 'ok') {
throw new Error(`API error: ${postResult.message || 'unknown error'}`);
}
// 2.2. Проверка примененных параметров
const getResponse = await fetch('/api/get/settings', { method: 'GET' });
if (!getResponse.ok) {
throw new Error(`HTTP error ${getResponse.status}`);
}
const fetchSettingsResult = await getResponse.json();
if (fetchSettingsResult.status !== 'ok') {
throw new Error('Не удалось получить текущие настройки');
}
// Проверка соответствия параметров
const appliedGroup = fetchSettingsResult.settings[groupName] || {};
const failedSettings = [];
for (const [key, value] of Object.entries(groupSettings)) {
if (appliedGroup[key] !== value) {
failedSettings.push(`${key} (ожидалось: ${value}, получено: ${appliedGroup[key]})`);
}
}
if (failedSettings.length > 0) {
throw new Error(`Не совпадают параметры: ${failedSettings.join(', ')}`);
}
} catch (groupError) {
errors.push(`Группа ${groupName}: ${groupError.message}`);
}
}
// 3. Показ ошибок, если они есть
if (errors.length > 0) {
const errorMessage = errors.join('\n\n') +
'\n\nНекоторые настройки могли примениться некорректно.\nСтраница будет перезагружена.';
alert(errorMessage);
}
} catch (error) {
alert(`Ошибка при восстановлении настроек: ${error.message}`);
return;
}
// 4. Перезагрузка страницы
location.reload();
},
async dumpAllSettings() {
function downloadAsFile(data, filename) {
let a = document.createElement("a");
let file = new Blob([data], {type: 'application/json'});
a.href = URL.createObjectURL(file);
a.download = filename;
a.click();
}
const response = await fetch('/api/get/settings', { method: 'GET' })
if (response.ok) {
const jres = await response.json()
if (jres["status"] === "ok") {
downloadAsFile(JSON.stringify(jres["settings"], null, 4), "backup-" + this.about.firmwareVersion + "-" + this.about.modemSn + ".json")
}
}
}, // ========== include end from 'common/admin-methods.js.j2' }, // ========== include end from 'common/admin-methods.js.j2'
@@ -706,6 +913,7 @@
this.settingFetchComplete = true this.settingFetchComplete = true
this.updateRxtxSettings(vals) this.updateRxtxSettings(vals)
this.updateBuclnbSettings(vals) this.updateBuclnbSettings(vals)
this.updateNetworkSettings(vals)
if ('netServerName' in vals['settings']) { if ('netServerName' in vals['settings']) {
document.getElementsByTagName('title')[0].innerText = vals['settings']['netServerName'] document.getElementsByTagName('title')[0].innerText = vals['settings']['netServerName']
@@ -740,11 +948,11 @@
try { try {
const fr = await fetch("/api/get/aboutFirmware") const fr = await fetch("/api/get/aboutFirmware")
const d = await fr.json() const d = await fr.json()
this.about.firmwareVersion = d["fw.version"] this.about.firmwareVersion = d["firmware"]["version"]
this.about.modemUid = d["fw.modemId"] this.about.modemUid = d["firmware"]["modemId"]
this.about.modemSn = d["fw.modemSn"] this.about.modemSn = d["firmware"]["modemSn"]
this.about.macManagement = d["fw.macMang"] this.about.macManagement = d["firmware"]["macMang"]
this.about.macData = d["fw.macData"] this.about.macData = d["firmware"]["macData"]
} catch (e) { } catch (e) {
console.log('Ошибка загрузки версии ПО', e) console.log('Ошибка загрузки версии ПО', e)
} }

View File

@@ -132,6 +132,7 @@
<input type="text" v-model.lazy="paramRxtx.txCentralFreq" @change="e => paramRxtx.txCentralFreq = inputFormatNumber(inputFormatNumber(e.target.value, {min:900000,step:0.01}), {min:900000,step:0.01})"/> <input type="text" v-model.lazy="paramRxtx.txCentralFreq" @change="e => paramRxtx.txCentralFreq = inputFormatNumber(inputFormatNumber(e.target.value, {min:900000,step:0.01}), {min:900000,step:0.01})"/>
</label> </label>
<label><span>Ослабление, дБ</span><input type="number" v-model="paramRxtx.txAttenuation" min="-90" step="1"/></label> <label><span>Ослабление, дБ</span><input type="number" v-model="paramRxtx.txAttenuation" min="-90" step="1"/></label>
<label><span>Ограничение ослабления</span><input type="number" v-model="paramRxtx.txAttenuationLimit" min="-40" step="0.25"/></label>
</div> </div>
<div class="settings-set-container"> <div class="settings-set-container">
<h3>Настройки приемника</h3> <h3>Настройки приемника</h3>
@@ -158,12 +159,12 @@
<label> <label>
<span>Roll-off</span> <span>Roll-off</span>
<select v-model="paramRxtx.rxRolloff"> <select v-model="paramRxtx.rxRolloff">
<option :value="2">0.02</option> <option :value="20">0.02</option>
<option :value="5">0.05</option> <option :value="50">0.05</option>
<option :value="10">0.10</option> <option :value="100">0.10</option>
<option :value="15">0.15</option> <option :value="150">0.15</option>
<option :value="20">0.20</option> <option :value="200">0.20</option>
<option :value="25">0.25</option> <option :value="250">0.25</option>
</select> </select>
</label> </label>
</div> </div>
@@ -173,16 +174,16 @@
<div class="settings-set-container"> <div class="settings-set-container">
<label> <label>
<span>Метод расчета задержки</span> <span>Метод расчета задержки</span>
<select v-model="paramDpdi.dpdiIsPositional"> <select v-model="paramDpdi.isPositional">
<option :value="true">Позиционированием</option> <option :value="true">Позиционированием</option>
<option :value="false">Окном задержки</option> <option :value="false">Окном задержки</option>
</select> </select>
</label> </label>
<h2 v-show="paramDpdi.dpdiIsPositional === true">Настройки позиционирования</h2> <h2 v-show="paramDpdi.isPositional === true">Настройки позиционирования</h2>
<label v-show="paramDpdi.dpdiIsPositional === true"><span>Широта станции</span><input type="number" v-model="paramDpdi.dpdiPositionStationLatitude" min="-180" max="180" step="1e-06"/></label> <label v-show="paramDpdi.isPositional === true"><span>Широта станции</span><input type="number" v-model="paramDpdi.positionStationLatitude" min="-180" max="180" step="1e-06"/></label>
<label v-show="paramDpdi.dpdiIsPositional === true"><span>Долгота станции</span><input type="number" v-model="paramDpdi.dpdiPositionStationLongitude" min="-180" max="180" step="1e-06"/></label> <label v-show="paramDpdi.isPositional === true"><span>Долгота станции</span><input type="number" v-model="paramDpdi.positionStationLongitude" min="-180" max="180" step="1e-06"/></label>
<label v-show="paramDpdi.dpdiIsPositional === true"><span>Подспутниковая точка</span><input type="number" v-model="paramDpdi.dpdiPositionSatelliteLongitude" min="-180" max="180" step="1e-06"/></label> <label v-show="paramDpdi.isPositional === true"><span>Подспутниковая точка</span><input type="number" v-model="paramDpdi.positionSatelliteLongitude" min="-180" max="180" step="1e-06"/></label>
<label v-show="paramDpdi.dpdiIsPositional === false"><span>Задержка до спутника, мс</span><input type="number" v-model="paramDpdi.dpdiDelay" max="400" step="0.1"/></label> <label v-show="paramDpdi.isPositional === false"><span>Задержка до спутника, мс</span><input type="number" v-model="paramDpdi.delay" max="400" step="0.1"/></label>
</div> </div>
<button class="action-button" @click="settingsSubmitDpdi()">Сохранить <span class="submit-spinner" v-show="submitStatus.dpdi"></span></button> <button class="action-button" @click="settingsSubmitDpdi()">Сохранить <span class="submit-spinner" v-show="submitStatus.dpdi"></span></button>
<h2>Настройки питания и опорного генератора</h2> <h2>Настройки питания и опорного генератора</h2>
@@ -200,6 +201,10 @@
<option :value="24">24В</option> <option :value="24">24В</option>
</select> </select>
</label> </label>
<label>
<span>Частота LO, кГц</span>
<input type="text" v-model.lazy="paramBuclnb.bucLoKhz" @change="e => paramBuclnb.bucLoKhz = inputFormatNumber(inputFormatNumber(e.target.value, {max:40000000,step:1}), {max:40000000,step:1})"/>
</label>
</div> </div>
<div class="settings-set-container"> <div class="settings-set-container">
<h3>Настройки LNB</h3> <h3>Настройки LNB</h3>
@@ -216,6 +221,10 @@
<option :value="24">24В</option> <option :value="24">24В</option>
</select> </select>
</label> </label>
<label>
<span>Частота LO, кГц</span>
<input type="text" v-model.lazy="paramBuclnb.lnbLoKhz" @change="e => paramBuclnb.lnbLoKhz = inputFormatNumber(inputFormatNumber(e.target.value, {max:40000000,step:1}), {max:40000000,step:1})"/>
</label>
</div> </div>
<div class="settings-set-container"> <div class="settings-set-container">
<h3>Сервисные настройки</h3> <h3>Сервисные настройки</h3>
@@ -233,18 +242,14 @@
</div> <div class="tabs-body-item" v-if="activeTab === 'admin' && settingFetchComplete"> </div> <div class="tabs-body-item" v-if="activeTab === 'admin' && settingFetchComplete">
<h2>Настройки сети</h2> <h2>Настройки сети</h2>
<div class="settings-set-container"> <div class="settings-set-container">
<label>
<span>Пароль для входа в сеть ЦЗС</span>
<input v-model="paramNetwork.netCesPassword" type="text">
</label>
<h3>Настройки интерфейса управления</h3> <h3>Настройки интерфейса управления</h3>
<label> <label>
<span>IP Интерфейса управления (/24)</span> <span>Интерфейс управления (a.d.d.r/mask)</span>
<input v-model="paramNetwork.netManagementIp" required type="text" pattern="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"> <input v-model="paramNetwork.managementIp" required type="text" pattern="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\/([0-9]|[1-2][0-9]|3[0-2])$">
</label> </label>
<label> <label>
<span>Имя веб-сервера</span> <span>Имя веб-сервера</span>
<input v-model="paramNetwork.netServerName" type="text"> <input v-model="paramNetwork.serverName" type="text">
</label> </label>
</div> </div>
<button class="action-button" @click="settingsSubmitNetwork()">Сохранить <span class="submit-spinner" v-show="submitStatus.network"></span></button> <button class="action-button" @click="settingsSubmitNetwork()">Сохранить <span class="submit-spinner" v-show="submitStatus.network"></span></button>
@@ -266,6 +271,16 @@
<div> <div>
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button> <button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
</div> </div>
<button class="action-button" @click="dumpAllSettings()">Сохранить бекап конфигурации</button>
<button class="dangerous-button" @click="restoreAllSettings()">Восстановить бекап конфигурации</button>
</div>
<h2>Вход в сеть ЦЗС</h2>
<div class="settings-set-container statistics-container">
<label>
<span>Хеш-строка пароля (выдается оператором NMS)</span>
<input v-model="cesPasswordValue" type="text">
</label>
<button class="action-button" @click="settingsPerformSetCesPassword()">Установить пароль<span class="submit-spinner" v-show="submitStatus.cesPassword"></span></button>
</div> </div>
<h2>Обновление ПО</h2> <h2>Обновление ПО</h2>
@@ -325,9 +340,11 @@
firmwareUpload: false, firmwareUpload: false,
firmwareUpgrade: false, firmwareUpgrade: false,
firmwareUpgradeOta: false, firmwareUpgradeOta: false,
cesPassword: false,
// когда модем перезагружается, тут должен быть счетчик. Направление счета - к нулю // когда модем перезагружается, тут должен быть счетчик. Направление счета - к нулю
modemReboot: null modemReboot: null
}, },
cesPasswordValue: '',
// ========== include from 'common/all-params-data.js.j2' // ========== include from 'common/all-params-data.js.j2'
paramRxtx: { paramRxtx: {
@@ -335,32 +352,34 @@
txModulatorIsTest: false, txModulatorIsTest: false,
txCentralFreq: 0, txCentralFreq: 0,
txAttenuation: -90, txAttenuation: -90,
txAttenuationLimit: -40,
rxAgcEn: true, rxAgcEn: true,
rxManualGain: -40, rxManualGain: -40,
rxSpectrumInversion: false, rxSpectrumInversion: false,
rxCentralFreq: 0, rxCentralFreq: 0,
rxBaudrate: 0, rxBaudrate: 0,
rxRolloff: 2, rxRolloff: 20,
}, },
paramBuclnb: { paramBuclnb: {
bucRefClk10M: false, bucRefClk10M: false,
bucPowering: 0, bucPowering: 0,
bucLoKhz: 0,
lnbRefClk10M: false, lnbRefClk10M: false,
lnbPowering: 0, lnbPowering: 0,
lnbLoKhz: 0,
srvRefClk10M: false, srvRefClk10M: false,
bucLnbAutoStart: false, bucLnbAutoStart: false,
}, },
paramDpdi: { paramDpdi: {
dpdiIsPositional: true, isPositional: true,
dpdiPositionStationLatitude: -180, positionStationLatitude: -180,
dpdiPositionStationLongitude: -180, positionStationLongitude: -180,
dpdiPositionSatelliteLongitude: -180, positionSatelliteLongitude: -180,
dpdiDelay: 0, delay: 0,
}, },
paramNetwork: { paramNetwork: {
netCesPassword: null, managementIp: null,
netManagementIp: null, serverName: null,
netServerName: null,
}, },
// ========== include end from 'common/all-params-data.js.j2' // ========== include end from 'common/all-params-data.js.j2'
@@ -482,6 +501,7 @@
"txModulatorIsTest": this.paramRxtx.txModulatorIsTest, "txModulatorIsTest": this.paramRxtx.txModulatorIsTest,
"txCentralFreq": parseFloat(this.paramRxtx.txCentralFreq.replace(/[^0-9,.]/g, '').replace(',', '.')), "txCentralFreq": parseFloat(this.paramRxtx.txCentralFreq.replace(/[^0-9,.]/g, '').replace(',', '.')),
"txAttenuation": this.paramRxtx.txAttenuation, "txAttenuation": this.paramRxtx.txAttenuation,
"txAttenuationLimit": this.paramRxtx.txAttenuationLimit,
"rxAgcEn": this.paramRxtx.rxAgcEn, "rxAgcEn": this.paramRxtx.rxAgcEn,
"rxManualGain": this.paramRxtx.rxManualGain, "rxManualGain": this.paramRxtx.rxManualGain,
"rxSpectrumInversion": this.paramRxtx.rxSpectrumInversion, "rxSpectrumInversion": this.paramRxtx.rxSpectrumInversion,
@@ -503,8 +523,10 @@
let query = { let query = {
"bucRefClk10M": this.paramBuclnb.bucRefClk10M, "bucRefClk10M": this.paramBuclnb.bucRefClk10M,
"bucPowering": this.paramBuclnb.bucPowering, "bucPowering": this.paramBuclnb.bucPowering,
"bucLoKhz": parseFloat(this.paramBuclnb.bucLoKhz.replace(/[^0-9,.]/g, '').replace(',', '.')),
"lnbRefClk10M": this.paramBuclnb.lnbRefClk10M, "lnbRefClk10M": this.paramBuclnb.lnbRefClk10M,
"lnbPowering": this.paramBuclnb.lnbPowering, "lnbPowering": this.paramBuclnb.lnbPowering,
"lnbLoKhz": parseFloat(this.paramBuclnb.lnbLoKhz.replace(/[^0-9,.]/g, '').replace(',', '.')),
"srvRefClk10M": this.paramBuclnb.srvRefClk10M, "srvRefClk10M": this.paramBuclnb.srvRefClk10M,
"bucLnbAutoStart": this.paramBuclnb.bucLnbAutoStart, "bucLnbAutoStart": this.paramBuclnb.bucLnbAutoStart,
} }
@@ -519,11 +541,11 @@
if (this.submitStatus.dpdi) { return } if (this.submitStatus.dpdi) { return }
let query = { let query = {
"dpdiIsPositional": this.paramDpdi.dpdiIsPositional, "isPositional": this.paramDpdi.isPositional,
"dpdiPositionStationLatitude": this.paramDpdi.dpdiPositionStationLatitude, "positionStationLatitude": this.paramDpdi.positionStationLatitude,
"dpdiPositionStationLongitude": this.paramDpdi.dpdiPositionStationLongitude, "positionStationLongitude": this.paramDpdi.positionStationLongitude,
"dpdiPositionSatelliteLongitude": this.paramDpdi.dpdiPositionSatelliteLongitude, "positionSatelliteLongitude": this.paramDpdi.positionSatelliteLongitude,
"dpdiDelay": this.paramDpdi.dpdiDelay, "delay": this.paramDpdi.delay,
} }
this.submitStatus.dpdi = true this.submitStatus.dpdi = true
@@ -537,9 +559,8 @@
{ if (!confirm("Применение этих настроек может сделать модем недоступным! Продолжить?")) return } { if (!confirm("Применение этих настроек может сделать модем недоступным! Продолжить?")) return }
let query = { let query = {
"netCesPassword": this.paramNetwork.netCesPassword, "managementIp": this.paramNetwork.managementIp,
"netManagementIp": this.paramNetwork.netManagementIp, "serverName": this.paramNetwork.serverName,
"netServerName": this.paramNetwork.netServerName,
} }
this.submitStatus.network = true this.submitStatus.network = true
@@ -551,39 +572,41 @@
updateRxtxSettings(vals) { updateRxtxSettings(vals) {
this.submitStatus.rxtx = false this.submitStatus.rxtx = false
this.paramRxtx.txEn = vals["settings"]["txEn"] this.paramRxtx.txEn = vals["settings"]["rxtx"]["txEn"]
this.paramRxtx.txModulatorIsTest = vals["settings"]["txModulatorIsTest"] this.paramRxtx.txModulatorIsTest = vals["settings"]["rxtx"]["txModulatorIsTest"]
this.paramRxtx.txCentralFreq = this.inputFormatNumber(vals["settings"]["txCentralFreq"], {min:900000,step:0.01}) this.paramRxtx.txCentralFreq = this.inputFormatNumber(vals["settings"]["rxtx"]["txCentralFreq"], {min:900000,step:0.01})
this.paramRxtx.txAttenuation = vals["settings"]["txAttenuation"] this.paramRxtx.txAttenuation = vals["settings"]["rxtx"]["txAttenuation"]
this.paramRxtx.rxAgcEn = vals["settings"]["rxAgcEn"] this.paramRxtx.txAttenuationLimit = vals["settings"]["rxtx"]["txAttenuationLimit"]
this.paramRxtx.rxManualGain = vals["settings"]["rxManualGain"] this.paramRxtx.rxAgcEn = vals["settings"]["rxtx"]["rxAgcEn"]
this.paramRxtx.rxSpectrumInversion = vals["settings"]["rxSpectrumInversion"] this.paramRxtx.rxManualGain = vals["settings"]["rxtx"]["rxManualGain"]
this.paramRxtx.rxCentralFreq = this.inputFormatNumber(vals["settings"]["rxCentralFreq"], {min:900000,step:0.01}) this.paramRxtx.rxSpectrumInversion = vals["settings"]["rxtx"]["rxSpectrumInversion"]
this.paramRxtx.rxBaudrate = this.inputFormatNumber(vals["settings"]["rxBaudrate"], {min:200000,max:54000000,step:1}) this.paramRxtx.rxCentralFreq = this.inputFormatNumber(vals["settings"]["rxtx"]["rxCentralFreq"], {min:900000,step:0.01})
this.paramRxtx.rxRolloff = vals["settings"]["rxRolloff"] this.paramRxtx.rxBaudrate = this.inputFormatNumber(vals["settings"]["rxtx"]["rxBaudrate"], {min:200000,max:54000000,step:1})
this.paramRxtx.rxRolloff = vals["settings"]["rxtx"]["rxRolloff"]
}, },
updateBuclnbSettings(vals) { updateBuclnbSettings(vals) {
this.submitStatus.buclnb = false this.submitStatus.buclnb = false
this.paramBuclnb.bucRefClk10M = vals["settings"]["bucRefClk10M"] this.paramBuclnb.bucRefClk10M = vals["settings"]["buclnb"]["bucRefClk10M"]
this.paramBuclnb.bucPowering = vals["settings"]["bucPowering"] this.paramBuclnb.bucPowering = vals["settings"]["buclnb"]["bucPowering"]
this.paramBuclnb.lnbRefClk10M = vals["settings"]["lnbRefClk10M"] this.paramBuclnb.bucLoKhz = this.inputFormatNumber(vals["settings"]["buclnb"]["bucLoKhz"], {max:40000000,step:1})
this.paramBuclnb.lnbPowering = vals["settings"]["lnbPowering"] this.paramBuclnb.lnbRefClk10M = vals["settings"]["buclnb"]["lnbRefClk10M"]
this.paramBuclnb.srvRefClk10M = vals["settings"]["srvRefClk10M"] this.paramBuclnb.lnbPowering = vals["settings"]["buclnb"]["lnbPowering"]
this.paramBuclnb.bucLnbAutoStart = vals["settings"]["bucLnbAutoStart"] this.paramBuclnb.lnbLoKhz = this.inputFormatNumber(vals["settings"]["buclnb"]["lnbLoKhz"], {max:40000000,step:1})
this.paramBuclnb.srvRefClk10M = vals["settings"]["buclnb"]["srvRefClk10M"]
this.paramBuclnb.bucLnbAutoStart = vals["settings"]["buclnb"]["bucLnbAutoStart"]
}, },
updateDpdiSettings(vals) { updateDpdiSettings(vals) {
this.submitStatus.dpdi = false this.submitStatus.dpdi = false
this.paramDpdi.dpdiIsPositional = vals["settings"]["dpdiIsPositional"] this.paramDpdi.isPositional = vals["settings"]["dpdi"]["isPositional"]
this.paramDpdi.dpdiPositionStationLatitude = vals["settings"]["dpdiPositionStationLatitude"] this.paramDpdi.positionStationLatitude = vals["settings"]["dpdi"]["positionStationLatitude"]
this.paramDpdi.dpdiPositionStationLongitude = vals["settings"]["dpdiPositionStationLongitude"] this.paramDpdi.positionStationLongitude = vals["settings"]["dpdi"]["positionStationLongitude"]
this.paramDpdi.dpdiPositionSatelliteLongitude = vals["settings"]["dpdiPositionSatelliteLongitude"] this.paramDpdi.positionSatelliteLongitude = vals["settings"]["dpdi"]["positionSatelliteLongitude"]
this.paramDpdi.dpdiDelay = vals["settings"]["dpdiDelay"] this.paramDpdi.delay = vals["settings"]["dpdi"]["delay"]
}, },
updateNetworkSettings(vals) { updateNetworkSettings(vals) {
this.submitStatus.network = false this.submitStatus.network = false
this.paramNetwork.netCesPassword = vals["settings"]["netCesPassword"] this.paramNetwork.managementIp = vals["settings"]["network"]["managementIp"]
this.paramNetwork.netManagementIp = vals["settings"]["netManagementIp"] this.paramNetwork.serverName = vals["settings"]["network"]["serverName"]
this.paramNetwork.netServerName = vals["settings"]["netServerName"]
}, },
// ========== include end from 'common/all-params-methods.js.j2' // ========== include end from 'common/all-params-methods.js.j2'
@@ -608,47 +631,46 @@
} }
this.lastUpdateTime = new Date(); this.lastUpdateTime = new Date();
this.initState = vals["mainState"]["initState"] this.initState = vals["state"]["initState"]
this.testState = vals["state"]["testState"]
this.statRx.state = vals["mainState"]["rx.state"] this.statRx.state = vals["state"]["rx"]["state"]
this.statRx.sym_sync_lock = vals["mainState"]["rx.sym_sync_lock"] this.statRx.sym_sync_lock = vals["state"]["rx"]["sym_sync_lock"]
this.statRx.freq_search_lock = vals["mainState"]["rx.freq_search_lock"] this.statRx.freq_search_lock = vals["state"]["rx"]["freq_search_lock"]
this.statRx.afc_lock = vals["mainState"]["rx.afc_lock"] this.statRx.afc_lock = vals["state"]["rx"]["afc_lock"]
this.statRx.pkt_sync = vals["mainState"]["rx.pkt_sync"] this.statRx.pkt_sync = vals["state"]["rx"]["pkt_sync"]
this.statRx.snr = vals["mainState"]["rx.snr"] this.statRx.snr = Math.round(vals["state"]["rx"]["snr"] * 10) / 10
this.statRx.rssi = vals["mainState"]["rx.rssi"] this.statRx.rssi = Math.round(vals["state"]["rx"]["rssi"] * 10) / 10
this.statRx.modcod = modcodToStr(vals["mainState"]["rx.modcod"]) this.statRx.modcod = modcodToStr(vals["state"]["rx"]["modcod"])
this.statRx.frameSizeNormal = vals["mainState"]["rx.frameSizeNormal"] this.statRx.frameSizeNormal = vals["state"]["rx"]["frameSizeNormal"]
this.statRx.isPilots = vals["mainState"]["rx.isPilots"] this.statRx.isPilots = vals["state"]["rx"]["isPilots"]
this.statRx.symError = vals["mainState"]["rx.symError"] this.statRx.symError = vals["state"]["rx"]["symError"]
this.statRx.freqErr = vals["mainState"]["rx.freqErr"] this.statRx.freqErr = Math.round(vals["state"]["rx"]["freqErr"] * 100) / 100
this.statRx.freqErrAcc = vals["mainState"]["rx.freqErrAcc"] this.statRx.freqErrAcc = Math.round(vals["state"]["rx"]["freqErrAcc"] * 100) / 100
this.statRx.inputSignalLevel = vals["mainState"]["rx.inputSignalLevel"] this.statRx.inputSignalLevel = vals["state"]["rx"]["inputSignalLevel"]
this.statRx.pllError = vals["mainState"]["rx.pllError"] this.statRx.pllError = Math.round(vals["state"]["rx"]["pllError"] * 100) / 100
this.statRx.speedOnRxKbit = vals["mainState"]["rx.speedOnRxKbit"] this.statRx.speedOnRxKbit = Math.round(vals["state"]["rx"]["speedOnRxKbit"] * 100) / 100
this.statRx.speedOnIifKbit = vals["mainState"]["rx.speedOnIifKbit"] this.statRx.speedOnIifKbit = Math.round(vals["state"]["rx"]["speedOnIifKbit"] * 100) / 100
this.statRx.packetsOk = vals["mainState"]["rx.packetsOk"] this.statRx.packetsOk = vals["state"]["rx"]["packetsOk"]
this.statRx.packetsBad = vals["mainState"]["rx.packetsBad"] this.statRx.packetsBad = vals["state"]["rx"]["packetsBad"]
this.statRx.packetsDummy = vals["mainState"]["rx.packetsDummy"] this.statRx.packetsDummy = vals["state"]["rx"]["packetsDummy"]
this.statTx.state = vals["mainState"]["tx.state"] this.statTx.state = vals["state"]["tx"]["state"]
this.statTx.modcod = modcodToStr(vals["mainState"]["tx.modcod"]) this.statTx.modcod = modcodToStr(vals["state"]["tx"]["modcod"])
this.statTx.speedOnTxKbit = vals["mainState"]["tx.speedOnTxKbit"] this.statTx.speedOnTxKbit = Math.round(vals["state"]["tx"]["speedOnTxKbit"] * 100) / 100
this.statTx.speedOnIifKbit = vals["mainState"]["tx.speedOnIifKbit"] this.statTx.speedOnIifKbit = Math.round(vals["state"]["tx"]["speedOnIifKbit"] * 100) / 100
this.statTx.centerFreq = vals["mainState"]["tx.centerFreq"] this.statTx.centerFreq = vals["state"]["tx"]["centerFreq"]
this.statTx.symSpeed = vals["mainState"]["tx.symSpeed"] this.statTx.symSpeed = vals["state"]["tx"]["symSpeed"]
this.statDevice.adrv = vals["mainState"]["device.adrv"] this.statDevice.adrv = vals["state"]["device"]["adrv"]
this.statDevice.zynq = vals["mainState"]["device.zynq"] this.statDevice.zynq = vals["state"]["device"]["zynq"]
this.statDevice.fpga = vals["mainState"]["device.fpga"] this.statDevice.fpga = vals["state"]["device"]["fpga"]
this.statDevice.upgradeStatus = vals["mainState"]["device.upgradeStatus"] this.statDevice.upgradeStatus = vals["state"]["device"]["upgradeStatus"]
this.statDevice.upgradePercent = vals["mainState"]["device.upgradePercent"] this.statDevice.upgradePercent = vals["state"]["device"]["upgradePercent"]
this.statDevice.upgradeImage = vals["mainState"]["device.upgradeImage"] this.statDevice.upgradeImage = vals["state"]["device"]["upgradeImage"]
this.testState = vals["mainState"]["testState"]
// аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид // аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид
let uptime = vals["sysinfo"]["uptime"] let uptime = vals["state"]["device"]["uptime"]
if (uptime) { if (uptime) {
let secs = uptime % 60; uptime = Math.floor(uptime / 60) let secs = uptime % 60; uptime = Math.floor(uptime / 60)
let mins = uptime % 60; uptime = Math.floor(uptime / 60) let mins = uptime % 60; uptime = Math.floor(uptime / 60)
@@ -660,11 +682,11 @@
} else { } else {
this.statOs.uptime = '?' this.statOs.uptime = '?'
} }
this.statOs.load1 = vals["sysinfo"]["load1min"] this.statOs.load1 = Math.round(vals["state"]["device"]["load1min"] * 100) / 100
this.statOs.load5 = vals["sysinfo"]["load5min"] this.statOs.load5 = Math.round(vals["state"]["device"]["load5min"] * 100) / 100
this.statOs.load15 = vals["sysinfo"]["load15min"] this.statOs.load15 = Math.round(vals["state"]["device"]["load15min"] * 100) / 100
this.statOs.totalram = vals["sysinfo"]["totalram"] this.statOs.totalram = vals["state"]["device"]["totalram"]
this.statOs.freeram = vals["sysinfo"]["freeram"] this.statOs.freeram = vals["state"]["device"]["freeram"]
}, },
resetPacketsStatistics() { resetPacketsStatistics() {
@@ -746,6 +768,22 @@
} }
this.submitStatus.firmwareUpgradeOta = false this.submitStatus.firmwareUpgradeOta = false
}, },
async settingsPerformSetCesPassword() {
if (this.submitStatus.cesPassword) { return }
this.submitStatus.cesPassword = true
try {
await fetch('/api/set/cesPassword', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({'password': this.cesPasswordValue})
})
} catch (e) {
console.log("failed to perform set CES password: ", e)
}
this.submitStatus.cesPassword = false
},
doModemReboot() { doModemReboot() {
if (this.submitStatus.modemReboot !== null) { if (this.submitStatus.modemReboot !== null) {
@@ -753,6 +791,133 @@
} }
this.submitStatus.modemReboot = 30 this.submitStatus.modemReboot = 30
fetch('/api/reboot', { method: 'POST' }).then((r) => {}) fetch('/api/reboot', { method: 'POST' }).then((r) => {})
},
async restoreAllSettings() {
// Порядок применения настроек
const settingsApplyOrder = ['qos', 'tcpaccel', 'dpdi', 'rxtx', 'buclnb', 'network'];
// 1. Чтение JSON-файла, выбранного пользователем
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.accept = '.json';
const filePromise = new Promise((resolve, reject) => {
fileInput.onchange = e => {
const file = e.target.files[0];
if (!file) {
reject(new Error('Файл не выбран'));
return;
}
const reader = new FileReader();
reader.onload = event => {
try {
const jsonData = JSON.parse(event.target.result);
resolve(jsonData);
} catch (error) {
reject(new Error('Ошибка парсинга JSON'));
}
};
reader.onerror = () => reject(new Error('Ошибка чтения файла'));
reader.readAsText(file);
};
fileInput.click();
});
try {
const settingsToApply = await filePromise;
const errors = [];
// 2. Перебор групп параметров в заданном порядке
for (const groupName of settingsApplyOrder) {
if (!settingsToApply.hasOwnProperty(groupName)) {
continue; // Пропускаем группы, которых нет в файле
}
const groupSettings = settingsToApply[groupName];
if (typeof groupSettings !== 'object' || groupSettings === null) {
continue;
}
try {
// 2.1. POST-запрос для применения группы параметров
const postResponse = await fetch(`/api/set/${groupName}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(groupSettings)
});
if (!postResponse.ok) {
throw new Error(`HTTP error ${postResponse.status}`);
}
const postResult = await postResponse.json();
if (postResult.status !== 'ok') {
throw new Error(`API error: ${postResult.message || 'unknown error'}`);
}
// 2.2. Проверка примененных параметров
const getResponse = await fetch('/api/get/settings', { method: 'GET' });
if (!getResponse.ok) {
throw new Error(`HTTP error ${getResponse.status}`);
}
const fetchSettingsResult = await getResponse.json();
if (fetchSettingsResult.status !== 'ok') {
throw new Error('Не удалось получить текущие настройки');
}
// Проверка соответствия параметров
const appliedGroup = fetchSettingsResult.settings[groupName] || {};
const failedSettings = [];
for (const [key, value] of Object.entries(groupSettings)) {
if (appliedGroup[key] !== value) {
failedSettings.push(`${key} (ожидалось: ${value}, получено: ${appliedGroup[key]})`);
}
}
if (failedSettings.length > 0) {
throw new Error(`Не совпадают параметры: ${failedSettings.join(', ')}`);
}
} catch (groupError) {
errors.push(`Группа ${groupName}: ${groupError.message}`);
}
}
// 3. Показ ошибок, если они есть
if (errors.length > 0) {
const errorMessage = errors.join('\n\n') +
'\n\nНекоторые настройки могли примениться некорректно.\nСтраница будет перезагружена.';
alert(errorMessage);
}
} catch (error) {
alert(`Ошибка при восстановлении настроек: ${error.message}`);
return;
}
// 4. Перезагрузка страницы
location.reload();
},
async dumpAllSettings() {
function downloadAsFile(data, filename) {
let a = document.createElement("a");
let file = new Blob([data], {type: 'application/json'});
a.href = URL.createObjectURL(file);
a.download = filename;
a.click();
}
const response = await fetch('/api/get/settings', { method: 'GET' })
if (response.ok) {
const jres = await response.json()
if (jres["status"] === "ok") {
downloadAsFile(JSON.stringify(jres["settings"], null, 4), "backup-" + this.about.firmwareVersion + "-" + this.about.modemSn + ".json")
}
}
}, // ========== include end from 'common/admin-methods.js.j2' }, // ========== include end from 'common/admin-methods.js.j2'
@@ -799,11 +964,11 @@
try { try {
const fr = await fetch("/api/get/aboutFirmware") const fr = await fetch("/api/get/aboutFirmware")
const d = await fr.json() const d = await fr.json()
this.about.firmwareVersion = d["fw.version"] this.about.firmwareVersion = d["firmware"]["version"]
this.about.modemUid = d["fw.modemId"] this.about.modemUid = d["firmware"]["modemId"]
this.about.modemSn = d["fw.modemSn"] this.about.modemSn = d["firmware"]["modemSn"]
this.about.macManagement = d["fw.macMang"] this.about.macManagement = d["firmware"]["macMang"]
this.about.macData = d["fw.macData"] this.about.macData = d["firmware"]["macData"]
} catch (e) { } catch (e) {
console.log('Ошибка загрузки версии ПО', e) console.log('Ошибка загрузки версии ПО', e)
} }