1 /******************************************************************************/
2 /* Mednafen - Multi-system Emulator */
3 /******************************************************************************/
4 /* megamouse.cpp:
5 ** Copyright (C) 2009-2016 Mednafen Team
6 **
7 ** This program is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU General Public License
9 ** as published by the Free Software Foundation; either version 2
10 ** of the License, or (at your option) any later version.
11 **
12 ** This program is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ** GNU General Public License for more details.
16 **
17 ** You should have received a copy of the GNU General Public License
18 ** along with this program; if not, write to the Free Software Foundation, Inc.,
19 ** 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 */
21
22 #include "../shared.h"
23 #include "megamouse.h"
24 #include <trio/trio.h>
25
26 namespace MDFN_IEN_MD
27 {
28
29 enum
30 {
31 MASK_TH = 0x40,
32 MASK_TR = 0x20,
33 MASK_TL = 0x10,
34 MASK_DATA = 0x0F
35 };
36
37 class MegaMouse final : public MD_Input_Device
38 {
39 public:
40 MegaMouse();
41 virtual ~MegaMouse() override;
42 virtual void UpdateBus(const int32 master_timestamp, uint8 &bus, const uint8 genesis_asserted) override;
43 virtual void UpdatePhysicalState(const void *data) override;
44 virtual void BeginTimePeriod(const int32 timestamp_base) override;
45 virtual void EndTimePeriod(const int32 master_timestamp) override;
46 virtual void Power(void) override;
47 virtual void StateAction(StateMem *sm, const unsigned load, const bool data_only, const char *section_prefix) override;
48
49 private:
50 int32 mouse_x;
51 int32 mouse_y;
52 uint8 buttons;
53
54 int32 busy_until;
55
56 uint8 phase;
57 uint8 bus_av;
58 uint8 data_buffer[0x8];
59 };
60
61 const IDIISG MegaMouseIDII =
62 {
63 IDIIS_AxisRel("motion", "Motion",/**/ "left", "Left",/**/ "right", "Right", 0),
64 IDIIS_AxisRel("motion", "Motion",/**/ "up", "Up",/**/ "down", "Down", 1),
65 IDIIS_Button("left", "Left Button", 2),
66 IDIIS_Button("right", "Right Button", 3),
67 IDIIS_Button("middle", "Middle Button", 4),
68 IDIIS_Button("start", "Start Button", 5),
69 };
70
71 enum
72 {
73 PHASE_RESETTING = 0,
74 PHASE_RESET_EXEC,
75 PHASE_INITIAL,
76 PHASE_BEGIN,
77 PHASE_DATA0,
78 PHASE_DATA1,
79 PHASE_DATA2,
80 PHASE_DATA3,
81 PHASE_DATA4,
82 PHASE_DATA5,
83 PHASE_DATA6,
84 PHASE_DATA7,
85 PHASE_END
86 };
87
MegaMouse()88 MegaMouse::MegaMouse()
89 {
90 mouse_x = 0;
91 mouse_y = 0;
92 buttons = 0;
93
94 phase = PHASE_INITIAL;
95 busy_until = -1;
96 }
97
~MegaMouse()98 MegaMouse::~MegaMouse()
99 {
100
101 }
102
Power(void)103 void MegaMouse::Power(void)
104 {
105 bus_av = 0x10;
106 phase = PHASE_INITIAL;
107 busy_until = -1;
108 }
109
110
BeginTimePeriod(const int32 timestamp_base)111 void MegaMouse::BeginTimePeriod(const int32 timestamp_base)
112 {
113 //puts("Begin");
114 if(busy_until >= 0)
115 busy_until += timestamp_base;
116 }
117
EndTimePeriod(const int32 master_timestamp)118 void MegaMouse::EndTimePeriod(const int32 master_timestamp)
119 {
120 if(busy_until >= 0 && master_timestamp >= busy_until)
121 {
122 //puts("Advance phase");
123 if(phase < PHASE_END)
124 phase++;
125 busy_until = -1;
126 }
127
128 if(busy_until >= 0)
129 busy_until -= master_timestamp;
130 }
131
UpdateBus(const int32 master_timestamp,uint8 & bus,const uint8 genesis_asserted)132 void MegaMouse::UpdateBus(const int32 master_timestamp, uint8 &bus, const uint8 genesis_asserted)
133 {
134 const bool th = bus & MASK_TH;
135 const bool tr = bus & MASK_TR;
136
137 if(th && tr && phase != PHASE_RESET_EXEC)
138 {
139 busy_until = -1;
140 phase = PHASE_INITIAL;
141 }
142
143 if(busy_until >= 0)
144 {
145 if(master_timestamp >= busy_until)
146 {
147 //puts("Advance phase");
148 if(phase < PHASE_END)
149 phase++;
150 busy_until = -1;
151 }
152 }
153
154 if(busy_until < 0)
155 {
156 switch(phase)
157 {
158 case PHASE_RESET_EXEC:
159 bus_av = 0x00;
160 if(tr)
161 busy_until = master_timestamp + 400;
162 break;
163
164 case PHASE_INITIAL:
165 if(th)
166 {
167 bus_av = 0x10;
168
169 if(!tr)
170 {
171 phase = PHASE_RESETTING;
172 busy_until = master_timestamp + 400;
173 }
174 }
175 else
176 {
177 phase++;
178 }
179 break;
180
181 case PHASE_BEGIN:
182 bus_av = 0x1B;
183 if(!tr)
184 {
185 int32 rel_x = mouse_x;
186 int32 rel_y = mouse_y;
187 bool x_neg = 0;
188 bool y_neg = 0;
189
190 if(rel_x < -255)
191 rel_x = -255;
192
193 if(rel_x > 255)
194 rel_x = 255;
195
196 if(rel_y < -255)
197 rel_y = -255;
198
199 if(rel_y > 255)
200 rel_y = 255;
201
202 mouse_x -= rel_x;
203 mouse_y -= rel_y;
204
205 rel_y = -rel_y;
206
207 x_neg = (rel_x < 0);
208 y_neg = (rel_y < 0);
209
210 data_buffer[0] = 0xF;
211 data_buffer[1] = 0xF;
212 data_buffer[2] = (x_neg ? 0x1 : 0x0) | (y_neg ? 0x2 : 0x0); // Axis sign and overflow
213 data_buffer[3] = buttons; // Button state
214 data_buffer[4] = (rel_x >> 4) & 0xF; // X axis MSN
215 data_buffer[5] = (rel_x >> 0) & 0xF; // X axis LSN
216 data_buffer[6] = (rel_y >> 4) & 0xF; // Y axis MSN
217 data_buffer[7] = (rel_y >> 0) & 0xF; // Y axis LSN
218
219 //printf("DB: %02x %02x %02x %02x %02x %02x %02x %02x\n", data_buffer[0], data_buffer[1], data_buffer[2], data_buffer[3], data_buffer[4], data_buffer[5], data_buffer[6], data_buffer[7]);
220
221 busy_until = master_timestamp + 400;
222 }
223 break;
224
225 case PHASE_DATA0: case PHASE_DATA1: case PHASE_DATA2: case PHASE_DATA3:
226 case PHASE_DATA4: case PHASE_DATA5: case PHASE_DATA6: case PHASE_DATA7:
227 bus_av = data_buffer[phase - PHASE_DATA0] | (((phase - PHASE_DATA0) & 1) << 4);
228 if(tr != ((phase - PHASE_DATA0) & 1))
229 busy_until = master_timestamp + 400;
230 break;
231
232 case PHASE_END:
233 bus_av ^= 0x10;
234
235 if(tr != (bool)(bus_av & 0x10))
236 {
237 busy_until = master_timestamp + 400;
238 }
239 break;
240 }
241 }
242
243 bus = (bus &~ 0x1F) | bus_av;
244 //printf("%02x, %02x --- %d -- %d\n", bus, bus_av, phase, master_timestamp);
245 }
246
UpdatePhysicalState(const void * data)247 void MegaMouse::UpdatePhysicalState(const void *data)
248 {
249 mouse_x += (int16)MDFN_de16lsb((uint8 *)data + 0);
250 mouse_y += (int16)MDFN_de16lsb((uint8 *)data + 2);
251 buttons = ((uint8 *)data)[4];
252 }
253
StateAction(StateMem * sm,const unsigned load,const bool data_only,const char * section_prefix)254 void MegaMouse::StateAction(StateMem *sm, const unsigned load, const bool data_only, const char *section_prefix)
255 {
256 SFORMAT StateRegs[] =
257 {
258 SFVAR(mouse_x),
259 SFVAR(mouse_y),
260 SFVAR(buttons),
261
262 SFVAR(busy_until),
263
264 SFVAR(phase),
265 SFVAR(bus_av),
266 SFVAR(data_buffer),
267
268 SFEND
269 };
270 char sname[64];
271
272 trio_snprintf(sname, sizeof(sname), "%s-mmouse", section_prefix);
273
274 if(!MDFNSS_StateAction(sm, load, data_only, StateRegs, sname, true) && load)
275 Power();
276 else if(load)
277 {
278
279 }
280 }
281
MDInput_MakeMegaMouse(void)282 MD_Input_Device *MDInput_MakeMegaMouse(void)
283 {
284 MD_Input_Device *ret = new MegaMouse();
285
286 return(ret);
287 }
288
289 }
290