first commit

This commit is contained in:
Your Name
2022-10-20 20:29:11 +08:00
commit 4d531f8044
3238 changed files with 1387862 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,363 @@
// kln89_page.hxx - a class to manage the simulation of a KLN89
// GPS unit. Note that this is primarily the
// simulation of the user interface and display
// - the core GPS calculations such as position
// and waypoint sequencing are done (or should
// be done) by FG code.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef _KLN89_HXX
#define _KLN89_HXX
#include <Instrumentation/dclgps.hxx>
#include "kln89_page.hxx"
class KLN89Page;
const int KLN89MapScales[2][21] = {{1, 2, 3, 5, 7, 10, 12, 15, 17, 20, 25, 30, 40, 60, 80, 100, 120, 160, 240, 320, 500},
{2, 4, 6, 9, 13, 18, 22, 28, 32, 37, 46, 55, 75, 110, 150, 185, 220, 300, 440, 600, 925}};
enum KLN89Mode {
KLN89_MODE_DISP,
KLN89_MODE_CRSR
};
enum KLN89DistanceUnits {
GPS_DIST_UNITS_NM = 0,
GPS_DIST_UNITS_KM
};
enum KLN89SpeedUnits {
GPS_VEL_UNITS_KT,
GPS_VEL_UNITS_KPH
};
enum KLN89AltitudeUnits {
GPS_ALT_UNITS_FT,
GPS_ALT_UNITS_M
};
enum KLN89PressureUnits {
GPS_PRES_UNITS_IN = 1,
GPS_PRES_UNITS_MB,
GPS_PRES_UNITS_HP
};
/*
const char* KLN89TimeCodes[20] = { "UTC", "GST", "GDT", "ATS", "ATD", "EST", "EDT", "CST", "CDT", "MST",
"MDT", "PST", "PDT", "AKS", "AKD", "HAS", "HAD", "SST", "SDT", "LCL" };
*/
// Used for storing airport town and county mapped by ID, since currently FG does not store this
typedef std::map<std::string, std::string> airport_id_str_map_type;
typedef airport_id_str_map_type::iterator airport_id_str_map_iterator;
typedef std::vector<KLN89Page*> kln89_page_list_type;
typedef kln89_page_list_type::iterator kln89_page_list_itr;
class KLN89 : public DCLGPS
{
friend class KLN89Page;
friend class KLN89AptPage;
friend class KLN89VorPage;
friend class KLN89NDBPage;
friend class KLN89IntPage;
friend class KLN89UsrPage;
friend class KLN89ActPage;
friend class KLN89NavPage;
friend class KLN89FplPage;
friend class KLN89CalPage;
friend class KLN89SetPage;
friend class KLN89OthPage;
friend class KLN89AltPage;
friend class KLN89DirPage;
friend class KLN89NrstPage;
public:
KLN89(RenderArea2D* instrument);
~KLN89();
// Subsystem API.
void bind() override;
void init() override;
void unbind() override;
void update(double dt) override;
// Subsystem identification.
static const char* staticSubsystemClassId() { return "KLN89"; }
// Set Units
// m if true, ft if false
inline void SetAltUnitsSI(bool b) { _altUnits = (b ? GPS_ALT_UNITS_M : GPS_ALT_UNITS_FT); }
// Returns true if alt units are SI (m), false if ft
inline bool GetAltUnitsSI() { return(_altUnits == GPS_ALT_UNITS_M ? true : false); }
// km and k/h if true, nm and kt if false
inline void SetDistVelUnitsSI(bool b) { _distUnits = (b ? GPS_DIST_UNITS_KM : GPS_DIST_UNITS_NM); _velUnits = (b ? GPS_VEL_UNITS_KPH : GPS_VEL_UNITS_KT); }
// Returns true if dist/vel units are SI
inline bool GetDistVelUnitsSI() { return(_distUnits == GPS_DIST_UNITS_KM && _velUnits == GPS_VEL_UNITS_KPH ? true : false); }
// Set baro units - 1 = in, 2 = mB, 3 = hP Wrapping if for the convienience of the GPS setter.
void SetBaroUnits(int n, bool wrap = false);
// Get baro units: 1 = in, 2 = mB, 3 = hP
inline int GetBaroUnits() { return((int)_baroUnits); }
inline void SetTurnAnticipation(bool b) { _turnAnticipationEnabled = b; }
inline bool GetTurnAnticipation() { return(_turnAnticipationEnabled); }
inline void SetSuaAlertEnabled(bool b) { _suaAlertEnabled = b; }
inline bool GetSuaAlertEnabled() { return(_suaAlertEnabled); }
inline void SetAltAlertEnabled(bool b) { _altAlertEnabled = b; }
inline bool GetAltAlertEnabled() { return(_altAlertEnabled); }
void SetMinDisplayBrightness(int n); // Set minDisplayBrightness (between 1 and 9)
void DecrementMinDisplayBrightness(); // Decrease by 1
void IncrementMinDisplayBrightness(); // Increase by 1
inline int GetMinDisplayBrightness() { return(_minDisplayBrightness); }
inline bool GetMsgAlert() const { return(!_messageStack.empty()); }
void Knob1Right1();
void Knob1Left1();
void Knob2Right1();
void Knob2Left1();
void CrsrPressed();
void EntPressed();
void ClrPressed();
void DtoPressed();
void NrstPressed();
void AltPressed();
void OBSPressed();
void MsgPressed();
void CreateDefaultFlightPlans();
private:
void ToggleOBSMode();
// Initiate Direct To operation to the supplied ID.
void DtoInitiate(const std::string& id);
//----------------------- Drawing functions which take CHARACTER units -------------------------
// Render string s in display field field at position x, y
// WHERE POSITION IS IN CHARACTER UNITS!
// zero y at bottom?
// invert: -1 => no inversion, 0 -> n => 1 char - s[invert] gets inverted, 99 => entire string gets inverted
void DrawText(const std::string& s, int field, int px, int py, bool bold = false, int invert = -1);
void DrawLatitude(double d, int field, int px, int py);
void DrawLongitude(double d, int field, int px, int py);
// Draw a frequency as xxx.xx
void DrawFreq(double d, int field, int px, int py);
// Draw a time in seconds as hh:mm
// NOTE: px is RIGHT JUSTIFIED!
void DrawTime(double time, int field, int px, int py);
// Draw an integer heading, where px specifies the position of the degrees sign at the RIGHT of the value.
void DrawHeading(int h, int field, int px, int py);
// Draw a distance spec'd as nm as an integer (TODO - may need 1 decimal place if < 100) where px specifies RHS of units.
// Some uses definately don't want decimal place though (as at present), so would have to be arg.
void DrawDist(double d, int field, int px, int py);
// Draw a speed specifed in knots. px is RHS of the units. Can draw up to 2 decimal places.
void DrawSpeed(double v, int field, int px, int py, int decimals = 0);
void Underline(int field, int px, int py, int len);
// Render a char at a given position as above (position in CHARACTER units)
void DrawChar(char c, int field, int px, int py, bool bold = false, bool invert = false);
void DrawSpecialChar(char c, int field, int cx, int cy, bool bold = false);
// Draws the dir/dist field at the bottom of the main field
void DrawDirDistField(double lat, double lon, int field, int px, int py, bool to_flag = true, bool cursel = false);
//
//--------------------------------- end char units -----------------------------------------------
//----------------------- Drawing functions which take PIXEL units ------------------------------
//
// Takes instrument *pixel* co-ordinates NOT character units
// Position is specified by the bottom of the *visible* portion, by default the left position unless align_right is true.
// The return value is the pixel width of the visible portion
int DrawSmallChar(char c, int x, int y, bool align_right = false);
void DrawFreeChar(char c, int x, int y, bool draw_background = false);
//
//----------------------------------- end pixel unit functions -----------------------------------
void DrawDivider();
void DrawEnt(int field = 1, int px = 0, int py = 1);
void DrawMessageAlert();
void DrawKPH(int field, int cx, int cy);
void DrawDTO(int field, int cx, int cy);
// Draw the bar that indicates which page we're on (zero-based)
void DrawBar(int page);
void DrawCDI();
void DrawLegTail(int py);
void DrawLongLegTail(int py);
void DrawHalfLegTail(int py);
void UpdateMapHeading();
// Draw the moving map
// Apt, VOR and SUA drawing can be suspended by setting draw_avs to false, without affecting the stored drawing preference state.
void DrawMap(bool draw_avs = true);
// Set whether the display should be drawn pixelated (more primitives, but might be closer to real-life)
// or not (in which case it is assumed that pixels are square and can be merged into quads).
bool _pixelated;
// Flashing output should be hidden when blink is true
bool _blink;
double _cum_dt;
// In Crsr mode, CRSR pressed events are passed to the active page, in disp mode they change which page is active
KLN89Mode _mode;
// And the facility to save a mode
KLN89Mode _lastMode;
// Increment/Decrement a character in the KLN89 A-Z,0-9 scheme.
// Set gap to true to get a space between A and 9 when wrapping, set wrap to false to disable wrap.
char IncChar(char c, bool gap = false, bool wrap = true);
char DecChar(char c, bool gap = false, bool wrap = true);
// ==================== Page organisation stuff =============
// The list of cyclical pages that the user can cycle through
kln89_page_list_type _pages;
// The currently active page
KLN89Page* _activePage;
// And a facility to save the immediately preceding active page
KLN89Page* _lastActivePage;
// Ugly hack. Housekeeping to allow us to temporarily display one page, while remembering which
// other page to "jump" back to. Used when the waypoint pages are used to review waypoint entry
// from the flightplan page.
int _entJump; // The page to jump back to if ENT is pressed. -1 indicates no jump.
int _clrJump; // The page to jump back to if CLR is pressed. -1 indicates no jump.
bool _jumpRestoreCrsr; // Indicates that jump back at this point should restore cursor mode.
// Misc pages that aren't in the cyclic list.
// ALT
KLN89Page* _alt_page;
// Direct To
KLN89Page* _dir_page;
// Nearest
KLN89Page* _nrst_page;
// ====================== end of page stuff ===================
// Moving-map display stuff
int _mapOrientation; // 0 => North (true) up, 1 => DTK up, 2 => TK up, 3 => heading up (only when connected to external heading source).
double _mapHeading; // Degrees. The actual map heading gets updated at a lower frequency than DrawMap() is called at, hence we need to store it.
double _mapHeadingUpdateTimer; // Timer to determine when to update the above.
bool _mapScaleAuto; // Indicates that map should autoscale when true.
int _mapScaleIndex; // Index into array of available map scales.
int _mapScaleUnits; // 0 => nm, 1 => km.
double _mapScale; // nm or km from aircraft position to top of map.
// Note that aircraft position differs depending on orientation, but 'scale' retains the same meaning,
// so the scale per pixel alters to suit the defined scale when the rendered aircraft position changes.
bool _drawSUA; // special user airspace
bool _drawVOR;
bool _drawApt;
// Convert map to instrument coordinates
void MapToInstrument(int &x, int &y);
// The following map drawing functions all take MAP co-ordinates, NOT instrument co-ordinates!
// Draw the diamond style of user pos
void DrawUser1(int x, int y);
// Draw the airplane style of user pos
void DrawUser2(int x, int y);
// Draw an airport symbol on the moving map
void DrawApt(int x, int y);
// Draw a waypoint on the moving map
void DrawWaypoint(int x, int y);
// Draw a VOR on the moving map
void DrawVOR(int x, int y);
// Draw an airport or waypoint label on the moving map
// Specify position by the map pixel co-ordinate of the left or right, bottom, of the *visible* portion of the label.
// The black background quad will automatically overlap this by 1 pixel.
void DrawLabel(const std::string& s, int x1, int y1, bool right_align = false);
int GetLabelQuadrant(double h);
int GetLabelQuadrant(double h1, double h2);
// Draw a line on the moving map
void DrawLine(int x1, int y1, int x2, int y2);
// Draw normal sized text on the moving map
void DrawMapText(const std::string& s, int x, int y, bool draw_background = false);
void DrawMapUpArrow(int x, int y);
// Draw a Quad on the moving map
void DrawMapQuad(int x1, int y1, int x2, int y2, bool invert = false);
// Airport town and state mapped by ID, since currently FG does not store this
airport_id_str_map_type _airportTowns;
airport_id_str_map_type _airportStates;
// NOTE - It is a deliberate decision not to have a proper message page class,
// since button events get directed to the page that was active before the
// message was displayed, not the message page itself.
bool _dispMsg; // Set true while the message page is being displayed
// Sometimes the datapages can be used to review a waypoint whilst the user makes a decision,
// and we need to remember why.
bool _dtoReview; // Set true when we a reviewing a waypoint for DTO operation.
// Configuration settings that the user can set via. the KLN89 SET pages.
KLN89SpeedUnits _velUnits;
KLN89DistanceUnits _distUnits;
KLN89PressureUnits _baroUnits;
KLN89AltitudeUnits _altUnits;
bool _suaAlertEnabled; // Alert user to potential SUA entry
bool _altAlertEnabled; // Alert user to min safe alt violation
int _minDisplayBrightness; // Minimum display brightness in low light.
char _defaultFirstChar; // Default first waypoint character.
// The user-settable barometric pressure.
// This can be set in the range 22.00 -> 32.99", or 745 -> 1117mB/hPa.
// For user input, we maintain a single integer value that is either between 2200 and 3299 (")
// or between 745 and 1117 (mB/hPa). It gets converted from one to the other only when the
// units are changed.
// For internal VNAV calculations (which we don't currently do) this will be converted to a floating
// point value before use.
int _userBaroSetting;
};
#endif // _KLN89_HXX

View File

@@ -0,0 +1,228 @@
// kln89_page.cxx - base class for the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#include "kln89_page.hxx"
#include <Main/fg_props.hxx>
#include <cstdio>
using std::string;
KLN89Page::KLN89Page(KLN89* parent) {
_kln89 = parent;
_entInvert = false;
_to_flag = true;
_subPage = 0;
}
KLN89Page::~KLN89Page() {
}
void KLN89Page::Update(double dt) {
bool crsr = (_kln89->_mode == KLN89_MODE_CRSR ? true : false);
bool nav1 = (_name == "NAV" && _subPage == 0);
bool nav4 = (_name == "NAV" && _subPage == 3);
// The extra level of check for the ACT page is necessary since
// ACT is implemented by using the other waypoint pages as
// appropriate.
bool act = (_kln89->_activePage->GetName() == "ACT");
_kln89->DrawDivider();
if(crsr) {
if(!nav4) _kln89->DrawText("*CRSR*", 1, 0, 0);
if(_uLinePos == 0) _kln89->Underline(1, 3, 1, 3);
} else {
if(!nav4) {
if(act) {
_kln89->DrawText("ACT", 1, 0, 0);
} else {
_kln89->DrawText(_name, 1, 0, 0);
}
if(_name == "DIR") {
// Don't draw a subpage number
} else if(_name == "USR" || _name == "FPL") {
// Zero-based
_kln89->DrawText(GPSitoa(_subPage), 1, 4, 0);
} else {
// One-based
_kln89->DrawText(GPSitoa(_subPage+1), 1, 4, 0);
}
}
}
if(crsr && _uLinePos == 0 && _kln89->_blink) {
// Don't draw
} else {
if(_kln89->_obsMode) {
_kln89->DrawText(GPSitoa(_kln89->_obsHeading), 1, 3, 1);
} else {
_kln89->DrawText("Leg", 1, 3, 1);
}
}
_kln89->DrawText((_kln89->GetDistVelUnitsSI() ? "km" : "nm"), 1, 4, 3);
GPSWaypoint* awp = _kln89->GetActiveWaypoint();
if(_kln89->_navFlagged) {
_kln89->DrawText("--.-", 1, 0 ,3);
// Only nav1 still gets speed drawn if nav is flagged - not ACT
if(!nav1) _kln89->DrawText("------", 1, 0, 2);
} else {
char buf[8];
float f = _kln89->GetDistToActiveWaypoint() * (_kln89->GetDistVelUnitsSI() ? 0.001 : SG_METER_TO_NM);
snprintf(buf, 5, (f >= 100.0 ? "%4.0f" : "%4.1f"), f);
string s = buf;
_kln89->DrawText(s, 1, 4 - s.size(), 3, true);
// Draw active waypoint ID, except for
// nav1, act, and any waypoint pages matching
// active waypoint that need speed drawn instead.
if(act || nav1 || (awp && awp->id == _id)) {
_kln89->DrawSpeed(_kln89->_groundSpeed_kts, 1, 5, 2);
} else {
if(!(_kln89->_waypointAlert && _kln89->_blink)) _kln89->DrawText(awp->id, 1, 0, 2);
}
}
/*
if(_noNrst) {
_kln89->DrawText(" No ", 1, 0, 1, false, 99);
_kln89->DrawText(" Nrst ", 1, 0, 0, false, 99);
}
*/
if(_scratchpadMsg) {
_kln89->DrawText(_scratchpadLine1, 1, 0, 1, false, 99);
_kln89->DrawText(_scratchpadLine2, 1, 0, 0, false, 99);
_scratchpadTimer += dt;
if(_scratchpadTimer > 4.0) {
_scratchpadMsg = false;
_scratchpadTimer = 0.0;
}
}
}
void KLN89Page::ShowScratchpadMessage(const string& line1, const string& line2) {
_scratchpadLine1 = line1;
_scratchpadLine2 = line2;
_scratchpadTimer = 0.0;
_scratchpadMsg = true;
}
void KLN89Page::Knob1Left1() {
if(_kln89->_mode == KLN89_MODE_CRSR) {
if(_uLinePos > 0) _uLinePos--;
}
}
void KLN89Page::Knob1Right1() {
if(_kln89->_mode == KLN89_MODE_CRSR) {
if(_uLinePos < _maxULinePos) _uLinePos++;
}
}
void KLN89Page::Knob2Left1() {
if(_kln89->_mode != KLN89_MODE_CRSR && !fgGetBool("/instrumentation/kln89/scan-pull")) {
_kln89->_activePage->LooseFocus();
_subPage--;
if(_subPage < 0) _subPage = _nSubPages - 1;
} else {
if(_uLinePos == 0 && _kln89->_obsMode) {
_kln89->_obsHeading--;
if(_kln89->_obsHeading < 0) {
_kln89->_obsHeading += 360;
}
_kln89->SetOBSFromWaypoint();
}
}
}
void KLN89Page::Knob2Right1() {
if(_kln89->_mode != KLN89_MODE_CRSR && !fgGetBool("/instrumentation/kln89/scan-pull")) {
_kln89->_activePage->LooseFocus();
_subPage++;
if(_subPage >= _nSubPages) _subPage = 0;
} else {
if(_uLinePos == 0 && _kln89->_obsMode) {
_kln89->_obsHeading++;
if(_kln89->_obsHeading > 359) {
_kln89->_obsHeading -= 360;
}
_kln89->SetOBSFromWaypoint();
}
}
}
void KLN89Page::CrsrPressed() {
// Stick some sensible defaults in
if(_kln89->_obsMode) {
_uLinePos = 0;
} else {
_uLinePos = 1;
}
_maxULinePos = 1;
}
void KLN89Page::EntPressed() {}
void KLN89Page::ClrPressed() {}
void KLN89Page::DtoPressed() {}
void KLN89Page::NrstPressed() {}
void KLN89Page::AltPressed() {}
void KLN89Page::OBSPressed() {
if(_kln89->_obsMode) {
// If ORS2 and not slaved to gps
_uLinePos = 0;
} else {
// Don't leave the cursor on in the leg position.
if(_uLinePos == 0) {
_kln89->_mode = KLN89_MODE_DISP;
}
}
}
void KLN89Page::MsgPressed() {}
void KLN89Page::CleanUp() {
_kln89->_cleanUpPage = -1;
}
void KLN89Page::LooseFocus() {
_entInvert = false;
}
void KLN89Page::SetId(const string& s) {
_id = s;
}
void KLN89Page::SetSubPage(int n) {
if(n < 0) n = 0;
if(n >= _nSubPages) n = _nSubPages-1;
_subPage = n;
}
const string& KLN89Page::GetId() {
return(_id);
}
// TODO - this function probably shouldn't be here - FG almost certainly has better handling
// of this somewhere already.
string KLN89Page::GPSitoa(int n) {
char buf[6];
snprintf(buf, 6, "%i", n);
string s = buf;
return(s);
}

View File

@@ -0,0 +1,114 @@
// kln89_page.hxx - base class for the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef _KLN89_PAGE_HXX
#define _KLN89_PAGE_HXX
#include <Instrumentation/dclgps.hxx>
#include "kln89.hxx"
class KLN89;
class KLN89Page {
public:
KLN89Page(KLN89* parent);
virtual ~KLN89Page();
virtual void Update(double dt);
virtual void Knob1Left1();
virtual void Knob1Right1();
virtual void Knob2Left1();
virtual void Knob2Right1();
virtual void CrsrPressed();
virtual void EntPressed();
virtual void ClrPressed();
// Even though some/all of the buttons below aren't processed directly by the current page,
// the current page often needs to save or change some state when they are pressed, and
// hence should provide a function to handle them.
virtual void DtoPressed();
virtual void NrstPressed();
virtual void AltPressed();
virtual void OBSPressed();
virtual void MsgPressed();
// Sometimes a page needs to maintain state for some return paths,
// but change it for others. The CleanUp function can be used for
// changing state for non-ENT return paths in conjunction with
// GPS::_cleanUpPage
virtual void CleanUp();
// The LooseFocus function is called when a page or subpage looses focus
// and allows pages to clean up state that is maintained whilst focus is
// retained, but lost on return.
virtual void LooseFocus();
inline void SetEntInvert(bool b) { _entInvert = b; }
// Get / Set a waypoint id, NOT the page name!
virtual void SetId(const std::string& s);
virtual const std::string& GetId();
inline int GetSubPage() { return(_subPage); }
void SetSubPage(int n);
inline int GetNSubPages() { return(_nSubPages); }
inline const std::string& GetName() { return(_name); }
protected:
KLN89* _kln89;
std::string _name; // eg. "APT", "NAV" etc
int _nSubPages;
// _subpage is zero based
int _subPage; // The subpage gets remembered when other pages are displayed
// Underline position in cursor mode is not persistant when subpage is changed - hence we only need one variable per page for it.
// Note that pos 0 is special - this is the leg pos in field 1, so pos will normally be set to 1 when crsr is pressed.
// Also note that in general it doesn't seem to wrap.
unsigned int _uLinePos;
unsigned int _maxULinePos;
// This is NOT the main gps to/from flag - derived page classes can use this flag
// for any purpose, typically whether a radial bearing should be displayed to or from.
bool _to_flag; // true for TO, false for FROM
// Invert ID and display ENT in field 1
bool _entInvert;
std::string _id; // The ID of the waypoint that the page is displaying.
// Doesn't make sense for all pages, but does for all the data pages.
void ShowScratchpadMessage(const std::string& line1, const std::string& line2);
bool _scratchpadMsg; // Set true when there is a scratchpad message to display
double _scratchpadTimer; // Used for displaying the scratchpad messages for the right amount of time.
std::string _scratchpadLine1;
std::string _scratchpadLine2;
// TODO - remove this function from this class and use a built in method instead.
std::string GPSitoa(int n);
};
#endif // _KLN89_PAGE_HXX

