Properly model analog input.

This commit is contained in:
Christian Speckner 2021-04-05 15:46:30 +02:00
parent c7d3a43f58
commit 8aa14d8c75
19 changed files with 205 additions and 106 deletions

View File

@ -18,7 +18,7 @@
#ifndef STATE_MANAGER_HXX
#define STATE_MANAGER_HXX
#define STATE_HEADER "06020100state"
#define STATE_HEADER "06050300state"
class OSystem;
class RewindManager;

View File

@ -93,9 +93,9 @@ void BoosterWidget::loadConfig()
myPins[kJFire]->setState(!getPin(ourPinNo[kJFire]));
myPins[kJBooster]->setState(
getPin(Controller::AnalogPin::Five) == Controller::MIN_RESISTANCE);
getPin(Controller::AnalogPin::Five) == AnalogReadout::connectToVcc());
myPins[kJTrigger]->setState(
getPin(Controller::AnalogPin::Nine) == Controller::MIN_RESISTANCE);
getPin(Controller::AnalogPin::Nine) == AnalogReadout::connectToVcc());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -115,13 +115,13 @@ void BoosterWidget::handleCommand(
break;
case kJBooster:
setPin(Controller::AnalogPin::Five,
myPins[id]->getState() ? Controller::MIN_RESISTANCE :
Controller::MAX_RESISTANCE);
myPins[id]->getState() ? AnalogReadout::connectToVcc() :
AnalogReadout::disconnect());
break;
case kJTrigger:
setPin(Controller::AnalogPin::Nine,
myPins[id]->getState() ? Controller::MIN_RESISTANCE :
Controller::MAX_RESISTANCE);
myPins[id]->getState() ? AnalogReadout::connectToVcc() :
AnalogReadout::disconnect());
break;
default:
break;

View File

@ -86,7 +86,7 @@ void GenesisWidget::loadConfig()
myPins[kJBbtn]->setState(!getPin(ourPinNo[kJBbtn]));
myPins[kJCbtn]->setState(
getPin(Controller::AnalogPin::Five) == Controller::MAX_RESISTANCE);
getPin(Controller::AnalogPin::Five) == AnalogReadout::disconnect());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -106,8 +106,8 @@ void GenesisWidget::handleCommand(
break;
case kJCbtn:
setPin(Controller::AnalogPin::Five,
myPins[id]->getState() ? Controller::MAX_RESISTANCE :
Controller::MIN_RESISTANCE);
myPins[id]->getState() ? AnalogReadout::disconnect() :
AnalogReadout::connectToVcc());
break;
default:
break;

View File

@ -109,9 +109,9 @@ PaddleWidget::PaddleWidget(GuiObject* boss, const GUI::Font& font, int x, int y,
void PaddleWidget::loadConfig()
{
myP0Resistance->setValue(Int32(Paddles::MAX_RESISTANCE -
getPin(Controller::AnalogPin::Nine)));
getPin(Controller::AnalogPin::Nine).resistance));
myP1Resistance->setValue(Int32(Paddles::MAX_RESISTANCE -
getPin(Controller::AnalogPin::Five)));
getPin(Controller::AnalogPin::Five).resistance));
myP0Fire->setState(!getPin(Controller::DigitalPin::Four));
myP1Fire->setState(!getPin(Controller::DigitalPin::Three));
}
@ -124,11 +124,11 @@ void PaddleWidget::handleCommand(
{
case kP0Changed:
setPin(Controller::AnalogPin::Nine,
static_cast<Int32>(Paddles::MAX_RESISTANCE - myP0Resistance->getValue()));
AnalogReadout::connectToVcc(Paddles::MAX_RESISTANCE - myP0Resistance->getValue()));
break;
case kP1Changed:
setPin(Controller::AnalogPin::Five,
static_cast<Int32>(Paddles::MAX_RESISTANCE - myP1Resistance->getValue()));
AnalogReadout::connectToVcc(Paddles::MAX_RESISTANCE - myP1Resistance->getValue()));
break;
case kP0Fire:
setPin(Controller::DigitalPin::Four, !myP0Fire->getState());

