// -*- C++ -*- generated by wxGlade 0.6.3 on Tue Mar 10 11:02:18 2009
/*
  Copyright 2009 Ronald S. Burkey <info@sandroid.org>

  This file is part of yaAGC.

  yaAGC 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.

  yaAGC 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 yaAGC; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

  Filename:	yaTelemetry.cpp
  Purpose:	A program to display telemetry-downlink info from AGC.
  Compiler:	GNU gcc.
  Reference:	http://www.ibibio.org/apollo
  Mode:		2009-03-09 RSB.	Began.
  		2009-03-13 RSB	Added --simple.
		2009-03-14 RSB	Use smaller default font sizes when the --simple
				switch is used.  Work around a funky socket 
				error which appears in Windows.
		2009-04-07 RSB	Began adding stuff related to MSK formtting.
  
  The program does nothing more than connect to yaAGC on a socket, and then
  display any telemetry messages it receives.  There is a single active widget,
  which is a text control.  A periodically-executing event handler fetches
  data from the socket, formats it properly, and sticks it into the text-control.
  The text control is read-only, meaning that the user can't type anything into
  it.  The text control is sized to have 80 columns and 43 rows, since this is
  the same as the size of the xterm which was previously used to display the 
  downlink data when yaDSKY processed it before yaTelemetry was created.
  
  Anyone who knows C++ will notice, I'm sure, that I duplicate a lot of functions
  between MainFrameClass and SimpleFrameClass that I should have just handled
  through inheritance.  If anyone wants to fix it up for me, that would be swell,
  though it might goof up maintenance of the classes via wxGlade.
*/

#include "yaTelemetry.h"
#include "../yaAGC/yaAGC.h"
#include "../yaAGC/agc_engine.h"

MainFrameClass *MainFrame = NULL;
SimpleFrameClass *SimpleFrame = NULL;

#include <cstdlib>
#include <stdio.h>
#include <errno.h>
#include <iostream>

using namespace std;

ProcessDownlinkList_t PrintMsk683, PrintMsk966, PrintMsk1123, PrintMsk1137;

#define PULSE_INTERVAL 100
static char DefaultHostname[] = "localhost";
char *Hostname = DefaultHostname;
static char NonDefaultHostname[129];
#ifdef WIN32
static int StartupDelay = 500;
#else
static int StartupDelay = 0;
#endif
#if defined (WIN32)
#define DEFAULT_FONTSIZE_RESIZABLE 8
#define DEFAULT_FONTSIZE_RETRO 9
#elif defined (__APPLE__)
#define DEFAULT_FONTSIZE_RESIZABLE 10
#define DEFAULT_FONTSIZE_RETRO 14
#else
#define DEFAULT_FONTSIZE_RESIZABLE 8
#define DEFAULT_FONTSIZE_RETRO 11
#endif
static int Points = DEFAULT_FONTSIZE_RETRO;
static bool Simple = false;

// Here are some templates for various MSK screens.

static char Msk683[] =
  "                               CSM GNC PRIMARY TAB                        0683 \n"
  "GMT     XX:XX:XX:XX               SITE  XXXXXXX                                \n"
  "GETA    XXXX:XX:XX                         QUADA     QUADB    QUADC    QUADD   \n"
  "CTE     XXXX:XX:XX       WPU  CAL C  LBS   XXXX.X    XXXX.X   XXXX.X   XXXX.X  \n"
  "CMC     XXXX:XX:XX       HE   P/T R  PCT   XXX.X     XXX.X    XXX.X    XXX.X   \n"
  "CMCB    XXXX:XX:XX      ______________________________________________________ \n"
  "GETC    XXXX:XX:XX     | PKG  TEMP   degF  +XXX.X    +XXX.X   +XXX.X   +XXX.X |\n"
  "CMC dT  XXX.XXX        | HE   TK P   PSIA  XXXX      XXXX     XXXX     XXXX   |\n"
  "ISS     XXXXXXX | M    | HE   TK T   degF  +XXX.X    +XXX.X   +XXX.X   +XXX.X |\n"
  "OPT     XXXX    | D    | HE   MN P   PSIA  XX.X      XX.X     XX.X     XX.X   |\n"
  "CMC     XXXX    | E    | FU   MN P   PSIA  XX.X      XX.X     XX.X     XX.X   |\n"
  "ID      XXXXXXX        | OX   MN P   PSIA  XX.X      XX.X     XX.X     XX.X   |\n"
  "                       |     CM-RCS        SYS 1     SYS 2          SPS       |\n"
  "VERB   NOUN   PRGM     | HE   TK P   PSIA  XX.X      XX.X     OX TK PSI XXXX  |\n"
  " XX     XX     XX      | HE   MN P   PSIA  XX.X      XX.X     OX LN PSI XXXX  |\n"
  "REG 1   +XXXXX         | HE   TK T   degF  +XXX.X    +XXX.X   EG CH PSI XXXX  |\n"
  "REG 2   +XXXXX         |___________________________________   FU TK PSI XXXX  |\n"
  "REG 3   +XXXXX               PITCH  YAW    ROLL            |  FU LN PSI XXXX  |\n"
  "                   ISS ATT   +XXX.X +XXX.X +XXX.X          |  HE TK PSI XXXX  |\n"
  "_______DAP_______      ACDU  +XXX.X +XXX.X +XXX.X          |__________________|\n"
  "RATE    DB             FCDU  +XXX.X +XXX.X +XXX.X                              \n"
  " X.X    X.X         ERR CMC  +XX.X  +XX.X  +XX.X     HE  TK   T  degF  +XXX.X  \n"
  "VEH ACC +XXX.X      ERR SCS  +XX.X  +XX.X  +XX.X     OX  FD  LN  degF  +XXX.X  \n"
  "VG X    +XXXX         | ENT  +XX.X  +XX.X  +XX.X     FU  FD  LN  degF  +XXX.X  \n"
  "VG Y    +XXXX    RATE | G/N  +XX.X  +XX.X  +XX.X     OX  LN   I  degF  +XXX.X  \n"
  "VG Z    +XXXX         | SCS  +XX.X  +XX.X  +XX.X     FU  LN   I  degF  +XXX.X  \n"
  "PIPX    +XXXXX                                       EG VLV      degF  +XXX.X  \n"
  "PIPY    +XXXXX      GMB CMD  +XX.XX +XX.XX +XX.XX    N2  TA       PSI  XXXX    \n"
  "PIPZ    +XXXXX      OCDU DC  +XX.XX +XX.XX           N2  TB       PSI  XXXX    \n"
  "PIP T   +XXX/X      SPS GMB  +XX.XX +XX.XX           OX  T1       PCT  XXX.X   \n"
  "TEV     XXXX:XX:XX   AT TVC  +X.XX  +X.XX            OX  T2       PCT  XXX.X   \n"
  "TIG     XXXX:XX:XX   MN TVC  +X.XX  +X.XX  +X.XX     FU  T1       PCT  XXX.X   \n"
  "                    DIF CUR  +XXX.X +XXX.X           FU  T2       PCT  XXX.X   ";

