Autopilot panel: light mode keys from per-mode status datarefs
Key feedback came from decoding the autopilot_state bitfield, whose bit positions don't reliably match X-Plane (e.g. bit 0 is auto-throttle, not the flight director), so several keys (FD/NAV/APR/BC/VS/VNV/FLC) never lit even when the mode was engaged. Read the dedicated *_status datarefs (off/armed/active) — the same source the PFD AFCS bar uses — so every key and the lateral/vertical annunciator reflect the real mode. NAV also lights on GPS-coupled (gpss) mode. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -6,19 +6,22 @@ import { num } from '../api/useXplane.js';
|
|||||||
// of lit mode keys, and selectors (HDG / ALT / VS / IAS) with knob steppers.
|
// of lit mode keys, and selectors (HDG / ALT / VS / IAS) with knob steppers.
|
||||||
// Buttons fire X-Plane's own autopilot commands; the sim stays the source of truth.
|
// Buttons fire X-Plane's own autopilot commands; the sim stays the source of truth.
|
||||||
|
|
||||||
const AP_BITS = {
|
// Per-mode autopilot status (0 off · 1 armed · 2 active) — the same reliable
|
||||||
fd: 1 << 0, hdg: 1 << 1, vs: 1 << 4, flc: 1 << 6,
|
// datarefs the PFD AFCS bar uses. The old approach decoded a single
|
||||||
nav: 1 << 8, apr: 1 << 9, vnav: 1 << 11, altHold: 1 << 14, bc: 1 << 18,
|
// autopilot_state bitfield, whose bit positions don't reliably match X-Plane
|
||||||
};
|
// (e.g. bit 0 is auto-throttle, not the flight director), so several mode keys
|
||||||
const on = (s, b) => (num(s) & b) !== 0;
|
// never lit up. Reading the dedicated *_status datarefs lights every key.
|
||||||
|
|
||||||
export default function AutopilotPanel({ xp }) {
|
export default function AutopilotPanel({ xp }) {
|
||||||
const { values: V, command, setDataref } = xp;
|
const { values: V, command, setDataref } = xp;
|
||||||
const s = num(V.apState);
|
const lit = (k) => num(V[k]) > 0; // armed or active
|
||||||
const eng = num(V.apEngaged) > 0;
|
const apMode = num(V.apMode); // 0 off · 1 FD · 2 AP
|
||||||
|
const eng = num(V.apEngaged) > 0 || apMode >= 2;
|
||||||
|
const fdOn = apMode >= 1 || eng;
|
||||||
|
|
||||||
const lateral = on(s, AP_BITS.apr) ? 'APR' : on(s, AP_BITS.nav) ? 'NAV' : on(s, AP_BITS.hdg) ? 'HDG' : 'ROL';
|
const lateral = lit('aprStatus') ? 'APR' : lit('gpssStatus') ? 'GPS' : lit('navStatus') ? 'VOR'
|
||||||
const vertical = on(s, AP_BITS.flc) ? 'FLC' : on(s, AP_BITS.vs) ? 'VS' : on(s, AP_BITS.vnav) ? 'VNV' : on(s, AP_BITS.altHold) ? 'ALT' : 'PIT';
|
: lit('bcStatus') ? 'BC' : lit('hdgStatus') ? 'HDG' : 'ROL';
|
||||||
|
const vertical = lit('gsStatus') ? 'GS' : lit('flcStatus') ? 'FLC' : lit('vsStatus') ? 'VS'
|
||||||
|
: lit('vnavStatus') ? 'VNV' : lit('altStatus') ? 'ALT' : 'PIT';
|
||||||
|
|
||||||
const Key = ({ label, cmd, active }) => (
|
const Key = ({ label, cmd, active }) => (
|
||||||
<button className={`apk ${active ? 'on' : ''}`} onClick={() => command(cmd)}>{label}</button>
|
<button className={`apk ${active ? 'on' : ''}`} onClick={() => command(cmd)}>{label}</button>
|
||||||
@@ -42,7 +45,7 @@ export default function AutopilotPanel({ xp }) {
|
|||||||
{/* annunciator bar */}
|
{/* annunciator bar */}
|
||||||
<div className="afcs-ann">
|
<div className="afcs-ann">
|
||||||
<span className={`ann ${eng ? 'on' : ''}`}>AP</span>
|
<span className={`ann ${eng ? 'on' : ''}`}>AP</span>
|
||||||
<span className={`ann ${on(s, AP_BITS.fd) ? 'on' : ''}`}>FD</span>
|
<span className={`ann ${fdOn ? 'on' : ''}`}>FD</span>
|
||||||
<span className="ann-sep" />
|
<span className="ann-sep" />
|
||||||
<span className="ann mode on">{lateral}</span>
|
<span className="ann mode on">{lateral}</span>
|
||||||
<span className="ann-gap" />
|
<span className="ann-gap" />
|
||||||
@@ -53,15 +56,15 @@ export default function AutopilotPanel({ xp }) {
|
|||||||
{/* mode keys */}
|
{/* mode keys */}
|
||||||
<div className="afcs-keys">
|
<div className="afcs-keys">
|
||||||
<Key label="AP" cmd="apToggle" active={eng} />
|
<Key label="AP" cmd="apToggle" active={eng} />
|
||||||
<Key label="FD" cmd="fdToggle" active={on(s, AP_BITS.fd)} />
|
<Key label="FD" cmd="fdToggle" active={fdOn} />
|
||||||
<Key label="HDG" cmd="hdg" active={on(s, AP_BITS.hdg)} />
|
<Key label="HDG" cmd="hdg" active={lit('hdgStatus')} />
|
||||||
<Key label="NAV" cmd="nav" active={on(s, AP_BITS.nav)} />
|
<Key label="NAV" cmd="nav" active={lit('navStatus') || lit('gpssStatus')} />
|
||||||
<Key label="APR" cmd="apr" active={on(s, AP_BITS.apr)} />
|
<Key label="APR" cmd="apr" active={lit('aprStatus')} />
|
||||||
<Key label="BC" cmd="backCourse" active={on(s, AP_BITS.bc)} />
|
<Key label="BC" cmd="backCourse" active={lit('bcStatus')} />
|
||||||
<Key label="ALT" cmd="altHold" active={on(s, AP_BITS.altHold)} />
|
<Key label="ALT" cmd="altHold" active={lit('altStatus')} />
|
||||||
<Key label="VS" cmd="vs" active={on(s, AP_BITS.vs)} />
|
<Key label="VS" cmd="vs" active={lit('vsStatus')} />
|
||||||
<Key label="VNV" cmd="vnav" active={on(s, AP_BITS.vnav)} />
|
<Key label="VNV" cmd="vnav" active={lit('vnavStatus')} />
|
||||||
<Key label="FLC" cmd="flc" active={on(s, AP_BITS.flc)} />
|
<Key label="FLC" cmd="flc" active={lit('flcStatus')} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* selectors */}
|
{/* selectors */}
|
||||||
|
|||||||
Reference in New Issue
Block a user