// NAV / COM / ADF radios. Holds the four tuned frequencies plus // VOR1/VOR2 OBS courses, looks up the active station for each radio // against the unified scenery station database, and exposes the // per-frame derived values the panel digits and gauge needles read. // // Frequency encoding mirrors FS2's chunk5 `DecodeBCDFreqString` and // chunk3 `LookupADFStation`: NAV/COM are two BCD pairs giving // XXX.X MHz (e.g. 0x1080 == 108.0 MHz, 0x1224 == 122.4 MHz). ADF is // `[BCD pair (mid+lo)] [single high digit]`, so 0x0703 == 703 kHz. #ifndef RADIOS_H #define RADIOS_H #include #include #include "aircraft.h" #include "sceneryStationsData.h" typedef enum RadioE { RADIO_NAV1 = 0, RADIO_NAV2 = 1, RADIO_ADF = 2, RADIO_COM1 = 3, RADIO_COUNT } RadioE; // VOR TO/FROM/OFF flag, indexed into chunk5 msg_vor_flags. typedef enum VorFlagE { VOR_FLAG_OFF = 0, VOR_FLAG_TO = 1, VOR_FLAG_FR = 2 } VorFlagE; typedef struct RadiosT { // BCD-packed tuned frequencies. See the file-level comment for // the encoding. uint16_t nav1Freq; uint16_t nav2Freq; uint16_t adfFreq; uint16_t com1Freq; // OBS courses for VOR1/VOR2 (byte angles, 256 == full turn). // Set by the pilot via the panel; the needle deflects from // course-line intercept. uint8_t nav1Obs; uint8_t nav2Obs; // Active station pointers (NULL = no station found at the // current frequency). Refreshed on tune-change and whenever // the aircraft moves into a different region's coverage. const StationDataT *nav1Station; const StationDataT *nav2Station; const StationDataT *adfStation; const StationDataT *com1Station; // Per-frame derived values, recomputed by `radiosUpdate`. // Bearings are byte angles (0 = north, 64 = east). DME is // nautical miles, integer (FS2 displayed it as "000"-style). // Needle deflections are signed byte deflection from "needle // centred", saturating at +/-32 -- matches needleData range. uint8_t nav1RelativeBearing; uint8_t nav2RelativeBearing; uint8_t adfRelativeBearing; // station bearing minus aircraft heading uint16_t nav1Dme; uint16_t nav2Dme; int8_t nav1NeedleDefl; int8_t nav2NeedleDefl; bool nav1Valid; // active station present + in receivable range bool nav2Valid; bool adfValid; // VOR1/VOR2 TO/FROM/OFF flag, mirroring chunk5 msg_vor_flags // (0 = OFF, 1 = TO, 2 = FR). Indexed straight into a 3-string // table at draw time. uint8_t nav1Flag; uint8_t nav2Flag; } RadiosT; void radiosInit(RadiosT *r); // Sweep the database for the nearest NAV / ADF / COM to the aircraft // and tune each radio to it. Useful for "find me something to listen // to" gestures and as a sanity check that the database is populated. void radiosTuneToNearest(RadiosT *r, const AircraftT *ac); // Step the named radio's frequency by one BCD click. Stride matches // real-radio behaviour: NAV/COM 0.05 MHz, ADF 1 kHz. Updates the // active station pointer. void radiosStepFreq(RadiosT *r, RadioE which, int direction); // Step the named VOR's OBS course by `deltaDegrees` (signed; will be // quantised to a byte-angle delta). NAV1/NAV2 only. void radiosStepObs(RadiosT *r, RadioE which, int deltaDegrees); // FS2 BCD per-digit entry. The user types a digit 0..9 and the // radio's frequency rotates one decimal slot left, dropping the high // digit. Mirrors chunk5 KeyDecreasePatch / KeyIncreasePatch with a // fixed digit input. void radiosEnterDigit(RadiosT *r, RadioE which, uint8_t digit); // BCD digit-entry mode (FS2 chunk5 InputMode $04..$0F). The caller // arms a target radio with `radiosBeginDigitEntry`; subsequent digit // keys feed `radiosEnterDigit` until the user clears with // `radiosEndDigitEntry`. RADIO_INPUT_NONE means digit keys go to // their normal binding (= mode toggles). typedef enum RadioInputModeE { RADIO_INPUT_NONE = 0, RADIO_INPUT_NAV1, RADIO_INPUT_NAV2, RADIO_INPUT_COM1, RADIO_INPUT_ADF } RadioInputModeE; // Recompute all derived values (bearings, DME, deflections) from the // aircraft's current position and the active station pointers. Call // once per frame after the flight integrator. void radiosUpdate(RadiosT *r, const AircraftT *ac); // Format a tuned frequency for display. NAV/COM produce "XXX.X" (5 // chars + null); ADF produces "XXX" (3 chars + null). `out` must be // at least 6 bytes. void radiosFormatFreq(uint16_t freq, RadioE which, char *out); // Look up a station by (type, freq). Returns NULL if no match. // Exposed for tests / tooling; `radiosStepFreq` does this internally. const StationDataT *radiosFindStation(char type, uint16_t freq); #endif