View File

@@ -0,0 +1,141 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "kln89_page_act.hxx"
#include "kln89_page_apt.hxx"
#include "kln89_page_vor.hxx"
#include "kln89_page_ndb.hxx"
#include "kln89_page_int.hxx"
#include "kln89_page_usr.hxx"
KLN89ActPage::KLN89ActPage(KLN89* parent)
: KLN89Page(parent) {
_nSubPages = 1;
_subPage = 0;
_name = "ACT";
_actWp = NULL;
_actWpId = -1;
_actPage = NULL;
_aptPage = new KLN89AptPage(parent);
_vorPage = new KLN89VorPage(parent);
_ndbPage = new KLN89NDBPage(parent);
_intPage = new KLN89IntPage(parent);
_usrPage = new KLN89UsrPage(parent);
}
KLN89ActPage::~KLN89ActPage() {
delete _aptPage;
delete _vorPage;
delete _ndbPage;
delete _intPage;
delete _usrPage;
}
void KLN89ActPage::Update(double dt) {
if(!_actWp) {
_actWp = _kln89->GetActiveWaypoint();
_actWpId = _kln89->GetActiveWaypointIndex();
}
if(_actWp) {
switch(_actWp->type) {
case GPS_WP_APT: _actPage = _aptPage; break;
case GPS_WP_VOR: _actPage = _vorPage; break;
case GPS_WP_NDB: _actPage = _ndbPage; break;
case GPS_WP_INT: _actPage = _intPage; break;
case GPS_WP_USR: _actPage = _usrPage; break;
default:
_actPage = NULL;
// ASSERT(0); // ie. we shouldn't ever get here.
}
}
_id = _actWp->id;
if(_actPage) {
_actPage->SetId(_actWp->id);
_actPage->Update(dt);
} else {
KLN89Page::Update(dt);
}
}
void KLN89ActPage::CrsrPressed() {
if(_actPage) {
_actPage->CrsrPressed();
} else {
KLN89Page::CrsrPressed();
}
}
void KLN89ActPage::EntPressed() {
if(_actPage) {
_actPage->EntPressed();
} else {
KLN89Page::EntPressed();
}
}
void KLN89ActPage::ClrPressed() {
if(_actPage) {
_actPage->ClrPressed();
} else {
KLN89Page::ClrPressed();
}
}
void KLN89ActPage::Knob1Left1() {
if(_actPage) {
_actPage->Knob1Left1();
}
}
void KLN89ActPage::Knob1Right1() {
if(_actPage) {
_actPage->Knob1Right1();
}
}
void KLN89ActPage::Knob2Left1() {
if((_kln89->_mode != KLN89_MODE_CRSR) && (_actPage)) {
_actPage->Knob2Left1();
}
}
void KLN89ActPage::Knob2Right1() {
if((_kln89->_mode != KLN89_MODE_CRSR) && (_actPage)) {
_actPage->Knob2Right1();
}
}
void KLN89ActPage::LooseFocus() {
// Setting to NULL and -1 is better than resetting to
// active waypoint and index since we can't guarantee that
// the fpl active waypoint won't change behind our backs
// when we don't have focus.
_actWp = NULL;
_actWpId = -1;
}

View File

@@ -0,0 +1,64 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef _KLN89_PAGE_ACT_HXX
#define _KLN89_PAGE_ACT_HXX
#include "kln89.hxx"
class KLN89ActPage : public KLN89Page {
public:
KLN89ActPage(KLN89* parent);
~KLN89ActPage();
void Update(double dt);
void CrsrPressed();
void EntPressed();
void ClrPressed();
void Knob1Left1();
void Knob1Right1();
void Knob2Left1();
void Knob2Right1();
void LooseFocus();
private:
// Position of the currently displayed waypoint within the active flightplan.
// -1 indicates no active flightplan.
int _actWpId;
GPSWaypoint* _actWp;
// The actual ACT page that gets displayed...
KLN89Page* _actPage;
// ...which points to one of the below.
KLN89Page* _aptPage;
KLN89Page* _vorPage;
KLN89Page* _ndbPage;
KLN89Page* _intPage;
KLN89Page* _usrPage;
};
#endif // _KLN89_PAGE_ACT_HXX

View File

@@ -0,0 +1,129 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2010.
//
// Copyright (C) 2010 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cstdio>
#include "kln89_page_alt.hxx"
using std::string;
KLN89AltPage::KLN89AltPage(KLN89* parent)
: KLN89Page(parent) {
_nSubPages = 2;
_subPage = 0;
_name = "ALT";
_uLinePos = 1;
_maxULinePos = 1;
}
KLN89AltPage::~KLN89AltPage() {
}
void KLN89AltPage::Update(double dt) {
if(_subPage == 0) {
_kln89->DrawText("BARO:", 2, 2, 3);
if(_kln89->_baroUnits == GPS_PRES_UNITS_IN) {
// If the units are not consistent with the setting, then convert to the correct
// units. We do it here instead of where the units are set in order to avoid any
// possible value creep with multiple unit toggling.
if(_kln89->_userBaroSetting >= 745 && _kln89->_userBaroSetting <= 1117) {
_kln89->_userBaroSetting = (int)((float)_kln89->_userBaroSetting * 0.0295301 * 100 + 0.5);
}
char buf[14];
snprintf(buf, sizeof(buf), "%2i.%02i", _kln89->_userBaroSetting/100, _kln89->_userBaroSetting % 100);
string s = buf;
if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 1 && _kln89->_blink)) {
_kln89->DrawText(s, 2, 7, 3);
}
if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 1) {
_kln89->Underline(2, 7, 3, 5);
}
_kln89->DrawText("\"", 2, 12, 3);
} else {
// If the units are not consistent with the setting, then convert to the correct
// units. We do it here instead of where the units are set in order to avoid any
// possible value creep with multiple unit toggling.
if(_kln89->_userBaroSetting >= 2200 && _kln89->_userBaroSetting <= 3299) {
_kln89->_userBaroSetting = (int)(((float)_kln89->_userBaroSetting / 100.0) * 33.8637526 + 0.5);
}
char buf[5];
snprintf(buf, sizeof(buf), "%4i", _kln89->_userBaroSetting);
string s = buf;
if(!(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 1 && _kln89->_blink)) {
_kln89->DrawText(s, 2, 8, 3);
}
if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 1) {
_kln89->Underline(2, 8, 3, 4);
}
_kln89->DrawText(_kln89->_baroUnits == GPS_PRES_UNITS_MB ? "mB" : "hP", 2, 12, 3);
}
_kln89->DrawText("MSA", 2, 2, 1);
_kln89->DrawText("ESA", 2, 2, 0);
// At the moment we have no obstruction database, so dash out MSA & ESA
_kln89->DrawText("----", 2, 8, 1);
_kln89->DrawText("----", 2, 8, 0);
if(_kln89->_altUnits == GPS_ALT_UNITS_FT) {
_kln89->DrawText("ft", 2, 12, 1);
_kln89->DrawText("ft", 2, 12, 0);
} else {
_kln89->DrawText("m", 2, 12, 1);
_kln89->DrawText("m", 2, 12, 0);
}
} else {
_kln89->DrawText("Vnv Inactive", 2, 0, 3);
}
KLN89Page::Update(dt);
}
void KLN89AltPage::CrsrPressed() {
}
void KLN89AltPage::EntPressed() {
}
void KLN89AltPage::Knob2Left1() {
_kln89->_userBaroSetting--;
if(_kln89->_baroUnits == GPS_PRES_UNITS_IN) {
if(_kln89->_userBaroSetting < 2200) _kln89->_userBaroSetting = 3299;
} else {
if(_kln89->_userBaroSetting < 745) _kln89->_userBaroSetting = 1117;
}
}
void KLN89AltPage::Knob2Right1() {
_kln89->_userBaroSetting++;
if(_kln89->_baroUnits == GPS_PRES_UNITS_IN) {
if(_kln89->_userBaroSetting > 3299) _kln89->_userBaroSetting = 2200;
} else {
if(_kln89->_userBaroSetting > 1117) _kln89->_userBaroSetting = 745;
}
}
void KLN89AltPage::LooseFocus() {
_uLinePos = 1;
}

View File

@@ -0,0 +1,47 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2010.
//
// Copyright (C) 2010 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef _KLN89_PAGE_ALT
#define _KLN89_PAGE_ALT
#include "kln89.hxx"
class KLN89AltPage : public KLN89Page {
public:
KLN89AltPage(KLN89* parent);
~KLN89AltPage();
void Update(double dt);
//void AltPressed();
void CrsrPressed();
void EntPressed();
//void ClrPressed();
//void Knob1Left1();
//void Knob1Right1();
void Knob2Left1();
void Knob2Right1();
void LooseFocus();
};
#endif // _KLN89_PAGE_ALT

View File

