1460 lines
87 KiB
HTML
1460 lines
87 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>RCSM-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>
|
||
<body>
|
||
|
||
<div id="app" hidden>
|
||
<header>
|
||
<span class="nav-bar-element">Прием: <span :class="{ indicator_bad: statRx.state === false, indicator_good: statRx.state === true, indicator: true }"></span></span>
|
||
<span class="nav-bar-element">Передача: <span :class="{ indicator_good: statTx.state === true, indicator: true }"></span></span>
|
||
<span class="nav-bar-element">Тест: <span :class="{ indicator_good: testState, indicator: true }"></span></span>
|
||
<!-- Последнее обновление: {{ lastUpdateTime }}-->
|
||
<span :class="{ value_bad: initState !== 'Успешная инициализация системы' }">{{ initState }}</span>
|
||
<div class="tabs-header">
|
||
<span style="font-weight:bold">RCSM-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">
|
||
|
||
<div class="tabs-body-item tabs-item-flex-container" v-if="activeTab === 'monitoring'">
|
||
<div class="settings-set-container statistics-container">
|
||
<h2>Статистика приема</h2>
|
||
<table>
|
||
<tbody>
|
||
<tr><th>Прием</th><td><span :class="{ indicator_bad: statRx.state === false, indicator_good: statRx.state === true, indicator: true }"></span></td></tr>
|
||
<tr><th>Захват символьной</th><td><span :class="{ indicator_bad: statRx.sym_sync_lock === false, indicator_good: statRx.sym_sync_lock === true, indicator: true }"></span></td></tr>
|
||
<tr><th>Захват ФАПЧ</th><td><span :class="{ indicator_bad: statRx.afc_lock === false, indicator_good: statRx.afc_lock === true, indicator: true }"></span></td></tr>
|
||
<tr><th>Захват поиска по частоте</th><td><span :class="{ indicator_bad: statRx.freq_search_lock === false, indicator_good: statRx.freq_search_lock === true, indicator: true }"></span></td></tr>
|
||
<tr><th>Захват пакетной синхр.</th><td><span :class="{ indicator_bad: statRx.pkt_sync === false, indicator_good: statRx.pkt_sync === true, indicator: true }"></span></td></tr>
|
||
<tr><th>SNR/RSSI</th><td>{{ statRx.snr }} / {{ statRx.rssi }}</td></tr>
|
||
<tr><th>Modcod</th><td>{{ statRx.modcod }}</td></tr>
|
||
<tr><th>Размер кадра</th><td>{{ statRx.frameSizeNormal ? 'normal' : 'short' }}</td></tr>
|
||
<tr><th>Пилот-символы</th><td>{{ statRx.isPilots ? 'pilots' : 'no pilots' }}</td></tr>
|
||
<tr><th>Символьная ошибка</th><td>{{ statRx.symError }}</td></tr>
|
||
<tr><th>Грубая/точная част. ошибка, Гц</th><td>{{ statRx.freqErr }} / {{ statRx.freqErrAcc }}</td></tr>
|
||
<tr><th>Ур. входного сигнала</th><td>{{ statRx.inputSignalLevel }}</td></tr>
|
||
<tr><th>Ошибка ФАПЧ</th><td>{{ statRx.pllError }}</td></tr>
|
||
<tr><th>Инф. скорость на приеме</th><td>{{ statRx.speedOnRxKbit }} кбит/с</td></tr>
|
||
<tr><th>Инф. скорость на интерфейсе</th><td>{{ statRx.speedOnIifKbit }} кбит/с</td></tr>
|
||
<tr><td colspan="2" style="padding-top: 1em; text-align: center">Статистика пакетов</td></tr>
|
||
<tr><th>Качественных пакетов</th><td>{{ statRx.packetsOk }}</td></tr>
|
||
<tr><th>Поврежденных пакетов</th><td>{{ statRx.packetsBad }}</td></tr>
|
||
<tr><th>DUMMY</th><td>{{ statRx.packetsDummy }}</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<button class="action-button" @click="resetPacketsStatistics()"> Сброс статистики </button>
|
||
</div>
|
||
<div class="settings-set-container statistics-container">
|
||
<h2>Статистика передачи</h2>
|
||
<table>
|
||
<tbody>
|
||
<tr><th>Передача</th><td><span :class="{ indicator_bad: statTx.state === false, indicator_good: statTx.state === true, indicator: true }"></span></td></tr>
|
||
<tr><th>ОСШ дальнего приема</th><td>{{ statTx.snr }}</td></tr>
|
||
<tr><th>Modcod</th><td>{{ statTx.modcod }}</td></tr>
|
||
<tr><th>Размер кадра</th><td>{{ statTx.frameSizeNormal ? 'normal' : 'short' }}</td></tr>
|
||
<tr><th>Пилот-символы</th><td>{{ statTx.isPilots ? 'pilots' : 'no pilots' }}</td></tr>
|
||
<tr><th>Инф. скорость на передаче</th><td>{{ statTx.speedOnTxKbit }} кбит/с</td></tr>
|
||
<tr><th>Инф. скорость на интерфейсе</th><td>{{ statTx.speedOnIifKbit }} кбит/с</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="settings-set-container statistics-container" v-if="paramRxtx.isCinC === true">
|
||
<h2>Статистика режима CinC</h2>
|
||
<table>
|
||
<tbody>
|
||
<tr><th>ОСС</th><td>{{ statCinc.occ }}</td></tr>
|
||
<tr><th>Захват коррелятора</th><td><span :class="{ indicator_bad: statCinc.correlator === false, indicator_good: statCinc.correlator === true, indicator: true }"></span></td></tr>
|
||
<tr><th>Кол-во срывов коррелятора</th><td>{{ statCinc.correlatorFails }}</td></tr>
|
||
<tr><th>Грубая/точная част. ошибка, Гц</th><td>{{ statCinc.freqErr }} / {{ statCinc.freqErrAcc }}</td></tr>
|
||
<tr><th>Задержка в канале, мс</th><td>{{ statCinc.channelDelay }}</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
<div class="settings-set-container statistics-container">
|
||
<h2>Состояние устройства</h2>
|
||
<table>
|
||
<tbody>
|
||
<tr><th>Температура ADRV</th><td>{{ statDevice.adrv }} °C</td></tr>
|
||
<tr><th>Температура ZYNQ</th><td>{{ statDevice.zynq }} °C</td></tr>
|
||
<tr><th>Температура FPGA</th><td>{{ statDevice.fpga }} °C</td></tr>
|
||
<tr><th>Время работы устройства</th><td>{{ statOs.uptime }}</td></tr>
|
||
<tr><th>Средняя загрузка ЦП (1/5/15 мин.)</th><td>{{ statOs.load1 }}% {{ statOs.load5 }}% {{ statOs.load15 }}%</td></tr>
|
||
<tr><th>ОЗУ всего/свободно</th><td>{{ statOs.totalram }}МБ/{{ statOs.freeram }}МБ</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
</div>
|
||
<div class="tabs-body-item" v-if="activeTab === 'setup' && settingFetchComplete">
|
||
<h2>Настройки приема/передачи</h2>
|
||
<div class="settings-set-container">
|
||
<label>
|
||
<span>Режим работы</span>
|
||
<select v-model="paramRxtx.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="paramRxtx.txEn" /><span class="slider"></span></span>
|
||
</label>
|
||
<label>
|
||
<span>Автоматический запуск передатчика</span>
|
||
<span class="toggle-input"><input type="checkbox" v-model="paramRxtx.txAutoStart" /><span class="slider"></span></span>
|
||
</label>
|
||
<label>
|
||
<span>Режим работы модулятора</span>
|
||
<select v-model="paramRxtx.txModulatorIsTest">
|
||
<option :value="false">Нормальный</option>
|
||
<option :value="true">Тест (CW)</option>
|
||
</select>
|
||
</label>
|
||
<label>
|
||
<span>Входные данные</span>
|
||
<select v-model="paramRxtx.txIsTestInput">
|
||
<option :value="false">Ethernet</option>
|
||
<option :value="true">Тест</option>
|
||
</select>
|
||
</label>
|
||
<h3>Параметры передачи</h3>
|
||
<label>
|
||
<span>Центральная частота, КГц</span>
|
||
<input type="text" v-model.lazy="paramRxtx.txCentralFreq" @change="e => paramRxtx.txCentralFreq = inputFormatNumber(inputFormatNumber(e.target.value, {min:950000,max:6000000,step:0.01}), {min:950000,max:6000000,step:0.01})"/>
|
||
</label>
|
||
<label>
|
||
<span>Символьная скорость, Бод</span>
|
||
<input type="text" v-model.lazy="paramRxtx.txBaudrate" @change="e => paramRxtx.txBaudrate = inputFormatNumber(inputFormatNumber(e.target.value, {min:200000,max:54000000,}), {min:200000,max:54000000,})"/>
|
||
</label>
|
||
<label>
|
||
<span>Roll-off</span>
|
||
<select v-model="paramRxtx.txRolloff">
|
||
<option :value="2">0.02</option>
|
||
<option :value="5">0.05</option>
|
||
<option :value="10">0.10</option>
|
||
<option :value="15">0.15</option>
|
||
<option :value="20">0.20</option>
|
||
<option :value="25">0.25</option>
|
||
</select>
|
||
</label>
|
||
<label>
|
||
<span>Номер последовательности Голда</span>
|
||
<select v-model="paramRxtx.txGoldan">
|
||
<option :value="0">0</option>
|
||
<option :value="1">1</option>
|
||
</select>
|
||
</label>
|
||
<label><span>Ослабление, дБ</span><input type="number" v-model="paramRxtx.txAttenuation" min="-40" step="0.25"/></label>
|
||
</div>
|
||
<div class="settings-set-container">
|
||
<h3>Режим работы DVB-S2</h3>
|
||
<label><span>Период служебных пакетов, сек</span><input type="number" v-model="paramRxtx.dvbServicePacketPeriod" max="60" step="1"/></label>
|
||
<label>
|
||
<span>Режим модуляции</span>
|
||
<select v-model="paramRxtx.dvbIsAcm">
|
||
<option :value="false">CCM</option>
|
||
<option :value="true">ACM</option>
|
||
</select>
|
||
</label>
|
||
<label>
|
||
<span>Размер кадра</span>
|
||
<select v-model="paramRxtx.txFrameSizeNormal">
|
||
<option :value="true">normal</option>
|
||
<option :value="false">short</option>
|
||
</select>
|
||
</label>
|
||
<label v-show="paramRxtx.dvbIsAcm === false">
|
||
<span>Модуляция</span>
|
||
<select v-model="paramRxtx.dvbCcmModulation" @change="paramRxtx.dvbCcmSpeed = correctModcodSpeed(paramRxtx.dvbCcmModulation, paramRxtx.dvbCcmSpeed)">
|
||
<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="paramRxtx.dvbIsAcm === false">
|
||
<span>Скорость кода</span>
|
||
<select v-model="paramRxtx.dvbCcmSpeed">
|
||
<option v-for="speed in getAvailableModcods(paramRxtx.dvbCcmModulation)" v-bind:value="speed">{{ speed }}</option>
|
||
</select>
|
||
</label>
|
||
<label v-show="paramRxtx.dvbIsAcm === false">
|
||
<span>Расчетная скорость</span><span>{{ calcInterfaceSpeedKb(paramRxtx.txBaudrate, paramRxtx.dvbCcmModulation, paramRxtx.dvbCcmSpeed, paramRxtx.txFrameSizeNormal) }}</span>
|
||
</label>
|
||
<label v-show="paramRxtx.dvbIsAcm === true">
|
||
<span>Текущий модкод</span><span>{{ statTx.modcod }}</span>
|
||
</label>
|
||
<label v-show="paramRxtx.dvbIsAcm === true">
|
||
<span>Модуляция (мин. режим)</span>
|
||
<select v-model="paramRxtx.dvbAcmMinModulation" @change="paramRxtx.dvbAcmMinSpeed = correctModcodSpeed(paramRxtx.dvbAcmMinModulation, paramRxtx.dvbAcmMinSpeed)">
|
||
<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="paramRxtx.dvbIsAcm === true">
|
||
<span>Скорость кода (мин. режим)</span>
|
||
<select v-model="paramRxtx.dvbAcmMinSpeed">
|
||
<option v-for="speed in getAvailableModcods(paramRxtx.dvbAcmMinModulation)" v-bind:value="speed">{{ speed }}</option>
|
||
</select>
|
||
</label>
|
||
<label v-show="paramRxtx.dvbIsAcm === true">
|
||
<span>Расчетная скорость (мин. режим)</span><span>{{ calcInterfaceSpeedKb(paramRxtx.txBaudrate, paramRxtx.dvbAcmMinModulation, paramRxtx.dvbAcmMinSpeed, paramRxtx.txFrameSizeNormal) }}</span>
|
||
</label>
|
||
<label v-show="paramRxtx.dvbIsAcm === true">
|
||
<span>Модуляция (макс. режим)</span>
|
||
<select v-model="paramRxtx.dvbAcmMaxModulation" @change="paramRxtx.dvbAcmMaxSpeed = correctModcodSpeed(paramRxtx.dvbAcmMaxModulation, paramRxtx.dvbAcmMaxSpeed)">
|
||
<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="paramRxtx.dvbIsAcm === true">
|
||
<span>Скорость кода (макс. режим)</span>
|
||
<select v-model="paramRxtx.dvbAcmMaxSpeed">
|
||
<option v-for="speed in getAvailableModcods(paramRxtx.dvbAcmMaxModulation)" v-bind:value="speed">{{ speed }}</option>
|
||
</select>
|
||
</label>
|
||
<label v-show="paramRxtx.dvbIsAcm === true">
|
||
<span>Расчетная скорость (макс. режим)</span><span>{{ calcInterfaceSpeedKb(paramRxtx.txBaudrate, paramRxtx.dvbAcmMaxModulation, paramRxtx.dvbAcmMaxSpeed, paramRxtx.txFrameSizeNormal) }}</span>
|
||
</label>
|
||
<label><span>Запас ОСШ, дБ</span><input type="number" v-model="paramRxtx.dvbSnrReserve" max="10" step="0.01"/></label>
|
||
</div>
|
||
<div class="settings-set-container">
|
||
<h3>Авто-регулировка мощности</h3>
|
||
<label>
|
||
<span>Авто-регулировка мощности</span>
|
||
<span class="toggle-input"><input type="checkbox" v-model="paramRxtx.aupcEn" /><span class="slider"></span></span>
|
||
</label>
|
||
<label><span>Минимальное ослабление, дБ</span><input type="number" v-model="paramRxtx.aupcMinAttenuation" max="10" step="0.1"/></label>
|
||
<label><span>Максимальное ослабление, дБ</span><input type="number" v-model="paramRxtx.aupcMaxAttenuation" max="10" step="0.1"/></label>
|
||
<label><span>Требуемое ОСШ</span><input type="number" v-model="paramRxtx.aupcRequiredSnr" max="10" step="0.01"/></label>
|
||
</div>
|
||
<div class="settings-set-container">
|
||
<h3>Настройки приемника</h3>
|
||
<label>
|
||
<span>Режим управления усилением</span>
|
||
<select v-model="paramRxtx.rxAgcEn">
|
||
<option :value="false">РРУ</option>
|
||
<option :value="true">АРУ</option>
|
||
</select>
|
||
</label>
|
||
<label v-show="paramRxtx.rxAgcEn === false"><span>Усиление, дБ</span><input type="number" v-model="paramRxtx.rxManualGain" min="-40" max="40" step="0.01"/></label>
|
||
<label v-show="paramRxtx.rxAgcEn === true">
|
||
<span>Текущее усиление</span><span>{{ paramRxtx.rxManualGain }}</span>
|
||
</label>
|
||
<label>
|
||
<span>Инверсия спектра</span>
|
||
<span class="toggle-input"><input type="checkbox" v-model="paramRxtx.rxSpectrumInversion" /><span class="slider"></span></span>
|
||
</label>
|
||
<label>
|
||
<span>Центральная частота, КГц</span>
|
||
<input type="text" v-model.lazy="paramRxtx.rxCentralFreq" @change="e => paramRxtx.rxCentralFreq = inputFormatNumber(inputFormatNumber(e.target.value, {min:950000,max:6000000,step:0.01}), {min:950000,max:6000000,step:0.01})"/>
|
||
</label>
|
||
<label>
|
||
<span>Символьная скорость, Бод</span>
|
||
<input type="text" v-model.lazy="paramRxtx.rxBaudrate" @change="e => paramRxtx.rxBaudrate = inputFormatNumber(inputFormatNumber(e.target.value, {min:200000,max:54000000,}), {min:200000,max:54000000,})"/>
|
||
</label>
|
||
<label>
|
||
<span>Roll-off</span>
|
||
<select v-model="paramRxtx.rxRolloff">
|
||
<option :value="2">0.02</option>
|
||
<option :value="5">0.05</option>
|
||
<option :value="10">0.10</option>
|
||
<option :value="15">0.15</option>
|
||
<option :value="20">0.20</option>
|
||
<option :value="25">0.25</option>
|
||
</select>
|
||
</label>
|
||
<label>
|
||
<span>Номер последовательности Голда</span>
|
||
<select v-model="paramRxtx.rxGoldan">
|
||
<option :value="0">0</option>
|
||
<option :value="1">1</option>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<button class="action-button" @click="settingsSubmitRxtx()">Сохранить <span class="submit-spinner" v-show="submitStatus.rxtx"></span></button>
|
||
<h2 v-show="paramRxtx.isCinC">Настройки режима CinC</h2>
|
||
<div class="settings-set-container" v-show="paramRxtx.isCinC">
|
||
<label>
|
||
<span>Метод расчета задержки</span>
|
||
<select v-model="paramDpdi.dpdiIsPositional">
|
||
<option :value="true">Позиционированием</option>
|
||
<option :value="false">Окном задержки</option>
|
||
</select>
|
||
</label>
|
||
<label><span>Полоса поиска, КГц ±</span><input type="number" v-model="paramDpdi.dpdiSearchBandwidth" max="100" step="1"/></label>
|
||
<h2 v-show="paramDpdi.dpdiIsPositional === true">Настройки позиционирования</h2>
|
||
<label v-show="paramDpdi.dpdiIsPositional === true"><span>Широта станции</span><input type="number" v-model="paramDpdi.dpdiPositionStationLatitude" min="-180" max="180" step="1e-06"/></label>
|
||
<label v-show="paramDpdi.dpdiIsPositional === true"><span>Долгота станции</span><input type="number" v-model="paramDpdi.dpdiPositionStationLongitude" min="-180" max="180" step="1e-06"/></label>
|
||
<label v-show="paramDpdi.dpdiIsPositional === true"><span>Подспутниковая точка</span><input type="number" v-model="paramDpdi.dpdiPositionSatelliteLongitude" min="-180" max="180" step="1e-06"/></label>
|
||
<h2 v-show="paramDpdi.dpdiIsPositional === false">Задержка до спутника</h2>
|
||
<label v-show="paramDpdi.dpdiIsPositional === false"><span>от, мс</span><input type="number" v-model="paramDpdi.dpdiDelayMin" max="400" step="0.1"/></label>
|
||
<label v-show="paramDpdi.dpdiIsPositional === false"><span>до, мс</span><input type="number" v-model="paramDpdi.dpdiDelayMax" max="400" step="0.1"/></label>
|
||
</div>
|
||
<button class="action-button" @click="settingsSubmitDpdi()" v-show="paramRxtx.isCinC">Сохранить <span class="submit-spinner" v-show="submitStatus.dpdi"></span></button>
|
||
<h2>Настройки питания и опорного генератора</h2>
|
||
<div class="tabs-item-flex-container">
|
||
<div class="settings-set-container">
|
||
<h3>Настройки BUC</h3>
|
||
<label>
|
||
<span>Подача опоры 10МГц</span>
|
||
<span class="toggle-input"><input type="checkbox" v-model="paramBuclnb.bucRefClk10M" /><span class="slider"></span></span>
|
||
</label>
|
||
<label>
|
||
<span>Питание BUC</span>
|
||
<select v-model="paramBuclnb.bucPowering">
|
||
<option :value="0">Выкл</option>
|
||
<option :value="24">24В</option>
|
||
<option :value="48">48В</option>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
<div class="settings-set-container">
|
||
<h3>Настройки LNB</h3>
|
||
<label>
|
||
<span>Подача опоры 10МГц</span>
|
||
<span class="toggle-input"><input type="checkbox" v-model="paramBuclnb.lnbRefClk10M" /><span class="slider"></span></span>
|
||
</label>
|
||
<label>
|
||
<span>Питание LNB</span>
|
||
<select v-model="paramBuclnb.lnbPowering">
|
||
<option :value="0">Выкл</option>
|
||
<option :value="13">13В</option>
|
||
<option :value="18">18В</option>
|
||
<option :value="24">24В</option>
|
||
</select>
|
||
</label>
|
||
</div>
|
||
<div class="settings-set-container">
|
||
<h3>Сервисные настройки</h3>
|
||
<label>
|
||
<span>Подача опоры 10МГц на 'Выход 10МГц'</span>
|
||
<span class="toggle-input"><input type="checkbox" v-model="paramBuclnb.srvRefClk10M" /><span class="slider"></span></span>
|
||
</label>
|
||
<label>
|
||
<span>Автозапуск BUC и LNB при включении</span>
|
||
<span class="toggle-input"><input type="checkbox" v-model="paramBuclnb.bucLnbAutoStart" /><span class="slider"></span></span>
|
||
</label>
|
||
</div>
|
||
</div>
|
||
<button class="action-button" @click="settingsSubmitBuclnb()">Сохранить <span class="submit-spinner" v-show="submitStatus.buclnb"></span></button>
|
||
</div>
|
||
<div class="tabs-body-item" v-if="activeTab === '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>
|
||
|
||
<h2>Настройки TCP-акселерации</h2>
|
||
<div class="settings-set-container">
|
||
<label>
|
||
<span>Активировать акселерацию</span>
|
||
<span class="toggle-input"><input type="checkbox" v-model="paramTcpaccel.accelEn" /><span class="slider"></span></span>
|
||
</label>
|
||
<label><span>Максимальное количество соединений</span><input type="number" v-model="paramTcpaccel.accelMaxConnections" max="4000" step="1"/></label>
|
||
</div>
|
||
<button class="action-button" @click="settingsSubmitTcpaccel()">Сохранить <span class="submit-spinner" v-show="submitStatus.tcpaccel"></span></button>
|
||
</div> <div class="tabs-body-item" v-if="activeTab === 'admin' && settingFetchComplete">
|
||
<h2>Настройки сети</h2>
|
||
<div class="settings-set-container">
|
||
<h3>Настройки интерфейса управления</h3>
|
||
<label>
|
||
<span>Интерфейс управления (/24)</span>
|
||
<input v-model="paramNetwork.netManagementIp" required type="text" pattern="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$">
|
||
</label>
|
||
<label>
|
||
<span>Режим сети</span>
|
||
<select v-model="paramNetwork.netIsL2">
|
||
<option :value="false">Маршрутизатор</option>
|
||
<option :value="true">Коммутатор</option>
|
||
</select>
|
||
</label>
|
||
<label v-show="paramNetwork.netIsL2 === false">
|
||
<span>Интерфейс данных (/24)</span>
|
||
<input v-model="paramNetwork.netDataIp" required type="text" pattern="^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$">
|
||
</label>
|
||
<label><span>MTU интерфейса данных</span><input type="number" v-model="paramNetwork.netDataMtu" min="1500" max="2000" step="1"/></label>
|
||
<label>
|
||
<span>Имя веб-сервера</span>
|
||
<input v-model="paramNetwork.netServerName" type="text">
|
||
</label>
|
||
</div>
|
||
<button class="action-button" @click="settingsSubmitNetwork()">Сохранить <span class="submit-spinner" v-show="submitStatus.network"></span></button>
|
||
|
||
<h2>Система</h2>
|
||
<div class="settings-set-container statistics-container">
|
||
<table>
|
||
<tbody>
|
||
<tr><th>Версия ПО</th><td>{{ about.firmwareVersion }}</td></tr>
|
||
<tr><th>ID модема</th><td>{{ about.modemUid }}</td></tr>
|
||
<tr><th>Серийный номер</th><td>{{ about.modemSn }}</td></tr>
|
||
<tr><th>MAC интерфейса управления</th><td>{{ about.macManagement }}</td></tr>
|
||
<tr><th>MAC интерфейса данных</th><td>{{ about.macData }}</td></tr>
|
||
</tbody>
|
||
</table>
|
||
<div>
|
||
<button class="dangerous-button" @click="doModemReboot()">Перезагрузить модем <span class="submit-spinner" v-show="submitStatus.modemReboot !== null"></span></button>
|
||
</div>
|
||
<div>
|
||
<button class="dangerous-button" onclick="fetch('/api/resetSettings', { method: 'POST' }).then((r) => { window.location.reload(); })">Сбросить модем до заводских настроек</button>
|
||
</div>
|
||
</div>
|
||
|
||
<h2>Обновление ПО</h2>
|
||
<div class="settings-set-container statistics-container">
|
||
<h3>Ручное обновление</h3>
|
||
<label>
|
||
<span>Файл {{ this.uploadFw.progress !== null ? `(${this.uploadFw.progress}%)` : '' }}</span>
|
||
<input type="file" accept="application/zip" @change="(e) => { this.uploadFw.filename = e.target.files[0] }">
|
||
<span v-if="uploadFw.sha256 !== null">SHA256: {{ uploadFw.sha256 }}</span>
|
||
</label>
|
||
<button class="action-button" @click="settingsUploadUpdate()">Загрузить<span class="submit-spinner" v-show="submitStatus.firmwareUpload"></span></button>
|
||
<button class="dangerous-button" v-show="uploadFw.sha256 !== null" @click="settingsPerformFirmwareUpgrade()">Обновить встроенное ПО<span class="submit-spinner" v-show="submitStatus.firmwareUpgrade"></span></button>
|
||
</div>
|
||
</div>
|
||
<p>Последнее обновление статистики: {{ lastUpdateTime }}</p>
|
||
</div>
|
||
</div>
|
||
<script src="/js/vue.js?v=3.5.13"></script>
|
||
<script>
|
||
const availableTabs = ['monitoring', 'setup', 'qos', 'admin']
|
||
|
||
// для обновления высоты хидера
|
||
function updateHeaderHeight() { const header = document.querySelector('header'); document.body.style.setProperty('--header-height', `${header.offsetHeight}px`); }
|
||
window.addEventListener('load', updateHeaderHeight); window.addEventListener('resize', updateHeaderHeight);
|
||
|
||
function getCurrentTab() {
|
||
const sl = window.location.hash.slice(1)
|
||
if (availableTabs.indexOf(sl) >= 0) {
|
||
return sl
|
||
}
|
||
return availableTabs[0]
|
||
}
|
||
|
||
function toLocaleStringWithSpaces(num) {
|
||
if (typeof num !== 'number') {
|
||
if (typeof num === 'string') { return num }
|
||
return String(num);
|
||
}
|
||
const numberString = num.toString()
|
||
const [integerPart, fractionalPart] = numberString.split('.')
|
||
const spacedIntegerPart = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, " ")
|
||
if (fractionalPart) { return `${spacedIntegerPart}.${fractionalPart}` }
|
||
else { return spacedIntegerPart }
|
||
}
|
||
|
||
const app = Vue.createApp({
|
||
data() {
|
||
return {
|
||
// false - означает что статистика не отправляется, true - отправляется
|
||
submitStatus: {
|
||
rxtx: false,
|
||
dpdi: false,
|
||
buclnb: false,
|
||
tcpaccel: false,
|
||
network: false,
|
||
firmwareUpload: false,
|
||
firmwareUpgrade: false,
|
||
// когда модем перезагружается, тут должен быть счетчик. Направление счета - к нулю
|
||
modemReboot: null
|
||
},
|
||
|
||
// ========== include from 'common/all-params-data.js.j2'
|
||
paramRxtx: {
|
||
isCinC: false,
|
||
txEn: false,
|
||
txAutoStart: false,
|
||
txModulatorIsTest: false,
|
||
txIsTestInput: false,
|
||
txCentralFreq: 0,
|
||
txBaudrate: 0,
|
||
txRolloff: 2,
|
||
txGoldan: 0,
|
||
txAttenuation: -40,
|
||
dvbServicePacketPeriod: 0,
|
||
dvbIsAcm: false,
|
||
txFrameSizeNormal: true,
|
||
dvbCcmModulation: "QPSK",
|
||
dvbCcmSpeed: "1/4",
|
||
dvbAcmMinModulation: "QPSK",
|
||
dvbAcmMinSpeed: "1/4",
|
||
dvbAcmMaxModulation: "QPSK",
|
||
dvbAcmMaxSpeed: "1/4",
|
||
dvbSnrReserve: 0,
|
||
aupcEn: false,
|
||
aupcMinAttenuation: 0,
|
||
aupcMaxAttenuation: 0,
|
||
aupcRequiredSnr: 0,
|
||
rxAgcEn: false,
|
||
rxManualGain: -40,
|
||
rxSpectrumInversion: false,
|
||
rxCentralFreq: 0,
|
||
rxBaudrate: 0,
|
||
rxRolloff: 2,
|
||
rxGoldan: 0,
|
||
},
|
||
paramDpdi: {
|
||
dpdiIsPositional: true,
|
||
dpdiSearchBandwidth: 0,
|
||
dpdiPositionStationLatitude: -180,
|
||
dpdiPositionStationLongitude: -180,
|
||
dpdiPositionSatelliteLongitude: -180,
|
||
dpdiDelayMin: 0,
|
||
dpdiDelayMax: 0,
|
||
},
|
||
paramBuclnb: {
|
||
bucRefClk10M: false,
|
||
bucPowering: 0,
|
||
lnbRefClk10M: false,
|
||
lnbPowering: 0,
|
||
srvRefClk10M: false,
|
||
bucLnbAutoStart: false,
|
||
},
|
||
paramTcpaccel: {
|
||
accelEn: false,
|
||
accelMaxConnections: 0,
|
||
},
|
||
paramNetwork: {
|
||
netManagementIp: null,
|
||
netIsL2: false,
|
||
netDataIp: null,
|
||
netDataMtu: 1500,
|
||
netServerName: null,
|
||
},
|
||
// ========== include end from 'common/all-params-data.js.j2'
|
||
|
||
// ========== include from 'common/monitoring-data.js.j2'
|
||
statRx: {
|
||
// индикаторы
|
||
state: '?', // общее состояние
|
||
sym_sync_lock: '?', // захват символьной
|
||
freq_search_lock: '?', // Захват поиска по частоте
|
||
afc_lock: '?', // захват ФАПЧ
|
||
pkt_sync: '?', // захват пакетной синхронизации
|
||
|
||
// куча других параметров, идет в том же порядке, что и в таблице
|
||
snr: '?', rssi: '?',
|
||
modcod: '?', frameSizeNormal: '?',
|
||
isPilots: '?',
|
||
symError: '?',
|
||
freqErr: '?', freqErrAcc: '?',
|
||
inputSignalLevel: '?',
|
||
pllError: '?',
|
||
speedOnRxKbit: '?',
|
||
speedOnIifKbit: '?',
|
||
|
||
// статистика пакетов
|
||
packetsOk: '?', packetsBad: '?', packetsDummy: '?',
|
||
},
|
||
statTx: {
|
||
// состояние
|
||
state: '?',
|
||
|
||
// прочие поля
|
||
snr: '?', modcod: '?', frameSizeNormal: '?', isPilots: '?', speedOnTxKbit: '?', speedOnIifKbit: '?'
|
||
},
|
||
statCinc: {
|
||
occ: '?',
|
||
correlator: null,
|
||
correlatorFails: '?',
|
||
freqErr: '?', freqErrAcc: '?',
|
||
channelDelay: '?'
|
||
},
|
||
statDevice: { // температурные датчики
|
||
adrv: 0, zynq: 0, fpga: 0
|
||
},
|
||
statOs: {uptime: '?', load1: '?', load5: '?', load15: '?', totalram: '?', freeram: '?'},
|
||
// ========== include end from 'common/monitoring-data.js.j2'
|
||
|
||
// ========== include from 'common/setup-data.js.j2'
|
||
// ========== include end from 'common/setup-data.js.j2'
|
||
|
||
// ========== include from 'common/qos-data.js.j2'
|
||
submitStatusQos: false,
|
||
paramQos: {
|
||
en: false,
|
||
rt1: [],
|
||
rt2: [],
|
||
rt3: [],
|
||
cd: [],
|
||
}, // ========== include end from 'common/qos-data.js.j2'
|
||
|
||
// ========== include from 'common/admin-data.js.j2'
|
||
// ========== include end from 'common/admin-data.js.j2'
|
||
|
||
uploadFw: {
|
||
progress: null,
|
||
filename: null,
|
||
sha256: null
|
||
},
|
||
|
||
// эти "настройки" - read only
|
||
about: {
|
||
firmwareVersion: '?',
|
||
modemUid: '?',
|
||
modemSn: '?',
|
||
macManagement: '?',
|
||
macData: '?',
|
||
},
|
||
|
||
testState: false,
|
||
initState: '',
|
||
lastUpdateTime: new Date(),
|
||
activeTab: getCurrentTab(),
|
||
settingFetchComplete: false,
|
||
}
|
||
},
|
||
methods: {
|
||
correctModcodSpeed(modulation, speed) {
|
||
const mod = modulation.toLowerCase()
|
||
const available = {
|
||
"qpsk": ['1/4', '1/3', '2/5', '1/2', '3/5', '2/3', '3/4', '4/5', '5/6', '8/9', '9/10'],
|
||
"8psk": ['2/3', '3/4', '5/6', '8/9', '9/10'],
|
||
"16apsk": ['2/3', '3/4', '4/5', '5/6', '8/9', '9/10'],
|
||
"32apsk": ['3/4', '4/5', '5/6', '8/9', '9/10']
|
||
}
|
||
if (mod in available) {
|
||
if (available[mod].indexOf(speed) >= 0) {
|
||
return speed
|
||
}
|
||
return available[mod][0]
|
||
}
|
||
return ""
|
||
},
|
||
getAvailableModcods(modulation) {
|
||
// NOTE модкоды со скоростью хода 3/5 не работают
|
||
switch (modulation) {
|
||
case 'qpsk':
|
||
return ['1/4', '1/3', '2/5', '1/2', '3/5', '2/3', '3/4', '4/5', '5/6', '8/9', '9/10']
|
||
case '8psk':
|
||
return ['3/5', '2/3', '3/4', '5/6', '8/9', '9/10']
|
||
case '16apsk':
|
||
return ['2/3', '3/4', '4/5', '5/6', '8/9', '9/10']
|
||
case '32apsk':
|
||
return ['3/4', '4/5', '5/6', '8/9', '9/10']
|
||
default:
|
||
return []
|
||
}
|
||
},
|
||
inputFormatNumber(src, validation) {
|
||
if (validation === null || validation === undefined) { validation = {} }
|
||
const rawVal = src.toString().replace(/[^0-9.,]/g, '').replace(',', '.')
|
||
let result = rawVal === '' ? 0 : parseFloat(rawVal)
|
||
const step = 'step' in validation ? validation['step']: 1.0
|
||
result = Math.round(result / step) * step
|
||
if ('min' in validation) { if (result <= validation['min']) { result = validation['min'] } }
|
||
if ('max' in validation) { if (result >= validation['max']) { result = validation['max'] } }
|
||
return toLocaleStringWithSpaces(result)
|
||
},
|
||
|
||
// ========== include from 'common/all-params-methods.js.j2'
|
||
settingsSubmitRxtx() {
|
||
if (this.submitStatus.rxtx) { return }
|
||
|
||
let query = {
|
||
"isCinC": this.paramRxtx.isCinC,
|
||
"txEn": this.paramRxtx.txEn,
|
||
"txAutoStart": this.paramRxtx.txAutoStart,
|
||
"txModulatorIsTest": this.paramRxtx.txModulatorIsTest,
|
||
"txIsTestInput": this.paramRxtx.txIsTestInput,
|
||
"txCentralFreq": parseFloat(this.paramRxtx.txCentralFreq.replace(/[^0-9,.]/g, '').replace(',', '.')),
|
||
"txBaudrate": parseFloat(this.paramRxtx.txBaudrate.replace(/[^0-9,.]/g, '').replace(',', '.')),
|
||
"txRolloff": this.paramRxtx.txRolloff,
|
||
"txGoldan": this.paramRxtx.txGoldan,
|
||
"txAttenuation": this.paramRxtx.txAttenuation,
|
||
"dvbServicePacketPeriod": this.paramRxtx.dvbServicePacketPeriod,
|
||
"dvbIsAcm": this.paramRxtx.dvbIsAcm,
|
||
"txFrameSizeNormal": this.paramRxtx.txFrameSizeNormal,
|
||
"dvbCcmModulation": this.paramRxtx.dvbCcmModulation,
|
||
"dvbCcmSpeed": this.paramRxtx.dvbCcmSpeed,
|
||
"dvbAcmMinModulation": this.paramRxtx.dvbAcmMinModulation,
|
||
"dvbAcmMinSpeed": this.paramRxtx.dvbAcmMinSpeed,
|
||
"dvbAcmMaxModulation": this.paramRxtx.dvbAcmMaxModulation,
|
||
"dvbAcmMaxSpeed": this.paramRxtx.dvbAcmMaxSpeed,
|
||
"dvbSnrReserve": this.paramRxtx.dvbSnrReserve,
|
||
"aupcEn": this.paramRxtx.aupcEn,
|
||
"aupcMinAttenuation": this.paramRxtx.aupcMinAttenuation,
|
||
"aupcMaxAttenuation": this.paramRxtx.aupcMaxAttenuation,
|
||
"aupcRequiredSnr": this.paramRxtx.aupcRequiredSnr,
|
||
"rxAgcEn": this.paramRxtx.rxAgcEn,
|
||
"rxManualGain": this.paramRxtx.rxManualGain,
|
||
"rxSpectrumInversion": this.paramRxtx.rxSpectrumInversion,
|
||
"rxCentralFreq": parseFloat(this.paramRxtx.rxCentralFreq.replace(/[^0-9,.]/g, '').replace(',', '.')),
|
||
"rxBaudrate": parseFloat(this.paramRxtx.rxBaudrate.replace(/[^0-9,.]/g, '').replace(',', '.')),
|
||
"rxRolloff": this.paramRxtx.rxRolloff,
|
||
"rxGoldan": this.paramRxtx.rxGoldan,
|
||
}
|
||
|
||
this.submitStatus.rxtx = true
|
||
fetch('/api/set/rxtx', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(query), credentials: 'same-origin' })
|
||
.then(async (resp) => { let vals = await resp.json(); if (vals['status'] !== 'ok') { throw new Error(vals['error'] ? vals['error'] : "Server returns undefined error") } this.updateRxtxSettings(vals) })
|
||
.catch((reason) => { alert(`Ошибка при применении настроек: ${reason}`) })
|
||
.finally(() => { this.submitStatus.rxtx = false })
|
||
},
|
||
settingsSubmitDpdi() {
|
||
if (this.submitStatus.dpdi) { return }
|
||
|
||
let query = {
|
||
"dpdiIsPositional": this.paramDpdi.dpdiIsPositional,
|
||
"dpdiSearchBandwidth": this.paramDpdi.dpdiSearchBandwidth,
|
||
"dpdiPositionStationLatitude": this.paramDpdi.dpdiPositionStationLatitude,
|
||
"dpdiPositionStationLongitude": this.paramDpdi.dpdiPositionStationLongitude,
|
||
"dpdiPositionSatelliteLongitude": this.paramDpdi.dpdiPositionSatelliteLongitude,
|
||
"dpdiDelayMin": this.paramDpdi.dpdiDelayMin,
|
||
"dpdiDelayMax": this.paramDpdi.dpdiDelayMax,
|
||
}
|
||
|
||
this.submitStatus.dpdi = true
|
||
fetch('/api/set/dpdi', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(query), credentials: 'same-origin' })
|
||
.then(async (resp) => { let vals = await resp.json(); if (vals['status'] !== 'ok') { throw new Error(vals['error'] ? vals['error'] : "Server returns undefined error") } this.updateDpdiSettings(vals) })
|
||
.catch((reason) => { alert(`Ошибка при применении настроек: ${reason}`) })
|
||
.finally(() => { this.submitStatus.dpdi = false })
|
||
},
|
||
settingsSubmitBuclnb() {
|
||
if (this.submitStatus.buclnb) { return }
|
||
{ if (!confirm("Применение неправильных настроек может вывести из строя оборудование! Продолжить?")) return }
|
||
|
||
let query = {
|
||
"bucRefClk10M": this.paramBuclnb.bucRefClk10M,
|
||
"bucPowering": this.paramBuclnb.bucPowering,
|
||
"lnbRefClk10M": this.paramBuclnb.lnbRefClk10M,
|
||
"lnbPowering": this.paramBuclnb.lnbPowering,
|
||
"srvRefClk10M": this.paramBuclnb.srvRefClk10M,
|
||
"bucLnbAutoStart": this.paramBuclnb.bucLnbAutoStart,
|
||
}
|
||
|
||
this.submitStatus.buclnb = true
|
||
fetch('/api/set/buclnb', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(query), credentials: 'same-origin' })
|
||
.then(async (resp) => { let vals = await resp.json(); if (vals['status'] !== 'ok') { throw new Error(vals['error'] ? vals['error'] : "Server returns undefined error") } this.updateBuclnbSettings(vals) })
|
||
.catch((reason) => { alert(`Ошибка при применении настроек: ${reason}`) })
|
||
.finally(() => { this.submitStatus.buclnb = false })
|
||
},
|
||
settingsSubmitTcpaccel() {
|
||
if (this.submitStatus.tcpaccel) { return }
|
||
|
||
let query = {
|
||
"accelEn": this.paramTcpaccel.accelEn,
|
||
"accelMaxConnections": this.paramTcpaccel.accelMaxConnections,
|
||
}
|
||
|
||
this.submitStatus.tcpaccel = true
|
||
fetch('/api/set/tcpaccel', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(query), credentials: 'same-origin' })
|
||
.then(async (resp) => { let vals = await resp.json(); if (vals['status'] !== 'ok') { throw new Error(vals['error'] ? vals['error'] : "Server returns undefined error") } this.updateTcpaccelSettings(vals) })
|
||
.catch((reason) => { alert(`Ошибка при применении настроек: ${reason}`) })
|
||
.finally(() => { this.submitStatus.tcpaccel = false })
|
||
},
|
||
settingsSubmitNetwork() {
|
||
if (this.submitStatus.network) { return }
|
||
{ if (!confirm("Применение этих настроек может сделать модем недоступным! Продолжить?")) return }
|
||
|
||
let query = {
|
||
"netManagementIp": this.paramNetwork.netManagementIp,
|
||
"netIsL2": this.paramNetwork.netIsL2,
|
||
"netDataIp": this.paramNetwork.netDataIp,
|
||
"netDataMtu": this.paramNetwork.netDataMtu,
|
||
"netServerName": this.paramNetwork.netServerName,
|
||
}
|
||
|
||
this.submitStatus.network = true
|
||
fetch('/api/set/network', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify(query), credentials: 'same-origin' })
|
||
.then(async (resp) => { let vals = await resp.json(); if (vals['status'] !== 'ok') { throw new Error(vals['error'] ? vals['error'] : "Server returns undefined error") } this.updateNetworkSettings(vals) })
|
||
.catch((reason) => { alert(`Ошибка при применении настроек: ${reason}`) })
|
||
.finally(() => { this.submitStatus.network = false })
|
||
},
|
||
|
||
updateRxtxSettings(vals) {
|
||
this.submitStatus.rxtx = false
|
||
this.paramRxtx.isCinC = vals["settings"]["isCinC"]
|
||
this.paramRxtx.txEn = vals["settings"]["txEn"]
|
||
this.paramRxtx.txAutoStart = vals["settings"]["txAutoStart"]
|
||
this.paramRxtx.txModulatorIsTest = vals["settings"]["txModulatorIsTest"]
|
||
this.paramRxtx.txIsTestInput = vals["settings"]["txIsTestInput"]
|
||
this.paramRxtx.txCentralFreq = this.inputFormatNumber(vals["settings"]["txCentralFreq"], {min:950000,max:6000000,step:0.01})
|
||
this.paramRxtx.txBaudrate = this.inputFormatNumber(vals["settings"]["txBaudrate"], {min:200000,max:54000000,})
|
||
this.paramRxtx.txRolloff = vals["settings"]["txRolloff"]
|
||
this.paramRxtx.txGoldan = vals["settings"]["txGoldan"]
|
||
this.paramRxtx.txAttenuation = vals["settings"]["txAttenuation"]
|
||
this.paramRxtx.dvbServicePacketPeriod = vals["settings"]["dvbServicePacketPeriod"]
|
||
this.paramRxtx.dvbIsAcm = vals["settings"]["dvbIsAcm"]
|
||
this.paramRxtx.txFrameSizeNormal = vals["settings"]["txFrameSizeNormal"]
|
||
this.paramRxtx.dvbCcmModulation = vals["settings"]["dvbCcmModulation"]
|
||
this.paramRxtx.dvbCcmSpeed = vals["settings"]["dvbCcmSpeed"]
|
||
this.paramRxtx.dvbAcmMinModulation = vals["settings"]["dvbAcmMinModulation"]
|
||
this.paramRxtx.dvbAcmMinSpeed = vals["settings"]["dvbAcmMinSpeed"]
|
||
this.paramRxtx.dvbAcmMaxModulation = vals["settings"]["dvbAcmMaxModulation"]
|
||
this.paramRxtx.dvbAcmMaxSpeed = vals["settings"]["dvbAcmMaxSpeed"]
|
||
this.paramRxtx.dvbSnrReserve = vals["settings"]["dvbSnrReserve"]
|
||
this.paramRxtx.aupcEn = vals["settings"]["aupcEn"]
|
||
this.paramRxtx.aupcMinAttenuation = vals["settings"]["aupcMinAttenuation"]
|
||
this.paramRxtx.aupcMaxAttenuation = vals["settings"]["aupcMaxAttenuation"]
|
||
this.paramRxtx.aupcRequiredSnr = vals["settings"]["aupcRequiredSnr"]
|
||
this.paramRxtx.rxAgcEn = vals["settings"]["rxAgcEn"]
|
||
this.paramRxtx.rxManualGain = vals["settings"]["rxManualGain"]
|
||
this.paramRxtx.rxSpectrumInversion = vals["settings"]["rxSpectrumInversion"]
|
||
this.paramRxtx.rxCentralFreq = this.inputFormatNumber(vals["settings"]["rxCentralFreq"], {min:950000,max:6000000,step:0.01})
|
||
this.paramRxtx.rxBaudrate = this.inputFormatNumber(vals["settings"]["rxBaudrate"], {min:200000,max:54000000,})
|
||
this.paramRxtx.rxRolloff = vals["settings"]["rxRolloff"]
|
||
this.paramRxtx.rxGoldan = vals["settings"]["rxGoldan"]
|
||
},
|
||
updateDpdiSettings(vals) {
|
||
this.submitStatus.dpdi = false
|
||
this.paramDpdi.dpdiIsPositional = vals["settings"]["dpdiIsPositional"]
|
||
this.paramDpdi.dpdiSearchBandwidth = vals["settings"]["dpdiSearchBandwidth"]
|
||
this.paramDpdi.dpdiPositionStationLatitude = vals["settings"]["dpdiPositionStationLatitude"]
|
||
this.paramDpdi.dpdiPositionStationLongitude = vals["settings"]["dpdiPositionStationLongitude"]
|
||
this.paramDpdi.dpdiPositionSatelliteLongitude = vals["settings"]["dpdiPositionSatelliteLongitude"]
|
||
this.paramDpdi.dpdiDelayMin = vals["settings"]["dpdiDelayMin"]
|
||
this.paramDpdi.dpdiDelayMax = vals["settings"]["dpdiDelayMax"]
|
||
},
|
||
updateBuclnbSettings(vals) {
|
||
this.submitStatus.buclnb = false
|
||
this.paramBuclnb.bucRefClk10M = vals["settings"]["bucRefClk10M"]
|
||
this.paramBuclnb.bucPowering = vals["settings"]["bucPowering"]
|
||
this.paramBuclnb.lnbRefClk10M = vals["settings"]["lnbRefClk10M"]
|
||
this.paramBuclnb.lnbPowering = vals["settings"]["lnbPowering"]
|
||
this.paramBuclnb.srvRefClk10M = vals["settings"]["srvRefClk10M"]
|
||
this.paramBuclnb.bucLnbAutoStart = vals["settings"]["bucLnbAutoStart"]
|
||
},
|
||
updateTcpaccelSettings(vals) {
|
||
this.submitStatus.tcpaccel = false
|
||
this.paramTcpaccel.accelEn = vals["settings"]["accelEn"]
|
||
this.paramTcpaccel.accelMaxConnections = vals["settings"]["accelMaxConnections"]
|
||
},
|
||
updateNetworkSettings(vals) {
|
||
this.submitStatus.network = false
|
||
this.paramNetwork.netManagementIp = vals["settings"]["netManagementIp"]
|
||
this.paramNetwork.netIsL2 = vals["settings"]["netIsL2"]
|
||
this.paramNetwork.netDataIp = vals["settings"]["netDataIp"]
|
||
this.paramNetwork.netDataMtu = vals["settings"]["netDataMtu"]
|
||
this.paramNetwork.netServerName = vals["settings"]["netServerName"]
|
||
},
|
||
// ========== include end from 'common/all-params-methods.js.j2'
|
||
|
||
// ========== include from 'common/monitoring-methods.js.j2'
|
||
updateStatistics(vals) {
|
||
function modcodToStr(modcod) {
|
||
// модкоды из раздела 5.5.2.2 https://www.etsi.org/deliver/etsi_en/302300_302399/302307/01.01.02_60/en_302307v010102p.pdf
|
||
const modcods = [
|
||
"DUMMY",
|
||
"QPSK 1/4", "QPSK 1/3", "QPSK 2/5", "QPSK 1/2", "QPSK 3/5", "QPSK 2/3", "QPSK 3/4", "QPSK 4/5", "QPSK 5/6", "QPSK 8/9", "QPSK 9/10",
|
||
"8PSK 3/5", "8PSK 2/3", "8PSK 3/4", "8PSK 5/6", "8PSK 8/9", "8PSK 9/10",
|
||
"16APSK 2/3", "16APSK 3/4", "16APSK 4/5", "16APSK 5/6", "16APSK 8/9", "16APSK 9/10",
|
||
"32APSK 3/4", "32APSK 4/5", "32APSK 5/6", "32APSK 8/9", "32APSK 9/10",
|
||
]
|
||
if (typeof modcod != "number") {
|
||
return "?";
|
||
}
|
||
if (modcod < 0 || modcod >= modcods.length) {
|
||
return `? (${modcod})`
|
||
}
|
||
return modcods[modcod]
|
||
}
|
||
|
||
this.lastUpdateTime = new Date();
|
||
this.initState = vals["mainState"]["initState"]
|
||
this.isCinC = vals["mainState"]["isCinC"]
|
||
|
||
this.statRx.state = vals["mainState"]["rx.state"]
|
||
this.statRx.sym_sync_lock = vals["mainState"]["rx.sym_sync_lock"]
|
||
this.statRx.freq_search_lock = vals["mainState"]["rx.freq_search_lock"]
|
||
this.statRx.afc_lock = vals["mainState"]["rx.afc_lock"]
|
||
this.statRx.pkt_sync = vals["mainState"]["rx.pkt_sync"]
|
||
this.statRx.snr = vals["mainState"]["rx.snr"]
|
||
this.statRx.rssi = vals["mainState"]["rx.rssi"]
|
||
this.statRx.modcod = modcodToStr(vals["mainState"]["rx.modcod"])
|
||
this.statRx.frameSizeNormal = vals["mainState"]["rx.frameSizeNormal"]
|
||
this.statRx.isPilots = vals["mainState"]["rx.isPilots"]
|
||
this.statRx.symError = vals["mainState"]["rx.symError"]
|
||
this.statRx.freqErr = vals["mainState"]["rx.freqErr"]
|
||
this.statRx.freqErrAcc = vals["mainState"]["rx.freqErrAcc"]
|
||
this.statRx.inputSignalLevel = vals["mainState"]["rx.inputSignalLevel"]
|
||
this.statRx.pllError = vals["mainState"]["rx.pllError"]
|
||
this.statRx.speedOnRxKbit = vals["mainState"]["rx.speedOnRxKbit"]
|
||
this.statRx.speedOnIifKbit = vals["mainState"]["rx.speedOnIifKbit"]
|
||
this.statRx.packetsOk = vals["mainState"]["rx.packetsOk"]
|
||
this.statRx.packetsBad = vals["mainState"]["rx.packetsBad"]
|
||
this.statRx.packetsDummy = vals["mainState"]["rx.packetsDummy"]
|
||
|
||
this.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"]
|
||
|
||
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} дней, ` + res }
|
||
this.statOs.uptime = res
|
||
} else {
|
||
this.statOs.uptime = '?'
|
||
}
|
||
this.statOs.load1 = vals["sysinfo"]["load1min"]
|
||
this.statOs.load5 = vals["sysinfo"]["load5min"]
|
||
this.statOs.load15 = vals["sysinfo"]["load15min"]
|
||
this.statOs.totalram = vals["sysinfo"]["totalram"]
|
||
this.statOs.freeram = vals["sysinfo"]["freeram"]
|
||
},
|
||
|
||
resetPacketsStatistics() {
|
||
fetch('/api/resetPacketStatistics', {
|
||
method: 'POST', credentials: 'same-origin'
|
||
}).then(() => {
|
||
this.statRx.packetsOk = 0
|
||
this.statRx.packetsBad = 0
|
||
this.statRx.packetsDummy = 0
|
||
})
|
||
},
|
||
// ========== include end from 'common/monitoring-methods.js.j2'
|
||
|
||
// ========== include from 'common/setup-methods.js.j2'
|
||
calcRequiredSnr(frameSizeNormal, modulation, speed) {
|
||
const snrValues = [
|
||
{fs: true, mod: 'qpsk', speed: '1/4', snr: 2.6}, {fs: true, mod: 'qpsk', speed: '1/3', snr: 2.6}, {fs: true, mod: 'qpsk', speed: '2/5', snr: 2.6}, {fs: true, mod: 'qpsk', speed: '1/2', snr: 2.6}, {fs: true, mod: 'qpsk', speed: '3/5', snr: 3.1}, {fs: true, mod: 'qpsk', speed: '2/3', snr: 3.8}, {fs: true, mod: 'qpsk', speed: '3/4', snr: 4.5}, {fs: true, mod: 'qpsk', speed: '4/5', snr: 5.2}, {fs: true, mod: 'qpsk', speed: '5/6', snr: 5.5}, {fs: true, mod: 'qpsk', speed: '8/9', snr: 6.4}, {fs: true, mod: 'qpsk', speed: '9/10', snr: 6.7},
|
||
{fs: true, mod: '8psk', speed: '3/5', snr: 7.4}, {fs: true, mod: '8psk', speed: '2/3', snr: 8.4}, {fs: true, mod: '8psk', speed: '3/4', snr: 8.7}, {fs: true, mod: '8psk', speed: '5/6', snr: 10}, {fs: true, mod: '8psk', speed: '8/9', snr: 10.9}, {fs: true, mod: '8psk', speed: '9/10', snr: 11.1},
|
||
{fs: true, mod: '16apsk', speed: '2/3', snr: 11.2}, {fs: true, mod: '16apsk', speed: '3/4', snr: 11.3}, {fs: true, mod: '16apsk', speed: '4/5', snr: 12.4}, {fs: true, mod: '16apsk', speed: '5/6', snr: 12.7}, {fs: true, mod: '16apsk', speed: '8/9', snr: 13.1}, {fs: true, mod: '16apsk', speed: '9/10', snr: 13.9},
|
||
{fs: true, mod: '32apsk', speed: '3/4', snr: 14.5}, {fs: true, mod: '32apsk', speed: '4/5', snr: 14.7}, {fs: true, mod: '32apsk', speed: '5/6', snr: 14.9}, {fs: true, mod: '32apsk', speed: '8/9', snr: 16.1}, {fs: true, mod: '32apsk', speed: '9/10', snr: 16.6},
|
||
|
||
{fs: false, mod: 'qpsk', speed: '1/4', snr: 4.1}, {fs: false, mod: 'qpsk', speed: '1/3', snr: 4.1}, {fs: false, mod: 'qpsk', speed: '2/5', snr: 4.1}, {fs: false, mod: 'qpsk', speed: '1/2', snr: 4.1}, {fs: false, mod: 'qpsk', speed: '3/5', snr: 4.6}, {fs: false, mod: 'qpsk', speed: '2/3', snr: 5.1}, {fs: false, mod: 'qpsk', speed: '3/4', snr: 5.3}, {fs: false, mod: 'qpsk', speed: '4/5', snr: 6.8}, {fs: false, mod: 'qpsk', speed: '5/6', snr: 7.8}, {fs: false, mod: 'qpsk', speed: '8/9', snr: 8.5},
|
||
{fs: false, mod: '8psk', speed: '3/5', snr: 9.5}, {fs: false, mod: '8psk', speed: '2/3', snr: 9.9}, {fs: false, mod: '8psk', speed: '3/4', snr: 10.5}, {fs: false, mod: '8psk', speed: '5/6', snr: 11.1}, {fs: false, mod: '8psk', speed: '8/9', snr: 11.3},
|
||
{fs: false, mod: '16apsk', speed: '2/3', snr: 11.6}, {fs: false, mod: '16apsk', speed: '3/4', snr: 11.8}, {fs: false, mod: '16apsk', speed: '4/5', snr: 12}, {fs: false, mod: '16apsk', speed: '5/6', snr: 12.3}, {fs: false, mod: '16apsk', speed: '8/9', snr: 13.4},
|
||
{fs: false, mod: '32apsk', speed: '3/4', snr: 14.1}, {fs: false, mod: '32apsk', speed: '4/5', snr: 14.7}, {fs: false, mod: '32apsk', speed: '5/6', snr: 15.3}, {fs: false, mod: '32apsk', speed: '8/9', snr: 16.5},
|
||
]
|
||
for (let i = 0; i < snrValues.length; i++) {
|
||
if (snrValues[i].fs === frameSizeNormal && snrValues[i].mod === modulation && snrValues[i].speed === speed) { return snrValues[i].snr }
|
||
}
|
||
return '?'
|
||
},
|
||
calcInterfaceSpeedKb(baud, modulation, speed, frameSizeNormal) {
|
||
const mBaud = parseInt(baud.replace(/[^0-9]/g, ''))
|
||
const mMod = Math.max(2, ['', '', 'qpsk', '8psk', '16apsk', '32apsk'].indexOf(modulation))
|
||
const speedVals = {'1/4': 0.25, '1/3': 0.333, '2/5': 0.4, '1/2': 0.5, '3/5': 0.6, '2/3': 0.666, '3/4': 0.75, '4/5': 0.8, '5/6': 0.833, '8/9': 0.888, '9/10': 0.9}
|
||
const mSpeed = speed in speedVals ? speedVals[speed] : 1
|
||
const result = (mBaud * mMod * mSpeed) / 1024
|
||
const calcSnr = this.calcRequiredSnr(frameSizeNormal, modulation, speed)
|
||
let snr;
|
||
if (isNaN(calcSnr)) { snr = `ОСШ=?` } else { snr=`ОСШ=${calcSnr}` }
|
||
if (result > 1024) {
|
||
return toLocaleStringWithSpaces(result / 1024) + ' Мбит/с; ' + snr
|
||
} else {
|
||
return toLocaleStringWithSpaces(result) + ' кбит/с; ' + snr
|
||
}
|
||
},
|
||
// ========== include end from 'common/setup-methods.js.j2'
|
||
|
||
// ========== include from 'common/qos-methods.js.j2'
|
||
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), credentials: 'same-origin'
|
||
}).then(async (resp) => {
|
||
this.submitStatusQos = false
|
||
if (resp['error']) { throw new Error(resp['error']) }
|
||
this.updateQosSettings(await resp.json())
|
||
}).catch((reason) => {
|
||
this.submitStatusQos = false
|
||
alert(`Ошибка при применении настроек: ${reason}`)
|
||
})
|
||
},
|
||
|
||
updateQosSettings(vals) {
|
||
this.submitStatusQos = false
|
||
this.paramQos.en = vals["settings"]["qosEnabled"]
|
||
|
||
const qosProfile = vals["settings"]["qosProfile"]
|
||
if (qosProfile !== null && qosProfile !== undefined) {
|
||
this.paramQos.rt1 = [] // .splice(0, this.paramQos.rt1.length)
|
||
this.paramQos.rt2 = [] // .splice(0, this.paramQos.rt2.length)
|
||
this.paramQos.rt3 = [] // .splice(0, this.paramQos.rt3.length)
|
||
this.paramQos.cd = [] // .splice(0, this.paramQos.cd.length)
|
||
|
||
for (let trafficClass in qosProfile) {
|
||
if (['rt1', 'rt2', 'rt3', 'cd'].indexOf(trafficClass) < 0) {
|
||
continue
|
||
}
|
||
|
||
if (Array.isArray(qosProfile[trafficClass])) {
|
||
for (let i = 0; i < qosProfile[trafficClass].length; i++) {
|
||
const qc = qosProfile[trafficClass][i]
|
||
let result = {
|
||
isEnabled: !qc.hasOwnProperty('disabled'),
|
||
cir: qc['cir'],
|
||
pir: 0,
|
||
description: qc['description'],
|
||
filters: []
|
||
}
|
||
if (trafficClass === 'cd') {
|
||
if (qc['pir']) {
|
||
result.pir = qc['pir']
|
||
}
|
||
}
|
||
for (let fi = 0; fi < qc['filters'].length; fi++) {
|
||
result.filters.push({
|
||
isEnabled: !qc['filters'][fi].hasOwnProperty('disabled'),
|
||
vlan: qc['filters'][fi].hasOwnProperty('vlan') ? qc['filters'][fi]['vlan'] : '',
|
||
proto: qc['filters'][fi].hasOwnProperty('proto') ? qc['filters'][fi]['proto'].split(',') : [],
|
||
sport: qc['filters'][fi].hasOwnProperty('sport') ? qc['filters'][fi]['sport'] : '',
|
||
dport: qc['filters'][fi].hasOwnProperty('dport') ? qc['filters'][fi]['dport'] : '',
|
||
ip_src: qc['filters'][fi].hasOwnProperty('ip_src') ? qc['filters'][fi]['ip_src'] : '',
|
||
ip_dest: qc['filters'][fi].hasOwnProperty('ip_dest') ? qc['filters'][fi]['ip_dest'] : '',
|
||
dscp: qc['filters'][fi].hasOwnProperty('dscp') ? qc['filters'][fi]['dscp'] : ''
|
||
})
|
||
}
|
||
switch (trafficClass) {
|
||
case 'rt1': this.paramQos.rt1.push(result); break
|
||
case 'rt2': this.paramQos.rt2.push(result); break
|
||
case 'rt3': this.paramQos.rt3.push(result); break
|
||
case 'cd': this.paramQos.cd.push(result); break
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
},
|
||
|
||
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
|
||
},
|
||
// ========== include end from 'common/qos-methods.js.j2'
|
||
|
||
// ========== include from 'common/admin-methods.js.j2'
|
||
async settingsUploadUpdate() {
|
||
if (!this.uploadFw.filename) {
|
||
alert('Выберите файл для загрузки');
|
||
return;
|
||
}
|
||
|
||
async function readFileAsArrayBuffer(fileName) {
|
||
return new Promise((resolve, reject) => {
|
||
if (!fileName) { reject(`Файл не выбран`); return }
|
||
const reader = new FileReader();
|
||
reader.onload = (e) => { resolve(reader.result) }
|
||
reader.onerror = (e) => { reject(e) }
|
||
reader.readAsArrayBuffer(fileName)
|
||
})
|
||
}
|
||
|
||
try {
|
||
this.submitStatus.firmwareUpload = true
|
||
this.uploadFw.progress = 0
|
||
const blob = await readFileAsArrayBuffer(this.uploadFw.filename)
|
||
|
||
const xhr = new XMLHttpRequest();
|
||
await new Promise((resolve) => {
|
||
xhr.upload.addEventListener("progress", (event) => {
|
||
if (event.lengthComputable) {
|
||
this.uploadFw.progress = Math.round((event.loaded / event.total) * 1000) / 10;
|
||
}
|
||
});
|
||
xhr.addEventListener("loadend", () => {
|
||
this.uploadFw.progress = 100
|
||
const rep = JSON.parse(xhr.responseText);
|
||
this.uploadFw.sha256 = rep['sha256']
|
||
resolve(xhr.readyState === 4 && xhr.status === 200);
|
||
});
|
||
xhr.open("PUT", "/api/firmwareUpdate", true);
|
||
xhr.setRequestHeader("Content-Type", "application/octet-stream");
|
||
xhr.send(blob);
|
||
});
|
||
} catch (e) {
|
||
alert(`Ошибка загрузки файла: ${e}`);
|
||
}
|
||
this.submitStatus.firmwareUpload = false
|
||
},
|
||
|
||
async settingsPerformFirmwareUpgrade() {
|
||
if (this.submitStatus.firmwareUpgrade) { return }
|
||
this.submitStatus.firmwareUpgrade = true
|
||
try {
|
||
await fetch('/api/doFirmwareUpgrade', { method: 'POST' })
|
||
} catch (e) {
|
||
console.log("failed to perform upgrade firmware: ", e)
|
||
}
|
||
this.submitStatus.firmwareUpgrade = false
|
||
},
|
||
|
||
doModemReboot() {
|
||
if (this.submitStatus.modemReboot !== null) {
|
||
return
|
||
}
|
||
this.submitStatus.modemReboot = 30
|
||
fetch('/api/reboot', { method: 'POST' }).then((r) => {})
|
||
}, // ========== include end from 'common/admin-methods.js.j2'
|
||
|
||
|
||
performUpdateSettings() {
|
||
const doFetchSettings = async () => {
|
||
let d = await fetch("/api/get/settings")
|
||
let vals = await d.json()
|
||
this.settingFetchComplete = true
|
||
this.updateRxtxSettings(vals)
|
||
this.updateDpdiSettings(vals)
|
||
this.updateBuclnbSettings(vals)
|
||
this.updateTcpaccelSettings(vals)
|
||
this.updateNetworkSettings(vals)
|
||
this.updateQosSettings(vals)
|
||
|
||
if ('netServerName' in vals['settings']) {
|
||
document.getElementsByTagName('title')[0].innerText = vals['settings']['netServerName']
|
||
}
|
||
}
|
||
|
||
doFetchSettings().then(() => {})
|
||
}
|
||
},
|
||
mounted() {
|
||
const doFetchStatistics = async () => {
|
||
if (this.submitStatus.modemReboot !== null) {
|
||
this.initState = `Перезагрузка модема... Осталось ${this.submitStatus.modemReboot} сек`
|
||
this.submitStatus.modemReboot--
|
||
if (this.submitStatus.modemReboot <= 0) {
|
||
window.location.reload()
|
||
}
|
||
} else {
|
||
try {
|
||
let d = await fetch("/api/get/statistics", { credentials: 'same-origin' })
|
||
this.updateStatistics(await d.json())
|
||
} catch (e) {
|
||
this.initState = "Ошибка обновления статистики"
|
||
}
|
||
}
|
||
setTimeout(() => {
|
||
doFetchStatistics()
|
||
}, 1000)
|
||
}
|
||
|
||
const doFetchAbout = async () => {
|
||
try {
|
||
const fr = await fetch("/api/get/aboutFirmware")
|
||
const d = await fr.json()
|
||
this.about.firmwareVersion = d["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")
|
||
}
|
||
});
|
||
app.mount('#app')
|
||
</script>
|
||
</body>
|
||
</html> |