Compare commits

..

11 Commits

Author SHA1 Message Date
e313027759 патч для работающей настройки "Последовательность Голда" 2025-01-15 17:27:51 +03:00
136d8dbb5b Merge branch 'refs/heads/dev-front-generator'
# Conflicts:
#	src/terminal_api_driver.cpp
#	static/main-scpc.html
2025-01-15 17:21:31 +03:00
456faedf7d косметические изменения 2025-01-15 17:11:49 +03:00
2c9d513613 добавил установку всех параметров 2025-01-15 17:11:38 +03:00
46497bfda0 работает получение параметров от бекенда (проверено SCPC и TDMA) 2025-01-15 12:00:29 +03:00
0982544c2e больше данных о системе в состоянии устройства (load average + RAM total/free) 2025-01-15 10:12:30 +03:00
5a94f9a4fd генератор фронта завершен 2025-01-14 17:42:38 +03:00
25a3b11ba8 рабочая генерация всех полей на вкладке настроек и Qos, осталось администрирование 2025-01-14 14:42:16 +03:00
bf2d374705 работающая генерация базовых полей (числа, select, checkbox) + законченные настройки для TDMA 2025-01-13 18:34:19 +03:00
a7242c186d работающая генерация настроек 2025-01-10 18:10:14 +03:00
44aec3a114 миграция на vue.js 2.7->3.5; рабочий front-generator (только для мониторинга и QoS) 2025-01-10 14:28:53 +03:00
27 changed files with 20911 additions and 15915 deletions

4
.gitignore vendored
View File

@ -5,3 +5,7 @@ cert.pem
key.pem key.pem
dh.pem dh.pem
/web-action /web-action
# эти файлы после генерации должны быть перемещены в `/static`
front-generator/main-scpc.html
front-generator/main-tdma.html

View File

@ -1,74 +1,336 @@
{ {
"monitoring-params": {},
"params": {
"rxtx": {
"rx.en": {
"model": "w:switch",
"label": "Включить передатчик"
},
"rx.isTestInputData": {
"model": "w:select",
"label": "Включить передатчик",
"items": [
{"value": "false", "label": "Ethernet"},
{"value": "true", "label": "Тест (CW)"}
]
},
"rx.freqKhz": {
"model": "w:number",
"number.type": "int",
"number.step": 1,
"number.min": 500000,
"number.max": 15000000
}
}
},
"modem_types": { "modem_types": {
"tdma": { "tdma": {
"modem_name": "RCSM-101 TDMA", "modem_name": "RCSM-101 TDMA",
"groupsList": ["rxtx"], "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": "select", "label": "Входные данные", "name": "txIsTestInput",
"values": [
{"label": "SCPC", "value": "false"},
{"label": "Тест", "value": "true"}
]
},
{"widget": "number", "label": "Центральная частота, КГц", "name": "txCentralFreq", "min": 900000, "step": 0.01, "v_show": "paramRxrx.txIsTestInput"},
{"widget": "number", "label": "Символьная скорость, Бод", "name": "txBaudrate", "min": 0, "step": 1, "v_show": "paramRxrx.txIsTestInput"},
{"widget": "number", "label": "Ослабление, дБ", "name": "txAttenuation", "min": 0, "step": 1}
]
},
{
"widget": "settings-container",
"childs": [
{ "widget": "h3", "label": "Настройки приемника" },
{
"widget": "select", "label": "Режим управления усилением", "name": "rxAgcEn",
"values": [
{"label": "АРУ", "value": "true"},
{"label": "РРУ", "value": "false"}
]
},
{"widget": "number", "label": "Ручное усиление, дБ", "name": "rxManualGain", "v_show": "!paramRxtx.rxAgcEn", "min": -40},
{"widget": "checkbox", "label": "Инверсия спектра", "name": "rxSpectrumInversion"},
{"widget": "number", "label": "Центральная частота, КГц", "name": "rxCentralFreq", "min": 900000, "step": 0.01},
{"widget": "number", "label": "Символьная скорость, Бод", "name": "rxBaudrate", "min": 0, "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"}]
}
]
}
]
}
],
"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"}
]
}
]
},
{
"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", "label": "Интерфейс управления (/24)", "name": "netManagementIp"},
{
"widget": "select", "label": "Режим сети", "name": "netIsL2",
"values": [{"label": "Маршрутизатор", "value": "false"}, {"label": "Коммутатор", "value": "true"}]
},
{"widget": "ip-address", "label": "Интерфейс данных (/24)", "name": "netDataIp", "v_show": "paramNetwork.netIsL2 === false"},
{"widget": "number", "label": "MTU интерфейса данных", "name": "netDataMtu", "min": 1500, "step": 1, "max": 2000}
]
}
]
},
"tabs": [ "tabs": [
{ {"name": "monitoring", "desc": "Мониторинг"},
"name": "monitoring", {"name": "setup", "desc": "Настройки"},
"desc": "Мониторинг" {"name": "admin", "desc": "Администрирование"}
},
{
"name": "setup",
"desc": "Настройки",
"widgets": [
{"group": "html", "name": "h3", "payload": "Настройки передатчика"},
{"group": "rxtx", "name": "rx.en"},
{"group": "rxtx", "name": "rx.isTestInputData"},
{"group": "html", "name": "h3", "payload": "Параметры передачи"},
{"group": "rxtx", "name": "rx.freqKhz"}
]
},
{
"name": "admin",
"desc": "Администрирование"
}
] ]
}, },
"scpc": { "scpc": {
"modem_name": "RCSM-101", "modem_name": "RCSM-101",
"groupsList": ["rxtx"], "dangerousParamGroups": {
"buclnb": "Применение неправильных настроек может вывести из строя оборудование! Продолжить?",
"network": "Применение этих настроек может сделать модем недоступным! Продолжить?"
},
"params": {
"rxtx": [
{"widget": "h2", "label": "Настройки приема/передачи"},
{
"widget": "settings-container",
"childs": [
{
"widget": "select", "label": "Режим работы", "name": "isCinC",
"values": [{"label": "SCPC", "value": "false"}, {"label": "CinC", "value": "true"}]
}
]
},
{
"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": "SCPC", "value": "false"}, {"label": "Тест", "value": "true"}]
},
{"widget": "h3", "label": "Параметры передачи"},
{"widget": "number", "label": "Центральная частота, КГц", "name": "txCentralFreq", "min": 900000, "step": 0.01},
{"widget": "number", "label": "Символьная скорость, Бод", "name": "txBaudrate", "min": 0, "step": 1},
{
"widget": "select", "label": "Roll-off", "name": "txRolloff",
"values": [{"label": "0.02", "value": "2"}, {"label": "0.05", "value": "5"}, {"label": "0.10", "value": "10"}, {"label": "0.15", "value": "15"}, {"label": "0.20", "value": "20"}, {"label": "0.25", "value": "25"}]
},
{
"widget": "select", "label": "Номер последовательности Голда", "name": "txGoldan",
"values": [{"label": "0", "value": "0"}, {"label": "1", "value": "1"}]
},
{"widget": "number", "label": "Ослабление, дБ", "name": "txAttenuation", "min": 0, "step": 1}
]
},
{
"widget": "settings-container",
"childs": [
{"widget": "h3", "label": "Режим работы DVB-S2"},
{"widget": "number", "label": "Период служебных пакетов, сек", "name": "dvbServicePacketPeriod", "min": 0, "step": 1, "max": 60},
{
"widget": "select", "label": "Режим модуляции", "name": "dvbIsAcm",
"values": [{"label": "CCM", "value": "false"}, {"label": "ACM", "value": "true"}]
},
{
"widget": "select", "label": "Размер кадра", "name": "txFrameSizeNormal",
"values": [{"label": "normal", "value": "true"}, {"label": "short", "value": "false"}]
},
{"widget": "modulation-modcod", "label": "Модуляция", "name": "dvbCcm", "v_show": "paramRxtx.dvbIsAcm === false"},
{"widget": "modulation-speed", "label": "Скорость кода", "name": "dvbCcm", "v_show": "paramRxtx.dvbIsAcm === false"},
{"widget": "watch", "label": "Текущий модкод", "model": "statRx.modcod", "v_show": "paramRxtx.dvbIsAcm === true"},
{"widget": "modulation-modcod", "label": "Модуляция (мин. режим)", "name": "dvbAcmMin", "v_show": "paramRxtx.dvbIsAcm === true"},
{"widget": "modulation-speed", "label": "Скорость кода (мин. режим)", "name": "dvbAcmMin", "v_show": "paramRxtx.dvbIsAcm === true"},
{"widget": "modulation-modcod", "label": "Модуляция (макс. режим)", "name": "dvbAcmMax", "v_show": "paramRxtx.dvbIsAcm === true"},
{"widget": "modulation-speed", "label": "Скорость кода (макс. режим)", "name": "dvbAcmMax", "v_show": "paramRxtx.dvbIsAcm === true"},
{"widget": "number", "label": "Запас ОСШ, дБ", "name": "dvbSnrReserve", "min": 0, "step": 0.01, "max": 10}
]
},
{
"widget": "settings-container",
"childs": [
{"widget": "h3", "label": "Авто-регулировка мощности"},
{"widget": "checkbox", "label": "Авто-регулировка мощности", "name": "aupcEn"},
{"widget": "number", "label": "Минимальное ослабление, дБ", "name": "aupcMinAttenuation", "min": 0, "step": 0.01, "max": 10},
{"widget": "number", "label": "Максимальное ослабление, дБ", "name": "aupcMaxAttenuation", "min": 0, "step": 0.01, "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": "checkbox", "label": "Инверсия спектра", "name": "rxSpectrumInversion"},
{"widget": "number", "label": "Центральная частота, КГц", "name": "rxCentralFreq", "min": 900000, "step": 0.01},
{"widget": "number", "label": "Символьная скорость, Бод", "name": "rxBaudrate", "min": 0, "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"}]
},
{
"widget": "select", "label": "Номер последовательности Голда", "name": "rxGoldan",
"values": [{"label": "0", "value": "0"}, {"label": "1", "value": "1"}]
}
]
}
]
}
],
"cinc": [
{"widget": "h2", "label": "Настройки режима CinC", "v_show": "paramRxtx.isCinC"},
{
"widget": "settings-container", "v_show": "paramRxtx.isCinC",
"childs": [
{
"widget": "select", "label": "Метод расчета задержки", "name": "cincIsPositional",
"values": [
{"label": "Позиционированием", "value": "true"},
{"label": "Окном задержки", "value": "false"}
]
},
{"widget": "number", "label": "Полоса поиска, КГц ±", "name": "cincSearchBandwidth", "min": 0, "step": 1, "max": 100},
{"widget": "h2", "label": "Настройки позиционирования", "v_show": "paramCinc.cincIsPositional === true"},
{"widget": "number", "label": "Широта станции", "name": "cincPositionStationLatitude", "v_show": "paramCinc.cincIsPositional === true", "min": -180, "step": 0.000001, "max": 180},
{"widget": "number", "label": "Долгота станции", "name": "cincPositionStationLongitude", "v_show": "paramCinc.cincIsPositional === true", "min": -180, "step": 0.000001, "max": 180},
{"widget": "number", "label": "Подспутниковая точка", "name": "cincPositionSatelliteLongitude", "v_show": "paramCinc.cincIsPositional === true", "min": -180, "step": 0.000001, "max": 180},
{"widget": "h2", "label": "Задержка до спутника", "v_show": "paramCinc.cincIsPositional === false"},
{"widget": "number", "label": "от, мс", "name": "cincDelayMin", "v_show": "paramCinc.cincIsPositional === false", "min": 0, "step": 0.1, "max": 400},
{"widget": "number", "label": "до, мс", "name": "cincDelayMax", "v_show": "paramCinc.cincIsPositional === false", "min": 0, "step": 0.1, "max": 400}]
},
{"widget": "submit", "v_show": "paramRxtx.isCinC"}
],
"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"}
]
}
]
}
],
"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": "select", "label": "Режим сети", "name": "netIsL2",
"values": [{"label": "Маршрутизатор", "value": "false"}, {"label": "Коммутатор", "value": "true"}]
},
{"widget": "ip-address", "label": "Интерфейс данных (/24)", "name": "netDataIp", "v_show": "paramNetwork.netIsL2 === false"},
{"widget": "number", "label": "MTU интерфейса данных", "name": "netDataMtu", "min": 1500, "step": 1, "max": 2000}
]
}
]
},
"tabs": [ "tabs": [
{ {"name": "monitoring", "desc": "Мониторинг"},
"name": "monitoring", {"name": "setup", "desc": "Настройки"},
"desc": "Мониторинг" {"name": "qos", "desc": "QoS"},
}, {"name": "admin", "desc": "Администрирование"}
{
"name": "setup",
"desc": "Настройки"
},
{
"name": "qos",
"desc": "QoS"
},
{
"name": "admin",
"desc": "Администрирование"
}
] ]
} }
} }

