Files
quectel-rgmii-toolkit/simpleadmin/www/network.html
Cameron Thompson 3ab9751fef Revert "Update network.html"
This reverts commit 21affeb5e4.
2024-05-04 13:19:27 -04:00

931 lines
32 KiB
HTML

<!DOCTYPE html>
<html lang="en" data-bs-theme="light">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Simple Admin</title>
<!-- <link
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
crossorigin="anonymous"
/> -->
<!-- Import all the bootstrap css files from css folder -->
<link rel="stylesheet" href="css/styles.css" />
<link rel="stylesheet" href="css/bootstrap.min.css" />
<!-- Import BootStrap Javascript -->
<script src="js/bootstrap.bundle.min.js"></script>
<script src="js/alpinejs.min.js" defer></script>
</head>
<body>
<main>
<div class="container my-4" x-data="cellLocking()">
<nav class="navbar navbar-expand-lg mt-2">
<div class="container-fluid">
<a class="navbar-brand" href="/"
><span class="mb-0 h4">Simple Admin</span></a
>
<button
class="navbar-toggler"
type="button"
data-bs-toggle="collapse"
data-bs-target="#navbarText"
aria-controls="navbarText"
aria-expanded="false"
aria-label="Toggle navigation"
>
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarText">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link" href="/">Home</a>
</li>
<li class="nav-item">
<a class="nav-link active" href="network.html" aria-current="page">Simple Network</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/settings.html">Simple Settings</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/sms.html">SMS</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/console">Console</a>
</li>
<li class="nav-item">
<a class="nav-link" href="deviceinfo.html">Device Information</a>
</li>
</ul>
<span class="navbar-text">
<button class="btn btn-link text-reset" id="darkModeToggle">Dark Mode</button>
</span>
<span class="navbar-text">
<button class="btn btn-link" href="logout.html">Log Out</button>
</span>
</div>
</div>
</nav>
<div class="row mt-5 gap-3">
<div class="col">
<div class="card">
<div class="card-header">
<div class="row align-items-center">
<div class="col">Band Locking</div>
<div class="col-md-3">
<select
class="form-select"
id="networkModeBand"
aria-label="LTE"
>
<option selected value="LTE">LTE</option>
<option value="NSA">NR5G-NSA</option>
<option value="SA">NR5G-SA</option>
</select>
</div>
</div>
</div>
<div class="card-body">
<h5 class="card-subtitle" x-show="isLoading">
Fetching supported bands...
</h5>
<form id="checkboxForm" x-show="isLoading === false">
<!-- Checkboxes will be populated here -->
</form>
</div>
<div class="card-footer">
<div class="d-flex align-items-center">
<div class="col">
<button
type="button"
class="btn btn-primary m-2"
@click="lockSelectedBands()"
>
Lock Bands
</button>
<button
type="button"
class="btn btn-info m-2"
id="uncheckAll"
>
Uncheck All
</button>
<button
type="button"
class="btn btn-danger m-2"
@click="resetBandLocking()"
>
Reset
</button>
</div>
</div>
</div>
<div class="card-footer">
<p x-text="'Active bands: ' + bands"></p>
</div>
</div>
</div>
</div>
<div class="row gap-3 mt-4">
<div class="col">
<form>
<div class="card">
<div class="card-header">Network Utilities</div>
<div class="card-body row">
<div class="col">
<div class="mb-4">
<label for="APN" class="form-label">APN</label>
<input
type="text"
class="form-control"
id="APN"
x-model="newApn"
aria-describedby="APN"
x-bind:placeholder="apn === '-' ? 'Fetching...' : apn"
/>
</div>
<div class="mb-4 input-group grid gap-3">
<label for="SIM1" class="form-label"> Change SIM</label>
<div class="form-check form-check-inline">
<input
class="form-check-input"
type="radio"
name="inlineRadioOptions"
aria-describedby="SIM1"
id="SIM1"
value="option1"
x-bind:checked="sim === '1'"
x-on:click="newSim = '1'"
/>
<label class="form-check-label" for="inlineRadio1"
>1</label
>
</div>
<div class="form-check form-check-inline">
<input
class="form-check-input"
type="radio"
name="inlineRadioOptions"
aria-describedby="SIM2"
id="SIM2"
value="option2"
x-bind:checked="sim === '2'"
x-on:click="newSim = '2'"
/>
<label class="form-check-label" for="inlineRadio2"
>2</label
>
</div>
</div>
</div>
<div class="col">
<div class="mb-4">
<label for="nrModeControl" class="form-label"
>Select Preferred Network</label
>
<select
class="form-select"
id="prefNetworkMode"
x-model="prefNetworkMode"
aria-label="prefNetworkMode"
>
<option
selected
x-text="prefNetwork === '-' ? 'Fetching...' : 'Current: ' + prefNetwork"
></option>
<option value="AUTO">AUTO</option>
<option value="LTE">LTE Only</option>
<option value="LTE:NR5G">NR5G-NSA</option>
<option value="NR5G">NR5G-SA</option>
</select>
</div>
<div class="mb-4">
<label for="prefNetwork" class="form-label"
>NR5G Mode Control</label
>
<select
class="form-select"
id="nrModeControl"
x-model="nrModeControl"
aria-label="nrModeControl"
>
<option
selected
x-text="nrModeControl === '-' ? 'Fetching...' : 'Current: ' + nrModeControl"
></option>
<option value="0">Enable All</option>
<option value="2">Disable NR5G-NSA</option>
<option value="1">Disable NR5G-SA</option>
</select>
</div>
</div>
</div>
<div class="card-footer">
<button
type="button"
class="btn btn-primary"
@click="saveChanges()"
>
Save Changes
</button>
</div>
</div>
</form>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-header">Cell Locking</div>
<div class="card-body">
<select
class="form-select"
id="networkModeCell"
x-model="networkModeCell"
aria-label="LTE"
>
<option
selected
x-text="'Cell Lock: ' + cellLockStatus"
></option>
<option>LTE</option>
<option>NR5G-SA</option>
<option>Unlock LTE</option>
<option>Unlock NR5G-SA</option>
</select>
<div class="my-4">
<!-- For LTE -->
<div id="lteElementsCell" x-show="networkModeCell == 'LTE'">
<div class="input-group mb-3">
<span class="input-group-text" id="basic-addon1"
>Num Cells</span
>
<input
type="number"
class="form-control"
placeholder="1-10"
min="1"
max="10"
aria-label="NumCells"
aria-describedby="basic-addon1"
x-model="cellNum"
/>
</div>
</div>
<div id="freqNumbersContainer">
<!-- Generate EARFCN and PCI here -->
</div>
<!-- For SA -->
<div
id="saElementsCell"
x-show="networkModeCell == 'NR5G-SA'"
>
<div
class="input-group mb-3"
x-show="networkModeCell == 'NR5G-SA'"
>
<input
type="text"
aria-label="EARFCN"
placeholder="EARFCN"
class="form-control"
x-model="earfcn1"
/>
<input
type="text"
aria-label="PCI"
placeholder="PCI"
class="form-control"
x-model="pci1"
/>
</div>
<div
class="input-group mb-3"
x-show="networkModeCell == 'NR5G-SA'"
>
<select
class="form-select"
x-model="scs"
aria-label="SCS"
>
<option selected>SCS</option>
<option>15</option>
<option>30</option>
<option>60</option>
<option>120</option>
<option>240</option>
</select>
<input
type="text"
aria-label="band"
placeholder="Band"
class="form-control"
x-model="band"
/>
</div>
</div>
<button
type="button"
class="btn btn-primary"
x-show="networkModeCell == 'LTE'"
@click="cellLockEnableLTE()"
>
Lock LTE Cells
</button>
<button
type="button"
class="btn btn-primary"
x-show="networkModeCell == 'NR5G-SA'"
@click="cellLockEnableNR()"
>
Lock NR5G-SA Cells
</button>
<button
type="button"
class="btn btn-danger"
x-show="networkModeCell == 'Unlock LTE'"
@click="cellLockDisableLTE()"
>
Unlock LTE Cells
</button>
<button
type="button"
class="btn btn-danger"
x-show="networkModeCell == 'Unlock NR5G-SA'"
@click="cellLockDisableNR()"
>
Unlock NR5G-SA Cells
</button>
</div>
</div>
</div>
</div>
</div>
<!-- Loading Modal for Locking Band -->
<div class="modal-overlay" x-show="showModal">
<div class="loading-modal">
<div class="loader"></div>
<div
class="loading-text"
style="display: flex; flex-direction: column"
>
<h3>Initializing Network...</h3>
<p style="margin-top: 0.5rem">
Please wait for
<span x-text="countdown" style="font-weight: 500"></span>
seconds.
</p>
</div>
</div>
</div>
</div>
</main>
<!-- Import Band Locking GUI JS -->
<!-- <script src="js/band-locking.js"></script> -->
<script src="js/generate-freq-box.js"></script>
<script src="js/populate-checkbox.js"></script>
<script src="js/parse-settings.js"></script>
<script>
function requestATInfo(atcmd) {
return fetch(
"/cgi-bin/get_atcommand?" +
new URLSearchParams({
atcmd: atcmd,
})
)
.then((response) => response.text())
.then((data) => {
return data;
})
.catch((error) => {
console.error("Error:", error);
// Throw the error again to ensure it's propagated
throw error;
});
}
function getSupportedBands() {
const atcmd = 'AT+QNWPREFCFG="policy_band"';
return requestATInfo(atcmd).then((rawdata) => {
let { lte_bands, nsa_bands, sa_bands } = parseSupportedBands(rawdata);
return {
lte_bands: lte_bands,
nsa_bands: nsa_bands,
sa_bands: sa_bands,
};
});
}
function parseSupportedBands(rawdata) {
const data = rawdata;
const regex = /"([^"]+)",([0-9:]+)/g;
// Object to store the results
const bands = {};
let match;
while ((match = regex.exec(data)) !== null) {
const bandType = match[1];
const numbers = match[2].split(":").map(Number);
bands[bandType] = numbers;
}
// Seperate the bands for each network mode
const lte_bands = bands.lte_band.join(":");
const nsa_bands = bands.nsa_nr5g_band.join(":");
const sa_bands = bands.nr5g_band.join(":");
return {
lte_bands,
nsa_bands,
sa_bands,
};
}
function parseLockedBands(rawdata) {
const data = rawdata;
const regex = /"([^"]+)",([0-9:]+)/g;
// Object to store the results
const bands = {};
let match;
while ((match = regex.exec(data)) !== null) {
const bandType = match[1];
const numbers = match[2].split(":").map(Number);
bands[bandType] = numbers;
}
// Seperate the bands for each network mode
const locked_lte_bands = bands.lte_band.join(":");
const locked_nsa_bands = bands.nsa_nr5g_band.join(":");
const locked_sa_bands = bands.nr5g_band.join(":");
return {
locked_lte_bands,
locked_nsa_bands,
locked_sa_bands,
};
}
function getLockedBands() {
const atcmd =
'AT+QNWPREFCFG="lte_band";+QNWPREFCFG= "nsa_nr5g_band";+QNWPREFCFG= "nr5g_band"';
return requestATInfo(atcmd).then((rawdata) => {
const lockedBandsData = parseLockedBands(rawdata);
return lockedBandsData;
});
}
function getCurrentSettings() {
const atcmd =
'AT+QUIMSLOT?;+CGCONTRDP=1;+QNWLOCK="common/4g";+QNWLOCK="common/5g";+QNWPREFCFG="mode_pref";+QNWPREFCFG="nr5g_disable_mode";+QCAINFO';
return requestATInfo(atcmd).then((rawdata) => {
const settings = parseCurrentSettings(rawdata);
return {
sim: settings.sim,
apn: settings.apn,
cellLockStatus: settings.cellLockStatus,
prefNetwork: settings.prefNetwork,
nrModeControl: settings.nrModeControl,
bands: settings.bands,
};
});
}
function cellLocking() {
return {
isLoading: false,
showModal: false,
countdown: 0,
networkModeCell: "-",
earfcn1: null,
pci1: null,
earfcn2: null,
pci2: null,
earfcn3: null,
pci3: null,
earfcn4: null,
pci4: null,
earfcn5: null,
pci5: null,
earfcn6: null,
pci6: null,
earfcn7: null,
pci7: null,
earfcn8: null,
pci8: null,
earfcn9: null,
pci9: null,
earfcn10: null,
pci10: null,
scs: null,
band: null,
apn: "-",
newApn: null,
prefNetwork: "-",
prefNetworkMode: null,
nrModeControl: "-",
cellNum: null,
lte_bands: null,
nsa_bands: null,
sa_bands: null,
locked_lte_bands: null,
locked_nsa_bands: null,
locked_sa_bands: null,
currentNetworkMode: "-",
updatedLockedBands: null,
sim: "-",
newSim: null,
cellLockStatus: null,
bands: "Fetching Bands...",
init() {
// Function to populate checkboxes
const showPopulateCheckboxes = () => {
this.isLoading = true;
Promise.all([getSupportedBands(), getLockedBands()])
.then(([supportedBandsData, lockedBandsData]) => {
this.lte_bands = supportedBandsData.lte_bands;
this.nsa_bands = supportedBandsData.nsa_bands;
this.sa_bands = supportedBandsData.sa_bands;
this.locked_lte_bands = lockedBandsData.locked_lte_bands;
this.locked_nsa_bands = lockedBandsData.locked_nsa_bands;
this.locked_sa_bands = lockedBandsData.locked_sa_bands;
// Once both promises are resolved, call populateCheckboxes
populateCheckboxes(
this.lte_bands,
this.nsa_bands,
this.sa_bands,
this.locked_lte_bands,
this.locked_nsa_bands,
this.locked_sa_bands,
this
);
// Set isLoading to false after populating checkboxes
this.isLoading = false;
// Add event listeners to checkboxes after populating them
addCheckboxListeners(this);
})
.catch((error) => {
console.error("Error:", error);
// Handle errors if any
});
};
// Function to track checkbox changes
this.trackCheckboxChanges = () => {
var selectedMode =
document.getElementById("networkModeBand").value;
var checkboxes = document.querySelectorAll(
'input[type="checkbox"]'
);
var newCheckedValues = [];
checkboxes.forEach(function (checkbox) {
if (checkbox.checked) {
newCheckedValues.push(checkbox.value);
}
});
// Update currentNetworkMode and updatedLockedBands
this.currentNetworkMode = selectedMode;
this.updatedLockedBands = newCheckedValues;
};
// Function to get the current settings
const getCurrentSettingsData = () => {
getCurrentSettings().then((settings) => {
this.sim = settings.sim;
this.apn = settings.apn;
this.cellLockStatus = settings.cellLockStatus;
this.prefNetwork = settings.prefNetwork;
this.nrModeControl = settings.nrModeControl;
this.bands = settings.bands;
});
};
// Function to add event listener to network mode dropdown
const addNetworkModeListener = () => {
document
.getElementById("networkModeBand")
.addEventListener("change", function () {
showPopulateCheckboxes(); // Update checkboxes when network mode changes
});
};
// Execute necessary functions on initialization
showPopulateCheckboxes();
addNetworkModeListener();
getCurrentSettingsData();
},
lockSelectedBands() {
// Get the updated this.currentNetworkMode = selectedMode; and this.updatedLockedBands = newCheckedValues;
const selectedMode = this.currentNetworkMode;
const newCheckedValues = this.updatedLockedBands;
let atcmd;
// Check if both values are null then show the error message
if (selectedMode === null || newCheckedValues === null) {
} else {
if (selectedMode === "LTE") {
atcmd = `AT+QNWPREFCFG="lte_band",${newCheckedValues.join(
":"
)}`;
this.sendATcommand(atcmd);
} else if (selectedMode === "NSA") {
atcmd = `AT+QNWPREFCFG="nsa_nr5g_band",${newCheckedValues.join(
":"
)}`;
this.sendATcommand(atcmd);
} else if (selectedMode === "SA") {
atcmd = `AT+QNWPREFCFG="nr5g_band",${newCheckedValues.join(
":"
)}`;
this.sendATcommand(atcmd);
} else {
alert("Invalid network mode selected");
}
// Do a 5 second countdown
this.showModal = true;
this.countdown = 5;
const interval = setInterval(() => {
this.countdown--;
if (this.countdown === 0) {
clearInterval(interval);
this.showModal = false;
// Refresh the page to show the updated bands
this.init();
}
}, 1000);
}
},
resetBandLocking() {
// Send the atcmd command to reset the locked bands
const atcmd = 'AT+QNWPREFCFG="restore_band"';
this.showModal = true;
this.sendATcommand(atcmd);
this.countdown = 5;
const interval = setInterval(() => {
this.countdown--;
if (this.countdown === 0) {
clearInterval(interval);
this.showModal = false;
// Refresh the page to show the updated bands
this.init();
}
}, 1000);
// Run init function to repopulate the checkboxes
this.init();
},
saveChanges() {
const newApn = this.newApn;
const newSim = this.newSim;
const prefNetworkMode = this.prefNetworkMode;
const nrModeControl = this.nrModeControl;
let atAPN, atSIM, ATNetwork, ATNRMode, atcmd;
atAPN = "";
atSIM = "";
ATNetwork = "";
ATNRMode = "";
if (newApn !== null) {
atAPN = `+CGDCONT=1,"IP","${newApn}";`;
}
if (newSim !== null) {
atSIM = `+QUIMSLOT=${newSim};`;
}
if (prefNetworkMode !== null) {
ATNetwork = `+QNWPREFCFG="mode_pref",${prefNetworkMode};`;
}
if (nrModeControl !== this.nrModeControl) {
ATNRMode = `+QNWPREFCFG="nr5g_disable_mode",${nrModeControl}`;
}
atcmd = `AT+${atAPN}${atSIM}${ATNetwork}${ATNRMode}`;
// If there is double + (++), remove 1 + from the command
atcmd = atcmd.replace("++", "+");
if (atcmd !== "AT+") {
this.showModal = true;
console.log(atcmd);
this.sendATcommand(atcmd);
// Do a 15 second countdown
this.countdown = 15;
const interval = setInterval(() => {
this.countdown--;
if (this.countdown === 0) {
clearInterval(interval);
this.showModal = false;
this.init();
}
}, 1000);
} else {
alert("No changes made");
}
},
cellLockEnableLTE() {
const cellNum = this.cellNum;
if (cellNum === null) {
alert("Please enter the number of cells to lock");
return; // Exit the function early if cellNum is null
}
// Create an array to hold earfcn and pci pairs
const earfcnPciPairs = [
{ earfcn: this.earfcn1, pci: this.pci1 },
{ earfcn: this.earfcn2, pci: this.pci2 },
{ earfcn: this.earfcn3, pci: this.pci3 },
{ earfcn: this.earfcn4, pci: this.pci4 },
{ earfcn: this.earfcn5, pci: this.pci5 },
{ earfcn: this.earfcn6, pci: this.pci6 },
{ earfcn: this.earfcn7, pci: this.pci7 },
{ earfcn: this.earfcn8, pci: this.pci8 },
{ earfcn: this.earfcn9, pci: this.pci9 },
{ earfcn: this.earfcn10, pci: this.pci10 },
];
// Filter out pairs where either earfcn or pci is null
const validPairs = earfcnPciPairs.filter(
(pair) => pair.earfcn !== null && pair.pci !== null
);
if (validPairs.length === 0) {
alert("Please enter at least one valid earfcn and pci pair");
return; // Exit the function early if no valid pairs are found
}
// Construct the AT command using the valid pairs
let atcmd = `+QNWLOCK="common/4g",${cellNum},${validPairs
.map((pair) => `${pair.earfcn},${pair.pci}`)
.join(",")}`;
atcmd = "AT+CFUN=0;" + atcmd + ";+CFUN=1";
// Mock data
this.showModal = true;
this.sendATcommand(atcmd);
// Do a 15 second countdown
this.countdown = 15;
const interval = setInterval(() => {
this.countdown--;
if (this.countdown === 0) {
clearInterval(interval);
this.showModal = false;
}
}, 1000);
},
cellLockEnableNR() {
const earfcn = this.earfcn1;
const pci = this.pci1;
const scs = this.scs;
const band = this.band;
if (
earfcn === null ||
pci === null ||
scs === null ||
band === null
) {
alert("Please enter all the required fields");
return; // Exit the function early if any of the fields are null
}
// Construct the AT command using the valid pairs
let atcmd = `+QNWLOCK="common/5g",${earfcn},${pci},${scs},${band}`;
atcmd = "AT+CFUN=0;" + atcmd + ";+CFUN=1";
// Mock data
this.showModal = true;
this.sendATcommand(atcmd);
// Do a 15 second countdown
this.countdown = 15;
const interval = setInterval(() => {
this.countdown--;
if (this.countdown === 0) {
clearInterval(interval);
this.showModal = false;
}
}, 1000);
},
cellLockDisableLTE() {
// Send the atcmd command to reset the locked bands
const atcmd = 'AT+CFUN=0;+QNWLOCK="common/4g,0;+CFUN=1"';
this.showModal = true;
this.sendATcommand(atcmd);
this.countdown = 15;
const interval = setInterval(() => {
this.countdown--;
if (this.countdown === 0) {
clearInterval(interval);
this.showModal = false;
}
}, 1000);
},
cellLockDisableNR() {
// Send the atcmd command to reset the locked bands
const atcmd = 'AT+CFUN=0;+QNWLOCK="common/5g,0;+CFUN=1"';
this.showModal = true;
this.sendATcommand(atcmd);
this.countdown = 15;
const interval = setInterval(() => {
this.countdown--;
if (this.countdown === 0) {
clearInterval(interval);
this.showModal = false;
}
}, 1000);
},
sendATcommand(atcmd) {
return fetch(
"/cgi-bin/get_atcommand?" +
new URLSearchParams({
atcmd: atcmd,
})
)
.then((response) => response.text())
.then((data) => {
return data;
})
.catch((error) => {
console.error("Error:", error);
// Throw the error again to ensure it's propagated
throw error;
});
},
};
}
function addCheckboxListeners(cellLock) {
// Remove existing event listeners
document
.querySelectorAll('input[type="checkbox"]')
.forEach(function (checkbox) {
checkbox.removeEventListener(
"change",
cellLock.trackCheckboxChanges
);
});
// Add new event listeners
document
.querySelectorAll('input[type="checkbox"]')
.forEach(function (checkbox) {
checkbox.addEventListener("change", cellLock.trackCheckboxChanges);
});
}
// Function for unchecking all checkboxes
document
.getElementById("uncheckAll")
.addEventListener("click", function () {
document
.querySelectorAll('input[type="checkbox"]')
.forEach(function (checkbox) {
checkbox.checked = false;
});
});
</script>
<script src="/js/dark-mode.js"></script>
</body>
</html>