Imports the current Win32 source for the pod-racing game 'Red Planet', built on the MUNGA engine and its L4 (Win32/DirectX) platform layer: - MUNGA / MUNGA_L4: cross-platform engine core and Win32 backend - RP / RP_L4: Red Planet game logic and Win32 application - DivLoader, Setup1: asset loader and installer project - lib, MUNGA_L4/openal, MUNGA_L4/sos: third-party audio dependencies Removed stale Subversion metadata and added .gitignore/.gitattributes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1675 lines
38 KiB
C++
1675 lines
38 KiB
C++
#include "mungal4.h"
|
|
#include "..\munga\controls.h"
|
|
#pragma hdrstop
|
|
|
|
#include "l4rio.h"
|
|
#include "l4ctrl.h"
|
|
|
|
#if defined(TRACE_RIO_RECEIVE_PACKET)
|
|
BitTrace RIO_Receive_Packet("RIO Receive Packet");
|
|
#endif
|
|
|
|
#if defined(TRACE_RIO_SEND_PACKET)
|
|
BitTrace RIO_Send_Packet("RIO Send Packet);
|
|
#endif
|
|
|
|
#if defined(DEBUG)
|
|
# define Test_Tell(n) DEBUG_STREAM << n
|
|
#else
|
|
# define Test_Tell(n)
|
|
#endif
|
|
|
|
#define default_deadband_value 0.03
|
|
|
|
static Byte RIOLengths[] = {
|
|
0, // CheckRequest
|
|
0, // VersionRequest
|
|
0, // AnalogRequest
|
|
1, // ResetRequest
|
|
2, // LampRequest
|
|
2, // CheckReply
|
|
2, // VersionReply
|
|
10, // AnalogReply
|
|
1, // ButtonPressed
|
|
1, // ButtonReleased
|
|
2, // KeyPressed
|
|
2, // KeyReleased
|
|
1 // TestModeChange
|
|
};
|
|
|
|
Byte RIO::reply_check_string[] = {RIO::CheckReply, 3, 2 };
|
|
Byte RIO::reply_version_string[] = {RIO::VersionReply, 1, 23};
|
|
Byte RIO::reply_button_press_string[] = {RIO::ButtonPressed, 22};
|
|
Byte RIO::reply_button_release_string[]= {RIO::ButtonReleased, 22};
|
|
Byte RIO::reply_key_press_string[] = {RIO::KeyPressed, 0, 4};
|
|
Byte RIO::reply_key_release_string[] = {RIO::KeyReleased, 0, 4};
|
|
Byte RIO::reply_test_enter_string[] = {RIO::TestModeChange, 1};
|
|
Byte RIO::reply_test_exit_string[] = {RIO::TestModeChange, 0};
|
|
Byte RIO::reply_analog_string[] =
|
|
{
|
|
RIO::AnalogReply, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0
|
|
};
|
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Utilities ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
int
|
|
CombinePair(Byte low_value, Byte high_value)
|
|
{
|
|
int result;
|
|
|
|
result = ((int) (low_value & 0x7F)) | (((int) high_value) << 7);
|
|
if (result & 0x2000)
|
|
{
|
|
result |= ~0x3FFF;
|
|
}
|
|
Check_Fpu();
|
|
return result;
|
|
}
|
|
|
|
|
|
void
|
|
BoardError(NotationFile *notation_file, char *type, int position)
|
|
{
|
|
Check(notation_file);
|
|
Check_Pointer(type);
|
|
|
|
char
|
|
where[40];
|
|
|
|
sprintf(where, "%s@Slot=%d:Address=%d", type, position >> 3, position & 7);
|
|
notation_file->AppendEntry("RIOBoardErrors", "error", where);
|
|
Check_Fpu();
|
|
}
|
|
|
|
//###########################################################################
|
|
//############################ Joystick classes #############################
|
|
//###########################################################################
|
|
const char *FilterChannel::highName = "high";
|
|
const char *FilterChannel::centerName = "center";
|
|
const char *FilterChannel::lowName = "low";
|
|
const char *FilterChannel::joystickXName = "JoystickX";
|
|
const char *FilterChannel::joystickYName = "JoystickY";
|
|
const char *FilterChannel::throttleName = "Throttle";
|
|
const char *FilterChannel::leftPedalName = "LeftPedal";
|
|
const char *FilterChannel::rightPedalName = "RightPedal";
|
|
|
|
FilterChannel::FilterChannel():
|
|
average(5,0)
|
|
{
|
|
valuesFromFile = False;
|
|
previousValue = 0;
|
|
polarity = unipolar;
|
|
mode = unaligned;
|
|
deadbandScalar = default_deadband_value;
|
|
|
|
lowerDeadband = 0;
|
|
upperDeadband = 0;
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
FilterChannel::FilterChannel(
|
|
NotationFile *init_file,
|
|
const char *page_name,
|
|
int default_min, int default_max
|
|
):
|
|
average(5,0)
|
|
{
|
|
valuesFromFile = True;
|
|
previousValue = 0;
|
|
polarity = unipolar;
|
|
mode = normal;
|
|
deadbandScalar = default_deadband_value;
|
|
|
|
pageName = page_name;
|
|
min = default_min;
|
|
max = default_max;
|
|
//-------------------------------------------
|
|
// Attempt to read calibration values from
|
|
// the notation file. If the values don't
|
|
// exist, then create them from the defaults.
|
|
//-------------------------------------------
|
|
if (init_file->GetEntry(pageName, highName, &max) == 0)
|
|
{
|
|
init_file->SetEntry(pageName, highName, default_max);
|
|
}
|
|
|
|
if (init_file->GetEntry(pageName, lowName, &min) == 0)
|
|
{
|
|
init_file->SetEntry(pageName, lowName, default_min);
|
|
}
|
|
|
|
center = (max-min)/2;
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
FilterChannel::FilterChannel(
|
|
NotationFile *init_file,
|
|
const char *page_name,
|
|
int default_min, int default_center, int default_max
|
|
):
|
|
average(5,0)
|
|
{
|
|
valuesFromFile = True;
|
|
previousValue = 0;
|
|
polarity = bipolar;
|
|
mode = normal;
|
|
deadbandScalar = default_deadband_value;
|
|
|
|
pageName = page_name;
|
|
min = default_min;
|
|
center = default_center;
|
|
max = default_max;
|
|
|
|
//-------------------------------------------
|
|
// Attempt to read calibration values from
|
|
// the notation file. If the values don't
|
|
// exist, then create them from the defaults.
|
|
//-------------------------------------------
|
|
|
|
if (init_file->GetEntry(pageName, highName, &max) == 0)
|
|
{
|
|
init_file->SetEntry(pageName, highName, default_max);
|
|
}
|
|
|
|
if (init_file->GetEntry(pageName, centerName, ¢er) == 0)
|
|
{
|
|
init_file->SetEntry(pageName, centerName, default_center);
|
|
}
|
|
|
|
if (init_file->GetEntry(pageName, lowName, &min) == 0)
|
|
{
|
|
init_file->SetEntry(pageName, lowName, default_min);
|
|
}
|
|
|
|
CalculateDeadBands();
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
FilterChannel::~FilterChannel()
|
|
{
|
|
Check(this);
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
FilterChannel::SetPolarity(PolarMode newPolarity)
|
|
{
|
|
Check(this);
|
|
polarity = newPolarity;
|
|
|
|
// HACK - filterchannel must be realigned when changing to bipolar!
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
FilterChannel::SetDeadBand(Scalar dead_band)
|
|
{
|
|
Check(this);
|
|
|
|
deadbandScalar = fabs(dead_band);
|
|
//---------------------------------------------------------
|
|
// Recalculate deadbands and ranges if needed
|
|
//---------------------------------------------------------
|
|
if (mode == normal)
|
|
{
|
|
CalculateDeadBands();
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
FilterChannel::BeginAlignment()
|
|
{
|
|
Check(this);
|
|
//---------------------------------------------------------
|
|
// Set bogus min/max, force update
|
|
//---------------------------------------------------------
|
|
mode = unaligned;
|
|
min = 10000;
|
|
max = -10000;
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
FilterChannel::EndAlignment(NotationFile *init_file)
|
|
{
|
|
Check(this);
|
|
//---------------------------------------------------------
|
|
// Save the most recent value as the center
|
|
//---------------------------------------------------------
|
|
center = previousValue;
|
|
//------------------------------------------------------------
|
|
// If channel was never adjusted, synthesize reasonable values
|
|
//------------------------------------------------------------
|
|
// I don't trust abs(): saw weirdness.
|
|
int
|
|
delta = max-min;
|
|
if (delta < 0)
|
|
{
|
|
delta = -delta;
|
|
}
|
|
|
|
if (delta < 10)
|
|
{
|
|
if (polarity == bipolar)
|
|
{
|
|
min = center-100;
|
|
max = center+100;
|
|
}
|
|
else
|
|
{
|
|
min = 0;
|
|
max = 100;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int
|
|
setback = delta/33; // move the edges in by 3%
|
|
|
|
max -= setback;
|
|
min += setback;
|
|
}
|
|
//---------------------------------------------------------
|
|
// Save the new values
|
|
//---------------------------------------------------------
|
|
if (valuesFromFile)
|
|
{
|
|
if (init_file != NULL)
|
|
{
|
|
init_file->SetEntry(pageName, highName, max);
|
|
init_file->SetEntry(pageName, lowName, min);
|
|
|
|
if (polarity == bipolar)
|
|
{
|
|
init_file->SetEntry(pageName, centerName, center);
|
|
}
|
|
}
|
|
}
|
|
//---------------------------------------------------------
|
|
// Calculate real deadband values
|
|
//---------------------------------------------------------
|
|
CalculateDeadBands();
|
|
//---------------------------------------------------------
|
|
// Go to normal mode
|
|
//---------------------------------------------------------
|
|
mode = normal;
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
Scalar
|
|
FilterChannel::Update(int value)
|
|
{
|
|
Check(this);
|
|
|
|
Scalar
|
|
result = 0.0;
|
|
|
|
previousValue = value;
|
|
|
|
//---------------------------------------------------------
|
|
// Generate average, use for min/max determination
|
|
//---------------------------------------------------------
|
|
average.Add(value);
|
|
{
|
|
int
|
|
the_average = average.CalculateOlympicAverage();
|
|
|
|
if (the_average < min) { min = the_average; }
|
|
if (the_average > max) { max = the_average; }
|
|
}
|
|
//---------------------------------------------------------
|
|
// Perform position calculations
|
|
//---------------------------------------------------------
|
|
switch (polarity)
|
|
{
|
|
case unipolar:
|
|
{
|
|
//---------------------------------------------------------
|
|
// Subtract 'min' from current value
|
|
//---------------------------------------------------------
|
|
value -= min;
|
|
//---------------------------------------------------------
|
|
// Subtract deadband value
|
|
//---------------------------------------------------------
|
|
int
|
|
deadband_adjustment = (int) ((max-min)*deadbandScalar);
|
|
|
|
value -= deadband_adjustment;
|
|
if (value > 0)
|
|
{
|
|
int
|
|
adjusted_maximum = max-deadband_adjustment;
|
|
|
|
if (adjusted_maximum > 0)
|
|
{
|
|
result = ((Scalar)value)/adjusted_maximum;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case bipolar:
|
|
if (mode == unaligned)
|
|
{
|
|
//---------------------------------------------------------
|
|
// Use 1/2 (max-min) as temporary center
|
|
//---------------------------------------------------------
|
|
center = (max-min) >> 1;
|
|
//---------------------------------------------------------
|
|
// Set temporary deadband values
|
|
//---------------------------------------------------------
|
|
upperDeadband = (int) ((max-min)*deadbandScalar);
|
|
lowerDeadband= upperDeadband;
|
|
}
|
|
//---------------------------------------------------------
|
|
// Adjust for center
|
|
//---------------------------------------------------------
|
|
value -= center;
|
|
//---------------------------------------------------------
|
|
// Generate scaled results
|
|
//---------------------------------------------------------
|
|
if (value < 0)
|
|
{
|
|
value += lowerDeadband;
|
|
if (value < 0)
|
|
{
|
|
if (lowerRange > 0)
|
|
{
|
|
if (value <= -lowerRange)
|
|
{
|
|
result = -1.0;
|
|
}
|
|
else
|
|
{
|
|
result = ((Scalar) value)/lowerRange;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
value -= upperDeadband;
|
|
if (value > 0)
|
|
{
|
|
if (upperRange > 0)
|
|
{
|
|
if (value >= upperRange)
|
|
{
|
|
result = 1.0;
|
|
}
|
|
else
|
|
{
|
|
result = ((Scalar) value)/upperRange;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
//---------------------------------------------------------
|
|
// Return result
|
|
//---------------------------------------------------------
|
|
Check_Fpu();
|
|
|
|
# if defined(DEBUG)
|
|
DEBUG_STREAM << pageName << ":" << value << "=" << result << "\n";
|
|
# endif
|
|
|
|
return result;
|
|
}
|
|
|
|
Logical
|
|
FilterChannel::TestInstance() const
|
|
{
|
|
return True;
|
|
}
|
|
|
|
void
|
|
FilterChannel::CalculateDeadBands()
|
|
{
|
|
Check(this);
|
|
|
|
lowerDeadband = (int) ((center-min)*deadbandScalar + .5);
|
|
lowerRange = center - (min+lowerDeadband);
|
|
|
|
upperDeadband = (int) ((max-center)*deadbandScalar + .5);
|
|
upperRange = (max-upperDeadband) - center;
|
|
|
|
# if defined(DEBUG)
|
|
DEBUG_STREAM << "pageName =" << pageName <<"\n";
|
|
DEBUG_STREAM << "min =" << min <<"\n";
|
|
DEBUG_STREAM << "center=" << center <<"\n";
|
|
DEBUG_STREAM << "max= " << max <<"\n";
|
|
DEBUG_STREAM << "lowerDeadband= " << lowerDeadband <<"\n";
|
|
DEBUG_STREAM << "lowerRange = " << lowerRange <<"\n";
|
|
DEBUG_STREAM << "upperDeadband= " << upperDeadband <<"\n";
|
|
DEBUG_STREAM << "upperRange = " << upperRange <<"\n";
|
|
# endif
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
|
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Ranger ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
Ranger::Ranger(
|
|
const char *page_name,
|
|
int hardware_min,
|
|
int hardware_max,
|
|
Scalar deadband
|
|
){
|
|
Check_Pointer(this);
|
|
|
|
pageName = page_name;
|
|
hardwareMinimum = hardware_min;
|
|
hardwareMaximum = hardware_max;
|
|
|
|
SetDeadBand(deadband);
|
|
//------------------------------------------------------------
|
|
// We ASSUME that the control is at rest (center for joystick)
|
|
//------------------------------------------------------------
|
|
ForceToZero();
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
Ranger::~Ranger()
|
|
{
|
|
Check(this);
|
|
Check_Fpu();
|
|
}
|
|
|
|
Logical
|
|
Ranger::TestInstance() const
|
|
{
|
|
Check_Fpu();
|
|
return True;
|
|
}
|
|
|
|
void
|
|
Ranger::SetDeadBand(Scalar dead_band)
|
|
{
|
|
Check(this);
|
|
|
|
deadbandInteger =
|
|
(int)((hardwareMaximum - hardwareMinimum) * fabs(dead_band));
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
Ranger::ForceToZero()
|
|
{
|
|
Check(this);
|
|
sampledInputFlag = False;
|
|
Check_Fpu();
|
|
}
|
|
|
|
Scalar
|
|
Ranger::Update(int input)
|
|
{
|
|
Check(this);
|
|
int
|
|
range;
|
|
Scalar
|
|
result = ((Scalar) 0);
|
|
|
|
Verify(hardwareMaximum > hardwareMinimum);
|
|
//------------------------------------------------------------
|
|
// Uncentered processing: slide offset to keep value
|
|
// within the proscribed range
|
|
//------------------------------------------------------------
|
|
if (hardwareMinimum >= 0) // this designates an uncentered Ranger
|
|
{
|
|
//---------------------------------------------------------
|
|
// Sample current input for offset value
|
|
//---------------------------------------------------------
|
|
if (!sampledInputFlag)
|
|
{
|
|
sampledInputFlag = True;
|
|
|
|
offset = -input;
|
|
//------------------------------------------
|
|
// Initialize to reasonable values
|
|
//------------------------------------------
|
|
highestInput = (hardwareMaximum*3)/4;
|
|
lowestInput = hardwareMinimum;
|
|
}
|
|
//------------------------------------------------------------
|
|
// Add offset
|
|
//------------------------------------------------------------
|
|
input += offset;
|
|
//------------------------------------------------------------
|
|
// Slide offset if needed
|
|
//------------------------------------------------------------
|
|
if (input > hardwareMaximum)
|
|
{
|
|
offset -= input-hardwareMaximum;
|
|
input = hardwareMaximum;
|
|
}
|
|
else if (input < hardwareMinimum)
|
|
{
|
|
offset -= input-hardwareMinimum;
|
|
input = hardwareMinimum;
|
|
}
|
|
//-----------------------------------------------------------------
|
|
// Keep track of limit (lowestValue will always be hardwareMinimum)
|
|
//-----------------------------------------------------------------
|
|
if (input > highestInput)
|
|
{
|
|
highestInput = input;
|
|
}
|
|
//------------------------------------------------------------
|
|
// Generate scaled result
|
|
//------------------------------------------------------------
|
|
input -= hardwareMinimum; // normalize to zero
|
|
|
|
if (input > deadbandInteger)
|
|
{
|
|
range = highestInput - lowestInput - deadbandInteger;
|
|
|
|
if (range > 0)
|
|
{
|
|
result = ((Scalar)(input-deadbandInteger))/(Scalar)range;
|
|
}
|
|
}
|
|
}
|
|
//------------------------------------------------------------
|
|
// Centered processing: keep max, min of input to
|
|
// determine total range
|
|
//------------------------------------------------------------
|
|
else
|
|
{
|
|
//---------------------------------------------------------
|
|
// Sample current input for offset value
|
|
//---------------------------------------------------------
|
|
if (!sampledInputFlag)
|
|
{
|
|
sampledInputFlag = True;
|
|
//------------------------------------------
|
|
// Set offset such that this is the new zero
|
|
//------------------------------------------
|
|
offset = -input;
|
|
//------------------------------------------
|
|
// Initialize to reasonable values...
|
|
// ...add offset to reflect true limits
|
|
// that are available with this offset
|
|
//------------------------------------------
|
|
// HardwareMinimum is known to be negative because of 'if' statement
|
|
Verify(hardwareMaximum > 0);
|
|
|
|
highestInput = (hardwareMaximum*3)/4 + offset;
|
|
lowestInput = (hardwareMinimum*3)/4 + offset;
|
|
}
|
|
//------------------------------------------------------------
|
|
// Adjust for offset
|
|
//------------------------------------------------------------
|
|
input += offset;
|
|
|
|
if (input > highestInput)
|
|
{
|
|
highestInput = input;
|
|
}
|
|
if (input < lowestInput)
|
|
{
|
|
lowestInput = input;
|
|
}
|
|
//---------------------------------------
|
|
// Let's make sure before we continue...
|
|
//---------------------------------------
|
|
Verify(highestInput >= lowestInput);
|
|
Verify(input <= highestInput);
|
|
Verify(input >= lowestInput);
|
|
//------------------------------------------------------------
|
|
// Generate scaled result
|
|
//------------------------------------------------------------
|
|
if (input < -deadbandInteger)
|
|
{
|
|
//---------------------------------------
|
|
// Generate range
|
|
//---------------------------------------
|
|
range = abs(lowestInput) - deadbandInteger;
|
|
//---------------------------------------
|
|
// Generate scaled result
|
|
//---------------------------------------
|
|
if (range > 0)
|
|
{
|
|
result = ((Scalar)(input+deadbandInteger))/(Scalar)range;
|
|
}
|
|
}
|
|
else if (input > deadbandInteger)
|
|
{
|
|
//---------------------------------------
|
|
// Generate range
|
|
//---------------------------------------
|
|
range = abs(highestInput) - deadbandInteger;
|
|
//---------------------------------------
|
|
// Generate scaled result
|
|
//---------------------------------------
|
|
if (range > 0)
|
|
{
|
|
result = ((Scalar)(input-deadbandInteger))/(Scalar)range;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (result > ((Scalar) 1.0))
|
|
{
|
|
DEBUG_STREAM <<
|
|
"Too high!" <<
|
|
" input=" << input << " result=" << result << "\n" <<
|
|
|
|
pageName <<
|
|
" offset=" << offset <<
|
|
" lowestInput=" << lowestInput <<
|
|
" highestInput=" << highestInput <<
|
|
" deadbandInteger=" << deadbandInteger <<
|
|
" range=" << range <<
|
|
"\n";
|
|
|
|
result = ((Scalar) 1.0);
|
|
//Fail("Ranger::Update above 1.0");
|
|
}
|
|
else if (result < ((Scalar)-1.0))
|
|
{
|
|
DEBUG_STREAM <<
|
|
"Too low!" <<
|
|
" input=" << input << " result=" << result << "\n" <<
|
|
|
|
pageName <<
|
|
" lowestInput=" << lowestInput <<
|
|
" highestInput=" << highestInput <<
|
|
" deadbandInteger=" << deadbandInteger <<
|
|
" range=" << range <<
|
|
"\n";
|
|
|
|
result = ((Scalar)-1.0);
|
|
//Fail("Ranger::Update below -1.0");
|
|
}
|
|
|
|
Verify(result <= ((Scalar) 1.0));
|
|
Verify(result >= ((Scalar) -1.0));
|
|
|
|
Check_Fpu();
|
|
return result;
|
|
}
|
|
|
|
void
|
|
Ranger::Statistics(NotationFile *failure_file)
|
|
{
|
|
Check(this);
|
|
Check(failure_file);
|
|
|
|
int
|
|
range = highestInput - lowestInput,
|
|
hardware_range = hardwareMaximum - hardwareMinimum;
|
|
|
|
Verify(hardware_range > 0);
|
|
|
|
Scalar
|
|
range_percentage = ((Scalar) range)/hardware_range;
|
|
//---------------------------------
|
|
// Report slippage
|
|
//---------------------------------
|
|
if (range_percentage > (Scalar) 1.1) // allow 10% overrange
|
|
{
|
|
failure_file->SetEntry(pageName, "Overrange", range_percentage);
|
|
}
|
|
//---------------------------------
|
|
// Report low range
|
|
//---------------------------------
|
|
if (range_percentage < (Scalar) .50)
|
|
{
|
|
failure_file->SetEntry(pageName, "UnderRange", range_percentage);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//########################################################################
|
|
//############################### RIO ####################################
|
|
//########################################################################
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Constructor
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//Win32 Serial support: ADB 02/13/07
|
|
//RIO::RIO(Word port, Word intNum, Logical perform_tests):
|
|
RIO::RIO(const char* port, Logical perform_tests):
|
|
PCSerialPacket()
|
|
{
|
|
Tell("RIO initialization: variables\n");
|
|
Check_Pointer(this);
|
|
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Initialize values
|
|
//---------------------------------------------------------------------
|
|
//
|
|
TestModeActive = 0;
|
|
|
|
Throttle = (Scalar) 0;
|
|
LeftPedal = (Scalar) 0;
|
|
RightPedal = (Scalar) 0;
|
|
JoystickX = (Scalar) 0;
|
|
JoystickY = (Scalar) 0;
|
|
|
|
remoteRetryCount = 0;
|
|
remoteAbandonCount = 0;
|
|
remoteFullBufferCount = 0;
|
|
lineErrorCount = 0;
|
|
overrunCount = 0;
|
|
abandonCount = 0;
|
|
operational = True;
|
|
// discardCount = 0;
|
|
|
|
failureFile = NULL;
|
|
failureFileOpenCount = 0;
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Clear error log
|
|
//---------------------------------------------------------------------
|
|
//
|
|
OpenFailureFile();
|
|
Check(failureFile);
|
|
failureFile->DeletePage("RIOBoardErrors");
|
|
failureFile->DeletePage("RIODeadLamps");
|
|
failureFile->DeletePage("RIOErrors");
|
|
CloseFailureFile();
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Read value ranges from notation file, initialize rangers
|
|
//
|
|
// Order of integers is: minimum, maximum, end-zone-range, deadband
|
|
//---------------------------------------------------------------------
|
|
//
|
|
{
|
|
// NotationFile
|
|
// stat_file((const char *) "RIO.INI");
|
|
|
|
leftPedalRanger = new Ranger("LeftPedal", 0, 470, .0);
|
|
Register_Object(leftPedalRanger);
|
|
|
|
rightPedalRanger = new Ranger("RightPedal", 0, 470, .0);
|
|
Register_Object(rightPedalRanger);
|
|
|
|
throttleRanger = new Ranger("Throttle", 0, 800, .05);
|
|
Register_Object(throttleRanger);
|
|
|
|
joystickXRanger = new Ranger("JoystickX", -96, 96, .05);
|
|
Register_Object(joystickXRanger);
|
|
|
|
joystickYRanger = new Ranger("JoystickY", -97, 108, .05);
|
|
Register_Object(joystickYRanger);
|
|
}
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Start the PCSerialPacket
|
|
//---------------------------------------------------------------------
|
|
//
|
|
//Win32 Serial support: ADB 02/13/07
|
|
//int status = PCSerialPacket::Initialize(
|
|
// PCSP_9600,
|
|
// port,
|
|
// intNum,
|
|
// (Byte *) RIOLengths,
|
|
// 13,
|
|
// (Byte *) RIOLengths,
|
|
// 13
|
|
// );
|
|
int status = PCSerialPacket::Initialize(PCS_9600, PCS_N81, port, (BYTE*)RIOLengths, 13, (BYTE*)RIOLengths, 13);
|
|
|
|
switch(status)
|
|
{
|
|
case PCSPAKInitOk:
|
|
// silent if OK
|
|
DEBUG_STREAM << "RIO successfully initialized!\n";
|
|
break;
|
|
//Win32 Serial Support: ADB 02/24/2007
|
|
//case PCSPAKInitErrDPMI:
|
|
// DEBUG_STREAM << "RIO::RIO DPMI error!\n";
|
|
// break;
|
|
//case PCSPAKInitErrAlloc:
|
|
// DEBUG_STREAM << "RIO::RIO buffer allocation error!\n";
|
|
// break;
|
|
case PCSPAKWin32Err:
|
|
DEBUG_STREAM << "RIO::RIO Win32 Serial Initalization error!\n";
|
|
break;
|
|
default:
|
|
DEBUG_STREAM << "RIO::RIO unexpected init result=" << status << "!\n";
|
|
break;
|
|
}
|
|
|
|
#if 0
|
|
extern Byte previousIMR, previousISR, previousIRR;
|
|
extern Byte middleIMR, middleISR, middleIRR;
|
|
extern Byte postIMR, postISR, postIRR;
|
|
extern Byte pcspakLSR, pcspakIER, pcspakIIR;
|
|
|
|
DEBUG_STREAM <<
|
|
hex <<
|
|
"previousIMR=" << (int) (previousIMR & 0xFF) <<
|
|
", mid=" << (int) (middleIMR & 0xFF) <<
|
|
", post=" << (int) (postIMR & 0xFF) << "\n" <<
|
|
|
|
"previousISR=" << (int) (previousISR & 0xFF) <<
|
|
", mid=" << (int) (middleISR & 0xFF) <<
|
|
", post=" << (int) (postISR & 0xFF) << "\n" <<
|
|
|
|
"previousIRR=" << (int) (previousIRR & 0xFF) <<
|
|
", mid=" << (int) (middleIRR & 0xFF) <<
|
|
", post=" << (int) (postIRR & 0xFF) << "\n" <<
|
|
|
|
"pcspakLSR=" << (int) (pcspakLSR & 0xFF) <<
|
|
", pcspakIER=" << (int) (pcspakIER & 0xFF) <<
|
|
", pcspakIIR was=" << (int) (pcspakIIR & 0xFF) << "\n" <<
|
|
dec;
|
|
#endif
|
|
|
|
MajorRevision = 0xFF;
|
|
MinorRevision = 0xFF;
|
|
|
|
if (perform_tests)
|
|
{
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Reset remote I/O board
|
|
//---------------------------------------------------------------------
|
|
//
|
|
Time
|
|
when;
|
|
int
|
|
bomb = 0;
|
|
|
|
RIOEvent
|
|
dummy_event;
|
|
|
|
Tell("RIO initialization: reset board\n");
|
|
|
|
// Reset RIO board
|
|
SetDTR(True); // Assert reset
|
|
when = Now();
|
|
for(when += .1f; Now() < when; );
|
|
|
|
SetDTR(False); // Retract reset
|
|
when = Now();
|
|
for(when += 1.0f; Now() < when; );
|
|
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Wait for test mode to start (or bomb out)
|
|
//---------------------------------------------------------------------
|
|
//
|
|
Tell("RIO initialization: check board\n");
|
|
RequestCheck();
|
|
|
|
when = Now();
|
|
when += 5.0f;
|
|
while (!TestModeActive)
|
|
{
|
|
if (Now() > when)
|
|
{
|
|
bomb = 1;
|
|
DEBUG_STREAM << "RIO never came back from check request!\n";
|
|
break;
|
|
}
|
|
GetNextEvent(&dummy_event);
|
|
}
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Wait for test mode to finish (or bomb out)
|
|
//---------------------------------------------------------------------
|
|
//
|
|
if (!bomb)
|
|
{
|
|
when = Now();
|
|
when += 5.0f;
|
|
while (TestModeActive)
|
|
{
|
|
if (Now() > when)
|
|
{
|
|
bomb = 1;
|
|
DEBUG_STREAM << "RIO never came back from test mode!\n";
|
|
break;
|
|
}
|
|
GetNextEvent(&dummy_event);
|
|
}
|
|
}
|
|
//
|
|
//---------------------------------------------------------------------
|
|
// Get version (or bomb out)
|
|
//---------------------------------------------------------------------
|
|
//
|
|
|
|
if (!bomb)
|
|
{
|
|
RequestVersion();
|
|
when = Now();
|
|
when += 5.0f;
|
|
while (MajorRevision == 0xFF)
|
|
{
|
|
if (Now() > when)
|
|
{
|
|
DEBUG_STREAM << "RIO never came back from version request!\n";
|
|
break;
|
|
}
|
|
GetNextEvent(&dummy_event);
|
|
}
|
|
}
|
|
|
|
if(!bomb)
|
|
{
|
|
DEBUG_STREAM<<"RIO initialization finished\n";
|
|
}
|
|
else
|
|
{
|
|
DEBUG_STREAM<<"RIO initialization failed! Shutting Down Serial Port!\n";
|
|
ShutdownRxThread();
|
|
}
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
// Destructor
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
extern int historyIndex;
|
|
extern Byte history[];
|
|
|
|
enum
|
|
{
|
|
txFlag=1,
|
|
rxFlag=2,
|
|
eventFlag=3
|
|
};
|
|
|
|
enum
|
|
{
|
|
IRQ_EVENT=0,
|
|
IRQ_EVENT_RX=1,
|
|
IRQ_EVENT_TX=2,
|
|
IRQ_EVENT_MSR=3,
|
|
IRQ_EVENT_LSR=4,
|
|
IRQ_EVENT_BOGUS=5,
|
|
|
|
TX_EVENT_RESTART=10,
|
|
TX_EVENT_ABANDON=11,
|
|
TX_EVENT_DONE=12,
|
|
TX_EVENT_ACK=13,
|
|
TX_EVENT_NAK=14,
|
|
TX_EVENT_EARLY=15,
|
|
TX_EVENT_EMPTY=16,
|
|
TX_EVENT_KICK=17,
|
|
|
|
RX_EVENT_FULL=20,
|
|
RX_EVENT_NOT_CMD=21,
|
|
RX_EVENT_FULLBODY=22,
|
|
RX_EVENT_NAK=23,
|
|
RX_EVENT_CKSMERR=24,
|
|
RX_EVENT_OK=25
|
|
};
|
|
|
|
RIO::~RIO()
|
|
{
|
|
Check(this);
|
|
|
|
#if 0
|
|
//---------------------------------------------------------------------
|
|
// Save serial history for debugging
|
|
//---------------------------------------------------------------------
|
|
// If you enable this, set KEEP_HISTORY in PCSPAK.ASM to '1' as well.
|
|
// Otherwise you will be viewing nonexistent history data.
|
|
const char
|
|
*commandName[13] =
|
|
{
|
|
"CheckReq", //=0x80
|
|
"VersionReq",
|
|
"AnalogReq",
|
|
"ResetReq",
|
|
"LampReq",
|
|
"CheckReply",
|
|
"VersionReply",
|
|
"AnalogReply",
|
|
"ButtonPressed",
|
|
"ButtonReleased",
|
|
"KeyPressed",
|
|
"KeyReleased",
|
|
"TestModeChange"
|
|
};
|
|
|
|
|
|
int i, type, j;
|
|
|
|
cout << flush;
|
|
printf("tx\t\trx\t\tevent\n");
|
|
printf("-----\t-----\t\t---------------------\n");
|
|
for(i=0; i<historyIndex; i+=2)
|
|
{
|
|
j = history[i]; // 80x86 stores as low, high
|
|
type = history[i+1];
|
|
|
|
switch(type)
|
|
{
|
|
case txFlag:
|
|
switch(j)
|
|
{
|
|
case 0xFC: printf("ACK\n"); break;
|
|
case 0xFD: printf("NAK\n"); break;
|
|
case 0xFE: printf("RST\n"); break;
|
|
case 0xFF: printf("IDL\n"); break;
|
|
default:
|
|
if ((j >= 0x80) && (j <= 0x8C))
|
|
{
|
|
printf("%s", commandName[j-0x80]);
|
|
}
|
|
else
|
|
{
|
|
printf("%02X", j);
|
|
}
|
|
printf("\n");
|
|
break;
|
|
}
|
|
break;
|
|
case rxFlag:
|
|
printf("\t\t");
|
|
switch(j)
|
|
{
|
|
case 0xFC: printf("ACK\n"); break;
|
|
case 0xFD: printf("NAK\n"); break;
|
|
case 0xFE: printf("RST\n"); break;
|
|
case 0xFF: printf("IDL\n"); break;
|
|
default:
|
|
if ((j >= 0x80) && (j <= 0x8C))
|
|
{
|
|
printf("%s", commandName[j-0x80]);
|
|
}
|
|
else
|
|
{
|
|
printf("%02X", j);
|
|
}
|
|
printf("\n");
|
|
break;
|
|
}
|
|
break;
|
|
case eventFlag:
|
|
printf("\t\t\t\t");
|
|
switch(j)
|
|
{
|
|
case IRQ_EVENT: printf("IRQ entry\n"); break;
|
|
case IRQ_EVENT_RX: printf("IRQ_EVENT_RX\n"); break;
|
|
case IRQ_EVENT_TX: printf("IRQ_EVENT_TX\n"); break;
|
|
case IRQ_EVENT_MSR: printf("IRQ_EVENT_MSR\n"); break;
|
|
case IRQ_EVENT_LSR: printf("IRQ_EVENT_LSR\n"); break;
|
|
case IRQ_EVENT_BOGUS: printf("IRQ_EVENT_BOGUS\n"); break;
|
|
|
|
case TX_EVENT_RESTART: printf("TX_EVENT_RESTART\n"); break;
|
|
case TX_EVENT_ABANDON: printf("TX_EVENT_ABANDON\n"); break;
|
|
case TX_EVENT_DONE: printf("TX_EVENT_DONE\n"); break;
|
|
case TX_EVENT_ACK: printf("TX_EVENT_ACK\n"); break;
|
|
case TX_EVENT_NAK: printf("TX_EVENT_NAK\n"); break;
|
|
case TX_EVENT_EARLY: printf("TX_EVENT_EARLY\n"); break;
|
|
case TX_EVENT_EMPTY: printf("TX_EVENT_EMPTY\n"); break;
|
|
case TX_EVENT_KICK: printf("TX_EVENT_KICK\n"); break;
|
|
|
|
case RX_EVENT_FULL: printf("RX_EVENT_FULL\n"); break;
|
|
case RX_EVENT_NOT_CMD: printf("RX_EVENT_NOT_CMD\n"); break;
|
|
case RX_EVENT_FULLBODY: printf("RX_EVENT_FULLBODY\n"); break;
|
|
case RX_EVENT_NAK: printf("RX_EVENT_NAK\n"); break;
|
|
case RX_EVENT_CKSMERR: printf("RX_EVENT_CKSMERR\n"); break;
|
|
case RX_EVENT_OK: printf("RX_EVENT_OK\n"); break;
|
|
default: printf("unknown event %02X\n", j); break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
fflush(stdout);
|
|
#endif
|
|
|
|
//---------------------------------------------------------------------
|
|
// Flush data to RIO
|
|
//---------------------------------------------------------------------
|
|
RIOEvent
|
|
dummy_event;
|
|
|
|
// This odd sequence of allocation, setting, and adding is necessary:
|
|
// if you try to combine them, the compiler gets confused as to which
|
|
// method to invoke for 'Now()'.
|
|
Time
|
|
then;
|
|
then = Now();
|
|
then += 5.0f;
|
|
while (Now() < then)
|
|
{
|
|
//-------------------------------------------------
|
|
// Drop out of loop when all packets have been
|
|
// transmitted and the last character has been sent
|
|
//-------------------------------------------------
|
|
if (TransmitQueueCount() <= 0)
|
|
{
|
|
if (!IsActive())
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
GetNextEvent(&dummy_event);
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// Update failure log
|
|
//---------------------------------------------------------------------
|
|
#if LOG_RIO_DATA
|
|
OpenFailureFile();
|
|
Check(failureFile);
|
|
|
|
failureFile->SetEntry("RIO","lineErrors",lineErrorCount);
|
|
failureFile->SetEntry("RIO","abandonedPackets",abandonCount);
|
|
failureFile->SetEntry("RIO","overruns",overrunCount);
|
|
failureFile->SetEntry("RIO","remoteRetry",remoteRetryCount);
|
|
failureFile->SetEntry("RIO","remoteAbandon",remoteAbandonCount);
|
|
failureFile->SetEntry("RIO","remoteFullBuffer",remoteFullBufferCount);
|
|
|
|
CloseFailureFile();
|
|
#endif
|
|
|
|
//-------------------------------------------
|
|
// Update ranger statistics, delete rangers
|
|
//-------------------------------------------
|
|
{
|
|
// NotationFile
|
|
// stat_file((const char *) "RIO.INI");
|
|
|
|
Check(leftPedalRanger);
|
|
// leftPedalRanger->Statistics(&stat_file);
|
|
Unregister_Object(leftPedalRanger);
|
|
delete leftPedalRanger;
|
|
leftPedalRanger = NULL;
|
|
|
|
Check(rightPedalRanger);
|
|
// rightPedalRanger->Statistics(&stat_file);
|
|
Unregister_Object(rightPedalRanger);
|
|
delete rightPedalRanger;
|
|
rightPedalRanger = NULL;
|
|
|
|
Check(throttleRanger);
|
|
// throttleRanger->Statistics(&stat_file);
|
|
Unregister_Object(throttleRanger);
|
|
delete throttleRanger;
|
|
throttleRanger = NULL;
|
|
|
|
Check(joystickXRanger);
|
|
// joystickXRanger->Statistics(&stat_file);
|
|
Unregister_Object(joystickXRanger);
|
|
delete joystickXRanger;
|
|
joystickXRanger = NULL;
|
|
|
|
Check(joystickYRanger);
|
|
// joystickYRanger->Statistics(&stat_file);
|
|
Unregister_Object(joystickYRanger);
|
|
delete joystickYRanger;
|
|
joystickYRanger = NULL;
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
Logical
|
|
RIO::TestInstance() const
|
|
{
|
|
return True;
|
|
}
|
|
|
|
extern Byte pic_isr, pic_imr, pic_irr;
|
|
extern Byte uart_iir;
|
|
extern Byte pcspak_active,pcspak_rxState,pcspak_txState;
|
|
extern Word pcspak_head,pcspak_tail;
|
|
extern Word pcspak_tempHead,pcspak_tempTail,pcspak_count;
|
|
|
|
extern "C" void
|
|
PCSPAKState(PCSerialPacket *ptr);
|
|
|
|
Logical
|
|
RIO::GetNextEvent(RIOEvent *destination)
|
|
{
|
|
Check(this);
|
|
|
|
Byte receive_buffer[256];
|
|
Logical reply, looping;
|
|
Word errors;
|
|
|
|
//PCSPAKState(this);
|
|
//
|
|
//cout << flush;
|
|
//printf(
|
|
// "RIO isr=%02X imr=%02X irr=%02X, iir=%02X, a=%1d c=%04X ts=%1d rs=%1d e=%X\n",
|
|
// pic_isr, pic_imr, pic_irr,
|
|
// uart_iir,
|
|
// pcspak_active,
|
|
// pcspak_count,
|
|
// pcspak_txState, pcspak_rxState,
|
|
// pcspak_tempHead,pcspak_tempTail,
|
|
// Errors()
|
|
//);
|
|
//fflush(stdout);
|
|
|
|
if (! operational)
|
|
{
|
|
return False;
|
|
}
|
|
|
|
errors = Errors();
|
|
if (errors)
|
|
{
|
|
if (errors & PCSerialPacket::initError)
|
|
{
|
|
NotationFile
|
|
failure((const char *) "FAILURE.LOG");
|
|
|
|
failure.SetEntry("RIOErrors","error","initialization");
|
|
operational = False;
|
|
}
|
|
else
|
|
{
|
|
if (errors & PCSerialPacket::txAbandonPacket)
|
|
{
|
|
//cout << "RIO:: packet abandoned\n";
|
|
++abandonCount;
|
|
}
|
|
if (errors & PCSerialPacket::overrunError)
|
|
{
|
|
//cout << "RIO:: overrun\n";
|
|
++overrunCount;
|
|
}
|
|
if (errors &
|
|
(
|
|
PCSerialPacket::parityError |
|
|
PCSerialPacket::framingError |
|
|
PCSerialPacket::overrunError
|
|
)
|
|
)
|
|
{
|
|
++lineErrorCount;
|
|
}
|
|
}
|
|
}
|
|
|
|
do
|
|
{
|
|
looping = False;
|
|
|
|
reply = ReceivePacket(receive_buffer);
|
|
if (reply)
|
|
{
|
|
switch(receive_buffer[0])
|
|
{
|
|
case CheckReply:
|
|
switch(receive_buffer[1])
|
|
{
|
|
case BoardMissing:
|
|
OpenFailureFile();
|
|
BoardError(failureFile,"missing_board",(int) receive_buffer[2]);
|
|
CloseFailureFile();
|
|
break;
|
|
|
|
case BoardBad:
|
|
OpenFailureFile();
|
|
BoardError(failureFile,"dead_board",(int) receive_buffer[2]);
|
|
CloseFailureFile();
|
|
break;
|
|
|
|
case LampBad:
|
|
OpenFailureFile();
|
|
Check(failureFile);
|
|
failureFile->AppendEntry(
|
|
"RIODeadLamps",
|
|
"lamp",
|
|
LBE4ControlsManager::GetLampName((int) receive_buffer[2])
|
|
);
|
|
CloseFailureFile();
|
|
break;
|
|
|
|
case RestartCount:
|
|
remoteRetryCount += receive_buffer[2];
|
|
break;
|
|
|
|
case AbandonCount:
|
|
remoteAbandonCount += receive_buffer[2];
|
|
break;
|
|
|
|
case FullBufferCount:
|
|
remoteFullBufferCount += receive_buffer[2];
|
|
break;
|
|
}
|
|
looping = True; // status events not sent to host
|
|
break;
|
|
|
|
case VersionReply:
|
|
destination->Type = RIO::VersionEvent;
|
|
MajorRevision = receive_buffer[1];
|
|
MinorRevision = receive_buffer[2];
|
|
break;
|
|
|
|
case AnalogReply:
|
|
destination->Type = RIO::AnalogEvent;
|
|
//
|
|
// NOTE: no data is sent in this packet.
|
|
// The application is expected to directly read
|
|
// the values in the object.
|
|
//
|
|
|
|
//----------------------------------------
|
|
// Discard the next N analog packets
|
|
// (set by ForceCenterJoystick)
|
|
//----------------------------------------
|
|
// if (discardCount)
|
|
// {
|
|
// --discardCount;
|
|
// }
|
|
// else
|
|
{
|
|
Check(throttleRanger);
|
|
Throttle = throttleRanger->Update(
|
|
// Note (-): Throttle counts BACKWARDS
|
|
-CombinePair(receive_buffer[1], receive_buffer[2])
|
|
);
|
|
|
|
Check(leftPedalRanger);
|
|
LeftPedal = leftPedalRanger->Update(
|
|
CombinePair(receive_buffer[3], receive_buffer[4])
|
|
);
|
|
|
|
Check(rightPedalRanger);
|
|
RightPedal = rightPedalRanger->Update(
|
|
CombinePair(receive_buffer[5], receive_buffer[6])
|
|
);
|
|
|
|
Check(joystickYRanger);
|
|
JoystickY = joystickYRanger->Update(
|
|
CombinePair(receive_buffer[7], receive_buffer[8])
|
|
);
|
|
|
|
Check(joystickXRanger);
|
|
JoystickX = joystickXRanger->Update(
|
|
CombinePair(receive_buffer[9], receive_buffer[10])
|
|
);
|
|
}
|
|
break;
|
|
|
|
case ButtonPressed:
|
|
destination->Type = RIO::ButtonPressedEvent;
|
|
destination->Data.Unit = receive_buffer[1];
|
|
break;
|
|
|
|
case ButtonReleased:
|
|
destination->Type = RIO::ButtonReleasedEvent;
|
|
destination->Data.Unit = receive_buffer[1];
|
|
break;
|
|
|
|
case KeyPressed:
|
|
destination->Type = RIO::KeyEvent;
|
|
destination->Data.Keyboard.Unit = receive_buffer[1];
|
|
destination->Data.Keyboard.Key = receive_buffer[2];
|
|
break;
|
|
|
|
case TestModeChange:
|
|
if (receive_buffer[1] != 0)
|
|
{
|
|
Tell("RIO entered test mode\n");
|
|
TestModeActive = 1;
|
|
|
|
OpenFailureFile();
|
|
Check(failureFile);
|
|
failureFile->DeletePage("RIOBoardErrors");
|
|
failureFile->DeletePage("RIODeadLamps");
|
|
}
|
|
else
|
|
{
|
|
Tell("RIO exited test mode\n");
|
|
TestModeActive = 0;
|
|
CloseFailureFile();
|
|
}
|
|
looping = True; // this event not sent to host
|
|
break;
|
|
|
|
default: // discard unused or bogus packets
|
|
looping = True;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
while (looping);
|
|
|
|
Check_Fpu();
|
|
return reply;
|
|
}
|
|
|
|
void
|
|
RIO::ForceCenterJoystick()
|
|
{
|
|
Check(this);
|
|
|
|
// ResetVerticalJoystick();
|
|
// ResetHorizontalJoystick();
|
|
//-------------------------------------------
|
|
// Make sure we don't use 'old' data
|
|
// (skip the next two packets)
|
|
// ...why 2? Just to make sure...
|
|
//-------------------------------------------
|
|
// discardCount = 2;
|
|
|
|
Check(joystickXRanger);
|
|
joystickXRanger->ForceToZero();
|
|
|
|
Check(joystickYRanger);
|
|
joystickYRanger->ForceToZero();
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
RIO::SetJoystickDeadBand(Scalar dead_band)
|
|
{
|
|
Check(this);
|
|
|
|
Check(joystickXRanger);
|
|
joystickXRanger->SetDeadBand(dead_band);
|
|
|
|
Check(joystickYRanger);
|
|
joystickYRanger->SetDeadBand(dead_band);
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
RIO::SetThrottleDeadBand(Scalar dead_band)
|
|
{
|
|
Check(this);
|
|
|
|
Check(throttleRanger);
|
|
throttleRanger->SetDeadBand(dead_band);
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
RIO::SetPedalsDeadBand(Scalar dead_band)
|
|
{
|
|
Check(this);
|
|
|
|
Check(leftPedalRanger);
|
|
leftPedalRanger->SetDeadBand(dead_band);
|
|
|
|
Check(rightPedalRanger);
|
|
rightPedalRanger->SetDeadBand(dead_band);
|
|
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
RIO::RequestCheck()
|
|
{
|
|
Check(this);
|
|
static Byte request_check_string[] = { RIO::CheckRequest };
|
|
|
|
if (operational && !TestModeActive)
|
|
{
|
|
SendPacket((Byte *) request_check_string);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
RIO::RequestVersion()
|
|
{
|
|
Check(this);
|
|
static Byte request_version_string[] = { RIO::VersionRequest };
|
|
|
|
if (operational && !TestModeActive)
|
|
{
|
|
SendPacket((Byte *) request_version_string);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
RIO::RequestAnalogUpdate()
|
|
{
|
|
//DEBUG_STREAM << "Analog Update Requested: " << GetTickCount() << std::endl << std::flush;
|
|
Check(this);
|
|
static Byte request_analog_string[] = { RIO::AnalogRequest };
|
|
|
|
if (operational && !TestModeActive)
|
|
{
|
|
SendPacket((Byte *) request_analog_string);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
RIO::GeneralReset()
|
|
{
|
|
Check(this);
|
|
static Byte request_reset_string[] = { RIO::ResetRequest, 0 };
|
|
|
|
if (operational && !TestModeActive)
|
|
{
|
|
SendPacket((Byte *) request_reset_string);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
RIO::ResetThrottle()
|
|
{
|
|
Check(this);
|
|
static Byte request_throttle_string[] = { RIO::ResetRequest, 1 };
|
|
|
|
if (operational && !TestModeActive)
|
|
{
|
|
SendPacket((Byte *) request_throttle_string);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
RIO::ResetLeftPedal()
|
|
{
|
|
Check(this);
|
|
static Byte request_lpedal_string[] = { RIO::ResetRequest, 2 };
|
|
|
|
if (operational && !TestModeActive)
|
|
{
|
|
SendPacket((Byte *) request_lpedal_string);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
RIO::ResetRightPedal()
|
|
{
|
|
Check(this);
|
|
static Byte request_rpedal_string[] = { RIO::ResetRequest, 3 };
|
|
|
|
if (operational && !TestModeActive)
|
|
{
|
|
SendPacket((Byte *) request_rpedal_string);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
RIO::ResetVerticalJoystick()
|
|
{
|
|
Check(this);
|
|
static Byte request_vstick_string[] = { RIO::ResetRequest, 4 };
|
|
|
|
if (operational && !TestModeActive)
|
|
{
|
|
SendPacket((Byte *) request_vstick_string);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
RIO::ResetHorizontalJoystick()
|
|
{
|
|
Check(this);
|
|
static Byte request_hstick_string[] = { RIO::ResetRequest, 5 };
|
|
|
|
if (operational && !TestModeActive)
|
|
{
|
|
SendPacket((Byte *) request_hstick_string);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
RIO::SetLamp(int lampNumber, int state)
|
|
{
|
|
Check(this);
|
|
static Byte request_lamp_string[] = { RIO::LampRequest, 0, 0 };
|
|
|
|
if (operational)
|
|
{
|
|
request_lamp_string[1] = (Byte) (lampNumber & 0x7F);
|
|
request_lamp_string[2] = (Byte) (state & 0x7F);
|
|
SendPacket((Byte *) request_lamp_string);
|
|
}
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
RIO::OpenFailureFile()
|
|
{
|
|
Check(this);
|
|
|
|
if (failureFileOpenCount == 0)
|
|
{
|
|
failureFile = new NotationFile("FAILURE.LOG");
|
|
Check(failureFile);
|
|
Register_Object(failureFile);
|
|
}
|
|
++failureFileOpenCount;
|
|
Check_Fpu();
|
|
}
|
|
|
|
void
|
|
RIO::CloseFailureFile()
|
|
{
|
|
Check(this);
|
|
|
|
--failureFileOpenCount;
|
|
if (failureFileOpenCount <= 0)
|
|
{
|
|
failureFileOpenCount = 0;
|
|
|
|
Check(failureFile);
|
|
Unregister_Object(failureFile);
|
|
delete failureFile;
|
|
}
|
|
Check_Fpu();
|
|
}
|