View File

@ -1,22 +1,90 @@
import json import json
from jinja2 import Environment, FileSystemLoader from jinja2 import Environment, FileSystemLoader
import sys import sys
import os
with open('render-params.json') as f:
GLOBAL_CONFIG = json.load(f)
def extract_param_names(mc):
result = []
def helper_extract(widget):
if 'childs' in widget:
r = []
for child in widget['childs']:
r += helper_extract(child)
return r
elif 'name' in widget:
match widget['widget']:
case 'select': return [{"name": widget['name'], "initValue": widget['values'][0]['value']}]
case 'checkbox': return [{"name": widget['name'], "initValue": 'false'}]
case 'number': return [{"name": widget['name'], "initValue": widget['min'] if widget['min'] else '0'}]
case 'modulation-modcod': return [{"name": widget['name'] + "Modulation", "initValue": '"QPSK"'}]
case 'modulation-speed': return [{"name": widget['name'] + "Speed", "initValue": '"1/4"'}]
case 'watch': return []
return [{"name": widget['name'], "initValue": 'null'}]
return []
for cat in mc['params']:
ws = []
for w in mc['params'][cat]:
ws += helper_extract(w)
# ws.sort(key=lambda k: k['name'])
result.append({
"group": cat,
"params": ws
})
return result
def add_submit_widgets(params):
def find_submit(w):
if w['widget'] == 'submit':
return True
if 'childs' in w:
for c in w['childs']:
if find_submit(c):
return True
return False
for group in params:
wid_found = False
for wid in params[group]:
if find_submit(wid):
wid_found = True
break
if wid_found:
continue
params[group].append({"widget": "submit"})
def extract_param_groups(mc):
return [k for k in mc['params']]
def build_modem_env(modem): def build_modem_env(modem):
with open('render-params.json') as f: if modem not in GLOBAL_CONFIG['modem_types']:
config = json.load(f)
if modem not in config['modem_types']:
raise RuntimeError(f"Modem '{modem}' is not exist in config!") raise RuntimeError(f"Modem '{modem}' is not exist in config!")
mc = config['modem_types'][modem] mc = GLOBAL_CONFIG['modem_types'][modem]
add_submit_widgets(mc['params'])
return { return {
"modem": modem,
"modem_name": mc['modem_name'], "modem_name": mc['modem_name'],
"header_tabs": mc['tabs'], "header_tabs": mc['tabs'],
"js_tabs_array": str([t['name'] for t in mc['tabs']]), "tab_names_array": [t['name'] for t in mc['tabs']],
"params": {"groupsList": mc["groupsList"]} | config["params"] "params": mc["params"],
"dangerousParamGroups": mc["dangerousParamGroups"] if 'dangerousParamGroups' in mc else {},
"paramGroups": extract_param_names(mc),
"paramGroupsList": extract_param_groups(mc),
} }
@ -32,8 +100,8 @@ def render_modem(modem):
if __name__ == '__main__': if __name__ == '__main__':
if len(sys.argv) != 2: for mt in GLOBAL_CONFIG['modem_types']:
print(f"Usage: {sys.argv[0]} <scpc|tdma>") print(f'Generating {mt} modem...')
render_modem(mt)
render_modem(sys.argv[1]) os.system(f'cp -u main-{mt}.html ../static')

View File

@ -0,0 +1,62 @@
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) => {})
},

View File

@ -0,0 +1,34 @@
{% from 'common/widgets.j2' import build_widget %}
<div class="tabs-body-item" v-if="activeTab === 'admin' && settingFetchComplete">
{% if 'network' in params %}
{% for w in params['network'] %}{{ build_widget('network', w) | indent(12, true) }}{% endfor %}
{% endif %}
{% raw %}
<h2>Система</h2>
<div class="settings-set-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>
<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>{% endraw %}
</div>

View File

@ -0,0 +1,7 @@
{% for g in paramGroups %}
param{{ g['group'] | title }}: {
{% for p in g['params'] %}
{{ p['name'] }}: {{ p['initValue'] }},
{% endfor %}
},
{% endfor %}

View File

@ -0,0 +1,29 @@
{% for g in paramGroups %}
settingsSubmit{{ g['group'] | title }}() {
if (this.submitStatus.{{ g['group'] }}) { return }
{% if g['group'] in dangerousParamGroups %}
{ if (!confirm("{{ dangerousParamGroups[g['group']] }}")) return }
{% endif %}
let query = {
{% for p in g['params'] %}
"{{ p['name'] }}": this.param{{ g['group'] | title }}.{{ p['name'] }},
{% endfor %}
}
this.submitStatus.{{ g['group'] }} = true
fetch('/api/set/{{ g["group"] }}', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(query) })
.then(async (resp) => { this.update{{ g['group'] | title }}Settings(await resp.json()) })
.catch((reason) => { alert(`Ошибка при применении настроек: ${reason}`) })
.finally(() => { this.submitStatus.{{ g['group'] }} = false })
},
{% endfor %}
{% for g in paramGroups %}
update{{ g['group'] | title }}Settings(vals) {
this.submitStatus.{{ g['group'] }} = false
{% for p in g['params'] %}
this.param{{ g['group'] | title }}.{{ p['name'] }} = vals["settings"]["{{ p['name'] }}"]
{% endfor %}
},
{% endfor %}

View File

@ -0,0 +1,47 @@
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: '?',
// прочие поля
{% if modem == 'scpc' %}
snr: '?', modcod: '?', frameSizeNormal: '?', isPilots: '?', speedOnTxKbit: '?', speedOnIifKbit: '?',
{% else %}
modcod: '?', speedOnTxKbit: '?', speedOnIifKbit: '?', centerFreq: '?', symSpeed: '?',
{% endif %}
},
{% if modem == 'scpc' %}
statCinc: {
occ: '?',
correlator: null,
correlatorFails: '?',
freqErr: '?', freqErrAcc: '?',
channelDelay: '?'
},
{% endif %}
statDevice: { // температурные датчики
adrv: 0, zynq: 0, fpga: 0
},
statOs: {uptime: '?', load1: '?', load5: '?', load15: '?', totalram: '?', freeram: '?'},

View File

@ -0,0 +1,102 @@
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" || modcod < 0 || modcod >= modcod.length) {
return "?";
}
return modcods[modcod]
}
this.lastUpdateTime = new Date();
this.initState = vals["mainState"]["initState"]
{% if modem == 'scpc' %}
this.isCinC = vals["mainState"]["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"]
{% if modem == 'scpc' %}
this.statTx.state = vals["mainState"]["tx.state"]
this.statTx.snr = vals["mainState"]["tx.snr"]
this.statTx.modcod = modcodToStr(vals["mainState"]["tx.modcod"])
this.statTx.frameSizeNormal = vals["mainState"]["tx.frameSizeNormal"]
this.statTx.isPilots = vals["mainState"]["tx.isPilots"]
this.statTx.speedOnTxKbit = vals["mainState"]["tx.speedOnTxKbit"]
this.statTx.speedOnIifKbit = vals["mainState"]["tx.speedOnIifKbit"]
this.statCinc.occ = vals["mainState"]["cinc.occ"]
this.statCinc.correlator = vals["mainState"]["cinc.correlator"]
this.statCinc.correlatorFails = vals["mainState"]["cinc.correlatorFails"]
this.statCinc.freqErr = vals["mainState"]["cinc.freqErr"]
this.statCinc.freqErrAcc = vals["mainState"]["cinc.freqErrAcc"]
this.statCinc.channelDelay = vals["mainState"]["cinc.channelDelay"]
{% else %}
this.statTx.state = vals["mainState"]["tx.state"]
this.statTx.modcod = modcodToStr(vals["mainState"]["tx.modcod"])
this.statTx.speedOnTxKbit = vals["mainState"]["tx.speedOnTxKbit"]
this.statTx.speedOnIifKbit = vals["mainState"]["tx.speedOnIifKbit"]
this.statTx.centerFreq = vals["mainState"]["tx.centerFreq"]
this.statTx.symSpeed = vals["mainState"]["tx.symSpeed"]
{% endif %}
this.statDevice.adrv = vals["mainState"]["device.adrv"]
this.statDevice.zynq = vals["mainState"]["device.zynq"]
this.statDevice.fpga = vals["mainState"]["device.fpga"]
this.testState = vals["mainState"]["testState"]
// аптайм приходит в секундах, надо преобразовать его в человеко-читаемый вид
let uptime = vals["sysinfo"]["uptime"]
if (uptime) {
let secs = uptime % 60; uptime = Math.floor(uptime / 60)
let mins = uptime % 60; uptime = Math.floor(uptime / 60)
let hours = uptime % 24
uptime = Math.floor( uptime / 24)
let res = `${hours}:${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`
if (uptime > 0) { res = `${uptime} days, ` + res }
this.statOs.uptime = res
} else {
this.statOs.uptime = '?'
}
this.statOs.load1 = vals["sysinfo"]["load1min"]
this.statOs.load5 = vals["sysinfo"]["load5min"]
this.statOs.load15 = vals["sysinfo"]["load15min"]
this.statOs.totalram = vals["sysinfo"]["totalram"]
this.statOs.freeram = vals["sysinfo"]["freeram"]
},
resetPacketsStatistics() {
fetch('/api/resetPacketStatistics', {
method: 'POST'
}).then(() => {
this.statRx.packetsOk = 0
this.statRx.packetsBad = 0
this.statRx.packetsDummy = 0
})
},

View File

@ -0,0 +1,84 @@
{% raw %}
<div class="tabs-body-item tabs-item-flex-container" v-if="activeTab === 'monitoring'">
<div class="settings-set-container">
<h2>Статистика приема</h2>
<table>
<tbody>
<tr><th>Прием</th><td><span :class="{ indicator_bad: statRx.state === false, indicator_good: statRx.state === true, indicator: true }"></span></td></tr>
<tr><th>Захват символьной</th><td><span :class="{ indicator_bad: statRx.sym_sync_lock === false, indicator_good: statRx.sym_sync_lock === true, indicator: true }"></span></td></tr>
<tr><th>Захват ФАПЧ</th><td><span :class="{ indicator_bad: statRx.afc_lock === false, indicator_good: statRx.afc_lock === true, indicator: true }"></span></td></tr>
<tr><th>Захват поиска по частоте</th><td><span :class="{ indicator_bad: statRx.freq_search_lock === false, indicator_good: statRx.freq_search_lock === true, indicator: true }"></span></td></tr>
<tr><th>Захват пакетной синхр.</th><td><span :class="{ indicator_bad: statRx.pkt_sync === false, indicator_good: statRx.pkt_sync === true, indicator: true }"></span></td></tr>
<tr><th>SNR/RSSI</th><td>{{ statRx.snr }} / {{ statRx.rssi }}</td></tr>
<tr><th>Modcod</th><td>{{ statRx.modcod }}</td></tr>
<tr><th>Размер кадра</th><td>{{ statRx.frameSizeNormal ? 'normal' : 'short' }}</td></tr>
<tr><th>Пилот-символы</th><td>{{ statRx.isPilots ? 'pilots' : 'no pilots' }}</td></tr>
<tr><th>Символьная ошибка</th><td>{{ statRx.symError }}</td></tr>
<tr><th>Грубая/точная част. ошибка, Гц</th><td>{{ statRx.freqErr }} / {{ statRx.freqErrAcc }}</td></tr>
<tr><th>Ур. входного сигнала</th><td>{{ statRx.inputSignalLevel }}</td></tr>
<tr><th>Ошибка ФАПЧ</th><td>{{ statRx.pllError }}</td></tr>
<tr><th>Инф. скорость на приеме</th><td>{{ statRx.speedOnRxKbit }} kbit/s</td></tr>
<tr><th>Инф. скорость на интерфейсе</th><td>{{ statRx.speedOnIifKbit }} kbit/s</td></tr>
</tbody>
</table>
<p> Статистика пакетов </p>
<table>
<tbody>
<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">
<h2>Статистика передачи</h2>{% endraw %}{% if modem == 'scpc' %}{% raw %}
<table>
<tbody>
<tr><th>Передача</th><td><span :class="{ indicator_bad: statTx.state === false, indicator_good: statTx.state === true, indicator: true }"></span></td></tr>
<tr><th>ОСШ дальнего приема</th><td>{{ statTx.snr }}</td></tr>
<tr><th>Modcod</th><td>{{ statTx.modcod }}</td></tr>
<tr><th>Размер кадра</th><td>{{ statTx.frameSizeNormal ? 'normal' : 'short' }}</td></tr>
<tr><th>Пилот-символы</th><td>{{ statTx.isPilots ? 'pilots' : 'no pilots' }}</td></tr>
<tr><th>Инф. скорость на передаче</th><td>{{ statTx.speedOnTxKbit }} kbit/s</td></tr>
<tr><th>Инф. скорость на интерфейсе</th><td>{{ statTx.speedOnIifKbit }} kbit/s</td></tr>
</tbody>
</table>{% endraw %}{% else %}{% raw %}
<table>
<tbody>
<tr><th>Передача</th><td><span :class="{ indicator_bad: statTx.state === false, indicator_good: statTx.state === true, indicator: true }"></span></td></tr>
<tr><th>Modcod</th><td>{{ statTx.modcod }}</td></tr>
<tr><th>Инф. скорость на передаче</th><td>{{ statTx.speedOnTxKbit }} kbit/s</td></tr>
<tr><th>Инф. скорость на интерфейсе</th><td>{{ statTx.speedOnIifKbit }} kbit/s</td></tr>
<tr><th>Центральная частота</th><td>{{ statTx.centerFreq }} kHz</td></tr>
<tr><th>Символьная скорость</th><td>{{ statTx.symSpeed }} ksymb</td></tr>
</tbody>
</table>{% endraw %}{% endif %}{% raw %}
</div>{% endraw %}{% if modem == 'scpc' %}{% raw %}
<div class="settings-set-container" v-if="paramRxtx.isCinC === true">
<h2>Статистика режима CinC</h2>
<table>
<tbody>
<tr><th>ОСС</th><td>{{ statCinc.occ }}</td></tr>
<tr><th>Захват коррелятора</th><td><span :class="{ indicator_bad: statCinc.correlator === false, indicator_good: statCinc.correlator === true, indicator: true }"></span></td></tr>
<tr><th>Кол-во срывов коррелятора</th><td>{{ statCinc.correlatorFails }}</td></tr>
<tr><th>Грубая/точная част. ошибка, Гц</th><td>{{ statCinc.freqErr }} / {{ statCinc.freqErrAcc }}</td></tr>
<tr><th>Задержка в канале, мс</th><td>{{ statCinc.channelDelay }}</td></tr>
</tbody>
</table>
</div>{% endraw %}{% endif %}{% raw %}
<div class="settings-set-container">
<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>Uptime</th><td>{{ statOs.uptime }}</td></tr>
<tr><th>Load average</th><td>{{ statOs.load1 }} {{ statOs.load5 }} {{ statOs.load15 }}</td></tr>
<tr><th>RAM total/free</th><td>{{ statOs.totalram }}Mb/{{ statOs.freeram }}Mb</td></tr>
</tbody>
</table>
</div>
</div>
{% endraw %}

