1//============================================================================
2//
3// SSSS tt lll lll
4// SS SS tt ll ll
5// SS tttttt eeee ll ll aaaa
6// SSSS tt ee ee ll ll aa
7// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8// SS SS tt ee ll ll aa aa
9// SSSS ttt eeeee llll llll aaaaa
10//
11// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12// and the Stella Team
13//
14// See the file "License.txt" for information on usage and redistribution of
15// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16//============================================================================
17
18#ifndef CONTROLLER_HXX
19#define CONTROLLER_HXX
20
21class Controller;
22class ControllerLowLevel;
23class Event;
24class System;
25
26#include <functional>
27
28#include "Serializable.hxx"
29#include "bspf.hxx"
30
31/**
32 A controller is a device that plugs into either the left or right
33 controller jack of the Video Computer System (VCS). The pins of
34 the controller jacks are mapped as follows:
35
36 -------------
37 \ 1 2 3 4 5 /
38 \ 6 7 8 9 /
39 ---------
40
41 Left Controller Right Controller
42
43 pin 1 D4 PIA SWCHA D0 PIA SWCHA
44 pin 2 D5 PIA SWCHA D1 PIA SWCHA
45 pin 3 D6 PIA SWCHA D2 PIA SWCHA
46 pin 4 D7 PIA SWCHA D3 PIA SWCHA
47 pin 5 D7 TIA INPT1 (Dumped) D7 TIA INPT3 (Dumped)
48 pin 6 D7 TIA INPT4 (Latched) D7 TIA INPT5 (Latched)
49 pin 7 +5 +5
50 pin 8 GND GND
51 pin 9 D7 TIA INPT0 (Dumped) D7 TIA INPT2 (Dumped)
52
53 Each of the pins connected to the PIA can be configured as an
54 input or output pin. The "dumped" TIA pins are used to charge
55 a capacitor. A potentiometer is sometimes connected to these
56 pins for analog input.
57
58 This is a base class for all controllers. It provides a view
59 of the controller from the perspective of the controller's jack.
60
61 @author Bradford W. Mott
62*/
63class Controller : public Serializable
64{
65 /**
66 Various classes that need special access to the underlying controller state
67 */
68 friend class M6532; // FIXME - only needs two methods from this class
69 friend class CompuMate; // FIXME - should go through CMControl instead
70 friend class ControllerLowLevel;
71
72 public:
73 /**
74 Enumeration of the controller jacks
75 */
76 enum class Jack { Left = 0, Right = 1 };
77
78 /**
79 Enumeration of the digital pins of a controller port
80 */
81 enum class DigitalPin { One, Two, Three, Four, Six };
82
83 /**
84 Enumeration of the analog pins of a controller port
85 */
86 enum class AnalogPin { Five, Nine };
87
88 /**
89 Enumeration of the controller types
90 */
91 enum class Type
92 {
93 Unknown,
94 AmigaMouse, AtariMouse, AtariVox, BoosterGrip, CompuMate,
95 Driving, Genesis, Joystick, Keyboard, KidVid, MindLink,
96 Paddles, PaddlesIAxis, PaddlesIAxDr, SaveKey, TrakBall,
97 LastType
98 };
99
100 /**
101 Callback type for analog pin updates
102 */
103 using onAnalogPinUpdateCallback = std::function<void(AnalogPin)>;
104
105 /**
106 Callback type for general controller messages
107 */
108 using onMessageCallback = std::function<void(const string&)>;
109
110 public:
111 /**
112 Create a new controller plugged into the specified jack
113
114 @param jack The jack the controller is plugged into
115 @param event The event object to use for events
116 @param system The system using this controller
117 @param type The type for this controller
118 */
119 Controller(Jack jack, const Event& event, const System& system,
120 Type type);
121 virtual ~Controller() = default;
122
123 /**
124 Returns the jack that this controller is plugged into.
125 */
126 Jack jack() const { return myJack; }
127
128 /**
129 Returns the type of this controller.
130 */
131 Type type() const { return myType; }
132
133 /**
134 Read the entire state of all digital pins for this controller.
135 Note that this method must use the lower 4 bits, and zero the upper bits.
136
137 @return The state of all digital pins
138 */
139 virtual uInt8 read();
140
141 /**
142 Read the value of the specified digital pin for this controller.
143
144 @param pin The pin of the controller jack to read
145 @return The state of the pin
146 */
147 virtual bool read(DigitalPin pin);
148
149 /**
150 Read the resistance at the specified analog pin for this controller.
151 The returned value is the resistance measured in ohms.
152
153 @param pin The pin of the controller jack to read
154 @return The resistance at the specified pin
155 */
156 virtual Int32 read(AnalogPin pin);
157
158 /**
159 Write the given value to the specified digital pin for this
160 controller. Writing is only allowed to the pins associated
161 with the PIA. Therefore you cannot write to pin six.
162
163 @param pin The pin of the controller jack to write to
164 @param value The value to write to the pin
165 */
166 virtual void write(DigitalPin pin, bool value) { }
167
168 /**
169 Called after *all* digital pins have been written on Port A.
170 Most controllers don't do anything in this case.
171
172 @param value The entire contents of the SWCHA register
173 */
174 virtual void controlWrite(uInt8 value) { }
175
176 /**
177 Update the entire digital and analog pin state according to the
178 events currently set.
179 */
180 virtual void update() = 0;
181
182 /**
183 Returns the name of this controller.
184 */
185 virtual string name() const = 0;
186
187 /**
188 Answers whether the controller is intrinsically an analog controller.
189 Specific controllers should override and implement this method.
190 */
191 virtual bool isAnalog() const { return false; }
192
193 /**
194 Notification method invoked by the system after its reset method has
195 been called. It may be necessary to override this method for
196 controllers that need to know a reset has occurred.
197 */
198 virtual void reset() { }
199
200 /**
201 Notification method invoked by the system indicating that the
202 console is about to be destroyed. It may be necessary to override
203 this method for controllers that need cleanup before exiting.
204 */
205 virtual void close() { }
206
207 /**
208 Determines how this controller will treat values received from the
209 X/Y axis and left/right buttons of the mouse. Since not all controllers
210 use the mouse the same way (or at all), it's up to the specific class to
211 decide how to use this data.
212
213 In the current implementation, the left button is tied to the X axis,
214 and the right one tied to the Y axis.
215
216 @param xtype The controller to use for x-axis data
217 @param xid The controller ID to use for x-axis data (-1 for no id)
218 @param ytype The controller to use for y-axis data
219 @param yid The controller ID to use for y-axis data (-1 for no id)
220
221 @return Whether the controller supports using the mouse
222 */
223 virtual bool setMouseControl(
224 Controller::Type xtype, int xid, Controller::Type ytype, int yid)
225 { return false; }
226
227 /**
228 Returns more detailed information about this controller.
229 */
230 virtual string about(bool swappedPorts) const
231 {
232 return name() + " in " + (((myJack == Jack::Left) ^ swappedPorts) ?
233 "left port" : "right port");
234 }
235
236 /**
237 Saves the current state of this controller to the given Serializer.
238
239 @param out The serializer device to save to.
240 @return The result of the save. True on success, false on failure.
241 */
242 bool save(Serializer& out) const override;
243
244 /**
245 Loads the current state of this controller from the given Serializer.
246
247 @param in The serializer device to load from.
248 @return The result of the load. True on success, false on failure.
249 */
250 bool load(Serializer& in) override;
251
252 /**
253 Inject a callback to be notified on analog pin updates.
254 */
255 void setOnAnalogPinUpdateCallback(onAnalogPinUpdateCallback callback) {
256 myOnAnalogPinUpdateCallback = callback;
257 }
258
259 /**
260 Returns the display name of the given controller type
261 */
262 static string getName(const Type type);
263
264 /**
265 Returns the property name of the given controller type
266 */
267 static string getPropName(const Type type);
268
269 /**
270 Returns the controller type of the given property name
271 */
272 static Type getType(const string& propName);
273
274 public:
275 /// Constant which represents maximum resistance for analog pins
276 static constexpr Int32 MAX_RESISTANCE = 0x7FFFFFFF;
277
278 /// Constant which represents minimum resistance for analog pins
279 static constexpr Int32 MIN_RESISTANCE = 0x00000000;
280
281 protected:
282 /**
283 Derived classes *must* use these accessor/mutator methods.
284 The read/write methods above are meant to be used at a higher level.
285 */
286 inline bool setPin(DigitalPin pin, bool value) {
287 return myDigitalPinState[static_cast<int>(pin)] = value;
288 }
289 inline bool getPin(DigitalPin pin) const {
290 return myDigitalPinState[static_cast<int>(pin)];
291 }
292 inline void setPin(AnalogPin pin, Int32 value) {
293 myAnalogPinValue[static_cast<int>(pin)] = value;
294 if(myOnAnalogPinUpdateCallback)
295 myOnAnalogPinUpdateCallback(pin);
296 }
297 inline Int32 getPin(AnalogPin pin) const {
298 return myAnalogPinValue[static_cast<int>(pin)];
299 }
300 inline void resetDigitalPins() {
301 setPin(DigitalPin::One, true);
302 setPin(DigitalPin::Two, true);
303 setPin(DigitalPin::Three, true);
304 setPin(DigitalPin::Four, true);
305 setPin(DigitalPin::Six, true);
306 }
307 inline void resetAnalogPins() {
308 setPin(AnalogPin::Five, MAX_RESISTANCE);
309 setPin(AnalogPin::Nine, MAX_RESISTANCE);
310 }
311
312 protected:
313 /// Specifies which jack the controller is plugged in
314 const Jack myJack;
315
316 /// Reference to the event object this controller uses
317 const Event& myEvent;
318
319 /// Pointer to the System object (used for timing purposes)
320 const System& mySystem;
321
322 /// Specifies which type of controller this is (defined by child classes)
323 const Type myType;
324
325 /// The callback that is dispatched whenver an analog pin has changed
326 onAnalogPinUpdateCallback myOnAnalogPinUpdateCallback;
327
328 private:
329 /// The boolean value on each digital pin
330 std::array<bool, 5> myDigitalPinState;
331
332 /// The analog value on each analog pin
333 std::array<Int32, 2> myAnalogPinValue;
334
335 private:
336 // Following constructors and assignment operators not supported
337 Controller() = delete;
338 Controller(const Controller&) = delete;
339 Controller(Controller&&) = delete;
340 Controller& operator=(const Controller&) = delete;
341 Controller& operator=(Controller&&) = delete;
342};
343
344#endif
345