mirror of
https://github.com/smittix/intercept.git
synced 2026-04-24 06:40:00 -07:00
Update default ACARS frequencies for North America to 131.725/131.825 MHz and add ISS (145.825 MHz) as a selectable APRS frequency region. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
209 lines
9.8 KiB
HTML
209 lines
9.8 KiB
HTML
<!-- ACARS AIRCRAFT MESSAGING MODE -->
|
|
<div id="acarsMode" class="mode-content" style="display: none;">
|
|
<div class="section">
|
|
<h3>ACARS Messaging</h3>
|
|
<div class="info-text" style="margin-bottom: 15px;">
|
|
Decode ACARS (Aircraft Communications Addressing and Reporting System) messages on VHF frequencies (~129-131 MHz). Captures flight data, weather reports, position updates, and operational messages from aircraft.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h3>Region & Frequencies</h3>
|
|
<div class="form-group">
|
|
<label>Region</label>
|
|
<select id="acarsRegionSelect" onchange="updateAcarsMainFreqs()" style="width: 100%;">
|
|
<option value="na">North America</option>
|
|
<option value="eu">Europe</option>
|
|
<option value="ap">Asia-Pacific</option>
|
|
</select>
|
|
</div>
|
|
<div id="acarsMainFreqSelector" style="display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 10px; font-size: 11px;">
|
|
<!-- Populated by JS -->
|
|
</div>
|
|
<div class="form-group">
|
|
<label>Gain (dB, 0 = auto)</label>
|
|
<input type="number" id="acarsGainInput" value="40" min="0" max="50" placeholder="0-50">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="section">
|
|
<h3>Status</h3>
|
|
<div id="acarsStatusDisplay" class="info-text">
|
|
<p>Status: <span id="acarsStatusText" style="color: var(--accent-yellow);">Standby</span></p>
|
|
<p>Messages: <span id="acarsMessageCount">0</span></p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Antenna Guide -->
|
|
<div class="section">
|
|
<h3>Antenna Guide</h3>
|
|
<div style="font-size: 11px; color: var(--text-dim); line-height: 1.5;">
|
|
<p style="margin-bottom: 8px; color: var(--accent-cyan); font-weight: 600;">
|
|
VHF Airband (~130 MHz) — stock SDR antenna may work at close range
|
|
</p>
|
|
|
|
<div style="background: var(--bg-primary); border: 1px solid var(--border-color); border-radius: 4px; padding: 10px; margin-bottom: 10px;">
|
|
<strong style="color: var(--accent-cyan); font-size: 12px;">Simple Dipole</strong>
|
|
<ul style="margin: 6px 0 0 14px; padding: 0;">
|
|
<li><strong style="color: var(--text-primary);">Element length:</strong> ~57 cm each (quarter-wave at 130 MHz)</li>
|
|
<li><strong style="color: var(--text-primary);">Material:</strong> Wire, coat hanger, or copper rod</li>
|
|
<li><strong style="color: var(--text-primary);">Orientation:</strong> Vertical (airband is vertically polarized)</li>
|
|
<li><strong style="color: var(--text-primary);">Placement:</strong> Outdoors, as high as possible with clear sky view</li>
|
|
</ul>
|
|
</div>
|
|
|
|
<div style="background: var(--bg-primary); border: 1px solid var(--border-color); border-radius: 4px; padding: 10px;">
|
|
<strong style="color: var(--accent-cyan); font-size: 12px;">Quick Reference</strong>
|
|
<table style="width: 100%; margin-top: 6px; font-size: 10px; border-collapse: collapse;">
|
|
<tr style="border-bottom: 1px solid var(--border-color);">
|
|
<td style="padding: 3px 4px; color: var(--text-dim);">Primary (N. America)</td>
|
|
<td style="padding: 3px 4px; color: var(--text-primary); text-align: right;">131.725 / 131.825 MHz</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid var(--border-color);">
|
|
<td style="padding: 3px 4px; color: var(--text-dim);">Quarter-wave length</td>
|
|
<td style="padding: 3px 4px; color: var(--text-primary); text-align: right;">57 cm</td>
|
|
</tr>
|
|
<tr style="border-bottom: 1px solid var(--border-color);">
|
|
<td style="padding: 3px 4px; color: var(--text-dim);">Modulation</td>
|
|
<td style="padding: 3px 4px; color: var(--text-primary); text-align: right;">AM MSK 2400 baud</td>
|
|
</tr>
|
|
<tr>
|
|
<td style="padding: 3px 4px; color: var(--text-dim);">Polarization</td>
|
|
<td style="padding: 3px 4px; color: var(--text-primary); text-align: right;">Vertical</td>
|
|
</tr>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<button class="run-btn" id="startAcarsBtn" onclick="startAcarsMode()">
|
|
Start ACARS
|
|
</button>
|
|
<button class="stop-btn" id="stopAcarsBtn" onclick="stopAcarsMode()" style="display: none;">
|
|
Stop ACARS
|
|
</button>
|
|
</div>
|
|
|
|
<script>
|
|
let acarsMainEventSource = null;
|
|
let acarsMainMsgCount = 0;
|
|
|
|
const acarsMainFrequencies = {
|
|
'na': ['131.725', '131.825'],
|
|
'eu': ['131.525', '131.725', '131.550'],
|
|
'ap': ['131.550', '131.450']
|
|
};
|
|
|
|
function updateAcarsMainFreqs() {
|
|
const region = document.getElementById('acarsRegionSelect').value;
|
|
const freqs = acarsMainFrequencies[region] || acarsMainFrequencies['na'];
|
|
const container = document.getElementById('acarsMainFreqSelector');
|
|
|
|
const previouslyChecked = new Set();
|
|
container.querySelectorAll('input:checked').forEach(cb => previouslyChecked.add(cb.value));
|
|
|
|
container.innerHTML = freqs.map(freq => {
|
|
const checked = previouslyChecked.size === 0 || previouslyChecked.has(freq) ? 'checked' : '';
|
|
return `
|
|
<label style="display: flex; align-items: center; gap: 3px; padding: 2px 6px; background: var(--bg-secondary); border-radius: 3px; cursor: pointer;">
|
|
<input type="checkbox" class="acars-main-freq-cb" value="${freq}" ${checked} style="margin: 0; cursor: pointer;">
|
|
<span>${freq}</span>
|
|
</label>
|
|
`;
|
|
}).join('');
|
|
}
|
|
|
|
function getAcarsMainSelectedFreqs() {
|
|
const checkboxes = document.querySelectorAll('.acars-main-freq-cb:checked');
|
|
const selected = Array.from(checkboxes).map(cb => cb.value);
|
|
if (selected.length === 0) {
|
|
const region = document.getElementById('acarsRegionSelect').value;
|
|
return acarsMainFrequencies[region] || acarsMainFrequencies['na'];
|
|
}
|
|
return selected;
|
|
}
|
|
|
|
function startAcarsMode() {
|
|
const gain = document.getElementById('acarsGainInput').value || '40';
|
|
const device = document.getElementById('deviceSelect')?.value || '0';
|
|
const frequencies = getAcarsMainSelectedFreqs();
|
|
|
|
fetch('/acars/start', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ device, gain, frequencies })
|
|
})
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
if (data.status === 'started') {
|
|
document.getElementById('startAcarsBtn').style.display = 'none';
|
|
document.getElementById('stopAcarsBtn').style.display = 'block';
|
|
document.getElementById('acarsStatusText').textContent = 'Listening';
|
|
document.getElementById('acarsStatusText').style.color = 'var(--accent-green)';
|
|
acarsMainMsgCount = 0;
|
|
startAcarsMainSSE();
|
|
} else {
|
|
alert(data.message || 'Failed to start ACARS');
|
|
}
|
|
})
|
|
.catch(err => alert('Error: ' + err.message));
|
|
}
|
|
|
|
function stopAcarsMode() {
|
|
fetch('/acars/stop', { method: 'POST' })
|
|
.then(r => r.json())
|
|
.then(() => {
|
|
document.getElementById('startAcarsBtn').style.display = 'block';
|
|
document.getElementById('stopAcarsBtn').style.display = 'none';
|
|
document.getElementById('acarsStatusText').textContent = 'Standby';
|
|
document.getElementById('acarsStatusText').style.color = 'var(--accent-yellow)';
|
|
if (acarsMainEventSource) {
|
|
acarsMainEventSource.close();
|
|
acarsMainEventSource = null;
|
|
}
|
|
});
|
|
}
|
|
|
|
function startAcarsMainSSE() {
|
|
if (acarsMainEventSource) acarsMainEventSource.close();
|
|
|
|
acarsMainEventSource = new EventSource('/acars/stream');
|
|
acarsMainEventSource.onmessage = function(e) {
|
|
try {
|
|
const data = JSON.parse(e.data);
|
|
if (data.type === 'acars') {
|
|
acarsMainMsgCount++;
|
|
document.getElementById('acarsMessageCount').textContent = acarsMainMsgCount;
|
|
}
|
|
} catch (err) {}
|
|
};
|
|
|
|
acarsMainEventSource.onerror = function() {
|
|
setTimeout(() => {
|
|
if (document.getElementById('stopAcarsBtn').style.display === 'block') {
|
|
startAcarsMainSSE();
|
|
}
|
|
}, 2000);
|
|
};
|
|
}
|
|
|
|
// Check initial status
|
|
fetch('/acars/status')
|
|
.then(r => r.json())
|
|
.then(data => {
|
|
if (data.running) {
|
|
document.getElementById('startAcarsBtn').style.display = 'none';
|
|
document.getElementById('stopAcarsBtn').style.display = 'block';
|
|
document.getElementById('acarsStatusText').textContent = 'Listening';
|
|
document.getElementById('acarsStatusText').style.color = 'var(--accent-green)';
|
|
document.getElementById('acarsMessageCount').textContent = data.message_count || 0;
|
|
acarsMainMsgCount = data.message_count || 0;
|
|
startAcarsMainSSE();
|
|
}
|
|
})
|
|
.catch(() => {});
|
|
|
|
// Initialize frequency checkboxes
|
|
document.addEventListener('DOMContentLoaded', () => updateAcarsMainFreqs());
|
|
</script>
|