V125-260722:(暂时发现DPD/FSSI/网页频谱显示都不正常,临时提交)1.合并增加 Web 端 FPGA .mcs 在线升级功能,支持升级进度及错误状态反馈。2.合并优化 FPGA 升级后的恢复流程,实现无需断电的 FPGA 配置、JESD 链路及 RF 热恢复。3.合并重构 ORx 功率、FSSI 和 FWD 计算;4.合并DPD相关优化和调试日志;5.合并IQ 频谱数据接收由 eth1 调整至 eth0,降低对外部网口连接状态的依赖。
This commit is contained in:
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
BKP_FILE=/aw/anywave/cfg/bkp/exc_cfg_bkp.conf
|
||||
if [ -f "$BKP_FILE" ];then
|
||||
cp -v -rf /aw/anywave/cfg/bkp/exc_cfg_bkp.conf /aw/anywave/cfg/bkp/exc_cfg_bbkkpp.conf
|
||||
echo "ccooppyy: exc_cfg_bkp.conf"
|
||||
cp -v -rf /aw/anywave/cfg/bkp/exc_cfg_bkp.conf /aw/anywave/cfg/exc_cfg.conf
|
||||
fi
|
||||
sync
|
||||
Executable
+13
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
CFG_FILE=/aw/anywave/cfg/exc_cfg.conf
|
||||
BKP_FILE=/aw/anywave/cfg/bkp/exc_cfg_bkp.conf
|
||||
if [ -f "$BKP_FILE" ];then
|
||||
cp -v -rf /aw/anywave/cfg/bkp/exc_cfg_bkp.conf /aw/anywave/cfg/bkp/exc_cfg_bkp_bbkkpp.conf
|
||||
rm -rf /aw/anywave/cfg/bkp/exc_cfg_bkp.conf
|
||||
echo "ccooppyy1: exc_cfg_bkp.conf"
|
||||
fi
|
||||
if [ -f "$BKP_FILE" ];then
|
||||
cp -v -rf /aw/anywave/cfg/exc_cfg.conf /aw/anywave/cfg/bkp/exc_cfg_bkp.conf
|
||||
echo "ccooppyy2: exc_cfg.conf"
|
||||
fi
|
||||
sync
|
||||
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash
|
||||
|
||||
## ------------------------------
|
||||
# function :
|
||||
# a. check package *.tar.gz in current dir
|
||||
# b. check package extract tar return value of ret
|
||||
# c. check package runme.sh
|
||||
## ------------------------------
|
||||
# return :
|
||||
## 0 ok
|
||||
## 2 Wrong package
|
||||
## 3 Wrong file extension
|
||||
## ------------------------------
|
||||
|
||||
|
||||
#-- This path has been defined in upload.cgi ,so if want to chang this path, you should chang upload.c .
|
||||
TAR_PACKAGE_PATH="/aw/upgrade"
|
||||
UPGRADE_FILE_PATH="/tmp/upgrade"
|
||||
PROJ_NAME="SMOD"
|
||||
|
||||
|
||||
if [ -d ${UPGRADE_FILE_PATH} ] ; then
|
||||
rm -rf ${UPGRADE_FILE_PATH}
|
||||
fi
|
||||
mkdir -p ${UPGRADE_FILE_PATH}
|
||||
|
||||
|
||||
check_tar=`find ${TAR_PACKAGE_PATH} -name '*.tar.gz'`
|
||||
ret=0
|
||||
|
||||
|
||||
if [ -z ${check_tar} ];then # 字符串长度为0
|
||||
let ret=3
|
||||
else
|
||||
cd ${TAR_PACKAGE_PATH} && ls SMOD*.tar.gz > list.txt
|
||||
|
||||
for TAR in `cat list.txt`
|
||||
do
|
||||
FILE_NAME=${TAR%.*.*}
|
||||
###echo "file name :${FILE_NAME}"
|
||||
###echo "tar -zxf $TAR -C ${UPGRADE_FILE_PATH}/"
|
||||
|
||||
tar -zxf $TAR -C ${UPGRADE_FILE_PATH}/
|
||||
|
||||
extract_tar_ret=$?
|
||||
|
||||
if [ ${extract_tar_ret} != "0" ];then
|
||||
let ret=2
|
||||
else
|
||||
let ret=0
|
||||
fi
|
||||
###echo "extract_tar_pg = ${ret}"
|
||||
done
|
||||
|
||||
rm -rf ${TAR_PACKAGE_PATH}/list.txt
|
||||
rm -rf ${TAR_PACKAGE_PATH}/*.tar.gz
|
||||
|
||||
###echo "ret = ${ret}"
|
||||
if [ ${ret} -eq 0 ];then
|
||||
# check package has runme.sh xxx_cp.sh xxx_remove.sh .
|
||||
# path = /dt_update/aics*/
|
||||
cd ${UPGRADE_FILE_PATH}/${PROJ_NAME}*
|
||||
if [ -f "runme.sh" ];then
|
||||
###echo "runme.sh ok"
|
||||
let ret=0
|
||||
else
|
||||
###echo "no runme.sh "
|
||||
let ret=2
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
if [ ${ret} -ne 0 ];then
|
||||
#echo "rm -rf ./package/*"
|
||||
rm ${TAR_PACKAGE_PATH}/* -rf
|
||||
sync
|
||||
fi
|
||||
|
||||
echo ${ret}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
UPGRADE_FILE_PATH="/tmp/upgrade"
|
||||
|
||||
cd ${UPGRADE_FILE_PATH}/SMOD* && ./runme.sh
|
||||
|
||||
Executable
BIN
Binary file not shown.
Executable
+2
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
killall http
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
#!/bin/sh
|
||||
|
||||
rm -rf /var/module_log.tar.gz
|
||||
cd /var
|
||||
tar -czvf module_log.tar.gz ./module_log
|
||||
|
||||
rm -rf /aw/anywave/web/www/module_log.tar.gz
|
||||
mv -f /var/module_log.tar.gz /aw/anywave/web/www/
|
||||
Executable
+2
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
/aw/anywave/web/bin/http -p 80 -d /aw/anywave/web/www -c *.cgi -t utf-8&
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
anywavecom:anywavecom
|
||||
hhee:hhee
|
||||
|
||||
BIN
Binary file not shown.
Executable
+73
@@ -0,0 +1,73 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var CHECK_INTERVAL = 30000;
|
||||
var SESSION_CHECK_URL = 'login.cgi';
|
||||
|
||||
|
||||
function initSessionCheck() {
|
||||
if (window.location.pathname.indexOf('login.html') !== -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkSession();
|
||||
|
||||
setInterval(checkSession, CHECK_INTERVAL);
|
||||
|
||||
document.addEventListener('mousemove', resetTimer);
|
||||
document.addEventListener('keydown', resetTimer);
|
||||
document.addEventListener('click', resetTimer);
|
||||
}
|
||||
|
||||
function checkSession() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', SESSION_CHECK_URL + '?t=' + Date.now(), true);
|
||||
xhr.setRequestHeader('Cache-Control', 'no-cache');
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === 4) {
|
||||
var response = xhr.responseText || '';
|
||||
|
||||
if (response.indexOf('UNAUTHORIZED') !== -1) {
|
||||
redirectToLogin();
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.indexOf('OK') !== -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
xhr.send();
|
||||
} catch (e) {
|
||||
console.log('Session check failed:', e);
|
||||
}
|
||||
}
|
||||
|
||||
function redirectToLogin() {
|
||||
var currentUrl = window.location.href;
|
||||
var loginUrl = 'login.html?redirect=' + encodeURIComponent(currentUrl);
|
||||
|
||||
if (window.top !== window.self) {
|
||||
window.top.location.href = loginUrl;
|
||||
} else {
|
||||
window.location.href = loginUrl;
|
||||
}
|
||||
}
|
||||
|
||||
var sessionTimer;
|
||||
function resetTimer() {
|
||||
clearTimeout(sessionTimer);
|
||||
sessionTimer = setTimeout(function() {
|
||||
checkSession();
|
||||
}, 60000);
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initSessionCheck);
|
||||
} else {
|
||||
initSessionCheck();
|
||||
}
|
||||
})();
|
||||
Executable
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
Executable
+1696
File diff suppressed because it is too large
Load Diff
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
BIN
Binary file not shown.
BIN
Binary file not shown.
BIN
Binary file not shown.
|
After Width: | Height: | Size: 4.4 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
Executable
BIN
Binary file not shown.
BIN
Binary file not shown.
Executable
+73
@@ -0,0 +1,73 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var CHECK_INTERVAL = 30000;
|
||||
var SESSION_CHECK_URL = 'login.cgi';
|
||||
|
||||
|
||||
function initSessionCheck() {
|
||||
if (window.location.pathname.indexOf('login.html') !== -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
checkSession();
|
||||
|
||||
setInterval(checkSession, CHECK_INTERVAL);
|
||||
|
||||
document.addEventListener('mousemove', resetTimer);
|
||||
document.addEventListener('keydown', resetTimer);
|
||||
document.addEventListener('click', resetTimer);
|
||||
}
|
||||
|
||||
function checkSession() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open('GET', SESSION_CHECK_URL + '?t=' + Date.now(), true);
|
||||
xhr.setRequestHeader('Cache-Control', 'no-cache');
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (xhr.readyState === 4) {
|
||||
var response = xhr.responseText || '';
|
||||
|
||||
if (response.indexOf('UNAUTHORIZED') !== -1) {
|
||||
redirectToLogin();
|
||||
return;
|
||||
}
|
||||
|
||||
if (response.indexOf('OK') !== -1) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
xhr.send();
|
||||
} catch (e) {
|
||||
console.log('Session check failed:', e);
|
||||
}
|
||||
}
|
||||
|
||||
function redirectToLogin() {
|
||||
var currentUrl = window.location.href;
|
||||
var loginUrl = 'login.html?redirect=' + encodeURIComponent(currentUrl);
|
||||
|
||||
if (window.top !== window.self) {
|
||||
window.top.location.href = loginUrl;
|
||||
} else {
|
||||
window.location.href = loginUrl;
|
||||
}
|
||||
}
|
||||
|
||||
var sessionTimer;
|
||||
function resetTimer() {
|
||||
clearTimeout(sessionTimer);
|
||||
sessionTimer = setTimeout(function() {
|
||||
checkSession();
|
||||
}, 60000);
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', initSessionCheck);
|
||||
} else {
|
||||
initSessionCheck();
|
||||
}
|
||||
})();
|
||||
+260
@@ -0,0 +1,260 @@
|
||||
/**
|
||||
* Shared Dashboard Update Module
|
||||
* Used by: sys_set.html, sys_rf.html, sys_ts.html, sys_psip.html, log_output.html, status_info.html
|
||||
*
|
||||
* This module provides a common refreshDashboard() function that updates
|
||||
* the summary dashboard cards with status data from the backend.
|
||||
*
|
||||
* For status_info.html which already fetches data, use updateDashboardCards()
|
||||
* to update cards without making an additional AJAX call.
|
||||
*/
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// Power decimal lookup table
|
||||
var POWER_DECIMALS = ["00","05","10","15","20","25","30","35","40","45","50","55","60","65","70","75","80","85","90","95"];
|
||||
|
||||
// Input source labels
|
||||
var INPUT_SOURCES = ["ASI1","ASI2","EAS","Tuner","TSoIP","None"];
|
||||
|
||||
/**
|
||||
* Calculate frequency from channel number
|
||||
* @param {number} chan - Channel number (2-83)
|
||||
* @returns {number} Frequency in MHz
|
||||
*/
|
||||
function calcFrequency(chan) {
|
||||
var freq = 0;
|
||||
if (chan >= 2 && chan <= 6) {
|
||||
freq = (chan - 2) * 6 + 57;
|
||||
if (freq > 69) freq += 4;
|
||||
} else if (chan >= 7 && chan <= 13) {
|
||||
freq = 177 + 6 * (chan - 7);
|
||||
} else if (chan >= 14 && chan <= 83) {
|
||||
freq = 473 + (chan - 14) * 6;
|
||||
}
|
||||
return freq;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert temperature based on unit
|
||||
* @param {number} rawValue - Raw temperature value
|
||||
* @param {number} unit - 0 = Fahrenheit, 1 = Celsius
|
||||
* @returns {number|string} Temperature in Fahrenheit
|
||||
*/
|
||||
function convertTemperature(rawValue, unit) {
|
||||
if (unit === 0) {
|
||||
return rawValue; // Already Fahrenheit
|
||||
} else {
|
||||
return (rawValue * 1.8 + 32).toFixed(2); // Celsius to Fahrenheit
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to set card value and status
|
||||
* @param {string} id - Element ID for the value
|
||||
* @param {string} dotId - Element ID for the status dot
|
||||
* @param {*} value - Value to display
|
||||
* @param {string} status - Status class (ok, warn, err, off, neutral)
|
||||
*/
|
||||
function setCard(id, dotId, value, status) {
|
||||
var el = document.getElementById(id);
|
||||
var dot = document.getElementById(dotId);
|
||||
if (el) {
|
||||
el.innerText = value;
|
||||
el.className = "summary-value value-" + status;
|
||||
}
|
||||
if (dot) {
|
||||
dot.className = "status-dot status-" + status;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get SNR status based on value
|
||||
* @param {string} snr - SNR value or "N/A"
|
||||
* @returns {string} Status class
|
||||
*/
|
||||
function getSnrStatus(snr) {
|
||||
if (snr === "N/A") return 'off';
|
||||
var val = parseFloat(snr); // already carries the +10 dB display offset
|
||||
if (val >= 37) return 'ok';
|
||||
if (val >= 30) return 'warn';
|
||||
return 'err';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get IMD status (UIMD/LIMD)
|
||||
* @param {string} imd - IMD value or "N/A"
|
||||
* @returns {string} Status class
|
||||
*/
|
||||
function getImdStatus(imd) {
|
||||
if (imd === "N/A") return 'off';
|
||||
return parseFloat(imd) >= 47 ? 'ok' : 'err';
|
||||
}
|
||||
|
||||
/**
|
||||
* Update all dashboard cards with provided data
|
||||
* Use this when you already have the data (e.g., from status_info.html)
|
||||
*
|
||||
* @param {Object} data - Dashboard data object
|
||||
* @param {number} data.freqVal - Frequency in MHz
|
||||
* @param {string} data.snr - SNR value
|
||||
* @param {string} data.limd - LIMD value
|
||||
* @param {string} data.uimd - UIMD value
|
||||
* @param {string} data.inputSrc - Input source label
|
||||
* @param {string} data.inputStatus - Input status (OK/Err)
|
||||
* @param {string} data.bitrate - Bitrate value
|
||||
* @param {string} data.temp - Temperature value
|
||||
* @param {string} data.agc - AGC status (On/Off)
|
||||
* @param {string} data.ctrl - Control mode (Remote/Local)
|
||||
* @param {number} data.rfStat - RF switch status (1=On, 0=Off)
|
||||
* @param {string} data.finalPower - Output power string
|
||||
*/
|
||||
window.updateDashboardCards = function(data) {
|
||||
setCard('sum_freq', 'dot_freq', data.freqVal, 'neutral');
|
||||
setCard('sum_snr', 'dot_snr', data.snr, getSnrStatus(data.snr));
|
||||
setCard('sum_uimd', 'dot_uimd', data.uimd, getImdStatus(data.uimd));
|
||||
setCard('sum_limd', 'dot_limd', data.limd, getImdStatus(data.limd));
|
||||
setCard('sum_input', 'dot_input', data.inputSrc, 'neutral');
|
||||
setCard('sum_input_status', 'dot_input_status', data.inputStatus,
|
||||
(data.inputStatus === "OK") ? 'ok' : 'err');
|
||||
setCard('sum_bitrate', 'dot_bitrate', data.bitrate, 'neutral');
|
||||
setCard('sum_temp', 'dot_temp', data.temp,
|
||||
(parseFloat(data.temp) >= 160) ? 'err' : 'ok');
|
||||
setCard('sum_agc', 'dot_agc', data.agc,
|
||||
(data.agc === "On") ? 'ok' : 'off');
|
||||
setCard('sum_control', 'dot_control', data.ctrl,
|
||||
(data.ctrl.toUpperCase() === "REMOTE") ? 'neutral' : 'warn');
|
||||
setCard('sum_rf', 'dot_rf', (data.rfStat === 1) ? "On" : "Off",
|
||||
(data.rfStat === 1) ? 'ok' : 'off');
|
||||
setCard('sum_outpow', 'dot_outpow', data.finalPower, 'ok');
|
||||
};
|
||||
|
||||
/**
|
||||
* Main function to refresh the dashboard
|
||||
* Fetches system state and updates all summary cards
|
||||
*/
|
||||
window.refreshDashboard = function() {
|
||||
var queryData = "State_SysState=&sys_rf=&atscmode=&";
|
||||
|
||||
$.get("atsc_status_cfg.cgi?" + queryData, function(data, status, xhr) {
|
||||
// Handle case where data is a JSON object (e.g., session expired)
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
if (data.error === 'session_expired' && data.redirect) {
|
||||
window.location.href = data.redirect;
|
||||
return;
|
||||
}
|
||||
console.error('Received JSON error response instead of expected data:', data);
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure data is a string before attempting to split
|
||||
var responseText = typeof data === 'string' ? data : (xhr && xhr.responseText) ? xhr.responseText : String(data || '');
|
||||
if (typeof responseText !== 'string') {
|
||||
console.error('Dashboard data is not a string:', typeof responseText, responseText);
|
||||
return;
|
||||
}
|
||||
|
||||
var table = responseText.split("|");
|
||||
if (!Array.isArray(table) || table.length < 2) {
|
||||
console.error('Invalid dashboard data format:', responseText);
|
||||
return;
|
||||
}
|
||||
|
||||
var form = table[0].split("#");
|
||||
if (!Array.isArray(form)) {
|
||||
console.error('Invalid form data format:', table[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
var rf_form = table[1].split("#");
|
||||
if (!Array.isArray(rf_form)) {
|
||||
console.error('Invalid rf_form data format:', table[1]);
|
||||
return;
|
||||
}
|
||||
|
||||
var atscmod_para = table[2] ? table[2].split("#") : ["", ""];
|
||||
if (!Array.isArray(atscmod_para)) {
|
||||
console.error('Invalid atscmod_para data format:', table[2]);
|
||||
return;
|
||||
}
|
||||
|
||||
// FSSI refresh mode check
|
||||
var ab_modenum = Number(form[25]);
|
||||
var temp_unit = Number(form[26]);
|
||||
|
||||
// Frequency
|
||||
var chan = Number(form[7]);
|
||||
var freqVal = calcFrequency(chan);
|
||||
|
||||
// SNR: half-dB from the app plus the fixed +10 dB display offset.
|
||||
var snr = (ab_modenum === 1) ? "N/A" : (Number(form[11]) / 2 + 10).toFixed(1);
|
||||
|
||||
// LIMD / UIMD: half-dB from the app plus the fixed +11 dB display offset.
|
||||
// Rounding the sum and then appending the half misreports odd half-dB
|
||||
// values by 1 dB, so format the sum directly.
|
||||
var limd = (ab_modenum === 1) ? "N/A" : (Number(form[12]) / 2 + 11).toFixed(1);
|
||||
var uimd = (ab_modenum === 1) ? "N/A" : (Number(form[13]) / 2 + 11).toFixed(1);
|
||||
|
||||
// Input source
|
||||
var inputIdx = Number(form[1]);
|
||||
if (inputIdx < 0 || inputIdx > 5) inputIdx = 5;
|
||||
var inputSrc = INPUT_SOURCES[inputIdx];
|
||||
|
||||
// Input status
|
||||
var inputStatus = (Number(form[2]) === 0) ? "OK" : "Err";
|
||||
|
||||
// Bitrate
|
||||
var bitrate = form[4];
|
||||
|
||||
// Temperature with unit conversion
|
||||
var temp = convertTemperature(Number(form[5]), temp_unit);
|
||||
|
||||
// AGC
|
||||
var agc = (Number(form[3]) === 0) ? "Off" : "On";
|
||||
|
||||
// Control
|
||||
var ctrl = (Number(form[14]) === 0) ? "Remote" : "Local";
|
||||
|
||||
// RF Switch
|
||||
var rfStat = Number(rf_form[4]);
|
||||
|
||||
// Output Power
|
||||
var p_sign = (Number(rf_form[1]) === 0) ? "+" : "-";
|
||||
var p_int = Number(rf_form[2]);
|
||||
var p_dec = POWER_DECIMALS[Number(rf_form[3])] || "00";
|
||||
var finalPower = p_sign + p_int + "." + p_dec;
|
||||
|
||||
// Update all cards using the shared function
|
||||
window.updateDashboardCards({
|
||||
freqVal: freqVal,
|
||||
snr: snr,
|
||||
limd: limd,
|
||||
uimd: uimd,
|
||||
inputSrc: inputSrc,
|
||||
inputStatus: inputStatus,
|
||||
bitrate: bitrate,
|
||||
temp: temp,
|
||||
agc: agc,
|
||||
ctrl: ctrl,
|
||||
rfStat: rfStat,
|
||||
finalPower: finalPower
|
||||
});
|
||||
}).fail(function(jqXHR, textStatus, errorThrown) {
|
||||
console.error('Failed to fetch dashboard data:', textStatus, errorThrown);
|
||||
console.log('Response text:', jqXHR.responseText);
|
||||
console.log('Status code:', jqXHR.status);
|
||||
});
|
||||
};
|
||||
|
||||
// Export helper functions for status_info.html
|
||||
window.DashboardHelpers = {
|
||||
calcFrequency: calcFrequency,
|
||||
convertTemperature: convertTemperature,
|
||||
setCard: setCard,
|
||||
getSnrStatus: getSnrStatus,
|
||||
getImdStatus: getImdStatus,
|
||||
POWER_DECIMALS: POWER_DECIMALS,
|
||||
INPUT_SOURCES: INPUT_SOURCES
|
||||
};
|
||||
|
||||
})();
|
||||
+2
File diff suppressed because one or more lines are too long
+538
@@ -0,0 +1,538 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title id="webtitle"></title>
|
||||
<link href="css/styles.css" rel="stylesheet" media="screen">
|
||||
<script src="js/auth.js"></script>
|
||||
<script src="js/jquery.js"></script>
|
||||
<script src="js/dashboard.js"></script>
|
||||
<script>
|
||||
var lastTime = new Date().getTime();
|
||||
var currentTime = new Date().getTime();
|
||||
var timeOut = 20 * 60 * 1000; // 20 minutes
|
||||
|
||||
$(function(){
|
||||
// Listen to multiple types of user activity to prevent timeout
|
||||
$(document).on('mousemove keydown click scroll touchstart', function(){
|
||||
lastTime = new Date().getTime();
|
||||
});
|
||||
});
|
||||
|
||||
function testTime(){
|
||||
currentTime = new Date().getTime();
|
||||
if(currentTime - lastTime > timeOut){
|
||||
window.location.href="login.cgi?logout=1";
|
||||
}
|
||||
}
|
||||
|
||||
// Timer check (1 second interval)
|
||||
window.setInterval(testTime, 1000);
|
||||
// Dashboard refresh (3 second interval)
|
||||
setInterval(refreshDashboard, 3000);
|
||||
|
||||
function get_remote_local_ctrl()
|
||||
{
|
||||
var queryData = "sys_cfg=&";
|
||||
$.get("atsc_status_cfg.cgi?"+queryData,function(data, status) {
|
||||
// Handle case where data is a JSON object (e.g., session expired)
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
if (data.error === 'session_expired' && data.redirect) {
|
||||
window.location.href = data.redirect;
|
||||
return;
|
||||
}
|
||||
console.error('Received JSON error response:', data);
|
||||
return;
|
||||
}
|
||||
|
||||
var table = data.split("|");
|
||||
// g_remot_local_ctrl = Number(table[0].split("#")[5]);
|
||||
// document.title = table[0].split("#")[11];
|
||||
});
|
||||
}
|
||||
|
||||
function refresh_show(){
|
||||
//get_remote_local_ctrl();
|
||||
SetFormDefaults();
|
||||
refreshDashboard();
|
||||
}
|
||||
|
||||
function SetFormDefaults()
|
||||
{
|
||||
// 1. DISABLE BUTTON START (Optional safety, though HTML handles initial load)
|
||||
$('#get_log_btn').attr("disabled", true).val("Loading...");
|
||||
// Placeholder for future initialization logic
|
||||
var queryData = "web_title=&";
|
||||
$.get("atsc_status_cfg.cgi?"+queryData,function(data, status) {
|
||||
// Handle case where data is a JSON object (e.g., session expired)
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
if (data.error === 'session_expired' && data.redirect) {
|
||||
window.location.href = data.redirect;
|
||||
return;
|
||||
}
|
||||
console.error('Received JSON error response:', data);
|
||||
return;
|
||||
}
|
||||
|
||||
var table = data.split("|");
|
||||
var title = table[0].split("#");
|
||||
|
||||
// 2. RE-ENABLE BUTTON END
|
||||
$('#get_log_btn').attr("disabled", false).val("Get");
|
||||
|
||||
document.getElementById('webtitle').textContent = title[1];
|
||||
document.getElementById('webtitle_header').textContent = title[1];
|
||||
}).fail(function() {
|
||||
// Optional: Error handling
|
||||
$('#get_log_btn').val("Load Failed");
|
||||
});
|
||||
}
|
||||
|
||||
function cmd_confirm()
|
||||
{
|
||||
return confirm("Please be patient, log data is being collected!");
|
||||
}
|
||||
|
||||
function log_download_show()
|
||||
{
|
||||
document.getElementById("id_download").style.visibility="visible";
|
||||
}
|
||||
|
||||
function Get_Log_File()
|
||||
{
|
||||
if(cmd_confirm()){
|
||||
var queryData = "log_output=&";
|
||||
$.get("atsc_status_cfg.cgi?"+queryData,function(data, status) {
|
||||
// Handle case where data is a JSON object (e.g., session expired)
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
if (data.error === 'session_expired' && data.redirect) {
|
||||
window.location.href = data.redirect;
|
||||
return;
|
||||
}
|
||||
console.error('Received JSON error response:', data);
|
||||
return;
|
||||
}
|
||||
|
||||
var table = data.split("|");
|
||||
var form0 = table[0].split("#");
|
||||
var ret_log = form0[1];
|
||||
|
||||
if(ret_log == 999){
|
||||
setTimeout(log_download_show, 2000);
|
||||
} else {
|
||||
alert("Log generation failed or system busy. Code: " + ret_log);
|
||||
}
|
||||
});
|
||||
}
|
||||
else{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Opens the modal - gets current username from server
|
||||
function openAccountModal() {
|
||||
// Fetch current username from server
|
||||
$.get("login.cgi?action=get_user", function(data) {
|
||||
var trimmedData = (data || "").trim();
|
||||
if (trimmedData && trimmedData !== "UNAUTHORIZED") {
|
||||
document.getElementById('current_user').value = trimmedData;
|
||||
}
|
||||
document.getElementById('accountModal').style.display = 'block';
|
||||
setTimeout(function() { document.getElementById('current_pwd').focus(); }, 100);
|
||||
}).fail(function() {
|
||||
document.getElementById('accountModal').style.display = 'block';
|
||||
setTimeout(function() { document.getElementById('current_pwd').focus(); }, 100);
|
||||
});
|
||||
}
|
||||
|
||||
// Closes the modal and clears the sensitive inputs
|
||||
function closeAccountModal() {
|
||||
document.getElementById('accountModal').style.display = 'none';
|
||||
document.getElementById('current_pwd').value = '';
|
||||
document.getElementById('new_pwd').value = '';
|
||||
document.getElementById('confirm_pwd').value = '';
|
||||
}
|
||||
|
||||
// Validates that a string contains only printable characters (excluding space)
|
||||
function isValidPrintableString(str) {
|
||||
// Regular expression to check for printable characters (ASCII 33-126), excluding space
|
||||
// Space is ASCII 32, and we want to exclude it
|
||||
var printableCharRegex = /^[!-~]+$/; // ! is ASCII 33, ~ is ASCII 126
|
||||
return printableCharRegex.test(str);
|
||||
}
|
||||
|
||||
// Validates the passwords match before submitting to the CGI script - All required fields must be filled
|
||||
function validateAccountForm() {
|
||||
var currentUser = document.getElementById('current_user').value;
|
||||
var currentPwd = document.getElementById('current_pwd').value;
|
||||
var newUsername = document.getElementById('new_user').value;
|
||||
var newPwd = document.getElementById('new_pwd').value;
|
||||
var confirmPwd = document.getElementById('confirm_pwd').value;
|
||||
|
||||
// Current password is required (cannot be empty)
|
||||
if (!currentPwd || currentPwd.trim() === "") {
|
||||
alert("Current password is required");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate current password contains only printable characters
|
||||
if (!isValidPrintableString(currentPwd)) {
|
||||
alert("Current password contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// New password is required (cannot be empty)
|
||||
if (!newPwd || newPwd.trim() === "") {
|
||||
alert("New password is required");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new password contains only printable characters
|
||||
if (!isValidPrintableString(newPwd)) {
|
||||
alert("New password contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new password length (max 16 chars)
|
||||
if (newPwd.length > 16) {
|
||||
alert("New password must be no more than 16 characters");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new password length
|
||||
if (newPwd.length < 6) {
|
||||
alert("New password must be at least 6 characters");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Confirm password must match new password
|
||||
if (newPwd !== confirmPwd) {
|
||||
alert("New passwords do not match");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate confirm password contains only printable characters
|
||||
if (!isValidPrintableString(confirmPwd)) {
|
||||
alert("Confirm password contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate confirm password length (max 16 chars)
|
||||
if (confirmPwd.length > 16) {
|
||||
alert("Confirm password must be no more than 16 characters");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new username if provided
|
||||
if (newUsername && newUsername.trim() !== "") {
|
||||
// Validate new username contains only printable characters
|
||||
if (!isValidPrintableString(newUsername)) {
|
||||
alert("New username contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new username length (max 16 chars)
|
||||
if (newUsername.length > 16) {
|
||||
alert("New username must be no more than 16 characters");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true; // Allows the form to submit
|
||||
}
|
||||
|
||||
// Form submission handler using fetch API
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var accountForm = document.getElementById('accountForm');
|
||||
if (accountForm) {
|
||||
accountForm.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!validateAccountForm()) return;
|
||||
|
||||
var formData = new URLSearchParams({
|
||||
Username: document.getElementById('current_user').value,
|
||||
OldPassword: document.getElementById('current_pwd').value,
|
||||
NewUsername: document.getElementById('new_user').value,
|
||||
NewPassword: document.getElementById('new_pwd').value,
|
||||
ConfirmPassword: document.getElementById('confirm_pwd').value
|
||||
});
|
||||
|
||||
fetch('login.cgi?action=change_account', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert("Update successful! Please login again.");
|
||||
closeAccountModal();
|
||||
// Redirect to login page after 1.5 seconds
|
||||
setTimeout(function() {
|
||||
window.location.href = 'login.cgi?logout=1';
|
||||
}, 1500);
|
||||
} else {
|
||||
alert(data.error || "Update failed");
|
||||
}
|
||||
})
|
||||
.catch(function(err) {
|
||||
alert("Network error: " + err);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Optional: Closes the modal if the user clicks the dark background outside the box
|
||||
window.onclick = function(event) {
|
||||
var modal = document.getElementById('accountModal');
|
||||
if (event.target == modal) {
|
||||
closeAccountModal();
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="refresh_show()">
|
||||
|
||||
<div class="app-layout">
|
||||
<aside class="app-sidebar">
|
||||
<ul class="items">
|
||||
<li><a href="status_info.html" title="Status">Status</a></li>
|
||||
<li><a href="sys_set.html" title="Settings">Settings</a></li>
|
||||
<li><a href="sys_rf.html" title="RF Control">RF Control</a></li>
|
||||
<li><a href="sys_psip.html" title="TSID&PSIP">TSID&PSIP</a></li>
|
||||
<li><a href="sys_ts.html" title="TSoIP">TSoIP</a></li>
|
||||
<li><a href="sys_spectrum.html" title="Spectrum">Spectrum</a></li>
|
||||
<li class="active"><a href="log_output.html" title="Log">Log</a></li>
|
||||
</ul>
|
||||
<div class="sidebar-footer">
|
||||
<h4>Anywave Broadcast Inc.</h4>
|
||||
<p>Copyright 2026<br><br><span class="redbox-label">Technical Support</span><br>+1 847 415 2258<br><a href="mailto:support@anywaveus.com">support@anywaveus.com</a></p>
|
||||
</div>
|
||||
</aside>
|
||||
<div class="sidebar-overlay" onclick="toggleSidebar()"></div>
|
||||
|
||||
<header class="app-header">
|
||||
<button class="menu-toggle" onclick="toggleSidebar()" aria-label="Toggle menu">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="3" y1="12" x2="21" y2="12"></line>
|
||||
<line x1="3" y1="6" x2="21" y2="6"></line>
|
||||
<line x1="3" y1="18" x2="21" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
<h1><a href="https://anywavecom.net/" class="logo-bg" title="Anywave Broadcast Inc."></a></h1>
|
||||
<h2 id="webtitle_header"><span></span></h2>
|
||||
<h3>
|
||||
<div class="dropdown">
|
||||
<button class="dropbtn-modern">Admin ▾</button>
|
||||
<div class="dropdown-content">
|
||||
<a href="#" onclick="openAccountModal(); return false;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="3"></circle>
|
||||
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06-.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06-.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06-.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
|
||||
</svg>
|
||||
Account Settings
|
||||
</a>
|
||||
<a href="login.cgi?logout=1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
|
||||
<polyline points="16 17 21 12 16 7"></polyline>
|
||||
<line x1="21" y1="12" x2="9" y2="12"></line>
|
||||
</svg>
|
||||
Logout
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</h3>
|
||||
</header>
|
||||
|
||||
<!-- Fixed Dashboard Summary - Top of page, under header -->
|
||||
<div class="dashboard-fixed">
|
||||
<div class="summary-dashboard">
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_freq" aria-hidden="true"></span>
|
||||
<span class="summary-label">Frequency</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_freq">--</span>
|
||||
<span class="summary-unit">MHz</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_snr" aria-hidden="true"></span>
|
||||
<span class="summary-label">SNR</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_snr">--</span>
|
||||
<span class="summary-unit">dB</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_uimd" aria-hidden="true"></span>
|
||||
<span class="summary-label">UIMD</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_uimd">--</span>
|
||||
<span class="summary-unit">dBc</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_limd" aria-hidden="true"></span>
|
||||
<span class="summary-label">LIMD</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_limd">--</span>
|
||||
<span class="summary-unit">dBc</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-off" id="dot_rf" aria-hidden="true"></span>
|
||||
<span class="summary-label">RF Switch</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-muted" id="sum_rf">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_outpow" aria-hidden="true"></span>
|
||||
<span class="summary-label">Output Power</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_outpow">--</span>
|
||||
<span class="summary-unit">dBm</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_input" aria-hidden="true"></span>
|
||||
<span class="summary-label">Input Source</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_input">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_input_status" aria-hidden="true"></span>
|
||||
<span class="summary-label">Input Status</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_input_status">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_bitrate" aria-hidden="true"></span>
|
||||
<span class="summary-label">Bitrate</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_bitrate">--</span>
|
||||
<span class="summary-unit">Mbps</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_temp" aria-hidden="true"></span>
|
||||
<span class="summary-label">Temperature</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_temp">--</span>
|
||||
<span class="summary-unit">°F</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-off" id="dot_agc" aria-hidden="true"></span>
|
||||
<span class="summary-label">AGC</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-muted" id="sum_agc">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_control" aria-hidden="true"></span>
|
||||
<span class="summary-label">Control</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_control">--</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main class="app-main">
|
||||
<h2>Output Log</h2>
|
||||
<div class="box log-export-box">
|
||||
<table>
|
||||
<tr>
|
||||
<td class="log-export-label">
|
||||
Export System Log
|
||||
</td>
|
||||
<td class="log-export-actions">
|
||||
<input type="button" class="btn-modern" id="get_log_btn" alt="GET" value="Get" disabled onclick="return Get_Log_File();">
|
||||
<a href="/module_log.zip" download="module_log.zip">
|
||||
<input type="button" class="btn-modern" style="visibility:hidden;" id="id_download" alt="DOWNLOAD" value="Download">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div id="accountModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3>Account Settings</h3>
|
||||
<span class="close" onclick="closeAccountModal()">×</span>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="accountForm" method="post" action="login.cgi?action=change_account" onsubmit="return validateAccountForm()">
|
||||
<table class="modal-table">
|
||||
<tr>
|
||||
<td>Current Username</td>
|
||||
<td><input type="text" id="current_user" name="current_user" readonly></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Current Password</td>
|
||||
<td><input type="password" id="current_pwd" name="current_pwd" required></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>New Username</td>
|
||||
<td><input type="text" id="new_user" name="new_user"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>New Password</td>
|
||||
<td><input type="password" id="new_pwd" name="new_pwd"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Confirm Password</td>
|
||||
<td><input type="password" id="confirm_pwd" name="confirm_pwd"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="modal-footer">
|
||||
<input type="button" class="btn-modern" style="background-color: #64748b;" value="Cancel" onclick="closeAccountModal()">
|
||||
<input type="submit" class="btn-modern" value="Save Changes">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toggleSidebar(){
|
||||
document.querySelector('.app-sidebar').classList.toggle('sidebar-open');
|
||||
document.querySelector('.sidebar-overlay').classList.toggle('active');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Executable
BIN
Binary file not shown.
Executable
+113
@@ -0,0 +1,113 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title id="webtitle"></title>
|
||||
<link href="css/styles.css" rel="stylesheet" media="screen">
|
||||
<style>
|
||||
#content .box table td:first-child {
|
||||
width: 45%;
|
||||
min-width: 200px;
|
||||
max-width: none;
|
||||
}
|
||||
</style>
|
||||
<script src="js/jquery.js"></script>
|
||||
|
||||
<script>
|
||||
function checkUser(){
|
||||
var result = document.getElementById("username_id").value;
|
||||
var password = document.getElementById("pwd_id").value;
|
||||
|
||||
if(result == ""){
|
||||
alert("User name cannot be empty!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if(password == ""){
|
||||
alert("Password cannot be empty!");
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
function loginsubmit() {
|
||||
if(checkUser() == false){
|
||||
return;
|
||||
}
|
||||
document.getElementById('loginformid').submit();
|
||||
}
|
||||
|
||||
function refresh_show(){
|
||||
var queryData = "web_title=&"
|
||||
$.get("atsc_status_cfg.cgi?"+queryData, function(data, status) {
|
||||
var table = data.split("|");
|
||||
var title = table[0].split("#");
|
||||
document.getElementById('webtitle').textContent = title[1];
|
||||
document.getElementById('webtitle_header').textContent = title[1];
|
||||
});
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
<body onload="refresh_show()">
|
||||
<div class="app-layout">
|
||||
<aside class="app-sidebar">
|
||||
<ul class="items">
|
||||
<li class="active"><a href="login.html" title="Login">Login</a></li>
|
||||
</ul>
|
||||
<div class="sidebar-footer">
|
||||
<h4>Anywave Broadcast Inc.</h4>
|
||||
<p>Copyright 2026<br><br><span class="redbox-label">Technical Support</span><br>+1 847 415 2258<br><a href="mailto:support@anywaveus.com">support@anywaveus.com</a></p>
|
||||
</div>
|
||||
</aside>
|
||||
<div class="sidebar-overlay" onclick="toggleSidebar()"></div>
|
||||
|
||||
<header class="app-header">
|
||||
<button class="menu-toggle" onclick="toggleSidebar()" aria-label="Toggle menu">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="3" y1="12" x2="21" y2="12"></line>
|
||||
<line x1="3" y1="6" x2="21" y2="6"></line>
|
||||
<line x1="3" y1="18" x2="21" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
<h1><a href="https://anywavecom.net/" class="logo-bg" title="Anywave Broadcast Inc."></a></h1>
|
||||
<h2 id="webtitle_header"><span></span></h2>
|
||||
</header>
|
||||
|
||||
<main class="app-main">
|
||||
<div class="login-container">
|
||||
<div class="login-box">
|
||||
<h2>Login</h2>
|
||||
<div class="box">
|
||||
<form method="post" action="login.cgi" name="loginformname" id="loginformid">
|
||||
<table>
|
||||
<tr>
|
||||
<td>User Name</td>
|
||||
<td><input type="text" name="Username" style="max-width: 150px;" id="username_id" value="" size="12" maxlength="12"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Password</td>
|
||||
<td><input type="password" name="Password" style="max-width: 150px;" id="pwd_id" value="" size="12" maxlength="12"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td><input type="button" class="btn-modern" alt="Up" value="Login" id="loginid" onclick="loginsubmit();"></td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toggleSidebar(){
|
||||
document.querySelector('.app-sidebar').classList.toggle('sidebar-open');
|
||||
document.querySelector('.sidebar-overlay').classList.toggle('active');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
./com-status-process
|
||||
./boot-limit-process
|
||||
File diff suppressed because it is too large
Load Diff
+4
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
|
||||
killall -9 com-status-process
|
||||
killall -9 boot-limit-process
|
||||
Executable
+847
@@ -0,0 +1,847 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title id="webtitle"></title>
|
||||
<link href="css/styles.css" rel="stylesheet" media="screen">
|
||||
<script src="js/auth.js"></script>
|
||||
<script src="js/jquery.js"></script>
|
||||
<script src="js/dashboard.js"></script>
|
||||
<script>
|
||||
var time_sec_cnt=0;
|
||||
var g_remot_local_ctrl = 0; // 0 remote 1 local
|
||||
var lastTime = new Date().getTime();
|
||||
var currentTime = new Date().getTime();
|
||||
var timeOut = 20 * 60 * 1000; // 20 min
|
||||
|
||||
$(function(){
|
||||
// Listen to multiple types of user activity to prevent timeout
|
||||
$(document).on('mousemove keydown click scroll touchstart', function(){
|
||||
lastTime = new Date().getTime();
|
||||
});
|
||||
});
|
||||
|
||||
function testTime(){
|
||||
currentTime = new Date().getTime();
|
||||
if(currentTime - lastTime > timeOut){
|
||||
window.location.href="login.cgi?logout=1"
|
||||
}
|
||||
|
||||
time_sec_cnt=time_sec_cnt+1;
|
||||
if(time_sec_cnt%3==0){
|
||||
get_remote_local_ctrl();
|
||||
if(g_remot_local_ctrl==1) { // local
|
||||
SetFormDefaults();
|
||||
}
|
||||
refreshDashboard();
|
||||
}
|
||||
}
|
||||
|
||||
// Timer check
|
||||
window.setInterval(testTime, 1000);
|
||||
refreshDashboard();
|
||||
|
||||
function get_remote_local_ctrl() {
|
||||
var queryData = "sys_cfg=&";
|
||||
$.get("atsc_status_cfg.cgi?"+queryData, function(data, status) {
|
||||
// Handle case where data is a JSON object (e.g., session expired)
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
if (data.error === 'session_expired' && data.redirect) {
|
||||
window.location.href = data.redirect;
|
||||
return;
|
||||
}
|
||||
console.error('Received JSON error response:', data);
|
||||
return;
|
||||
}
|
||||
|
||||
var table = data.split("|");
|
||||
g_remot_local_ctrl = Number(table[0].split("#")[5]);
|
||||
document.title = table[0].split("#")[11];
|
||||
});
|
||||
}
|
||||
|
||||
// Updated SetFormDefaults to populate the Single Form
|
||||
function SetFormDefaults() {
|
||||
// 1. DISABLE BUTTONS START (only in Remote mode)
|
||||
if(g_remot_local_ctrl == 1) {
|
||||
// Local mode: just fetch data, don't change button text
|
||||
var queryData = "tsid_psip=&psip_cfg=&web_title=&";
|
||||
} else {
|
||||
// Remote mode: show LOADING indicator
|
||||
$('#tsid_form input[type="button"], #psip_table_form input[type="button"]')
|
||||
.attr("disabled", true)
|
||||
.val("LOADING...");
|
||||
var queryData = "tsid_psip=&psip_cfg=&web_title=&";
|
||||
}
|
||||
$.get("atsc_status_cfg.cgi?" + queryData, function(data, status) {
|
||||
// Handle case where data is a JSON object (e.g., session expired)
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
if (data.error === 'session_expired' && data.redirect) {
|
||||
window.location.href = data.redirect;
|
||||
return;
|
||||
}
|
||||
console.error('Received JSON error response:', data);
|
||||
return;
|
||||
}
|
||||
|
||||
var table = data.split("|");
|
||||
var form = table[0].split("#");
|
||||
var title= table[1].split("#");
|
||||
|
||||
// 1. Handle Top Settings (Form 0)
|
||||
var cf = document.getElementById("tsid_form");
|
||||
var i = 1;
|
||||
cf.ts_edit.value = form[i++];
|
||||
cf.tsid.value = form[i++];
|
||||
var index_max = Number(form[i++]);
|
||||
|
||||
// 2. Handle PSIP Table (Form 1 - The new single form)
|
||||
var psipForm = document.getElementById("psip_table_form");
|
||||
|
||||
// Loop through all 13 potential rows (0 to 12)
|
||||
for (var k = 0; k < 13; k++) {
|
||||
// Populate inputs by name (e.g., "index0", "sht_name0")
|
||||
if(psipForm.elements['index' + k]) {
|
||||
psipForm.elements['index' + k].value = form[i++];
|
||||
psipForm.elements['sht_name' + k].value = form[i++];
|
||||
psipForm.elements['maj_num' + k].value = form[i++];
|
||||
psipForm.elements['min_num' + k].value = form[i++];
|
||||
}
|
||||
|
||||
// Hide unused rows
|
||||
var row = document.getElementById("psip" + k);
|
||||
if (row) {
|
||||
if (k >= index_max && k != 0) {
|
||||
row.style.display = "none";
|
||||
} else {
|
||||
row.style.display = "table-row"; // Ensure visible rows display correctly
|
||||
}
|
||||
}
|
||||
}
|
||||
// 2. RE-ENABLE BUTTONS END (only in Remote mode)
|
||||
if(g_remot_local_ctrl == 1) {
|
||||
// Local mode: keep buttons disabled
|
||||
$('#tsid_form input[type="button"], #psip_table_form input[type="button"]')
|
||||
.attr("disabled", true)
|
||||
.val("Local Mode");
|
||||
} else {
|
||||
// Remote mode: enable buttons
|
||||
$('#tsid_form input[type="button"], #psip_table_form input[type="button"]')
|
||||
.attr("disabled", false)
|
||||
.val("Set");
|
||||
}
|
||||
if (typeof setTsidFormSnapshotUpdate === 'function') setTsidFormSnapshotUpdate();
|
||||
if (typeof psipFormSnapshotUpdate === 'function') psipFormSnapshotUpdate();
|
||||
|
||||
document.getElementById('webtitle').textContent = title[1];
|
||||
document.getElementById('webtitle_header').textContent = title[1];
|
||||
}).fail(function() {
|
||||
// Optional: Error handling
|
||||
$('#tsid_form input[type="button"], #psip_table_form input[type="button"]').val("LOAD FAILED");
|
||||
});
|
||||
}
|
||||
|
||||
// ----- SET (unsaved) reminder: tsid_form (per-row: CTRL vs TSID) + psip_table_form (per-row), vanilla JS -----
|
||||
var tsidFormSnapshotPerRow = [];
|
||||
function getFormSnapshot(formId) {
|
||||
var f = document.getElementById(formId);
|
||||
if (!f) return [];
|
||||
var out = [], els = f.querySelectorAll('select, input:not([type="button"])'), i, el, v;
|
||||
for (i = 0; i < els.length; i++) {
|
||||
el = els[i];
|
||||
v = el.tagName === 'SELECT' ? (el.options[el.selectedIndex] ? el.options[el.selectedIndex].value : '') : (el.value || '');
|
||||
out.push({ name: el.name || el.id, value: String(v) });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
function getFormSnapshotPerRowTsid(formId) {
|
||||
var f = document.getElementById(formId);
|
||||
if (!f) return [];
|
||||
var rows = f.querySelectorAll('table tr'), out = [], i;
|
||||
for (i = 0; i < rows.length; i++) {
|
||||
if (rows[i].querySelector('input[type="button"]')) out.push(getRowValues(rows[i]));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
function setTsidRowButtonState(tr, unsaved) {
|
||||
var btn = tr.querySelector('input[type="button"]');
|
||||
if (!btn || btn.disabled) return;
|
||||
btn.value = unsaved ? 'Set (unsaved)' : 'Set';
|
||||
if (unsaved) btn.classList.add('is-unsaved'); else btn.classList.remove('is-unsaved');
|
||||
}
|
||||
function setTsidFormSnapshotUpdate() {
|
||||
var f = document.getElementById('tsid_form');
|
||||
if (f) tsidFormSnapshotPerRow = getFormSnapshotPerRowTsid('tsid_form');
|
||||
f = document.getElementById('tsid_form');
|
||||
if (f) {
|
||||
var rows = f.querySelectorAll('table tr');
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
if (rows[i].querySelector('input[type="button"]')) setTsidRowButtonState(rows[i], false);
|
||||
}
|
||||
}
|
||||
}
|
||||
function updateTsidFormRowButtonStates() {
|
||||
var f = document.getElementById('tsid_form');
|
||||
if (!f || !tsidFormSnapshotPerRow.length) return;
|
||||
var rows = f.querySelectorAll('table tr');
|
||||
var rowIdx = 0;
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
if (!rows[i].querySelector('input[type="button"]')) continue;
|
||||
var dirty = rowIdx < tsidFormSnapshotPerRow.length && isRowDirty(getRowValues(rows[i]), tsidFormSnapshotPerRow[rowIdx]);
|
||||
setTsidRowButtonState(rows[i], dirty);
|
||||
rowIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
var psipFormSnapshotPerRow = [];
|
||||
function getRowValues(tr) {
|
||||
var out = [], els = tr.querySelectorAll('select, input:not([type="button"])'), i, el, v;
|
||||
for (i = 0; i < els.length; i++) {
|
||||
el = els[i];
|
||||
v = el.tagName === 'SELECT' ? (el.options[el.selectedIndex] ? el.options[el.selectedIndex].value : '') : (el.value || '');
|
||||
out.push({ name: el.name || el.id, value: String(v) });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
function getFormSnapshotPerRow(formId) {
|
||||
var f = document.getElementById(formId);
|
||||
if (!f) return [];
|
||||
var rows = f.querySelectorAll('table tr'), out = [], i;
|
||||
for (i = 0; i < rows.length; i++) {
|
||||
if (rows[i].querySelector('input[type="button"]')) out.push(getRowValues(rows[i]));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
function isRowDirty(rowValues, rowSnapshot) {
|
||||
if (rowValues.length !== rowSnapshot.length) return true;
|
||||
for (var i = 0; i < rowValues.length; i++) {
|
||||
if (rowValues[i].name !== rowSnapshot[i].name || rowValues[i].value !== rowSnapshot[i].value) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function setPsipRowButtonState(tr, unsaved) {
|
||||
var btn = tr.querySelector('input[type="button"]');
|
||||
if (!btn || btn.disabled) return;
|
||||
btn.value = unsaved ? 'Set (unsaved)' : 'Set';
|
||||
if (unsaved) btn.classList.add('is-unsaved'); else btn.classList.remove('is-unsaved');
|
||||
}
|
||||
function updateAllPsipRowButtonStates(formId) {
|
||||
var f = document.getElementById(formId);
|
||||
if (!f || !psipFormSnapshotPerRow.length) return;
|
||||
var rows = f.querySelectorAll('table tr');
|
||||
var rowIdx = 0;
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
if (!rows[i].querySelector('input[type="button"]')) continue;
|
||||
setPsipRowButtonState(rows[i], rowIdx < psipFormSnapshotPerRow.length && isRowDirty(getRowValues(rows[i]), psipFormSnapshotPerRow[rowIdx]));
|
||||
rowIdx++;
|
||||
}
|
||||
}
|
||||
function setAllPsipRowButtonsSaved() {
|
||||
var f = document.getElementById('psip_table_form');
|
||||
if (!f) return;
|
||||
var rows = f.querySelectorAll('table tr');
|
||||
for (var i = 0; i < rows.length; i++) setPsipRowButtonState(rows[i], false);
|
||||
}
|
||||
function psipFormSnapshotUpdate() {
|
||||
psipFormSnapshotPerRow = getFormSnapshotPerRow('psip_table_form');
|
||||
setAllPsipRowButtonsSaved();
|
||||
}
|
||||
function attachPsipUnsavedListeners() {
|
||||
var f = document.getElementById('tsid_form');
|
||||
if (f) {
|
||||
f.addEventListener('change', updateTsidFormRowButtonStates);
|
||||
f.addEventListener('input', updateTsidFormRowButtonStates);
|
||||
}
|
||||
var pf = document.getElementById('psip_table_form');
|
||||
if (pf) pf.addEventListener('change', function() { updateAllPsipRowButtonStates('psip_table_form'); });
|
||||
}
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', attachPsipUnsavedListeners);
|
||||
} else {
|
||||
attachPsipUnsavedListeners();
|
||||
}
|
||||
|
||||
function refresh_show(){
|
||||
get_remote_local_ctrl();
|
||||
SetFormDefaults();
|
||||
refreshDashboard();
|
||||
}
|
||||
|
||||
function cmd_confirm() {
|
||||
return confirm("Please choose to confirm or cancel!");
|
||||
}
|
||||
|
||||
function tsid_psip_top_set() {
|
||||
var postData = "tsid_psip=";
|
||||
var cf = document.forms[0];
|
||||
|
||||
postData += "#"+cf.ts_edit.value;
|
||||
postData += "#"+cf.tsid.value;
|
||||
if(cmd_confirm()){
|
||||
|
||||
$.post("atsc_status_cfg.cgi", postData, function(data, status){
|
||||
if(status=="success"){
|
||||
setTimeout(function() { SetFormDefaults(); }, 2000);
|
||||
} else {
|
||||
alert("post val err");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Updated Sub Set Function to read from Single Form
|
||||
function tsid_psip_sub_set(clickedIndex) {
|
||||
var postData = "psip_cfg=";
|
||||
var psipForm = document.getElementById("psip_table_form");
|
||||
|
||||
// Iterate through all 13 rows to build the data string
|
||||
for(var k=0; k<13; k++) {
|
||||
// Access values directly from the single form using names
|
||||
postData += "#" + psipForm.elements['index'+k].value;
|
||||
postData += "#" + psipForm.elements['sht_name'+k].value;
|
||||
postData += "#" + psipForm.elements['maj_num'+k].value;
|
||||
postData += "#" + psipForm.elements['min_num'+k].value;
|
||||
}
|
||||
|
||||
if(cmd_confirm()){
|
||||
$.post("atsc_status_cfg.cgi", postData, function(data, status){
|
||||
if(status=="success"){
|
||||
setTimeout(function() { SetFormDefaults(); }, 2000);
|
||||
} else {
|
||||
alert("post val err");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Modal Logic - Open and close account modal
|
||||
function openAccountModal() {
|
||||
// Fetch current username from server
|
||||
$.get("login.cgi?action=get_user", function(data) {
|
||||
var trimmedData = (data || "").trim();
|
||||
if (trimmedData && trimmedData !== "UNAUTHORIZED") {
|
||||
document.getElementById('current_user').value = trimmedData;
|
||||
}
|
||||
document.getElementById('accountModal').style.display = 'block';
|
||||
setTimeout(function() { document.getElementById('current_pwd').focus(); }, 100);
|
||||
}).fail(function() {
|
||||
document.getElementById('accountModal').style.display = 'block';
|
||||
setTimeout(function() { document.getElementById('current_pwd').focus(); }, 100);
|
||||
});
|
||||
}
|
||||
|
||||
function closeAccountModal() {
|
||||
document.getElementById('accountModal').style.display = 'none';
|
||||
// Clear sensitive fields
|
||||
document.getElementById('current_pwd').value = '';
|
||||
document.getElementById('new_pwd').value = '';
|
||||
document.getElementById('confirm_pwd').value = '';
|
||||
}
|
||||
|
||||
// Validates that a string contains only printable characters (excluding space)
|
||||
function isValidPrintableString(str) {
|
||||
// Regular expression to check for printable characters (ASCII 33-126), excluding space
|
||||
// Space is ASCII 32, and we want to exclude it
|
||||
var printableCharRegex = /^[!-~]+$/; // ! is ASCII 33, ~ is ASCII 126
|
||||
return printableCharRegex.test(str);
|
||||
}
|
||||
|
||||
// Validation - All required fields must be filled
|
||||
function validateAccountForm() {
|
||||
var currentUser = document.getElementById('current_user').value;
|
||||
var currentPwd = document.getElementById('current_pwd').value;
|
||||
var newUsername = document.getElementById('new_user').value;
|
||||
var newPwd = document.getElementById('new_pwd').value;
|
||||
var confirmPwd = document.getElementById('confirm_pwd').value;
|
||||
|
||||
// Current password is required (cannot be empty)
|
||||
if (!currentPwd || currentPwd.trim() === "") {
|
||||
alert("Current password is required");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate current password contains only printable characters
|
||||
if (!isValidPrintableString(currentPwd)) {
|
||||
alert("Current password contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// New password is required (cannot be empty)
|
||||
if (!newPwd || newPwd.trim() === "") {
|
||||
alert("New password is required");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new password contains only printable characters
|
||||
if (!isValidPrintableString(newPwd)) {
|
||||
alert("New password contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new password length (max 16 chars)
|
||||
if (newPwd.length > 16) {
|
||||
alert("New password must be no more than 16 characters");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new password length
|
||||
if (newPwd.length < 6) {
|
||||
alert("New password must be at least 6 characters");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Confirm password must match new password
|
||||
if (newPwd !== confirmPwd) {
|
||||
alert("New passwords do not match");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate confirm password contains only printable characters
|
||||
if (!isValidPrintableString(confirmPwd)) {
|
||||
alert("Confirm password contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate confirm password length (max 16 chars)
|
||||
if (confirmPwd.length > 16) {
|
||||
alert("Confirm password must be no more than 16 characters");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new username if provided
|
||||
if (newUsername && newUsername.trim() !== "") {
|
||||
// Validate new username contains only printable characters
|
||||
if (!isValidPrintableString(newUsername)) {
|
||||
alert("New username contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new username length (max 16 chars)
|
||||
if (newUsername.length > 16) {
|
||||
alert("New username must be no more than 16 characters");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Form submission handler using fetch API
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var accountForm = document.getElementById('accountForm');
|
||||
if (accountForm) {
|
||||
accountForm.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!validateAccountForm()) return;
|
||||
|
||||
var formData = new URLSearchParams({
|
||||
Username: document.getElementById('current_user').value,
|
||||
OldPassword: document.getElementById('current_pwd').value,
|
||||
NewUsername: document.getElementById('new_user').value,
|
||||
NewPassword: document.getElementById('new_pwd').value,
|
||||
ConfirmPassword: document.getElementById('confirm_pwd').value
|
||||
});
|
||||
|
||||
fetch('login.cgi?action=change_account', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert("Update successful! Please login again.");
|
||||
closeAccountModal();
|
||||
// Redirect to login page after 1.5 seconds
|
||||
setTimeout(function() {
|
||||
window.location.href = 'login.cgi?logout=1';
|
||||
}, 1500);
|
||||
} else {
|
||||
alert(data.error || "Update failed");
|
||||
}
|
||||
})
|
||||
.catch(function(err) {
|
||||
alert("Network error: " + err);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="refresh_show()">
|
||||
<div class="app-layout">
|
||||
<aside class="app-sidebar">
|
||||
<ul class="items">
|
||||
<li><a href="status_info.html" title="Status">Status</a></li>
|
||||
<li><a href="sys_set.html" title="Settings">Settings</a></li>
|
||||
<li><a href="sys_rf.html" title="RF Control">RF Control</a></li>
|
||||
<li class="active"><a href="sys_psip.html" title="TSID&PSIP">TSID&PSIP</a></li>
|
||||
<li><a href="sys_ts.html" title="TSoIP">TSoIP</a></li>
|
||||
<li><a href="sys_spectrum.html" title="Spectrum">Spectrum</a></li>
|
||||
<li><a href="log_output.html" title="Log">Log</a></li>
|
||||
</ul>
|
||||
<div class="sidebar-footer">
|
||||
<h4>Anywave Broadcast Inc.</h4>
|
||||
<p>Copyright 2026<br><br><span class="redbox-label">Technical Support</span><br>+1 847 415 2258<br><a href="mailto:support@anywaveus.com">support@anywaveus.com</a></p>
|
||||
</div>
|
||||
</aside>
|
||||
<div class="sidebar-overlay" onclick="toggleSidebar()"></div>
|
||||
|
||||
<header class="app-header">
|
||||
<button class="menu-toggle" onclick="toggleSidebar()" aria-label="Toggle menu">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="3" y1="12" x2="21" y2="12"></line>
|
||||
<line x1="3" y1="6" x2="21" y2="6"></line>
|
||||
<line x1="3" y1="18" x2="21" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
<h1><a href="https://anywavecom.net/" class="logo-bg" title="Anywave Broadcast Inc."></a></h1>
|
||||
<h2 id="webtitle_header"><span></span></h2>
|
||||
<h3>
|
||||
<div class="dropdown">
|
||||
<button class="dropbtn-modern">Admin ▾</button>
|
||||
<div class="dropdown-content">
|
||||
<a href="#" onclick="openAccountModal(); return false;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="3"></circle>
|
||||
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06-.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06-.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06-.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
|
||||
</svg>
|
||||
Account Settings
|
||||
</a>
|
||||
<a href="login.cgi?logout=1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
|
||||
<polyline points="16 17 21 12 16 7"></polyline>
|
||||
<line x1="21" y1="12" x2="9" y2="12"></line>
|
||||
</svg>
|
||||
Logout
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</h3>
|
||||
</header>
|
||||
|
||||
<!-- Fixed Dashboard Summary - Top of page, under header -->
|
||||
<div class="dashboard-fixed">
|
||||
<div class="summary-dashboard">
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_freq" aria-hidden="true"></span>
|
||||
<span class="summary-label">Frequency</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_freq">--</span>
|
||||
<span class="summary-unit">MHz</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_snr" aria-hidden="true"></span>
|
||||
<span class="summary-label">SNR</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_snr">--</span>
|
||||
<span class="summary-unit">dB</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_uimd" aria-hidden="true"></span>
|
||||
<span class="summary-label">UIMD</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_uimd">--</span>
|
||||
<span class="summary-unit">dBc</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_limd" aria-hidden="true"></span>
|
||||
<span class="summary-label">LIMD</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_limd">--</span>
|
||||
<span class="summary-unit">dBc</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-off" id="dot_rf" aria-hidden="true"></span>
|
||||
<span class="summary-label">RF Switch</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-muted" id="sum_rf">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_outpow" aria-hidden="true"></span>
|
||||
<span class="summary-label">Output Power</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_outpow">--</span>
|
||||
<span class="summary-unit">dBm</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_input" aria-hidden="true"></span>
|
||||
<span class="summary-label">Input Source</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_input">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_input_status" aria-hidden="true"></span>
|
||||
<span class="summary-label">Input Status</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_input_status">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_bitrate" aria-hidden="true"></span>
|
||||
<span class="summary-label">Bitrate</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_bitrate">--</span>
|
||||
<span class="summary-unit">Mbps</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_temp" aria-hidden="true"></span>
|
||||
<span class="summary-label">Temperature</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_temp">--</span>
|
||||
<span class="summary-unit">°F</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-off" id="dot_agc" aria-hidden="true"></span>
|
||||
<span class="summary-label">AGC</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-muted" id="sum_agc">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_control" aria-hidden="true"></span>
|
||||
<span class="summary-label">Control</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_control">--</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main class="app-main">
|
||||
<h2>TSID&PSIP</h2>
|
||||
<div class="box">
|
||||
<form id="tsid_form">
|
||||
<table>
|
||||
<tr>
|
||||
<td>CTRL</td>
|
||||
<td>
|
||||
<select name="ts_edit" id="ts_edit">
|
||||
<option value="0">Disable
|
||||
<option value="1">Enable
|
||||
<option value="2">Clear
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="button" class="btn-modern" alt="Set" value="Set" disabled onclick="return tsid_psip_top_set();">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>TSID</td>
|
||||
<td>
|
||||
<input type="text" maxlength="5" size="8" name="tsid" id="tsid" value="">
|
||||
</td>
|
||||
<td>
|
||||
<input type="button" class="btn-modern" alt="Set" value="Set" disabled onclick="return tsid_psip_top_set();">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div class="box">
|
||||
<form name="psip_table_form" id="psip_table_form">
|
||||
<table id="psip_table">
|
||||
<tr class="header-row">
|
||||
<td style="width: 25%">Program</td>
|
||||
<td style="width: 25%">Short Name</td>
|
||||
<td style="width: 25%">Major Channel Number</td>
|
||||
<td style="width: 25%">Minor Channel Number</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr id="psip0">
|
||||
<td><input type="text" name="index0" readonly></td>
|
||||
<td><input type="text" name="sht_name0"></td>
|
||||
<td><input type="text" name="maj_num0"></td>
|
||||
<td><input type="text" name="min_num0"></td>
|
||||
<td><input type="button" class="btn-modern" value="Set" disabled onclick="return tsid_psip_sub_set(0);"></td>
|
||||
</tr>
|
||||
|
||||
<tr id="psip1">
|
||||
<td><input type="text" name="index1" readonly></td>
|
||||
<td><input type="text" name="sht_name1"></td>
|
||||
<td><input type="text" name="maj_num1"></td>
|
||||
<td><input type="text" name="min_num1"></td>
|
||||
<td><input type="button" class="btn-modern" value="Set" disabled onclick="return tsid_psip_sub_set(1);"></td>
|
||||
</tr>
|
||||
|
||||
<tr id="psip2">
|
||||
<td><input type="text" name="index2" readonly></td>
|
||||
<td><input type="text" name="sht_name2"></td>
|
||||
<td><input type="text" name="maj_num2"></td>
|
||||
<td><input type="text" name="min_num2"></td>
|
||||
<td><input type="button" class="btn-modern" value="Set" disabled disabled onclick="return tsid_psip_sub_set(2);"></td>
|
||||
</tr>
|
||||
|
||||
<tr id="psip3">
|
||||
<td><input type="text" name="index3" readonly></td>
|
||||
<td><input type="text" name="sht_name3"></td>
|
||||
<td><input type="text" name="maj_num3"></td>
|
||||
<td><input type="text" name="min_num3"></td>
|
||||
<td><input type="button" class="btn-modern" value="Set" disabled disabled onclick="return tsid_psip_sub_set(3);"></td>
|
||||
</tr>
|
||||
|
||||
<tr id="psip4">
|
||||
<td><input type="text" name="index4" readonly></td>
|
||||
<td><input type="text" name="sht_name4"></td>
|
||||
<td><input type="text" name="maj_num4"></td>
|
||||
<td><input type="text" name="min_num4"></td>
|
||||
<td><input type="button" class="btn-modern" value="Set" disabled onclick="return tsid_psip_sub_set(4);"></td>
|
||||
</tr>
|
||||
|
||||
<tr id="psip5">
|
||||
<td><input type="text" name="index5" readonly></td>
|
||||
<td><input type="text" name="sht_name5"></td>
|
||||
<td><input type="text" name="maj_num5"></td>
|
||||
<td><input type="text" name="min_num5"></td>
|
||||
<td><input type="button" class="btn-modern" value="Set" disabled onclick="return tsid_psip_sub_set(5);"></td>
|
||||
</tr>
|
||||
|
||||
<tr id="psip6">
|
||||
<td><input type="text" name="index6" readonly></td>
|
||||
<td><input type="text" name="sht_name6"></td>
|
||||
<td><input type="text" name="maj_num6"></td>
|
||||
<td><input type="text" name="min_num6"></td>
|
||||
<td><input type="button" class="btn-modern" value="Set" disabled onclick="return tsid_psip_sub_set(6);"></td>
|
||||
</tr>
|
||||
|
||||
<tr id="psip7">
|
||||
<td><input type="text" name="index7" readonly></td>
|
||||
<td><input type="text" name="sht_name7"></td>
|
||||
<td><input type="text" name="maj_num7"></td>
|
||||
<td><input type="text" name="min_num7"></td>
|
||||
<td><input type="button" class="btn-modern" value="Set" disabled onclick="return tsid_psip_sub_set(7);"></td>
|
||||
</tr>
|
||||
|
||||
<tr id="psip8">
|
||||
<td><input type="text" name="index8" readonly></td>
|
||||
<td><input type="text" name="sht_name8"></td>
|
||||
<td><input type="text" name="maj_num8"></td>
|
||||
<td><input type="text" name="min_num8"></td>
|
||||
<td><input type="button" class="btn-modern" value="Set" disabled onclick="return tsid_psip_sub_set(8);"></td>
|
||||
</tr>
|
||||
|
||||
<tr id="psip9">
|
||||
<td><input type="text" name="index9" readonly></td>
|
||||
<td><input type="text" name="sht_name9"></td>
|
||||
<td><input type="text" name="maj_num9"></td>
|
||||
<td><input type="text" name="min_num9"></td>
|
||||
<td><input type="button" class="btn-modern" value="Set" disabled onclick="return tsid_psip_sub_set(9);"></td>
|
||||
</tr>
|
||||
|
||||
<tr id="psip10">
|
||||
<td><input type="text" name="index10" readonly></td>
|
||||
<td><input type="text" name="sht_name10"></td>
|
||||
<td><input type="text" name="maj_num10"></td>
|
||||
<td><input type="text" name="min_num10"></td>
|
||||
<td><input type="button" class="btn-modern" value="Set" disabled onclick="return tsid_psip_sub_set(10);"></td>
|
||||
</tr>
|
||||
|
||||
<tr id="psip11">
|
||||
<td><input type="text" name="index11" readonly></td>
|
||||
<td><input type="text" name="sht_name11"></td>
|
||||
<td><input type="text" name="maj_num11"></td>
|
||||
<td><input type="text" name="min_num11"></td>
|
||||
<td><input type="button" class="btn-modern" value="Set" disabled onclick="return tsid_psip_sub_set(11);"></td>
|
||||
</tr>
|
||||
|
||||
<tr id="psip12">
|
||||
<td><input type="text" name="index12" readonly></td>
|
||||
<td><input type="text" name="sht_name12"></td>
|
||||
<td><input type="text" name="maj_num12"></td>
|
||||
<td><input type="text" name="min_num12"></td>
|
||||
<td><input type="button" class="btn-modern" value="Set" disabled onclick="return tsid_psip_sub_set(12);"></td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div id="accountModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3>Account Settings</h3>
|
||||
<span class="close" onclick="closeAccountModal()">×</span>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="accountForm" method="post" action="login.cgi?action=change_account" onsubmit="return validateAccountForm()">
|
||||
<table class="modal-table">
|
||||
<tr>
|
||||
<td>Current Username</td>
|
||||
<td><input type="text" id="current_user" name="current_user" readonly></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Current Password</td>
|
||||
<td><input type="password" id="current_pwd" name="current_pwd" required></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>New Username</td>
|
||||
<td><input type="text" id="new_user" name="new_user"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>New Password</td>
|
||||
<td><input type="password" id="new_pwd" name="new_pwd"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Confirm Password</td>
|
||||
<td><input type="password" id="confirm_pwd" name="confirm_pwd"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="modal-footer">
|
||||
<input type="button" class="btn-modern" style="background-color: #64748b;" value="Cancel" onclick="closeAccountModal()">
|
||||
<input type="submit" class="btn-modern" value="Save Changes">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toggleSidebar(){
|
||||
document.querySelector('.app-sidebar').classList.toggle('sidebar-open');
|
||||
document.querySelector('.sidebar-overlay').classList.toggle('active');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Executable
+957
@@ -0,0 +1,957 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title id="webtitle"></title>
|
||||
<link href="css/styles.css" rel="stylesheet" media="screen">
|
||||
<script src="js/auth.js"></script>
|
||||
<script src="js/jquery.js"></script>
|
||||
<script src="js/dashboard.js"></script>
|
||||
<script>
|
||||
var time_sec_cnt=0;
|
||||
var g_remot_local_ctrl = 3; //0 remote 1 local
|
||||
var g_old_power = 0;
|
||||
var g_old_power_p0 = 0;
|
||||
var g_old_power_p1 = 0;
|
||||
var g_old_power_p2 = 0;
|
||||
var g_old_freq_channel = -1;
|
||||
var g_rx_freq=0;
|
||||
var wait_freq_flg = 0;
|
||||
var g_rx_freq_countdown_active = false; // Flag to prevent rx_freq update during countdown
|
||||
var arry_sign = [1, -1];
|
||||
var arry_p = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95];
|
||||
var lastTime = new Date().getTime();
|
||||
var currentTime = new Date().getTime();
|
||||
var timeOut = 20 * 60 * 1000; // 20 min timeout
|
||||
|
||||
$(function(){
|
||||
// Listen to multiple types of user activity to prevent timeout
|
||||
$(document).on('mousemove keydown click scroll touchstart', function(){
|
||||
lastTime = new Date().getTime();
|
||||
});
|
||||
});
|
||||
|
||||
function testTime(){
|
||||
currentTime = new Date().getTime();
|
||||
if(currentTime - lastTime > timeOut){
|
||||
window.location.href="login.cgi?logout=1"
|
||||
}
|
||||
|
||||
time_sec_cnt=time_sec_cnt+1;
|
||||
if(time_sec_cnt%3==0){
|
||||
get_remote_local_ctrl();
|
||||
if(g_remot_local_ctrl==1) { // local
|
||||
SetFormDefaults();
|
||||
}
|
||||
refreshDashboard();
|
||||
}
|
||||
}
|
||||
|
||||
// Timer check
|
||||
window.setInterval(testTime, 1000);
|
||||
|
||||
function get_remote_local_ctrl() {
|
||||
var queryData = "sys_cfg=&";
|
||||
$.get("atsc_status_cfg.cgi?"+queryData, function(data, status) {
|
||||
// Handle case where data is a JSON object (e.g., session expired)
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
if (data.error === 'session_expired' && data.redirect) {
|
||||
window.location.href = data.redirect;
|
||||
return;
|
||||
}
|
||||
console.error('Received JSON error response:', data);
|
||||
return;
|
||||
}
|
||||
|
||||
var table = data.split("|");
|
||||
g_remot_local_ctrl = Number(table[0].split("#")[5]);
|
||||
document.title = table[0].split("#")[11];
|
||||
});
|
||||
}
|
||||
|
||||
function cmd_confirm() {
|
||||
return confirm("Please choose to confirm or cancel!");
|
||||
}
|
||||
|
||||
function SetFormDefaults() {
|
||||
// 1. DISABLE BUTTONS START (only in Remote mode)
|
||||
if(g_remot_local_ctrl == 1) {
|
||||
// Local mode: just fetch data, don't change button
|
||||
var queryData = "sys_rf=&web_title=&";
|
||||
} else {
|
||||
// Remote mode: show LOADING indicator
|
||||
$('#rf_form input[type="button"]').attr("disabled", true).val("LOADING...");
|
||||
var queryData = "sys_rf=&web_title=&";
|
||||
}
|
||||
|
||||
$.get("atsc_status_cfg.cgi?"+queryData, function(data, status) {
|
||||
// Handle case where data is a JSON object (e.g., session expired)
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
if (data.error === 'session_expired' && data.redirect) {
|
||||
window.location.href = data.redirect;
|
||||
return;
|
||||
}
|
||||
console.error('Received JSON error response:', data);
|
||||
return;
|
||||
}
|
||||
|
||||
var table = data.split("|");
|
||||
var rfpara= table[0].split("#");
|
||||
var title = table[1].split("#");
|
||||
var cf = document.getElementById("rf_form");
|
||||
|
||||
g_old_power_p0 = Number(rfpara[1]);
|
||||
g_old_power_p1 = Number(rfpara[2]);
|
||||
g_old_power_p2 = Number(rfpara[3]);
|
||||
|
||||
cf.pw0.value = Number(rfpara[1]);
|
||||
cf.pw1.value = Number(rfpara[2]);
|
||||
cf.pw2.value = Number(rfpara[3]);
|
||||
cf.rfy.value = Number(rfpara[4]);
|
||||
cf.agc.value = Number(rfpara[5]);
|
||||
|
||||
var tmp = Number(rfpara[6]);
|
||||
cf.tx.value = Number(rfpara[7]);
|
||||
cf.freq6m.value = Number(rfpara[8]);
|
||||
|
||||
// Only update rx_freq if not in countdown mode (to prevent jumping back to old value)
|
||||
if (!g_rx_freq_countdown_active) {
|
||||
cf.rx_freq.value = Number(rfpara[9]);
|
||||
g_rx_freq = Number(rfpara[9]);
|
||||
}
|
||||
|
||||
// 2. RE-ENABLE BUTTONS END (only in Remote mode)
|
||||
if(g_remot_local_ctrl == 1) {
|
||||
// Local mode: keep button disabled
|
||||
$('#rf_form input[type="button"]').attr("disabled", true).val("Local Mode");
|
||||
} else {
|
||||
// Remote mode: enable button
|
||||
$('#rf_form input[type="button"]').attr("disabled", false).val("Set");
|
||||
}
|
||||
|
||||
document.getElementById('webtitle').textContent = title[1];
|
||||
document.getElementById('webtitle_header').textContent = title[1];
|
||||
if (typeof rfFormSnapshotUpdate === 'function') rfFormSnapshotUpdate();
|
||||
}).fail(function() {
|
||||
// Optional: Error handling
|
||||
if(g_remot_local_ctrl == 0) {
|
||||
$('#rf_form input[type="button"]').val("Load Failed");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function refresh_show(){
|
||||
get_remote_local_ctrl();
|
||||
SetFormDefaults();
|
||||
refreshDashboard();
|
||||
m10_load();
|
||||
}
|
||||
|
||||
// PR07: 10 MHz reference output enable (FPGA reg_map_dpd seg5 0x1f bit0).
|
||||
// Independent of the RF form and of Local/Remote mode: it is a hardware
|
||||
// reference-clock output, applied live and reset to OFF on every power-up.
|
||||
function m10_load(){
|
||||
$.get("atsc_status_cfg.cgi?sys_m10=&", function(data, status){
|
||||
if(typeof data === 'object' && data !== null){
|
||||
if(data.error === 'session_expired' && data.redirect){ window.location.href = data.redirect; }
|
||||
return;
|
||||
}
|
||||
var v = Number(data.split("|")[0].split("#")[1]); // "#<0|1>|"
|
||||
var sel = document.getElementById("m10_en");
|
||||
if(sel && !isNaN(v)) sel.value = v;
|
||||
});
|
||||
}
|
||||
function m10_set(){
|
||||
var sel = document.getElementById("m10_en");
|
||||
if(!sel) return false;
|
||||
$.post("atsc_status_cfg.cgi", "sys_m10="+sel.value, function(data, status){
|
||||
m10_load();
|
||||
});
|
||||
return false;
|
||||
}
|
||||
|
||||
function set_rxfreq_button_enable(is_enable){
|
||||
if(is_enable == 0){
|
||||
$('#rx_freq').attr("disabled", true);
|
||||
$('#id_rxfreq_button').attr("disabled", true);
|
||||
}else{
|
||||
$('#rx_freq').attr("disabled", false);
|
||||
$('#id_rxfreq_button').attr("disabled", false);
|
||||
}
|
||||
}
|
||||
|
||||
function exc_sysRfSet() {
|
||||
var postData = "sys_rf=";
|
||||
var cf = document.forms[0];
|
||||
|
||||
var new_power = (arry_sign[Number(cf.pw0.value)]) * (Number(cf.pw1.value)*100+(arry_p[Number(cf.pw2.value)]));
|
||||
g_old_power = arry_sign[g_old_power_p0]*(g_old_power_p1*100+arry_p[g_old_power_p2]);
|
||||
|
||||
if((new_power - g_old_power) > 100){
|
||||
alert("Please do not increase power for more than 1dB each time, change will be discarded!");
|
||||
SetFormDefaults();
|
||||
return;
|
||||
}
|
||||
|
||||
postData += "#"+cf.pw0.value;
|
||||
postData += "#"+cf.pw1.value;
|
||||
postData += "#"+cf.pw2.value;
|
||||
postData += "#"+cf.rfy.value;
|
||||
postData += "#"+cf.agc.value;
|
||||
postData += "#"+0;
|
||||
postData += "#"+cf.tx.value;
|
||||
postData += "#"+cf.freq6m.value;
|
||||
postData += "#"+cf.rx_freq.value;
|
||||
|
||||
cur_rx_freq = Number($("#rx_freq").val());
|
||||
|
||||
if(cmd_confirm()){
|
||||
if(g_rx_freq != cur_rx_freq){
|
||||
g_rx_freq_countdown_active = true; // Start countdown, prevent rx_freq update
|
||||
$("#set_rxfreq_note").text(" wait 10 s");
|
||||
set_rxfreq_button_enable(0);
|
||||
var note_sec = 10;
|
||||
var set_tnote_intv = setInterval(function() {
|
||||
if(note_sec == 0) {
|
||||
clearInterval(set_tnote_intv);
|
||||
$("#set_rxfreq_note").text(" ");
|
||||
set_rxfreq_button_enable(1);
|
||||
g_rx_freq_countdown_active = false; // End countdown, allow rx_freq update
|
||||
SetFormDefaults();
|
||||
return;
|
||||
}else{
|
||||
note_sec = note_sec-1;
|
||||
$("#set_rxfreq_note").text(" wait "+note_sec+" s ");
|
||||
set_rxfreq_button_enable(0);
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
setAllRfRowButtonsSaved();
|
||||
$.post("atsc_status_cfg.cgi", postData, function(data, status){
|
||||
if(status=="success"){
|
||||
SetFormDefaults();
|
||||
}else{
|
||||
alert("post val err");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Modal Logic - Open and close account modal
|
||||
function openAccountModal() {
|
||||
// Fetch current username from server
|
||||
$.get("login.cgi?action=get_user", function(data) {
|
||||
var trimmedData = (data || "").trim();
|
||||
if (trimmedData && trimmedData !== "UNAUTHORIZED") {
|
||||
document.getElementById('current_user').value = trimmedData;
|
||||
}
|
||||
document.getElementById('accountModal').style.display = 'block';
|
||||
setTimeout(function() { document.getElementById('current_pwd').focus(); }, 100);
|
||||
}).fail(function() {
|
||||
document.getElementById('accountModal').style.display = 'block';
|
||||
setTimeout(function() { document.getElementById('current_pwd').focus(); }, 100);
|
||||
});
|
||||
}
|
||||
|
||||
function closeAccountModal() {
|
||||
document.getElementById('accountModal').style.display = 'none';
|
||||
// Clear sensitive fields
|
||||
document.getElementById('current_pwd').value = '';
|
||||
document.getElementById('new_pwd').value = '';
|
||||
document.getElementById('confirm_pwd').value = '';
|
||||
}
|
||||
|
||||
// Validates that a string contains only printable characters (excluding space)
|
||||
function isValidPrintableString(str) {
|
||||
// Regular expression to check for printable characters (ASCII 33-126), excluding space
|
||||
// Space is ASCII 32, and we want to exclude it
|
||||
var printableCharRegex = /^[!-~]+$/; // ! is ASCII 33, ~ is ASCII 126
|
||||
return printableCharRegex.test(str);
|
||||
}
|
||||
|
||||
// Validate Account Form - All required fields must be filled
|
||||
function validateAccountForm() {
|
||||
var currentUser = document.getElementById('current_user').value;
|
||||
var currentPwd = document.getElementById('current_pwd').value;
|
||||
var newUsername = document.getElementById('new_user').value;
|
||||
var newPwd = document.getElementById('new_pwd').value;
|
||||
var confirmPwd = document.getElementById('confirm_pwd').value;
|
||||
|
||||
// Current password is required (cannot be empty)
|
||||
if (!currentPwd || currentPwd.trim() === "") {
|
||||
alert("Current password is required");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate current password contains only printable characters
|
||||
if (!isValidPrintableString(currentPwd)) {
|
||||
alert("Current password contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// New password is required (cannot be empty)
|
||||
if (!newPwd || newPwd.trim() === "") {
|
||||
alert("New password is required");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new password contains only printable characters
|
||||
if (!isValidPrintableString(newPwd)) {
|
||||
alert("New password contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new password length (max 16 chars)
|
||||
if (newPwd.length > 16) {
|
||||
alert("New password must be no more than 16 characters");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new password length
|
||||
if (newPwd.length < 6) {
|
||||
alert("New password must be at least 6 characters");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Confirm password must match new password
|
||||
if (newPwd !== confirmPwd) {
|
||||
alert("New passwords do not match");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate confirm password contains only printable characters
|
||||
if (!isValidPrintableString(confirmPwd)) {
|
||||
alert("Confirm password contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate confirm password length (max 16 chars)
|
||||
if (confirmPwd.length > 16) {
|
||||
alert("Confirm password must be no more than 16 characters");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new username if provided
|
||||
if (newUsername && newUsername.trim() !== "") {
|
||||
// Validate new username contains only printable characters
|
||||
if (!isValidPrintableString(newUsername)) {
|
||||
alert("New username contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new username length (max 16 chars)
|
||||
if (newUsername.length > 16) {
|
||||
alert("New username must be no more than 16 characters");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true; // Allows the form to submit
|
||||
}
|
||||
|
||||
// Form submission handler using fetch API
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var accountForm = document.getElementById('accountForm');
|
||||
if (accountForm) {
|
||||
accountForm.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!validateAccountForm()) return;
|
||||
|
||||
var formData = new URLSearchParams({
|
||||
Username: document.getElementById('current_user').value,
|
||||
OldPassword: document.getElementById('current_pwd').value,
|
||||
NewUsername: document.getElementById('new_user').value,
|
||||
NewPassword: document.getElementById('new_pwd').value,
|
||||
ConfirmPassword: document.getElementById('confirm_pwd').value
|
||||
});
|
||||
|
||||
fetch('login.cgi?action=change_account', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert("Update successful! Please login again.");
|
||||
closeAccountModal();
|
||||
// Redirect to login page after 1.5 seconds
|
||||
setTimeout(function() {
|
||||
window.location.href = 'login.cgi?logout=1';
|
||||
}, 1500);
|
||||
} else {
|
||||
alert(data.error || "Update failed");
|
||||
}
|
||||
})
|
||||
.catch(function(err) {
|
||||
alert("Network error: " + err);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// ----- SET (unsaved) reminder: per-row, vanilla JS -----
|
||||
var rfFormSnapshotPerRow = [];
|
||||
function getRowValues(tr) {
|
||||
var out = [], els = tr.querySelectorAll('select, input:not([type="button"])'), i, el, v;
|
||||
for (i = 0; i < els.length; i++) {
|
||||
el = els[i];
|
||||
v = el.tagName === 'SELECT' ? (el.options[el.selectedIndex] ? el.options[el.selectedIndex].value : '') : el.value;
|
||||
out.push({ name: el.name, value: String(v) });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
function getFormSnapshotPerRow(formId) {
|
||||
var f = document.getElementById(formId);
|
||||
if (!f) return [];
|
||||
var rows = f.querySelectorAll('table tr'), out = [], i;
|
||||
for (i = 0; i < rows.length; i++) {
|
||||
if (rows[i].querySelector('input[type="button"]')) out.push(getRowValues(rows[i]));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
function isRowDirty(rowValues, rowSnapshot) {
|
||||
if (rowValues.length !== rowSnapshot.length) return true;
|
||||
for (var i = 0; i < rowValues.length; i++) {
|
||||
if (rowValues[i].name !== rowSnapshot[i].name || rowValues[i].value !== rowSnapshot[i].value) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function setRowButtonState(tr, unsaved) {
|
||||
var btn = tr.querySelector('input[type="button"]');
|
||||
if (!btn || btn.disabled) return;
|
||||
btn.value = unsaved ? 'Set (unsaved)' : 'Set';
|
||||
if (unsaved) btn.classList.add('is-unsaved'); else btn.classList.remove('is-unsaved');
|
||||
}
|
||||
function updateAllRowButtonStates(formId) {
|
||||
var f = document.getElementById(formId);
|
||||
if (!f || !rfFormSnapshotPerRow.length) return;
|
||||
var rows = f.querySelectorAll('table tr');
|
||||
var rowIdx = 0;
|
||||
for (var i = 0; i < rows.length; i++) {
|
||||
if (!rows[i].querySelector('input[type="button"]')) continue;
|
||||
setRowButtonState(rows[i], rowIdx < rfFormSnapshotPerRow.length && isRowDirty(getRowValues(rows[i]), rfFormSnapshotPerRow[rowIdx]));
|
||||
rowIdx++;
|
||||
}
|
||||
}
|
||||
function setAllRfRowButtonsSaved() {
|
||||
var f = document.getElementById('rf_form');
|
||||
if (!f) return;
|
||||
var rows = f.querySelectorAll('table tr');
|
||||
for (var i = 0; i < rows.length; i++) setRowButtonState(rows[i], false);
|
||||
}
|
||||
function rfFormSnapshotUpdate() {
|
||||
rfFormSnapshotPerRow = getFormSnapshotPerRow('rf_form');
|
||||
setAllRfRowButtonsSaved();
|
||||
}
|
||||
function attachRfFormUnsavedListener() {
|
||||
var f = document.getElementById('rf_form');
|
||||
if (!f) return;
|
||||
f.addEventListener('change', function() {
|
||||
updateAllRowButtonStates('rf_form');
|
||||
});
|
||||
}
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', attachRfFormUnsavedListener);
|
||||
} else {
|
||||
attachRfFormUnsavedListener();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="refresh_show()">
|
||||
<div class="app-layout">
|
||||
<aside class="app-sidebar">
|
||||
<ul class="items">
|
||||
<li><a href="status_info.html" title="Status">Status</a></li>
|
||||
<li><a href="sys_set.html" title="Settings">Settings</a></li>
|
||||
<li class="active"><a href="sys_rf.html" title="RF Control">RF Control</a></li>
|
||||
<li><a href="sys_psip.html" title="TSID&PSIP">TSID&PSIP</a></li>
|
||||
<li><a href="sys_ts.html" title="TSoIP">TSoIP</a></li>
|
||||
<li><a href="sys_spectrum.html" title="Spectrum">Spectrum</a></li>
|
||||
<li><a href="log_output.html" title="Log">Log</a></li>
|
||||
</ul>
|
||||
<div class="sidebar-footer">
|
||||
<h4>Anywave Broadcast Inc.</h4>
|
||||
<p>Copyright 2026<br><br><span class="redbox-label">Technical Support</span><br>+1 847 415 2258<br><a href="mailto:support@anywaveus.com">support@anywaveus.com</a></p>
|
||||
</div>
|
||||
</aside>
|
||||
<div class="sidebar-overlay" onclick="toggleSidebar()"></div>
|
||||
|
||||
<header class="app-header">
|
||||
<button class="menu-toggle" onclick="toggleSidebar()" aria-label="Toggle menu">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="3" y1="12" x2="21" y2="12"></line>
|
||||
<line x1="3" y1="6" x2="21" y2="6"></line>
|
||||
<line x1="3" y1="18" x2="21" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
<h1><a href="https://anywavecom.net/" class="logo-bg" title="Anywave Broadcast Inc."></a></h1>
|
||||
<h2 id="webtitle_header"><span></span></h2>
|
||||
<h3>
|
||||
<div class="dropdown">
|
||||
<button class="dropbtn-modern">Admin ▾</button>
|
||||
<div class="dropdown-content">
|
||||
<a href="#" onclick="openAccountModal(); return false;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="3"></circle>
|
||||
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06-.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06-.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06-.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
|
||||
</svg>
|
||||
Account Settings
|
||||
</a>
|
||||
<a href="login.cgi?logout=1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
|
||||
<polyline points="16 17 21 12 16 7"></polyline>
|
||||
<line x1="21" y1="12" x2="9" y2="12"></line>
|
||||
</svg>
|
||||
Logout
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</h3>
|
||||
</header>
|
||||
|
||||
<!-- Fixed Dashboard Summary - Top of page, under header -->
|
||||
<div class="dashboard-fixed">
|
||||
<div class="summary-dashboard">
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_freq" aria-hidden="true"></span>
|
||||
<span class="summary-label">Frequency</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_freq">--</span>
|
||||
<span class="summary-unit">MHz</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_snr" aria-hidden="true"></span>
|
||||
<span class="summary-label">SNR</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_snr">--</span>
|
||||
<span class="summary-unit">dB</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_uimd" aria-hidden="true"></span>
|
||||
<span class="summary-label">UIMD</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_uimd">--</span>
|
||||
<span class="summary-unit">dBc</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_limd" aria-hidden="true"></span>
|
||||
<span class="summary-label">LIMD</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_limd">--</span>
|
||||
<span class="summary-unit">dBc</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-off" id="dot_rf" aria-hidden="true"></span>
|
||||
<span class="summary-label">RF Switch</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-muted" id="sum_rf">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_outpow" aria-hidden="true"></span>
|
||||
<span class="summary-label">Output Power</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_outpow">--</span>
|
||||
<span class="summary-unit">dBm</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_input" aria-hidden="true"></span>
|
||||
<span class="summary-label">Input Source</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_input">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_input_status" aria-hidden="true"></span>
|
||||
<span class="summary-label">Input Status</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_input_status">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_bitrate" aria-hidden="true"></span>
|
||||
<span class="summary-label">Bitrate</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_bitrate">--</span>
|
||||
<span class="summary-unit">Mbps</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_temp" aria-hidden="true"></span>
|
||||
<span class="summary-label">Temperature</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_temp">--</span>
|
||||
<span class="summary-unit">°F</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-off" id="dot_agc" aria-hidden="true"></span>
|
||||
<span class="summary-label">AGC</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-muted" id="sum_agc">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_control" aria-hidden="true"></span>
|
||||
<span class="summary-label">Control</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_control">--</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main class="app-main">
|
||||
<h2>RF Control</h2>
|
||||
<div class="box">
|
||||
<form name="rf_control_form" id="rf_form">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Output Power</td>
|
||||
<td><fieldset>
|
||||
<select style="width:40px" name="pw0" id="pw0">
|
||||
<option value="0">+
|
||||
<option value="1">-
|
||||
</select>
|
||||
<select style="width:40px" name="pw1" id="pw1">
|
||||
<option value="0">0 <option value="1">1 <option value="2">2 <option value="3">3 <option value="4">4 <option value="5">5
|
||||
<option value="6">6 <option value="7">7 <option value="8">8 <option value="9">9 <option value="10">10 <option value="11">11
|
||||
<option value="12">12 <option value="13">13 <option value="14">14 <option value="15">15 <option value="16">16 <option value="17">17
|
||||
<option value="18">18 <option value="19">19 <option value="20">20 <option value="21">21 <option value="22">22 <option value="23">23
|
||||
<option value="24">24 <option value="25">25
|
||||
</select>.
|
||||
<select style="width:40px" name="pw2" id="pw2">
|
||||
<option value="0">00
|
||||
<option value="1">05
|
||||
<option value="2">10
|
||||
<option value="3">15
|
||||
<option value="4">20
|
||||
<option value="5">25
|
||||
<option value="6">30
|
||||
<option value="7">35
|
||||
<option value="8">40
|
||||
<option value="9">45
|
||||
<option value="10">50
|
||||
<option value="11">55
|
||||
<option value="12">60
|
||||
<option value="13">65
|
||||
<option value="14">70
|
||||
<option value="15">75
|
||||
<option value="16">80
|
||||
<option value="17">85
|
||||
<option value="18">90
|
||||
<option value="19">95
|
||||
</select>dBm (-25.00 ~ +5.00dBm)
|
||||
</fieldset></td>
|
||||
<td>
|
||||
<input type="button" class="btn-modern" alt="Set" value="Set" disabled onclick="return exc_sysRfSet();">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>RF</td>
|
||||
<td>
|
||||
<select name="rfy" id="rfy">
|
||||
<option value="0">Off
|
||||
<option value="1">On
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="button" class="btn-modern" alt="Set" value="Set" disabled onclick="return exc_sysRfSet();">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>AGC</td>
|
||||
<td>
|
||||
<select name="agc" id="agc">
|
||||
<option value="0">Off
|
||||
<option value="1">On
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="button" class="btn-modern" alt="Set" value="Set" disabled onclick="return exc_sysRfSet();">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr id="tx_form" style="display: none" >
|
||||
<td >TX</td>
|
||||
<td>
|
||||
<select name="tx" id="tx">
|
||||
<option value="0">Off
|
||||
<option value="1">On
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="button" class="btn-modern" alt="Set" value="Set" disabled onclick="return exc_sysRfSet();">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>RX Frequency</td>
|
||||
<td>
|
||||
<select name="rx_freq" id="rx_freq">
|
||||
<option value="0">57
|
||||
<option value="1">63
|
||||
<option value="2">69
|
||||
<option value="3">79
|
||||
<option value="4">85
|
||||
<option value="5">177
|
||||
<option value="6">183
|
||||
<option value="7">189
|
||||
<option value="8">195
|
||||
<option value="9">201
|
||||
<option value="10">207
|
||||
<option value="11">213
|
||||
<option value="12">473
|
||||
<option value="13">479
|
||||
<option value="14">485
|
||||
<option value="15">491
|
||||
<option value="16">497
|
||||
<option value="17">503
|
||||
<option value="18">509
|
||||
<option value="19">515
|
||||
<option value="20">521
|
||||
<option value="21">527
|
||||
<option value="22">533
|
||||
<option value="23">539
|
||||
<option value="24">545
|
||||
<option value="25">551
|
||||
<option value="26">557
|
||||
<option value="27">563
|
||||
<option value="28">569
|
||||
<option value="29">575
|
||||
<option value="30">581
|
||||
<option value="31">587
|
||||
<option value="32">593
|
||||
<option value="33">599
|
||||
<option value="34">605
|
||||
<option value="35">611
|
||||
<option value="36">617
|
||||
<option value="37">623
|
||||
<option value="38">629
|
||||
<option value="39">635
|
||||
<option value="40">641
|
||||
<option value="41">647
|
||||
<option value="42">653
|
||||
<option value="43">659
|
||||
<option value="44">665
|
||||
<option value="45">671
|
||||
<option value="46">677
|
||||
<option value="47">683
|
||||
<option value="48">689
|
||||
<option value="49">695
|
||||
<option value="50">701
|
||||
<option value="51">707
|
||||
<option value="52">713
|
||||
<option value="53">719
|
||||
<option value="54">725
|
||||
<option value="55">731
|
||||
<option value="56">737
|
||||
<option value="57">743
|
||||
<option value="58">749
|
||||
<option value="59">755
|
||||
<option value="60">761
|
||||
<option value="61">767
|
||||
<option value="62">773
|
||||
<option value="63">779
|
||||
<option value="64">785
|
||||
<option value="65">791
|
||||
<option value="66">797
|
||||
<option value="67">803
|
||||
</select> MHz
|
||||
</td>
|
||||
<td>
|
||||
<input type="button" class="btn-modern" id="id_rxfreq_button" alt="Set" value="Set" disabled onclick="return exc_sysRfSet();">
|
||||
<span id="set_rxfreq_note"></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td id="freq6m_h">TX Frequency</td>
|
||||
<td id="freq6m_i">
|
||||
<select name="freq6m" id="freq6m">
|
||||
<option value="0">57
|
||||
<option value="1">63
|
||||
<option value="2">69
|
||||
<option value="3">79
|
||||
<option value="4">85
|
||||
<option value="5">177
|
||||
<option value="6">183
|
||||
<option value="7">189
|
||||
<option value="8">195
|
||||
<option value="9">201
|
||||
<option value="10">207
|
||||
<option value="11">213
|
||||
<option value="12">473
|
||||
<option value="13">479
|
||||
<option value="14">485
|
||||
<option value="15">491
|
||||
<option value="16">497
|
||||
<option value="17">503
|
||||
<option value="18">509
|
||||
<option value="19">515
|
||||
<option value="20">521
|
||||
<option value="21">527
|
||||
<option value="22">533
|
||||
<option value="23">539
|
||||
<option value="24">545
|
||||
<option value="25">551
|
||||
<option value="26">557
|
||||
<option value="27">563
|
||||
<option value="28">569
|
||||
<option value="29">575
|
||||
<option value="30">581
|
||||
<option value="31">587
|
||||
<option value="32">593
|
||||
<option value="33">599
|
||||
<option value="34">605
|
||||
<option value="35">611
|
||||
<option value="36">617
|
||||
<option value="37">623
|
||||
<option value="38">629
|
||||
<option value="39">635
|
||||
<option value="40">641
|
||||
<option value="41">647
|
||||
<option value="42">653
|
||||
<option value="43">659
|
||||
<option value="44">665
|
||||
<option value="45">671
|
||||
<option value="46">677
|
||||
<option value="47">683
|
||||
<option value="48">689
|
||||
<option value="49">695
|
||||
<option value="50">701
|
||||
<option value="51">707
|
||||
<option value="52">713
|
||||
<option value="53">719
|
||||
<option value="54">725
|
||||
<option value="55">731
|
||||
<option value="56">737
|
||||
<option value="57">743
|
||||
<option value="58">749
|
||||
<option value="59">755
|
||||
<option value="60">761
|
||||
<option value="61">767
|
||||
<option value="62">773
|
||||
<option value="63">779
|
||||
<option value="64">785
|
||||
<option value="65">791
|
||||
<option value="66">797
|
||||
<option value="67">803
|
||||
</select> MHz
|
||||
</td>
|
||||
<td>
|
||||
<input type="button" class="btn-modern" alt="Set" value="Set" disabled onclick="return exc_sysRfSet();">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
|
||||
<h2>Reference Output</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<td>10 MHz Output</td>
|
||||
<td>
|
||||
<select name="m10_en" id="m10_en">
|
||||
<option value="0">Off
|
||||
<option value="1">On
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input type="button" class="btn-modern" value="Set" onclick="return m10_set();">
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div style="padding: 4px 10px; color: #64748b; font-size: 12px;">
|
||||
Enables the AB5 10 MHz reference clock output. Default Off; resets to Off on every power-up.
|
||||
</div>
|
||||
|
||||
<div style="padding: 10px; color: #b91c1c; font-weight: 500;">
|
||||
Warning: Exciter RF Output Power will be reset to -25dBm when the channel(TX Frequency) is changed.
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div id="accountModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3>ACCOUNT SETTINGS</h3>
|
||||
<span class="close" onclick="closeAccountModal()">×</span>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="accountForm" method="post" action="login.cgi?action=change_account" onsubmit="return validateAccountForm()">
|
||||
<table class="modal-table">
|
||||
<tr>
|
||||
<td>Current Username</td>
|
||||
<td><input type="text" id="current_user" name="current_user" readonly></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Current Password</td>
|
||||
<td><input type="password" id="current_pwd" name="current_pwd" required></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>New Username</td>
|
||||
<td><input type="text" id="new_user" name="new_user"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>New Password</td>
|
||||
<td><input type="password" id="new_pwd" name="new_pwd"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Confirm Password</td>
|
||||
<td><input type="password" id="confirm_pwd" name="confirm_pwd"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="modal-footer">
|
||||
<input type="button" class="btn-modern" style="background-color: #64748b;" value="Cancel" onclick="closeAccountModal()">
|
||||
<input type="submit" class="btn-modern" value="Save Changes">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toggleSidebar(){
|
||||
document.querySelector('.app-sidebar').classList.toggle('sidebar-open');
|
||||
document.querySelector('.sidebar-overlay').classList.toggle('active');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Executable
+1834
File diff suppressed because it is too large
Load Diff
+770
@@ -0,0 +1,770 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title id="webtitle"></title>
|
||||
<link href="css/styles.css" rel="stylesheet" media="screen">
|
||||
<script src="js/auth.js"></script>
|
||||
<script src="js/jquery.js"></script>
|
||||
<script src="js/dashboard.js"></script>
|
||||
<style>
|
||||
/* inherit the page's colours: styles.css themes this shell light or dark */
|
||||
.spec-toolbar { display:flex; flex-wrap:wrap; gap:18px; align-items:center; margin-bottom:10px; }
|
||||
.spec-toolbar label { font-size:13px; color:inherit; }
|
||||
.spec-readouts { display:flex; flex-wrap:wrap; gap:10px; margin-top:12px; }
|
||||
.spec-readout { min-width:130px; padding:8px 12px; border:1px solid rgba(148,163,184,0.35); border-radius:6px; }
|
||||
.spec-readout .k { display:block; font-size:11px; letter-spacing:.04em; text-transform:uppercase; opacity:.7; }
|
||||
.spec-readout .v { display:block; font-size:18px; font-weight:600; }
|
||||
#spec_canvas { width:100%; height:420px; display:block; background:#0b1220; border-radius:6px; }
|
||||
#eye_canvas { width:100%; height:380px; display:block; background:#0b1220; border-radius:6px; }
|
||||
#eye_state { font-size:13px; opacity:.7; margin-left:auto; }
|
||||
#spec_state { font-size:13px; opacity:.7; margin-left:auto; }
|
||||
</style>
|
||||
<script>
|
||||
var lastTime = new Date().getTime();
|
||||
var currentTime = new Date().getTime();
|
||||
var timeOut = 20 * 60 * 1000; // 20 minutes
|
||||
|
||||
$(function(){
|
||||
$(document).on('mousemove keydown click scroll touchstart', function(){
|
||||
lastTime = new Date().getTime();
|
||||
});
|
||||
});
|
||||
|
||||
function testTime(){
|
||||
currentTime = new Date().getTime();
|
||||
if(currentTime - lastTime > timeOut){
|
||||
window.location.href="login.cgi?logout=1";
|
||||
}
|
||||
}
|
||||
window.setInterval(testTime, 1000);
|
||||
setInterval(refreshDashboard, 3000);
|
||||
|
||||
function get_remote_local_ctrl()
|
||||
{
|
||||
$.get("atsc_status_cfg.cgi?sys_cfg=&", function(data, status){
|
||||
if (typeof data === 'object' && data !== null) return;
|
||||
var table = String(data).split("|");
|
||||
document.title = table[0].split("#")[11];
|
||||
});
|
||||
}
|
||||
|
||||
function refresh_show(){
|
||||
get_remote_local_ctrl();
|
||||
refreshDashboard();
|
||||
specInit();
|
||||
}
|
||||
|
||||
/* ================= ORx IQ spectrum =================
|
||||
* iq_spectrum.cgi hands back the newest window analysed by the app's iq_rx
|
||||
* thread: a 1024-point Welch over one 26.2 ms window of the 10 MSPS complex
|
||||
* ORx stream. psd[] is in dB relative to the mean in-band flat density
|
||||
* (|f| < 2.5 MHz) -- the only shoulder yardstick that does not move when the
|
||||
* FFT length changes. See Notes/Result06-5.md section 7.
|
||||
*/
|
||||
var SPEC_TIMER = null;
|
||||
var specPeak = null; // peak-hold trace
|
||||
var specLast = null;
|
||||
var specFails = 0;
|
||||
|
||||
var Y_TOP = 30, Y_BOT = -80; // dB rel in-band flat density
|
||||
var SH_LO = 3.5, SH_HI = 4.8; // shoulder band the app takes the median over
|
||||
|
||||
function specInit(){
|
||||
window.addEventListener('resize', function(){ if (specLast) drawSpectrum(specLast); else drawGrid(); });
|
||||
drawGrid();
|
||||
specRestart();
|
||||
eyeRestart();
|
||||
}
|
||||
|
||||
function specRestart(){
|
||||
if (SPEC_TIMER) clearInterval(SPEC_TIMER);
|
||||
if (document.getElementById('spec_pause').checked) { setState('paused'); return; }
|
||||
var ms = Number(document.getElementById('spec_rate').value);
|
||||
specFetch();
|
||||
SPEC_TIMER = setInterval(specFetch, ms);
|
||||
}
|
||||
|
||||
function setState(s){ document.getElementById('spec_state').innerText = s; }
|
||||
|
||||
function specFetch(){
|
||||
$.ajax({url: 'iq_spectrum.cgi?t=' + Date.now(), dataType: 'json', cache: false})
|
||||
.done(function(d){
|
||||
if (!d || d.error){
|
||||
if (d && d.redirect) { window.location.href = d.redirect; return; }
|
||||
setState(d && d.error === 'nodata' ? 'no window captured yet' : 'error');
|
||||
return;
|
||||
}
|
||||
specFails = 0;
|
||||
specLast = d;
|
||||
updateReadouts(d);
|
||||
drawSpectrum(d);
|
||||
setState('window ' + d.wid + ' | updated ' + new Date().toLocaleTimeString());
|
||||
})
|
||||
.fail(function(){ specFails++; setState('fetch failed (' + specFails + ')'); });
|
||||
}
|
||||
|
||||
function updateReadouts(d){
|
||||
document.getElementById('rd_shoulder').innerText = d.shoulder.toFixed(1);
|
||||
document.getElementById('rd_limd').innerText = (d.limd === undefined) ? '--' : d.limd.toFixed(1);
|
||||
document.getElementById('rd_uimd').innerText = (d.uimd === undefined) ? '--' : d.uimd.toFixed(1);
|
||||
document.getElementById('rd_pilot').innerText = d.pilot.toFixed(4);
|
||||
document.getElementById('rd_peak').innerText = d.peak.toFixed(1);
|
||||
document.getElementById('rd_rbw').innerText = d.rbw_khz.toFixed(2);
|
||||
document.getElementById('rd_pkts').innerText = d.pkts + '/' + d.npkt;
|
||||
document.getElementById('rd_ms').innerText = d.ms.toFixed(2);
|
||||
document.getElementById('rd_pkts').style.color = (d.pkts === d.npkt) ? '' : '#ef4444';
|
||||
var fld = document.getElementById('rd_field');
|
||||
fld.innerText = (d.ms > 24.2) ? 'yes' : 'no'; // one ATSC data field = 24.2 ms
|
||||
fld.style.color = (d.ms > 24.2) ? '#22c55e' : '#ef4444';
|
||||
}
|
||||
|
||||
|
||||
/* ================= 8VSB eye =================
|
||||
* iq_eye.cgi returns the newest window demodulated by the app's iq_vsb thread:
|
||||
* matched filter -> j^k derotation -> 130 x 192 persistence map (base64, log-scaled).
|
||||
* The demod is expensive and nice'd, so a new eye lands roughly every 10 s; the page
|
||||
* polls at the same rate as the spectrum and redraws only when the window id changes.
|
||||
*/
|
||||
var EYE_TIMER = null, eyeWid = -1, eyeFails = 0;
|
||||
|
||||
function eyeRestart(){
|
||||
if (EYE_TIMER) clearInterval(EYE_TIMER);
|
||||
if (document.getElementById('spec_pause').checked) return;
|
||||
eyeFetch();
|
||||
EYE_TIMER = setInterval(eyeFetch, Number(document.getElementById('spec_rate').value));
|
||||
}
|
||||
|
||||
function eyeFetch(){
|
||||
$.ajax({url: 'iq_eye.cgi?t=' + Date.now(), dataType: 'json', cache: false})
|
||||
.done(function(d){
|
||||
var st = document.getElementById('eye_state');
|
||||
if (!d || d.error){
|
||||
if (d && d.redirect) { window.location.href = d.redirect; return; }
|
||||
st.innerText = (d && d.error === 'nodata') ? 'no window demodulated yet' : 'error';
|
||||
return;
|
||||
}
|
||||
if (!d.sync){ st.innerText = 'no symbol lock'; return; }
|
||||
eyeFails = 0;
|
||||
eyeReadouts(d);
|
||||
if (d.wid !== eyeWid){ eyeWid = d.wid; drawEye(d); }
|
||||
st.innerText = 'window ' + d.wid + ' | ' + d.nsym + ' symbols | updated ' +
|
||||
new Date(d.ts * 1000).toLocaleTimeString();
|
||||
})
|
||||
.fail(function(){ eyeFails++;
|
||||
document.getElementById('eye_state').innerText = 'fetch failed (' + eyeFails + ')'; });
|
||||
}
|
||||
|
||||
function eyeReadouts(d){
|
||||
var minh = Math.min.apply(null, d.eye_h);
|
||||
var sAvg = d.sigma.reduce(function(a,b){ return a + b; }, 0) / d.sigma.length;
|
||||
document.getElementById('rd_snr').innerText = d.snr_db.toFixed(2);
|
||||
document.getElementById('rd_eyeh').innerText = minh.toFixed(2);
|
||||
document.getElementById('rd_eyew').innerText = d.eye_w_ui.toFixed(3);
|
||||
document.getElementById('rd_tau').innerText = d.tau.toFixed(4);
|
||||
document.getElementById('rd_segsync').innerText = d.segsync_ratio.toFixed(1);
|
||||
document.getElementById('rd_coff').innerText = d.carrier_off_hz.toFixed(3);
|
||||
document.getElementById('rd_snrraw').innerText = (d.snr_raw_db === undefined) ? '--' : d.snr_raw_db.toFixed(2);
|
||||
document.getElementById('rd_gjit').innerText = (d.gain_jitter_pct === undefined) ? '--' : d.gain_jitter_pct.toFixed(2);
|
||||
var gj = document.getElementById('rd_gjit');
|
||||
gj.style.color = (d.gain_jitter_pct < 1.0) ? '#22c55e' : (d.gain_jitter_pct < 4 ? '#f59e0b' : '#ef4444');
|
||||
/* min(eye_h) should track 2 - 6*sigma. A big shortfall means ISI or non-Gaussian
|
||||
* distortion -- something a single SNR number cannot show. Guard the absolute
|
||||
* value too: once sigma is large, 2-6*sigma goes negative and a shut eye would
|
||||
* otherwise pass the relative test. */
|
||||
var el = document.getElementById('rd_eyeh');
|
||||
el.style.color = (minh > 0.6 && minh > 2 - 6 * sAvg - 0.35) ? '#22c55e'
|
||||
: (minh > 0.3 ? '#f59e0b' : '#ef4444');
|
||||
var sn = document.getElementById('rd_snr');
|
||||
sn.style.color = (d.snr_db >= 27) ? '#22c55e' : (d.snr_db >= 20 ? '#f59e0b' : '#ef4444');
|
||||
}
|
||||
|
||||
function drawEye(d){
|
||||
var c = document.getElementById('eye_canvas');
|
||||
var dpr = window.devicePixelRatio || 1;
|
||||
var W = c.clientWidth, H = c.clientHeight;
|
||||
if (c.width !== Math.round(W*dpr) || c.height !== Math.round(H*dpr)){
|
||||
c.width = Math.round(W*dpr); c.height = Math.round(H*dpr);
|
||||
}
|
||||
var g = c.getContext('2d');
|
||||
g.setTransform(dpr,0,0,dpr,0,0);
|
||||
g.clearRect(0,0,W,H);
|
||||
g.fillStyle = '#0b1220'; g.fillRect(0,0,W,H);
|
||||
|
||||
var cols = d.eye.cols, rows = d.eye.rows, amp = d.eye.amp;
|
||||
var bin = atob(d.eye.data), x, y;
|
||||
/* Build the histogram off-screen at its native size and let the browser scale it:
|
||||
* one putImageData beats stroking a thousand paths. */
|
||||
var off = document.createElement('canvas');
|
||||
off.width = cols; off.height = rows;
|
||||
var og = off.getContext('2d');
|
||||
var img = og.createImageData(cols, rows);
|
||||
for (x = 0; x < cols; x++){
|
||||
for (y = 0; y < rows; y++){
|
||||
var v = bin.charCodeAt(x * rows + y) / 255; /* column-major, row 0 = -amp */
|
||||
var p = ((rows - 1 - y) * cols + x) * 4; /* canvas y grows downward */
|
||||
img.data[p] = Math.min(255, 40 + 255 * Math.pow(v, 0.75));
|
||||
img.data[p + 1] = Math.min(255, 20 + 200 * Math.pow(v, 1.6));
|
||||
img.data[p + 2] = Math.min(255, 60 + 120 * Math.pow(v, 2.6));
|
||||
img.data[p + 3] = v > 0 ? 255 : 0;
|
||||
}
|
||||
}
|
||||
og.putImageData(img, 0, 0);
|
||||
|
||||
var L = 46, R = 12, T = 10, B = 28;
|
||||
g.imageSmoothingEnabled = true;
|
||||
g.drawImage(off, L, T, W - L - R, H - T - B);
|
||||
|
||||
function yOfLvl(v){ return T + (amp - v) / (2 * amp) * (H - T - B); }
|
||||
g.strokeStyle = 'rgba(57,208,255,0.45)'; g.lineWidth = 0.7;
|
||||
[-7,-5,-3,-1,1,3,5,7].forEach(function(v){
|
||||
var yy = yOfLvl(v);
|
||||
g.beginPath(); g.moveTo(L,yy); g.lineTo(W-R,yy); g.stroke();
|
||||
});
|
||||
var xc = L + (W - L - R) / 2; /* decision instant = centre column */
|
||||
g.strokeStyle = '#a3e635'; g.setLineDash([4,3]);
|
||||
g.beginPath(); g.moveTo(xc,T); g.lineTo(xc,H-B); g.stroke();
|
||||
g.setLineDash([]);
|
||||
|
||||
g.fillStyle = '#94a3b8'; g.font = '11px sans-serif';
|
||||
g.textAlign = 'right'; g.textBaseline = 'middle';
|
||||
[-7,-5,-3,-1,1,3,5,7].forEach(function(v){ g.fillText(v.toFixed(0), L-6, yOfLvl(v)); });
|
||||
g.textAlign = 'center'; g.textBaseline = 'top';
|
||||
[-1,-0.5,0,0.5,1].forEach(function(u){
|
||||
g.fillText(u.toFixed(1), L + (u+1)/2*(W-L-R), H-B+5);
|
||||
});
|
||||
g.fillStyle = '#64748b'; g.textBaseline = 'bottom';
|
||||
g.fillText('symbol periods (UI) - decision instant at 0', (L+W-R)/2, H-2);
|
||||
g.save(); g.translate(12,(T+H-B)/2); g.rotate(-Math.PI/2);
|
||||
g.textBaseline = 'top'; g.fillText('normalised I level', 0, 0); g.restore();
|
||||
}
|
||||
|
||||
/* ---- canvas ---- */
|
||||
function specGeom(){
|
||||
var c = document.getElementById('spec_canvas');
|
||||
var dpr = window.devicePixelRatio || 1;
|
||||
var w = c.clientWidth, h = c.clientHeight;
|
||||
if (c.width !== Math.round(w*dpr) || c.height !== Math.round(h*dpr)){
|
||||
c.width = Math.round(w*dpr); c.height = Math.round(h*dpr);
|
||||
}
|
||||
var g = c.getContext('2d');
|
||||
g.setTransform(dpr,0,0,dpr,0,0);
|
||||
return {g:g, w:w, h:h, l:56, r:14, t:14, b:30};
|
||||
}
|
||||
function xOf(m, f, fmin, fmax){ return m.l + (f - fmin)/(fmax - fmin) * (m.w - m.l - m.r); }
|
||||
function yOf(m, db){ return m.t + (Y_TOP - db)/(Y_TOP - Y_BOT) * (m.h - m.t - m.b); }
|
||||
|
||||
function drawGrid(fmin, fmax){
|
||||
if (fmin === undefined){ fmin = -5; fmax = 5; }
|
||||
var m = specGeom(), g = m.g, f, db;
|
||||
g.clearRect(0,0,m.w,m.h);
|
||||
g.fillStyle = '#0b1220'; g.fillRect(0,0,m.w,m.h);
|
||||
|
||||
g.fillStyle = 'rgba(56,189,248,0.10)'; // the band the shoulder is measured in
|
||||
[[SH_LO,SH_HI],[-SH_HI,-SH_LO]].forEach(function(b){
|
||||
var x0 = xOf(m,Math.max(b[0],fmin),fmin,fmax), x1 = xOf(m,Math.min(b[1],fmax),fmin,fmax);
|
||||
g.fillRect(x0, m.t, x1-x0, m.h-m.t-m.b);
|
||||
});
|
||||
|
||||
g.lineWidth = 1;
|
||||
g.font = '11px sans-serif';
|
||||
g.textAlign = 'center'; g.textBaseline = 'top';
|
||||
for (f = Math.ceil(fmin); f <= fmax; f++){
|
||||
var x = Math.round(xOf(m,f,fmin,fmax)) + 0.5;
|
||||
g.strokeStyle = '#1e293b';
|
||||
g.beginPath(); g.moveTo(x,m.t); g.lineTo(x,m.h-m.b); g.stroke();
|
||||
g.fillStyle = '#94a3b8'; g.fillText(f.toFixed(0), x, m.h-m.b+5);
|
||||
}
|
||||
g.textAlign = 'right'; g.textBaseline = 'middle';
|
||||
for (db = Y_TOP; db >= Y_BOT; db -= 10){
|
||||
var y = Math.round(yOf(m,db)) + 0.5;
|
||||
g.strokeStyle = (db === 0) ? '#334155' : '#1e293b';
|
||||
g.beginPath(); g.moveTo(m.l,y); g.lineTo(m.w-m.r,y); g.stroke();
|
||||
g.fillStyle = '#94a3b8'; g.fillText(db.toFixed(0), m.l-6, y);
|
||||
}
|
||||
g.fillStyle = '#64748b'; g.textAlign = 'center'; g.textBaseline = 'bottom';
|
||||
g.fillText('MHz from carrier', (m.l+m.w-m.r)/2, m.h-2);
|
||||
g.save(); g.translate(12,(m.t+m.h-m.b)/2); g.rotate(-Math.PI/2);
|
||||
g.textBaseline = 'top'; g.fillText('dB rel. in-band flat density', 0, 0); g.restore();
|
||||
return m;
|
||||
}
|
||||
|
||||
function trace(m, psd, f0, df, fmin, fmax, color, width){
|
||||
var g = m.g, i, started = false;
|
||||
g.strokeStyle = color; g.lineWidth = width; g.beginPath();
|
||||
for (i = 0; i < psd.length; i++){
|
||||
var f = f0 + i*df;
|
||||
if (f < fmin || f > fmax) continue;
|
||||
var x = xOf(m,f,fmin,fmax), y = yOf(m, Math.max(Math.min(psd[i],Y_TOP),Y_BOT));
|
||||
if (!started){ g.moveTo(x,y); started = true; } else g.lineTo(x,y);
|
||||
}
|
||||
g.stroke();
|
||||
}
|
||||
|
||||
function drawSpectrum(d){
|
||||
var fmin = d.f0, fmax = d.f0 + (d.n-1)*d.df;
|
||||
var m = drawGrid(fmin, fmax), i;
|
||||
|
||||
if (document.getElementById('spec_hold').checked){
|
||||
if (!specPeak || specPeak.length !== d.psd.length) specPeak = d.psd.slice();
|
||||
else for (i = 0; i < d.psd.length; i++) if (d.psd[i] > specPeak[i]) specPeak[i] = d.psd[i];
|
||||
trace(m, specPeak, d.f0, d.df, fmin, fmax, '#f59e0b', 1);
|
||||
} else specPeak = null;
|
||||
|
||||
trace(m, d.psd, d.f0, d.df, fmin, fmax, '#38bdf8', 1.2);
|
||||
|
||||
var y = yOf(m, d.shoulder); // measured shoulder level
|
||||
m.g.strokeStyle = '#f87171'; m.g.setLineDash([5,4]); m.g.lineWidth = 1;
|
||||
m.g.beginPath(); m.g.moveTo(m.l,y); m.g.lineTo(m.w-m.r,y); m.g.stroke();
|
||||
m.g.setLineDash([]);
|
||||
m.g.fillStyle = '#f87171'; m.g.textAlign = 'left'; m.g.textBaseline = 'bottom';
|
||||
m.g.fillText('shoulder ' + d.shoulder.toFixed(1) + ' dB', m.l+6, y-3);
|
||||
|
||||
var xp = xOf(m, d.pilot, fmin, fmax); // pilot marker
|
||||
m.g.strokeStyle = '#a3e635'; m.g.beginPath();
|
||||
m.g.moveTo(xp, m.t); m.g.lineTo(xp, m.h-m.b); m.g.stroke();
|
||||
m.g.fillStyle = '#a3e635'; m.g.textAlign = 'left'; m.g.textBaseline = 'top';
|
||||
m.g.fillText('pilot ' + d.pilot.toFixed(3) + ' MHz', xp+4, m.t+2);
|
||||
}
|
||||
|
||||
// Opens the modal - gets current username from server
|
||||
function openAccountModal() {
|
||||
// Fetch current username from server
|
||||
$.get("login.cgi?action=get_user", function(data) {
|
||||
var trimmedData = (data || "").trim();
|
||||
if (trimmedData && trimmedData !== "UNAUTHORIZED") {
|
||||
document.getElementById('current_user').value = trimmedData;
|
||||
}
|
||||
document.getElementById('accountModal').style.display = 'block';
|
||||
setTimeout(function() { document.getElementById('current_pwd').focus(); }, 100);
|
||||
}).fail(function() {
|
||||
document.getElementById('accountModal').style.display = 'block';
|
||||
setTimeout(function() { document.getElementById('current_pwd').focus(); }, 100);
|
||||
});
|
||||
}
|
||||
|
||||
// Closes the modal and clears the sensitive inputs
|
||||
function closeAccountModal() {
|
||||
document.getElementById('accountModal').style.display = 'none';
|
||||
document.getElementById('current_pwd').value = '';
|
||||
document.getElementById('new_pwd').value = '';
|
||||
document.getElementById('confirm_pwd').value = '';
|
||||
}
|
||||
|
||||
// Validates that a string contains only printable characters (excluding space)
|
||||
function isValidPrintableString(str) {
|
||||
// Regular expression to check for printable characters (ASCII 33-126), excluding space
|
||||
// Space is ASCII 32, and we want to exclude it
|
||||
var printableCharRegex = /^[!-~]+$/; // ! is ASCII 33, ~ is ASCII 126
|
||||
return printableCharRegex.test(str);
|
||||
}
|
||||
|
||||
// Validates the passwords match before submitting to the CGI script - All required fields must be filled
|
||||
function validateAccountForm() {
|
||||
var currentUser = document.getElementById('current_user').value;
|
||||
var currentPwd = document.getElementById('current_pwd').value;
|
||||
var newUsername = document.getElementById('new_user').value;
|
||||
var newPwd = document.getElementById('new_pwd').value;
|
||||
var confirmPwd = document.getElementById('confirm_pwd').value;
|
||||
|
||||
// Current password is required (cannot be empty)
|
||||
if (!currentPwd || currentPwd.trim() === "") {
|
||||
alert("Current password is required");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate current password contains only printable characters
|
||||
if (!isValidPrintableString(currentPwd)) {
|
||||
alert("Current password contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// New password is required (cannot be empty)
|
||||
if (!newPwd || newPwd.trim() === "") {
|
||||
alert("New password is required");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new password contains only printable characters
|
||||
if (!isValidPrintableString(newPwd)) {
|
||||
alert("New password contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new password length (max 16 chars)
|
||||
if (newPwd.length > 16) {
|
||||
alert("New password must be no more than 16 characters");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new password length
|
||||
if (newPwd.length < 6) {
|
||||
alert("New password must be at least 6 characters");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Confirm password must match new password
|
||||
if (newPwd !== confirmPwd) {
|
||||
alert("New passwords do not match");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate confirm password contains only printable characters
|
||||
if (!isValidPrintableString(confirmPwd)) {
|
||||
alert("Confirm password contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate confirm password length (max 16 chars)
|
||||
if (confirmPwd.length > 16) {
|
||||
alert("Confirm password must be no more than 16 characters");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new username if provided
|
||||
if (newUsername && newUsername.trim() !== "") {
|
||||
// Validate new username contains only printable characters
|
||||
if (!isValidPrintableString(newUsername)) {
|
||||
alert("New username contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new username length (max 16 chars)
|
||||
if (newUsername.length > 16) {
|
||||
alert("New username must be no more than 16 characters");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true; // Allows the form to submit
|
||||
}
|
||||
|
||||
// Form submission handler using fetch API
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var accountForm = document.getElementById('accountForm');
|
||||
if (accountForm) {
|
||||
accountForm.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!validateAccountForm()) return;
|
||||
|
||||
var formData = new URLSearchParams({
|
||||
Username: document.getElementById('current_user').value,
|
||||
OldPassword: document.getElementById('current_pwd').value,
|
||||
NewUsername: document.getElementById('new_user').value,
|
||||
NewPassword: document.getElementById('new_pwd').value,
|
||||
ConfirmPassword: document.getElementById('confirm_pwd').value
|
||||
});
|
||||
|
||||
fetch('login.cgi?action=change_account', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert("Update successful! Please login again.");
|
||||
closeAccountModal();
|
||||
// Redirect to login page after 1.5 seconds
|
||||
setTimeout(function() {
|
||||
window.location.href = 'login.cgi?logout=1';
|
||||
}, 1500);
|
||||
} else {
|
||||
alert(data.error || "Update failed");
|
||||
}
|
||||
})
|
||||
.catch(function(err) {
|
||||
alert("Network error: " + err);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Optional: Closes the modal if the user clicks the dark background outside the box
|
||||
window.onclick = function(event) {
|
||||
var modal = document.getElementById('accountModal');
|
||||
if (event.target == modal) {
|
||||
closeAccountModal();
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="refresh_show()">
|
||||
|
||||
|
||||
<div class="app-layout">
|
||||
<aside class="app-sidebar">
|
||||
<ul class="items">
|
||||
<li><a href="status_info.html" title="Status">Status</a></li>
|
||||
<li><a href="sys_set.html" title="Settings">Settings</a></li>
|
||||
<li><a href="sys_rf.html" title="RF Control">RF Control</a></li>
|
||||
<li><a href="sys_psip.html" title="TSID&PSIP">TSID&PSIP</a></li>
|
||||
<li><a href="sys_ts.html" title="TSoIP">TSoIP</a></li>
|
||||
<li class="active"><a href="sys_spectrum.html" title="Spectrum">Spectrum</a></li>
|
||||
<li><a href="log_output.html" title="Log">Log</a></li>
|
||||
</ul>
|
||||
<div class="sidebar-footer">
|
||||
<h4>Anywave Broadcast Inc.</h4>
|
||||
<p>Copyright 2026<br><br><span class="redbox-label">Technical Support</span><br>+1 847 415 2258<br><a href="mailto:support@anywaveus.com">support@anywaveus.com</a></p>
|
||||
</div>
|
||||
</aside>
|
||||
<div class="sidebar-overlay" onclick="toggleSidebar()"></div>
|
||||
|
||||
<header class="app-header">
|
||||
<button class="menu-toggle" onclick="toggleSidebar()" aria-label="Toggle menu">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="3" y1="12" x2="21" y2="12"></line>
|
||||
<line x1="3" y1="6" x2="21" y2="6"></line>
|
||||
<line x1="3" y1="18" x2="21" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
<h1><a href="https://anywavecom.net/" class="logo-bg" title="Anywave Broadcast Inc."></a></h1>
|
||||
<h2 id="webtitle_header"><span></span></h2>
|
||||
<h3>
|
||||
<div class="dropdown">
|
||||
<button class="dropbtn-modern">Admin ▾</button>
|
||||
<div class="dropdown-content">
|
||||
<a href="#" onclick="openAccountModal(); return false;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="3"></circle>
|
||||
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06-.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06-.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06-.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
|
||||
</svg>
|
||||
Account Settings
|
||||
</a>
|
||||
<a href="login.cgi?logout=1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
|
||||
<polyline points="16 17 21 12 16 7"></polyline>
|
||||
<line x1="21" y1="12" x2="9" y2="12"></line>
|
||||
</svg>
|
||||
Logout
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</h3>
|
||||
</header>
|
||||
|
||||
<!-- Fixed Dashboard Summary - Top of page, under header -->
|
||||
<div class="dashboard-fixed">
|
||||
<div class="summary-dashboard">
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_freq" aria-hidden="true"></span>
|
||||
<span class="summary-label">Frequency</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_freq">--</span>
|
||||
<span class="summary-unit">MHz</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_snr" aria-hidden="true"></span>
|
||||
<span class="summary-label">SNR</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_snr">--</span>
|
||||
<span class="summary-unit">dB</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_uimd" aria-hidden="true"></span>
|
||||
<span class="summary-label">UIMD</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_uimd">--</span>
|
||||
<span class="summary-unit">dBc</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_limd" aria-hidden="true"></span>
|
||||
<span class="summary-label">LIMD</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_limd">--</span>
|
||||
<span class="summary-unit">dBc</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-off" id="dot_rf" aria-hidden="true"></span>
|
||||
<span class="summary-label">RF Switch</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-muted" id="sum_rf">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_outpow" aria-hidden="true"></span>
|
||||
<span class="summary-label">Output Power</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_outpow">--</span>
|
||||
<span class="summary-unit">dBm</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_input" aria-hidden="true"></span>
|
||||
<span class="summary-label">Input Source</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_input">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_input_status" aria-hidden="true"></span>
|
||||
<span class="summary-label">Input Status</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_input_status">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_bitrate" aria-hidden="true"></span>
|
||||
<span class="summary-label">Bitrate</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_bitrate">--</span>
|
||||
<span class="summary-unit">Mbps</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_temp" aria-hidden="true"></span>
|
||||
<span class="summary-label">Temperature</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_temp">--</span>
|
||||
<span class="summary-unit">°F</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-off" id="dot_agc" aria-hidden="true"></span>
|
||||
<span class="summary-label">AGC</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-muted" id="sum_agc">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_control" aria-hidden="true"></span>
|
||||
<span class="summary-label">Control</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_control">--</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<main class="app-main">
|
||||
<h2>ORx Receive Spectrum</h2>
|
||||
<div class="box">
|
||||
<div class="spec-toolbar">
|
||||
<label>Refresh
|
||||
<select id="spec_rate" onchange="specRestart()">
|
||||
<option value="500">0.5 s</option>
|
||||
<option value="1000" selected>1 s</option>
|
||||
<option value="2000">2 s</option>
|
||||
<option value="5000">5 s</option>
|
||||
</select>
|
||||
</label>
|
||||
<label><input type="checkbox" id="spec_pause" onchange="specRestart()"> Pause</label>
|
||||
<label><input type="checkbox" id="spec_hold" onchange="specPeak=null"> Peak hold</label>
|
||||
<span id="spec_state">starting…</span>
|
||||
</div>
|
||||
<canvas id="spec_canvas"></canvas>
|
||||
<div class="spec-readouts">
|
||||
<div class="spec-readout"><span class="k">Shoulder</span><span class="v"><span id="rd_shoulder">--</span> dB</span></div>
|
||||
<div class="spec-readout" title="10log10(P@+24kHz / P@3.1494MHz on the pilot side), 11 bins each. Raw dB, without the +11 dB offset the Status page adds."><span class="k">LIMD raw</span><span class="v"><span id="rd_limd">--</span> dB</span></div>
|
||||
<div class="spec-readout" title="10log10(P@+24kHz / P@3.1494MHz opposite the pilot), 11 bins each. Raw dB, without the +11 dB offset the Status page adds."><span class="k">UIMD raw</span><span class="v"><span id="rd_uimd">--</span> dB</span></div>
|
||||
<div class="spec-readout"><span class="k">Pilot</span><span class="v"><span id="rd_pilot">--</span> MHz</span></div>
|
||||
<div class="spec-readout"><span class="k">Peak</span><span class="v"><span id="rd_peak">--</span> dB</span></div>
|
||||
<div class="spec-readout"><span class="k">RBW</span><span class="v"><span id="rd_rbw">--</span> kHz</span></div>
|
||||
<div class="spec-readout"><span class="k">Packets</span><span class="v" id="rd_pkts">--</span></div>
|
||||
<div class="spec-readout"><span class="k">Contiguous</span><span class="v"><span id="rd_ms">--</span> ms</span></div>
|
||||
<div class="spec-readout"><span class="k">> 1 field</span><span class="v" id="rd_field">--</span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>8VSB Eye Diagram</h2>
|
||||
<div class="box">
|
||||
<div class="spec-toolbar">
|
||||
<span style="font-size:13px;opacity:.75">Matched-filtered I rail, 2 symbol periods, log persistence</span>
|
||||
<span id="eye_state">waiting for the demodulator…</span>
|
||||
</div>
|
||||
<canvas id="eye_canvas"></canvas>
|
||||
<div class="spec-readouts">
|
||||
<div class="spec-readout" title="MER, I-path definition: 10log10(sum d^2 / sum (r-d)^2)"><span class="k">SNR / MER</span><span class="v"><span id="rd_snr">--</span> dB</span></div>
|
||||
<div class="spec-readout" title="Smallest of the 7 eye openings at the decision instant (1%/99% percentiles); ideal 2.00"><span class="k">Min eye height</span><span class="v" id="rd_eyeh">--</span></div>
|
||||
<div class="spec-readout" title="Time span over which the central eye stays open"><span class="k">Eye width</span><span class="v"><span id="rd_eyew">--</span> UI</span></div>
|
||||
<div class="spec-readout" title="Sampling phase offset; re-solved for every window because the capture start is not symbol-locked"><span class="k">τ0</span><span class="v"><span id="rd_tau">--</span> sa</span></div>
|
||||
<div class="spec-readout" title="Correlation peak / rms of the 4-symbol segment sync, period 832. Above 10 means locked"><span class="k">Seg sync</span><span class="v" id="rd_segsync">--</span></div>
|
||||
<div class="spec-readout" title="Pilot phase drift across the window. TX and ORx share the LO, so this must be ~0"><span class="k">Carrier offset</span><span class="v"><span id="rd_coff">--</span> Hz</span></div>
|
||||
<div class="spec-readout" title="MER before the ORx AGC gain steps are tracked out. The gap to SNR/MER is what the observation receiver costs you, not the transmitter."><span class="k">SNR raw</span><span class="v"><span id="rd_snrraw">--</span> dB</span></div>
|
||||
<div class="spec-readout" title="rms of the ORx RF AGC gain steps over the window (0.43 dB per gain index). This is a receiver artifact; a dead zone in dpd_rx_rfagc would remove it at the source."><span class="k">ORx AGC jitter</span><span class="v"><span id="rd_gjit">--</span> %</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
|
||||
<div id="accountModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3>Account Settings</h3>
|
||||
<span class="close" onclick="closeAccountModal()">×</span>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="accountForm" method="post" action="login.cgi?action=change_account" onsubmit="return validateAccountForm()">
|
||||
<table class="modal-table">
|
||||
<tr>
|
||||
<td>Current Username</td>
|
||||
<td><input type="text" id="current_user" name="current_user" readonly></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Current Password</td>
|
||||
<td><input type="password" id="current_pwd" name="current_pwd" required></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>New Username</td>
|
||||
<td><input type="text" id="new_user" name="new_user"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>New Password</td>
|
||||
<td><input type="password" id="new_pwd" name="new_pwd"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Confirm Password</td>
|
||||
<td><input type="password" id="confirm_pwd" name="confirm_pwd"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="modal-footer">
|
||||
<input type="button" class="btn-modern" style="background-color: #64748b;" value="Cancel" onclick="closeAccountModal()">
|
||||
<input type="submit" class="btn-modern" value="Save Changes">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toggleSidebar(){
|
||||
document.querySelector('.app-sidebar').classList.toggle('sidebar-open');
|
||||
document.querySelector('.sidebar-overlay').classList.toggle('active');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Executable
+867
@@ -0,0 +1,867 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title id="webtitle"></title>
|
||||
<link href="css/styles.css" rel="stylesheet" media="screen">
|
||||
<script src="js/auth.js"></script>
|
||||
<script src="js/jquery.js"></script>
|
||||
<script src="js/dashboard.js"></script>
|
||||
<script>
|
||||
var time_sec_cnt=0;
|
||||
var g_remot_local_ctrl = 0;// 0 remote 1 local
|
||||
|
||||
var lastTime = new Date().getTime();
|
||||
var currentTime = new Date().getTime();
|
||||
var timeOut = 20 * 60 * 1000; // 20 min
|
||||
|
||||
$(function(){
|
||||
// Listen to multiple types of user activity to prevent timeout
|
||||
$(document).on('mousemove keydown click scroll touchstart', function(){
|
||||
lastTime = new Date().getTime();
|
||||
});
|
||||
});
|
||||
|
||||
function testTime(){
|
||||
currentTime = new Date().getTime();
|
||||
if(currentTime - lastTime > timeOut){
|
||||
window.location.href="login.cgi?logout=1"
|
||||
}
|
||||
|
||||
time_sec_cnt=time_sec_cnt+1;
|
||||
if(time_sec_cnt%3==0){
|
||||
get_remote_local_ctrl();
|
||||
if(g_remot_local_ctrl==1) { // local
|
||||
SetFormDefaults();
|
||||
}
|
||||
refreshDashboard();
|
||||
}
|
||||
}
|
||||
|
||||
// Timer check (1s)
|
||||
window.setInterval(testTime, 1000);
|
||||
refreshDashboard();
|
||||
|
||||
function get_remote_local_ctrl() {
|
||||
var queryData = "sys_cfg=&";
|
||||
$.get("atsc_status_cfg.cgi?"+queryData, function(data, status) {
|
||||
// Handle case where data is a JSON object (e.g., session expired)
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
if (data.error === 'session_expired' && data.redirect) {
|
||||
window.location.href = data.redirect;
|
||||
return;
|
||||
}
|
||||
console.error('Received JSON error response:', data);
|
||||
return;
|
||||
}
|
||||
|
||||
var table = data.split("|");
|
||||
g_remot_local_ctrl = Number(table[0].split("#")[5]);
|
||||
document.title = table[0].split("#")[11];
|
||||
});
|
||||
}
|
||||
|
||||
function SetFormDefaults() {
|
||||
// 1. DISABLE BUTTONS START (only in Remote mode)
|
||||
if(g_remot_local_ctrl == 1) {
|
||||
// Local mode: just fetch data, don't change button text
|
||||
var ops = 0;
|
||||
var i = 0;
|
||||
var queryData = "tsoip_num=&tsoip_systs1=&tsoip_systs2=&web_title=&"
|
||||
} else {
|
||||
// Remote mode: show Loading indicator
|
||||
$('#setnet_id_1, #setcfg_id1').attr("disabled", true).val("Loading...");
|
||||
var ops = 0;
|
||||
var i = 0;
|
||||
var queryData = "tsoip_num=&tsoip_systs1=&tsoip_systs2=&web_title=&"
|
||||
}
|
||||
|
||||
$.get("atsc_status_cfg.cgi?"+queryData, function(data, status) {
|
||||
// Handle case where data is a JSON object (e.g., session expired)
|
||||
if (typeof data === 'object' && data !== null) {
|
||||
if (data.error === 'session_expired' && data.redirect) {
|
||||
window.location.href = data.redirect;
|
||||
return;
|
||||
}
|
||||
console.error('Received JSON error response:', data);
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate response structure
|
||||
var table = data.split("|");
|
||||
if (table.length < 4) {
|
||||
console.error("TSoIP: Invalid response - expected 4 sections, got", table.length);
|
||||
$('#setnet_id_1, #setcfg_id1').val("Data Error");
|
||||
return;
|
||||
}
|
||||
|
||||
var form = table[0].split("#"); // tsoip_num
|
||||
var tsoip_total_num = Number(form[1]);
|
||||
var tb_systs = table[1].split("#"); // tsoip_systs1
|
||||
var tb_systs2 = table[2].split("#");// tsoip_systs2
|
||||
var title = table[3].split("#");
|
||||
|
||||
// Validate field counts for TSoIP configuration
|
||||
// Expected: Network config (13 fields) + Rx config (12 fields) = 25+ fields
|
||||
if (tb_systs.length < 25) {
|
||||
console.warn("TSoIP: Incomplete data - expected 25+ fields, got", tb_systs.length);
|
||||
console.log("TSoIP data:", tb_systs);
|
||||
}
|
||||
|
||||
var fnet1 = document.getElementById('ts1_net_form');
|
||||
var fcfg1 = document.getElementById('ts1_cfg_form');
|
||||
|
||||
ops = 1;
|
||||
fnet1.ip1.value = tb_systs[ops];
|
||||
ops++;
|
||||
fnet1.ip2.value = (Number(tb_systs[ops])&0x00ff0000)>>16;
|
||||
fnet1.ip3.value = (Number(tb_systs[ops])&0x0000ff00)>>8;
|
||||
fnet1.ip4.value = (Number(tb_systs[ops])&0x000000ff)>>0;
|
||||
ops++;
|
||||
|
||||
fnet1.gt1.value = tb_systs[ops];
|
||||
ops++;
|
||||
fnet1.gt2.value = (Number(tb_systs[ops])&0x00ff0000)>>16;
|
||||
fnet1.gt3.value = (Number(tb_systs[ops])&0x0000ff00)>>8;
|
||||
fnet1.gt4.value = (Number(tb_systs[ops])&0x000000ff)>>0;
|
||||
ops++;
|
||||
|
||||
fnet1.mk1.value = tb_systs[ops];
|
||||
ops++;
|
||||
fnet1.mk2.value = (Number(tb_systs[ops])&0x00ff0000)>>16;
|
||||
fnet1.mk3.value = (Number(tb_systs[ops])&0x0000ff00)>>8;
|
||||
fnet1.mk4.value = (Number(tb_systs[ops])&0x000000ff)>>0;
|
||||
ops++;
|
||||
|
||||
$("#tsoipmac").html(tb_systs[ops]);
|
||||
ops++;
|
||||
|
||||
// Read all 4 octets of Multicast IP
|
||||
fcfg1.ma1.value = tb_systs[ops];
|
||||
ops++;
|
||||
fcfg1.ma2.value = (Number(tb_systs[ops])&0x00ff0000)>>16;
|
||||
fcfg1.ma3.value = (Number(tb_systs[ops])&0x0000ff00)>>8;
|
||||
fcfg1.ma4.value = (Number(tb_systs[ops])&0x000000ff)>>0;
|
||||
ops++;
|
||||
// Then read Port
|
||||
fcfg1.uport.value = tb_systs[ops];
|
||||
ops++;
|
||||
var lpk_para = Number(tb_systs[ops]);
|
||||
ops++;
|
||||
|
||||
i = (lpk_para&0xff0000)>>16;
|
||||
if(i >= 2) i = 2;
|
||||
fcfg1.pktp.selectedIndex = i;
|
||||
|
||||
i = (lpk_para&0x00ff00)>>8;
|
||||
if(i >= 2) i = 2;
|
||||
fcfg1.pklen.selectedIndex = i;
|
||||
|
||||
i = (lpk_para&0x0000ff);
|
||||
if(i >= 2) i = 2;
|
||||
fcfg1.pkrec.selectedIndex = i;
|
||||
|
||||
fcfg1.fec_swh.selectedIndex=Number(tb_systs[ops]);
|
||||
ops++;
|
||||
fcfg1.fec_dly.value=Number(tb_systs[ops]);
|
||||
ops++;
|
||||
fcfg1.fec_row.value=Number(tb_systs[ops]);
|
||||
ops++;
|
||||
fcfg1.fec_col.value=Number(tb_systs[ops]);
|
||||
ops++;
|
||||
|
||||
// Logic for a second TS input (if enabled in backend)
|
||||
if(tsoip_total_num == 2){
|
||||
// Note: The original file did NOT have forms[2] and forms[3] in the HTML
|
||||
// If you need the second interface, you must duplicate the HTML blocks below
|
||||
// and ensure the IDs/Forms exist. For now, this follows the source file provided.
|
||||
}
|
||||
|
||||
// 2. RE-ENABLE BUTTONS END (only in Remote mode)
|
||||
if(g_remot_local_ctrl == 1) {
|
||||
// Local mode: keep button disabled
|
||||
$('#setnet_id_1, #setcfg_id1').attr("disabled", true).val("Local Mode");
|
||||
} else {
|
||||
// Remote mode: enable button
|
||||
$('#setnet_id_1, #setcfg_id1').attr("disabled", false).val("Set");
|
||||
}
|
||||
|
||||
if (typeof setFormSnapshotUpdate === 'function') setFormSnapshotUpdate();
|
||||
|
||||
document.getElementById('webtitle').textContent = title[1];
|
||||
document.getElementById('webtitle_header').textContent = title[1];
|
||||
}).fail(function() {
|
||||
// Optional: Handle error case
|
||||
$('#setnet_id_1, #setcfg_id1').val("Load Failed");
|
||||
});
|
||||
}
|
||||
|
||||
// ----- SET (unsaved) reminder: per-form, vanilla JS -----
|
||||
var setFormSnapshots = {};
|
||||
var setFormConfig = [
|
||||
{ formId: 'ts1_net_form', buttonId: 'setnet_id_1' },
|
||||
{ formId: 'ts1_cfg_form', buttonId: 'setcfg_id1' }
|
||||
];
|
||||
function getFormSnapshot(formId) {
|
||||
var f = document.getElementById(formId);
|
||||
if (!f) return [];
|
||||
var out = [], els = f.querySelectorAll('select, input:not([type="button"])'), i, el, v;
|
||||
for (i = 0; i < els.length; i++) {
|
||||
el = els[i];
|
||||
v = el.tagName === 'SELECT' ? (el.options[el.selectedIndex] ? el.options[el.selectedIndex].value : '') : (el.value || '');
|
||||
out.push({ name: el.name || el.id, value: String(v) });
|
||||
}
|
||||
return out;
|
||||
}
|
||||
function isFormDirty(formId, snapshot) {
|
||||
var current = getFormSnapshot(formId);
|
||||
if (current.length !== snapshot.length) return true;
|
||||
for (var i = 0; i < current.length; i++) {
|
||||
if (current[i].name !== snapshot[i].name || current[i].value !== snapshot[i].value) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function setSetButtonState(btnId, unsaved) {
|
||||
var btn = document.getElementById(btnId);
|
||||
if (!btn || btn.disabled) return;
|
||||
btn.value = unsaved ? 'Set (unsaved)' : 'Set';
|
||||
if (unsaved) btn.classList.add('is-unsaved'); else btn.classList.remove('is-unsaved');
|
||||
}
|
||||
function setFormSnapshotUpdate() {
|
||||
for (var i = 0; i < setFormConfig.length; i++) {
|
||||
var c = setFormConfig[i];
|
||||
var f = document.getElementById(c.formId);
|
||||
if (f) setFormSnapshots[c.formId] = getFormSnapshot(c.formId);
|
||||
setSetButtonState(c.buttonId, false);
|
||||
}
|
||||
}
|
||||
function updateSetButtonForForm(formId) {
|
||||
for (var i = 0; i < setFormConfig.length; i++) {
|
||||
if (setFormConfig[i].formId !== formId) continue;
|
||||
var c = setFormConfig[i];
|
||||
var snap = setFormSnapshots[c.formId];
|
||||
var dirty = !snap || snap.length === 0 || isFormDirty(c.formId, snap);
|
||||
setSetButtonState(c.buttonId, dirty);
|
||||
return;
|
||||
}
|
||||
}
|
||||
function attachSetFormUnsavedListeners() {
|
||||
for (var i = 0; i < setFormConfig.length; i++) {
|
||||
var f = document.getElementById(setFormConfig[i].formId);
|
||||
if (!f) continue;
|
||||
f.addEventListener('change', function() { updateSetButtonForForm(this.id); });
|
||||
f.addEventListener('input', function() { updateSetButtonForForm(this.id); });
|
||||
}
|
||||
}
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', attachSetFormUnsavedListeners);
|
||||
} else {
|
||||
attachSetFormUnsavedListeners();
|
||||
}
|
||||
|
||||
function refresh_show(){
|
||||
get_remote_local_ctrl();
|
||||
SetFormDefaults();
|
||||
refreshDashboard();
|
||||
}
|
||||
|
||||
function cmd_confirm() {
|
||||
return confirm("Please choose to confirm or cancel!");
|
||||
}
|
||||
|
||||
function tsoip_setnet(ts_index) {
|
||||
var postData;
|
||||
var forms_net;
|
||||
|
||||
if(ts_index==0){
|
||||
postData = "tsoip_net1=";
|
||||
forms_net = document.forms[0];
|
||||
}
|
||||
else if(ts_index==1){
|
||||
postData = "tsoip_net2=";
|
||||
forms_net = document.forms[2];
|
||||
}
|
||||
|
||||
postData += "#"+forms_net.ip1.value;
|
||||
postData += "#"+forms_net.ip2.value;
|
||||
postData += "#"+forms_net.ip3.value;
|
||||
postData += "#"+forms_net.ip4.value;
|
||||
|
||||
postData += "#"+forms_net.gt1.value;
|
||||
postData += "#"+forms_net.gt2.value;
|
||||
postData += "#"+forms_net.gt3.value;
|
||||
postData += "#"+forms_net.gt4.value;
|
||||
|
||||
postData += "#"+forms_net.mk1.value;
|
||||
postData += "#"+forms_net.mk2.value;
|
||||
postData += "#"+forms_net.mk3.value;
|
||||
postData += "#"+forms_net.mk4.value;
|
||||
|
||||
postData += "#"+forms_net.eth_spd.value;
|
||||
|
||||
if(cmd_confirm()){
|
||||
$.post("atsc_status_cfg.cgi?", postData, function(data, status){
|
||||
if(status=="success"){
|
||||
SetFormDefaults();
|
||||
} else{
|
||||
alert("post val err");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function tsoip_setcfg(ts_index) {
|
||||
var postData = "";
|
||||
var forms;
|
||||
|
||||
if(ts_index==0){
|
||||
postData = "tsoip_systs1=";
|
||||
forms = document.forms[1];
|
||||
}
|
||||
else if(ts_index==1){
|
||||
postData = "tsoip_systs2=";
|
||||
forms = document.forms[3];
|
||||
}
|
||||
|
||||
postData += "#"+forms.ma1.value;
|
||||
postData += "#"+forms.ma2.value;
|
||||
postData += "#"+forms.ma3.value;
|
||||
postData += "#"+forms.ma4.value;
|
||||
|
||||
postData += "#"+forms.uport.value;
|
||||
postData += "#"+forms.pktp.value;
|
||||
postData += "#"+forms.pklen.value;
|
||||
postData += "#"+forms.pkrec.value;
|
||||
postData += "#"+forms.fec_swh.value;
|
||||
|
||||
postData += "#"+forms.fec_dly.value;
|
||||
postData += "#"+forms.fec_row.value;
|
||||
postData += "#"+forms.fec_col.value;
|
||||
postData += "#0"; // force 0
|
||||
|
||||
if(cmd_confirm()){
|
||||
$.post("atsc_status_cfg.cgi?", postData, function(data, status){
|
||||
if(status=="success"){
|
||||
SetFormDefaults();
|
||||
} else{
|
||||
alert("post val err");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Modal & Dropdown Logic - Open and close account modal
|
||||
function openAccountModal() {
|
||||
// Fetch current username from server
|
||||
$.get("login.cgi?action=get_user", function(data) {
|
||||
var trimmedData = (data || "").trim();
|
||||
if (trimmedData && trimmedData !== "UNAUTHORIZED") {
|
||||
document.getElementById('current_user').value = trimmedData;
|
||||
}
|
||||
document.getElementById('accountModal').style.display = 'block';
|
||||
setTimeout(function() { document.getElementById('current_pwd').focus(); }, 100);
|
||||
}).fail(function() {
|
||||
document.getElementById('accountModal').style.display = 'block';
|
||||
setTimeout(function() { document.getElementById('current_pwd').focus(); }, 100);
|
||||
});
|
||||
}
|
||||
|
||||
function closeAccountModal() {
|
||||
document.getElementById('accountModal').style.display = 'none';
|
||||
// Clear sensitive fields
|
||||
document.getElementById('current_pwd').value = '';
|
||||
document.getElementById('new_pwd').value = '';
|
||||
document.getElementById('confirm_pwd').value = '';
|
||||
}
|
||||
|
||||
// Validates that a string contains only printable characters (excluding space)
|
||||
function isValidPrintableString(str) {
|
||||
// Regular expression to check for printable characters (ASCII 33-126), excluding space
|
||||
// Space is ASCII 32, and we want to exclude it
|
||||
var printableCharRegex = /^[!-~]+$/; // ! is ASCII 33, ~ is ASCII 126
|
||||
return printableCharRegex.test(str);
|
||||
}
|
||||
|
||||
function validateAccountForm() {
|
||||
var currentUser = document.getElementById('current_user').value;
|
||||
var currentPwd = document.getElementById('current_pwd').value;
|
||||
var newUsername = document.getElementById('new_user').value;
|
||||
var newPwd = document.getElementById('new_pwd').value;
|
||||
var confirmPwd = document.getElementById('confirm_pwd').value;
|
||||
|
||||
// Current password is required (cannot be empty)
|
||||
if (!currentPwd || currentPwd.trim() === "") {
|
||||
alert("Current password is required");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate current password contains only printable characters
|
||||
if (!isValidPrintableString(currentPwd)) {
|
||||
alert("Current password contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// New password is required (cannot be empty)
|
||||
if (!newPwd || newPwd.trim() === "") {
|
||||
alert("New password is required");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new password contains only printable characters
|
||||
if (!isValidPrintableString(newPwd)) {
|
||||
alert("New password contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new password length (max 16 chars)
|
||||
if (newPwd.length > 16) {
|
||||
alert("New password must be no more than 16 characters");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new password length
|
||||
if (newPwd.length < 6) {
|
||||
alert("New password must be at least 6 characters");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Confirm password must match new password
|
||||
if (newPwd !== confirmPwd) {
|
||||
alert("New passwords do not match");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate confirm password contains only printable characters
|
||||
if (!isValidPrintableString(confirmPwd)) {
|
||||
alert("Confirm password contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate confirm password length (max 16 chars)
|
||||
if (confirmPwd.length > 16) {
|
||||
alert("Confirm password must be no more than 16 characters");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new username if provided
|
||||
if (newUsername && newUsername.trim() !== "") {
|
||||
// Validate new username contains only printable characters
|
||||
if (!isValidPrintableString(newUsername)) {
|
||||
alert("New username contains invalid characters. Only printable characters (excluding space) are allowed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate new username length (max 16 chars)
|
||||
if (newUsername.length > 16) {
|
||||
alert("New username must be no more than 16 characters");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Form submission handler using fetch API
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
var accountForm = document.getElementById('accountForm');
|
||||
if (accountForm) {
|
||||
accountForm.addEventListener('submit', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!validateAccountForm()) return;
|
||||
|
||||
var formData = new URLSearchParams({
|
||||
Username: document.getElementById('current_user').value,
|
||||
OldPassword: document.getElementById('current_pwd').value,
|
||||
NewUsername: document.getElementById('new_user').value,
|
||||
NewPassword: document.getElementById('new_pwd').value,
|
||||
ConfirmPassword: document.getElementById('confirm_pwd').value
|
||||
});
|
||||
|
||||
fetch('login.cgi?action=change_account', {
|
||||
method: 'POST',
|
||||
body: formData
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
alert("Update successful! Please login again.");
|
||||
closeAccountModal();
|
||||
// Redirect to login page after 1.5 seconds
|
||||
setTimeout(function() {
|
||||
window.location.href = 'login.cgi?logout=1';
|
||||
}, 1500);
|
||||
} else {
|
||||
alert(data.error || "Update failed");
|
||||
}
|
||||
})
|
||||
.catch(function(err) {
|
||||
alert("Network error: " + err);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body onload="refresh_show()">
|
||||
|
||||
<div class="app-layout">
|
||||
<aside class="app-sidebar">
|
||||
<ul class="items">
|
||||
<li><a href="status_info.html" title="Status">Status</a></li>
|
||||
<li><a href="sys_set.html" title="Settings">Settings</a></li>
|
||||
<li><a href="sys_rf.html" title="RF Control">RF Control</a></li>
|
||||
<li><a href="sys_psip.html" title="TSID&PSIP">TSID&PSIP</a></li>
|
||||
<li class="active"><a href="sys_ts.html" title="TSoIP">TSoIP</a></li>
|
||||
<li><a href="sys_spectrum.html" title="Spectrum">Spectrum</a></li>
|
||||
<li><a href="log_output.html" title="Log">Log</a></li>
|
||||
</ul>
|
||||
<div class="sidebar-footer">
|
||||
<h4>Anywave Broadcast Inc.</h4>
|
||||
<p>Copyright 2026<br><br><span class="redbox-label">Technical Support</span><br>+1 847 415 2258<br><a href="mailto:support@anywaveus.com">support@anywaveus.com</a></p>
|
||||
</div>
|
||||
</aside>
|
||||
<div class="sidebar-overlay" onclick="toggleSidebar()"></div>
|
||||
|
||||
<header class="app-header">
|
||||
<button class="menu-toggle" onclick="toggleSidebar()" aria-label="Toggle menu">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<line x1="3" y1="12" x2="21" y2="12"></line>
|
||||
<line x1="3" y1="6" x2="21" y2="6"></line>
|
||||
<line x1="3" y1="18" x2="21" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
<h1><a href="https://anywavecom.net/" class="logo-bg" title="Anywave Broadcast Inc."></a></h1>
|
||||
<h2 id="webtitle_header"><span></span></h2>
|
||||
<h3>
|
||||
<div class="dropdown">
|
||||
<button class="dropbtn-modern">Admin ▾</button>
|
||||
<div class="dropdown-content">
|
||||
<a href="#" onclick="openAccountModal(); return false;">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<circle cx="12" cy="12" r="3"></circle>
|
||||
<path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06-.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06-.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06-.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path>
|
||||
</svg>
|
||||
Account Settings
|
||||
</a>
|
||||
<a href="login.cgi?logout=1">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"></path>
|
||||
<polyline points="16 17 21 12 16 7"></polyline>
|
||||
<line x1="21" y1="12" x2="9" y2="12"></line>
|
||||
</svg>
|
||||
Logout
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</h3>
|
||||
</header>
|
||||
|
||||
<!-- Fixed Dashboard Summary - Top of page, under header -->
|
||||
<div class="dashboard-fixed">
|
||||
<div class="summary-dashboard">
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_freq" aria-hidden="true"></span>
|
||||
<span class="summary-label">Frequency</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_freq">--</span>
|
||||
<span class="summary-unit">MHz</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_snr" aria-hidden="true"></span>
|
||||
<span class="summary-label">SNR</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_snr">--</span>
|
||||
<span class="summary-unit">dB</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_uimd" aria-hidden="true"></span>
|
||||
<span class="summary-label">UIMD</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_uimd">--</span>
|
||||
<span class="summary-unit">dBc</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_limd" aria-hidden="true"></span>
|
||||
<span class="summary-label">LIMD</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_limd">--</span>
|
||||
<span class="summary-unit">dBc</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-off" id="dot_rf" aria-hidden="true"></span>
|
||||
<span class="summary-label">RF Switch</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-muted" id="sum_rf">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_outpow" aria-hidden="true"></span>
|
||||
<span class="summary-label">Output Power</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_outpow">--</span>
|
||||
<span class="summary-unit">dBm</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_input" aria-hidden="true"></span>
|
||||
<span class="summary-label">Input Source</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_input">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_input_status" aria-hidden="true"></span>
|
||||
<span class="summary-label">Input Status</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_input_status">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_bitrate" aria-hidden="true"></span>
|
||||
<span class="summary-label">Bitrate</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_bitrate">--</span>
|
||||
<span class="summary-unit">Mbps</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-ok" id="dot_temp" aria-hidden="true"></span>
|
||||
<span class="summary-label">Temperature</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-ok" id="sum_temp">--</span>
|
||||
<span class="summary-unit">°F</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-off" id="dot_agc" aria-hidden="true"></span>
|
||||
<span class="summary-label">AGC</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-muted" id="sum_agc">--</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="summary-card">
|
||||
<div class="summary-label-row">
|
||||
<span class="status-dot status-neutral" id="dot_control" aria-hidden="true"></span>
|
||||
<span class="summary-label">Control</span>
|
||||
</div>
|
||||
<div class="summary-value-wrapper">
|
||||
<span class="summary-value value-neutral" id="sum_control">--</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main class="app-main">
|
||||
<h2>TSoIP (IP1) Network Configuration</h2>
|
||||
<div class="box">
|
||||
<form name="ts1_net" id="ts1_net_form">
|
||||
<table>
|
||||
<tr>
|
||||
<td>IP</td>
|
||||
<td><fieldset>
|
||||
<input style="width:40px" maxlength="3" size="3" name="ip1" id="ip1" value="">.
|
||||
<input style="width:40px" maxlength="3" size="3" name="ip2" id="ip2" value="">.
|
||||
<input style="width:40px" maxlength="3" size="3" name="ip3" id="ip3" value="">.
|
||||
<input style="width:40px" maxlength="3" size="3" name="ip4" id="ip4" value="">
|
||||
</fieldset></td>
|
||||
|
||||
<td>Gateway</td>
|
||||
<td><fieldset>
|
||||
<input style="width:40px" maxlength="3" size="3" name="gt1" id="gt1" value="">.
|
||||
<input style="width:40px" maxlength="3" size="3" name="gt2" id="gt2" value="">.
|
||||
<input style="width:40px" maxlength="3" size="3" name="gt3" id="gt3" value="">.
|
||||
<input style="width:40px" maxlength="3" size="3" name="gt4" id="gt4" value="">
|
||||
</fieldset></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Mask</td>
|
||||
<td><fieldset>
|
||||
<input style="width:40px" maxlength="3" size="3" name="mk1" id="mk1" value="">.
|
||||
<input style="width:40px" maxlength="3" size="3" name="mk2" id="mk2" value="">.
|
||||
<input style="width:40px" maxlength="3" size="3" name="mk3" id="mk3" value="">.
|
||||
<input style="width:40px" maxlength="3" size="3" name="mk4" id="mk4" value="">
|
||||
</fieldset></td>
|
||||
|
||||
<td>MAC</td>
|
||||
<td><span id="tsoipmac"></span></td>
|
||||
</tr>
|
||||
|
||||
<tr style="display: none;">
|
||||
<td>NET SPEED</td>
|
||||
<td>
|
||||
<select name="eth_spd" id="eth_spd">
|
||||
<option value="0">100Mbps
|
||||
<option value="1">1000Mbps
|
||||
<option value="2">Auto
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td> <input type="button" class="btn-modern" alt="Set" value="Set" disabled id="setnet_id_1" onclick="return tsoip_setnet(0);"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
<br><br>
|
||||
|
||||
<h2>TSoIP (IP1) Rx Configuration</h2>
|
||||
<div class="box">
|
||||
<form name="ts1_cfg" id="ts1_cfg_form">
|
||||
<table>
|
||||
<tr>
|
||||
<td>Multicast IP</td>
|
||||
<td><fieldset>
|
||||
<input style="width:40px" maxlength="3" size="3" name="ma1" id="ma1" value="">.
|
||||
<input style="width:40px" maxlength="3" size="3" name="ma2" id="ma2" value="">.
|
||||
<input style="width:40px" maxlength="3" size="3" name="ma3" id="ma3" value="">.
|
||||
<input style="width:40px" maxlength="3" size="3" name="ma4" id="ma4" value="">
|
||||
</fieldset></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Port</td>
|
||||
<td>
|
||||
<input maxlength="6" size="6" name="uport" id="uport" value="">
|
||||
</td>
|
||||
<td>Protocol</td>
|
||||
<td>
|
||||
<select name="pktp" id="pktp">
|
||||
<option value="0">UDP
|
||||
<option value="1">RTP
|
||||
<option value="2">Invalid
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Length</td>
|
||||
<td>
|
||||
<select name="pklen" id="pklen">
|
||||
<option value="0">188
|
||||
<option value="1">204
|
||||
<option value="2">Invalid
|
||||
</select>
|
||||
</td>
|
||||
<td>Type</td>
|
||||
<td>
|
||||
<select name="pkrec" id="pkrec">
|
||||
<option value="0">Multicast
|
||||
<option value="1">Unicast
|
||||
<option value="2">Invalid
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr style="display: none">
|
||||
<td>FEC</td>
|
||||
<td>
|
||||
<select name="fec_swh" id="fec_swh">
|
||||
<option value="0">Disable
|
||||
<option value="1">Enable
|
||||
</select>
|
||||
</td>
|
||||
<td>Delay</td>
|
||||
<td>
|
||||
<input maxlength="6" size="6" name="fec_dly" id="fec_dly" value="">
|
||||
</td>
|
||||
</tr>
|
||||
<tr style="display: none">
|
||||
<td>FEC Row</td>
|
||||
<td>
|
||||
<input maxlength="4" size="4" name="fec_row" id="fec_row" value="">
|
||||
</td>
|
||||
<td>FEC Col</td>
|
||||
<td>
|
||||
<input maxlength="4" size="4" name="fec_col" id="fec_col" value="">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td> <input type="button" class="btn-modern" alt="Set" value="Set" disabled id="setcfg_id1" onclick="return tsoip_setcfg(0);"> </td>
|
||||
</tr>
|
||||
</table>
|
||||
</form>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
<div id="accountModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h3>Account Settings</h3>
|
||||
<span class="close" onclick="closeAccountModal()">×</span>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form id="accountForm" method="post" action="login.cgi?action=change_account" onsubmit="return validateAccountForm()">
|
||||
<table class="modal-table">
|
||||
<tr>
|
||||
<td>Current Username</td>
|
||||
<td><input type="text" id="current_user" name="current_user" readonly></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Current Password</td>
|
||||
<td><input type="password" id="current_pwd" name="current_pwd" required></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>New Username</td>
|
||||
<td><input type="text" id="new_user" name="new_user"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>New Password</td>
|
||||
<td><input type="password" id="new_pwd" name="new_pwd"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Confirm Password</td>
|
||||
<td><input type="password" id="confirm_pwd" name="confirm_pwd"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="modal-footer">
|
||||
<input type="button" class="btn-modern" style="background-color: #64748b;" value="Cancel" onclick="closeAccountModal()">
|
||||
<input type="submit" class="btn-modern" value="Save Changes">
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function toggleSidebar(){
|
||||
document.querySelector('.app-sidebar').classList.toggle('sidebar-open');
|
||||
document.querySelector('.sidebar-overlay').classList.toggle('active');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Executable
BIN
Binary file not shown.
@@ -0,0 +1,2 @@
|
||||
anywavecom:anywavecom
|
||||
|
||||
Executable
+162
@@ -0,0 +1,162 @@
|
||||
#!/bin/sh
|
||||
### Auther : F
|
||||
### Date : 2021-12-7
|
||||
### Function: Start anywave work
|
||||
echo " "
|
||||
echo " "
|
||||
echo "--------------------------------"
|
||||
echo " ... HELLO , ANYWAVE ... "
|
||||
echo "--------------------------------"
|
||||
echo " "
|
||||
echo " "
|
||||
|
||||
setnetmac.sh
|
||||
|
||||
ifconfig eth0 192.168.1.143
|
||||
ifconfig eth1 192.168.2.143
|
||||
route add default gw 192.168.1.1
|
||||
|
||||
echo "clk prepare..."
|
||||
sleep 5
|
||||
echo "clk rdy"
|
||||
|
||||
init_ad9528_reset_gpio.sh
|
||||
imx_cfgad9528
|
||||
|
||||
mkdir -p /aw/anywave/dpd_log
|
||||
|
||||
### Path for web upgrade
|
||||
mkdir -p /aw/upgrade
|
||||
mkdir -p /aw/tmp
|
||||
mkdir -p /aw/anywave/cfg
|
||||
mkdir -p /aw/anywave/cfg/bkp
|
||||
mkdir -p /aw/anywave/dpd_curve
|
||||
mkdir -p /aw/anywave/lib
|
||||
mkdir -p /aw/log
|
||||
mkdir -p /etc/logrotate.d/
|
||||
echo "== web start =="
|
||||
cd /aw/anywave/web/sh && ./start_web.sh
|
||||
|
||||
MODULE_LOG_PATH=/var/module_log/
|
||||
mkdir -p $MODULE_LOG_PATH
|
||||
|
||||
echo 10 > /sys/class/gpio/export
|
||||
echo 11 > /sys/class/gpio/export
|
||||
echo 12 > /sys/class/gpio/export
|
||||
echo 13 > /sys/class/gpio/export
|
||||
echo 14 > /sys/class/gpio/export
|
||||
echo 15 > /sys/class/gpio/export
|
||||
insmod /aw/anywave/lib/key-bsp.ko
|
||||
|
||||
#logconf
|
||||
LOG_CONF_FILE=/etc/logrotate.d/log.conf
|
||||
rm -f $LOG_CONF_FILE
|
||||
set_log_conf()
|
||||
{
|
||||
echo "$1$2{
|
||||
$3
|
||||
daily
|
||||
rotate 3
|
||||
size 1K
|
||||
dateext
|
||||
extension .log
|
||||
compress
|
||||
notifempty
|
||||
sharedscripts
|
||||
create 644 root root
|
||||
sharedscripts
|
||||
postrotate
|
||||
$4
|
||||
endscript
|
||||
}
|
||||
" >> $LOG_CONF_FILE
|
||||
}
|
||||
|
||||
start_and_log()
|
||||
{
|
||||
if [ $# -lt 4 ];then
|
||||
echo 'Usage:start_and_log command_path command_with_param log_path log_name enable_output &'
|
||||
echo "For example:"
|
||||
echo "start_and_log /app ./app /var/module_log/ app.log 0 &"
|
||||
echo "or start_and_log /app ./app /var/module_log/ app.log 1 &"
|
||||
return 1
|
||||
fi
|
||||
set_log_conf $3 $4
|
||||
cd $1 && $2 2>&1 | loglog $3 $4 $5 $6
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
set_longlog_conf()
|
||||
{
|
||||
echo "$1$2{
|
||||
$3
|
||||
daily
|
||||
rotate 3
|
||||
size 500K
|
||||
dateext
|
||||
extension .log
|
||||
compress
|
||||
notifempty
|
||||
create 644 root root
|
||||
sharedscripts
|
||||
postrotate
|
||||
$4
|
||||
endscript
|
||||
}
|
||||
" >> $LOG_CONF_FILE
|
||||
}
|
||||
start_and_longlog()
|
||||
{
|
||||
if [ $# -lt 4 ];then
|
||||
echo 'Usage:start_and_longlog command_path command_with_param log_path log_name enable_output &'
|
||||
echo "For example:"
|
||||
echo "start_and_longlog /app ./app /var/module_log/ app.log 0 &"
|
||||
echo "or start_and_longlog /app ./app /var/module_log/ app.log 1 &"
|
||||
return 1
|
||||
fi
|
||||
set_longlog_conf $3 $4
|
||||
cd $1 && $2 2>&1 | loglog $3 $4 $5 $6
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
echo "== app start =="
|
||||
#cd /aw/anywave/app/ && ./imx_atsc_app&
|
||||
start_and_log /aw/anywave/app ./imx_atsc_app $MODULE_LOG_PATH imx_atsc_app.log 1 &
|
||||
|
||||
echo "== daemon_system start =="
|
||||
#daemon_system
|
||||
start_and_longlog /usr/sbin daemon_system $MODULE_LOG_PATH daemon_system.log 1 &
|
||||
|
||||
echo " "
|
||||
echo "== start finished =="
|
||||
echo " "
|
||||
|
||||
|
||||
#----------daemon_app-------------
|
||||
#ProcNumber=`ps -ef |grep -w daemon_app|grep -v grep|wc -l`
|
||||
#if [ $ProcNumber -le 0 ];then
|
||||
#/usr/sbin/daemon_app &
|
||||
#echo "daemon_app first run"
|
||||
#else
|
||||
#echo "daemon_app have been run"
|
||||
#fi
|
||||
|
||||
|
||||
start_and_longlog /usr/sbin logrotateStart $MODULE_LOG_PATH logrotateStart.log 0 &
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Executable
+87
@@ -0,0 +1,87 @@
|
||||
#!/bin/bash
|
||||
|
||||
## ------------------------------
|
||||
# function :
|
||||
# a. check package *.tar.gz in current dir
|
||||
# b. check package extract tar return value of ret
|
||||
# c. check package runme.sh
|
||||
## ------------------------------
|
||||
# return :
|
||||
## 0 ok
|
||||
## 2 Wrong package
|
||||
## 3 Wrong file extension
|
||||
## ------------------------------
|
||||
|
||||
|
||||
#-- This path has been defined in upload.cgi ,so if want to chang this path, you should chang upload.c .
|
||||
TAR_PACKAGE_PATH="/aw/upgrade"
|
||||
UPGRADE_FILE_PATH="/tmp/upgrade"
|
||||
PROJ_NAME="EMV"
|
||||
|
||||
|
||||
if [ -d ${UPGRADE_FILE_PATH} ] ; then
|
||||
rm -rf ${UPGRADE_FILE_PATH}
|
||||
fi
|
||||
mkdir -p ${UPGRADE_FILE_PATH}
|
||||
|
||||
|
||||
check_tar=`find ${TAR_PACKAGE_PATH} -name '*.tar.gz'`
|
||||
ret=0
|
||||
|
||||
|
||||
if [ -z ${check_tar} ];then # 字符串长度为0
|
||||
let ret=3
|
||||
else
|
||||
cd ${TAR_PACKAGE_PATH} && ls *.tar.gz > list.txt
|
||||
|
||||
for TAR in `cat list.txt`
|
||||
do
|
||||
FILE_NAME=${TAR%.*.*}
|
||||
###echo "file name :${FILE_NAME}"
|
||||
###echo "tar -zxf $TAR -C ${UPGRADE_FILE_PATH}/"
|
||||
|
||||
tar -zxf $TAR -C ${UPGRADE_FILE_PATH}/
|
||||
|
||||
extract_tar_ret=$?
|
||||
|
||||
if [ ${extract_tar_ret} != "0" ];then
|
||||
let ret=2
|
||||
else
|
||||
let ret=0
|
||||
fi
|
||||
###echo "extract_tar_pg = ${ret}"
|
||||
done
|
||||
|
||||
rm -rf ${TAR_PACKAGE_PATH}/list.txt
|
||||
rm -rf ${TAR_PACKAGE_PATH}/*.tar.gz
|
||||
|
||||
###echo "ret = ${ret}"
|
||||
if [ ${ret} -eq 0 ];then
|
||||
# check package has runme.sh xxx_cp.sh xxx_remove.sh .
|
||||
# path = /dt_update/aics*/
|
||||
cd ${UPGRADE_FILE_PATH}/${PROJ_NAME}*
|
||||
if [ -f "runme.sh" ];then
|
||||
###echo "runme.sh ok"
|
||||
let ret=0
|
||||
else
|
||||
###echo "no runme.sh "
|
||||
let ret=2
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
if [ ${ret} -ne 0 ];then
|
||||
#echo "rm -rf ./package/*"
|
||||
rm ${TAR_PACKAGE_PATH}/* -rf
|
||||
sync
|
||||
fi
|
||||
|
||||
echo ${ret}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Executable
+6
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
UPGRADE_FILE_PATH="/tmp/upgrade"
|
||||
|
||||
cd ${UPGRADE_FILE_PATH}/EMV* && ./runme.sh
|
||||
|
||||
Executable
+4
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
cp -v -rf /aw/anywave/cfg/exc_cfg_bkp.conf /aw/anywave/cfg/exc_cfg_bbkkpp.conf
|
||||
cp -v -rf /aw/anywave/cfg/bkp/exc_cfg_bkp.conf /aw/anywave/cfg/exc_cfg.conf
|
||||
sync
|
||||
Executable
+1
@@ -0,0 +1 @@
|
||||
7_260722_125
|
||||
Executable
+5
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
cp -v -rf /aw/anywave/cfg/bkp/exc_cfg_bkp.conf /aw/anywave/cfg/bkp/exc_cfg_bkp_bbkkpp.conf
|
||||
rm -rf /aw/anywave/cfg/bkp/exc_cfg_bkp.conf
|
||||
cp -v -rf /aw/anywave/cfg/exc_cfg.conf /aw/anywave/cfg/bkp/exc_cfg_bkp.conf
|
||||
sync
|
||||
@@ -0,0 +1,24 @@
|
||||
# see "man logrotate" for details
|
||||
# rotate log files weekly
|
||||
daily
|
||||
|
||||
# keep 4 weeks worth of backlogs
|
||||
rotate 3
|
||||
|
||||
# create new (empty) log files after rotating old ones
|
||||
create
|
||||
|
||||
# use date as a suffix of the rotated file
|
||||
dateext
|
||||
|
||||
# uncomment this if you want your log files compressed
|
||||
compress
|
||||
|
||||
|
||||
# RPM packages drop log rotation information into this directory
|
||||
include /etc/logrotate.d
|
||||
|
||||
# no packages own wtmp and btmp -- we'll rotate them here
|
||||
|
||||
|
||||
# system-specific logs may be also be configured here.
|
||||
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Executable
BIN
Binary file not shown.
Binary file not shown.
Executable
BIN
Binary file not shown.
Reference in New Issue
Block a user