Add agent ACARS f00b4r0 support and UI state sync

- Agent: Add _detect_acarsdec_fork() for f00b4r0/DragonOS support
- Agent: Use --output json:file, --rtlsdr, -m 256 for f00b4r0 fork
- UI: Add setAcarsRunning() to sync button state with agent
- UI: Add 'acars' to syncModeUI uiSetters map
This commit is contained in:
cemaxecuter
2026-01-27 10:20:53 -05:00
parent d3cb20cdae
commit 717dec4e54
3 changed files with 75 additions and 5 deletions

View File

@@ -2357,6 +2357,37 @@ class ModeManager:
# ACARS MODE (acarsdec)
# -------------------------------------------------------------------------
def _detect_acarsdec_fork(self, acarsdec_path: str) -> str:
"""Detect which acarsdec fork is installed.
Returns:
'--output' for f00b4r0 fork (DragonOS)
'-j' for TLeconte v4+
'-o' for TLeconte v3.x
"""
try:
result = subprocess.run(
[acarsdec_path],
capture_output=True,
text=True,
timeout=5
)
output = result.stdout + result.stderr
# f00b4r0 fork uses --output instead of -j/-o
if '--output' in output:
return '--output'
# Parse version for TLeconte
import re
version_match = re.search(r'acarsdec[^\d]*v?(\d+)\.(\d+)', output, re.IGNORECASE)
if version_match:
major = int(version_match.group(1))
return '-j' if major >= 4 else '-o'
except Exception:
pass
return '-j' # Default to TLeconte v4+
def _start_acars(self, params: dict) -> dict:
"""Start ACARS decoding using acarsdec."""
gain = params.get('gain', '40')
@@ -2367,10 +2398,24 @@ class ModeManager:
if not acarsdec_path:
return {'status': 'error', 'message': 'acarsdec not found. Install acarsdec.'}
# Build command with JSON output
cmd = [acarsdec_path, '-j', '-r', str(device), '-g', str(gain)]
for freq in frequencies:
cmd.append(freq)
# Detect fork and build appropriate command
fork_type = self._detect_acarsdec_fork(acarsdec_path)
cmd = [acarsdec_path]
if fork_type == '--output':
# f00b4r0 fork (DragonOS): different syntax
cmd.extend(['--output', 'json:file']) # stdout
cmd.extend(['-g', str(gain)])
cmd.extend(['-m', '256']) # 3.2 MS/s for wider bandwidth
cmd.extend(['--rtlsdr', str(device)])
elif fork_type == '-j':
# TLeconte v4+
cmd.extend(['-j', '-g', str(gain), '-r', str(device)])
else:
# TLeconte v3.x
cmd.extend(['-o', '4', '-g', str(gain), '-r', str(device)])
cmd.extend(frequencies)
logger.info(f"Starting acarsdec: {' '.join(cmd)}")

View File

@@ -678,7 +678,8 @@ function syncModeUI(mode, isRunning, agentId = null) {
'pager': 'setPagerRunning',
'adsb': 'setADSBRunning',
'wifi': 'setWiFiRunning',
'bluetooth': 'setBluetoothRunning'
'bluetooth': 'setBluetoothRunning',
'acars': 'setAcarsRunning'
};
const setterName = uiSetters[mode];

View File

@@ -3763,6 +3763,30 @@ sudo make install</code>
});
}
// Sync ACARS UI state (called by syncModeUI in agents.js)
function setAcarsRunning(running, agentId = null) {
isAcarsRunning = running;
const btn = document.getElementById('acarsToggleBtn');
const indicator = document.getElementById('acarsPanelIndicator');
if (running) {
acarsCurrentAgent = agentId;
btn.textContent = '■ STOP ACARS';
btn.classList.add('active');
if (indicator) indicator.classList.add('active');
// Start stream if not already running
if (!acarsEventSource && !acarsPollTimer) {
startAcarsStream(agentId !== null);
}
} else {
btn.textContent = '▶ START ACARS';
btn.classList.remove('active');
if (indicator) indicator.classList.remove('active');
}
}
// Expose to global scope for syncModeUI
window.setAcarsRunning = setAcarsRunning;
function startAcarsStream(isAgentMode = false) {
if (acarsEventSource) acarsEventSource.close();