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 | |
21 | class Controller; |
22 | class ControllerLowLevel; |
23 | class Event; |
24 | class 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 | */ |
63 | class 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 | |