static char Msk966[] =
  "                              CMC MONITOR D H/S                            966 \n"
  " _____________________________________________________________________________ \n"
  "| ID  XXXXX       GMT   XX:XX:XX.XX  SITE  XXXXXXX     X/ROLL Y/PITCH  Z/YAW  |\n"
  "|                 CTE   XXXX:XX:XX             PIPA   +XXX.XX +XXX.XX +XXX.XX |\n"
  "| FGWD  0 XXXXX   GETA  XXXX:XX:XX             DELV   +XXX.XX +XXX.XX +XXX.XX |\n"
  "| FGWD  1 XXXXX   GETC  XXXX:XX:XX             VGIMU  +XXX.XX +XXX.XX +XXX.XX |\n"
  "| FGWD  2 XXXXX   CMCB  XXXX:XX:XX                                            |\n"
  "| FGWD  3 XXXXX   CMC   XXX:XX:XX.XX           FCDU   +XXX.XX +XXX.XX +XXX.XX |\n"
  "| FGWD  4 XXXXX   TCMSV XXX:XX:XX.XX           DCDU   +XXX.XX +XXX.XX +XXX.XX |\n"
  "| FGWD  5 XXXXX   TLMSV XXX:XX:XX.XX           ACDU   +XXX.XX +XXX.XX +XXX.XX |\n"
  "| FGWD  6 XXXXX   TGO   XXX:XX:XX                                             |\n"
  "| FGWD  7 XXXXX   TIG   XXX:XX:XX.XX           ERROR  +XXX.XX +XXX.XX +XXX.XX |\n"
  "| FGWD  8 XXXXX   TEVNT XXX:XX:XX.XX           AK     +XXX.XX +XXX.XX +XXX.XX |\n"
  "| FGWD  9 XXXXX  _______________________       ADOT   +XXX.XX +XXX.XX +XXX.XX |\n"
  "| FGWD 10 XXXXX | PG XX  FL  X  WARN  X |      OMGAC  +XXX.XX +XXX.XX +XXX.XX |\n"
  "| FGWD 11 XXXXX | VB XX  NN XX  PRG   X | P    ERR    +XXX.XX +XXX.XX +XXX.XX |\n"
  "|               |               KKK   X | I    BIAS   +XXX.XX +XXX.XX +XXX.XX |\n"
  "| CHNL 11 XXXXX | R1   +XXXXX   UPFST X | P    OCTL   +XXX.XX +XXX.XX +XXX.XX |\n"
  "| CHNL 12 XXXXX | R2   +XXXXX   UPSW  X |    LM XXXXX  ACTOFF +XX.XXX +XX.XXX |\n"
  "| CHNL 13 XXXXX | R3   +XXXXX   CMD   X |   CSM XXXXX GMBDCMD +XX.XXX +XX.XXX |\n"
  "| CHNL 14 XXXXX |_______________________|                                     |\n"
  "| CHNL 30 XXXXX   REDO   DSTB11 XXXXX      HAPO +XXXX.X     TCSI XXX:XX:XX.XX |\n"
  "| CHNL 31 XXXXX   XXXXX  FAILRG            HPER +XXXX.X     TCDH XXX:XX:XX.XX |\n"
  "| CHNL 32 XXXXX   RSBBQ  XXXXX              LAT +XX.XXX     TTPI XXX:XX:XX.XX |\n"
  "| CHNL 33 XXXXX   XXXXX  XXXXX             LONG +XXX.XX     TTPF XXX:XX:XX.XX |\n"
  "|                 XXXXX  XXXXX            VMAGI XXXXX       TMRK XXX:XX:XX.XX |\n"
  "| IMDE 30 XXXXX   HLDFG  INTEG TIME       VGTLI XXXXX       TVHF XXX:XX:XX.XX |\n"
  "| IMDE 31 XXXXX   XXXXX  XXX:XX:XX.XX        dT XXX:XX.XXX  VHFRNG NM +XXX.XX |\n"
  "| OPTMDE  XXXXX   RCSFG  STARID1 XXX     CDH dH +XX.XX      ELEVN ANG +XXX.XX |\n"
  "| DPDTR1  XXXXX   XXXXX  STARID2 XXX        VHF XX  OPT XX  CNTRL ANG +XXX.XX |\n"
  "| DPDTR2  XXXX          CDU SHFT +XXX.XX   dVLX +XXXX.X  Y +XXXX.X  Z +XXXX.X |\n"
  "|                       CDU TRUN +XX.XXX dVR/PX +XXXX.X  Y +XXXX.X  Z +XXXX.X |\n"
  "|_____________________________________________________________________________|";

static char Msk1123[] = 
  "                    LM GUID, CONTROL, and PROP RT   |     |     |     |   1123 \n"
  "                                                    | AEA | LGC | PCM |        \n"
  "GET   XXX:XX:XX     MET   XXX:XX:XX                 |_____|_____|_____|        \n"
  "AGS   XXX:XX:XX     LGC   XXX:XX:XX     LGC FMT   XXXXXX         SITE  XXXXXXX \n"
  "T/E   XXX:XX:XX     TGO   XX:XX         TTF/8     XX:XX                        \n"
  "PGNS RATE      XX.X        XX.X        XX.X        ____________________________\n"
  "RGA RATE       XX.X        XX.X        XX.X       |                            \n"
  "ASA RATE       XX.X        XX.X        XX.X       |             ____VEH WT_____\n"
  "______________ROLL/Z_____PITCH/Y______YAW/X_______|            |               \n"
  "ATT CMDS       XX.X        XX.X        XX.X       |            |  XXXXX  LGC   \n"
  "RSVR GMBL     XXX.X       XXX.X       XXX.X       |            |  XXXXX  CAL   \n"
  "_________________FDAI ATTITUDES___________________|            |_______________\n"
  "ICDUD ATT     XXX.X       XXX.X       XXX.X       |                            \n"
  "IMU ATT       XXX.X       XXX.X       XXX.X       |                            \n"
  "CDUA ATT      XXX.X       XXX.X       XXX.X       |                _TORQUE_    \n"
  "AGS ATT       XXX.X       XXX.X       XXX.X       |               |        |   \n"
  "_________________ATTITUDE ERRORS__________________|            +U |  XX.X  |   \n"
  "PGNS ERR       XX.X        XX.X        XX.X       |            -U |  XX.X  |   \n"
  "AGS ERR       XXX.X       XXX.X       XXX.X       |            +V |  XX.X  |   \n"
  "___________________VELOCITIES_____________________|            -V |  XX.X  |   \n"
  "LGC DEL V      XX.X        XX.X        XX.X       |               |________|   \n"
  "AGS DEL V      XX.X        XX.X        XX.X       |                            \n"
  "AGS ULL       XX.XX        ACT VEL     XX.X       |                            \n"
  "              AUTO         XX          F0   XXXXX |                            \n"
  "R   XXX.X     ATT H        XX          F1   XXXXX |                            \n"
  "P   XXX.X   ______LR______             F2   XXXXX |                            \n"
  "Y   XXX.X  | AP      X    |____DEDA________DSKY___|                            \n"
  "RR  XXXXX  | ALT XX  V XX | AD  XXX    | P XX     |                            \n"
  "TRK XXXXX  |              | RO  +XXXXX | V XX     |             _______________\n"
  "R   XXX.XX | SR    XXXXX  | CLR X      | N XX     |            |    XXX GTC    \n"
  "RDT XXXX   | VX   +XXXXX  | M   +XXXXX | 1 +XXXXX |            |    XXX CMD    \n"
  "SH  +XXX   | VY   +XXXXX  |     +XXXXX | 2 +XXXXX |            |    XXX POS    \n"
  "TR  +XXX   | VZ   +XXXXX  | REDO XXXXX | 3 +XXXXX |            |    XXX TH     ";