View File

@ -0,0 +1,8 @@
submitStatusQos: false,
paramQos: {
en: false,
rt1: [],
rt2: [],
rt3: [],
cd: [],
},

View File

@ -0,0 +1,221 @@
settingsSubmitQoS() {
if (this.submitStatusQos) { return }
this.submitStatusQos = true
function _translateQosClass(trafficClass, qc) {
let res = {
cir: qc['cir'],
description: qc['description'],
filters: []
}
if (trafficClass === 'cd') {
res.pir = qc.pir
}
if (!qc.isEnabled) {
res.disabled = true
}
for (const fi in qc.filters) {
let filter = {}
if (qc['filters'][fi].vlan !== "") { filter['vlan'] = qc['filters'][fi].vlan }
if (qc['filters'][fi].proto.length > 0) {
let tmp = "";
for (let pid = 0; pid < qc['filters'][fi].proto.length; pid++) {
if (pid !== 0) { tmp += ',' }
tmp += qc['filters'][fi].proto[pid]
}
filter['proto'] = tmp
}
if (qc['filters'][fi].sport !== "") { filter['sport'] = qc['filters'][fi].sport }
if (qc['filters'][fi].dport !== "") { filter['dport'] = qc['filters'][fi].dport }
if (qc['filters'][fi].ip_src !== "") { filter['ip_src'] = qc['filters'][fi].ip_src }
if (qc['filters'][fi].ip_dest !== "") { filter['ip_dest'] = qc['filters'][fi].ip_dest }
if (qc['filters'][fi].dscp !== "") { filter['dscp'] = qc['filters'][fi].dscp }
if (Object.keys(filter).length === 0) { continue }
if (!qc.filters[fi].isEnabled) { filter['disabled'] = true }
res.filters.push(filter)
}
if (res.filters.length === 0) {
// автоматическое выключение класса, если правил нет
res.disabled = true
}
return res
}
let query = {
"en": this.paramQos.en,
"rt1": [],
"rt2": [],
"rt3": [],
"cd": []
}
for (let i = 0; i < this.paramQos.rt1.length; i++) { query.rt1.push(_translateQosClass('rt', this.paramQos.rt1[i])) }
for (let i = 0; i < this.paramQos.rt2.length; i++) { query.rt2.push(_translateQosClass('rt', this.paramQos.rt2[i])) }
for (let i = 0; i < this.paramQos.rt3.length; i++) { query.rt3.push(_translateQosClass('rt', this.paramQos.rt3[i])) }
for (let i = 0; i < this.paramQos.cd.length; i++) { query.cd.push(_translateQosClass('rt', this.paramQos.cd[i])) }
//console.log(query)
fetch('/api/set/qos', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(query)
}).then(async (resp) => {
this.submitStatusQos = false
this.updateQosSettings(await resp.json())
}).catch((reason) => {
this.submitStatusQos = false
alert(`Ошибка при применении настроек: ${reason}`)
})
},
updateQosSettings(vals) {
this.submitStatusQos = false
this.paramQos.en = vals["settings"]["qos.enabled"]
const qosProfile = vals["settings"]["qos.profile"]
if (qosProfile !== null && qosProfile !== undefined) {
this.paramQos.rt1 = [] // .splice(0, this.paramQos.rt1.length)
this.paramQos.rt2 = [] // .splice(0, this.paramQos.rt2.length)
this.paramQos.rt3 = [] // .splice(0, this.paramQos.rt3.length)
this.paramQos.cd = [] // .splice(0, this.paramQos.cd.length)
for (let trafficClass in qosProfile) {
if (['rt1', 'rt2', 'rt3', 'cd'].indexOf(trafficClass) < 0) {
continue
}
if (Array.isArray(qosProfile[trafficClass])) {
for (let i = 0; i < qosProfile[trafficClass].length; i++) {
const qc = qosProfile[trafficClass][i]
let result = {
isEnabled: !qc.hasOwnProperty('disabled'),
cir: qc['cir'],
pir: 0,
description: qc['description'],
filters: []
}
if (trafficClass === 'cd') {
if (qc['pir']) {
result.pir = qc['pir']
}
}
for (let fi = 0; fi < qc['filters'].length; fi++) {
result.filters.push({
isEnabled: !qc['filters'][fi].hasOwnProperty('disabled'),
vlan: qc['filters'][fi].hasOwnProperty('vlan') ? qc['filters'][fi]['vlan'] : '',
proto: qc['filters'][fi].hasOwnProperty('proto') ? qc['filters'][fi]['proto'].split(',') : [],
sport: qc['filters'][fi].hasOwnProperty('sport') ? qc['filters'][fi]['sport'] : '',
dport: qc['filters'][fi].hasOwnProperty('dport') ? qc['filters'][fi]['dport'] : '',
ip_src: qc['filters'][fi].hasOwnProperty('ip_src') ? qc['filters'][fi]['ip_src'] : '',
ip_dest: qc['filters'][fi].hasOwnProperty('ip_dest') ? qc['filters'][fi]['ip_dest'] : '',
dscp: qc['filters'][fi].hasOwnProperty('dscp') ? qc['filters'][fi]['dscp'] : ''
})
}
switch (trafficClass) {
case 'rt1': this.paramQos.rt1.push(result); break
case 'rt2': this.paramQos.rt2.push(result); break
case 'rt3': this.paramQos.rt3.push(result); break
case 'cd': this.paramQos.cd.push(result); break
}
}
}
}
}
},
qosAddClass(name) {
let res = {
isEnabled: true,
cir: 0,
pir: 0,
description: "",
filters: []
}
switch (name) {
case 'rt1': this.paramQos.rt1.push(res); break
case 'rt2': this.paramQos.rt2.push(res); break
case 'rt3': this.paramQos.rt3.push(res); break
case 'cd': this.paramQos.cd.push(res); break
}
},
qosClassAddRule(name, index) {
let rule = {
isEnabled: true,
vlan: "",
proto: [],
sport: "",
dport: "",
ip_src: "",
ip_dest: "",
dscp: ""
}
switch (name) {
case 'rt1': this.paramQos.rt1[index].filters.push(rule); break
case 'rt2': this.paramQos.rt2[index].filters.push(rule); break
case 'rt3': this.paramQos.rt3[index].filters.push(rule); break
case 'cd': this.paramQos.cd[index].filters.push(rule); break
}
},
qosDelClass(name, index) {
switch (name) {
case 'rt1': this.paramQos.rt1.splice(index, 1); break
case 'rt2': this.paramQos.rt2.splice(index, 1); break
case 'rt3': this.paramQos.rt3.splice(index, 1); break
case 'cd': this.paramQos.cd.splice(index, 1); break
}
},
qosDelFilter(name, index, filterIndex) {
switch (name) {
case 'rt1': this.paramQos.rt1[index].filters.splice(filterIndex, 1); break
case 'rt2': this.paramQos.rt2[index].filters.splice(filterIndex, 1); break
case 'rt3': this.paramQos.rt3[index].filters.splice(filterIndex, 1); break
case 'cd': this.paramQos.cd[index].filters.splice(filterIndex, 1); break
}
},
qosGenerateRuleDescription(filter) {
// попытка 1: просто отобразить все фильтры
let result = ""
let isFirst = true;
for (const key in filter) {
if (key === "isEnabled" || !filter[key] || (key === "proto" && filter['proto'].length === 0)) {
continue
}
if (isFirst) {
isFirst = false;
} else {
result += '; '
}
result += `${key}: ${filter[key]}`
}
if (result === "") {
return "пустой"
}
const maxResultLen = 60
if (result.length > maxResultLen) {
// попытка 2, отобразить что вообще в этом фильтре использовалось
result = ""
isFirst = true;
for (const key in filter) {
if (key === "isEnabled" || !filter[key] || (key === "proto" && filter['proto'].length === 0)) {
continue
}
if (isFirst) {
isFirst = false;
} else {
result += ', '
}
result += `${key}`
}
}
return result
},

View File