@@ -0,0 +1,875 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "kln89_page_apt.hxx"
#include <simgear/structure/exception.hxx>
#include <cassert>
#include <cstdio>
#include <ATC/CommStation.hxx>
#include <Main/globals.hxx>
#include <Airports/runways.hxx>
#include <Airports/airport.hxx>
using std::string;
KLN89AptPage::KLN89AptPage(KLN89* parent)
: KLN89Page(parent) {
_nSubPages = 8;
_subPage = 0;
_name = "APT";
_apt_id = "KHWD";
// Make sure that _last_apt_id doesn't match at startup to force airport data to be fetched on first update.
_last_apt_id = "XXXX";
_nRwyPages = 1;
_curRwyPage = 0;
_nFreqPages = 1;
_curFreqPage = 0;
ap = NULL;
_iapStart = 0;
_iafStart = 0;
_fStart = 0;
_iaps.clear();
_iafDialog = false;
_addDialog = false;
_replaceDialog = false;
_curIap = 0;
_curIaf = 0;
}
KLN89AptPage::~KLN89AptPage() {
}
void KLN89AptPage::Update(double dt) {
bool actPage = (_kln89->_activePage->GetName() == "ACT" ? true : false);
bool multi; // Not set by FindFirst...
bool exact = false;
if(_apt_id.size() == 4) exact = true;
// TODO - move this search out to where the button is pressed, and cache the result!
if(_apt_id != _last_apt_id || ap == NULL) ap = _kln89->FindFirstAptById(_apt_id, multi, exact);
//if(np == NULL) cout << "NULL... ";
//if(b == false) cout << "false...\n";
/*
if(np && b) {
cout << "VOR FOUND!\n";
} else {
cout << ":-(\n";
}
*/
if(ap) {
//cout << "Valid airport found! id = " << ap->getId() << ", elev = " << ap->getElevation() << '\n';
if(_apt_id != _last_apt_id) {
UpdateAirport(ap->getId());
_last_apt_id = _apt_id;
_curFreqPage = 0;
_curRwyPage = 0;
}
_apt_id = ap->getId();
if(_kln89->GetActiveWaypoint()) {
if(_apt_id == _kln89->GetActiveWaypoint()->id) {
if(!(_kln89->_waypointAlert && _kln89->_blink)) {
// Active waypoint arrow
_kln89->DrawSpecialChar(4, 2, 0, 3);
}
}
}
if(_kln89->_mode != KLN89_MODE_CRSR) {
if(!(_subPage == 7 && (_iafDialog || _addDialog || _replaceDialog))) { // Don't draw the airport name when the IAP dialogs are active
if(!_entInvert) {
if(!actPage) {
_kln89->DrawText(ap->getId(), 2, 1, 3);
} else {
// If it's the ACT page, The ID is shifted slightly right to make space for the waypoint index.
_kln89->DrawText(ap->getId(), 2, 4, 3);
char buf[3];
int n = snprintf(buf, 3, "%i", _kln89->GetActiveWaypointIndex() + 1);
_kln89->DrawText((string)buf, 2, 3 - n, 3);
}
} else {
if(!_kln89->_blink) {
_kln89->DrawText(ap->getId(), 2, 1, 3, false, 99);
_kln89->DrawEnt();
}
}
}
}
if(_subPage == 0) {
// Name
_kln89->DrawText(ap->getName(), 2, 0, 2);
// Elevation
_kln89->DrawText(_kln89->_altUnits == GPS_ALT_UNITS_FT ? "ft" : "m", 2, 14, 3);
char buf[6];
int n = snprintf(buf, 5, "%i", (_kln89->_altUnits == GPS_ALT_UNITS_FT ? (int)(ap->getElevation()) : (int)((double)ap->getElevation() * SG_FEET_TO_METER)));
_kln89->DrawText((string)buf, 2, 14 - n, 3);
// Town
airport_id_str_map_iterator itr = _kln89->_airportTowns.find(_apt_id);
if(itr != _kln89->_airportTowns.end()) {
_kln89->DrawText(itr->second, 2, 0, 1);
}
// State / Province / Country
itr = _kln89->_airportStates.find(_apt_id);
if(itr != _kln89->_airportStates.end()) {
_kln89->DrawText(itr->second, 2, 0, 0);
}
} else if(_subPage == 1) {
_kln89->DrawLatitude(ap->getLatitude(), 2, 3, 2);
_kln89->DrawLongitude(ap->getLongitude(), 2, 3, 1);
_kln89->DrawDirDistField(ap->getLatitude() * SG_DEGREES_TO_RADIANS, ap->getLongitude() * SG_DEGREES_TO_RADIANS,
2, 0, 0, _to_flag, (_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 5 ? true : false));
} else if(_subPage == 2) {
// Try and calculate a realistic difference from UTC based on longitude
// Since 0 longitude is the middle of UTC, the boundaries will be at 7.5, 22.5, 37.5 etc.
int hrDiff = ((int)((fabs(ap->getLongitude())) + 7.5)) / 15;
_kln89->DrawText("UTC", 2, 0, 2);
if(hrDiff != 0) {
_kln89->DrawText(ap->getLongitude() >= 0.0 ? "+" : "-", 2, 3, 2);
char buf[10];
snprintf(buf, sizeof(buf), "%02i", hrDiff);
_kln89->DrawText((string)buf, 2, 4, 2);
_kln89->DrawText("( DT)", 2, 6, 2);
if(ap->getLongitude() >= 0.0) {
hrDiff++;
} else {
hrDiff--;
}
_kln89->DrawText(ap->getLongitude() >= 0.0 ? "+" : "-", 2, 7, 2);
snprintf(buf, sizeof(buf), "%02i", hrDiff);
_kln89->DrawText((string)buf, 2, 8, 2);
}
// I guess we can make a heuristic guess as to fuel availability from the runway sizes
// For now assume that airports with asphalt or concrete runways will have at least 100L,
// and that runways over 4000ft will have JET.
if(_aptRwys[0]->surface() <= 2) {
if(_aptRwys[0]->lengthFt() >= 4000) {
_kln89->DrawText("JET 100L", 2, 0, 1);
} else {
_kln89->DrawText("100L", 2, 0, 1);
}
}
if(_iaps.empty()) {
_kln89->DrawText("NO APR", 2, 0, 0);
} else {
// TODO - output proper differentiation of ILS and NP APR and NP APR type eg GPS(R)
_kln89->DrawText("NP APR", 2, 0, 0);
}
} else if(_subPage == 3) {
if(_nRwyPages > 1) {
_kln89->DrawChar('+', 1, 3, 0);
}
unsigned int i = _curRwyPage * 2;
string s;
if(i < _aptRwys.size()) {
// Rwy No.
string s = _aptRwys[i]->ident();
_kln89->DrawText(s, 2, 9, 3);
_kln89->DrawText("/", 2, 12, 3);
string recipIdent = _aptRwys[i]->reciprocalRunway()->ident();
_kln89->DrawText(recipIdent, 2, 13, 3);
// Length
s = GPSitoa(int(float(_aptRwys[i]->lengthFt()) * (_kln89->_altUnits == GPS_ALT_UNITS_FT ? 1.0 : SG_FEET_TO_METER) + 0.5));
_kln89->DrawText(s, 2, 5 - s.size(), 2);
_kln89->DrawText((_kln89->_altUnits == GPS_ALT_UNITS_FT ? "ft" : "m"), 2, 5, 2);
// Surface
// TODO - why not store these strings as an array?
switch(_aptRwys[i]->surface()) {
case 1:
// Asphalt - fall through
case 2:
// Concrete
_kln89->DrawText("HRD", 2, 9, 2);
break;
case 3:
case 8:
// Turf / Turf helipad
_kln89->DrawText("TRF", 2, 9, 2);
break;
case 4:
case 9:
// Dirt / Dirt helipad
_kln89->DrawText("DRT", 2, 9, 2);
break;
case 5:
// Gravel
_kln89->DrawText("GRV", 2, 9, 2);
break;
case 6:
// Asphalt helipad - fall through
case 7:
// Concrete helipad
_kln89->DrawText("HRD", 2, 9, 2);
break;
case 12:
// Lakebed
_kln89->DrawText("CLY", 2, 9, 2);
break;
default:
// erm? ...
_kln89->DrawText("MAT", 2, 9, 2);
}
}
i++;
if(i < _aptRwys.size()) {
// Rwy No.
string s = _aptRwys[i]->ident();
_kln89->DrawText(s, 2, 9, 1);
_kln89->DrawText("/", 2, 12, 1);
string recip = _aptRwys[i]->reciprocalRunway()->ident();
_kln89->DrawText(recip, 2, 13, 1);
// Length
s = GPSitoa(int(float(_aptRwys[i]->lengthFt()) * (_kln89->_altUnits == GPS_ALT_UNITS_FT ? 1.0 : SG_FEET_TO_METER) + 0.5));
_kln89->DrawText(s, 2, 5 - s.size(), 0);
_kln89->DrawText((_kln89->_altUnits == GPS_ALT_UNITS_FT ? "ft" : "m"), 2, 5, 0);
// Surface
// TODO - why not store these strings as an array?
switch(_aptRwys[i]->surface()) {
case 1:
// Asphalt - fall through
case 2:
// Concrete
_kln89->DrawText("HRD", 2, 9, 0);
break;
case 3:
case 8:
// Turf / Turf helipad
_kln89->DrawText("TRF", 2, 9, 0);
break;
case 4:
case 9:
// Dirt / Dirt helipad
_kln89->DrawText("DRT", 2, 9, 0);
break;
case 5:
// Gravel
_kln89->DrawText("GRV", 2, 9, 0);
break;
case 6:
// Asphalt helipad - fall through
case 7:
// Concrete helipad
_kln89->DrawText("HRD", 2, 9, 0);
break;
case 12:
// Lakebed
_kln89->DrawText("CLY", 2, 9, 0);
break;
default:
// erm? ...
_kln89->DrawText("MAT", 2, 9, 0);
}
}
} else if(_subPage == 4) {
if(_nFreqPages > 1) {
_kln89->DrawChar('+', 1, 3, 0);
}
unsigned int i = _curFreqPage * 3;
if(i < _aptFreqs.size()) {
_kln89->DrawText(_aptFreqs[i].service, 2, 0, 2);
_kln89->DrawFreq(_aptFreqs[i].freq, 2, 7, 2);
}
i++;
if(i < _aptFreqs.size()) {
_kln89->DrawText(_aptFreqs[i].service, 2, 0, 1);
_kln89->DrawFreq(_aptFreqs[i].freq, 2, 7, 1);
}
i++;
if(i < _aptFreqs.size()) {
_kln89->DrawText(_aptFreqs[i].service, 2, 0, 0);
_kln89->DrawFreq(_aptFreqs[i].freq, 2, 7, 0);
}
} else if(_subPage == 5) {
// TODO - user ought to be allowed to leave persistent remarks
_kln89->DrawText("[Remarks]", 2, 2, 2);
} else if(_subPage == 6) {
// We don't have SID/STAR database yet
// TODO
_kln89->DrawText("No SID/STAR", 2, 3, 2);
_kln89->DrawText("In Data Base", 2, 2, 1);
_kln89->DrawText("For This Airport", 2, 0, 0);
} else if(_subPage == 7) {
if(_iaps.empty()) {
_kln89->DrawText("IAP", 2, 11, 3);
_kln89->DrawText("No Approach", 2, 3, 2);
_kln89->DrawText("In Data Base", 2, 2, 1);
_kln89->DrawText("For This Airport", 2, 0, 0);
} else {
if(_iafDialog) {
_kln89->DrawText(_iaps[_curIap]->_ident, 2, 1, 3);
_kln89->DrawText(_iaps[_curIap]->_rwyStr, 2, 7, 3);
_kln89->DrawText(_iaps[_curIap]->_aptIdent, 2, 12, 3);
_kln89->DrawText("IAF", 2, 2, 2);
unsigned int line = 0;
for(unsigned int i=_iafStart; i<_approachRoutes.size(); ++i) {
if(line == 2) {
i = _approachRoutes.size() - 1;
}
// Assume that the IAF number is always single digit!
_kln89->DrawText(GPSitoa(i+1), 2, 6, 2-line);
if(!(_kln89->_mode == KLN89_MODE_CRSR && _kln89->_blink && _uLinePos == (line + 1))) {
_kln89->DrawText(_approachRoutes[i]->waypoints[0]->id, 2, 8, 2-line);
}
if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == (line + 1) && !(_kln89->_blink )) {
_kln89->Underline(2, 8, 2-line, 5);
}
++line;
}
if(_uLinePos > 0 && !(_kln89->_blink)) {
_kln89->DrawEnt();
}
} else if(_addDialog) {
_kln89->DrawText(_iaps[_curIap]->_ident, 2, 1, 3);
_kln89->DrawText(_iaps[_curIap]->_rwyStr, 2, 7, 3);
_kln89->DrawText(_iaps[_curIap]->_aptIdent, 2, 12, 3);
string s = GPSitoa(_fStart + 1);
_kln89->DrawText(s, 2, 2-s.size(), 2);
s = GPSitoa(_kln89->_approachFP->waypoints.size());
_kln89->DrawText(s, 2, 2-s.size(), 1);
if(!(_uLinePos == _fStart+1 && _kln89->_blink)) {
_kln89->DrawText(_kln89->_approachFP->waypoints[_fStart]->id, 2, 4, 2);
if(_uLinePos == _fStart+1) _kln89->Underline(2, 4, 2, 6);
}
if(!(_uLinePos == _maxULinePos-1 && _kln89->_blink)) {
_kln89->DrawText(_kln89->_approachFP->waypoints[_kln89->_approachFP->waypoints.size()-1]->id, 2, 4, 1);
if(_uLinePos == _maxULinePos-1) _kln89->Underline(2, 4, 1, 6);
}
if(!(_uLinePos > _kln89->_approachFP->waypoints.size() && _kln89->_blink)) {
_kln89->DrawText("ADD TO FPL 0?", 2, 2, 0);
if(_uLinePos > _kln89->_approachFP->waypoints.size()) {
_kln89->Underline(2, 2, 0, 13);
_kln89->DrawEnt();
}
}
} else if(_replaceDialog) {
_kln89->DrawText(_iaps[_curIap]->_ident, 2, 1, 3);
_kln89->DrawText(_iaps[_curIap]->_rwyStr, 2, 7, 3);
_kln89->DrawText(_iaps[_curIap]->_aptIdent, 2, 12, 3);
_kln89->DrawText("Replace Existing", 2, 0, 2);
_kln89->DrawText("Approach", 2, 4, 1);
if(_uLinePos > 0 && !(_kln89->_blink)) {
_kln89->DrawText("APPROVE?", 2, 4, 0);
_kln89->Underline(2, 4, 0, 8);
_kln89->DrawEnt();
}
} else {
_kln89->DrawText("IAP", 2, 11, 3);
bool selApp = false;
if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos > 4) {
selApp = true;
if(!_kln89->_blink) _kln89->DrawEnt();
}
// _maxULine pos should be 4 + iaps.size() at this point.
// Draw a maximum of 3 IAPs.
// If there are more than 3 IAPs for this airport, then we need to offset the start
// of the list if _uLinePos is pointing at the 4th or later IAP.
unsigned int offset = 0;
unsigned int index;
if(_uLinePos > 7) {
offset = _uLinePos - 7;
}
for(unsigned int i=0; i<3; ++i) {
index = offset + i;
if(index < _iaps.size()) {
string s = GPSitoa(index+1);
_kln89->DrawText(s, 2, 2 - s.size(), 2-i);
if(!(selApp && _uLinePos == index+5 && _kln89->_blink)) {
_kln89->DrawText(_iaps[index]->_ident, 2, 3, 2-i);
_kln89->DrawText(_iaps[index]->_rwyStr, 2, 9, 2-i);
}
if(selApp && _uLinePos == index+5 && !_kln89->_blink) {
_kln89->Underline(2, 3, 2-i, 9);
}
} else {
break;
}
}
}
}
}
} else {
if(_kln89->_mode != KLN89_MODE_CRSR) _kln89->DrawText(_apt_id, 2, 1, 3);
if(_subPage == 0) {
/*
_kln89->DrawText("----.-", 2, 9, 3);
_kln89->DrawText("--------------", 2, 0, 2);
_kln89->DrawText("- -- --.--'", 2, 3, 1);
_kln89->DrawText("---- --.--'", 2, 3, 0);
_kln89->DrawSpecialChar(0, 2, 7, 1);
_kln89->DrawSpecialChar(0, 2, 7, 0);
*/
}
}
if(_kln89->_mode == KLN89_MODE_CRSR) {
if(!(_subPage == 7 && (_iafDialog || _addDialog || _replaceDialog))) {
if(_uLinePos > 0 && _uLinePos < 5) {
// TODO - blink as well
_kln89->Underline(2, _uLinePos, 3, 1);
}
for(unsigned int i = 0; i < _apt_id.size(); ++i) {
if(_uLinePos != (i + 1)) {
_kln89->DrawChar(_apt_id[i], 2, i + 1, 3);
} else {
if(!_kln89->_blink) _kln89->DrawChar(_apt_id[i], 2, i + 1, 3);
}
}
}
}
_id = _apt_id;
KLN89Page::Update(dt);
}
void KLN89AptPage::SetId(const string& s) {
if(s != _apt_id || s != _last_apt_id) {
UpdateAirport(s); // If we don't do this here we break things if s is the same as the current ID since the update wouldn't get called then.
/*
DCL: Hmmm - I wrote the comment above, but I don't quite understand it!
I'm not quite sure why I don't simply set _apt_id here (and NOT _last_apt_id)
and let the logic in Update(...) handle the airport details cache update.
*/
}
_last_apt_id = _apt_id;
_save_apt_id = _apt_id;
_apt_id = s;
}
// Update the cached airport details
void KLN89AptPage::UpdateAirport(const string& id) {
// Frequencies
_aptFreqs.clear();
const FGAirport* apt = fgFindAirportID(id);
if (!apt) {
throw sg_exception("UpdateAirport: unknown airport id " + id);
}
for (unsigned int c=0; c<apt->commStations().size(); ++c) {
flightgear::CommStation* comm = apt->commStations()[c];
AptFreq aq;
aq.freq = comm->freqKHz();
switch (comm->type()) {
case FGPositioned::FREQ_ATIS:
aq.service = "ATIS*"; break;
case FGPositioned::FREQ_GROUND:
aq.service = "GRND*"; break;
case FGPositioned::FREQ_TOWER:
aq.service = "TWR *"; break;
case FGPositioned::FREQ_APP_DEP:
aq.service = "APR *"; break;
default:
continue;
}
}
_nFreqPages = (unsigned int)ceil((float(_aptFreqs.size())) / 3.0f);
// Runways
_aptRwys.clear();
// build local array, longest runway first
for (unsigned int r=0; r<apt->numRunways(); ++r) {
FGRunway* rwy(apt->getRunwayByIndex(r));
if ((r > 0) && (rwy->lengthFt() > _aptRwys.front()->lengthFt())) {
_aptRwys.insert(_aptRwys.begin(), rwy);
} else {
_aptRwys.push_back(rwy);
}
}
_nRwyPages = (_aptRwys.size() + 1) / 2; // 2 runways per page.
if(_nFreqPages < 1) _nFreqPages = 1;
if(_nRwyPages < 1) _nRwyPages = 1;
// Instrument approaches
// Only non-precision for now - TODO - handle precision approaches if necessary
_iaps.clear();
iap_map_iterator itr = _kln89->_np_iap.find(id);
if(itr != _kln89->_np_iap.end()) {
_iaps = itr->second;
}
if(_subPage == 7) {
if(_iafDialog || _addDialog || _replaceDialog) {
// Eek - major logic error if an airport details cache update occurs
// with one of these dialogs active.
// TODO - output a warning.
//cout << "HELP!!!!!!!!!!\n";
} else {
_maxULinePos = 4 + _iaps.size(); // We shouldn't need to check the crsr for out-of-bounds here since we only update the airport details when the airport code is changed - ie. _uLinePos <= 4!
}
}
}
void KLN89AptPage::CrsrPressed() {
if(_kln89->_mode == KLN89_MODE_DISP) {
if(_subPage == 7) {
// Pressing crsr jumps back to vanilla IAP page.
_iafDialog = false;
_addDialog = false;
_replaceDialog = false;
}
return;
}
if(_kln89->_obsMode) {
_uLinePos = 0;
} else {
_uLinePos = 1;
}
if(_subPage == 0) {
_maxULinePos = 32;
} else if(_subPage == 7) {
// Don't *think* we need some of this since some of it we can only get to by pressing ENT, not CRSR.
if(_iafDialog) {
_maxULinePos = _approachRoutes.size();
_uLinePos = 1;
} else if(_addDialog) {
_maxULinePos = 1;
_uLinePos = 1;
} else if(_replaceDialog) {
_maxULinePos = 1;
_uLinePos = 1;
} else {
_maxULinePos = 4 + _iaps.size();
if(_iaps.empty()) {
_uLinePos = 1;
} else {
_uLinePos = 5;
}
}
} else {
_maxULinePos = 5;
}
}
void KLN89AptPage::ClrPressed() {
if(_subPage == 1 && _uLinePos == 5) {
_to_flag = !_to_flag;
} else if(_subPage == 7) {
// Clear backs out IAP selection one step at a time
if(_iafDialog) {
_iafDialog = false;
_maxULinePos = 4 + _iaps.size();
if(_iaps.empty()) {
_uLinePos = 1;
} else {
_uLinePos = 5;
}
} else if(_addDialog) {
_addDialog = false;
if(_approachRoutes.size() > 1) {
_iafDialog = true;
_maxULinePos = 1;
// Don't reset _curIaf since it is remembed.
_uLinePos = 1 + _curIaf; // TODO - make this robust to more than 3 IAF
} else {
_maxULinePos = 4 + _iaps.size();
if(_iaps.empty()) {
_uLinePos = 1;
} else {
_uLinePos = 5;
}
}
} else if(_replaceDialog) {
_replaceDialog = false;
_addDialog = true;
_maxULinePos = 1;
_uLinePos = 1;
}
}
}
void KLN89AptPage::EntPressed() {
if(_entInvert) {
_entInvert = false;
if(_kln89->_dtoReview) {
_kln89->DtoInitiate(_apt_id);
} else {
_last_apt_id = _apt_id;
_apt_id = _save_apt_id;
}
} else if(_subPage == 7 && _kln89->_mode == KLN89_MODE_CRSR && _uLinePos > 0) {
// We are selecting an approach
if(_iafDialog) {
if(_uLinePos > 0) {
// Record the IAF that was picked
if(_uLinePos == 3) {
_curIaf = _approachRoutes.size() - 1;
} else {
_curIaf = _uLinePos - 1 + _iafStart;
}
//cout << "_curIaf = " << _curIaf << '\n';
// TODO - delete the waypoints inside _approachFP before clearing them!!!!!!!
_kln89->_approachFP->waypoints.clear();
GPSWaypoint* wp = new GPSWaypoint;
*wp = *(_approachRoutes[_curIaf]->waypoints[0]); // Need to make copies here since we're going to alter ID and type sometimes
string iafid = wp->id;
_kln89->_approachFP->waypoints.push_back(wp);
for(unsigned int i=0; i<_IAP.size(); ++i) {
if(_IAP[i]->id != iafid) { // Don't duplicate waypoints that are part of the initial fix list and the approach procedure list.
// FIXME - allow the same waypoint to be both the IAF and the FAF in some
// approaches that have a procedure turn eg. KDLL
// Also allow MAF to be the same as IAF!
wp = new GPSWaypoint;
*wp = *_IAP[i];
//cout << "Adding waypoint " << wp->id << ", type is " << wp->appType << '\n';
//if(wp->appType == GPS_FAF) wp->id += 'f';
//if(wp->appType == GPS_MAP) wp->id += 'm';
//cout << "New id = " << wp->id << '\n';
_kln89->_approachFP->waypoints.push_back(wp);
}
}
_iafDialog = false;
_addDialog = true;
_maxULinePos = _kln89->_approachFP->waypoints.size() + 1;
_uLinePos = _maxULinePos;
}
} else if(_addDialog) {
if(_uLinePos == _maxULinePos) {
_addDialog = false;
if(_kln89->ApproachLoaded()) {
_replaceDialog = true;
_uLinePos = 1;
_maxULinePos = 1;
} else {
// Now load the approach into the active flightplan.
// As far as I can tell, the rules are this:
// If the airport of the approach is in the flightplan, insert it prior to this. (Not sure what happens if airport has already been passed).
// If the airport is not in the flightplan, append the approach to the flightplan, even if it is closer than the current active leg,
// in which case reorientate to flightplan might put us on the approach, but unable to activate it.
// However, it appears from the sim as if this can indeed happen if the user is not carefull.
bool added = false;
for(unsigned int i=0; i<_kln89->_activeFP->waypoints.size(); ++i) {
if(_kln89->_activeFP->waypoints[i]->id == _apt_id) {
_kln89->_activeFP->waypoints.insert(_kln89->_activeFP->waypoints.begin()+i, _kln89->_approachFP->waypoints.begin(), _kln89->_approachFP->waypoints.end());
added = true;
break;
}
}
if(!added) {
_kln89->_activeFP->waypoints.insert(_kln89->_activeFP->waypoints.end(), _kln89->_approachFP->waypoints.begin(), _kln89->_approachFP->waypoints.end());
}
_kln89->_approachID = _apt_id;
_kln89->_approachAbbrev = _iaps[_curIap]->_ident;
_kln89->_approachRwyStr = _iaps[_curIap]->_rwyStr;
_kln89->_approachLoaded = true;
//_kln89->_messageStack.push_back("*Press ALT To Set Baro");
// Actually - this message is only sent when we go into appraoch-arm mode.
// TODO - check the flightplan for consistency
_kln89->OrientateToActiveFlightPlan();
_kln89->_mode = KLN89_MODE_DISP;
_kln89->_curPage = 7;
_kln89->_activePage = _kln89->_pages[7]; // Do we need to clean up here at all before jumping?
}
}
} else if(_replaceDialog) {
// TODO - load the approach!
} else if(_uLinePos > 4) {
_approachRoutes.clear();
_IAP.clear();
_curIaf = 0;
_approachRoutes = ((FGNPIAP*)(_iaps[_uLinePos-5]))->_approachRoutes;
_IAP = ((FGNPIAP*)(_iaps[_uLinePos-5]))->_IAP;
_curIap = _uLinePos - 5; // TODO - handle the start of list ! no. 1, and the end of list not sequential!
_uLinePos = 1;
if(_approachRoutes.size() > 1) {
// More than 1 IAF - display the selection dialog
_iafDialog = true;
_maxULinePos = _approachRoutes.size();
} else {
// There is only 1 IAF, so load the waypoints into the approach flightplan here.
// TODO - there is nasty code duplication loading the approach FP between the case here where we have only one
// IAF and the case where we must choose the IAF from a list. Try to tidy this after it is all working properly.
_kln89->_approachFP->waypoints.clear();
GPSWaypoint* wp = new GPSWaypoint;
*wp = *(_approachRoutes[0]->waypoints[0]); // Need to make copies here since we're going to alter ID and type sometimes
string iafid = wp->id;
_kln89->_approachFP->waypoints.push_back(wp);
for(unsigned int i=0; i<_IAP.size(); ++i) {
if(_IAP[i]->id != iafid) { // Don't duplicate waypoints that are part of the initial fix list and the approach procedure list.
// FIXME - allow the same waypoint to be both the IAF and the FAF in some
// approaches that have a procedure turn eg. KDLL
// Also allow MAF to be the same as IAF!
wp = new GPSWaypoint;
*wp = *_IAP[i];
_kln89->_approachFP->waypoints.push_back(wp);
}
}
_addDialog = true;
_maxULinePos = 1;
}
}
}
}
void KLN89AptPage::Knob1Left1() {
if(_kln89->_mode == KLN89_MODE_CRSR && _subPage == 7 && _addDialog) {
if(_uLinePos == _maxULinePos) {
_uLinePos--;
if(_kln89->_approachFP->waypoints.size() > 1) _fStart = _kln89->_approachFP->waypoints.size() - 2;
} else if(_uLinePos == _maxULinePos - 1) {
_uLinePos--;
} else if(_uLinePos > 0) {
if(_fStart == 0) {
_uLinePos--;
} else {
_uLinePos--;
_fStart--;
}
}
} else {
KLN89Page::Knob1Left1();
}
}
void KLN89AptPage::Knob1Right1() {
if(_kln89->_mode == KLN89_MODE_CRSR && _subPage == 7 && _addDialog) {
if(_uLinePos == _maxULinePos) {
// no-op
} else if(_uLinePos == _maxULinePos - 1) {
_uLinePos++;
_fStart = 0;
} else if(_uLinePos > 0) {
if(_fStart >= _kln89->_approachFP->waypoints.size() - 2) {
_uLinePos++;
} else {
_uLinePos++;
_fStart++;
}
} else if(_uLinePos == 0) {
_uLinePos++;
_fStart = 0;
}
} else {
KLN89Page::Knob1Right1();
}
}
void KLN89AptPage::Knob2Left1() {
if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
if(_uLinePos == 0 && _kln89->_mode == KLN89_MODE_CRSR && _kln89->_obsMode) {
KLN89Page::Knob2Left1();
} else if(_subPage == 5) {
_subPage = 4;
_curFreqPage = _nFreqPages - 1;
} else if(_subPage == 4) {
// Freqency pages
if(_curFreqPage == 0) {
_subPage = 3;
_curRwyPage = _nRwyPages - 1;
} else {
_curFreqPage--;
}
} else if(_subPage == 3) {
if(_curRwyPage == 0) {
KLN89Page::Knob2Left1();
} else {
_curRwyPage--;
}
} else if(_subPage == 0) {
_subPage = 7;
// We have to set _uLinePos here even though the cursor isn't pressed, to
// ensure that the list displays properly.
if(_iaps.empty()) {
_uLinePos = 1;
} else {
_uLinePos = 5;
}
} else {
KLN89Page::Knob2Left1();
}
} else {
if(_uLinePos < 5 && !(_subPage == 7 && (_iafDialog || _addDialog || _replaceDialog))) {
// Same logic for all pages - set the ID
_apt_id = _apt_id.substr(0, _uLinePos);
// ASSERT(_uLinePos > 0);
if(_uLinePos == (_apt_id.size() + 1)) {
_apt_id += '9';
} else {
_apt_id[_uLinePos - 1] = _kln89->DecChar(_apt_id[_uLinePos - 1], (_uLinePos == 1 ? false : true));
}
} else {
if(_subPage == 0) {
// TODO - set by name
} else {
// NO-OP - to/fr is cycled by clr button
}
}
}
}
void KLN89AptPage::Knob2Right1() {
if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
if(_uLinePos == 0 && _kln89->_mode == KLN89_MODE_CRSR && _kln89->_obsMode) {
KLN89Page::Knob2Right1();
} else if(_subPage == 2) {
_subPage = 3;
_curRwyPage = 0;
} else if(_subPage == 3) {
if(_curRwyPage == _nRwyPages - 1) {
_subPage = 4;
_curFreqPage = 0;
} else {
_curRwyPage++;
}
} else if(_subPage == 4) {
if(_curFreqPage == _nFreqPages - 1) {
_subPage = 5;
} else {
_curFreqPage++;
}
} else if(_subPage == 6) {
_subPage = 7;
// We have to set _uLinePos here even though the cursor isn't pressed, to
// ensure that the list displays properly.
if(_iaps.empty()) {
_uLinePos = 1;
} else {
_uLinePos = 5;
}
} else {
KLN89Page::Knob2Right1();
}
} else {
if(_uLinePos < 5 && !(_subPage == 7 && (_iafDialog || _addDialog || _replaceDialog))) {
// Same logic for all pages - set the ID
_apt_id = _apt_id.substr(0, _uLinePos);
// ASSERT(_uLinePos > 0);
if(_uLinePos == (_apt_id.size() + 1)) {
_apt_id += 'A';
} else {
_apt_id[_uLinePos - 1] = _kln89->IncChar(_apt_id[_uLinePos - 1], (_uLinePos == 1 ? false : true));
}
} else {
if(_subPage == 0) {
// TODO - set by name
} else {
// NO-OP - to/fr is cycled by clr button
}
}
}
}

View File

@@ -0,0 +1,95 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef _KLN89_PAGE_APT
#define _KLN89_PAGE_APT
#include "kln89.hxx"
class FGRunway;
struct AptFreq {
std::string service;
unsigned short int freq;
};
class KLN89AptPage : public KLN89Page {
public:
KLN89AptPage(KLN89* parent);
~KLN89AptPage();
void Update(double dt);
void CrsrPressed();
void ClrPressed();
void EntPressed();
void Knob1Left1();
void Knob1Right1();
void Knob2Left1();
void Knob2Right1();
void SetId(const std::string& s);
private:
// Update the cached airport details
void UpdateAirport(const std::string& id);
std::string _apt_id;
std::string _last_apt_id;
std::string _save_apt_id;
const FGAirport* ap;
vector<FGRunway*> _aptRwys;
vector<AptFreq> _aptFreqs;
iap_list_type _iaps;
unsigned int _curIap; // The index into _iaps of the IAP we are currently selecting
vector<GPSFlightPlan*> _approachRoutes; // The approach route(s) from the IAF(s) to the IF.
vector<GPSWaypoint*> _IAP; // The compulsory waypoints of the approach procedure (may duplicate one of the above).
// _IAP includes the FAF and MAF.
vector<GPSWaypoint*> _MAP; // The missed approach procedure (doesn't include the MAF).
unsigned int _curIaf; // The index into _approachRoutes of the IAF we are currently selecting, and then remembered as the one we selected
// Position in rwy pages
unsigned int _curRwyPage;
unsigned int _nRwyPages;
// Position in freq pages
unsigned int _curFreqPage;
unsigned int _nFreqPages;
// Position in IAP list (0-based number of first IAP displayed)
unsigned int _iapStart;
// ditto for IAF list (can't test this since can't find an approach with > 3 IAF at the moment!)
unsigned int _iafStart;
// ditto for list of approach fixes when asking load confirmation
unsigned int _fStart;
// Various IAP related dialog states that we might need to remember
bool _iafDialog;
bool _addDialog;
bool _replaceDialog;
};
#endif // _KLN89_PAGE_APT