static char Msk1137[] =
  "GET  XXX:XX:XX      LGC  XXX:XX:XX     GMT  XXX:XX:XX  AEA  LGC  PCM      1137 \n"
  "______THRTL_______            ROLL-R PITCH-Q  YAW-P    _____________ SITE XXXXX\n"
  "SELECT    XXXX    | LGC XXXXX +XX.X   +XX.X   +XX.X    WT   XXXXX     D/L XXXXX\n"
  "DECA      +XXX.XX | AGS ERR   +XXX.X  +XXX.X  +XXX.X   CSM  XXXXX    XXX C5 MSK\n"
  "MAN  THR  XXX%    | OMEGA-D   +X.XX   +X.XX   +X.XX    BUG  000XX    XXX C6 MSK\n"
  "AUTO THR  XXX%    | OFFSET    +XX.XXX +XX.XXX +XX.XXX  DAP  XXXXX  XXXXX C 30  \n"
  "CMD  THR  XXX%    | GMBL DR   XX      XX      XX       C 11 XXXXX  XXXXX C 31  \n"
  "VAR  ACT  XXX%    |   SC      TORQ-U  TORQ-V  TORQ-P   C 12 XXXXX  XXXXX C 32  \n"
  "GUID CMD  XXX%    | AUTO XX   XX.XX   XX.XX   XX.XX    C 13 XXXXX  XXXXX C 33  \n"
  "TCP       XXX%    | A/H  XX   XX.XX   XX.XX   XX.XX    C 14 XXXXX  XXXXX RAD   \n"
  "_____________ATTITUDES___________________STATUS__________________LR____________\n"
  "       ROLL-Z   PITCH-Y  YAW-X      | _____DAP_____ | LR RNG XXXX     VEL XXXX \n"
  "B      +XXX.XXX +XXX.XXX +XXX.XXX   | TIG XXX:XX:XX |      LR XXX PGNSd  AGSd  \n"
  "OCTAL  XXXXX    XXXXX    XXXXX      | TGO XXXXX     | VXS  XXXXX  XXXXX  XXXXX \n"
  "RSVRS  +XXX.XX  +XXX.XX  +XXX.XX    | T/E XXX:XX:XX | VYS  XXXXX  XXXXX  XXXXX \n"
  "ACDU   +XXX.XX  +XXX.XX  +XXX.XX    |  T/P   XXXXX  | VZS  XXXXX  XXXXX  XXXXX \n"
  "RSVR   +XXX.XX  +XXX.XX  +XXX.XX    |  LGC   X      | RNG  XXXXX  XXXXX  XXXXX \n"
  "ACT    +XXX.XX  +XXX.XX  +XXX.XX    |  ISS   X      | ___________RR____________\n"
  "IDES   +XXX.XX  +XXX.XX  +XXX.XX    |  PCNS  X      | MODE XXXXX  XXXXX  XXXXX \n"
  "FDES   +XXX.XX  +XXX.XX  +XXX.XX    |  CH 77 XXXXX  | DATA XXXXX  XXXXX  XXXXX \n"
  "AGS    +XXX.XX  +XXX.XX  +XXX.XX    |  FREG0 XXXXX  |                          \n"
  "dERR   +XX.XX   +XX.XX   +XX.XX     |  FREG1 XXXXX  | _______SHFT_____TRUN_____\n"
  "                                    |  FREG2 XXXXX  | LGC    +XXX.X   +XXX.X   \n"
  "______________RATES_________________|  REDO  X      | RR     +XXX.X   +XXX.X   \n"
  "PGNS-B +XX.XX   +XX.XX   +XX.XX     |  PROG  XX     | ERR    +XX.XX   +XX.XX   \n"
  "RGA-B  +XX.X    +XX.X    +XX.X      |  VERB  XX     | RANGE  XXX.XX   XXX.XX   \n"
  "                                    |  NOUN  XX     | RNGRT  +XXXX    +XXXX    \n"
  "________DELTA VELOCITIES____________|__  FL  +XXXXX |                          \n"
  "AGS-B  +XX.X    +XX.X    +XX.X | +XX.X | R1  +XXXXX | _______POWER____TEMPS____\n"
  "LGC-B  +XX.X    +XX.X    +XX.X | +XX.X | R2  +XXXXX | 800~   XX.X     XX.X     \n"
  "ACD dV XX.X     XX.X     XX.X  | +XX.X | R3  +XXXXX | 3200~  XX.X     XX.X     \n"
  "PIP-S  XXXXX    XXXXX    XXXXX |  VEL  |            | 120v   XXX      XXX      \n"
  "SM     XX.X     XX.X     XX.X  | GAIN  |            | BIAS   X.XX     X.XX     ";


// Clears the output text control.  The reason we use this instead of the 
// text-control's native Clear function is that we want the text control
// to always contain exactly TELEMETRY_ROWS x TELEMETRY_COLUMNS worth of 
// stuff, even if that stuff is blank spaces.  This makes it easier for us
// to read and write to random locations, since the writing can always be
// replacement of existing text.  We expect this function to be called only
// at startup, or when the downlink mode changes, so we don't bother to
// optimize it for speed.
void
MainFrameClass::ClearScreen (void)
{
  wxString EmptyScreen;
  wxTextAttr Style;
  wxColor TextColor;
  int i, j;
  for (i = 0; i < TELEMETRY_ROWS; i++)
    {
      if (i > 0)
        EmptyScreen += wxT ("\n");
      for (j = 0; j < TELEMETRY_COLUMNS; j++)
        EmptyScreen += wxT (" ");
    }
  Style = TextCtrl->GetDefaultStyle ();
#ifdef __APPLE__
  // On the Mac, the background color of the text control does not come out
  // right --- it's always white, no matter what I do.  It also has a 
  // (disabled) scrollbar no matter what I do.  I've expended more time on
  // it than it's worth to me, so on the Mac I simply eliminate the decorative
  // border into which the text control (which is supposed to be black) is
  // supposed to blend, and choose a text color that shows up okay on the 
  // (wrong) white background.
  TextColor.Set (0x000000UL);
#else
  TextColor.Set (0xc0c0c0UL);
#endif
  Style.SetTextColour (TextColor);
  TextCtrl->SetDefaultStyle (Style);
  TextCtrl->Clear ();
  TextCtrl->FitInside ();
  TextCtrl->ChangeValue (EmptyScreen);
}

