Citation X cockpit profile: full Primus 2000 suite (PFD/MFD/EICAS/AP/RMU)
Add a switchable cockpit-profile selector (Garmin G1000 / Cessna Citation X / GA steam) and recreate the Citation X Honeywell Primus 2000 avionics line-for- line from the X-Plane Citation X + FMS manuals: - CitPFD: attitude w/ FD command bars, speed tape (Vmo barber-pole, Vfe, low- speed red/amber bands), AOA index, altitude tape + trend, VSI, round HSI with CDI/course pointer + VOR/ADF bearing pointers, radar altimeter, minimums, STD/BARO/CRS/HDG bezel. - CitEICAS: twin FAN%/ITT bar gauges, OIL °C/PSI, FUEL (flow/qty PPH·LBS), ELECTRICAL, HYDRAULICS, slat chevron, STAB trim, FLAPS, CAS message stack, softkeys NORM/FUEL-HYD/ELEC/CTRL-POS/ENG + control-position overlay. - CitMFD: Honeywell heading-up arc map, FMS route (magenta active/white future), TCAS, terrain/WX, range arc, ETE/SAT/TAS/GSPD block, clock + ET/FT timer, V-SPEEDS reference card, MFD-setup overlays (TRAFFIC/TERRAIN/APTS/VOR). - CitAP: HDG/NAV/APP/BC · ALT/VNAV/BANK/STBY · FLC/C-O/VS · pitch wheel · AP/YD/M-TRIM/PFD-SEL, FMA bar + lamps from per-mode *_status datarefs. - CitRMU: COM/NAV active+standby tuning, transponder, ADF, TCAS range/mode, IDENT + Nav Source Selector (NAV1/2/FMS, VOR/ADF/FMS bearing source). Integration: all avionics stream live via the X-Plane Web API (new datarefs for N1/N2/ITT, radar-alt, AOA, hydraulics, trim, flaps/slats/gear, control positions, ADF, mach, yaw-damper); the existing fms-sync.lua drives the Citation's built-in FMS (aircraft-agnostic XPLM FMS SDK). Demo seeds added so every panel renders offline. Verified headless via Playwright (no console errors; G1000/GA profiles unaffected). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,100 @@
|
||||
import React, { useState } from 'react';
|
||||
import { num } from '../../api/useXplane.js';
|
||||
|
||||
// ============================================================================
|
||||
// Citation X — Honeywell Primus 2000 Autopilot / Flight Guidance Controller.
|
||||
// Exact button layout per the manual (pages 26-28):
|
||||
// col1: HDG NAV APP BC col2: ALT VNAV BANK STBY
|
||||
// col3: FLC C/O VS center: PITCH WHEEL (NOSE DN / NOSE UP)
|
||||
// col4: AP YD M TRIM PFD SEL
|
||||
// Mode lamps read the per-mode *_status datarefs (0 off · 1 armed · 2 active),
|
||||
// the same reliable source the PFD uses. Buttons fire X-Plane AP commands.
|
||||
// ============================================================================
|
||||
|
||||
export default function CitAP({ xp }) {
|
||||
const V = xp.values || {};
|
||||
const cmd = xp.command;
|
||||
const stat = (k) => num(V[k]); // 0 off · 1 armed · 2 active
|
||||
const apOn = num(V.apEngaged) > 0 || num(V.apMode) >= 2;
|
||||
const ydOn = num(V.ydOn) > 0 || apOn;
|
||||
const [bank, setBank] = useState(false); // BANK (low-bank 17°) — annunc only
|
||||
const [mtrim, setMtrim] = useState(true); // M TRIM (mach trim) — annunc only
|
||||
const [pfdSel, setPfdSel] = useState('PILOT'); // PFD SEL — pilot/copilot guidance
|
||||
|
||||
// active mode strings for the annunciator bar (matches the PFD)
|
||||
const lateral = stat('aprStatus') ? ['APP', stat('aprStatus')] : stat('navStatus') ? ['NAV', stat('navStatus')]
|
||||
: stat('bcStatus') ? ['BC', stat('bcStatus')] : stat('hdgStatus') ? ['HDG', stat('hdgStatus')] : ['ROL', 2];
|
||||
const vertical = stat('gsStatus') ? ['GS', stat('gsStatus')] : stat('vnavStatus') ? ['VNAV', stat('vnavStatus')]
|
||||
: stat('flcStatus') ? ['FLC', stat('flcStatus')] : stat('vsStatus') ? ['VS', stat('vsStatus')]
|
||||
: stat('altStatus') ? ['ALT', stat('altStatus')] : ['PIT', 2];
|
||||
|
||||
// A mode button: green lamp when its status is active(2), amber when armed(1).
|
||||
const lamp = (k) => (stat(k) >= 2 ? 'active' : stat(k) === 1 ? 'armed' : '');
|
||||
const Btn = ({ label, cmd: c, on, cls = '', onClick }) => (
|
||||
<button className={`citap-btn ${on || cls} ${cls}`} onClick={onClick || (() => c && cmd(c))}>
|
||||
<span className="citap-arrow">▸</span>{label}
|
||||
</button>
|
||||
);
|
||||
|
||||
const sel = num(V.apAltBug);
|
||||
|
||||
return (
|
||||
<div className="cit-screen citap-screen">
|
||||
{/* selected references row (alt / hdg / spd / vs) */}
|
||||
<div className="citap-refs">
|
||||
<div><span>ALT SEL</span><b>{Math.round(num(V.apAltBug))}</b></div>
|
||||
<div><span>HDG</span><b>{String(Math.round(num(V.apHdgBug)) % 360).padStart(3, '0')}</b></div>
|
||||
<div><span>IAS/M</span><b>{num(V.mach) >= 0.4 ? num(V.mach).toFixed(2) : Math.round(num(V.apSpdBug))}</b></div>
|
||||
<div><span>VS</span><b>{Math.round(num(V.apVsBug))}</b></div>
|
||||
</div>
|
||||
|
||||
{/* FMA annunciator bar (active = green, armed = white) */}
|
||||
<div className="citap-fma">
|
||||
<span className={lateral[1] >= 2 ? 'fma-act' : 'fma-arm'}>{lateral[0]}</span>
|
||||
<span className="fma-ap">{apOn ? 'AP' : 'FD'}{ydOn ? ' · YD' : ''}</span>
|
||||
<span className={vertical[1] >= 2 ? 'fma-act' : 'fma-arm'}>{vertical[0]}</span>
|
||||
</div>
|
||||
|
||||
<div className="citap-panel">
|
||||
<div className="citap-col">
|
||||
<Btn label="HDG" cmd="hdg" on={lamp('hdgStatus')} />
|
||||
<Btn label="NAV" cmd="nav" on={lamp('navStatus')} />
|
||||
<Btn label="APP" cmd="apr" on={lamp('aprStatus')} />
|
||||
<Btn label="BC" cmd="backCourse" on={lamp('bcStatus')} />
|
||||
</div>
|
||||
<div className="citap-col">
|
||||
<Btn label="ALT" cmd="altHold" on={lamp('altStatus')} />
|
||||
<Btn label="VNAV" cmd="vnav" on={lamp('vnavStatus')} />
|
||||
<Btn label="BANK" on={bank ? 'active' : ''} onClick={() => setBank((v) => !v)} />
|
||||
<Btn label="STBY" cmd="apStby" onClick={() => cmd('apStby')} />
|
||||
</div>
|
||||
<div className="citap-col">
|
||||
<Btn label="FLC" cmd="flc" on={lamp('flcStatus')} />
|
||||
<Btn label="C/O" cls="dim" onClick={() => {}} />
|
||||
<Btn label="VS" cmd="vs" on={lamp('vsStatus')} />
|
||||
</div>
|
||||
|
||||
{/* PITCH WHEEL — VS rate (in VS) or IAS/Mach target (in FLC) */}
|
||||
<div className="citap-wheel">
|
||||
<div className="citap-wlbl">NOSE UP</div>
|
||||
<button className="citap-wbtn" onClick={() => cmd(stat('flcStatus') ? 'spdDown' : 'vsUp')}>▲</button>
|
||||
<div className="citap-wheelface" />
|
||||
<button className="citap-wbtn" onClick={() => cmd(stat('flcStatus') ? 'spdUp' : 'vsDown')}>▼</button>
|
||||
<div className="citap-wlbl">NOSE DN</div>
|
||||
</div>
|
||||
|
||||
<div className="citap-col citap-master">
|
||||
<Btn label="AP" cmd="apToggle" on={apOn ? 'active' : ''} />
|
||||
<Btn label="YD" cmd="yawDamper" on={ydOn ? 'active' : ''} />
|
||||
<Btn label="M TRIM" on={mtrim ? 'active' : ''} onClick={() => setMtrim((v) => !v)} />
|
||||
<Btn label="PFD SEL" onClick={() => setPfdSel((p) => (p === 'PILOT' ? 'COPILOT' : 'PILOT'))} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="citap-foot">
|
||||
AP MASTER engages Yaw Damper automatically · PITCH WHEEL sets V/S rate or FLC speed ·
|
||||
PFD SEL: <b>{pfdSel}</b> guidance{bank ? ' · LOW BANK 17°' : ''}{mtrim ? ' · MACH TRIM' : ''}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user