From 78c673ed4db133dc37cf1c05fe1d3bf50968628b Mon Sep 17 00:00:00 2001 From: Russel Yasol Date: Fri, 4 Oct 2024 06:02:21 +0800 Subject: [PATCH] fixed apn and improved javascripts --- www/bandlock.html | 36 +- www/cgi-bin/home_data.sh | 2 +- www/js/advance/fetch-current.settings.js | 680 +++++++++-------------- www/js/band-locking/fetch-bands.js | 214 +++++++ 4 files changed, 492 insertions(+), 440 deletions(-) create mode 100644 www/js/band-locking/fetch-bands.js diff --git a/www/bandlock.html b/www/bandlock.html index 2ecbf26..c171b95 100644 --- a/www/bandlock.html +++ b/www/bandlock.html @@ -25,6 +25,7 @@ + --> diff --git a/www/cgi-bin/home_data.sh b/www/cgi-bin/home_data.sh index 9a8791e..a6fb3e0 100644 --- a/www/cgi-bin/home_data.sh +++ b/www/cgi-bin/home_data.sh @@ -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" diff --git a/www/js/advance/fetch-current.settings.js b/www/js/advance/fetch-current.settings.js index 2a125d2..d2831e1 100644 --- a/www/js/advance/fetch-current.settings.js +++ b/www/js/advance/fetch-current.settings.js @@ -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); \ No newline at end of file diff --git a/www/js/band-locking/fetch-bands.js b/www/js/band-locking/fetch-bands.js new file mode 100644 index 0000000..f9bea49 --- /dev/null +++ b/www/js/band-locking/fetch-bands.js @@ -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 => ` +
+ +
+ `).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(); +}); \ No newline at end of file