// Print to screen at coordinates x,y.  Clipping is performed, but
// not wrapping.  In other words, any call to Print() will go on
// a single line.  Don't try to defeat it by putting in newlines,
// as this will just mess up the rationale by which the screen is
// being managed.

void 
MainFrameClass::Print (int x, int y, wxString &Value)
{
  int From, To, Length, xend;
  // Sanity checking.  Abort if the string will be completely
  // off the screen.  The usual case is that everthing will be
  // fine and on-screen, so we do a quick check for that case.
  if (y < 0 || y >= TELEMETRY_ROWS)
    return;
  Length = Value.Length ();
  xend = x + Length;
  if (x < 0 || xend > TELEMETRY_COLUMNS)
    {
      // Perhaps it's completely off-screen!
      if (xend <= 0 || x >= TELEMETRY_COLUMNS)
	return;
      // No, at least partially on-screen.
      if (xend > TELEMETRY_COLUMNS)
        {
	  Length -= (xend - TELEMETRY_COLUMNS);
	  Value = Value.Left (Length);
	}
      if (x < 0)
        {
	  Length += x;
	  Value = Value.Right (Length);
	}
    }
  // All checked and/or clipped.  Output it.
  From = TextCtrl->XYToPosition (x, y);
  To = From + Length;
  TextCtrl->Replace (From, To, Value);
}

// Set font-size in the text control.
void 
MainFrameClass::FontSize (int Points)
{
  TextCtrl->SetFont(wxFont(Points, wxMODERN, wxNORMAL, wxNORMAL, 0, wxT("")));
}

// Remove frame decorations.
void
MainFrameClass::Undecorate (void)
{
    delete bitmap_1;
    delete bitmap_5;
    delete bitmap_3;
    delete bitmap_2;
    bitmap_1 = new wxStaticBitmap(this, wxID_ANY, wxBitmap(wxT("tTelemetryLeft.jpg"), wxBITMAP_TYPE_ANY));
    bitmap_5 = new wxStaticBitmap(this, wxID_ANY, wxBitmap(wxT("tTelemetryTop.jpg"), wxBITMAP_TYPE_ANY));
    bitmap_3 = new wxStaticBitmap(this, wxID_ANY, wxBitmap(wxT("tTelemetryBottom.jpg"), wxBITMAP_TYPE_ANY));
    bitmap_2 = new wxStaticBitmap(this, wxID_ANY, wxBitmap(wxT("tTelemetryRight.jpg"), wxBITMAP_TYPE_ANY));
    do_layout();
}

// Clears the output text control.  The reason we use this instead of the 
// text-control's native Clear function is that we want the text control
// to always contain exactly RowsToUse x TELEMETRY_COLUMNS worth of 
// stuff, even if that stuff is blank spaces.  This makes it easier for us
// to read and write to random locations, since the writing can always be
// replacement of existing text.  We expect this function to be called only
// at startup, or when the downlink mode changes, so we don't bother to
// optimize it for speed.
void
SimpleFrameClass::ClearScreen (void)
{
  wxString EmptyScreen;
  //wxTextAttr Style;
  wxColor TextColor;
  int i, j;
  switch (MskType)
    {
    case 683:  EmptyScreen = wxString::FromAscii (Msk683); break;
    case 966:  EmptyScreen = wxString::FromAscii (Msk966); break;
    case 1123: EmptyScreen = wxString::FromAscii (Msk1123); break;
    case 1137: EmptyScreen = wxString::FromAscii (Msk1137); break;
    default:
      for (i = 0; i < RowsToUse; i++)
	{
	  if (i > 0)
	    EmptyScreen += wxT ("\n");
	  for (j = 0; j < TELEMETRY_COLUMNS; j++)
	    EmptyScreen += wxT (" ");
	}
      break;
    }
  //Style = TextCtrl->GetDefaultStyle ();
  //TextColor.Set (0x000000UL);
  //Style.SetTextColour (TextColor);
  //TextCtrl->SetDefaultStyle (Style);
  //TextCtrl->Clear ();
  //TextCtrl->FitInside ();
  TextCtrl->SetLabel (EmptyScreen);
  //TextCtrl->Fit ();
  Fit ();
}

#if 0
// Print to screen at coordinates x,y.  Clipping is performed, but
// not wrapping.  In other words, any call to Print() will go on
// a single line.  Don't try to defeat it by putting in newlines,
// as this will just mess up the rationale by which the screen is
// being managed.

void 
SimpleFrameClass::Print (int x, int y, wxString &Value)
{
  int From, To, Length, xend;
  // Sanity checking.  Abort if the string will be completely
  // off the screen.  The usual case is that everthing will be
  // fine and on-screen, so we do a quick check for that case.
  if (y < 0 || y >= RowsToUse)
    return;
  Length = Value.Length ();
  xend = x + Length;
  if (x < 0 || xend > TELEMETRY_COLUMNS)
    {
      // Perhaps it's completely off-screen!
      if (xend <= 0 || x >= TELEMETRY_COLUMNS)
	return;
      // No, at least partially on-screen.
      if (xend > TELEMETRY_COLUMNS)
        {
	  Length -= (xend - TELEMETRY_COLUMNS);
	  Value = Value.Left (Length);
	}
      if (x < 0)
        {
	  Length += x;
	  Value = Value.Right (Length);
	}
    }
  // All checked and/or clipped.  Output it.
  From = TextCtrl->XYToPosition (x, y);
  To = From + Length;
  TextCtrl->Replace (From, To, Value);
}
#endif

// Set font-size in the text control.
void 
SimpleFrameClass::FontSize (int Points)
{
  TextCtrl->SetFont(wxFont(Points, wxMODERN, wxNORMAL, wxNORMAL, 0, wxT("")));
}

void
SwriteTelemetry (void)
{
  int i;
  wxString Dummy;
  for (i = 0; i < Sheight; i++)
    {
      Dummy = wxString::FromAscii (Sbuffer[i]);
      MainFrame->Print (0, i, Dummy);
    }
}

void
SwriteTelemetrySimple (void)
{
  int i;
  wxString Dummy;
  for (i = 0; i < Sheight; i++)
    {
      if (i > 0)
        Dummy += wxT ("\n");
      Dummy += wxString::FromAscii (Sbuffer[i]);
    }
  SimpleFrame->TextCtrl->SetLabel (Dummy);
}

// This is the event handler for the background timer.  The background timer
// executes about every 100 ms. and services the socket interface.  Upon 
// receiving downlink data, it updates the output screen.

