Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
added Joy 2B+ support (resolves #909)
  • Loading branch information
thrust26 committed Jun 30, 2022
1 parent e01d49e commit 73ffb94
Show file tree
Hide file tree
Showing 21 changed files with 475 additions and 20 deletions.
122 changes: 117 additions & 5 deletions docs/index.html
Expand Up @@ -273,10 +273,11 @@ <h2><b><a name="Features">Features</a></b></h2>
Atari 2600 FPGA project, including cycle-exact audio, analog interference
from mixing of audio channels, as well as stereo sound support; dynamic
sound resampling is also included</li>
<li>Emulates the Atari 2600 Joystick, Paddle, Driving, CBS Booster Grip, Sega Genesis, QuadTari controllers using your computer's keyboard,
joysticks or mouse</li>
<li>Emulates CX22/CX80 style Trak-Balls, Amiga/Atari mouse, MindLink controller and the Light Gun using your
computer's mouse</li>
<li>Emulates the Atari 2600 Joystick, Paddle, Driving, CBS Booster Grip,
Sega Genesis, <a href="https://github.com/ascrnet/Joy2Bplus">Joy 2B+</a>,
QuadTari controllers using your computer's keyboard, joysticks or mouse</li>
<li>Emulates CX22/CX80 style Trak-Balls, Amiga/Atari mouse, MindLink controller
and the Light Gun using your computer's mouse</li>
<li>Emulates the Atari 2600 Keyboard controllers using your computer's keyboard</li>
<li>Emulates <a href="https://en.wikipedia.org/wiki/CompuMate">Spectravideo CompuMate</a> system using your computer's keyboard,
including mapping of CompuMate 'Backspace', 'Space' and 'Enter' functionality to
Expand Down Expand Up @@ -992,6 +993,108 @@ <h2><b><a name="Hotkeys">Hotkeys</a></b></h2>
</tr>
</table>

<p><b>Joy 2B+ Controller (cannot be remapped, always associated with joystick and Booster Grip controllers)</b></p>

<table style="border: hidden">
<tr>
<td style="padding: 0px">
<table>
<tr>
<th colspan=2>Left Pad</th>
</tr>

<tr>
<th>Function</th>
<th>Key</th>
</tr>

<tr>
<td>Pad Up</td>
<td>Same as Left Joystick 'Up'</td>
</tr>

<tr>
<td>Pad Down</td>
<td>Same as Left Joystick 'Down'</td>
</tr>

<tr>
<td>Pad Left</td>
<td>Same as Left Joystick 'Left'</td>
</tr>

<tr>
<td>Pad Right</td>
<td>Same as Left Joystick 'Right'</td>
</tr>

<tr>
<td>Button 'B'</td>
<td>Same as Left Joystick 'Fire'</td>
</tr>

<tr>
<td>Button 'C'</td>
<td>Same as Left Joystick 'Top Booster Button'</td>
</tr>

<tr>
<td>Button '3'</td>
<td>Same as Left Joystick 'Handle Grip Trigger'</td>
</tr>
</table>
</td>
<td style="border: hidden"></td>
<td style="padding: 0px">
<table>
<tr>
<th colspan=2>Right Pad</th>
</tr>

<tr>
<th>Function</th>
<th>Key</th>
</tr>

<tr>
<td>Pad Up</td>
<td>Same as Right Joystick 'Up'</td>
</tr>

<tr>
<td>Pad Down</td>
<td>Same as Right Joystick 'Down'</td>
</tr>

<tr>
<td>Pad Left</td>
<td>Same as Right Joystick 'Left'</td>
</tr>

<tr>
<td>Pad Right</td>
<td>Same as Right Joystick 'Right'</td>
</tr>

<tr>
<td>Button 'B'</td>
<td>Same as Right Joystick 'Fire'</td>
</tr>

<tr>
<td>Button 'C'</td>
<td>Same as Right Joystick 'Top Booster Button'</td>
</tr>

<tr>
<td>Button '3'</td>
<td>Same as Right Joystick 'Handle Grip Trigger'</td>
</tr>
</table>
</td>
</tr>
</table>

</br>
<p><b>Driving Controller (can be remapped)</b></p>

Expand Down Expand Up @@ -2556,7 +2659,7 @@ <h2><b><a name="ControlMap">Controller Map</a></b></h2>
<tr>
<th> Booster Grip</th>
<td> &#x2713;</td>
<td> &#x2713;</td>
<td> &#x2713; (+ extra)</td>
<td> &#x2713; (+ extra)</td>
<td> &#x2715;</td>
<td> &#x2713; (+ extra)</td>
Expand All @@ -2569,6 +2672,14 @@ <h2><b><a name="ControlMap">Controller Map</a></b></h2>
<td> &#x2715;</td>
<td> &#x2715;</td>
</tr>
<tr>
<th> Joy 2B+</th>
<td> &#x2713;</td>
<td> &#x2713; (+ extra)</td>
<td> &#x2713; (+ extra)</td>
<td> &#x2715;</td>
<td> &#x2715; (+ extra)</td>
</tr>
<tr>
<th> Keyboard</th>
<td> &#x2713;</td>
Expand Down Expand Up @@ -5260,6 +5371,7 @@ <h3><a name="ControllerProps"><b>Controller Properties</b></a></h3>
<tr><td><a href="https://atariage.com/store/index.php?l=product_detail&p=1045">AtariVox &#185</a></td><td>A SpeakJet based unlimited-vocabulary speech/sound synthesizer with 32K EEPROM.</td></tr>
<tr><td>SaveKey</td><td>A 32K EEPROM for saving high scores, etc. (the EEPROM portion of an AtariVox).</td></tr>
<tr><td>Genesis </td><td>Sega Genesis controller, which can be used similar to a Booster Grip, giving an extra button.</td></tr>
<tr><td>Joy2B+ </td><td><a href="https://github.com/ascrnet/Joy2Bplus">Joy 2B+</a> controller, which can be used similar to a Booster Grip, giving two extra buttons.</td></tr>
<tr><td>CompuMate &#185</td><td>Spectravideo CompuMate (if either left or right is set, CompuMate is used for both).</td></tr>
<tr><td>Lightgun</td><td>Atari XG-1 compatible Light Gun.</td></tr>
<tr><td>MindLink &#185</td><td>MindLink controller.</td></tr>
Expand Down
53 changes: 53 additions & 0 deletions src/debugger/gui/Joy2BPlusWidget.hxx
@@ -0,0 +1,53 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================

#ifndef JOY2BPLUS_WIDGET_HXX
#define JOY2BPLUS_WIDGET_HXX

#include "Control.hxx"
#include "ControllerWidget.hxx"

class Joy2BPlusWidget : public ControllerWidget
{
public:
Joy2BPlusWidget(GuiObject* boss, const GUI::Font& font, int x, int y,
Controller& controller);
~Joy2BPlusWidget() override = default;

private:
enum { kJUp = 0, kJDown, kJLeft, kJRight, kJButtonB, kJButtonC, kJButton3 };

std::array<CheckboxWidget*, 7> myPins{nullptr};
static constexpr std::array<Controller::DigitalPin, 5> ourPinNo = {{
Controller::DigitalPin::One, Controller::DigitalPin::Two,
Controller::DigitalPin::Three, Controller::DigitalPin::Four,
Controller::DigitalPin::Six
}};

private:
void loadConfig() override;
void handleCommand(CommandSender* sender, int cmd, int data, int id) override;

// Following constructors and assignment operators not supported
Joy2BPlusWidget() = delete;
Joy2BPlusWidget(const Joy2BPlusWidget&) = delete;
Joy2BPlusWidget(Joy2BPlusWidget&&) = delete;
Joy2BPlusWidget& operator=(const Joy2BPlusWidget&) = delete;
Joy2BPlusWidget& operator=(Joy2BPlusWidget&&) = delete;
};

#endif
133 changes: 133 additions & 0 deletions src/debugger/gui/Joy2PlusWidget.cxx
@@ -0,0 +1,133 @@
//============================================================================
//
// SSSS tt lll lll
// SS SS tt ll ll
// SS tttttt eeee ll ll aaaa
// SSSS tt ee ee ll ll aa
// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
// SS SS tt ee ll ll aa aa
// SSSS ttt eeeee llll llll aaaaa
//
// Copyright (c) 1995-2022 by Bradford W. Mott, Stephen Anthony
// and the Stella Team
//
// See the file "License.txt" for information on usage and redistribution of
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
//============================================================================

#include "Joy2BPlusWidget.hxx"

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Joy2BPlusWidget::Joy2BPlusWidget(GuiObject* boss, const GUI::Font& font,
int x, int y, Controller& controller)
: ControllerWidget(boss, font, x, y, controller)
{
const string& label = isLeftPort() ? "Left (Joy 2B+)" : "Right (Joy 2B+)";

const int fontHeight = font.getFontHeight();
int xpos = x, ypos = y, lwidth = font.getStringWidth("Right (Joy 2B+)");
StaticTextWidget* t;

t = new StaticTextWidget(boss, font, xpos, ypos+2, lwidth,
fontHeight, label, TextAlign::Left);
xpos += t->getWidth()/2 - 5; ypos += t->getHeight() + 10;
myPins[kJUp] = new CheckboxWidget(boss, font, xpos, ypos, "",
CheckboxWidget::kCheckActionCmd);
myPins[kJUp]->setID(kJUp);
myPins[kJUp]->setTarget(this);

ypos += myPins[kJUp]->getHeight() * 2 + 10;
myPins[kJDown] = new CheckboxWidget(boss, font, xpos, ypos, "",
CheckboxWidget::kCheckActionCmd);
myPins[kJDown]->setID(kJDown);
myPins[kJDown]->setTarget(this);

xpos -= myPins[kJUp]->getWidth() + 5;
ypos -= myPins[kJUp]->getHeight() + 5;
myPins[kJLeft] = new CheckboxWidget(boss, font, xpos, ypos, "",
CheckboxWidget::kCheckActionCmd);
myPins[kJLeft]->setID(kJLeft);
myPins[kJLeft]->setTarget(this);

xpos += (myPins[kJUp]->getWidth() + 5) * 2;
myPins[kJRight] = new CheckboxWidget(boss, font, xpos, ypos, "",
CheckboxWidget::kCheckActionCmd);
myPins[kJRight]->setID(kJRight);
myPins[kJRight]->setTarget(this);

xpos -= (myPins[kJUp]->getWidth() + 5) * 2;
ypos = 20 + (myPins[kJUp]->getHeight() + 10) * 3;
myPins[kJButtonB] = new CheckboxWidget(boss, font, xpos, ypos, "Button B",
CheckboxWidget::kCheckActionCmd);
myPins[kJButtonB]->setID(kJButtonB);
myPins[kJButtonB]->setTarget(this);

ypos += myPins[kJButtonB]->getHeight() + 5;
myPins[kJButtonC] = new CheckboxWidget(boss, font, xpos, ypos, "Button C",
CheckboxWidget::kCheckActionCmd);
myPins[kJButtonC]->setID(kJButtonC);
myPins[kJButtonC]->setTarget(this);

ypos += myPins[kJButtonC]->getHeight() + 5;
myPins[kJButton3] = new CheckboxWidget(boss, font, xpos, ypos, "Button 3",
CheckboxWidget::kCheckActionCmd);
myPins[kJButton3]->setID(kJButton3);
myPins[kJButton3]->setTarget(this);

addFocusWidget(myPins[kJUp]);
addFocusWidget(myPins[kJLeft]);
addFocusWidget(myPins[kJRight]);
addFocusWidget(myPins[kJDown]);
addFocusWidget(myPins[kJButtonB]);
addFocusWidget(myPins[kJButtonC]);
addFocusWidget(myPins[kJButton3]);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Joy2BPlusWidget::loadConfig()
{
myPins[kJUp]->setState(!getPin(ourPinNo[kJUp]));
myPins[kJDown]->setState(!getPin(ourPinNo[kJDown]));
myPins[kJLeft]->setState(!getPin(ourPinNo[kJLeft]));
myPins[kJRight]->setState(!getPin(ourPinNo[kJRight]));
myPins[kJButtonB]->setState(!getPin(ourPinNo[kJButtonB]));

myPins[kJButton3]->setState(
getPin(Controller::AnalogPin::Five) == AnalogReadout::connectToGround());
myPins[kJButtonC]->setState(
getPin(Controller::AnalogPin::Nine) == AnalogReadout::connectToGround());
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void Joy2BPlusWidget::handleCommand(
CommandSender* sender, int cmd, int data, int id)
{
if(cmd == CheckboxWidget::kCheckActionCmd)
{
switch(id)
{
case kJUp:
case kJDown:
case kJLeft:
case kJRight:
case kJButtonB:
setPin(ourPinNo[id], !myPins[id]->getState());
break;
case kJButtonC:
setPin(Controller::AnalogPin::Nine,
myPins[id]->getState() ? AnalogReadout::connectToGround()
: AnalogReadout::connectToVcc());
break;
case kJButton3:
setPin(Controller::AnalogPin::Five,
myPins[id]->getState() ? AnalogReadout::connectToGround()
: AnalogReadout::connectToVcc());
break;
default:
break;
}
}
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
constexpr std::array<Controller::DigitalPin, 5> Joy2BPlusWidget::ourPinNo;
7 changes: 5 additions & 2 deletions src/debugger/gui/RiotWidget.cxx
Expand Up @@ -40,6 +40,7 @@
#include "AtariMouseWidget.hxx"
#include "TrakBallWidget.hxx"
#include "QuadTariWidget.hxx"
#include "Joy2BPlusWidget.hxx"

#include "RiotWidget.hxx"

Expand Down Expand Up @@ -537,21 +538,23 @@ ControllerWidget* RiotWidget::addControlWidget(GuiObject* boss, const GUI::Font&
return new DrivingWidget(boss, font, x, y, controller);
case Controller::Type::Genesis:
return new GenesisWidget(boss, font, x, y, controller);
case Controller::Type::Joy2BPlus:
return new Joy2BPlusWidget(boss, font, x, y, controller);
case Controller::Type::Joystick:
return new JoystickWidget(boss, font, x, y, controller);
case Controller::Type::Keyboard:
return new KeyboardWidget(boss, font, x, y, controller);
// case Controller::Type::KidVid: // TODO - implement this
// case Controller::Type::MindLink: // TODO - implement this
// case Controller::Type::Lightgun: // TODO - implement this
case Controller::Type::QuadTari:
return new QuadTariWidget(boss, font, x, y, controller);
case Controller::Type::Paddles:
return new PaddleWidget(boss, font, x, y, controller);
case Controller::Type::SaveKey:
return new SaveKeyWidget(boss, font, x, y, controller);
case Controller::Type::TrakBall:
return new TrakBallWidget(boss, font, x, y, controller);
case Controller::Type::QuadTari:
return new QuadTariWidget(boss, font, x, y, controller);
default:
return new NullControlWidget(boss, font, x, y, controller);
}
Expand Down
3 changes: 2 additions & 1 deletion src/debugger/gui/module.mk
Expand Up @@ -56,13 +56,14 @@ MODULE_OBJS := \
src/debugger/gui/CartDebugWidget.o \
src/debugger/gui/CpuWidget.o \
src/debugger/gui/DataGridOpsWidget.o \
src/debugger/gui/DataGridRamWidget.o \
src/debugger/gui/DataGridRamWidget.o \
src/debugger/gui/DataGridWidget.o \
src/debugger/gui/DebuggerDialog.o \
src/debugger/gui/DelayQueueWidget.o \
src/debugger/gui/DrivingWidget.o \
src/debugger/gui/FlashWidget.o \
src/debugger/gui/GenesisWidget.o \
src/debugger/gui/Joy2BPlusWidget.o \
src/debugger/gui/JoystickWidget.o \
src/debugger/gui/KeyboardWidget.o \
src/debugger/gui/PaddleWidget.o \
Expand Down

4 comments on commit 73ffb94

@sa666666
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thrust26, there is a naming issue here. File Joy2PlusWidget.cxx should be named Joy2BPlusWidget.cxx. I guess do a git mv, and then update the Windows project. Ironically, it's spelled correctly in the module.mk; that's how I found the issue 😄

@thrust26
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, that's a type. Who will fix this?

@sa666666
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can fix it, but not until I get home and get access to my Windows machine.

@thrust26
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then I will do it.

Please sign in to comment.