Compare commits
1 Commits
master
...
2ee11b5945
Author | SHA1 | Date | |
---|---|---|---|
2ee11b5945 |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -7,10 +7,8 @@ dh.pem
|
||||
/web-action
|
||||
|
||||
# эти файлы после генерации должны быть перемещены в `/static`
|
||||
front-generator/main-*.html
|
||||
front-generator/main-scpc.html
|
||||
front-generator/main-tdma.html
|
||||
|
||||
# логи сервера в релизной версии
|
||||
http_server_*.log
|
||||
|
||||
# папка с логами, используется для разработки
|
||||
logs/
|
||||
|
@@ -1,26 +0,0 @@
|
||||
stages:
|
||||
- build
|
||||
|
||||
test for build:
|
||||
stage: build
|
||||
image: localhost:5000/cpp-test-universal:latest
|
||||
tags:
|
||||
- cpp-test-universal
|
||||
only:
|
||||
- master
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
script:
|
||||
- cmake -DCMAKE_BUILD_TYPE=Debug -DMODEM_TYPE=TDMA -B cmake-build-debug-tdma
|
||||
- cmake -DCMAKE_BUILD_TYPE=Debug -DMODEM_TYPE=SCPC -B cmake-build-debug-scpc
|
||||
- cmake -DCMAKE_BUILD_TYPE=Debug -DMODEM_TYPE=SHPS -B cmake-build-debug-shps
|
||||
- cmake -DCMAKE_BUILD_TYPE=Release -DMODEM_TYPE=TDMA -B cmake-build-release-tdma
|
||||
- cmake -DCMAKE_BUILD_TYPE=Release -DMODEM_TYPE=SCPC -B cmake-build-release-scpc
|
||||
- cmake -DCMAKE_BUILD_TYPE=Release -DMODEM_TYPE=SHPS -B cmake-build-release-shps
|
||||
- cmake --build cmake-build-debug-tdma -j 4
|
||||
- cmake --build cmake-build-debug-scpc -j 4
|
||||
- cmake --build cmake-build-debug-shps -j 4
|
||||
- cmake --build cmake-build-release-tdma -j 4
|
||||
- cmake --build cmake-build-release-scpc -j 4
|
||||
- cmake --build cmake-build-release-shps -j 4
|
||||
|
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -1,9 +1,3 @@
|
||||
[submodule "dependencies/control_system_client"]
|
||||
path = dependencies/control_system_client
|
||||
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
|
||||
|
@@ -18,17 +18,11 @@ endif()
|
||||
if("${MODEM_TYPE}" STREQUAL "SCPC")
|
||||
add_definitions(-DMODEM_IS_SCPC)
|
||||
message(STATUS "Selected SCPC modem")
|
||||
add_subdirectory(dependencies/control_system_client) # подключение правильного control system client SCPC, ветка main
|
||||
elseif ("${MODEM_TYPE}" STREQUAL "TDMA")
|
||||
add_definitions(-DMODEM_IS_TDMA)
|
||||
message(STATUS "Selected TDMA modem")
|
||||
add_subdirectory(dependencies/control_system_client_tdma) # подключение правильного control system client TDMA, ветка terminal-tdma
|
||||
elseif ("${MODEM_TYPE}" STREQUAL "SHPS")
|
||||
add_definitions(-DMODEM_IS_SHPS)
|
||||
message(STATUS "Selected SHPS modem")
|
||||
add_subdirectory(dependencies/control_system_client_shps) # подключение правильного control system client SHPS, ветка shps
|
||||
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\"!")
|
||||
endif()
|
||||
|
||||
SET(PROJECT_GIT_REVISION "0")
|
||||
@@ -54,21 +48,12 @@ add_compile_options(-Wall -Wextra -Wsign-conversion -DPROJECT_GIT_REVISION="${PR
|
||||
|
||||
# максимальный размер тела запроса 200mb
|
||||
add_definitions(-DHTTP_MAX_PAYLOAD=200000000)
|
||||
if(MANAGER_LOGS_DIR)
|
||||
add_definitions(-DMANAGER_LOGS_DIR="${MANAGER_LOGS_DIR}")
|
||||
endif()
|
||||
|
||||
add_subdirectory(dependencies/control_system_client)
|
||||
|
||||
include_directories(src/)
|
||||
|
||||
add_executable(terminal-web-server
|
||||
src/api-driver/daemon.h
|
||||
src/api-driver/daemon.cpp
|
||||
src/api-driver/proxy.h
|
||||
src/api-driver/proxy.cpp
|
||||
src/api-driver/structs.h
|
||||
src/api-driver/structs.cpp
|
||||
src/common/nlohmann/json.hpp
|
||||
src/server/mime_types.hpp
|
||||
src/server/mime_types.cpp
|
||||
src/server/request_parser.hpp
|
||||
@@ -92,7 +77,6 @@ add_executable(terminal-web-server
|
||||
src/auth/utils.cpp
|
||||
src/auth/utils.h
|
||||
src/version.h
|
||||
src/api-driver/stricts-enable.h
|
||||
)
|
||||
|
||||
add_definitions(-DBOOST_LOG_DYN_LINK)
|
||||
|
@@ -4,10 +4,10 @@
|
||||
|
||||
# Зависимости
|
||||
|
||||
По идее только `boost` и `ssl`
|
||||
По идее только libboost
|
||||
|
||||
```shell
|
||||
sudo apt-get install libboost-all-dev libssl-dev
|
||||
sudo apt-get install libboost-all-dev
|
||||
```
|
||||
|
||||
Для библиотеки api нужно еще такое:
|
||||
|
2
dependencies/control_system_client
vendored
2
dependencies/control_system_client
vendored
Submodule dependencies/control_system_client updated: 76d6dcdb08...467f8d6bf6
1
dependencies/control_system_client_shps
vendored
1
dependencies/control_system_client_shps
vendored
Submodule dependencies/control_system_client_shps deleted from 6fb944f930
1
dependencies/control_system_client_tdma
vendored
1
dependencies/control_system_client_tdma
vendored
Submodule dependencies/control_system_client_tdma deleted from e91aac881a
33
devtool.py
33
devtool.py
@@ -44,25 +44,6 @@ def cp_get_dma_debug(base_url, param_name):
|
||||
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):
|
||||
print(cp_set_dma_debug(base_url, "log_bool", value))
|
||||
|
||||
@@ -72,8 +53,6 @@ if __name__ == '__main__':
|
||||
print(f"Usage: {sys.argv[0]} http(s)://terminal-url logging on|off")
|
||||
print(f" set_dma_debug <param_name> <value>")
|
||||
print(f" get_dma_debug <param_name>")
|
||||
print(f" set_network <param_name> <value>")
|
||||
print(f" get_network <param_name>")
|
||||
exit(1)
|
||||
|
||||
if sys.argv[2] == "logging":
|
||||
@@ -88,17 +67,7 @@ if __name__ == '__main__':
|
||||
print(cp_set_dma_debug(sys.argv[1], sys.argv[3], sys.argv[4]))
|
||||
elif sys.argv[2] == "get_dma_debug":
|
||||
if len(sys.argv) != 4:
|
||||
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!")
|
||||
print("Wrong set dma debug usage!")
|
||||
else:
|
||||
print(cp_get_dma_debug(sys.argv[1], sys.argv[3]))
|
||||
else:
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"modem_types": {
|
||||
"tdma": {
|
||||
"modem_name": "VSAT Модем",
|
||||
"modem_name": "RCSM-101 TDMA",
|
||||
"dangerousParamGroups": {
|
||||
"buclnb": "Применение неправильных настроек может вывести из строя оборудование! Продолжить?",
|
||||
"network": "Применение этих настроек может сделать модем недоступным! Продолжить?"
|
||||
@@ -22,9 +22,7 @@
|
||||
"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", "label": "Ослабление, дБ", "name": "txAttenuation", "max": 0, "min": -90, "step": 1},
|
||||
{"widget": "number", "label": "Ослабление для запросных слотов, дБ", "name": "txAttenuationAck", "max": 0, "min": -90, "step": 1},
|
||||
{"widget": "number", "label": "Ограничение ослабления", "name": "txAttenuationLimit", "max": 0, "min": -40, "step": 0.25}
|
||||
{"widget": "number", "label": "Ослабление, дБ", "name": "txAttenuation", "max": 0, "min": -40, "step": 1}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -44,7 +42,7 @@
|
||||
{"widget": "number-int", "label": "Символьная скорость, Бод", "name": "rxBaudrate", "min": 200000, "max": 54000000, "step": 1},
|
||||
{
|
||||
"widget": "select", "label": "Roll-off", "name": "rxRolloff",
|
||||
"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"}]
|
||||
"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"}]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -67,8 +65,7 @@
|
||||
{"label": "Выкл", "value": "0"},
|
||||
{"label": "24В", "value": "24"}
|
||||
]
|
||||
},
|
||||
{"widget": "number-int", "label": "Частота LO, кГц", "name": "bucLoKhz", "min": 0, "max": 40000000, "step": 1}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -84,8 +81,7 @@
|
||||
{"label": "18В", "value": "18"},
|
||||
{"label": "24В", "value": "24"}
|
||||
]
|
||||
},
|
||||
{"widget": "number-int", "label": "Частота LO, кГц", "name": "lnbLoKhz", "min": 0, "max": 40000000, "step": 1}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -105,17 +101,17 @@
|
||||
"widget": "settings-container",
|
||||
"childs": [
|
||||
{
|
||||
"widget": "select", "label": "Метод расчета задержки", "name": "isPositional",
|
||||
"widget": "select", "label": "Метод расчета задержки", "name": "dpdiIsPositional",
|
||||
"values": [
|
||||
{"label": "Позиционированием", "value": "true"},
|
||||
{"label": "Окном задержки", "value": "false"}
|
||||
]
|
||||
},
|
||||
{"widget": "h2", "label": "Настройки позиционирования", "v_show": "paramDpdi.isPositional === true"},
|
||||
{"widget": "number", "label": "Широта станции", "name": "positionStationLatitude", "v_show": "paramDpdi.isPositional === 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": "positionSatelliteLongitude", "v_show": "paramDpdi.isPositional === true", "min": -180, "step": 0.000001, "max": 180},
|
||||
{"widget": "number", "label": "Задержка до спутника, мс", "name": "delay", "v_show": "paramDpdi.isPositional === false", "min": 0, "step": 0.1, "max": 400}]
|
||||
{"widget": "h2", "label": "Настройки позиционирования", "v_show": "paramDpdi.dpdiIsPositional === true"},
|
||||
{"widget": "number", "label": "Широта станции", "name": "dpdiPositionStationLatitude", "v_show": "paramDpdi.dpdiIsPositional === 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": "dpdiPositionSatelliteLongitude", "v_show": "paramDpdi.dpdiIsPositional === 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": "submit"}
|
||||
],
|
||||
@@ -125,8 +121,14 @@
|
||||
"widget": "settings-container",
|
||||
"childs": [
|
||||
{"widget": "h3", "label": "Настройки интерфейса управления"},
|
||||
{"widget": "ip-address-mask", "label": "Интерфейс управления (a.d.d.r/mask)", "name": "managementIp"},
|
||||
{"widget": "text", "label": "Имя веб-сервера", "name": "serverName"}
|
||||
{"widget": "ip-address", "label": "Интерфейс управления (/24)", "name": "netManagementIp"},
|
||||
{
|
||||
"widget": "select", "label": "Режим сети", "name": "netIsL2",
|
||||
"values": [{"label": "Маршрутизатор", "value": "false"}, {"label": "Коммутатор", "value": "true"}]
|
||||
},
|
||||
{"widget": "ip-address", "label": "Интерфейс данных (/24)", "name": "netDataIp", "v_show": "paramNetwork.netIsL2 === false"},
|
||||
{"widget": "number", "label": "MTU интерфейса данных", "name": "netDataMtu", "min": 1500, "step": 1, "max": 2000},
|
||||
{"widget": "text", "label": "Имя веб-сервера", "name": "netServerName"}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -134,8 +136,7 @@
|
||||
"tabs": [
|
||||
{"name": "monitoring", "desc": "Мониторинг"},
|
||||
{"name": "setup", "desc": "Настройки"},
|
||||
{"name": "admin", "desc": "Администрирование"},
|
||||
{"name": "logs", "desc": "Журнал"}
|
||||
{"name": "admin", "desc": "Администрирование"}
|
||||
]
|
||||
},
|
||||
"scpc": {
|
||||
@@ -174,11 +175,11 @@
|
||||
"values": [{"label": "Ethernet", "value": "false"}, {"label": "Тест", "value": "true"}]
|
||||
},
|
||||
{"widget": "h3", "label": "Параметры передачи"},
|
||||
{"widget": "number-int", "label": "Центральная частота, КГц", "name": "txCentralFreq", "min": 100000, "max": 6000000, "step": 0.01},
|
||||
{"widget": "number-int", "label": "Центральная частота, КГц", "name": "txCentralFreq", "min": 950000, "max": 6000000, "step": 0.01},
|
||||
{"widget": "number-int", "label": "Символьная скорость, Бод", "name": "txBaudrate", "min": 200000, "max": 54000000},
|
||||
{
|
||||
"widget": "select", "label": "Roll-off", "name": "txRolloff",
|
||||
"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"}]
|
||||
"values": [{"label": "0.02", "value": "2"}, {"label": "0.05", "value": "5"}, {"label": "0.10", "value": "10"}, {"label": "0.15", "value": "15"}, {"label": "0.20", "value": "20"}, {"label": "0.25", "value": "25"}]
|
||||
},
|
||||
{
|
||||
"widget": "select", "label": "Номер последовательности Голда", "name": "txGoldan",
|
||||
@@ -200,7 +201,6 @@
|
||||
"widget": "select", "label": "Размер кадра", "name": "txFrameSizeNormal",
|
||||
"values": [{"label": "normal", "value": "true"}, {"label": "short", "value": "false"}]
|
||||
},
|
||||
{"widget": "checkbox", "label": "Пилот-символы", "name": "txIsPilots"},
|
||||
{"widget": "modulation-modcod", "label": "Модуляция", "name": "dvbCcm", "v_show": "paramRxtx.dvbIsAcm === false"},
|
||||
{"widget": "modulation-speed", "label": "Скорость кода", "name": "dvbCcm", "v_show": "paramRxtx.dvbIsAcm === false"},
|
||||
{"widget": "watch-expr", "label": "Расчетная скорость", "expr": "calcInterfaceSpeedKb(paramRxtx.txBaudrate, paramRxtx.dvbCcmModulation, paramRxtx.dvbCcmSpeed, paramRxtx.txFrameSizeNormal)", "v_show": "paramRxtx.dvbIsAcm === false"},
|
||||
@@ -221,7 +221,7 @@
|
||||
{"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}
|
||||
{"widget": "number", "label": "Требуемое ОСШ", "name": "aupcRequiredSnr", "min": 0, "step": 0.01, "max": 10}
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -235,11 +235,11 @@
|
||||
{"widget": "number", "label": "Усиление, дБ", "name": "rxManualGain", "min": -40, "step": 0.01, "max": 40, "v_show": "paramRxtx.rxAgcEn === false"},
|
||||
{"widget": "watch-expr", "label": "Текущее усиление", "expr": "paramRxtx.rxManualGain", "v_show": "paramRxtx.rxAgcEn === true"},
|
||||
{"widget": "checkbox", "label": "Инверсия спектра", "name": "rxSpectrumInversion"},
|
||||
{"widget": "number-int", "label": "Центральная частота, КГц", "name": "rxCentralFreq", "min": 100000, "max": 6000000, "step": 0.01},
|
||||
{"widget": "number-int", "label": "Центральная частота, КГц", "name": "rxCentralFreq", "min": 950000, "max": 6000000, "step": 0.01},
|
||||
{"widget": "number-int", "label": "Символьная скорость, Бод", "name": "rxBaudrate", "min": 200000, "max": 54000000},
|
||||
{
|
||||
"widget": "select", "label": "Roll-off", "name": "rxRolloff",
|
||||
"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"}]
|
||||
"values": [{"label": "0.02", "value": "2"}, {"label": "0.05", "value": "5"}, {"label": "0.10", "value": "10"}, {"label": "0.15", "value": "15"}, {"label": "0.20", "value": "20"}, {"label": "0.25", "value": "25"}]
|
||||
},
|
||||
{
|
||||
"widget": "select", "label": "Номер последовательности Голда", "name": "rxGoldan",
|
||||
@@ -256,20 +256,20 @@
|
||||
"widget": "settings-container", "v_show": "paramRxtx.isCinC",
|
||||
"childs": [
|
||||
{
|
||||
"widget": "select", "label": "Метод расчета задержки", "name": "isPositional",
|
||||
"widget": "select", "label": "Метод расчета задержки", "name": "dpdiIsPositional",
|
||||
"values": [
|
||||
{"label": "Позиционированием", "value": "true"},
|
||||
{"label": "Окном задержки", "value": "false"}
|
||||
]
|
||||
},
|
||||
{"widget": "number", "label": "Полоса поиска, КГц ±", "name": "searchBandwidth", "min": 0, "step": 1, "max": 100},
|
||||
{"widget": "h2", "label": "Настройки позиционирования", "v_show": "paramDpdi.isPositional === true"},
|
||||
{"widget": "number", "label": "Широта станции", "name": "positionStationLatitude", "v_show": "paramDpdi.isPositional === 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": "positionSatelliteLongitude", "v_show": "paramDpdi.isPositional === true", "min": -180, "step": 0.000001, "max": 180},
|
||||
{"widget": "h2", "label": "Задержка до спутника", "v_show": "paramDpdi.isPositional === false"},
|
||||
{"widget": "number", "label": "от, мс", "name": "delayMin", "v_show": "paramDpdi.isPositional === 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": "number", "label": "Полоса поиска, КГц ±", "name": "dpdiSearchBandwidth", "min": 0, "step": 1, "max": 100},
|
||||
{"widget": "h2", "label": "Настройки позиционирования", "v_show": "paramDpdi.dpdiIsPositional === true"},
|
||||
{"widget": "number", "label": "Широта станции", "name": "dpdiPositionStationLatitude", "v_show": "paramDpdi.dpdiIsPositional === 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": "dpdiPositionSatelliteLongitude", "v_show": "paramDpdi.dpdiIsPositional === true", "min": -180, "step": 0.000001, "max": 180},
|
||||
{"widget": "h2", "label": "Задержка до спутника", "v_show": "paramDpdi.dpdiIsPositional === false"},
|
||||
{"widget": "number", "label": "от, мс", "name": "dpdiDelayMin", "v_show": "paramDpdi.dpdiIsPositional === 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": "submit", "v_show": "paramRxtx.isCinC"}
|
||||
],
|
||||
@@ -320,20 +320,30 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"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": [
|
||||
{"widget": "h2", "label": "Настройки сети"},
|
||||
{
|
||||
"widget": "settings-container",
|
||||
"childs": [
|
||||
{"widget": "h3", "label": "Настройки интерфейса управления"},
|
||||
{"widget": "ip-address-mask", "label": "Интерфейс управления (a.d.d.r/mask)", "name": "managementIp"},
|
||||
{"widget": "ip-address", "label": "Интерфейс управления (/24)", "name": "netManagementIp"},
|
||||
{
|
||||
"widget": "select", "label": "Режим сети", "name": "isL2",
|
||||
"widget": "select", "label": "Режим сети", "name": "netIsL2",
|
||||
"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"}
|
||||
{"widget": "ip-address", "label": "Интерфейс данных (/24)", "name": "netDataIp", "v_show": "paramNetwork.netIsL2 === false"},
|
||||
{"widget": "number", "label": "MTU интерфейса данных", "name": "netDataMtu", "min": 1500, "step": 1, "max": 2000},
|
||||
{"widget": "text", "label": "Имя веб-сервера", "name": "netServerName"}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -344,150 +354,6 @@
|
||||
{"name": "qos", "desc": "QoS"},
|
||||
{"name": "admin", "desc": "Администрирование"}
|
||||
]
|
||||
},
|
||||
"shps": {
|
||||
"modem_name": "ШПС Модем",
|
||||
"dangerousParamGroups": {
|
||||
"buclnb": "Применение неправильных настроек может вывести из строя оборудование! Продолжить?",
|
||||
"network": "Применение этих настроек может сделать модем недоступным! Продолжить?"
|
||||
},
|
||||
"params": {
|
||||
"rxtx": [
|
||||
{"widget": "h2", "label": "Настройки приема/передачи"},
|
||||
{
|
||||
"widget": "flex-container",
|
||||
"childs": [
|
||||
{
|
||||
"widget": "settings-container",
|
||||
"childs": [
|
||||
{"widget": "h3", "label": "Настройки передатчика"},
|
||||
{"widget": "checkbox", "label": "Включить передатчик", "name": "txEn"},
|
||||
{"widget": "checkbox", "label": "Автоматический запуск передатчика", "name": "txAutoStart"},
|
||||
{
|
||||
"widget": "select", "label": "Режим работы модулятора", "name": "txModulatorIsTest",
|
||||
"values": [{"label": "Нормальный", "value": "false"}, {"label": "Тест (CW)", "value": "true"}]
|
||||
},
|
||||
{"widget": "number", "label": "Ослабление, дБ", "name": "txAttenuation", "max": 0, "min": -80, "step": 0.25},
|
||||
{
|
||||
"widget": "select", "label": "Входные данные", "name": "txIsTestInput",
|
||||
"values": [{"label": "Ethernet", "value": "false"}, {"label": "Тест", "value": "true"}]
|
||||
},
|
||||
{"widget": "h3", "label": "Параметры передачи"},
|
||||
{"widget": "number-int", "label": "Центральная частота, КГц", "name": "txCentralFreq", "min": 70000, "max": 6000000, "step": 0.01},
|
||||
{"widget": "number-int", "label": "Символьная скорость, Бод", "name": "txBaudrate", "min": 128000, "max": 30000000},
|
||||
{
|
||||
"widget": "select", "label": "Roll-off", "name": "txRolloff",
|
||||
"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": "settings-container",
|
||||
"childs": [
|
||||
{"widget": "h3", "label": "Авто-регулировка мощности"},
|
||||
{"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}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widget": "settings-container",
|
||||
"childs": [
|
||||
{"widget": "h3", "label": "Настройки приемника"},
|
||||
{
|
||||
"widget": "select", "label": "Режим управления усилением", "name": "rxAgcEn",
|
||||
"values": [{"label": "РРУ", "value": "false"}, {"label": "АРУ", "value": "true"}]
|
||||
},
|
||||
{"widget": "number", "label": "Усиление, дБ", "name": "rxManualGain", "min": -40, "step": 0.01, "max": 40, "v_show": "paramRxtx.rxAgcEn === false"},
|
||||
{"widget": "watch-expr", "label": "Текущее усиление", "expr": "paramRxtx.rxManualGain", "v_show": "paramRxtx.rxAgcEn === true"},
|
||||
{"widget": "checkbox", "label": "Инверсия спектра", "name": "rxSpectrumInversion"},
|
||||
{"widget": "number-int", "label": "Центральная частота, КГц", "name": "rxCentralFreq", "min": 70000, "max": 6000000, "step": 0.01},
|
||||
{"widget": "number-int", "label": "Символьная скорость, Бод", "name": "rxBaudrate", "min": 128000, "max": 30000000},
|
||||
{
|
||||
"widget": "select", "label": "Roll-off", "name": "rxRolloff",
|
||||
"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": 1024, "min": 8, "step": 2},
|
||||
{"widget": "number", "label": "Порог коррелятора", "name": "rxFftShift", "max": 10, "min": 1, "step": 0.125},
|
||||
{"widget": "number", "label": "Кол-во пакетов на преамбулу", "name": "rxFieldsDataPreamble", "max": 255, "min": 1, "step": 1}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"buclnb": [
|
||||
{"widget": "h2", "label": "Настройки питания и опорного генератора"},
|
||||
{
|
||||
"widget": "flex-container",
|
||||
"childs": [
|
||||
{
|
||||
"widget": "settings-container",
|
||||
"childs": [
|
||||
{"widget": "h3", "label": "Настройки BUC"},
|
||||
{"widget": "checkbox", "label": "Подача опоры 10МГц", "name": "bucRefClk10M"},
|
||||
{
|
||||
"widget": "select", "label": "Питание BUC", "name": "bucPowering",
|
||||
"values": [
|
||||
{"label": "Выкл", "value": "0"},
|
||||
{"label": "24В", "value": "24"},
|
||||
{"label": "48В", "value": "48"}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widget": "settings-container",
|
||||
"childs": [
|
||||
{"widget": "h3", "label": "Настройки LNB"},
|
||||
{"widget": "checkbox", "label": "Подача опоры 10МГц", "name": "lnbRefClk10M"},
|
||||
{
|
||||
"widget": "select", "label": "Питание LNB", "name": "lnbPowering",
|
||||
"values": [
|
||||
{"label": "Выкл", "value": "0"},
|
||||
{"label": "13В", "value": "13"},
|
||||
{"label": "18В", "value": "18"},
|
||||
{"label": "24В", "value": "24"}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widget": "settings-container",
|
||||
"childs": [
|
||||
{"widget": "h3", "label": "Сервисные настройки"},
|
||||
{"widget": "checkbox", "label": "Подача опоры 10МГц на 'Выход 10МГц'", "name": "srvRefClk10M"},
|
||||
{"widget": "checkbox", "label": "Автозапуск BUC и LNB при включении", "name": "bucLnbAutoStart"}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"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": [
|
||||
{"name": "monitoring", "desc": "Мониторинг"},
|
||||
{"name": "setup", "desc": "Настройки"},
|
||||
{"name": "admin", "desc": "Администрирование"}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@@ -1,218 +1,74 @@
|
||||
async settingsUploadUpdate() {
|
||||
if (!this.uploadFw.filename) {
|
||||
alert('Выберите файл для загрузки');
|
||||
return;
|
||||
}
|
||||
|
||||
async function readFileAsArrayBuffer(fileName) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!fileName) { reject(`Файл не выбран`); return }
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => { resolve(reader.result) }
|
||||
reader.onerror = (e) => { reject(e) }
|
||||
reader.readAsArrayBuffer(fileName)
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
this.submitStatus.firmwareUpload = true
|
||||
this.uploadFw.progress = 0
|
||||
const blob = await readFileAsArrayBuffer(this.uploadFw.filename)
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
await new Promise((resolve) => {
|
||||
xhr.upload.addEventListener("progress", (event) => {
|
||||
if (event.lengthComputable) {
|
||||
this.uploadFw.progress = Math.round((event.loaded / event.total) * 1000) / 10;
|
||||
async settingsUploadUpdate() {
|
||||
if (!this.uploadFw.filename) {
|
||||
alert('Выберите файл для загрузки');
|
||||
return;
|
||||
}
|
||||
});
|
||||
xhr.addEventListener("loadend", () => {
|
||||
this.uploadFw.progress = 100
|
||||
const rep = JSON.parse(xhr.responseText);
|
||||
this.uploadFw.sha256 = rep['sha256']
|
||||
resolve(xhr.readyState === 4 && xhr.status === 200);
|
||||
});
|
||||
xhr.open("PUT", "/api/firmwareUpdate", true);
|
||||
xhr.setRequestHeader("Content-Type", "application/octet-stream");
|
||||
xhr.send(blob);
|
||||
});
|
||||
} catch (e) {
|
||||
alert(`Ошибка загрузки файла: ${e}`);
|
||||
}
|
||||
this.submitStatus.firmwareUpload = false
|
||||
},
|
||||
|
||||
async settingsPerformFirmwareUpgrade() {
|
||||
if (this.submitStatus.firmwareUpgrade) { return }
|
||||
this.submitStatus.firmwareUpgrade = true
|
||||
try {
|
||||
await fetch('/api/doFirmwareUpgrade', { method: 'POST' })
|
||||
} catch (e) {
|
||||
console.log("failed to perform upgrade firmware: ", e)
|
||||
}
|
||||
this.submitStatus.firmwareUpgrade = false
|
||||
},
|
||||
{% if modem == 'tdma' %}
|
||||
async settingsPerformFirmwareUpgradeOta() {
|
||||
if (this.submitStatus.firmwareUpgradeOta) { return }
|
||||
this.submitStatus.firmwareUpgradeOta = true
|
||||
try {
|
||||
await fetch('/api/doFirmwareUpgrade?ota=1', { method: 'POST' })
|
||||
} catch (e) {
|
||||
console.log("failed to perform upgrade firmware: ", e)
|
||||
}
|
||||
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 %}
|
||||
async function readFileAsArrayBuffer(fileName) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!fileName) { reject(`Файл не выбран`); return }
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => { resolve(reader.result) }
|
||||
reader.onerror = (e) => { reject(e) }
|
||||
reader.readAsArrayBuffer(fileName)
|
||||
})
|
||||
}
|
||||
|
||||
doModemReboot() {
|
||||
if (this.submitStatus.modemReboot !== null) {
|
||||
return
|
||||
}
|
||||
this.submitStatus.modemReboot = 30
|
||||
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'));
|
||||
this.submitStatus.firmwareUpload = true
|
||||
this.uploadFw.progress = 0
|
||||
const blob = await readFileAsArrayBuffer(this.uploadFw.filename)
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
await new Promise((resolve) => {
|
||||
xhr.upload.addEventListener("progress", (event) => {
|
||||
if (event.lengthComputable) {
|
||||
this.uploadFw.progress = Math.round((event.loaded / event.total) * 1000) / 10;
|
||||
}
|
||||
});
|
||||
xhr.addEventListener("loadend", () => {
|
||||
this.uploadFw.progress = 100
|
||||
const rep = JSON.parse(xhr.responseText);
|
||||
this.uploadFw.sha256 = rep['sha256']
|
||||
resolve(xhr.readyState === 4 && xhr.status === 200);
|
||||
});
|
||||
xhr.open("PUT", "/api/firmwareUpdate", true);
|
||||
xhr.setRequestHeader("Content-Type", "application/octet-stream");
|
||||
xhr.send(blob);
|
||||
});
|
||||
} catch (e) {
|
||||
alert(`Ошибка загрузки файла: ${e}`);
|
||||
}
|
||||
};
|
||||
reader.onerror = () => reject(new Error('Ошибка чтения файла'));
|
||||
reader.readAsText(file);
|
||||
};
|
||||
fileInput.click();
|
||||
});
|
||||
this.submitStatus.firmwareUpload = false
|
||||
},
|
||||
|
||||
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}`);
|
||||
async settingsPerformFirmwareUpgrade() {
|
||||
if (this.submitStatus.firmwareUpgrade) { return }
|
||||
this.submitStatus.firmwareUpgrade = true
|
||||
try {
|
||||
await fetch('/api/doFirmwareUpgrade', { method: 'POST' })
|
||||
} catch (e) {
|
||||
console.log("failed to perform upgrade firmware: ", e)
|
||||
}
|
||||
|
||||
const postResult = await postResponse.json();
|
||||
if (postResult.status !== 'ok') {
|
||||
throw new Error(`API error: ${postResult.message || 'unknown error'}`);
|
||||
this.submitStatus.firmwareUpgrade = false
|
||||
},
|
||||
{% if modem == 'tdma' %}
|
||||
async settingsPerformFirmwareUpgradeOta() {
|
||||
if (this.submitStatus.firmwareUpgradeOta) { return }
|
||||
this.submitStatus.firmwareUpgradeOta = true
|
||||
try {
|
||||
await fetch('/api/doFirmwareUpgrade?ota=1', { method: 'POST' })
|
||||
} catch (e) {
|
||||
console.log("failed to perform upgrade firmware: ", e)
|
||||
}
|
||||
this.submitStatus.firmwareUpgradeOta = false
|
||||
},
|
||||
{% endif %}
|
||||
|
||||
// 2.2. Проверка примененных параметров
|
||||
const getResponse = await fetch('/api/get/settings', { method: 'GET' });
|
||||
if (!getResponse.ok) {
|
||||
throw new Error(`HTTP error ${getResponse.status}`);
|
||||
doModemReboot() {
|
||||
if (this.submitStatus.modemReboot !== null) {
|
||||
return
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
this.submitStatus.modemReboot = 30
|
||||
fetch('/api/reboot', { method: 'POST' }).then((r) => {})
|
||||
},
|
||||
|
@@ -1,53 +1,41 @@
|
||||
{% from 'common/widgets.j2' import build_widget %}
|
||||
<div class="tabs-body-item" v-if="activeTab === 'admin' && settingFetchComplete">
|
||||
{% if 'network' in params %}
|
||||
{% for w in params['network'] %}{{ build_widget('network', w) | indent(4, true) }}{% endfor %}
|
||||
{% endif %}
|
||||
{% raw %}
|
||||
<h2>Система</h2>
|
||||
<div class="settings-set-container statistics-container">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>Версия ПО</th><td>{{ about.firmwareVersion }}</td></tr>
|
||||
<tr><th>ID модема</th><td>{{ about.modemUid }}</td></tr>
|
||||
<tr><th>Серийный номер</th><td>{{ about.modemSn }}</td></tr>
|
||||
<tr><th>MAC интерфейса управления</th><td>{{ about.macManagement }}</td></tr>
|
||||
<tr><th>MAC интерфейса данных</th><td>{{ about.macData }}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div>
|
||||
<button class="dangerous-button" @click="doModemReboot()">Перезагрузить модем <span class="submit-spinner" v-show="submitStatus.modemReboot !== null"></span></button>
|
||||
<div class="tabs-body-item" v-if="activeTab === 'admin' && settingFetchComplete">
|
||||
{% if 'network' in params %}
|
||||
{% for w in params['network'] %}{{ build_widget('network', w) | indent(12, true) }}{% endfor %}
|
||||
{% endif %}
|
||||
{% raw %}
|
||||
<h2>Система</h2>
|
||||
<div class="settings-set-container statistics-container">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>Версия ПО</th><td>{{ about.firmwareVersion }}</td></tr>
|
||||
<tr><th>ID модема</th><td>{{ about.modemUid }}</td></tr>
|
||||
<tr><th>Серийный номер</th><td>{{ about.modemSn }}</td></tr>
|
||||
<tr><th>MAC интерфейса управления</th><td>{{ about.macManagement }}</td></tr>
|
||||
<tr><th>MAC интерфейса данных</th><td>{{ about.macData }}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div>
|
||||
<button class="dangerous-button" @click="doModemReboot()">Перезагрузить модем <span class="submit-spinner" v-show="submitStatus.modemReboot !== null"></span></button>
|
||||
</div>
|
||||
<div>
|
||||
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Обновление ПО</h2>
|
||||
<div class="settings-set-container statistics-container">
|
||||
<h3>Ручное обновление</h3>
|
||||
<label>
|
||||
<span>Файл {{ this.uploadFw.progress !== null ? `(${this.uploadFw.progress}%)` : '' }}</span>
|
||||
<input type="file" accept="application/zip" @change="(e) => { this.uploadFw.filename = e.target.files[0] }">
|
||||
<span v-if="uploadFw.sha256 !== null">SHA256: {{ uploadFw.sha256 }}</span>
|
||||
</label>
|
||||
<button class="action-button" @click="settingsUploadUpdate()">Загрузить<span class="submit-spinner" v-show="submitStatus.firmwareUpload"></span></button>
|
||||
<button class="dangerous-button" v-show="uploadFw.sha256 !== null" @click="settingsPerformFirmwareUpgrade()">Обновить встроенное ПО<span class="submit-spinner" v-show="submitStatus.firmwareUpgrade"></span></button>
|
||||
{% endraw %}{% if modem == 'tdma' %}
|
||||
<h3 v-show="statDevice.upgradePercent >= 100">Обновление "по воздуху"</h3>
|
||||
<button class="dangerous-button" v-show="statDevice.upgradePercent >= 100" @click="settingsPerformFirmwareUpgradeOta()">Обновить встроенное ПО<span class="submit-spinner" v-show="submitStatus.firmwareUpgradeOta"></span></button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
|
||||
</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>
|
||||
<div class="settings-set-container statistics-container">
|
||||
<h3>Ручное обновление</h3>
|
||||
<label>
|
||||
<span>Файл {{ this.uploadFw.progress !== null ? `(${this.uploadFw.progress}%)` : '' }}</span>
|
||||
<input type="file" accept="application/zip" @change="(e) => { this.uploadFw.filename = e.target.files[0] }">
|
||||
<span v-if="uploadFw.sha256 !== null">SHA256: {{ uploadFw.sha256 }}</span>
|
||||
</label>
|
||||
<button class="action-button" @click="settingsUploadUpdate()">Загрузить<span class="submit-spinner" v-show="submitStatus.firmwareUpload"></span></button>
|
||||
<button class="dangerous-button" v-show="uploadFw.sha256 !== null" @click="settingsPerformFirmwareUpgrade()">Обновить встроенное ПО<span class="submit-spinner" v-show="submitStatus.firmwareUpgrade"></span></button>
|
||||
{% endraw %}{% if modem == 'tdma' %}
|
||||
<h3 v-show="statDevice.upgradePercent >= 100">Обновление "по воздуху"</h3>
|
||||
<button class="dangerous-button" v-show="statDevice.upgradePercent >= 100" @click="settingsPerformFirmwareUpgradeOta()">Обновить встроенное ПО<span class="submit-spinner" v-show="submitStatus.firmwareUpgradeOta"></span></button>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
{% for g in paramGroups %}
|
||||
param{{ g['group'] | title }}: {
|
||||
{% for p in g['params'] %}
|
||||
{{ p['name'] }}: {{ p['initValue'] }},
|
||||
{% endfor %}
|
||||
},
|
||||
param{{ g['group'] | title }}: {
|
||||
{% for p in g['params'] %}
|
||||
{{ p['name'] }}: {{ p['initValue'] }},
|
||||
{% endfor %}
|
||||
},
|
||||
{% endfor %}
|
@@ -1,30 +1,30 @@
|
||||
{% from 'common/widgets.j2' import build_getter_js, build_setter_js %}
|
||||
{% for g in paramGroups %}
|
||||
settingsSubmit{{ g['group'] | title }}() {
|
||||
if (this.submitStatus.{{ g['group'] }}) { return }
|
||||
{% if g['group'] in dangerousParamGroups %}
|
||||
{ if (!confirm("{{ dangerousParamGroups[g['group']] }}")) return }
|
||||
{% endif %}
|
||||
{% for g in paramGroups %}
|
||||
settingsSubmit{{ g['group'] | title }}() {
|
||||
if (this.submitStatus.{{ g['group'] }}) { return }
|
||||
{% if g['group'] in dangerousParamGroups %}
|
||||
{ if (!confirm("{{ dangerousParamGroups[g['group']] }}")) return }
|
||||
{% endif %}
|
||||
|
||||
let query = {
|
||||
{% for p in g['params'] %}
|
||||
"{{ p['name'] }}": {{ build_getter_js(g['group'], p) }},
|
||||
{% endfor %}
|
||||
}
|
||||
let query = {
|
||||
{% for p in g['params'] %}
|
||||
"{{ p['name'] }}": {{ build_getter_js(g['group'], p) }},
|
||||
{% endfor %}
|
||||
}
|
||||
|
||||
this.submitStatus.{{ g['group'] }} = true
|
||||
fetch('/api/set/{{ g["group"] }}', {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.update{{ g['group'] | title }}Settings(vals) })
|
||||
.catch((reason) => { alert(`Ошибка при применении настроек: ${reason}`) })
|
||||
.finally(() => { this.submitStatus.{{ g['group'] }} = false })
|
||||
},
|
||||
{% endfor %}
|
||||
this.submitStatus.{{ g['group'] }} = true
|
||||
fetch('/api/set/{{ g["group"] }}', {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.update{{ g['group'] | title }}Settings(vals) })
|
||||
.catch((reason) => { alert(`Ошибка при применении настроек: ${reason}`) })
|
||||
.finally(() => { this.submitStatus.{{ g['group'] }} = false })
|
||||
},
|
||||
{% endfor %}
|
||||
|
||||
{% for g in paramGroups %}
|
||||
update{{ g['group'] | title }}Settings(vals) {
|
||||
this.submitStatus.{{ g['group'] }} = false
|
||||
{% for p in g['params'] %}
|
||||
{{ build_setter_js(g['group'], p, "vals[\"settings\"][\"" ~ g['group'] ~ "\"][\"" ~ p['name'] ~ "\"]") }}
|
||||
{% endfor %}
|
||||
},
|
||||
{% endfor %}
|
||||
{% for g in paramGroups %}
|
||||
update{{ g['group'] | title }}Settings(vals) {
|
||||
this.submitStatus.{{ g['group'] }} = false
|
||||
{% for p in g['params'] %}
|
||||
{{ build_setter_js(g['group'], p, "vals[\"settings\"][\"" ~ p['name'] ~ "\"]") }}
|
||||
{% endfor %}
|
||||
},
|
||||
{% endfor %}
|
@@ -1,8 +0,0 @@
|
||||
paramLogs: {
|
||||
submitClearLogs: false,
|
||||
submitUpdateLogs: false,
|
||||
revercePreview: true,
|
||||
data: "",
|
||||
level: ""
|
||||
},
|
||||
|
@@ -1,12 +0,0 @@
|
||||
logsUpdate() {
|
||||
if (this.paramLogs.submitUpdateLogs) { return }
|
||||
this.paramLogs.submitUpdateLogs = true
|
||||
fetch(`/api/get/manager.log?preview${this.paramLogs.revercePreview ? '&reverse' : ''}`, {method: 'GET', credentials: 'same-origin', })
|
||||
.then(async (resp) => {
|
||||
this.paramLogs.data = await resp.text()
|
||||
})
|
||||
.catch((reason) => { this.paramLogs.data = `Ошибка при чтении логов: ${reason}` })
|
||||
.finally(() => { this.paramLogs.submitUpdateLogs = false })
|
||||
},
|
||||
|
||||
|
@@ -1,18 +0,0 @@
|
||||
{% from 'common/widgets.j2' import build_widget %}
|
||||
<div class="tabs-body-item" v-if="activeTab === 'logs'">
|
||||
<h2>Журнал <code>manager</code></h2>
|
||||
<div class="settings-set-container">
|
||||
{{ build_widget('logs', {
|
||||
"widget": "select", "label": "Фильтрация лога (отображение)", "name": "level",
|
||||
"values": [{"label": "Без фильтрации", "value": "''"}, {"label": "Информация", "value": "'info'"}, {"label": "Предупреждение", "value": "'warning'"}, {"label": "Ошибка", "value": "'error'"}, {"label": "Фатальная ошибка", "value": "'fatal'"}]
|
||||
}) | indent(8, true) }}
|
||||
{{ build_widget('logs', {"widget": "checkbox", "label": "Обратная сортировка строк", "name": "revercePreview"},) | indent(8, true) }}
|
||||
<button class="action-button" @click="logsUpdate()">Обновить (последние 1000 строк) <span class="submit-spinner" v-show="paramLogs.submitUpdateLogs"></span></button></button>
|
||||
<a href="/api/get/manager.log" class="action-button" download>Скачать все</a>
|
||||
<pre style="overflow-x: auto">{{ '{{ paramLogs.data }}' }}</pre>
|
||||
<div><button class="action-button" v-if="paramLogs.data !== ''" @click="logsUpdate()">Обновить (последние 1000 строк) <span class="submit-spinner" v-show="paramLogs.submitUpdateLogs"></span></button></div>
|
||||
</div>
|
||||
<div class="settings-set-container statistics-container">
|
||||
<div><button class="dangerous-button" @click="logsClear()">Очистить логи <span class="submit-spinner" v-show="paramLogs.submitClearLogs"></span></button></div>
|
||||
</div>
|
||||
</div>
|
@@ -1,48 +1,50 @@
|
||||
statRx: {
|
||||
// индикаторы
|
||||
state: '?', // общее состояние
|
||||
sym_sync_lock: '?', // захват символьной
|
||||
freq_search_lock: '?', // Захват поиска по частоте
|
||||
afc_lock: '?', // захват ФАПЧ
|
||||
pkt_sync: '?', // захват пакетной синхронизации
|
||||
statRx: {
|
||||
// индикаторы
|
||||
state: '?', // общее состояние
|
||||
sym_sync_lock: '?', // захват символьной
|
||||
freq_search_lock: '?', // Захват поиска по частоте
|
||||
afc_lock: '?', // захват ФАПЧ
|
||||
pkt_sync: '?', // захват пакетной синхронизации
|
||||
|
||||
// куча других параметров, идет в том же порядке, что и в таблице
|
||||
snr: '?', rssi: '?',
|
||||
modcod: '?', frameSizeNormal: '?',
|
||||
isPilots: '?',
|
||||
symError: '?',
|
||||
freqErr: '?', freqErrAcc: '?',
|
||||
inputSignalLevel: '?',
|
||||
pllError: '?',
|
||||
speedOnRxKbit: '?',
|
||||
speedOnIifKbit: '?',
|
||||
// куча других параметров, идет в том же порядке, что и в таблице
|
||||
snr: '?', rssi: '?',
|
||||
modcod: '?', frameSizeNormal: '?',
|
||||
isPilots: '?',
|
||||
symError: '?',
|
||||
freqErr: '?', freqErrAcc: '?',
|
||||
inputSignalLevel: '?',
|
||||
pllError: '?',
|
||||
speedOnRxKbit: '?',
|
||||
speedOnIifKbit: '?',
|
||||
|
||||
// статистика пакетов
|
||||
packetsOk: '?', packetsBad: '?', packetsDummy: '?',
|
||||
},
|
||||
statTx: {
|
||||
// состояние
|
||||
state: '?',
|
||||
// статистика пакетов
|
||||
packetsOk: '?', packetsBad: '?', packetsDummy: '?',
|
||||
},
|
||||
statTx: {
|
||||
// состояние
|
||||
state: '?',
|
||||
|
||||
// прочие поля
|
||||
{% if modem == 'scpc' %}
|
||||
snr: '?', modcod: '?', frameSizeNormal: '?', isPilots: '?', speedOnTxKbit: '?', speedOnIifKbit: '?'
|
||||
{% else %}
|
||||
modcod: '?', speedOnTxKbit: '?', speedOnIifKbit: '?', centerFreq: '?', symSpeed: '?'
|
||||
{% endif %}
|
||||
},
|
||||
{% if modem == 'scpc' %}
|
||||
statCinc: {
|
||||
occ: '?',
|
||||
correlator: null,
|
||||
correlatorFails: '?',
|
||||
freqErr: '?', freqErrAcc: '?',
|
||||
channelDelay: '?'
|
||||
},
|
||||
{% endif %}
|
||||
statDevice: { // температурные датчики
|
||||
adrv: 0, zynq: 0, fpga: 0{% if modem == 'tdma' %}, upgradeStatus: "", upgradePercent: 0, upgradeImage: ""{% endif %}
|
||||
|
||||
},
|
||||
statOs: {uptime: '?', load1: '?', load5: '?', load15: '?', totalram: '?', freeram: '?'},
|
||||
// прочие поля
|
||||
{% if modem == 'scpc' %}
|
||||
snr: '?', modcod: '?', frameSizeNormal: '?', isPilots: '?', speedOnTxKbit: '?', speedOnIifKbit: '?'
|
||||
{% else %}
|
||||
modcod: '?', speedOnTxKbit: '?', speedOnIifKbit: '?', centerFreq: '?', symSpeed: '?'
|
||||
{% endif %}
|
||||
},
|
||||
{% if modem == 'scpc' %}
|
||||
statCinc: {
|
||||
occ: '?',
|
||||
correlator: null,
|
||||
correlatorFails: '?',
|
||||
freqErr: '?', freqErrAcc: '?',
|
||||
channelDelay: '?'
|
||||
},
|
||||
{% endif %}
|
||||
statDevice: { // температурные датчики
|
||||
adrv: 0, zynq: 0, fpga: 0
|
||||
{% if modem == 'tdma' %},
|
||||
upgradeStatus: "", upgradePercent: 0, upgradeImage: ""
|
||||
{% endif %}
|
||||
},
|
||||
statOs: {uptime: '?', load1: '?', load5: '?', load15: '?', totalram: '?', freeram: '?'},
|
||||
|
||||
|
@@ -1,110 +1,111 @@
|
||||
updateStatistics(vals) {
|
||||
function modcodToStr(modcod) {
|
||||
// модкоды из раздела 5.5.2.2 https://www.etsi.org/deliver/etsi_en/302300_302399/302307/01.01.02_60/en_302307v010102p.pdf
|
||||
const modcods = [
|
||||
"DUMMY",
|
||||
"QPSK 1/4", "QPSK 1/3", "QPSK 2/5", "QPSK 1/2", "QPSK 3/5", "QPSK 2/3", "QPSK 3/4", "QPSK 4/5", "QPSK 5/6", "QPSK 8/9", "QPSK 9/10",
|
||||
"8PSK 3/5", "8PSK 2/3", "8PSK 3/4", "8PSK 5/6", "8PSK 8/9", "8PSK 9/10",
|
||||
"16APSK 2/3", "16APSK 3/4", "16APSK 4/5", "16APSK 5/6", "16APSK 8/9", "16APSK 9/10",
|
||||
"32APSK 3/4", "32APSK 4/5", "32APSK 5/6", "32APSK 8/9", "32APSK 9/10",
|
||||
]
|
||||
if (typeof modcod != "number") {
|
||||
return "?";
|
||||
}
|
||||
if (modcod < 0 || modcod >= modcods.length) {
|
||||
return `? (${modcod})`
|
||||
}
|
||||
return modcods[modcod]
|
||||
}
|
||||
updateStatistics(vals) {
|
||||
function modcodToStr(modcod) {
|
||||
// модкоды из раздела 5.5.2.2 https://www.etsi.org/deliver/etsi_en/302300_302399/302307/01.01.02_60/en_302307v010102p.pdf
|
||||
const modcods = [
|
||||
"DUMMY",
|
||||
"QPSK 1/4", "QPSK 1/3", "QPSK 2/5", "QPSK 1/2", "QPSK 3/5", "QPSK 2/3", "QPSK 3/4", "QPSK 4/5", "QPSK 5/6", "QPSK 8/9", "QPSK 9/10",
|
||||
"8PSK 3/5", "8PSK 2/3", "8PSK 3/4", "8PSK 5/6", "8PSK 8/9", "8PSK 9/10",
|
||||
"16APSK 2/3", "16APSK 3/4", "16APSK 4/5", "16APSK 5/6", "16APSK 8/9", "16APSK 9/10",
|
||||
"32APSK 3/4", "32APSK 4/5", "32APSK 5/6", "32APSK 8/9", "32APSK 9/10",
|
||||
]
|
||||
if (typeof modcod != "number") {
|
||||
return "?";
|
||||
}
|
||||
if (modcod < 0 || modcod >= modcods.length) {
|
||||
return `? (${modcod})`
|
||||
}
|
||||
return modcods[modcod]
|
||||
}
|
||||
|
||||
this.lastUpdateTime = new Date();
|
||||
this.initState = vals["state"]["initState"]
|
||||
this.testState = vals["state"]["testState"]
|
||||
{% if modem == 'scpc' %}
|
||||
this.isCinC = vals["state"]["isCinC"]
|
||||
{% endif %}
|
||||
this.lastUpdateTime = new Date();
|
||||
this.initState = vals["mainState"]["initState"]
|
||||
{% if modem == 'scpc' %}
|
||||
this.isCinC = vals["mainState"]["isCinC"]
|
||||
{% endif %}
|
||||
|
||||
this.statRx.state = vals["state"]["rx"]["state"]
|
||||
this.statRx.sym_sync_lock = vals["state"]["rx"]["sym_sync_lock"]
|
||||
this.statRx.freq_search_lock = vals["state"]["rx"]["freq_search_lock"]
|
||||
this.statRx.afc_lock = vals["state"]["rx"]["afc_lock"]
|
||||
this.statRx.pkt_sync = vals["state"]["rx"]["pkt_sync"]
|
||||
this.statRx.snr = Math.round(vals["state"]["rx"]["snr"] * 10) / 10
|
||||
this.statRx.rssi = Math.round(vals["state"]["rx"]["rssi"] * 10) / 10
|
||||
this.statRx.modcod = modcodToStr(vals["state"]["rx"]["modcod"])
|
||||
this.statRx.frameSizeNormal = vals["state"]["rx"]["frameSizeNormal"]
|
||||
this.statRx.isPilots = vals["state"]["rx"]["isPilots"]
|
||||
this.statRx.symError = vals["state"]["rx"]["symError"]
|
||||
this.statRx.freqErr = Math.round(vals["state"]["rx"]["freqErr"] * 100) / 100
|
||||
this.statRx.freqErrAcc = Math.round(vals["state"]["rx"]["freqErrAcc"] * 100) / 100
|
||||
this.statRx.inputSignalLevel = vals["state"]["rx"]["inputSignalLevel"]
|
||||
this.statRx.pllError = Math.round(vals["state"]["rx"]["pllError"] * 100) / 100
|
||||
this.statRx.speedOnRxKbit = Math.round(vals["state"]["rx"]["speedOnRxKbit"] * 100) / 100
|
||||
this.statRx.speedOnIifKbit = Math.round(vals["state"]["rx"]["speedOnIifKbit"] * 100) / 100
|
||||
this.statRx.packetsOk = vals["state"]["rx"]["packetsOk"]
|
||||
this.statRx.packetsBad = vals["state"]["rx"]["packetsBad"]
|
||||
this.statRx.packetsDummy = vals["state"]["rx"]["packetsDummy"]
|
||||
this.statRx.state = vals["mainState"]["rx.state"]
|
||||
this.statRx.sym_sync_lock = vals["mainState"]["rx.sym_sync_lock"]
|
||||
this.statRx.freq_search_lock = vals["mainState"]["rx.freq_search_lock"]
|
||||
this.statRx.afc_lock = vals["mainState"]["rx.afc_lock"]
|
||||
this.statRx.pkt_sync = vals["mainState"]["rx.pkt_sync"]
|
||||
this.statRx.snr = vals["mainState"]["rx.snr"]
|
||||
this.statRx.rssi = vals["mainState"]["rx.rssi"]
|
||||
this.statRx.modcod = modcodToStr(vals["mainState"]["rx.modcod"])
|
||||
this.statRx.frameSizeNormal = vals["mainState"]["rx.frameSizeNormal"]
|
||||
this.statRx.isPilots = vals["mainState"]["rx.isPilots"]
|
||||
this.statRx.symError = vals["mainState"]["rx.symError"]
|
||||
this.statRx.freqErr = vals["mainState"]["rx.freqErr"]
|
||||
this.statRx.freqErrAcc = vals["mainState"]["rx.freqErrAcc"]
|
||||
this.statRx.inputSignalLevel = vals["mainState"]["rx.inputSignalLevel"]
|
||||
this.statRx.pllError = vals["mainState"]["rx.pllError"]
|
||||
this.statRx.speedOnRxKbit = vals["mainState"]["rx.speedOnRxKbit"]
|
||||
this.statRx.speedOnIifKbit = vals["mainState"]["rx.speedOnIifKbit"]
|
||||
this.statRx.packetsOk = vals["mainState"]["rx.packetsOk"]
|
||||
this.statRx.packetsBad = vals["mainState"]["rx.packetsBad"]
|
||||
this.statRx.packetsDummy = vals["mainState"]["rx.packetsDummy"]
|
||||
|
||||
{% if modem == 'scpc' %}
|
||||
this.statTx.state = vals["state"]["tx"]["state"]
|
||||
this.statTx.snr = Math.round(vals["state"]["tx"]["snr"] * 100) / 100
|
||||
this.statTx.modcod = modcodToStr(vals["state"]["tx"]["modcod"])
|
||||
this.statTx.frameSizeNormal = vals["state"]["tx"]["frameSizeNormal"]
|
||||
this.statTx.isPilots = vals["state"]["tx"]["isPilots"]
|
||||
this.statTx.speedOnTxKbit = Math.round(vals["state"]["tx"]["speedOnTxKbit"] * 100) / 100
|
||||
this.statTx.speedOnIifKbit = Math.round(vals["state"]["tx"]["speedOnIifKbit"] * 100) / 100
|
||||
{% if modem == 'scpc' %}
|
||||
this.statTx.state = vals["mainState"]["tx.state"]
|
||||
this.statTx.snr = vals["mainState"]["tx.snr"]
|
||||
this.statTx.modcod = modcodToStr(vals["mainState"]["tx.modcod"])
|
||||
this.statTx.frameSizeNormal = vals["mainState"]["tx.frameSizeNormal"]
|
||||
this.statTx.isPilots = vals["mainState"]["tx.isPilots"]
|
||||
this.statTx.speedOnTxKbit = vals["mainState"]["tx.speedOnTxKbit"]
|
||||
this.statTx.speedOnIifKbit = vals["mainState"]["tx.speedOnIifKbit"]
|
||||
|
||||
this.statCinc.occ = vals["state"]["cinc"]["occ"]
|
||||
this.statCinc.correlator = vals["state"]["cinc"]["correlator"]
|
||||
this.statCinc.correlatorFails = vals["state"]["cinc"]["correlatorFails"]
|
||||
this.statCinc.freqErr = Math.round(vals["state"]["cinc"]["freqErr"] * 100) / 100
|
||||
this.statCinc.freqErrAcc = Math.round(vals["state"]["cinc"]["freqErrAcc"] * 100) / 100
|
||||
this.statCinc.channelDelay = vals["state"]["cinc"]["channelDelay"]
|
||||
{% else %}
|
||||
this.statTx.state = vals["state"]["tx"]["state"]
|
||||
this.statTx.modcod = modcodToStr(vals["state"]["tx"]["modcod"])
|
||||
this.statTx.speedOnTxKbit = Math.round(vals["state"]["tx"]["speedOnTxKbit"] * 100) / 100
|
||||
this.statTx.speedOnIifKbit = Math.round(vals["state"]["tx"]["speedOnIifKbit"] * 100) / 100
|
||||
this.statTx.centerFreq = vals["state"]["tx"]["centerFreq"]
|
||||
this.statTx.symSpeed = vals["state"]["tx"]["symSpeed"]
|
||||
{% endif %}
|
||||
this.statCinc.occ = vals["mainState"]["cinc.occ"]
|
||||
this.statCinc.correlator = vals["mainState"]["cinc.correlator"]
|
||||
this.statCinc.correlatorFails = vals["mainState"]["cinc.correlatorFails"]
|
||||
this.statCinc.freqErr = vals["mainState"]["cinc.freqErr"]
|
||||
this.statCinc.freqErrAcc = vals["mainState"]["cinc.freqErrAcc"]
|
||||
this.statCinc.channelDelay = vals["mainState"]["cinc.channelDelay"]
|
||||
{% else %}
|
||||
this.statTx.state = vals["mainState"]["tx.state"]
|
||||
this.statTx.modcod = modcodToStr(vals["mainState"]["tx.modcod"])
|
||||
this.statTx.speedOnTxKbit = vals["mainState"]["tx.speedOnTxKbit"]
|
||||
this.statTx.speedOnIifKbit = vals["mainState"]["tx.speedOnIifKbit"]
|
||||
this.statTx.centerFreq = vals["mainState"]["tx.centerFreq"]
|
||||
this.statTx.symSpeed = vals["mainState"]["tx.symSpeed"]
|
||||
{% endif %}
|
||||
|
||||
this.statDevice.adrv = vals["state"]["device"]["adrv"]
|
||||
this.statDevice.zynq = vals["state"]["device"]["zynq"]
|
||||
this.statDevice.fpga = vals["state"]["device"]["fpga"]
|
||||
{% if modem == 'tdma' %}
|
||||
this.statDevice.upgradeStatus = vals["state"]["device"]["upgradeStatus"]
|
||||
this.statDevice.upgradePercent = vals["state"]["device"]["upgradePercent"]
|
||||
this.statDevice.upgradeImage = vals["state"]["device"]["upgradeImage"]
|
||||
{% endif %}
|
||||
this.statDevice.adrv = vals["mainState"]["device.adrv"]
|
||||
this.statDevice.zynq = vals["mainState"]["device.zynq"]
|
||||
this.statDevice.fpga = vals["mainState"]["device.fpga"]
|
||||
{% if modem == 'tdma' %}
|
||||
this.statDevice.upgradeStatus = vals["mainState"]["device.upgradeStatus"]
|
||||
this.statDevice.upgradePercent = vals["mainState"]["device.upgradePercent"]
|
||||
this.statDevice.upgradeImage = vals["mainState"]["device.upgradeImage"]
|
||||
{% endif %}
|
||||
|
||||
// аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид
|
||||
let uptime = vals["state"]["device"]["uptime"]
|
||||
if (uptime) {
|
||||
let secs = uptime % 60; uptime = Math.floor(uptime / 60)
|
||||
let mins = uptime % 60; uptime = Math.floor(uptime / 60)
|
||||
let hours = uptime % 24
|
||||
uptime = Math.floor( uptime / 24)
|
||||
let res = `${hours}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
|
||||
if (uptime > 0) { res = `${uptime} дней, ` + res }
|
||||
this.statOs.uptime = res
|
||||
} else {
|
||||
this.statOs.uptime = '?'
|
||||
}
|
||||
this.statOs.load1 = Math.round(vals["state"]["device"]["load1min"] * 100) / 100
|
||||
this.statOs.load5 = Math.round(vals["state"]["device"]["load5min"] * 100) / 100
|
||||
this.statOs.load15 = Math.round(vals["state"]["device"]["load15min"] * 100) / 100
|
||||
this.statOs.totalram = vals["state"]["device"]["totalram"]
|
||||
this.statOs.freeram = vals["state"]["device"]["freeram"]
|
||||
},
|
||||
this.testState = vals["mainState"]["testState"]
|
||||
|
||||
resetPacketsStatistics() {
|
||||
fetch('/api/resetPacketStatistics', {
|
||||
method: 'POST', credentials: 'same-origin'
|
||||
}).then(() => {
|
||||
this.statRx.packetsOk = 0
|
||||
this.statRx.packetsBad = 0
|
||||
this.statRx.packetsDummy = 0
|
||||
})
|
||||
},
|
||||
// аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид
|
||||
let uptime = vals["sysinfo"]["uptime"]
|
||||
if (uptime) {
|
||||
let secs = uptime % 60; uptime = Math.floor(uptime / 60)
|
||||
let mins = uptime % 60; uptime = Math.floor(uptime / 60)
|
||||
let hours = uptime % 24
|
||||
uptime = Math.floor( uptime / 24)
|
||||
let res = `${hours}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
|
||||
if (uptime > 0) { res = `${uptime} дней, ` + res }
|
||||
this.statOs.uptime = res
|
||||
} else {
|
||||
this.statOs.uptime = '?'
|
||||
}
|
||||
this.statOs.load1 = vals["sysinfo"]["load1min"]
|
||||
this.statOs.load5 = vals["sysinfo"]["load5min"]
|
||||
this.statOs.load15 = vals["sysinfo"]["load15min"]
|
||||
this.statOs.totalram = vals["sysinfo"]["totalram"]
|
||||
this.statOs.freeram = vals["sysinfo"]["freeram"]
|
||||
},
|
||||
|
||||
resetPacketsStatistics() {
|
||||
fetch('/api/resetPacketStatistics', {
|
||||
method: 'POST', credentials: 'same-origin'
|
||||
}).then(() => {
|
||||
this.statRx.packetsOk = 0
|
||||
this.statRx.packetsBad = 0
|
||||
this.statRx.packetsDummy = 0
|
||||
})
|
||||
},
|
||||
|
||||
|
@@ -1,102 +1,84 @@
|
||||
{% raw %}<div class="tabs-body-item tabs-item-flex-container" v-if="activeTab === 'monitoring'">
|
||||
<div class="settings-set-container statistics-container">
|
||||
<h2>Статистика приема</h2>
|
||||
<table>
|
||||
<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.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>Modcod</th><td>{{ statRx.modcod }}</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.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>
|
||||
<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>
|
||||
</table>
|
||||
<button class="action-button" @click="resetPacketsStatistics()"> Сброс статистики </button>
|
||||
</div>
|
||||
<div class="settings-set-container statistics-container">
|
||||
<h2>Статистика передачи</h2>{% endraw %}{% if modem == 'scpc' %}{% 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.snr }}</td></tr>
|
||||
<tr><th>Modcod</th><td>{{ statTx.modcod }}</td></tr>
|
||||
<tr><th>Размер кадра</th><td>{{ statTx.frameSizeNormal ? 'normal' : 'short' }}</td></tr>
|
||||
<tr><th>Пилот-символы</th><td>{{ statTx.isPilots ? 'pilots' : 'no pilots' }}</td></tr>
|
||||
<tr><th>Инф. скорость на передаче</th><td>{{ statTx.speedOnTxKbit }} кбит/с</td></tr>
|
||||
<tr><th>Инф. скорость на интерфейсе</th><td>{{ statTx.speedOnIifKbit }} кбит/с</td></tr>
|
||||
</tbody>
|
||||
</table>{% endraw %}{% elif modem == 'tdma' %}{% 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>Modcod</th><td>{{ statTx.modcod }}</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 %}{% 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 %}
|
||||
</div>{% endraw %}{% if modem == 'scpc' %}{% raw %}
|
||||
<div class="settings-set-container statistics-container" v-if="paramRxtx.isCinC === true">
|
||||
<h2>Статистика режима CinC</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>ОСС</th><td>{{ statCinc.occ }}</td></tr>
|
||||
<tr><th>Захват коррелятора</th><td><span :class="{ indicator_bad: statCinc.correlator === false, indicator_good: statCinc.correlator === true, indicator: true }"></span></td></tr>
|
||||
<tr><th>Кол-во срывов коррелятора</th><td>{{ statCinc.correlatorFails }}</td></tr>
|
||||
<tr><th>Грубая/точная част. ошибка, Гц</th><td>{{ statCinc.freqErr }} / {{ statCinc.freqErrAcc }}</td></tr>
|
||||
<tr><th>Задержка в канале, мс</th><td>{{ statCinc.channelDelay }}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>{% endraw %}{% endif %}{% raw %}
|
||||
<div class="settings-set-container statistics-container">
|
||||
<h2>Состояние устройства</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>Температура ADRV</th><td>{{ statDevice.adrv }} °C</td></tr>
|
||||
<tr><th>Температура ZYNQ</th><td>{{ statDevice.zynq }} °C</td></tr>
|
||||
<tr><th>Температура FPGA</th><td>{{ statDevice.fpga }} °C</td></tr>
|
||||
<tr><th>Время работы устройства</th><td>{{ statOs.uptime }}</td></tr>
|
||||
<tr><th>Средняя загрузка ЦП (1/5/15 мин.)</th><td>{{ statOs.load1 }}% {{ statOs.load5 }}% {{ statOs.load15 }}%</td></tr>
|
||||
<tr><th>ОЗУ всего/свободно</th><td>{{ statOs.totalram }}МБ/{{ statOs.freeram }}МБ</td></tr>{% endraw %}{% if modem == 'tdma' %}{% raw %}
|
||||
<tr><td colspan="2" style="padding-top: 1em; text-align: center">Статус обновления</td></tr>
|
||||
<tr><th>Статус</th><td>{{ statDevice.upgradeStatus }}</td></tr>
|
||||
<tr><th>Прогресс</th><td>{{ statDevice.upgradePercent }}%</td></tr>
|
||||
<tr><th>Имя образа</th><td><code>{{ statDevice.upgradeImage }}</code></td></tr>{% endraw %}{% endif %}{% raw %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endraw %}
|
||||
{% raw %}
|
||||
<div class="tabs-body-item tabs-item-flex-container" v-if="activeTab === 'monitoring'">
|
||||
<div class="settings-set-container statistics-container">
|
||||
<h2>Статистика приема</h2>
|
||||
<table>
|
||||
<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.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>SNR/RSSI</th><td>{{ statRx.snr }} / {{ statRx.rssi }}</td></tr>
|
||||
<tr><th>Modcod</th><td>{{ statRx.modcod }}</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.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>
|
||||
<tr><th>DUMMY</th><td>{{ statRx.packetsDummy }}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<button class="action-button" @click="resetPacketsStatistics()"> Сброс статистики </button>
|
||||
</div>
|
||||
<div class="settings-set-container statistics-container">
|
||||
<h2>Статистика передачи</h2>{% endraw %}{% if modem == 'scpc' %}{% 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.snr }}</td></tr>
|
||||
<tr><th>Modcod</th><td>{{ statTx.modcod }}</td></tr>
|
||||
<tr><th>Размер кадра</th><td>{{ statTx.frameSizeNormal ? 'normal' : 'short' }}</td></tr>
|
||||
<tr><th>Пилот-символы</th><td>{{ statTx.isPilots ? 'pilots' : 'no pilots' }}</td></tr>
|
||||
<tr><th>Инф. скорость на передаче</th><td>{{ statTx.speedOnTxKbit }} кбит/с</td></tr>
|
||||
<tr><th>Инф. скорость на интерфейсе</th><td>{{ statTx.speedOnIifKbit }} кбит/с</td></tr>
|
||||
</tbody>
|
||||
</table>{% endraw %}{% else %}{% 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>Modcod</th><td>{{ statTx.modcod }}</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 %}
|
||||
</div>{% endraw %}{% if modem == 'scpc' %}{% raw %}
|
||||
<div class="settings-set-container statistics-container" v-if="paramRxtx.isCinC === true">
|
||||
<h2>Статистика режима CinC</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>ОСС</th><td>{{ statCinc.occ }}</td></tr>
|
||||
<tr><th>Захват коррелятора</th><td><span :class="{ indicator_bad: statCinc.correlator === false, indicator_good: statCinc.correlator === true, indicator: true }"></span></td></tr>
|
||||
<tr><th>Кол-во срывов коррелятора</th><td>{{ statCinc.correlatorFails }}</td></tr>
|
||||
<tr><th>Грубая/точная част. ошибка, Гц</th><td>{{ statCinc.freqErr }} / {{ statCinc.freqErrAcc }}</td></tr>
|
||||
<tr><th>Задержка в канале, мс</th><td>{{ statCinc.channelDelay }}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>{% endraw %}{% endif %}{% raw %}
|
||||
<div class="settings-set-container statistics-container">
|
||||
<h2>Состояние устройства</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>Температура ADRV</th><td>{{ statDevice.adrv }} °C</td></tr>
|
||||
<tr><th>Температура ZYNQ</th><td>{{ statDevice.zynq }} °C</td></tr>
|
||||
<tr><th>Температура FPGA</th><td>{{ statDevice.fpga }} °C</td></tr>
|
||||
<tr><th>Время работы устройства</th><td>{{ statOs.uptime }}</td></tr>
|
||||
<tr><th>Средняя загрузка ЦП (1/5/15 мин.)</th><td>{{ statOs.load1 }}% {{ statOs.load5 }}% {{ statOs.load15 }}%</td></tr>
|
||||
<tr><th>ОЗУ всего/свободно</th><td>{{ statOs.totalram }}МБ/{{ statOs.freeram }}МБ</td></tr>{% endraw %}{% if modem == 'tdma' %}{% raw %}
|
||||
<tr><td colspan="2" style="padding-top: 1em; text-align: center">Статус обновления</td></tr>
|
||||
<tr><th>Статус</th><td>{{ statDevice.upgradeStatus }}</td></tr>
|
||||
<tr><th>Прогресс</th><td>{{ statDevice.upgradePercent }}%</td></tr>
|
||||
<tr><th>Имя образа</th><td><code>{{ statDevice.upgradeImage }}</code></td></tr>{% endraw %}{% endif %}{% raw %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
{% endraw %}
|
@@ -1,9 +1,8 @@
|
||||
submitStatusQos: false,
|
||||
paramQos: {
|
||||
en: false,
|
||||
rt1: [],
|
||||
rt2: [],
|
||||
rt3: [],
|
||||
cd: [],
|
||||
},
|
||||
|
||||
submitStatusQos: false,
|
||||
paramQos: {
|
||||
en: false,
|
||||
rt1: [],
|
||||
rt2: [],
|
||||
rt3: [],
|
||||
cd: [],
|
||||
},
|
||||
|
@@ -1,224 +1,222 @@
|
||||
settingsSubmitQoS() {
|
||||
if (this.submitStatusQos) { return }
|
||||
this.submitStatusQos = true
|
||||
function _translateQosClass(trafficClass, qc) {
|
||||
let res = {
|
||||
cir: qc['cir'],
|
||||
description: qc['description'],
|
||||
filters: []
|
||||
}
|
||||
if (trafficClass === 'cd') {
|
||||
res.pir = qc.pir
|
||||
}
|
||||
if (!qc.isEnabled) {
|
||||
res.disabled = true
|
||||
}
|
||||
for (const fi in qc.filters) {
|
||||
let filter = {}
|
||||
if (qc['filters'][fi].vlan !== "") { filter['vlan'] = qc['filters'][fi].vlan }
|
||||
if (qc['filters'][fi].proto.length > 0) {
|
||||
let tmp = "";
|
||||
for (let pid = 0; pid < qc['filters'][fi].proto.length; pid++) {
|
||||
if (pid !== 0) { tmp += ',' }
|
||||
tmp += qc['filters'][fi].proto[pid]
|
||||
}
|
||||
filter['proto'] = tmp
|
||||
}
|
||||
if (qc['filters'][fi].sport !== "") { filter['sport'] = qc['filters'][fi].sport }
|
||||
if (qc['filters'][fi].dport !== "") { filter['dport'] = qc['filters'][fi].dport }
|
||||
if (qc['filters'][fi].ip_src !== "") { filter['ip_src'] = qc['filters'][fi].ip_src }
|
||||
if (qc['filters'][fi].ip_dest !== "") { filter['ip_dest'] = qc['filters'][fi].ip_dest }
|
||||
if (qc['filters'][fi].dscp !== "") { filter['dscp'] = qc['filters'][fi].dscp }
|
||||
|
||||
if (Object.keys(filter).length === 0) { continue }
|
||||
if (!qc.filters[fi].isEnabled) { filter['disabled'] = true }
|
||||
|
||||
res.filters.push(filter)
|
||||
}
|
||||
if (res.filters.length === 0) {
|
||||
// автоматическое выключение класса, если правил нет
|
||||
res.disabled = true
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
let query = {
|
||||
"en": this.paramQos.en,
|
||||
"profile": {
|
||||
"rt1": [],
|
||||
"rt2": [],
|
||||
"rt3": [],
|
||||
"cd": []
|
||||
}
|
||||
}
|
||||
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.rt2.length; i++) { query.profile.rt2.push(_translateQosClass('rt', this.paramQos.rt2[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)
|
||||
fetch('/api/set/qos', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(query), credentials: 'same-origin'
|
||||
}).then(async (resp) => {
|
||||
this.submitStatusQos = false
|
||||
if (resp['error']) { throw new Error(resp['error']) }
|
||||
this.updateQosSettings(await resp.json())
|
||||
}).catch((reason) => {
|
||||
this.submitStatusQos = false
|
||||
alert(`Ошибка при применении настроек: ${reason}`)
|
||||
})
|
||||
},
|
||||
|
||||
updateQosSettings(vals) {
|
||||
this.submitStatusQos = false
|
||||
this.paramQos.en = vals["settings"]["qos"]["en"]
|
||||
|
||||
const qosProfile = vals["settings"]["qos"]["profile"]
|
||||
if (qosProfile !== null && qosProfile !== undefined) {
|
||||
this.paramQos.rt1 = [] // .splice(0, this.paramQos.rt1.length)
|
||||
this.paramQos.rt2 = [] // .splice(0, this.paramQos.rt2.length)
|
||||
this.paramQos.rt3 = [] // .splice(0, this.paramQos.rt3.length)
|
||||
this.paramQos.cd = [] // .splice(0, this.paramQos.cd.length)
|
||||
|
||||
for (let trafficClass in qosProfile) {
|
||||
if (['rt1', 'rt2', 'rt3', 'cd'].indexOf(trafficClass) < 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (Array.isArray(qosProfile[trafficClass])) {
|
||||
for (let i = 0; i < qosProfile[trafficClass].length; i++) {
|
||||
const qc = qosProfile[trafficClass][i]
|
||||
let result = {
|
||||
isEnabled: !qc.hasOwnProperty('disabled'),
|
||||
settingsSubmitQoS() {
|
||||
if (this.submitStatusQos) { return }
|
||||
this.submitStatusQos = true
|
||||
function _translateQosClass(trafficClass, qc) {
|
||||
let res = {
|
||||
cir: qc['cir'],
|
||||
pir: 0,
|
||||
description: qc['description'],
|
||||
filters: []
|
||||
}
|
||||
if (trafficClass === 'cd') {
|
||||
if (qc['pir']) {
|
||||
result.pir = qc['pir']
|
||||
res.pir = qc.pir
|
||||
}
|
||||
if (!qc.isEnabled) {
|
||||
res.disabled = true
|
||||
}
|
||||
for (const fi in qc.filters) {
|
||||
let filter = {}
|
||||
if (qc['filters'][fi].vlan !== "") { filter['vlan'] = qc['filters'][fi].vlan }
|
||||
if (qc['filters'][fi].proto.length > 0) {
|
||||
let tmp = "";
|
||||
for (let pid = 0; pid < qc['filters'][fi].proto.length; pid++) {
|
||||
if (pid !== 0) { tmp += ',' }
|
||||
tmp += qc['filters'][fi].proto[pid]
|
||||
}
|
||||
filter['proto'] = tmp
|
||||
}
|
||||
if (qc['filters'][fi].sport !== "") { filter['sport'] = qc['filters'][fi].sport }
|
||||
if (qc['filters'][fi].dport !== "") { filter['dport'] = qc['filters'][fi].dport }
|
||||
if (qc['filters'][fi].ip_src !== "") { filter['ip_src'] = qc['filters'][fi].ip_src }
|
||||
if (qc['filters'][fi].ip_dest !== "") { filter['ip_dest'] = qc['filters'][fi].ip_dest }
|
||||
if (qc['filters'][fi].dscp !== "") { filter['dscp'] = qc['filters'][fi].dscp }
|
||||
|
||||
if (Object.keys(filter).length === 0) { continue }
|
||||
if (!qc.filters[fi].isEnabled) { filter['disabled'] = true }
|
||||
|
||||
res.filters.push(filter)
|
||||
}
|
||||
if (res.filters.length === 0) {
|
||||
// автоматическое выключение класса, если правил нет
|
||||
res.disabled = true
|
||||
}
|
||||
|
||||
return res
|
||||
}
|
||||
let query = {
|
||||
"en": this.paramQos.en,
|
||||
"rt1": [],
|
||||
"rt2": [],
|
||||
"rt3": [],
|
||||
"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.rt3.length; i++) { query.rt3.push(_translateQosClass('rt', this.paramQos.rt3[i])) }
|
||||
for (let i = 0; i < this.paramQos.cd.length; i++) { query.cd.push(_translateQosClass('rt', this.paramQos.cd[i])) }
|
||||
|
||||
//console.log(query)
|
||||
fetch('/api/set/qos', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(query), credentials: 'same-origin'
|
||||
}).then(async (resp) => {
|
||||
this.submitStatusQos = false
|
||||
if (resp['error']) { throw new Error(resp['error']) }
|
||||
this.updateQosSettings(await resp.json())
|
||||
}).catch((reason) => {
|
||||
this.submitStatusQos = false
|
||||
alert(`Ошибка при применении настроек: ${reason}`)
|
||||
})
|
||||
},
|
||||
|
||||
updateQosSettings(vals) {
|
||||
this.submitStatusQos = false
|
||||
this.paramQos.en = vals["settings"]["qosEnabled"]
|
||||
|
||||
const qosProfile = vals["settings"]["qosProfile"]
|
||||
if (qosProfile !== null && qosProfile !== undefined) {
|
||||
this.paramQos.rt1 = [] // .splice(0, this.paramQos.rt1.length)
|
||||
this.paramQos.rt2 = [] // .splice(0, this.paramQos.rt2.length)
|
||||
this.paramQos.rt3 = [] // .splice(0, this.paramQos.rt3.length)
|
||||
this.paramQos.cd = [] // .splice(0, this.paramQos.cd.length)
|
||||
|
||||
for (let trafficClass in qosProfile) {
|
||||
if (['rt1', 'rt2', 'rt3', 'cd'].indexOf(trafficClass) < 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
if (Array.isArray(qosProfile[trafficClass])) {
|
||||
for (let i = 0; i < qosProfile[trafficClass].length; i++) {
|
||||
const qc = qosProfile[trafficClass][i]
|
||||
let result = {
|
||||
isEnabled: !qc.hasOwnProperty('disabled'),
|
||||
cir: qc['cir'],
|
||||
pir: 0,
|
||||
description: qc['description'],
|
||||
filters: []
|
||||
}
|
||||
if (trafficClass === 'cd') {
|
||||
if (qc['pir']) {
|
||||
result.pir = qc['pir']
|
||||
}
|
||||
}
|
||||
for (let fi = 0; fi < qc['filters'].length; fi++) {
|
||||
result.filters.push({
|
||||
isEnabled: !qc['filters'][fi].hasOwnProperty('disabled'),
|
||||
vlan: qc['filters'][fi].hasOwnProperty('vlan') ? qc['filters'][fi]['vlan'] : '',
|
||||
proto: qc['filters'][fi].hasOwnProperty('proto') ? qc['filters'][fi]['proto'].split(',') : [],
|
||||
sport: qc['filters'][fi].hasOwnProperty('sport') ? qc['filters'][fi]['sport'] : '',
|
||||
dport: qc['filters'][fi].hasOwnProperty('dport') ? qc['filters'][fi]['dport'] : '',
|
||||
ip_src: qc['filters'][fi].hasOwnProperty('ip_src') ? qc['filters'][fi]['ip_src'] : '',
|
||||
ip_dest: qc['filters'][fi].hasOwnProperty('ip_dest') ? qc['filters'][fi]['ip_dest'] : '',
|
||||
dscp: qc['filters'][fi].hasOwnProperty('dscp') ? qc['filters'][fi]['dscp'] : ''
|
||||
})
|
||||
}
|
||||
switch (trafficClass) {
|
||||
case 'rt1': this.paramQos.rt1.push(result); break
|
||||
case 'rt2': this.paramQos.rt2.push(result); break
|
||||
case 'rt3': this.paramQos.rt3.push(result); break
|
||||
case 'cd': this.paramQos.cd.push(result); break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (let fi = 0; fi < qc['filters'].length; fi++) {
|
||||
result.filters.push({
|
||||
isEnabled: !qc['filters'][fi].hasOwnProperty('disabled'),
|
||||
vlan: qc['filters'][fi].hasOwnProperty('vlan') ? qc['filters'][fi]['vlan'] : '',
|
||||
proto: qc['filters'][fi].hasOwnProperty('proto') ? qc['filters'][fi]['proto'].split(',') : [],
|
||||
sport: qc['filters'][fi].hasOwnProperty('sport') ? qc['filters'][fi]['sport'] : '',
|
||||
dport: qc['filters'][fi].hasOwnProperty('dport') ? qc['filters'][fi]['dport'] : '',
|
||||
ip_src: qc['filters'][fi].hasOwnProperty('ip_src') ? qc['filters'][fi]['ip_src'] : '',
|
||||
ip_dest: qc['filters'][fi].hasOwnProperty('ip_dest') ? qc['filters'][fi]['ip_dest'] : '',
|
||||
dscp: qc['filters'][fi].hasOwnProperty('dscp') ? qc['filters'][fi]['dscp'] : ''
|
||||
})
|
||||
}
|
||||
},
|
||||
|
||||
qosAddClass(name) {
|
||||
let res = {
|
||||
isEnabled: true,
|
||||
cir: 0,
|
||||
pir: 0,
|
||||
description: "",
|
||||
filters: []
|
||||
}
|
||||
switch (name) {
|
||||
case 'rt1': this.paramQos.rt1.push(res); break
|
||||
case 'rt2': this.paramQos.rt2.push(res); break
|
||||
case 'rt3': this.paramQos.rt3.push(res); break
|
||||
case 'cd': this.paramQos.cd.push(res); break
|
||||
}
|
||||
},
|
||||
|
||||
qosClassAddRule(name, index) {
|
||||
let rule = {
|
||||
isEnabled: true,
|
||||
vlan: "",
|
||||
proto: [],
|
||||
sport: "",
|
||||
dport: "",
|
||||
ip_src: "",
|
||||
ip_dest: "",
|
||||
dscp: ""
|
||||
}
|
||||
switch (name) {
|
||||
case 'rt1': this.paramQos.rt1[index].filters.push(rule); break
|
||||
case 'rt2': this.paramQos.rt2[index].filters.push(rule); break
|
||||
case 'rt3': this.paramQos.rt3[index].filters.push(rule); break
|
||||
case 'cd': this.paramQos.cd[index].filters.push(rule); break
|
||||
}
|
||||
},
|
||||
|
||||
qosDelClass(name, index) {
|
||||
switch (name) {
|
||||
case 'rt1': this.paramQos.rt1.splice(index, 1); break
|
||||
case 'rt2': this.paramQos.rt2.splice(index, 1); break
|
||||
case 'rt3': this.paramQos.rt3.splice(index, 1); break
|
||||
case 'cd': this.paramQos.cd.splice(index, 1); break
|
||||
}
|
||||
},
|
||||
|
||||
qosDelFilter(name, index, filterIndex) {
|
||||
switch (name) {
|
||||
case 'rt1': this.paramQos.rt1[index].filters.splice(filterIndex, 1); break
|
||||
case 'rt2': this.paramQos.rt2[index].filters.splice(filterIndex, 1); break
|
||||
case 'rt3': this.paramQos.rt3[index].filters.splice(filterIndex, 1); break
|
||||
case 'cd': this.paramQos.cd[index].filters.splice(filterIndex, 1); break
|
||||
}
|
||||
},
|
||||
|
||||
qosGenerateRuleDescription(filter) {
|
||||
// попытка 1: просто отобразить все фильтры
|
||||
let result = ""
|
||||
let isFirst = true;
|
||||
for (const key in filter) {
|
||||
if (key === "isEnabled" || !filter[key] || (key === "proto" && filter['proto'].length === 0)) {
|
||||
continue
|
||||
}
|
||||
switch (trafficClass) {
|
||||
case 'rt1': this.paramQos.rt1.push(result); break
|
||||
case 'rt2': this.paramQos.rt2.push(result); break
|
||||
case 'rt3': this.paramQos.rt3.push(result); break
|
||||
case 'cd': this.paramQos.cd.push(result); break
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
} else {
|
||||
result += '; '
|
||||
}
|
||||
result += `${key}: ${filter[key]}`
|
||||
}
|
||||
if (result === "") {
|
||||
return "пустой"
|
||||
}
|
||||
|
||||
const maxResultLen = 60
|
||||
|
||||
if (result.length > maxResultLen) {
|
||||
// попытка 2, отобразить что вообще в этом фильтре использовалось
|
||||
result = ""
|
||||
isFirst = true;
|
||||
for (const key in filter) {
|
||||
if (key === "isEnabled" || !filter[key] || (key === "proto" && filter['proto'].length === 0)) {
|
||||
continue
|
||||
}
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
} else {
|
||||
result += ', '
|
||||
}
|
||||
result += `${key}`
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
qosAddClass(name) {
|
||||
let res = {
|
||||
isEnabled: true,
|
||||
cir: 0,
|
||||
pir: 0,
|
||||
description: "",
|
||||
filters: []
|
||||
}
|
||||
switch (name) {
|
||||
case 'rt1': this.paramQos.rt1.push(res); break
|
||||
case 'rt2': this.paramQos.rt2.push(res); break
|
||||
case 'rt3': this.paramQos.rt3.push(res); break
|
||||
case 'cd': this.paramQos.cd.push(res); break
|
||||
}
|
||||
},
|
||||
|
||||
qosClassAddRule(name, index) {
|
||||
let rule = {
|
||||
isEnabled: true,
|
||||
vlan: "",
|
||||
proto: [],
|
||||
sport: "",
|
||||
dport: "",
|
||||
ip_src: "",
|
||||
ip_dest: "",
|
||||
dscp: ""
|
||||
}
|
||||
switch (name) {
|
||||
case 'rt1': this.paramQos.rt1[index].filters.push(rule); break
|
||||
case 'rt2': this.paramQos.rt2[index].filters.push(rule); break
|
||||
case 'rt3': this.paramQos.rt3[index].filters.push(rule); break
|
||||
case 'cd': this.paramQos.cd[index].filters.push(rule); break
|
||||
}
|
||||
},
|
||||
|
||||
qosDelClass(name, index) {
|
||||
switch (name) {
|
||||
case 'rt1': this.paramQos.rt1.splice(index, 1); break
|
||||
case 'rt2': this.paramQos.rt2.splice(index, 1); break
|
||||
case 'rt3': this.paramQos.rt3.splice(index, 1); break
|
||||
case 'cd': this.paramQos.cd.splice(index, 1); break
|
||||
}
|
||||
},
|
||||
|
||||
qosDelFilter(name, index, filterIndex) {
|
||||
switch (name) {
|
||||
case 'rt1': this.paramQos.rt1[index].filters.splice(filterIndex, 1); break
|
||||
case 'rt2': this.paramQos.rt2[index].filters.splice(filterIndex, 1); break
|
||||
case 'rt3': this.paramQos.rt3[index].filters.splice(filterIndex, 1); break
|
||||
case 'cd': this.paramQos.cd[index].filters.splice(filterIndex, 1); break
|
||||
}
|
||||
},
|
||||
|
||||
qosGenerateRuleDescription(filter) {
|
||||
// попытка 1: просто отобразить все фильтры
|
||||
let result = ""
|
||||
let isFirst = true;
|
||||
for (const key in filter) {
|
||||
if (key === "isEnabled" || !filter[key] || (key === "proto" && filter['proto'].length === 0)) {
|
||||
continue
|
||||
}
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
} else {
|
||||
result += '; '
|
||||
}
|
||||
result += `${key}: ${filter[key]}`
|
||||
}
|
||||
if (result === "") {
|
||||
return "пустой"
|
||||
}
|
||||
|
||||
const maxResultLen = 60
|
||||
|
||||
if (result.length > maxResultLen) {
|
||||
// попытка 2, отобразить что вообще в этом фильтре использовалось
|
||||
result = ""
|
||||
isFirst = true;
|
||||
for (const key in filter) {
|
||||
if (key === "isEnabled" || !filter[key] || (key === "proto" && filter['proto'].length === 0)) {
|
||||
continue
|
||||
}
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
} else {
|
||||
result += ', '
|
||||
}
|
||||
result += `${key}`
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
},
|
||||
return result
|
||||
},
|
||||
|
||||
|
@@ -1,107 +1,107 @@
|
||||
{% from 'common/widgets.j2' import build_widget %}
|
||||
{% raw %}
|
||||
<div class="tabs-body-item" v-if="activeTab === 'qos' && settingFetchComplete">
|
||||
<h2>Настройки QoS</h2>
|
||||
<div class="settings-set-container">
|
||||
<label>
|
||||
<span>Активировать QoS</span>
|
||||
<span class="toggle-input"><input type="checkbox" v-model="paramQos.en" /><span class="slider"></span></span>
|
||||
</label>
|
||||
</div>
|
||||
<div v-for="classesGroup in ['rt1', 'rt2', 'rt3', 'cd']">
|
||||
<h3>Классы {{ classesGroup.toUpperCase() }} <button class="action-button" @click="qosAddClass(classesGroup)"> + </button></h3>
|
||||
<details v-for="(qosClass, index) in paramQos[classesGroup]" :key="index" class="settings-set-container">
|
||||
<summary>
|
||||
<span v-if="classesGroup === 'cd'">#{{ index }} CIR={{ qosClass.cir }}кбит, PIR={{ qosClass.pir }}кбит {{ qosClass.description }}</span>
|
||||
<span v-if="classesGroup !== 'cd'">#{{ index }} CBR={{ qosClass.cir }}кбит {{ qosClass.description }}</span>
|
||||
<span class="summary-actions">
|
||||
<label>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="qosClass.isEnabled" />
|
||||
<span class="slider"></span>
|
||||
<div class="tabs-body-item" v-if="activeTab === 'qos' && settingFetchComplete">
|
||||
<h2>Настройки QoS</h2>
|
||||
<div class="settings-set-container">
|
||||
<label>
|
||||
<span>Активировать QoS</span>
|
||||
<span class="toggle-input"><input type="checkbox" v-model="paramQos.en" /><span class="slider"></span></span>
|
||||
</label>
|
||||
</div>
|
||||
<div v-for="classesGroup in ['rt1', 'rt2', 'rt3', 'cd']">
|
||||
<h3>Классы {{ classesGroup.toUpperCase() }} <button class="action-button" @click="qosAddClass(classesGroup)"> + </button></h3>
|
||||
<details v-for="(qosClass, index) in paramQos[classesGroup]" :key="index" class="settings-set-container">
|
||||
<summary>
|
||||
<span v-if="classesGroup === 'cd'">#{{ index }} CIR={{ qosClass.cir }}кбит, PIR={{ qosClass.pir }}кбит {{ qosClass.description }}</span>
|
||||
<span v-if="classesGroup !== 'cd'">#{{ index }} CBR={{ qosClass.cir }}кбит {{ qosClass.description }}</span>
|
||||
<span class="summary-actions">
|
||||
<label>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="qosClass.isEnabled" />
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
</span>
|
||||
</summary>
|
||||
<label>
|
||||
<span v-if="classesGroup === 'cd'">CIR</span> <span v-if="classesGroup !== 'cd'">CBR</span>
|
||||
<input v-model="qosClass.cir" type="number"/>
|
||||
</label>
|
||||
<label v-if="classesGroup === 'cd'">
|
||||
<span>PIR</span>
|
||||
<input v-model="qosClass.pir" type="number"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Описание</span>
|
||||
<input v-model="qosClass.description"/>
|
||||
</label>
|
||||
</span>
|
||||
</summary>
|
||||
<label>
|
||||
<span v-if="classesGroup === 'cd'">CIR</span> <span v-if="classesGroup !== 'cd'">CBR</span>
|
||||
<input v-model="qosClass.cir" type="number"/>
|
||||
</label>
|
||||
<label v-if="classesGroup === 'cd'">
|
||||
<span>PIR</span>
|
||||
<input v-model="qosClass.pir" type="number"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Описание</span>
|
||||
<input v-model="qosClass.description"/>
|
||||
</label>
|
||||
|
||||
<h3>Фильтры ({{ qosClass.filters.length }})</h3>
|
||||
<div>
|
||||
<button class="action-button" @click="qosClassAddRule(classesGroup, index)">Добавить правило</button>
|
||||
</div>
|
||||
<details v-for="(filter, filterIndex) in qosClass.filters" :key="filterIndex" class="settings-set-container">
|
||||
<summary>
|
||||
<span>#{{ filterIndex }} {{ qosGenerateRuleDescription(filter) }}</span>
|
||||
<span class="summary-actions">
|
||||
<label>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="filter.isEnabled" />
|
||||
<span class="slider"></span>
|
||||
<h3>Фильтры ({{ qosClass.filters.length }})</h3>
|
||||
<div>
|
||||
<button class="action-button" @click="qosClassAddRule(classesGroup, index)">Добавить правило</button>
|
||||
</div>
|
||||
<details v-for="(filter, filterIndex) in qosClass.filters" :key="filterIndex" class="settings-set-container">
|
||||
<summary>
|
||||
<span>#{{ filterIndex }} {{ qosGenerateRuleDescription(filter) }}</span>
|
||||
<span class="summary-actions">
|
||||
<label>
|
||||
<span class="toggle-input">
|
||||
<input type="checkbox" v-model="filter.isEnabled" />
|
||||
<span class="slider"></span>
|
||||
</span>
|
||||
</label>
|
||||
<button class="dangerous-button" @click="qosDelFilter(classesGroup, index, filterIndex)">Del</button>
|
||||
</span>
|
||||
</summary>
|
||||
<label>
|
||||
<span>VLAN ID</span>
|
||||
<!-- singleVlanExpr: (([0-9]{1,4}-[0-9]{1,4})|([0-9]{1,4}))-->
|
||||
<!-- expr: ^(((single,)+single)|single)$-->
|
||||
<input v-model="filter.vlan" type="text" pattern="^((((([0-9]{1,4}-[0-9]{1,4})|([0-9]{1,4})),)+(([0-9]{1,4}-[0-9]{1,4})|([0-9]{1,4})))|(([0-9]{1,4}-[0-9]{1,4})|([0-9]{1,4})))$">
|
||||
</label>
|
||||
<button class="dangerous-button" @click="qosDelFilter(classesGroup, index, filterIndex)">Del</button>
|
||||
</span>
|
||||
</summary>
|
||||
<label>
|
||||
<span>VLAN ID</span>
|
||||
<!-- singleVlanExpr: (([0-9]{1,4}-[0-9]{1,4})|([0-9]{1,4}))-->
|
||||
<!-- expr: ^(((single,)+single)|single)$-->
|
||||
<input v-model="filter.vlan" type="text" pattern="^((((([0-9]{1,4}-[0-9]{1,4})|([0-9]{1,4})),)+(([0-9]{1,4}-[0-9]{1,4})|([0-9]{1,4})))|(([0-9]{1,4}-[0-9]{1,4})|([0-9]{1,4})))$">
|
||||
</label>
|
||||
<div>
|
||||
<span>Протокол L3</span>
|
||||
<label class="l3-proto-label"><span>AH:</span><input type="checkbox" value="ah" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>COMP:</span><input type="checkbox" value="comp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>DCCP:</span><input type="checkbox" value="dccp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>ESP:</span><input type="checkbox" value="esp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>ICMP:</span><input type="checkbox" value="icmp" v-model="filter.proto"></label>
|
||||
<!-- <label class="l3-proto-label"><span>ICMPV6:</span><input type="checkbox" value="icmpv6" v-model="filter.proto"></label>-->
|
||||
<label class="l3-proto-label"><span>SCTP:</span><input type="checkbox" value="sctp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>TCP:</span><input type="checkbox" value="tcp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>UDP:</span><input type="checkbox" value="udp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>UDPLITE:</span><input type="checkbox" value="udplite" v-model="filter.proto"></label>
|
||||
</div>
|
||||
<label>
|
||||
<span>Порт источника</span>
|
||||
<input v-model="filter.sport" type="text" pattern="^((((([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})),)+(([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})))|(([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})))$">
|
||||
</label>
|
||||
<label>
|
||||
<span>Порт назначения</span>
|
||||
<input v-model="filter.dport" type="text" pattern="^((((([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})),)+(([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})))|(([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})))$">
|
||||
</label>
|
||||
<label>
|
||||
<span>IP источника</span>
|
||||
<input v-model="filter.ip_src" type="text">
|
||||
</label>
|
||||
<label>
|
||||
<span>IP назначения</span>
|
||||
<input v-model="filter.ip_dest" type="text">
|
||||
</label>
|
||||
<label>
|
||||
<span>Метка IP.DSCP</span>
|
||||
<input v-model="filter.dscp" type="text">
|
||||
</label>
|
||||
</details>
|
||||
<div>
|
||||
<span>Протокол L3</span>
|
||||
<label class="l3-proto-label"><span>AH:</span><input type="checkbox" value="ah" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>COMP:</span><input type="checkbox" value="comp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>DCCP:</span><input type="checkbox" value="dccp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>ESP:</span><input type="checkbox" value="esp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>ICMP:</span><input type="checkbox" value="icmp" v-model="filter.proto"></label>
|
||||
<!-- <label class="l3-proto-label"><span>ICMPV6:</span><input type="checkbox" value="icmpv6" v-model="filter.proto"></label>-->
|
||||
<label class="l3-proto-label"><span>SCTP:</span><input type="checkbox" value="sctp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>TCP:</span><input type="checkbox" value="tcp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>UDP:</span><input type="checkbox" value="udp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>UDPLITE:</span><input type="checkbox" value="udplite" v-model="filter.proto"></label>
|
||||
</div>
|
||||
<label>
|
||||
<span>Порт источника</span>
|
||||
<input v-model="filter.sport" type="text" pattern="^((((([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})),)+(([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})))|(([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})))$">
|
||||
</label>
|
||||
<label>
|
||||
<span>Порт назначения</span>
|
||||
<input v-model="filter.dport" type="text" pattern="^((((([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})),)+(([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})))|(([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})))$">
|
||||
</label>
|
||||
<label>
|
||||
<span>IP источника</span>
|
||||
<input v-model="filter.ip_src" type="text">
|
||||
</label>
|
||||
<label>
|
||||
<span>IP назначения</span>
|
||||
<input v-model="filter.ip_dest" type="text">
|
||||
</label>
|
||||
<label>
|
||||
<span>Метка IP.DSCP</span>
|
||||
<input v-model="filter.dscp" type="text">
|
||||
</label>
|
||||
</details>
|
||||
|
||||
<div>
|
||||
<button class="dangerous-button" @click="qosDelClass(classesGroup, index)">Удалить класс QoS</button>
|
||||
<div>
|
||||
<button class="dangerous-button" @click="qosDelClass(classesGroup, index)">Удалить класс QoS</button>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</details>
|
||||
</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>
|
||||
|
||||
{% endraw %}{% if 'tcpaccel' in params %}
|
||||
{% for w in params['tcpaccel'] %}{{ build_widget('tcpaccel', w) | indent(4, true) }}{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endraw %}{% if 'tcpaccel' in params %}
|
||||
{% for w in params['tcpaccel'] %}{{ build_widget('tcpaccel', w) | indent(12, true) }}{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
@@ -1,34 +1,34 @@
|
||||
{% if 'rxtx' in params and modem == 'scpc' %}
|
||||
calcRequiredSnr(frameSizeNormal, modulation, speed) {
|
||||
const snrValues = [
|
||||
{fs: true, mod: 'qpsk', speed: '1/4', snr: 2.6}, {fs: true, mod: 'qpsk', speed: '1/3', snr: 2.6}, {fs: true, mod: 'qpsk', speed: '2/5', snr: 2.6}, {fs: true, mod: 'qpsk', speed: '1/2', snr: 2.6}, {fs: true, mod: 'qpsk', speed: '3/5', snr: 3.1}, {fs: true, mod: 'qpsk', speed: '2/3', snr: 3.8}, {fs: true, mod: 'qpsk', speed: '3/4', snr: 4.5}, {fs: true, mod: 'qpsk', speed: '4/5', snr: 5.2}, {fs: true, mod: 'qpsk', speed: '5/6', snr: 5.5}, {fs: true, mod: 'qpsk', speed: '8/9', snr: 6.4}, {fs: true, mod: 'qpsk', speed: '9/10', snr: 6.7},
|
||||
{fs: true, mod: '8psk', speed: '3/5', snr: 7.4}, {fs: true, mod: '8psk', speed: '2/3', snr: 8.4}, {fs: true, mod: '8psk', speed: '3/4', snr: 8.7}, {fs: true, mod: '8psk', speed: '5/6', snr: 10}, {fs: true, mod: '8psk', speed: '8/9', snr: 10.9}, {fs: true, mod: '8psk', speed: '9/10', snr: 11.1},
|
||||
{fs: true, mod: '16apsk', speed: '2/3', snr: 11.2}, {fs: true, mod: '16apsk', speed: '3/4', snr: 11.3}, {fs: true, mod: '16apsk', speed: '4/5', snr: 12.4}, {fs: true, mod: '16apsk', speed: '5/6', snr: 12.7}, {fs: true, mod: '16apsk', speed: '8/9', snr: 13.1}, {fs: true, mod: '16apsk', speed: '9/10', snr: 13.9},
|
||||
{fs: true, mod: '32apsk', speed: '3/4', snr: 14.5}, {fs: true, mod: '32apsk', speed: '4/5', snr: 14.7}, {fs: true, mod: '32apsk', speed: '5/6', snr: 14.9}, {fs: true, mod: '32apsk', speed: '8/9', snr: 16.1}, {fs: true, mod: '32apsk', speed: '9/10', snr: 16.6},
|
||||
calcRequiredSnr(frameSizeNormal, modulation, speed) {
|
||||
const snrValues = [
|
||||
{fs: true, mod: 'qpsk', speed: '1/4', snr: 2.6}, {fs: true, mod: 'qpsk', speed: '1/3', snr: 2.6}, {fs: true, mod: 'qpsk', speed: '2/5', snr: 2.6}, {fs: true, mod: 'qpsk', speed: '1/2', snr: 2.6}, {fs: true, mod: 'qpsk', speed: '3/5', snr: 3.1}, {fs: true, mod: 'qpsk', speed: '2/3', snr: 3.8}, {fs: true, mod: 'qpsk', speed: '3/4', snr: 4.5}, {fs: true, mod: 'qpsk', speed: '4/5', snr: 5.2}, {fs: true, mod: 'qpsk', speed: '5/6', snr: 5.5}, {fs: true, mod: 'qpsk', speed: '8/9', snr: 6.4}, {fs: true, mod: 'qpsk', speed: '9/10', snr: 6.7},
|
||||
{fs: true, mod: '8psk', speed: '3/5', snr: 7.4}, {fs: true, mod: '8psk', speed: '2/3', snr: 8.4}, {fs: true, mod: '8psk', speed: '3/4', snr: 8.7}, {fs: true, mod: '8psk', speed: '5/6', snr: 10}, {fs: true, mod: '8psk', speed: '8/9', snr: 10.9}, {fs: true, mod: '8psk', speed: '9/10', snr: 11.1},
|
||||
{fs: true, mod: '16apsk', speed: '2/3', snr: 11.2}, {fs: true, mod: '16apsk', speed: '3/4', snr: 11.3}, {fs: true, mod: '16apsk', speed: '4/5', snr: 12.4}, {fs: true, mod: '16apsk', speed: '5/6', snr: 12.7}, {fs: true, mod: '16apsk', speed: '8/9', snr: 13.1}, {fs: true, mod: '16apsk', speed: '9/10', snr: 13.9},
|
||||
{fs: true, mod: '32apsk', speed: '3/4', snr: 14.5}, {fs: true, mod: '32apsk', speed: '4/5', snr: 14.7}, {fs: true, mod: '32apsk', speed: '5/6', snr: 14.9}, {fs: true, mod: '32apsk', speed: '8/9', snr: 16.1}, {fs: true, mod: '32apsk', speed: '9/10', snr: 16.6},
|
||||
|
||||
{fs: false, mod: 'qpsk', speed: '1/4', snr: 4.1}, {fs: false, mod: 'qpsk', speed: '1/3', snr: 4.1}, {fs: false, mod: 'qpsk', speed: '2/5', snr: 4.1}, {fs: false, mod: 'qpsk', speed: '1/2', snr: 4.1}, {fs: false, mod: 'qpsk', speed: '3/5', snr: 4.6}, {fs: false, mod: 'qpsk', speed: '2/3', snr: 5.1}, {fs: false, mod: 'qpsk', speed: '3/4', snr: 5.3}, {fs: false, mod: 'qpsk', speed: '4/5', snr: 6.8}, {fs: false, mod: 'qpsk', speed: '5/6', snr: 7.8}, {fs: false, mod: 'qpsk', speed: '8/9', snr: 8.5},
|
||||
{fs: false, mod: '8psk', speed: '3/5', snr: 9.5}, {fs: false, mod: '8psk', speed: '2/3', snr: 9.9}, {fs: false, mod: '8psk', speed: '3/4', snr: 10.5}, {fs: false, mod: '8psk', speed: '5/6', snr: 11.1}, {fs: false, mod: '8psk', speed: '8/9', snr: 11.3},
|
||||
{fs: false, mod: '16apsk', speed: '2/3', snr: 11.6}, {fs: false, mod: '16apsk', speed: '3/4', snr: 11.8}, {fs: false, mod: '16apsk', speed: '4/5', snr: 12}, {fs: false, mod: '16apsk', speed: '5/6', snr: 12.3}, {fs: false, mod: '16apsk', speed: '8/9', snr: 13.4},
|
||||
{fs: false, mod: '32apsk', speed: '3/4', snr: 14.1}, {fs: false, mod: '32apsk', speed: '4/5', snr: 14.7}, {fs: false, mod: '32apsk', speed: '5/6', snr: 15.3}, {fs: false, mod: '32apsk', speed: '8/9', snr: 16.5},
|
||||
]
|
||||
for (let i = 0; i < snrValues.length; i++) {
|
||||
if (snrValues[i].fs === frameSizeNormal && snrValues[i].mod === modulation && snrValues[i].speed === speed) { return snrValues[i].snr }
|
||||
}
|
||||
return '?'
|
||||
},
|
||||
calcInterfaceSpeedKb(baud, modulation, speed, frameSizeNormal) {
|
||||
const mBaud = parseInt(baud.replace(/[^0-9]/g, ''))
|
||||
const mMod = Math.max(2, ['', '', 'qpsk', '8psk', '16apsk', '32apsk'].indexOf(modulation))
|
||||
const speedVals = {'1/4': 0.25, '1/3': 0.333, '2/5': 0.4, '1/2': 0.5, '3/5': 0.6, '2/3': 0.666, '3/4': 0.75, '4/5': 0.8, '5/6': 0.833, '8/9': 0.888, '9/10': 0.9}
|
||||
const mSpeed = speed in speedVals ? speedVals[speed] : 1
|
||||
const result = (mBaud * mMod * mSpeed) / 1024
|
||||
const calcSnr = this.calcRequiredSnr(frameSizeNormal, modulation, speed)
|
||||
let snr;
|
||||
if (isNaN(calcSnr)) { snr = `ОСШ=?` } else { snr=`ОСШ=${calcSnr}` }
|
||||
if (result > 1024) {
|
||||
return toLocaleStringWithSpaces(result / 1024) + ' Мбит/с; ' + snr
|
||||
} else {
|
||||
return toLocaleStringWithSpaces(result) + ' кбит/с; ' + snr
|
||||
}
|
||||
},
|
||||
{fs: false, mod: 'qpsk', speed: '1/4', snr: 4.1}, {fs: false, mod: 'qpsk', speed: '1/3', snr: 4.1}, {fs: false, mod: 'qpsk', speed: '2/5', snr: 4.1}, {fs: false, mod: 'qpsk', speed: '1/2', snr: 4.1}, {fs: false, mod: 'qpsk', speed: '3/5', snr: 4.6}, {fs: false, mod: 'qpsk', speed: '2/3', snr: 5.1}, {fs: false, mod: 'qpsk', speed: '3/4', snr: 5.3}, {fs: false, mod: 'qpsk', speed: '4/5', snr: 6.8}, {fs: false, mod: 'qpsk', speed: '5/6', snr: 7.8}, {fs: false, mod: 'qpsk', speed: '8/9', snr: 8.5},
|
||||
{fs: false, mod: '8psk', speed: '3/5', snr: 9.5}, {fs: false, mod: '8psk', speed: '2/3', snr: 9.9}, {fs: false, mod: '8psk', speed: '3/4', snr: 10.5}, {fs: false, mod: '8psk', speed: '5/6', snr: 11.1}, {fs: false, mod: '8psk', speed: '8/9', snr: 11.3},
|
||||
{fs: false, mod: '16apsk', speed: '2/3', snr: 11.6}, {fs: false, mod: '16apsk', speed: '3/4', snr: 11.8}, {fs: false, mod: '16apsk', speed: '4/5', snr: 12}, {fs: false, mod: '16apsk', speed: '5/6', snr: 12.3}, {fs: false, mod: '16apsk', speed: '8/9', snr: 13.4},
|
||||
{fs: false, mod: '32apsk', speed: '3/4', snr: 14.1}, {fs: false, mod: '32apsk', speed: '4/5', snr: 14.7}, {fs: false, mod: '32apsk', speed: '5/6', snr: 15.3}, {fs: false, mod: '32apsk', speed: '8/9', snr: 16.5},
|
||||
]
|
||||
for (let i = 0; i < snrValues.length; i++) {
|
||||
if (snrValues[i].fs === frameSizeNormal && snrValues[i].mod === modulation && snrValues[i].speed === speed) { return snrValues[i].snr }
|
||||
}
|
||||
return '?'
|
||||
},
|
||||
calcInterfaceSpeedKb(baud, modulation, speed, frameSizeNormal) {
|
||||
const mBaud = parseInt(baud.replace(/[^0-9]/g, ''))
|
||||
const mMod = Math.max(2, ['', '', 'qpsk', '8psk', '16apsk', '32apsk'].indexOf(modulation))
|
||||
const speedVals = {'1/4': 0.25, '1/3': 0.333, '2/5': 0.4, '1/2': 0.5, '3/5': 0.6, '2/3': 0.666, '3/4': 0.75, '4/5': 0.8, '5/6': 0.833, '8/9': 0.888, '9/10': 0.9}
|
||||
const mSpeed = speed in speedVals ? speedVals[speed] : 1
|
||||
const result = (mBaud * mMod * mSpeed) / 1024
|
||||
const calcSnr = this.calcRequiredSnr(frameSizeNormal, modulation, speed)
|
||||
let snr;
|
||||
if (isNaN(calcSnr)) { snr = `ОСШ=?` } else { snr=`ОСШ=${calcSnr}` }
|
||||
if (result > 1024) {
|
||||
return toLocaleStringWithSpaces(result / 1024) + ' Мбит/с; ' + snr
|
||||
} else {
|
||||
return toLocaleStringWithSpaces(result) + ' кбит/с; ' + snr
|
||||
}
|
||||
},
|
||||
{% endif %}
|
||||
|
@@ -1,8 +1,8 @@
|
||||
{% from 'common/widgets.j2' import build_widget %}
|
||||
<div class="tabs-body-item" v-if="activeTab === 'setup' && settingFetchComplete">
|
||||
{% for cat in ['rxtx', 'dpdi', 'buclnb'] %}
|
||||
{% if cat in params %}
|
||||
{% for w in params[cat] %}{{ build_widget(cat, w) | indent(4, true) }}{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
<div class="tabs-body-item" v-if="activeTab === 'setup' && settingFetchComplete">
|
||||
{% for cat in ['rxtx', 'dpdi', 'buclnb'] %}
|
||||
{% if cat in params %}
|
||||
{% for w in params[cat] %}{{ build_widget(cat, w) | indent(12, true) }}{% endfor %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</div>
|
@@ -58,10 +58,6 @@
|
||||
<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]?)$">
|
||||
</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 %}>
|
||||
<span>{{ widget.label }}</span>
|
||||
@@ -82,23 +78,22 @@
|
||||
{% 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 == '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) }}
|
||||
{% else %}<p>Widget '{{ widget.widget }}' not defined!</p><p>{{ widget }}</p>
|
||||
{% endif %}
|
||||
{% endmacro %}
|
||||
|
||||
{% 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', 'ip-address-mask', 'modulation-modcod', 'modulation-speed', 'text'] %}this.param{{ param_group | title }}.{{ widget.name }}{%
|
||||
elif widget.widget in ['checkbox', 'number', 'select', 'ip-address', '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(',', '.')){%
|
||||
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{%
|
||||
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 in ['checkbox', 'number', 'select', 'ip-address', '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) }}){%
|
||||
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{%
|
||||
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 in ['checkbox', 'number', 'select', 'ip-address', '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) }}){%
|
||||
else %}<p>Widget '{{ widget.widget }}' not defined!</p><p>{{ widget }}</p>{% endif %}{% endmacro %}
|
||||
|
@@ -1,18 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
{% macro include_macro(file) %}
|
||||
// ========== include from '{{ file }}'
|
||||
{% include file %}
|
||||
// ========== include end from '{{ file }}'
|
||||
{% endmacro %}
|
||||
{% macro include_macro_no_comment(file) %}
|
||||
{% include file %}
|
||||
{% endmacro %}
|
||||
{% macro include_macro_ignore_missing(file) %}
|
||||
// ========== include from '{{ file }}'
|
||||
{% include file ignore missing %}
|
||||
// ========== include end from '{{ file }}'
|
||||
{% endmacro %}
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
@@ -66,7 +53,7 @@
|
||||
</div>
|
||||
</header>
|
||||
<div id="content">
|
||||
{% for tab in header_tabs %}{{ include_macro_no_comment('common/' ~ tab.name ~ '.html.j2') | indent(8, true) }}{% endfor %}
|
||||
{% for tab in header_tabs %}{% include 'common/' ~ tab.name ~ '.html.j2' %}{% endfor %}
|
||||
{% raw %}
|
||||
<p>Последнее обновление статистики: {{ lastUpdateTime }}</p>
|
||||
</div>
|
||||
@@ -112,18 +99,20 @@
|
||||
firmwareUpgrade: false,
|
||||
{% if modem == 'tdma' %}
|
||||
firmwareUpgradeOta: false,
|
||||
cesPassword: false,
|
||||
{% endif %}
|
||||
// когда модем перезагружается, тут должен быть счетчик. Направление счета - к нулю
|
||||
modemReboot: null
|
||||
},
|
||||
{% if modem == 'tdma' %}
|
||||
cesPasswordValue: '',
|
||||
{% endif %}
|
||||
|
||||
{{ include_macro('common/all-params-data.js.j2') | indent(16, true) }}
|
||||
// ========== include from 'common/all-params-data.js.j2'
|
||||
{% include 'common/all-params-data.js.j2' %}
|
||||
// ========== include end from 'common/all-params-data.js.j2'
|
||||
|
||||
{% for tab in header_tabs %}
|
||||
{{ include_macro_ignore_missing('common/' ~ tab.name ~ '-data.js.j2') | indent(16, true) }}
|
||||
// ========== include from '{{ 'common/' ~ tab.name ~ '-data.js.j2' }}'
|
||||
{% include 'common/' ~ tab.name ~ '-data.js.j2' ignore missing %}
|
||||
// ========== include end from '{{ 'common/' ~ tab.name ~ '-data.js.j2' }}'
|
||||
|
||||
{% endfor %}
|
||||
uploadFw: {
|
||||
progress: null,
|
||||
@@ -190,9 +179,15 @@
|
||||
return toLocaleStringWithSpaces(result)
|
||||
},
|
||||
|
||||
{{ include_macro('common/all-params-methods.js.j2') | indent(12, true) }}
|
||||
// ========== include from 'common/all-params-methods.js.j2'
|
||||
{% include 'common/all-params-methods.js.j2' %}
|
||||
// ========== include end from 'common/all-params-methods.js.j2'
|
||||
|
||||
{% for tab in header_tabs %}
|
||||
{{ include_macro_ignore_missing('common/' ~ tab.name ~ '-methods.js.j2') | indent(12, true) }}
|
||||
// ========== include from '{{ 'common/' ~ tab.name ~ '-methods.js.j2' }}'
|
||||
{% include 'common/' ~ tab.name ~ '-methods.js.j2' ignore missing %}
|
||||
// ========== include end from '{{ 'common/' ~ tab.name ~ '-methods.js.j2' }}'
|
||||
|
||||
{% endfor %}
|
||||
|
||||
performUpdateSettings() {
|
||||
@@ -240,11 +235,11 @@
|
||||
try {
|
||||
const fr = await fetch("/api/get/aboutFirmware")
|
||||
const d = await fr.json()
|
||||
this.about.firmwareVersion = d["firmware"]["version"]
|
||||
this.about.modemUid = d["firmware"]["modemId"]
|
||||
this.about.modemSn = d["firmware"]["modemSn"]
|
||||
this.about.macManagement = d["firmware"]["macMang"]
|
||||
this.about.macData = d["firmware"]["macData"]
|
||||
this.about.firmwareVersion = d["fw.version"]
|
||||
this.about.modemUid = d["fw.modemId"]
|
||||
this.about.modemSn = d["fw.modemSn"]
|
||||
this.about.macManagement = d["fw.macMang"]
|
||||
this.about.macData = d["fw.macData"]
|
||||
} catch (e) {
|
||||
console.log('Ошибка загрузки версии ПО', e)
|
||||
}
|
||||
|
@@ -1,283 +0,0 @@
|
||||
#include "daemon.h"
|
||||
#include <utility>
|
||||
|
||||
#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() {
|
||||
{
|
||||
std::lock_guard _lock(this->stateMutex);
|
||||
this->state.fInitState = "Not connected to API";
|
||||
}
|
||||
#ifdef API_OBJECT_NETWORK_SETTINGS_ENABLE
|
||||
{
|
||||
std::lock_guard _lock(this->settingsMutex);
|
||||
this->settingsNetwork.loadDefaults();
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int connectAttempt = 0;; connectAttempt++) {
|
||||
BOOST_LOG_TRIVIAL(info) << "api_driver::TerminalApiDaemon::connectToApi(): Try to connect api (attempt " << connectAttempt << ")...";
|
||||
try {
|
||||
cp.connect();
|
||||
|
||||
std::string tmp = cp.getDmaDebug("status_init");
|
||||
{
|
||||
std::lock_guard _lock(this->stateMutex);
|
||||
this->state.fInitState = tmp;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << "api_driver::TerminalApiDaemon::connectToApi(): Success connect!";
|
||||
BOOST_LOG_TRIVIAL(info) << "api_driver::TerminalApiDaemon::connectToApi(): API status: " << tmp;
|
||||
|
||||
obj::TerminalFirmwareVersion f;
|
||||
f.load(cp);
|
||||
|
||||
{
|
||||
std::lock_guard _lock(this->firmwareMutex);
|
||||
this->firmware = f;
|
||||
}
|
||||
|
||||
cp.lastCpError = OK;
|
||||
break;
|
||||
} catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::connectToApi(): connect error " << e.what();
|
||||
}
|
||||
boost::this_thread::sleep_for(boost::chrono::duration(boost::chrono::milliseconds(1000)));
|
||||
}
|
||||
}
|
||||
|
||||
void api_driver::TerminalApiDaemon::run() {
|
||||
// это демон, который в бесконечном цикле опрашивает API
|
||||
this->connectToApi();
|
||||
|
||||
struct {
|
||||
CpUpdatebleObject uo;
|
||||
std::string updaterName;
|
||||
} updaters[] = {
|
||||
#ifdef API_OBJECT_DEBUG_METRICS_ENABLE
|
||||
// обновление логов
|
||||
{.uo = CpUpdatebleObject([this]() {
|
||||
this->statsLogs.updateCallback(cp);
|
||||
}), .updaterName = "updateDebugMetrics"},
|
||||
#endif
|
||||
// обновление статистики
|
||||
{.uo = CpUpdatebleObject([this]() {
|
||||
|
||||
obj::TerminalState tmp;
|
||||
{
|
||||
std::shared_lock _slock1(this->settingsMutex);
|
||||
tmp = state;
|
||||
}
|
||||
|
||||
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"},
|
||||
// обновление кеша настроек
|
||||
{.uo = CpUpdatebleObject([this]() {
|
||||
obj::TerminalRxTxSettings rxtx;
|
||||
rxtx.updateCallback(cp);
|
||||
std::lock_guard _slock2(this->settingsMutex);
|
||||
settingsRxTx = rxtx;
|
||||
}, 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);
|
||||
std::lock_guard _slock2(this->settingsMutex);
|
||||
settingsNetwork = net;
|
||||
}, CACHE_SETTINGS_UPDATE_MS), .updaterName = "updateNetworkSettings"},
|
||||
#endif
|
||||
#ifdef API_OBJECT_QOS_SETTINGS_ENABLE
|
||||
// обновление кеша QoS
|
||||
{.uo = CpUpdatebleObject([this]() {
|
||||
obj::TerminalQosSettings qos;
|
||||
qos.updateCallback(cp);
|
||||
std::lock_guard _slock(this->settingsMutex);
|
||||
settingsQos = qos;
|
||||
}, CACHE_SETTINGS_UPDATE_MS), .updaterName = "updateQosSettings"},
|
||||
#endif
|
||||
};
|
||||
|
||||
while (true) {
|
||||
if (this->cp.lastCpError == ERROR || this->cp.lastCpError == TIMEOUT) {
|
||||
BOOST_LOG_TRIVIAL(error) << "api_driver::TerminalApiDaemon::run(): close current daemon session caused error " << this->cp.lastCpError;
|
||||
cp.disconnect();
|
||||
this->connectToApi();
|
||||
}
|
||||
#ifdef API_OBJECT_DEBUG_METRICS_ENABLE
|
||||
updaters[0].uo.updatePeriodMs = this->statsLogs.logEn ? this->statsLogs.logPeriodMs.load() : -1;
|
||||
#endif
|
||||
int64_t sleepTime = 60000; // минута по-умолчанию
|
||||
auto now = TimeNow();
|
||||
for (auto& u: updaters) {
|
||||
if (u.uo.checkNeedUpdate(now)) {
|
||||
auto targetTime = u.uo.lastUpdate + u.uo.updatePeriodMs;
|
||||
if (targetTime + SLEEP_THRESHOLD <= now && targetTime - SLEEP_THRESHOLD >= now) {
|
||||
u.uo.lastUpdate = targetTime;
|
||||
} else {
|
||||
u.uo.lastUpdate = now;
|
||||
}
|
||||
|
||||
try {
|
||||
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();
|
||||
}
|
||||
|
||||
now = TimeNow();
|
||||
}
|
||||
if (u.uo.updatePeriodMs >= 0) {
|
||||
sleepTime = std::min(sleepTime, u.uo.getNextUpdate(now));
|
||||
}
|
||||
}
|
||||
|
||||
if (sleepTime > 0) {
|
||||
boost::this_thread::sleep_for(boost::chrono::duration(boost::chrono::milliseconds(sleepTime)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
api_driver::TerminalApiDaemon::TerminalApiDaemon(): daemon([this]() { this->run(); }) {}
|
||||
|
||||
void api_driver::TerminalApiDaemon::getState(obj::TerminalState &dest) {
|
||||
std::shared_lock _lock(stateMutex);
|
||||
dest = state;
|
||||
}
|
||||
|
||||
void api_driver::TerminalApiDaemon::getDeviceState(obj::TerminalDeviceState &dest) {
|
||||
std::shared_lock _lock(stateMutex);
|
||||
dest = stateDev;
|
||||
}
|
||||
|
||||
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::setSettingsRxTx(obj::TerminalRxTxSettings &s) {
|
||||
std::lock_guard _olock(settingsMutex);
|
||||
settingsRxTx = s;
|
||||
}
|
||||
|
||||
#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::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::setQosSettings(obj::TerminalQosSettings &s) {
|
||||
std::lock_guard _olock(settingsMutex);
|
||||
settingsQos = s;
|
||||
}
|
||||
#endif
|
||||
|
||||
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() {
|
||||
std::lock_guard lock(this->cpApiMutex);
|
||||
cp.getDmaDebug("reset_cnt_rx");
|
||||
}
|
||||
|
||||
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() {
|
||||
try {
|
||||
daemon.interrupt();
|
||||
daemon.try_join_for(boost::chrono::seconds(2));
|
||||
} catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "api_driver::~TerminalApiDaemon(): " << e.what();
|
||||
}
|
||||
}
|
@@ -1,79 +0,0 @@
|
||||
#ifndef API_DRIVER_DAEMON_H
|
||||
#define API_DRIVER_DAEMON_H
|
||||
|
||||
#include "proxy.h"
|
||||
#include "api-driver/structs.h"
|
||||
#include <boost/thread/thread.hpp>
|
||||
|
||||
namespace api_driver {
|
||||
int64_t TimeNow();
|
||||
|
||||
class TerminalApiDaemon {
|
||||
boost::thread daemon;
|
||||
|
||||
void connectToApi();
|
||||
|
||||
void run();
|
||||
|
||||
std::shared_mutex stateMutex;
|
||||
obj::TerminalState state;
|
||||
obj::TerminalDeviceState stateDev;
|
||||
|
||||
std::shared_mutex settingsMutex;
|
||||
obj::TerminalRxTxSettings settingsRxTx;
|
||||
#ifdef API_OBJECT_NETWORK_SETTINGS_ENABLE
|
||||
obj::TerminalNetworkSettings settingsNetwork;
|
||||
#endif
|
||||
#ifdef API_OBJECT_QOS_SETTINGS_ENABLE
|
||||
obj::TerminalQosSettings settingsQos;
|
||||
#endif
|
||||
|
||||
std::shared_mutex firmwareMutex;
|
||||
obj::TerminalFirmwareVersion firmware;
|
||||
|
||||
public:
|
||||
std::mutex cpApiMutex;
|
||||
proxy::CpProxy cp;
|
||||
|
||||
#ifdef API_OBJECT_DEBUG_METRICS_ENABLE
|
||||
obj::StatisticsLogger statsLogs;
|
||||
#endif
|
||||
|
||||
explicit TerminalApiDaemon();
|
||||
|
||||
/**
|
||||
* Получение статистики, копирует текущие значения в структуры, переданные по указателю. Если передан пустой указатель, копирования не произойдет.
|
||||
*/
|
||||
void getState(obj::TerminalState &dest);
|
||||
|
||||
void getDeviceState(obj::TerminalDeviceState &dest);
|
||||
|
||||
// /**
|
||||
// * Получение настроек, копирует текущие значения в структуры, переданные по указателю. Если передан пустой указатель, копирования не произойдет.
|
||||
// * Установка настроек просто копирует настройки и устанавливает их текущими
|
||||
// */
|
||||
obj::TerminalRxTxSettings getSettingsRxTx();
|
||||
void setSettingsRxTx(obj::TerminalRxTxSettings &s);
|
||||
|
||||
#ifdef API_OBJECT_NETWORK_SETTINGS_ENABLE
|
||||
obj::TerminalNetworkSettings getNetworkSettings();
|
||||
void setNetworkSettings(obj::TerminalNetworkSettings &s);
|
||||
#endif
|
||||
|
||||
#ifdef API_OBJECT_QOS_SETTINGS_ENABLE
|
||||
obj::TerminalQosSettings getQosSettings();
|
||||
void setQosSettings(obj::TerminalQosSettings &s);
|
||||
#endif
|
||||
|
||||
obj::TerminalFirmwareVersion getFirmware();
|
||||
|
||||
void resetPacketStatistics();
|
||||
|
||||
void resetDefaultSettings();
|
||||
|
||||
~TerminalApiDaemon();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif //API_DRIVER_DAEMON_H
|
@@ -1,137 +0,0 @@
|
||||
#include "proxy.h"
|
||||
#include "sstream"
|
||||
|
||||
#define CPAPI_PROXY_CALL_HELPER(callfrom, func, funcArgs, throwArgs) do { lastCpError = func funcArgs; if (lastCpError != OK) { \
|
||||
std::stringstream err; err << callfrom ": CP Api error " #func "("; err << throwArgs; err << "): " << lastCpError;\
|
||||
throw std::runtime_error(err.str());\
|
||||
} } while (0)
|
||||
|
||||
|
||||
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 ¶m) {
|
||||
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 ¶m, 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();
|
||||
}
|
@@ -1,82 +0,0 @@
|
||||
#ifndef PROXY_H
|
||||
#define PROXY_H
|
||||
|
||||
#include "api-driver/stricts-enable.h"
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <terminal_api/ControlProtoCInterface.h>
|
||||
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, CP_Result result);
|
||||
|
||||
namespace api_driver::proxy {
|
||||
class CpProxy {
|
||||
public:
|
||||
TSID sid;
|
||||
CP_Result lastCpError = OK;
|
||||
CpProxy();
|
||||
CpProxy(TSID s);
|
||||
|
||||
/**
|
||||
* Вызывает процедуру подключения к CP_API. Бросает исключение, если не удалось подключиться.
|
||||
*/
|
||||
void connect();
|
||||
|
||||
/**
|
||||
* Процедура отключения от API, после ее вызова запрещается использовать CP_API
|
||||
*/
|
||||
void disconnect();
|
||||
|
||||
std::string getDmaDebug(const std::string& arg);
|
||||
void setDmaDebug(const std::string& arg, const std::string& value);
|
||||
|
||||
std::string getNetwork(const std::string& param);
|
||||
void setNetwork(const std::string& param, const std::string& value);
|
||||
|
||||
void getModState(modulator_state& dest);
|
||||
void getModSettings(modulator_settings& dest);
|
||||
void setModSettings(modulator_settings& dest);
|
||||
|
||||
void getDemodState(demodulator_state& dest);
|
||||
void getDemodSettings(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);
|
||||
|
||||
#ifdef API_OBJECT_QOS_SETTINGS_ENABLE
|
||||
std::tuple<std::string, bool> getQosSettings();
|
||||
void setQosSettings(const std::string& rules, bool enable);
|
||||
#endif
|
||||
|
||||
#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);
|
||||
#endif
|
||||
|
||||
#ifdef MODEM_IS_TDMA
|
||||
void getUpdateStatus(progress_msg& dest);
|
||||
#endif
|
||||
|
||||
~CpProxy();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif //PROXY_H
|
@@ -1,34 +0,0 @@
|
||||
#ifndef API_DRIVER_STRICTS_ENABLE_H
|
||||
#define API_DRIVER_STRICTS_ENABLE_H
|
||||
|
||||
|
||||
#if defined(MODEM_IS_SCPC)
|
||||
#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
|
||||
|
||||
#if defined(MODEM_IS_TDMA)
|
||||
#define API_OBJECT_MANAGER_LOGS_ENABLE
|
||||
#endif
|
||||
|
||||
|
||||
#endif //API_DRIVER_STRICTS_ENABLE_H
|
File diff suppressed because it is too large
Load Diff
@@ -1,277 +0,0 @@
|
||||
#ifndef STRUCTS_H
|
||||
#define STRUCTS_H
|
||||
|
||||
#include "api-driver/stricts-enable.h"
|
||||
#include "proxy.h"
|
||||
#include <atomic>
|
||||
#include <fstream>
|
||||
#include <shared_mutex>
|
||||
#include <string>
|
||||
#include "common/nlohmann/json.hpp"
|
||||
|
||||
|
||||
namespace api_driver::obj {
|
||||
#ifdef API_OBJECT_DEBUG_METRICS_ENABLE
|
||||
class StatisticsLogger {
|
||||
public:
|
||||
StatisticsLogger();
|
||||
|
||||
static constexpr const char* LOG_FILENAME = "/tmp/weblog-statistics.csv";
|
||||
|
||||
int64_t timeStart;
|
||||
|
||||
bool logEn = false;
|
||||
std::atomic<int> logPeriodMs = 1000;
|
||||
std::atomic<int> maxAgeMs = 10000;
|
||||
|
||||
/**
|
||||
*
|
||||
* @return {"en": bool, "logPeriodMs": int, "maxAgeMs": int}
|
||||
*/
|
||||
nlohmann::json getSettings();
|
||||
void setSettings(const nlohmann::json& data);
|
||||
|
||||
void updateCallback(proxy::CpProxy& cp);
|
||||
/**
|
||||
* Записать значение в "базу данных". Метку при этом вставлять не нужно, она будет вставлена автоматически.
|
||||
* @param item
|
||||
*/
|
||||
void putItem(const debug_metrics& item);
|
||||
|
||||
// void collectExpiredItems();
|
||||
|
||||
// void resetLogs() {
|
||||
// std::lock_guard _lock(mutex);
|
||||
// logs.clear();
|
||||
// }
|
||||
|
||||
~StatisticsLogger();
|
||||
private:
|
||||
// std::pmr::deque<LogItem> logs;
|
||||
std::fstream logFile{};
|
||||
std::shared_mutex mutex;
|
||||
};
|
||||
#endif
|
||||
|
||||
#if defined(MODEM_IS_SCPC)
|
||||
static constexpr const char* DEFAULT_SERVER_NAME = "RSCM-101";
|
||||
#elif defined(MODEM_IS_TDMA)
|
||||
static constexpr const char* DEFAULT_SERVER_NAME = "TDMA Abonent";
|
||||
#elif defined(MODEM_IS_SHPS)
|
||||
static constexpr const char* DEFAULT_SERVER_NAME = "SHPS Terminal";
|
||||
#else
|
||||
#error "Selected modem type not supported!"
|
||||
#endif
|
||||
|
||||
#ifdef API_OBJECT_NETWORK_SETTINGS_ENABLE
|
||||
class TerminalNetworkSettings {
|
||||
public:
|
||||
std::string managementIp, managementGateway, dataIp, serverName;
|
||||
bool isL2 = true;
|
||||
unsigned int dataMtu = 1500;
|
||||
|
||||
TerminalNetworkSettings();
|
||||
TerminalNetworkSettings(const TerminalNetworkSettings& src);
|
||||
TerminalNetworkSettings& operator= (const TerminalNetworkSettings& src);
|
||||
|
||||
void loadDefaults();
|
||||
|
||||
void updateCallback(proxy::CpProxy& cp);
|
||||
void updateFromJson(const nlohmann::json& data);
|
||||
void store(proxy::CpProxy& cp);
|
||||
nlohmann::json asJson();
|
||||
|
||||
~TerminalNetworkSettings();
|
||||
};
|
||||
#endif
|
||||
|
||||
#ifdef API_OBJECT_QOS_SETTINGS_ENABLE
|
||||
class TerminalQosSettings {
|
||||
public:
|
||||
static constexpr const char* DEFAULT_QOS_CLASSES = R"({"rt1":[],"rt2":[],"rt3":[],"cd":[]})";
|
||||
nlohmann::json qosSettingsJson;
|
||||
bool qosEnabled = false;
|
||||
|
||||
TerminalQosSettings();
|
||||
TerminalQosSettings(const TerminalQosSettings& src);
|
||||
TerminalQosSettings& operator= (const TerminalQosSettings& src);
|
||||
|
||||
void loadDefaults();
|
||||
|
||||
void updateCallback(proxy::CpProxy& cp);
|
||||
void updateFromJson(const nlohmann::json& data);
|
||||
void store(proxy::CpProxy& cp);
|
||||
nlohmann::json asJson();
|
||||
|
||||
~TerminalQosSettings();
|
||||
};
|
||||
#endif
|
||||
|
||||
class TerminalFirmwareVersion {
|
||||
public:
|
||||
std::string version, modemId, modemSn, macMang, macData;
|
||||
|
||||
TerminalFirmwareVersion();
|
||||
TerminalFirmwareVersion(const TerminalFirmwareVersion& src);
|
||||
TerminalFirmwareVersion& operator= (const TerminalFirmwareVersion& src);
|
||||
|
||||
void load(proxy::CpProxy& cp);
|
||||
nlohmann::json asJson();
|
||||
|
||||
~TerminalFirmwareVersion();
|
||||
};
|
||||
|
||||
/**
|
||||
* Обертка состояния терминала, тут состояние девайса, модулятора/демодулятора, состояние автоматического обновления.
|
||||
*/
|
||||
class TerminalState {
|
||||
public:
|
||||
std::string fInitState{};
|
||||
bool fIsTest = false; // daemon->isTest()
|
||||
bool fTxState = false;
|
||||
#ifdef MODEM_IS_SCPC
|
||||
bool fIsCinC = false;
|
||||
#endif
|
||||
|
||||
bool fRxState{};
|
||||
#ifndef MODEM_IS_SHPS
|
||||
bool fRxSymSyncLock{};
|
||||
bool fRxFreqSearchLock{};
|
||||
bool fRxAfcLock{};
|
||||
bool fRxPktSync{};
|
||||
#endif
|
||||
|
||||
float fRxSnr{};
|
||||
float fRxRssi{};
|
||||
#ifndef MODEM_IS_SHPS
|
||||
uint16_t fRxModcod{};
|
||||
bool fRxFrameSizeNormal{};
|
||||
bool fRxIsPilots{};
|
||||
double fRxSymError{};
|
||||
double fRxFreqErr{};
|
||||
#endif
|
||||
double fRxFreqErrAcc{};
|
||||
double fRxInputSignalLevel{};
|
||||
double fRxPllError{};
|
||||
double fRxSpeedOnRxKbit{};
|
||||
double fRxSpeedOnIifKbit{};
|
||||
uint32_t fRxPacketsOk{};
|
||||
uint32_t fRxPacketsBad{};
|
||||
#ifndef MODEM_IS_SHPS
|
||||
uint32_t fRxPacketsDummy{};
|
||||
uint16_t fTxModcod{};
|
||||
#endif
|
||||
double fTxSpeedOnTxKbit{};
|
||||
double fTxSpeedOnIifKbit{};
|
||||
#ifdef MODEM_IS_SCPC
|
||||
float fTxSnr{};
|
||||
bool fTxFrameSizeNormal{};
|
||||
bool fTxIsPilots{};
|
||||
double fCincOcc{};
|
||||
bool fCincCorrelator{};
|
||||
uint32_t fCincCorrelatorFails{};
|
||||
int32_t fCincFreqErr{};
|
||||
int32_t fCincFreqErrAcc{};
|
||||
float fCincChannelDelay{};
|
||||
#endif
|
||||
double fTxCenterFreq;
|
||||
double fTxSymSpeed;
|
||||
|
||||
TerminalState();
|
||||
|
||||
/**
|
||||
* Обновление основной части статистики, то есть RX/TX и sysinfo
|
||||
*/
|
||||
void updateCallback(proxy::CpProxy& cp);
|
||||
nlohmann::json asJson();
|
||||
|
||||
~TerminalState();
|
||||
};
|
||||
|
||||
class TerminalDeviceState {
|
||||
public:
|
||||
time_t fOsUptime{};
|
||||
double fOsLoad1{};
|
||||
double fOsLoad5{};
|
||||
double fOsLoad15{};
|
||||
unsigned int fOsTotalram{};
|
||||
unsigned int fOsFreeram{};
|
||||
unsigned int fOsProcs{};
|
||||
|
||||
double fTempAdrv{};
|
||||
double fTempZynq{};
|
||||
double fTempFpga{};
|
||||
#ifdef MODEM_IS_TDMA
|
||||
DOWNLOAD_STATUS fUpgradeStatus{};
|
||||
unsigned int fUpgradePercent{};
|
||||
std::string fUpgradeImage;
|
||||
#endif
|
||||
|
||||
TerminalDeviceState();
|
||||
TerminalDeviceState(const TerminalDeviceState& src);
|
||||
TerminalDeviceState& operator= (const TerminalDeviceState& src);
|
||||
|
||||
void updateCallback(proxy::CpProxy& cp);
|
||||
nlohmann::json asJson() const;
|
||||
|
||||
~TerminalDeviceState();
|
||||
};
|
||||
|
||||
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:
|
||||
|
||||
TerminalRxTxSettings();
|
||||
TerminalRxTxSettings(const TerminalRxTxSettings& src);
|
||||
TerminalRxTxSettings& operator= (const TerminalRxTxSettings& src);
|
||||
|
||||
void updateCallback(proxy::CpProxy& cp);
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
#ifdef API_OBJECT_MANAGER_LOGS_ENABLE
|
||||
class TerminalManagerLogs {
|
||||
public:
|
||||
const std::string logsFileDir;
|
||||
|
||||
TerminalManagerLogs(const std::string& path);
|
||||
|
||||
std::string loadPreview(bool isReverse);
|
||||
|
||||
std::string loadPreviewWithFilter(bool isReverse, const std::string& logLevel);
|
||||
|
||||
void loadFullLog(std::vector<char>& destData);
|
||||
|
||||
~TerminalManagerLogs();
|
||||
};
|
||||
#endif // API_OBJECT_MANAGER_LOGS_ENABLE
|
||||
}
|
||||
|
||||
#endif //STRUCTS_H
|
@@ -47,12 +47,11 @@ namespace http::auth {
|
||||
static constexpr uint32_t SUPERUSER = 0x0001;
|
||||
static constexpr uint32_t WATCH_STATISTICS = 0x0002; // мониторинг модема
|
||||
static constexpr uint32_t RESET_PACKET_STATISTICS = 0x0004; // сброс статистики пакетов
|
||||
static constexpr uint32_t WATCH_SETTINGS = 0x0008; // просмотр настроек, если недоступно, то вкладки с настройками не будет
|
||||
static constexpr uint32_t WATCH_SETTINGS = 0x0008; // просмотр настроек , если недоступно, то вкладки с настройками не будет
|
||||
static constexpr uint32_t EDIT_SETTINGS = 0x0010; // редактирование настроек, установка параметров модулятора/демодулятора/dma/cinc
|
||||
static constexpr uint32_t UPDATE_FIRMWARE = 0x0020; // обновление прошивки
|
||||
static constexpr uint32_t SETUP_QOS = 0x0040; // управление профилем QoS
|
||||
static constexpr uint32_t DEVELOPER = 0x0080; // использование функций для разработчиков
|
||||
static constexpr uint32_t VIEW_LOGS = 0x0100; // просмотр логов
|
||||
|
||||
/**
|
||||
* Проверить, что у пользователя есть нужное право. Если это суперпользователь, то у него по умолчанию все права есть.
|
||||
|
File diff suppressed because it is too large
Load Diff
434
src/main.cpp
434
src/main.cpp
@@ -11,6 +11,7 @@
|
||||
#include <boost/log/utility/setup/formatter_parser.hpp>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/ssl/context.hpp>
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <fstream>
|
||||
@@ -20,7 +21,6 @@
|
||||
#include "auth/resources.h"
|
||||
#include "auth/jwt.h"
|
||||
#include "auth/utils.h"
|
||||
#include "common/nlohmann/json.hpp"
|
||||
|
||||
|
||||
namespace ssl = boost::asio::ssl; // from <boost/asio/ssl.hpp>
|
||||
@@ -76,25 +76,25 @@ class ServerResources {
|
||||
}
|
||||
|
||||
void doTerminalUpgrade() const {
|
||||
api->executeInApi([](api_driver::proxy::CpProxy& cp) {
|
||||
cp.setDmaDebug("begin_save_config", "");
|
||||
api->executeInApi([](TSID sid) {
|
||||
CP_SetDmaDebug(sid, "begin_save_config", "");
|
||||
std::string cmd(UPGRADE_COMMAND);
|
||||
cmd += " ";
|
||||
cmd += FIRMWARE_LOCATION;
|
||||
std::ignore = system(cmd.c_str());
|
||||
cp.setDmaDebug("save_config", "");
|
||||
system(cmd.c_str());
|
||||
CP_SetDmaDebug(sid, "save_config", "");
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef MODEM_IS_TDMA
|
||||
void doTerminalUpgradeOta() const {
|
||||
api->executeInApi([&](auto& cp) {
|
||||
cp.setDmaDebug("begin_save_config", "");
|
||||
api->executeInApi([&](TSID sid) {
|
||||
CP_SetDmaDebug(sid, "begin_save_config", "");
|
||||
std::string cmd(UPGRADE_COMMAND);
|
||||
cmd += " ";
|
||||
cmd += api->getOtaFileLocation();
|
||||
system(cmd.c_str());
|
||||
cp.setDmaDebug("save_config", "");
|
||||
CP_SetDmaDebug(sid, "save_config", "");
|
||||
});
|
||||
}
|
||||
#endif
|
||||
@@ -104,8 +104,6 @@ public:
|
||||
static constexpr const char* INDEX_HTML = "/main-tdma.html";
|
||||
#elif defined(MODEM_IS_SCPC)
|
||||
static constexpr const char* INDEX_HTML = "/main-scpc.html";
|
||||
#elif defined(MODEM_IS_SHPS)
|
||||
static constexpr const char* INDEX_HTML = "/main-shps.html";
|
||||
#else
|
||||
#error "Modem type not defined!"
|
||||
#endif
|
||||
@@ -115,9 +113,6 @@ public:
|
||||
// картинки, их даже можно кешировать
|
||||
static constexpr const char* FAVICON_ICO = "/favicon.ico";
|
||||
static constexpr const char* VUE_JS = "/js/vue.js"; // это тоже можно кешировать
|
||||
static constexpr const char* CHARTJS = "/js/chart.js";
|
||||
static constexpr const char* MOMENT_JS = "/js/moment.js";
|
||||
static constexpr const char* CHARTJS_ADAPTER_MOMENT = "/js/chartjs-adapter-moment.js";
|
||||
|
||||
// а эти стили нельзя кешировать в отладочной версии
|
||||
static constexpr const char* STYLE_CSS = "/style.css";
|
||||
@@ -134,16 +129,12 @@ public:
|
||||
http::auth::User::WATCH_SETTINGS |
|
||||
http::auth::User::EDIT_SETTINGS |
|
||||
http::auth::User::UPDATE_FIRMWARE |
|
||||
http::auth::User::SETUP_QOS |
|
||||
http::auth::User::VIEW_LOGS));
|
||||
http::auth::User::SETUP_QOS));
|
||||
|
||||
// пароль fuckyou123
|
||||
auth.users.emplace_back(std::make_shared<http::auth::User>("developer", "10628cfc434fb87f31d675d37e0402c2d824cfe8393aff7a61ee57aaa7d909c3", http::auth::User::SUPERUSER));
|
||||
|
||||
sf->registerFile(staticFilesPath + "/favicon.png", FAVICON_ICO, mime_types::image_png, true);
|
||||
sf->registerFile(staticFilesPath + CHARTJS, CHARTJS, mime_types::javascript, true);
|
||||
sf->registerFile(staticFilesPath + MOMENT_JS, MOMENT_JS, mime_types::javascript, true);
|
||||
sf->registerFile(staticFilesPath + CHARTJS_ADAPTER_MOMENT, CHARTJS_ADAPTER_MOMENT, mime_types::javascript, true);
|
||||
#ifdef USE_DEBUG
|
||||
sf->registerFile(staticFilesPath + VUE_JS, VUE_JS, mime_types::javascript, true);
|
||||
#else
|
||||
@@ -180,9 +171,11 @@ public:
|
||||
rep.headers.clear();
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||
try {
|
||||
auto reqJson = nlohmann::json::parse(std::string(req.payload.begin(), req.payload.end()));
|
||||
std::istringstream is(std::string(req.payload.data(), req.payload.size()));
|
||||
boost::property_tree::ptree pt;
|
||||
read_json(is, pt);
|
||||
|
||||
auto u = auth.doAuth(reqJson["username"], reqJson["password"], req, rep);
|
||||
auto u = auth.doAuth(pt.get<std::string>("username"), pt.get<std::string>("password"), req, rep);
|
||||
if (u == nullptr) {
|
||||
throw std::runtime_error("invalid session");
|
||||
}
|
||||
@@ -210,9 +203,6 @@ public:
|
||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>(STYLE_CSS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(STYLE_CSS, rep); }));
|
||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>(FIELDS_CSS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(FIELDS_CSS, rep); }));
|
||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>(VUE_JS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(VUE_JS, rep); }));
|
||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>(CHARTJS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(CHARTJS, rep); }));
|
||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>(MOMENT_JS, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(MOMENT_JS, rep); }));
|
||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>(CHARTJS_ADAPTER_MOMENT, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(CHARTJS_ADAPTER_MOMENT, rep); }));
|
||||
s.resources.emplace_back(std::make_unique<http::resource::GenericResource>(INTERNET_JPG, [this](const auto& req, auto& rep) { boost::ignore_unused(req); sf->serve(INTERNET_JPG, rep); }));
|
||||
|
||||
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/get/statistics", this->auth, http::auth::User::WATCH_STATISTICS, [this](const auto& req, auto& rep) {
|
||||
@@ -220,21 +210,14 @@ public:
|
||||
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 {
|
||||
resultJson["status"] = "ok";
|
||||
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();
|
||||
std::string result = R"({"mainState":)";
|
||||
result += api->loadTerminalState();
|
||||
result += R"(,"sysinfo":)";
|
||||
result += api->loadSysInfo();
|
||||
result += "}";
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
}));
|
||||
|
||||
@@ -243,22 +226,12 @@ public:
|
||||
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 {
|
||||
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();
|
||||
std::string result = R"({"settings":)";
|
||||
result += api->loadSettings();
|
||||
result += "}";
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
}));
|
||||
|
||||
@@ -270,20 +243,7 @@ public:
|
||||
|
||||
rep.status = http::server::ok;
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||
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();
|
||||
const auto result = api->loadFirmwareVersion();
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
}));
|
||||
|
||||
@@ -300,7 +260,6 @@ public:
|
||||
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) {
|
||||
if (req.method != "POST") {
|
||||
http::server::stockReply(http::server::bad_request, rep);
|
||||
@@ -309,27 +268,27 @@ public:
|
||||
|
||||
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()));
|
||||
api->setQosSettings(reqJson);
|
||||
resultJson["status"] = "ok";
|
||||
resultJson["settings"] = api->loadSettings();
|
||||
std::stringstream ss;
|
||||
ss.str(std::string(req.payload.begin(), req.payload.end()));
|
||||
boost::property_tree::ptree pt;
|
||||
read_json(ss, pt);
|
||||
|
||||
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) {
|
||||
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/qos): Can't set QoS settings: " << e.what();
|
||||
resultJson.clear();
|
||||
resultJson["status"] = "error";
|
||||
resultJson["error"] = e.what();
|
||||
const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}";
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
}
|
||||
|
||||
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::SUPERUSER, [this](const auto& req, auto& rep) {
|
||||
if (req.method != "POST") {
|
||||
http::server::stockReply(http::server::bad_request, rep);
|
||||
return;
|
||||
@@ -338,26 +297,25 @@ public:
|
||||
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()));
|
||||
api->setBucLnbSettings(reqJson);
|
||||
resultJson["status"] = "ok";
|
||||
resultJson["settings"] = api->loadSettings();
|
||||
std::stringstream ss;
|
||||
ss.str(std::string(req.payload.begin(), req.payload.end()));
|
||||
boost::property_tree::ptree pt;
|
||||
read_json(ss, pt);
|
||||
|
||||
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) {
|
||||
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/buclnb): Can't set BUC LNB settings: " << e.what();
|
||||
resultJson.clear();
|
||||
resultJson["status"] = "error";
|
||||
resultJson["error"] = e.what();
|
||||
const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}";
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
}
|
||||
|
||||
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) {
|
||||
if (req.method != "POST") {
|
||||
http::server::stockReply(http::server::bad_request, rep);
|
||||
@@ -366,24 +324,25 @@ public:
|
||||
|
||||
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()));
|
||||
api->setDpdiSettings(reqJson);
|
||||
resultJson["status"] = "ok";
|
||||
resultJson["settings"] = api->loadSettings();
|
||||
std::stringstream ss;
|
||||
ss.str(std::string(req.payload.begin(), req.payload.end()));
|
||||
boost::property_tree::ptree pt;
|
||||
read_json(ss, pt);
|
||||
|
||||
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) {
|
||||
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/dpdi): Can't set DPDI settings: " << e.what();
|
||||
resultJson.clear();
|
||||
resultJson["status"] = "error";
|
||||
resultJson["error"] = e.what();
|
||||
const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}";
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
}
|
||||
|
||||
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) {
|
||||
if (req.method != "POST") {
|
||||
@@ -393,25 +352,26 @@ public:
|
||||
|
||||
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()));
|
||||
api->setRxTxSettings(reqJson);
|
||||
resultJson["status"] = "ok";
|
||||
resultJson["settings"] = api->loadSettings();
|
||||
std::stringstream ss;
|
||||
ss.str(std::string(req.payload.begin(), req.payload.end()));
|
||||
boost::property_tree::ptree pt;
|
||||
read_json(ss, pt);
|
||||
|
||||
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) {
|
||||
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/rxtx): Can't set RX/TX settings: " << e.what();
|
||||
resultJson.clear();
|
||||
resultJson["status"] = "error";
|
||||
resultJson["error"] = e.what();
|
||||
const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}";
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
}
|
||||
|
||||
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) {
|
||||
if (req.method != "POST") {
|
||||
http::server::stockReply(http::server::bad_request, rep);
|
||||
@@ -420,54 +380,25 @@ public:
|
||||
|
||||
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()));
|
||||
api->setNetworkSettings(reqJson);
|
||||
resultJson["status"] = "ok";
|
||||
resultJson["settings"] = api->loadSettings();
|
||||
std::stringstream ss;
|
||||
ss.str(std::string(req.payload.begin(), req.payload.end()));
|
||||
boost::property_tree::ptree pt;
|
||||
read_json(ss, pt);
|
||||
|
||||
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) {
|
||||
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/network): Can't set network settings: " << e.what();
|
||||
resultJson.clear();
|
||||
resultJson["status"] = "error";
|
||||
resultJson["error"] = e.what();
|
||||
const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}";
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
}
|
||||
|
||||
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) {
|
||||
if (req.method != "POST") {
|
||||
@@ -479,7 +410,7 @@ public:
|
||||
const std::string result = R"({"status":"ok"})";
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
this->upgradeOrRebootRunning = true;
|
||||
std::ignore = system(REBOOT_COMMAND);
|
||||
system(REBOOT_COMMAND);
|
||||
}));
|
||||
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/resetSettings", this->auth, http::auth::User::EDIT_SETTINGS, [this](const auto& req, auto& rep) {
|
||||
if (req.method != "POST") {
|
||||
@@ -491,7 +422,7 @@ public:
|
||||
const std::string result = R"({"status":"ok"})";
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
api->resetDefaultSettings();
|
||||
std::ignore = system(REBOOT_COMMAND);
|
||||
system(REBOOT_COMMAND);
|
||||
}));
|
||||
|
||||
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/firmwareUpdate", this->auth, http::auth::User::UPDATE_FIRMWARE, [this](const auto& req, auto& rep) {
|
||||
@@ -518,13 +449,7 @@ public:
|
||||
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 {
|
||||
this->upgradeOrRebootRunning = true;
|
||||
this->upgradeOrRebootRunning = true;
|
||||
#ifdef MODEM_IS_TDMA
|
||||
if (req.url->params.find("ota") != req.url->params.end()) {
|
||||
doTerminalUpgradeOta();
|
||||
@@ -534,15 +459,10 @@ public:
|
||||
#else
|
||||
doTerminalUpgrade();
|
||||
#endif
|
||||
resultJson["status"] = "ok";
|
||||
} catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/doFirmwareUpgrade): Error: " << e.what();
|
||||
resultJson.clear();
|
||||
resultJson["status"] = "error";
|
||||
resultJson["error"] = e.what();
|
||||
}
|
||||
|
||||
auto result = resultJson.dump();
|
||||
rep.status = http::server::ok;
|
||||
rep.headers.clear();
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||
const auto result = api->loadFirmwareVersion();
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
}));
|
||||
|
||||
@@ -561,103 +481,59 @@ public:
|
||||
return;
|
||||
}
|
||||
const auto func = req.url->params["f"];
|
||||
std::string result = R"({"status":"ok"})";
|
||||
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("value") == req.url->params.end()) { http::server::stockReply(http::server::bad_request, rep); return; }
|
||||
this->api->executeInApi([&](auto sid) {
|
||||
CP_SetDmaDebug(sid, req.url->params["param"].c_str(), req.url->params["value"]);
|
||||
});
|
||||
} else if (func == "GetDmaDebug") {
|
||||
if (req.url->params.find("param") == req.url->params.end()) { http::server::stockReply(http::server::bad_request, rep); return; }
|
||||
this->api->executeInApi([&](auto sid) {
|
||||
std::string tmp{};
|
||||
CP_GetDmaDebug(sid, req.url->params["param"].c_str(), &tmp);
|
||||
result = R"({"status":"ok","result":)";
|
||||
result += api_driver::buildEscapedString(tmp);
|
||||
result += "}";
|
||||
});
|
||||
} else {
|
||||
http::server::stockReply(http::server::not_implemented, rep);
|
||||
return;
|
||||
}
|
||||
|
||||
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 (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 {
|
||||
this->api->executeInApi([&](auto& cp) {
|
||||
cp.setDmaDebug(req.url->params["param"], req.url->params["value"]);
|
||||
});
|
||||
}
|
||||
} else if (func == "GetDmaDebug") {
|
||||
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.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 {
|
||||
this->api->executeInApi([&](auto& cp) {
|
||||
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();
|
||||
}
|
||||
|
||||
auto result = resultJson.dump();
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
}));
|
||||
#ifdef API_OBJECT_DEBUG_METRICS_ENABLE
|
||||
#ifdef MODEM_IS_SCPC
|
||||
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/dev/settings", this->auth, http::auth::User::DEVELOPER, [this](const auto& req, auto& rep) {
|
||||
rep.status = http::server::ok;
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::text_plain)});
|
||||
nlohmann::json resultJson;
|
||||
std::string result;
|
||||
if (req.method == "GET") {
|
||||
result = R"({"status":"ok","logstat":)";
|
||||
result += this->api->getLoggingStatisticsSettings();
|
||||
result += "}";
|
||||
} else if (req.method == "POST") {
|
||||
std::stringstream ss;
|
||||
ss.str(std::string(req.payload.begin(), req.payload.end()));
|
||||
boost::property_tree::ptree pt;
|
||||
read_json(ss, pt);
|
||||
|
||||
try {
|
||||
if (req.method == "GET") {
|
||||
resultJson["status"] = "ok";
|
||||
resultJson["logstat"] = api->getLoggingStatisticsSettings();
|
||||
} else if (req.method == "POST") {
|
||||
auto reqJson = nlohmann::json::parse(std::string(req.payload.begin(), req.payload.end()));
|
||||
api->setLoggingStatisticsSettings(reqJson);
|
||||
api->setLoggingStatisticsSettings(pt);
|
||||
|
||||
resultJson["status"] = "ok";
|
||||
resultJson["logstat"] = api->getLoggingStatisticsSettings();
|
||||
} else {
|
||||
rep.status = http::server::bad_request;
|
||||
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();
|
||||
result = R"({"status":"ok","logstat":)";
|
||||
result += this->api->getLoggingStatisticsSettings();
|
||||
result += "}";
|
||||
} else {
|
||||
http::server::stockReply(http::server::bad_request, rep);
|
||||
return;
|
||||
}
|
||||
|
||||
auto result = resultJson.dump();
|
||||
rep.status = http::server::ok;
|
||||
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());
|
||||
}));
|
||||
#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) {
|
||||
if (req.method != "GET") {
|
||||
http::server::stockReply(http::server::bad_request, rep);
|
||||
@@ -670,40 +546,6 @@ public:
|
||||
http::resource::loadFile("/tmp/weblog-statistics.csv", rep.content);
|
||||
}));
|
||||
#endif
|
||||
|
||||
#ifdef API_OBJECT_MANAGER_LOGS_ENABLE
|
||||
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/get/manager.log", this->auth, http::auth::User::VIEW_LOGS, [this](const http::server::Request& req, auto& rep) {
|
||||
if (req.method != "GET") {
|
||||
http::server::stockReply(http::server::bad_request, rep);
|
||||
return;
|
||||
}
|
||||
|
||||
bool isPreview = false;
|
||||
if (req.url->params.find("preview") != req.url->params.end()) {
|
||||
isPreview = true;
|
||||
}
|
||||
|
||||
bool isReversePreview = false;
|
||||
if (req.url->params.find("reverse") != req.url->params.end()) {
|
||||
isReversePreview = true;
|
||||
}
|
||||
|
||||
std::string logLevelFilter;
|
||||
if (req.url->params.find("level") != req.url->params.end()) {
|
||||
logLevelFilter = req.url->params["level"];
|
||||
}
|
||||
|
||||
rep.status = http::server::ok;
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::text_plain)});
|
||||
rep.content.clear();
|
||||
if (isPreview) {
|
||||
auto result = logLevelFilter.empty() ? this->api->logs.loadPreview(isReversePreview) : this->api->logs.loadPreviewWithFilter(isReversePreview, logLevelFilter);
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
} else {
|
||||
this->api->logs.loadFullLog(rep.content);
|
||||
}
|
||||
}));
|
||||
#endif
|
||||
}
|
||||
|
||||
~ServerResources() = default;
|
||||
|
@@ -26,19 +26,17 @@ namespace http::server {
|
||||
}
|
||||
|
||||
static void parseParams(Url& u, const std::string& query) {
|
||||
std::istringstream iss(query);
|
||||
std::string param;
|
||||
while (std::getline(iss, param, '&')) {
|
||||
size_t equal_pos = param.find('=');
|
||||
if (equal_pos != std::string::npos) {
|
||||
const std::string key = param.substr(0, equal_pos);
|
||||
const std::string value = param.substr(equal_pos + 1);
|
||||
u.params[key] = value;
|
||||
} else {
|
||||
u.params[param] = "";
|
||||
std::istringstream iss(query);
|
||||
std::string param;
|
||||
while (std::getline(iss, param, '&')) {
|
||||
size_t equal_pos = param.find('=');
|
||||
if (equal_pos != std::string::npos) {
|
||||
const std::string key = param.substr(0, equal_pos);
|
||||
const std::string value = param.substr(equal_pos + 1);
|
||||
u.params[key] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Url::Url(const std::string &url) {
|
||||
size_t question_mark_pos = url.find('?');
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,13 +1,12 @@
|
||||
#ifndef TERMINAL_API_DRIVER_H
|
||||
#define TERMINAL_API_DRIVER_H
|
||||
|
||||
#include "api-driver/stricts-enable.h"
|
||||
#include "api-driver/proxy.h"
|
||||
#include <deque>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <terminal_api/ControlProtoCInterface.h>
|
||||
|
||||
#include "api-driver/structs.h"
|
||||
#include "common/nlohmann/json.hpp"
|
||||
|
||||
namespace api_driver {
|
||||
constexpr int CACHE_STATISTICS_UPDATE_MS = 500; ///< время обновления кеша статистики модулятора/демодулятора
|
||||
@@ -15,6 +14,7 @@ namespace api_driver {
|
||||
constexpr int CACHE_SETTINGS_UPDATE_MS = 5000;
|
||||
constexpr int CACHE_QOS_UPDATE_MS = 5000;
|
||||
|
||||
class StatisticsLogger;
|
||||
class TerminalApiDaemon;
|
||||
|
||||
/**
|
||||
@@ -31,56 +31,50 @@ 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}
|
||||
*/
|
||||
nlohmann::json loadTerminalState() const;
|
||||
std::string loadTerminalState() const;
|
||||
|
||||
/**
|
||||
* Сбросить статистику пакетов
|
||||
*/
|
||||
void resetPacketStatistics() const;
|
||||
|
||||
nlohmann::json loadSettings() const;
|
||||
std::string loadSettings() const;
|
||||
|
||||
nlohmann::json loadFirmwareVersion() const;
|
||||
std::string loadFirmwareVersion() const;
|
||||
|
||||
/**
|
||||
* Установить настройки RX/TX, readback можно получить используя loadTerminalState
|
||||
*/
|
||||
void setRxTxSettings(const nlohmann::json& data);
|
||||
void setRxTxSettings(boost::property_tree::ptree &pt);
|
||||
|
||||
|
||||
#ifdef API_OBJECT_DPDI_SETTINGS_ENABLE
|
||||
/**
|
||||
* Установить настройки DPDI, readback можно получить используя loadTerminalState.
|
||||
* @note Для TDMA и SCPC модемов эти настройки доступны
|
||||
*/
|
||||
void setDpdiSettings(const nlohmann::json& data);
|
||||
#endif
|
||||
void setDpdiSettings(boost::property_tree::ptree &pt);
|
||||
|
||||
#ifdef API_OBJECT_BUCLNB_SETTINGS_ENABLE
|
||||
/**
|
||||
* Установить настройки BUC и LNB, readback можно получить используя loadTerminalState.
|
||||
*/
|
||||
void setBucLnbSettings(const nlohmann::json& data);
|
||||
#endif
|
||||
void setBucLnbSettings(boost::property_tree::ptree &pt);
|
||||
|
||||
#ifdef API_OBJECT_QOS_SETTINGS_ENABLE
|
||||
/**
|
||||
* Установить настройки QoS, readback можно получить используя loadTerminalState.
|
||||
*/
|
||||
void setQosSettings(const nlohmann::json& data);
|
||||
#endif
|
||||
void setQosSettings(boost::property_tree::ptree &pt);
|
||||
|
||||
#ifdef API_OBJECT_NETWORK_SETTINGS_ENABLE
|
||||
void setNetworkSettings(const nlohmann::json& data);
|
||||
#endif
|
||||
void setNetworkSettings(boost::property_tree::ptree &pt);
|
||||
|
||||
void resetDefaultSettings();
|
||||
|
||||
void executeInApi(const std::function<void(proxy::CpProxy&)> &callback);
|
||||
void executeInApi(const std::function<void(TSID sid)> &callback);
|
||||
|
||||
#ifdef API_OBJECT_DEBUG_METRICS_ENABLE
|
||||
nlohmann::json getLoggingStatisticsSettings();
|
||||
void setLoggingStatisticsSettings(const nlohmann::json& data);
|
||||
#ifdef MODEM_IS_SCPC
|
||||
std::string getLoggingStatisticsSettings();
|
||||
void setLoggingStatisticsSettings(boost::property_tree::ptree &pt);
|
||||
|
||||
/**
|
||||
* Получить статистику в формате json. Выход будет дописан в вектор
|
||||
@@ -97,9 +91,7 @@ namespace api_driver {
|
||||
std::string getOtaFileLocation() const;
|
||||
#endif
|
||||
|
||||
#ifdef API_OBJECT_MANAGER_LOGS_ENABLE
|
||||
obj::TerminalManagerLogs logs;
|
||||
#endif
|
||||
static std::string loadSysInfo();
|
||||
|
||||
~ApiDriver();
|
||||
|
||||
|
@@ -7,10 +7,6 @@
|
||||
#define PROJECT_GIT_REVISION "no-git"
|
||||
#endif
|
||||
|
||||
#define PROJECT_BUILD_TIME __TIMESTAMP__ " compiler version " __VERSION__
|
||||
|
||||
#ifndef MANAGER_LOGS_DIR
|
||||
#define MANAGER_LOGS_DIR "/root/"
|
||||
#endif
|
||||
#define PROJECT_BUILD_TIME __TIMESTAMP__
|
||||
|
||||
#endif //VERSION_H
|
||||
|
@@ -94,52 +94,27 @@
|
||||
<h2>Просмотр логов</h2>
|
||||
<button class="action-button" @click="logView()">Обновить <span class="submit-spinner" v-show="submitStatus.logView"></span></button>
|
||||
<a href="/dev/logs.csv" class="action-button" download>Скачать</a>
|
||||
<div v-if="logsTable.headers.length != 0" style="overflow-x: auto;">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th v-for="h in logsTable.headers">{{ h }}</th>
|
||||
</tr>
|
||||
<tr v-for="r in logsTable.rows">
|
||||
<td v-for="value in r">{{ value }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settings-set-container"><h2>График</h2><canvas id="mainChart" style="display: block; box-sizing: border-box;"></canvas></div>
|
||||
|
||||
<script src="/js/vue.js?v=3.5.13"></script>
|
||||
<script src="/js/chart.js"></script>
|
||||
<script src="/js/moment.js"></script>
|
||||
<script src="/js/chartjs-adapter-moment.js"></script>
|
||||
<script>
|
||||
// для обновления высоты хидера
|
||||
function updateHeaderHeight() { const header = document.querySelector('header'); document.body.style.setProperty('--header-height', `${header.offsetHeight}px`); }
|
||||
window.addEventListener('load', updateHeaderHeight); window.addEventListener('resize', updateHeaderHeight);
|
||||
|
||||
let MainChart = new Chart(document.getElementById('mainChart').getContext('2d'), {
|
||||
type: 'line',
|
||||
data: {
|
||||
datasets: []
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
scales: {
|
||||
x: {
|
||||
type: 'time',
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Время',
|
||||
font: {
|
||||
padding: 4,
|
||||
size: 20,
|
||||
weight: 'bold',
|
||||
family: 'Arial'
|
||||
},
|
||||
//color: 'darkblue'
|
||||
},
|
||||
},
|
||||
y: {
|
||||
beginAtZero: true,
|
||||
type: 'linear',
|
||||
position: 'left'
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const app = Vue.createApp({
|
||||
data() {
|
||||
return {
|
||||
@@ -157,7 +132,10 @@
|
||||
maxAgeMs: 0
|
||||
}
|
||||
},
|
||||
chart: null,
|
||||
logsTable: {
|
||||
headers: [],
|
||||
rows: []
|
||||
},
|
||||
|
||||
settingFetchComplete: false
|
||||
}
|
||||
@@ -214,28 +192,11 @@
|
||||
let logfileContent = await resp.text()
|
||||
const lines = logfileContent.trim().split(/\r\n|\n/)
|
||||
|
||||
let datasets = []
|
||||
// Первая строка содержит заголовки
|
||||
this.logsTable.headers = lines.shift().split('\t')
|
||||
|
||||
// столбец timestamp пропускаем
|
||||
let labels = lines.shift().split('\t')
|
||||
labels.shift()
|
||||
let rows = lines.map(line => line.split('\t'))
|
||||
|
||||
for (let li = 0; li < labels.length; li++) {
|
||||
let td = []
|
||||
for (let ri = 0; ri < rows.length; ri++) {
|
||||
td.push({x: new Date(rows[ri][0]), y: rows[ri][li + 1]})
|
||||
}
|
||||
datasets.push({
|
||||
label: labels[li],
|
||||
data: td,
|
||||
//borderColor: 'blue',
|
||||
borderWidth: 2,
|
||||
fill: false,
|
||||
})
|
||||
}
|
||||
MainChart.datasets = datasets
|
||||
MainChart.update()
|
||||
// Остальные строки содержат данные
|
||||
this.logsTable.rows = lines.map(line => line.split('\t'))
|
||||
})
|
||||
.catch((reason) => { alert(`Ошибка при чтении логов: ${reason}`) })
|
||||
.finally(() => { this.submitStatus.logView = false })
|
||||
@@ -255,7 +216,6 @@
|
||||
}
|
||||
doFetchSettings().then(() => {})
|
||||
document.getElementById("app").removeAttribute("hidden")
|
||||
//this.chart = chart
|
||||
}
|
||||
});
|
||||
app.mount('#app')
|
||||
|
File diff suppressed because one or more lines are too long
@@ -1,7 +0,0 @@
|
||||
/*!
|
||||
* chartjs-adapter-moment v1.0.1
|
||||
* https://www.chartjs.org
|
||||
* (c) 2022 chartjs-adapter-moment Contributors
|
||||
* Released under the MIT license
|
||||
*/
|
||||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(require("moment"),require("chart.js")):"function"==typeof define&&define.amd?define(["moment","chart.js"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).moment,e.Chart)}(this,(function(e,t){"use strict";function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var f=n(e);const a={datetime:"MMM D, YYYY, h:mm:ss a",millisecond:"h:mm:ss.SSS a",second:"h:mm:ss a",minute:"h:mm a",hour:"hA",day:"MMM D",week:"ll",month:"MMM YYYY",quarter:"[Q]Q - YYYY",year:"YYYY"};t._adapters._date.override("function"==typeof f.default?{_id:"moment",formats:function(){return a},parse:function(e,t){return"string"==typeof e&&"string"==typeof t?e=f.default(e,t):e instanceof f.default||(e=f.default(e)),e.isValid()?e.valueOf():null},format:function(e,t){return f.default(e).format(t)},add:function(e,t,n){return f.default(e).add(t,n).valueOf()},diff:function(e,t,n){return f.default(e).diff(f.default(t),n)},startOf:function(e,t,n){return e=f.default(e),"isoWeek"===t?(n=Math.trunc(Math.min(Math.max(0,n),6)),e.isoWeekday(n).startOf("day").valueOf()):e.startOf(t).valueOf()},endOf:function(e,t){return f.default(e).endOf(t).valueOf()}}:{})}));
|
File diff suppressed because one or more lines are too long
@@ -52,6 +52,7 @@
|
||||
</div>
|
||||
</header>
|
||||
<div id="content">
|
||||
|
||||
<div class="tabs-body-item tabs-item-flex-container" v-if="activeTab === 'monitoring'">
|
||||
<div class="settings-set-container statistics-container">
|
||||
<h2>Статистика приема</h2>
|
||||
@@ -62,7 +63,7 @@
|
||||
<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>SNR/RSSI</th><td>{{ statRx.snr }} / {{ statRx.rssi }}</td></tr>
|
||||
<tr><th>Modcod</th><td>{{ statRx.modcod }}</td></tr>
|
||||
<tr><th>Размер кадра</th><td>{{ statRx.frameSizeNormal ? 'normal' : 'short' }}</td></tr>
|
||||
<tr><th>Пилот-символы</th><td>{{ statRx.isPilots ? 'pilots' : 'no pilots' }}</td></tr>
|
||||
@@ -159,7 +160,7 @@
|
||||
<h3>Параметры передачи</h3>
|
||||
<label>
|
||||
<span>Центральная частота, КГц</span>
|
||||
<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})"/>
|
||||
<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})"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Символьная скорость, Бод</span>
|
||||
@@ -168,12 +169,12 @@
|
||||
<label>
|
||||
<span>Roll-off</span>
|
||||
<select v-model="paramRxtx.txRolloff">
|
||||
<option :value="20">0.02</option>
|
||||
<option :value="50">0.05</option>
|
||||
<option :value="100">0.10</option>
|
||||
<option :value="150">0.15</option>
|
||||
<option :value="200">0.20</option>
|
||||
<option :value="250">0.25</option>
|
||||
<option :value="2">0.02</option>
|
||||
<option :value="5">0.05</option>
|
||||
<option :value="10">0.10</option>
|
||||
<option :value="15">0.15</option>
|
||||
<option :value="20">0.20</option>
|
||||
<option :value="25">0.25</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
@@ -202,10 +203,6 @@
|
||||
<option :value="false">short</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
<span>Пилот-символы</span>
|
||||
<span class="toggle-input"><input type="checkbox" v-model="paramRxtx.txIsPilots" /><span class="slider"></span></span>
|
||||
</label>
|
||||
<label v-show="paramRxtx.dvbIsAcm === false">
|
||||
<span>Модуляция</span>
|
||||
<select v-model="paramRxtx.dvbCcmModulation" @change="paramRxtx.dvbCcmSpeed = correctModcodSpeed(paramRxtx.dvbCcmModulation, paramRxtx.dvbCcmSpeed)">
|
||||
@@ -273,7 +270,7 @@
|
||||
</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>
|
||||
<label><span>Требуемое ОСШ</span><input type="number" v-model="paramRxtx.aupcRequiredSnr" max="10" step="0.01"/></label>
|
||||
</div>
|
||||
<div class="settings-set-container">
|
||||
<h3>Настройки приемника</h3>
|
||||
@@ -294,7 +291,7 @@
|
||||
</label>
|
||||
<label>
|
||||
<span>Центральная частота, КГц</span>
|
||||
<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})"/>
|
||||
<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})"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Символьная скорость, Бод</span>
|
||||
@@ -303,12 +300,12 @@
|
||||
<label>
|
||||
<span>Roll-off</span>
|
||||
<select v-model="paramRxtx.rxRolloff">
|
||||
<option :value="20">0.02</option>
|
||||
<option :value="50">0.05</option>
|
||||
<option :value="100">0.10</option>
|
||||
<option :value="150">0.15</option>
|
||||
<option :value="200">0.20</option>
|
||||
<option :value="250">0.25</option>
|
||||
<option :value="2">0.02</option>
|
||||
<option :value="5">0.05</option>
|
||||
<option :value="10">0.10</option>
|
||||
<option :value="15">0.15</option>
|
||||
<option :value="20">0.20</option>
|
||||
<option :value="25">0.25</option>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
@@ -325,19 +322,19 @@
|
||||
<div class="settings-set-container" v-show="paramRxtx.isCinC">
|
||||
<label>
|
||||
<span>Метод расчета задержки</span>
|
||||
<select v-model="paramDpdi.isPositional">
|
||||
<select v-model="paramDpdi.dpdiIsPositional">
|
||||
<option :value="true">Позиционированием</option>
|
||||
<option :value="false">Окном задержки</option>
|
||||
</select>
|
||||
</label>
|
||||
<label><span>Полоса поиска, КГц ±</span><input type="number" v-model="paramDpdi.searchBandwidth" max="100" step="1"/></label>
|
||||
<h2 v-show="paramDpdi.isPositional === true">Настройки позиционирования</h2>
|
||||
<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.isPositional === true"><span>Долгота станции</span><input type="number" v-model="paramDpdi.positionStationLongitude" 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.isPositional === false">Задержка до спутника</h2>
|
||||
<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.isPositional === false"><span>до, мс</span><input type="number" v-model="paramDpdi.delayMax" max="400" step="0.1"/></label>
|
||||
<label><span>Полоса поиска, КГц ±</span><input type="number" v-model="paramDpdi.dpdiSearchBandwidth" max="100" step="1"/></label>
|
||||
<h2 v-show="paramDpdi.dpdiIsPositional === 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.dpdiIsPositional === true"><span>Долгота станции</span><input type="number" v-model="paramDpdi.dpdiPositionStationLongitude" 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>
|
||||
<h2 v-show="paramDpdi.dpdiIsPositional === 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.dpdiIsPositional === false"><span>до, мс</span><input type="number" v-model="paramDpdi.dpdiDelayMax" max="400" step="0.1"/></label>
|
||||
</div>
|
||||
<button class="action-button" @click="settingsSubmitDpdi()" v-show="paramRxtx.isCinC">Сохранить <span class="submit-spinner" v-show="submitStatus.dpdi"></span></button>
|
||||
<h2>Настройки питания и опорного генератора</h2>
|
||||
@@ -386,7 +383,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<button class="action-button" @click="settingsSubmitBuclnb()">Сохранить <span class="submit-spinner" v-show="submitStatus.buclnb"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tabs-body-item" v-if="activeTab === 'qos' && settingFetchComplete">
|
||||
<h2>Настройки QoS</h2>
|
||||
<div class="settings-set-container">
|
||||
@@ -453,7 +450,7 @@
|
||||
<label class="l3-proto-label"><span>DCCP:</span><input type="checkbox" value="dccp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>ESP:</span><input type="checkbox" value="esp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>ICMP:</span><input type="checkbox" value="icmp" v-model="filter.proto"></label>
|
||||
<!-- <label class="l3-proto-label"><span>ICMPV6:</span><input type="checkbox" value="icmpv6" v-model="filter.proto"></label>-->
|
||||
<!-- <label class="l3-proto-label"><span>ICMPV6:</span><input type="checkbox" value="icmpv6" v-model="filter.proto"></label>-->
|
||||
<label class="l3-proto-label"><span>SCTP:</span><input type="checkbox" value="sctp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>TCP:</span><input type="checkbox" value="tcp" v-model="filter.proto"></label>
|
||||
<label class="l3-proto-label"><span>UDP:</span><input type="checkbox" value="udp" v-model="filter.proto"></label>
|
||||
@@ -488,29 +485,38 @@
|
||||
</div>
|
||||
<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">
|
||||
<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])$">
|
||||
<span>Интерфейс управления (/24)</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]?)$">
|
||||
</label>
|
||||
<label>
|
||||
<span>Режим сети</span>
|
||||
<select v-model="paramNetwork.isL2">
|
||||
<select v-model="paramNetwork.netIsL2">
|
||||
<option :value="false">Маршрутизатор</option>
|
||||
<option :value="true">Коммутатор</option>
|
||||
</select>
|
||||
</label>
|
||||
<label v-show="paramNetwork.isL2 === false">
|
||||
<label v-show="paramNetwork.netIsL2 === 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]?)$">
|
||||
<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]?)$">
|
||||
</label>
|
||||
<label><span>MTU интерфейса данных</span><input type="number" v-model="paramNetwork.dataMtu" min="1500" max="2000" step="1"/></label>
|
||||
<label><span>MTU интерфейса данных</span><input type="number" v-model="paramNetwork.netDataMtu" min="1500" max="2000" step="1"/></label>
|
||||
<label>
|
||||
<span>Имя веб-сервера</span>
|
||||
<input v-model="paramNetwork.serverName" type="text">
|
||||
<input v-model="paramNetwork.netServerName" type="text">
|
||||
</label>
|
||||
</div>
|
||||
<button class="action-button" @click="settingsSubmitNetwork()">Сохранить <span class="submit-spinner" v-show="submitStatus.network"></span></button>
|
||||
@@ -532,8 +538,6 @@
|
||||
<div>
|
||||
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
|
||||
</div>
|
||||
<button class="action-button" @click="dumpAllSettings()">Сохранить бекап конфигурации</button>
|
||||
<button class="dangerous-button" @click="restoreAllSettings()">Восстановить бекап конфигурации</button>
|
||||
</div>
|
||||
|
||||
<h2>Обновление ПО</h2>
|
||||
@@ -548,7 +552,6 @@
|
||||
<button class="dangerous-button" v-show="uploadFw.sha256 !== null" @click="settingsPerformFirmwareUpgrade()">Обновить встроенное ПО<span class="submit-spinner" v-show="submitStatus.firmwareUpgrade"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>Последнее обновление статистики: {{ lastUpdateTime }}</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -588,6 +591,7 @@
|
||||
rxtx: false,
|
||||
dpdi: false,
|
||||
buclnb: false,
|
||||
tcpaccel: false,
|
||||
network: false,
|
||||
firmwareUpload: false,
|
||||
firmwareUpgrade: false,
|
||||
@@ -604,13 +608,12 @@
|
||||
txIsTestInput: false,
|
||||
txCentralFreq: 0,
|
||||
txBaudrate: 0,
|
||||
txRolloff: 20,
|
||||
txRolloff: 2,
|
||||
txGoldan: 0,
|
||||
txAttenuation: -40,
|
||||
dvbServicePacketPeriod: 0,
|
||||
dvbIsAcm: false,
|
||||
txFrameSizeNormal: true,
|
||||
txIsPilots: false,
|
||||
dvbCcmModulation: "QPSK",
|
||||
dvbCcmSpeed: "1/4",
|
||||
dvbAcmMinModulation: "QPSK",
|
||||
@@ -627,17 +630,17 @@
|
||||
rxSpectrumInversion: false,
|
||||
rxCentralFreq: 0,
|
||||
rxBaudrate: 0,
|
||||
rxRolloff: 20,
|
||||
rxRolloff: 2,
|
||||
rxGoldan: 0,
|
||||
},
|
||||
paramDpdi: {
|
||||
isPositional: true,
|
||||
searchBandwidth: 0,
|
||||
positionStationLatitude: -180,
|
||||
positionStationLongitude: -180,
|
||||
positionSatelliteLongitude: -180,
|
||||
delayMin: 0,
|
||||
delayMax: 0,
|
||||
dpdiIsPositional: true,
|
||||
dpdiSearchBandwidth: 0,
|
||||
dpdiPositionStationLatitude: -180,
|
||||
dpdiPositionStationLongitude: -180,
|
||||
dpdiPositionSatelliteLongitude: -180,
|
||||
dpdiDelayMin: 0,
|
||||
dpdiDelayMax: 0,
|
||||
},
|
||||
paramBuclnb: {
|
||||
bucRefClk10M: false,
|
||||
@@ -647,12 +650,16 @@
|
||||
srvRefClk10M: false,
|
||||
bucLnbAutoStart: false,
|
||||
},
|
||||
paramTcpaccel: {
|
||||
accelEn: false,
|
||||
accelMaxConnections: 0,
|
||||
},
|
||||
paramNetwork: {
|
||||
managementIp: null,
|
||||
isL2: false,
|
||||
dataIp: null,
|
||||
dataMtu: 1500,
|
||||
serverName: null,
|
||||
netManagementIp: null,
|
||||
netIsL2: false,
|
||||
netDataIp: null,
|
||||
netDataMtu: 1500,
|
||||
netServerName: null,
|
||||
},
|
||||
// ========== include end from 'common/all-params-data.js.j2'
|
||||
|
||||
@@ -710,8 +717,7 @@
|
||||
rt2: [],
|
||||
rt3: [],
|
||||
cd: [],
|
||||
},
|
||||
// ========== include end from 'common/qos-data.js.j2'
|
||||
}, // ========== include end from 'common/qos-data.js.j2'
|
||||
|
||||
// ========== include from 'common/admin-data.js.j2'
|
||||
// ========== include end from 'common/admin-data.js.j2'
|
||||
@@ -799,7 +805,6 @@
|
||||
"dvbServicePacketPeriod": this.paramRxtx.dvbServicePacketPeriod,
|
||||
"dvbIsAcm": this.paramRxtx.dvbIsAcm,
|
||||
"txFrameSizeNormal": this.paramRxtx.txFrameSizeNormal,
|
||||
"txIsPilots": this.paramRxtx.txIsPilots,
|
||||
"dvbCcmModulation": this.paramRxtx.dvbCcmModulation,
|
||||
"dvbCcmSpeed": this.paramRxtx.dvbCcmSpeed,
|
||||
"dvbAcmMinModulation": this.paramRxtx.dvbAcmMinModulation,
|
||||
@@ -830,13 +835,13 @@
|
||||
if (this.submitStatus.dpdi) { return }
|
||||
|
||||
let query = {
|
||||
"isPositional": this.paramDpdi.isPositional,
|
||||
"searchBandwidth": this.paramDpdi.searchBandwidth,
|
||||
"positionStationLatitude": this.paramDpdi.positionStationLatitude,
|
||||
"positionStationLongitude": this.paramDpdi.positionStationLongitude,
|
||||
"positionSatelliteLongitude": this.paramDpdi.positionSatelliteLongitude,
|
||||
"delayMin": this.paramDpdi.delayMin,
|
||||
"delayMax": this.paramDpdi.delayMax,
|
||||
"dpdiIsPositional": this.paramDpdi.dpdiIsPositional,
|
||||
"dpdiSearchBandwidth": this.paramDpdi.dpdiSearchBandwidth,
|
||||
"dpdiPositionStationLatitude": this.paramDpdi.dpdiPositionStationLatitude,
|
||||
"dpdiPositionStationLongitude": this.paramDpdi.dpdiPositionStationLongitude,
|
||||
"dpdiPositionSatelliteLongitude": this.paramDpdi.dpdiPositionSatelliteLongitude,
|
||||
"dpdiDelayMin": this.paramDpdi.dpdiDelayMin,
|
||||
"dpdiDelayMax": this.paramDpdi.dpdiDelayMax,
|
||||
}
|
||||
|
||||
this.submitStatus.dpdi = true
|
||||
@@ -864,16 +869,30 @@
|
||||
.catch((reason) => { alert(`Ошибка при применении настроек: ${reason}`) })
|
||||
.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() {
|
||||
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,
|
||||
"netManagementIp": this.paramNetwork.netManagementIp,
|
||||
"netIsL2": this.paramNetwork.netIsL2,
|
||||
"netDataIp": this.paramNetwork.netDataIp,
|
||||
"netDataMtu": this.paramNetwork.netDataMtu,
|
||||
"netServerName": this.paramNetwork.netServerName,
|
||||
}
|
||||
|
||||
this.submitStatus.network = true
|
||||
@@ -885,65 +904,69 @@
|
||||
|
||||
updateRxtxSettings(vals) {
|
||||
this.submitStatus.rxtx = false
|
||||
this.paramRxtx.isCinC = vals["settings"]["rxtx"]["isCinC"]
|
||||
this.paramRxtx.txEn = vals["settings"]["rxtx"]["txEn"]
|
||||
this.paramRxtx.txAutoStart = vals["settings"]["rxtx"]["txAutoStart"]
|
||||
this.paramRxtx.txModulatorIsTest = vals["settings"]["rxtx"]["txModulatorIsTest"]
|
||||
this.paramRxtx.txIsTestInput = vals["settings"]["rxtx"]["txIsTestInput"]
|
||||
this.paramRxtx.txCentralFreq = this.inputFormatNumber(vals["settings"]["rxtx"]["txCentralFreq"], {min:100000,max:6000000,step:0.01})
|
||||
this.paramRxtx.txBaudrate = this.inputFormatNumber(vals["settings"]["rxtx"]["txBaudrate"], {min:200000,max:54000000,})
|
||||
this.paramRxtx.txRolloff = vals["settings"]["rxtx"]["txRolloff"]
|
||||
this.paramRxtx.txGoldan = vals["settings"]["rxtx"]["txGoldan"]
|
||||
this.paramRxtx.txAttenuation = vals["settings"]["rxtx"]["txAttenuation"]
|
||||
this.paramRxtx.dvbServicePacketPeriod = vals["settings"]["rxtx"]["dvbServicePacketPeriod"]
|
||||
this.paramRxtx.dvbIsAcm = vals["settings"]["rxtx"]["dvbIsAcm"]
|
||||
this.paramRxtx.txFrameSizeNormal = vals["settings"]["rxtx"]["txFrameSizeNormal"]
|
||||
this.paramRxtx.txIsPilots = vals["settings"]["rxtx"]["txIsPilots"]
|
||||
this.paramRxtx.dvbCcmModulation = vals["settings"]["rxtx"]["dvbCcmModulation"]
|
||||
this.paramRxtx.dvbCcmSpeed = vals["settings"]["rxtx"]["dvbCcmSpeed"]
|
||||
this.paramRxtx.dvbAcmMinModulation = vals["settings"]["rxtx"]["dvbAcmMinModulation"]
|
||||
this.paramRxtx.dvbAcmMinSpeed = vals["settings"]["rxtx"]["dvbAcmMinSpeed"]
|
||||
this.paramRxtx.dvbAcmMaxModulation = vals["settings"]["rxtx"]["dvbAcmMaxModulation"]
|
||||
this.paramRxtx.dvbAcmMaxSpeed = vals["settings"]["rxtx"]["dvbAcmMaxSpeed"]
|
||||
this.paramRxtx.dvbSnrReserve = vals["settings"]["rxtx"]["dvbSnrReserve"]
|
||||
this.paramRxtx.aupcEn = vals["settings"]["rxtx"]["aupcEn"]
|
||||
this.paramRxtx.aupcMinAttenuation = vals["settings"]["rxtx"]["aupcMinAttenuation"]
|
||||
this.paramRxtx.aupcMaxAttenuation = vals["settings"]["rxtx"]["aupcMaxAttenuation"]
|
||||
this.paramRxtx.aupcRequiredSnr = vals["settings"]["rxtx"]["aupcRequiredSnr"]
|
||||
this.paramRxtx.rxAgcEn = vals["settings"]["rxtx"]["rxAgcEn"]
|
||||
this.paramRxtx.rxManualGain = vals["settings"]["rxtx"]["rxManualGain"]
|
||||
this.paramRxtx.rxSpectrumInversion = vals["settings"]["rxtx"]["rxSpectrumInversion"]
|
||||
this.paramRxtx.rxCentralFreq = this.inputFormatNumber(vals["settings"]["rxtx"]["rxCentralFreq"], {min:100000,max:6000000,step:0.01})
|
||||
this.paramRxtx.rxBaudrate = this.inputFormatNumber(vals["settings"]["rxtx"]["rxBaudrate"], {min:200000,max:54000000,})
|
||||
this.paramRxtx.rxRolloff = vals["settings"]["rxtx"]["rxRolloff"]
|
||||
this.paramRxtx.rxGoldan = vals["settings"]["rxtx"]["rxGoldan"]
|
||||
this.paramRxtx.isCinC = vals["settings"]["isCinC"]
|
||||
this.paramRxtx.txEn = vals["settings"]["txEn"]
|
||||
this.paramRxtx.txAutoStart = vals["settings"]["txAutoStart"]
|
||||
this.paramRxtx.txModulatorIsTest = vals["settings"]["txModulatorIsTest"]
|
||||
this.paramRxtx.txIsTestInput = vals["settings"]["txIsTestInput"]
|
||||
this.paramRxtx.txCentralFreq = this.inputFormatNumber(vals["settings"]["txCentralFreq"], {min:950000,max:6000000,step:0.01})
|
||||
this.paramRxtx.txBaudrate = this.inputFormatNumber(vals["settings"]["txBaudrate"], {min:200000,max:54000000,})
|
||||
this.paramRxtx.txRolloff = vals["settings"]["txRolloff"]
|
||||
this.paramRxtx.txGoldan = vals["settings"]["txGoldan"]
|
||||
this.paramRxtx.txAttenuation = vals["settings"]["txAttenuation"]
|
||||
this.paramRxtx.dvbServicePacketPeriod = vals["settings"]["dvbServicePacketPeriod"]
|
||||
this.paramRxtx.dvbIsAcm = vals["settings"]["dvbIsAcm"]
|
||||
this.paramRxtx.txFrameSizeNormal = vals["settings"]["txFrameSizeNormal"]
|
||||
this.paramRxtx.dvbCcmModulation = vals["settings"]["dvbCcmModulation"]
|
||||
this.paramRxtx.dvbCcmSpeed = vals["settings"]["dvbCcmSpeed"]
|
||||
this.paramRxtx.dvbAcmMinModulation = vals["settings"]["dvbAcmMinModulation"]
|
||||
this.paramRxtx.dvbAcmMinSpeed = vals["settings"]["dvbAcmMinSpeed"]
|
||||
this.paramRxtx.dvbAcmMaxModulation = vals["settings"]["dvbAcmMaxModulation"]
|
||||
this.paramRxtx.dvbAcmMaxSpeed = vals["settings"]["dvbAcmMaxSpeed"]
|
||||
this.paramRxtx.dvbSnrReserve = vals["settings"]["dvbSnrReserve"]
|
||||
this.paramRxtx.aupcEn = vals["settings"]["aupcEn"]
|
||||
this.paramRxtx.aupcMinAttenuation = vals["settings"]["aupcMinAttenuation"]
|
||||
this.paramRxtx.aupcMaxAttenuation = vals["settings"]["aupcMaxAttenuation"]
|
||||
this.paramRxtx.aupcRequiredSnr = vals["settings"]["aupcRequiredSnr"]
|
||||
this.paramRxtx.rxAgcEn = vals["settings"]["rxAgcEn"]
|
||||
this.paramRxtx.rxManualGain = vals["settings"]["rxManualGain"]
|
||||
this.paramRxtx.rxSpectrumInversion = vals["settings"]["rxSpectrumInversion"]
|
||||
this.paramRxtx.rxCentralFreq = this.inputFormatNumber(vals["settings"]["rxCentralFreq"], {min:950000,max:6000000,step:0.01})
|
||||
this.paramRxtx.rxBaudrate = this.inputFormatNumber(vals["settings"]["rxBaudrate"], {min:200000,max:54000000,})
|
||||
this.paramRxtx.rxRolloff = vals["settings"]["rxRolloff"]
|
||||
this.paramRxtx.rxGoldan = vals["settings"]["rxGoldan"]
|
||||
},
|
||||
updateDpdiSettings(vals) {
|
||||
this.submitStatus.dpdi = false
|
||||
this.paramDpdi.isPositional = vals["settings"]["dpdi"]["isPositional"]
|
||||
this.paramDpdi.searchBandwidth = vals["settings"]["dpdi"]["searchBandwidth"]
|
||||
this.paramDpdi.positionStationLatitude = vals["settings"]["dpdi"]["positionStationLatitude"]
|
||||
this.paramDpdi.positionStationLongitude = vals["settings"]["dpdi"]["positionStationLongitude"]
|
||||
this.paramDpdi.positionSatelliteLongitude = vals["settings"]["dpdi"]["positionSatelliteLongitude"]
|
||||
this.paramDpdi.delayMin = vals["settings"]["dpdi"]["delayMin"]
|
||||
this.paramDpdi.delayMax = vals["settings"]["dpdi"]["delayMax"]
|
||||
this.paramDpdi.dpdiIsPositional = vals["settings"]["dpdiIsPositional"]
|
||||
this.paramDpdi.dpdiSearchBandwidth = vals["settings"]["dpdiSearchBandwidth"]
|
||||
this.paramDpdi.dpdiPositionStationLatitude = vals["settings"]["dpdiPositionStationLatitude"]
|
||||
this.paramDpdi.dpdiPositionStationLongitude = vals["settings"]["dpdiPositionStationLongitude"]
|
||||
this.paramDpdi.dpdiPositionSatelliteLongitude = vals["settings"]["dpdiPositionSatelliteLongitude"]
|
||||
this.paramDpdi.dpdiDelayMin = vals["settings"]["dpdiDelayMin"]
|
||||
this.paramDpdi.dpdiDelayMax = vals["settings"]["dpdiDelayMax"]
|
||||
},
|
||||
updateBuclnbSettings(vals) {
|
||||
this.submitStatus.buclnb = false
|
||||
this.paramBuclnb.bucRefClk10M = vals["settings"]["buclnb"]["bucRefClk10M"]
|
||||
this.paramBuclnb.bucPowering = vals["settings"]["buclnb"]["bucPowering"]
|
||||
this.paramBuclnb.lnbRefClk10M = vals["settings"]["buclnb"]["lnbRefClk10M"]
|
||||
this.paramBuclnb.lnbPowering = vals["settings"]["buclnb"]["lnbPowering"]
|
||||
this.paramBuclnb.srvRefClk10M = vals["settings"]["buclnb"]["srvRefClk10M"]
|
||||
this.paramBuclnb.bucLnbAutoStart = vals["settings"]["buclnb"]["bucLnbAutoStart"]
|
||||
this.paramBuclnb.bucRefClk10M = vals["settings"]["bucRefClk10M"]
|
||||
this.paramBuclnb.bucPowering = vals["settings"]["bucPowering"]
|
||||
this.paramBuclnb.lnbRefClk10M = vals["settings"]["lnbRefClk10M"]
|
||||
this.paramBuclnb.lnbPowering = vals["settings"]["lnbPowering"]
|
||||
this.paramBuclnb.srvRefClk10M = vals["settings"]["srvRefClk10M"]
|
||||
this.paramBuclnb.bucLnbAutoStart = vals["settings"]["bucLnbAutoStart"]
|
||||
},
|
||||
updateTcpaccelSettings(vals) {
|
||||
this.submitStatus.tcpaccel = false
|
||||
this.paramTcpaccel.accelEn = vals["settings"]["accelEn"]
|
||||
this.paramTcpaccel.accelMaxConnections = vals["settings"]["accelMaxConnections"]
|
||||
},
|
||||
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"]
|
||||
this.paramNetwork.netManagementIp = vals["settings"]["netManagementIp"]
|
||||
this.paramNetwork.netIsL2 = vals["settings"]["netIsL2"]
|
||||
this.paramNetwork.netDataIp = vals["settings"]["netDataIp"]
|
||||
this.paramNetwork.netDataMtu = vals["settings"]["netDataMtu"]
|
||||
this.paramNetwork.netServerName = vals["settings"]["netServerName"]
|
||||
},
|
||||
// ========== include end from 'common/all-params-methods.js.j2'
|
||||
|
||||
@@ -968,52 +991,53 @@
|
||||
}
|
||||
|
||||
this.lastUpdateTime = new Date();
|
||||
this.initState = vals["state"]["initState"]
|
||||
this.testState = vals["state"]["testState"]
|
||||
this.isCinC = vals["state"]["isCinC"]
|
||||
this.initState = vals["mainState"]["initState"]
|
||||
this.isCinC = vals["mainState"]["isCinC"]
|
||||
|
||||
this.statRx.state = vals["state"]["rx"]["state"]
|
||||
this.statRx.sym_sync_lock = vals["state"]["rx"]["sym_sync_lock"]
|
||||
this.statRx.freq_search_lock = vals["state"]["rx"]["freq_search_lock"]
|
||||
this.statRx.afc_lock = vals["state"]["rx"]["afc_lock"]
|
||||
this.statRx.pkt_sync = vals["state"]["rx"]["pkt_sync"]
|
||||
this.statRx.snr = Math.round(vals["state"]["rx"]["snr"] * 10) / 10
|
||||
this.statRx.rssi = Math.round(vals["state"]["rx"]["rssi"] * 10) / 10
|
||||
this.statRx.modcod = modcodToStr(vals["state"]["rx"]["modcod"])
|
||||
this.statRx.frameSizeNormal = vals["state"]["rx"]["frameSizeNormal"]
|
||||
this.statRx.isPilots = vals["state"]["rx"]["isPilots"]
|
||||
this.statRx.symError = vals["state"]["rx"]["symError"]
|
||||
this.statRx.freqErr = Math.round(vals["state"]["rx"]["freqErr"] * 100) / 100
|
||||
this.statRx.freqErrAcc = Math.round(vals["state"]["rx"]["freqErrAcc"] * 100) / 100
|
||||
this.statRx.inputSignalLevel = vals["state"]["rx"]["inputSignalLevel"]
|
||||
this.statRx.pllError = Math.round(vals["state"]["rx"]["pllError"] * 100) / 100
|
||||
this.statRx.speedOnRxKbit = Math.round(vals["state"]["rx"]["speedOnRxKbit"] * 100) / 100
|
||||
this.statRx.speedOnIifKbit = Math.round(vals["state"]["rx"]["speedOnIifKbit"] * 100) / 100
|
||||
this.statRx.packetsOk = vals["state"]["rx"]["packetsOk"]
|
||||
this.statRx.packetsBad = vals["state"]["rx"]["packetsBad"]
|
||||
this.statRx.packetsDummy = vals["state"]["rx"]["packetsDummy"]
|
||||
this.statRx.state = vals["mainState"]["rx.state"]
|
||||
this.statRx.sym_sync_lock = vals["mainState"]["rx.sym_sync_lock"]
|
||||
this.statRx.freq_search_lock = vals["mainState"]["rx.freq_search_lock"]
|
||||
this.statRx.afc_lock = vals["mainState"]["rx.afc_lock"]
|
||||
this.statRx.pkt_sync = vals["mainState"]["rx.pkt_sync"]
|
||||
this.statRx.snr = vals["mainState"]["rx.snr"]
|
||||
this.statRx.rssi = vals["mainState"]["rx.rssi"]
|
||||
this.statRx.modcod = modcodToStr(vals["mainState"]["rx.modcod"])
|
||||
this.statRx.frameSizeNormal = vals["mainState"]["rx.frameSizeNormal"]
|
||||
this.statRx.isPilots = vals["mainState"]["rx.isPilots"]
|
||||
this.statRx.symError = vals["mainState"]["rx.symError"]
|
||||
this.statRx.freqErr = vals["mainState"]["rx.freqErr"]
|
||||
this.statRx.freqErrAcc = vals["mainState"]["rx.freqErrAcc"]
|
||||
this.statRx.inputSignalLevel = vals["mainState"]["rx.inputSignalLevel"]
|
||||
this.statRx.pllError = vals["mainState"]["rx.pllError"]
|
||||
this.statRx.speedOnRxKbit = vals["mainState"]["rx.speedOnRxKbit"]
|
||||
this.statRx.speedOnIifKbit = vals["mainState"]["rx.speedOnIifKbit"]
|
||||
this.statRx.packetsOk = vals["mainState"]["rx.packetsOk"]
|
||||
this.statRx.packetsBad = vals["mainState"]["rx.packetsBad"]
|
||||
this.statRx.packetsDummy = vals["mainState"]["rx.packetsDummy"]
|
||||
|
||||
this.statTx.state = vals["state"]["tx"]["state"]
|
||||
this.statTx.snr = Math.round(vals["state"]["tx"]["snr"] * 100) / 100
|
||||
this.statTx.modcod = modcodToStr(vals["state"]["tx"]["modcod"])
|
||||
this.statTx.frameSizeNormal = vals["state"]["tx"]["frameSizeNormal"]
|
||||
this.statTx.isPilots = vals["state"]["tx"]["isPilots"]
|
||||
this.statTx.speedOnTxKbit = Math.round(vals["state"]["tx"]["speedOnTxKbit"] * 100) / 100
|
||||
this.statTx.speedOnIifKbit = Math.round(vals["state"]["tx"]["speedOnIifKbit"] * 100) / 100
|
||||
this.statTx.state = vals["mainState"]["tx.state"]
|
||||
this.statTx.snr = vals["mainState"]["tx.snr"]
|
||||
this.statTx.modcod = modcodToStr(vals["mainState"]["tx.modcod"])
|
||||
this.statTx.frameSizeNormal = vals["mainState"]["tx.frameSizeNormal"]
|
||||
this.statTx.isPilots = vals["mainState"]["tx.isPilots"]
|
||||
this.statTx.speedOnTxKbit = vals["mainState"]["tx.speedOnTxKbit"]
|
||||
this.statTx.speedOnIifKbit = vals["mainState"]["tx.speedOnIifKbit"]
|
||||
|
||||
this.statCinc.occ = vals["state"]["cinc"]["occ"]
|
||||
this.statCinc.correlator = vals["state"]["cinc"]["correlator"]
|
||||
this.statCinc.correlatorFails = vals["state"]["cinc"]["correlatorFails"]
|
||||
this.statCinc.freqErr = Math.round(vals["state"]["cinc"]["freqErr"] * 100) / 100
|
||||
this.statCinc.freqErrAcc = Math.round(vals["state"]["cinc"]["freqErrAcc"] * 100) / 100
|
||||
this.statCinc.channelDelay = vals["state"]["cinc"]["channelDelay"]
|
||||
this.statCinc.occ = vals["mainState"]["cinc.occ"]
|
||||
this.statCinc.correlator = vals["mainState"]["cinc.correlator"]
|
||||
this.statCinc.correlatorFails = vals["mainState"]["cinc.correlatorFails"]
|
||||
this.statCinc.freqErr = vals["mainState"]["cinc.freqErr"]
|
||||
this.statCinc.freqErrAcc = vals["mainState"]["cinc.freqErrAcc"]
|
||||
this.statCinc.channelDelay = vals["mainState"]["cinc.channelDelay"]
|
||||
|
||||
this.statDevice.adrv = vals["state"]["device"]["adrv"]
|
||||
this.statDevice.zynq = vals["state"]["device"]["zynq"]
|
||||
this.statDevice.fpga = vals["state"]["device"]["fpga"]
|
||||
this.statDevice.adrv = vals["mainState"]["device.adrv"]
|
||||
this.statDevice.zynq = vals["mainState"]["device.zynq"]
|
||||
this.statDevice.fpga = vals["mainState"]["device.fpga"]
|
||||
|
||||
this.testState = vals["mainState"]["testState"]
|
||||
|
||||
// аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид
|
||||
let uptime = vals["state"]["device"]["uptime"]
|
||||
let uptime = vals["sysinfo"]["uptime"]
|
||||
if (uptime) {
|
||||
let secs = uptime % 60; uptime = Math.floor(uptime / 60)
|
||||
let mins = uptime % 60; uptime = Math.floor(uptime / 60)
|
||||
@@ -1025,11 +1049,11 @@
|
||||
} else {
|
||||
this.statOs.uptime = '?'
|
||||
}
|
||||
this.statOs.load1 = Math.round(vals["state"]["device"]["load1min"] * 100) / 100
|
||||
this.statOs.load5 = Math.round(vals["state"]["device"]["load5min"] * 100) / 100
|
||||
this.statOs.load15 = Math.round(vals["state"]["device"]["load15min"] * 100) / 100
|
||||
this.statOs.totalram = vals["state"]["device"]["totalram"]
|
||||
this.statOs.freeram = vals["state"]["device"]["freeram"]
|
||||
this.statOs.load1 = vals["sysinfo"]["load1min"]
|
||||
this.statOs.load5 = vals["sysinfo"]["load5min"]
|
||||
this.statOs.load15 = vals["sysinfo"]["load15min"]
|
||||
this.statOs.totalram = vals["sysinfo"]["totalram"]
|
||||
this.statOs.freeram = vals["sysinfo"]["freeram"]
|
||||
},
|
||||
|
||||
resetPacketsStatistics() {
|
||||
@@ -1125,17 +1149,15 @@
|
||||
}
|
||||
let query = {
|
||||
"en": this.paramQos.en,
|
||||
"profile": {
|
||||
"rt1": [],
|
||||
"rt2": [],
|
||||
"rt3": [],
|
||||
"cd": []
|
||||
}
|
||||
"rt1": [],
|
||||
"rt2": [],
|
||||
"rt3": [],
|
||||
"cd": []
|
||||
}
|
||||
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.rt2.length; i++) { query.profile.rt2.push(_translateQosClass('rt', this.paramQos.rt2[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])) }
|
||||
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.rt3.length; i++) { query.rt3.push(_translateQosClass('rt', this.paramQos.rt3[i])) }
|
||||
for (let i = 0; i < this.paramQos.cd.length; i++) { query.cd.push(_translateQosClass('rt', this.paramQos.cd[i])) }
|
||||
|
||||
//console.log(query)
|
||||
fetch('/api/set/qos', {
|
||||
@@ -1156,9 +1178,9 @@
|
||||
|
||||
updateQosSettings(vals) {
|
||||
this.submitStatusQos = false
|
||||
this.paramQos.en = vals["settings"]["qos"]["en"]
|
||||
this.paramQos.en = vals["settings"]["qosEnabled"]
|
||||
|
||||
const qosProfile = vals["settings"]["qos"]["profile"]
|
||||
const qosProfile = vals["settings"]["qosProfile"]
|
||||
if (qosProfile !== null && qosProfile !== undefined) {
|
||||
this.paramQos.rt1 = [] // .splice(0, this.paramQos.rt1.length)
|
||||
this.paramQos.rt2 = [] // .splice(0, this.paramQos.rt2.length)
|
||||
@@ -1366,135 +1388,7 @@
|
||||
}
|
||||
this.submitStatus.modemReboot = 30
|
||||
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'
|
||||
|
||||
|
||||
performUpdateSettings() {
|
||||
@@ -1505,6 +1399,7 @@
|
||||
this.updateRxtxSettings(vals)
|
||||
this.updateDpdiSettings(vals)
|
||||
this.updateBuclnbSettings(vals)
|
||||
this.updateTcpaccelSettings(vals)
|
||||
this.updateNetworkSettings(vals)
|
||||
this.updateQosSettings(vals)
|
||||
|
||||
@@ -1541,11 +1436,11 @@
|
||||
try {
|
||||
const fr = await fetch("/api/get/aboutFirmware")
|
||||
const d = await fr.json()
|
||||
this.about.firmwareVersion = d["firmware"]["version"]
|
||||
this.about.modemUid = d["firmware"]["modemId"]
|
||||
this.about.modemSn = d["firmware"]["modemSn"]
|
||||
this.about.macManagement = d["firmware"]["macMang"]
|
||||
this.about.macData = d["firmware"]["macData"]
|
||||
this.about.firmwareVersion = d["fw.version"]
|
||||
this.about.modemUid = d["fw.modemId"]
|
||||
this.about.modemSn = d["fw.modemSn"]
|
||||
this.about.macManagement = d["fw.macMang"]
|
||||
this.about.macData = d["fw.macData"]
|
||||
} catch (e) {
|
||||
console.log('Ошибка загрузки версии ПО', e)
|
||||
}
|
||||
|
@@ -1,973 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>ШПС Модем</title>
|
||||
<link rel="stylesheet" type="text/css" href="/style.css">
|
||||
<link rel="stylesheet" type="text/css" href="/fields.css">
|
||||
<style>
|
||||
header {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
background: var(--bg-selected);
|
||||
}
|
||||
|
||||
body { /* значение по-умолчанию */ --header-height: 60px; }
|
||||
|
||||
#content {
|
||||
padding-top: var(--header-height);
|
||||
}
|
||||
|
||||
.l3-proto-label {
|
||||
margin: 0 0 0 0.5em;
|
||||
}
|
||||
.l3-proto-label > * {
|
||||
display: inline-block;
|
||||
}
|
||||
.l3-proto-label input[type=checkbox] {
|
||||
width: auto;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id="app" hidden>
|
||||
<header>
|
||||
<span class="nav-bar-element">Прием: <span :class="{ indicator_bad: statRx.state === false, indicator_good: statRx.state === true, indicator: true }"></span></span>
|
||||
<span class="nav-bar-element">Передача: <span :class="{ indicator_good: statTx.state === true, indicator: true }"></span></span>
|
||||
<span class="nav-bar-element">Тест: <span :class="{ indicator_good: testState, indicator: true }"></span></span>
|
||||
<!-- Последнее обновление: {{ lastUpdateTime }}-->
|
||||
<span :class="{ value_bad: initState !== 'Успешная инициализация системы' }">{{ initState }}</span>
|
||||
<div class="tabs-header">
|
||||
<span style="font-weight:bold">ШПС Модем</span>
|
||||
<a href="#monitoring" class="tabs-btn" @click="activeTab = 'monitoring'" :class="{ active: activeTab === 'monitoring' }">Мониторинг</a>
|
||||
<a href="#setup" class="tabs-btn" @click="activeTab = 'setup'" :class="{ active: activeTab === 'setup' }">Настройки</a>
|
||||
<a href="#admin" class="tabs-btn" @click="activeTab = 'admin'" :class="{ active: activeTab === 'admin' }">Администрирование</a>
|
||||
<a href="/logout" class="tabs-btn">Выход</a>
|
||||
</div>
|
||||
</header>
|
||||
<div id="content">
|
||||
<div class="tabs-body-item tabs-item-flex-container" v-if="activeTab === 'monitoring'">
|
||||
<div class="settings-set-container statistics-container">
|
||||
<h2>Статистика приема</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<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>
|
||||
</tbody>
|
||||
</table>
|
||||
<button class="action-button" @click="resetPacketsStatistics()"> Сброс статистики </button>
|
||||
</div>
|
||||
<div class="settings-set-container statistics-container">
|
||||
<h2>Статистика передачи</h2>
|
||||
<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>
|
||||
</div>
|
||||
<div class="settings-set-container statistics-container">
|
||||
<h2>Состояние устройства</h2>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>Температура ADRV</th><td>{{ statDevice.adrv }} °C</td></tr>
|
||||
<tr><th>Температура ZYNQ</th><td>{{ statDevice.zynq }} °C</td></tr>
|
||||
<tr><th>Температура FPGA</th><td>{{ statDevice.fpga }} °C</td></tr>
|
||||
<tr><th>Время работы устройства</th><td>{{ statOs.uptime }}</td></tr>
|
||||
<tr><th>Средняя загрузка ЦП (1/5/15 мин.)</th><td>{{ statOs.load1 }}% {{ statOs.load5 }}% {{ statOs.load15 }}%</td></tr>
|
||||
<tr><th>ОЗУ всего/свободно</th><td>{{ statOs.totalram }}МБ/{{ statOs.freeram }}МБ</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tabs-body-item" v-if="activeTab === 'setup' && settingFetchComplete">
|
||||
<h2>Настройки приема/передачи</h2>
|
||||
<div class="tabs-item-flex-container">
|
||||
<div class="settings-set-container">
|
||||
<h3>Настройки передатчика</h3>
|
||||
<label>
|
||||
<span>Включить передатчик</span>
|
||||
<span class="toggle-input"><input type="checkbox" v-model="paramRxtx.txEn" /><span class="slider"></span></span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Автоматический запуск передатчика</span>
|
||||
<span class="toggle-input"><input type="checkbox" v-model="paramRxtx.txAutoStart" /><span class="slider"></span></span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Режим работы модулятора</span>
|
||||
<select v-model="paramRxtx.txModulatorIsTest">
|
||||
<option :value="false">Нормальный</option>
|
||||
<option :value="true">Тест (CW)</option>
|
||||
</select>
|
||||
</label>
|
||||
<label><span>Ослабление, дБ</span><input type="number" v-model="paramRxtx.txAttenuation" min="-80" step="0.25"/></label>
|
||||
<label>
|
||||
<span>Входные данные</span>
|
||||
<select v-model="paramRxtx.txIsTestInput">
|
||||
<option :value="false">Ethernet</option>
|
||||
<option :value="true">Тест</option>
|
||||
</select>
|
||||
</label>
|
||||
<h3>Параметры передачи</h3>
|
||||
<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:0.01}), {min:70000,max:6000000,step:0.01})"/>
|
||||
</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>
|
||||
<span>Roll-off</span>
|
||||
<select v-model="paramRxtx.txRolloff">
|
||||
<option :value="20">0.02</option>
|
||||
<option :value="50">0.05</option>
|
||||
<option :value="100">0.10</option>
|
||||
<option :value="150">0.15</option>
|
||||
<option :value="200">0.20</option>
|
||||
<option :value="250">0.25</option>
|
||||
<option :value="300">0.30</option>
|
||||
<option :value="350">0.35</option>
|
||||
</select>
|
||||
</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>
|
||||
<span>Авто-регулировка мощности</span>
|
||||
<span class="toggle-input"><input type="checkbox" v-model="paramRxtx.aupcEn" /><span class="slider"></span></span>
|
||||
</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 class="settings-set-container">
|
||||
<h3>Настройки приемника</h3>
|
||||
<label>
|
||||
<span>Режим управления усилением</span>
|
||||
<select v-model="paramRxtx.rxAgcEn">
|
||||
<option :value="false">РРУ</option>
|
||||
<option :value="true">АРУ</option>
|
||||
</select>
|
||||
</label>
|
||||
<label v-show="paramRxtx.rxAgcEn === false"><span>Усиление, дБ</span><input type="number" v-model="paramRxtx.rxManualGain" min="-40" max="40" step="0.01"/></label>
|
||||
<label v-show="paramRxtx.rxAgcEn === true">
|
||||
<span>Текущее усиление</span><span>{{ paramRxtx.rxManualGain }}</span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Инверсия спектра</span>
|
||||
<span class="toggle-input"><input type="checkbox" v-model="paramRxtx.rxSpectrumInversion" /><span class="slider"></span></span>
|
||||
</label>
|
||||
<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:0.01}), {min:70000,max:6000000,step:0.01})"/>
|
||||
</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>
|
||||
<span>Roll-off</span>
|
||||
<select v-model="paramRxtx.rxRolloff">
|
||||
<option :value="20">0.02</option>
|
||||
<option :value="50">0.05</option>
|
||||
<option :value="100">0.10</option>
|
||||
<option :value="150">0.15</option>
|
||||
<option :value="200">0.20</option>
|
||||
<option :value="250">0.25</option>
|
||||
<option :value="300">0.30</option>
|
||||
<option :value="350">0.35</option>
|
||||
</select>
|
||||
</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>
|
||||
<button class="action-button" @click="settingsSubmitRxtx()">Сохранить <span class="submit-spinner" v-show="submitStatus.rxtx"></span></button>
|
||||
<h2>Настройки питания и опорного генератора</h2>
|
||||
<div class="tabs-item-flex-container">
|
||||
<div class="settings-set-container">
|
||||
<h3>Настройки BUC</h3>
|
||||
<label>
|
||||
<span>Подача опоры 10МГц</span>
|
||||
<span class="toggle-input"><input type="checkbox" v-model="paramBuclnb.bucRefClk10M" /><span class="slider"></span></span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Питание BUC</span>
|
||||
<select v-model="paramBuclnb.bucPowering">
|
||||
<option :value="0">Выкл</option>
|
||||
<option :value="24">24В</option>
|
||||
<option :value="48">48В</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="settings-set-container">
|
||||
<h3>Настройки LNB</h3>
|
||||
<label>
|
||||
<span>Подача опоры 10МГц</span>
|
||||
<span class="toggle-input"><input type="checkbox" v-model="paramBuclnb.lnbRefClk10M" /><span class="slider"></span></span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Питание LNB</span>
|
||||
<select v-model="paramBuclnb.lnbPowering">
|
||||
<option :value="0">Выкл</option>
|
||||
<option :value="13">13В</option>
|
||||
<option :value="18">18В</option>
|
||||
<option :value="24">24В</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
<div class="settings-set-container">
|
||||
<h3>Сервисные настройки</h3>
|
||||
<label>
|
||||
<span>Подача опоры 10МГц на 'Выход 10МГц'</span>
|
||||
<span class="toggle-input"><input type="checkbox" v-model="paramBuclnb.srvRefClk10M" /><span class="slider"></span></span>
|
||||
</label>
|
||||
<label>
|
||||
<span>Автозапуск BUC и LNB при включении</span>
|
||||
<span class="toggle-input"><input type="checkbox" v-model="paramBuclnb.bucLnbAutoStart" /><span class="slider"></span></span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<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">
|
||||
<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>
|
||||
<div class="settings-set-container statistics-container">
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>Версия ПО</th><td>{{ about.firmwareVersion }}</td></tr>
|
||||
<tr><th>ID модема</th><td>{{ about.modemUid }}</td></tr>
|
||||
<tr><th>Серийный номер</th><td>{{ about.modemSn }}</td></tr>
|
||||
<tr><th>MAC интерфейса управления</th><td>{{ about.macManagement }}</td></tr>
|
||||
<tr><th>MAC интерфейса данных</th><td>{{ about.macData }}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div>
|
||||
<button class="dangerous-button" @click="doModemReboot()">Перезагрузить модем <span class="submit-spinner" v-show="submitStatus.modemReboot !== null"></span></button>
|
||||
</div>
|
||||
<div>
|
||||
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
|
||||
</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">
|
||||
<h3>Ручное обновление</h3>
|
||||
<label>
|
||||
<span>Файл {{ this.uploadFw.progress !== null ? `(${this.uploadFw.progress}%)` : '' }}</span>
|
||||
<input type="file" accept="application/zip" @change="(e) => { this.uploadFw.filename = e.target.files[0] }">
|
||||
<span v-if="uploadFw.sha256 !== null">SHA256: {{ uploadFw.sha256 }}</span>
|
||||
</label>
|
||||
<button class="action-button" @click="settingsUploadUpdate()">Загрузить<span class="submit-spinner" v-show="submitStatus.firmwareUpload"></span></button>
|
||||
<button class="dangerous-button" v-show="uploadFw.sha256 !== null" @click="settingsPerformFirmwareUpgrade()">Обновить встроенное ПО<span class="submit-spinner" v-show="submitStatus.firmwareUpgrade"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>Последнее обновление статистики: {{ lastUpdateTime }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/js/vue.js?v=3.5.13"></script>
|
||||
<script>
|
||||
const availableTabs = ['monitoring', 'setup', 'admin']
|
||||
|
||||
// для обновления высоты хидера
|
||||
function updateHeaderHeight() { const header = document.querySelector('header'); document.body.style.setProperty('--header-height', `${header.offsetHeight}px`); }
|
||||
window.addEventListener('load', updateHeaderHeight); window.addEventListener('resize', updateHeaderHeight);
|
||||
|
||||
function getCurrentTab() {
|
||||
const sl = window.location.hash.slice(1)
|
||||
if (availableTabs.indexOf(sl) >= 0) {
|
||||
return sl
|
||||
}
|
||||
return availableTabs[0]
|
||||
}
|
||||
|
||||
function toLocaleStringWithSpaces(num) {
|
||||
if (typeof num !== 'number') {
|
||||
if (typeof num === 'string') { return num }
|
||||
return String(num);
|
||||
}
|
||||
const numberString = num.toString()
|
||||
const [integerPart, fractionalPart] = numberString.split('.')
|
||||
const spacedIntegerPart = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, " ")
|
||||
if (fractionalPart) { return `${spacedIntegerPart}.${fractionalPart}` }
|
||||
else { return spacedIntegerPart }
|
||||
}
|
||||
|
||||
const app = Vue.createApp({
|
||||
data() {
|
||||
return {
|
||||
// false - означает что статистика не отправляется, true - отправляется
|
||||
submitStatus: {
|
||||
rxtx: false,
|
||||
buclnb: false,
|
||||
network: false,
|
||||
firmwareUpload: false,
|
||||
firmwareUpgrade: false,
|
||||
// когда модем перезагружается, тут должен быть счетчик. Направление счета - к нулю
|
||||
modemReboot: null
|
||||
},
|
||||
|
||||
// ========== include from 'common/all-params-data.js.j2'
|
||||
paramRxtx: {
|
||||
txEn: false,
|
||||
txAutoStart: false,
|
||||
txModulatorIsTest: false,
|
||||
txAttenuation: -80,
|
||||
txIsTestInput: false,
|
||||
txCentralFreq: 0,
|
||||
txBaudrate: 0,
|
||||
txRolloff: 20,
|
||||
txSpreadCoef: 8,
|
||||
txFieldsDataPreamble: 1,
|
||||
aupcEn: false,
|
||||
aupcMinAttenuation: 0,
|
||||
aupcMaxAttenuation: 0,
|
||||
aupcRequiredSnr: 0,
|
||||
rxAgcEn: false,
|
||||
rxManualGain: -40,
|
||||
rxSpectrumInversion: false,
|
||||
rxCentralFreq: 0,
|
||||
rxBaudrate: 0,
|
||||
rxRolloff: 20,
|
||||
rxSpreadCoef: 8,
|
||||
rxFftShift: 1,
|
||||
rxFieldsDataPreamble: 1,
|
||||
},
|
||||
paramBuclnb: {
|
||||
bucRefClk10M: false,
|
||||
bucPowering: 0,
|
||||
lnbRefClk10M: false,
|
||||
lnbPowering: 0,
|
||||
srvRefClk10M: false,
|
||||
bucLnbAutoStart: false,
|
||||
},
|
||||
paramNetwork: {
|
||||
managementIp: null,
|
||||
isL2: false,
|
||||
dataIp: null,
|
||||
dataMtu: 1500,
|
||||
serverName: null,
|
||||
},
|
||||
// ========== include end from 'common/all-params-data.js.j2'
|
||||
|
||||
// ========== include from 'common/monitoring-data.js.j2'
|
||||
statRx: {
|
||||
// индикаторы
|
||||
state: '?', // общее состояние
|
||||
sym_sync_lock: '?', // захват символьной
|
||||
freq_search_lock: '?', // Захват поиска по частоте
|
||||
afc_lock: '?', // захват ФАПЧ
|
||||
pkt_sync: '?', // захват пакетной синхронизации
|
||||
|
||||
// куча других параметров, идет в том же порядке, что и в таблице
|
||||
snr: '?', rssi: '?',
|
||||
modcod: '?', frameSizeNormal: '?',
|
||||
isPilots: '?',
|
||||
symError: '?',
|
||||
freqErr: '?', freqErrAcc: '?',
|
||||
inputSignalLevel: '?',
|
||||
pllError: '?',
|
||||
speedOnRxKbit: '?',
|
||||
speedOnIifKbit: '?',
|
||||
|
||||
// статистика пакетов
|
||||
packetsOk: '?', packetsBad: '?', packetsDummy: '?',
|
||||
},
|
||||
statTx: {
|
||||
// состояние
|
||||
state: '?',
|
||||
|
||||
// прочие поля
|
||||
modcod: '?', speedOnTxKbit: '?', speedOnIifKbit: '?', centerFreq: '?', symSpeed: '?'
|
||||
},
|
||||
statDevice: { // температурные датчики
|
||||
adrv: 0, zynq: 0, fpga: 0
|
||||
},
|
||||
statOs: {uptime: '?', load1: '?', load5: '?', load15: '?', totalram: '?', freeram: '?'},
|
||||
// ========== include end from 'common/monitoring-data.js.j2'
|
||||
|
||||
// ========== include from 'common/setup-data.js.j2'
|
||||
// ========== include end from 'common/setup-data.js.j2'
|
||||
|
||||
// ========== include from 'common/admin-data.js.j2'
|
||||
// ========== include end from 'common/admin-data.js.j2'
|
||||
|
||||
uploadFw: {
|
||||
progress: null,
|
||||
filename: null,
|
||||
sha256: null
|
||||
},
|
||||
|
||||
// эти "настройки" - read only
|
||||
about: {
|
||||
firmwareVersion: '?',
|
||||
modemUid: '?',
|
||||
modemSn: '?',
|
||||
macManagement: '?',
|
||||
macData: '?',
|
||||
},
|
||||
|
||||
testState: false,
|
||||
initState: '',
|
||||
lastUpdateTime: new Date(),
|
||||
activeTab: getCurrentTab(),
|
||||
settingFetchComplete: false,
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
correctModcodSpeed(modulation, speed) {
|
||||
const mod = modulation.toLowerCase()
|
||||
const available = {
|
||||
"qpsk": ['1/4', '1/3', '2/5', '1/2', '3/5', '2/3', '3/4', '4/5', '5/6', '8/9', '9/10'],
|
||||
"8psk": ['2/3', '3/4', '5/6', '8/9', '9/10'],
|
||||
"16apsk": ['2/3', '3/4', '4/5', '5/6', '8/9', '9/10'],
|
||||
"32apsk": ['3/4', '4/5', '5/6', '8/9', '9/10']
|
||||
}
|
||||
if (mod in available) {
|
||||
if (available[mod].indexOf(speed) >= 0) {
|
||||
return speed
|
||||
}
|
||||
return available[mod][0]
|
||||
}
|
||||
return ""
|
||||
},
|
||||
getAvailableModcods(modulation) {
|
||||
// NOTE модкоды со скоростью хода 3/5 не работают
|
||||
switch (modulation) {
|
||||
case 'qpsk':
|
||||
return ['1/4', '1/3', '2/5', '1/2', '3/5', '2/3', '3/4', '4/5', '5/6', '8/9', '9/10']
|
||||
case '8psk':
|
||||
return ['3/5', '2/3', '3/4', '5/6', '8/9', '9/10']
|
||||
case '16apsk':
|
||||
return ['2/3', '3/4', '4/5', '5/6', '8/9', '9/10']
|
||||
case '32apsk':
|
||||
return ['3/4', '4/5', '5/6', '8/9', '9/10']
|
||||
default:
|
||||
return []
|
||||
}
|
||||
},
|
||||
inputFormatNumber(src, validation) {
|
||||
if (validation === null || validation === undefined) { validation = {} }
|
||||
const rawVal = src.toString().replace(/[^0-9.,]/g, '').replace(',', '.')
|
||||
let result = rawVal === '' ? 0 : parseFloat(rawVal)
|
||||
const step = 'step' in validation ? validation['step']: 1.0
|
||||
result = Math.round(result / step) * step
|
||||
if ('min' in validation) { if (result <= validation['min']) { result = validation['min'] } }
|
||||
if ('max' in validation) { if (result >= validation['max']) { result = validation['max'] } }
|
||||
return toLocaleStringWithSpaces(result)
|
||||
},
|
||||
|
||||
// ========== include from 'common/all-params-methods.js.j2'
|
||||
settingsSubmitRxtx() {
|
||||
if (this.submitStatus.rxtx) { return }
|
||||
|
||||
let query = {
|
||||
"txEn": this.paramRxtx.txEn,
|
||||
"txAutoStart": this.paramRxtx.txAutoStart,
|
||||
"txModulatorIsTest": this.paramRxtx.txModulatorIsTest,
|
||||
"txAttenuation": this.paramRxtx.txAttenuation,
|
||||
"txIsTestInput": this.paramRxtx.txIsTestInput,
|
||||
"txCentralFreq": parseFloat(this.paramRxtx.txCentralFreq.replace(/[^0-9,.]/g, '').replace(',', '.')),
|
||||
"txBaudrate": parseFloat(this.paramRxtx.txBaudrate.replace(/[^0-9,.]/g, '').replace(',', '.')),
|
||||
"txRolloff": this.paramRxtx.txRolloff,
|
||||
"txSpreadCoef": this.paramRxtx.txSpreadCoef,
|
||||
"txFieldsDataPreamble": this.paramRxtx.txFieldsDataPreamble,
|
||||
"aupcEn": this.paramRxtx.aupcEn,
|
||||
"aupcMinAttenuation": this.paramRxtx.aupcMinAttenuation,
|
||||
"aupcMaxAttenuation": this.paramRxtx.aupcMaxAttenuation,
|
||||
"aupcRequiredSnr": this.paramRxtx.aupcRequiredSnr,
|
||||
"rxAgcEn": this.paramRxtx.rxAgcEn,
|
||||
"rxManualGain": this.paramRxtx.rxManualGain,
|
||||
"rxSpectrumInversion": this.paramRxtx.rxSpectrumInversion,
|
||||
"rxCentralFreq": parseFloat(this.paramRxtx.rxCentralFreq.replace(/[^0-9,.]/g, '').replace(',', '.')),
|
||||
"rxBaudrate": parseFloat(this.paramRxtx.rxBaudrate.replace(/[^0-9,.]/g, '').replace(',', '.')),
|
||||
"rxRolloff": this.paramRxtx.rxRolloff,
|
||||
"rxSpreadCoef": this.paramRxtx.rxSpreadCoef,
|
||||
"rxFftShift": this.paramRxtx.rxFftShift,
|
||||
"rxFieldsDataPreamble": this.paramRxtx.rxFieldsDataPreamble,
|
||||
}
|
||||
|
||||
this.submitStatus.rxtx = true
|
||||
fetch('/api/set/rxtx', {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.updateRxtxSettings(vals) })
|
||||
.catch((reason) => { alert(`Ошибка при применении настроек: ${reason}`) })
|
||||
.finally(() => { this.submitStatus.rxtx = false })
|
||||
},
|
||||
settingsSubmitBuclnb() {
|
||||
if (this.submitStatus.buclnb) { return }
|
||||
{ if (!confirm("Применение неправильных настроек может вывести из строя оборудование! Продолжить?")) return }
|
||||
|
||||
let query = {
|
||||
"bucRefClk10M": this.paramBuclnb.bucRefClk10M,
|
||||
"bucPowering": this.paramBuclnb.bucPowering,
|
||||
"lnbRefClk10M": this.paramBuclnb.lnbRefClk10M,
|
||||
"lnbPowering": this.paramBuclnb.lnbPowering,
|
||||
"srvRefClk10M": this.paramBuclnb.srvRefClk10M,
|
||||
"bucLnbAutoStart": this.paramBuclnb.bucLnbAutoStart,
|
||||
}
|
||||
|
||||
this.submitStatus.buclnb = true
|
||||
fetch('/api/set/buclnb', {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.updateBuclnbSettings(vals) })
|
||||
.catch((reason) => { alert(`Ошибка при применении настроек: ${reason}`) })
|
||||
.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) {
|
||||
this.submitStatus.rxtx = false
|
||||
this.paramRxtx.txEn = vals["settings"]["rxtx"]["txEn"]
|
||||
this.paramRxtx.txAutoStart = vals["settings"]["rxtx"]["txAutoStart"]
|
||||
this.paramRxtx.txModulatorIsTest = vals["settings"]["rxtx"]["txModulatorIsTest"]
|
||||
this.paramRxtx.txAttenuation = vals["settings"]["rxtx"]["txAttenuation"]
|
||||
this.paramRxtx.txIsTestInput = vals["settings"]["rxtx"]["txIsTestInput"]
|
||||
this.paramRxtx.txCentralFreq = this.inputFormatNumber(vals["settings"]["rxtx"]["txCentralFreq"], {min:70000,max:6000000,step:0.01})
|
||||
this.paramRxtx.txBaudrate = this.inputFormatNumber(vals["settings"]["rxtx"]["txBaudrate"], {min:128000,max:30000000,})
|
||||
this.paramRxtx.txRolloff = vals["settings"]["rxtx"]["txRolloff"]
|
||||
this.paramRxtx.txSpreadCoef = vals["settings"]["rxtx"]["txSpreadCoef"]
|
||||
this.paramRxtx.txFieldsDataPreamble = vals["settings"]["rxtx"]["txFieldsDataPreamble"]
|
||||
this.paramRxtx.aupcEn = vals["settings"]["rxtx"]["aupcEn"]
|
||||
this.paramRxtx.aupcMinAttenuation = vals["settings"]["rxtx"]["aupcMinAttenuation"]
|
||||
this.paramRxtx.aupcMaxAttenuation = vals["settings"]["rxtx"]["aupcMaxAttenuation"]
|
||||
this.paramRxtx.aupcRequiredSnr = vals["settings"]["rxtx"]["aupcRequiredSnr"]
|
||||
this.paramRxtx.rxAgcEn = vals["settings"]["rxtx"]["rxAgcEn"]
|
||||
this.paramRxtx.rxManualGain = vals["settings"]["rxtx"]["rxManualGain"]
|
||||
this.paramRxtx.rxSpectrumInversion = vals["settings"]["rxtx"]["rxSpectrumInversion"]
|
||||
this.paramRxtx.rxCentralFreq = this.inputFormatNumber(vals["settings"]["rxtx"]["rxCentralFreq"], {min:70000,max:6000000,step:0.01})
|
||||
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) {
|
||||
this.submitStatus.buclnb = false
|
||||
this.paramBuclnb.bucRefClk10M = vals["settings"]["buclnb"]["bucRefClk10M"]
|
||||
this.paramBuclnb.bucPowering = vals["settings"]["buclnb"]["bucPowering"]
|
||||
this.paramBuclnb.lnbRefClk10M = vals["settings"]["buclnb"]["lnbRefClk10M"]
|
||||
this.paramBuclnb.lnbPowering = vals["settings"]["buclnb"]["lnbPowering"]
|
||||
this.paramBuclnb.srvRefClk10M = vals["settings"]["buclnb"]["srvRefClk10M"]
|
||||
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 from 'common/monitoring-methods.js.j2'
|
||||
updateStatistics(vals) {
|
||||
function modcodToStr(modcod) {
|
||||
// модкоды из раздела 5.5.2.2 https://www.etsi.org/deliver/etsi_en/302300_302399/302307/01.01.02_60/en_302307v010102p.pdf
|
||||
const modcods = [
|
||||
"DUMMY",
|
||||
"QPSK 1/4", "QPSK 1/3", "QPSK 2/5", "QPSK 1/2", "QPSK 3/5", "QPSK 2/3", "QPSK 3/4", "QPSK 4/5", "QPSK 5/6", "QPSK 8/9", "QPSK 9/10",
|
||||
"8PSK 3/5", "8PSK 2/3", "8PSK 3/4", "8PSK 5/6", "8PSK 8/9", "8PSK 9/10",
|
||||
"16APSK 2/3", "16APSK 3/4", "16APSK 4/5", "16APSK 5/6", "16APSK 8/9", "16APSK 9/10",
|
||||
"32APSK 3/4", "32APSK 4/5", "32APSK 5/6", "32APSK 8/9", "32APSK 9/10",
|
||||
]
|
||||
if (typeof modcod != "number") {
|
||||
return "?";
|
||||
}
|
||||
if (modcod < 0 || modcod >= modcods.length) {
|
||||
return `? (${modcod})`
|
||||
}
|
||||
return modcods[modcod]
|
||||
}
|
||||
|
||||
this.lastUpdateTime = new Date();
|
||||
this.initState = vals["state"]["initState"]
|
||||
this.testState = vals["state"]["testState"]
|
||||
|
||||
this.statRx.state = vals["state"]["rx"]["state"]
|
||||
this.statRx.sym_sync_lock = vals["state"]["rx"]["sym_sync_lock"]
|
||||
this.statRx.freq_search_lock = vals["state"]["rx"]["freq_search_lock"]
|
||||
this.statRx.afc_lock = vals["state"]["rx"]["afc_lock"]
|
||||
this.statRx.pkt_sync = vals["state"]["rx"]["pkt_sync"]
|
||||
this.statRx.snr = Math.round(vals["state"]["rx"]["snr"] * 10) / 10
|
||||
this.statRx.rssi = Math.round(vals["state"]["rx"]["rssi"] * 10) / 10
|
||||
this.statRx.modcod = modcodToStr(vals["state"]["rx"]["modcod"])
|
||||
this.statRx.frameSizeNormal = vals["state"]["rx"]["frameSizeNormal"]
|
||||
this.statRx.isPilots = vals["state"]["rx"]["isPilots"]
|
||||
this.statRx.symError = vals["state"]["rx"]["symError"]
|
||||
this.statRx.freqErr = Math.round(vals["state"]["rx"]["freqErr"] * 100) / 100
|
||||
this.statRx.freqErrAcc = Math.round(vals["state"]["rx"]["freqErrAcc"] * 100) / 100
|
||||
this.statRx.inputSignalLevel = vals["state"]["rx"]["inputSignalLevel"]
|
||||
this.statRx.pllError = Math.round(vals["state"]["rx"]["pllError"] * 100) / 100
|
||||
this.statRx.speedOnRxKbit = Math.round(vals["state"]["rx"]["speedOnRxKbit"] * 100) / 100
|
||||
this.statRx.speedOnIifKbit = Math.round(vals["state"]["rx"]["speedOnIifKbit"] * 100) / 100
|
||||
this.statRx.packetsOk = vals["state"]["rx"]["packetsOk"]
|
||||
this.statRx.packetsBad = vals["state"]["rx"]["packetsBad"]
|
||||
this.statRx.packetsDummy = vals["state"]["rx"]["packetsDummy"]
|
||||
|
||||
this.statTx.state = vals["state"]["tx"]["state"]
|
||||
this.statTx.modcod = modcodToStr(vals["state"]["tx"]["modcod"])
|
||||
this.statTx.speedOnTxKbit = Math.round(vals["state"]["tx"]["speedOnTxKbit"] * 100) / 100
|
||||
this.statTx.speedOnIifKbit = Math.round(vals["state"]["tx"]["speedOnIifKbit"] * 100) / 100
|
||||
this.statTx.centerFreq = vals["state"]["tx"]["centerFreq"]
|
||||
this.statTx.symSpeed = vals["state"]["tx"]["symSpeed"]
|
||||
|
||||
this.statDevice.adrv = vals["state"]["device"]["adrv"]
|
||||
this.statDevice.zynq = vals["state"]["device"]["zynq"]
|
||||
this.statDevice.fpga = vals["state"]["device"]["fpga"]
|
||||
|
||||
// аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид
|
||||
let uptime = vals["state"]["device"]["uptime"]
|
||||
if (uptime) {
|
||||
let secs = uptime % 60; uptime = Math.floor(uptime / 60)
|
||||
let mins = uptime % 60; uptime = Math.floor(uptime / 60)
|
||||
let hours = uptime % 24
|
||||
uptime = Math.floor( uptime / 24)
|
||||
let res = `${hours}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
|
||||
if (uptime > 0) { res = `${uptime} дней, ` + res }
|
||||
this.statOs.uptime = res
|
||||
} else {
|
||||
this.statOs.uptime = '?'
|
||||
}
|
||||
this.statOs.load1 = Math.round(vals["state"]["device"]["load1min"] * 100) / 100
|
||||
this.statOs.load5 = Math.round(vals["state"]["device"]["load5min"] * 100) / 100
|
||||
this.statOs.load15 = Math.round(vals["state"]["device"]["load15min"] * 100) / 100
|
||||
this.statOs.totalram = vals["state"]["device"]["totalram"]
|
||||
this.statOs.freeram = vals["state"]["device"]["freeram"]
|
||||
},
|
||||
|
||||
resetPacketsStatistics() {
|
||||
fetch('/api/resetPacketStatistics', {
|
||||
method: 'POST', credentials: 'same-origin'
|
||||
}).then(() => {
|
||||
this.statRx.packetsOk = 0
|
||||
this.statRx.packetsBad = 0
|
||||
this.statRx.packetsDummy = 0
|
||||
})
|
||||
},
|
||||
// ========== include end from 'common/monitoring-methods.js.j2'
|
||||
|
||||
// ========== include from 'common/setup-methods.js.j2'
|
||||
// ========== include end from 'common/setup-methods.js.j2'
|
||||
|
||||
// ========== include from 'common/admin-methods.js.j2'
|
||||
async settingsUploadUpdate() {
|
||||
if (!this.uploadFw.filename) {
|
||||
alert('Выберите файл для загрузки');
|
||||
return;
|
||||
}
|
||||
|
||||
async function readFileAsArrayBuffer(fileName) {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!fileName) { reject(`Файл не выбран`); return }
|
||||
const reader = new FileReader();
|
||||
reader.onload = (e) => { resolve(reader.result) }
|
||||
reader.onerror = (e) => { reject(e) }
|
||||
reader.readAsArrayBuffer(fileName)
|
||||
})
|
||||
}
|
||||
|
||||
try {
|
||||
this.submitStatus.firmwareUpload = true
|
||||
this.uploadFw.progress = 0
|
||||
const blob = await readFileAsArrayBuffer(this.uploadFw.filename)
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
await new Promise((resolve) => {
|
||||
xhr.upload.addEventListener("progress", (event) => {
|
||||
if (event.lengthComputable) {
|
||||
this.uploadFw.progress = Math.round((event.loaded / event.total) * 1000) / 10;
|
||||
}
|
||||
});
|
||||
xhr.addEventListener("loadend", () => {
|
||||
this.uploadFw.progress = 100
|
||||
const rep = JSON.parse(xhr.responseText);
|
||||
this.uploadFw.sha256 = rep['sha256']
|
||||
resolve(xhr.readyState === 4 && xhr.status === 200);
|
||||
});
|
||||
xhr.open("PUT", "/api/firmwareUpdate", true);
|
||||
xhr.setRequestHeader("Content-Type", "application/octet-stream");
|
||||
xhr.send(blob);
|
||||
});
|
||||
} catch (e) {
|
||||
alert(`Ошибка загрузки файла: ${e}`);
|
||||
}
|
||||
this.submitStatus.firmwareUpload = false
|
||||
},
|
||||
|
||||
async settingsPerformFirmwareUpgrade() {
|
||||
if (this.submitStatus.firmwareUpgrade) { return }
|
||||
this.submitStatus.firmwareUpgrade = true
|
||||
try {
|
||||
await fetch('/api/doFirmwareUpgrade', { method: 'POST' })
|
||||
} catch (e) {
|
||||
console.log("failed to perform upgrade firmware: ", e)
|
||||
}
|
||||
this.submitStatus.firmwareUpgrade = false
|
||||
},
|
||||
|
||||
doModemReboot() {
|
||||
if (this.submitStatus.modemReboot !== null) {
|
||||
return
|
||||
}
|
||||
this.submitStatus.modemReboot = 30
|
||||
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'
|
||||
|
||||
|
||||
performUpdateSettings() {
|
||||
const doFetchSettings = async () => {
|
||||
let d = await fetch("/api/get/settings")
|
||||
let vals = await d.json()
|
||||
this.settingFetchComplete = true
|
||||
this.updateRxtxSettings(vals)
|
||||
this.updateBuclnbSettings(vals)
|
||||
this.updateNetworkSettings(vals)
|
||||
|
||||
if ('netServerName' in vals['settings']) {
|
||||
document.getElementsByTagName('title')[0].innerText = vals['settings']['netServerName']
|
||||
}
|
||||
}
|
||||
|
||||
doFetchSettings().then(() => {})
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
const doFetchStatistics = async () => {
|
||||
if (this.submitStatus.modemReboot !== null) {
|
||||
this.initState = `Перезагрузка модема... Осталось ${this.submitStatus.modemReboot} сек`
|
||||
this.submitStatus.modemReboot--
|
||||
if (this.submitStatus.modemReboot <= 0) {
|
||||
window.location.reload()
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
let d = await fetch("/api/get/statistics", { credentials: 'same-origin' })
|
||||
this.updateStatistics(await d.json())
|
||||
} catch (e) {
|
||||
this.initState = "Ошибка обновления статистики"
|
||||
}
|
||||
}
|
||||
setTimeout(() => {
|
||||
doFetchStatistics()
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
const doFetchAbout = async () => {
|
||||
try {
|
||||
const fr = await fetch("/api/get/aboutFirmware")
|
||||
const d = await fr.json()
|
||||
this.about.firmwareVersion = d["firmware"]["version"]
|
||||
this.about.modemUid = d["firmware"]["modemId"]
|
||||
this.about.modemSn = d["firmware"]["modemSn"]
|
||||
this.about.macManagement = d["firmware"]["macMang"]
|
||||
this.about.macData = d["firmware"]["macData"]
|
||||
} catch (e) {
|
||||
console.log('Ошибка загрузки версии ПО', e)
|
||||
}
|
||||
}
|
||||
|
||||
doFetchStatistics().then(() => {})
|
||||
doFetchAbout().then(() => {})
|
||||
|
||||
this.performUpdateSettings()
|
||||
|
||||
document.getElementById("app").removeAttribute("hidden")
|
||||
}
|
||||
});
|
||||
app.mount('#app')
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>VSAT Модем</title>
|
||||
<title>RCSM-101 TDMA</title>
|
||||
<link rel="stylesheet" type="text/css" href="/style.css">
|
||||
<link rel="stylesheet" type="text/css" href="/fields.css">
|
||||
<style>
|
||||
@@ -43,15 +43,15 @@
|
||||
<!-- Последнее обновление: {{ lastUpdateTime }}-->
|
||||
<span :class="{ value_bad: initState !== 'Успешная инициализация системы' }">{{ initState }}</span>
|
||||
<div class="tabs-header">
|
||||
<span style="font-weight:bold">VSAT Модем</span>
|
||||
<span style="font-weight:bold">RCSM-101 TDMA</span>
|
||||
<a href="#monitoring" class="tabs-btn" @click="activeTab = 'monitoring'" :class="{ active: activeTab === 'monitoring' }">Мониторинг</a>
|
||||
<a href="#setup" class="tabs-btn" @click="activeTab = 'setup'" :class="{ active: activeTab === 'setup' }">Настройки</a>
|
||||
<a href="#admin" class="tabs-btn" @click="activeTab = 'admin'" :class="{ active: activeTab === 'admin' }">Администрирование</a>
|
||||
<a href="#logs" class="tabs-btn" @click="activeTab = 'logs'" :class="{ active: activeTab === 'logs' }">Журнал</a>
|
||||
<a href="/logout" class="tabs-btn">Выход</a>
|
||||
</div>
|
||||
</header>
|
||||
<div id="content">
|
||||
|
||||
<div class="tabs-body-item tabs-item-flex-container" v-if="activeTab === 'monitoring'">
|
||||
<div class="settings-set-container statistics-container">
|
||||
<h2>Статистика приема</h2>
|
||||
@@ -62,7 +62,7 @@
|
||||
<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>SNR/RSSI</th><td>{{ statRx.snr }} / {{ statRx.rssi }}</td></tr>
|
||||
<tr><th>Modcod</th><td>{{ statRx.modcod }}</td></tr>
|
||||
<tr><th>Размер кадра</th><td>{{ statRx.frameSizeNormal ? 'normal' : 'short' }}</td></tr>
|
||||
<tr><th>Пилот-символы</th><td>{{ statRx.isPilots ? 'pilots' : 'no pilots' }}</td></tr>
|
||||
@@ -131,9 +131,7 @@
|
||||
<span>Центральная частота, КГц</span>
|
||||
<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><span>Ослабление, дБ</span><input type="number" v-model="paramRxtx.txAttenuation" min="-90" step="1"/></label>
|
||||
<label><span>Ослабление для запросных слотов, дБ</span><input type="number" v-model="paramRxtx.txAttenuationAck" min="-90" step="1"/></label>
|
||||
<label><span>Ограничение ослабления</span><input type="number" v-model="paramRxtx.txAttenuationLimit" min="-40" step="0.25"/></label>
|
||||
<label><span>Ослабление, дБ</span><input type="number" v-model="paramRxtx.txAttenuation" min="-40" step="1"/></label>
|
||||
</div>
|
||||
<div class="settings-set-container">
|
||||
<h3>Настройки приемника</h3>
|
||||
@@ -160,12 +158,12 @@
|
||||
<label>
|
||||
<span>Roll-off</span>
|
||||
<select v-model="paramRxtx.rxRolloff">
|
||||
<option :value="20">0.02</option>
|
||||
<option :value="50">0.05</option>
|
||||
<option :value="100">0.10</option>
|
||||
<option :value="150">0.15</option>
|
||||
<option :value="200">0.20</option>
|
||||
<option :value="250">0.25</option>
|
||||
<option :value="2">0.02</option>
|
||||
<option :value="5">0.05</option>
|
||||
<option :value="10">0.10</option>
|
||||
<option :value="15">0.15</option>
|
||||
<option :value="20">0.20</option>
|
||||
<option :value="25">0.25</option>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
@@ -175,16 +173,16 @@
|
||||
<div class="settings-set-container">
|
||||
<label>
|
||||
<span>Метод расчета задержки</span>
|
||||
<select v-model="paramDpdi.isPositional">
|
||||
<select v-model="paramDpdi.dpdiIsPositional">
|
||||
<option :value="true">Позиционированием</option>
|
||||
<option :value="false">Окном задержки</option>
|
||||
</select>
|
||||
</label>
|
||||
<h2 v-show="paramDpdi.isPositional === true">Настройки позиционирования</h2>
|
||||
<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.isPositional === true"><span>Долгота станции</span><input type="number" v-model="paramDpdi.positionStationLongitude" 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.isPositional === false"><span>Задержка до спутника, мс</span><input type="number" v-model="paramDpdi.delay" max="400" step="0.1"/></label>
|
||||
<h2 v-show="paramDpdi.dpdiIsPositional === 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.dpdiIsPositional === true"><span>Долгота станции</span><input type="number" v-model="paramDpdi.dpdiPositionStationLongitude" 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.dpdiIsPositional === false"><span>Задержка до спутника, мс</span><input type="number" v-model="paramDpdi.dpdiDelay" max="400" step="0.1"/></label>
|
||||
</div>
|
||||
<button class="action-button" @click="settingsSubmitDpdi()">Сохранить <span class="submit-spinner" v-show="submitStatus.dpdi"></span></button>
|
||||
<h2>Настройки питания и опорного генератора</h2>
|
||||
@@ -202,10 +200,6 @@
|
||||
<option :value="24">24В</option>
|
||||
</select>
|
||||
</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 class="settings-set-container">
|
||||
<h3>Настройки LNB</h3>
|
||||
@@ -222,10 +216,6 @@
|
||||
<option :value="24">24В</option>
|
||||
</select>
|
||||
</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 class="settings-set-container">
|
||||
<h3>Сервисные настройки</h3>
|
||||
@@ -245,12 +235,24 @@
|
||||
<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])$">
|
||||
<span>Интерфейс управления (/24)</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]?)$">
|
||||
</label>
|
||||
<label>
|
||||
<span>Режим сети</span>
|
||||
<select v-model="paramNetwork.netIsL2">
|
||||
<option :value="false">Маршрутизатор</option>
|
||||
<option :value="true">Коммутатор</option>
|
||||
</select>
|
||||
</label>
|
||||
<label v-show="paramNetwork.netIsL2 === false">
|
||||
<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]?)$">
|
||||
</label>
|
||||
<label><span>MTU интерфейса данных</span><input type="number" v-model="paramNetwork.netDataMtu" min="1500" max="2000" step="1"/></label>
|
||||
<label>
|
||||
<span>Имя веб-сервера</span>
|
||||
<input v-model="paramNetwork.serverName" type="text">
|
||||
<input v-model="paramNetwork.netServerName" type="text">
|
||||
</label>
|
||||
</div>
|
||||
<button class="action-button" @click="settingsSubmitNetwork()">Сохранить <span class="submit-spinner" v-show="submitStatus.network"></span></button>
|
||||
@@ -272,16 +274,6 @@
|
||||
<div>
|
||||
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
|
||||
</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>
|
||||
|
||||
<h2>Обновление ПО</h2>
|
||||
@@ -298,40 +290,12 @@
|
||||
<button class="dangerous-button" v-show="statDevice.upgradePercent >= 100" @click="settingsPerformFirmwareUpgradeOta()">Обновить встроенное ПО<span class="submit-spinner" v-show="submitStatus.firmwareUpgradeOta"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="tabs-body-item" v-if="activeTab === 'logs'">
|
||||
<h2>Журнал <code>manager</code></h2>
|
||||
<div class="settings-set-container">
|
||||
<label>
|
||||
<span>Фильтрация лога (отображение)</span>
|
||||
<select v-model="paramLogs.level">
|
||||
<option :value="''">Без фильтрации</option>
|
||||
<option :value="'info'">Информация</option>
|
||||
<option :value="'warning'">Предупреждение</option>
|
||||
<option :value="'error'">Ошибка</option>
|
||||
<option :value="'fatal'">Фатальная ошибка</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<span>Обратная сортировка строк</span>
|
||||
<span class="toggle-input"><input type="checkbox" v-model="paramLogs.revercePreview" /><span class="slider"></span></span>
|
||||
</label>
|
||||
|
||||
<button class="action-button" @click="logsUpdate()">Обновить (последние 1000 строк) <span class="submit-spinner" v-show="paramLogs.submitUpdateLogs"></span></button></button>
|
||||
<a href="/api/get/manager.log" class="action-button" download>Скачать все</a>
|
||||
<pre style="overflow-x: auto">{{ paramLogs.data }}</pre>
|
||||
<div><button class="action-button" v-if="paramLogs.data !== ''" @click="logsUpdate()">Обновить (последние 1000 строк) <span class="submit-spinner" v-show="paramLogs.submitUpdateLogs"></span></button></div>
|
||||
</div>
|
||||
<div class="settings-set-container statistics-container">
|
||||
<div><button class="dangerous-button" @click="logsClear()">Очистить логи <span class="submit-spinner" v-show="paramLogs.submitClearLogs"></span></button></div>
|
||||
</div>
|
||||
</div>
|
||||
<p>Последнее обновление статистики: {{ lastUpdateTime }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/js/vue.js?v=3.5.13"></script>
|
||||
<script>
|
||||
const availableTabs = ['monitoring', 'setup', 'admin', 'logs']
|
||||
const availableTabs = ['monitoring', 'setup', 'admin']
|
||||
|
||||
// для обновления высоты хидера
|
||||
function updateHeaderHeight() { const header = document.querySelector('header'); document.body.style.setProperty('--header-height', `${header.offsetHeight}px`); }
|
||||
@@ -369,47 +333,44 @@
|
||||
firmwareUpload: false,
|
||||
firmwareUpgrade: false,
|
||||
firmwareUpgradeOta: false,
|
||||
cesPassword: false,
|
||||
// когда модем перезагружается, тут должен быть счетчик. Направление счета - к нулю
|
||||
modemReboot: null
|
||||
},
|
||||
cesPasswordValue: '',
|
||||
|
||||
// ========== include from 'common/all-params-data.js.j2'
|
||||
paramRxtx: {
|
||||
txEn: false,
|
||||
txModulatorIsTest: false,
|
||||
txCentralFreq: 0,
|
||||
txAttenuation: -90,
|
||||
txAttenuationAck: -90,
|
||||
txAttenuationLimit: -40,
|
||||
txAttenuation: -40,
|
||||
rxAgcEn: true,
|
||||
rxManualGain: -40,
|
||||
rxSpectrumInversion: false,
|
||||
rxCentralFreq: 0,
|
||||
rxBaudrate: 0,
|
||||
rxRolloff: 20,
|
||||
rxRolloff: 2,
|
||||
},
|
||||
paramBuclnb: {
|
||||
bucRefClk10M: false,
|
||||
bucPowering: 0,
|
||||
bucLoKhz: 0,
|
||||
lnbRefClk10M: false,
|
||||
lnbPowering: 0,
|
||||
lnbLoKhz: 0,
|
||||
srvRefClk10M: false,
|
||||
bucLnbAutoStart: false,
|
||||
},
|
||||
paramDpdi: {
|
||||
isPositional: true,
|
||||
positionStationLatitude: -180,
|
||||
positionStationLongitude: -180,
|
||||
positionSatelliteLongitude: -180,
|
||||
delay: 0,
|
||||
dpdiIsPositional: true,
|
||||
dpdiPositionStationLatitude: -180,
|
||||
dpdiPositionStationLongitude: -180,
|
||||
dpdiPositionSatelliteLongitude: -180,
|
||||
dpdiDelay: 0,
|
||||
},
|
||||
paramNetwork: {
|
||||
managementIp: null,
|
||||
serverName: null,
|
||||
netManagementIp: null,
|
||||
netIsL2: false,
|
||||
netDataIp: null,
|
||||
netDataMtu: 1500,
|
||||
netServerName: null,
|
||||
},
|
||||
// ========== include end from 'common/all-params-data.js.j2'
|
||||
|
||||
@@ -444,7 +405,9 @@
|
||||
modcod: '?', speedOnTxKbit: '?', speedOnIifKbit: '?', centerFreq: '?', symSpeed: '?'
|
||||
},
|
||||
statDevice: { // температурные датчики
|
||||
adrv: 0, zynq: 0, fpga: 0, upgradeStatus: "", upgradePercent: 0, upgradeImage: ""
|
||||
adrv: 0, zynq: 0, fpga: 0
|
||||
,
|
||||
upgradeStatus: "", upgradePercent: 0, upgradeImage: ""
|
||||
},
|
||||
statOs: {uptime: '?', load1: '?', load5: '?', load15: '?', totalram: '?', freeram: '?'},
|
||||
// ========== include end from 'common/monitoring-data.js.j2'
|
||||
@@ -455,16 +418,6 @@
|
||||
// ========== include from 'common/admin-data.js.j2'
|
||||
// ========== include end from 'common/admin-data.js.j2'
|
||||
|
||||
// ========== include from 'common/logs-data.js.j2'
|
||||
paramLogs: {
|
||||
submitClearLogs: false,
|
||||
submitUpdateLogs: false,
|
||||
revercePreview: true,
|
||||
data: "",
|
||||
level: ""
|
||||
},
|
||||
// ========== include end from 'common/logs-data.js.j2'
|
||||
|
||||
uploadFw: {
|
||||
progress: null,
|
||||
filename: null,
|
||||
@@ -539,8 +492,6 @@
|
||||
"txModulatorIsTest": this.paramRxtx.txModulatorIsTest,
|
||||
"txCentralFreq": parseFloat(this.paramRxtx.txCentralFreq.replace(/[^0-9,.]/g, '').replace(',', '.')),
|
||||
"txAttenuation": this.paramRxtx.txAttenuation,
|
||||
"txAttenuationAck": this.paramRxtx.txAttenuationAck,
|
||||
"txAttenuationLimit": this.paramRxtx.txAttenuationLimit,
|
||||
"rxAgcEn": this.paramRxtx.rxAgcEn,
|
||||
"rxManualGain": this.paramRxtx.rxManualGain,
|
||||
"rxSpectrumInversion": this.paramRxtx.rxSpectrumInversion,
|
||||
@@ -562,10 +513,8 @@
|
||||
let query = {
|
||||
"bucRefClk10M": this.paramBuclnb.bucRefClk10M,
|
||||
"bucPowering": this.paramBuclnb.bucPowering,
|
||||
"bucLoKhz": parseFloat(this.paramBuclnb.bucLoKhz.replace(/[^0-9,.]/g, '').replace(',', '.')),
|
||||
"lnbRefClk10M": this.paramBuclnb.lnbRefClk10M,
|
||||
"lnbPowering": this.paramBuclnb.lnbPowering,
|
||||
"lnbLoKhz": parseFloat(this.paramBuclnb.lnbLoKhz.replace(/[^0-9,.]/g, '').replace(',', '.')),
|
||||
"srvRefClk10M": this.paramBuclnb.srvRefClk10M,
|
||||
"bucLnbAutoStart": this.paramBuclnb.bucLnbAutoStart,
|
||||
}
|
||||
@@ -580,11 +529,11 @@
|
||||
if (this.submitStatus.dpdi) { return }
|
||||
|
||||
let query = {
|
||||
"isPositional": this.paramDpdi.isPositional,
|
||||
"positionStationLatitude": this.paramDpdi.positionStationLatitude,
|
||||
"positionStationLongitude": this.paramDpdi.positionStationLongitude,
|
||||
"positionSatelliteLongitude": this.paramDpdi.positionSatelliteLongitude,
|
||||
"delay": this.paramDpdi.delay,
|
||||
"dpdiIsPositional": this.paramDpdi.dpdiIsPositional,
|
||||
"dpdiPositionStationLatitude": this.paramDpdi.dpdiPositionStationLatitude,
|
||||
"dpdiPositionStationLongitude": this.paramDpdi.dpdiPositionStationLongitude,
|
||||
"dpdiPositionSatelliteLongitude": this.paramDpdi.dpdiPositionSatelliteLongitude,
|
||||
"dpdiDelay": this.paramDpdi.dpdiDelay,
|
||||
}
|
||||
|
||||
this.submitStatus.dpdi = true
|
||||
@@ -598,8 +547,11 @@
|
||||
{ if (!confirm("Применение этих настроек может сделать модем недоступным! Продолжить?")) return }
|
||||
|
||||
let query = {
|
||||
"managementIp": this.paramNetwork.managementIp,
|
||||
"serverName": this.paramNetwork.serverName,
|
||||
"netManagementIp": this.paramNetwork.netManagementIp,
|
||||
"netIsL2": this.paramNetwork.netIsL2,
|
||||
"netDataIp": this.paramNetwork.netDataIp,
|
||||
"netDataMtu": this.paramNetwork.netDataMtu,
|
||||
"netServerName": this.paramNetwork.netServerName,
|
||||
}
|
||||
|
||||
this.submitStatus.network = true
|
||||
@@ -611,42 +563,41 @@
|
||||
|
||||
updateRxtxSettings(vals) {
|
||||
this.submitStatus.rxtx = false
|
||||
this.paramRxtx.txEn = vals["settings"]["rxtx"]["txEn"]
|
||||
this.paramRxtx.txModulatorIsTest = vals["settings"]["rxtx"]["txModulatorIsTest"]
|
||||
this.paramRxtx.txCentralFreq = this.inputFormatNumber(vals["settings"]["rxtx"]["txCentralFreq"], {min:900000,step:0.01})
|
||||
this.paramRxtx.txAttenuation = vals["settings"]["rxtx"]["txAttenuation"]
|
||||
this.paramRxtx.txAttenuationAck = vals["settings"]["rxtx"]["txAttenuationAck"]
|
||||
this.paramRxtx.txAttenuationLimit = vals["settings"]["rxtx"]["txAttenuationLimit"]
|
||||
this.paramRxtx.rxAgcEn = vals["settings"]["rxtx"]["rxAgcEn"]
|
||||
this.paramRxtx.rxManualGain = vals["settings"]["rxtx"]["rxManualGain"]
|
||||
this.paramRxtx.rxSpectrumInversion = vals["settings"]["rxtx"]["rxSpectrumInversion"]
|
||||
this.paramRxtx.rxCentralFreq = this.inputFormatNumber(vals["settings"]["rxtx"]["rxCentralFreq"], {min:900000,step:0.01})
|
||||
this.paramRxtx.rxBaudrate = this.inputFormatNumber(vals["settings"]["rxtx"]["rxBaudrate"], {min:200000,max:54000000,step:1})
|
||||
this.paramRxtx.rxRolloff = vals["settings"]["rxtx"]["rxRolloff"]
|
||||
this.paramRxtx.txEn = vals["settings"]["txEn"]
|
||||
this.paramRxtx.txModulatorIsTest = vals["settings"]["txModulatorIsTest"]
|
||||
this.paramRxtx.txCentralFreq = this.inputFormatNumber(vals["settings"]["txCentralFreq"], {min:900000,step:0.01})
|
||||
this.paramRxtx.txAttenuation = vals["settings"]["txAttenuation"]
|
||||
this.paramRxtx.rxAgcEn = vals["settings"]["rxAgcEn"]
|
||||
this.paramRxtx.rxManualGain = vals["settings"]["rxManualGain"]
|
||||
this.paramRxtx.rxSpectrumInversion = vals["settings"]["rxSpectrumInversion"]
|
||||
this.paramRxtx.rxCentralFreq = this.inputFormatNumber(vals["settings"]["rxCentralFreq"], {min:900000,step:0.01})
|
||||
this.paramRxtx.rxBaudrate = this.inputFormatNumber(vals["settings"]["rxBaudrate"], {min:200000,max:54000000,step:1})
|
||||
this.paramRxtx.rxRolloff = vals["settings"]["rxRolloff"]
|
||||
},
|
||||
updateBuclnbSettings(vals) {
|
||||
this.submitStatus.buclnb = false
|
||||
this.paramBuclnb.bucRefClk10M = vals["settings"]["buclnb"]["bucRefClk10M"]
|
||||
this.paramBuclnb.bucPowering = vals["settings"]["buclnb"]["bucPowering"]
|
||||
this.paramBuclnb.bucLoKhz = this.inputFormatNumber(vals["settings"]["buclnb"]["bucLoKhz"], {max:40000000,step:1})
|
||||
this.paramBuclnb.lnbRefClk10M = vals["settings"]["buclnb"]["lnbRefClk10M"]
|
||||
this.paramBuclnb.lnbPowering = vals["settings"]["buclnb"]["lnbPowering"]
|
||||
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"]
|
||||
this.paramBuclnb.bucRefClk10M = vals["settings"]["bucRefClk10M"]
|
||||
this.paramBuclnb.bucPowering = vals["settings"]["bucPowering"]
|
||||
this.paramBuclnb.lnbRefClk10M = vals["settings"]["lnbRefClk10M"]
|
||||
this.paramBuclnb.lnbPowering = vals["settings"]["lnbPowering"]
|
||||
this.paramBuclnb.srvRefClk10M = vals["settings"]["srvRefClk10M"]
|
||||
this.paramBuclnb.bucLnbAutoStart = vals["settings"]["bucLnbAutoStart"]
|
||||
},
|
||||
updateDpdiSettings(vals) {
|
||||
this.submitStatus.dpdi = false
|
||||
this.paramDpdi.isPositional = vals["settings"]["dpdi"]["isPositional"]
|
||||
this.paramDpdi.positionStationLatitude = vals["settings"]["dpdi"]["positionStationLatitude"]
|
||||
this.paramDpdi.positionStationLongitude = vals["settings"]["dpdi"]["positionStationLongitude"]
|
||||
this.paramDpdi.positionSatelliteLongitude = vals["settings"]["dpdi"]["positionSatelliteLongitude"]
|
||||
this.paramDpdi.delay = vals["settings"]["dpdi"]["delay"]
|
||||
this.paramDpdi.dpdiIsPositional = vals["settings"]["dpdiIsPositional"]
|
||||
this.paramDpdi.dpdiPositionStationLatitude = vals["settings"]["dpdiPositionStationLatitude"]
|
||||
this.paramDpdi.dpdiPositionStationLongitude = vals["settings"]["dpdiPositionStationLongitude"]
|
||||
this.paramDpdi.dpdiPositionSatelliteLongitude = vals["settings"]["dpdiPositionSatelliteLongitude"]
|
||||
this.paramDpdi.dpdiDelay = vals["settings"]["dpdiDelay"]
|
||||
},
|
||||
updateNetworkSettings(vals) {
|
||||
this.submitStatus.network = false
|
||||
this.paramNetwork.managementIp = vals["settings"]["network"]["managementIp"]
|
||||
this.paramNetwork.serverName = vals["settings"]["network"]["serverName"]
|
||||
this.paramNetwork.netManagementIp = vals["settings"]["netManagementIp"]
|
||||
this.paramNetwork.netIsL2 = vals["settings"]["netIsL2"]
|
||||
this.paramNetwork.netDataIp = vals["settings"]["netDataIp"]
|
||||
this.paramNetwork.netDataMtu = vals["settings"]["netDataMtu"]
|
||||
this.paramNetwork.netServerName = vals["settings"]["netServerName"]
|
||||
},
|
||||
// ========== include end from 'common/all-params-methods.js.j2'
|
||||
|
||||
@@ -671,46 +622,47 @@
|
||||
}
|
||||
|
||||
this.lastUpdateTime = new Date();
|
||||
this.initState = vals["state"]["initState"]
|
||||
this.testState = vals["state"]["testState"]
|
||||
this.initState = vals["mainState"]["initState"]
|
||||
|
||||
this.statRx.state = vals["state"]["rx"]["state"]
|
||||
this.statRx.sym_sync_lock = vals["state"]["rx"]["sym_sync_lock"]
|
||||
this.statRx.freq_search_lock = vals["state"]["rx"]["freq_search_lock"]
|
||||
this.statRx.afc_lock = vals["state"]["rx"]["afc_lock"]
|
||||
this.statRx.pkt_sync = vals["state"]["rx"]["pkt_sync"]
|
||||
this.statRx.snr = Math.round(vals["state"]["rx"]["snr"] * 10) / 10
|
||||
this.statRx.rssi = Math.round(vals["state"]["rx"]["rssi"] * 10) / 10
|
||||
this.statRx.modcod = modcodToStr(vals["state"]["rx"]["modcod"])
|
||||
this.statRx.frameSizeNormal = vals["state"]["rx"]["frameSizeNormal"]
|
||||
this.statRx.isPilots = vals["state"]["rx"]["isPilots"]
|
||||
this.statRx.symError = vals["state"]["rx"]["symError"]
|
||||
this.statRx.freqErr = Math.round(vals["state"]["rx"]["freqErr"] * 100) / 100
|
||||
this.statRx.freqErrAcc = Math.round(vals["state"]["rx"]["freqErrAcc"] * 100) / 100
|
||||
this.statRx.inputSignalLevel = vals["state"]["rx"]["inputSignalLevel"]
|
||||
this.statRx.pllError = Math.round(vals["state"]["rx"]["pllError"] * 100) / 100
|
||||
this.statRx.speedOnRxKbit = Math.round(vals["state"]["rx"]["speedOnRxKbit"] * 100) / 100
|
||||
this.statRx.speedOnIifKbit = Math.round(vals["state"]["rx"]["speedOnIifKbit"] * 100) / 100
|
||||
this.statRx.packetsOk = vals["state"]["rx"]["packetsOk"]
|
||||
this.statRx.packetsBad = vals["state"]["rx"]["packetsBad"]
|
||||
this.statRx.packetsDummy = vals["state"]["rx"]["packetsDummy"]
|
||||
this.statRx.state = vals["mainState"]["rx.state"]
|
||||
this.statRx.sym_sync_lock = vals["mainState"]["rx.sym_sync_lock"]
|
||||
this.statRx.freq_search_lock = vals["mainState"]["rx.freq_search_lock"]
|
||||
this.statRx.afc_lock = vals["mainState"]["rx.afc_lock"]
|
||||
this.statRx.pkt_sync = vals["mainState"]["rx.pkt_sync"]
|
||||
this.statRx.snr = vals["mainState"]["rx.snr"]
|
||||
this.statRx.rssi = vals["mainState"]["rx.rssi"]
|
||||
this.statRx.modcod = modcodToStr(vals["mainState"]["rx.modcod"])
|
||||
this.statRx.frameSizeNormal = vals["mainState"]["rx.frameSizeNormal"]
|
||||
this.statRx.isPilots = vals["mainState"]["rx.isPilots"]
|
||||
this.statRx.symError = vals["mainState"]["rx.symError"]
|
||||
this.statRx.freqErr = vals["mainState"]["rx.freqErr"]
|
||||
this.statRx.freqErrAcc = vals["mainState"]["rx.freqErrAcc"]
|
||||
this.statRx.inputSignalLevel = vals["mainState"]["rx.inputSignalLevel"]
|
||||
this.statRx.pllError = vals["mainState"]["rx.pllError"]
|
||||
this.statRx.speedOnRxKbit = vals["mainState"]["rx.speedOnRxKbit"]
|
||||
this.statRx.speedOnIifKbit = vals["mainState"]["rx.speedOnIifKbit"]
|
||||
this.statRx.packetsOk = vals["mainState"]["rx.packetsOk"]
|
||||
this.statRx.packetsBad = vals["mainState"]["rx.packetsBad"]
|
||||
this.statRx.packetsDummy = vals["mainState"]["rx.packetsDummy"]
|
||||
|
||||
this.statTx.state = vals["state"]["tx"]["state"]
|
||||
this.statTx.modcod = modcodToStr(vals["state"]["tx"]["modcod"])
|
||||
this.statTx.speedOnTxKbit = Math.round(vals["state"]["tx"]["speedOnTxKbit"] * 100) / 100
|
||||
this.statTx.speedOnIifKbit = Math.round(vals["state"]["tx"]["speedOnIifKbit"] * 100) / 100
|
||||
this.statTx.centerFreq = vals["state"]["tx"]["centerFreq"]
|
||||
this.statTx.symSpeed = vals["state"]["tx"]["symSpeed"]
|
||||
this.statTx.state = vals["mainState"]["tx.state"]
|
||||
this.statTx.modcod = modcodToStr(vals["mainState"]["tx.modcod"])
|
||||
this.statTx.speedOnTxKbit = vals["mainState"]["tx.speedOnTxKbit"]
|
||||
this.statTx.speedOnIifKbit = vals["mainState"]["tx.speedOnIifKbit"]
|
||||
this.statTx.centerFreq = vals["mainState"]["tx.centerFreq"]
|
||||
this.statTx.symSpeed = vals["mainState"]["tx.symSpeed"]
|
||||
|
||||
this.statDevice.adrv = vals["state"]["device"]["adrv"]
|
||||
this.statDevice.zynq = vals["state"]["device"]["zynq"]
|
||||
this.statDevice.fpga = vals["state"]["device"]["fpga"]
|
||||
this.statDevice.upgradeStatus = vals["state"]["device"]["upgradeStatus"]
|
||||
this.statDevice.upgradePercent = vals["state"]["device"]["upgradePercent"]
|
||||
this.statDevice.upgradeImage = vals["state"]["device"]["upgradeImage"]
|
||||
this.statDevice.adrv = vals["mainState"]["device.adrv"]
|
||||
this.statDevice.zynq = vals["mainState"]["device.zynq"]
|
||||
this.statDevice.fpga = vals["mainState"]["device.fpga"]
|
||||
this.statDevice.upgradeStatus = vals["mainState"]["device.upgradeStatus"]
|
||||
this.statDevice.upgradePercent = vals["mainState"]["device.upgradePercent"]
|
||||
this.statDevice.upgradeImage = vals["mainState"]["device.upgradeImage"]
|
||||
|
||||
this.testState = vals["mainState"]["testState"]
|
||||
|
||||
// аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид
|
||||
let uptime = vals["state"]["device"]["uptime"]
|
||||
let uptime = vals["sysinfo"]["uptime"]
|
||||
if (uptime) {
|
||||
let secs = uptime % 60; uptime = Math.floor(uptime / 60)
|
||||
let mins = uptime % 60; uptime = Math.floor(uptime / 60)
|
||||
@@ -722,11 +674,11 @@
|
||||
} else {
|
||||
this.statOs.uptime = '?'
|
||||
}
|
||||
this.statOs.load1 = Math.round(vals["state"]["device"]["load1min"] * 100) / 100
|
||||
this.statOs.load5 = Math.round(vals["state"]["device"]["load5min"] * 100) / 100
|
||||
this.statOs.load15 = Math.round(vals["state"]["device"]["load15min"] * 100) / 100
|
||||
this.statOs.totalram = vals["state"]["device"]["totalram"]
|
||||
this.statOs.freeram = vals["state"]["device"]["freeram"]
|
||||
this.statOs.load1 = vals["sysinfo"]["load1min"]
|
||||
this.statOs.load5 = vals["sysinfo"]["load5min"]
|
||||
this.statOs.load15 = vals["sysinfo"]["load15min"]
|
||||
this.statOs.totalram = vals["sysinfo"]["totalram"]
|
||||
this.statOs.freeram = vals["sysinfo"]["freeram"]
|
||||
},
|
||||
|
||||
resetPacketsStatistics() {
|
||||
@@ -808,22 +760,6 @@
|
||||
}
|
||||
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() {
|
||||
if (this.submitStatus.modemReboot !== null) {
|
||||
@@ -831,149 +767,7 @@
|
||||
}
|
||||
this.submitStatus.modemReboot = 30
|
||||
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 from 'common/logs-methods.js.j2'
|
||||
logsUpdate() {
|
||||
if (this.paramLogs.submitUpdateLogs) { return }
|
||||
this.paramLogs.submitUpdateLogs = true
|
||||
fetch(`/api/get/manager.log?preview${this.paramLogs.revercePreview ? '&reverse' : ''}`, {method: 'GET', credentials: 'same-origin', })
|
||||
.then(async (resp) => {
|
||||
this.paramLogs.data = await resp.text()
|
||||
})
|
||||
.catch((reason) => { this.paramLogs.data = `Ошибка при чтении логов: ${reason}` })
|
||||
.finally(() => { this.paramLogs.submitUpdateLogs = false })
|
||||
},
|
||||
|
||||
// ========== include end from 'common/logs-methods.js.j2'
|
||||
}, // ========== include end from 'common/admin-methods.js.j2'
|
||||
|
||||
|
||||
performUpdateSettings() {
|
||||
@@ -1019,11 +813,11 @@
|
||||
try {
|
||||
const fr = await fetch("/api/get/aboutFirmware")
|
||||
const d = await fr.json()
|
||||
this.about.firmwareVersion = d["firmware"]["version"]
|
||||
this.about.modemUid = d["firmware"]["modemId"]
|
||||
this.about.modemSn = d["firmware"]["modemSn"]
|
||||
this.about.macManagement = d["firmware"]["macMang"]
|
||||
this.about.macData = d["firmware"]["macData"]
|
||||
this.about.firmwareVersion = d["fw.version"]
|
||||
this.about.modemUid = d["fw.modemId"]
|
||||
this.about.modemSn = d["fw.modemSn"]
|
||||
this.about.macManagement = d["fw.macMang"]
|
||||
this.about.macData = d["fw.macData"]
|
||||
} catch (e) {
|
||||
console.log('Ошибка загрузки версии ПО', e)
|
||||
}
|
||||
|
Reference in New Issue
Block a user