Revision d33f3576dde18d9e177bfaaa75951d5527616e7a authored by Ron Burkey on 29 August 2016, 22:59:59 UTC, committed by Ron Burkey on 29 August 2016, 22:59:59 UTC
1 parent 154c67e
yaACA2.cpp
// -*- C++ -*- generated by wxGlade 0.6.3 on Mon Mar 16 15:10:36 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: yaACA2.cpp
Purpose: Apollo LM rotational hand-controller emulation module for
yaAGC.
Reference: http://www.ibiblio.org/apollo/index.html
Mode: 2009-03-19 RSB Began.
2009-03-22 RSB Removed strict dependence on wxJoystick, so
that Allegro or SDL joystick code could be
used, according to the command-line switches.
2009-03-23 RSB Correctly implemented END_OF_MAIN() so that
Allegro and wxWidgets can play together on
the Mac. (I hope!) Began trying to add
SDL support.
2009-04-09 RSB Backed out all Allegro and SDL stuff.
yaACA and yaACA3 are perfectly fine
Allegro and SDL programs, and I don't need
this stuff cluttering up yaACA2.
*/
#define VER(x) #x
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include "yaACA2.h"
#include "../yaAGC/yaAGC.h"
#include "../yaAGC/agc_engine.h"
#include <wx/file.h>
#include <wx/textfile.h>
// Interval (ms.) at which the timer fires for servicing the socket.
#define PULSE_INTERVAL 100
static yaAcaFrameClass* yaAcaFrame;
static char DefaultHostname[] = "localhost";
static char *Hostname = DefaultHostname;
static char NonDefaultHostname[129];
#ifdef WIN32
static int StartupDelay = 500;
#else
static int StartupDelay = 0;
#endif
extern int Portnum;
static int ServerSocket = -1, LastServerSocket = -1;
static int ControllerNumber = 0;
static int JoystickConnectionTimeout = 0;
// begin wxGlade: ::extracode
// end wxGlade
// Sets parameters to all defaults. These parameters are
// for my Logitech 3D Extreme.
void
yaAcaFrameClass::DefaultParameters (void)
{
Roll.Axis = AXIS_X;
Roll.PositiveSense = true;
Pitch.Axis = AXIS_Y;
Pitch.PositiveSense = true;
#if defined (WIN32)
Yaw.Axis = AXIS_RUDDER;
#elif defined (__APPLE__)
Yaw.Axis = AXIS_U;
#else // Linux
Yaw.Axis = AXIS_Z;
#endif
Yaw.PositiveSense = false;
}
// Gets parameters from a cfg file if available, from defaults otherwise.
void
yaAcaFrameClass::GetParameters (int ControllerNumber)
{
DefaultParameters ();
wxTextFile File;
wxString Filename;
Filename = wxString::Format (wxT ("yaACA2-%d.cfg"), ControllerNumber);
if (wxFileExists (Filename))
{
wxString Dummy, Name, Value;
int LineCount, i;
long iValue;
File.Open (Filename);
LineCount = File.GetLineCount ();
for (i = 0; i < LineCount; i++)
{
Dummy = File.GetLine (i);
Name = Dummy.BeforeLast ('=');
Value = Dummy.AfterLast ('=');
if (!Value.ToLong (&iValue))
iValue = 0;
if (Name.IsSameAs (wxT ("Roll.Axis")))
Roll.Axis = iValue;
else if (Name.IsSameAs (wxT ("Roll.PositiveSense")))
Roll.PositiveSense = (iValue == 0);
else if (Name.IsSameAs (wxT ("Pitch.Axis")))
Pitch.Axis = iValue;
else if (Name.IsSameAs (wxT ("Pitch.PositiveSense")))
Pitch.PositiveSense = (iValue == 0);
else if (Name.IsSameAs (wxT ("Yaw.Axis")))
Yaw.Axis = iValue;
else if (Name.IsSameAs (wxT ("Yaw.PositiveSense")))
Yaw.PositiveSense = (iValue == 0);
}
File.Close ();
}
}
// Writes parameters to a cfg file.
void
yaAcaFrameClass:: WriteParameters (int ControllerNumber)
{
wxFile File;
wxString Filename;
Filename = wxString::Format (wxT ("yaACA2-%d.cfg"), ControllerNumber);
if (File.Create (Filename, true))
{
wxString Dummy;
Dummy = wxString::Format (wxT ("Roll.Axis=%d\n"), Roll.Axis);
File.Write (Dummy);
Dummy = wxString::Format (wxT ("Roll.PositiveSense=%d\n"), Roll.PositiveSense ? 0 : 1);
File.Write (Dummy);
Dummy = wxString::Format (wxT ("Pitch.Axis=%d\n"), Pitch.Axis);
File.Write (Dummy);
Dummy = wxString::Format (wxT ("Pitch.PositiveSense=%d\n"), Pitch.PositiveSense ? 0 : 1);
File.Write (Dummy);
Dummy = wxString::Format (wxT ("Yaw.Axis=%d\n"), Yaw.Axis);
File.Write (Dummy);
Dummy = wxString::Format (wxT ("Yaw.PositiveSense=%d\n"), Yaw.PositiveSense ? 0 : 1);
File.Write (Dummy);
File.Close ();
}
else
{
Filename = wxT ("Cannot create file ") + Filename + wxT (".\nConfiguration not saved.");
wxMessageBox (Filename, wxT ("Error"), wxICON_ERROR);
}
}
yaAcaFrameClass::yaAcaFrameClass(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style):
wxFrame(parent, id, title, pos, size, wxDEFAULT_FRAME_STYLE|wxCLOSE_BOX)
{
GetParameters (ControllerNumber);
Roll.CurrentAdjustedReading = 0;
Roll.LastRawReading = 0;
Pitch.CurrentAdjustedReading = 0;
Pitch.LastRawReading = 0;
Yaw.CurrentAdjustedReading = 0;
Yaw.LastRawReading = 0;
// begin wxGlade: yaAcaFrameClass::yaAcaFrameClass
StatusPanel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER|wxTAB_TRAVERSAL);
ControllerPositionPanel_copy_1 = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER|wxTAB_TRAVERSAL);
ControllerPositionPanel_copy = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER|wxTAB_TRAVERSAL);
ControllerPitchPanel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER|wxTAB_TRAVERSAL);
panel_1 = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER|wxTAB_TRAVERSAL);
ModelPanel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER|wxTAB_TRAVERSAL);
ControllerNumberPanel = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER|wxTAB_TRAVERSAL);
ControllerSizer_staticbox = new wxStaticBox(this, -1, wxT("Joystick Controller"));
RollBox_staticbox = new wxStaticBox(this, -1, wxT("Roll Axis Configuration"));
PitchBox_staticbox = new wxStaticBox(this, -1, wxT("Pitch Axis Configuration"));
YawBox_staticbox = new wxStaticBox(this, -1, wxT("Yaw Axis Configuration"));
panel_2 = new wxPanel(this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER|wxTAB_TRAVERSAL);
label_4 = new wxStaticText(this, wxID_ANY, wxT("Drivers: "));
ToolkitLabel = new wxStaticText(panel_2, wxID_ANY, wxT("0 (wxWidgets)"));
label_1 = new wxStaticText(this, wxID_ANY, wxT("Controller: "));
ControllerNumberLabel = new wxStaticText(ControllerNumberPanel, wxID_ANY, wxT("0"));
label_1_copy_3 = new wxStaticText(this, wxID_ANY, wxT("Model: "));
ControllerModelLabel = new wxStaticText(ModelPanel, wxID_ANY, wxT("(no joystick controller attached)"));
label_3 = new wxStaticText(this, wxID_ANY, wxT("Axes: "));
BoxAxis0 = new wxCheckBox(panel_1, wxID_ANY, wxT("0"));
BoxAxis1 = new wxCheckBox(panel_1, wxID_ANY, wxT("1"));
BoxAxis2 = new wxCheckBox(panel_1, wxID_ANY, wxT("2"));
BoxAxis3 = new wxCheckBox(panel_1, wxID_ANY, wxT("3"));
BoxAxis4 = new wxCheckBox(panel_1, wxID_ANY, wxT("4"));
BoxAxis5 = new wxCheckBox(panel_1, wxID_ANY, wxT("5"));
BoxAxis6 = new wxCheckBox(panel_1, wxID_ANY, wxT("6"));
label_1_copy_1 = new wxStaticText(this, wxID_ANY, wxT("Pitch: "));
ControllerPitchLabel = new wxStaticText(ControllerPitchPanel, wxID_ANY, wxT("0"));
label_1_copy_4 = new wxStaticText(this, wxID_ANY, wxT("Roll: "));
ControllerRollLabel = new wxStaticText(ControllerPositionPanel_copy, wxID_ANY, wxT("0"));
label_1_copy = new wxStaticText(this, wxID_ANY, wxT("Yaw: "));
ControllerYawLabel = new wxStaticText(ControllerPositionPanel_copy_1, wxID_ANY, wxT("0"));
label_2 = new wxStaticText(this, wxID_ANY, wxT("Axis number: "));
RollAxisCtrl = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 6);
const wxString RollPolarityBox_choices[] = {
wxT("Positive"),
wxT("Negative")
};
RollPolarityBox = new wxRadioBox(this, wxID_ANY, wxT("Polarity"), wxDefaultPosition, wxDefaultSize, 2, RollPolarityBox_choices, 0, wxRA_SPECIFY_ROWS);
label_2_copy = new wxStaticText(this, wxID_ANY, wxT("Axis number: "));
PitchAxisCtrl = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 6);
const wxString PitchPolarityBox_choices[] = {
wxT("Positive"),
wxT("Negative")
};
PitchPolarityBox = new wxRadioBox(this, wxID_ANY, wxT("Polarity"), wxDefaultPosition, wxDefaultSize, 2, PitchPolarityBox_choices, 0, wxRA_SPECIFY_ROWS);
label_2_copy_1 = new wxStaticText(this, wxID_ANY, wxT("Axis number: "));
YawAxisCtrl = new wxSpinCtrl(this, wxID_ANY, wxT("0"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 6);
const wxString YawPolarityBox_choices[] = {
wxT("Positive"),
wxT("Negative")
};
YawPolarityBox = new wxRadioBox(this, wxID_ANY, wxT("Polarity"), wxDefaultPosition, wxDefaultSize, 2, YawPolarityBox_choices, 0, wxRA_SPECIFY_ROWS);
DefaultButton = new wxButton(this, ID_DEFAULT, wxT("Default"));
SetButton = new wxButton(this, ID_SET, wxT("Set"));
StatusLabel = new wxStaticText(StatusPanel, wxID_ANY, wxT("Waiting for connection to yaAGC ..."));
set_properties();
do_layout();
// end wxGlade
RollAxisCtrl->SetValue (Roll.Axis);
RollPolarityBox->SetSelection (Roll.PositiveSense ? 0 : 1);
PitchAxisCtrl->SetValue (Pitch.Axis);
PitchPolarityBox->SetSelection (Pitch.PositiveSense ? 0 : 1);
YawAxisCtrl->SetValue (Yaw.Axis);
YawPolarityBox->SetSelection (Yaw.PositiveSense ? 0 : 1);
ToolkitLabel->SetLabel (wxT ("wxWidgets"));
wxString Dummy = wxString::Format (wxT ("%d"), ControllerNumber);
ControllerNumberLabel->SetLabel (Dummy);
ControllerModelLabel->SetLabel (wxT ("(no joystick controller attached)"));
ControllerRollLabel->SetLabel (wxT ("(none)"));
ControllerPitchLabel->SetLabel (wxT ("(none)"));
ControllerYawLabel->SetLabel (wxT ("(none)"));
BoxAxis0->SetValue (false);
BoxAxis1->SetValue (false);
BoxAxis2->SetValue (false);
BoxAxis3->SetValue (false);
BoxAxis4->SetValue (false);
BoxAxis5->SetValue (false);
BoxAxis6->SetValue (false);
}
BEGIN_EVENT_TABLE(yaAcaFrameClass, wxFrame)
// begin wxGlade: yaAcaFrameClass::event_table
EVT_BUTTON(ID_DEFAULT, yaAcaFrameClass::OnDefaultPressed)
EVT_BUTTON(ID_SET, yaAcaFrameClass::OnSetPressed)
// end wxGlade
EVT_CLOSE(yaAcaFrameClass::TimerStop)
END_EVENT_TABLE();
// wxGlade: add yaAcaFrameClass event handlers
void yaAcaFrameClass::OnDefaultPressed (wxCommandEvent &event)
{
DefaultParameters ();
RollAxisCtrl->SetValue (Roll.Axis);
RollPolarityBox->SetSelection (Roll.PositiveSense ? 0 : 1);
PitchAxisCtrl->SetValue (Pitch.Axis);
PitchPolarityBox->SetSelection (Pitch.PositiveSense ? 0 : 1);
YawAxisCtrl->SetValue (Yaw.Axis);
YawPolarityBox->SetSelection (Yaw.PositiveSense ? 0 : 1);
WriteParameters (ControllerNumber);
}
void yaAcaFrameClass::OnSetPressed (wxCommandEvent &event)
{
Roll.Axis = RollAxisCtrl->GetValue ();
Roll.PositiveSense = (RollPolarityBox->GetSelection () == 0);
Pitch.Axis = PitchAxisCtrl->GetValue ();
Pitch.PositiveSense = (PitchPolarityBox->GetSelection () == 0);
Yaw.Axis = YawAxisCtrl->GetValue ();
Yaw.PositiveSense = (YawPolarityBox->GetSelection () == 0);
WriteParameters (ControllerNumber);
}
void yaAcaFrameClass::set_properties()
{
// begin wxGlade: yaAcaFrameClass::set_properties
SetTitle(wxT("yaACA2 by Ron Burkey"));
wxIcon _icon;
_icon.CopyFromBitmap(wxBitmap(wxT("ApolloPatch2.png"), wxBITMAP_TYPE_ANY));
SetIcon(_icon);
SetBackgroundColour(wxColour(255, 255, 255));
BoxAxis0->Enable(false);
BoxAxis0->SetValue(1);
BoxAxis1->Enable(false);
BoxAxis1->SetValue(1);
BoxAxis2->Enable(false);
BoxAxis3->Enable(false);
BoxAxis4->Enable(false);
BoxAxis5->Enable(false);
BoxAxis6->Enable(false);
RollAxisCtrl->SetToolTip(wxT("For a joystick controller that has multiple degrees of freedom, it's necessary to select which such dimension is associate with pitch, with roll, and with yaw. A different degree of freedom is associated wtih each. This setting does not take effect until the \"Set\" button is clicked."));
RollPolarityBox->SetToolTip(wxT("Determine whether which direction is \"positive\" and which is \"negative\"."));
RollPolarityBox->SetSelection(0);
PitchAxisCtrl->SetToolTip(wxT("For a joystick controller that has multiple degrees of freedom, it's necessary to select which such dimension is associate with pitch, with roll, and with yaw. A different degree of freedom is associated wtih each. This setting does not take effect until the \"Set\" button is clicked."));
PitchPolarityBox->SetToolTip(wxT("Determine whether which direction is \"positive\" and which is \"negative\"."));
PitchPolarityBox->SetSelection(0);
YawAxisCtrl->SetToolTip(wxT("For a joystick controller that has multiple degrees of freedom, it's necessary to select which such dimension is associate with pitch, with roll, and with yaw. A different degree of freedom is associated wtih each. This setting does not take effect until the \"Set\" button is clicked."));
YawPolarityBox->SetToolTip(wxT("Determine whether which direction is \"positive\" and which is \"negative\"."));
YawPolarityBox->SetSelection(0);
DefaultButton->SetToolTip(wxT("Click this to restore the defaults. The new settings go into effect as soon as this button is clicked."));
SetButton->SetToolTip(wxT("Click this to accept the settings above. The settings do not take effect until this button is clicked."));
// end wxGlade
}
void yaAcaFrameClass::do_layout()
{
// begin wxGlade: yaAcaFrameClass::do_layout
wxFlexGridSizer* TopSizer = new wxFlexGridSizer(6, 3, 0, 0);
wxBoxSizer* StatusSizer = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* sizer_6 = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* ControllerBox = new wxBoxSizer(wxVERTICAL);
wxStaticBoxSizer* YawBox = new wxStaticBoxSizer(YawBox_staticbox, wxVERTICAL);
wxBoxSizer* sizer_1_copy_1 = new wxBoxSizer(wxHORIZONTAL);
wxStaticBoxSizer* PitchBox = new wxStaticBoxSizer(PitchBox_staticbox, wxVERTICAL);
wxBoxSizer* sizer_1_copy = new wxBoxSizer(wxHORIZONTAL);
wxStaticBoxSizer* RollBox = new wxStaticBoxSizer(RollBox_staticbox, wxVERTICAL);
wxBoxSizer* sizer_1 = new wxBoxSizer(wxHORIZONTAL);
wxStaticBoxSizer* ControllerSizer = new wxStaticBoxSizer(ControllerSizer_staticbox, wxVERTICAL);
wxFlexGridSizer* grid_sizer_1 = new wxFlexGridSizer(6, 2, 0, 0);
wxBoxSizer* ControllerPositionSizer_copy_1 = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* ControllerPositionSizer_copy = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* ControllerPositionSizer = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* sizer_2 = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* sizer_2_copy = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* ModelSizer = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* ModelSizer_copy = new wxBoxSizer(wxHORIZONTAL);
wxBoxSizer* sizer_3 = new wxBoxSizer(wxHORIZONTAL);
TopSizer->Add(20, 10, 0, 0, 0);
TopSizer->Add(20, 10, 0, 0, 0);
TopSizer->Add(20, 10, 0, 0, 0);
TopSizer->Add(20, 20, 0, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0);
grid_sizer_1->Add(label_4, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 0);
sizer_3->Add(ToolkitLabel, 1, wxEXPAND, 0);
panel_2->SetSizer(sizer_3);
grid_sizer_1->Add(panel_2, 1, wxEXPAND, 0);
grid_sizer_1->Add(label_1, 0, wxALIGN_RIGHT, 0);
ModelSizer_copy->Add(ControllerNumberLabel, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0);
ControllerNumberPanel->SetSizer(ModelSizer_copy);
grid_sizer_1->Add(ControllerNumberPanel, 1, wxEXPAND, 0);
grid_sizer_1->Add(label_1_copy_3, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 0);
ModelSizer->Add(ControllerModelLabel, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0);
ModelPanel->SetSizer(ModelSizer);
grid_sizer_1->Add(ModelPanel, 1, wxEXPAND, 0);
grid_sizer_1->Add(label_3, 0, wxALIGN_RIGHT, 0);
sizer_2_copy->Add(BoxAxis0, 0, 0, 0);
sizer_2_copy->Add(BoxAxis1, 0, 0, 0);
sizer_2_copy->Add(BoxAxis2, 0, 0, 0);
sizer_2_copy->Add(BoxAxis3, 0, 0, 0);
sizer_2_copy->Add(BoxAxis4, 0, 0, 0);
sizer_2_copy->Add(BoxAxis5, 0, 0, 0);
sizer_2_copy->Add(BoxAxis6, 0, 0, 0);
sizer_2->Add(sizer_2_copy, 1, wxEXPAND, 0);
panel_1->SetSizer(sizer_2);
grid_sizer_1->Add(panel_1, 1, wxEXPAND, 0);
grid_sizer_1->Add(label_1_copy_1, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 0);
ControllerPositionSizer->Add(ControllerPitchLabel, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0);
ControllerPitchPanel->SetSizer(ControllerPositionSizer);
grid_sizer_1->Add(ControllerPitchPanel, 1, wxEXPAND, 0);
grid_sizer_1->Add(label_1_copy_4, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 0);
ControllerPositionSizer_copy->Add(ControllerRollLabel, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0);
ControllerPositionPanel_copy->SetSizer(ControllerPositionSizer_copy);
grid_sizer_1->Add(ControllerPositionPanel_copy, 1, wxEXPAND, 0);
grid_sizer_1->Add(label_1_copy, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL, 0);
ControllerPositionSizer_copy_1->Add(ControllerYawLabel, 1, wxEXPAND|wxALIGN_CENTER_VERTICAL, 0);
ControllerPositionPanel_copy_1->SetSizer(ControllerPositionSizer_copy_1);
grid_sizer_1->Add(ControllerPositionPanel_copy_1, 1, wxEXPAND, 0);
ControllerSizer->Add(grid_sizer_1, 1, wxEXPAND|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 0);
ControllerBox->Add(ControllerSizer, 1, wxEXPAND, 0);
ControllerBox->Add(20, 20, 0, 0, 0);
sizer_1->Add(label_2, 0, wxALIGN_CENTER_VERTICAL, 0);
sizer_1->Add(RollAxisCtrl, 0, 0, 0);
RollBox->Add(sizer_1, 0, wxALIGN_CENTER_HORIZONTAL, 0);
RollBox->Add(RollPolarityBox, 0, wxALIGN_CENTER_HORIZONTAL, 0);
ControllerBox->Add(RollBox, 0, wxEXPAND, 0);
ControllerBox->Add(20, 20, 0, 0, 0);
sizer_1_copy->Add(label_2_copy, 0, wxALIGN_CENTER_VERTICAL, 0);
sizer_1_copy->Add(PitchAxisCtrl, 0, 0, 0);
PitchBox->Add(sizer_1_copy, 0, wxALIGN_CENTER_HORIZONTAL, 0);
PitchBox->Add(PitchPolarityBox, 0, wxALIGN_CENTER_HORIZONTAL, 0);
ControllerBox->Add(PitchBox, 0, wxEXPAND, 0);
ControllerBox->Add(20, 20, 0, 0, 0);
sizer_1_copy_1->Add(label_2_copy_1, 0, wxALIGN_CENTER_VERTICAL, 0);
sizer_1_copy_1->Add(YawAxisCtrl, 0, 0, 0);
YawBox->Add(sizer_1_copy_1, 0, wxALIGN_CENTER_HORIZONTAL, 0);
YawBox->Add(YawPolarityBox, 0, wxALIGN_CENTER_HORIZONTAL, 0);
ControllerBox->Add(YawBox, 0, wxEXPAND, 0);
TopSizer->Add(ControllerBox, 1, wxEXPAND, 0);
TopSizer->Add(20, 20, 0, 0, 0);
TopSizer->Add(20, 20, 0, 0, 0);
TopSizer->Add(20, 20, 0, 0, 0);
TopSizer->Add(20, 20, 0, 0, 0);
TopSizer->Add(20, 20, 0, 0, 0);
sizer_6->Add(20, 20, 1, 0, 0);
sizer_6->Add(DefaultButton, 0, 0, 0);
sizer_6->Add(20, 20, 0, 0, 0);
sizer_6->Add(SetButton, 0, 0, 0);
sizer_6->Add(20, 20, 1, 0, 0);
TopSizer->Add(sizer_6, 1, wxEXPAND, 0);
TopSizer->Add(20, 20, 0, 0, 0);
TopSizer->Add(20, 20, 0, 0, 0);
TopSizer->Add(20, 20, 0, 0, 0);
TopSizer->Add(20, 20, 0, 0, 0);
TopSizer->Add(20, 20, 0, 0, 0);
StatusSizer->Add(StatusLabel, 0, 0, 0);
StatusPanel->SetSizer(StatusSizer);
TopSizer->Add(StatusPanel, 1, wxEXPAND, 0);
TopSizer->Add(20, 20, 0, 0, 0);
SetSizer(TopSizer);
TopSizer->Fit(this);
Layout();
// end wxGlade
}
class yaAcaAppClass: public wxApp {
public:
bool OnInit();
};
IMPLEMENT_APP(yaAcaAppClass)
static wxApp *App;
bool yaAcaAppClass::OnInit()
{
int i;
App = this;
printf ("yaACA2 Apollo ACA simulation, ver " VER(NVER) ", built " __DATE__ " " __TIME__ "\n");
printf ("Copyright 2009 by Ronald S. Burkey\n");
printf ("Refer to http://www.ibiblio.org/apollo/index.html for more information.\n");
Portnum = 19803;
for (i = 1; i < argc; i++)
{
wxString Arg = argv[i];
wxString ArgStart = Arg.BeforeFirst ('=');
wxString ArgEnd = Arg.AfterFirst ('=');
if (ArgStart.IsSameAs (wxT ("--ip")))
{
strcpy (NonDefaultHostname, ArgEnd.char_str ());
Hostname = NonDefaultHostname;
}
else if (ArgStart.IsSameAs (wxT ("--port")))
{
long lPortnum;
ArgEnd.ToLong (&lPortnum);
Portnum = lPortnum;
if (Portnum <= 0 || Portnum >= 0x10000)
{
printf ("The --port switch is out of range. Must be 1-64K.\n");
goto Help;
}
}
else if (ArgStart.IsSameAs (wxT ("--delay")))
{
long lj;
ArgEnd.ToLong (&lj);
StartupDelay = lj;
}
else if (ArgStart.IsSameAs (wxT ("--controller")))
{
long lj;
ArgEnd.ToLong (&lj);
if (lj < 0 || lj > 1)
{
wxMessageBox (wxT ("Only --controller=0 and --controller=1 are allowed."),
wxT ("Error"), wxICON_ERROR);
goto Help;
}
else
ControllerNumber = lj;
}
else
{
Help:
printf ("USAGE:\n");
printf ("\tyaACA2 [OPTIONS]\n");
printf ("The available options are:\n");
printf ("--ip=Hostname\n");
printf ("\tThe yaACA2 program and the yaAGC Apollo Guidance Computer simulation\n");
printf ("\texist in a \"client/server\" relationship, in which the yaACA2 program\n");
printf ("\tneeds to be aware of the IP address or symbolic name of the host \n");
printf ("\tcomputer running the yaAGC program. By default, this is \"localhost\",\n");
printf ("\tmeaning that both yaACA2 and yaAGC are running on the same computer.\n");
printf ("--port=Portnumber\n");
printf ("\tBy default, yaACA2 attempts to connect to the yaAGC program using port\n");
printf ("\tnumber %d. However, if more than one instance of yaACA2 is being\n",
Portnum);
printf ("\trun, or if yaAGC has been configured to listen on different ports, then\n");
printf ("\tdifferent port settings for yaACA2 are needed. Note that by default,\n");
printf ("\tyaAGC listens for new connections on ports %d-%d.\n",
19697, 19697 + 10 - 1);
printf ("--delay=N\n");
printf ("\t\"Start-up delay\", in ms. Defaults to %d. What the start-up\n", StartupDelay);
printf ("\tdelay does is to prevent yaACA2 from attempting to communicate with\n");
printf ("\tyaAGC for a brief time after power-up. This option is really only\n");
printf ("\tuseful in Win32, to work around a problem with race-conditions at\n");
printf ("\tstart-up.\n");
printf ("--roll=...\n");
printf ("--pitch=...\n");
printf ("--yaw=...\n");
printf ("\tThese options are accepted for backward-compatibility with yaACA, the\n");
printf ("\tpredecessor to yaACA2, but are ignored.\n");
printf ("--controller=N\n");
printf ("\tIn case there are two joystick controllers attached, this allows\n");
printf ("\tselection of just one of them. The default is N=0, but N=1 is also\n");
printf ("\tallowed. If there are more than two attached, only the first two can\n");
printf ("\tbe accessed.\n");
exit (1);
}
}
wxInitAllImageHandlers();
yaAcaFrame = new yaAcaFrameClass(NULL, wxID_ANY, wxEmptyString);
SetTopWindow(yaAcaFrame);
yaAcaFrame->Timer = new TimerClass ();
yaAcaFrame->Timer->Initialization = 0;
yaAcaFrame->Timer->Start (PULSE_INTERVAL);
yaAcaFrame->Show();
return true;
}
// This function translates a raw joystick reading to the -57..+57 range expected by AGC.
void
TimerClass::Translate (Axis_t *AxisPtr)
{
int i, Axis;
bool PositiveSense;
if (Initialization < 2)
i = 0;
else
{
i = AxisPtr->LastRawReading;
Axis = AxisPtr->Axis;
PositiveSense = AxisPtr->PositiveSense;
// Center around midpoint.
i -= Axes[Axis].Midpoint;
// Polarity.
if (!PositiveSense)
i = -i;
// Cut out the deadzone around the midpoint.
if (i > 0)
{
i -= Axes[Axis].Deadzone;
if (i < 0)
i = 0;
}
else if (i < 0)
{
i += Axes[Axis].Deadzone;
if (i > 0)
i = 0;
}
// Scale.
i /= Axes[Axis].Divisor;
// Sanity check.
if (i > 57)
i = 57;
else if (i < -57)
i = -57;
}
// Output!
AxisPtr->CurrentAdjustedReading = i;
}
void yaAcaFrameClass::TimerStop(wxCloseEvent &event)
{
Timer->Stop ();
delete Timer;
//event.Skip ();
Close ();
}
//-------------------------------------------------------------------------
// This function is called every PULSE_INTERVAL milliseconds. It manages
// the server connection, and causes display-updates based on input from
// yaAGC.
void
TimerClass::Notify ()
{
int i;
// Service the joystick. In all cases, the idea here is that yaAcaFrame's
// Roll, Pitch, and Yaw structures are updated with current information
// with respect to the joystick hardware and/or joystick drivers.
ServiceJoystick_wxWidgets ();
// Convert the readings to the form expected by yaAcaFrame, update screen,
// output to yaAGC.
yaAcaFrame->UpdateJoystick ();
// Service the socket connection.
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 ("yaACA2 is connected, socket=%d.\n", ServerSocket);
}
if (ServerSocket != LastServerSocket)
{
if (ServerSocket == -1)
yaAcaFrame->StatusLabel->SetLabel (wxT ("Waiting for connection to yaAGC ..."));
else
yaAcaFrame->StatusLabel->SetLabel (wxT ("Connected to yaAGC"));
LastServerSocket = ServerSocket;
}
}
// Service the joystick using the wxWidgets toolkit.
void
TimerClass::ServiceJoystick_wxWidgets (void)
{
static wxJoystick *Joystick = NULL;
int i;
// If no joystick has been attached yet, then try to attach one. There is,
// unfortunately, no corresponding method of determining that the joystick
// has become *disconnected*, since Joystick->IsOk() seems to stubbornly keep
// returning whatever value it had when the wxJoystick object was created.
// We only check for connections about once per second.
if (Joystick == NULL) // No joystick found so far?
{
if (JoystickConnectionTimeout <= 0)
{
JoystickConnectionTimeout = 1000;
if (ControllerNumber == 0)
Joystick = new wxJoystick (wxJOYSTICK1);
else
Joystick = new wxJoystick (wxJOYSTICK2);
if (!Joystick->IsOk ())
{
delete Joystick;
Joystick = NULL;
}
else
{
// Get the parameters of the joystick controller.
yaAcaFrame->ControllerModelLabel->SetLabel (Joystick->GetProductName ());
i = 0;
Axes[i].Has = true;
yaAcaFrame->BoxAxis0->SetValue (true);
Axes[i].Minimum = Joystick->GetXMin ();
Axes[i].Maximum = Joystick->GetXMax ();
Axes[i].CurrentRawReading = 0;
i++;
yaAcaFrame->BoxAxis1->SetValue (true);
Axes[i].Has = true;
Axes[i].Minimum = Joystick->GetYMin ();
Axes[i].Maximum = Joystick->GetYMax ();
Axes[i].CurrentRawReading = 0;
i++;
Axes[i].Has = Joystick->HasZ ();
if (Axes[i].Has)
{
yaAcaFrame->BoxAxis2->SetValue (true);
Axes[i].Minimum = Joystick->GetZMin ();
Axes[i].Maximum = Joystick->GetZMax ();
}
Axes[i].CurrentRawReading = 0;
i++;
Axes[i].Has = Joystick->HasU ();
if (Axes[i].Has)
{
yaAcaFrame->BoxAxis3->SetValue (true);
Axes[i].Minimum = Joystick->GetUMin ();
Axes[i].Maximum = Joystick->GetUMax ();
}
Axes[i].CurrentRawReading = 0;
i++;
Axes[i].Has = Joystick->HasV ();
if (Axes[i].Has)
{
yaAcaFrame->BoxAxis4->SetValue (true);
Axes[i].Minimum = Joystick->GetVMin ();
Axes[i].Maximum = Joystick->GetVMax ();
}
Axes[i].CurrentRawReading = 0;
i++;
Axes[i].Has = Joystick->HasRudder ();
if (Axes[i].Has)
{
yaAcaFrame->BoxAxis5->SetValue (true);
Axes[i].Minimum = Joystick->GetRudderMin ();
Axes[i].Maximum = Joystick->GetRudderMax ();
}
Axes[i].CurrentRawReading = 0;
i++;
Axes[i].Has = Joystick->HasPOVCTS ();
if (Axes[i].Has)
{
yaAcaFrame->BoxAxis6->SetValue (true);
Axes[i].Minimum = 0;
Axes[i].Maximum = 35999;
}
Axes[i].CurrentRawReading = 0;
// Compute parameters that derive from Maximum and Minimum.
for (i = 0; i < NUM_AXES; i++)
if (Axes[i].Has)
{
Axes[i].Midpoint = (Axes[i].Minimum + Axes[i].Maximum) / 2;
Axes[i].Deadzone = (Axes[i].Maximum - Axes[i].Minimum) / 20;
Axes[i].Divisor = ((Axes[i].Maximum - Axes[i].Minimum) * 9 + 10 * 57) / (20 * 57);
}
else
{
Axes[i].Midpoint = 0;
Axes[i].Deadzone = 13;
Axes[i].Divisor = 2;
}
// Make the current position will update ASAP.
yaAcaFrame->Roll.LastRawReading = 100000;
yaAcaFrame->Pitch.LastRawReading = 100000;
yaAcaFrame->Yaw.LastRawReading = 100000;
#ifndef __APPLE__
// For reasons I can't fathom, this causes the entire frame to
// blank out on Mac OS X.
yaAcaFrame->Hide ();
yaAcaFrame->Fit ();
yaAcaFrame->Show ();
#endif
Initialization = 2;
}
}
else
{
JoystickConnectionTimeout -= PULSE_INTERVAL;
}
}
// Find the current position.
if (Joystick != NULL)
{
// Read all of the axes.
wxPoint Position;
Position = Joystick->GetPosition ();
Axes[AXIS_X].CurrentRawReading = Position.x;
Axes[AXIS_Y].CurrentRawReading = Position.y;
if (Axes[AXIS_Z].Has)
Axes[AXIS_Z].CurrentRawReading = Joystick->GetZPosition ();
if (Axes[AXIS_U].Has)
Axes[AXIS_U].CurrentRawReading = Joystick->GetUPosition ();
if (Axes[AXIS_V].Has)
Axes[AXIS_V].CurrentRawReading = Joystick->GetVPosition ();
if (Axes[AXIS_RUDDER].Has)
Axes[AXIS_RUDDER].CurrentRawReading = Joystick->GetRudderPosition ();
}
}
// Output joystick positions to yaAGC.
static void
OutputTranslated (int Channel, int Value)
{
unsigned char Packet[4];
int j;
if (ServerSocket == -1)
return;
if (Value < 0) // Make negative values 1's-complement.
Value = (077777 & (~(-Value)));
FormIoPacket (Channel, Value, Packet);
j = send (ServerSocket, (const char *) Packet, 4, MSG_NOSIGNAL);
if (j == SOCKET_ERROR && SOCKET_BROKEN)
{
close (ServerSocket);
ServerSocket = -1;
fprintf (stdout, "\nServer connection lost.\n");
}
}
// Update screen and/or output changed joystick data to yaAGC.
void
yaAcaFrameClass::UpdateJoystick (void)
{
static int LastAdjustedRoll = 1000, LastAdjustedPitch = 1000, LastAdjustedYaw = 1000;
static int Last31 = -1;
int New31, j;
if (Roll.LastRawReading != Timer->Axes[Roll.Axis].CurrentRawReading)
{
Roll.LastRawReading = Timer->Axes[Roll.Axis].CurrentRawReading;
Timer->Translate (&Roll);
ControllerRollLabel->SetLabel (wxString::Format (wxT ("%d"), Roll.CurrentAdjustedReading));
}
if (Pitch.LastRawReading != Timer->Axes[Pitch.Axis].CurrentRawReading)
{
Pitch.LastRawReading = Timer->Axes[Pitch.Axis].CurrentRawReading;
Timer->Translate (&Pitch);
ControllerPitchLabel->SetLabel (wxString::Format (wxT ("%d"), Pitch.CurrentAdjustedReading));
}
if (Yaw.LastRawReading != Timer->Axes[Yaw.Axis].CurrentRawReading)
{
Yaw.LastRawReading = Timer->Axes[Yaw.Axis].CurrentRawReading;
Timer->Translate (&Yaw);
ControllerYawLabel->SetLabel (wxString::Format (wxT ("%d"), Yaw.CurrentAdjustedReading));
}
// Report to yaAGC.
New31 = 077777;
if (Roll.CurrentAdjustedReading < 0)
New31 &= ~040040;
else if (Roll.CurrentAdjustedReading > 0)
New31 &= ~040020;
if (Yaw.CurrentAdjustedReading < 0)
New31 &= ~040010;
else if (Yaw.CurrentAdjustedReading > 0)
New31 &= ~040004;
if (Pitch.CurrentAdjustedReading < 0)
New31 &= ~040002;
else if (Pitch.CurrentAdjustedReading > 0)
New31 &= ~040001;
if (ServerSocket != -1 && New31 != Last31)
{
unsigned char Packet[8];
Last31 = New31;
// First, create the mask which will tell the CPU to only pay attention to
// relevant bits of channel (031).
FormIoPacket (0431, 040077, Packet);
FormIoPacket (031, New31, &Packet[4]);
// And, send it all.
j = send (ServerSocket, (const char *) Packet, 8, MSG_NOSIGNAL);
if (j == SOCKET_ERROR && SOCKET_BROKEN)
{
close (ServerSocket);
ServerSocket = -1;
fprintf (stdout, "\nServer connection lost.\n");
return;
}
}
if (Roll.CurrentAdjustedReading != LastAdjustedRoll)
{
OutputTranslated (0170, LastAdjustedRoll = Roll.CurrentAdjustedReading);
}
if (Pitch.CurrentAdjustedReading != LastAdjustedPitch)
{
OutputTranslated (0166, LastAdjustedPitch = Pitch.CurrentAdjustedReading);
}
if (Yaw.CurrentAdjustedReading != LastAdjustedYaw)
{
OutputTranslated (0167, LastAdjustedYaw = Yaw.CurrentAdjustedReading);
}
}
![swh spinner](/static/img/swh-spinner.gif)
Computing file changes ...