View File

@ -32,8 +32,8 @@ BoosterGrip::BoosterGrip(Jack jack, const Event& event, const System& system)
myBoosterEvent = Event::JoystickOneFire9;
}
setPin(AnalogPin::Five, MAX_RESISTANCE);
setPin(AnalogPin::Nine, MAX_RESISTANCE);
setPin(AnalogPin::Five, AnalogReadout::disconnect());
setPin(AnalogPin::Nine, AnalogReadout::disconnect());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -48,6 +48,7 @@ void BoosterGrip::updateButtons()
updateMouseButtons(firePressed, boosterPressed);
setPin(DigitalPin::Six, !getAutoFireState(firePressed));
setPin(AnalogPin::Five, triggerPressed ? MIN_RESISTANCE : MAX_RESISTANCE);
setPin(AnalogPin::Nine, boosterPressed ? MIN_RESISTANCE : MAX_RESISTANCE);
setPin(AnalogPin::Five, triggerPressed ? AnalogReadout::connectToVcc() : AnalogReadout::disconnect());
setPin(AnalogPin::Nine, boosterPressed ? AnalogReadout::connectToVcc() : AnalogReadout::disconnect());
}

View File

@ -31,10 +31,10 @@ CompuMate::CompuMate(const Console& console, const Event& event,
myLeftController = make_unique<CMControl>(*this, Controller::Jack::Left, event, system);
myRightController = make_unique<CMControl>(*this, Controller::Jack::Right, event, system);
myLeftController->setPin(Controller::AnalogPin::Nine, Controller::MAX_RESISTANCE);
myLeftController->setPin(Controller::AnalogPin::Five, Controller::MIN_RESISTANCE);
myRightController->setPin(Controller::AnalogPin::Nine, Controller::MIN_RESISTANCE);
myRightController->setPin(Controller::AnalogPin::Five, Controller::MAX_RESISTANCE);
myLeftController->setPin(Controller::AnalogPin::Nine, AnalogReadout::connectToGround());
myLeftController->setPin(Controller::AnalogPin::Five, AnalogReadout::connectToVcc());
myRightController->setPin(Controller::AnalogPin::Nine, AnalogReadout::connectToVcc());
myRightController->setPin(Controller::AnalogPin::Five, AnalogReadout::connectToGround());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -44,17 +44,17 @@ void CompuMate::update()
Controller& lp = myConsole.leftController();
Controller& rp = myConsole.rightController();
lp.setPin(Controller::AnalogPin::Nine, Controller::MAX_RESISTANCE);
lp.setPin(Controller::AnalogPin::Five, Controller::MIN_RESISTANCE);
lp.setPin(Controller::AnalogPin::Nine, AnalogReadout::connectToGround());
lp.setPin(Controller::AnalogPin::Five, AnalogReadout::connectToVcc());
lp.setPin(Controller::DigitalPin::Six, true);
rp.setPin(Controller::AnalogPin::Nine, Controller::MIN_RESISTANCE);
rp.setPin(Controller::AnalogPin::Five, Controller::MAX_RESISTANCE);
rp.setPin(Controller::AnalogPin::Nine, AnalogReadout::connectToVcc());
rp.setPin(Controller::AnalogPin::Five, AnalogReadout::connectToGround());
rp.setPin(Controller::DigitalPin::Six, true);
if (myEvent.get(Event::CompuMateShift))
rp.setPin(Controller::AnalogPin::Five, Controller::MIN_RESISTANCE);
rp.setPin(Controller::AnalogPin::Five, AnalogReadout::connectToVcc());
if (myEvent.get(Event::CompuMateFunc))
lp.setPin(Controller::AnalogPin::Nine, Controller::MIN_RESISTANCE);
lp.setPin(Controller::AnalogPin::Nine, AnalogReadout::connectToVcc());
rp.setPin(Controller::DigitalPin::Three, true);
rp.setPin(Controller::DigitalPin::Four, true);
@ -72,7 +72,7 @@ void CompuMate::update()
// Emulate the '?' character (Shift-6) with the actual question key
if (myEvent.get(Event::CompuMateQuestion))
{
rp.setPin(Controller::AnalogPin::Five, Controller::MIN_RESISTANCE);
rp.setPin(Controller::AnalogPin::Five, AnalogReadout::connectToVcc());
lp.setPin(Controller::DigitalPin::Six, false);
}
if (myEvent.get(Event::CompuMateY)) rp.setPin(Controller::DigitalPin::Three, false);
@ -84,7 +84,7 @@ void CompuMate::update()
// Emulate the '[' character (Shift-8) with the actual key
if (myEvent.get(Event::CompuMateLeftBracket))
{
rp.setPin(Controller::AnalogPin::Five, Controller::MIN_RESISTANCE);
rp.setPin(Controller::AnalogPin::Five, AnalogReadout::connectToVcc());
lp.setPin(Controller::DigitalPin::Six, false);
}
if (myEvent.get(Event::CompuMateI)) rp.setPin(Controller::DigitalPin::Three, false);
@ -96,7 +96,7 @@ void CompuMate::update()
// Emulate the '-' character (Shift-2) with the actual minus key
if (myEvent.get(Event::CompuMateMinus))
{
rp.setPin(Controller::AnalogPin::Five, Controller::MIN_RESISTANCE);
rp.setPin(Controller::AnalogPin::Five, AnalogReadout::connectToVcc());
lp.setPin(Controller::DigitalPin::Six, false);
}
if (myEvent.get(Event::CompuMateW)) rp.setPin(Controller::DigitalPin::Three, false);
@ -114,7 +114,7 @@ void CompuMate::update()
// Emulate the quote character (Shift-0) with the actual quote key
if (myEvent.get(Event::CompuMateQuote))
{
rp.setPin(Controller::AnalogPin::Five, Controller::MIN_RESISTANCE);
rp.setPin(Controller::AnalogPin::Five, AnalogReadout::connectToVcc());
lp.setPin(Controller::DigitalPin::Six, false);
}
if (myEvent.get(Event::CompuMateP)) rp.setPin(Controller::DigitalPin::Three, false);
@ -123,7 +123,7 @@ void CompuMate::update()
// Emulate Ctrl-space (aka backspace) with the actual Backspace key
if (myEvent.get(Event::CompuMateBackspace))
{
lp.setPin(Controller::AnalogPin::Nine, Controller::MIN_RESISTANCE);
lp.setPin(Controller::AnalogPin::Nine, AnalogReadout::connectToVcc());
rp.setPin(Controller::DigitalPin::Four, false);
}
break;
@ -132,7 +132,7 @@ void CompuMate::update()
// Emulate the ']' character (Shift-9) with the actual key
if (myEvent.get(Event::CompuMateRightBracket))
{
rp.setPin(Controller::AnalogPin::Five, Controller::MIN_RESISTANCE);
rp.setPin(Controller::AnalogPin::Five, AnalogReadout::connectToVcc());
lp.setPin(Controller::DigitalPin::Six, false);
}
if (myEvent.get(Event::CompuMateO)) rp.setPin(Controller::DigitalPin::Three, false);
@ -144,7 +144,7 @@ void CompuMate::update()
// Emulate the '=' character (Shift-5) with the actual equals key
if (myEvent.get(Event::CompuMateEquals))
{
rp.setPin(Controller::AnalogPin::Five, Controller::MIN_RESISTANCE);
rp.setPin(Controller::AnalogPin::Five, AnalogReadout::connectToVcc());
lp.setPin(Controller::DigitalPin::Six, false);
}
if (myEvent.get(Event::CompuMateT)) rp.setPin(Controller::DigitalPin::Three, false);
@ -156,7 +156,7 @@ void CompuMate::update()
// Emulate the '+' character (Shift-1) with the actual plus key (Shift-=)
if (myEvent.get(Event::CompuMatePlus))
{
rp.setPin(Controller::AnalogPin::Five, Controller::MIN_RESISTANCE);
rp.setPin(Controller::AnalogPin::Five, AnalogReadout::connectToVcc());
lp.setPin(Controller::DigitalPin::Six, false);
}
if (myEvent.get(Event::CompuMateQ)) rp.setPin(Controller::DigitalPin::Three, false);
@ -168,7 +168,7 @@ void CompuMate::update()
// Emulate the '/' character (Shift-4) with the actual slash key
if (myEvent.get(Event::CompuMateSlash))
{
rp.setPin(Controller::AnalogPin::Five, Controller::MIN_RESISTANCE);
rp.setPin(Controller::AnalogPin::Five, AnalogReadout::connectToVcc());
lp.setPin(Controller::DigitalPin::Six, false);
}
if (myEvent.get(Event::CompuMateR)) rp.setPin(Controller::DigitalPin::Three, false);

View File

@ -48,7 +48,7 @@ bool Controller::read(DigitalPin pin)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Int32 Controller::read(AnalogPin pin)
AnalogReadout::Connection Controller::read(AnalogPin pin)
{
return getPin(pin);
}
@ -66,8 +66,8 @@ bool Controller::save(Serializer& out) const
out.putBool(getPin(DigitalPin::Six));
// Output the analog pins
out.putInt(getPin(AnalogPin::Five));
out.putInt(getPin(AnalogPin::Nine));
getPin(AnalogPin::Five).save(out);
getPin(AnalogPin::Nine).save(out);
}
catch(...)
{
@ -90,8 +90,8 @@ bool Controller::load(Serializer& in)
setPin(DigitalPin::Six, in.getBool());
// Input the analog pins
setPin(AnalogPin::Five, in.getInt());
setPin(AnalogPin::Nine, in.getInt());
getPin(AnalogPin::Five).load(in);
getPin(AnalogPin::Nine).load(in);
}
catch(...)
{

View File

@ -27,6 +27,7 @@ class System;
#include "bspf.hxx"
#include "Serializable.hxx"
#include "AnalogReadout.hxx"
/**
A controller is a device that plugs into either the left or right
@ -154,7 +155,7 @@ class Controller : public Serializable
@param pin The pin of the controller jack to read
@return The resistance at the specified pin
*/
virtual Int32 read(AnalogPin pin);
virtual AnalogReadout::Connection read(AnalogPin pin);
/**
Write the given value to the specified digital pin for this
@ -280,13 +281,6 @@ class Controller : public Serializable
*/
static void setAutoFireRate(int rate, bool isNTSC = true);
public:
/// Constant which represents maximum resistance for analog pins
static constexpr Int32 MAX_RESISTANCE = 0x7FFFFFFF;
/// Constant which represents minimum resistance for analog pins
static constexpr Int32 MIN_RESISTANCE = 0x00000000;
protected:
/**
Derived classes *must* use these accessor/mutator methods.
@ -298,12 +292,12 @@ class Controller : public Serializable
inline bool getPin(DigitalPin pin) const {
return myDigitalPinState[static_cast<int>(pin)];
}
inline void setPin(AnalogPin pin, Int32 value) {
inline void setPin(AnalogPin pin, AnalogReadout::Connection value) {
myAnalogPinValue[static_cast<int>(pin)] = value;
if(myOnAnalogPinUpdateCallback)
myOnAnalogPinUpdateCallback(pin);
}
inline Int32 getPin(AnalogPin pin) const {
inline AnalogReadout::Connection getPin(AnalogPin pin) const {
return myAnalogPinValue[static_cast<int>(pin)];
}
inline void resetDigitalPins() {
@ -314,8 +308,8 @@ class Controller : public Serializable
setPin(DigitalPin::Six, true);
}
inline void resetAnalogPins() {
setPin(AnalogPin::Five, MAX_RESISTANCE);
setPin(AnalogPin::Nine, MAX_RESISTANCE);
setPin(AnalogPin::Five, AnalogReadout::disconnect());
setPin(AnalogPin::Nine, AnalogReadout::disconnect());
}
/**
@ -384,7 +378,8 @@ class Controller : public Serializable
std::array<bool, 5> myDigitalPinState{true, true, true, true, true};
/// The analog value on each analog pin
std::array<Int32, 2> myAnalogPinValue{MAX_RESISTANCE, MAX_RESISTANCE};
std::array<AnalogReadout::Connection, 2>
myAnalogPinValue{AnalogReadout::disconnect(), AnalogReadout::disconnect()};
private:
// Following constructors and assignment operators not supported

View File

@ -44,10 +44,10 @@ class ControllerLowLevel
inline bool getPin(Controller::DigitalPin pin) const {
return myController.getPin(pin);
}
inline void setPin(Controller::AnalogPin pin, Int32 value) {
inline void setPin(Controller::AnalogPin pin, AnalogReadout::Connection value) {
myController.setPin(pin, value);
}
inline Int32 getPin(Controller::AnalogPin pin) const {
inline AnalogReadout::Connection getPin(Controller::AnalogPin pin) const {
return myController.getPin(pin);
}
inline void resetDigitalPins() {

View File

@ -26,7 +26,7 @@ Genesis::Genesis(Jack jack, const Event& event, const System& system)
else
myButtonCEvent = Event::JoystickOneFire5;
setPin(AnalogPin::Five, MIN_RESISTANCE);
setPin(AnalogPin::Five, AnalogReadout::connectToVcc());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -41,5 +41,5 @@ void Genesis::updateButtons()
updateMouseButtons(firePressed, buttonCPressed);
setPin(DigitalPin::Six, !getAutoFireState(firePressed));
setPin(AnalogPin::Five, buttonCPressed ? MAX_RESISTANCE : MIN_RESISTANCE);
setPin(AnalogPin::Five, buttonCPressed ? AnalogReadout::disconnect() : AnalogReadout::connectToVcc());
}

View File

@ -67,16 +67,16 @@ Keyboard::ColumnState Keyboard::processColumn(const Event::Type buttons[]) {
return ColumnState::notConnected;
}
Int32 Keyboard::columnStateToAnalogSignal(ColumnState state) const {
AnalogReadout::Connection Keyboard::columnStateToAnalogSignal(ColumnState state) const {
switch (state) {
case ColumnState::gnd:
return MAX_RESISTANCE;
return AnalogReadout::connectToGround();
case ColumnState::vcc:
return 0;
return AnalogReadout::connectToVcc();
case ColumnState::notConnected:
return INTERNAL_RESISTANCE;
return AnalogReadout::connectToVcc(INTERNAL_RESISTANCE);
default:
throw runtime_error("unreachable");

View File

@ -70,7 +70,7 @@ class Keyboard : public Controller
private:
ColumnState processColumn(const Event::Type buttons[]);
Int32 columnStateToAnalogSignal(ColumnState state) const;
AnalogReadout::Connection columnStateToAnalogSignal(ColumnState state) const;
private:
// Pre-compute the events we care about based on given port

View File

@ -27,8 +27,8 @@ Paddles::Paddles(Jack jack, const Event& event, const System& system,
{
// We must start with minimum resistance; see commit
// 38b452e1a047a0dca38c5bcce7c271d40f76736e for more information
setPin(AnalogPin::Five, MIN_RESISTANCE);
setPin(AnalogPin::Nine, MIN_RESISTANCE);
setPin(AnalogPin::Five, AnalogReadout::connectToVcc());
setPin(AnalogPin::Nine, AnalogReadout::connectToVcc());
// The following logic reflects that mapping paddles to different
// devices can be extremely complex
@ -181,12 +181,12 @@ void Paddles::update()
// Only change state if the charge has actually changed
if(myCharge[1] != myLastCharge[1])
{
setPin(AnalogPin::Five, Int32(MAX_RESISTANCE * (myCharge[1] / double(TRIGMAX))));
setPin(AnalogPin::Five, AnalogReadout::connectToVcc(MAX_RESISTANCE * (myCharge[1] / double(TRIGMAX))));
myLastCharge[1] = myCharge[1];
}
if(myCharge[0] != myLastCharge[0])
{
setPin(AnalogPin::Nine, Int32(MAX_RESISTANCE * (myCharge[0] / double(TRIGMAX))));
setPin(AnalogPin::Nine, AnalogReadout::connectToVcc(MAX_RESISTANCE * (myCharge[0] / double(TRIGMAX))));
myLastCharge[0] = myCharge[0];
}
}
@ -235,7 +235,7 @@ bool Paddles::updateAnalogAxes()
if(abs(new_val - sa_xaxis) > 10)
sa_xaxis = new_val;
setPin(AnalogPin::Nine, Int32(MAX_RESISTANCE *
setPin(AnalogPin::Nine, AnalogReadout::connectToVcc(MAX_RESISTANCE *
(BSPF::clamp(32768 - Int32(Int32(sa_xaxis) * SENSITIVITY + XCENTER), 0, 65536) / 65536.0)));
sa_changed = true;
}
@ -250,7 +250,7 @@ bool Paddles::updateAnalogAxes()
if(abs(new_val - sa_yaxis) > 10)
sa_yaxis = new_val;
setPin(AnalogPin::Five, Int32(MAX_RESISTANCE *
setPin(AnalogPin::Five, AnalogReadout::connectToVcc(MAX_RESISTANCE *
(BSPF::clamp(32768 - Int32(Int32(sa_yaxis) * SENSITIVITY + YCENTER), 0, 65536) / 65536.0)));
sa_changed = true;
}

View File

@ -162,7 +162,8 @@ class Paddles : public Controller
*/
static void setDigitalPaddleRange(int range);
static constexpr double MAX_RESISTANCE = 1000000.0;
// The maximum value of the paddle pot = 1MOhm
static constexpr uInt32 MAX_RESISTANCE = 1000000;
private:
// Range of values over which digital and mouse movement is scaled

View File

@ -61,8 +61,8 @@ QuadTari::QuadTari(Jack jack, const OSystem& osystem, const System& system,
mySecondController = addController(secondType, true);
// QuadTari auto detection setting
setPin(AnalogPin::Five, MIN_RESISTANCE);
setPin(AnalogPin::Nine, MAX_RESISTANCE);
setPin(AnalogPin::Five, AnalogReadout::connectToVcc());
setPin(AnalogPin::Nine, AnalogReadout::connectToGround());
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -31,7 +31,7 @@ void AnalogReadout::reset(uInt64 timestamp)
myU = 0;
myIsDumped = false;
myValue = 0;
myConnection = disconnect();
myTimestamp = timestamp;
setConsoleTiming(ConsoleTiming::ntsc);
@ -64,14 +64,14 @@ uInt8 AnalogReadout::inpt(uInt64 timestamp)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AnalogReadout::update(double value, uInt64 timestamp, ConsoleTiming consoleTiming)
void AnalogReadout::update(Connection connection, uInt64 timestamp, ConsoleTiming consoleTiming)
{
if (consoleTiming != myConsoleTiming) {
setConsoleTiming(consoleTiming);
}
if (value != myValue) {
myValue = value;
if (connection != myConnection) {
myConnection = connection;
updateCharge(timestamp);
}
@ -89,11 +89,28 @@ void AnalogReadout::setConsoleTiming(ConsoleTiming consoleTiming)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void AnalogReadout::updateCharge(uInt64 timestamp)
{
if (myValue >= 0 && !myIsDumped)
myU = U_SUPP * (1 - (1 - myU / U_SUPP) *
exp(-static_cast<double>(timestamp - myTimestamp) / (myValue * R_POT + R0) / C / myClockFreq));
else
myU *= exp(-static_cast<double>(timestamp - myTimestamp) / (myIsDumped ? R_DUMP : R0) / C / myClockFreq);
if (myIsDumped) {
myU *= exp(-static_cast<double>(timestamp - myTimestamp) / R_DUMP / C / myClockFreq);
} else {
switch (myConnection.type) {
case ConnectionType::vcc:
myU = U_SUPP * (1 - (1 - myU / U_SUPP) *
exp(-static_cast<double>(timestamp - myTimestamp) / (myConnection.resistance + R0) / C / myClockFreq));
break;
case ConnectionType::ground:
myU *= exp(-static_cast<double>(timestamp - myTimestamp) / (myConnection.resistance + R0) / C / myClockFreq);
break;
case ConnectionType::disconnected:
break;
default:
throw runtime_error("unreachable");
}
}
myTimestamp = timestamp;
}
@ -106,7 +123,7 @@ bool AnalogReadout::save(Serializer& out) const
out.putDouble(myUThresh);
out.putDouble(myU);
out.putDouble(myValue);
myConnection.save(out);
out.putLong(myTimestamp);
out.putInt(int(myConsoleTiming));
@ -131,7 +148,7 @@ bool AnalogReadout::load(Serializer& in)
myUThresh = in.getDouble();
myU = in.getDouble();
myValue = in.getDouble();
myConnection.load(in);
myTimestamp = in.getLong();
myConsoleTiming = ConsoleTiming(in.getInt());
@ -147,3 +164,63 @@ bool AnalogReadout::load(Serializer& in)
return true;
}
AnalogReadout::Connection AnalogReadout::connectToGround(uInt32 resistance)
{
return Connection{ConnectionType::ground, resistance};
}
AnalogReadout::Connection AnalogReadout::connectToVcc(uInt32 resistance)
{
return Connection{ConnectionType::vcc, resistance};
}
AnalogReadout::Connection AnalogReadout::disconnect()
{
return Connection{ConnectionType::disconnected, 0};
}
bool AnalogReadout::Connection::save(Serializer& out) const
{
try
{
out.putInt(static_cast<uInt8>(type));
out.putInt(resistance);
}
catch(...)
{
cerr << "ERROR: AnalogReadout::Connection::save" << endl;
return false;
}
return true;
}
bool AnalogReadout::Connection::load(Serializer& in)
{
try
{
type = ConnectionType(in.getInt());
resistance = in.getInt();
}
catch(...)
{
cerr << "ERROR: AnalogReadout::Connection::load" << endl;
return false;
}
return true;
}
bool operator==(const AnalogReadout::Connection& c1, const AnalogReadout::Connection& c2)
{
if (c1.type == AnalogReadout::ConnectionType::disconnected)
return c2.type == AnalogReadout::ConnectionType::disconnected;
return c1.type == c2.type && c1.resistance == c2.resistance;
}
bool operator!=(const AnalogReadout::Connection& c1, const AnalogReadout::Connection& c2)
{
return !(c1 == c2);
}

View File

@ -26,10 +26,24 @@ class AnalogReadout : public Serializable
{
public:
AnalogReadout();
enum class ConnectionType : uInt8 {
ground = 0, vcc = 1, disconnected = 2
};
struct Connection {
ConnectionType type;
uInt32 resistance;
bool save(Serializer& out) const;
bool load(Serializer& in);
friend bool operator==(const AnalogReadout::Connection& c1, const AnalogReadout::Connection& c2);
};
public:
AnalogReadout();
void reset(uInt64 timestamp);
void vblank(uInt8 value, uInt64 timestamp);
@ -37,7 +51,7 @@ class AnalogReadout : public Serializable
uInt8 inpt(uInt64 timestamp);
void update(double value, uInt64 timestamp, ConsoleTiming consoleTiming);
void update(Connection connection, uInt64 timestamp, ConsoleTiming consoleTiming);
/**
Serializable methods (see that class for more information).
@ -45,6 +59,14 @@ class AnalogReadout : public Serializable
bool save(Serializer& out) const override;
bool load(Serializer& in) override;
public:
static Connection connectToGround(uInt32 resistance = 0);
static Connection connectToVcc(uInt32 resistance = 0);
static Connection disconnect();
private:
void setConsoleTiming(ConsoleTiming timing);
@ -56,7 +78,7 @@ class AnalogReadout : public Serializable
double myUThresh{0.0};
double myU{0.0};
double myValue{0.0};
Connection myConnection{ConnectionType::disconnected, 0};
uInt64 myTimestamp{0};
ConsoleTiming myConsoleTiming;
@ -80,4 +102,7 @@ class AnalogReadout : public Serializable
AnalogReadout& operator=(AnalogReadout&&) = delete;
};
bool operator==(const AnalogReadout::Connection& c1, const AnalogReadout::Connection& c2);
bool operator!=(const AnalogReadout::Connection& c1, const AnalogReadout::Connection& c2);
#endif // TIA_ANALOG_READOUT

View File

@ -391,11 +391,11 @@ void TIA::bindToControllers()
switch (pin) {
case Controller::AnalogPin::Five:
updatePaddle(1);
updateAnalogReadout(1);
break;
case Controller::AnalogPin::Nine:
updatePaddle(0);
updateAnalogReadout(0);
break;
}
}
@ -407,18 +407,18 @@ void TIA::bindToControllers()
switch (pin) {
case Controller::AnalogPin::Five:
updatePaddle(3);
updateAnalogReadout(3);
break;
case Controller::AnalogPin::Nine:
updatePaddle(2);
updateAnalogReadout(2);
break;
}
}
);
for (uInt8 i = 0; i < 4; ++i)
updatePaddle(i);
updateAnalogReadout(i);
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -464,22 +464,22 @@ uInt8 TIA::peek(uInt16 address)
break;
case INPT0:
updatePaddle(0);
updateAnalogReadout(0);
result = myAnalogReadouts[0].inpt(myTimestamp) & 0b10000000;
break;
case INPT1:
updatePaddle(1);
updateAnalogReadout(1);
result = myAnalogReadouts[1].inpt(myTimestamp) & 0b10000000;
break;
case INPT2:
updatePaddle(2);
updateAnalogReadout(2);
result = myAnalogReadouts[2].inpt(myTimestamp) & 0b10000000;
break;
case INPT3:
updatePaddle(3);
updateAnalogReadout(3);
result = myAnalogReadouts[3].inpt(myTimestamp) & 0b10000000;
break;
@ -1804,32 +1804,32 @@ void TIA::delayedWrite(uInt8 address, uInt8 value)
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void TIA::updatePaddle(uInt8 idx)
void TIA::updateAnalogReadout(uInt8 idx)
{
Int32 resistance;
AnalogReadout::Connection connection;
switch (idx) {
case 0:
resistance = myConsole.leftController().read(Controller::AnalogPin::Nine);
connection = myConsole.leftController().read(Controller::AnalogPin::Nine);
break;
case 1:
resistance = myConsole.leftController().read(Controller::AnalogPin::Five);
connection = myConsole.leftController().read(Controller::AnalogPin::Five);
break;
case 2:
resistance = myConsole.rightController().read(Controller::AnalogPin::Nine);
connection = myConsole.rightController().read(Controller::AnalogPin::Nine);
break;
case 3:
resistance = myConsole.rightController().read(Controller::AnalogPin::Five);
connection = myConsole.rightController().read(Controller::AnalogPin::Five);
break;
default:
throw runtime_error("invalid paddle index");
throw runtime_error("invalid analog input");
}
myAnalogReadouts[idx].update(
(resistance == Controller::MAX_RESISTANCE) ? -1 : (double(resistance) / Paddles::MAX_RESISTANCE),
connection,
myTimestamp,
myTimingProvider()
);

View File

@ -663,9 +663,9 @@ class TIA : public Device
void delayedWrite(uInt8 address, uInt8 value);
/**
* Update all paddle readout circuits to the current controller state.
* Update analog readout circuit to the current controller state.
*/
void updatePaddle(uInt8 idx);
void updateAnalogReadout(uInt8 idx);
/**
* Get the target counter value during a RESx. This essentially depends on