From c33bccbc6169240109ba0035f5468029965d6825 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Mon, 5 Apr 2021 15:46:30 +0200 Subject: [PATCH] Properly model analog input. --- src/common/StateManager.hxx | 2 +- src/debugger/gui/BoosterWidget.cxx | 12 ++-- src/debugger/gui/GenesisWidget.cxx | 6 +- src/debugger/gui/PaddleWidget.cxx | 8 +-- src/emucore/Booster.cxx | 9 +-- src/emucore/CompuMate.cxx | 38 ++++++------ src/emucore/Control.cxx | 10 +-- src/emucore/Control.hxx | 21 +++---- src/emucore/ControlLowLevel.hxx | 4 +- src/emucore/Genesis.cxx | 4 +- src/emucore/Keyboard.cxx | 8 +-- src/emucore/Keyboard.hxx | 2 +- src/emucore/Paddles.cxx | 12 ++-- src/emucore/Paddles.hxx | 3 +- src/emucore/QuadTari.cxx | 4 +- src/emucore/tia/AnalogReadout.cxx | 99 ++++++++++++++++++++++++++---- src/emucore/tia/AnalogReadout.hxx | 31 +++++++++- src/emucore/tia/TIA.cxx | 34 +++++----- src/emucore/tia/TIA.hxx | 4 +- 19 files changed, 205 insertions(+), 106 deletions(-) diff --git a/src/common/StateManager.hxx b/src/common/StateManager.hxx index ccda3be1a..da4159b06 100644 --- a/src/common/StateManager.hxx +++ b/src/common/StateManager.hxx @@ -18,7 +18,7 @@ #ifndef STATE_MANAGER_HXX #define STATE_MANAGER_HXX -#define STATE_HEADER "06020100state" +#define STATE_HEADER "06050300state" class OSystem; class RewindManager; diff --git a/src/debugger/gui/BoosterWidget.cxx b/src/debugger/gui/BoosterWidget.cxx index 390e0a21d..17cbcd51b 100644 --- a/src/debugger/gui/BoosterWidget.cxx +++ b/src/debugger/gui/BoosterWidget.cxx @@ -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; diff --git a/src/debugger/gui/GenesisWidget.cxx b/src/debugger/gui/GenesisWidget.cxx index aeacc0c27..ae67a064f 100644 --- a/src/debugger/gui/GenesisWidget.cxx +++ b/src/debugger/gui/GenesisWidget.cxx @@ -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; diff --git a/src/debugger/gui/PaddleWidget.cxx b/src/debugger/gui/PaddleWidget.cxx index 8eb1a80a5..7dd1af4e9 100644 --- a/src/debugger/gui/PaddleWidget.cxx +++ b/src/debugger/gui/PaddleWidget.cxx @@ -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(Paddles::MAX_RESISTANCE - myP0Resistance->getValue())); + AnalogReadout::connectToVcc(Paddles::MAX_RESISTANCE - myP0Resistance->getValue())); break; case kP1Changed: setPin(Controller::AnalogPin::Five, - static_cast(Paddles::MAX_RESISTANCE - myP1Resistance->getValue())); + AnalogReadout::connectToVcc(Paddles::MAX_RESISTANCE - myP1Resistance->getValue())); break; case kP0Fire: setPin(Controller::DigitalPin::Four, !myP0Fire->getState()); diff --git a/src/emucore/Booster.cxx b/src/emucore/Booster.cxx index be48bc4e8..30120436d 100644 --- a/src/emucore/Booster.cxx +++ b/src/emucore/Booster.cxx @@ -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()); } + diff --git a/src/emucore/CompuMate.cxx b/src/emucore/CompuMate.cxx index d6c25dd71..9a4b36002 100644 --- a/src/emucore/CompuMate.cxx +++ b/src/emucore/CompuMate.cxx @@ -31,10 +31,10 @@ CompuMate::CompuMate(const Console& console, const Event& event, myLeftController = make_unique(*this, Controller::Jack::Left, event, system); myRightController = make_unique(*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); diff --git a/src/emucore/Control.cxx b/src/emucore/Control.cxx index 8e7b0e391..8f7448fc7 100644 --- a/src/emucore/Control.cxx +++ b/src/emucore/Control.cxx @@ -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(...) { diff --git a/src/emucore/Control.hxx b/src/emucore/Control.hxx index 8b8f1e9bb..c329ecf2c 100644 --- a/src/emucore/Control.hxx +++ b/src/emucore/Control.hxx @@ -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(pin)]; } - inline void setPin(AnalogPin pin, Int32 value) { + inline void setPin(AnalogPin pin, AnalogReadout::Connection value) { myAnalogPinValue[static_cast(pin)] = value; if(myOnAnalogPinUpdateCallback) myOnAnalogPinUpdateCallback(pin); } - inline Int32 getPin(AnalogPin pin) const { + inline AnalogReadout::Connection getPin(AnalogPin pin) const { return myAnalogPinValue[static_cast(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 myDigitalPinState{true, true, true, true, true}; /// The analog value on each analog pin - std::array myAnalogPinValue{MAX_RESISTANCE, MAX_RESISTANCE}; + std::array + myAnalogPinValue{AnalogReadout::disconnect(), AnalogReadout::disconnect()}; private: // Following constructors and assignment operators not supported diff --git a/src/emucore/ControlLowLevel.hxx b/src/emucore/ControlLowLevel.hxx index fac5113d2..305da45a3 100644 --- a/src/emucore/ControlLowLevel.hxx +++ b/src/emucore/ControlLowLevel.hxx @@ -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() { diff --git a/src/emucore/Genesis.cxx b/src/emucore/Genesis.cxx index fc5459d82..e5b9840f6 100644 --- a/src/emucore/Genesis.cxx +++ b/src/emucore/Genesis.cxx @@ -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()); } diff --git a/src/emucore/Keyboard.cxx b/src/emucore/Keyboard.cxx index d0ee168a7..101fa89d5 100644 --- a/src/emucore/Keyboard.cxx +++ b/src/emucore/Keyboard.cxx @@ -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"); diff --git a/src/emucore/Keyboard.hxx b/src/emucore/Keyboard.hxx index 7ff9001e6..a0470a799 100644 --- a/src/emucore/Keyboard.hxx +++ b/src/emucore/Keyboard.hxx @@ -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 diff --git a/src/emucore/Paddles.cxx b/src/emucore/Paddles.cxx index f247d3995..5635d143b 100644 --- a/src/emucore/Paddles.cxx +++ b/src/emucore/Paddles.cxx @@ -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; } diff --git a/src/emucore/Paddles.hxx b/src/emucore/Paddles.hxx index 62d7bd04c..4920229bb 100644 --- a/src/emucore/Paddles.hxx +++ b/src/emucore/Paddles.hxx @@ -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 diff --git a/src/emucore/QuadTari.cxx b/src/emucore/QuadTari.cxx index c0303d6be..8ef19993a 100644 --- a/src/emucore/QuadTari.cxx +++ b/src/emucore/QuadTari.cxx @@ -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()); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/tia/AnalogReadout.cxx b/src/emucore/tia/AnalogReadout.cxx index 4fffadb49..d356584d3 100644 --- a/src/emucore/tia/AnalogReadout.cxx +++ b/src/emucore/tia/AnalogReadout.cxx @@ -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(timestamp - myTimestamp) / (myValue * R_POT + R0) / C / myClockFreq)); - else - myU *= exp(-static_cast(timestamp - myTimestamp) / (myIsDumped ? R_DUMP : R0) / C / myClockFreq); + if (myIsDumped) { + myU *= exp(-static_cast(timestamp - myTimestamp) / R_DUMP / C / myClockFreq); + } else { + switch (myConnection.type) { + case ConnectionType::vcc: + myU = U_SUPP * (1 - (1 - myU / U_SUPP) * + exp(-static_cast(timestamp - myTimestamp) / (myConnection.resistance + R0) / C / myClockFreq)); + + break; + + case ConnectionType::ground: + myU *= exp(-static_cast(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(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); +} diff --git a/src/emucore/tia/AnalogReadout.hxx b/src/emucore/tia/AnalogReadout.hxx index 6ae5d0ec5..64d310f5a 100644 --- a/src/emucore/tia/AnalogReadout.hxx +++ b/src/emucore/tia/AnalogReadout.hxx @@ -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 diff --git a/src/emucore/tia/TIA.cxx b/src/emucore/tia/TIA.cxx index ecc757f5d..a086bfef8 100644 --- a/src/emucore/tia/TIA.cxx +++ b/src/emucore/tia/TIA.cxx @@ -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() ); diff --git a/src/emucore/tia/TIA.hxx b/src/emucore/tia/TIA.hxx index e8d29c83a..d12dd62fd 100644 --- a/src/emucore/tia/TIA.hxx +++ b/src/emucore/tia/TIA.hxx @@ -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