/** * ISMS Listening Station Mode * Spectrum monitoring, cellular environment, tower mapping */ // ============== STATE ============== let isIsmsScanRunning = false; let ismsEventSource = null; let ismsTowerMap = null; let ismsTowerMarkers = []; let ismsLocation = { lat: null, lon: null }; let ismsBandMetrics = {}; let ismsFindings = []; let ismsPeaks = []; let ismsBaselineRecording = false; let ismsInitialized = false; // Finding counts let ismsFindingCounts = { high: 0, warn: 0, info: 0 }; // GSM scanner state let isGsmScanRunning = false; let ismsGsmCells = []; // ============== INITIALIZATION ============== function initIsmsMode() { if (ismsInitialized) return; // Initialize Leaflet map for towers initIsmsTowerMap(); // Load baselines ismsRefreshBaselines(); // Check for GPS ismsCheckGps(); // Populate SDR devices ismsPopulateSdrDevices(); // Set up event listeners setupIsmsEventListeners(); ismsInitialized = true; console.log('ISMS mode initialized'); } function initIsmsTowerMap() { const container = document.getElementById('ismsTowerMap'); if (!container || ismsTowerMap) return; // Clear placeholder content container.innerHTML = ''; ismsTowerMap = L.map('ismsTowerMap', { center: [51.5074, -0.1278], zoom: 12, zoomControl: false, }); L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { attribution: '© OSM' }).addTo(ismsTowerMap); // Add zoom control to bottom right L.control.zoom({ position: 'bottomright' }).addTo(ismsTowerMap); } function setupIsmsEventListeners() { // Preset change const presetSelect = document.getElementById('ismsScanPreset'); if (presetSelect) { presetSelect.addEventListener('change', function() { const customRange = document.getElementById('ismsCustomRange'); if (customRange) { customRange.style.display = this.value === 'custom' ? 'block' : 'none'; } }); } // Gain slider const gainSlider = document.getElementById('ismsGain'); if (gainSlider) { gainSlider.addEventListener('input', function() { document.getElementById('ismsGainValue').textContent = this.value; }); } // Threshold slider const thresholdSlider = document.getElementById('ismsActivityThreshold'); if (thresholdSlider) { thresholdSlider.addEventListener('input', function() { document.getElementById('ismsThresholdValue').textContent = this.value + '%'; }); } } async function ismsPopulateSdrDevices() { try { const response = await fetch('/devices'); const devices = await response.json(); const select = document.getElementById('ismsSdrDevice'); if (!select) return; select.innerHTML = ''; if (devices.length === 0) { select.innerHTML = ''; return; } devices.forEach((device, index) => { const option = document.createElement('option'); option.value = index; option.textContent = `${index}: ${device.name || 'RTL-SDR'}`; select.appendChild(option); }); } catch (e) { console.error('Failed to load SDR devices:', e); } } // ============== GPS ============== async function ismsCheckGps() { try { const response = await fetch('/gps/status'); const data = await response.json(); if (data.connected && data.position) { ismsLocation.lat = data.position.latitude; ismsLocation.lon = data.position.longitude; updateIsmsLocationDisplay(); } } catch (e) { console.debug('GPS not available'); } } function ismsUseGPS() { fetch('/gps/status') .then(r => r.json()) .then(data => { if (data.connected && data.position) { ismsLocation.lat = data.position.latitude; ismsLocation.lon = data.position.longitude; updateIsmsLocationDisplay(); ismsNotify('ISMS', 'GPS location acquired'); } else { ismsNotify('ISMS', 'GPS not available. Connect GPS first.'); } }) .catch(() => { ismsNotify('ISMS', 'Failed to get GPS position'); }); } function ismsSetManualLocation() { const lat = prompt('Enter latitude:', ismsLocation.lat || '51.5074'); if (lat === null) return; const lon = prompt('Enter longitude:', ismsLocation.lon || '-0.1278'); if (lon === null) return; ismsLocation.lat = parseFloat(lat); ismsLocation.lon = parseFloat(lon); updateIsmsLocationDisplay(); } function updateIsmsLocationDisplay() { const coordsEl = document.getElementById('ismsCoords'); const quickLocEl = document.getElementById('ismsQuickLocation'); if (ismsLocation.lat && ismsLocation.lon) { const text = `${ismsLocation.lat.toFixed(4)}, ${ismsLocation.lon.toFixed(4)}`; if (coordsEl) coordsEl.textContent = `Lat: ${ismsLocation.lat.toFixed(4)}, Lon: ${ismsLocation.lon.toFixed(4)}`; if (quickLocEl) quickLocEl.textContent = text; // Center map on location if (ismsTowerMap) { ismsTowerMap.setView([ismsLocation.lat, ismsLocation.lon], 13); } } } // ============== SCAN CONTROLS ============== function ismsToggleScan() { if (isIsmsScanRunning) { ismsStopScan(); } else { ismsStartScan(); } } async function ismsStartScan() { const preset = document.getElementById('ismsScanPreset').value; const device = parseInt(document.getElementById('ismsSdrDevice').value || '0'); const gain = parseInt(document.getElementById('ismsGain').value || '40'); const threshold = parseInt(document.getElementById('ismsActivityThreshold').value || '50'); const baselineId = document.getElementById('ismsBaselineSelect').value || null; const config = { preset: preset, device: device, gain: gain, threshold: threshold, baseline_id: baselineId ? parseInt(baselineId) : null, }; // Add custom range if selected if (preset === 'custom') { config.freq_start = parseFloat(document.getElementById('ismsStartFreq').value); config.freq_end = parseFloat(document.getElementById('ismsEndFreq').value); } // Add location if (ismsLocation.lat && ismsLocation.lon) { config.lat = ismsLocation.lat; config.lon = ismsLocation.lon; } try { const response = await fetch('/isms/start_scan', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(config) }); const data = await response.json(); if (data.status === 'started') { isIsmsScanRunning = true; updateIsmsUI('scanning'); connectIsmsStream(); // Reset findings ismsFindingCounts = { high: 0, warn: 0, info: 0 }; ismsFindings = []; ismsPeaks = []; updateIsmsFindingsBadges(); } else { ismsNotify('ISMS Error', data.message || 'Failed to start scan'); } } catch (e) { ismsNotify('ISMS Error', 'Failed to start scan: ' + e.message); } } async function ismsStopScan() { try { await fetch('/isms/stop_scan', { method: 'POST' }); } catch (e) { console.error('Error stopping scan:', e); } isIsmsScanRunning = false; disconnectIsmsStream(); updateIsmsUI('stopped'); } function updateIsmsUI(state) { const startBtn = document.getElementById('ismsStartBtn'); const quickStatus = document.getElementById('ismsQuickStatus'); const scanStatus = document.getElementById('ismsScanStatus'); if (state === 'scanning') { if (startBtn) { startBtn.textContent = 'Stop Scan'; startBtn.classList.add('running'); } if (quickStatus) quickStatus.textContent = 'SCANNING'; if (scanStatus) scanStatus.textContent = 'SCANNING'; // Update quick band display const presetSelect = document.getElementById('ismsScanPreset'); const quickBand = document.getElementById('ismsQuickBand'); if (presetSelect && quickBand) { quickBand.textContent = presetSelect.options[presetSelect.selectedIndex].text; } } else { if (startBtn) { startBtn.textContent = 'Start Scan'; startBtn.classList.remove('running'); } if (quickStatus) quickStatus.textContent = 'IDLE'; if (scanStatus) scanStatus.textContent = 'IDLE'; } } // ============== SSE STREAM ============== function connectIsmsStream() { if (ismsEventSource) { ismsEventSource.close(); } ismsEventSource = new EventSource('/isms/stream'); ismsEventSource.onmessage = function(event) { try { const data = JSON.parse(event.data); handleIsmsEvent(data); } catch (e) { console.error('Failed to parse ISMS event:', e); } }; ismsEventSource.onerror = function() { console.error('ISMS stream error'); }; } function disconnectIsmsStream() { if (ismsEventSource) { ismsEventSource.close(); ismsEventSource = null; } } function handleIsmsEvent(data) { switch (data.type) { case 'meter': updateIsmsBandMeter(data.band, data.level, data.noise_floor); break; case 'spectrum_peak': addIsmsPeak(data); break; case 'finding': addIsmsFinding(data); break; case 'status': updateIsmsStatus(data); break; case 'gsm_cell': handleGsmCell(data.cell); break; case 'gsm_scan_complete': handleGsmScanComplete(data); break; case 'gsm_scanning': case 'gsm_stopped': case 'gsm_error': handleGsmStatus(data); break; case 'keepalive': // Ignore break; default: console.debug('Unknown ISMS event:', data.type); } } // ============== BAND METERS ============== function updateIsmsBandMeter(band, level, noiseFloor) { ismsBandMetrics[band] = { level, noiseFloor }; const container = document.getElementById('ismsBandMeters'); if (!container) return; // Find or create meter for this band let meter = container.querySelector(`[data-band="${band}"]`); if (!meter) { // Clear placeholder if first meter if (container.querySelector('div:not([data-band])')) { container.innerHTML = ''; } meter = document.createElement('div'); meter.setAttribute('data-band', band); meter.className = 'isms-band-meter'; meter.style.cssText = 'text-align: center; min-width: 80px;'; meter.innerHTML = `
${band}
${level.toFixed(0)}%
${noiseFloor.toFixed(1)} dB
`; container.appendChild(meter); } // Update meter values const fill = meter.querySelector('.meter-fill'); const value = meter.querySelector('.meter-value'); const noise = meter.querySelector('.meter-noise'); if (fill) fill.style.height = level + '%'; if (value) value.textContent = level.toFixed(0) + '%'; if (noise) noise.textContent = noiseFloor.toFixed(1) + ' dB'; } // ============== PEAKS ============== function addIsmsPeak(data) { // Add to peaks array (keep last 20) ismsPeaks.unshift({ freq: data.freq_mhz, power: data.power_db, band: data.band, timestamp: new Date() }); if (ismsPeaks.length > 20) { ismsPeaks.pop(); } updateIsmsPeaksList(); } function updateIsmsPeaksList() { const tbody = document.getElementById('ismsPeaksBody'); const countEl = document.getElementById('ismsPeakCount'); if (!tbody) return; if (ismsPeaks.length === 0) { tbody.innerHTML = 'No peaks detected'; if (countEl) countEl.textContent = '0'; return; } tbody.innerHTML = ismsPeaks.map(peak => ` ${peak.freq.toFixed(3)} MHz ${peak.power.toFixed(1)} dB ${peak.band || '--'} `).join(''); if (countEl) countEl.textContent = ismsPeaks.length; } // ============== FINDINGS ============== function addIsmsFinding(data) { const finding = { severity: data.severity, text: data.text, details: data.details, timestamp: data.timestamp || new Date().toISOString() }; ismsFindings.unshift(finding); // Update counts if (data.severity === 'high') ismsFindingCounts.high++; else if (data.severity === 'warn') ismsFindingCounts.warn++; else ismsFindingCounts.info++; updateIsmsFindingsBadges(); updateIsmsFindingsTimeline(); // Update quick findings count const quickFindings = document.getElementById('ismsQuickFindings'); if (quickFindings) { quickFindings.textContent = ismsFindings.length; quickFindings.style.color = ismsFindingCounts.high > 0 ? 'var(--accent-red)' : ismsFindingCounts.warn > 0 ? 'var(--accent-orange)' : 'var(--accent-green)'; } } function updateIsmsFindingsBadges() { const highBadge = document.getElementById('ismsFindingsHigh'); const warnBadge = document.getElementById('ismsFindingsWarn'); const infoBadge = document.getElementById('ismsFindingsInfo'); if (highBadge) { highBadge.textContent = ismsFindingCounts.high + ' HIGH'; highBadge.style.display = ismsFindingCounts.high > 0 ? 'inline-block' : 'none'; } if (warnBadge) { warnBadge.textContent = ismsFindingCounts.warn + ' WARN'; warnBadge.style.display = ismsFindingCounts.warn > 0 ? 'inline-block' : 'none'; } if (infoBadge) { infoBadge.textContent = ismsFindingCounts.info + ' INFO'; } } function updateIsmsFindingsTimeline() { const timeline = document.getElementById('ismsFindingsTimeline'); if (!timeline) return; if (ismsFindings.length === 0) { timeline.innerHTML = `
No findings yet. Start a scan and enable baseline comparison.
`; return; } timeline.innerHTML = ismsFindings.slice(0, 50).map(finding => { const severityColor = finding.severity === 'high' ? 'var(--accent-red)' : finding.severity === 'warn' ? 'var(--accent-orange)' : 'var(--accent-cyan)'; const time = new Date(finding.timestamp).toLocaleTimeString(); return `
${finding.severity} ${time}
${finding.text}
`; }).join(''); } // ============== STATUS ============== function updateIsmsStatus(data) { if (data.state === 'stopped' || data.state === 'error') { isIsmsScanRunning = false; updateIsmsUI('stopped'); if (data.state === 'error') { ismsNotify('ISMS Error', data.message || 'Scan error'); } } } // ============== TOWERS ============== async function ismsRefreshTowers() { if (!ismsLocation.lat || !ismsLocation.lon) { ismsNotify('ISMS', 'Set location first to query towers'); return; } const towerCountEl = document.getElementById('ismsTowerCount'); if (towerCountEl) towerCountEl.textContent = 'Querying...'; try { const response = await fetch(`/isms/towers?lat=${ismsLocation.lat}&lon=${ismsLocation.lon}&radius=5`); const data = await response.json(); if (data.status === 'error') { if (towerCountEl) towerCountEl.textContent = data.message; if (data.config_required) { ismsNotify('ISMS', 'OpenCelliD token required. Set OPENCELLID_TOKEN environment variable.'); } return; } updateIsmsTowerMap(data.towers); updateIsmsTowerList(data.towers); if (towerCountEl) towerCountEl.textContent = `${data.count} towers found`; } catch (e) { console.error('Failed to query towers:', e); if (towerCountEl) towerCountEl.textContent = 'Query failed'; } } function updateIsmsTowerMap(towers) { if (!ismsTowerMap) return; // Clear existing markers ismsTowerMarkers.forEach(marker => marker.remove()); ismsTowerMarkers = []; // Add tower markers towers.forEach(tower => { const marker = L.circleMarker([tower.lat, tower.lon], { radius: 6, fillColor: getTowerColor(tower.radio), color: '#fff', weight: 1, opacity: 1, fillOpacity: 0.8 }); marker.bindPopup(`
${tower.operator}
${tower.radio} - CID: ${tower.cellid}
Distance: ${tower.distance_km} km
CellMapper
`); marker.addTo(ismsTowerMap); ismsTowerMarkers.push(marker); }); // Add user location marker if (ismsLocation.lat && ismsLocation.lon) { const userMarker = L.marker([ismsLocation.lat, ismsLocation.lon], { icon: L.divIcon({ className: 'isms-user-marker', html: '
', iconSize: [16, 16], iconAnchor: [8, 8] }) }); userMarker.addTo(ismsTowerMap); ismsTowerMarkers.push(userMarker); } // Fit map to markers if we have towers if (towers.length > 0 && ismsTowerMarkers.length > 0) { const group = L.featureGroup(ismsTowerMarkers); ismsTowerMap.fitBounds(group.getBounds().pad(0.1)); } } function getTowerColor(radio) { switch (radio) { case 'LTE': return '#00d4ff'; case 'NR': return '#ff00ff'; case 'UMTS': return '#00ff88'; case 'GSM': return '#ffaa00'; default: return '#888'; } } function updateIsmsTowerList(towers) { const list = document.getElementById('ismsTowerList'); if (!list) return; if (towers.length === 0) { list.innerHTML = '
No towers found
'; return; } list.innerHTML = towers.slice(0, 10).map(tower => `
${tower.radio} ${tower.operator} ${tower.distance_km} km
`).join(''); } // ============== BASELINES ============== async function ismsRefreshBaselines() { try { const response = await fetch('/isms/baselines'); const data = await response.json(); const select = document.getElementById('ismsBaselineSelect'); if (!select) return; // Keep the "No Baseline" option select.innerHTML = ''; data.baselines.forEach(baseline => { const option = document.createElement('option'); option.value = baseline.id; option.textContent = `${baseline.name}${baseline.is_active ? ' (Active)' : ''}`; if (baseline.is_active) option.selected = true; select.appendChild(option); }); } catch (e) { console.error('Failed to load baselines:', e); } } function ismsToggleBaselineRecording() { if (ismsBaselineRecording) { ismsStopBaselineRecording(); } else { ismsStartBaselineRecording(); } } async function ismsStartBaselineRecording() { try { const response = await fetch('/isms/baseline/record/start', { method: 'POST' }); const data = await response.json(); if (data.status === 'recording_started') { ismsBaselineRecording = true; const btn = document.getElementById('ismsRecordBaselineBtn'); const status = document.getElementById('ismsBaselineRecordingStatus'); if (btn) { btn.textContent = 'Stop Recording'; btn.style.background = 'var(--accent-red)'; } if (status) status.style.display = 'block'; ismsNotify('ISMS', 'Baseline recording started'); } } catch (e) { ismsNotify('ISMS Error', 'Failed to start recording'); } } async function ismsStopBaselineRecording() { const name = prompt('Enter baseline name:', `Baseline ${new Date().toLocaleDateString()}`); if (!name) return; try { const response = await fetch('/isms/baseline/record/stop', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ name: name, latitude: ismsLocation.lat, longitude: ismsLocation.lon }) }); const data = await response.json(); if (data.status === 'saved') { ismsBaselineRecording = false; const btn = document.getElementById('ismsRecordBaselineBtn'); const status = document.getElementById('ismsBaselineRecordingStatus'); if (btn) { btn.textContent = 'Record New'; btn.style.background = ''; } if (status) status.style.display = 'none'; ismsNotify('ISMS', `Baseline saved: ${data.summary.bands} bands, ${data.summary.towers} towers`); ismsRefreshBaselines(); } } catch (e) { ismsNotify('ISMS Error', 'Failed to save baseline'); } } // ============== BASELINE PANEL ============== function ismsToggleBaselinePanel() { const content = document.getElementById('ismsBaselineCompare'); const icon = document.getElementById('ismsBaselinePanelIcon'); if (content && icon) { const isVisible = content.style.display !== 'none'; content.style.display = isVisible ? 'none' : 'block'; icon.textContent = isVisible ? '▶' : '▼'; } } // ============== UTILITY ============== function ismsNotify(title, message) { // Use existing notification system if available (defined in audio.js) if (typeof showNotification === 'function' && showNotification !== ismsNotify) { showNotification(title, message); } else { console.log(`[${title}] ${message}`); } } // ============== GSM SCANNING ============== function ismsToggleGsmScan() { if (isGsmScanRunning) { ismsStopGsmScan(); } else { ismsStartGsmScan(); } } async function ismsStartGsmScan() { const band = document.getElementById('ismsGsmBand').value; const gain = parseInt(document.getElementById('ismsGain').value || '40'); const config = { band: band, gain: gain, timeout: 60 }; try { const response = await fetch('/isms/gsm/scan', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(config) }); const data = await response.json(); if (data.status === 'started') { isGsmScanRunning = true; ismsGsmCells = []; updateGsmScanUI('scanning'); // Connect to SSE stream if not already connected if (!ismsEventSource) { connectIsmsStream(); } ismsNotify('ISMS', `GSM scan started on ${band}`); } else { // Update status display with error const statusText = document.getElementById('ismsGsmStatusText'); if (statusText) { statusText.textContent = 'Not Available'; statusText.style.color = 'var(--accent-red)'; } if (data.grgsm_available === false) { ismsNotify('ISMS', 'gr-gsm not installed. GSM scanning requires grgsm_scanner.'); } else { ismsNotify('ISMS Error', data.message || 'Failed to start GSM scan'); } } } catch (e) { ismsNotify('ISMS Error', 'Failed to start GSM scan: ' + e.message); } } async function ismsStopGsmScan() { try { await fetch('/isms/gsm/scan', { method: 'DELETE' }); } catch (e) { console.error('Error stopping GSM scan:', e); } isGsmScanRunning = false; updateGsmScanUI('stopped'); } function updateGsmScanUI(state) { const btn = document.getElementById('ismsGsmScanBtn'); const statusText = document.getElementById('ismsGsmStatusText'); if (state === 'scanning') { if (btn) { btn.textContent = 'Stop Scan'; btn.style.background = 'var(--accent-red)'; } if (statusText) { statusText.textContent = 'Scanning...'; statusText.style.color = 'var(--accent-orange)'; } } else { if (btn) { btn.textContent = 'Scan GSM Cells'; btn.style.background = ''; } if (statusText) { statusText.textContent = 'Ready'; statusText.style.color = 'var(--accent-cyan)'; } } } function handleGsmCell(cell) { // Check if we already have this ARFCN const existing = ismsGsmCells.find(c => c.arfcn === cell.arfcn); if (existing) { // Update if stronger signal if (cell.power_dbm > existing.power_dbm) { Object.assign(existing, cell); } } else { ismsGsmCells.push(cell); } // Update count display const countEl = document.getElementById('ismsGsmCellCount'); if (countEl) { countEl.textContent = ismsGsmCells.length; } // Update cells list updateGsmCellsList(); } function handleGsmScanComplete(data) { isGsmScanRunning = false; updateGsmScanUI('stopped'); // Update with final cell list if (data.cells) { ismsGsmCells = data.cells; updateGsmCellsList(); } const countEl = document.getElementById('ismsGsmCellCount'); if (countEl) { countEl.textContent = data.cell_count || ismsGsmCells.length; } ismsNotify('ISMS', `GSM scan complete: ${data.cell_count} cells found`); } function handleGsmStatus(data) { const statusText = document.getElementById('ismsGsmStatusText'); if (data.type === 'gsm_scanning') { if (statusText) { statusText.textContent = `Scanning ${data.band || 'GSM'}...`; statusText.style.color = 'var(--accent-orange)'; } } else if (data.type === 'gsm_stopped') { isGsmScanRunning = false; updateGsmScanUI('stopped'); if (statusText) { statusText.textContent = `Found ${data.cell_count || 0} cells`; statusText.style.color = 'var(--accent-green)'; } } else if (data.type === 'gsm_error') { isGsmScanRunning = false; updateGsmScanUI('stopped'); if (statusText) { statusText.textContent = 'Error'; statusText.style.color = 'var(--accent-red)'; } ismsNotify('ISMS Error', data.message || 'GSM scan error'); } } function updateGsmCellsList() { const container = document.getElementById('ismsGsmCells'); if (!container) return; if (ismsGsmCells.length === 0) { container.innerHTML = '
No cells detected
'; return; } // Sort by signal strength const sortedCells = [...ismsGsmCells].sort((a, b) => b.power_dbm - a.power_dbm); container.innerHTML = sortedCells.map(cell => { const signalColor = cell.power_dbm > -70 ? 'var(--accent-green)' : cell.power_dbm > -85 ? 'var(--accent-orange)' : 'var(--text-muted)'; const operator = cell.plmn ? getOperatorName(cell.plmn) : '--'; return `
ARFCN ${cell.arfcn} ${cell.power_dbm.toFixed(0)} dBm
${cell.freq_mhz.toFixed(1)} MHz | ${operator} ${cell.cell_id ? ` | CID: ${cell.cell_id}` : ''}
`; }).join(''); } function getOperatorName(plmn) { // UK operators const operators = { '234-10': 'O2', '234-15': 'Vodafone', '234-20': 'Three', '234-30': 'EE', '234-31': 'EE', '234-32': 'EE', '234-33': 'EE', }; return operators[plmn] || plmn; } async function ismsSetGsmBaseline() { if (ismsGsmCells.length === 0) { ismsNotify('ISMS', 'No GSM cells to save. Run a scan first.'); return; } try { const response = await fetch('/isms/gsm/baseline', { method: 'POST', headers: { 'Content-Type': 'application/json' } }); const data = await response.json(); if (data.status === 'saved') { ismsNotify('ISMS', `GSM baseline saved: ${data.cell_count} cells`); } else { ismsNotify('ISMS Error', data.message || 'Failed to save baseline'); } } catch (e) { ismsNotify('ISMS Error', 'Failed to save GSM baseline'); } } // Export for global access window.initIsmsMode = initIsmsMode; window.ismsToggleScan = ismsToggleScan; window.ismsRefreshTowers = ismsRefreshTowers; window.ismsUseGPS = ismsUseGPS; window.ismsSetManualLocation = ismsSetManualLocation; window.ismsRefreshBaselines = ismsRefreshBaselines; window.ismsToggleBaselineRecording = ismsToggleBaselineRecording; window.ismsToggleBaselinePanel = ismsToggleBaselinePanel; window.ismsToggleGsmScan = ismsToggleGsmScan; window.ismsSetGsmBaseline = ismsSetGsmBaseline;