The rewrite of the 737NG logic (Zibo's zibomod and the XLua scripts) as one
WASM gauge, lu737_systems.wasm, loaded by panel.cfg
(VCockpit01, WasmInstrument.html?wasm_module=lu737_systems.wasm&wasm_gauge=LU737_Systems).
src/core/ systems code, portable C++20, no MSFS headers (talks to the sim via SimIO)
src/msfs/ MSFS adapter: gauge callback, L:/A: variables through the WASM var API
test/ native unit tests (FakeSimIO)
tools/ check_wasm.py: exports, imports and MVP feature check of the built module
wasm/build.sh test # native tests (ASan/UBSan)
wasm/build.sh # wasm/out/lu737_systems.wasm + check
wasm/build.sh install # also copies it into the package's panel folder
Toolchain: clang/wasm-ld 18 (apt install clang-18 lld-18) with the MSFS 2024
SDK files in third_party/msfs2024-sdk. CI: .github/workflows/build-wasm.yml.
In-sim check (milestone 1)#
With the aircraft loaded, the developer-mode console shows
LU737 systems: initialised, and these L:vars are live (Behaviors debugger or
the Coherent/variable watch):
| L:var | Expected |
|---|---|
LU737_WASM_ALIVE |
1 |
LU737_WASM_BUILD |
kBuildNumber in src/core/version.h (14 for this build) |
LU737_WASM_FRAME |
increasing every frame |
LU737_WASM_TIME |
seconds of simulation since load |
Electrics (milestone 3)#
src/core/elec/electrics.{h,cpp} is Zibo 2.S1.50's electrical system (docs/specs/electrics.md):
Electrics (inputs struct, Zibo command handlers, update(dt), outputs = Zibo's datarefs and the X-Plane
electrical state it keeps itself) and ElecSci (elec_sci.{h,cpp}: SCI states out, SCI events in).
Systems runs it once per frame (Annunciators → Switches → Electric_bus → generators → meters → 2 Hz ground
power, Zibo's order) and publishes the states after it.
Published L:vars (L:LU737_<STATE>, contract data/sci/contract/10_elec.json unless noted):
| Group | States |
|---|---|
| Positions (enum index) | ELEC_BAT_POS, ELEC_STBY_PWR_POS, ELEC_DC_METER_POS (Zibo's index: 3–5 = TR 1–3, 6 = hold), ELEC_AC_METER_POS, ELEC_GPU_POS, ELEC_GEN1/2_POS, ELEC_APUGEN1/2_POS, ELEC_BUS_TRANS_POS, ELEC_DRIVE1/2_DISC_POS, ELEC_CAB_UTIL_POS, ELEC_IFE_POS |
| Guards (0 closed / 1 open) | ELEC_BAT_GRD, ELEC_STBY_PWR_GRD; raw guard positions (0..1, 90_cockpit) BUTTON_SWITCH_COVER_POSITION_4/5/6 |
| Sources | SRC_GPU_AVAIL, SRC_APU_GEN_RDY, SRC_IDG1/2_RDY (Zibo's gen1/2_available) |
| Buses (0/1) | BUS_HOT_BAT, BUS_SW_HOT_BAT (Zibo batbus_status), BUS_BAT (Zibo dir_batbus_status), BUS_DC1/2, BUS_DC_STBY, BUS_AC_STBY, BUS_XFR1/2, BUS_MAIN1/2, BUS_GND_SVC1/2, ELEC_POWERED, ELEC_AC_POWERED, ELEC_STATE |
| Display / device power | DU_*_PWR (Zibo's gate: switched hot battery bus ∧ DC STBY or DC 2 ∧ 32 s warm-up ∧ content), CDU1/2_PWR (DC STBY / DC 2 ∧ 30 s boot), ISFD_PWR (battery bus), MCP_PWR, EFIS_CPT/FO_PWR, RADIO1/2_PWR, CLOCK_PWR, ELEC_METER_PWR, ELEC_DC_VOLTS, ELEC_AC_VOLTS |
| Lights (brightness 0..1) | ANN_BAT_DISCHARGE, ANN_TR_UNIT, ANN_ELEC, ANN_STBY_PWR_OFF, ANN_GRD_PWR_AVAIL, ANN_DRIVE1/2, ANN_TRANS_BUS_OFF1/2, ANN_SOURCE_OFF1/2, ANN_GEN_OFF_BUS1/2, ANN_APU_GEN_OFF_BUS, ANN_SIXPACK_ELEC |
| X-Plane values the model reads (90_cockpit) | SIM_COCKPIT2_ELECTRICAL_BUS_VOLTS_0, SIM_COCKPIT_ELECTRICAL_AVIONICS_ON |
Placeholders in Systems |
TOGGLE_SWITCH_BRIGHT_TEST (−1 DIM, 0 BRT, 1 TEST) |
SRC_APU_GEN_RDY is the APU's apu_bus_enable (section APU); the APU's own states are published by ApuSci.
Events handled (Systems::event(control, action, arg) or Systems::eventByName("LU737_<CONTROL>_<ACTION>");
results OK, BLOCKED_GUARD, REJECTED, UNKNOWN as the oracle's acks):
| Control | Actions | Behaviour |
|---|---|---|
ELEC_BAT, ELEC_STBY_PWR |
INC, DEC, TOGGLE, SET_n, GUARD_TOGGLE/OPEN/CLOSE, RELEASE | under a closed guard a click only opens the guard (BLOCKED_GUARD); closing the guard forces BAT ON / STBY AUTO (Zibo) |
ELEC_BAT_GRD, ELEC_STBY_PWR_GRD |
TOGGLE, PRESS, SET_n, GUARD_* | guard target |
ELEC_GPU, ELEC_GEN1/2, ELEC_APUGEN1/2 |
INC, DEC, SET_0/1/2, PRESS, RELEASE | spring: OFF/ON held until RELEASE (command begin/end) |
ELEC_DC_METER, ELEC_AC_METER |
INC, DEC, SET_n | one Zibo step per position |
ELEC_BUS_TRANS, ELEC_DRIVE1/2_DISC, ELEC_CAB_UTIL, ELEC_IFE |
INC, DEC, TOGGLE, SET_n | BUS TRANSFER is held at AUTO while its guard is closed |
BUS_TRANSFER_COVER, DRIVE_DISCONNECT_COVER_1, DRIVE_DISCONNECT_2_COVER |
PRESS (RELEASE ignored) | toggles the guard |
MASTER_CAUTION_ACCEPT, MASTER_CAUTION_ACCEPT_2 |
PRESS, RELEASE | clears the ELEC and APU six-pack latches (other systems later) |
LIGHTS_TEST_BRIGHTNESS_CONTROL |
INC, DEC | placeholder of the annunciator subsystem (Zibo bright_test_up/dn) |
The EFB ground-power cart (laminar/B738/gpu_toggle) is Electrics::cmdGpuToggle(); MSFS
EXTERNAL POWER AVAILABLE:1 acts as a powered jetway (Zibo's SAM source).
Inputs from other subsystems (Systems::readSimInputs): engine N2 = Zibo's N2 written to X-Plane
(Engines n2Xp, build 6; before: MSFS TURB ENG N2:n), start levers = Zibo's mixture_ratio1/2; not
written yet: annunciator brightness from the BRT/DIM switch, day factor 1;
glideslope/autoland DC-tie opening = never; on ground / ground speed / radio height from SIM ON GROUND,
GROUND VELOCITY, RADIO HEIGHT. Flight start: cold & dark, or engines running when MSFS starts with
combustion.
Differential tests: test/sci_script_runner.cpp runs the oracle's scripts xphost/test/sci/elec_spec_battery,
elec_spec_sources, elec_cold_start, elec_degraded on the rewrite with the same checks (all steps, the
APU ones included since build 5), and compares elec_trace.json frame by frame with the oracle's trace in
test/data/elec_trace_oracle.txt (regeneration command in the script). LU737_SCI_VERBOSE=1 wasm/out/lu737_tests sci_ prints every check.
APU (milestone 3b, build 5)#
src/core/apu/apu.{h,cpp} is Zibo 2.S1.50's APU controller (docs/specs/apu.md): Apu (inputs struct,
Zibo command handlers, update(dt), outputs = Zibo's APU datarefs) and XPlaneApu, the X-Plane APU that
Zibo commands (APU_start held 1 s, APU_on, APU_off) and reads (N1, running), modelled from the .acf
values (spec §7): with DC power, APU_start opens the inlet door over 9 s, then N1 rises 0 → 100 % in 53 s,
running from 50 %; APU_off: 7 s cool-down, N1 100 → 0 % in 18 s, running clears below 50 %, door closes in
9 s; the EFB failure APU STARTING/RUNNING (rel_apu) spools it down for good. The MSFS APU stays off
(its N1 would block Zibo's start at ≥ 7 %, spec finding 3); the module neither reads nor drives it.
ApuSci (apu_sci.{h,cpp}) publishes the states and handles the events.
Systems runs it every frame after the electrics (Zibo runs the APU timers/lights in Annunciators and the
controller after Electric_bus; nothing of it feeds back into the electrics within the frame): inputs from
the electrics of this frame (switched hot battery bus, DC 2, transfer-bus sources and loads, annunciator
brightness, APU-generator failure), then apu_bus_enable goes to the electrics (their next frame, as in
Zibo, and SRC_APU_GEN_RDY of this frame).
Published L:vars (L:LU737_<STATE>):
| Group | States |
|---|---|
| Switch | APU_SW_POS (0 OFF, 1 ON, 2 START), TOGGLE_SWITCH_BLEED_AIR_APU_POS |
| Sources | SRC_APU_RUNNING (APU N1 > 95 %, profile), SRC_APU_GEN_RDY (apu_bus_enable, published by ElecSci) |
| Lights (0..1) | ANN_APU_LOW_OIL, ANN_APU_FAULT, ANN_APU_MAINT, ANN_APU_OVERSPEED, ANN_SIXPACK_APU; ANN_APU_GEN_OFF_BUS (electrics) |
| Gauges (90_cockpit, raw) | ELECTRICAL_APU_TEMP (EGT needle 0..100), ELECTRICAL_APU_DOOR (0..1) |
| Diagnostics (not in the contract) | APU_N1 (%), APU_RUNNING (X-Plane's flag), APU_EGT (Zibo's EGT, ≈ °C/10), APU_BLEED_PSI (air/apu_psi), APU_BLEED_VALVE |
Events:
| Control | Actions | Behaviour |
|---|---|---|
APU_SW |
INC, DEC, SET_n, DRAG, RELEASE | OFF ↔ ON; INC from ON = START (Zibo APU_start_pos_dn held), RELEASE springs back to ON and starts the APU. START is shown at least 0.5 s (contract momentary, profile min_hold_s): a release within 0.5 s is applied when the 0.5 s are over. No 7 s gate (the old host's, spec §6.2). |
APU_BLEED_AIR |
PRESS (TOGGLE), RELEASE, SET_n | toggles bleed_air_apu_pos |
Inputs (apu::Inputs, Systems::readApuInputs): TAT = TOTAL AIR TEMPERATURE, elevation = PLANE ALTITUDE, barometer = AMBIENT PRESSURE, tank contents = FUEL TANK LEFT MAIN / CENTER / RIGHT MAIN QUANTITY
× FUEL WEIGHT PER GALLON; packs, isolation valve, APU leak (pneumatics) and start / starter valves (engines)
of the previous frame since build 6. Not modelled yet: fuel pumps off, LOW PRESSURE lights lit, crossfeed
closed (fuel system), fire handle in, no fire (fire system). The APU's fuel burn is computed (Outputs::fuelBurnt, kg per tank) but not applied to MSFS's
tanks yet (fuel system). The APU start load is not added to the electrics' bus loads.
Differential tests: apu_spec_start and apu_spec_delay_fault (oracle scripts, same checks) and
apu_trace.json frame by frame against test/data/apu_trace_oracle.txt (EGT not compared while the APU
bleed loads the APU: it scales with Zibo's per-flight random maximum bleed pressure). The oracle has no
X-Plane APU, so the scripts inject APU_N1_percent / APU_running; the runner feeds exactly these values to
the controller (Inputs::n1/running overrides), so Zibo's logic is compared on the same trajectory, and it
reproduces the oracle host's 7 s START gate for APU_SW_INC events (the elec scripts' timing assumes it). The
own spool, cool-down, ON during cool-down, faults (start failure → FAULT at 120 s, OVERSPEED, LOW OIL
QUANTITY, battery off), fuel supply and the events are unit-tested in test/test_apu.cpp.
Pneumatics (milestone 3c, build 6)#
src/core/pneu/pneumatics.{h,cpp} is Zibo 2.S1.50's bleed air (docs/specs/pneumatics.md §4.2–4.6, §4.8):
engine 5th/9th-stage pressure (pneu_fn), HP valve (9th stage regulated to 38 psi, 5th-stage latch 34/38 psi),
PRSOV (duct regulated to 50 psi), precooler and duct temperature, bleed trip latch and TRIP RESET, ground air
cart (48 psi, 6 psi/s), isolation valve (CLOSE / AUTO / OPEN, motor on AC transfer bus 1), duct pressures L/R
(real for the logic, gauge frozen without AC transfer bus 2) and the load sharing between engines, APU and
ground air (packs 4, wing 8, cowl 4, starter 2 × 5 psi; the APU leak goes back to the APU for the next frame),
pack valves (≥ 4 psi, battery bus), X-Plane bleed mode and DUAL BLEED, PACK lights (AC loss latch), and the
bleed side of the engine cowl and wing anti-ice (valves, ground logic, lift-off trip-off, VALVE OPEN lights).
The APU bleed (warm-up, raw pressure, load control with the packs, APU bleed valve) stays in apu::Apu; the
pneumatics take its output pressure and the valve position of the previous frame. The "start valve opened
with the packs AUTO soon after the APU came up" quirk (spec §6.3) follows from Zibo's numbers: the APU valve
cycles and the ducts stay at about 3–9 psi, the starter does not turn (test_engines.cpp).
Not in this build: pressurization (§4.7: cabin altitude / rate / differential, AUTO / ALTN / MAN, FLT/LAND
ALT, outflow valve; next step), the zone temperatures (§4.9), WING-BODY OVERHEAT, the COWL ANTI-ICE (ice)
lights, X-Plane's bleed actuators (no MSFS meaning). PneuSci publishes and handles:
| Group | States (L:LU737_<STATE>) |
|---|---|
| Switches (raw Zibo values) | TOGGLE_SWITCH_BLEED_AIR_1/2_POS, AIR_L/R_PACK_POS (0 OFF, 1 AUTO, 2 HIGH), AIR_ISOLATION_VALVE_POS (0 CLOSE, 1 AUTO, 2 OPEN), AIR_L/R_RECIRC_FAN_POS, AIR_TRIM_AIR_POS, PUSH_BUTTON_TRIP_RESET, PUSH_BUTTON_DUCT_OVHT_TEST_POS, ICE_ENG1/2_HEAT_POS, ICE_WING_HEAT_POS |
| Gauge, lights | INDICATORS_DUCT_PRESS_L/R (psi), ANNUNCIATOR_DUAL_BLEED, ANNUNCIATOR_BLEED_TRIP_1/2, ANNUNCIATOR_PACK_LEFT/RIGHT, ANNUNCIATOR_COWL_ICE_ON_0/1, ANNUNCIATOR_WING_ICE_ON_L/R |
| Diagnostics (not in the contract) | PNEU_DUCT_L/R (real duct psi), PNEU_ISO_VALVE, PNEU_PACK_VALVE_L/R, PNEU_ENG1/2_PSI (engine bleed after the PRSOV), PNEU_PRSOV_1/2, PNEU_ASU_PSI, PNEU_APU_LEAK, PNEU_ASU_CONNECTED |
| Control | Actions | Behaviour |
|---|---|---|
ENGINE_1/2_BLEED_AIR, LEFT/RIGHT_RECIRC_FAN, TRIM_AIR, ENGINE_1/2_ANTI_ICE, WING_ANTI_ICE |
PRESS/TOGGLE (RELEASE ignored), INC/DEC/SET_n | toggle on press (Zibo command begin) |
L_PACK, R_PACK, ISOLATION_VALVE |
INC (Zibo _up: toward OFF / CLOSE), DEC (toward HIGH / OPEN), SET_n, RELEASE |
one step per event |
BLEED_TRIP_RESET, DUCT_OVERHEAT |
PRESS, RELEASE | held while pressed |
Ground air cart: the EFB is not rewritten yet; L:LU737_ENGINE_AIR_START = 1 connects it (Zibo's
laminar/B738/engine/engine_air_start). Inputs: elevation from AMBIENT PRESSURE (Zibo's formula), OAT =
AMBIENT TEMPERATURE, on ground / RA; fire handles in (fire system not written).
Engines and engine start (milestone 3c, build 6)#
src/core/engine/engines.{h,cpp} is Zibo's CFM56-7B26 engine logic (docs/specs/engine_start_and_dynamics.md)
on the bit-exact tables of cfm56_7b.* and the helpers of engine_fn (spool-down tables, start EGT tables,
Animate_physical3, fuel-flow corrections, throttle-use mapping; all compared bit for bit with the original
functions in test_engine_zibo.cpp). Two phases in Zibo's frame order (spec App. A): front() = Idle_mode,
Engine_n1_n2, Thr_shift, Eicas_thrust, Xbleed_start, Starter, Engine_calculation, Engine_model
(before the electrics); systems() = the start-switch part of Systems (after the electrics, APU and bleed air):
knob animation and solenoid release (55.3–58 % N2), ignition (IGN L / BOTH / R, CONT, FLT, auto-relight, restart
lock-out, igniter power from AC transfer / AC standby), start valves (2.5 s) and starter valves, EGT start limit and
hot start (EEC abort > 710 °C), ground-air start code, EICAS energise; the fuel spar / engine valves (Zibo's
Annunciators, part of the future fuel system).
X-Plane's engine (spec §7.1, modelled here): burns fuel once Zibo's lagged mixture (start lever, 1/s) is above
0.1 with the ignition key on (from 25 % N2, or FLT windmill) and fuel in a tank; stops when the lagged mixture
falls to 0.1 (≈ 2.3 s after CUTOFF), without fuel, or in the restart lock-out. The threshold is one constant
(kMixtureBurn) until it is measured in X-Plane (spec §9 Q1). Oil temperature input = MSFS GENERAL ENG OIL TEMPERATURE:n (spec §7.2: "until measured, use MSFS's"). Not modelled yet: failures and flameouts (§4.12),
reversers (§4.14, the engines stay in forward thrust), A/T, fuel tank selection (fuel available while a tank
holds > 150 kg), engine icing, precipitation.
EngineSci publishes and handles:
| Group | States (L:LU737_<STATE>) |
|---|---|
| Controls (raw Zibo values) | ENGINE_STARTER1/2_POS (0 GRD, 1 OFF, 2 CONT, 3 FLT; fractional while the knob moves), ENGINE_STARTER1/2_POS2, TOGGLE_SWITCH_ENG_START_SOURCE (−1 IGN L, 0 BOTH, 1 IGN R), ENGINE_MIXTURE_RATIO1/2 (start levers 0 CUTOFF … 1 IDLE), ENGINE_THRUST1/2/12_LEVELER, SIM_COCKPIT2_ENGINE_ACTUATORS_FADEC_ON_0/1 (EEC), BUTTON_SWITCH_COVER_POSITION_0/1 (EEC guards), ENGINE_ROT_ANG0/1 (fan angle) |
| Diagnostics (not in the contract; the EICAS comes with M4) | ENGn_N1, ENGn_N2 (indicated %), ENGn_EGT (°C), ENGn_FF (kg/s), ENGn_OIL_PRESS (psi), ENGn_OIL_TEMP (°C), ENGn_START_VALVE (0..1, START VALVE OPEN), ENGn_IGNITION (X-Plane ignition key 0..3), ENGn_RUNNING (X-Plane burning), ENGn_N1_CMD (commanded N1 %), ENGn_VIB, ENGn_EICAS_ON (FF readout energised), ENG_IDLE_N1, ENG_IDLE_N2, ENG_IDLE_MODE |
| Control | Actions | Behaviour |
|---|---|---|
ENGINE_1/2_STARTER |
DEC (Zibo engN_start_left: toward GRD), INC (toward FLT), SET_n (rotary command), RELEASE ignored |
one position per event; GRD is held by the solenoid until 55.3–58 % N2 |
ENGINE_START_SOURCE |
INC (toward IGN R), DEC (toward IGN L) | |
MIXTURE_ENGINE_1/2 |
INC / DEC (± 0.1, Zibo profile), SET_n | lever drag |
MIXTURE_ENGINE_1_2, MIXTURE_ENGINE_2_2 |
TOGGLE (CUTOFF ↔ IDLE) | lever click |
EEC_1/2 |
TOGGLE, SET_n | X-Plane fadec_on |
EEC_1/2_GATE |
PRESS | guard |
THROTTLE_ENGINE_1/2, THROTTLE_ALL |
INC / DEC (± 0.1) | moves the MSFS throttle (K:THROTTLEn_SET), see below |
Differential tests: pneu_spec_ground_air (21 checks), pneu_spec_apu_bleed (17) and start_spec_eng1_ground
(12) pass on the rewrite as on the oracle (the X-Plane light-off and APU N1 are injected as in the oracle);
start_trace.json (engine 1 and 2 start on ground air, ground air removed, shutdown) is compared frame by frame
with test/data/start_trace_oracle.txt (8197 frames × 33 values: start switches, start/starter valves, ducts,
isolation valve, engine 1 bleed, N1/N2 indicated and X-Plane, EGT, oil, fuel flow, ignition, mixture, EICAS
flags, ground-air start code). Zibo draws a random EGT offset per engine and flight (egt_rnd, ±5 °C, seeded
with the clock): the runner takes it from the settled idle EGTs (calibrate_egt_frame), then every value must
agree. The APU-bleed motoring after the quirk is chaotic (valve cycling) and depends on Zibo's random maximum APU
pressure, so it is compared qualitatively (test_engines.cpp).
MSFS engines (milestone 3c, build 6)#
Zibo's engine is what the cockpit shows; MSFS's own engine gives sound, exterior effects and thrust, and runs
whenever Zibo's engine burns fuel (Systems::coupleMsfsEngines). Thrust in this build comes from MSFS's
engine model and the throttle position, so MSFS's N1 differs from Zibo's (spec §7.3 option 2, the closed-loop
N1 follow, is the next step). SimVars and events used:
| Use | SimVar / K: event |
|---|---|
| Start MSFS engine k (on Zibo light-off) | K:MASTER_BATTERY_ON (only if ELECTRICAL MASTER BATTERY:1 is 0: the MSFS fuel valves need its bus), K:FUELSYSTEM_VALVE_OPEN k (spar valve k), K:MIXTURE1_SET / K:MIXTURE2_SET 16383, K:CONDITION_LEVER_k_SET 1 (low idle; with DisableMixtureControls its 0 is fuel cutoff, build 23), K:TURBINE_IGNITION_SWITCH_SETk 1, write GENERAL ENG COMBUSTION:k = 1 |
| Stop MSFS engine k (Zibo stops burning: start lever CUTOFF) | write GENERAL ENG COMBUSTION:k = 0, K:FUELSYSTEM_VALVE_CLOSE k, K:MIXTUREk_SET 0, K:CONDITION_LEVER_k_SET 0 |
| Retry | if GENERAL ENG COMBUSTION:k still disagrees after 5 s: the request again, and for a start K:SET_STARTERk_HELD 1 until MSFS lights (then 0) |
| MSFS fuel feed (build 22) | while Zibo's engine k burns: K:ELECTRICAL_CIRCUIT_TOGGLE for its pump / spar valve circuits that are off, K:FUELSYSTEM_PUMP_ON for its main tank pumps (once a second); diagnostics L:LU737_MSFS_ENGn_* (TEST_PLAN build 23) |
| Thrust levers | read GENERAL ENG THROTTLE LEVER POSITION:k (%, negative = reverse range → 0); cockpit lever events send K:THROTTLE1_SET / K:THROTTLE2_SET (0..16383) |
| Flight start | GENERAL ENG COMBUSTION:1/2 at the first frame: engines-running state (start levers IDLE, N2 58.5 %, packs AUTO, isolation AUTO) |
| Environment | TOTAL AIR TEMPERATURE, AMBIENT TEMPERATURE, AMBIENT PRESSURE (inHg; Pa = × 3386.389), AMBIENT DENSITY (σ = ρ / 1.225), AIRSPEED MACH, AIRSPEED TRUE, AIRSPEED INDICATED, PRESSURE ALTITUDE, PLANE ALTITUDE, RADIO HEIGHT, SIM ON GROUND, GROUND VELOCITY, TOTAL WEIGHT, AMBIENT WIND VELOCITY / DIRECTION, PLANE HEADING DEGREES MAGNETIC, FLAPS HANDLE PERCENT, tank quantities, GENERAL ENG OIL TEMPERATURE:k |
The electrics' engine generators now use Zibo's N2 (no MSFS engine values are read for the systems). An MSFS engine started by other means (MSFS auto-start, key bindings) is stopped again after 5 s while Zibo's engine is not running.
Upper EICAS states (build 9)#
EngineSci also publishes, per engine, Zibo's EICAS flags the upper EICAS needs (docs/EICAS.md):
LU737_ENGn_EICAS_OIL_PRESS, _EICAS_OIL_TEMP (readouts energised), _EGT_REDLINE (start EGT limit
mark), _EGT_HOTSTART (0, 1 hot start below 725 C, 2 above). Test: eicas_flags_follow_the_engine_start.
(Builds 7 and 8 were a dataref mirror for the bitmap-interpreter EICAS, reverted in 1d51041.)
Display units (milestone 4c, build 10)#
display/display_units.* (docs/LOWER_DU.md): Zibo's lower DU page selection (MFD ENG / SYS SCI events,
forced ENG page without AC transfer bus 2, auto display on engine out / start lever CUTOFF airborne /
exceedance), the LevelUp page transition, the compact-format warning (10 s flash) and the "was red"
exceedance latches. Frame order as zibomod: engine-out check before the engine model, warnings after
it, page transition with the systems. Published: LU737_LOWER_DU_PAGE, _LOWER_DU_PAGE2,
_FF_EICAS_SHOW, _DU_LU_INIT, _EICAS_WARN, _ENGn_OUT, _ENGn_WAS_N1_RED / _N2_RED / _EGT_RED.
Tests: lower_du_pages_and_compact_warning, lower_du_engine_page_on_start_lever_cutoff_in_flight.
IRS (milestone 4d, build 15)#
irs/irs.* (docs/specs/irs.md): Zibo's IRS (B738.LATLON.lua): mode selectors (H:LU737_IRS_LEFT /
_RIGHT _INC / _DEC), IRS source switch (H:LU737_IRS_SOURCE_*), ADIRU power, self-test, alignment
(real / quick / ATT), shutdown cycle, motion restart, lights, PFD/ND flags. Option L:LU737_IRS_ALIGN_TIME
(0 real, 1 fast 60 s, 2 instant, 3 long 150 s). Until the IRS display unit / FMC POS INIT are rewritten,
the present position (and the ATT heading) is entered automatically. Published: LU737_IRS_L_MODE,
_R_MODE, _L_REMAIN, _R_REMAIN, LU737_ANNUNCIATOR_IRS_*, LU737_IRS_PFD_ALLIGN*, _ND_ALLIGN*, etc.
Timers as XLua's (float sim time), Lua arithmetic in doubles. Tests: sci_trace_irs_matches_oracle
(frame by frame against the oracle, 14 445 frames), irs_* in test_irs.cpp.
PFD speed bands (build 16)#
speeds/speeds.* (docs/PFD.md): Zibo's B738_calc_min_max_spd (737-800): minimum speed, maximum speed,
manoeuvre bands and show flags, L:LU737_PFD_*. Test: sci_trace_speeds_matches_oracle (0 mismatches over
2550 frames; the script's runner_fms_phase gives the FMS flight phase the oracle traced).
EFIS control panel (build 17)#
efis/efis.* (docs/PFD.md): MINS / BARO / STD / MTRS / FPV of both EFIS control panels, the PFD minimums
alert and baro boxes; the captain's setting drives MSFS altimeter 1. Tests: sci_trace_efis_matches_oracle
(0 mismatches), efis_* in test_efis.cpp.
NAV radios (build 18)#
nav/nav_radio.* (docs/PFD.md): NAV 1 / 2 standby tuning and transfer (MSFS receivers follow), MMR mode,
station identification (6.5 s), VHF NAV source switch, L:LU737_FMS_HIDE_MMR = 1. Tests: nav_* in test_nav.cpp.
MSFS fuel feed (build 22)#
MSFS's engines draw through electric tank pumps (flight_model.cfg FUEL_SYSTEM v4) on MSFS circuits; since the
systems-module rewrite nothing turned them on (owner: fuel pressure 0, no combustion, no thrust). While Zibo's engine
k burns, Systems::coupleMsfsEngines keeps its main tank pumps (K:FUELSYSTEM_PUMP_ON 1-2 / 3-4) and the circuits
2-3 / 4-5 and spar valve circuit 9 / 10 (K:ELECTRICAL_CIRCUIT_TOGGLE when CIRCUIT SWITCH ON reads off) on, once a
second. engines.cfg: ignition_auto_type = 1, min_condition_lever_for_combustion = 0. Diagnostics
L:LU737_MSFS_ENGn_N1 / N2 / COMBUSTION / FF / FUELPRESS / PUMPS / CIRCUITS / VALVE / WANT, L:LU737_MSFS_BUS_VOLTS.
Also: the gauge's K: table now has KOHLSMAN_SET and the NAV frequency events (missing since builds 17-18).
engines.cfg from the engine model (tools)#
tools/engine_sweep.sh builds tools/engine_sweep.cpp with the engine sources and prints Zibo's steady states
(lever × pressure altitude × Mach, ISA, ground and airborne) and Zibo's thrust table as JSON; the output is
committed as data/msfs/zibo_engine_sweep.json and read by tools/msfs/engine_schedule.py to generate
engines.cfg's N1 schedule, thrust and fuel-flow tables (docs/FDE_TUNING.md, "Engine schedule from Zibo").
Re-run both after a change to the engine model:
wasm/tools/engine_sweep.sh > data/msfs/zibo_engine_sweep.json
python3 tools/msfs/generate_configs.py --out msfs2024
Throttle jumping to idle (open)#
Owner report: after the engine start the throttle sometimes jumps back to idle. Build 11 tried a throttle guard (no MSFS engine re-start while its N1 is above 15 %, throttle put back after a re-send, diagnostic counters); it did not solve it and was reverted in build 14. Still open, to be fixed later.
Hot-start abort (build 12)#
Owner report: during a start the EGT reached about 710 C and then jumped to about 1000 C. Cause: Zibo's
EEC hot-start protection eec_hotstart is a latch (zibomod Systems), the rewrite evaluated it per
frame — the ignition came back the frame after the cut, the start EGT logic re-captured its motoring base
at the hot EGT and its target jumped to ~1100 C. Also hot_start_warn was cleared above 725 C and on a
flat EGT, which Zibo does not do. Both now as zibomod (spec §4.11.4 corrected). Oracle checks: wet start
on ground air and wet start with the thrust lever at 5 % abort at ~711 C, EGT falls, N2 hangs at 29.6 %
(wet_start_with_early_start_lever_is_a_hot_start, wet_start_with_thrust_lever_open_is_aborted_without_egt_jump).
Option (build 13, not Zibo): L:LU737_EEC_HOTSTART_OFF = 1 disables the EEC hot-start abort. A wet start
then runs into the red (Zibo's start EGT model peaks near 980 C on a start lever at IDLE from 0 % N2,
without jumps) until the start lever is cut or the engine reaches idle. Default 0 = Zibo.
Test: eec_hotstart_off_option_lets_a_wet_start_run_into_the_red.