void 
TimerClass::Notify ()
{
#ifdef DEBUG
  static int Count = 0;
  int j;
  wxString Dummy;
  j = Count % TELEMETRY_ROWS;
  Dummy = wxT ("Hello #");
  Dummy << Count++;
  MainFrame->Print (2 * j, j, Dummy);
#endif

  static int ServerSocket = -1;
  static unsigned char Packet[4];
  static int PacketSize = 0;
  int i;
  unsigned char c;
  if (StartupDelay > 0)
    {
      StartupDelay -= PULSE_INTERVAL;
      return;
    }
  // Try to connect to the server (yaAGC) if not already connected.
  if (ServerSocket == -1)
    {
      ServerSocket = CallSocket (Hostname, Portnum);
      if (ServerSocket != -1)
        printf ("yaTelemetry is connected.\n");
    }
  if (ServerSocket != -1)
    {
      for (;;)
        {
	  i = recv (ServerSocket, (char *) &c, 1, MSG_NOSIGNAL);
	  if (i == -1)
	    {
	      // The conditions i==-1,errno==0 or 9 occur only on Win32,
	      // and I'm not sure exactly what they corresponds to---but
	      // empirically I find that ignoring them makes no difference
	      // to the operation of the program.
	      if (errno == EAGAIN || errno == 0 || errno == 9)
	        i = 0;
	      else
	        {	
		  //wxString Dummy;
		  //Dummy << wxT ("yaTelemetry reports server error ") << errno;
		  //wxMessageBox (Dummy);
		  printf ("yaTerminal reports server error %d\n", errno);
		  close (ServerSocket);
		  ServerSocket = -1;
		  break;
	        }
	    }
	  if (i == 0)
	    break;
	  if (0 == (0xc0 & c))
	    PacketSize = 0;
	  if (PacketSize != 0 || (0xc0 & c) == 0)	      
	    { 
	      Packet[PacketSize++] = c;
	      if (PacketSize >= 4)
		{
		  ActOnIncomingIO (Packet);
		  PacketSize = 0;   
		}  
	    }
	}
    }
}

void
TimerClass::ActOnIncomingIO (unsigned char *Packet)
{
  int Channel, Value, uBit;
  // Check to see if the message has a yaAGC signature.  If not,
  // ignore it.  The yaAGC signature is 00 01 10 11 in the 
  // 2 most-significant bits of the packet's bytes.  We are 
  // guaranteed that the first byte is signed 00, so we don't 
  // need to check it.
  if (0x40 != (Packet[1] & 0xc0) ||
      0x80 != (Packet[2] & 0xc0) ||
      0xc0 != (Packet[3] & 0xc0))
    return;
  if (ParseIoPacket (Packet, &Channel, &Value, &uBit))
    goto Error;
  // Decode the digital downlink data.  The way this works is that
  // DecodeDigitalDownlink() buffers the incoming downlink list, 
  // and when it is fully buffered calls a callback function to 
  // process it.  The default library callback function is called 
  // when MskType==0 ("raw" data).  For other MskTypes, the 
  // default processor is overridden and one of the ProcessMskXXXX()
  // functions from later in this file becomes the callback function
  // instead.
  if (Channel == 013 || Channel == 034 || Channel == 035)
    DecodeDigitalDownlink (Channel, Value, CmOrLm);
  return;
Error:
  IoErrorCount++;
}



///////////////////////////////////////////////////////////////////////////////
// The stuff below this line was created by wxGlade, and could conceivably be
// modified by wxGlade in the future.  So try to confine useful code to the 
// area above this line, to the extent feasible.

// begin wxGlade: ::extracode
// end wxGlade



MainFrameClass::MainFrameClass(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style):
    wxFrame(parent, id, title, pos, size, wxCAPTION|wxCLOSE_BOX|wxMINIMIZE_BOX|wxSYSTEM_MENU)
{
    // begin wxGlade: MainFrameClass::MainFrameClass
    bitmap_1 = new wxStaticBitmap(this, wxID_ANY, wxBitmap(wxT("TelemetryLeft.jpg"), wxBITMAP_TYPE_ANY));
    bitmap_5 = new wxStaticBitmap(this, wxID_ANY, wxBitmap(wxT("TelemetryTop.jpg"), wxBITMAP_TYPE_ANY));
    TextCtrl = new wxTextCtrl(this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_MULTILINE|wxTE_READONLY|wxTE_RICH|wxNO_BORDER);
    bitmap_3 = new wxStaticBitmap(this, wxID_ANY, wxBitmap(wxT("TelemetryBottom.jpg"), wxBITMAP_TYPE_ANY));
    bitmap_2 = new wxStaticBitmap(this, wxID_ANY, wxBitmap(wxT("TelemetryRight.jpg"), wxBITMAP_TYPE_ANY));

    set_properties();
    do_layout();
    // end wxGlade
}

BEGIN_EVENT_TABLE(MainFrameClass, wxFrame)
// content of this block not found: did you rename this class?
    EVT_CLOSE(MainFrameClass::TimerStop)
END_EVENT_TABLE();

void MainFrameClass::set_properties()
{
    // begin wxGlade: MainFrameClass::set_properties
    SetTitle(wxT("yaTelemetry by Ron Burkey"));
    wxIcon _icon;
    _icon.CopyFromBitmap(wxBitmap(wxT("ApolloPatch2.png"), wxBITMAP_TYPE_ANY));
    SetIcon(_icon);
    SetBackgroundColour(wxColour(0, 0, 0));
    SetForegroundColour(wxColour(192, 192, 192));
    SetFocus();
    bitmap_1->SetBackgroundColour(wxColour(0, 0, 0));
    bitmap_5->SetBackgroundColour(wxColour(0, 0, 0));
    TextCtrl->SetBackgroundColour(wxColour(0, 0, 0));
    TextCtrl->SetForegroundColour(wxColour(192, 192, 192));
    TextCtrl->SetFont(wxFont(11, wxMODERN, wxNORMAL, wxNORMAL, 0, wxT("")));
    bitmap_3->SetBackgroundColour(wxColour(0, 0, 0));
    bitmap_2->SetBackgroundColour(wxColour(0, 0, 0));
    // end wxGlade
}


void MainFrameClass::do_layout()
{
    // begin wxGlade: MainFrameClass::do_layout
    wxBoxSizer* sizer_1 = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer* sizer_2 = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer* sizer_3 = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer* sizer_4 = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer* sizer_5 = new wxBoxSizer(wxVERTICAL);
    sizer_2->Add(bitmap_1, 0, 0, 0);
    sizer_3->Add(bitmap_5, 0, 0, 0);
    sizer_4->Add(15, 20, 0, 0, 0);
    sizer_5->Add(20, 30, 0, 0, 0);
    sizer_5->Add(TextCtrl, 1, wxEXPAND, 0);
    sizer_5->Add(20, 30, 0, 0, 0);
    sizer_4->Add(sizer_5, 1, wxEXPAND, 0);
    sizer_4->Add(15, 20, 0, 0, 0);
    sizer_3->Add(sizer_4, 1, wxEXPAND, 0);
    sizer_3->Add(bitmap_3, 0, 0, 0);
    sizer_2->Add(sizer_3, 1, wxEXPAND, 0);
    sizer_2->Add(bitmap_2, 0, 0, 0);
    sizer_1->Add(sizer_2, 1, wxEXPAND, 0);
    SetSizer(sizer_1);
    sizer_1->Fit(this);
    Layout();
    // end wxGlade
}


