openMSX
Paddle.cc
Go to the documentation of this file.
1 #include "Paddle.hh"
2 #include "MSXEventDistributor.hh"
4 #include "InputEvents.hh"
5 #include "StateChange.hh"
6 #include "checked_cast.hh"
7 #include "serialize.hh"
8 #include "serialize_meta.hh"
9 #include <algorithm>
10 
11 namespace openmsx {
12 
13 class PaddleState final : public StateChange
14 {
15 public:
16  PaddleState() = default; // for serialize
17  PaddleState(EmuTime::param time_, int delta_)
18  : StateChange(time_), delta(delta_) {}
19  int getDelta() const { return delta; }
20 
21  template<typename Archive> void serialize(Archive& ar, unsigned /*version*/)
22  {
23  ar.template serializeBase<StateChange>(*this);
24  ar.serialize("delta", delta);
25  }
26 private:
27  int delta;
28 };
30 
31 
33  StateChangeDistributor& stateChangeDistributor_)
34  : eventDistributor(eventDistributor_)
35  , stateChangeDistributor(stateChangeDistributor_)
36  , lastPulse(EmuTime::zero())
37  , analogValue(128)
38  , lastInput(0)
39 {
40 }
41 
43 {
44  if (isPluggedIn()) {
45  Paddle::unplugHelper(EmuTime::dummy());
46  }
47 }
48 
49 
50 // Pluggable
51 const std::string& Paddle::getName() const
52 {
53  static const std::string name("paddle");
54  return name;
55 }
56 
57 std::string_view Paddle::getDescription() const
58 {
59  return "MSX Paddle";
60 }
61 
62 void Paddle::plugHelper(Connector& /*connector*/, EmuTime::param /*time*/)
63 {
64  eventDistributor.registerEventListener(*this);
65  stateChangeDistributor.registerListener(*this);
66 }
67 
68 void Paddle::unplugHelper(EmuTime::param /*time*/)
69 {
70  stateChangeDistributor.unregisterListener(*this);
71  eventDistributor.unregisterEventListener(*this);
72 }
73 
74 // JoystickDevice
75 byte Paddle::read(EmuTime::param time)
76 {
77  // The loop in the BIOS routine that reads the paddle status takes
78  // 41 Z80 cycles per iteration.
79  static constexpr auto TICK = EmuDuration::hz(3579545) * 41;
80 
81  assert(time >= lastPulse);
82  bool before = (time - lastPulse) < (TICK * analogValue);
83  bool output = before && !(lastInput & 4);
84  return output ? 0x3F : 0x3E; // pin1 (up)
85 }
86 
87 void Paddle::write(byte value, EmuTime::param time)
88 {
89  byte diff = lastInput ^ value;
90  lastInput = value;
91  if ((diff & 4) && !(lastInput & 4)) { // high->low edge
92  lastPulse = time;
93  }
94 }
95 
96 // MSXEventListener
97 void Paddle::signalMSXEvent(const std::shared_ptr<const Event>& event,
98  EmuTime::param time)
99 {
100  if (event->getType() != OPENMSX_MOUSE_MOTION_EVENT) return;
101 
102  auto& mev = checked_cast<const MouseMotionEvent&>(*event);
103  constexpr int SCALE = 2;
104  int delta = mev.getX() / SCALE;
105  if (delta == 0) return;
106 
107  stateChangeDistributor.distributeNew(
108  std::make_shared<PaddleState>(time, delta));
109 }
110 
111 // StateChangeListener
112 void Paddle::signalStateChange(const std::shared_ptr<StateChange>& event)
113 {
114  auto ps = dynamic_cast<PaddleState*>(event.get());
115  if (!ps) return;
116  int newAnalog = analogValue + ps->getDelta();
117  analogValue = std::min(std::max(newAnalog, 0), 255);
118 }
119 
120 void Paddle::stopReplay(EmuTime::param /*time*/)
121 {
122 }
123 
124 template<typename Archive>
125 void Paddle::serialize(Archive& ar, unsigned /*version*/)
126 {
127  ar.serialize("lastPulse", lastPulse,
128  "analogValue", analogValue,
129  "lastInput", lastInput);
130 
131  if (ar.isLoader() && isPluggedIn()) {
132  plugHelper(*getConnector(), EmuTime::dummy());
133  }
134 }
137 
138 } // namespace openmsx
gl::min
vecN< N, T > min(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:274
openmsx::OPENMSX_MOUSE_MOTION_EVENT
@ OPENMSX_MOUSE_MOTION_EVENT
Definition: Event.hh:15
serialize.hh
MSXEventDistributor.hh
openmsx::Paddle::serialize
void serialize(Archive &ar, unsigned version)
Definition: Paddle.cc:125
openmsx::MSXEventDistributor
Definition: MSXEventDistributor.hh:14
openmsx::StateChange
Base class for all external MSX state changing events.
Definition: StateChange.hh:14
openmsx::StateChangeDistributor::registerListener
void registerListener(StateChangeListener &listener)
(Un)registers the given object to receive state change events.
Definition: StateChangeDistributor.cc:19
serialize_meta.hh
openmsx::StateChangeDistributor::distributeNew
void distributeNew(const EventPtr &event)
Deliver the event to all registered listeners MSX input devices should call the distributeNew() versi...
Definition: StateChangeDistributor.cc:43
openmsx::PaddleState::getDelta
int getDelta() const
Definition: Paddle.cc:19
openmsx::StateChangeDistributor
Definition: StateChangeDistributor.hh:15
openmsx::Pluggable
Definition: Pluggable.hh:12
StateChangeDistributor.hh
openmsx::Pluggable::getConnector
Connector * getConnector() const
Get the connector this Pluggable is plugged into.
Definition: Pluggable.hh:43
openmsx::PaddleState::PaddleState
PaddleState()=default
Paddle.hh
openmsx::SCALE
constexpr int SCALE
Definition: ArkanoidPad.cc:29
openmsx::PaddleState::PaddleState
PaddleState(EmuTime::param time_, int delta_)
Definition: Paddle.cc:17
openmsx::Paddle::Paddle
Paddle(MSXEventDistributor &eventDistributor, StateChangeDistributor &stateChangeDistributor)
Definition: Paddle.cc:32
InputEvents.hh
INSTANTIATE_SERIALIZE_METHODS
#define INSTANTIATE_SERIALIZE_METHODS(CLASS)
Definition: serialize.hh:981
StateChange.hh
openmsx::Paddle
Definition: Paddle.hh:15
openmsx::PaddleState
Definition: Paddle.cc:14
openmsx::EmuDuration::hz
static constexpr EmuDuration hz(unsigned x)
Definition: EmuDuration.hh:45
checked_cast.hh
openmsx::Paddle::~Paddle
~Paddle() override
Definition: Paddle.cc:42
openmsx::MSXEventDistributor::unregisterEventListener
void unregisterEventListener(MSXEventListener &listener)
Unregisters a previously registered event listener.
Definition: MSXEventDistributor.cc:24
openmsx::StateChangeDistributor::unregisterListener
void unregisterListener(StateChangeListener &listener)
Definition: StateChangeDistributor.cc:25
gl::max
vecN< N, T > max(const vecN< N, T > &x, const vecN< N, T > &y)
Definition: gl_vec.hh:292
openmsx::PaddleState::serialize
void serialize(Archive &ar, unsigned)
Definition: Paddle.cc:21
openmsx::REGISTER_POLYMORPHIC_CLASS
REGISTER_POLYMORPHIC_CLASS(DiskContainer, NowindRomDisk, "NowindRomDisk")
openmsx::Pluggable::isPluggedIn
bool isPluggedIn() const
Returns true if this pluggable is currently plugged into a connector.
Definition: Pluggable.hh:49
openmsx
This file implemented 3 utility functions:
Definition: Autofire.cc:5
openmsx::REGISTER_POLYMORPHIC_INITIALIZER
REGISTER_POLYMORPHIC_INITIALIZER(Pluggable, CassettePlayer, "CassettePlayer")
openmsx::MSXEventDistributor::registerEventListener
void registerEventListener(MSXEventListener &listener)
Registers a given object to receive certain events.
Definition: MSXEventDistributor.cc:18
openmsx::Connector
Connector
Definition: Connector.cc:83