View File

@@ -0,0 +1,338 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff: daveluff --AT-- ntlworld --D0T-- com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cstdlib>
#include <cstdio>
#include <Main/fg_props.hxx>
#include "kln89_page_cal.hxx"
using std::string;
KLN89CalPage::KLN89CalPage(KLN89* parent)
: KLN89Page(parent) {
_nSubPages = 8;
_subPage = 0;
_name = "CAL";
_nFp0 = 0;
_ground_speed_ms = 110 * 0.514444444444;
_alarmAnnotate = false;
_alarmSet = false;
}
KLN89CalPage::~KLN89CalPage() {
}
void KLN89CalPage::Update(double dt) {
bool crsr = (_kln89->_mode == KLN89_MODE_CRSR);
bool blink = _kln89->_blink;
if(_subPage == 0) {
if(1) { // TODO - fix this hardwiring!
// Flightplan calc
_kln89->DrawText(">Fpl:", 2, 0, 3);
_kln89->DrawText("0", 2, 6, 3);// TODO - fix this hardwiring!
GPSFlightPlan* fp = _kln89->_flightPlans[_nFp0];
if(fp) {
unsigned int n = fp->waypoints.size();
if(n < 2) {
// TODO - check that this is what really happens
_kln89->DrawText("----", 2, 9, 3);
_kln89->DrawText("----", 2, 9, 2);
} else {
_kln89->DrawText(fp->waypoints[0]->id, 2, 9, 3);
_kln89->DrawText(fp->waypoints[n-1]->id, 2, 9, 2);
double cum_tot_m = 0.0;
for(unsigned int i = 1; i < fp->waypoints.size(); ++i) {
cum_tot_m += _kln89->GetGreatCircleDistance(fp->waypoints[i-1]->lat, fp->waypoints[i-1]->lon,
fp->waypoints[i]->lat, fp->waypoints[i]->lon);
}
double ete = (cum_tot_m * SG_NM_TO_METER) / _ground_speed_ms;
_kln89->DrawDist(cum_tot_m, 2, 5, 1);
_kln89->DrawSpeed(_ground_speed_ms / 0.5144444444, 2, 5, 0);
_kln89->DrawTime(ete, 2, 14, 0);
}
} else {
_kln89->DrawText("----", 2, 9, 3);
_kln89->DrawText("----", 2, 9, 2);
}
} else {
_kln89->DrawText(">Wpt:", 2, 0, 3);
}
_kln89->DrawText("To", 2, 6, 2);
_kln89->DrawText("ESA ----'", 2, 7, 1); // TODO - implement an ESA calc
_kln89->DrawText("ETE", 2, 7, 0);
} else if(_subPage == 1) {
_kln89->DrawText(">Fpl: 0", 2, 0, 3); // TODO - fix this hardwiring!
_kln89->DrawText("FF:", 2, 0, 2);
_kln89->DrawText("Res:", 2, 7, 1);
_kln89->DrawText("Fuel Req", 2, 0, 0);
} else if(_subPage == 2) {
_kln89->DrawText("Time:", 2, 0, 3);
// TODO - hardwired to UTC at the moment
if(!(_uLinePos == 1 && crsr && blink)) { _kln89->DrawText("UTC", 2, 6, 3); }
if(_uLinePos == 1 && crsr) { _kln89->Underline(2, 6, 3, 3); }
string th = fgGetString("/instrumentation/clock/indicated-hour");
string tm = fgGetString("/instrumentation/clock/indicated-min");
ClockTime t(std::stoi(th), std::stoi(tm));
if(th.size() == 1) th = "0" + th;
if(tm.size() == 1) tm = "0" + tm;
_kln89->DrawText(th + tm, 2, 11, 3);
char buf[12];
_kln89->DrawText("Alarm at:", 2, 0, 2);
_kln89->DrawText("in:", 2, 6, 1);
if(_alarmAnnotate) {
_alarmIn = _alarmTime - t;
snprintf(buf, 5, "%02i", _alarmTime.hr());
if(!(_uLinePos == 2 && crsr && blink)) { _kln89->DrawText((string)buf, 2, 11, 2); }
snprintf(buf, 5, "%02i", _alarmTime.min());
if(!(_uLinePos == 3 && crsr && blink)) { _kln89->DrawText((string)buf, 2, 13, 2); }
} else {
if(!(_uLinePos == 2 && crsr && blink)) { _kln89->DrawText("--", 2, 11, 2); }
if(!(_uLinePos == 3 && crsr && blink)) { _kln89->DrawText("--", 2, 13, 2); }
}
if(_alarmAnnotate && _alarmIn.hr() < 10) {
snprintf(buf, sizeof(buf), "%01i", _alarmIn.hr());
if(!(_uLinePos == 4 && crsr && blink)) { _kln89->DrawText((string)buf, 2, 11, 1); }
snprintf(buf, sizeof(buf), "%02i", _alarmIn.min());
if(!(_uLinePos == 5 && crsr && blink)) { _kln89->DrawText((string)buf, 2, 13, 1); }
} else {
if(!(_uLinePos == 4 && crsr && blink)) { _kln89->DrawText("-", 2, 11, 1); }
if(!(_uLinePos == 5 && crsr && blink)) { _kln89->DrawText("--", 2, 13, 1); }
}
_kln89->DrawText(":", 2, 12, 1);
if(crsr) {
if(_uLinePos == 2) { _kln89->Underline(2, 11, 2, 2); }
if(_uLinePos == 3) { _kln89->Underline(2, 13, 2, 2); }
if(_uLinePos == 4) { _kln89->Underline(2, 11, 1, 1); }
if(_uLinePos == 5) { _kln89->Underline(2, 13, 1, 2); }
}
// TODO
_kln89->DrawText("Elapsed", 2, 0, 0);
ClockTime te = t - _kln89->_powerOnTime;
// There is the possibility that when we reset it we may end up a minute ahead of the
// alarm time for a second, so treat 23:59 as 0.00
if(te.hr() == 23 && te.min() == 59) {
te.set_hr(0);
te.set_min(0);
}
if(!(_uLinePos == 6 && crsr && blink)) {
if(te.hr() > 9) {
// The elapsed time blanks out
// when past 9:59 on the kln89 sim.
_kln89->DrawText("-:--", 2, 11, 0);
} else {
snprintf(buf, 5, "%01i:%02i", te.hr(), te.min());
_kln89->DrawText((string)buf, 2, 11, 0);
}
}
if(_uLinePos == 6 && crsr) { _kln89->Underline(2, 11, 0, 4); }
} else if(_subPage == 3) {
_kln89->DrawText("PRESSURE ALT", 2, 1, 3);
_kln89->DrawText("Ind:", 2, 0, 2);
_kln89->DrawText("Baro:", 2, 0, 1);
_kln89->DrawText("Prs", 2, 0, 0);
} else if(_subPage == 4) {
_kln89->DrawText("DENSITY ALT", 2, 1, 3);
_kln89->DrawText("Prs:", 2, 0, 2);
_kln89->DrawText("Temp:", 2, 0, 1);
_kln89->DrawText("Den", 2, 0, 0);
} else if(_subPage == 5) {
_kln89->DrawText("CAS:", 2, 0, 3);
_kln89->DrawText("Prs:", 2, 0, 2);
_kln89->DrawText("Temp:", 2, 0, 1);
_kln89->DrawText("TAS", 2, 0, 0);
} else if(_subPage == 6) {
_kln89->DrawText("TAS:", 2, 0, 3);
_kln89->DrawText("Hdg:", 2, 0, 2);
_kln89->DrawText("Headwind:", 2, 0, 1);
_kln89->DrawText("True", 2, 4, 0);
} else {
_kln89->DrawText("SUNRISE", 2, 0, 1);
_kln89->DrawText("SUNSET", 2, 0, 0);
}
KLN89Page::Update(dt);
}
void KLN89CalPage::CrsrPressed() {
if(_kln89->_obsMode) {
_uLinePos = 0;
} else {
_uLinePos = 1;
}
if(_subPage == 2) {
_maxULinePos = 6;
}
}
void KLN89CalPage::ClrPressed() {
if(_kln89->_mode != KLN89_MODE_CRSR) {
KLN89Page::ClrPressed();
}
if(_subPage == 2 && _uLinePos == 6) {
_kln89->ResetPowerOnTimer();
} else {
KLN89Page::ClrPressed();
}
}
void KLN89CalPage::Knob2Left1() {
if(_kln89->_mode != KLN89_MODE_CRSR) {
KLN89Page::Knob2Left1();
return;
}
if(_subPage == 2) {
if(_uLinePos == 1) {
// TODO - allow time zone to be changed
} else if(_uLinePos == 2) {
ClockTime t(1,0);
if(_alarmAnnotate) {
_alarmTime = _alarmTime - t;
} else {
_alarmTime.set_hr(std::stoi(fgGetString("/instrumentation/clock/indicated-hour")));
_alarmTime.set_min(std::stoi(fgGetString("/instrumentation/clock/indicated-min")));
_alarmTime = _alarmTime - t;
_alarmAnnotate = true;
}
_alarmSet = true;
} else if(_uLinePos == 3) {
ClockTime t(0,1);
if(_alarmAnnotate) {
_alarmTime = _alarmTime - t;
} else {
_alarmTime.set_hr(std::stoi(fgGetString("/instrumentation/clock/indicated-hour")));
_alarmTime.set_min(std::stoi(fgGetString("/instrumentation/clock/indicated-min")));
_alarmTime = _alarmTime - t;
_alarmAnnotate = true;
}
_alarmSet = true;
} else if(_uLinePos == 4) {
ClockTime t(1,0);
// If the _alarmIn time is dashed out due to being > 9:59
// then changing it starts from zero again.
if(_alarmAnnotate && _alarmIn.hr() < 10) {
_alarmIn = _alarmIn - t;
if(_alarmIn.hr() > 9) { _alarmIn.set_hr(9); }
} else {
_alarmIn.set_hr(9);
_alarmIn.set_min(0);
_alarmAnnotate = true;
}
_alarmSet = true;
t.set_hr(std::stoi(fgGetString("/instrumentation/clock/indicated-hour")));
t.set_min(std::stoi(fgGetString("/instrumentation/clock/indicated-min")));
_alarmTime = t + _alarmIn;
} else if(_uLinePos == 5) {
ClockTime t(0,1);
if(_alarmAnnotate && _alarmIn.hr() < 10) {
_alarmIn = _alarmIn - t;
if(_alarmIn.hr() > 9) { _alarmIn.set_hr(9); }
} else {
_alarmIn.set_hr(9);
_alarmIn.set_min(59);
_alarmAnnotate = true;
}
_alarmSet = true;
t.set_hr(std::stoi(fgGetString("/instrumentation/clock/indicated-hour")));
t.set_min(std::stoi(fgGetString("/instrumentation/clock/indicated-min")));
_alarmTime = t + _alarmIn;
}
}
}
void KLN89CalPage::Knob2Right1() {
if(_kln89->_mode != KLN89_MODE_CRSR) {
KLN89Page::Knob2Right1();
return;
}
if(_subPage == 2) {
if(_uLinePos == 1) {
// TODO - allow time zone to be changed
} else if(_uLinePos == 2) {
ClockTime t(1,0);
if(_alarmAnnotate) {
_alarmTime = _alarmTime + t;
} else {
_alarmTime.set_hr(std::stoi(fgGetString("/instrumentation/clock/indicated-hour")));
_alarmTime.set_min(std::stoi(fgGetString("/instrumentation/clock/indicated-min")));
_alarmTime = _alarmTime + t;
_alarmAnnotate = true;
}
_alarmSet = true;
} else if(_uLinePos == 3) {
ClockTime t(0,1);
if(_alarmAnnotate) {
_alarmTime = _alarmTime + t;
} else {
_alarmTime.set_hr(std::stoi(fgGetString("/instrumentation/clock/indicated-hour")));
_alarmTime.set_min(std::stoi(fgGetString("/instrumentation/clock/indicated-min")));
_alarmTime = _alarmTime + t;
_alarmAnnotate = true;
}
_alarmSet = true;
} else if(_uLinePos == 4) {
ClockTime t(1,0);
if(_alarmAnnotate && _alarmIn.hr() < 10) {
_alarmIn = _alarmIn + t;
if(_alarmIn.hr() > 9) { _alarmIn.set_hr(0); }
} else {
_alarmIn.set_hr(1);
_alarmIn.set_min(0);
_alarmAnnotate = true;
}
_alarmSet = true;
t.set_hr(std::stoi(fgGetString("/instrumentation/clock/indicated-hour")));
t.set_min(std::stoi(fgGetString("/instrumentation/clock/indicated-min")));
_alarmTime = t + _alarmIn;
} else if(_uLinePos == 5) {
ClockTime t(0,1);
if(_alarmAnnotate && _alarmIn.hr() < 10) {
_alarmIn = _alarmIn + t;
if(_alarmIn.hr() > 9) { _alarmIn.set_hr(0); }
} else {
_alarmIn.set_hr(0);
_alarmIn.set_min(1);
_alarmAnnotate = true;
}
_alarmSet = true;
t.set_hr(std::stoi(fgGetString("/instrumentation/clock/indicated-hour")));
t.set_min(std::stoi(fgGetString("/instrumentation/clock/indicated-min")));
_alarmTime = t + _alarmIn;
}
}
}
void KLN89CalPage::LooseFocus() {
if(_alarmSet) {
_kln89->SetAlarm(_alarmTime.hr(), _alarmTime.min());
_alarmSet = false;
}
}

View File

@@ -0,0 +1,78 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff: daveluff --AT-- ntlworld --D0T-- com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef _KLN89_PAGE_CAL
#define _KLN89_PAGE_CAL
#include "kln89.hxx"
class KLN89CalPage : public KLN89Page {
public:
KLN89CalPage(KLN89* parent);
~KLN89CalPage();
void Update(double dt);
void CrsrPressed();
void ClrPressed();
void Knob2Left1();
void Knob2Right1();
void LooseFocus();
private:
unsigned int _nFp0; // flightplan no. displayed on page 1 (_subPage == 0).
double _ground_speed_ms; // Assumed ground speed for ete calc on page 1 (user can alter this).
// CAL3 (alarm) page
ClockTime _alarmTime;
ClockTime _alarmIn;
// _alarmAnnotate shows that the alarm has been set at least once
// so the time should now be always annotated (there seems to be
// no way to remove it once set once!).
bool _alarmAnnotate;
// _alarmSet indicates that the alarm has been changed by the user
// and should be set in the main unit when the page looses focus
// (I don't think the alarm goes off unless the user leaves the
// CAL3 page after setting it).
bool _alarmSet;
// Calculate the alarm time based on the alarm-in value
void CalcAlarmTime();
// Calculate alarm-in based on the alarm time.
void CalcAlarmIn();
// Calculate the difference between 2 hr:min times.
// It is assumed that the second time is always later than the first one
// ie. that the day has wrapped if the second one is less,
// but is limited to intervals of < 24hr.
void TimeDiff(int hr1, int min1, int hr2, int min2, int &hrDiff, int &minDiff);
};
inline std::ostream& operator<< (std::ostream& out, const ClockTime& t) {
return(out << t._hr << ':' << t._min);
}
#endif // _KLN89_PAGE_CAL

View File

@@ -0,0 +1,312 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "kln89_page_dir.hxx"
#include <Main/fg_props.hxx>
using std::string;
KLN89DirPage::KLN89DirPage(KLN89* parent)
: KLN89Page(parent) {
_nSubPages = 1;
_subPage = 0;
_name = "DIR";
_maxULinePos = 4;
_DToWpDispMode = 2;
}
KLN89DirPage::~KLN89DirPage() {
}
void KLN89DirPage::Update(double dt) {
// TODO - this can apparently be "ACTIVATE:" under some circumstances
_kln89->DrawText("DIRECT TO:", 2, 2, 3);
if(_kln89->_mode == KLN89_MODE_CRSR) {
string s = _id;
while(s.size() < 5) s += ' ';
if(_DToWpDispMode == 0) {
if(!_kln89->_blink) {
_kln89->DrawText(s, 2, 4, 1, false, 99);
_kln89->DrawEnt(1, 0, 1);
}
} else if(_DToWpDispMode == 1) {
if(!_kln89->_blink) {
_kln89->DrawText(s, 2, 4, 1, false, _uLinePos);
_kln89->DrawEnt(1, 0, 1);
}
_kln89->Underline(2, 4, 1, 5);
} else {
if(!_kln89->_blink) _kln89->DrawText("_____", 2, 4, 1);
_kln89->Underline(2, 4, 1, 5);
}
} else {
_kln89->DrawText("_____", 2, 4, 1);
}
KLN89Page::Update(dt);
}
// This can only be called from the KLN89 when DTO is pressed from outside of the DIR page.
// DO NOT USE IT to set _id internally from the DIR page, since it initialises various state
// based on the assumption that the DIR page is being first entered.
void KLN89DirPage::SetId(const string& s) {
if(s.size()) {
_id = s;
_DToWpDispMode = 0;
if(!_kln89->_activeFP->IsEmpty()) {
_DToWpDispIndex = (int)_kln89->_activeFP->waypoints.size() - 1;
}
} else {
_DToWpDispMode = 2;
}
_saveMasterMode = _kln89->_mode;
_uLinePos = 1; // Needed to stop Leg flashing
}
void KLN89DirPage::CrsrPressed() {
// Pressing CRSR clears the ID field (from sim).
_DToWpDispMode = 2;
}
void KLN89DirPage::ClrPressed() {
if(_kln89->_mode == KLN89_MODE_CRSR) {
if(_DToWpDispMode <= 1) {
_DToWpDispMode = 2;
_id.clear();
} else {
// Restore the original master mode
_kln89->_mode = _saveMasterMode;
// Stop displaying dir page
_kln89->_activePage = _kln89->_pages[_kln89->_curPage];
}
} else {
// TODO
}
}
void KLN89DirPage::EntPressed() {
// Trim any RH whitespace from _id
while(!_id.empty()) {
if(_id[_id.size()-1] == ' ') {
_id = _id.substr(0, _id.size()-1);
} else {
// Important to break, since usr waypoint names may contain space.
break;
}
}
if(_DToWpDispMode == 2 || _id.empty()) {
_kln89->DtoCancel();
} else {
if(_DToWpDispMode == 0) {
// It's a waypoint from the active flightplan - these get processed without data page review.
_kln89->DtoInitiate(_id);
} else {
// Display the appropriate data page for review (USR page if the ident is not currently valid)
_kln89->_dtoReview = true;
GPSWaypoint* wp = _kln89->FindFirstByExactId(_id);
if(wp) {
// Set the current page to be the appropriate data page
_kln89->_curPage = wp->type;
delete wp;
} else {
// Set the current page to be the user page
_kln89->_curPage = 4;
}
// set the page ID and entInvert, and activate the current page.
_kln89->_activePage = _kln89->_pages[_kln89->_curPage];
_kln89->_activePage->SetId(_id);
_kln89->_activePage->SetEntInvert(true);
}
}
}
void KLN89DirPage::Knob2Left1() {
if(_kln89->_mode == KLN89_MODE_CRSR) {
if(fgGetBool("/instrumentation/kln89/scan-pull")) {
if(_DToWpDispMode == 2) {
if(!_kln89->_activeFP->IsEmpty()) {
// Switch to mode 0, set the position to the end of the active flightplan *and* run the mode 0 case.
_DToWpDispMode = 0;
_DToWpDispIndex = (int)_kln89->_activeFP->waypoints.size() - 1;
}
}
if(_DToWpDispMode == 0) {
// If the knob is pulled out, then the unit cycles through the waypoints of the active flight plan
// (This is deduced from the Bendix-King sim, I haven't found it documented in the pilot guide).
// If the active flight plan is empty it clears the field (this is possible, e.g. if a data page was
// active when DTO was pressed).
if(!_kln89->_activeFP->IsEmpty()) {
if(_DToWpDispIndex == 0) {
_DToWpDispIndex = (int)_kln89->_activeFP->waypoints.size() - 1;
} else {
_DToWpDispIndex--;
}
_id = _kln89->_activeFP->waypoints[_DToWpDispIndex]->id;
} else {
_DToWpDispMode = 2;
}
}
// _DToWpDispMode == 1 is a NO-OP when the knob is out.
} else {
if(_DToWpDispMode == 0) {
// If the knob is not pulled out, then turning it transitions the DIR page to the waypoint selection mode
// and sets the waypoint to the first beginning with '9'
_id = "9";
GPSWaypoint* wp = _kln89->FindFirstById(_id);
if(wp) {
_id = wp->id;
delete wp;
}
_uLinePos = 0;
_DToWpDispMode = 1;
} else if(_DToWpDispMode == 1) {
while(_id.size() < (_uLinePos + 1)) {
_id += ' ';
}
char ch = _id[_uLinePos];
if(ch == ' ') {
ch = '9';
} else if(ch == '0') {
ch = 'Z';
} else if(ch == 'A') {
// It seems that blanks are allowed within the name, but not for the first character
if(_uLinePos == 0) {
ch = '9';
} else {
ch = ' ';
}
} else {
ch--;
}
_id[_uLinePos] = ch;
GPSWaypoint* wp = _kln89->FindFirstById(_id.substr(0, _uLinePos+1));
if(wp) {
_id = wp->id;
delete wp;
}
} else {
_id = "9";
GPSWaypoint* wp = _kln89->FindFirstById(_id);
if(wp) {
_id = wp->id;
delete wp;
}
_uLinePos = 0;
_DToWpDispMode = 1;
}
}
} else {
// If the cursor is not displayed, then we return to the page that was displayed prior to DTO being pressed,
// and pass the knob turn to that page, whether pulled out or not.
_kln89->_activePage = _kln89->_pages[_kln89->_curPage];
_kln89->_activePage->Knob2Left1();
}
}
void KLN89DirPage::Knob2Right1() {
if(_kln89->_mode == KLN89_MODE_CRSR) {
if(fgGetBool("/instrumentation/kln89/scan-pull")) {
if(_DToWpDispMode == 2) {
if(!_kln89->_activeFP->IsEmpty()) {
// Switch to mode 0, set the position to the end of the active flightplan *and* run the mode 0 case.
_DToWpDispMode = 0;
_DToWpDispIndex = (int)_kln89->_activeFP->waypoints.size() - 1;
}
}
if(_DToWpDispMode == 0) {
// If the knob is pulled out, then the unit cycles through the waypoints of the active flight plan
// (This is deduced from the Bendix-King sim, I haven't found it documented in the pilot guide).
// If the active flight plan is empty it clears the field (this is possible, e.g. if a data page was
// active when DTO was pressed).
if(!_kln89->_activeFP->IsEmpty()) {
if(_DToWpDispIndex == (int)_kln89->_activeFP->waypoints.size() - 1) {
_DToWpDispIndex = 0;
} else {
_DToWpDispIndex++;
}
_id = _kln89->_activeFP->waypoints[_DToWpDispIndex]->id;
} else {
_DToWpDispMode = 2;
}
}
// _DToWpDispMode == 1 is a NO-OP when the knob is out.
} else {
if(_DToWpDispMode == 0) {
// If the knob is not pulled out, then turning it transitions the DIR page to the waypoint selection mode
// and sets the waypoint to the first beginning with 'A'
_id = "A";
GPSWaypoint* wp = _kln89->FindFirstById(_id);
if(wp) {
_id = wp->id;
delete wp;
}
_uLinePos = 0;
_DToWpDispMode = 1;
} else if(_DToWpDispMode == 1) {
while(_id.size() < (_uLinePos + 1)) {
_id += ' ';
}
char ch = _id[_uLinePos];
if(ch == ' ') {
ch = 'A';
} else if(ch == 'Z') {
ch = '0';
} else if(ch == '9') {
// It seems that blanks are allowed within the name, but not for the first character
if(_uLinePos == 0) {
ch = 'A';
} else {
ch = ' ';
}
} else {
ch++;
}
_id[_uLinePos] = ch;
GPSWaypoint* wp = _kln89->FindFirstById(_id.substr(0, _uLinePos+1));
if(wp) {
_id = wp->id;
delete wp;
}
} else {
_id = "A";
GPSWaypoint* wp = _kln89->FindFirstById(_id);
if(wp) {
_id = wp->id;
delete wp;
}
_uLinePos = 0;
_DToWpDispMode = 1;
}
}
} else {
// If the cursor is not displayed, then we return to the page that was displayed prior to DTO being pressed,
// and pass the knob turn to that page, whether pulled out or not.
_kln89->_activePage = _kln89->_pages[_kln89->_curPage];
_kln89->_activePage->Knob2Right1();
}
}