class yaTelemetryApp: public wxApp {
public:
    bool OnInit();
};

IMPLEMENT_APP(yaTelemetryApp)

static wxApp *App;

bool yaTelemetryApp::OnInit()
{
    App = this;
    wxInitAllImageHandlers();
    MainFrame = new MainFrameClass(NULL, wxID_ANY, wxEmptyString);
    SimpleFrame = new SimpleFrameClass (NULL, wxID_ANY, wxEmptyString);
    int i, Undecorated = 0, FontSizeSwitch = 0;
    
    printf ("\n");
    printf ("yaTelemetry build " __DATE__ " " __TIME__ ", Copyright 2009 Ronald Burkey\n");
    printf ("For more information, consult http://www.ibiblio.org/apollo.\n");
	    
    // Read the command-line arguments.
    Portnum = 19800;
    CmOrLm = 0;
    for (i = 1; i < argc; i++)
      {
        long IntValue;
        wxString Arg, Command, Value;
	Arg = argv[i];
	Command = Arg.BeforeFirst ('=');
	Value = Arg.AfterFirst ('=');
	if (!Value.ToLong (&IntValue))
	  IntValue = 0;
	if (Arg.IsSameAs (wxT ("--help")))
	  {
	  Help:
	    printf ("\n");
	    printf ("This program provides a terminal on which to view downlinked telemetry\n");
	    printf ("from the AGC, which is to say from a running yaAGC server.\n");
	    printf ("\n");
	    printf ("USAGE:\n");
	    printf ("     yaTelemetry [OPTIONS]\n");
	    printf ("\n");
	    printf ("The available options are:\n");
	    printf ("\n");
	    printf ("     --help          Displays this message.\n");
	    printf ("     --delay=MS      Provides a delay after startup before\n");
	    printf ("                     attempting to connect to the yaAGC server.\n");
	    printf ("                     This allows elimination of certain race\n");
	    printf ("                     conditions which can occur when starting up\n");
	    printf ("                     a bunch of Virtual AGC servers and clients\n");
	    printf ("                     using scripts.  MS is the delay time, in \n");
	    printf ("                     milliseconds.  It defaults to 500 in Windows\n");
	    printf ("                     and 0 otherwise.\n");
	    printf ("     --port=P        The port number on which to try and set up a\n");
	    printf ("                     socket to the listening yaAGC server.  By\n");
	    printf ("                     convention, the virtual CM uses ports 19697\n");
	    printf ("                     through 19706, whilst the virutal LM uses\n");
	    printf ("                     ports 19797-19806.  By default, yaTelemetry\n");
	    printf ("                     uses 19800.\n");
	    printf ("     --ip=H          The hostname or IP address of the yaAGC server\n");
	    printf ("                     to which yaTelemetry should connect.  The\n");
	    printf ("                     default is \"localhost\".\n");
	    printf ("     --spacecraft=S  The type of spacecraft, either LM or CM.  This\n");
	    printf ("                     defaults to LM.\n");
	    printf ("     --font-size=P   Font size, in points.  Defaults to %d on this\n", DEFAULT_FONTSIZE_RETRO);
	    printf ("                     platform for the default or --undecorated style,\n");
	    printf ("                     and to %d for the --simple style (see below).\n", DEFAULT_FONTSIZE_RESIZABLE);
	    printf ("                     Generally, for the default or --undecorated style,\n");
	    printf ("                     the size should be chosen as the maximum for which\n");
	    printf ("                     scrollbars do not appear.  For the --simple style,\n");
	    printf ("                     the minimum size for comfortable reading should be\n");
	    printf ("                     selected.\n");
	    printf ("     --undecorated   This option is not recommended; you should use\n");
	    printf ("                     --simple instead.  What this option does is to\n");
	    printf ("                     remove decorations (the fake console around the\n");
	    printf ("                     displayed data), in order to reduce amount of screen\n");
	    printf ("                     space occupied.  If the screen height is too\n");
	    printf ("                     small to contain the decorations, then this \n");
	    printf ("                     switch is automatically selected.  It is also\n");
	    printf ("                     the default on Mac OS X.\n");
	    printf ("     --simple        Produces a simple text display, allowing dynamic\n");
	    printf ("                     resizing of the text.  This is by far the best choice\n");
	    printf ("                     when there is limited display-screen real estate.\n");
	    printf ("\n");
	    fflush (stdout);
	    return (false);
	  }
	else if (Command.IsSameAs (wxT ("--delay")))
	  StartupDelay = IntValue;
	else if (Command.IsSameAs (wxT ("--port")))
	  Portnum = IntValue;
	else if (Command.IsSameAs (wxT ("--ip")))
	  {
	    strcpy (NonDefaultHostname, Value.char_str ());
	    Hostname = NonDefaultHostname;
	  }
	else if (Command.IsSameAs (wxT ("--spacecraft")))
	  {
	    Value = Value.Lower ();
	    if (Value.IsSameAs (wxT ("lm")))
	      CmOrLm = 0;
	    else if (Value.IsSameAs (wxT ("cm")))
	      CmOrLm = 1;
	    else
	      {
		char s[129];
		strcpy (s, Arg.char_str ()); 
		printf ("Illegal command-line option: %s\n", s);
		goto Help;
	      }
	  }
	else if (Command.IsSameAs (wxT ("--font-size")))
	  {
	    Points = IntValue;
	    FontSizeSwitch = 1;
	  }
	else if (Command.IsSameAs (wxT ("--undecorated")))
	  Undecorated = 1;
	else if (Command.IsSameAs (wxT ("--simple")))
	  {
	    Simple = true;
	    if (!FontSizeSwitch)
	      Points = DEFAULT_FONTSIZE_RESIZABLE;
	  }
	else // Illegal option.
	  {
	    char s[129];
	    strcpy (s, Arg.char_str ()); 
	    printf ("Unrecognized command-line option: %s\n", s);
	    goto Help;
	  }
      }

    printf ("     --delay=%d\n", StartupDelay);
    printf ("     --port=%d\n", Portnum);
    printf ("     --ip=%s\n", Hostname);
    if (CmOrLm)
      printf ("     --spacecraft=CM\n");
    else
      printf ("     --spacecraft=LM\n");
    printf ("     --font-size=%d\n", Points);
#ifdef __APPLE__
    Undecorated = 1;
#endif    
    if (Undecorated)
      printf ("     --undecorated\n");
    if (Simple)
      printf ("     --simple\n");
    
    int x, y, height, width;
    wxClientDisplayRect (&x, &y, &width, &height);
    if (height < 1040)
      Undecorated = 1;
    printf ("     height=%d\n", height);
    fflush (stdout);

    if (Simple)
      {
      
	SimpleFrame->FontSize (Points);

	SetTopWindow(SimpleFrame);
    
	extern Swrite_t *SwritePtr;
	SwritePtr = SwriteTelemetrySimple;
	SimpleFrame->ClearScreen ();
	SimpleFrame->Timer = new TimerClass ();
	SimpleFrame->Timer->Start (PULSE_INTERVAL);
    
	SimpleFrame->Show();
	
      }
      
    else
    
      {

	MainFrame->FontSize (Points);
	if (Undecorated)
	  MainFrame->Undecorate ();

	SetTopWindow(MainFrame);
    
	extern Swrite_t *SwritePtr;
	SwritePtr = SwriteTelemetry;
	MainFrame->ClearScreen ();
	MainFrame->Timer = new TimerClass ();
	MainFrame->Timer->Start (PULSE_INTERVAL);
    
	MainFrame->Show();
    
      }
    return true;
}

