Adjust paddle parameters, improve keyboard controller emulation, emulate cap discharge,

This commit is contained in:
Christian Speckner 2021-04-02 00:15:13 +02:00
parent bdd7035fef
commit 3902778b12
5 changed files with 60 additions and 51 deletions

View File

@ -54,44 +54,50 @@ Keyboard::Keyboard(Jack jack, const Event& event, const System& system)
} }
} }
Keyboard::ColumnState Keyboard::processColumn(const Event::Type buttons[]) {
constexpr DigitalPin signals[] =
{DigitalPin::One, DigitalPin::Two, DigitalPin::Three, DigitalPin::Four};
for (uInt8 i = 0; i < 4; i++)
if (myEvent.get(buttons[i]) && !getPin(signals[i])) return ColumnState::gnd;
for (uInt8 i = 0; i < 4; i++)
if (myEvent.get(buttons[i]) && getPin(signals[i])) return ColumnState::vcc;
return ColumnState::notConneccted;
}
Int32 Keyboard::columnStateToAnalogSignal(ColumnState state) const {
switch (state) {
case ColumnState::gnd:
return MAX_RESISTANCE;
case ColumnState::vcc:
return 0;
case ColumnState::notConneccted:
return INTERNAL_RESISTANCE;
default:
throw runtime_error("unreachable");
}
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Keyboard::write(DigitalPin pin, bool value) void Keyboard::write(DigitalPin pin, bool value)
{ {
setPin(pin, value); setPin(pin, value);
// Set defaults const Event::Type col0[] = {myOneEvent, myFourEvent, mySevenEvent, myStarEvent};
setPin(DigitalPin::Six, true); const Event::Type col1[] = {myTwoEvent, myFiveEvent, myEightEvent, myZeroEvent};
Int32 resistanceFive = MIN_RESISTANCE; const Event::Type col2[] = {myThreeEvent, mySixEvent, myNineEvent, myPoundEvent};
Int32 resistanceNine = MIN_RESISTANCE;
// Now scan the rows and columns ColumnState stateCol0 = processColumn(col0);
if(!getPin(DigitalPin::Four)) ColumnState stateCol1 = processColumn(col1);
{ ColumnState stateCol2 = processColumn(col2);
setPin(DigitalPin::Six, myEvent.get(myPoundEvent) == 0);
if(myEvent.get(myZeroEvent) != 0) resistanceFive = MAX_RESISTANCE;
if(myEvent.get(myStarEvent) != 0) resistanceNine = MAX_RESISTANCE;
}
if(!getPin(DigitalPin::Three))
{
setPin(DigitalPin::Six, myEvent.get(myNineEvent) == 0);
if(myEvent.get(myEightEvent) != 0) resistanceFive = MAX_RESISTANCE;
if(myEvent.get(mySevenEvent) != 0) resistanceNine = MAX_RESISTANCE;
}
if(!getPin(DigitalPin::Two))
{
setPin(DigitalPin::Six, myEvent.get(mySixEvent) == 0);
if(myEvent.get(myFiveEvent) != 0) resistanceFive = MAX_RESISTANCE;
if(myEvent.get(myFourEvent) != 0) resistanceNine = MAX_RESISTANCE;
}
if(!getPin(DigitalPin::One))
{
setPin(DigitalPin::Six, myEvent.get(myThreeEvent) == 0);
if(myEvent.get(myTwoEvent) != 0) resistanceFive = MAX_RESISTANCE;
if(myEvent.get(myOneEvent) != 0) resistanceNine = MAX_RESISTANCE;
}
if(resistanceFive != read(AnalogPin::Five)) setPin(DigitalPin::Six, stateCol2 == ColumnState::gnd ? 0 : 1);
setPin(AnalogPin::Five, resistanceFive); setPin(AnalogPin::Five, columnStateToAnalogSignal(stateCol1));
if(resistanceNine != read(AnalogPin::Nine)) setPin(AnalogPin::Nine, columnStateToAnalogSignal(stateCol0));
setPin(AnalogPin::Nine, resistanceNine);
} }

View File

@ -62,6 +62,16 @@ class Keyboard : public Controller
*/ */
string name() const override { return "Keyboard"; } string name() const override { return "Keyboard"; }
private:
enum class ColumnState {
vcc, gnd, notConneccted
};
private:
ColumnState processColumn(const Event::Type buttons[]);
Int32 columnStateToAnalogSignal(ColumnState state) const;
private: private:
// Pre-compute the events we care about based on given port // Pre-compute the events we care about based on given port
// This will eliminate test for left or right port in update() // This will eliminate test for left or right port in update()
@ -70,7 +80,7 @@ class Keyboard : public Controller
mySevenEvent, myEightEvent, myNineEvent, mySevenEvent, myEightEvent, myNineEvent,
myStarEvent, myZeroEvent, myPoundEvent; myStarEvent, myZeroEvent, myPoundEvent;
static constexpr Int32 MIN_RESISTANCE = 5600; static constexpr Int32 INTERNAL_RESISTANCE = 4700;
private: private:
// Following constructors and assignment operators not supported // Following constructors and assignment operators not supported

View File

@ -162,7 +162,7 @@ class Paddles : public Controller
*/ */
static void setDigitalPaddleRange(int range); static void setDigitalPaddleRange(int range);
static constexpr double MAX_RESISTANCE = 1400000.0; static constexpr double MAX_RESISTANCE = 1000000.0;
private: private:
// Range of values over which digital and mouse movement is scaled // Range of values over which digital and mouse movement is scaled

View File

@ -40,16 +40,17 @@ void PaddleReader::reset(uInt64 timestamp)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PaddleReader::vblank(uInt8 value, uInt64 timestamp) void PaddleReader::vblank(uInt8 value, uInt64 timestamp)
{ {
updateCharge(timestamp);
bool oldIsDumped = myIsDumped; bool oldIsDumped = myIsDumped;
if (value & 0x80) { if (value & 0x80) {
myIsDumped = true; myIsDumped = true;
myU = 0;
myTimestamp = timestamp;
} else if (oldIsDumped) { } else if (oldIsDumped) {
myIsDumped = false; myIsDumped = false;
myTimestamp = timestamp;
} }
myTimestamp = timestamp;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@ -72,15 +73,7 @@ void PaddleReader::update(double value, uInt64 timestamp, ConsoleTiming consoleT
if (value != myValue) { if (value != myValue) {
myValue = value; myValue = value;
if (myValue < 0) { updateCharge(timestamp);
// value < 0 signifies either maximum resistance OR analog input connected to
// ground (keyboard controllers). As we have no way to tell these apart we just
// assume ground and discharge.
myU = 0;
myTimestamp = timestamp;
} else {
updateCharge(timestamp);
}
} }
} }
@ -96,11 +89,11 @@ void PaddleReader::setConsoleTiming(ConsoleTiming consoleTiming)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void PaddleReader::updateCharge(uInt64 timestamp) void PaddleReader::updateCharge(uInt64 timestamp)
{ {
if (myIsDumped) return; if (myValue >= 0 && !myIsDumped)
if (myValue >= 0)
myU = USUPP * (1 - (1 - myU / USUPP) * myU = USUPP * (1 - (1 - myU / USUPP) *
exp(-static_cast<double>(timestamp - myTimestamp) / (myValue * RPOT + R0) / C / myClockFreq)); exp(-static_cast<double>(timestamp - myTimestamp) / (myValue * RPOT + R0) / C / myClockFreq));
else
myU *= exp(-static_cast<double>(timestamp - myTimestamp) / R0 / C / myClockFreq);
myTimestamp = timestamp; myTimestamp = timestamp;
} }

View File

@ -65,7 +65,7 @@ class PaddleReader : public Serializable
bool myIsDumped{false}; bool myIsDumped{false};
static constexpr double static constexpr double
R0 = 1.5e3, R0 = 1.8e3,
C = 68e-9, C = 68e-9,
RPOT = 1e6, RPOT = 1e6,
USUPP = 5; USUPP = 5;