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#include "Event.hxx"
19#include "System.hxx"
20
21#include "Driving.hxx"
22
23// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
24Driving::Driving(Jack jack, const Event& event, const System& system)
25 : Controller(jack, event, system, Controller::Type::Driving),
26 myCounter(0),
27 myGrayIndex(0),
28 myLastYaxis(0),
29 myControlID(-1),
30 myControlIDX(-1),
31 myControlIDY(-1)
32{
33 if(myJack == Jack::Left)
34 {
35 myCCWEvent = Event::JoystickZeroLeft;
36 myCWEvent = Event::JoystickZeroRight;
37 myFireEvent = Event::JoystickZeroFire;
38 myXAxisValue = Event::PaddleZeroAnalog;
39 myYAxisValue = Event::PaddleOneAnalog;
40 }
41 else
42 {
43 myCCWEvent = Event::JoystickOneLeft;
44 myCWEvent = Event::JoystickOneRight;
45 myFireEvent = Event::JoystickOneFire;
46 myXAxisValue = Event::PaddleTwoAnalog;
47 myYAxisValue = Event::PaddleThreeAnalog;
48 }
49
50 // Digital pins 3 and 4 are not connected
51 setPin(DigitalPin::Three, true);
52 setPin(DigitalPin::Four, true);
53}
54
55// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
56void Driving::update()
57{
58 // Make sure direct gray codes from Stelladaptor stay in sync with
59 // simulated gray codes generated by PC keyboard or PC joystick
60 myCounter = (myGrayIndex << 2) | (myCounter & 3);
61
62 // Digital events (from keyboard or joystick hats & buttons)
63 setPin(DigitalPin::Six, myEvent.get(myFireEvent) == 0);
64 int d_axis = myEvent.get(myXAxisValue);
65 if(myEvent.get(myCCWEvent) != 0 || d_axis < -16384) --myCounter;
66 else if(myEvent.get(myCWEvent) != 0 || d_axis > 16384) ++myCounter;
67
68 // Mouse motion and button events
69 if(myControlID > -1)
70 {
71 int m_axis = myEvent.get(Event::MouseAxisXValue);
72 if(m_axis < -2) --myCounter;
73 else if(m_axis > 2) ++myCounter;
74 if(myEvent.get(Event::MouseButtonLeftValue) ||
75 myEvent.get(Event::MouseButtonRightValue))
76 setPin(DigitalPin::Six, false);
77 }
78 else
79 {
80 // Test for 'untied' mouse axis mode, where each axis is potentially
81 // mapped to a separate driving controller
82 if(myControlIDX > -1)
83 {
84 int m_axis = myEvent.get(Event::MouseAxisXValue);
85 if(m_axis < -2) --myCounter;
86 else if(m_axis > 2) ++myCounter;
87 if(myEvent.get(Event::MouseButtonLeftValue))
88 setPin(DigitalPin::Six, false);
89 }
90 if(myControlIDY > -1)
91 {
92 int m_axis = myEvent.get(Event::MouseAxisYValue);
93 if(m_axis < -2) --myCounter;
94 else if(m_axis > 2) ++myCounter;
95 if(myEvent.get(Event::MouseButtonRightValue))
96 setPin(DigitalPin::Six, false);
97 }
98 }
99
100 // Only consider the lower-most bits (corresponding to pins 1 & 2)
101 myCounter &= 0x0f;
102 myGrayIndex = myCounter >> 2;
103
104 // Stelladaptor is the only controller that should set this
105 int yaxis = myEvent.get(myYAxisValue);
106
107 // Only overwrite gray code when Stelladaptor input has changed
108 // (that means real changes, not just analog signal jitter)
109 if((yaxis < (myLastYaxis - 1024)) || (yaxis > (myLastYaxis + 1024)))
110 {
111 myLastYaxis = yaxis;
112 if(yaxis <= -16384-4096)
113 myGrayIndex = 3; // up
114 else if(yaxis > 16384+4096)
115 myGrayIndex = 1; // down
116 else if(yaxis >= 16384-4096)
117 myGrayIndex = 2; // up + down
118 else /* if(yaxis < 16384-4096) */
119 myGrayIndex = 0; // no movement
120 }
121
122 // Gray codes for rotation
123 static constexpr uInt8 graytable[] = { 0x03, 0x01, 0x00, 0x02 };
124
125 // Determine which bits are set
126 uInt8 gray = graytable[myGrayIndex];
127 setPin(DigitalPin::One, (gray & 0x1) != 0);
128 setPin(DigitalPin::Two, (gray & 0x2) != 0);
129}
130
131// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
132bool Driving::setMouseControl(
133 Controller::Type xtype, int xid, Controller::Type ytype, int yid)
134{
135 // When the mouse emulates a single driving controller, only the X-axis is
136 // used, and both mouse buttons map to the same 'fire' event
137 if(xtype == Controller::Type::Driving && ytype == Controller::Type::Driving && xid == yid)
138 {
139 myControlID = ((myJack == Jack::Left && xid == 0) ||
140 (myJack == Jack::Right && xid == 1)
141 ) ? xid : -1;
142 myControlIDX = myControlIDY = -1;
143 }
144 else
145 {
146 // Otherwise, each axis can be mapped to a separate driving controller,
147 // and the buttons map to separate (corresponding) controllers
148 myControlID = -1;
149 if(myJack == Jack::Left)
150 {
151 myControlIDX = (xtype == Controller::Type::Driving && xid == 0) ? 0 : -1;
152 myControlIDY = (ytype == Controller::Type::Driving && yid == 0) ? 0 : -1;
153 }
154 else // myJack == Right
155 {
156 myControlIDX = (xtype == Controller::Type::Driving && xid == 1) ? 1 : -1;
157 myControlIDY = (ytype == Controller::Type::Driving && yid == 1) ? 1 : -1;
158 }
159 }
160
161 return true;
162}
163