fs2port/port/include/radios.h
2026-05-13 21:32:05 -05:00

132 lines
4.9 KiB
C

// 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 <stdbool.h>
#include <stdint.h>
#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