View File

@@ -0,0 +1,61 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef _KLN89_PAGE_DIR
#define _KLN89_PAGE_DIR
#include "kln89.hxx"
class KLN89DirPage : public KLN89Page {
public:
KLN89DirPage(KLN89* parent);
~KLN89DirPage();
void Update(double dt);
void SetId(const std::string& s);
void CrsrPressed();
void ClrPressed();
void EntPressed();
void Knob2Left1();
void Knob2Right1();
private:
// Waypoint display mode.
// There are a number of ways that the waypoint can be displayed in the DIR page:
// 0 => Whole candidate waypoint displayed, entirely inverted. This is normally how the page is initially displayed, unless a candidate waypoint cannot be determined.
// 1 => Waypoint being entered, with a corresponding cursor position, and only the cursor position inverted.
// 2 => Blanks. These can be displayed flashing when the cursor is active (eg. when CLR is pressed) and are always displayed if the cursor is turned off.
int _DToWpDispMode;
// Position of the list in the mode that scans through the active flight plan.
// This should be initialised to point at the final waypoint of the active flight plan when we enter mode zero above.
int _DToWpDispIndex;
// We need to save the mode when DTO gets pressed, since potentially this class handles page exit via. the CLR event handler
KLN89Mode _saveMasterMode;
};
#endif // _KLN89_PAGE_DIR

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,91 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef _KLN89_PAGE_FPL_HXX
#define _KLN89_PAGE_FPL_HXX
#include "kln89.hxx"
class KLN89FplPage : public KLN89Page {
public:
KLN89FplPage(KLN89* parent);
~KLN89FplPage();
void Update(double dt);
void CrsrPressed();
void EntPressed();
void ClrPressed();
void Knob1Left1();
void Knob1Right1();
void Knob2Left1();
void Knob2Right1();
void CleanUp();
void LooseFocus();
// Override the base class GetId function to return the waypoint ID under the cursor
// on FPL0 page, if there is one and the cursor is on.
// Otherwise return an empty string.
inline const std::string& GetId() { return(_fp0SelWpId); }
private:
int _fpMode; // 0 = Dis, 1 = Dtk
int _actFpMode; // 0 = Dis, 1 = ETE, 2 = ETA, 3 = Dtk/OBS
bool _bEntWp; // set true when a waypoint is being entered
bool _bEntExp; // Set true when ent is expected to set the currently entered waypoint as entered.
std::string _entWpStr; // The currently entered wp ID (need not be valid)
GPSWaypoint* _entWp; // Waypoint being currently entered
// The position of the cursor in a waypoint being entered
unsigned int _wLinePos;
unsigned int _fplPos; // The position of the start of the FP (NOT the active one) (zero-based).
// since this is reset when subpage changes we only need 1, not an array of 25!
bool _resetFplPos0; // Set true when a recalculation of _fplPos for the active flightplan page is required.
int _hdrPos;
int _fencePos;
// Get the waypoint (returned thru the pointer) at the zero-based position (pos)
// in the waypoint display of the current page.
// Returns 0 if no waypoint, 1 if sucessfull, 2 if appr header, 3 if approach fence.
//int GetFPWaypoint(GPSWaypoint* wp, int pos);
bool _delFP; // Set true when the delete FP? dialogue is being displayed
bool _delWp; // The position of the waypoint to delete is given by _uLinePos
bool _delAppr; // Set true when the delete approach dialogue is being displayed
bool _changeAppr;
void DrawFpMode(int ypos);
void Calc();
// The ID of the waypoint under the cursor in fpl0, if those conditions exist!
std::string _fp0SelWpId;
std::vector<std::string> _params;
};
#endif // _KLN89_PAGE_FPL_HXX

View File

@@ -0,0 +1,257 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cstdio>
#include "kln89_page_int.hxx"
#include <Navaids/fix.hxx>
#include <Navaids/navrecord.hxx>
using std::string;
KLN89IntPage::KLN89IntPage(KLN89* parent)
: KLN89Page(parent) {
_nSubPages = 2;
_subPage = 0;
_name = "INT";
_int_id = "PORTE";
_last_int_id = "";
_fp = NULL;
_nearestVor = NULL;
_refNav = NULL;
}
KLN89IntPage::~KLN89IntPage() {
}
void KLN89IntPage::Update(double dt) {
bool actPage = (_kln89->_activePage->GetName() == "ACT" ? true : false);
bool multi; // Not set by FindFirst...
bool exact = false;
if(_int_id.size() == 5) exact = true;
if(_fp == NULL) {
_fp = _kln89->FindFirstIntById(_int_id, multi, exact);
} else if(_fp->get_ident() != _int_id) {
_fp = _kln89->FindFirstIntById(_int_id, multi, exact);
}
if(_fp) {
_int_id = _fp->get_ident();
if(_kln89->GetActiveWaypoint()) {
if(_int_id == _kln89->GetActiveWaypoint()->id) {
if(!(_kln89->_waypointAlert && _kln89->_blink)) {
// Active waypoint arrow
_kln89->DrawSpecialChar(4, 2, 0, 3);
}
}
}
if(_int_id != _last_int_id) {
_nearestVor = _kln89->FindClosestVor(_fp->get_lat() * SG_DEGREES_TO_RADIANS, _fp->get_lon() * SG_DEGREES_TO_RADIANS);
if(_nearestVor) {
_nvRadial = _kln89->GetMagHeadingFromTo(_nearestVor->get_lat() * SG_DEGREES_TO_RADIANS, _nearestVor->get_lon() * SG_DEGREES_TO_RADIANS,
_fp->get_lat() * SG_DEGREES_TO_RADIANS, _fp->get_lon() * SG_DEGREES_TO_RADIANS);
_nvDist = _kln89->GetGreatCircleDistance(_nearestVor->get_lat() * SG_DEGREES_TO_RADIANS, _nearestVor->get_lon() * SG_DEGREES_TO_RADIANS,
_fp->get_lat() * SG_DEGREES_TO_RADIANS, _fp->get_lon() * SG_DEGREES_TO_RADIANS);
_refNav = _nearestVor; // TODO - check that this *always* holds - eg. when changing INT id after explicitly setting ref nav
// but with no loss of focus.
} else {
_refNav = NULL;
}
_last_int_id = _int_id;
}
if(_kln89->_mode != KLN89_MODE_CRSR) {
if(!_entInvert) {
if(!actPage) {
_kln89->DrawText(_fp->get_ident(), 2, 1, 3);
} else {
// If it's the ACT page, The ID is shifted slightly right to make space for the waypoint index.
_kln89->DrawText(_fp->get_ident(), 2, 4, 3);
char buf[3];
int n = snprintf(buf, 3, "%i", _kln89->GetActiveWaypointIndex() + 1);
_kln89->DrawText((string)buf, 2, 3 - n, 3);
// We also draw an I to differentiate INT from USR when it's the ACT page
_kln89->DrawText("I", 2, 11, 3);
}
} else {
if(!_kln89->_blink) {
_kln89->DrawText(_fp->get_ident(), 2, 1, 3, false, 99);
_kln89->DrawEnt();
}
}
}
if(_subPage == 0) {
_kln89->DrawLatitude(_fp->get_lat(), 2, 3, 2);
_kln89->DrawLongitude(_fp->get_lon(), 2, 3, 1);
_kln89->DrawDirDistField(_fp->get_lat() * SG_DEGREES_TO_RADIANS, _fp->get_lon() * SG_DEGREES_TO_RADIANS, 2, 0, 0,
_to_flag, (_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 6 ? true : false));
} else {
_kln89->DrawText("Ref:", 2, 1, 2);
_kln89->DrawText("Rad:", 2, 1, 1);
_kln89->DrawText("Dis:", 2, 1, 0);
if(_refNav) {
_kln89->DrawText(_refNav->get_ident(), 2, 9, 2); // TODO - flash and allow to change if under cursor
//_kln89->DrawHeading(_nvRadial, 2, 11, 1);
//_kln89->DrawDist(_nvDist, 2, 11, 0);
// Currently our draw heading and draw dist functions don't do as many decimal points as we want here,
// so draw it ourselves!
// Heading
char buf[10];
snprintf(buf, 6, "%.1f", _nvRadial);
string s = buf;
_kln89->DrawText(s, 2, 13 - s.size(), 1);
_kln89->DrawSpecialChar(0, 2, 13, 1); // Degrees symbol
// Dist
double d = _nvDist;
d *= (_kln89->_distUnits == GPS_DIST_UNITS_NM ? 1.0 : SG_NM_TO_METER * 0.001);
snprintf(buf, 9, "%.1f", d);
s = buf;
s += (_kln89->_distUnits == GPS_DIST_UNITS_NM ? "nm" : "Km");
_kln89->DrawText(s, 2, 14 - s.size(), 0);
}
}
} else {
// TODO - when we leave the page with invalid id and return it should
// revert to showing the last valid id. Same for vor/ndb/probably apt etc.
if(_kln89->_mode != KLN89_MODE_CRSR) _kln89->DrawText(_int_id, 2, 1, 3);
if(_subPage == 0) {
_kln89->DrawText("- -- --.--'", 2, 3, 2);
_kln89->DrawText("---- --.--'", 2, 3, 1);
_kln89->DrawSpecialChar(0, 2, 7, 2);
_kln89->DrawSpecialChar(0, 2, 7, 1);
_kln89->DrawText(">--- ----", 2, 0, 0);
_kln89->DrawSpecialChar(0, 2, 4, 0);
_kln89->DrawText(_to_flag ? "To" : "Fr", 2, 5, 0);
_kln89->DrawText(_kln89->_distUnits == GPS_DIST_UNITS_NM ? "nm" : "km", 2, 12, 0);
}
}
if(_kln89->_mode == KLN89_MODE_CRSR) {
if(_uLinePos > 0 && _uLinePos < 6) {
// TODO - blink as well
_kln89->Underline(2, _uLinePos, 3, 1);
}
for(unsigned int i = 0; i < _int_id.size(); ++i) {
if(_uLinePos != (i + 1)) {
_kln89->DrawChar(_int_id[i], 2, i + 1, 3);
} else {
if(!_kln89->_blink) _kln89->DrawChar(_int_id[i], 2, i + 1, 3);
}
}
}
// TODO - fix this duplication - use _id instead of _apt_id, _vor_id, _ndb_id, _int_id etc!
_id = _int_id;
KLN89Page::Update(dt);
}
void KLN89IntPage::SetId(const string& s) {
_last_int_id = _int_id;
_save_int_id = _int_id;
_int_id = s;
_fp = NULL;
}
void KLN89IntPage::CrsrPressed() {
if(_kln89->_mode == KLN89_MODE_DISP) return;
if(_kln89->_obsMode) {
_uLinePos = 0;
} else {
_uLinePos = 1;
}
if(_subPage == 0) {
_maxULinePos = 6;
} else {
_maxULinePos = 6;
}
}
void KLN89IntPage::ClrPressed() {
if(_subPage == 0 && _uLinePos == 6) {
_to_flag = !_to_flag;
}
}
void KLN89IntPage::EntPressed() {
if(_entInvert) {
_entInvert = false;
_entInvert = false;
if(_kln89->_dtoReview) {
_kln89->DtoInitiate(_int_id);
} else {
_last_int_id = _int_id;
_int_id = _save_int_id;
}
}
}
void KLN89IntPage::Knob2Left1() {
if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
KLN89Page::Knob2Left1();
} else {
if(_uLinePos < 6) {
// Same logic for both pages - set the ID
_int_id = _int_id.substr(0, _uLinePos);
// ASSERT(_uLinePos > 0);
if(_uLinePos == (_int_id.size() + 1)) {
_int_id += '9';
} else {
_int_id[_uLinePos - 1] = _kln89->DecChar(_int_id[_uLinePos - 1], (_uLinePos == 1 ? false : true));
}
} else {
if(_subPage == 0) {
// NO-OP - from/to field is switched by clr button, not inner knob.
} else {
// TODO - LNR type field.
}
}
}
}
void KLN89IntPage::Knob2Right1() {
if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
KLN89Page::Knob2Right1();
} else {
if(_uLinePos < 6) {
// Same logic for both pages - set the ID
_int_id = _int_id.substr(0, _uLinePos);
// ASSERT(_uLinePos > 0);
if(_uLinePos == (_int_id.size() + 1)) {
_int_id += 'A';
} else {
_int_id[_uLinePos - 1] = _kln89->IncChar(_int_id[_uLinePos - 1], (_uLinePos == 1 ? false : true));
}
} else {
if(_subPage == 0) {
// NO-OP - from/to field is switched by clr button, not inner knob.
} else {
// TODO - LNR type field.
}
}
}
}

View File

@@ -0,0 +1,58 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef _KLN89_PAGE_INT_HXX
#define _KLN89_PAGE_INT_HXX
#include "kln89.hxx"
class FGFix;
class KLN89IntPage : public KLN89Page {
public:
KLN89IntPage(KLN89* parent);
~KLN89IntPage();
void Update(double dt);
void CrsrPressed();
void ClrPressed();
void EntPressed();
void Knob2Left1();
void Knob2Right1();
void SetId(const std::string& s);
private:
std::string _int_id;
std::string _last_int_id;
std::string _save_int_id;
const FGFix* _fp;
FGNavRecord* _nearestVor;
FGNavRecord* _refNav; // Will usually be the same as _nearestVor, and gets reset to _nearestVor when page looses focus.
double _nvRadial; // radial from nearest VOR
double _nvDist; // distance to nearest VOR
};
#endif // _KLN89_PAGE_INT_HXX

View File

@@ -0,0 +1,610 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cstdlib>
#include <cstdio>
#include "kln89_page_nav.hxx"
#include <Main/fg_props.hxx>
using std::string;
KLN89NavPage::KLN89NavPage(KLN89* parent)
: KLN89Page(parent) {
_nSubPages = 4;
_subPage = 0;
_name = "NAV";
_posFormat = 0; // Check - should this default to ref from waypoint?
_vnv = 0;
_nav4DataSnippet = 0;
_cdiFormat = 0;
_menuActive = false;
_menuPos = 0;
_suspendAVS = false;
_scanWpSet = false;
_scanWpIndex = -1;
}
KLN89NavPage::~KLN89NavPage() {
}
void KLN89NavPage::Update(double dt) {
GPSFlightPlan* fp = _kln89->_activeFP;
GPSWaypoint* awp = _kln89->GetActiveWaypoint();
// Scan-pull out on nav4 page switches off the cursor
if(3 == _subPage && fgGetBool("/instrumentation/kln89/scan-pull")) { _kln89->_mode = KLN89_MODE_DISP; }
bool crsr = (_kln89->_mode == KLN89_MODE_CRSR);
bool blink = _kln89->_blink;
double lat = _kln89->_gpsLat * SG_RADIANS_TO_DEGREES;
double lon = _kln89->_gpsLon * SG_RADIANS_TO_DEGREES;
if(_subPage != 3) { _scanWpSet = false; }
if(0 == _subPage) {
if(_kln89->_navFlagged) {
_kln89->DrawText("> F L A G", 2, 0, 2);
_kln89->DrawText("DTK --- TK ---", 2, 0, 1);
_kln89->DrawText(">--- To --:--", 2, 0, 0);
_kln89->DrawSpecialChar(0, 2, 7, 1);
_kln89->DrawSpecialChar(0, 2, 15, 1);
_kln89->DrawSpecialChar(0, 2, 4, 0);
_kln89->DrawSpecialChar(1, 2, 3, 2);
_kln89->DrawSpecialChar(1, 2, 4, 2);
_kln89->DrawSpecialChar(1, 2, 6, 2);
_kln89->DrawSpecialChar(1, 2, 10, 2);
_kln89->DrawSpecialChar(1, 2, 12, 2);
_kln89->DrawSpecialChar(1, 2, 13, 2);
} else {
if(_kln89->_dto) {
_kln89->DrawDTO(2, 7, 3);
} else {
if(!(_kln89->_waypointAlert && _kln89->_blink)) {
_kln89->DrawSpecialChar(3, 2, 8, 3);
}
}
_kln89->DrawText(awp->id, 2, 10, 3);
if(!_kln89->_dto && !_kln89->_obsMode && !_kln89->_fromWaypoint.id.empty()) {
if(_kln89->_fromWaypoint.type != GPS_WP_VIRT) { // Don't draw the virtual waypoint names
_kln89->DrawText(_kln89->_fromWaypoint.id, 2, 1, 3);
}
}
if(!(crsr && blink && _uLinePos == 1)) {
if(_cdiFormat == 0) {
_kln89->DrawCDI();
} else if(_cdiFormat == 1) {
_kln89->DrawText("Fly", 2, 2, 2);
double x = _kln89->CalcCrossTrackDeviation();
// TODO - check the R/L from sign of x below - I *think* it holds but not sure!
// Note also that we're setting Fly R or L based on the aircraft
// position only, not the heading. Not sure if this is correct or not.
_kln89->DrawText(x < 0.0 ? "R" : "L", 2, 6, 2);
char buf[6];
int n;
x = fabs(x * (_kln89->_distUnits == GPS_DIST_UNITS_NM ? 1.0 : SG_NM_TO_METER * 0.001));
if(x < 1.0) {
n = snprintf(buf, 6, "%0.2f", x);
} else if(x < 100.0) {
n = snprintf(buf, 6, "%0.1f", x);
} else {
n = snprintf(buf, 6, "%i", (int)(x+0.5));
}
_kln89->DrawText((string)buf, 2, 13-n, 2);
_kln89->DrawText(_kln89->_distUnits == GPS_DIST_UNITS_NM ? "nm" : "km", 2, 13, 2);
} else {
_kln89->DrawText("CDI Scale:", 2, 1, 2);
double d = _kln89->_cdiScales[_kln89->_currentCdiScaleIndex] * (_kln89->_distUnits == GPS_DIST_UNITS_NM ? 1.0 : SG_NM_TO_METER * 0.001);
char buf[5];
string s;
if(d >= 1.0) {
snprintf(buf, 4, "%2.1f", d);
s = buf;
} else {
snprintf(buf, 5, "%2.2f", d);
// trim the leading zero
s = buf;
s = s.substr(1, s.size() - 1);
}
_kln89->DrawText(s, 2, 11, 2);
_kln89->DrawText(_kln89->_distUnits == GPS_DIST_UNITS_NM ? "nm" : "km", 2, 14, 2);
}
}
_kln89->DrawChar('>', 2, 0, 2);
_kln89->DrawChar('>', 2, 0, 0);
if(crsr) {
if(_uLinePos == 1) _kln89->Underline(2, 1, 2, 15);
else if(_uLinePos == 2) _kln89->Underline(2, 1, 0, 9);
}
// Desired and actual magnetic track
if(!_kln89->_obsMode) {
_kln89->DrawText("DTK", 2, 0, 1);
_kln89->DrawHeading((int)_kln89->_dtkMag, 2, 7, 1);
}
_kln89->DrawText("TK", 2, 9, 1);
if(_kln89->_groundSpeed_ms > 3) { // about 6 knots, don't know exactly what value to disable track
// The trouble with relying on FG gps's track value is we don't know when it's valid.
_kln89->DrawHeading((int)_kln89->_magTrackDeg, 2, 15, 1);
} else {
_kln89->DrawText("---", 2, 12, 1);
_kln89->DrawSpecialChar(0, 2, 15, 1);
}
// Radial to/from active waypoint.
// TODO - Not sure if this either is or should be true or mag!!!!!!!
if(!(crsr && blink && _uLinePos == 2)) {
if(0 == _vnv) {
_kln89->DrawHeading((int)_kln89->GetHeadingToActiveWaypoint(), 2, 4, 0);
_kln89->DrawText("To", 2, 5, 0);
} else if(1 == _vnv) {
_kln89->DrawHeading((int)_kln89->GetHeadingFromActiveWaypoint(), 2, 4, 0);
_kln89->DrawText("Fr", 2, 5, 0);
} else {
_kln89->DrawText("Vnv Off", 2, 1, 0);
}
}
// It seems that the floating point groundspeed must be at least 30kt
// for an ETA to be calculated. Note that this means that (integer) 30kt
// can appear in the frame 1 display both with and without an ETA displayed.
// TODO - need to switch off track (and heading bug change) based on instantaneous speed as well
// since the long gps lag filter means we can still be displaying when stopped on ground.
if(_kln89->_groundSpeed_kts > 30.0) {
// Assuming eta display is always hh:mm
// Does it ever switch to seconds when close?
if(_kln89->_eta / 3600.0 > 100.0) {
// More that 100 hours ! - Doesn't fit.
_kln89->DrawText("--:--", 2, 11, 0);
} else {
_kln89->DrawTime(_kln89->_eta, 2, 15, 0);
}
} else {
_kln89->DrawText("--:--", 2, 11, 0);
}
}
} else if(1 == _subPage) {
// Present position
_kln89->DrawChar('>', 2, 1, 3);
if(!(crsr && blink && _uLinePos == 1)) _kln89->DrawText("PRESENT POSN", 2, 2, 3);
if(crsr && _uLinePos == 1) _kln89->Underline(2, 2, 3, 12);
if(0 == _posFormat) {
// Lat/lon
_kln89->DrawLatitude(lat, 2, 3, 1);
_kln89->DrawLongitude(lon, 2, 3, 0);
} else {
// Ref from wp - defaults to nearest vor (and resets to default when page left and re-entered).
}
} else if(2 == _subPage) {
_kln89->DrawText("Time", 2, 0, 3);
// TODO - hardwired to UTC at the moment
_kln89->DrawText("UTC", 2, 6, 3);
string th = fgGetString("/instrumentation/clock/indicated-hour");
string tm = fgGetString("/instrumentation/clock/indicated-min");
if(th.size() == 1) th = "0" + th;
if(tm.size() == 1) tm = "0" + tm;
_kln89->DrawText(th + tm, 2, 11, 3);
_kln89->DrawText("Depart", 2, 0, 2);
_kln89->DrawText(_kln89->_departureTimeString, 2, 11, 2);
_kln89->DrawText("ETA", 2, 0, 1);
if(_kln89->_departed) {
/* Rules of ETA waypoint are:
If the active waypoint is part of the active flightplan, then display
the ETA to the final (destination) waypoint of the active flightplan.
If the active waypoint is not part of the active flightplan, then
display the ETA to the active waypoint. */
// TODO - implement the above properly - we haven't below!
string wid = "";
if(fp->waypoints.size()) {
wid = fp->waypoints[fp->waypoints.size() - 1]->id;
} else if(awp) {
wid = awp->id;
}
if(!wid.empty()) {
_kln89->DrawText(wid, 2, 4, 1);
double tsec = _kln89->GetTimeToWaypoint(wid);
if(tsec < 0.0) {
_kln89->DrawText("----", 2, 11, 1);
} else {
int etah = (int)tsec / 3600;
int etam = ((int)tsec - etah * 3600) / 60;
etah += std::stoi(fgGetString("/instrumentation/clock/indicated-hour"));
etam += std::stoi(fgGetString("/instrumentation/clock/indicated-min"));
while(etam > 59) {
etam -= 60;
etah += 1;
}
while(etah > 23) {
etah -= 24;
}
char buf[6];
int n = snprintf(buf, 6, "%02i%02i", etah, etam);
_kln89->DrawText((string)buf, 2, 15-n, 1);
}
} else {
_kln89->DrawText("----", 2, 11, 1);
}
} else {
_kln89->DrawText("----", 2, 11, 1);
}
_kln89->DrawText("Flight", 2, 0, 0);
if(_kln89->_departed) {
int eh = (int)_kln89->_elapsedTime / 3600;
int em = ((int)_kln89->_elapsedTime - eh * 3600) / 60;
char buf[6];
int n = snprintf(buf, 6, "%i:%02i", eh, em);
_kln89->DrawText((string)buf, 2, 15-n, 0);
} else {
_kln89->DrawText("-:--", 2, 11, 0);
}
} else { // if(3 == _subPage)
//
// Switch the cursor off if scan-pull is out on this page.
//
if(fgGetBool("/instrumentation/kln89/scan-pull")) { _kln89->_mode = KLN89_MODE_DISP; }
//
// Draw the moving map if valid.
// We call the core KLN89 class to do this.
//
if(_kln89->_mapOrientation == 2 && _kln89->_groundSpeed_kts < 2) {
// Don't draw it if in track up mode and groundspeed < 2kts, as per real-life unit.
} else {
_kln89->DrawMap(!_suspendAVS);
}
//
// Now that the map has been drawn, add the annotation (scale, etc).
//
int scale = KLN89MapScales[_kln89->_mapScaleUnits][_kln89->_mapScaleIndex];
string scle_str = GPSitoa(scale);
if(crsr) {
if(_menuActive) {
// Draw a background quad to encompass on/off for the first three at 'off' length
_kln89->DrawMapQuad(28, 9, 48, 36, true);
_kln89->DrawMapText("SUA:", 1, 27, true);
if(!(_menuPos == 0 && _kln89->_blink)) _kln89->DrawMapText((_kln89->_drawSUA ? "on" : "off"), 29, 27, true);
if(_menuPos == 0) _kln89->DrawLine(28, 27, 48, 27);
_kln89->DrawMapText("VOR:", 1, 18, true);
if(!(_menuPos == 1 && _kln89->_blink)) _kln89->DrawMapText((_kln89->_drawVOR ? "on" : "off"), 29, 18, true);
if(_menuPos == 1) _kln89->DrawLine(28, 18, 48, 18);
_kln89->DrawMapText("APT:", 1, 9, true);
if(!(_menuPos == 2 && _kln89->_blink)) _kln89->DrawMapText((_kln89->_drawApt ? "on" : "off"), 29, 9, true);
if(_menuPos == 2) _kln89->DrawLine(28, 9, 48, 9);
_kln89->DrawMapQuad(0, 0, 27, 8, true);
if(!(_menuPos == 3 && _kln89->_blink)) {
if(_kln89->_mapOrientation == 0) {
_kln89->DrawMapText("N", 1, 0, true);
_kln89->DrawMapUpArrow(7, 1);
} else if(_kln89->_mapOrientation == 1) {
_kln89->DrawMapText("DTK", 1, 0, true);
_kln89->DrawMapUpArrow(21, 1);
} else {
// Don't bother with heading up for now!
_kln89->DrawMapText("TK", 1, 0, true);
_kln89->DrawMapUpArrow(14, 1);
}
}
if(_menuPos == 3) _kln89->DrawLine(0, 0, 27, 0);
} else {
if(_uLinePos == 2) {
if(!_kln89->_blink) {
_kln89->DrawMapText("Menu?", 1, 9, true);
_kln89->DrawEnt();
_kln89->DrawLine(0, 9, 34, 9);
} else {
_kln89->DrawMapQuad(0, 9, 34, 17, true);
}
} else {
_kln89->DrawMapText("Menu?", 1, 9, true);
}
// right-justify the scale when _uLinePos == 3
if(!(_uLinePos == 3 && _kln89->_blink)) _kln89->DrawMapText(scle_str, (_uLinePos == 3 ? 29 - (scle_str.size() * 7) : 1), 0, true);
if(_uLinePos == 3) _kln89->DrawLine(0, 0, 27, 0);
}
} else {
// Just draw the scale
_kln89->DrawMapText(scle_str, 1, 0, true);
}
// If the scan-pull knob is out, draw one of the waypoints (if applicable).
if(fgGetBool("/instrumentation/kln89/scan-pull")) {
if(_kln89->_activeFP->waypoints.size()) {
//cout << "Need to draw a waypoint!\n";
_kln89->DrawLine(70, 0, 111, 0);
if(!_kln89->_blink) {
//_kln89->DrawMapQuad(45, 0, 97, 8, true);
if(!_scanWpSet) {
_scanWpIndex = _kln89->GetActiveWaypointIndex();
_scanWpSet = true;
}
_kln89->DrawMapText(_kln89->_activeFP->waypoints[_scanWpIndex]->id, 71, 0, true);
}
}
}
//
// Do part of the field 1 update, since NAV 4 is a special case for the last line.
//
_kln89->DrawChar('>', 1, 0, 0);
if(crsr && _uLinePos == 1) _kln89->Underline(1, 1, 0, 5);
if(!(crsr && _uLinePos == 1 && _kln89->_blink)) {
if(_kln89->_obsMode && _nav4DataSnippet == 0) _nav4DataSnippet = 1;
double tsec;
switch(_nav4DataSnippet) {
case 0:
// DTK
_kln89->DrawLabel("DTK", -39, 6);
// TODO - check we have an active FP / dtk and draw dashes if not.
char buf0[4];
snprintf(buf0, 4, "%03i", (int)(_kln89->_dtkMag));
_kln89->DrawText((string)buf0, 1, 3, 0);
break;
case 1:
// groundspeed
_kln89->DrawSpeed(_kln89->_groundSpeed_kts, 1, 5, 0);
break;
case 2:
// ETE
tsec = _kln89->GetETE();
if(tsec < 0.0) {
_kln89->DrawText("--:--", 1, 1, 0);
} else {
int eteh = (int)tsec / 3600;
int etem = ((int)tsec - eteh * 3600) / 60;
char buf[6];
int n = snprintf(buf, 6, "%02i:%02i", eteh, etem);
_kln89->DrawText((string)buf, 1, 6-n, 0);
}
break;
case 3:
// Cross-track correction
double x = _kln89->CalcCrossTrackDeviation();
if(x < 0.0) {
_kln89->DrawSpecialChar(3, 1, 5, 0);
} else {
_kln89->DrawSpecialChar(7, 1, 5, 0);
}
char buf3[6];
int n;
x = fabs(x * (_kln89->_distUnits == GPS_DIST_UNITS_NM ? 1.0 : SG_NM_TO_METER * 0.001));
if(x < 1.0) {
n = snprintf(buf3, 6, "%0.2f", x);
} else if(x < 100.0) {
n = snprintf(buf3, 6, "%0.1f", x);
} else {
n = snprintf(buf3, 6, "%i", (int)(x+0.5));
}
_kln89->DrawText((string)buf3, 1, 5-n, 0);
break;
}
}
}
KLN89Page::Update(dt);
}
// Returns the id string of the selected waypoint on NAV4 if valid, else returns an empty string.
string KLN89NavPage::GetNav4WpId() {
if(3 == _subPage) {
if(fgGetBool("/instrumentation/kln89/scan-pull")) {
if(_kln89->_activeFP->waypoints.size()) {
if(!_scanWpSet) {
return(_kln89->_activeWaypoint.id);
} else {
return(_kln89->_activeFP->waypoints[_scanWpIndex]->id);
}
}
}
}
return("");
}
void KLN89NavPage::LooseFocus() {
_suspendAVS = false;
_scanWpSet = false;
}
void KLN89NavPage::CrsrPressed() {
if(_kln89->_mode == KLN89_MODE_DISP) {
// Crsr just switched off
_menuActive = false;
} else {
// Crsr just switched on
if(_subPage < 3) {
_uLinePos = 1;
} else {
_uLinePos = 3;
}
}
}
void KLN89NavPage::EntPressed() {
if(_kln89->_mode == KLN89_MODE_CRSR) {
if(_subPage == 3 && _uLinePos == 2 && !_menuActive) {
_menuActive = true;
_menuPos = 0;
_suspendAVS = false;
}
}
}
void KLN89NavPage::ClrPressed() {
if(_kln89->_mode == KLN89_MODE_CRSR) {
if(_subPage == 0) {
if(_uLinePos == 1) {
_cdiFormat++;
if(_cdiFormat > 2) _cdiFormat = 0;
} else if(_uLinePos == 2) {
_vnv++;
if(_vnv > 2) _vnv = 0;
}
}
if(_subPage == 3) {
if(_uLinePos > 1) {
_suspendAVS = !_suspendAVS;
_menuActive = false;
} else if(_uLinePos == 1) {
_nav4DataSnippet++;
if(_nav4DataSnippet > 3) _nav4DataSnippet = 0;
}
}
} else {
if(_subPage == 3) {
_suspendAVS = !_suspendAVS;
}
}
}
void KLN89NavPage::Knob1Left1() {
if(_kln89->_mode == KLN89_MODE_CRSR) {
if(!(_subPage == 3 && _menuActive)) {
if(_uLinePos > 0) _uLinePos--;
} else {
if(_menuPos > 0) _menuPos--;
}
}
}
void KLN89NavPage::Knob1Right1() {
if(_kln89->_mode == KLN89_MODE_CRSR) {
if(_subPage < 2) {
if(_uLinePos < 2) _uLinePos++;
} else if(_subPage == 2) {
_uLinePos = 1;
} else {
// NAV 4 - this is complicated by whether the menu is displayed or not.
if(_menuActive) {
if(_menuPos < 3) _menuPos++;
} else {
if(_uLinePos < 3) _uLinePos++;
}
}
}
}
void KLN89NavPage::Knob2Left1() {
// If the inner-knob is out on the nav4 page, the only effect is to cycle the displayed waypoint.
if(3 == _subPage && fgGetBool("/instrumentation/kln89/scan-pull")) {
if(_kln89->_activeFP->waypoints.size()) { // TODO - find out what happens when scan-pull is on on nav4 without an active FP.
// It's unlikely that we could get here without _scanWpSet, but theoretically possible, so we need to cover it.
if(!_scanWpSet) {
_scanWpIndex = _kln89->GetActiveWaypointIndex();
_scanWpSet = true;
} else {
if(0 == _scanWpIndex) {
_scanWpIndex = _kln89->_activeFP->waypoints.size() - 1;
} else {
_scanWpIndex--;
}
}
}
return;
}
if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
KLN89Page::Knob2Left1();
return;
}
if(_subPage == 0) {
if(_uLinePos == 1 && _cdiFormat == 2) {
_kln89->CDIFSDIncrease();
}
} else if(_subPage == 3) {
if(_menuActive) {
if(_menuPos == 0) {
_kln89->_drawSUA = !_kln89->_drawSUA;
} else if(_menuPos == 1) {
_kln89->_drawVOR = !_kln89->_drawVOR;
} else if(_menuPos == 2) {
_kln89->_drawApt = !_kln89->_drawApt;
} else {
if(_kln89->_mapOrientation == 0) {
// Don't allow heading up for now
_kln89->_mapOrientation = 2;
} else {
_kln89->_mapOrientation--;
}
_kln89->UpdateMapHeading();
}
} else if(_uLinePos == 3) {
// TODO - add AUTO
if(_kln89->_mapScaleIndex == 0) {
_kln89->_mapScaleIndex = 20;
} else {
_kln89->_mapScaleIndex--;
}
}
}
}
void KLN89NavPage::Knob2Right1() {
// If the inner-knob is out on the nav4 page, the only effect is to cycle the displayed waypoint.
if(3 == _subPage && fgGetBool("/instrumentation/kln89/scan-pull")) {
if(_kln89->_activeFP->waypoints.size()) { // TODO - find out what happens when scan-pull is on on nav4 without an active FP.
// It's unlikely that we could get here without _scanWpSet, but theoretically possible, so we need to cover it.
if(!_scanWpSet) {
_scanWpIndex = _kln89->GetActiveWaypointIndex();
_scanWpSet = true;
} else {
_scanWpIndex++;
if(_scanWpIndex > static_cast<int>(_kln89->_activeFP->waypoints.size()) - 1) {
_scanWpIndex = 0;
}
}
}
return;
}
if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
KLN89Page::Knob2Right1();
return;
}
if(_subPage == 0) {
if(_uLinePos == 1 && _cdiFormat == 2) {
_kln89->CDIFSDDecrease();
}
} else if(_subPage == 3) {
if(_menuActive) {
if(_menuPos == 0) {
_kln89->_drawSUA = !_kln89->_drawSUA;
} else if(_menuPos == 1) {
_kln89->_drawVOR = !_kln89->_drawVOR;
} else if(_menuPos == 2) {
_kln89->_drawApt = !_kln89->_drawApt;
} else {
if(_kln89->_mapOrientation >= 2) {
// Don't allow heading up for now
_kln89->_mapOrientation = 0;
} else {
_kln89->_mapOrientation++;
}
_kln89->UpdateMapHeading();
}
} else if(_uLinePos == 3) {
// TODO - add AUTO
if(_kln89->_mapScaleIndex == 20) {
_kln89->_mapScaleIndex = 0;
} else {
_kln89->_mapScaleIndex++;
}
}
}
}

View File

@@ -0,0 +1,70 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#include "kln89.hxx"
class KLN89NavPage : public KLN89Page {
public:
KLN89NavPage(KLN89* parent);
~KLN89NavPage();
void Update(double dt);
void CrsrPressed();
void EntPressed();
void ClrPressed();
void Knob1Left1();
void Knob1Right1();
void Knob2Left1();
void Knob2Right1();
void LooseFocus();
// Returns the id string of the selected waypoint on NAV4 if valid, else returns an empty string.
std::string GetNav4WpId();
private:
int _posFormat; // 0 => lat,lon; 1 => ref to wp.
int _vnv; // 0 => To, 1 => Fr, 2 => off.
// The data snippet to be displayed in field 1 when the moving map is active (NAV 4)
int _nav4DataSnippet; // 0 => DTK, 1 => groundspeed, 2 => ETE, 3 => cross-track correction.
// Format to draw in the CDI field.
// 0 => CDI, 1 => Cross track correction (eg " Fly R 2.15nm"), 2 => cdi scale (eg "CDI Scale:5.0nm")
int _cdiFormat;
// Drawing of apt, vor and sua on the moving map can be temporarily suspended
// Note that this should be cleared when page focus is lost, or when the menu is displayed.
bool _suspendAVS;
// NAV 4 menu stuff
bool _menuActive;
int _menuPos;
// NAV 4 waypoint scan drawing housekeeping.
bool _scanWpSet;
int _scanWpIndex;
};

View File

@@ -0,0 +1,218 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cstdio>
#include "kln89_page_ndb.hxx"
#include <Navaids/navrecord.hxx>
using std::string;
KLN89NDBPage::KLN89NDBPage(KLN89* parent)
: KLN89Page(parent) {
_nSubPages = 2;
_subPage = 0;
_name = "NDB";
_ndb_id = "SF";
np = NULL;
}
KLN89NDBPage::~KLN89NDBPage() {
}
void KLN89NDBPage::Update(double dt) {
bool actPage = (_kln89->_activePage->GetName() == "ACT" ? true : false);
bool multi; // Not set by FindFirst...
bool exact = false;
if(_ndb_id.size() == 3) exact = true;
if(np == NULL) {
np = _kln89->FindFirstNDBById(_ndb_id, multi, exact);
} else if(np->get_ident() != _ndb_id) {
np = _kln89->FindFirstNDBById(_ndb_id, multi, exact);
}
//if(np == NULL) cout << "NULL... ";
//if(b == false) cout << "false...\n";
/*
if(np && b) {
cout << "VOR FOUND!\n";
} else {
cout << ":-(\n";
}
*/
if(np) {
//cout << np->id << '\n';
_ndb_id = np->get_ident();
if(_kln89->GetActiveWaypoint()) {
if(_ndb_id == _kln89->GetActiveWaypoint()->id) {
if(!(_kln89->_waypointAlert && _kln89->_blink)) {
// Active waypoint arrow
_kln89->DrawSpecialChar(4, 2, 0, 3);
}
}
}
if(_kln89->_mode != KLN89_MODE_CRSR) {
if(!_entInvert) {
if(!actPage) {
_kln89->DrawText(np->get_ident(), 2, 1, 3);
} else {
// If it's the ACT page, The ID is shifted slightly right to make space for the waypoint index.
_kln89->DrawText(np->get_ident(), 2, 4, 3);
char buf[3];
int n = snprintf(buf, 3, "%i", _kln89->GetActiveWaypointIndex() + 1);
_kln89->DrawText((string)buf, 2, 3 - n, 3);
}
} else {
if(!_kln89->_blink) {
_kln89->DrawText(np->get_ident(), 2, 1, 3, false, 99);
_kln89->DrawEnt();
}
}
}
if(_subPage == 0) {
// TODO - trim VOR-DME from the name, convert to uppercase, abbreviate, etc
_kln89->DrawText(np->name(), 2, 0, 2);
_kln89->DrawLatitude(np->get_lat(), 2, 3, 1);
_kln89->DrawLongitude(np->get_lon(), 2, 3, 0);
} else {
_kln89->DrawDirDistField(np->get_lat() * SG_DEGREES_TO_RADIANS, np->get_lon() * SG_DEGREES_TO_RADIANS,
2, 0, 0, _to_flag, (_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 4 ? true : false));
}
} else {
if(_kln89->_mode != KLN89_MODE_CRSR) _kln89->DrawText(_ndb_id, 2, 1, 3);
if(_subPage == 0) {
_kln89->DrawText("----.-", 2, 9, 3);
_kln89->DrawText("--------------", 2, 0, 2);
_kln89->DrawText("- -- --.--'", 2, 3, 1);
_kln89->DrawText("---- --.--'", 2, 3, 0);
_kln89->DrawSpecialChar(0, 2, 7, 1);
_kln89->DrawSpecialChar(0, 2, 7, 0);
}
}
if(_kln89->_mode == KLN89_MODE_CRSR) {
if(_uLinePos > 0 && _uLinePos < 4) {
// TODO - blink as well
_kln89->Underline(2, _uLinePos, 3, 1);
}
for(unsigned int i = 0; i < _ndb_id.size(); ++i) {
if(_uLinePos != (i + 1)) {
_kln89->DrawChar(_ndb_id[i], 2, i + 1, 3);
} else {
if(!_kln89->_blink) _kln89->DrawChar(_ndb_id[i], 2, i + 1, 3);
}
}
}
_id = _ndb_id;
KLN89Page::Update(dt);
}
void KLN89NDBPage::SetId(const string& s) {
_last_ndb_id = _ndb_id;
_save_ndb_id = _ndb_id;
_ndb_id = s;
np = NULL;
}
void KLN89NDBPage::CrsrPressed() {
if(_kln89->_mode == KLN89_MODE_DISP) return;
if(_kln89->_obsMode) {
_uLinePos = 0;
} else {
_uLinePos = 1;
}
if(_subPage == 0) {
_maxULinePos = 17;
} else {
_maxULinePos = 4;
}
}
void KLN89NDBPage::ClrPressed() {
if(_subPage == 1 && _uLinePos == 4) {
_to_flag = !_to_flag;
}
}
void KLN89NDBPage::EntPressed() {
if(_entInvert) {
_entInvert = false;
if(_kln89->_dtoReview) {
_kln89->DtoInitiate(_ndb_id);
} else {
_last_ndb_id = _ndb_id;
_ndb_id = _save_ndb_id;
}
}
}
void KLN89NDBPage::Knob2Left1() {
if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
KLN89Page::Knob2Left1();
} else {
if(_uLinePos < 4) {
// Same logic for both pages - set the ID
_ndb_id = _ndb_id.substr(0, _uLinePos);
// ASSERT(_uLinePos > 0);
if(_uLinePos == (_ndb_id.size() + 1)) {
_ndb_id += '9';
} else {
_ndb_id[_uLinePos - 1] = _kln89->DecChar(_ndb_id[_uLinePos - 1], (_uLinePos == 1 ? false : true));
}
} else {
if(_subPage == 0) {
// set by name
} else {
// NO-OP - from/to field is switched by clr button, not inner knob.
}
}
}
}
void KLN89NDBPage::Knob2Right1() {
if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
KLN89Page::Knob2Right1();
} else {
if(_uLinePos < 4) {
// Same logic for both pages - set the ID
_ndb_id = _ndb_id.substr(0, _uLinePos);
// ASSERT(_uLinePos > 0);
if(_uLinePos == (_ndb_id.size() + 1)) {
_ndb_id += 'A';
} else {
_ndb_id[_uLinePos - 1] = _kln89->IncChar(_ndb_id[_uLinePos - 1], (_uLinePos == 1 ? false : true));
}
} else {
if(_subPage == 0) {
// set by name
} else {
// NO-OP - from/to field is switched by clr button, not inner knob.
}
}
}
}

View File

@@ -0,0 +1,52 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef _KLN89_PAGE_NDB_HXX
#define _KLN89_PAGE_NDB_HXX
#include "kln89.hxx"
class KLN89NDBPage : public KLN89Page {
public:
KLN89NDBPage(KLN89* parent);
~KLN89NDBPage();
void Update(double dt);
void CrsrPressed();
void ClrPressed();
void EntPressed();
void Knob2Left1();
void Knob2Right1();
void SetId(const std::string& s);
private:
std::string _ndb_id;
std::string _last_ndb_id;
std::string _save_ndb_id;
FGNavRecord* np;
};
#endif // _KLN89_PAGE_NDB_HXX

View File

@@ -0,0 +1,90 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "kln89_page_nrst.hxx"
KLN89NrstPage::KLN89NrstPage(KLN89* parent)
: KLN89Page(parent) {
_nSubPages = 2;
_subPage = 0;
_name = "NRST";
_uLinePos = 1;
_maxULinePos = 8;
}
KLN89NrstPage::~KLN89NrstPage() {
}
void KLN89NrstPage::Update(double dt) {
// crsr is always on on nearest page
bool blink = _kln89->_blink;
_kln89->DrawText("NEAREST", 2, 3, 3);
if(!(_uLinePos == 1 && blink)) _kln89->DrawText("APT?", 2, 0, 2);
if(!(_uLinePos == 2 && blink)) _kln89->DrawText("VOR?", 2, 5, 2);
if(!(_uLinePos == 3 && blink)) _kln89->DrawText("NDB?", 2, 10, 2);
if(!(_uLinePos == 4 && blink)) _kln89->DrawText("INT?", 2, 0, 1);
if(!(_uLinePos == 5 && blink)) _kln89->DrawText("USR?", 2, 5, 1);
if(!(_uLinePos == 6 && blink)) _kln89->DrawText("SUA?", 2, 10, 1);
if(!(_uLinePos == 7 && blink)) _kln89->DrawText("FSS?", 2, 0, 0);
if(!(_uLinePos == 8 && blink)) _kln89->DrawText("CTR?", 2, 5, 0);
switch(_uLinePos) {
case 1: _kln89->Underline(2, 0, 2, 4); break;
case 2: _kln89->Underline(2, 5, 2, 4); break;
case 3: _kln89->Underline(2, 10, 2, 4); break;
case 4: _kln89->Underline(2, 0, 1, 4); break;
case 5: _kln89->Underline(2, 5, 1, 4); break;
case 6: _kln89->Underline(2, 10, 1, 4); break;
case 7: _kln89->Underline(2, 0, 0, 4); break;
case 8: _kln89->Underline(2, 5, 0, 4); break;
}
// Actually, the kln89 sim from Bendix-King dosn't draw the 'ENT'
// for 'APT?' if it was on 'Leg' (pos 0) immediately previously, but does if
// it was not on 'Leg' immediately previously. I think we can desist from
// reproducing this probable bug.
if(_uLinePos > 0) {
if(!blink) _kln89->DrawEnt();
}
KLN89Page::Update(dt);
}
void KLN89NrstPage::CrsrPressed() {
}
void KLN89NrstPage::EntPressed() {
if(_uLinePos > 4) {
ShowScratchpadMessage(" No ", " Nrst ");
}
}
void KLN89NrstPage::LooseFocus() {
_uLinePos = 1;
_scratchpadMsg = false;
}

View File

@@ -0,0 +1,48 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef _KLN89_PAGE_NRST
#define _KLN89_PAGE_NRST
#include "kln89.hxx"
class KLN89NrstPage : public KLN89Page {
public:
KLN89NrstPage(KLN89* parent);
~KLN89NrstPage();
void Update(double dt);
void CrsrPressed();
void EntPressed();
//void ClrPressed();
//void Knob1Left1();
//void Knob1Right1();
//void Knob2Left1();
//void Knob2Right1();
void LooseFocus();
};
#endif // _KLN89_PAGE_NRST

View File

@@ -0,0 +1,66 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cstdio>
#include "kln89_page_oth.hxx"
using std::string;
KLN89OthPage::KLN89OthPage(KLN89* parent)
: KLN89Page(parent) {
_nSubPages = 12;
_subPage = 0;
_name = "OTH";
}
KLN89OthPage::~KLN89OthPage() {
}
void KLN89OthPage::Update(double dt) {
// The OTH pages aren't terribly important at the moment, since we don't simulate
// error and failure, but lets hardwire some representitive output anyway.
if(_subPage == 0) {
_kln89->DrawText("State", 2, 0, 3);
_kln89->DrawText("GPS Alt", 2, 0, 2);
_kln89->DrawText("Estimated Posn", 2, 0, 1);
_kln89->DrawText("Error", 2, 1, 0);
// FIXME - hardwired value.
_kln89->DrawText("NAV D", 2, 9, 3);
// TODO - add error physics to FG GPS where the alt value comes from.
char buf[6];
int n = snprintf(buf, 5, "%i", _kln89->_altUnits == GPS_ALT_UNITS_FT ? (int)_kln89->_alt : (int)(_kln89->_alt * SG_FEET_TO_METER));
_kln89->DrawText((string)buf, 2, 13-n, 2);
_kln89->DrawText(_kln89->_altUnits == GPS_ALT_UNITS_FT ? "ft" : "m", 2, 13, 2);
// FIXME - hardwired values.
// Note that a 5th digit if required is left padded one further at position 7.
_kln89->DrawText(_kln89->_distUnits == GPS_DIST_UNITS_NM ? "0.02nm" : "0.03km", 2, 8, 0);
}
KLN89Page::Update(dt);
}

View File

@@ -0,0 +1,39 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef _KLN89_PAGE_OTH
#define _KLN89_PAGE_OTH
#include "kln89.hxx"
class KLN89OthPage : public KLN89Page {
public:
KLN89OthPage(KLN89* parent);
~KLN89OthPage();
void Update(double dt);
};
#endif // _KLN89_PAGE_OTH

View File

@@ -0,0 +1,332 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "kln89_page_set.hxx"
#include <iostream>
using namespace std;
KLN89SetPage::KLN89SetPage(KLN89* parent)
: KLN89Page(parent) {
_nSubPages = 11;
_subPage = 0;
_name = "SET";
}
KLN89SetPage::~KLN89SetPage() {
}
void KLN89SetPage::Update(double dt) {
string sBaro, sAlt, sVel;
switch(_subPage+1) {
case 1:
_kln89->DrawText("INIT POS:", 2, 0, 3);
break;
case 2:
_kln89->DrawText("DATE", 2, 0, 3);
_kln89->DrawText("TIME", 2, 0, 2);
_kln89->DrawText("Cord", 2, 0, 1);
_kln89->DrawText("Mag Var:", 2, 0, 0);
break;
case 3:
_kln89->DrawText("Update DB on", 2, 1, 3);
_kln89->DrawText("ground only", 2, 1, 2);
_kln89->DrawText("Key", 2, 0, 1);
_kln89->DrawText("Update pub DB?", 2, 0, 0);
break;
case 4:
//cout << "_uLinePos = " << _uLinePos << '\n';
_kln89->DrawText("TURN", 2, 5, 3);
_kln89->DrawText("ANTICIPATION", 2, 1, 2);
if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 1) {
if(!_kln89->_blink) {
_kln89->DrawText((_kln89->GetTurnAnticipation() ? "ENABLED" : "DISABLED"), 2, 3, 1);
}
_kln89->Underline(2, 3, 1, 8);
} else {
_kln89->DrawText((_kln89->GetTurnAnticipation() ? "ENABLED" : "DISABLED"), 2, 3, 1);
}
break;
case 5:
_kln89->DrawText("Default First", 2, 0, 3);
_kln89->DrawText("Character of", 2, 1, 2);
_kln89->DrawText("Wpt identifier", 2, 0, 1);
_kln89->DrawText("Entry:", 2, 3, 0);
if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 1) {
if(!_kln89->_blink) {
_kln89->DrawChar(_kln89->_defaultFirstChar, 2, 10, 0);
}
_kln89->Underline(2, 10, 0, 1);
} else {
_kln89->DrawChar(_kln89->_defaultFirstChar, 2, 10, 0);
}
break;
case 6:
_kln89->DrawText("NEAREST APT", 2, 1, 3);
_kln89->DrawText("CRITERIA", 2, 3, 2);
_kln89->DrawText("Length:", 2, 0, 1);
_kln89->DrawText("Surface:", 2, 0, 0);
break;
case 7:
_kln89->DrawText("SUA ALERT", 2, 3, 3);
if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 1) {
if(!_kln89->_blink) {
_kln89->DrawText((_kln89->GetSuaAlertEnabled() ? "ENABLED" : "DISABLED"), 2, 4, 2);
}
_kln89->Underline(2, 4, 2, 8);
} else {
_kln89->DrawText((_kln89->GetSuaAlertEnabled() ? "ENABLED" : "DISABLED"), 2, 4, 2);
}
if(_kln89->GetSuaAlertEnabled()) {
_kln89->DrawText("Buffer:", 2, 0, 1);
_kln89->DrawSpecialChar(5, 2, 7, 1); // +- sign.
if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 2) {
if(!_kln89->_blink) {
_kln89->DrawText("00300", 2, 8, 1); // TODO - fix this hardwiring!!!!
}
_kln89->Underline(2, 8, 1, 5);
} else {
_kln89->DrawText("00300", 2, 8, 1); // TODO - fix this hardwiring!!!!
}
_kln89->DrawText("ft", 2, 13, 1); // TODO - fix this hardwiring!!!!
}
break;
case 8:
_kln89->DrawText("SET UNITS:", 2, 3, 3);
_kln89->DrawText("Baro :", 2, 0, 2);
_kln89->DrawText("Alt-APT :", 2, 0, 1);
_kln89->DrawText("Dist-Vel:", 2, 0, 0);
switch(_kln89->_baroUnits) {
case GPS_PRES_UNITS_IN:
sBaro = "\"";
break;
case GPS_PRES_UNITS_MB:
sBaro = "mB";
break;
case GPS_PRES_UNITS_HP:
sBaro = "hP";
break;
}
if(_kln89->_altUnits == GPS_ALT_UNITS_FT) sAlt = "ft";
else sAlt = "m";
if(_kln89->_distUnits == GPS_DIST_UNITS_NM) sVel = "nm-kt";
else sVel = "km-";
if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 1) {
if(!_kln89->_blink) {
_kln89->DrawText(sBaro, 2, 10, 2);
}
_kln89->Underline(2, 10, 2, 2);
} else {
_kln89->DrawText(sBaro, 2, 10, 2);
}
if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 2) {
if(!_kln89->_blink) {
_kln89->DrawText(sAlt, 2, 10, 1);
}
_kln89->Underline(2, 10, 1, 2);
} else {
_kln89->DrawText(sAlt, 2, 10, 1);
}
if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 3) {
if(!_kln89->_blink) {
_kln89->DrawText(sVel, 2, 10, 0);
if(_kln89->_distUnits != GPS_DIST_UNITS_NM) _kln89->DrawKPH(2, 13, 0);
}
_kln89->Underline(2, 10, 0, 5);
} else {
_kln89->DrawText(sVel, 2, 10, 0);
if(_kln89->_distUnits != GPS_DIST_UNITS_NM) _kln89->DrawKPH(2, 13, 0);
}
break;
case 9:
_kln89->DrawText("Altitude", 2, 3, 3);
_kln89->DrawText("Alert:", 2, 1, 2);
break;
case 10:
_kln89->DrawText("BUS MONITOR", 2, 2, 3);
_kln89->DrawText("Bus Volt", 2, 0, 2);
_kln89->DrawText("Alert Volt", 2, 0, 1);
_kln89->DrawText("Alert Delay", 2, 0, 0);
break;
case 11:
_kln89->DrawText("MIN DISPLAY", 2, 2, 3);
_kln89->DrawText("BRIGHTNESS ADJ", 2, 1, 2);
if(_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 1) {
if(!_kln89->_blink) {
_kln89->DrawChar('0' + _kln89->GetMinDisplayBrightness(), 2, 6, 0);
}
_kln89->Underline(2, 6, 0, 1);
} else {
_kln89->DrawChar('0' + _kln89->GetMinDisplayBrightness(), 2, 6, 0);
}
if(_kln89->GetMinDisplayBrightness() == 4) {
_kln89->DrawText("Default", 2, 8, 0);
}
break;
}
KLN89Page::Update(dt);
}
void KLN89SetPage::CrsrPressed() {
if(_kln89->_mode == KLN89_MODE_DISP) return;
if(_kln89->_obsMode) {
_uLinePos = 0;
} else {
_uLinePos = 1;
}
switch(_subPage+1) {
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
_maxULinePos = 1;
break;
case 5:
_maxULinePos = 1;
break;
case 6:
_maxULinePos = 2;
break;
case 7:
if(_kln89->GetSuaAlertEnabled()) _maxULinePos = 2;
else _maxULinePos = 1;
break;
case 8:
_maxULinePos = 3;
break;
case 9:
break;
case 10:
break;
case 11:
_maxULinePos = 1;
break;
}
}
void KLN89SetPage::Knob2Left1() {
if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
KLN89Page::Knob2Left1();
} else {
switch(_subPage+1) {
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
if(_uLinePos == 1) {
_kln89->SetTurnAnticipation(!_kln89->GetTurnAnticipation());
}
break;
case 5:
if(_uLinePos == 1) {
_kln89->_defaultFirstChar = _kln89->DecChar(_kln89->_defaultFirstChar, false, true);
}
break;
case 6:
break;
case 7:
if(_uLinePos == 1) {
_kln89->SetSuaAlertEnabled(!_kln89->GetSuaAlertEnabled());
_maxULinePos = (_kln89->GetSuaAlertEnabled() ? 2 : 1);
} else if(_uLinePos == 2) {
// TODO - implement variable sua alert buffer
}
break;
case 8:
if(_uLinePos == 1) { // baro units
_kln89->SetBaroUnits(_kln89->GetBaroUnits() - 1, true);
} else if(_uLinePos == 2) {
_kln89->SetAltUnitsSI(!_kln89->GetAltUnitsSI());
} else if(_uLinePos == 3) {
_kln89->SetDistVelUnitsSI(!_kln89->GetDistVelUnitsSI());
}
break;
case 11:
if(_uLinePos == 1) {
_kln89->DecrementMinDisplayBrightness();
}
break;
}
}
}
void KLN89SetPage::Knob2Right1() {
if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
KLN89Page::Knob2Right1();
} else {
switch(_subPage+1) {
case 1:
break;
case 2:
break;
case 3:
break;
case 4:
if(_uLinePos == 1) { // Which it should be!
_kln89->SetTurnAnticipation(!_kln89->GetTurnAnticipation());
}
break;
case 5:
if(_uLinePos == 1) {
_kln89->_defaultFirstChar = _kln89->IncChar(_kln89->_defaultFirstChar, false, true);
}
break;
case 6:
break;
case 7:
if(_uLinePos == 1) {
_kln89->SetSuaAlertEnabled(!_kln89->GetSuaAlertEnabled());
_maxULinePos = (_kln89->GetSuaAlertEnabled() ? 2 : 1);
} else if(_uLinePos == 2) {
// TODO - implement variable sua alert buffer
}
break;
case 8:
if(_uLinePos == 1) { // baro units
_kln89->SetBaroUnits(_kln89->GetBaroUnits() + 1, true);
} else if(_uLinePos == 2) {
_kln89->SetAltUnitsSI(!_kln89->GetAltUnitsSI());
} else if(_uLinePos == 3) {
_kln89->SetDistVelUnitsSI(!_kln89->GetDistVelUnitsSI());
}
break;
case 11:
if(_uLinePos == 1) {
_kln89->IncrementMinDisplayBrightness();
}
break;
}
}
}

View File

@@ -0,0 +1,42 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef _KLN89_PAGE_SET_HXX
#define _KLN89_PAGE_SET_HXX
#include "kln89.hxx"
class KLN89SetPage : public KLN89Page {
public:
KLN89SetPage(KLN89* parent);
~KLN89SetPage();
void Update(double dt);
void CrsrPressed();
void Knob2Left1();
void Knob2Right1();
};
#endif // _KLN89_PAGE_SET_HXX

View File

@@ -0,0 +1,55 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include "kln89_page_usr.hxx"
KLN89UsrPage::KLN89UsrPage(KLN89* parent)
: KLN89Page(parent) {
_nSubPages = 4;
_subPage = 0;
_name = "USR";
}
KLN89UsrPage::~KLN89UsrPage() {
}
void KLN89UsrPage::Update(double dt) {
// bool actPage = (_kln89->_activePage->GetName() == "ACT" ? true : false);
bool crsr = (_kln89->_mode == KLN89_MODE_CRSR);
bool blink = _kln89->_blink;
if(_subPage == 0) {
// Hardwire no-waypoint output for now
_kln89->DrawText("0", 2, 1, 3);
_kln89->DrawText("USR at:", 2, 7, 3);
if(!(crsr && _uLinePos == 6 && blink)) _kln89->DrawText("User Pos L/L?", 2, 1, 2);
if(!(crsr && _uLinePos == 7 && blink)) _kln89->DrawText("User Pos R/D?", 2, 1, 1);
if(!(crsr && _uLinePos == 8 && blink)) _kln89->DrawText("Present Pos?", 2, 1, 0);
}
KLN89Page::Update(dt);
}

View File

@@ -0,0 +1,39 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef _KLN89_PAGE_USR_HXX
#define _KLN89_PAGE_USR_HXX
#include "kln89.hxx"
class KLN89UsrPage : public KLN89Page {
public:
KLN89UsrPage(KLN89* parent);
~KLN89UsrPage();
void Update(double dt);
};
#endif // _KLN89_PAGE_USR_HXX

View File

@@ -0,0 +1,231 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cstdio>
#include "kln89_page_vor.hxx"
#include <Navaids/navrecord.hxx>
using std::string;
KLN89VorPage::KLN89VorPage(KLN89* parent)
: KLN89Page(parent) {
_nSubPages = 2;
_subPage = 0;
_name = "VOR";
_vor_id = "OSI"; // TODO - check a property for an initial value to allow user-override.
np = NULL;
}
KLN89VorPage::~KLN89VorPage() {
}
void KLN89VorPage::Update(double dt) {
bool actPage = (_kln89->_activePage->GetName() == "ACT" ? true : false);
bool multi; // Not set by FindFirst...
bool exact = false;
if(_vor_id.size() == 3) exact = true;
if(np == NULL) {
np = _kln89->FindFirstVorById(_vor_id, multi, exact);
} else if(np->get_ident() != _vor_id) {
np = _kln89->FindFirstVorById(_vor_id, multi, exact);
}
//if(np == NULL) cout << "NULL... ";
//if(b == false) cout << "false...\n";
/*
if(np && b) {
cout << "VOR FOUND!\n";
} else {
cout << ":-(\n";
}
*/
if(np) {
//cout << np->id << '\n';
_vor_id = np->get_ident();
if(_kln89->GetActiveWaypoint()) {
if(_vor_id == _kln89->GetActiveWaypoint()->id) {
if(!(_kln89->_waypointAlert && _kln89->_blink)) {
// Active waypoint arrow
_kln89->DrawSpecialChar(4, 2, 0, 3);
}
}
}
if(_kln89->_mode != KLN89_MODE_CRSR) {
if(!_entInvert) {
if(!actPage) {
_kln89->DrawText(np->get_ident(), 2, 1, 3);
} else {
// If it's the ACT page, The ID is shifted slightly right to make space for the waypoint index.
_kln89->DrawText(np->get_ident(), 2, 4, 3);
char buf[3];
int n = snprintf(buf, 3, "%i", _kln89->GetActiveWaypointIndex() + 1);
_kln89->DrawText((string)buf, 2, 3 - n, 3);
}
} else {
if(!_kln89->_blink) {
_kln89->DrawText(np->get_ident(), 2, 1, 3, false, 99);
_kln89->DrawEnt();
}
}
}
if(_subPage == 0) {
//// TODO - will almost certainly have to process freq below for FG
_kln89->DrawFreq(np->get_freq(), 2, 9, 3);
// TODO - trim VOR-DME from the name, convert to uppercase, abbreviate, etc
_kln89->DrawText(np->name(), 2, 0, 2);
//cout << np->lat << "... ";
_kln89->DrawLatitude(np->get_lat(), 2, 3, 1);
_kln89->DrawLongitude(np->get_lon(), 2, 3, 0);
} else {
_kln89->DrawText("Mag Var", 2, 0, 2);
////float mvf = np->magvar * SG_RADIANS_TO_DEGREES;
//// TODO FIXME BELOW
float mvf = 0.0;
_kln89->DrawChar((mvf <= 0 ? 'E' : 'W'), 2, 9, 2);
int mvi = (int)(fabs(mvf) + 0.5);
string mvs = GPSitoa(mvi);
_kln89->DrawText(mvs, 2, 13 - mvs.size(), 2);
_kln89->DrawSpecialChar(0, 2, 13, 2);
_kln89->DrawDirDistField(np->get_lat() * SG_DEGREES_TO_RADIANS, np->get_lon() * SG_DEGREES_TO_RADIANS, 2, 0, 0,
_to_flag, (_kln89->_mode == KLN89_MODE_CRSR && _uLinePos == 4 ? true : false));
}
} else {
if(_kln89->_mode != KLN89_MODE_CRSR) _kln89->DrawText(_vor_id, 2, 1, 3);
if(_subPage == 0) {
_kln89->DrawText("---.--", 2, 9, 3);
_kln89->DrawText("--------------", 2, 0, 2);
_kln89->DrawText("- -- --.--'", 2, 3, 1);
_kln89->DrawText("---- --.--'", 2, 3, 0);
_kln89->DrawSpecialChar(0, 2, 7, 1);
_kln89->DrawSpecialChar(0, 2, 7, 0);
}
}
if(_kln89->_mode == KLN89_MODE_CRSR) {
if(_uLinePos > 0 && _uLinePos < 4) {
// TODO - blink as well
_kln89->Underline(2, _uLinePos, 3, 1);
}
for(unsigned int i = 0; i < _vor_id.size(); ++i) {
if(_uLinePos != (i + 1)) {
_kln89->DrawChar(_vor_id[i], 2, i + 1, 3);
} else {
if(!_kln89->_blink) _kln89->DrawChar(_vor_id[i], 2, i + 1, 3);
}
}
}
_id = _vor_id;
KLN89Page::Update(dt);
}
void KLN89VorPage::SetId(const string& s) {
_last_vor_id = _vor_id;
_save_vor_id = _vor_id;
_vor_id = s;
np = NULL;
}
void KLN89VorPage::CrsrPressed() {
if(_kln89->_mode == KLN89_MODE_DISP) return;
if(_kln89->_obsMode) {
_uLinePos = 0;
} else {
_uLinePos = 1;
}
if(_subPage == 0) {
_maxULinePos = 17;
} else {
_maxULinePos = 4;
}
}
void KLN89VorPage::ClrPressed() {
if(_subPage == 1 && _uLinePos == 4) {
_to_flag = !_to_flag;
}
}
void KLN89VorPage::EntPressed() {
if(_entInvert) {
_entInvert = false;
_entInvert = false;
if(_kln89->_dtoReview) {
_kln89->DtoInitiate(_vor_id);
} else {
_last_vor_id = _vor_id;
_vor_id = _save_vor_id;
}
}
}
void KLN89VorPage::Knob2Left1() {
if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
KLN89Page::Knob2Left1();
} else {
if(_uLinePos < 4) {
// Same logic for both pages - set the ID
_vor_id = _vor_id.substr(0, _uLinePos);
// ASSERT(_uLinePos > 0);
if(_uLinePos == (_vor_id.size() + 1)) {
_vor_id += '9';
} else {
_vor_id[_uLinePos - 1] = _kln89->DecChar(_vor_id[_uLinePos - 1], (_uLinePos == 1 ? false : true));
}
} else {
if(_subPage == 0) {
// set by name
} else {
// NO-OP - from/to field is switched by clr button, not inner knob.
}
}
}
}
void KLN89VorPage::Knob2Right1() {
if(_kln89->_mode != KLN89_MODE_CRSR || _uLinePos == 0) {
KLN89Page::Knob2Right1();
} else {
if(_uLinePos < 4) {
// Same logic for both pages - set the ID
_vor_id = _vor_id.substr(0, _uLinePos);
// ASSERT(_uLinePos > 0);
if(_uLinePos == (_vor_id.size() + 1)) {
_vor_id += 'A';
} else {
_vor_id[_uLinePos - 1] = _kln89->IncChar(_vor_id[_uLinePos - 1], (_uLinePos == 1 ? false : true));
}
} else {
if(_subPage == 0) {
// set by name
} else {
// NO-OP - from/to field is switched by clr button, not inner knob.
}
}
}
}

View File

@@ -0,0 +1,52 @@
// kln89_page_*.[ch]xx - this file is one of the "pages" that
// are used in the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 - David C Luff - daveluff AT ntlworld.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#ifndef _KLN89_PAGE_VOR_HXX
#define _KLN89_PAGE_VOR_HXX
#include "kln89.hxx"
class KLN89VorPage : public KLN89Page {
public:
KLN89VorPage(KLN89* parent);
~KLN89VorPage();
void Update(double dt);
void CrsrPressed();
void ClrPressed();
void EntPressed();
void Knob2Left1();
void Knob2Right1();
void SetId(const std::string& s);
private:
std::string _vor_id;
std::string _last_vor_id;
std::string _save_vor_id;
FGNavRecord* np;
};
#endif // _KLN89_PAGE_VOR_HXX

View File

@@ -0,0 +1,172 @@
// kln89_symbols.hxx - pixel-encoded symbols for the KLN89 GPS unit simulation.
//
// Written by David Luff, started 2005.
//
// Copyright (C) 2005 David C Luff: daveluff --AT-- ntlworld --D0T-- com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
const char NumbersBold[][8] = {{0x1E, 0x3F, 0x33, 0x33, 0x33, 0x33, 0x3F, 0x1E}, // 0
{0x0C, 0x1C, 0x1C, 0x0C, 0x0C, 0x0C, 0x1E, 0x1E}, // 1
{0x1E, 0x3F, 0x33, 0x03, 0x06, 0x1C, 0x3F, 0x3F}, // 2
{0x3E, 0x3F, 0x03, 0x1F, 0x1E, 0x03, 0x3F, 0x3E}, // 3
{0x06, 0x0E, 0x16, 0x26, 0x3F, 0x3F, 0x06, 0x06}, // 4
{0x3F, 0x3F, 0x30, 0x3E, 0x3F, 0x03, 0x3F, 0x3E}, // 5
{0x0E, 0x1E, 0x30, 0x3E, 0x3F, 0x33, 0x3F, 0x1E}, // 6
{0x3F, 0x3F, 0x03, 0x06, 0x0C, 0x18, 0x18, 0x18}, // 7
{0x1E, 0x3F, 0x33, 0x3F, 0x1E, 0x33, 0x3F, 0x1E}, // 8
{0x1E, 0x3F, 0x33, 0x3F, 0x1F, 0x03, 0x1E, 0x1C}}; // 9
const char UpperAlpha[][8] = {{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // !
{0x00, 0x1B, 0x09, 0x12, 0x00, 0x00, 0x00, 0x00}, // "
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // #
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // $
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // %
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // &
{0x00, 0x06, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00}, // '
{0x00, 0x02, 0x04, 0x08, 0x08, 0x08, 0x04, 0x02}, // (
{0x00, 0x08, 0x04, 0x02, 0x02, 0x02, 0x04, 0x08}, // )
{0x00, 0x00, 0x0A, 0x04, 0x1F, 0x04, 0x0A, 0x00}, // *
{0x00, 0x00, 0x04, 0x04, 0x1F, 0x04, 0x04, 0x00}, // +
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // ,
{0x00, 0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00}, // -
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C}, // .
{0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x00}, // /
{0x00, 0x0E, 0x11, 0x13, 0x15, 0x19, 0x11, 0x0E}, // 0
{0x00, 0x04, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x0E}, // 1
{0x00, 0x0E, 0x11, 0x01, 0x02, 0x04, 0x08, 0x1F}, // 2
{0x00, 0x0E, 0x11, 0x01, 0x0E, 0x01, 0x11, 0x0E}, // 3
{0x00, 0x02, 0x06, 0x0A, 0x12, 0x1F, 0x02, 0x02}, // 4
{0x00, 0x1F, 0x10, 0x1E, 0x01, 0x01, 0x11, 0x0E}, // 5
{0x00, 0x06, 0x08, 0x10, 0x1E, 0x11, 0x11, 0x0E}, // 6
{0x00, 0x1F, 0x01, 0x02, 0x04, 0x08, 0x08, 0x08}, // 7
{0x00, 0x0E, 0x11, 0x11, 0x0E, 0x11, 0x11, 0x0E}, // 8
{0x00, 0x0E, 0x11, 0x11, 0x0F, 0x01, 0x02, 0x0C}, // 9
{0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x0C, 0x0C}, // :
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // ;
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // <
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // =
{0x00, 0x10, 0x08, 0x04, 0x02, 0x04, 0x08, 0x10}, // >
{0x00, 0x0E, 0x11, 0x01, 0x02, 0x04, 0x00, 0x04}, // ?
{0x00, 0x0E, 0x11, 0x17, 0x15, 0x17, 0x10, 0x0F}, // @
{0x00, 0x0E, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11}, // A
{0x00, 0x1E, 0x11, 0x11, 0x1E, 0x11, 0x11, 0x1E}, // B
{0x00, 0x0E, 0x11, 0x10, 0x10, 0x10, 0x11, 0x0E}, // C
{0x00, 0x1C, 0x12, 0x11, 0x11, 0x11, 0x12, 0x1C}, // D
{0x00, 0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x1F}, // E
{0x00, 0x1F, 0x10, 0x10, 0x1E, 0x10, 0x10, 0x10}, // F
{0x00, 0x0E, 0x11, 0x10, 0x10, 0x17, 0x11, 0x0E}, // G
{0x00, 0x11, 0x11, 0x11, 0x1F, 0x11, 0x11, 0x11}, // H
{0x00, 0x0E, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E}, // I
{0x00, 0x07, 0x02, 0x02, 0x02, 0x02, 0x12, 0x0C}, // J
{0x00, 0x11, 0x12, 0x14, 0x18, 0x14, 0x12, 0x11}, // K
{0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1F}, // L
{0x00, 0x11, 0x1B, 0x15, 0x15, 0x11, 0x11, 0x11}, // M
{0x00, 0x11, 0x11, 0x19, 0x15, 0x13, 0x11, 0x11}, // N
{0x00, 0x0E, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E}, // O
{0x00, 0x1E, 0x11, 0x11, 0x1E, 0x10, 0x10, 0x10}, // P
{0x00, 0x0E, 0x11, 0x11, 0x11, 0x15, 0x12, 0x0D}, // Q
{0x00, 0x1E, 0x11, 0x11, 0x1E, 0x14, 0x12, 0x11}, // R
{0x00, 0x0F, 0x10, 0x10, 0x0E, 0x01, 0x01, 0x1E}, // S
{0x00, 0x1F, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04}, // T
{0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0E}, // U
{0x00, 0x11, 0x11, 0x11, 0x11, 0x11, 0x0A, 0x04}, // V
{0x00, 0x11, 0x11, 0x11, 0x15, 0x15, 0x15, 0x0A}, // W
{0x00, 0x11, 0x11, 0x0A, 0x04, 0x0A, 0x11, 0x11}, // X
{0x00, 0x11, 0x11, 0x11, 0x0A, 0x04, 0x04, 0x04}, // Y
{0x00, 0x1F, 0x01, 0x02, 0x04, 0x08, 0x10, 0x1F}, // Z
{0x00, 0x1E, 0x10, 0x10, 0x10, 0x10, 0x10, 0x1E}, // [
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* \ */ // Have to be carefull with forward slash - it's multiline comment!
{0x00, 0x1E, 0x02, 0x02, 0x02, 0x02, 0x02, 0x1E}, // ]
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // ^
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F}, // _
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, // `
{0x00, 0x00, 0x00, 0x0E, 0x01, 0x0F, 0x11, 0x0F}, // a
{0x00, 0x10, 0x10, 0x10, 0x16, 0x19, 0x11, 0x1E}, // b
{0x00, 0x00, 0x00, 0x0E, 0x10, 0x10, 0x10, 0x0E}, // c
{0x00, 0x01, 0x01, 0x01, 0x0D, 0x13, 0x11, 0x0F}, // d
{0x00, 0x00, 0x00, 0x0E, 0x11, 0x1F, 0x10, 0x0E}, // e
{0x00, 0x06, 0x09, 0x08, 0x1C, 0x08, 0x08, 0x08}, // f
{0x00, 0x00, 0x0E, 0x11, 0x11, 0x0F, 0x01, 0x0E}, // g
{0x00, 0x10, 0x10, 0x16, 0x19, 0x11, 0x11, 0x11}, // h
{0x00, 0x04, 0x00, 0x0C, 0x04, 0x04, 0x04, 0x0E}, // i
{0x00, 0x02, 0x00, 0x06, 0x02, 0x02, 0x12, 0x0C}, // j (Never found j - this is a guess!)
{0x00, 0x10, 0x10, 0x11, 0x12, 0x1C, 0x12, 0x11}, // k
{0x00, 0x0C, 0x04, 0x04, 0x04, 0x04, 0x04, 0x0E}, // l
{0x00, 0x00, 0x00, 0x1A, 0x15, 0x11, 0x11, 0x11}, // m
{0x00, 0x00, 0x00, 0x16, 0x19, 0x11, 0x11, 0x11}, // n
{0x00, 0x00, 0x00, 0x0E, 0x11, 0x11, 0x11, 0x0E}, // o
{0x00, 0x00, 0x00, 0x1E, 0x11, 0x1E, 0x10, 0x10}, // p
{0x00, 0x00, 0x00, 0x0F, 0x11, 0x0F, 0x01, 0x01}, // q
{0x00, 0x00, 0x00, 0x16, 0x19, 0x10, 0x10, 0x10}, // r
{0x00, 0x00, 0x00, 0x0E, 0x10, 0x0E, 0x01, 0x0E}, // s
{0x00, 0x08, 0x08, 0x1C, 0x08, 0x08, 0x09, 0x06}, // t
{0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x13, 0x0D}, // u
{0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x0A, 0x04}, // v
{0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x15, 0x0A}, // w
{0x00, 0x00, 0x00, 0x11, 0x0A, 0x04, 0x0A, 0x11}, // x
{0x00, 0x00, 0x00, 0x11, 0x11, 0x0F, 0x01, 0x0E}, // y
{0x00, 0x00, 0x00, 0x1F, 0x02, 0x04, 0x08, 0x1F}}; // z
const char SpecialChar[][8] = {{0x00, 0x04, 0x0A, 0x04, 0x00, 0x00, 0x00, 0x00}, // 0: degrees sign
{0x00, 0x00, 0x00, 0x04, 0x0E, 0x04, 0x00, 0x00}, // 1: Smaller plus sign
{0x00, 0x00, 0x00, 0x08, 0x1C, 0x08, 0x00, 0x00}, // 2: Left-shifted smaller plus sign
{0x00, 0x00, 0x04, 0x06, 0x3F, 0x06, 0x04, 0x00}, // 3: Active arrow
{0x00, 0x00, 0x04, 0x06, 0x1F, 0x06, 0x04, 0x00}, // 4: Slightly shorter active arrow
{0x00, 0x04, 0x04, 0x1F, 0x04, 0x04, 0x00, 0x1F}, // 5: +- sign.
{0x00, 0x1E, 0x11, 0x11, 0x3F, 0x11, 0x11, 0x1E}, // 6: the barred 'D' of the DTO symbol
{0x00, 0x00, 0x04, 0x0C, 0x1F, 0x0C, 0x04, 0x00}}; // 7: Left pointing arrow.
// For small char, the first char is the number of pixels horizontally that are used for drawing,
// since these chars are not fixed width. (Used for the labels in the moving map display).
// The hex values are referenced from the right-most pixel position, and the chars are 5 pixels high (last 5 chars).
const char SmallChar[][8] = {{0x03, 0x00, 0x00, 0x07, 0x05, 0x05, 0x05, 0x07}, // 0
{0x03, 0x00, 0x00, 0x02, 0x06, 0x02, 0x02, 0x07}, // 1
{0x03, 0x00, 0x00, 0x06, 0x01, 0x02, 0x04, 0x07}, // 2
{0x03, 0x00, 0x00, 0x07, 0x01, 0x03, 0x01, 0x07}, // 3
{0x03, 0x00, 0x00, 0x01, 0x03, 0x05, 0x07, 0x01}, // 4
{0x03, 0x00, 0x00, 0x07, 0x04, 0x07, 0x01, 0x07}, // 5
{0x03, 0x00, 0x00, 0x07, 0x04, 0x07, 0x05, 0x07}, // 6
{0x03, 0x00, 0x00, 0x07, 0x01, 0x02, 0x02, 0x02}, // 7
{0x03, 0x00, 0x00, 0x07, 0x05, 0x07, 0x05, 0x07}, // 8
{0x03, 0x00, 0x00, 0x07, 0x05, 0x07, 0x01, 0x07}, // 9
{0x03, 0x00, 0x00, 0x02, 0x05, 0x05, 0x07, 0x05}, // A
{0x03, 0x00, 0x00, 0x06, 0x05, 0x06, 0x05, 0x06}, // B
{0x03, 0x00, 0x00, 0x03, 0x04, 0x04, 0x04, 0x03}, // C
{0x04, 0x00, 0x00, 0x0E, 0x09, 0x09, 0x09, 0x0E}, // D
{0x03, 0x00, 0x00, 0x07, 0x04, 0x06, 0x04, 0x07}, // E
{0x03, 0x00, 0x00, 0x07, 0x04, 0x06, 0x04, 0x04}, // F
{0x04, 0x00, 0x00, 0x06, 0x08, 0x0B, 0x09, 0x06}, // G
{0x03, 0x00, 0x00, 0x05, 0x05, 0x07, 0x05, 0x05}, // H
{0x03, 0x00, 0x00, 0x07, 0x02, 0x02, 0x02, 0x07}, // I
{0x04, 0x00, 0x00, 0x01, 0x01, 0x01, 0x09, 0x06}, // J
{0x04, 0x00, 0x00, 0x09, 0x0A, 0x0C, 0x0A, 0x09}, // K
{0x03, 0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x07}, // L
{0x05, 0x00, 0x00, 0x11, 0x1B, 0x15, 0x11, 0x11}, // M
{0x04, 0x00, 0x00, 0x09, 0x0D, 0x0F, 0x0B, 0x09}, // N
{0x04, 0x00, 0x00, 0x06, 0x09, 0x09, 0x09, 0x06}, // O
{0x03, 0x00, 0x00, 0x07, 0x05, 0x07, 0x04, 0x04}, // P
{0x04, 0x00, 0x00, 0x06, 0x09, 0x09, 0x0B, 0x07}, // Q
{0x04, 0x00, 0x00, 0x0E, 0x09, 0x0E, 0x0A, 0x09}, // R
{0x04, 0x00, 0x00, 0x07, 0x08, 0x06, 0x01, 0x0E}, // S
{0x03, 0x00, 0x00, 0x07, 0x02, 0x02, 0x02, 0x02}, // T
{0x03, 0x00, 0x00, 0x05, 0x05, 0x05, 0x05, 0x07}, // U
{0x03, 0x00, 0x00, 0x05, 0x05, 0x05, 0x05, 0x02}, // V
{0x05, 0x00, 0x00, 0x11, 0x11, 0x11, 0x15, 0x0A}, // W
{0x03, 0x00, 0x00, 0x05, 0x05, 0x02, 0x05, 0x05}, // X
{0x03, 0x00, 0x00, 0x05, 0x05, 0x07, 0x02, 0x02}, // Y
{0x03, 0x00, 0x00, 0x07, 0x01, 0x02, 0x04, 0x07}}; // Z