Build sdxpinn-quecmanger ipk
-Removed no longer needed files -Created ipk for quecmanager -Thank you @dr-dolomite for your hard work on this! Co-Authored-By: Russel Yasol <73575327+dr-dolomite@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,179 @@
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const form = document.getElementById('apnProfileForm');
|
||||
|
||||
// Helper function to show notifications
|
||||
function showNotification(message, isError = false) {
|
||||
// Remove existing notification if any
|
||||
const existingNotification = form.previousElementSibling;
|
||||
if (existingNotification && existingNotification.classList.contains('notification')) {
|
||||
existingNotification.remove();
|
||||
}
|
||||
|
||||
const notification = document.createElement('div');
|
||||
notification.className = `notification ${isError ? 'is-danger' : 'is-success'} is-light`;
|
||||
notification.innerHTML = `
|
||||
<button class="delete"></button>
|
||||
${message}
|
||||
`;
|
||||
|
||||
form.insertAdjacentElement('beforebegin', notification);
|
||||
|
||||
// Remove notification after 5 seconds
|
||||
setTimeout(() => notification.remove(), 5000);
|
||||
|
||||
// Allow manual close
|
||||
notification.querySelector('.delete').addEventListener('click', () => notification.remove());
|
||||
}
|
||||
|
||||
// Function to validate ICCID format
|
||||
function validateICCID(iccid) {
|
||||
return /^\d{19,20}$/.test(iccid);
|
||||
}
|
||||
|
||||
// Function to validate APN format
|
||||
function validateAPN(apn) {
|
||||
return /^[a-zA-Z0-9.-]+$/.test(apn);
|
||||
}
|
||||
|
||||
// Function to set select element value
|
||||
function setSelectValue(selectElement, value) {
|
||||
const options = selectElement.options;
|
||||
for (let i = 0; i < options.length; i++) {
|
||||
if (options[i].value === value) {
|
||||
selectElement.selectedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Function to fetch and display existing profiles
|
||||
function fetchProfiles() {
|
||||
fetch('/cgi-bin/cell-settings/fetch-apn-profiles.sh')
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.status === 'success') {
|
||||
// Fill Profile 1
|
||||
if (data.profiles.profile1) {
|
||||
const p1 = data.profiles.profile1;
|
||||
if (p1.iccid) document.getElementById('iccidProfile1').value = p1.iccid;
|
||||
if (p1.apn) document.getElementById('apnProfile1').value = p1.apn;
|
||||
if (p1.pdpType) setSelectValue(document.getElementById('apnPDPType1'), p1.pdpType);
|
||||
}
|
||||
|
||||
// Fill Profile 2
|
||||
if (data.profiles.profile2) {
|
||||
const p2 = data.profiles.profile2;
|
||||
if (p2.iccid) document.getElementById('iccidProfile2').value = p2.iccid;
|
||||
if (p2.apn) document.getElementById('apnProfile2').value = p2.apn;
|
||||
if (p2.pdpType) setSelectValue(document.getElementById('apnPDPType2'), p2.pdpType);
|
||||
}
|
||||
} else {
|
||||
showNotification('No existing profiles found', true);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showNotification('Error fetching profiles: ' + error.message, true);
|
||||
});
|
||||
}
|
||||
|
||||
// Function to validate form
|
||||
function validateForm() {
|
||||
const iccid1 = document.getElementById('iccidProfile1').value;
|
||||
const apn1 = document.getElementById('apnProfile1').value;
|
||||
const pdp1 = document.getElementById('apnPDPType1').value;
|
||||
|
||||
const iccid2 = document.getElementById('iccidProfile2').value;
|
||||
const apn2 = document.getElementById('apnProfile2').value;
|
||||
const pdp2 = document.getElementById('apnPDPType2').value;
|
||||
|
||||
// Validate first profile (required)
|
||||
if (!iccid1 || !apn1 || pdp1 === 'Select APN PDP Type') {
|
||||
showNotification('Please fill in all fields for Profile 1', true);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!validateICCID(iccid1)) {
|
||||
showNotification('Invalid ICCID format in Profile 1 (should be 19-20 digits)', true);
|
||||
return false;
|
||||
}
|
||||
if (!validateAPN(apn1)) {
|
||||
showNotification('Invalid APN format in Profile 1 (alphanumeric, dots, and hyphens only)', true);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate second profile only if any field is filled
|
||||
if (iccid2 || apn2 || pdp2 !== 'Select APN PDP Type') {
|
||||
if (!validateICCID(iccid2)) {
|
||||
showNotification('Invalid ICCID format in Profile 2 (should be 19-20 digits)', true);
|
||||
return false;
|
||||
}
|
||||
if (!validateAPN(apn2)) {
|
||||
showNotification('Invalid APN format in Profile 2 (alphanumeric, dots, and hyphens only)', true);
|
||||
return false;
|
||||
}
|
||||
if (pdp2 === 'Select APN PDP Type') {
|
||||
showNotification('Please select PDP type for Profile 2', true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle form submission
|
||||
document.getElementById('saveAPNProfile').addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
if (!validateForm()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const formData = {
|
||||
iccidProfile1: document.getElementById('iccidProfile1').value,
|
||||
apnProfile1: document.getElementById('apnProfile1').value,
|
||||
pdpType1: document.getElementById('apnPDPType1').value,
|
||||
iccidProfile2: document.getElementById('iccidProfile2').value || '',
|
||||
apnProfile2: document.getElementById('apnProfile2').value || '',
|
||||
pdpType2: document.getElementById('apnPDPType2').value || 'IP' // Default value if not selected
|
||||
};
|
||||
|
||||
// Send data to the server
|
||||
fetch('/cgi-bin/cell-settings/apn-profile.sh', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: Object.keys(formData).map(key => {
|
||||
return encodeURIComponent(key) + '=' + encodeURIComponent(formData[key])
|
||||
}).join('&')
|
||||
})
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
if (data.status === 'success') {
|
||||
showNotification('APN profiles saved successfully');
|
||||
} else {
|
||||
showNotification(data.message || 'Error saving APN profiles', true);
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
showNotification('Error saving APN profiles: ' + error.message, true);
|
||||
});
|
||||
});
|
||||
|
||||
// Handle reset button
|
||||
document.getElementById('resetAPNProfile').addEventListener('click', function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
document.getElementById('iccidProfile1').value = '';
|
||||
document.getElementById('apnProfile1').value = '';
|
||||
document.getElementById('apnPDPType1').selectedIndex = 0;
|
||||
document.getElementById('iccidProfile2').value = '';
|
||||
document.getElementById('apnProfile2').value = '';
|
||||
document.getElementById('apnPDPType2').selectedIndex = 0;
|
||||
|
||||
showNotification('Form has been reset');
|
||||
});
|
||||
|
||||
// Fetch existing profiles when the page loads
|
||||
fetchProfiles();
|
||||
});
|
||||
@@ -0,0 +1,310 @@
|
||||
// State variables to track current values
|
||||
let currentSettings = {
|
||||
apn: "",
|
||||
pdpType: "",
|
||||
};
|
||||
|
||||
let updatedSettings = {
|
||||
apn: "",
|
||||
pdpType: "",
|
||||
};
|
||||
|
||||
let updatedNetworkMode = "";
|
||||
let currentNetworkMode = "";
|
||||
|
||||
let currentNr5GModeControl = "";
|
||||
let updatedNr5GModeControl = "";
|
||||
|
||||
// Function to check if settings have changed
|
||||
function haveSettingsChanged() {
|
||||
return (
|
||||
currentSettings.apn !== updatedSettings.apn ||
|
||||
currentSettings.pdpType !== updatedSettings.pdpType
|
||||
);
|
||||
}
|
||||
|
||||
// Function to check if network mode has changed
|
||||
function haveNetworkModeChanged() {
|
||||
console.log("Current network mode:", currentNetworkMode);
|
||||
console.log("Updated network mode:", updatedNetworkMode);
|
||||
return currentNetworkMode !== updatedNetworkMode;
|
||||
}
|
||||
|
||||
// Function to check if NR5G mode control has changed
|
||||
function haveNr5GModeControlChanged() {
|
||||
console.log("Current NR5G mode control:", currentNr5GModeControl);
|
||||
console.log("Updated NR5G mode control:", updatedNr5GModeControl);
|
||||
return currentNr5GModeControl !== updatedNr5GModeControl;
|
||||
}
|
||||
|
||||
// Function to apply network mode changes immediately
|
||||
async function applyNetworkModeChange() {
|
||||
if (!haveNetworkModeChanged()) {
|
||||
alert("No changes detected in the network mode.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const atCommand = `AT+QNWPREFCFG="mode_pref",${updatedNetworkMode}`;
|
||||
console.log("Sending AT command for network mode change:", atCommand);
|
||||
const response = await sendATCommand(atCommand);
|
||||
console.log("AT command response:", response);
|
||||
alert("Network mode applied successfully!");
|
||||
} catch (error) {
|
||||
console.error("Error applying network mode:", error);
|
||||
alert("Error applying network mode. Please try again.");
|
||||
}
|
||||
}
|
||||
|
||||
// Function to apply NR5G mode control changes immediately
|
||||
async function applyNr5GModeControlChange() {
|
||||
if (!haveNr5GModeControlChanged()) {
|
||||
alert("No changes detected in the NR5G mode control.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const atCommand = `AT+QNWPREFCFG="nr5g_disable_mode",${updatedNr5GModeControl}`;
|
||||
console.log("Sending AT command for NR5G mode control change:", atCommand);
|
||||
const response = await sendATCommand(atCommand);
|
||||
console.log("AT command response:", response);
|
||||
alert("NR5G mode control applied successfully!");
|
||||
} catch (error) {
|
||||
console.error("Error applying NR5G mode control:", error);
|
||||
alert("Error applying NR5G mode control. Please try again.");
|
||||
}
|
||||
}
|
||||
|
||||
// Function to send settings to the modem
|
||||
async function saveSettings() {
|
||||
if (!haveSettingsChanged()) {
|
||||
alert("No changes detected in the settings.");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const atCommand = `AT+QMBNCFG="AutoSel",0;+CGDCONT=1,"${updatedSettings.pdpType}","${updatedSettings.apn}"`;
|
||||
console.log("Sending AT command:", atCommand);
|
||||
|
||||
// Disable the input fields while the settings are being saved
|
||||
const inputs = document.querySelectorAll("input, select");
|
||||
inputs.forEach((input) => {
|
||||
input.disabled = true;
|
||||
});
|
||||
const response = await sendATCommand(atCommand);
|
||||
console.log("AT command response:", response);
|
||||
|
||||
await sendATCommand(`AT+COPS=2`);
|
||||
// Wait for 2 seconds before turning on the modem
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
await sendATCommand(`AT+COPS=0`);
|
||||
|
||||
// Re-enable the input fields after the settings are saved
|
||||
inputs.forEach((input) => {
|
||||
input.disabled = false;
|
||||
});
|
||||
|
||||
// Update current settings after successful save
|
||||
currentSettings = { ...updatedSettings };
|
||||
alert("Settings saved successfully!");
|
||||
} catch (error) {
|
||||
console.error("Error saving settings:", error);
|
||||
alert("Error saving settings. Please try again.");
|
||||
}
|
||||
}
|
||||
|
||||
async function resetAPN() {
|
||||
atCommand = `AT+QMBNCFG="AutoSel",1`;
|
||||
console.log("Sending AT command:", atCommand);
|
||||
|
||||
try {
|
||||
const response = await sendATCommand(atCommand);
|
||||
console.log("AT command response:", response);
|
||||
|
||||
// Restart connection after resetting APN settings
|
||||
await sendATCommand("AT+COPS=2");
|
||||
// Wait for 2 seconds before turning on the modem
|
||||
await new Promise((resolve) => setTimeout(resolve, 2000));
|
||||
await sendATCommand("AT+COPS=0");
|
||||
alert("APN settings reset successfully!");
|
||||
} catch (error) {
|
||||
console.error("Error resetting APN settings:", error);
|
||||
alert("Error resetting APN settings. Please try again.");
|
||||
}
|
||||
}
|
||||
|
||||
async function sendATCommand(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),
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
const data = await response.json();
|
||||
return data;
|
||||
} catch (error) {
|
||||
console.error("Error sending AT command:", error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Function to fetch cell settings data
|
||||
async function fetchCellSettings() {
|
||||
try {
|
||||
const response = await fetch("/cgi-bin/cell-settings/cell-settings.sh");
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
console.log("Full response:", data);
|
||||
|
||||
data.forEach((item) => {
|
||||
if (item.response.includes("CGDCONT?")) {
|
||||
const apn = item.response
|
||||
.split("\n")[1]
|
||||
.split(":")[1]
|
||||
.split(",")[2]
|
||||
.replace(/"/g, "")
|
||||
.trim();
|
||||
|
||||
currentSettings.apn = apn;
|
||||
updatedSettings.apn = apn;
|
||||
|
||||
const apnInput = document.getElementById("currentAPN");
|
||||
if (apnInput) {
|
||||
apnInput.value = apn;
|
||||
|
||||
// Add event listener for APN changes
|
||||
if (!apnInput.hasListener) {
|
||||
apnInput.hasListener = true;
|
||||
apnInput.addEventListener("input", (e) => {
|
||||
updatedSettings.apn = e.target.value;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const pdpType = item.response
|
||||
.split("\n")[1]
|
||||
.split(":")[1]
|
||||
.split(",")[1]
|
||||
.replace(/"/g, "")
|
||||
.trim();
|
||||
|
||||
currentSettings.pdpType = pdpType;
|
||||
updatedSettings.pdpType = pdpType;
|
||||
|
||||
const pdpTypeSelect = document.getElementById("apnPDP");
|
||||
if (pdpTypeSelect) {
|
||||
// Set initial value
|
||||
pdpTypeSelect.value =
|
||||
pdpType === "IPV4V6"
|
||||
? "IPV4V6"
|
||||
: pdpType === "IPV6"
|
||||
? "IPV6"
|
||||
: pdpType === "PPP"
|
||||
? "PPP"
|
||||
: "IP";
|
||||
|
||||
// Add event listener for PDP type changes
|
||||
if (!pdpTypeSelect.hasListener) {
|
||||
pdpTypeSelect.hasListener = true;
|
||||
pdpTypeSelect.addEventListener("change", (e) => {
|
||||
updatedSettings.pdpType = e.target.value;
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (item.response.includes("mode_pref")) {
|
||||
const networkMode = item.response
|
||||
.split("\n")[1]
|
||||
.replace("+QNWPREFCFG: ", "")
|
||||
.split(",")[1]
|
||||
.trim();
|
||||
|
||||
currentNetworkMode = networkMode;
|
||||
updatedNetworkMode = networkMode;
|
||||
|
||||
console.log("Network mode:", networkMode);
|
||||
|
||||
const networkSelect = document.getElementById("networkPreference");
|
||||
if (networkSelect) {
|
||||
// Set initial value based on actual value from modem
|
||||
networkSelect.value =
|
||||
networkMode === "LTE:NR5G"
|
||||
? "LTE:NR5G"
|
||||
: networkMode === "NR5G"
|
||||
? "NR5G"
|
||||
: networkMode === "LTE"
|
||||
? "LTE"
|
||||
: "AUTO";
|
||||
|
||||
// Add event listener for network mode changes, if there is, run applyNetworkModeChange
|
||||
if (!networkSelect.hasListener) {
|
||||
networkSelect.hasListener = true;
|
||||
networkSelect.addEventListener("change", (e) => {
|
||||
updatedNetworkMode = e.target.value;
|
||||
applyNetworkModeChange();
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (item.response.includes("nr5g_disable_mode")) {
|
||||
const nr5GModeControl = item.response
|
||||
.split("\n")[1]
|
||||
.split(":")[1]
|
||||
.split(",")[1]
|
||||
.trim();
|
||||
|
||||
console.log("NR5G mode control:", nr5GModeControl);
|
||||
|
||||
currentNr5GModeControl = nr5GModeControl;
|
||||
updatedNr5GModeControl = nr5GModeControl;
|
||||
|
||||
const nr5GControlSelect = document.getElementById("nr5gModeControl");
|
||||
|
||||
if (nr5GControlSelect) {
|
||||
// Set initial value based on actual value from modem
|
||||
nr5GControlSelect.value =
|
||||
nr5GModeControl === "0" ? "0" : nr5GModeControl === "1" ? "1" : "2";
|
||||
|
||||
// Add event listener for NR5G mode control changes, if there is, run applyNr5GModeControlChange
|
||||
if (!nr5GControlSelect.hasListener) {
|
||||
nr5GControlSelect.hasListener = true;
|
||||
nr5GControlSelect.addEventListener("change", (e) => {
|
||||
updatedNr5GModeControl = e.target.value;
|
||||
applyNr5GModeControlChange();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error fetching cell settings:", error);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize when DOM is loaded
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
fetchCellSettings();
|
||||
|
||||
// Add event listener for both save buttons
|
||||
const saveButtons = document.querySelectorAll(".card-footer-item");
|
||||
saveButtons.forEach((button) => {
|
||||
if (button.textContent.trim() === "Save APN") {
|
||||
button.addEventListener("click", saveSettings);
|
||||
} else if (button.textContent.trim() === "Reset APN") {
|
||||
button.addEventListener("click", resetAPN);
|
||||
}
|
||||
});
|
||||
|
||||
// For every alert and close button, add event listener to refetch cell settings
|
||||
const alertButtons = document.querySelectorAll(".delete");
|
||||
alertButtons.forEach((button) => {
|
||||
button.addEventListener("click", fetchCellSettings);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user