Compare commits
15 Commits
17cdd69207
...
bb90a3fec2
Author | SHA1 | Date | |
---|---|---|---|
bb90a3fec2 | |||
9fbe88b64d | |||
996e711436 | |||
57ba61da41 | |||
b9a25e8734 | |||
1e185a987d | |||
4c555d5400 | |||
38a00173a2 | |||
e5e6878351 | |||
55fc322c13 | |||
f30e1adb49 | |||
50f82483fd | |||
c2dd4b13e8 | |||
3e38e77069 | |||
3745f98a82 |
3
.gitignore
vendored
3
.gitignore
vendored
@ -7,8 +7,7 @@ dh.pem
|
||||
/web-action
|
||||
|
||||
# эти файлы после генерации должны быть перемещены в `/static`
|
||||
front-generator/main-scpc.html
|
||||
front-generator/main-tdma.html
|
||||
front-generator/main-*.html
|
||||
|
||||
# логи сервера в релизной версии
|
||||
http_server_*.log
|
||||
|
@ -1,8 +1,8 @@
|
||||
stages:
|
||||
- deploy
|
||||
- build
|
||||
|
||||
test for build:
|
||||
stage: deploy
|
||||
stage: build
|
||||
image: localhost:5000/cpp-test-universal:latest
|
||||
tags:
|
||||
- cpp-test-universal
|
||||
@ -13,10 +13,14 @@ test for build:
|
||||
- git submodule update
|
||||
- cmake -DCMAKE_BUILD_TYPE=Debug -DMODEM_TYPE=TDMA -B cmake-build-debug-tdma
|
||||
- cmake -DCMAKE_BUILD_TYPE=Debug -DMODEM_TYPE=SCPC -B cmake-build-debug-scpc
|
||||
- cmake -DCMAKE_BUILD_TYPE=Debug -DMODEM_TYPE=SHPS -B cmake-build-debug-shps
|
||||
- cmake -DCMAKE_BUILD_TYPE=Release -DMODEM_TYPE=TDMA -B cmake-build-release-tdma
|
||||
- cmake -DCMAKE_BUILD_TYPE=Release -DMODEM_TYPE=SCPC -B cmake-build-release-scpc
|
||||
- cmake -DCMAKE_BUILD_TYPE=Release -DMODEM_TYPE=SHPS -B cmake-build-release-shps
|
||||
- cmake --build cmake-build-debug-tdma -j 4
|
||||
- cmake --build cmake-build-debug-scpc -j 4
|
||||
- cmake --build cmake-build-debug-shps -j 4
|
||||
- cmake --build cmake-build-release-tdma -j 4
|
||||
- cmake --build cmake-build-release-scpc -j 4
|
||||
- cmake --build cmake-build-release-shps -j 4
|
||||
|
||||
|
@ -21,8 +21,11 @@ if("${MODEM_TYPE}" STREQUAL "SCPC")
|
||||
elseif ("${MODEM_TYPE}" STREQUAL "TDMA")
|
||||
add_definitions(-DMODEM_IS_TDMA)
|
||||
message(STATUS "Selected TDMA modem")
|
||||
elseif ("${MODEM_TYPE}" STREQUAL "SHPS")
|
||||
add_definitions(-DMODEM_IS_SHPS)
|
||||
message(STATUS "Selected SHPS modem")
|
||||
else()
|
||||
message(FATAL_ERROR "You must set `MODEM_TYPE` \"SCPC\" or \"TDMA\"!")
|
||||
message(FATAL_ERROR "You must set `MODEM_TYPE` \"SCPC\" or \"TDMA\" or \"SHPS\"!")
|
||||
endif()
|
||||
|
||||
SET(PROJECT_GIT_REVISION "0")
|
||||
@ -54,6 +57,13 @@ 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
|
||||
@ -77,6 +87,7 @@ 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)
|
||||
|
2
dependencies/control_system_client
vendored
2
dependencies/control_system_client
vendored
@ -1 +1 @@
|
||||
Subproject commit 76d6dcdb08d3602ad33f2236a60cc78841b5bdc5
|
||||
Subproject commit 92fcb8ab674eb592b6237a7b82af2dfb1a0ae00c
|
33
devtool.py
33
devtool.py
@ -44,6 +44,25 @@ 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))
|
||||
|
||||
@ -53,6 +72,8 @@ 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":
|
||||
@ -67,7 +88,17 @@ 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 set dma debug usage!")
|
||||
print("Wrong get dma debug usage!")
|
||||
else:
|
||||
print(cp_get_dma_debug(sys.argv[1], sys.argv[3]))
|
||||
elif sys.argv[2] == "set_network":
|
||||
if len(sys.argv) != 5:
|
||||
print("Wrong set network usage!")
|
||||
else:
|
||||
print(cp_set_dma_debug(sys.argv[1], sys.argv[3], sys.argv[4]))
|
||||
elif sys.argv[2] == "get_network":
|
||||
if len(sys.argv) != 4:
|
||||
print("Wrong get dma debug usage!")
|
||||
else:
|
||||
print(cp_get_dma_debug(sys.argv[1], sys.argv[3]))
|
||||
else:
|
||||
|
@ -42,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": "2"}, {"label": "0.05", "value": "5"}, {"label": "0.10", "value": "10"}, {"label": "0.15", "value": "15"}, {"label": "0.20", "value": "20"}, {"label": "0.25", "value": "25"}]
|
||||
"values": [{"label": "0.02", "value": "20"}, {"label": "0.05", "value": "50"}, {"label": "0.10", "value": "100"}, {"label": "0.15", "value": "150"}, {"label": "0.20", "value": "200"}, {"label": "0.25", "value": "250"}]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -120,10 +120,10 @@
|
||||
{
|
||||
"widget": "settings-container",
|
||||
"childs": [
|
||||
{"widget": "text", "label": "Пароль для входа в сеть ЦЗС", "name": "netCesPassword"},
|
||||
{"widget": "text", "label": "Пароль для входа в сеть ЦЗС", "name": "cesPassword"},
|
||||
{"widget": "h3", "label": "Настройки интерфейса управления"},
|
||||
{"widget": "ip-address", "label": "IP Интерфейса управления (/24)", "name": "netManagementIp"},
|
||||
{"widget": "text", "label": "Имя веб-сервера", "name": "netServerName"}
|
||||
{"widget": "ip-address-mask", "label": "Интерфейс управления (a.d.d.r/mask)", "name": "managementIp"},
|
||||
{"widget": "text", "label": "Имя веб-сервера", "name": "serverName"}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -170,11 +170,11 @@
|
||||
"values": [{"label": "Ethernet", "value": "false"}, {"label": "Тест", "value": "true"}]
|
||||
},
|
||||
{"widget": "h3", "label": "Параметры передачи"},
|
||||
{"widget": "number-int", "label": "Центральная частота, КГц", "name": "txCentralFreq", "min": 950000, "max": 6000000, "step": 0.01},
|
||||
{"widget": "number-int", "label": "Центральная частота, КГц", "name": "txCentralFreq", "min": 100000, "max": 6000000, "step": 0.01},
|
||||
{"widget": "number-int", "label": "Символьная скорость, Бод", "name": "txBaudrate", "min": 200000, "max": 54000000},
|
||||
{
|
||||
"widget": "select", "label": "Roll-off", "name": "txRolloff",
|
||||
"values": [{"label": "0.02", "value": "2"}, {"label": "0.05", "value": "5"}, {"label": "0.10", "value": "10"}, {"label": "0.15", "value": "15"}, {"label": "0.20", "value": "20"}, {"label": "0.25", "value": "25"}]
|
||||
"values": [{"label": "0.02", "value": "20"}, {"label": "0.05", "value": "50"}, {"label": "0.10", "value": "100"}, {"label": "0.15", "value": "150"}, {"label": "0.20", "value": "200"}, {"label": "0.25", "value": "250"}]
|
||||
},
|
||||
{
|
||||
"widget": "select", "label": "Номер последовательности Голда", "name": "txGoldan",
|
||||
@ -231,11 +231,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": 950000, "max": 6000000, "step": 0.01},
|
||||
{"widget": "number-int", "label": "Центральная частота, КГц", "name": "rxCentralFreq", "min": 100000, "max": 6000000, "step": 0.01},
|
||||
{"widget": "number-int", "label": "Символьная скорость, Бод", "name": "rxBaudrate", "min": 200000, "max": 54000000},
|
||||
{
|
||||
"widget": "select", "label": "Roll-off", "name": "rxRolloff",
|
||||
"values": [{"label": "0.02", "value": "2"}, {"label": "0.05", "value": "5"}, {"label": "0.10", "value": "10"}, {"label": "0.15", "value": "15"}, {"label": "0.20", "value": "20"}, {"label": "0.25", "value": "25"}]
|
||||
"values": [{"label": "0.02", "value": "20"}, {"label": "0.05", "value": "50"}, {"label": "0.10", "value": "100"}, {"label": "0.15", "value": "150"}, {"label": "0.20", "value": "200"}, {"label": "0.25", "value": "250"}]
|
||||
},
|
||||
{
|
||||
"widget": "select", "label": "Номер последовательности Голда", "name": "rxGoldan",
|
||||
@ -316,30 +316,20 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"tcpaccel": [
|
||||
{"widget": "h2", "label": "Настройки TCP-акселерации"},
|
||||
{
|
||||
"widget": "settings-container",
|
||||
"childs": [
|
||||
{"widget": "checkbox", "label": "Активировать акселерацию", "name": "accelEn"},
|
||||
{"widget": "number", "label": "Максимальное количество соединений", "name": "accelMaxConnections", "min": 0, "step": 1, "max": 4000}
|
||||
]
|
||||
}
|
||||
],
|
||||
"network": [
|
||||
{"widget": "h2", "label": "Настройки сети"},
|
||||
{
|
||||
"widget": "settings-container",
|
||||
"childs": [
|
||||
{"widget": "h3", "label": "Настройки интерфейса управления"},
|
||||
{"widget": "ip-address", "label": "Интерфейс управления (/24)", "name": "netManagementIp"},
|
||||
{"widget": "ip-address-mask", "label": "Интерфейс управления (a.d.d.r/mask)", "name": "managementIp"},
|
||||
{
|
||||
"widget": "select", "label": "Режим сети", "name": "netIsL2",
|
||||
"widget": "select", "label": "Режим сети", "name": "isL2",
|
||||
"values": [{"label": "Маршрутизатор", "value": "false"}, {"label": "Коммутатор", "value": "true"}]
|
||||
},
|
||||
{"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"}
|
||||
{"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"}
|
||||
]
|
||||
}
|
||||
]
|
||||
@ -350,6 +340,147 @@
|
||||
{"name": "qos", "desc": "QoS"},
|
||||
{"name": "admin", "desc": "Администрирование"}
|
||||
]
|
||||
},
|
||||
"shps": {
|
||||
"modem_name": "ШПС Модем",
|
||||
"dangerousParamGroups": {
|
||||
"buclnb": "Применение неправильных настроек может вывести из строя оборудование! Продолжить?",
|
||||
"network": "Применение этих настроек может сделать модем недоступным! Продолжить?"
|
||||
},
|
||||
"params": {
|
||||
"rxtx": [
|
||||
{"widget": "h2", "label": "Настройки приема/передачи"},
|
||||
{
|
||||
"widget": "flex-container",
|
||||
"childs": [
|
||||
{
|
||||
"widget": "settings-container",
|
||||
"childs": [
|
||||
{"widget": "h3", "label": "Настройки передатчика"},
|
||||
{"widget": "checkbox", "label": "Включить передатчик", "name": "txEn"},
|
||||
{"widget": "checkbox", "label": "Автоматический запуск передатчика", "name": "txAutoStart"},
|
||||
{
|
||||
"widget": "select", "label": "Режим работы модулятора", "name": "txModulatorIsTest",
|
||||
"values": [{"label": "Нормальный", "value": "false"}, {"label": "Тест (CW)", "value": "true"}]
|
||||
},
|
||||
{
|
||||
"widget": "select", "label": "Входные данные", "name": "txIsTestInput",
|
||||
"values": [{"label": "Ethernet", "value": "false"}, {"label": "Тест", "value": "true"}]
|
||||
},
|
||||
{"widget": "h3", "label": "Параметры передачи"},
|
||||
{"widget": "number", "label": "Центральная частота, КГц", "name": "txCentralFreq", "min": 100000, "max": 6000000, "step": 0.01},
|
||||
{"widget": "number", "label": "Символьная скорость, Бод", "name": "txBaudrate", "min": 200000, "max": 54000000},
|
||||
{
|
||||
"widget": "select", "label": "Roll-off", "name": "txRolloff",
|
||||
"values": [{"label": "0.02", "value": "20"}, {"label": "0.05", "value": "50"}, {"label": "0.10", "value": "100"}, {"label": "0.15", "value": "150"}, {"label": "0.20", "value": "200"}, {"label": "0.25", "value": "250"}]
|
||||
},
|
||||
{"widget": "number", "label": "Коэф. расширения", "name": "txSpreadCoef", "max": 1000, "min": -1000, "step": 0.01},
|
||||
{"widget": "number", "label": "Ослабление, дБ", "name": "txAttenuation", "max": 0, "min": -40, "step": 0.25}
|
||||
]
|
||||
},
|
||||
{
|
||||
"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": 10}
|
||||
]
|
||||
},
|
||||
{
|
||||
"widget": "settings-container",
|
||||
"childs": [
|
||||
{"widget": "h3", "label": "Настройки приемника"},
|
||||
{
|
||||
"widget": "select", "label": "Режим управления усилением", "name": "rxAgcEn",
|
||||
"values": [{"label": "РРУ", "value": "false"}, {"label": "АРУ", "value": "true"}]
|
||||
},
|
||||
{"widget": "number", "label": "Усиление, дБ", "name": "rxManualGain", "min": -40, "step": 0.01, "max": 40, "v_show": "paramRxtx.rxAgcEn === false"},
|
||||
{"widget": "watch-expr", "label": "Текущее усиление", "expr": "paramRxtx.rxManualGain", "v_show": "paramRxtx.rxAgcEn === true"},
|
||||
{"widget": "checkbox", "label": "Инверсия спектра", "name": "rxSpectrumInversion"},
|
||||
{"widget": "number", "label": "Центральная частота, КГц", "name": "rxCentralFreq", "min": 100000, "max": 6000000, "step": 0.01},
|
||||
{"widget": "number", "label": "Символьная скорость, Бод", "name": "rxBaudrate", "min": 200000, "max": 54000000},
|
||||
{
|
||||
"widget": "select", "label": "Roll-off", "name": "rxRolloff",
|
||||
"values": [{"label": "0.02", "value": "20"}, {"label": "0.05", "value": "50"}, {"label": "0.10", "value": "100"}, {"label": "0.15", "value": "150"}, {"label": "0.20", "value": "200"}, {"label": "0.25", "value": "250"}]
|
||||
},
|
||||
{"widget": "number", "label": "Коэф. расширения", "name": "rxSpreadCoef", "max": 1000, "min": -1000, "step": 0.01}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"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": "Администрирование"}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
@ -72,3 +72,130 @@
|
||||
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")
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -21,6 +21,8 @@
|
||||
<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>
|
||||
|
@ -24,7 +24,7 @@
|
||||
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'] ~ "\"]") }}
|
||||
{{ build_setter_js(g['group'], p, "vals[\"settings\"][\"" ~ g['group'] ~ "\"][\"" ~ p['name'] ~ "\"]") }}
|
||||
{% endfor %}
|
||||
},
|
||||
{% endfor %}
|
@ -18,69 +18,68 @@
|
||||
}
|
||||
|
||||
this.lastUpdateTime = new Date();
|
||||
this.initState = vals["mainState"]["initState"]
|
||||
this.initState = vals["state"]["initState"]
|
||||
this.testState = vals["state"]["testState"]
|
||||
{% if modem == 'scpc' %}
|
||||
this.isCinC = vals["mainState"]["isCinC"]
|
||||
this.isCinC = vals["state"]["isCinC"]
|
||||
{% endif %}
|
||||
|
||||
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.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 = vals["state"]["rx"]["freqErr"]
|
||||
this.statRx.freqErrAcc = vals["state"]["rx"]["freqErrAcc"]
|
||||
this.statRx.inputSignalLevel = vals["state"]["rx"]["inputSignalLevel"]
|
||||
this.statRx.pllError = vals["state"]["rx"]["pllError"]
|
||||
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"]
|
||||
|
||||
{% 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.statTx.state = vals["state"]["tx"]["state"]
|
||||
this.statTx.snr = vals["state"]["tx"]["snr"]
|
||||
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 = vals["state"]["tx"]["speedOnTxKbit"]
|
||||
this.statTx.speedOnIifKbit = vals["state"]["tx"]["speedOnIifKbit"]
|
||||
|
||||
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.statCinc.occ = vals["state"]["cinc"]["occ"]
|
||||
this.statCinc.correlator = vals["state"]["cinc"]["correlator"]
|
||||
this.statCinc.correlatorFails = vals["state"]["cinc"]["correlatorFails"]
|
||||
this.statCinc.freqErr = vals["state"]["cinc"]["freqErr"]
|
||||
this.statCinc.freqErrAcc = vals["state"]["cinc"]["freqErrAcc"]
|
||||
this.statCinc.channelDelay = vals["state"]["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"]
|
||||
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.statDevice.adrv = vals["mainState"]["device.adrv"]
|
||||
this.statDevice.zynq = vals["mainState"]["device.zynq"]
|
||||
this.statDevice.fpga = vals["mainState"]["device.fpga"]
|
||||
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["mainState"]["device.upgradeStatus"]
|
||||
this.statDevice.upgradePercent = vals["mainState"]["device.upgradePercent"]
|
||||
this.statDevice.upgradeImage = vals["mainState"]["device.upgradeImage"]
|
||||
this.statDevice.upgradeStatus = vals["state"]["device"]["upgradeStatus"]
|
||||
this.statDevice.upgradePercent = vals["state"]["device"]["upgradePercent"]
|
||||
this.statDevice.upgradeImage = vals["state"]["device"]["upgradeImage"]
|
||||
{% endif %}
|
||||
|
||||
this.testState = vals["mainState"]["testState"]
|
||||
|
||||
// аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид
|
||||
let uptime = vals["sysinfo"]["uptime"]
|
||||
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)
|
||||
@ -92,11 +91,11 @@
|
||||
} 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"]
|
||||
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() {
|
||||
|
@ -44,15 +44,17 @@
|
||||
}
|
||||
let query = {
|
||||
"en": this.paramQos.en,
|
||||
"profile": {
|
||||
"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])) }
|
||||
}
|
||||
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', {
|
||||
@ -73,9 +75,9 @@
|
||||
|
||||
updateQosSettings(vals) {
|
||||
this.submitStatusQos = false
|
||||
this.paramQos.en = vals["settings"]["qosEnabled"]
|
||||
this.paramQos.en = vals["settings"]["qos"]["en"]
|
||||
|
||||
const qosProfile = vals["settings"]["qosProfile"]
|
||||
const qosProfile = vals["settings"]["qos"]["profile"]
|
||||
if (qosProfile !== null && qosProfile !== undefined) {
|
||||
this.paramQos.rt1 = [] // .splice(0, this.paramQos.rt1.length)
|
||||
this.paramQos.rt2 = [] // .splice(0, this.paramQos.rt2.length)
|
||||
|
@ -58,6 +58,10 @@
|
||||
<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>
|
||||
@ -78,22 +82,23 @@
|
||||
{% 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', 'modulation-modcod', 'modulation-speed', 'text'] %}this.param{{ param_group | title }}.{{ widget.name }}{%
|
||||
elif widget.widget in ['checkbox', 'number', 'select', 'ip-address', 'ip-address-mask', 'modulation-modcod', 'modulation-speed', 'text'] %}this.param{{ param_group | title }}.{{ widget.name }}{%
|
||||
elif widget.widget == 'number-int' %}parseFloat(this.param{{ param_group | title }}.{{ widget.name }}.replace(/[^0-9,.]/g, '').replace(',', '.')){%
|
||||
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', 'modulation-modcod', 'modulation-speed', 'text'] %}this.param{{ param_group | title }}.{{ widget.name }} = {{ expr }}{%
|
||||
elif widget.widget in ['checkbox', 'number', 'select', 'ip-address', 'ip-address-mask', 'modulation-modcod', 'modulation-speed', 'text'] %}this.param{{ param_group | title }}.{{ widget.name }} = {{ expr }}{%
|
||||
elif widget.widget == 'number-int' %}this.param{{ param_group | title }}.{{ widget.name }} = this.inputFormatNumber({{ expr }}, {{ js_build_number_number_validator(widget) }}){%
|
||||
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', 'modulation-modcod', 'modulation-speed', 'text'] %}param{{ param_group | title }}.{{ widget.name }} = {{ expr }}{%
|
||||
elif widget.widget in ['checkbox', 'number', 'select', 'ip-address', 'ip-address-mask', 'modulation-modcod', 'modulation-speed', 'text'] %}param{{ param_group | title }}.{{ widget.name }} = {{ expr }}{%
|
||||
elif widget.widget == 'number-int' %}param{{ param_group | title }}.{{ widget.name }} = inputFormatNumber({{ expr }}, {{ js_build_number_number_validator(widget) }}){%
|
||||
else %}<p>Widget '{{ widget.widget }}' not defined!</p><p>{{ widget }}</p>{% endif %}{% endmacro %}
|
||||
|
@ -235,11 +235,11 @@
|
||||
try {
|
||||
const fr = await fetch("/api/get/aboutFirmware")
|
||||
const d = await fr.json()
|
||||
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"]
|
||||
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)
|
||||
}
|
||||
|
283
src/api-driver/daemon.cpp
Normal file
283
src/api-driver/daemon.cpp
Normal file
@ -0,0 +1,283 @@
|
||||
#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();
|
||||
}
|
||||
}
|
79
src/api-driver/daemon.h
Normal file
79
src/api-driver/daemon.h
Normal file
@ -0,0 +1,79 @@
|
||||
#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
|
137
src/api-driver/proxy.cpp
Normal file
137
src/api-driver/proxy.cpp
Normal file
@ -0,0 +1,137 @@
|
||||
#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_GetAcmParams, (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();
|
||||
}
|
82
src/api-driver/proxy.h
Normal file
82
src/api-driver/proxy.h
Normal file
@ -0,0 +1,82 @@
|
||||
#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
|
30
src/api-driver/stricts-enable.h
Normal file
30
src/api-driver/stricts-enable.h
Normal file
@ -0,0 +1,30 @@
|
||||
#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
|
||||
|
||||
|
||||
#endif //API_DRIVER_STRICTS_ENABLE_H
|
941
src/api-driver/structs.cpp
Normal file
941
src/api-driver/structs.cpp
Normal file
@ -0,0 +1,941 @@
|
||||
#include "api-driver/structs.h"
|
||||
#include "api-driver/proxy.h"
|
||||
#include "common/nlohmann/json.hpp"
|
||||
#include <iomanip>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include "terminal_api_driver.h"
|
||||
|
||||
|
||||
#define TIME_NOW() std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now()).time_since_epoch().count()
|
||||
|
||||
static inline void rtrim(std::string &s) {
|
||||
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
|
||||
return !std::isspace(ch);
|
||||
}).base(), s.end());
|
||||
}
|
||||
static inline const char* boolAsStr(bool value) {
|
||||
return value ? "true" : "false";
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& out, CP_Result result) {
|
||||
switch (result) {
|
||||
case OK: out << "OK"; break;
|
||||
case TIMEOUT: out << "TIMEOUT"; break;
|
||||
case ERROR: out << "ERROR"; break;
|
||||
case ABORT: out << "ABORT"; break;
|
||||
case BUSY: out << "BUSY"; break;
|
||||
default:
|
||||
out << static_cast<int>(result);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string makeTimepointFromMillis(int64_t unix_time_ms) {
|
||||
// Преобразуем миллисекунды в микросекунды для std::chrono
|
||||
auto time_point = std::chrono::time_point<std::chrono::system_clock,
|
||||
std::chrono::microseconds>(std::chrono::microseconds(unix_time_ms * 1000));
|
||||
|
||||
auto tp = std::chrono::system_clock::to_time_t(time_point);
|
||||
tm* t = std::localtime(&tp);
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::put_time(t, "%Y-%m-%d %H:%M:%S");
|
||||
auto ms = (unix_time_ms % 1000);
|
||||
ss << '.' << std::setw(3) << std::setfill('0') << ms;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
#ifdef API_OBJECT_DEBUG_METRICS_ENABLE
|
||||
api_driver::obj::StatisticsLogger::StatisticsLogger(): timeStart(TIME_NOW()) {}
|
||||
|
||||
nlohmann::json api_driver::obj::StatisticsLogger::getSettings() {
|
||||
std::lock_guard _lock(mutex);
|
||||
nlohmann::json res;
|
||||
res["en"] = this->logEn;
|
||||
res["logPeriodMs"] = logPeriodMs.load();
|
||||
res["maxAgeMs"] = maxAgeMs.load();
|
||||
return res;
|
||||
}
|
||||
|
||||
void api_driver::obj::StatisticsLogger::setSettings(const nlohmann::json& data) {
|
||||
const bool newEn = data.value("en", logEn);
|
||||
const int newInterval = data.value("logPeriodMs", logPeriodMs.load());
|
||||
const int newMaxAgeMs = data.value("maxAgeMs", maxAgeMs.load());
|
||||
|
||||
std::lock_guard _lock(this->mutex);
|
||||
this->logPeriodMs = newInterval;
|
||||
this->maxAgeMs = newMaxAgeMs;
|
||||
|
||||
if (newEn != this->logEn) {
|
||||
if (newEn) {
|
||||
this->logFile.open(LOG_FILENAME, std::ios::out);
|
||||
if (this->logFile.is_open()) {
|
||||
const auto* header = "timestamp\tcnt ok\tcnt bad\tfine freq dem\tcrs freq dem\tcrs freq compensator\tcrs time est\tfine time est\tmax level corr\tcurrent delay\tSNR\tcurrent modcod\tfine freq compensator\tind freq grb\tind freq tochn\tind filt adapt\tfilter corr cinc\tcorr cnt\tRSS\tcor erl\tcor lat\tgc gain\tpower pl rx\n";
|
||||
this->logFile.write(header, static_cast<std::streamsize>(strlen(header)));
|
||||
this->logEn = true;
|
||||
this->timeStart = TIME_NOW();
|
||||
}
|
||||
} else {
|
||||
if (this->logFile.is_open()) {
|
||||
this->logFile.close();
|
||||
}
|
||||
this->logEn = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void api_driver::obj::StatisticsLogger::updateCallback(proxy::CpProxy &cp) {
|
||||
if (!logEn) return;
|
||||
|
||||
debug_metrics dm{};
|
||||
cp.getDebugMetrics(dm);
|
||||
putItem(dm);
|
||||
}
|
||||
|
||||
void api_driver::obj::StatisticsLogger::putItem(const debug_metrics &item) {
|
||||
std::lock_guard _lock(this->mutex);
|
||||
if (!logEn) return;
|
||||
if (this->logFile.is_open()) {
|
||||
std::stringstream res;
|
||||
res << makeTimepointFromMillis(TIME_NOW()) << '\t';
|
||||
res << item.cnt_ok << '\t';
|
||||
res << item.cnt_bad << '\t';
|
||||
res << item.fine_freq_dem << '\t';
|
||||
res << item.crs_freq_dem << '\t';
|
||||
res << item.crs_freq_compensator << '\t';
|
||||
res << item.crs_time_est << '\t';
|
||||
res << item.fine_time_est << '\t';
|
||||
res << item.max_level_corr << '\t';
|
||||
res << item.current_delay << '\t';
|
||||
res << item.SNR << '\t';
|
||||
res << item.current_modcod << '\t';
|
||||
res << item.fine_freq_compensator << '\t';
|
||||
res << item.ind_freq_grb << '\t';
|
||||
res << item.ind_freq_tochn << '\t';
|
||||
res << item.ind_filt_adapt << '\t';
|
||||
res << item.filter_corr_cinc << '\t';
|
||||
res << item.corr_cnt << '\t';
|
||||
res << item.RSS << '\t';
|
||||
res << item.cor_erl << '\t';
|
||||
res << item.cor_lat << '\t';
|
||||
res << item.gc_gain << '\t';
|
||||
res << item.power_pl_rx << '\n';
|
||||
|
||||
const auto out = res.str();
|
||||
this->logFile.write(out.c_str(), static_cast<std::streamsize>(out.length()));
|
||||
this->logFile.flush();
|
||||
}
|
||||
}
|
||||
|
||||
api_driver::obj::StatisticsLogger::~StatisticsLogger() = default;
|
||||
#endif
|
||||
|
||||
#ifdef API_OBJECT_NETWORK_SETTINGS_ENABLE
|
||||
static int calculateSubnetMask(const std::string& subnet_mask) {
|
||||
int mask = 0;
|
||||
std::istringstream iss(subnet_mask);
|
||||
std::string octet;
|
||||
while (std::getline(iss, octet, '.')) {
|
||||
int octet_value = std::stoi(octet);
|
||||
for (int i = 7; i >= 0; i--) {
|
||||
if (octet_value & (1 << i)) {
|
||||
mask++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Преобразует строку вида `1.2.3.4/24` в пару строк вида `1.2.3.4` `255.255.255.0`
|
||||
*/
|
||||
std::pair<std::string, std::string> splitIpAndMask(const std::string& input) {
|
||||
auto pos = input.find('/');
|
||||
if (pos == std::string::npos) {
|
||||
// Обработка ошибки: нет символа '/'
|
||||
throw std::runtime_error("address not contains mask");
|
||||
}
|
||||
std::string ip = input.substr(0, pos);
|
||||
const unsigned int mask_int = std::stoul(input.substr(pos + 1));
|
||||
|
||||
if (mask_int > 32) {
|
||||
throw std::runtime_error("invalid mask");
|
||||
}
|
||||
|
||||
std::string mask_binary = std::string(mask_int, '1') + std::string(32 - mask_int, '0');
|
||||
std::string mask_str;
|
||||
|
||||
for (unsigned int i = 0; i < 4; ++i) {
|
||||
std::string octet = mask_binary.substr(i * 8u, 8);
|
||||
int octet_value = std::stoi(octet, nullptr, 2);
|
||||
mask_str += std::to_string(octet_value) + (i < 3 ? "." : "");
|
||||
}
|
||||
|
||||
return std::make_pair(ip, mask_str);
|
||||
}
|
||||
|
||||
api_driver::obj::TerminalNetworkSettings::TerminalNetworkSettings() { loadDefaults(); }
|
||||
|
||||
api_driver::obj::TerminalNetworkSettings::TerminalNetworkSettings(const TerminalNetworkSettings &src) = default;
|
||||
|
||||
api_driver::obj::TerminalNetworkSettings & api_driver::obj::TerminalNetworkSettings::operator=(const TerminalNetworkSettings &src) = default;
|
||||
|
||||
void api_driver::obj::TerminalNetworkSettings::loadDefaults() {
|
||||
managementIp = "0.0.0.0/24";
|
||||
managementGateway = "";
|
||||
isL2 = true;
|
||||
dataIp = "0.0.0.0";
|
||||
dataMtu = 1500;
|
||||
serverName = DEFAULT_SERVER_NAME;
|
||||
}
|
||||
|
||||
void api_driver::obj::TerminalNetworkSettings::updateCallback(proxy::CpProxy &cp) {
|
||||
loadDefaults();
|
||||
try {
|
||||
managementIp = cp.getNetwork("addr");
|
||||
managementIp += "/";
|
||||
managementIp += std::to_string(calculateSubnetMask(cp.getNetwork("mask")));
|
||||
|
||||
managementGateway = cp.getNetwork("gateway");
|
||||
if (cp.getNetwork("mode") == "tun") {
|
||||
isL2 = false;
|
||||
dataIp = cp.getNetwork("addr_data");
|
||||
} else {
|
||||
isL2 = true;
|
||||
}
|
||||
dataMtu = 1500;
|
||||
serverName = cp.getNetwork("name_serv");
|
||||
if (serverName.empty()) {
|
||||
serverName = DEFAULT_SERVER_NAME;
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
throw std::runtime_error(std::string("api_driver::obj::TerminalNetworkSettings::updateCallback() error: ") + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
void api_driver::obj::TerminalNetworkSettings::updateFromJson(const nlohmann::json &data) {
|
||||
managementIp = data.value("managementIp", managementIp);
|
||||
isL2 = data.value("isL2", isL2);
|
||||
dataIp = data.value("dataIp", dataIp);
|
||||
dataMtu = data.value("dataMtu", dataMtu);
|
||||
serverName = data.value("serverName", serverName);
|
||||
}
|
||||
|
||||
void api_driver::obj::TerminalNetworkSettings::store(proxy::CpProxy& cp) {
|
||||
try {
|
||||
cp.setNetwork("mode", isL2 ? "tap" : "tun");
|
||||
auto [mAddr, mMask] = splitIpAndMask(managementIp);
|
||||
cp.setNetwork("addr", mAddr);
|
||||
cp.setNetwork("mask", mMask);
|
||||
|
||||
if (!isL2) {
|
||||
cp.setNetwork("addr_data", dataIp);
|
||||
}
|
||||
cp.setNetwork("gateway", managementGateway);
|
||||
|
||||
// cp.setNetwork("data_mtu", std::to_string(dataMtu));
|
||||
|
||||
cp.setNetwork("name_serv", serverName);
|
||||
} catch (std::exception& e) {
|
||||
throw std::runtime_error(std::string("api_driver::obj::TerminalNetworkSettings::store() error: ") + e.what());
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json api_driver::obj::TerminalNetworkSettings::asJson() {
|
||||
nlohmann::json res;
|
||||
res["isL2"] = isL2;
|
||||
res["managementIp"] = managementIp;
|
||||
res["managementGateway"] = managementGateway;
|
||||
res["dataIp"] = dataIp;
|
||||
res["dataMtu"] = dataMtu;
|
||||
res["serverName"] = serverName;
|
||||
return res;
|
||||
}
|
||||
|
||||
api_driver::obj::TerminalNetworkSettings::~TerminalNetworkSettings() = default;
|
||||
#endif
|
||||
|
||||
#ifdef API_OBJECT_QOS_SETTINGS_ENABLE
|
||||
api_driver::obj::TerminalQosSettings::TerminalQosSettings(): qosSettingsJson(DEFAULT_QOS_CLASSES) {};
|
||||
api_driver::obj::TerminalQosSettings::TerminalQosSettings(const TerminalQosSettings &src) = default;
|
||||
api_driver::obj::TerminalQosSettings & api_driver::obj::TerminalQosSettings::operator=(const TerminalQosSettings &src) = default;
|
||||
|
||||
void api_driver::obj::TerminalQosSettings::loadDefaults() {
|
||||
qosEnabled = false;
|
||||
qosSettingsJson = DEFAULT_QOS_CLASSES;
|
||||
}
|
||||
|
||||
void api_driver::obj::TerminalQosSettings::updateCallback(proxy::CpProxy &cp) {
|
||||
auto [profile, en] = cp.getQosSettings();
|
||||
qosEnabled = en;
|
||||
try {
|
||||
qosSettingsJson = nlohmann::json::parse(profile);
|
||||
} catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(warning) << "api_driver::obj::TerminalQosSettings::updateCallback(): Failed to parse QoS settings json: " << e.what();
|
||||
qosSettingsJson = DEFAULT_QOS_CLASSES;
|
||||
}
|
||||
}
|
||||
|
||||
void api_driver::obj::TerminalQosSettings::updateFromJson(const nlohmann::json &data) {
|
||||
qosEnabled = data.value("en", qosEnabled);
|
||||
qosSettingsJson = data.value("profile", qosSettingsJson);
|
||||
}
|
||||
|
||||
void api_driver::obj::TerminalQosSettings::store(proxy::CpProxy &cp) {
|
||||
cp.setQosSettings(qosSettingsJson.dump(), qosEnabled);
|
||||
}
|
||||
|
||||
nlohmann::json api_driver::obj::TerminalQosSettings::asJson() {
|
||||
nlohmann::json res;
|
||||
res["en"] = qosEnabled;
|
||||
res["profile"] = qosSettingsJson;
|
||||
return res;
|
||||
}
|
||||
|
||||
api_driver::obj::TerminalQosSettings::~TerminalQosSettings() = default;
|
||||
#endif
|
||||
|
||||
api_driver::obj::TerminalFirmwareVersion::TerminalFirmwareVersion() = default;
|
||||
api_driver::obj::TerminalFirmwareVersion::TerminalFirmwareVersion(const TerminalFirmwareVersion &src) = default;
|
||||
api_driver::obj::TerminalFirmwareVersion & api_driver::obj::TerminalFirmwareVersion::operator=(const TerminalFirmwareVersion &src) = default;
|
||||
|
||||
void api_driver::obj::TerminalFirmwareVersion::load(proxy::CpProxy &cp) {
|
||||
version = cp.getNetwork("version");
|
||||
modemId = cp.getNetwork("chip_id");
|
||||
rtrim(modemId);
|
||||
modemSn = cp.getNetwork("serial");
|
||||
macMang = cp.getNetwork("mac_eth0");
|
||||
macData = cp.getNetwork("mac_eth1");
|
||||
}
|
||||
|
||||
nlohmann::json api_driver::obj::TerminalFirmwareVersion::asJson() {
|
||||
nlohmann::json res;
|
||||
res["version"] = version;
|
||||
res["modemId"] = modemId;
|
||||
res["modemSn"] = modemSn;
|
||||
res["macMang"] = macMang;
|
||||
res["macData"] = macData;
|
||||
return res;
|
||||
}
|
||||
|
||||
api_driver::obj::TerminalFirmwareVersion::~TerminalFirmwareVersion() = default;
|
||||
|
||||
|
||||
api_driver::obj::TerminalState::TerminalState() = default;
|
||||
|
||||
void api_driver::obj::TerminalState::updateCallback(proxy::CpProxy& cp) {
|
||||
modulator_state mod{};
|
||||
modulator_settings modSet{};
|
||||
demodulator_state demod{};
|
||||
#ifdef MODEM_IS_SCPC
|
||||
CinC_state cinc{};
|
||||
#endif
|
||||
try {
|
||||
cp.getModState(mod);
|
||||
cp.getDemodState(demod);
|
||||
cp.getModSettings(modSet);
|
||||
|
||||
fTxState = modSet.tx_is_on;
|
||||
fIsTest = modSet.tx_is_on && (!modSet.is_carrier || modSet.is_test_data);
|
||||
#ifdef MODEM_IS_SCPC
|
||||
fIsCinC = modSet.is_cinc;
|
||||
if (fIsCinC) {
|
||||
cp.getCincState(cinc);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MODEM_IS_TDMA
|
||||
fInitState = cp.getDmaDebug("status_init");
|
||||
#endif
|
||||
} catch (std::exception& e) {
|
||||
throw std::runtime_error(std::string("api_driver::obj::TerminalState::updateCallback() error: ") + e.what());
|
||||
}
|
||||
|
||||
fRxState = demod.locks.sym_sync_lock && demod.locks.freq_lock && demod.locks.afc_lock && demod.locks.pkt_sync;
|
||||
fRxSymSyncLock = demod.locks.sym_sync_lock;
|
||||
fRxFreqSearchLock = demod.locks.freq_lock;
|
||||
fRxAfcLock = demod.locks.afc_lock;
|
||||
fRxPktSync = demod.locks.pkt_sync;
|
||||
|
||||
fRxSnr = demod.snr;
|
||||
fRxRssi = demod.rssi;
|
||||
fRxModcod = demod.modcod;
|
||||
fRxFrameSizeNormal = !demod.is_short;
|
||||
fRxIsPilots = demod.is_pilots;
|
||||
|
||||
fRxSymError = demod.sym_err;
|
||||
fRxFreqErr = demod.crs_freq_err;
|
||||
fRxFreqErrAcc = demod.fine_freq_err;
|
||||
fRxInputSignalLevel = demod.if_overload;
|
||||
fRxPllError = demod.afc_err;
|
||||
fRxSpeedOnRxKbit = static_cast<double>(demod.speed_in_bytes_rx) / 128.0;
|
||||
fRxSpeedOnIifKbit = static_cast<double>(demod.speed_in_bytes_rx_iface) / 128.0;
|
||||
fRxPacketsOk = demod.packet_ok_cnt;
|
||||
fRxPacketsBad = demod.packet_bad_cnt;
|
||||
fRxPacketsDummy = demod.dummy_cnt;
|
||||
|
||||
fTxModcod = mod.modcod;
|
||||
fTxSpeedOnTxKbit = static_cast<double>(mod.speed_in_bytes_tx) / 128.0;
|
||||
fTxSpeedOnIifKbit = static_cast<double>(mod.speed_in_bytes_tx_iface) / 128.0;
|
||||
#ifdef MODEM_IS_SCPC
|
||||
fTxSnr = mod.snr_remote;
|
||||
fTxFrameSizeNormal = !mod.is_short;
|
||||
fTxIsPilots = mod.is_pilots;
|
||||
fCincOcc = cinc.ratio_signal_signal;
|
||||
fCincCorrelator = cinc.carrier_lock;
|
||||
fCincCorrelatorFails = cinc.cnt_bad_lock;
|
||||
fCincFreqErr = cinc.freq_error_offset;
|
||||
fCincFreqErrAcc = cinc.freq_fine_estimate;
|
||||
fCincChannelDelay = cinc.delay_dpdi;
|
||||
#endif
|
||||
fTxCenterFreq = modSet.central_freq_in_kGz;
|
||||
fTxSymSpeed = static_cast<double>(modSet.baudrate) / 1000.0;
|
||||
}
|
||||
|
||||
nlohmann::json api_driver::obj::TerminalState::asJson() {
|
||||
nlohmann::json res{};
|
||||
|
||||
res["initState"] = fInitState;
|
||||
res["testState"] = fIsTest;
|
||||
#ifdef MODEM_IS_SCPC
|
||||
res["isCinC"] = fIsCinC;
|
||||
#endif
|
||||
|
||||
res["rx"]["state"] = fRxState;
|
||||
res["rx"]["sym_sync_lock"] = fRxSymSyncLock;
|
||||
res["rx"]["freq_search_lock"] = fRxFreqSearchLock;
|
||||
res["rx"]["afc_lock"] = fRxAfcLock;
|
||||
res["rx"]["pkt_sync"] = fRxPktSync;
|
||||
|
||||
res["rx"]["snr"] = fRxSnr;
|
||||
res["rx"]["rssi"] = fRxRssi;
|
||||
res["rx"]["modcod"] = fRxModcod;
|
||||
res["rx"]["frameSizeNormal"] = fRxFrameSizeNormal;
|
||||
res["rx"]["isPilots"] = fRxIsPilots;
|
||||
|
||||
res["rx"]["symError"] = fRxSymError;
|
||||
res["rx"]["freqErr"] = fRxFreqErr;
|
||||
res["rx"]["freqErrAcc"] = fRxFreqErrAcc;
|
||||
res["rx"]["inputSignalLevel"] = fRxInputSignalLevel;
|
||||
res["rx"]["pllError"] = fRxPllError;
|
||||
res["rx"]["speedOnRxKbit"] = fRxSpeedOnRxKbit;
|
||||
res["rx"]["speedOnIifKbit"] = fRxSpeedOnIifKbit;
|
||||
res["rx"]["packetsOk"] = fRxPacketsOk;
|
||||
res["rx"]["packetsBad"] = fRxPacketsBad;
|
||||
res["rx"]["packetsDummy"] = fRxPacketsDummy;
|
||||
|
||||
res["tx"]["modcod"] = fTxModcod;
|
||||
res["tx"]["state"] = fTxState;
|
||||
res["tx"]["speedOnTxKbit"] = fTxSpeedOnTxKbit;
|
||||
res["tx"]["speedOnIifKbit"] = fTxSpeedOnIifKbit;
|
||||
#ifdef MODEM_IS_SCPC
|
||||
res["tx"]["snr"] = fTxSnr;
|
||||
res["tx"]["frameSizeNormal"] = fTxFrameSizeNormal;
|
||||
res["tx"]["isPilots"] = fTxIsPilots;
|
||||
|
||||
if (fIsCinC) {
|
||||
if (fTxState) {
|
||||
res["cinc"]["correlator"] = fCincCorrelator;
|
||||
} else {
|
||||
res["cinc"]["correlator"] = nullptr;
|
||||
}
|
||||
|
||||
res["cinc"]["occ"] = fCincOcc;
|
||||
res["cinc"]["correlatorFails"] = fCincCorrelatorFails;
|
||||
res["cinc"]["freqErr"] = fCincFreqErr;
|
||||
res["cinc"]["freqErrAcc"] = fCincFreqErrAcc;
|
||||
res["cinc"]["channelDelay"] = fCincChannelDelay;
|
||||
} else {
|
||||
res["cinc"]["correlator"] = nullptr;
|
||||
}
|
||||
#endif
|
||||
res["tx"]["centerFreq"] = fTxCenterFreq;
|
||||
res["tx"]["symSpeed"] = fTxSymSpeed;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
api_driver::obj::TerminalState::~TerminalState() = default;
|
||||
|
||||
|
||||
api_driver::obj::TerminalDeviceState::TerminalDeviceState() = default;
|
||||
api_driver::obj::TerminalDeviceState::TerminalDeviceState(const TerminalDeviceState &src) = default;
|
||||
api_driver::obj::TerminalDeviceState & api_driver::obj::TerminalDeviceState::operator=(const TerminalDeviceState &src) = default;
|
||||
|
||||
void api_driver::obj::TerminalDeviceState::updateCallback(proxy::CpProxy &cp) {
|
||||
{
|
||||
device_state ds{};
|
||||
cp.getDeviceState(ds);
|
||||
fTempAdrv = ds.adrv_temp;
|
||||
fTempZynq = ds.pl_temp;
|
||||
fTempFpga = ds.zynq_temp;
|
||||
}
|
||||
#ifdef MODEM_IS_TDMA
|
||||
{
|
||||
progress_msg ds{};
|
||||
cp.getUpdateStatus(ds);
|
||||
fUpgradeStatus = ds.status;
|
||||
fUpgradePercent = ds.dwl_percent;
|
||||
fUpgradeImage = ds.cur_image;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct sysinfo info{};
|
||||
sysinfo(&info);
|
||||
|
||||
const double f_load = 100.0 / ((1 << SI_LOAD_SHIFT) * get_nprocs());
|
||||
fOsUptime = info.uptime;
|
||||
fOsLoad1 = f_load * static_cast<double>(info.loads[0]);
|
||||
fOsLoad5 = f_load * static_cast<double>(info.loads[1]);
|
||||
fOsLoad15 = f_load * static_cast<double>(info.loads[2]);
|
||||
fOsTotalram = (info.totalram * info.mem_unit) >> 20; // Mb
|
||||
fOsFreeram = (info.totalram * info.mem_unit) >> 20; // Mb
|
||||
fOsProcs = info.procs;
|
||||
}
|
||||
|
||||
nlohmann::json api_driver::obj::TerminalDeviceState::asJson() const {
|
||||
nlohmann::json res;
|
||||
res["uptime"] = fOsUptime;
|
||||
res["load1min"] = fOsLoad1;
|
||||
res["load5min"] = fOsLoad5;
|
||||
res["load15min"] = fOsLoad15;
|
||||
res["totalram"] = fOsTotalram;
|
||||
res["freeram"] = fOsFreeram;
|
||||
res["procs"] = fOsProcs;
|
||||
res["adrv"] = fTempAdrv;
|
||||
res["fpga"] = fTempFpga;
|
||||
res["zynq"] = fTempZynq;
|
||||
#ifdef MODEM_IS_TDMA
|
||||
if (fUpgradeImage.empty()) {
|
||||
res["upgradeStatus"] = "Нет обновлений";
|
||||
res["upgradePercent"] = 0;
|
||||
res["upgradeImage"] = "";
|
||||
} else {
|
||||
switch (fUpgradeStatus) {
|
||||
case NORM_RX_OBJECT_NEW_API: res["upgradeStatus"] = "Начало загрузки"; break;
|
||||
case NORM_RX_OBJECT_INFO_API: res["upgradeStatus"] = "Получено имя образа"; break;
|
||||
case NORM_RX_OBJECT_UPDATED_API: res["upgradeStatus"] = "Загружается"; break;
|
||||
case NORM_RX_OBJECT_COMPLETED_API: res["upgradeStatus"] = "Загрузка завершена"; break;
|
||||
case NORM_RX_OBJECT_ABORTED_API: res["upgradeStatus"] = "Загрузка прервана"; break;
|
||||
default: res["upgradeStatus"] = "?";
|
||||
}
|
||||
res["upgradePercent"] = fUpgradePercent;
|
||||
res["upgradeImage"] = fUpgradeImage;
|
||||
}
|
||||
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
api_driver::obj::TerminalDeviceState::~TerminalDeviceState() = default;
|
||||
|
||||
|
||||
api_driver::obj::TerminalRxTxSettings::TerminalRxTxSettings() = default;
|
||||
api_driver::obj::TerminalRxTxSettings::TerminalRxTxSettings(const TerminalRxTxSettings &src) = default;
|
||||
api_driver::obj::TerminalRxTxSettings & api_driver::obj::TerminalRxTxSettings::operator=(const TerminalRxTxSettings &src) = default;
|
||||
|
||||
void api_driver::obj::TerminalRxTxSettings::updateCallback(proxy::CpProxy &cp) {
|
||||
cp.getModSettings(mod);
|
||||
cp.getDemodSettings(dem);
|
||||
#ifdef API_STRUCT_ACM_ENABLE
|
||||
cp.getAcmSettings(acm);
|
||||
#endif
|
||||
#ifdef API_OBJECT_DPDI_SETTINGS_ENABLE
|
||||
cp.getDpdiSettings(dpdi);
|
||||
#endif
|
||||
#ifdef API_OBJECT_BUCLNB_SETTINGS_ENABLE
|
||||
cp.getBuclnbSettings(buclnb);
|
||||
#endif
|
||||
}
|
||||
|
||||
void api_driver::obj::TerminalRxTxSettings::storeMainSettings(proxy::CpProxy &cp) {
|
||||
cp.setModSettings(mod);
|
||||
cp.setDemodSettings(dem);
|
||||
#ifdef API_STRUCT_ACM_ENABLE
|
||||
cp.setAcmSettings(acm);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
struct ModcodDef_t {const char* modulation; const char* speed;};
|
||||
const static ModcodDef_t ModcodDefs[] = {
|
||||
{.modulation = "dummy", .speed = "0"},
|
||||
{.modulation = "qpsk", .speed = "1/4"},
|
||||
{.modulation = "qpsk", .speed = "1/3"},
|
||||
{.modulation = "qpsk", .speed = "2/5"},
|
||||
{.modulation = "qpsk", .speed = "1/2"},
|
||||
{.modulation = "qpsk", .speed = "3/5"},
|
||||
{.modulation = "qpsk", .speed = "2/3"},
|
||||
{.modulation = "qpsk", .speed = "3/4"},
|
||||
{.modulation = "qpsk", .speed = "4/5"},
|
||||
{.modulation = "qpsk", .speed = "5/6"},
|
||||
{.modulation = "qpsk", .speed = "8/9"},
|
||||
{.modulation = "qpsk", .speed = "9/10"},
|
||||
{.modulation = "8psk", .speed = "3/5"},
|
||||
{.modulation = "8psk", .speed = "2/3"},
|
||||
{.modulation = "8psk", .speed = "3/4"},
|
||||
{.modulation = "8psk", .speed = "5/6"},
|
||||
{.modulation = "8psk", .speed = "8/9"},
|
||||
{.modulation = "8psk", .speed = "9/10"},
|
||||
{.modulation = "16apsk", .speed = "2/3"},
|
||||
{.modulation = "16apsk", .speed = "3/4"},
|
||||
{.modulation = "16apsk", .speed = "4/5"},
|
||||
{.modulation = "16apsk", .speed = "5/6"},
|
||||
{.modulation = "16apsk", .speed = "8/9"},
|
||||
{.modulation = "16apsk", .speed = "9/10"},
|
||||
{.modulation = "32apsk", .speed = "3/4"},
|
||||
{.modulation = "32apsk", .speed = "4/5"},
|
||||
{.modulation = "32apsk", .speed = "5/6"},
|
||||
{.modulation = "32apsk", .speed = "8/9"},
|
||||
{.modulation = "32apsk", .speed = "9/10"},
|
||||
};
|
||||
|
||||
static const char* extractModcodModulation(uint32_t modcod, bool defaultQpsk1_4 = true) {
|
||||
modcod >>= 2;
|
||||
const auto* d = defaultQpsk1_4 ? ModcodDefs : ModcodDefs + 1;
|
||||
if (modcod < (sizeof(ModcodDefs) / sizeof(ModcodDef_t))) {
|
||||
d = ModcodDefs + modcod;
|
||||
}
|
||||
return d->modulation;
|
||||
}
|
||||
static const char* extractModcodSpeed(uint32_t modcod, bool defaultQpsk1_4 = true) {
|
||||
modcod >>= 2;
|
||||
const auto* d = defaultQpsk1_4 ? ModcodDefs : ModcodDefs + 1;
|
||||
if (modcod < (sizeof(ModcodDefs) / sizeof(ModcodDef_t))) {
|
||||
d = ModcodDefs + modcod;
|
||||
}
|
||||
return d->speed;
|
||||
}
|
||||
static bool extractModcodFrameSizeNormal(uint32_t modcod) { return (modcod & 2) == 0; }
|
||||
static bool extractModcodIsPilots(uint32_t modcod) { return (modcod & 1) != 0; }
|
||||
static uint32_t buildModcodFromJson(const nlohmann::json& data, uint32_t modcod, const std::string& name, bool isNormalFrame, bool isPilots = false) {
|
||||
const std::string mod = data.value(name + "Modulation", extractModcodModulation(modcod));
|
||||
const std::string speed = data.value(name + "Speed", extractModcodSpeed(modcod));
|
||||
uint32_t _index = 0;
|
||||
for (const auto& m: ModcodDefs) {
|
||||
if (mod == m.modulation) {
|
||||
if (modcod == 0) modcod = _index;
|
||||
if (speed == m.speed) {
|
||||
modcod = _index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_index++;
|
||||
}
|
||||
return (modcod << 2)| (isNormalFrame ? 0 : 2) | (isPilots ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
void api_driver::obj::TerminalRxTxSettings::updateMainSettings(const nlohmann::json &data) {
|
||||
// для модулятора
|
||||
#ifdef MODEM_IS_SCPC
|
||||
mod.is_cinc = data.value("isCinC", mod.is_cinc);
|
||||
#endif
|
||||
mod.tx_is_on = data.value("txEn", mod.tx_is_on);
|
||||
#if defined(MODEM_IS_SCPC) || defined (MODEM_IS_SHPS)
|
||||
mod.is_save_current_state = data.value("txAutoStart", mod.is_save_current_state);
|
||||
mod.is_test_data = data.value("txIsTestInput", mod.is_test_data);
|
||||
#endif
|
||||
mod.is_carrier = !data.value("txModulatorIsTest", !mod.is_carrier);
|
||||
mod.central_freq_in_kGz = data.value("txCentralFreq", mod.central_freq_in_kGz);
|
||||
#if defined(MODEM_IS_SCPC) || defined (MODEM_IS_SHPS)
|
||||
mod.baudrate = data.value("txBaudrate", mod.baudrate);
|
||||
mod.rollof = data.value("txRolloff", mod.rollof);
|
||||
mod.gold_seq_is_active = data.value("txGoldan", mod.gold_seq_is_active ? 1 : 0);
|
||||
#endif
|
||||
mod.attenuation = data.value("txAttenuation", mod.attenuation);
|
||||
|
||||
#if defined(MODEM_IS_SCPC) || defined(MODEM_IS_SHPS)
|
||||
bool acmIsFrameSizeNormal = extractModcodFrameSizeNormal(mod.modcod_tx);
|
||||
bool acmIsPilots = extractModcodIsPilots(mod.modcod_tx);
|
||||
|
||||
acmIsFrameSizeNormal = data.value("txFrameSizeNormal", acmIsFrameSizeNormal);
|
||||
acmIsPilots = data.value("txIsPilots", acmIsPilots);
|
||||
mod.modcod_tx = buildModcodFromJson(data, mod.modcod_tx, "dvbCcm", acmIsFrameSizeNormal, acmIsPilots);
|
||||
#endif
|
||||
#ifdef MODEM_IS_SHPS
|
||||
mod.koef_spread = data.value("txSpreadCoef", mod.koef_spread);
|
||||
#endif
|
||||
|
||||
// демодулятор
|
||||
dem.is_aru_on = data.value("rxAgcEn", dem.is_aru_on);
|
||||
dem.gain = data.value("rxManualGain", dem.gain);
|
||||
dem.is_rvt_iq = data.value("rxSpectrumInversion", dem.is_rvt_iq);
|
||||
dem.central_freq_in_kGz = data.value("rxCentralFreq", dem.central_freq_in_kGz);
|
||||
dem.baudrate = data.value("rxBaudrate", dem.baudrate);
|
||||
dem.rollof = data.value("rxRolloff", dem.rollof);
|
||||
#if defined(MODEM_IS_SCPC) || defined (MODEM_IS_SHPS)
|
||||
dem.gold_seq_is_active = data.value("rxGoldan", dem.gold_seq_is_active ? 1 : 0);
|
||||
#endif
|
||||
#ifdef MODEM_IS_SHPS
|
||||
dem.koef_spread = data.value("rxSpreadCoef", dem.koef_spread);
|
||||
#endif
|
||||
|
||||
#ifdef API_STRUCT_ACM_ENABLE
|
||||
// ACM
|
||||
#ifdef MODEM_IS_SCPC
|
||||
// эти настройки только в SCPC
|
||||
acm.period_pack_acm = data.value("dvbServicePacketPeriod", acm.period_pack_acm);
|
||||
acm.enable_acm = data.value("dvbIsAcm", acm.enable_acm);
|
||||
acm.min_modcod_acm = buildModcodFromJson(data, acm.min_modcod_acm, "dvbAcmMin", acmIsFrameSizeNormal, acmIsPilots);
|
||||
acm.min_modcod_acm = buildModcodFromJson(data, acm.max_modcod_acm, "dvbAcmMax", acmIsFrameSizeNormal, acmIsPilots);
|
||||
acm.snr_threashold_acm = data.value("dvbSnrReserve", acm.snr_threashold_acm); // запас ОСШ
|
||||
#endif
|
||||
|
||||
acm.enable_aupc = data.value("aupcEn", acm.enable_aupc);
|
||||
acm.min_attenuation_aupc = data.value("aupcMinAttenuation", acm.min_attenuation_aupc);
|
||||
acm.max_attenuation_aupc = data.value("aupcMaxAttenuation", acm.max_attenuation_aupc);
|
||||
acm.snr_threashold_aupc = data.value("aupcRequiredSnr", acm.snr_threashold_aupc);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef API_OBJECT_DPDI_SETTINGS_ENABLE
|
||||
static double translateCoordinates(uint8_t deg, uint8_t min) {
|
||||
return static_cast<double>(deg) + static_cast<double>(min) / 60;
|
||||
}
|
||||
|
||||
static std::tuple<uint8_t, uint8_t> translateCoordinates(double abs) {
|
||||
auto deg = static_cast<uint8_t>(abs);
|
||||
double min_double = (abs - deg) * 60;
|
||||
auto min = static_cast<uint8_t>(min_double);
|
||||
return std::make_tuple(deg, min);
|
||||
}
|
||||
|
||||
void api_driver::obj::TerminalRxTxSettings::updateDpdiSettings(const nlohmann::json &data) {
|
||||
dpdi.is_delay_window = !data.value("isPositional", !dpdi.is_delay_window);
|
||||
#ifdef MODEM_IS_SCPC
|
||||
dpdi.freq_offset = data.value("searchBandwidth", dpdi.freq_offset);
|
||||
#endif
|
||||
|
||||
if (data.contains("positionStationLatitude")) {
|
||||
const double pos = data["positionStationLatitude"];
|
||||
const auto [g, m] = translateCoordinates(pos);
|
||||
dpdi.latitude_station_grad = g;
|
||||
dpdi.latitude_station_minute = m;
|
||||
}
|
||||
|
||||
if (data.contains("positionStationLongitude")) {
|
||||
const double pos = data["positionStationLongitude"];
|
||||
const auto [g, m] = translateCoordinates(pos);
|
||||
dpdi.longitude_station_grad = g;
|
||||
dpdi.longitude_station_minute = m;
|
||||
}
|
||||
|
||||
if (data.contains("positionSatelliteLongitude")) {
|
||||
const double pos = data["positionSatelliteLongitude"];
|
||||
const auto [g, m] = translateCoordinates(pos);
|
||||
dpdi.longitude_sattelite_grad = g;
|
||||
dpdi.longitude_sattelite_minute = m;
|
||||
}
|
||||
|
||||
#ifdef MODEM_IS_SCPC
|
||||
dpdi.min_delay = data.value("delayMin", dpdi.min_delay);
|
||||
dpdi.max_delay = data.value("delayMax", dpdi.max_delay);
|
||||
#else
|
||||
dpdi.min_delay = 0;
|
||||
dpdi.max_delay = data.value("dpdiDelay", dpdi.max_delay);
|
||||
#endif
|
||||
}
|
||||
void api_driver::obj::TerminalRxTxSettings::storeDpdiSettings(proxy::CpProxy &cp) {
|
||||
cp.setDpdiSettings(dpdi);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef API_OBJECT_BUCLNB_SETTINGS_ENABLE
|
||||
void api_driver::obj::TerminalRxTxSettings::updateBuclnbSettings(const nlohmann::json &data) {
|
||||
{
|
||||
// напряжение buc
|
||||
int oldVoltage = 0;
|
||||
if (buclnb.buc == voltage_buc::_24V) { oldVoltage = 24; }
|
||||
#ifdef MODEM_IS_SCPC
|
||||
if (buclnb.buc == voltage_buc::_24V) { oldVoltage = 24; }
|
||||
#endif
|
||||
|
||||
auto result = data.value("bucPowering", oldVoltage);
|
||||
switch (result) {
|
||||
case 24: buclnb.buc = voltage_buc::_24V; break;
|
||||
#ifdef MODEM_IS_SCPC
|
||||
case 48: buclnb.buc = voltage_buc::_48V; break;
|
||||
#endif
|
||||
case 0:
|
||||
default:
|
||||
buclnb.buc = voltage_buc::DISABLE;
|
||||
}
|
||||
}
|
||||
buclnb.is_ref_10MHz_buc = data.value("bucRefClk10M", buclnb.is_ref_10MHz_buc);
|
||||
|
||||
{
|
||||
// напряжение lnb
|
||||
int oldVoltage;
|
||||
switch (buclnb.lnb) {
|
||||
case voltage_lnb::_13V: oldVoltage = 13; break;
|
||||
case voltage_lnb::_18V: oldVoltage = 18; break;
|
||||
case voltage_lnb::_24V: oldVoltage = 24; break;
|
||||
default: oldVoltage = 0;
|
||||
}
|
||||
|
||||
auto result = data.value("lnbPowering", oldVoltage);
|
||||
switch (result) {
|
||||
case 13: buclnb.lnb = voltage_lnb::_13V; break;
|
||||
case 18: buclnb.lnb = voltage_lnb::_18V; break;
|
||||
case 24: buclnb.lnb = voltage_lnb::_24V; break;
|
||||
default: buclnb.lnb = voltage_lnb::DISABLE;
|
||||
}
|
||||
}
|
||||
|
||||
buclnb.is_ref_10MHz_lnb = data.value("lnbRefClk10M", buclnb.is_ref_10MHz_lnb);
|
||||
|
||||
buclnb.is_ref_10MHz_output = data.value("srvRefClk10M", buclnb.is_ref_10MHz_output);
|
||||
buclnb.is_save_current_state = data.value("bucLnbAutoStart", buclnb.is_save_current_state);
|
||||
}
|
||||
void api_driver::obj::TerminalRxTxSettings::storeBuclnbSettings(proxy::CpProxy &cp) {
|
||||
cp.setBuclnbSettings(buclnb);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void api_driver::obj::TerminalRxTxSettings::storeAll(proxy::CpProxy &cp) {
|
||||
storeMainSettings(cp);
|
||||
#ifdef API_OBJECT_DPDI_SETTINGS_ENABLE
|
||||
storeDpdiSettings(cp);
|
||||
#endif
|
||||
#ifdef API_OBJECT_BUCLNB_SETTINGS_ENABLE
|
||||
storeBuclnbSettings(cp);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
nlohmann::json api_driver::obj::TerminalRxTxSettings::asJson() const {
|
||||
nlohmann::json res;
|
||||
|
||||
// RX TX
|
||||
{
|
||||
auto& rxtx = res["rxtx"];
|
||||
// для модулятора
|
||||
#ifdef MODEM_IS_SCPC
|
||||
rxtx["isCinC"] = mod.is_cinc;
|
||||
#endif
|
||||
rxtx["txEn"] = mod.tx_is_on;
|
||||
#if defined(MODEM_IS_SCPC) || defined (MODEM_IS_SHPS)
|
||||
rxtx["txAutoStart"] = mod.is_save_current_state;
|
||||
rxtx["txIsTestInput"] = mod.is_test_data;
|
||||
#endif
|
||||
rxtx["txModulatorIsTest"] = !mod.is_carrier;
|
||||
rxtx["txCentralFreq"] = mod.central_freq_in_kGz;
|
||||
#if defined(MODEM_IS_SCPC) || defined (MODEM_IS_SHPS)
|
||||
rxtx["txBaudrate"] = mod.baudrate;
|
||||
rxtx["txRolloff"] = mod.rollof;
|
||||
rxtx["txGoldan"] = mod.gold_seq_is_active ? 1 : 0;
|
||||
#endif
|
||||
rxtx["txAttenuation"] = mod.attenuation;
|
||||
#ifdef MODEM_IS_SHPS
|
||||
rxtx["txSpreadCoef"] = mod.koef_spread;
|
||||
#endif
|
||||
|
||||
#if defined(MODEM_IS_SCPC) || defined(MODEM_IS_SHPS)
|
||||
const bool acmIsFrameSizeNormal = extractModcodFrameSizeNormal(mod.modcod_tx);
|
||||
const bool acmIsPilots = extractModcodIsPilots(mod.modcod_tx);
|
||||
|
||||
rxtx["txFrameSizeNormal"] = acmIsFrameSizeNormal;
|
||||
rxtx["txIsPilots"] = acmIsPilots;
|
||||
|
||||
rxtx["dvbCcmModulation"] = extractModcodModulation(mod.modcod_tx);
|
||||
rxtx["dvbCcmSpeed"] = extractModcodSpeed(mod.modcod_tx);
|
||||
#endif
|
||||
|
||||
// демодулятор
|
||||
rxtx["rxAgcEn"] = dem.is_aru_on;
|
||||
rxtx["rxManualGain"] = dem.gain;
|
||||
rxtx["rxSpectrumInversion"] = dem.is_rvt_iq;
|
||||
rxtx["rxCentralFreq"] = dem.central_freq_in_kGz;
|
||||
rxtx["rxBaudrate"] = dem.baudrate;
|
||||
rxtx["rxRolloff"] = dem.rollof;
|
||||
#if defined(MODEM_IS_SCPC) || defined (MODEM_IS_SHPS)
|
||||
rxtx["rxGoldan"] = dem.gold_seq_is_active ? 1 : 0;
|
||||
#endif
|
||||
#ifdef MODEM_IS_SHPS
|
||||
rxtx["txSpreadCoef"] = mod.koef_spread;
|
||||
rxtx["rxSpreadCoef"] = dem.koef_spread;
|
||||
#endif
|
||||
|
||||
#ifdef API_STRUCT_ACM_ENABLE
|
||||
// ACM
|
||||
#ifdef MODEM_IS_SCPC
|
||||
// эти настройки только в SCPC
|
||||
rxtx["dvbServicePacketPeriod"] = acm.period_pack_acm;
|
||||
rxtx["dvbIsAcm"] = acm.enable_acm;
|
||||
|
||||
rxtx["dvbAcmMinModulation"] = extractModcodModulation(acm.min_modcod_acm);
|
||||
rxtx["dvbAcmMinSpeed"] = extractModcodSpeed(acm.min_modcod_acm);
|
||||
|
||||
rxtx["dvbAcmMaxModulation"] = extractModcodModulation(acm.max_modcod_acm);
|
||||
rxtx["dvbAcmMaxSpeed"] = extractModcodSpeed(acm.max_modcod_acm);
|
||||
|
||||
rxtx["dvbSnrReserve"] = acm.snr_threashold_acm; // запас ОСШ
|
||||
#endif
|
||||
|
||||
rxtx["aupcEn"] = acm.enable_aupc;
|
||||
rxtx["aupcMinAttenuation"] = acm.min_attenuation_aupc;
|
||||
rxtx["aupcMaxAttenuation"] = acm.max_attenuation_aupc;
|
||||
rxtx["aupcRequiredSnr"] = acm.snr_threashold_aupc;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef API_OBJECT_DPDI_SETTINGS_ENABLE
|
||||
{
|
||||
auto& dp = res["dpdi"];
|
||||
|
||||
dp["isPositional"] = !dpdi.is_delay_window;
|
||||
#ifdef MODEM_IS_SCPC
|
||||
dp["searchBandwidth"] = dpdi.freq_offset;
|
||||
#endif
|
||||
|
||||
dp["positionStationLatitude"] = translateCoordinates(dpdi.latitude_station_grad, dpdi.latitude_station_minute);
|
||||
dp["positionStationLongitude"] = translateCoordinates(dpdi.longitude_station_grad, dpdi.longitude_station_minute);
|
||||
dp["positionSatelliteLongitude"] = translateCoordinates(dpdi.longitude_sattelite_grad, dpdi.longitude_sattelite_minute);
|
||||
|
||||
#ifdef MODEM_IS_SCPC
|
||||
dp["delayMin"] = dpdi.min_delay;
|
||||
dp["delayMax"] = dpdi.max_delay;
|
||||
#else
|
||||
dp["delay"] = dpdi.max_delay;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// BucLnb
|
||||
#ifdef API_OBJECT_BUCLNB_SETTINGS_ENABLE
|
||||
{
|
||||
auto& bl = res["buclnb"];
|
||||
switch (buclnb.buc) {
|
||||
case voltage_buc::_24V: bl["bucPowering"] = 24; break;
|
||||
#ifdef MODEM_IS_SCPC
|
||||
case voltage_buc::_48V: bl["bucPowering"] = 48; break;
|
||||
#endif
|
||||
default: bl["bucPowering"] = 0;
|
||||
}
|
||||
|
||||
bl["bucRefClk10M"] = buclnb.is_ref_10MHz_buc;
|
||||
switch (buclnb.lnb) {
|
||||
case voltage_lnb::_13V: bl["lnbPowering"] = 13; break;
|
||||
case voltage_lnb::_18V: bl["lnbPowering"] = 18; break;
|
||||
case voltage_lnb::_24V: bl["lnbPowering"] = 24; break;
|
||||
default: bl["lnbPowering"] = 0;
|
||||
}
|
||||
bl["lnbRefClk10M"] = buclnb.is_ref_10MHz_lnb;
|
||||
|
||||
bl["srvRefClk10M"] = buclnb.is_ref_10MHz_output;
|
||||
bl["bucLnbAutoStart"] = buclnb.is_save_current_state;
|
||||
}
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
api_driver::obj::TerminalRxTxSettings::~TerminalRxTxSettings() = default;
|
||||
|
||||
|
||||
|
||||
|
||||
|
256
src/api-driver/structs.h
Normal file
256
src/api-driver/structs.h
Normal file
@ -0,0 +1,256 @@
|
||||
#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{};
|
||||
bool fRxSymSyncLock{};
|
||||
bool fRxFreqSearchLock{};
|
||||
bool fRxAfcLock{};
|
||||
bool fRxPktSync{};
|
||||
|
||||
float fRxSnr{};
|
||||
float fRxRssi{};
|
||||
uint16_t fRxModcod{};
|
||||
bool fRxFrameSizeNormal{};
|
||||
bool fRxIsPilots{};
|
||||
|
||||
double fRxSymError{};
|
||||
double fRxFreqErr{};
|
||||
double fRxFreqErrAcc{};
|
||||
double fRxInputSignalLevel{};
|
||||
double fRxPllError{};
|
||||
double fRxSpeedOnRxKbit{};
|
||||
double fRxSpeedOnIifKbit{};
|
||||
uint32_t fRxPacketsOk{};
|
||||
uint32_t fRxPacketsBad{};
|
||||
uint32_t fRxPacketsDummy{};
|
||||
|
||||
uint16_t fTxModcod{};
|
||||
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();
|
||||
};
|
||||
}
|
||||
|
||||
#endif //STRUCTS_H
|
24765
src/common/nlohmann/json.hpp
Normal file
24765
src/common/nlohmann/json.hpp
Normal file
File diff suppressed because it is too large
Load Diff
338
src/main.cpp
338
src/main.cpp
@ -11,7 +11,6 @@
|
||||
#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>
|
||||
@ -21,6 +20,7 @@
|
||||
#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([](TSID sid) {
|
||||
CP_SetDmaDebug(sid, "begin_save_config", "");
|
||||
api->executeInApi([](api_driver::proxy::CpProxy& cp) {
|
||||
cp.setDmaDebug("begin_save_config", "");
|
||||
std::string cmd(UPGRADE_COMMAND);
|
||||
cmd += " ";
|
||||
cmd += FIRMWARE_LOCATION;
|
||||
system(cmd.c_str());
|
||||
CP_SetDmaDebug(sid, "save_config", "");
|
||||
cp.setDmaDebug("save_config", "");
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef MODEM_IS_TDMA
|
||||
void doTerminalUpgradeOta() const {
|
||||
api->executeInApi([&](TSID sid) {
|
||||
CP_SetDmaDebug(sid, "begin_save_config", "");
|
||||
api->executeInApi([&](auto& cp) {
|
||||
cp.setDmaDebug("begin_save_config", "");
|
||||
std::string cmd(UPGRADE_COMMAND);
|
||||
cmd += " ";
|
||||
cmd += api->getOtaFileLocation();
|
||||
system(cmd.c_str());
|
||||
CP_SetDmaDebug(sid, "save_config", "");
|
||||
cp.setDmaDebug("save_config", "");
|
||||
});
|
||||
}
|
||||
#endif
|
||||
@ -104,6 +104,8 @@ 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
|
||||
@ -177,11 +179,9 @@ public:
|
||||
rep.headers.clear();
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||
try {
|
||||
std::istringstream is(std::string(req.payload.data(), req.payload.size()));
|
||||
boost::property_tree::ptree pt;
|
||||
read_json(is, pt);
|
||||
auto reqJson = nlohmann::json::parse(std::string(req.payload.begin(), req.payload.end()));
|
||||
|
||||
auto u = auth.doAuth(pt.get<std::string>("username"), pt.get<std::string>("password"), req, rep);
|
||||
auto u = auth.doAuth(reqJson["username"], reqJson["password"], req, rep);
|
||||
if (u == nullptr) {
|
||||
throw std::runtime_error("invalid session");
|
||||
}
|
||||
@ -219,14 +219,21 @@ 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)});
|
||||
std::string result = R"({"mainState":)";
|
||||
result += api->loadTerminalState();
|
||||
result += R"(,"sysinfo":)";
|
||||
result += api->loadSysInfo();
|
||||
result += "}";
|
||||
nlohmann::json resultJson;
|
||||
|
||||
try {
|
||||
resultJson["status"] = "ok";
|
||||
resultJson["state"] = api->loadTerminalState();
|
||||
} 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());
|
||||
}));
|
||||
|
||||
@ -235,12 +242,22 @@ 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)});
|
||||
std::string result = R"({"settings":)";
|
||||
result += api->loadSettings();
|
||||
result += "}";
|
||||
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();
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
}));
|
||||
|
||||
@ -252,7 +269,20 @@ public:
|
||||
|
||||
rep.status = http::server::ok;
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||
const auto result = api->loadFirmwareVersion();
|
||||
nlohmann::json resultJson;
|
||||
|
||||
try {
|
||||
resultJson["status"] = "ok";
|
||||
resultJson["firmware"] = api->loadFirmwareVersion();
|
||||
} catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/get/aboutFirmware): Can't get object: " << e.what();
|
||||
resultJson.clear();
|
||||
rep.status = http::server::internal_server_error;
|
||||
resultJson["status"] = "error";
|
||||
resultJson["error"] = e.what();
|
||||
}
|
||||
|
||||
auto result = resultJson.dump();
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
}));
|
||||
|
||||
@ -269,6 +299,7 @@ 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);
|
||||
@ -277,26 +308,26 @@ public:
|
||||
|
||||
rep.status = http::server::ok;
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||
nlohmann::json resultJson;
|
||||
|
||||
try {
|
||||
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());
|
||||
auto reqJson = nlohmann::json::parse(std::string(req.payload.begin(), req.payload.end()));
|
||||
api->setQosSettings(reqJson);
|
||||
resultJson["status"] = "ok";
|
||||
resultJson["settings"] = api->loadSettings();
|
||||
} catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/qos): Can't set QoS settings: " << e.what();
|
||||
const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}";
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
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
|
||||
|
||||
#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) {
|
||||
if (req.method != "POST") {
|
||||
http::server::stockReply(http::server::bad_request, rep);
|
||||
@ -306,25 +337,26 @@ public:
|
||||
rep.status = http::server::ok;
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||
|
||||
nlohmann::json resultJson;
|
||||
|
||||
try {
|
||||
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());
|
||||
auto reqJson = nlohmann::json::parse(std::string(req.payload.begin(), req.payload.end()));
|
||||
api->setBucLnbSettings(reqJson);
|
||||
resultJson["status"] = "ok";
|
||||
resultJson["settings"] = api->loadSettings();
|
||||
} catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/buclnb): Can't set BUC LNB settings: " << e.what();
|
||||
const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}";
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
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
|
||||
|
||||
#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);
|
||||
@ -333,25 +365,24 @@ public:
|
||||
|
||||
rep.status = http::server::ok;
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||
nlohmann::json resultJson;
|
||||
|
||||
try {
|
||||
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());
|
||||
auto reqJson = nlohmann::json::parse(std::string(req.payload.begin(), req.payload.end()));
|
||||
api->setDpdiSettings(reqJson);
|
||||
resultJson["status"] = "ok";
|
||||
resultJson["settings"] = api->loadSettings();
|
||||
} catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/dpdi): Can't set DPDI settings: " << e.what();
|
||||
const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}";
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
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
|
||||
|
||||
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") {
|
||||
@ -361,26 +392,25 @@ public:
|
||||
|
||||
rep.status = http::server::ok;
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||
nlohmann::json resultJson;
|
||||
|
||||
try {
|
||||
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());
|
||||
auto reqJson = nlohmann::json::parse(std::string(req.payload.begin(), req.payload.end()));
|
||||
api->setRxTxSettings(reqJson);
|
||||
resultJson["status"] = "ok";
|
||||
resultJson["settings"] = api->loadSettings();
|
||||
} catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/rxtx): Can't set RX/TX settings: " << e.what();
|
||||
const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}";
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
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_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);
|
||||
@ -389,25 +419,24 @@ public:
|
||||
|
||||
rep.status = http::server::ok;
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||
nlohmann::json resultJson;
|
||||
|
||||
try {
|
||||
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());
|
||||
auto reqJson = nlohmann::json::parse(std::string(req.payload.begin(), req.payload.end()));
|
||||
api->setNetworkSettings(reqJson);
|
||||
resultJson["status"] = "ok";
|
||||
resultJson["settings"] = api->loadSettings();
|
||||
} catch (std::exception& e) {
|
||||
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/network): Can't set network settings: " << e.what();
|
||||
const std::string result = R"({"status": "error", "error": )" + api_driver::buildEscapedString(e.what()) + "}";
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
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
|
||||
|
||||
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") {
|
||||
@ -458,6 +487,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 {
|
||||
this->upgradeOrRebootRunning = true;
|
||||
#ifdef MODEM_IS_TDMA
|
||||
if (req.url->params.find("ota") != req.url->params.end()) {
|
||||
@ -468,10 +503,15 @@ public:
|
||||
#else
|
||||
doTerminalUpgrade();
|
||||
#endif
|
||||
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();
|
||||
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.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
}));
|
||||
|
||||
@ -490,59 +530,103 @@ public:
|
||||
return;
|
||||
}
|
||||
const auto func = req.url->params["f"];
|
||||
std::string result = R"({"status":"ok"})";
|
||||
rep.status = http::server::ok;
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||
nlohmann::json resultJson;
|
||||
|
||||
try {
|
||||
resultJson["status"] = "error";
|
||||
if (func == "SetDmaDebug") {
|
||||
if (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"]);
|
||||
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()) { 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 += "}";
|
||||
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 {
|
||||
http::server::stockReply(http::server::not_implemented, rep);
|
||||
return;
|
||||
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();
|
||||
}
|
||||
|
||||
rep.status = http::server::ok;
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||
auto result = resultJson.dump();
|
||||
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
|
||||
}));
|
||||
#ifdef MODEM_IS_SCPC
|
||||
#ifdef API_OBJECT_DEBUG_METRICS_ENABLE
|
||||
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/dev/settings", this->auth, http::auth::User::DEVELOPER, [this](const auto& req, auto& rep) {
|
||||
std::string result;
|
||||
rep.status = http::server::ok;
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::text_plain)});
|
||||
nlohmann::json resultJson;
|
||||
|
||||
try {
|
||||
if (req.method == "GET") {
|
||||
result = R"({"status":"ok","logstat":)";
|
||||
result += this->api->getLoggingStatisticsSettings();
|
||||
result += "}";
|
||||
resultJson["status"] = "ok";
|
||||
resultJson["logstat"] = api->getLoggingStatisticsSettings();
|
||||
} 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);
|
||||
auto reqJson = nlohmann::json::parse(std::string(req.payload.begin(), req.payload.end()));
|
||||
api->setLoggingStatisticsSettings(reqJson);
|
||||
|
||||
api->setLoggingStatisticsSettings(pt);
|
||||
|
||||
result = R"({"status":"ok","logstat":)";
|
||||
result += this->api->getLoggingStatisticsSettings();
|
||||
result += "}";
|
||||
resultJson["status"] = "ok";
|
||||
resultJson["logstat"] = api->getLoggingStatisticsSettings();
|
||||
} else {
|
||||
http::server::stockReply(http::server::bad_request, rep);
|
||||
return;
|
||||
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();
|
||||
}
|
||||
|
||||
rep.status = http::server::ok;
|
||||
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
|
||||
auto result = resultJson.dump();
|
||||
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);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,12 +1,12 @@
|
||||
#ifndef TERMINAL_API_DRIVER_H
|
||||
#define TERMINAL_API_DRIVER_H
|
||||
|
||||
#include <deque>
|
||||
#include "api-driver/stricts-enable.h"
|
||||
#include "api-driver/proxy.h"
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <terminal_api/ControlProtoCInterface.h>
|
||||
|
||||
#include "common/nlohmann/json.hpp"
|
||||
|
||||
namespace api_driver {
|
||||
constexpr int CACHE_STATISTICS_UPDATE_MS = 500; ///< время обновления кеша статистики модулятора/демодулятора
|
||||
@ -14,7 +14,6 @@ namespace api_driver {
|
||||
constexpr int CACHE_SETTINGS_UPDATE_MS = 5000;
|
||||
constexpr int CACHE_QOS_UPDATE_MS = 5000;
|
||||
|
||||
class StatisticsLogger;
|
||||
class TerminalApiDaemon;
|
||||
|
||||
/**
|
||||
@ -31,50 +30,56 @@ namespace api_driver {
|
||||
|
||||
/**
|
||||
* Запросить общее состояние терминала
|
||||
* @return {"txState":false,"rxState":false,"rx.sym_sync_lock":false,"rx.freq_search_lock":false,"rx.afc_lock":false,"rx.pkt_sync":false}
|
||||
*/
|
||||
std::string loadTerminalState() const;
|
||||
nlohmann::json loadTerminalState() const;
|
||||
|
||||
/**
|
||||
* Сбросить статистику пакетов
|
||||
*/
|
||||
void resetPacketStatistics() const;
|
||||
|
||||
std::string loadSettings() const;
|
||||
nlohmann::json loadSettings() const;
|
||||
|
||||
std::string loadFirmwareVersion() const;
|
||||
nlohmann::json loadFirmwareVersion() const;
|
||||
|
||||
/**
|
||||
* Установить настройки RX/TX, readback можно получить используя loadTerminalState
|
||||
*/
|
||||
void setRxTxSettings(boost::property_tree::ptree &pt);
|
||||
|
||||
void setRxTxSettings(const nlohmann::json& data);
|
||||
|
||||
#ifdef API_OBJECT_DPDI_SETTINGS_ENABLE
|
||||
/**
|
||||
* Установить настройки DPDI, readback можно получить используя loadTerminalState.
|
||||
* @note Для TDMA и SCPC модемов эти настройки доступны
|
||||
*/
|
||||
void setDpdiSettings(boost::property_tree::ptree &pt);
|
||||
void setDpdiSettings(const nlohmann::json& data);
|
||||
#endif
|
||||
|
||||
#ifdef API_OBJECT_BUCLNB_SETTINGS_ENABLE
|
||||
/**
|
||||
* Установить настройки BUC и LNB, readback можно получить используя loadTerminalState.
|
||||
*/
|
||||
void setBucLnbSettings(boost::property_tree::ptree &pt);
|
||||
void setBucLnbSettings(const nlohmann::json& data);
|
||||
#endif
|
||||
|
||||
#ifdef API_OBJECT_QOS_SETTINGS_ENABLE
|
||||
/**
|
||||
* Установить настройки QoS, readback можно получить используя loadTerminalState.
|
||||
*/
|
||||
void setQosSettings(boost::property_tree::ptree &pt);
|
||||
void setQosSettings(const nlohmann::json& data);
|
||||
#endif
|
||||
|
||||
void setNetworkSettings(boost::property_tree::ptree &pt);
|
||||
#ifdef API_OBJECT_NETWORK_SETTINGS_ENABLE
|
||||
void setNetworkSettings(const nlohmann::json& data);
|
||||
#endif
|
||||
|
||||
void resetDefaultSettings();
|
||||
|
||||
void executeInApi(const std::function<void(TSID sid)> &callback);
|
||||
void executeInApi(const std::function<void(proxy::CpProxy&)> &callback);
|
||||
|
||||
#ifdef MODEM_IS_SCPC
|
||||
std::string getLoggingStatisticsSettings();
|
||||
void setLoggingStatisticsSettings(boost::property_tree::ptree &pt);
|
||||
#ifdef API_OBJECT_DEBUG_METRICS_ENABLE
|
||||
nlohmann::json getLoggingStatisticsSettings();
|
||||
void setLoggingStatisticsSettings(const nlohmann::json& data);
|
||||
|
||||
/**
|
||||
* Получить статистику в формате json. Выход будет дописан в вектор
|
||||
@ -91,8 +96,6 @@ namespace api_driver {
|
||||
std::string getOtaFileLocation() const;
|
||||
#endif
|
||||
|
||||
static std::string loadSysInfo();
|
||||
|
||||
~ApiDriver();
|
||||
|
||||
private:
|
||||
|
@ -160,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:950000,max:6000000,step:0.01}), {min:950000,max:6000000,step:0.01})"/>
|
||||
<input type="text" v-model.lazy="paramRxtx.txCentralFreq" @change="e => paramRxtx.txCentralFreq = inputFormatNumber(inputFormatNumber(e.target.value, {min:100000,max:6000000,step:0.01}), {min:100000,max:6000000,step:0.01})"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Символьная скорость, Бод</span>
|
||||
@ -169,12 +169,12 @@
|
||||
<label>
|
||||
<span>Roll-off</span>
|
||||
<select v-model="paramRxtx.txRolloff">
|
||||
<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>
|
||||
<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>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
@ -295,7 +295,7 @@
|
||||
</label>
|
||||
<label>
|
||||
<span>Центральная частота, КГц</span>
|
||||
<input type="text" v-model.lazy="paramRxtx.rxCentralFreq" @change="e => paramRxtx.rxCentralFreq = inputFormatNumber(inputFormatNumber(e.target.value, {min:950000,max:6000000,step:0.01}), {min:950000,max:6000000,step:0.01})"/>
|
||||
<input type="text" v-model.lazy="paramRxtx.rxCentralFreq" @change="e => paramRxtx.rxCentralFreq = inputFormatNumber(inputFormatNumber(e.target.value, {min:100000,max:6000000,step:0.01}), {min:100000,max:6000000,step:0.01})"/>
|
||||
</label>
|
||||
<label>
|
||||
<span>Символьная скорость, Бод</span>
|
||||
@ -304,12 +304,12 @@
|
||||
<label>
|
||||
<span>Roll-off</span>
|
||||
<select v-model="paramRxtx.rxRolloff">
|
||||
<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>
|
||||
<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>
|
||||
</select>
|
||||
</label>
|
||||
<label>
|
||||
@ -489,38 +489,29 @@
|
||||
</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>Интерфейс управления (/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]?)$">
|
||||
<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.netIsL2">
|
||||
<select v-model="paramNetwork.isL2">
|
||||
<option :value="false">Маршрутизатор</option>
|
||||
<option :value="true">Коммутатор</option>
|
||||
</select>
|
||||
</label>
|
||||
<label v-show="paramNetwork.netIsL2 === false">
|
||||
<label v-show="paramNetwork.isL2 === 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]?)$">
|
||||
<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.netDataMtu" min="1500" max="2000" step="1"/></label>
|
||||
<label><span>MTU интерфейса данных</span><input type="number" v-model="paramNetwork.dataMtu" min="1500" max="2000" step="1"/></label>
|
||||
<label>
|
||||
<span>Имя веб-сервера</span>
|
||||
<input v-model="paramNetwork.netServerName" type="text">
|
||||
<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>
|
||||
@ -542,6 +533,8 @@
|
||||
<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>
|
||||
@ -595,7 +588,6 @@
|
||||
rxtx: false,
|
||||
dpdi: false,
|
||||
buclnb: false,
|
||||
tcpaccel: false,
|
||||
network: false,
|
||||
firmwareUpload: false,
|
||||
firmwareUpgrade: false,
|
||||
@ -612,7 +604,7 @@
|
||||
txIsTestInput: false,
|
||||
txCentralFreq: 0,
|
||||
txBaudrate: 0,
|
||||
txRolloff: 2,
|
||||
txRolloff: 20,
|
||||
txGoldan: 0,
|
||||
txAttenuation: -40,
|
||||
dvbServicePacketPeriod: 0,
|
||||
@ -635,7 +627,7 @@
|
||||
rxSpectrumInversion: false,
|
||||
rxCentralFreq: 0,
|
||||
rxBaudrate: 0,
|
||||
rxRolloff: 2,
|
||||
rxRolloff: 20,
|
||||
rxGoldan: 0,
|
||||
},
|
||||
paramDpdi: {
|
||||
@ -655,16 +647,12 @@
|
||||
srvRefClk10M: false,
|
||||
bucLnbAutoStart: false,
|
||||
},
|
||||
paramTcpaccel: {
|
||||
accelEn: false,
|
||||
accelMaxConnections: 0,
|
||||
},
|
||||
paramNetwork: {
|
||||
netManagementIp: null,
|
||||
netIsL2: false,
|
||||
netDataIp: null,
|
||||
netDataMtu: 1500,
|
||||
netServerName: null,
|
||||
managementIp: null,
|
||||
isL2: false,
|
||||
dataIp: null,
|
||||
dataMtu: 1500,
|
||||
serverName: null,
|
||||
},
|
||||
// ========== include end from 'common/all-params-data.js.j2'
|
||||
|
||||
@ -875,30 +863,16 @@
|
||||
.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 = {
|
||||
"netManagementIp": this.paramNetwork.netManagementIp,
|
||||
"netIsL2": this.paramNetwork.netIsL2,
|
||||
"netDataIp": this.paramNetwork.netDataIp,
|
||||
"netDataMtu": this.paramNetwork.netDataMtu,
|
||||
"netServerName": this.paramNetwork.netServerName,
|
||||
"managementIp": this.paramNetwork.managementIp,
|
||||
"isL2": this.paramNetwork.isL2,
|
||||
"dataIp": this.paramNetwork.dataIp,
|
||||
"dataMtu": this.paramNetwork.dataMtu,
|
||||
"serverName": this.paramNetwork.serverName,
|
||||
}
|
||||
|
||||
this.submitStatus.network = true
|
||||
@ -910,70 +884,65 @@
|
||||
|
||||
updateRxtxSettings(vals) {
|
||||
this.submitStatus.rxtx = false
|
||||
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.txIsPilots = vals["settings"]["txIsPilots"]
|
||||
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"]
|
||||
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"]
|
||||
},
|
||||
updateDpdiSettings(vals) {
|
||||
this.submitStatus.dpdi = false
|
||||
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"]
|
||||
this.paramDpdi.dpdiIsPositional = vals["settings"]["dpdi"]["dpdiIsPositional"]
|
||||
this.paramDpdi.dpdiSearchBandwidth = vals["settings"]["dpdi"]["dpdiSearchBandwidth"]
|
||||
this.paramDpdi.dpdiPositionStationLatitude = vals["settings"]["dpdi"]["dpdiPositionStationLatitude"]
|
||||
this.paramDpdi.dpdiPositionStationLongitude = vals["settings"]["dpdi"]["dpdiPositionStationLongitude"]
|
||||
this.paramDpdi.dpdiPositionSatelliteLongitude = vals["settings"]["dpdi"]["dpdiPositionSatelliteLongitude"]
|
||||
this.paramDpdi.dpdiDelayMin = vals["settings"]["dpdi"]["dpdiDelayMin"]
|
||||
this.paramDpdi.dpdiDelayMax = vals["settings"]["dpdi"]["dpdiDelayMax"]
|
||||
},
|
||||
updateBuclnbSettings(vals) {
|
||||
this.submitStatus.buclnb = false
|
||||
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"]
|
||||
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.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"]
|
||||
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'
|
||||
|
||||
@ -998,53 +967,52 @@
|
||||
}
|
||||
|
||||
this.lastUpdateTime = new Date();
|
||||
this.initState = vals["mainState"]["initState"]
|
||||
this.isCinC = vals["mainState"]["isCinC"]
|
||||
this.initState = vals["state"]["initState"]
|
||||
this.testState = vals["state"]["testState"]
|
||||
this.isCinC = vals["state"]["isCinC"]
|
||||
|
||||
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.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 = vals["state"]["rx"]["freqErr"]
|
||||
this.statRx.freqErrAcc = vals["state"]["rx"]["freqErrAcc"]
|
||||
this.statRx.inputSignalLevel = vals["state"]["rx"]["inputSignalLevel"]
|
||||
this.statRx.pllError = vals["state"]["rx"]["pllError"]
|
||||
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["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.statTx.state = vals["state"]["tx"]["state"]
|
||||
this.statTx.snr = vals["state"]["tx"]["snr"]
|
||||
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 = vals["state"]["tx"]["speedOnTxKbit"]
|
||||
this.statTx.speedOnIifKbit = vals["state"]["tx"]["speedOnIifKbit"]
|
||||
|
||||
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.statCinc.occ = vals["state"]["cinc"]["occ"]
|
||||
this.statCinc.correlator = vals["state"]["cinc"]["correlator"]
|
||||
this.statCinc.correlatorFails = vals["state"]["cinc"]["correlatorFails"]
|
||||
this.statCinc.freqErr = vals["state"]["cinc"]["freqErr"]
|
||||
this.statCinc.freqErrAcc = vals["state"]["cinc"]["freqErrAcc"]
|
||||
this.statCinc.channelDelay = vals["state"]["cinc"]["channelDelay"]
|
||||
|
||||
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"]
|
||||
this.statDevice.adrv = vals["state"]["device"]["adrv"]
|
||||
this.statDevice.zynq = vals["state"]["device"]["zynq"]
|
||||
this.statDevice.fpga = vals["state"]["device"]["fpga"]
|
||||
|
||||
// аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид
|
||||
let uptime = vals["sysinfo"]["uptime"]
|
||||
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)
|
||||
@ -1056,11 +1024,11 @@
|
||||
} 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"]
|
||||
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() {
|
||||
@ -1156,15 +1124,17 @@
|
||||
}
|
||||
let query = {
|
||||
"en": this.paramQos.en,
|
||||
"profile": {
|
||||
"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])) }
|
||||
}
|
||||
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', {
|
||||
@ -1185,9 +1155,9 @@
|
||||
|
||||
updateQosSettings(vals) {
|
||||
this.submitStatusQos = false
|
||||
this.paramQos.en = vals["settings"]["qosEnabled"]
|
||||
this.paramQos.en = vals["settings"]["qos"]["en"]
|
||||
|
||||
const qosProfile = vals["settings"]["qosProfile"]
|
||||
const qosProfile = vals["settings"]["qos"]["profile"]
|
||||
if (qosProfile !== null && qosProfile !== undefined) {
|
||||
this.paramQos.rt1 = [] // .splice(0, this.paramQos.rt1.length)
|
||||
this.paramQos.rt2 = [] // .splice(0, this.paramQos.rt2.length)
|
||||
@ -1395,6 +1365,133 @@
|
||||
}
|
||||
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'
|
||||
|
||||
|
||||
@ -1406,7 +1503,6 @@
|
||||
this.updateRxtxSettings(vals)
|
||||
this.updateDpdiSettings(vals)
|
||||
this.updateBuclnbSettings(vals)
|
||||
this.updateTcpaccelSettings(vals)
|
||||
this.updateNetworkSettings(vals)
|
||||
this.updateQosSettings(vals)
|
||||
|
||||
@ -1443,11 +1539,11 @@
|
||||
try {
|
||||
const fr = await fetch("/api/get/aboutFirmware")
|
||||
const d = await fr.json()
|
||||
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"]
|
||||
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)
|
||||
}
|
||||
|
954
static/main-shps.html
Normal file
954
static/main-shps.html
Normal file
@ -0,0 +1,954 @@
|
||||
<!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>Захват символьной</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>
|
||||
</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>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>
|
||||
</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>
|
||||
<select v-model="paramRxtx.txIsTestInput">
|
||||
<option :value="false">Ethernet</option>
|
||||
<option :value="true">Тест</option>
|
||||
</select>
|
||||
</label>
|
||||
<h3>Параметры передачи</h3>
|
||||
<label><span>Центральная частота, КГц</span><input type="number" v-model="paramRxtx.txCentralFreq" min="100000" max="6000000" step="0.01"/></label>
|
||||
<label><span>Символьная скорость, Бод</span><input type="number" v-model="paramRxtx.txBaudrate" min="200000" max="54000000"/></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>
|
||||
</select>
|
||||
</label>
|
||||
<label><span>Коэф. расширения</span><input type="number" v-model="paramRxtx.txSpreadCoef" min="-1000" max="1000" step="0.01"/></label>
|
||||
<label><span>Ослабление, дБ</span><input type="number" v-model="paramRxtx.txAttenuation" min="-40" step="0.25"/></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="10" 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="number" v-model="paramRxtx.rxCentralFreq" min="100000" max="6000000" step="0.01"/></label>
|
||||
<label><span>Символьная скорость, Бод</span><input type="number" v-model="paramRxtx.rxBaudrate" min="200000" max="54000000"/></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>
|
||||
</select>
|
||||
</label>
|
||||
<label><span>Коэф. расширения</span><input type="number" v-model="paramRxtx.rxSpreadCoef" min="-1000" max="1000" step="0.01"/></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,
|
||||
txIsTestInput: false,
|
||||
txCentralFreq: 100000,
|
||||
txBaudrate: 200000,
|
||||
txRolloff: 20,
|
||||
txSpreadCoef: -1000,
|
||||
txAttenuation: -40,
|
||||
aupcEn: false,
|
||||
aupcMinAttenuation: 0,
|
||||
aupcMaxAttenuation: 0,
|
||||
aupcRequiredSnr: 0,
|
||||
rxAgcEn: false,
|
||||
rxManualGain: -40,
|
||||
rxSpectrumInversion: false,
|
||||
rxCentralFreq: 100000,
|
||||
rxBaudrate: 200000,
|
||||
rxRolloff: 20,
|
||||
rxSpreadCoef: -1000,
|
||||
},
|
||||
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,
|
||||
"txIsTestInput": this.paramRxtx.txIsTestInput,
|
||||
"txCentralFreq": this.paramRxtx.txCentralFreq,
|
||||
"txBaudrate": this.paramRxtx.txBaudrate,
|
||||
"txRolloff": this.paramRxtx.txRolloff,
|
||||
"txSpreadCoef": this.paramRxtx.txSpreadCoef,
|
||||
"txAttenuation": this.paramRxtx.txAttenuation,
|
||||
"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": this.paramRxtx.rxCentralFreq,
|
||||
"rxBaudrate": this.paramRxtx.rxBaudrate,
|
||||
"rxRolloff": this.paramRxtx.rxRolloff,
|
||||
"rxSpreadCoef": this.paramRxtx.rxSpreadCoef,
|
||||
}
|
||||
|
||||
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.txIsTestInput = vals["settings"]["rxtx"]["txIsTestInput"]
|
||||
this.paramRxtx.txCentralFreq = vals["settings"]["rxtx"]["txCentralFreq"]
|
||||
this.paramRxtx.txBaudrate = vals["settings"]["rxtx"]["txBaudrate"]
|
||||
this.paramRxtx.txRolloff = vals["settings"]["rxtx"]["txRolloff"]
|
||||
this.paramRxtx.txSpreadCoef = vals["settings"]["rxtx"]["txSpreadCoef"]
|
||||
this.paramRxtx.txAttenuation = vals["settings"]["rxtx"]["txAttenuation"]
|
||||
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 = vals["settings"]["rxtx"]["rxCentralFreq"]
|
||||
this.paramRxtx.rxBaudrate = vals["settings"]["rxtx"]["rxBaudrate"]
|
||||
this.paramRxtx.rxRolloff = vals["settings"]["rxtx"]["rxRolloff"]
|
||||
this.paramRxtx.rxSpreadCoef = vals["settings"]["rxtx"]["rxSpreadCoef"]
|
||||
},
|
||||
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 = vals["state"]["rx"]["freqErr"]
|
||||
this.statRx.freqErrAcc = vals["state"]["rx"]["freqErrAcc"]
|
||||
this.statRx.inputSignalLevel = vals["state"]["rx"]["inputSignalLevel"]
|
||||
this.statRx.pllError = vals["state"]["rx"]["pllError"]
|
||||
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>
|
@ -158,12 +158,12 @@
|
||||
<label>
|
||||
<span>Roll-off</span>
|
||||
<select v-model="paramRxtx.rxRolloff">
|
||||
<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>
|
||||
<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>
|
||||
</select>
|
||||
</label>
|
||||
</div>
|
||||
@ -235,16 +235,16 @@
|
||||
<div class="settings-set-container">
|
||||
<label>
|
||||
<span>Пароль для входа в сеть ЦЗС</span>
|
||||
<input v-model="paramNetwork.netCesPassword" type="text">
|
||||
<input v-model="paramNetwork.cesPassword" type="text">
|
||||
</label>
|
||||
<h3>Настройки интерфейса управления</h3>
|
||||
<label>
|
||||
<span>IP Интерфейса управления (/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]?)$">
|
||||
<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>
|
||||
<input v-model="paramNetwork.netServerName" type="text">
|
||||
<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>
|
||||
@ -266,6 +266,8 @@
|
||||
<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>
|
||||
@ -340,7 +342,7 @@
|
||||
rxSpectrumInversion: false,
|
||||
rxCentralFreq: 0,
|
||||
rxBaudrate: 0,
|
||||
rxRolloff: 2,
|
||||
rxRolloff: 20,
|
||||
},
|
||||
paramBuclnb: {
|
||||
bucRefClk10M: false,
|
||||
@ -358,9 +360,9 @@
|
||||
dpdiDelay: 0,
|
||||
},
|
||||
paramNetwork: {
|
||||
netCesPassword: null,
|
||||
netManagementIp: null,
|
||||
netServerName: null,
|
||||
cesPassword: null,
|
||||
managementIp: null,
|
||||
serverName: null,
|
||||
},
|
||||
// ========== include end from 'common/all-params-data.js.j2'
|
||||
|
||||
@ -537,9 +539,9 @@
|
||||
{ if (!confirm("Применение этих настроек может сделать модем недоступным! Продолжить?")) return }
|
||||
|
||||
let query = {
|
||||
"netCesPassword": this.paramNetwork.netCesPassword,
|
||||
"netManagementIp": this.paramNetwork.netManagementIp,
|
||||
"netServerName": this.paramNetwork.netServerName,
|
||||
"cesPassword": this.paramNetwork.cesPassword,
|
||||
"managementIp": this.paramNetwork.managementIp,
|
||||
"serverName": this.paramNetwork.serverName,
|
||||
}
|
||||
|
||||
this.submitStatus.network = true
|
||||
@ -551,39 +553,39 @@
|
||||
|
||||
updateRxtxSettings(vals) {
|
||||
this.submitStatus.rxtx = false
|
||||
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"]
|
||||
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.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"]
|
||||
},
|
||||
updateBuclnbSettings(vals) {
|
||||
this.submitStatus.buclnb = false
|
||||
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"]
|
||||
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"]
|
||||
},
|
||||
updateDpdiSettings(vals) {
|
||||
this.submitStatus.dpdi = false
|
||||
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"]
|
||||
this.paramDpdi.dpdiIsPositional = vals["settings"]["dpdi"]["dpdiIsPositional"]
|
||||
this.paramDpdi.dpdiPositionStationLatitude = vals["settings"]["dpdi"]["dpdiPositionStationLatitude"]
|
||||
this.paramDpdi.dpdiPositionStationLongitude = vals["settings"]["dpdi"]["dpdiPositionStationLongitude"]
|
||||
this.paramDpdi.dpdiPositionSatelliteLongitude = vals["settings"]["dpdi"]["dpdiPositionSatelliteLongitude"]
|
||||
this.paramDpdi.dpdiDelay = vals["settings"]["dpdi"]["dpdiDelay"]
|
||||
},
|
||||
updateNetworkSettings(vals) {
|
||||
this.submitStatus.network = false
|
||||
this.paramNetwork.netCesPassword = vals["settings"]["netCesPassword"]
|
||||
this.paramNetwork.netManagementIp = vals["settings"]["netManagementIp"]
|
||||
this.paramNetwork.netServerName = vals["settings"]["netServerName"]
|
||||
this.paramNetwork.cesPassword = vals["settings"]["network"]["cesPassword"]
|
||||
this.paramNetwork.managementIp = vals["settings"]["network"]["managementIp"]
|
||||
this.paramNetwork.serverName = vals["settings"]["network"]["serverName"]
|
||||
},
|
||||
// ========== include end from 'common/all-params-methods.js.j2'
|
||||
|
||||
@ -608,47 +610,46 @@
|
||||
}
|
||||
|
||||
this.lastUpdateTime = new Date();
|
||||
this.initState = vals["mainState"]["initState"]
|
||||
this.initState = vals["state"]["initState"]
|
||||
this.testState = vals["state"]["testState"]
|
||||
|
||||
this.statRx.state = vals["mainState"]["rx.state"]
|
||||
this.statRx.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.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 = vals["state"]["rx"]["freqErr"]
|
||||
this.statRx.freqErrAcc = vals["state"]["rx"]["freqErrAcc"]
|
||||
this.statRx.inputSignalLevel = vals["state"]["rx"]["inputSignalLevel"]
|
||||
this.statRx.pllError = vals["state"]["rx"]["pllError"]
|
||||
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["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.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["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"]
|
||||
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"]
|
||||
|
||||
// аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид
|
||||
let uptime = vals["sysinfo"]["uptime"]
|
||||
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)
|
||||
@ -660,11 +661,11 @@
|
||||
} 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"]
|
||||
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() {
|
||||
@ -753,6 +754,133 @@
|
||||
}
|
||||
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'
|
||||
|
||||
|
||||
@ -799,11 +927,11 @@
|
||||
try {
|
||||
const fr = await fetch("/api/get/aboutFirmware")
|
||||
const d = await fr.json()
|
||||
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"]
|
||||
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)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user