diff --git a/html/saraR4.html b/html/saraR4.html index b241061..a1081a1 100755 --- a/html/saraR4.html +++ b/html/saraR4.html @@ -58,6 +58,14 @@ + + + +
@@ -1397,7 +1461,254 @@ function update_modem_configMode(param, checked){ }); } +// ============================================ +// SELF TEST FUNCTIONS +// ============================================ +function runSelfTest() { + console.log("Starting Self Test..."); + + // Reset UI + resetSelfTestUI(); + + // Show modal + const modal = new bootstrap.Modal(document.getElementById('selfTestModal')); + modal.show(); + + // Disable close buttons during test + document.getElementById('selfTestCloseBtn').disabled = true; + document.getElementById('selfTestDoneBtn').disabled = true; + document.getElementById('btn_selfTest').disabled = true; + + // Start test sequence + selfTestSequence(); +} + +function resetSelfTestUI() { + // Reset status + document.getElementById('selftest_status').innerHTML = ` +
+
+ Preparing test... +
`; + + // Reset test items + document.getElementById('test_modem_status').className = 'badge bg-secondary'; + document.getElementById('test_modem_status').textContent = 'Pending'; + document.getElementById('test_modem_detail').textContent = 'Waiting...'; + + document.getElementById('test_sim_status').className = 'badge bg-secondary'; + document.getElementById('test_sim_status').textContent = 'Pending'; + document.getElementById('test_sim_detail').textContent = 'Waiting...'; + + // Reset logs + document.getElementById('selftest_logs').innerHTML = ''; + + // Reset summary + document.getElementById('selftest_summary').innerHTML = ''; +} + +function addSelfTestLog(message) { + const logsEl = document.getElementById('selftest_logs'); + const timestamp = new Date().toLocaleTimeString(); + logsEl.innerHTML += `[${timestamp}] ${message}
`; + // Auto-scroll to bottom + logsEl.parentElement.scrollTop = logsEl.parentElement.scrollHeight; +} + +function updateTestStatus(testId, status, detail, badge) { + document.getElementById(`test_${testId}_status`).className = `badge ${badge}`; + document.getElementById(`test_${testId}_status`).textContent = status; + document.getElementById(`test_${testId}_detail`).textContent = detail; +} + +function setConfigMode(enabled) { + return new Promise((resolve, reject) => { + addSelfTestLog(`Setting modem_config_mode to ${enabled}...`); + + $.ajax({ + url: `launcher.php?type=update_config_sqlite¶m=modem_config_mode&value=${enabled}`, + dataType: 'json', + method: 'GET', + cache: false, + success: function(response) { + if (response.success) { + addSelfTestLog(`modem_config_mode set to ${enabled}`); + // Update checkbox state + document.getElementById('check_modem_configMode').checked = enabled; + resolve(true); + } else { + addSelfTestLog(`Failed to set modem_config_mode: ${response.error || 'Unknown error'}`); + reject(new Error(response.error || 'Failed to set config mode')); + } + }, + error: function(xhr, status, error) { + addSelfTestLog(`AJAX error setting config mode: ${error}`); + reject(new Error(error)); + } + }); + }); +} + +function sendATCommand(command, timeout) { + return new Promise((resolve, reject) => { + addSelfTestLog(`Sending AT command: ${command}`); + + $.ajax({ + url: `launcher.php?type=sara&port=ttyAMA2&command=${encodeURIComponent(command)}&timeout=${timeout}`, + dataType: 'text', + method: 'GET', + success: function(response) { + addSelfTestLog(`Response: ${response.replace(/\n/g, ' | ')}`); + resolve(response); + }, + error: function(xhr, status, error) { + addSelfTestLog(`AT command error: ${error}`); + reject(new Error(error)); + } + }); + }); +} + +function delay(ms) { + return new Promise(resolve => setTimeout(resolve, ms)); +} + +async function selfTestSequence() { + let testsPassed = 0; + let testsFailed = 0; + + try { + // Step 1: Enable config mode + document.getElementById('selftest_status').innerHTML = ` +
+
+ Enabling configuration mode... +
`; + + await setConfigMode(true); + + // Wait for SARA script to release the port (2 seconds should be enough) + addSelfTestLog('Waiting for modem port to be available...'); + await delay(2000); + + // Step 2: Test Modem Connection (ATI) + document.getElementById('selftest_status').innerHTML = ` +
+
+ Testing modem connection... +
`; + + updateTestStatus('modem', 'Testing...', 'Sending ATI command...', 'bg-info'); + + try { + const modemResponse = await sendATCommand('ATI', 5); + + if (modemResponse.includes('OK') && (modemResponse.toUpperCase().includes('SARA-R5') || modemResponse.toUpperCase().includes('SARA-R4'))) { + // Extract model + const modelMatch = modemResponse.match(/SARA-R[45]\d*[A-Z]*-\d+[A-Z]*-\d+/i); + const model = modelMatch ? modelMatch[0] : 'SARA module'; + updateTestStatus('modem', 'Passed', `Model: ${model}`, 'bg-success'); + testsPassed++; + } else if (modemResponse.includes('OK')) { + updateTestStatus('modem', 'Passed', 'Modem responding', 'bg-success'); + testsPassed++; + } else { + updateTestStatus('modem', 'Failed', 'No valid response', 'bg-danger'); + testsFailed++; + } + } catch (error) { + updateTestStatus('modem', 'Failed', error.message, 'bg-danger'); + testsFailed++; + } + + // Delay between AT commands + await delay(1000); + + // Step 3: Test SIM Card (AT+CCID?) + document.getElementById('selftest_status').innerHTML = ` +
+
+ Testing SIM card... +
`; + + updateTestStatus('sim', 'Testing...', 'Sending AT+CCID? command...', 'bg-info'); + + try { + const simResponse = await sendATCommand('AT+CCID?', 5); + + const ccidMatch = simResponse.match(/\+CCID:\s*(\d{18,22})/); + if (simResponse.includes('OK') && ccidMatch) { + const iccid = ccidMatch[1]; + // Show last 4 digits only for privacy + const maskedIccid = '****' + iccid.slice(-4); + updateTestStatus('sim', 'Passed', `ICCID: ...${maskedIccid}`, 'bg-success'); + testsPassed++; + } else if (simResponse.includes('ERROR')) { + updateTestStatus('sim', 'Failed', 'SIM card not detected', 'bg-danger'); + testsFailed++; + } else { + updateTestStatus('sim', 'Warning', 'Unable to read ICCID', 'bg-warning'); + testsFailed++; + } + } catch (error) { + updateTestStatus('sim', 'Failed', error.message, 'bg-danger'); + testsFailed++; + } + + } catch (error) { + addSelfTestLog(`Test sequence error: ${error.message}`); + } finally { + // Always disable config mode at the end + document.getElementById('selftest_status').innerHTML = ` +
+
+ Disabling configuration mode... +
`; + + try { + await delay(500); + await setConfigMode(false); + } catch (error) { + addSelfTestLog(`Warning: Failed to disable config mode: ${error.message}`); + } + + // Show final status + const totalTests = testsPassed + testsFailed; + let statusClass, statusIcon, statusText; + + if (testsFailed === 0) { + statusClass = 'text-success'; + statusIcon = '✓'; + statusText = 'All tests passed'; + } else if (testsPassed === 0) { + statusClass = 'text-danger'; + statusIcon = '✗'; + statusText = 'All tests failed'; + } else { + statusClass = 'text-warning'; + statusIcon = '!'; + statusText = 'Some tests failed'; + } + + document.getElementById('selftest_status').innerHTML = ` +
+ ${statusIcon} + ${statusText} +
`; + + document.getElementById('selftest_summary').innerHTML = ` + ${testsPassed} passed + ${testsFailed} failed`; + + // Enable close buttons + document.getElementById('selfTestCloseBtn').disabled = false; + document.getElementById('selfTestDoneBtn').disabled = false; + document.getElementById('btn_selfTest').disabled = false; + + addSelfTestLog('Self test completed.'); + } +}