Files
BT412/engine/MUNGA_L4/L4RIO.h
T
CydandClaude Fable 5 fe97746a51 Input: PadRIO -- play without the pod (L4CONTROLS=PAD), Workstream A.1
Ported from RP412: RIOBase split out of the serial RIO (L4RIO.h),
rioPointer is RIOBase* (L4CTRL.h), PAD token -> new PadRIO() speaking
the RIO surface from an XInput pad + keyboard (L4PADRIO/L4PADBINDINGS,
vRIO bindings.txt grammar, hot-plug), KeyLight RGB mirror TU
(BT412KEYLIGHT, /std:c++17 per-file).

BT-side fixes PadRIO forced into the open:
- Both keyboard input bridges (mech4.cpp, mechmppr.cpp BT_KEY_BRIDGE)
  stand down when a RIO device exists -- they overwrote the engine
  controls push every frame. M/X conveniences stay live.
- Mapper attribute chain OFF BY ONE (latent real-pod bug): the DOS
  chain below MechControlsMapper carried two base attributes, WinTesla
  carries one, and AttributeIndexSet::Find is positional -- the .CTL
  stick mapping wrote throttlePosition. Pad slot + binary-locked enum;
  gotcha ledgered (reconstruction-gotchas #11).

Verified: PAD throttle lever ramps + sticks, stick turns with the
authentic speed-vs-turn clamp (61.5 -> 22.0 u/s), mech drives; keyboard
fallback intact (BT_FORCE_THROTTLE harness). New diags: BT_CTRLMAP_LOG,
BT_STICK_LOG. (Phase 2 of docs/BT412-ROADMAP.md)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 08:16:33 -05:00

390 lines
7.7 KiB
C++

#pragma once
#include "l4pcspak.h"
#include "..\munga\notation.h"
#include "..\munga\average.h"
// These are purposely grouped as two parameters in one equate
// (See PCSPAK.HH).
// The standard PC COM ports ALWAYS use these combinations.
//#define RIO_COM1 PCSP_COM1
//#define RIO_COM2 PCSP_COM2
//#define RIO_COM3 PCSP_COM3
//#define RIO_COM4 PCSP_COM4
class FilterChannel SIGNATURED
{
public:
static const char *highName;
static const char *centerName;
static const char *lowName;
static const char *joystickXName;
static const char *joystickYName;
static const char *throttleName;
static const char *leftPedalName;
static const char *rightPedalName;
enum AlignMode { unaligned, normal };
enum PolarMode { unipolar, bipolar };
FilterChannel();
FilterChannel(
NotationFile *init_file,
const char *page_name,
int default_min, int default_max
);
FilterChannel(
NotationFile *init_file,
const char *page_name,
int default_min, int default_center, int default_max
);
~FilterChannel();
void
SetPolarity(PolarMode newPolarity);
void
SetDeadBand(Scalar amount_of_deadband);
virtual void
BeginAlignment();
virtual void
EndAlignment(NotationFile *init_file=NULL);
virtual Scalar
Update(int value);
Logical
TestInstance() const;
protected:
void
CalculateDeadBands();
const char *pageName;
PolarMode polarity;
AlignMode mode;
int previousValue, min, max, center;
int lowerRange, lowerDeadband;
int upperRange, upperDeadband;
Scalar deadbandScalar;
Logical valuesFromFile;
AverageOf<int> average;
};
class RIO;
class Ranger SIGNATURED
{
friend class RIO;
protected:
Ranger(
const char *page_name,
int default_min,
int default_max,
Scalar deadband_scalar
);
~Ranger();
void
ForceToZero();
void
SetDeadBand(Scalar amount_of_deadband);
Scalar
Update(int input);
Logical
TestInstance() const;
void
Statistics(NotationFile *stat_file);
const char
*pageName;
Logical
sampledInputFlag;
int
offset,
hardwareMinimum,
hardwareMaximum,
hardwareRange,
deadbandInteger,
highestInput,
lowestInput;
};
//########################################################################
//############################### RIOBase ################################
//########################################################################
//
// The control surface the game consumes from the cockpit RIO board,
// independent of transport. RIO (below) is the serial-hardware
// implementation; PadRIO (l4padrio.h) synthesizes the same surface from
// an XInput controller + the PC keyboard for cockpit-less play.
//
class RIOBase
{
public:
enum RIOStatusType {
BoardOk=0, BoardMissing=1, BoardBad=2,
LampBad=3,
RestartCount=4, AbandonCount=5, FullBufferCount=6
};
enum LampState{
solid=0, flashSlow=1, flashMed=2, flashFast=3,
state1Off=0x00, state1Dim=0x04, state1Bright=0x0C,
state2Off=0x00, state2Dim=0x10, state2Bright=0x30,
};
enum RIOEventType {
ButtonPressedEvent,
ButtonReleasedEvent,
KeyEvent,
AnalogEvent,
VersionEvent
};
struct RIOKeyPair
{
int Unit;
int Key;
};
struct RIOEvent
{
RIOEventType Type;
union
{
int Unit;
RIOKeyPair Keyboard;
}Data;
};
RIOBase()
{
TestModeActive = 0;
Throttle = (Scalar) 0;
LeftPedal = (Scalar) 0;
RightPedal = (Scalar) 0;
JoystickX = (Scalar) 0;
JoystickY = (Scalar) 0;
MajorRevision = 0;
MinorRevision = 0;
}
virtual ~RIOBase() {}
virtual Logical
TestInstance() const
{ return True; }
virtual Logical
GetNextEvent(RIOEvent *destinationPointer) = 0;
virtual void
ForceCenterJoystick() {}
virtual void
SetJoystickDeadBand(Scalar) {}
virtual void
SetThrottleDeadBand(Scalar) {}
virtual void
SetPedalsDeadBand(Scalar) {}
virtual void
RequestCheck() {}
virtual void
RequestVersion() {}
virtual void
RequestAnalogUpdate() {}
virtual void
GeneralReset() {}
virtual void
ResetThrottle() {}
virtual void
ResetLeftPedal() {}
virtual void
ResetRightPedal() {}
virtual void
ResetVerticalJoystick() {}
virtual void
ResetHorizontalJoystick() {}
virtual void
SetLamp(int lampNumber, int state) = 0;
int
TestModeActive;
Scalar
Throttle, LeftPedal, RightPedal, JoystickX, JoystickY;
int
MajorRevision, MinorRevision;
};
class RIO :
public RIOBase,
public PCSerialPacket
{
protected:
enum RIOCommand{
CheckRequest=0x80,
VersionRequest,
AnalogRequest,
ResetRequest,
LampRequest,
CheckReply,
VersionReply,
AnalogReply,
ButtonPressed,
ButtonReleased,
KeyPressed,
KeyReleased,
TestModeChange
};
public:
//Win32 Serial support: ADB 02/13/07
//RIO(Word port, Word intNum, Logical perform_tests = True);
RIO(const char* port, Logical perform_tests = True);
~RIO();
Logical
TestInstance() const;
Logical
GetNextEvent(RIOEvent *destinationPointer);
void
ForceCenterJoystick(),
SetJoystickDeadBand(Scalar dead_band),
SetThrottleDeadBand(Scalar dead_band),
SetPedalsDeadBand(Scalar dead_band);
void
RequestCheck(),
RequestVersion(),
RequestAnalogUpdate();
void
GeneralReset(),
ResetThrottle(),
ResetLeftPedal(),
ResetRightPedal(),
ResetVerticalJoystick(),
ResetHorizontalJoystick();
void
SetLamp(int lampNumber, int state);
void
TestCheckReply(int type, int location)
{
RIO::reply_check_string[1] = (Byte) (type & 0x7F);
RIO::reply_check_string[2] = (Byte) (location & 0x7F);
SendPacket((Byte *)reply_check_string);
}
void
TestVersionReply(int major, int minor)
{
RIO::reply_version_string[1] = (Byte) (major & 0x7F);
RIO::reply_version_string[2] = (Byte) (minor & 0x7F);
SendPacket((Byte *)reply_version_string);
}
void
TestAnalogReply()
{
SendPacket((Byte *)reply_analog_string);
}
void
TestButtonPressed(int button)
{
RIO::reply_button_press_string[1] = (Byte) (button & 0x7F);
SendPacket((Byte *)reply_button_press_string);
}
void
TestButtonReleased(int button)
{
RIO::reply_button_release_string[1] = (Byte) (button & 0x7F);
SendPacket((Byte *)reply_button_release_string);
}
void
TestKeyPressed(int board, int key)
{
RIO::reply_key_press_string[1] = (Byte) (board & 0x7F);
RIO::reply_key_press_string[2] = (Byte) (key & 0x7F);
SendPacket((Byte *)reply_key_press_string);
}
void
TestKeyReleased(int board, int key)
{
RIO::reply_key_release_string[1] = (Byte) (board & 0x7F);
RIO::reply_key_release_string[2] = (Byte) (key & 0x7F);
SendPacket((Byte *)reply_key_release_string);
}
void
TestEnterTestMode()
{SendPacket((Byte *)reply_test_enter_string);}
void
TestExitTestMode()
{SendPacket((Byte *)reply_test_exit_string);}
int
ReceiveQueueCount()
{ return PCSerialPacket::ReceiveQueueCount(); }
int
TransmitQueueCount()
{ return PCSerialPacket::TransmitQueueCount(); }
// TestModeActive, the five analog Scalars, and Major/MinorRevision
// now live in RIOBase.
int remoteRetryCount;
int remoteAbandonCount;
int remoteFullBufferCount;
int lineErrorCount;
int abandonCount;
int overrunCount;
int discardCount; // used by BeginAnalogCalibration()
protected:
void
OpenFailureFile();
void
CloseFailureFile();
void
CheckErrors();
Logical
operational;
Ranger
*leftPedalRanger, *rightPedalRanger;
Ranger
*throttleRanger;
Ranger
*joystickXRanger, *joystickYRanger;
NotationFile
*failureFile;
int
failureFileOpenCount;
static Byte reply_check_string[];
static Byte reply_version_string[];
static Byte reply_analog_string[];
static Byte reply_button_press_string[];
static Byte reply_button_release_string[];
static Byte reply_key_press_string[];
static Byte reply_key_release_string[];
static Byte reply_test_enter_string[];
static Byte reply_test_exit_string[];
};