fixed apn and improved javascripts

This commit is contained in:
Russel Yasol
2024-10-04 06:02:21 +08:00
parent 46c1d92f90
commit 78c673ed4d
4 changed files with 492 additions and 440 deletions

View File

@@ -25,6 +25,7 @@
<script src="/js/utils/reboot.js"></script>
<script src="/js/utils/restart-connection.js"></script>
<script defer src="/js/auth/auth.js"></script>
<script src="/js/band-locking/fetch-bands.js"></script>
<script>
(function () {
@@ -140,7 +141,7 @@
<div class="column-margin">
<div class="fixed-grid has-2-cols has-1-cols-mobile">
<div class="grid is-gap-5">
<div class="cell">
<div class="cell is-col-span-2 is-col-span-1-mobile">
<div class="card">
<div class="card-header">
<div class="card-header-title">4G LTE Band Locking</div>
@@ -175,7 +176,7 @@
</div>
</div>
<div class="cell">
<!-- <div class="cell">
<div class="card">
<div class="card-header">
<div class="card-header-title">5G-NR SA Band Locking</div>
@@ -183,7 +184,6 @@
<div class="card-content">
<div class="fixed-grid has-5-cols has-3-cols-mobile">
<div class="grid" id="sa_bands">
<!-- SA bands will be populated here -->
</div>
</div>
</div>
@@ -208,7 +208,7 @@
</a>
</div>
</div>
</div>
</div> -->
<div class="cell">
<div class="card">
@@ -335,7 +335,7 @@
</section>
</div>
</div>
<script>
<!-- <script>
// Function to fetch current active bands and display them in the footer
async function fetchCurrentBands() {
try {
@@ -385,13 +385,13 @@
const lteBandsMatch = data.output.match(/"lte_band",([0-9:]+)/);
const nsaBandsMatch = data.output.match(/"nsa_nr5g_band",([0-9:]+)/);
const saBandsMatch = data.output.match(/"nr5g_band",([0-9:]+)/);
// const saBandsMatch = data.output.match(/"nr5g_band",([0-9:]+)/);
const saDcBandsMatch = data.output.match(
/"nrdc_nr5g_band",([0-9:]+)/
);
if (lteBandsMatch) populateBands(lteBandsMatch[1], "#lte_bands");
if (saBandsMatch) populateBands(saBandsMatch[1], "#sa_bands");
// if (saBandsMatch) populateBands(saBandsMatch[1], "#sa_bands");
if (nsaBandsMatch) populateBands(nsaBandsMatch[1], "#nsa_bands");
if (saDcBandsMatch) populateBands(saDcBandsMatch[1], "#sanrdc_bands");
@@ -429,9 +429,9 @@
const activeNsaBands = data.output
.match(/"nsa_nr5g_band",([0-9:]+)/)[1]
.split(":");
const activeSaBands = data.output
.match(/"nr5g_band",([0-9:]+)/)[1]
.split(":");
// const activeSaBands = data.output
// .match(/"nr5g_band",([0-9:]+)/)[1]
// .split(":");
// get the the second to the last line of the output and use it for active sa-dc bands
const activeSaDcBandsLine = data.output
.split("\n")[6]
@@ -441,7 +441,7 @@
// // Mark checkboxes as checked for active bands
markActiveBands(activeLteBands, "#lte_bands");
markActiveBands(activeNsaBands, "#nsa_bands");
markActiveBands(activeSaBands, "#sa_bands");
// markActiveBands(activeSaBands, "#sa_bands");
markActiveBands(activeSaDcBandsLine, "#sanrdc_bands");
// Fetch current active bands and display them in the footer
@@ -505,12 +505,12 @@
uncheckAll("#nsa_bands");
});
document
.getElementById("uncheckSa")
.addEventListener("click", function (event) {
event.preventDefault();
uncheckAll("#sa_bands");
});
// document
// .getElementById("uncheckSa")
// .addEventListener("click", function (event) {
// event.preventDefault();
// uncheckAll("#sa_bands");
// });
document
.getElementById("uncheckSaDc")
@@ -675,6 +675,6 @@
// Initial call to fetch supported bands on page load
window.onload = fetchSupportedBands;
</script>
</script> -->
</body>
</html>

View File

@@ -29,7 +29,7 @@ escape_json() {
JSON_RESPONSE="["
# List of AT commands to run, one by one
for COMMAND in "AT+QUIMSLOT?" "AT+CNUM" "AT+COPS?" "AT+CIMI" "AT+ICCID" "AT+CGSN" "AT+CPIN?" "AT+CGCONTRDP" "AT+CREG?" "AT+CFUN?" "AT+QENG=\"servingcell\"" "AT+QTEMP" "AT+CGCONTRDP" "AT+QCAINFO" "AT+QRSRP" 'AT+QMAP="WWAN"'; do
for COMMAND in "AT+QUIMSLOT?" "AT+CNUM" "AT+COPS?" "AT+CIMI" "AT+ICCID" "AT+CGSN" "AT+CPIN?" "AT+CGCONTRDP=1" "AT+CREG?" "AT+CFUN?" "AT+QENG=\"servingcell\"" "AT+QTEMP" "AT+CGCONTRDP" "AT+QCAINFO" "AT+QRSRP" 'AT+QMAP="WWAN"'; do
# Write the command to the input file
echo "$COMMAND" > "$INPUT_FILE"

View File

@@ -1,461 +1,299 @@
async function fetchCurrentSettings() {
try {
const response = await fetch("/cgi-bin/advanced_settings.sh");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
// api.js - API related functions
const api = {
async fetch(endpoint, options = {}) {
try {
const response = await fetch(endpoint, options);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error(`API Error (${endpoint}):`, error);
return null;
}
const data = await response.json();
},
async fetchCurrentSettings() {
const data = await this.fetch("/cgi-bin/advanced_settings.sh");
console.log("Current settings:", data);
return data;
} catch (error) {
console.error("Error fetching current settings:", error);
return null;
}
}
},
async function fetchConnectedDevices() {
try {
const response = await fetch("/cgi-bin/fetch_macs.sh");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
console.log("Connected devices:", data);
async fetchConnectedDevices() {
const data = await this.fetch("/cgi-bin/fetch_macs.sh");
return data;
} catch (error) {
console.error("Error fetching connected devices:", error);
return null;
},
async sendATCommand(command) {
return await this.fetch("/cgi-bin/atinout_handler.sh", {
method: "POST",
body: "command=" + encodeURIComponent(command)
});
}
}
};
function populateConnectedDevices(devices) {
const selectElement = document.getElementById("connected-devices");
if (!selectElement) {
console.error("Connected devices select element not found");
return;
}
// uiManager.js - UI related functions
const uiManager = {
elements: {
ipPassthrough: () => document.getElementById("ip-passthrough-mode"),
dnsProxy: () => document.getElementById("dns-proxy-mode"),
usbModem: () => document.getElementById("usb-modem-protocol"),
connectedDevices: () => document.getElementById("connected-devices"),
loadingContent: () => document.getElementById("loading-content"),
modalButtons: () => document.getElementById("modal-buttons"),
countdown: () => document.getElementById("countdown"),
rebootModal: () => document.getElementById("reboot-modal"),
advancedSettingsIcons: () => document.querySelectorAll(".advanced-settings i")
},
// Clear existing options except the first one
while (selectElement.options.length > 1) {
selectElement.remove(1);
}
showLoadingSpinners() {
this.elements.advancedSettingsIcons().forEach(icon => {
icon.classList.add("fa-spinner", "fa-spin");
});
},
// Add new options
devices.forEach((device) => {
const option = document.createElement("option");
option.value = device.mac;
option.textContent = `${device.hostname} - ${device.mac}`;
selectElement.appendChild(option);
});
}
hideLoadingSpinners() {
this.elements.advancedSettingsIcons().forEach(icon => {
icon.classList.remove("fa-spinner", "fa-spin");
});
},
function updatePassthroughModeState(isEnabled) {
const ipPassthroughSelect = document.getElementById("ip-passthrough-mode");
if (!ipPassthroughSelect) return;
updatePassthroughModeState(isEnabled) {
const select = this.elements.ipPassthrough();
if (!select) return;
if (isEnabled) {
ipPassthroughSelect.removeAttribute("disabled");
ipPassthroughSelect.classList.remove("is-warning");
const helpText = ipPassthroughSelect.parentElement.querySelector(".help");
if (helpText) {
helpText.textContent = "Select a passthrough mode to apply.";
helpText.classList.remove("is-warning");
helpText.classList.add("is-info");
}
} else {
ipPassthroughSelect.setAttribute("disabled", "disabled");
ipPassthroughSelect.classList.add("is-warning");
ipPassthroughSelect.value = "Select IP Passthrough Mode";
const helpText = ipPassthroughSelect.parentElement.querySelector(".help");
if (helpText) {
helpText.textContent = "Please select a device first.";
helpText.classList.remove("is-info");
helpText.classList.add("is-warning");
}
}
}
function updateUIElements(data) {
// Get all required DOM elements
const elements = {
ipPassthrough: document.getElementById("ip-passthrough-mode"),
dnsProxy: document.getElementById("dns-proxy-mode"),
usbModem: document.getElementById("usb-modem-protocol"),
};
// Check if all elements exist
const missingElements = Object.entries(elements)
.filter(([key, element]) => !element)
.map(([key]) => key);
if (missingElements.length > 0) {
console.error("Missing DOM elements:", missingElements);
return false;
}
try {
// Initially disable IP Passthrough mode
updatePassthroughModeState(false);
// Passthrough Mode (will be disabled until device is selected)
const mpdnRuleLine = data[0].response.split("\n")[1];
if (mpdnRuleLine) {
const mpdnRule = mpdnRuleLine.split(":")[1].trim();
switch (mpdnRule) {
case '"MPDN_rule",0,0,0,0,0':
elements.ipPassthrough.value = "Disabled";
break;
case '"MPDN_rule",0,1,0,1,1':
elements.ipPassthrough.value = "ETH Only";
break;
case '"MPDN_rule",0,1,0,3,1':
elements.ipPassthrough.value = "USB Only";
break;
default:
elements.ipPassthrough.value = "Select IP Passthrough Mode";
break;
const helpText = select.parentElement.querySelector(".help");
if (isEnabled) {
select.removeAttribute("disabled");
select.classList.remove("is-warning");
if (helpText) {
helpText.textContent = "Select a passthrough mode to apply.";
helpText.classList.remove("is-warning");
helpText.classList.add("is-info");
}
} else {
select.setAttribute("disabled", "disabled");
select.classList.add("is-warning");
select.value = "Select IP Passthrough Mode";
if (helpText) {
helpText.textContent = "Please select a device first.";
helpText.classList.remove("is-info");
helpText.classList.add("is-warning");
}
}
},
// DNS Proxy
const dnsProxyLine = data[1].response
.split("\n")[1]
.split(":")[1]
.split(",")[1]
.trim();
if (dnsProxyLine) {
elements.dnsProxy.value =
dnsProxyLine === '"disable"' ? "Disabled" : "Enabled";
} else {
elements.dnsProxy.value = "Select Onboard DNS Proxy";
populateConnectedDevices(devices) {
const select = this.elements.connectedDevices();
if (!select) {
console.error("Connected devices select element not found");
return;
}
// USB Modem Protocol
const usbModemProtocolLine = data[2].response
.split("\n")[1]
.split(":")[1]
.split(",")[1]
.trim();
switch (usbModemProtocolLine) {
case "0":
elements.usbModem.value = "RMNET";
break;
case "1":
elements.usbModem.value = "ECM (Recommended)";
break;
case "2":
elements.usbModem.value = "MBIM";
break;
case "3":
elements.usbModem.value = "RNDIS";
break;
default:
elements.usbModem.value = "Select USB Modem Protocol";
break;
// Clear existing options except the first one
while (select.options.length > 1) {
select.remove(1);
}
return true;
} catch (error) {
console.error("Error updating UI elements:", error);
return false;
}
}
// Function to send an AT command based on the DNS proxy mode
async function sendDnsProxyCommand(command) {
try {
const response = await fetch("/cgi-bin/atinout_handler.sh", {
method: "POST",
body: "command=" + encodeURIComponent(command),
// Add new options
devices.forEach(device => {
const option = document.createElement("option");
option.value = device.mac;
option.textContent = `${device.hostname} - ${device.mac}`;
select.appendChild(option);
});
},
const data = await response.json();
console.log("DNS Proxy AT command executed:", data.output);
} catch (error) {
console.error("Error sending DNS Proxy AT command:", error);
showModal() {
const modal = this.elements.rebootModal();
if (modal) {
modal.classList.add("is-active");
}
},
showLoadingContent() {
this.elements.loadingContent().style.display = "flex";
this.elements.modalButtons().style.display = "none";
this.showModal();
},
startCountdown(duration) {
const countdownElement = this.elements.countdown();
let countdown = duration;
const interval = setInterval(() => {
countdown--;
countdownElement.textContent = countdown;
if (countdown <= 0) {
clearInterval(interval);
location.reload();
}
}, 1000);
}
}
};
// Function to handle DNS Proxy changes
function handleDnsProxyChange() {
const dnsProxySelect = document.getElementById("dns-proxy-mode");
const currentDnsProxyMode = dnsProxySelect.getAttribute("data-current-mode"); // Store current mode as a data attribute
// settingsManager.js - Settings management
const settingsManager = {
async updateSettings(data) {
const elements = {
ipPassthrough: uiManager.elements.ipPassthrough(),
dnsProxy: uiManager.elements.dnsProxy(),
usbModem: uiManager.elements.usbModem()
};
dnsProxySelect.addEventListener("change", function (e) {
// Validate required elements
const missingElements = Object.entries(elements)
.filter(([, element]) => !element)
.map(([key]) => key);
if (missingElements.length > 0) {
console.error("Missing DOM elements:", missingElements);
return false;
}
try {
uiManager.updatePassthroughModeState(false);
// Update IP Passthrough Mode
const mpdnRuleLine = data[0].response.split("\n")[1];
if (mpdnRuleLine) {
const mpdnRule = mpdnRuleLine.split(":")[1].trim();
elements.ipPassthrough.value = this.getPassthroughModeValue(mpdnRule);
}
// Update DNS Proxy
const dnsProxyLine = data[1].response.split("\n")[1].split(":")[1].split(",")[1].trim();
elements.dnsProxy.value = dnsProxyLine === '"disable"' ? "Disabled" : "Enabled";
// Update USB Modem Protocol
const usbModemProtocolLine = data[2].response.split("\n")[1].split(":")[1].split(",")[1].trim();
elements.usbModem.value = this.getUsbModemProtocolValue(usbModemProtocolLine);
return true;
} catch (error) {
console.error("Error updating settings:", error);
return false;
}
},
getPassthroughModeValue(mpdnRule) {
const modes = {
'"MPDN_rule",0,0,0,0,0': "Disabled",
'"MPDN_rule",0,1,0,1,1': "ETH Only",
'"MPDN_rule",0,1,0,3,1': "USB Only"
};
return modes[mpdnRule] || "Select IP Passthrough Mode";
},
getUsbModemProtocolValue(protocol) {
const protocols = {
"0": "RMNET",
"1": "ECM (Recommended)",
"2": "MBIM",
"3": "RNDIS"
};
return protocols[protocol] || "Select USB Modem Protocol";
}
};
// eventHandlers.js - Event handling
const eventHandlers = {
async handleDnsProxyChange(e) {
const selectedMode = e.target.value;
const currentMode = e.target.getAttribute("data-current-mode");
// Send AT command only if the selected mode differs from the current one
if (selectedMode !== currentDnsProxyMode) {
if (selectedMode === "Enabled") {
sendDnsProxyCommand('AT+QMAP="DHCPV4DNS","enable"');
} else if (selectedMode === "Disabled") {
sendDnsProxyCommand('AT+QMAP="DHCPV4DNS","disable"');
}
} else {
console.log("No changes made to DNS Proxy mode");
if (selectedMode !== currentMode) {
const command = selectedMode === "Enabled"
? 'AT+QMAP="DHCPV4DNS","enable"'
: 'AT+QMAP="DHCPV4DNS","disable"';
await api.sendATCommand(command);
}
});
}
},
// Function to send an AT command based on the IP Passthrough mode
async function sendIpPassthroughCommand(command) {
if (command) {
showLoadingContent(); // Show loading content and hide the buttons
startCountdown(80); // Start the countdown for 5 seconds
}
try {
const response = await fetch("/cgi-bin/atinout_handler.sh", {
method: "POST",
body: "command=" + encodeURIComponent(command),
});
const data = await response.json();
console.log("IP Passthrough AT command executed:", data.output);
} catch (error) {
console.error("Error sending IP Passthrough AT command:", error);
}
}
// Function to handle IP Passthrough mode changes
function handleIpPassthroughChange() {
// track if the device is selected by listening to the connected devices dropdown change event
const connectedDevicesSelect = document.getElementById("connected-devices");
if (connectedDevicesSelect) {
connectedDevicesSelect.addEventListener("change", function (e) {
const selectedMAC = e.target.value;
const selectedHostname = e.target.options[e.target.selectedIndex].text;
console.log("Selected device:", {
mac: selectedMAC,
hostname: selectedHostname,
});
// Enable/disable IP Passthrough mode based on selection
const isDeviceSelected = selectedMAC !== "Select Device MAC";
if (isDeviceSelected) {
updatePassthroughModeState(true);
} else {
updatePassthroughModeState(false);
}
});
}
const ipPassthroughSelect = document.getElementById("ip-passthrough-mode");
const currentIpPassthroughMode =
ipPassthroughSelect.getAttribute("data-current-mode"); // Store current mode as a data attribute
ipPassthroughSelect.addEventListener("change", function (e) {
async handleIpPassthroughChange(e) {
const selectedMode = e.target.value;
const selectedDeviceMAC =
document.getElementById("connected-devices").value;
const currentMode = e.target.getAttribute("data-current-mode");
const selectedDeviceMAC = uiManager.elements.connectedDevices().value;
// Send AT command only if the selected mode differs from the current one
if (selectedMode !== currentIpPassthroughMode) {
let command;
switch (selectedMode) {
case "Disabled":
command = 'AT+QMPDN="MPDN_rule",0;+CFUN=1,1';
break;
case "ETH Only":
command = `AT+QMPDN="MPDN_rule",0,1,0,1,1,"${selectedDeviceMAC}"`;
break;
case "USB Only":
command = `AT+QMPDN="MPDN_rule",0,1,0,3,1,"${selectedDeviceMAC}"`;
break;
default:
console.error("Invalid IP Passthrough mode:", selectedMode);
return;
if (selectedMode !== currentMode) {
const commands = {
"Disabled": 'AT+QMPDN="MPDN_rule",0;+CFUN=1,1',
"ETH Only": `AT+QMPDN="MPDN_rule",0,1,0,1,1,"${selectedDeviceMAC}"`,
"USB Only": `AT+QMPDN="MPDN_rule",0,1,0,3,1,"${selectedDeviceMAC}"`
};
const command = commands[selectedMode];
if (command) {
uiManager.showLoadingContent();
uiManager.startCountdown(80);
await api.sendATCommand(command);
}
sendIpPassthroughCommand(command);
} else {
console.log("No changes made to IP Passthrough mode");
}
});
}
},
// Function to send an AT command based on the USB Modem Protocol
async function sendUsbModemProtocolCommand(command) {
try {
if (command) {
showLoadingContent(); // Show loading content and hide the buttons
startCountdown(80); // Start the countdown for 5 seconds
}
const response = await fetch("/cgi-bin/atinout_handler.sh", {
method: "POST",
body: "command=" + encodeURIComponent(command),
});
const data = await response.json();
console.log("USB Modem Protocol AT command executed:", data.output);
} catch (error) {
console.error("Error sending USB Modem Protocol AT command:", error);
}
}
// Function to handle USB Modem Protocol changes
function handleUsbModemProtocolChange() {
const usbModemSelect = document.getElementById("usb-modem-protocol");
const currentUsbModemProtocol = usbModemSelect.getAttribute(
"data-current-protocol"
); // Store current protocol as a data attribute
usbModemSelect.addEventListener("change", function (e) {
async handleUsbModemProtocolChange(e) {
const selectedProtocol = e.target.value;
const currentProtocol = e.target.getAttribute("data-current-protocol");
// Send AT command only if the selected protocol differs from the current one
if (selectedProtocol !== currentUsbModemProtocol) {
let command;
switch (selectedProtocol) {
case "RMNET":
command = 'AT+QCFG="usbnet",0;+CFUN=1,1';
break;
case "ECM (Recommended)":
command = 'AT+QCFG="usbnet",1;+CFUN=1,1';
break;
case "MBIM":
command = 'AT+QCFG="usbnet",2;+CFUN=1,1';
break;
case "RNDIS":
command = 'AT+QCFG="usbnet",3;+CFUN=1,1';
break;
default:
console.error("Invalid USB Modem Protocol:", selectedProtocol);
return;
if (selectedProtocol !== currentProtocol) {
const commands = {
"RMNET": 'AT+QCFG="usbnet",0;+CFUN=1,1',
"ECM (Recommended)": 'AT+QCFG="usbnet",1;+CFUN=1,1',
"MBIM": 'AT+QCFG="usbnet",2;+CFUN=1,1',
"RNDIS": 'AT+QCFG="usbnet",3;+CFUN=1,1'
};
const command = commands[selectedProtocol];
if (command) {
uiManager.showLoadingContent();
uiManager.startCountdown(80);
await api.sendATCommand(command);
}
sendUsbModemProtocolCommand(command);
} else {
console.log("No changes made to USB Modem Protocol");
}
});
}
},
// Function to show the modal
function showModal() {
const modal = document.getElementById("reboot-modal");
if (modal) {
modal.classList.add("is-active"); // Bulma modals require "is-active" to be shown
handleDeviceSelection(e) {
const selectedMAC = e.target.value;
const selectedHostname = e.target.options[e.target.selectedIndex].text;
console.log("Selected device:", { mac: selectedMAC, hostname: selectedHostname });
const isDeviceSelected = selectedMAC !== "Select Device MAC";
uiManager.updatePassthroughModeState(isDeviceSelected);
}
};
// main.js - Application initialization
async function init() {
uiManager.showLoadingSpinners();
try {
const [settings, devices] = await Promise.all([
api.fetchCurrentSettings(),
api.fetchConnectedDevices()
]);
if (settings) {
const updateSuccess = await settingsManager.updateSettings(settings);
if (updateSuccess) {
uiManager.hideLoadingSpinners();
// Set up event listeners
uiManager.elements.dnsProxy().addEventListener("change", eventHandlers.handleDnsProxyChange);
uiManager.elements.ipPassthrough().addEventListener("change", eventHandlers.handleIpPassthroughChange);
uiManager.elements.usbModem().addEventListener("change", eventHandlers.handleUsbModemProtocolChange);
uiManager.elements.connectedDevices().addEventListener("change", eventHandlers.handleDeviceSelection);
}
}
if (devices) {
uiManager.populateConnectedDevices(devices);
}
} catch (error) {
console.error("Initialization error:", error);
}
}
// Function to show loading content and show the modal
function showLoadingContent() {
document.getElementById("loading-content").style.display = "flex"; // Show the loading section
document.getElementById("modal-buttons").style.display = "none"; // Hide the buttons
// Activate the modal
showModal();
}
// Function to start the countdown
function startCountdown(duration) {
let countdownElement = document.getElementById("countdown");
let countdown = duration;
let interval = setInterval(function () {
countdown--;
countdownElement.textContent = countdown;
if (countdown <= 0) {
clearInterval(interval);
// Add any additional logic after countdown reaches 0 (like reloading or closing the modal)
location.reload(); // Reload the page
}
}, 1000);
}
// Function for initializing the page
function init() {
// Replace all i elements under the class advanced-settings with a spinner icon initially
const advancedSettingsIcons = document.querySelectorAll(
".advanced-settings i"
);
advancedSettingsIcons.forEach((icon) => {
icon.classList.add("fa-spinner", "fa-spin");
});
Promise.all([fetchCurrentSettings(), fetchConnectedDevices()])
.then(([settings, devices]) => {
if (settings) {
const updateSuccess = updateUIElements(settings);
if (!updateSuccess) {
console.error("Failed to update UI elements");
} else {
// Revert the spinner icons back to their original state
advancedSettingsIcons.forEach((icon) => {
icon.classList.remove("fa-spinner", "fa-spin");
});
handleDnsProxyChange(); // Add event listener for DNS Proxy changes
handleUsbModemProtocolChange(); // Add event listener for USB Modem Protocol changes
handleIpPassthroughChange(); // Add event listener for IP Passthrough changes
}
} else {
console.error("Failed to fetch current settings");
}
if (devices) {
populateConnectedDevices(devices);
} else {
console.error("Failed to fetch connected devices");
}
})
.catch((error) => {
console.error("Error during initialization:", error);
});
}
// Initialize event listeners when DOM is ready
// document.addEventListener("DOMContentLoaded", () => {
// // Initialize the page
// init();
// // Add event listener for usb modem protocol changes
// handleUsbModemProtocolChange();
// // Add event listener for connected devices dropdown
// const connectedDevicesSelect = document.getElementById("connected-devices");
// if (connectedDevicesSelect) {
// connectedDevicesSelect.addEventListener("change", function (e) {
// const selectedMAC = e.target.value;
// const selectedHostname = e.target.options[e.target.selectedIndex].text;
// console.log("Selected device:", {
// mac: selectedMAC,
// hostname: selectedHostname,
// });
// // Enable/disable IP Passthrough mode based on selection
// const isDeviceSelected = selectedMAC !== "Select Device MAC";
// updatePassthroughModeState(isDeviceSelected);
// });
// }
// // Add event listener for IP Passthrough mode changes
// const ipPassthroughSelect = document.getElementById("ip-passthrough-mode");
// if (ipPassthroughSelect) {
// ipPassthroughSelect.addEventListener("change", function (e) {
// const selectedMode = e.target.value;
// const connectedDevicesSelect =
// document.getElementById("connected-devices");
// const selectedMAC = connectedDevicesSelect
// ? connectedDevicesSelect.value
// : null;
// if (selectedMAC && selectedMAC !== "Select Device MAC") {
// console.log("Applying IP Passthrough mode:", {
// mode: selectedMode,
// deviceMAC: selectedMAC,
// });
// // Here you can add the API call to apply the passthrough mode
// } else {
// console.error("No device selected for IP Passthrough mode");
// e.target.value = "Select IP Passthrough Mode";
// }
// });
// }
// });
// Initialize event listeners when DOM is ready
document.addEventListener("DOMContentLoaded", () => {
// Initialize the page
init();
});
// Initialize when DOM is ready
document.addEventListener("DOMContentLoaded", init);

View File

@@ -0,0 +1,214 @@
// api.js - API related functions
const api = {
async sendCommand(command) {
try {
const response = await fetch("/cgi-bin/atinout_handler.sh", {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded",
},
body: `command=${encodeURIComponent(command)}`,
});
return await response.json();
} catch (error) {
console.error("API Error:", error);
throw error;
}
}
};
// bandManager.js - Band management functionality
const bandManager = {
async fetchCurrentBands() {
try {
const data = await api.sendCommand("AT+QCAINFO");
const lteBands = data.output.match(/LTE BAND ([0-9]+)/g) || [];
const nrBands = data.output.match(/NR5G BAND ([0-9]+)/g) || [];
const currentBandsElement = document.getElementById("currentBands");
if (!currentBandsElement) return;
if (lteBands.length === 0 && nrBands.length === 0) {
currentBandsElement.textContent = "No active bands found";
} else if (lteBands.length === 0) {
currentBandsElement.textContent = nrBands.join(", ");
} else if (nrBands.length === 0) {
currentBandsElement.textContent = lteBands.join(", ");
} else {
currentBandsElement.textContent = [...lteBands, ...nrBands].join(", ");
}
} catch (error) {
console.error("Error fetching current bands:", error);
}
},
async fetchSupportedBands() {
try {
const data = await api.sendCommand('AT+QNWPREFCFG="policy_band"');
const matches = {
lte: data.output.match(/"lte_band",([0-9:]+)/),
nsa: data.output.match(/"nsa_nr5g_band",([0-9:]+)/),
saDc: data.output.match(/"nrdc_nr5g_band",([0-9:]+)/)
};
if (matches.lte) this.populateBands(matches.lte[1], "#lte_bands");
if (matches.nsa) this.populateBands(matches.nsa[1], "#nsa_bands");
if (matches.saDc) this.populateBands(matches.saDc[1], "#sanrdc_bands");
await this.fetchActiveBands();
} catch (error) {
console.error("Error fetching supported bands:", error);
}
},
async fetchActiveBands() {
try {
const command = 'AT+QNWPREFCFG="lte_band";+QNWPREFCFG="nsa_nr5g_band";+QNWPREFCFG="nr5g_band";+QNWPREFCFG="nrdc_nr5g_band"';
const data = await api.sendCommand(command);
const output = data.output.split("\n").slice(1).join("\n").replace("OK", "");
const matches = {
lte: output.match(/"lte_band",([0-9:]+)/),
nsa: output.match(/"nsa_nr5g_band",([0-9:]+)/),
saDc: output.split("\n")[6]?.match(/"nr5g_band",([0-9:]+)/)
};
if (matches.lte) this.markActiveBands(matches.lte[1].split(":"), "#lte_bands");
if (matches.nsa) this.markActiveBands(matches.nsa[1].split(":"), "#nsa_bands");
if (matches.saDc) this.markActiveBands(matches.saDc[1].split(":"), "#sanrdc_bands");
await this.fetchCurrentBands();
} catch (error) {
console.error("Error fetching active bands:", error);
}
},
populateBands(bandsString, targetId) {
const container = document.querySelector(targetId);
if (!container) return;
const html = bandsString.split(":").map(band => `
<div class="cell">
<label class="checkbox">
<input type="checkbox" value="${band}" /> B${band}
</label>
</div>
`).join("");
container.innerHTML = html;
},
markActiveBands(activeBands, targetId) {
document.querySelectorAll(`${targetId} input[type="checkbox"]`).forEach(checkbox => {
if (activeBands.includes(checkbox.value)) {
checkbox.setAttribute("checked", "checked");
}
});
},
uncheckAll(targetId) {
document.querySelectorAll(`${targetId} input[type="checkbox"]`).forEach(checkbox => {
checkbox.removeAttribute("checked");
checkbox.checked = false;
});
},
async lockBands(targetId, commandType) {
const checkboxes = document.querySelectorAll(`${targetId} input[type="checkbox"]:checked`);
const checkedBands = Array.from(checkboxes)
.map(cb => cb.value)
.sort((a, b) => a - b);
if (checkedBands.length === 0) {
alert("Please select at least one band to lock.");
return;
}
try {
const command = `AT+QNWPREFCFG="${commandType}",${checkedBands.join(":")}`;
await api.sendCommand(command);
alert(`Successfully locked ${commandType.split("_")[0].toUpperCase()} bands`);
await this.fetchActiveBands();
} catch (error) {
alert(`Failed to lock bands: ${error.message}`);
}
},
async resetBands(targetId, bandType) {
const checkboxes = document.querySelectorAll(`${targetId} input[type="checkbox"]`);
const selectedBands = [];
checkboxes.forEach(checkbox => {
checkbox.setAttribute("checked", "checked");
checkbox.checked = true;
selectedBands.push(checkbox.value);
});
try {
const command = `AT+QNWPREFCFG="${bandType}",${selectedBands.join(":")}`;
await api.sendCommand(command);
await this.fetchActiveBands();
} catch (error) {
console.error(`Error resetting ${bandType}:`, error);
}
}
};
// eventHandlers.js - Event handling setup
function setupEventListeners() {
const handlers = {
uncheck: {
"uncheckLte": "#lte_bands",
"uncheckNsa": "#nsa_bands",
"uncheckSaDc": "#sanrdc_bands"
},
lock: {
"lockLte": ["#lte_bands", "lte_band"],
"lockNsa": ["#nsa_bands", "nsa_nr5g_band"],
"lockSaDc": ["#sanrdc_bands", "nrdc_nr5g_band"]
},
reset: {
"resetLte": ["#lte_bands", "lte_band"],
"resetNsa": ["#nsa_bands", "nsa_nr5g_band"],
"resetSaDc": ["#sanrdc_bands", "nrdc_nr5g_band"]
}
};
// Setup uncheck handlers
Object.entries(handlers.uncheck).forEach(([id, targetId]) => {
const element = document.getElementById(id);
if (element) {
element.addEventListener("click", (e) => {
e.preventDefault();
bandManager.uncheckAll(targetId);
});
}
});
// Setup lock handlers
Object.entries(handlers.lock).forEach(([id, [targetId, commandType]]) => {
const element = document.getElementById(id);
if (element) {
element.addEventListener("click", () => bandManager.lockBands(targetId, commandType));
}
});
// Setup reset handlers
Object.entries(handlers.reset).forEach(([id, [targetId, bandType]]) => {
const element = document.getElementById(id);
if (element) {
element.addEventListener("click", (e) => {
e.preventDefault();
bandManager.resetBands(targetId, bandType);
});
}
});
}
// main.js - Application initialization
document.addEventListener("DOMContentLoaded", () => {
setupEventListeners();
bandManager.fetchSupportedBands();
});