@ -0,0 +1,107 @@
{% from 'common/widgets.j2' import build_widget %}
{% raw %}
<div class="tabs-body-item" v-if="activeTab === 'qos' && settingFetchComplete">
<h2>Настройки QoS</h2>
<div class="settings-set-container">
<label>
<span>Активировать QoS</span>
<span class="toggle-input"><input type="checkbox" v-model="paramQos.en" /><span class="slider"></span></span>
</label>
</div>
<div v-for="classesGroup in ['rt1', 'rt2', 'rt3', 'cd']">
<h3>Классы {{ classesGroup.toUpperCase() }} <button class="action-button" @click="qosAddClass(classesGroup)"> + </button></h3>
<details v-for="(qosClass, index) in paramQos[classesGroup]" :key="index" class="settings-set-container">
<summary>
<span v-if="classesGroup === 'cd'">#{{ index }} CIR={{ qosClass.cir }}кбит, PIR={{ qosClass.pir }}кбит {{ qosClass.description }}</span>
<span v-if="classesGroup !== 'cd'">#{{ index }} CBR={{ qosClass.cir }}кбит {{ qosClass.description }}</span>
<span class="summary-actions">
<label>
<span class="toggle-input">
<input type="checkbox" v-model="qosClass.isEnabled" />
<span class="slider"></span>
</span>
</label>
</span>
</summary>
<label>
<span v-if="classesGroup === 'cd'">CIR</span> <span v-if="classesGroup !== 'cd'">CBR</span>
<input v-model="qosClass.cir" type="number"/>
</label>
<label v-if="classesGroup === 'cd'">
<span>PIR</span>
<input v-model="qosClass.pir" type="number"/>
</label>
<label>
<span>Описание</span>
<input v-model="qosClass.description"/>
</label>
<h3>Фильтры ({{ qosClass.filters.length }})</h3>
<div>
<button class="action-button" @click="qosClassAddRule(classesGroup, index)">Добавить правило</button>
</div>
<details v-for="(filter, filterIndex) in qosClass.filters" :key="filterIndex" class="settings-set-container">
<summary>
<span>#{{ filterIndex }} {{ qosGenerateRuleDescription(filter) }}</span>
<span class="summary-actions">
<label>
<span class="toggle-input">
<input type="checkbox" v-model="filter.isEnabled" />
<span class="slider"></span>
</span>
</label>
<button class="dangerous-button" @click="qosDelFilter(classesGroup, index, filterIndex)">Del</button>
</span>
</summary>
<label>
<span>VLAN ID</span>
<!-- singleVlanExpr: (([0-9]{1,4}-[0-9]{1,4})|([0-9]{1,4}))-->
<!-- expr: ^(((single,)+single)|single)$-->
<input v-model="filter.vlan" type="text" pattern="^((((([0-9]{1,4}-[0-9]{1,4})|([0-9]{1,4})),)+(([0-9]{1,4}-[0-9]{1,4})|([0-9]{1,4})))|(([0-9]{1,4}-[0-9]{1,4})|([0-9]{1,4})))$">
</label>
<div>
<span>Протокол L3</span>
<label class="l3-proto-label"><span>AH:</span><input type="checkbox" value="ah" v-model="filter.proto"></label>
<label class="l3-proto-label"><span>COMP:</span><input type="checkbox" value="comp" v-model="filter.proto"></label>
<label class="l3-proto-label"><span>DCCP:</span><input type="checkbox" value="dccp" v-model="filter.proto"></label>
<label class="l3-proto-label"><span>ESP:</span><input type="checkbox" value="esp" v-model="filter.proto"></label>
<label class="l3-proto-label"><span>ICMP:</span><input type="checkbox" value="icmp" v-model="filter.proto"></label>
<!-- <label class="l3-proto-label"><span>ICMPV6:</span><input type="checkbox" value="icmpv6" v-model="filter.proto"></label>-->
<label class="l3-proto-label"><span>SCTP:</span><input type="checkbox" value="sctp" v-model="filter.proto"></label>
<label class="l3-proto-label"><span>TCP:</span><input type="checkbox" value="tcp" v-model="filter.proto"></label>
<label class="l3-proto-label"><span>UDP:</span><input type="checkbox" value="udp" v-model="filter.proto"></label>
<label class="l3-proto-label"><span>UDPLITE:</span><input type="checkbox" value="udplite" v-model="filter.proto"></label>
</div>
<label>
<span>Порт источника</span>
<input v-model="filter.sport" type="text" pattern="^((((([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})),)+(([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})))|(([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})))$">
</label>
<label>
<span>Порт назначения</span>
<input v-model="filter.dport" type="text" pattern="^((((([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})),)+(([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})))|(([0-9]{1,5}-[0-9]{1,5})|([0-9]{1,5})))$">
</label>
<label>
<span>IP источника</span>
<input v-model="filter.ip_src" type="text">
</label>
<label>
<span>IP назначения</span>
<input v-model="filter.ip_dest" type="text">
</label>
<label>
<span>Метка IP.DSCP</span>
<input v-model="filter.dscp" type="text">
</label>
</details>
<div>
<button class="dangerous-button" @click="qosDelClass(classesGroup, index)">Удалить класс QoS</button>
</div>
</details>
</div>
<button class="action-button" @click="settingsSubmitQoS()">Применить <span class="submit-spinner" v-show="submitStatusQos"></span></button>
{% endraw %}{% if 'tcpaccel' in params %}
{% for w in params['tcpaccel'] %}{{ build_widget('tcpaccel', w) | indent(12, true) }}{% endfor %}
{% endif %}
</div>

View File

@ -0,0 +1,8 @@
{% from 'common/widgets.j2' import build_widget %}
<div class="tabs-body-item" v-if="activeTab === 'setup' && settingFetchComplete">
{% for cat in ['rxtx', 'cinc', 'buclnb'] %}
{% if cat in params %}
{% for w in params[cat] %}{{ build_widget(cat, w) | indent(12, true) }}{% endfor %}
{% endif %}
{% endfor %}
</div>

View File

@ -0,0 +1,63 @@
{% macro build_widget_checkbox(param_group, widget) %}<label{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>
<span>{{ widget.label }}</span>
<span class="toggle-input"><input type="checkbox" v-model="param{{ param_group | title }}.{{ widget.name }}" /><span class="slider"></span></span>
</label>{% endmacro %}
{# https://ru.stackoverflow.com/questions/1241064 #}
{% macro build_widget_number(param_group, widget) %}<label{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}><span>{{ widget.label }}</span><input type="number" v-model="param{{ param_group | title }}.{{ widget.name }}"{% if widget['min'] %} min="{{ widget['min'] }}"{% endif %}{% if widget['max'] %} max="{{ widget['max'] }}"{% endif %}{% if widget['step'] %} step="{{ widget['step'] }}"{% endif %}/></label>{% endmacro %}
{% macro build_widget_select(param_group, widget) %}<label{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>
<span>{{ widget.label }}</span>
<select v-model="param{{ param_group | title }}.{{ widget.name }}">
{% for opt in widget['values'] %} <option :value="{{ opt.value }}">{{ opt.label }}</option>
{% endfor %}
</select>
</label>{% endmacro %}
{% macro build_widget_watch(param_group, widget) %}<label{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}><span>{{ widget.label }}</span><input type="text" readonly v-model="{{ widget.model }}"/></label>{% endmacro %}
{% macro build_widget_modulation_modcod(param_group, widget) %}<label{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>
<span>{{ widget.label }}</span>
<select v-model="param{{ param_group | title }}.{{ widget.name }}Modulation" @change="param{{ param_group | title }}.{{ widget.name }}Speed = correctModcodSpeed(param{{ param_group | title }}.{{ widget.name }}Modulation, param{{ param_group | title }}.{{ widget.name }}Speed)">
<option :value="'qpsk'">QPSK</option>
<option :value="'8psk'">8PSK</option>
<option :value="'16apsk'">16APSK</option>
<option :value="'32apsk'">32APSK</option>
</select>
</label>{% endmacro %}
{% macro build_widget_modulation_speed(param_group, widget) %}<label{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>
<span>{{ widget.label }}</span>
<select v-model="param{{ param_group | title }}.{{ widget.name }}Speed">
<option v-for="speed in getAvailableModcods(param{{ param_group | title }}.{{ widget.name }}Modulation)" v-bind:value="speed">{{ '{{' }} speed {{ '}}' }}</option>
</select>
</label>{% endmacro %}
{% macro build_widget_flex_container(param_group, widget) %}<div class="tabs-item-flex-container"{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>
{% for w in widget.childs %}{{ build_widget(param_group, w) | indent(4, true) }}{% endfor %}
</div>{% endmacro %}
{% macro build_widget_settings_container(param_group, widget) %}<div class="settings-set-container"{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>
{% for w in widget.childs %}{{ build_widget(param_group, w) | indent(4, true) }}{% endfor %}
</div>{% endmacro %}
{% macro build_widget_ip_address(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]?)$">
</label>{% endmacro %}
{% macro build_widget(param_group, widget) %}{% if widget.widget == 'flex-container' %}{{ build_widget_flex_container(param_group, widget) }}
{% elif widget.widget == 'settings-container' %}{{ build_widget_settings_container(param_group, widget) }}
{% elif widget.widget == 'h2' %}<h2{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>{{ widget.label }}</h2>
{% elif widget.widget == 'h3' %}<h3{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>{{ widget.label }}</h3>
{% elif widget.widget == 'submit' %}<button class="action-button" @click="settingsSubmit{{ param_group | title }}()"{% if widget.v_show %} v-show="{{ widget.v_show }}"{% endif %}>Сохранить <span class="submit-spinner" v-show="submitStatus.{{ param_group }}"></span></button>
{% elif widget.widget == 'checkbox' %}{{ build_widget_checkbox(param_group, widget) }}
{% elif widget.widget == 'number' %}{{ build_widget_number(param_group, widget) }}
{% elif widget.widget == 'watch' %}{{ build_widget_watch(param_group, widget) }}
{% elif widget.widget == 'select' %}{{ build_widget_select(param_group, widget) }}
{% elif widget.widget == 'modulation-modcod' %}{{ build_widget_modulation_modcod(param_group, widget) }}
{% elif widget.widget == 'modulation-speed' %}{{ build_widget_modulation_speed(param_group, widget) }}
{% elif widget.widget == 'ip-address' %}{{ build_widget_ip_address(param_group, widget) }}
{% else %}<p>Widget '{{ widget.widget }}' not defined!</p><p>{{ widget }}</p>
{% endif %}
{% endmacro %}

View File

@ -1,139 +0,0 @@
{% raw %}// для обновления высоты хидера
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 defaultTab
}
function modcodToStr(modcod) {
// модкоды из раздела 5.5.2.2 https://www.etsi.org/deliver/etsi_en/302300_302399/302307/01.01.02_60/en_302307v010102p.pdf
// NOTE модкоды со скоростью хода 3/5 не работают
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" || modcod < 0 || modcod >= modcod.length) {
return "?";
}
return modcods[modcod]
}
function toModcod(modulation, speed) {
switch (modulation.toLowerCase()) {
case 'qpsk':
switch (speed) {
case '1/4': return 1
case '1/3': return 2
case '2/5': return 3
case '1/2': return 4
case '3/5': return 5 // отключено
case '2/3': return 6
case '3/4': return 7
case '4/5': return 8
case '5/6': return 9
case '8/9': return 10
case '9/10': return 11
default: return 1 // минимальная скорость
}
case '8psk':
switch (speed) {
case '3/5': return 12 // отключено
case '2/3': return 13
case '3/4': return 14
case '5/6': return 15
case '8/9': return 16
case '9/10': return 17
default: return 13 // минимальная скорость
}
case '16apsk':
switch (speed) {
case '2/3': return 18
case '3/4': return 19
case '4/5': return 20
case '5/6': return 21
case '8/9': return 22
case '9/10': return 23
default: return 18 // минимальная скорость
}
case '32apsk':
switch (speed) {
case '3/4': return 24
case '4/5': return 25
case '5/6': return 26
case '8/9': return 27
case '9/10': return 28
default: return 24
}
}
}
function extractModulationAndSpeedFromModcod(modcod) {
switch (modcod) {
case 1: return { modulation: 'qpsk', speed: '1/4' }
case 2: return { modulation: 'qpsk', speed: '1/3' }
case 3: return { modulation: 'qpsk', speed: '2/5' }
case 4: return { modulation: 'qpsk', speed: '1/2' }
case 5: return { modulation: 'qpsk', speed: '3/5' }
case 6: return { modulation: 'qpsk', speed: '2/3' }
case 7: return { modulation: 'qpsk', speed: '3/4' }
case 8: return { modulation: 'qpsk', speed: '4/5' }
case 9: return { modulation: 'qpsk', speed: '5/6' }
case 10: return { modulation: 'qpsk', speed: '8/9' }
case 11: return { modulation: 'qpsk', speed: '9/10' }
case 12: return { modulation: '8psk', speed: '3/5' }
case 13: return { modulation: '8psk', speed: '2/3' }
case 14: return { modulation: '8psk', speed: '3/4' }
case 15: return { modulation: '8psk', speed: '5/6' }
case 16: return { modulation: '8psk', speed: '8/9' }
case 17: return { modulation: '8psk', speed: '9/10' }
case 18: return { modulation: '16apsk', speed: '2/3' }
case 19: return { modulation: '16apsk', speed: '3/4' }
case 20: return { modulation: '16apsk', speed: '4/5' }
case 21: return { modulation: '16apsk', speed: '5/6' }
case 22: return { modulation: '16apsk', speed: '8/9' }
case 23: return { modulation: '16apsk', speed: '9/10' }
case 24: return { modulation: '32apsk', speed: '3/4' }
case 25: return { modulation: '32apsk', speed: '4/5' }
case 26: return { modulation: '32apsk', speed: '5/6' }
case 27: return { modulation: '32apsk', speed: '8/9' }
case 28: return { modulation: '32apsk', speed: '9/10' }
}
return { modulation: 'qpsk', speed: '1/4' }
}
{% endraw %}

File diff suppressed because it is too large Load Diff

View File

@ -1,181 +0,0 @@
isCinC: false,
// false - означает что статистика не отправляется, true - отправляется
submitStatus: {
{% for pg in params.groupsList %}
{{ pg }}: false,
{% endfor %}
firmwareUpload: false,
firmwareUpgrade: false,
// когда модем перезагружается, тут должен быть счетчик. Направление счета - к нулю
modemReboot: null
},
stat: {
}
stat_rx: {
// индикаторы
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: '?',
},
stat_tx: {
// состояние
state: '?',
// прочие поля
snr: '?', modcod: '?', frameSizeNormal: '?', isPilots: '?', speedOnTxKbit: '?', speedOnIifKbit: '?',
},
stat_cinc: {
occ: '?',
correlator: null,
correlatorFails: '?',
freqErr: '?', freqErrAcc: '?',
channelDelay: '?'
},
stat_device: { // температурные датчики
adrv: 0, zynq: 0, fpga: 0
},
param: {
general: {
isCinC: Boolean,
txEn: Boolean, // включен/выключен
modulatorMode: 'normal', // режим работы модулятора
autoStartTx: Boolean, // было "режим работы передатчика"
isTestInputData: Boolean, // входные данные: eth или test
},
tx: {
attenuation: Number, // ослабление
rolloff: Number,
cymRate: Number,
centerFreq: Number,
},
dvbs2: {
mode: null, // ccm/acm
frameSizeNormal: null, // 'normal' / 'short'
// isPilots: false,
// CCM
ccm_modulation: null,
ccm_speed: null,
// ACM
acm_maxModulation: null,
acm_maxSpeed: null,
acm_minModulation: null,
acm_minSpeed: null,
snrReserve: null,
servicePacketPeriod: null,
},
// авто-регулировка мощности
acm: {
en: false,
maxAttenuation: null,
minAttenuation: null,
requiredSnr: null,
},
rx: {
gainMode: null, // 'auto'/'manual' режим управления усилением
manualGain: 0, // усиление, только для ручного режима
spectrumInversion: false,
rolloff: 0,
cymRate: 100000,
centerFreq: 1200000.0,
},
cinc: {
mode: null, // 'positional' | 'delay'
searchBandwidth: 0, // полоса поиска в кГц
position: {
station: {
latitude: 0,
longitude: 0
},
satelliteLongitude: 0,
},
delayMin: 0,
delayMax: 0
},
buc: {
refClk10M: false, // подача опоры 10MHz
powering: 0 // 0, 24, 48
},
lnb: {
refClk10M: false, // подача опоры 10MHz
powering: 0 // 0, 13, 18, 24
},
serviceSettings: {
refClk10M: false, // подача опоры 10MHz
autoStart: false
},
network: {
managementIp: '', // 0.0.0.0/24
managementGateway: '',
mode: String, // l2 | l3
dataIp: '', //
dataMtu: 1500
},
debugSend: {
en: false,
receiverIp: '0.0.0.0', // 0.0.0.0
portCinC: 0,
portData: 0,
timeout: 0
},
qos: {
en: false,
rt1: [],
rt2: [],
rt3: [],
cd: [],
},
tcpAccel: {
en: false,
maxConnections: 128
},
},
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,

View File

@ -132,7 +132,11 @@ public:
auth.users.emplace_back(std::make_shared<http::auth::User>("admin", "", http::auth::User::SUPERUSER)); auth.users.emplace_back(std::make_shared<http::auth::User>("admin", "", http::auth::User::SUPERUSER));
sf->registerFile(staticFilesPath + "/favicon.png", FAVICON_ICO, mime_types::image_png, true); sf->registerFile(staticFilesPath + "/favicon.png", FAVICON_ICO, mime_types::image_png, true);
#ifdef USE_DEBUG
sf->registerFile(staticFilesPath + VUE_JS, VUE_JS, mime_types::javascript, true); sf->registerFile(staticFilesPath + VUE_JS, VUE_JS, mime_types::javascript, true);
#else
sf->registerFile(staticFilesPath + "/js/vue.prod.js", VUE_JS, mime_types::javascript, true);
#endif
sf->registerFile(staticFilesPath + STYLE_CSS, STYLE_CSS, mime_types::text_css, true); sf->registerFile(staticFilesPath + STYLE_CSS, STYLE_CSS, mime_types::text_css, true);
sf->registerFile(staticFilesPath + FIELDS_CSS, FIELDS_CSS, mime_types::text_css, true); sf->registerFile(staticFilesPath + FIELDS_CSS, FIELDS_CSS, mime_types::text_css, true);
sf->registerFile(staticFilesPath + INDEX_HTML, INDEX_HTML, mime_types::text_html, false); sf->registerFile(staticFilesPath + INDEX_HTML, INDEX_HTML, mime_types::text_html, false);
@ -282,7 +286,7 @@ public:
} }
})); }));
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/bucLnb", this->auth, http::auth::User::SUPERUSER, [this](const auto& req, auto& rep) { s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/buclnb", this->auth, http::auth::User::SUPERUSER, [this](const auto& req, auto& rep) {
if (req.method != "POST") { if (req.method != "POST") {
http::server::stockReply(http::server::bad_request, rep); http::server::stockReply(http::server::bad_request, rep);
} }
@ -304,7 +308,7 @@ public:
result += "}"; result += "}";
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
} catch (std::exception& e) { } catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/bucLnb): Can't set settings: " << e.what(); BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/buclnb): Can't set BUC LNB settings: " << e.what();
const std::string result = R"({"status":"error"})"; const std::string result = R"({"status":"error"})";
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
} }
@ -388,35 +392,7 @@ public:
result += "}"; result += "}";
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
} catch (std::exception& e) { } catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/rxtx): Can't set RX/TX settings: " << e.what(); BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/network): Can't set network settings: " << e.what();
const std::string result = R"({"status":"error"})";
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
}
}));
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/api/set/debugSend", 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);
}
rep.status = http::server::ok;
rep.headers.clear();
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
try {
std::stringstream ss;
ss.str(std::string(req.payload.begin(), req.payload.end()));
boost::property_tree::ptree pt;
read_json(ss, pt);
api->setDebugSendSettings(pt);
std::string result = R"({"status":"ok","settings":)";
result += api->loadSettings();
result += "}";
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
} catch (std::exception& e) {
BOOST_LOG_TRIVIAL(error) << "WebHandle(/api/set/rxtx): Can't set RX/TX settings: " << e.what();
const std::string result = R"({"status":"error"})"; const std::string result = R"({"status":"error"})";
rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size()); rep.content.insert(rep.content.end(), result.c_str(), result.c_str() + result.size());
} }
@ -481,16 +457,16 @@ public:
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/dev", this->auth, http::auth::User::SUPERUSER, [this](const auto& req, auto& rep) { s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/dev", this->auth, http::auth::User::SUPERUSER, [this](const auto& req, auto& rep) {
boost::ignore_unused(req); boost::ignore_unused(req);
sf->serve(INTERNET_JPG, rep); sf->serve(DEV_HTML, rep);
})); }));
s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/dev/fetchParams", this->auth, http::auth::User::SUPERUSER, [this](const auto& req, auto& rep) { // s.resources.emplace_back(std::make_unique<http::auth::AuthRequiredResource>("/dev/fetchParams", this->auth, http::auth::User::SUPERUSER, [this](const auto& req, auto& rep) {
rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)}); // rep.headers.push_back({.name = "Content-Type", .value = toString(mime_types::json)});
std::string result = R"({"status":"ok","fwsize":)"; // std::string result = R"({"status":"ok","fwsize":)";
result += std::to_string(req.payload.size()); // result += std::to_string(req.payload.size());
result += R"(,"sha256":")"; // result += R"(,"sha256":")";
result += "\"}"; // result += "\"}";
})); // }));
} }
~ServerResources() = default; ~ServerResources() = default;

