1361 lines
74 KiB
HTML
1361 lines
74 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>{{ modem_name }}</title>
|
||
<link rel="stylesheet" type="text/css" href="/style.css">
|
||
<link rel="stylesheet" type="text/css" href="/fields.css">
|
||
<style>{% raw %}
|
||
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;
|
||
}
|
||
{% endraw %}
|
||
</style>
|
||
</head>
|
||
<body>
|
||
|
||
<div id="app" hidden>
|
||
<header>{% raw %}
|
||
<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="nav-bar-element">Передача: <span :class="{ indicator_good: stat_tx.state === true, indicator: true }"></span></span>
|
||
<span class="nav-bar-element">Тест: <span :class="{ indicator_good: (param.general.isTestInputData === true || param.general.modulatorMode === 'test'), indicator: true }"></span></span>
|
||
<!-- Последнее обновление: {{ lastUpdateTime }}-->
|
||
<span :class="{ value_bad: initState !== 'Успешная инициализация системы' }">{{ initState }}</span>
|
||
{% endraw %}
|
||
<div class="tabs-header">
|
||
<span style="font-weight:bold">{{ modem_name }}</span>
|
||
{% for tab in header_tabs %}
|
||
<a href="#{{ tab.name }}" class="tabs-btn" @click="activeTab = '{{ tab.name }}'" :class="{{ '{' }} active: activeTab === '{{ tab.name }}' {{ '}' }}">{{ tab.description }}</a>
|
||
{% endfor %}
|
||
</div>
|
||
</header>
|
||
{% raw %}
|
||
<div id="content">
|
||
<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: stat_rx.state === false, indicator_good: stat_rx.state === true, indicator: true }"></span></td></tr>
|
||
<tr><th>Захват символьной</th><td><span :class="{ indicator_bad: stat_rx.sym_sync_lock === false, indicator_good: stat_rx.sym_sync_lock === true, indicator: true }"></span></td></tr>
|
||
<tr><th>Захват ФАПЧ</th><td><span :class="{ indicator_bad: stat_rx.afc_lock === false, indicator_good: stat_rx.afc_lock === true, indicator: true }"></span></td></tr>
|
||
<tr><th>Захват поиска по частоте</th><td><span :class="{ indicator_bad: stat_rx.freq_search_lock === false, indicator_good: stat_rx.freq_search_lock === true, indicator: true }"></span></td></tr>
|
||
<tr><th>Захват пакетной синхр.</th><td><span :class="{ indicator_bad: stat_rx.pkt_sync === false, indicator_good: stat_rx.pkt_sync === true, indicator: true }"></span></td></tr>
|
||
<tr><th>ОСШ/RSSI</th><td>{{ stat_rx.snr }} / {{ stat_rx.rssi }}</td></tr>
|
||
<tr><th>Modcod</th><td>{{ stat_rx.modcod }}</td></tr>
|
||
<tr><th>Размер кадра</th><td>{{ stat_rx.frameSizeNormal ? 'normal' : 'short' }}</td></tr>
|
||
<tr><th>Пилот-символы</th><td>{{ stat_rx.isPilots ? 'pilots' : 'no pilots' }}</td></tr>
|
||
<tr><th>Символьная ошибка</th><td>{{ stat_rx.symError }}</td></tr>
|
||
<tr><th>Грубая/точная част. ошибка, Гц</th><td>{{ stat_rx.freqErr }} / {{ stat_rx.freqErrAcc }}</td></tr>
|
||
<tr><th>Ур. входного сигнала</th><td>{{ stat_rx.inputSignalLevel }}</td></tr>
|
||
<tr><th>Ошибка ФАПЧ</th><td>{{ stat_rx.pllError }}</td></tr>
|
||
<tr><th>Инф. скорость на приеме</th><td>{{ stat_rx.speedOnRxKbit }} kbit/s</td></tr>
|
||
<tr><th>Инф. скорость на интерфейсе</th><td>{{ stat_rx.speedOnIifKbit }} kbit/s</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<p> Статистика пакетов </p>
|
||
<table>
|
||
<tbody>
|
||
<tr><th>Качественных пакетов</th><td>{{ stat_rx.packetsOk }}</td></tr>
|
||
<tr><th>Поврежденных пакетов</th><td>{{ stat_rx.packetsBad }}</td></tr>
|
||
<tr><th>DUMMY</th><td>{{ stat_rx.packetsDummy }}</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<button class="action-button" @click="resetPacketsStatistics()"> Сброс статистики </button>
|
||
</div>
|
||
<div class="settings-set-container">
|
||
<h2>Статистика передачи</h2>
|
||
<table>
|
||
<tbody>
|
||
<tr><th>Передача</th><td><span :class="{ indicator_bad: stat_tx.state === false, indicator_good: stat_tx.state === true, indicator: true }"></span></td></tr>
|
||
<tr><th>ОСШ дальнего приема</th><td>{{ stat_tx.snr }}</td></tr>
|
||
<tr><th>Modcod</th><td>{{ stat_tx.modcod }}</td></tr>
|
||
<tr><th>Размер кадра</th><td>{{ stat_tx.frameSizeNormal ? 'normal' : 'short' }}</td></tr>
|
||
<tr><th>Пилот-символы</th><td>{{ stat_tx.isPilots ? 'pilots' : 'no pilots' }}</td></tr>
|
||
<tr><th>Инф. скорость на передаче</th><td>{{ stat_tx.speedOnTxKbit }} kbit/s</td></tr>
|
||
<tr><th>Инф. скорость на интерфейсе</th><td>{{ stat_tx.speedOnIifKbit }} kbit/s</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="settings-set-container" v-if="isCinC === true">
|
||
<h2>Статистика режима CinC</h2>
|
||
<table>
|
||
<tbody>
|
||
<tr><th>ОСС</th><td>{{ stat_cinc.occ }}</td></tr>
|
||
<tr><th>Захват коррелятора</th><td><span :class="{ indicator_bad: stat_cinc.correlator === false, indicator_good: stat_cinc.correlator === true, indicator: true }"></span></td></tr>
|
||
<tr><th>Кол-во срывов коррелятора</th><td>{{ stat_cinc.correlatorFails }}</td></tr>
|
||
<tr><th>Грубая/точная част. ошибка, Гц</th><td>{{ stat_cinc.freqErr }} / {{ stat_cinc.freqErrAcc }}</td></tr>
|
||
<tr><th>Задержка в канале, мс</th><td>{{ stat_cinc.channelDelay }}</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="settings-set-container">
|
||
<h2>Состояние устройства</h2>
|
||
<table>
|
||
<tbody>
|
||
<tr><th>Температура ADRV</th><td>{{ stat_device.adrv }} °C</td></tr>
|
||
<tr><th>Температура ZYNQ</th><td>{{ stat_device.zynq }} °C</td></tr>
|
||
<tr><th>Температура FPGA</th><td>{{ stat_device.fpga }} °C</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="tabs-body-item" v-if="activeTab === 'setup' && settingFetchComplete">
|
||
<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>
|
||
</div>
|
||
<div class="tabs-item-flex-container">
|
||
<div class="settings-set-container">
|
||
<h3>Настройки передатчика</h3>
|
||
<label>
|
||
<span>Включить передатчик</span>
|
||
<span class="toggle-input">
|
||
<input type="checkbox" v-model="param.general.txEn" />
|
||
<span class="slider"></span>
|
||
</span>
|
||
</label>
|
||
<label>
|
||
<span>Автоматический запуск передатчика</span>
|
||
<span class="toggle-input">
|
||
<input type="checkbox" v-model="param.general.autoStartTx" />
|
||
<span class="slider"></span>
|
||
</span>
|
||
</label>
|
||
<label>
|
||
<span>Режим работы модулятора</span>
|
||
<select v-model="param.general.modulatorMode">
|
||
<option value="normal">Нормальный</option>
|
||
<option value="test">Тест (CW)</option>
|
||
</select>
|
||
</label>
|
||
<label>
|
||
<span>Входные данные</span>
|
||
<select v-model="param.general.isTestInputData">
|
||
<option :value="false">Ethernet</option>
|
||
<option :value="true">Тест (CW)</option>
|
||
</select>
|
||
</label>
|
||
<h3>Параметры передачи</h3>
|
||
<label>
|
||
<span>Центральная частота, КГц</span>
|
||
<input v-model="param.tx.centerFreq" type="number" step="0.01"/>
|
||
</label>
|
||
<label>
|
||
<span>Символьная скорость, Бод</span>
|
||
<input v-model="param.tx.cymRate" type="number"/>
|
||
</label>
|
||
<label>
|
||
<span>Roll-off</span>
|
||
<select v-model="param.tx.rolloff">
|
||
<option :value="5">0.05</option>
|
||
<option :value="10">0.10</option>
|
||
<option :value="15">0.15</option>
|
||
<option :value="20">0.20</option>
|
||
<option :value="25">0.25</option>
|
||
</select>
|
||
</label>
|
||
<label>
|
||
<span>Ослабление, дБ</span>
|
||
<input v-model="param.tx.attenuation" type="number" step="0.01"/>
|
||
</label>
|
||
</div>
|
||
|
||
<div class="settings-set-container">
|
||
<h3>Режим работы DVB-S2</h3>
|
||
<label>
|
||
<span>Период служебных пакетов, сек</span>
|
||
<input v-model="param.dvbs2.servicePacketPeriod" type="number">
|
||
</label>
|
||
<label>
|
||
<span>Режим</span>
|
||
<select v-model="param.dvbs2.mode">
|
||
<option value="ccm">CCM</option>
|
||
<option value="acm">ACM</option>
|
||
</select>
|
||
</label>
|
||
<label>
|
||
<span>Размер кадра</span>
|
||
<select v-model="param.dvbs2.frameSizeNormal">
|
||
<option :value="true">normal</option>
|
||
<option :value="false">short</option>
|
||
</select>
|
||
</label>
|
||
<!-- <label>-->
|
||
<!-- <span>Пилот-символы</span>-->
|
||
<!-- <select v-model="param.dvbs2.isPilots">-->
|
||
<!-- <option :value="true">pilots</option>-->
|
||
<!-- <option :value="false">no pilots</option>-->
|
||
<!-- </select>-->
|
||
<!-- </label>-->
|
||
|
||
<label v-show="param.dvbs2.mode === 'ccm'">
|
||
<span>Модуляция</span>
|
||
<select v-model="param.dvbs2.ccm_modulation" @change="param.dvbs2.ccm_speed = correctModcodSpeed(param.dvbs2.ccm_modulation, param.dvbs2.ccm_speed)">
|
||
<option value="qpsk">QPSK</option>
|
||
<option value="8psk">8PSK</option>
|
||
<option value="16apsk">16APSK</option>
|
||
<option value="32apsk">32APSK</option>
|
||
</select>
|
||
</label>
|
||
<label v-show="param.dvbs2.mode === 'ccm'">
|
||
<span>Скорость кода</span>
|
||
<select v-model="param.dvbs2.ccm_speed">
|
||
<option v-for="speed in getAvailableModcods(param.dvbs2.ccm_modulation)" v-bind:value="speed">{{ speed }}</option>
|
||
</select>
|
||
</label>
|
||
|
||
<label v-show="param.dvbs2.mode === 'acm'">
|
||
<span>Текущий модкод</span>
|
||
<input v-model="stat_rx.modcod" readonly>
|
||
</label>
|
||
|
||
<label v-show="param.dvbs2.mode === 'acm'">
|
||
<span>Модуляция (макс. режим)</span>
|
||
<select v-model="param.dvbs2.acm_maxModulation" @change="param.dvbs2.acm_maxSpeed = correctModcodSpeed(param.dvbs2.acm_maxModulation, param.dvbs2.acm_maxSpeed)">
|
||
<option value="qpsk">QPSK</option>
|
||
<option value="8psk">8PSK</option>
|
||
<option value="16apsk">16APSK</option>
|
||
<option value="32apsk">32APSK</option>
|
||
</select>
|
||
</label>
|
||
<label v-show="param.dvbs2.mode === 'acm'">
|
||
<span>Скорость кода (макс. режим)</span>
|
||
<select v-model="param.dvbs2.acm_maxSpeed">
|
||
<option v-for="speed in getAvailableModcods(param.dvbs2.acm_maxModulation)" v-bind:value="speed">{{ speed }}</option>
|
||
</select>
|
||
</label>
|
||
<label v-show="param.dvbs2.mode === 'acm'">
|
||
<span>Модуляция (мин. режим)</span>
|
||
<select v-model="param.dvbs2.acm_minModulation" @change="param.dvbs2.acm_minSpeed = correctModcodSpeed(param.dvbs2.acm_minModulation, param.dvbs2.acm_minSpeed)">
|
||
<option value="qpsk">QPSK</option>
|
||
<option value="8psk">8PSK</option>
|
||
<option value="16apsk">16APSK</option>
|
||
<option value="32apsk">32APSK</option>
|
||
</select>
|
||
</label>
|
||
<label v-show="param.dvbs2.mode === 'acm'">
|
||
<span>Скорость кода (мин. режим)</span>
|
||
<select v-model="param.dvbs2.acm_minSpeed">
|
||
<option v-for="speed in getAvailableModcods(param.dvbs2.acm_minModulation)" v-bind:value="speed">{{ speed }}</option>
|
||
</select>
|
||
</label>
|
||
<label v-show="param.dvbs2.mode === 'acm'">
|
||
<span>Запас ОСШ</span>
|
||
<input v-model="param.dvbs2.snrReserve" type="number" step="0.01">
|
||
</label>
|
||
|
||
<h3>Авто-регулировка мощности</h3>
|
||
<label>
|
||
<span>Авто-регулировка мощности</span>
|
||
<span class="toggle-input">
|
||
<input type="checkbox" v-model="param.acm.en" />
|
||
<span class="slider"></span>
|
||
</span>
|
||
</label>
|
||
<label>
|
||
<span>Максимальное ослабление</span>
|
||
<input v-model="param.acm.maxAttenuation" type="number" step="0.01"/>
|
||
</label>
|
||
<label>
|
||
<span>Минимальное ослабление</span>
|
||
<input v-model="param.acm.minAttenuation" type="number" step="0.01"/>
|
||
</label>
|
||
<label>
|
||
<span>Требуемое ОСШ</span>
|
||
<input v-model="param.acm.requiredSnr" type="number" step="0.01"/>
|
||
</label>
|
||
</div>
|
||
<div class="settings-set-container">
|
||
<h3>Настройка приемника</h3>
|
||
<label>
|
||
<span>Режим управления усилением</span>
|
||
<select v-model="param.rx.gainMode">
|
||
<option value="auto">АРУ</option>
|
||
<option value="manual">РРУ</option>
|
||
</select>
|
||
</label>
|
||
<label v-show="param.rx.gainMode === 'manual'">
|
||
<span>Усиление, dB</span>
|
||
<input v-model="param.rx.manualGain" type="number"/>
|
||
</label>
|
||
<label>
|
||
<span>Инверсия спектра</span>
|
||
<span class="toggle-input">
|
||
<input type="checkbox" v-model="param.rx.spectrumInversion" />
|
||
<span class="slider"></span>
|
||
</span>
|
||
</label>
|
||
<label>
|
||
<span>Центральная частота, кГц</span>
|
||
<input v-model="param.rx.centerFreq" type="number" step="0.01"/>
|
||
</label>
|
||
<label>
|
||
<span>Символьная скорость, Бод</span>
|
||
<input v-model="param.rx.cymRate" type="number"/>
|
||
</label>
|
||
<label>
|
||
<span>Roll-off</span>
|
||
<select v-model="param.rx.rolloff">
|
||
<option :value="5">0.05</option>
|
||
<option :value="10">0.10</option>
|
||
<option :value="15">0.15</option>
|
||
<option :value="20">0.20</option>
|
||
<option :value="25">0.25</option>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<button class="action-button" @click="settingsSubmitRxTx()">Сохранить <span class="submit-spinner" v-show="submitStatus.rxTx"></span></button>
|
||
|
||
<h2 v-show="param.general.isCinC === true">Настройки режима CinC</h2>
|
||
<div v-show="param.general.isCinC === true" class="settings-set-container">
|
||
<label>
|
||
<span>Метод расчета задержки</span>
|
||
<select v-model="param.cinc.mode">
|
||
<option value="positional">Позиционированием</option>
|
||
<option value="delay">Окном задержки</option>
|
||
</select>
|
||
</label>
|
||
|
||
<h3 v-show="param.cinc.mode === 'positional'">Настройки позиционирования</h3>
|
||
<label v-show="param.cinc.mode === 'positional'">
|
||
<span>Широта станции</span>
|
||
<input v-model="param.cinc.position.station.latitude" type="number" step="0.000001"/>
|
||
</label>
|
||
<label v-show="param.cinc.mode === 'positional'">
|
||
<span>Долгота станции</span>
|
||
<input v-model="param.cinc.position.station.longitude" type="number" step="0.000001"/>
|
||
</label>
|
||
<label v-show="param.cinc.mode === 'positional'">
|
||
<span>Подспутниковая точка</span>
|
||
<input v-model="param.cinc.position.satelliteLongitude" type="number" step="0.000001"/>
|
||
</label>
|
||
|
||
<h3 v-show="param.cinc.mode === 'delay'">Задержка до спутника</h3>
|
||
<label v-show="param.cinc.mode === 'delay'">
|
||
<span>от, мс</span>
|
||
<input v-model="param.cinc.delayMin" type="number"/>
|
||
</label>
|
||
<label v-show="param.cinc.mode === 'delay'">
|
||
<span>до, мс</span>
|
||
<input v-model="param.cinc.delayMax" type="number"/>
|
||
</label>
|
||
</div>
|
||
<button class="action-button" v-show="param.general.isCinC" @click="settingsSubmitCinC()" type="submit">Сохранить <span class="submit-spinner" v-show="submitStatus.cinc"></span></button>
|
||
|
||
<h2>Настройки питания и опорного генератора</h2>
|
||
<div class="tabs-item-flex-container">
|
||
<div class="settings-set-container">
|
||
<h3>Настройки BUC</h3>
|
||
<label>
|
||
<span>Подача опоры 10МГц</span>
|
||
<span class="toggle-input">
|
||
<input type="checkbox" v-model="param.buc.refClk10M" />
|
||
<span class="slider"></span>
|
||
</span>
|
||
</label>
|
||
<label>
|
||
<span>Питание BUC</span>
|
||
<select v-model="param.buc.powering">
|
||
<option value="0">выкл</option>
|
||
<option value="24">24В</option>
|
||
<option value="48">48В</option>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
<div class="settings-set-container">
|
||
<h3>Настройки LNB</h3>
|
||
<label>
|
||
<span>Подача опоры 10МГц</span>
|
||
<span class="toggle-input">
|
||
<input type="checkbox" v-model="param.lnb.refClk10M" />
|
||
<span class="slider"></span>
|
||
</span>
|
||
</label>
|
||
<label>
|
||
<span>Питание LNB</span>
|
||
<select v-model="param.lnb.powering">
|
||
<option value="0">выкл</option>
|
||
<option value="13">13В</option>
|
||
<option value="18">18В</option>
|
||
<option value="24">24В</option>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
<div class="settings-set-container">
|
||
<h3>Сервисные настройки</h3>
|
||
<label>
|
||
<span>Подача опоры 10МГц на 'Выход 10МГц'</span>
|
||
<span class="toggle-input">
|
||
<input type="checkbox" v-model="param.serviceSettings.refClk10M" />
|
||
<span class="slider"></span>
|
||
</span>
|
||
</label>
|
||
<label>
|
||
<span>Автозапуск BUC и LNB при включении</span>
|
||
<span class="toggle-input">
|
||
<input type="checkbox" v-model="param.serviceSettings.autoStart" />
|
||
<span class="slider"></span>
|
||
</span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<button class="action-button" @click="settingsSubmitBucLnb()">Сохранить <span class="submit-spinner" v-show="submitStatus.bucLnb"></span></button>
|
||
</div>
|
||
<div class="tabs-body-item" v-if="activeTab === 'qos' && settingFetchComplete">
|
||
<h2>Настройки QoS</h2>
|
||
<div class="settings-set-container">
|
||
<label>
|
||
<span>Активировать QoS</span>
|
||
<span class="toggle-input"><input type="checkbox" v-model="param.qos.en" /><span class="slider"></span></span>
|
||
</label>
|
||
</div>
|
||
<template>
|
||
<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 param.qos[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>
|
||
</template>
|
||
<button class="action-button" @click="settingsSubmitQoS()">Применить <span class="submit-spinner" v-show="submitStatus.qos"></span></button>
|
||
|
||
<h2 hidden>Настройки TCP-акселерации</h2>
|
||
<div hidden class="settings-set-container">
|
||
<label>
|
||
<span>Активировать акселерацию</span>
|
||
<span class="toggle-input"><input type="checkbox" v-model="param.tcpAccel.en" /><span class="slider"></span></span>
|
||
</label>
|
||
<label>
|
||
<span>Максимальное количество соединений</span>
|
||
<input type="number" v-model="param.tcpAccel.maxConnections" min="1" max="10000" />
|
||
</label>
|
||
</div>
|
||
<button hidden class="action-button" @click="settingsSubmitTcpAccel()">Применить <span class="submit-spinner" v-show="submitStatus.tcpAccel"></span></button>
|
||
</div>
|
||
<div class="tabs-body-item" v-if="activeTab === 'admin' && settingFetchComplete">
|
||
<h2>Настройки сети</h2>
|
||
<div class="settings-set-container">
|
||
<h3>Интерфейс управления</h3>
|
||
<label>
|
||
<span>IP адрес/маска</span>
|
||
<input v-model="param.network.managementIp" required type="text" pattern="^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}$">
|
||
</label>
|
||
<label>
|
||
<span>Шлюз интерфейса управления</span>
|
||
<input v-model="param.network.managementGateway" type="text" pattern="^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}$">
|
||
</label>
|
||
<label>
|
||
<span>Режим модема</span>
|
||
<select v-model="param.network.mode">
|
||
<option value="l2">Коммутатор</option>
|
||
<option value="l3">Маршрутизатор</option>
|
||
</select>
|
||
</label>
|
||
<h3>Интерфейс данных</h3>
|
||
<label v-if="param.network.mode === 'l3'">
|
||
<span>IP адрес/маска</span>
|
||
<input v-model="param.network.dataIp" required type="text" pattern="^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}$">
|
||
</label>
|
||
<label>
|
||
<span>MTU</span>
|
||
<input v-model="param.network.dataMtu" required type="number" min="1500" max="9000">
|
||
</label>
|
||
<button class="action-button" @click="settingsSubmitNetwork()">Применить <span class="submit-spinner" v-show="submitStatus.network"></span></button>
|
||
</div>
|
||
<div class="settings-set-container">
|
||
<h3>Отладка</h3>
|
||
<label>
|
||
<span>Передача отладочной информации</span>
|
||
<span class="toggle-input">
|
||
<input type="checkbox" v-model="param.debugSend.en" />
|
||
<span class="slider"></span>
|
||
</span>
|
||
</label>
|
||
<label v-if="param.debugSend.en">
|
||
<span>IP адрес получателя</span>
|
||
<input v-model="param.debugSend.receiverIp" required type="text" pattern="^([0-9]{1,3}\.){3}[0-9]{1,3}">
|
||
</label>
|
||
<label>
|
||
<span>Порт для данных</span>
|
||
<input v-model="param.debugSend.portCinC" type="number" min="0" max="65535">
|
||
</label>
|
||
<label>
|
||
<span>Порт для CinC</span>
|
||
<input v-model="param.debugSend.portData" type="number" min="0" max="65535">
|
||
</label>
|
||
<label>
|
||
<span>Таймаут</span>
|
||
<input v-model="param.debugSend.timeout" type="number" pattern="^[0-9]+$">
|
||
</label>
|
||
<button class="action-button" @click="settingsSubmitDebugSend()">Применить <span class="submit-spinner" v-show="submitStatus.network"></span></button>
|
||
</div>
|
||
<div class="settings-set-container">
|
||
<h3>Управление ПО</h3>
|
||
<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>
|
||
</div>
|
||
<p>Последнее обновление статистики: {{ lastUpdateTime }}</p>
|
||
</div>
|
||
{% endraw %}
|
||
</div>
|
||
<script src="/js/vue.js"></script>
|
||
<script>
|
||
// const router = useRouter();
|
||
const availableTabs = {{ js_tabs_array }}
|
||
const defaultTab = availableTabs[0]
|
||
|
||
{% include 'default-js.js' %}
|
||
{% raw %}
|
||
const app = new Vue({
|
||
el: '#app',
|
||
data: {
|
||
{% endraw %}{% include 'vue-data.js' %}{% raw %}
|
||
},
|
||
methods: {
|
||
getAvailableModcods(modulation) {
|
||
// NOTE модкоды со скоростью хода 3/5 не работают
|
||
switch (modulation) {
|
||
case 'qpsk':
|
||
return ['1/4', '1/3', '2/5', '1/2', /* '3/5',*/ '2/3', '3/4', '4/5', '5/6', '8/9', '9/10']
|
||
case '8psk':
|
||
return [/* '3/5',*/ '2/3', '3/4', '5/6', '8/9', '9/10']
|
||
case '16apsk':
|
||
return ['2/3', '3/4', '4/5', '5/6', '8/9', '9/10']
|
||
case '32apsk':
|
||
return ['3/4', '4/5', '5/6', '8/9', '9/10']
|
||
default:
|
||
return []
|
||
}
|
||
},
|
||
|
||
updateStatistics(vals) {
|
||
this.lastUpdateTime = new Date();
|
||
this.initState = vals["mainState"]["initState"]
|
||
this.isCinC = vals["mainState"]["isCinC"]
|
||
|
||
this.stat_rx.state = vals["mainState"]["rx.state"]
|
||
this.stat_rx.sym_sync_lock = vals["mainState"]["rx.sym_sync_lock"]
|
||
this.stat_rx.freq_search_lock = vals["mainState"]["rx.freq_search_lock"]
|
||
this.stat_rx.afc_lock = vals["mainState"]["rx.afc_lock"]
|
||
this.stat_rx.pkt_sync = vals["mainState"]["rx.pkt_sync"]
|
||
this.stat_rx.snr = vals["mainState"]["rx.snr"]
|
||
this.stat_rx.rssi = vals["mainState"]["rx.rssi"]
|
||
this.stat_rx.modcod = modcodToStr(vals["mainState"]["rx.modcod"])
|
||
this.stat_rx.frameSizeNormal = vals["mainState"]["rx.frameSizeNormal"]
|
||
this.stat_rx.isPilots = vals["mainState"]["rx.isPilots"]
|
||
this.stat_rx.symError = vals["mainState"]["rx.symError"]
|
||
this.stat_rx.freqErr = vals["mainState"]["rx.freqErr"]
|
||
this.stat_rx.freqErrAcc = vals["mainState"]["rx.freqErrAcc"]
|
||
this.stat_rx.inputSignalLevel = vals["mainState"]["rx.inputSignalLevel"]
|
||
this.stat_rx.pllError = vals["mainState"]["rx.pllError"]
|
||
this.stat_rx.speedOnRxKbit = vals["mainState"]["rx.speedOnRxKbit"]
|
||
this.stat_rx.speedOnIifKbit = vals["mainState"]["rx.speedOnIifKbit"]
|
||
this.stat_rx.packetsOk = vals["mainState"]["rx.packetsOk"]
|
||
this.stat_rx.packetsBad = vals["mainState"]["rx.packetsBad"]
|
||
this.stat_rx.packetsDummy = vals["mainState"]["rx.packetsDummy"]
|
||
|
||
this.stat_tx.state = vals["mainState"]["tx.state"]
|
||
this.stat_tx.snr = vals["mainState"]["tx.snr"]
|
||
this.stat_tx.modcod = modcodToStr(vals["mainState"]["tx.modcod"])
|
||
this.stat_tx.frameSizeNormal = vals["mainState"]["tx.frameSizeNormal"]
|
||
this.stat_tx.isPilots = vals["mainState"]["tx.isPilots"]
|
||
this.stat_tx.speedOnTxKbit = vals["mainState"]["tx.speedOnTxKbit"]
|
||
this.stat_tx.speedOnIifKbit = vals["mainState"]["tx.speedOnIifKbit"]
|
||
|
||
this.stat_cinc.occ = vals["mainState"]["cinc.occ"]
|
||
this.stat_cinc.correlator = vals["mainState"]["cinc.correlator"]
|
||
this.stat_cinc.correlatorFails = vals["mainState"]["cinc.correlatorFails"]
|
||
this.stat_cinc.freqErr = vals["mainState"]["cinc.freqErr"]
|
||
this.stat_cinc.freqErrAcc = vals["mainState"]["cinc.freqErrAcc"]
|
||
this.stat_cinc.channelDelay = vals["mainState"]["cinc.channelDelay"]
|
||
|
||
this.stat_device.adrv = vals["mainState"]["device.adrv"]
|
||
this.stat_device.zynq = vals["mainState"]["device.zynq"]
|
||
this.stat_device.fpga = vals["mainState"]["device.fpga"]
|
||
|
||
this.testState = vals["mainState"]["testState"]
|
||
},
|
||
|
||
resetPacketsStatistics() {
|
||
fetch('/api/resetPacketStatistics', {
|
||
method: 'POST'
|
||
}).then(() => {
|
||
this.stat_rx.packetsOk = 0
|
||
this.stat_rx.packetsBad = 0
|
||
this.stat_rx.packetsDummy = 0
|
||
})
|
||
},
|
||
|
||
settingsSubmitRxTx() {
|
||
if (this.submitStatus.rxTx) { return }
|
||
// потом добавить: "dvbs2.isPilots": this.param.dvbs2.isPilots
|
||
let query = {
|
||
"general.isCinC": this.param.general.isCinC,
|
||
"general.txEn": this.param.general.txEn,
|
||
"general.modulatorMode": this.param.general.modulatorMode,
|
||
"general.autoStartTx": this.param.general.autoStartTx,
|
||
"general.isTestInputData": this.param.general.isTestInputData,
|
||
"tx.attenuation": this.param.tx.attenuation,
|
||
"tx.rolloff": this.param.tx.rolloff,
|
||
"tx.cymRate": this.param.tx.cymRate,
|
||
"tx.centerFreq": this.param.tx.centerFreq,
|
||
"dvbs2.isAcm": this.param.dvbs2.mode === 'acm',
|
||
"dvbs2.frameSizeNormal": this.param.dvbs2.frameSizeNormal,
|
||
"dvbs2.ccm_modcod": toModcod(this.param.dvbs2.ccm_modulation, this.param.dvbs2.ccm_speed),
|
||
"dvbs2.acm_minModcod": toModcod(this.param.dvbs2.acm_minModulation, this.param.dvbs2.acm_minSpeed),
|
||
"dvbs2.acm_maxModcod": toModcod(this.param.dvbs2.acm_maxModulation, this.param.dvbs2.acm_maxSpeed),
|
||
"dvbs2.snrReserve": this.param.dvbs2.snrReserve,
|
||
"dvbs2.servicePacketPeriod": this.param.dvbs2.servicePacketPeriod,
|
||
"acm.en": this.param.acm.en,
|
||
"acm.maxAttenuation": this.param.acm.maxAttenuation,
|
||
"acm.minAttenuation": this.param.acm.minAttenuation,
|
||
"acm.requiredSnr": this.param.acm.requiredSnr,
|
||
"rx.gainMode": this.param.rx.gainMode,
|
||
"rx.manualGain": this.param.rx.manualGain,
|
||
"rx.spectrumInversion": this.param.rx.spectrumInversion,
|
||
"rx.rolloff": this.param.rx.rolloff,
|
||
"rx.cymRate": this.param.rx.cymRate,
|
||
"rx.centerFreq": this.param.rx.centerFreq
|
||
}
|
||
|
||
this.submitStatus.rxTx = true
|
||
fetch('/api/set/rxtx', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify(query)
|
||
}).then(async (resp) => {
|
||
this.submitStatus.rxTx = false
|
||
this.updateRxTxSettings(await resp.json())
|
||
}).catch((reason) => {
|
||
this.submitStatus.rxTx = false
|
||
alert(`Ошибка при применении настроек: ${reason}`)
|
||
})
|
||
},
|
||
|
||
settingsSubmitCinC() {
|
||
if (this.submitStatus.cinc) { return }
|
||
|
||
let query = {
|
||
"cinc.mode": this.param.cinc.mode,
|
||
"cinc.searchBandwidth": this.param.cinc.searchBandwidth,
|
||
"cinc.position.station.latitude": this.param.cinc.position.station.latitude,
|
||
"cinc.position.station.longitude": this.param.cinc.position.station.longitude,
|
||
"cinc.position.satelliteLongitude": this.param.cinc.position.satelliteLongitude,
|
||
"cinc.delayMin": this.param.cinc.delayMin,
|
||
"cinc.delayMax": this.param.cinc.delayMax
|
||
}
|
||
this.submitStatus.cinc = true
|
||
fetch('/api/set/cinc', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify(query)
|
||
}).then(async (resp) => {
|
||
this.submitStatus.cinc = false
|
||
this.updateCincSettings(await resp.json())
|
||
}).catch((reason) => {
|
||
this.submitStatus.cinc = false
|
||
alert(`Ошибка при применении настроек: ${reason}`)
|
||
})
|
||
},
|
||
|
||
settingsSubmitBucLnb() {
|
||
if (this.submitStatus.bucLnb) { return }
|
||
let query = {
|
||
"buc.refClk10M": this.param.buc.refClk10M,
|
||
"buc.powering": parseInt(this.param.buc.powering),
|
||
"lnb.refClk10M": this.param.lnb.refClk10M,
|
||
"lnb.powering": parseInt(this.param.lnb.powering),
|
||
"serviceSettings.refClk10M": this.param.serviceSettings.refClk10M,
|
||
"serviceSettings.autoStart": this.param.serviceSettings.autoStart
|
||
}
|
||
if (confirm('Вы уверены, что хотите сохранить настройки BUC и LNB?')) {
|
||
this.submitStatus.bucLnb = true
|
||
fetch('/api/set/bucLnb', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify(query)
|
||
}).then(async (resp) => {
|
||
this.submitStatus.bucLnb = false
|
||
this.updateBucLnbSettings(await resp.json())
|
||
}).catch((reason) => {
|
||
this.submitStatus.bucLnb = false
|
||
alert(`Ошибка при применении настроек: ${reason}`)
|
||
})
|
||
}
|
||
},
|
||
|
||
settingsSubmitQoS() {
|
||
if (this.submitStatus.qos) { return }
|
||
this.submitStatus.qos = 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.param.qos.en,
|
||
"rt1": [],
|
||
"rt2": [],
|
||
"rt3": [],
|
||
"cd": []
|
||
}
|
||
for (let i = 0; i < this.param.qos.rt1.length; i++) { query.rt1.push(_translateQosClass('rt', this.param.qos.rt1[i])) }
|
||
for (let i = 0; i < this.param.qos.rt2.length; i++) { query.rt2.push(_translateQosClass('rt', this.param.qos.rt2[i])) }
|
||
for (let i = 0; i < this.param.qos.rt3.length; i++) { query.rt3.push(_translateQosClass('rt', this.param.qos.rt3[i])) }
|
||
for (let i = 0; i < this.param.qos.cd.length; i++) { query.cd.push(_translateQosClass('rt', this.param.qos.cd[i])) }
|
||
|
||
console.log(query)
|
||
fetch('/api/set/qos', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify(query)
|
||
}).then(async (resp) => {
|
||
this.submitStatus.qos = false
|
||
this.updateQosSettings(await resp.json())
|
||
}).catch((reason) => {
|
||
this.submitStatus.qos = false
|
||
alert(`Ошибка при применении настроек: ${reason}`)
|
||
})
|
||
},
|
||
|
||
settingsSubmitTcpAccel() {
|
||
if (this.submitStatus.tcpAccel) { return }
|
||
this.submitStatus.tcpAccel = true
|
||
fetch('/api/set/tcpAccel', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify({
|
||
"tcpAccel.en": this.param.tcpAccel.en,
|
||
"tcpAccel.maxConnections": this.param.tcpAccel.maxConnections
|
||
})
|
||
}).then(async (resp) => {
|
||
this.submitStatus.tcpAccel = false
|
||
this.updateNetworkSettings(await resp.json())
|
||
}).catch((reason) => {
|
||
this.submitStatus.tcpAccel = false
|
||
alert(`Ошибка при применении настроек: ${reason}`)
|
||
})
|
||
},
|
||
|
||
settingsSubmitNetwork() {
|
||
if (this.submitStatus.network) { return }
|
||
let query = {
|
||
"network.managementIp": this.param.network.managementIp,
|
||
"network.managementGateway": this.param.network.managementGateway,
|
||
"network.mode": this.param.network.mode,
|
||
"network.dataIp": this.param.network.dataIp,
|
||
"network.dataMtu": this.param.network.dataMtu
|
||
}
|
||
if (confirm('Вы уверены, что хотите сохранить настройки сети? После этого модем может стать недоступным.')) {
|
||
this.submitStatus.network = true
|
||
fetch('/api/set/network', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify(query)
|
||
}).then(async (resp) => {
|
||
this.submitStatus.network = false
|
||
this.updateNetworkSettings(await resp.json())
|
||
}).catch((reason) => {
|
||
this.submitStatus.network = false
|
||
alert(`Ошибка при применении настроек: ${reason}`)
|
||
})
|
||
}
|
||
},
|
||
|
||
settingsSubmitDebugSend() {
|
||
if (this.submitStatus.debugSend) { return }
|
||
let query = {
|
||
"debugSend.en": this.param.debugSend.en,
|
||
"debugSend.receiverIp": this.param.debugSend.receiverIp,
|
||
"debugSend.portCinC": this.param.debugSend.portCinC,
|
||
"debugSend.portData": this.param.debugSend.portData,
|
||
"debugSend.timeout": this.param.debugSend.timeout
|
||
}
|
||
this.submitStatus.debugSend = true
|
||
fetch('/api/set/debugSend', {
|
||
method: 'POST',
|
||
headers: {
|
||
'Content-Type': 'application/json'
|
||
},
|
||
body: JSON.stringify(query)
|
||
}).then(async (resp) => {
|
||
this.submitStatus.debugSend = false
|
||
this.updateNetworkSettings(await resp.json())
|
||
}).catch((reason) => {
|
||
this.submitStatus.debugSend = false
|
||
alert(`Ошибка при применении настроек: ${reason}`)
|
||
})
|
||
},
|
||
|
||
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
|
||
},
|
||
|
||
performUpdateSettings(reloadParts) {
|
||
const doFetchSettings = async () => {
|
||
let d = await fetch("/api/get/settings")
|
||
let vals = await d.json()
|
||
if (reloadParts !== undefined) {
|
||
if (reloadParts.indexOf('rxtx')) { this.updateRxTxSettings(vals) }
|
||
if (reloadParts.indexOf('cinc')) { this.updateCincSettings(vals) }
|
||
if (reloadParts.indexOf('buclnb')) { this.updateBucLnbSettings(vals) }
|
||
if (reloadParts.indexOf('qos')) { this.updateQosSettings(vals) }
|
||
} else {
|
||
this.updateSettings(vals)
|
||
}
|
||
}
|
||
|
||
doFetchSettings().then(() => {})
|
||
},
|
||
|
||
updateRxTxSettings(vals) {
|
||
this.submitStatus.rxTx = false
|
||
this.param.general.isCinC = vals["settings"]["general.isCinC"]
|
||
this.param.general.txEn = vals["settings"]["general.txEn"]
|
||
this.param.general.modulatorMode = vals["settings"]["general.modulatorMode"]
|
||
this.param.general.autoStartTx = vals["settings"]["general.autoStartTx"]
|
||
this.param.general.isTestInputData = vals["settings"]["general.isTestInputData"]
|
||
|
||
this.param.tx.attenuation = vals["settings"]["tx.attenuation"]
|
||
this.param.tx.rolloff = vals["settings"]["tx.rolloff"]
|
||
this.param.tx.cymRate = vals["settings"]["tx.cymRate"]
|
||
this.param.tx.centerFreq = vals["settings"]["tx.centerFreq"]
|
||
|
||
this.param.dvbs2.mode = (vals["settings"]["dvbs2.isAcm"] ? 'acm' : 'ccm')
|
||
this.param.dvbs2.frameSizeNormal = vals["settings"]["dvbs2.frameSizeNormal"]
|
||
// this.param.dvbs2.isPilots = vals["settings"]["dvbs2.isPilots"]
|
||
|
||
let m = extractModulationAndSpeedFromModcod(vals["settings"]["dvbs2.ccm_modcod"])
|
||
this.param.dvbs2.ccm_modulation = m.modulation
|
||
this.param.dvbs2.ccm_speed = m.speed
|
||
m = extractModulationAndSpeedFromModcod(vals["settings"]["dvbs2.acm_maxModcod"])
|
||
this.param.dvbs2.acm_maxModulation = m.modulation
|
||
this.param.dvbs2.acm_maxSpeed = m.speed
|
||
m = extractModulationAndSpeedFromModcod(vals["settings"]["dvbs2.acm_minModcod"])
|
||
this.param.dvbs2.acm_minModulation = m.modulation
|
||
this.param.dvbs2.acm_minSpeed = m.speed
|
||
|
||
this.param.dvbs2.snrReserve = vals["settings"]["dvbs2.snrReserve"]
|
||
this.param.dvbs2.servicePacketPeriod = vals["settings"]["dvbs2.servicePacketPeriod"]
|
||
|
||
this.param.acm.en = vals["settings"]["acm.en"]
|
||
this.param.acm.maxAttenuation = vals["settings"]["acm.maxAttenuation"]
|
||
this.param.acm.minAttenuation = vals["settings"]["acm.minAttenuation"]
|
||
this.param.acm.requiredSnr = vals["settings"]["acm.requiredSnr"]
|
||
|
||
this.param.rx.gainMode = vals["settings"]["rx.gainMode"]
|
||
this.param.rx.manualGain = vals["settings"]["rx.manualGain"]
|
||
this.param.rx.spectrumInversion = vals["settings"]["rx.spectrumInversion"]
|
||
this.param.rx.rolloff = vals["settings"]["rx.rolloff"]
|
||
this.param.rx.cymRate = vals["settings"]["rx.cymRate"]
|
||
this.param.rx.centerFreq = vals["settings"]["rx.centerFreq"]
|
||
},
|
||
|
||
updateCincSettings(vals) {
|
||
this.submitStatus.cinc = false
|
||
this.param.cinc.mode = vals["settings"]["cinc.mode"]
|
||
this.param.cinc.searchBandwidth = vals["settings"]["cinc.searchBandwidth"]
|
||
this.param.cinc.position.station.latitude = vals["settings"]["cinc.position.station.latitude"]
|
||
this.param.cinc.position.station.longitude = vals["settings"]["cinc.position.station.longitude"]
|
||
this.param.cinc.position.satelliteLongitude = vals["settings"]["cinc.position.satelliteLongitude"]
|
||
this.param.cinc.delayMin = vals["settings"]["cinc.delayMin"]
|
||
this.param.cinc.delayMax = vals["settings"]["cinc.delayMax"]
|
||
},
|
||
|
||
updateBucLnbSettings(vals) {
|
||
this.submitStatus.bucLnb = false
|
||
this.param.buc.refClk10M = vals["settings"]["buc.refClk10M"]
|
||
this.param.buc.powering = vals["settings"]["buc.powering"]
|
||
this.param.lnb.refClk10M = vals["settings"]["lnb.refClk10M"]
|
||
this.param.lnb.powering = vals["settings"]["lnb.powering"]
|
||
this.param.serviceSettings.refClk10M = vals["settings"]["serviceSettings.refClk10M"]
|
||
this.param.serviceSettings.autoStart = vals["settings"]["serviceSettings.autoStart"]
|
||
},
|
||
|
||
updateQosSettings(vals) {
|
||
this.submitStatus.qos = false
|
||
this.param.qos.en = vals["settings"]["qos.enabled"]
|
||
|
||
const qosProfile = vals["settings"]["qos.profile"]
|
||
if (qosProfile !== null && qosProfile !== undefined) {
|
||
this.param.qos.rt1 = [] // .splice(0, this.param.qos.rt1.length)
|
||
this.param.qos.rt2 = [] // .splice(0, this.param.qos.rt2.length)
|
||
this.param.qos.rt3 = [] // .splice(0, this.param.qos.rt3.length)
|
||
this.param.qos.cd = [] // .splice(0, this.param.qos.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.param.qos.rt1.push(result); break
|
||
case 'rt2': this.param.qos.rt2.push(result); break
|
||
case 'rt3': this.param.qos.rt3.push(result); break
|
||
case 'cd': this.param.qos.cd.push(result); break
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
updateNetworkSettings(vals) {
|
||
this.submitStatus.network = false
|
||
this.param.network.managementIp = vals["settings"]["network.managementIp"]
|
||
this.param.network.managementGateway = vals["settings"]["network.managementGateway"]
|
||
this.param.network.mode = vals["settings"]["network.mode"]
|
||
this.param.network.dataIp = vals["settings"]["network.dataIp"]
|
||
this.param.network.dataMtu = vals["settings"]["network.dataMtu"]
|
||
},
|
||
|
||
updateDebugSendSettings(vals) {
|
||
this.submitStatus.debugSend = false
|
||
this.param.debugSend.en = vals["settings"]["debugSend.en"]
|
||
this.param.debugSend.receiverIp = vals["settings"]["debugSend.receiverIp"]
|
||
this.param.debugSend.portCinC = vals["settings"]["debugSend.portCinC"]
|
||
this.param.debugSend.portData = vals["settings"]["debugSend.portData"]
|
||
this.param.debugSend.timeout = vals["settings"]["debugSend.timeout"]
|
||
},
|
||
|
||
updateSettings(vals) {
|
||
this.settingFetchComplete = true
|
||
this.updateRxTxSettings(vals)
|
||
this.updateCincSettings(vals)
|
||
this.updateBucLnbSettings(vals)
|
||
this.updateQosSettings(vals)
|
||
this.updateNetworkSettings(vals)
|
||
this.updateDebugSendSettings(vals)
|
||
},
|
||
|
||
qosAddClass(name) {
|
||
let res = {
|
||
isEnabled: true,
|
||
cir: 0,
|
||
pir: 0,
|
||
description: "",
|
||
filters: []
|
||
}
|
||
switch (name) {
|
||
case 'rt1': this.param.qos.rt1.push(res); break
|
||
case 'rt2': this.param.qos.rt2.push(res); break
|
||
case 'rt3': this.param.qos.rt3.push(res); break
|
||
case 'cd': this.param.qos.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.param.qos.rt1[index].filters.push(rule); break
|
||
case 'rt2': this.param.qos.rt2[index].filters.push(rule); break
|
||
case 'rt3': this.param.qos.rt3[index].filters.push(rule); break
|
||
case 'cd': this.param.qos.cd[index].filters.push(rule); break
|
||
}
|
||
},
|
||
|
||
qosDelClass(name, index) {
|
||
switch (name) {
|
||
case 'rt1': this.param.qos.rt1.splice(index, 1); break
|
||
case 'rt2': this.param.qos.rt2.splice(index, 1); break
|
||
case 'rt3': this.param.qos.rt3.splice(index, 1); break
|
||
case 'cd': this.param.qos.cd.splice(index, 1); break
|
||
}
|
||
},
|
||
|
||
qosDelFilter(name, index, filterIndex) {
|
||
switch (name) {
|
||
case 'rt1': this.param.qos.rt1[index].filters.splice(filterIndex, 1); break
|
||
case 'rt2': this.param.qos.rt2[index].filters.splice(filterIndex, 1); break
|
||
case 'rt3': this.param.qos.rt3[index].filters.splice(filterIndex, 1); break
|
||
case 'cd': this.param.qos.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
|
||
},
|
||
|
||
correctModcodSpeed(modulation, speed) {
|
||
const mod = modulation.toLowerCase()
|
||
const available = {
|
||
"qpsk": ['1/4', '1/3', '2/5', '1/2', '3/5', '2/3', '3/4', '4/5', '5/6', '8/9', '9/10'],
|
||
"8psk": ['2/3', '3/4', '5/6', '8/9', '9/10'],
|
||
"16apsk": ['2/3', '3/4', '4/5', '5/6', '8/9', '9/10'],
|
||
"32apsk": ['3/4', '4/5', '5/6', '8/9', '9/10']
|
||
}
|
||
if (mod in available) {
|
||
if (available[mod].indexOf(speed) >= 0) {
|
||
return speed
|
||
}
|
||
return available[mod][0]
|
||
}
|
||
return ""
|
||
},
|
||
|
||
doModemReboot() {
|
||
if (this.submitStatus.modemReboot !== null) {
|
||
return
|
||
}
|
||
this.submitStatus.modemReboot = 30
|
||
fetch('/api/reboot', { method: 'POST' }).then((r) => {})
|
||
}
|
||
},
|
||
mounted() {
|
||
const doFetchStatistics = async () => {
|
||
if (this.submitStatus.modemReboot !== null) {
|
||
this.initState = `Перезагрузка модема... Осталось ${this.submitStatus.modemReboot} сек`
|
||
this.submitStatus.modemReboot--
|
||
if (this.submitStatus.modemReboot <= 0) {
|
||
window.location.reload()
|
||
}
|
||
} else {
|
||
try {
|
||
let d = await fetch("/api/get/statistics")
|
||
this.updateStatistics(await d.json())
|
||
} catch (e) {
|
||
this.initState = "Ошибка обновления статистики"
|
||
}
|
||
}
|
||
setTimeout(() => {
|
||
doFetchStatistics()
|
||
}, 1000)
|
||
}
|
||
|
||
const doFetchAbout = async () => {
|
||
try {
|
||
const fr = await fetch("/api/get/aboutFirmware")
|
||
const d = await fr.json()
|
||
this.about.firmwareVersion = d["fw.version"]
|
||
this.about.modemUid = d["fw.modemId"]
|
||
this.about.modemSn = d["fw.modemSn"]
|
||
this.about.macManagement = d["fw.macMang"]
|
||
this.about.macData = d["fw.macData"]
|
||
} catch (e) {
|
||
console.log('Ошибка загрузки версии ПО', e)
|
||
}
|
||
}
|
||
|
||
doFetchStatistics().then(() => {})
|
||
doFetchAbout().then(() => {})
|
||
|
||
this.performUpdateSettings()
|
||
|
||
document.getElementById("app").removeAttribute("hidden")
|
||
}
|
||
})
|
||
//{% endraw %}
|
||
</script>
|
||
</body>
|
||
</html> |