SimpleFrameClass::SimpleFrameClass(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style):
    wxFrame(parent, id, title, pos, size, wxDEFAULT_FRAME_STYLE)
{
    // begin wxGlade: SimpleFrameClass::SimpleFrameClass
    panel_1 = new wxPanel(this, wxID_ANY);
    sizer_10_staticbox = new wxStaticBox(panel_1, -1, wxT("Change text size"));
    Bigger = new wxButton(panel_1, ID_BIGGER, wxT("Bigger"));
    Smaller = new wxButton(panel_1, ID_SMALLER, wxT("Smaller"));
    const wxString DecodingBox_choices[] = {
        wxT("Raw downlinked data"),
        wxT("MSK-683 (CM) CRT display"),
        wxT("MSK-966 (CM) CRT display"),
        wxT("MSK-1123 (LM) CRT display"),
        wxT("MSK-1137 (LM) CRT display")
    };
    DecodingBox = new wxRadioBox(panel_1, ID_DECODINGBOX, wxT("Downlink formatting"), wxDefaultPosition, wxDefaultSize, 5, DecodingBox_choices, 0, wxRA_SPECIFY_ROWS);
    TextCtrl = new wxStaticText(this, wxID_ANY, wxEmptyString);

    set_properties();
    do_layout();
    // end wxGlade
    
    MskType = 0;
    RowsToUse = TELEMETRY_ROWS;
}


BEGIN_EVENT_TABLE(SimpleFrameClass, wxFrame)
    // begin wxGlade: SimpleFrameClass::event_table
    EVT_BUTTON(ID_BIGGER, SimpleFrameClass::BiggerPressed)
    EVT_BUTTON(ID_SMALLER, SimpleFrameClass::SmallerPressed)
    EVT_RADIOBOX(ID_DECODINGBOX, SimpleFrameClass::FormattingBoxEvent)
    // end wxGlade
    EVT_CLOSE(SimpleFrameClass::TimerStop)
END_EVENT_TABLE();


// wxGlade: add SimpleFrameClass event handlers

void SimpleFrameClass::BiggerPressed(wxCommandEvent &event)
{
    FontSize (++Points);
    Fit ();
}


void SimpleFrameClass::SmallerPressed(wxCommandEvent &event)
{
    if (Points > 6)
      {
        FontSize (--Points);
	Fit ();
      }
}


void SimpleFrameClass::FormattingBoxEvent(wxCommandEvent &event)
{
  switch (DecodingBox->GetSelection ())
    {
    case 1: 
      MskType = 683 ; 
      ProcessDownlinkList = PrintMsk683;
      break;
    case 2: 
      MskType = 966 ; 
      ProcessDownlinkList = PrintMsk966;
      break;
    case 3: 
      MskType = 1123 ; 
      ProcessDownlinkList = PrintMsk1123;
      break;
    case 4: 
      MskType = 1137 ; 
      ProcessDownlinkList = PrintMsk1137;
      break;
    default:
      MskType = 0; 
      ProcessDownlinkList = PrintDownlinkList;
      break;
    }
  if (MskType)
    {
      // The MSK-type displays --- or at least, my verions of them ---
      // each have 33 rows.
      RowsToUse = 33;
    }
  else
    {
      // TELEMETRY_ROWS is the maximum possible number of 
      // screen rows, and was tailored for raw (lightly-formatted)
      // downlinked data.
      RowsToUse = TELEMETRY_ROWS;
    }
  ClearScreen ();
  Hide ();
  InvalidateBestSize ();
  Layout ();
  Fit ();
  Refresh ();
  Update ();
  Show ();
}


// wxGlade: add MainFramClass event handlers>
void MainFrameClass::TimerStop(wxCloseEvent &event)
{
  Timer->Stop ();
  delete Timer;
  event.Skip ();
  App->ExitMainLoop ();
}

void SimpleFrameClass::TimerStop(wxCloseEvent &event)
{
  Timer->Stop ();
  delete Timer;
  event.Skip ();
  App->ExitMainLoop ();
}

void SimpleFrameClass::set_properties()
{
    // begin wxGlade: SimpleFrameClass::set_properties
    SetTitle(wxT("yaTelemetry by Ron Burkey"));
    wxIcon _icon;
    _icon.CopyFromBitmap(wxBitmap(wxT("ApolloPatch2.png"), wxBITMAP_TYPE_ANY));
    SetIcon(_icon);
    Bigger->SetToolTip(wxT("Make text bigger by clicking this button."));
    Smaller->SetToolTip(wxT("Make text smaller by clicking this button."));
    DecodingBox->SetToolTip(wxT("Use this box to select how the on-screen downlinked telemetry data is formatted.  The MSK settings provide our approximations to the actual CRT displays used by Apollo Program ground-control CRTs.  The \"raw\" setting has little formatting but insures that all of the downlinked data is displayed."));
    DecodingBox->Enable(false);
    DecodingBox->SetSelection(0);
    panel_1->SetBackgroundColour(wxColour(255, 255, 255));
    TextCtrl->SetBackgroundColour(wxColour(255, 255, 255));
    TextCtrl->SetForegroundColour(wxColour(0, 0, 0));
    // end wxGlade
}


void SimpleFrameClass::do_layout()
{
    // begin wxGlade: SimpleFrameClass::do_layout
    wxBoxSizer* sizer_6 = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer* sizer_7 = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer* sizer_7_copy = new wxBoxSizer(wxHORIZONTAL);
    wxStaticBoxSizer* sizer_10 = new wxStaticBoxSizer(sizer_10_staticbox, wxHORIZONTAL);
    wxBoxSizer* sizer_11 = new wxBoxSizer(wxVERTICAL);
    sizer_7->Add(20, 10, 0, 0, 0);
    sizer_7_copy->Add(20, 20, 3, 0, 0);
    sizer_10->Add(20, 20, 0, wxADJUST_MINSIZE, 0);
    sizer_11->Add(20, 5, 1, wxADJUST_MINSIZE, 0);
    sizer_11->Add(Bigger, 0, 0, 0);
    sizer_11->Add(20, 5, 1, wxADJUST_MINSIZE, 0);
    sizer_11->Add(Smaller, 0, 0, 0);
    sizer_11->Add(20, 5, 1, wxADJUST_MINSIZE, 0);
    sizer_10->Add(sizer_11, 1, wxEXPAND, 0);
    sizer_10->Add(20, 20, 0, wxADJUST_MINSIZE, 0);
    sizer_7_copy->Add(sizer_10, 0, wxEXPAND, 0);
    sizer_7_copy->Add(10, 20, 1, 0, 0);
    sizer_7_copy->Add(DecodingBox, 0, wxADJUST_MINSIZE, 0);
    sizer_7_copy->Add(20, 20, 3, 0, 0);
    sizer_7->Add(sizer_7_copy, 0, wxEXPAND, 0);
    sizer_7->Add(20, 10, 0, 0, 0);
    panel_1->SetSizer(sizer_7);
    sizer_6->Add(panel_1, 0, wxEXPAND, 0);
    sizer_6->Add(TextCtrl, 1, wxEXPAND, 0);
    SetSizer(sizer_6);
    sizer_6->Fit(this);
    Layout();
    // end wxGlade
}


// Function and data structures to parse a buffered downlink list into 
// meaningful data fields.

typedef struct {
  int adot[3];
  int agsbuff[12];
  int agsk;
  int aig;
  int ak[3];
  int alfa180;
  int alphaq, alphar;
  int alt;
  int amg;
  int aog;
  int aotcode;
  int at;
  int besti, bestj;
  int beta180;
  int c32flwrd;
  int cadrflsh[3];
  int cdus;
  int cdux, cduy, cduz, cdut;
  int cduxd, cduyd, cduzd;
  int centang;
  int chan77;
  int chn11, chn12, chn13, chn14, chn30, chn31, chn32, chn33;
  int cmdapmod;
  int cm_epoch;
  int compnumb;
  int csmmass;
  int csteer;
  int dapbools;
  int dapdatr1, dapdatr2;
  int dellt4;
  int deltah;
  int deltar;
  int delv[3];
  int delveet[3], delveet1[3], delveet2[3], delveet3[3];
  int delvslv[3];
  int delvtpf;
  int diffalt;
  int dnlralt;
  int dnlrvelx, dnlrvely, dnlrvelz;
  int dnrange;
  int dnrrdot;
  int dsptb[6];
  int ecsteer;
  int eight_nn;
  int elev;
  int errorx, errory, errorz;
  int failreg[3];
  int fc;
  int gammaei;
  int gsav[3];
  int hapox;
  int hmeas;
  int holdflag;
  int hperx;
  int id;
  int igc;
  int imodes30, imodes33;
  int land[3];
  int landmark;
  int lastxcmd, lastycmd;
  int lat;
  int latang;
  int lat_spl;
  int launchaz;
  int lemmass;
  int lm_epoch;
  int lng_spl;
  int long_;
  int lrxcdudl, lrycdudl, lrzcdudl;
  int lrvtimdl;
  int l_d1;
  int mark2dwn[6];
  int markdown[6];
  int mgc;
  int mktime;
  int negtorku, negtorkv, negtorkp;
  int nn;
  int offset;
  int ogc;
  int omegap, omegaq, omegar;
  int omegapd, omegaqd, omegard;
  int option1, option2;
  int optmodes;
  int pactoff;
  int paxerr1;
  int pcmd;
  int pipax, pipay, pipaz;
  int piptime, piptime1;
  int postorku, postorkv, postorkp;
  int prel, qrel, rrel;
  int pseudo55;
  int radmodes;
  int range;
  int rangrdot;
  int rcsflags;
  int rdot;
  int redoctr;
  int refsmmat[6];
  int rgu[3];
  int rls[3];
  int rm;
  int rn[3];
  int rollc;
  int rolltm;
  int rrate;
  int rsbbq[2];
  int rtarg[3];
  int rtargx, rtargy, rtargz;
  int rtheta;
  int r_other[3];
  int starsav1[3], starsav2[3];
  int state[6];
  int svmrkdat[31];
  int sync;
  int talign;
  int tangnb[2];
  int tcdh;
  int tcsi;
  int tet;
  int tevent;
  int tgo;
  int thetad[3];
  int thetadx, thetady, thetadz;
  int thetah;
  int thetax, thetay, thetaz;
  int tig;
  int time;
  int tland;
  int tpass4;
  int trkmkcnt;
  int tte;
  int ttf8;
  int ttogo;
  int ttpf;
  int ttpi;
  int t_other;
  int unfc2[3];
  int upbuf[10];
  int upcount;
  int upoldmod;
  int upverb;
  int vgtig[3];
  int vgvect[2];
  int vgu[3];
  int vhfcount;
  int vhftime;
  int vtio;
  int vmeas;
  int vn[3];  
  int vpred;
  int vselect;
  int vtig[3];
  int v_other[3];
  int wbody[3];
  int x789[2];
  int yactoff;  
  int ycmd;
  int ynbsav[3];
  int zdotd;
  int znbsav[3];
} ParsedDownlinkList_t;
static ParsedDownlinkList_t ParsedDownlinkList;

void
ParseDownlinkList (const DownlinkListSpec_t *Spec)
{
}


// MSK-based replacements for the low-level function that prints a downlink list
// that has been buffered in memory.

void
PrintMsk683 (const DownlinkListSpec_t *Spec)
{
  ParseDownlinkList (Spec);

  int i;
  //sprintf (&Sbuffer[0][0], "%s", Spec->Title);
  for (i = 0; i < MAX_DOWNLINK_LIST; i++)
    {
      if (i && !Spec->FieldSpecs[i].IndexIntoList)
	break;		// End of field-list.
      //PrintField (&Spec->FieldSpecs[i]);
    }
}


void
PrintMsk966 (const DownlinkListSpec_t *Spec)
{
  ParseDownlinkList (Spec);
  
  int i;
  //sprintf (&Sbuffer[0][0], "%s", Spec->Title);
  for (i = 0; i < MAX_DOWNLINK_LIST; i++)
    {
      if (i && !Spec->FieldSpecs[i].IndexIntoList)
	break;		// End of field-list.
      //PrintField (&Spec->FieldSpecs[i]);
    }
}


void
PrintMsk1123 (const DownlinkListSpec_t *Spec)
{
  ParseDownlinkList (Spec);
  
  int i;
  //sprintf (&Sbuffer[0][0], "%s", Spec->Title);
  for (i = 0; i < MAX_DOWNLINK_LIST; i++)
    {
      if (i && !Spec->FieldSpecs[i].IndexIntoList)
	break;		// End of field-list.
      //PrintField (&Spec->FieldSpecs[i]);
    }
}


void
PrintMsk1137 (const DownlinkListSpec_t *Spec)
{
  ParseDownlinkList (Spec);


  int i;
  //sprintf (&Sbuffer[0][0], "%s", Spec->Title);
  for (i = 0; i < MAX_DOWNLINK_LIST; i++)
    {
      if (i && !Spec->FieldSpecs[i].IndexIntoList)
	break;		// End of field-list.
      //PrintField (&Spec->FieldSpecs[i]);
    }
}
