View File

@ -16,48 +16,48 @@ typedef boost::property_tree::ptree::path_type json_path;
static constexpr const char* DEFAULT_QOS_CLASSES = R"({"rt1":[],"rt2":[],"rt3":[],"cd":[]})"; static constexpr const char* DEFAULT_QOS_CLASSES = R"({"rt1":[],"rt2":[],"rt3":[],"cd":[]})";
static int calculateSubnetMask(const std::string& subnet_mask) { // static int calculateSubnetMask(const std::string& subnet_mask) {
int mask = 0; // int mask = 0;
std::istringstream iss(subnet_mask); // std::istringstream iss(subnet_mask);
std::string octet; // std::string octet;
while (std::getline(iss, octet, '.')) { // while (std::getline(iss, octet, '.')) {
int octet_value = std::stoi(octet); // int octet_value = std::stoi(octet);
for (int i = 7; i >= 0; i--) { // for (int i = 7; i >= 0; i--) {
if (octet_value & (1 << i)) { // if (octet_value & (1 << i)) {
mask++; // mask++;
} // }
} // }
} // }
return mask; // return mask;
} // }
/** /**
* Преобразует строку вида `1.2.3.4/24` в пару строк вида `1.2.3.4` `255.255.255.0` * Преобразует строку вида `1.2.3.4/24` в пару строк вида `1.2.3.4` `255.255.255.0`
*/ */
std::pair<std::string, std::string> splitIpAndMask(const std::string& input) { // std::pair<std::string, std::string> splitIpAndMask(const std::string& input) {
auto pos = input.find('/'); // auto pos = input.find('/');
if (pos == std::string::npos) { // if (pos == std::string::npos) {
// Обработка ошибки: нет символа '/' // // Обработка ошибки: нет символа '/'
throw std::runtime_error("address not contains mask"); // throw std::runtime_error("address not contains mask");
} // }
std::string ip = input.substr(0, pos); // std::string ip = input.substr(0, pos);
const unsigned int mask_int = std::stoul(input.substr(pos + 1)); // const unsigned int mask_int = std::stoul(input.substr(pos + 1));
//
if (mask_int > 32) { // if (mask_int > 32) {
throw std::runtime_error("invalid mask"); // throw std::runtime_error("invalid mask");
} // }
//
std::string mask_binary = std::string(mask_int, '1') + std::string(32 - mask_int, '0'); // std::string mask_binary = std::string(mask_int, '1') + std::string(32 - mask_int, '0');
std::string mask_str; // std::string mask_str;
//
for (unsigned int i = 0; i < 4; ++i) { // for (unsigned int i = 0; i < 4; ++i) {
std::string octet = mask_binary.substr(i * 8u, 8); // std::string octet = mask_binary.substr(i * 8u, 8);
int octet_value = std::stoi(octet, nullptr, 2); // int octet_value = std::stoi(octet, nullptr, 2);
mask_str += std::to_string(octet_value) + (i < 3 ? "." : ""); // mask_str += std::to_string(octet_value) + (i < 3 ? "." : "");
} // }
//
return std::make_pair(ip, mask_str); // return std::make_pair(ip, mask_str);
} // }
static inline void rtrim(std::string &s) { static inline void rtrim(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) { s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
@ -67,7 +67,8 @@ static inline void rtrim(std::string &s) {
class TerminalNetworkSettings { class TerminalNetworkSettings {
public: public:
std::string managementIp, managementGateway, mode, dataIp; std::string managementIp, managementGateway, dataIp;
bool isL2 = true;
unsigned int dataMtu = 1500; unsigned int dataMtu = 1500;
TerminalNetworkSettings() = default; TerminalNetworkSettings() = default;
@ -77,10 +78,10 @@ public:
TerminalNetworkSettings& operator= (const TerminalNetworkSettings& src) = default; TerminalNetworkSettings& operator= (const TerminalNetworkSettings& src) = default;
void loadDefaults() { void loadDefaults() {
managementIp = "0.0.0.0/0"; managementIp = "0.0.0.0";
managementGateway = ""; managementGateway = "";
mode = "l2"; isL2 = true;
dataIp = "0.0.0.0/0"; dataIp = "0.0.0.0";
dataMtu = 1500; dataMtu = 1500;
} }
}; };
@ -193,21 +194,22 @@ private:
void updateNetworkSettings() { void updateNetworkSettings() {
TerminalNetworkSettings s; TerminalNetworkSettings s;
std::string tmp;
std::lock_guard lock(this->cpApiMutex); std::lock_guard lock(this->cpApiMutex);
logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(addr)", CP_GetNetwork(sid, "addr", &tmp)); logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(addr)", CP_GetNetwork(sid, "addr", &s.managementIp));
s.managementIp = tmp + "/"; // s.managementIp = tmp + "/";
tmp.clear(); logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(mask)", CP_GetNetwork(sid, "mask", &tmp)); // tmp.clear(); logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(mask)", CP_GetNetwork(sid, "mask", &tmp));
s.managementIp += std::to_string(calculateSubnetMask(tmp)); // s.managementIp += std::to_string(calculateSubnetMask(tmp));
tmp.clear(); logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(gateway)", CP_GetNetwork(sid, "gateway", &s.managementGateway)); s.managementGateway = tmp; logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(gateway)", CP_GetNetwork(sid, "gateway", &s.managementGateway));
tmp.clear(); logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(mode)", CP_GetNetwork(sid, "mode", &tmp)); std::string nm; logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(mode)", CP_GetNetwork(sid, "mode", &nm));
if (tmp == "tun") { if (nm == "tun") {
s.mode = "l3"; s.isL2 = false;
logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(addr_data)", CP_GetNetwork(sid, "addr_data", &s.dataIp)); logCpApiError("api_driver::TerminalApiDaemon::updateNetworkSettings()->CP_GetNetwork(addr_data)", CP_GetNetwork(sid, "addr_data", &s.dataIp));
s.dataIp += "/24"; // s.dataIp += "/24";
} else { } else {
s.mode = "l2"; s.isL2 = true;
s.dataIp = "0.0.0.0/24"; // s.dataIp = "0.0.0.0/24";
s.dataIp = "0.0.0.0";
} }
s.dataMtu = 1500; s.dataMtu = 1500;
@ -564,41 +566,39 @@ public:
} }
void setNetworkSettings(TerminalNetworkSettings& s, bool readback = true) { void setNetworkSettings(TerminalNetworkSettings& s, bool readback = true) {
const auto mang = splitIpAndMask(s.managementIp); // const auto mang = splitIpAndMask();
std::pair<std::string, std::string> data; // std::pair<std::string, std::string> data;
bool isL2; // if (!s.isL2) {
if (s.mode == "l2") { isL2 = true; } // data = splitIpAndMask(s.dataIp);
else if (s.mode == "l3") { isL2 = false; data = splitIpAndMask(s.dataIp); } // }
else { throw std::runtime_error("invalid mode"); }
std::lock_guard lock(this->cpApiMutex); std::lock_guard lock(this->cpApiMutex);
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetDmaDebug(begin_save_config)", CP_SetDmaDebug(sid, "begin_save_config", "")); logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetDmaDebug(begin_save_config)", CP_SetDmaDebug(sid, "begin_save_config", ""));
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(mode)", CP_SetNetwork(sid, "mode", isL2 ? "tap" : "tun")); logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(mode)", CP_SetNetwork(sid, "mode", s.isL2 ? "tap" : "tun"));
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(addr)", CP_SetNetwork(sid, "addr", mang.first.c_str())); logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(addr)", CP_SetNetwork(sid, "addr", s.managementIp.c_str()));
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(mask)", CP_SetNetwork(sid, "mask", mang.second.c_str())); logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(mask)", CP_SetNetwork(sid, "mask", "255.255.255.0"));
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(gateway)", CP_SetNetwork(sid, "gateway", s.managementGateway.c_str())); logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(gateway)", CP_SetNetwork(sid, "gateway", s.managementGateway.c_str()));
if (!isL2) { if (!s.isL2) {
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(data_addr)", CP_SetNetwork(sid, "data_addr", data.first.c_str())); logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_SetNetwork(data_addr)", CP_SetNetwork(sid, "data_addr", s.dataIp.c_str()));
// TODO маска не устанавливается, потому что в API этого нет // TODO маска не устанавливается, потому что в API этого нет
} }
// TODO MTU не устанавливается, потому что в API этого нет // TODO MTU не устанавливается, потому что в API этого нет
if (readback) { if (readback) {
std::string tmp;
s.loadDefaults(); s.loadDefaults();
s.managementIp.clear(); s.managementIp.clear();
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(addr)", CP_GetNetwork(sid, "addr", &s.managementIp)); logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(addr)", CP_GetNetwork(sid, "addr", &s.managementIp));
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(mask)", CP_GetNetwork(sid, "mask", &tmp)); // logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(mask)", CP_GetNetwork(sid, "mask", &tmp));
s.managementIp += "/"; // s.managementIp += "/";
s.managementIp += std::to_string(calculateSubnetMask(tmp)); // s.managementIp += std::to_string(calculateSubnetMask(tmp));
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(gateway)", CP_GetNetwork(sid, "gateway", &s.managementGateway)); logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(gateway)", CP_GetNetwork(sid, "gateway", &s.managementGateway));
tmp.clear(); logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(mode)", CP_GetNetwork(sid, "mode", &tmp)); std::string nm; logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(mode)", CP_GetNetwork(sid, "mode", &nm));
if (tmp == "tun") { if (nm == "tun") {
s.mode = "l3"; s.isL2 = false;
logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(addr_data)", CP_GetNetwork(sid, "addr_data", &s.dataIp)); logCpApiError("api_driver::TerminalApiDaemon::setNetworkSettings()->CP_GetNetwork(addr_data)", CP_GetNetwork(sid, "addr_data", &s.dataIp));
} else { } else {
s.mode = "l2"; s.isL2 = true;
s.dataIp = "0.0.0.0/24"; s.dataIp = "0.0.0.0";
} }
s.dataMtu = 1500; s.dataMtu = 1500;
{ {
@ -778,7 +778,7 @@ std::string api_driver::ApiDriver::loadTerminalState() const {
result << ",\"cinc.correlatorFails\":" << cinc.cnt_bad_lock; result << ",\"cinc.correlatorFails\":" << cinc.cnt_bad_lock;
result << ",\"cinc.freqErr\":" << cinc.freq_error_offset; result << ",\"cinc.freqErr\":" << cinc.freq_error_offset;
result << ",\"cinc.freqErrAcc\":" << cinc.freq_fine_estimate; result << ",\"cinc.freqErrAcc\":" << cinc.freq_fine_estimate;
result << ",\"cinc.channelDelay\":"; writeDouble(result, cinc.delay_dpdi, 1); result << ",\"cinc.channelDelay\":" << cinc.delay_dpdi;
} else { } else {
result << R"(,"cinc.correlator":null)"; result << R"(,"cinc.correlator":null)";
} }
@ -799,6 +799,59 @@ void api_driver::ApiDriver::resetPacketStatistics() const {
this->daemon->resetPacketStatistics(); this->daemon->resetPacketStatistics();
} }
#ifdef MODEM_IS_SCPC
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 < 28) {
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 < 28) {
d = ModcodDefs + modcod;
}
return d->speed;
}
#endif
std::string api_driver::ApiDriver::loadSettings() const { std::string api_driver::ApiDriver::loadSettings() const {
if (daemon == nullptr) { if (daemon == nullptr) {
return R"({"error": "api daemon not started!"})"; return R"({"error": "api daemon not started!"})";
@ -818,93 +871,92 @@ std::string api_driver::ApiDriver::loadSettings() const {
daemon->getNetworkSettings(network); daemon->getNetworkSettings(network);
std::stringstream result; std::stringstream result;
result << "{\n\"txAutoStart\":" << boolAsStr(modSettings.is_save_current_state);
#ifdef MODEM_IS_SCPC #ifdef MODEM_IS_SCPC
result << "{\n\"general.isCinC\":" << boolAsStr(modSettings.is_cinc); result << ",\"txModulatorIsTest\":" << boolAsStr(!modSettings.is_carrier);
result << ",\"general.txEn\":" << boolAsStr(modSettings.tx_is_on); #endif
result << ",\"general.modulatorMode\":" << (modSettings.is_carrier ? "\"normal\"" : "\"test\""); result << ",\"txIsTestInput\":" << boolAsStr(modSettings.is_test_data);
result << ",\"general.autoStartTx\":" << boolAsStr(modSettings.is_save_current_state); result << ",\"txCentralFreq\":"; writeDouble(result, modSettings.central_freq_in_kGz);
result << ",\"general.isTestInputData\":" << boolAsStr(modSettings.is_test_data); result << ",\"txBaudrate\":" << modSettings.baudrate;
result << ",\n\"tx.attenuation\":"; writeDouble(result, modSettings.attenuation); result << ",\"txRolloff\":" << static_cast<int>(modSettings.rollof * 100);
result << ",\"tx.rolloff\":" << static_cast<int>(modSettings.rollof * 100); #ifdef MODEM_IS_SCPC
result << ",\"tx.goldan\":" << static_cast<int>(modSettings.qold_seq_is_active); result << ",\"txGoldan\":" << static_cast<int>(modSettings.qold_seq_is_active);
result << ",\"tx.cymRate\":" << modSettings.baudrate; #endif
result << ",\"tx.centerFreq\":"; writeDouble(result, modSettings.central_freq_in_kGz, 3); result << ",\"txAttenuation\":"; writeDouble(result, modSettings.attenuation);
result << ",\"dvbs2.frameSizeNormal\":" << boolAsStr(!(modSettings.modcod_tx & 2));
result << ",\"dvbs2.ccm_modcod\":" << (modSettings.modcod_tx >> 2);
// result << ",\"dvbs2.isPilots\":" << "null"; #ifdef MODEM_IS_SCPC
result << ",\n\"dvbs2.isAcm\":" << boolAsStr(acmSettings.enable); result << ",\n\"isCinC\":" << boolAsStr(modSettings.is_cinc);
result << ",\"dvbs2.acm_maxModcod\":" << (acmSettings.max_modcod >> 2); result << ",\n\"dvbServicePacketPeriod\":" << acmSettings.period_pack;
result << ",\"dvbs2.acm_minModcod\":" << (acmSettings.min_modcod >> 2); result << ",\"dvbIsAcm\":" << boolAsStr(acmSettings.enable);
result << ",\"dvbs2.snrReserve\":"; writeDouble(result, acmSettings.snr_treashold_acm); result << ",\"txFrameSizeNormal\":" << boolAsStr((modSettings.modcod_tx & 2) == 0);
result << ",\"dvbs2.servicePacketPeriod\":" << acmSettings.period_pack;
result << ",\n\"acm.en\":" << boolAsStr(acmSettings.enable_auto_atten); result << R"(,"dvbCcmModulation":")" << extractModcodModulation(modSettings.modcod_tx) << "\"";
result << ",\"acm.maxAttenuation\":"; writeDouble(result, acmSettings.max_attenuation); result << R"(,"dvbCcmSpeed":")" << extractModcodSpeed(modSettings.modcod_tx) << "\"";
result << ",\"acm.minAttenuation\":"; writeDouble(result, acmSettings.min_attenuation); result << R"(,"dvbAcmMinModulation":")" << extractModcodModulation(acmSettings.min_modcod) << "\"";
result << ",\"acm.requiredSnr\":"; writeDouble(result, acmSettings.snr_treashold); result << R"(,"dvbAcmMinSpeed":")" << extractModcodSpeed(acmSettings.min_modcod) << "\"";
result << R"(,"dvbAcmMaxModulation":")" << extractModcodModulation(acmSettings.max_modcod) << "\"";
result << R"(,"dvbAcmMaxSpeed":")" << extractModcodSpeed(acmSettings.max_modcod) << "\"";
result << ",\"dvbSnrReserve\":"; writeDouble(result, acmSettings.snr_treashold_acm);
result << ",\n\"rx.gainMode\":" << (demodSettings.is_aru_on ? "\"auto\"" : "\"manual\""); result << ",\n\"aupcEn\":" << boolAsStr(acmSettings.enable_auto_atten);
result << ",\"rx.manualGain\":"; writeDouble(result, demodSettings.gain); result << ",\"aupcMinAttenuation\":"; writeDouble(result, acmSettings.min_attenuation);
result << ",\"rx.spectrumInversion\":" << boolAsStr(demodSettings.is_rvt_iq); result << ",\"aupcMaxAttenuation\":"; writeDouble(result, acmSettings.max_attenuation);
result << ",\"rx.rolloff\":" << static_cast<int>(demodSettings.rollof * 100); result << ",\"aupcRequiredSnr\":"; writeDouble(result, acmSettings.snr_treashold);
result << ",\"rx.goldan\":" << static_cast<int>(demodSettings.qold_seq_is_active);
result << ",\"rx.cymRate\":" << demodSettings.baudrate;
result << ",\"rx.centerFreq\":"; writeDouble(result, demodSettings.central_freq_in_kGz);
result << ",\n\"cinc.mode\":" << (dpdiSettings.is_delay_window ? "\"delay\"" : "\"positional\""); result << ",\n\"cincIsPositional\":" << boolAsStr(!dpdiSettings.is_delay_window);
result << ",\"cinc.searchBandwidth\":" << dpdiSettings.freq_offset; // полоса поиска в кГц result << ",\"cincSearchBandwidth\":" << dpdiSettings.freq_offset; // полоса поиска в кГц
result << ",\"cinc.position.station.latitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.latitude_station_grad, dpdiSettings.latitude_station_minute), 6); result << ",\"cincPositionStationLatitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.latitude_station_grad, dpdiSettings.latitude_station_minute), 6);
result << ",\"cinc.position.station.longitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.longitude_station_grad, dpdiSettings.longitude_station_minute), 6); result << ",\"cincPositionStationLongitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.longitude_station_grad, dpdiSettings.longitude_station_minute), 6);
result << ",\"cinc.position.satelliteLongitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.longitude_sattelite_grad, dpdiSettings.longitude_sattelite_minute), 6); result << ",\"cincPositionSatelliteLongitude\":"; writeDouble(result, translateCoordinates(dpdiSettings.longitude_sattelite_grad, dpdiSettings.longitude_sattelite_minute), 6);
result << ",\"cinc.delayMin\":" << dpdiSettings.min_delay; result << ",\"cincDelayMin\":" << dpdiSettings.min_delay;
result << ",\"cinc.delayMax\":" << dpdiSettings.max_delay; result << ",\"cincDelayMax\":" << dpdiSettings.max_delay;
#else
result << "{\n\"tx.txEn\":" << boolAsStr(modSettings.tx_is_on);
result << ",\"tx.isTestInputData\":" << boolAsStr(modSettings.is_test_data);
result << ",\"tx.cymRate\":" << modSettings.baudrate;
result << ",\"tx.centerFreq\":"; writeDouble(result, modSettings.central_freq_in_kGz, 3);
result << ",\"tx.attenuation\":"; writeDouble(result, modSettings.attenuation);
result << ",\n\"rx.gainMode\":" << (demodSettings.is_aru_on ? "\"auto\"" : "\"manual\"");
result << ",\"rx.manualGain\":"; writeDouble(result, demodSettings.gain);
result << ",\"rx.spectrumInversion\":" << boolAsStr(demodSettings.is_rvt_iq);
result << ",\"rx.rolloff\":" << static_cast<int>(demodSettings.rollof * 100);
result << ",\"rx.cymRate\":" << demodSettings.baudrate;
result << ",\"rx.centerFreq\":"; writeDouble(result, demodSettings.central_freq_in_kGz);
#endif #endif
result << ",\n\"buc.refClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_buc); result << ",\n\"rxAgcEn\":" << boolAsStr(demodSettings.is_aru_on);
result << ",\"rxSpectrumInversion\":" << boolAsStr(demodSettings.is_rvt_iq);
result << ",\"rxManualGain\":"; writeDouble(result, demodSettings.gain);
result << ",\"rxCentralFreq\":"; writeDouble(result, demodSettings.central_freq_in_kGz);
result << ",\"rxBaudrate\":" << demodSettings.baudrate;
result << ",\"rxRolloff\":" << static_cast<int>(demodSettings.rollof * 100);
#ifdef MODEM_IS_SCPC
result << ",\"txGoldan\":" << static_cast<int>(demodSettings.qold_seq_is_active);
#endif
// BUC LNB
result << ",\n\"bucRefClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_buc);
switch (bucLnb.buc) { switch (bucLnb.buc) {
case voltage_buc::_24V: result << ",\"buc.powering\":24"; break; case voltage_buc::_24V: result << ",\"bucPowering\":24"; break;
case voltage_buc::_48V: result << ",\"buc.powering\":48"; break; #ifdef MODEM_IS_SCPC
case voltage_buc::_48V: result << ",\"bucPowering\":48"; break;
#endif
case voltage_buc::DISABLE: case voltage_buc::DISABLE:
default: result << ",\"buc.powering\":0"; default: result << ",\"bucPowering\":0";
} }
result << ",\n\"lnb.refClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_lnb); result << ",\"lnbRefClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_lnb);
switch (bucLnb.lnb) { switch (bucLnb.lnb) {
case voltage_lnb::_13V: result << ",\"lnb.powering\":13"; break; case voltage_lnb::_13V: result << ",\"lnbPowering\":13"; break;
case voltage_lnb::_18V: result << ",\"lnb.powering\":18"; break; case voltage_lnb::_18V: result << ",\"lnbPowering\":18"; break;
case voltage_lnb::_24V: result << ",\"lnb.powering\":24"; break; case voltage_lnb::_24V: result << ",\"lnbPowering\":24"; break;
case voltage_lnb::DISABLE: case voltage_lnb::DISABLE:
default: result << ",\"lnb.powering\":0"; default: result << ",\"lnbPowering\":0";
} }
result << ",\n\"serviceSettings.refClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_output); result << ",\"srvRefClk10M\":" << boolAsStr(bucLnb.is_ref_10MHz_output);
result << ",\"serviceSettings.autoStart\":" << boolAsStr(bucLnb.is_save_current_state); result << ",\"bucLnbAutoStart\":" << boolAsStr(bucLnb.is_save_current_state);
// QoS
bool qosEnabled = false; std::string qosClasses; bool qosEnabled = false; std::string qosClasses;
daemon->getQosSettings(qosEnabled, qosClasses); daemon->getQosSettings(qosEnabled, qosClasses);
result << ",\n\"qos.enabled\":" << boolAsStr(qosEnabled); result << ",\n\"qosEnabled\":" << boolAsStr(qosEnabled);
result << ",\"qos.profile\":" << qosClasses; result << ",\"qosProfile\":" << qosClasses;
// сеть // сеть
result << ",\"network.managementIp\":\n" << buildEscapedString(network.managementIp); result << ",\"netManagementIp\":\n" << buildEscapedString(network.managementIp);
result << ",\"network.managementGateway\":\n" << buildEscapedString(network.managementGateway); result << ",\"netIsL2\":\n" << boolAsStr(network.isL2);
result << ",\"network.mode\":\n" << buildEscapedString(network.mode); result << ",\"netManagementGateway\":\n" << buildEscapedString(network.managementGateway);
result << ",\"network.dataIp\":\n" << buildEscapedString(network.dataIp); result << ",\"netDataIp\":\n" << buildEscapedString(network.dataIp);
result << ",\"network.dataMtu\":\n" << network.dataMtu; result << ",\"netDataMtu\":\n" << network.dataMtu;
result << "}"; result << "}";
return result.str(); return result.str();
@ -926,66 +978,81 @@ std::string api_driver::ApiDriver::loadFirmwareVersion() const {
return result.str(); return result.str();
} }
#ifdef MODEM_IS_SCPC
static uint32_t buildModcodFromPt(const boost::property_tree::ptree& pt, const std::string& name, bool isShortFrame) {
uint32_t modcod = 0;
const auto mod = pt.get<std::string>(name + "Modulation");
const auto speed = pt.get<std::string>(name + "Speed");
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) | (isShortFrame ? 2 : 0);
}
#endif
void api_driver::ApiDriver::setRxTxSettings(boost::property_tree::ptree &pt) { void api_driver::ApiDriver::setRxTxSettings(boost::property_tree::ptree &pt) {
modulator_settings mod{}; modulator_settings mod{};
demodulator_settings demod{}; demodulator_settings demod{};
#ifdef MODEM_IS_SCPC #ifdef MODEM_IS_SCPC
ACM_parameters_serv_ acm{}; ACM_parameters_serv_ acm{};
daemon->getSettings(&mod, &demod, &acm, nullptr, nullptr);
#else
daemon->getSettings(&mod, &demod, nullptr);
#endif #endif
// для модулятора // для модулятора
#ifdef MODEM_IS_SCPC #ifdef MODEM_IS_SCPC
mod.is_cinc = pt.get<bool>(json_path("general.isCinC", '/')); mod.is_cinc = pt.get<bool>("isCinC");
mod.tx_is_on = pt.get<bool>(json_path("general.txEn", '/')); #endif
auto tmp = pt.get<std::string>(json_path("general.modulatorMode", '/')); mod.tx_is_on = pt.get<bool>("txEn");
if (tmp == "normal") { mod.is_carrier = true; } #ifdef MODEM_IS_SCPC
else if (tmp == "test") { mod.is_carrier = false; } mod.is_save_current_state = pt.get<bool>("txAutoStart");
else { throw std::runtime_error("api_driver::ApiDriver::setRxTxSettings(): Wrong carrier mode: " + tmp); } mod.is_carrier = !pt.get<bool>("txModulatorIsTest");
mod.is_save_current_state = pt.get<bool>(json_path("general.autoStartTx", '/')); #endif
mod.is_test_data = pt.get<bool>(json_path("general.isTestInputData", '/')); mod.is_test_data = pt.get<bool>("txIsTestInput");
mod.attenuation = pt.get<double>(json_path("tx.attenuation", '/')); mod.central_freq_in_kGz = pt.get<double>("txCentralFreq");
mod.rollof = pt.get<double>(json_path("tx.rolloff", '/')) / 100.0; mod.baudrate = pt.get<uint32_t>("txBaudrate");
mod.qold_seq_is_active = pt.get<int>(json_path("tx.goldan", '/')); mod.rollof = pt.get<int>("txRolloff") / 100.0;
mod.baudrate = pt.get<uint32_t>(json_path("tx.cymRate", '/')); #ifdef MODEM_IS_SCPC
mod.central_freq_in_kGz = pt.get<double>(json_path("tx.centerFreq", '/')); mod.qold_seq_is_active = pt.get<bool>("txGoldan");
#endif
mod.attenuation = pt.get<double>("txAttenuation");
const bool acmIsShortFrame = !pt.get<bool>(json_path("dvbs2.frameSizeNormal", '/')); #ifdef MODEM_IS_SCPC
mod.modcod_tx = (pt.get<uint32_t>(json_path("dvbs2.ccm_modcod", '/')) << 2) | (acmIsShortFrame ? 2 : 0); const bool acmIsShortFrame = !pt.get<bool>("txFrameSizeNormal");
#else mod.modcod_tx = buildModcodFromPt(pt, "dvbCcm", acmIsShortFrame);
mod.tx_is_on = pt.get<bool>(json_path("tx.txEn", '/'));
mod.is_test_data = pt.get<bool>(json_path("tx.isTestInputData", '/'));
mod.central_freq_in_kGz = pt.get<double>(json_path("tx.centerFreq", '/'));
mod.baudrate = pt.get<uint32_t>(json_path("tx.cymRate", '/'));
mod.attenuation = pt.get<double>(json_path("tx.attenuation", '/'));
#endif #endif
// демодулятор // демодулятор
demod.is_aru_on = pt.get<bool>("rxAgcEn");
demod.gain = pt.get<bool>("rxManualGain");
demod.is_rvt_iq = pt.get<bool>("aupcEn");
demod.central_freq_in_kGz = pt.get<double>("rxCentralFreq");
demod.baudrate = pt.get<uint32_t>("rxBaudrate");
demod.rollof = pt.get<int>("rxRolloff") / 100.0;
#ifdef MODEM_IS_SCPC #ifdef MODEM_IS_SCPC
tmp = pt.get<std::string>(json_path("rx.gainMode", '/')); demod.qold_seq_is_active = pt.get<bool>("rxGoldan");
demod.qold_seq_is_active = pt.get<int>(json_path("rx.goldan", '/'));
#else
auto tmp = pt.get<std::string>(json_path("rx.gainMode", '/'));
#endif #endif
if (tmp == "auto") { demod.is_aru_on = true; }
else if (tmp == "manual") { demod.is_aru_on = false; }
else { throw std::runtime_error("api_driver::ApiDriver::setRxTxSettings(): Wrong gain mode: " + tmp); }
demod.gain = pt.get<double>(json_path("rx.manualGain", '/'));
demod.baudrate = pt.get<uint32_t>(json_path("rx.cymRate", '/'));
demod.is_rvt_iq = pt.get<bool>(json_path("rx.spectrumInversion", '/'));
demod.rollof = pt.get<double>(json_path("rx.rolloff", '/')) / 100.0;
demod.central_freq_in_kGz = pt.get<double>(json_path("rx.centerFreq", '/'));
#ifdef MODEM_IS_SCPC #ifdef MODEM_IS_SCPC
// ACM // ACM
acm.enable = pt.get<bool>(json_path("dvbs2.isAcm", '/')); acm.period_pack = pt.get<uint32_t>("dvbServicePacketPeriod");
acm.max_modcod = (pt.get<uint32_t>(json_path("dvbs2.acm_maxModcod", '/')) << 2) | (acmIsShortFrame ? 2 : 0); acm.enable = pt.get<bool>("rxAgcEn");
acm.min_modcod = (pt.get<uint32_t>(json_path("dvbs2.acm_minModcod", '/')) << 2) | (acmIsShortFrame ? 2 : 0); acm.min_modcod = buildModcodFromPt(pt, "dvbAcmMin", acmIsShortFrame);
acm.snr_treashold_acm = pt.get<double>(json_path("dvbs2.snrReserve", '/')); // запас ОСШ acm.max_modcod = buildModcodFromPt(pt, "dvbAcmMax", acmIsShortFrame);
acm.period_pack = pt.get<uint32_t>(json_path("dvbs2.servicePacketPeriod", '/')); acm.snr_treashold_acm = pt.get<double>("dvbSnrReserve"); // запас ОСШ
acm.enable_auto_atten = pt.get<bool>(json_path("acm.en", '/')); acm.enable_auto_atten = pt.get<bool>(json_path("aupcEn", '/'));
acm.max_attenuation = pt.get<double>(json_path("acm.maxAttenuation", '/')); acm.min_attenuation = pt.get<int>("aupcMinAttenuation");
acm.min_attenuation = pt.get<double>(json_path("acm.minAttenuation", '/')); acm.max_attenuation = pt.get<int>("aupcMaxAttenuation");
acm.snr_treashold = pt.get<double>(json_path("acm.requiredSnr", '/')); // требуемый ОСШ acm.snr_treashold = pt.get<double>("aupcRequiredSnr");
daemon->setSettingsRxTx(mod, demod, acm); daemon->setSettingsRxTx(mod, demod, acm);
#else #else
@ -997,30 +1064,23 @@ void api_driver::ApiDriver::setRxTxSettings(boost::property_tree::ptree &pt) {
void api_driver::ApiDriver::setCincSettings(boost::property_tree::ptree &pt) { void api_driver::ApiDriver::setCincSettings(boost::property_tree::ptree &pt) {
DPDI_parmeters s{}; DPDI_parmeters s{};
//result << ",\n\"cinc.mode\":" << (dpdiSettings.is_delay_window ? "\"delay\"" : "\"positional\""); s.is_delay_window = !pt.get<bool>("cincIsPositional");
auto tmp = pt.get<std::string>(json_path("cinc.mode", '/')); s.freq_offset = pt.get<uint32_t>("cincSearchBandwidth");
if (tmp == "delay") { s.is_delay_window = true; }
else if (tmp == "positional") { s.is_delay_window = false; }
else {
throw std::runtime_error("Wrong CinC mode: " + tmp);
}
auto ctmp = translateCoordinates(pt.get<double>(json_path("cinc.position.station.latitude", '/'))); auto ctmp = translateCoordinates(pt.get<double>("cincPositionStationLatitude"));
s.latitude_station_grad = std::get<0>(ctmp); s.latitude_station_grad = std::get<0>(ctmp);
s.latitude_station_minute = std::get<1>(ctmp); s.latitude_station_minute = std::get<1>(ctmp);
ctmp = translateCoordinates(pt.get<double>(json_path("cinc.position.station.longitude", '/'))); ctmp = translateCoordinates(pt.get<double>("cincPositionStationLongitude"));
s.longitude_station_grad = std::get<0>(ctmp); s.longitude_station_grad = std::get<0>(ctmp);
s.longitude_station_minute = std::get<1>(ctmp); s.longitude_station_minute = std::get<1>(ctmp);
ctmp = translateCoordinates(pt.get<double>(json_path("cinc.position.satelliteLongitude", '/'))); ctmp = translateCoordinates(pt.get<double>("cincPositionSatelliteLongitude"));
s.longitude_sattelite_grad = std::get<0>(ctmp); s.longitude_sattelite_grad = std::get<0>(ctmp);
s.longitude_sattelite_minute = std::get<1>(ctmp); s.longitude_sattelite_minute = std::get<1>(ctmp);
s.max_delay = pt.get<uint32_t>(json_path("cinc.delayMax", '/')); s.min_delay = pt.get<uint32_t>("cincDelayMin");
s.min_delay = pt.get<uint32_t>(json_path("cinc.delayMin", '/')); s.max_delay = pt.get<uint32_t>("cincDelayMax");
s.freq_offset = pt.get<uint32_t>(json_path("cinc.searchBandwidth", '/'));
this->daemon->setSettingsCinc(s); this->daemon->setSettingsCinc(s);
} }
@ -1028,19 +1088,13 @@ void api_driver::ApiDriver::setCincSettings(boost::property_tree::ptree &pt) {
void api_driver::ApiDriver::setBucLnbSettings(boost::property_tree::ptree &pt) { void api_driver::ApiDriver::setBucLnbSettings(boost::property_tree::ptree &pt) {
buc_lnb_settings s{}; buc_lnb_settings s{};
#ifdef MODEM_IS_SCPC
daemon->getSettings(nullptr, nullptr, nullptr, nullptr, &s);
#else
daemon->getSettings(nullptr, nullptr, &s);
#endif
auto tmp = pt.get<int>(json_path("lnb.powering", '/')); auto tmp = pt.get<int>("bucPowering");
switch (tmp) {
case 13: s.lnb = voltage_lnb::_13V; break;
case 18: s.lnb = voltage_lnb::_18V; break;
case 24: s.lnb = voltage_lnb::_24V; break;
case 0:
default:
s.lnb = voltage_lnb::DISABLE;
}
s.is_ref_10MHz_lnb = pt.get<bool>(json_path("lnb.refClk10M", '/'));
tmp = pt.get<int>(json_path("buc.powering", '/'));
switch (tmp) { switch (tmp) {
case 24: s.buc = voltage_buc::_24V; break; case 24: s.buc = voltage_buc::_24V; break;
#ifdef MODEM_IS_SCPC #ifdef MODEM_IS_SCPC
@ -1050,11 +1104,21 @@ void api_driver::ApiDriver::setBucLnbSettings(boost::property_tree::ptree &pt) {
default: default:
s.lnb = voltage_lnb::DISABLE; s.lnb = voltage_lnb::DISABLE;
} }
s.is_ref_10MHz_buc = pt.get<bool>("bucRefClk10M");
s.is_ref_10MHz_buc = pt.get<bool>(json_path("buc.refClk10M", '/')); tmp = pt.get<int>("lnbPowering");
switch (tmp) {
case 13: s.lnb = voltage_lnb::_13V; break;
case 18: s.lnb = voltage_lnb::_18V; break;
case 24: s.lnb = voltage_lnb::_24V; break;
case 0:
default:
s.lnb = voltage_lnb::DISABLE;
}
s.is_ref_10MHz_lnb = pt.get<bool>("lnbRefClk10M");
s.is_ref_10MHz_output = pt.get<bool>(json_path("serviceSettings.refClk10M", '/')); s.is_ref_10MHz_output = pt.get<bool>("srvRefClk10M");
s.is_save_current_state = pt.get<bool>(json_path("serviceSettings.autoStart", '/')); s.is_save_current_state = pt.get<bool>("bucLnbAutoStart");
this->daemon->setSettingsBucLnb(s); this->daemon->setSettingsBucLnb(s);
} }
@ -1071,19 +1135,17 @@ void api_driver::ApiDriver::setQosSettings(boost::property_tree::ptree &pt) {
void api_driver::ApiDriver::setNetworkSettings(boost::property_tree::ptree &pt) { void api_driver::ApiDriver::setNetworkSettings(boost::property_tree::ptree &pt) {
TerminalNetworkSettings s; TerminalNetworkSettings s;
s.managementIp = pt.get<std::string>(json_path("network.managementIp", '/')); daemon->getNetworkSettings(s);
s.managementGateway = pt.get<std::string>(json_path("network.managementGateway", '/'));
s.mode = pt.get<std::string>(json_path("network.mode", '/')); s.managementIp = pt.get<std::string>("netManagementIp");
s.dataIp = pt.get<std::string>(json_path("network.dataIp", '/')); // s.managementGateway = pt.get<std::string>(json_path("network.managementGateway", '/'));
s.dataMtu = pt.get<unsigned int>(json_path("network.dataMtu", '/')); s.isL2 = pt.get<bool>("netIsL2");
s.dataIp = pt.get<std::string>("netDataIp");
s.dataMtu = pt.get<unsigned int>("netDataMtu");
daemon->setNetworkSettings(s); daemon->setNetworkSettings(s);
} }
void api_driver::ApiDriver::setDebugSendSettings(boost::property_tree::ptree &pt) {
boost::ignore_unused(pt);
}
void api_driver::ApiDriver::resetDefaultSettings() { void api_driver::ApiDriver::resetDefaultSettings() {
daemon->resetDefaultSettings(); daemon->resetDefaultSettings();
} }
@ -1102,35 +1164,34 @@ std::string api_driver::ApiDriver::loadSysInfo() {
struct sysinfo info{}; struct sysinfo info{};
sysinfo(&info); sysinfo(&info);
struct sysinfo { // struct sysinfo {
long uptime; /* Seconds since boot */ // long uptime; /* Seconds since boot */
unsigned long loads[3]; /* 1, 5, and 15 minute load averages */ // unsigned long loads[3]; /* 1, 5, and 15 minute load averages */
unsigned long totalram; /* Total usable main memory size */ // unsigned long totalram; /* Total usable main memory size */
unsigned long freeram; /* Available memory size */ // unsigned long freeram; /* Available memory size */
unsigned long sharedram; /* Amount of shared memory */ // unsigned long sharedram; /* Amount of shared memory */
unsigned long bufferram; /* Memory used by buffers */ // unsigned long bufferram; /* Memory used by buffers */
unsigned long totalswap; /* Total swap space size */ // unsigned long totalswap; /* Total swap space size */
unsigned long freeswap; /* Swap space still available */ // unsigned long freeswap; /* Swap space still available */
unsigned short procs; /* Number of current processes */ // unsigned short procs; /* Number of current processes */
unsigned long totalhigh; /* Total high memory size */ // unsigned long totalhigh; /* Total high memory size */
unsigned long freehigh; /* Available high memory size */ // unsigned long freehigh; /* Available high memory size */
unsigned int mem_unit; /* Memory unit size in bytes */ // unsigned int mem_unit; /* Memory unit size in bytes */
}; // };
double f_load = 1.0 / (1 << SI_LOAD_SHIFT);
result << "{\n\"uptime\":" << info.uptime; result << "{\n\"uptime\":" << info.uptime;
result << ",\"load1min\":" << info.loads[0]; result << ",\"load1min\":"; writeDouble(result, f_load * static_cast<double>(info.loads[0]), 2);
result << ",\"load5min\":" << info.loads[1]; result << ",\"load5min\":"; writeDouble(result, f_load * static_cast<double>(info.loads[1]), 2);
result << ",\"load15min\":" << info.loads[2]; result << ",\"load15min\":"; writeDouble(result, f_load * static_cast<double>(info.loads[2]), 2);
result << ",\"totalram\":" << info.totalram; result << ",\"totalram\":" << ((info.totalram * info.mem_unit) >> 20); // Mb
result << ",\"freeram\":" << info.freeram; result << ",\"freeram\":" << ((info.freeram * info.mem_unit) >> 20); // Mb
result << ",\"sharedram\":" << info.sharedram; // result << ",\"sharedram\":" << ((info.sharedram * info.mem_unit) >> 20); // Mb
result << ",\"bufferram\":" << info.bufferram; // result << ",\"bufferram\":" << ((info.bufferram * info.mem_unit) >> 20); // Mb
result << ",\"totalswap\":" << info.totalswap; // result << ",\"totalswap\":" << info.totalswap * info.mem_unit;
result << ",\"freeswap\":" << info.freeswap; // result << ",\"freeswap\":" << info.freeswap * info.mem_unit;
result << ",\"procs\":" << static_cast<long>(info.procs); result << ",\"procs\":" << static_cast<long>(info.procs);
result << ",\"totalhigh\":" << info.totalhigh;
result << ",\"freehigh\":" << info.freehigh;
result << ",\"mem_unit\":" << info.mem_unit;
result << "\n}"; result << "\n}";
return result.str(); return result.str();
} }

View File

@ -64,8 +64,6 @@ namespace api_driver {
void setNetworkSettings(boost::property_tree::ptree & pt); void setNetworkSettings(boost::property_tree::ptree & pt);
void setDebugSendSettings(boost::property_tree::ptree & pt);
void resetDefaultSettings(); void resetDefaultSettings();
void executeInApi(const std::function<void(TSID sid)>& callback); void executeInApi(const std::function<void(TSID sid)>& callback);

View File

@ -2,9 +2,103 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Title</title> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>RSCM-101</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> </head>
<body> <body>
<div id="app" hidden>
<header>
<span class="nav-bar-element">Прием: <span :class="{ indicator_bad: stat_rx.state === false, indicator_good: stat_rx.state === true, indicator: true }"></span></span>
<span :class="{ value_bad: initState !== 'Успешная инициализация системы' }">{{ initState }}</span>
<div class="tabs-header">
<span style="font-weight:bold">RSCM-101</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="#qos" class="tabs-btn" @click="activeTab = 'qos'" :class="{ active: activeTab === 'qos' }">QoS</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">
<p>Прием: <span :class="{ indicator_bad: stat_rx.state === false, indicator_good: stat_rx.state === true, indicator: true }"></span></p>
<p>Скорость: <span>{{ stat_rx.speedOnRxKbit }}</span></p>
<h2>Настройки</h2>
<div class="settings-set-container">
<label>
<span>Режим работы</span>
<select v-model="param.general.isCinC">
<option :value="false">SCPC</option>
<option :value="true">CinC</option>
</select>
</label>
<label>
<span>Полоса поиска, кгц ±</span>
<input v-model="param.num" type="number" min="0" max="100" step="1"/>
</label>
</div>
</div>
</div>
<script src="/js/vue.js"></script>
<script>
const app = Vue.createApp({
data() {
return {
stat_rx: {
state: false,
},
param: {
general: {
isCinC: true,
isTestInputData: false,
modulatorMode: 'test'
},
num: 1
},
initState: '?',
activeTab: 'setup'
}
},
methods: {
},
mounted() {
document.getElementById("app").removeAttribute("hidden")
}
});
app.mount('#app')
</script>
</body> </body>
</html> </html>

View File

@ -135,7 +135,7 @@ select * {
} }
.settings-set-container th, .settings-set-container td { .settings-set-container th, .settings-set-container td {
border-bottom: solid 1px var(--text-color2); border-bottom: solid 1px var(--bg-element);
} }
.settings-set-container table { border-collapse: collapse; } .settings-set-container table { border-collapse: collapse; }

File diff suppressed because it is too large Load Diff

9
static/js/vue.prod.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff