1 // license:BSD-3-Clause
2 // copyright-holders:Vas Crabb
3 /**************************************************************************
4
5 PC Serial Mouse Simulation
6
7 Microsoft mouse is the classic two-button PC mouse. Data is 7N1 at
8 1,200 Baud. Mouse can be reset by de-asserting RTS. On start, the
9 mouse identifies itself with the string "M". Bit 6 is only set for
10 the first byte of a report - it's clear for all subsequent bytes of
11 a report, and also for all identification bytes.
12
13 Reports consist of three bytes: the first byte contains the button
14 state and the two high bits of the Y and X delta; the second byte
15 contains the low six bits of the X delta; the third byte contains
16 the low six bits of the Y delta. Button bits are set when pressed,
17 and positive delta is rightwards/downwards.
18
19 1lryyxx 0xxxxxx 0yyyyyy
20
21 Logitech extended the Microsoft protocol to support a third button.
22 The mouse identifies itself with the string "M3". If the third
23 button changes state, and additional byte is sent indicating the
24 new state of the third button.
25
26 1lryyxx 0xxxxxx 0yyyyyy 0m00000
27
28 The serial wheel mouse protocol extends the Microsoft mouse protocol
29 in a different way. The mouse identifies itself with the string
30 "MZ@\0\0\0". If the third button or wheel state changes, a fourth
31 an additional byte is sent containing the third button state and a
32 four-bit wheel delta value. The wheel value is positive for
33 downward movement. Note that the third button is value is in a
34 different position to the logitech protocol.
35
36 1lryyxx 0xxxxxx 0yyyyyy 00mwwww
37
38 The Mouse Systems non-rotatable protocol provides two-axis movement
39 and three buttons. Data is 8N1 at 1,200 Baud (the M-1 mouse could
40 also be configured for 300 Baud by turning DIP switch 1 off). The
41 mouse does not send an identification string. The first byte of a
42 report can be identified by a fixed pattern in the five most
43 significant bits.
44
45 Reports are five bytes long. The first byte contains the button
46 state; the second and fourth bytes contain X delta; the third and
47 fifth bytes contain Y delta. The two delta values for each axis
48 should be summed. Delta values range from -120 to 127 to prevent
49 being mistaken for the lead byte of a report. Button bits are clear
50 when set, and positive delta is rightwards/upwards. Delta values
51 are generated immediately before transmission - reports are not
52 atomic.
53
54 10000lmr xxxxxxxx yyyyyyyy xxxxxxxx yyyyyyyy
55
56 The Mouse systems rotatable protcol allows the host to infer
57 rotation around the third axis at the cost of halving the maximum
58 sustained movement speed. The M-1 mouse has two sensors spaced 100
59 counts apart horizontally. If DIP switch 2 is on, the X and Y delta
60 for each sensor is reported separately. The right sensor delta is
61 reported before the left sensor delta. If the mouse is rotated, the
62 delta values for the two sensors will differ.
63
64 **************************************************************************/
65
66 #include "emu.h"
67 #include "hlemouse.h"
68
69 #include <cassert>
70 #include <cmath>
71
72
73 //**************************************************
74 // Device type globals
75 //**************************************************
76
77 DEFINE_DEVICE_TYPE_NS(MSFT_HLE_SERIAL_MOUSE, bus::rs232, hle_msft_mouse_device, "rs232_mouse_hle_msft", "Microsoft 2-Button Serial Mouse (HLE)")
78 DEFINE_DEVICE_TYPE_NS(LOGITECH_HLE_SERIAL_MOUSE, bus::rs232, hle_logitech_mouse_device, "rs232_mouse_hle_logitech", "Logitech 3-Button Serial Mouse (HLE)")
79 DEFINE_DEVICE_TYPE_NS(WHEEL_HLE_SERIAL_MOUSE, bus::rs232, hle_wheel_mouse_device, "rs232_mouse_hle_wheel", "Microsoft Serial Mouse with Wheel (HLE)")
80 DEFINE_DEVICE_TYPE_NS(MSYSTEMS_HLE_SERIAL_MOUSE, bus::rs232, hle_msystems_mouse_device, "rs232_mouse_hle_msystems", "Mouse Systems Non-rotatable Mouse (HLE)")
81 DEFINE_DEVICE_TYPE_NS(ROTATABLE_HLE_SERIAL_MOUSE, bus::rs232, hle_rotatable_mouse_device, "rs232_mouse_hle_rotatable", "Mouse Systems Rotatable Mouse (HLE)")
82 DEFINE_DEVICE_TYPE_NS(SGI_HLE_SERIAL_MOUSE, bus::rs232, hle_sgi_mouse_device, "rs232_mouse_hle_sgi", "SGI IRIS Indigo Mouse (HLE)")
83
84 namespace bus { namespace rs232 {
85
86 namespace {
87
88 INPUT_PORTS_START(msft)
89 PORT_START("BTN")
90 PORT_BIT( 0xfffc, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_CODE(MOUSECODE_BUTTON1)91 PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_CODE(MOUSECODE_BUTTON1) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_msmouse_device_base, input_changed, 0)
92 PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_CODE(MOUSECODE_BUTTON2) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_msmouse_device_base, input_changed, 0)
93
94 PORT_START("X")
95 PORT_BIT( 0xf000, IP_ACTIVE_HIGH, IPT_UNUSED )
96 PORT_BIT( 0x0fff, 0x00, IPT_MOUSE_X ) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_msmouse_device_base, input_changed, 0)
97
98 PORT_START("Y")
99 PORT_BIT( 0xf000, IP_ACTIVE_HIGH, IPT_UNUSED )
100 PORT_BIT( 0x0fff, 0x00, IPT_MOUSE_Y ) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_msmouse_device_base, input_changed, 0)
101 INPUT_PORTS_END
102
103
104 INPUT_PORTS_START(logitech)
105 PORT_INCLUDE(msft)
106
107 PORT_MODIFY("BTN")
108 PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_CODE(MOUSECODE_BUTTON3) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_msmouse_device_base, input_changed, 0)
109 PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_CODE(MOUSECODE_BUTTON2) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_msmouse_device_base, input_changed, 0)
110 INPUT_PORTS_END
111
112
113 INPUT_PORTS_START(wheel)
114 PORT_INCLUDE(logitech)
115
116 PORT_START("WHEEL")
117 PORT_BIT( 0xf000, IP_ACTIVE_HIGH, IPT_UNUSED )
118 PORT_BIT( 0x0fff, 0x00, IPT_DIAL_V ) PORT_SENSITIVITY(10) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_msmouse_device_base, input_changed, 0)
119 INPUT_PORTS_END
120
121
122 INPUT_PORTS_START(msystems)
123 PORT_START("BTN")
124 PORT_BIT( 0xfff8, IP_ACTIVE_HIGH, IPT_UNUSED )
125 PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_CODE(MOUSECODE_BUTTON1) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_msystems_device_base, input_changed, 0)
126 PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_CODE(MOUSECODE_BUTTON3) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_msystems_device_base, input_changed, 0)
127 PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_CODE(MOUSECODE_BUTTON2) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_msystems_device_base, input_changed, 0)
128
129 PORT_START("X")
130 PORT_BIT( 0xf000, IP_ACTIVE_HIGH, IPT_UNUSED )
131 PORT_BIT( 0x0fff, 0x00, IPT_MOUSE_X ) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_msystems_device_base, input_changed, 0)
132
133 PORT_START("Y")
134 PORT_BIT( 0xf000, IP_ACTIVE_HIGH, IPT_UNUSED )
135 PORT_BIT( 0x0fff, 0x00, IPT_MOUSE_Y ) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_msystems_device_base, input_changed, 0)
136 INPUT_PORTS_END
137
138
139 INPUT_PORTS_START(rotatable)
140 PORT_INCLUDE(msystems)
141
142 PORT_START("ROT")
143 PORT_BIT( 0xf000, IP_ACTIVE_HIGH, IPT_UNUSED )
144 PORT_BIT( 0x0fff, 0x00, IPT_DIAL ) PORT_SENSITIVITY(10) PORT_CHANGED_MEMBER(DEVICE_SELF, hle_msystems_device_base, input_changed, 0)
145 INPUT_PORTS_END
146
147
148 template <unsigned Bits, typename T>
149 std::make_signed_t<T> read_axis(ioport_port &port, T &val)
150 {
151 static_assert((1U < Bits) && ((sizeof(T) * 8) > Bits), "invalid field bits");
152
153 T const updated(T(std::make_unsigned_t<T>(port.read())) & make_bitmask<T>(Bits));
154 std::make_signed_t<T> delta(std::make_signed_t<T>(updated) - std::make_signed_t<T>(val));
155 if (std::make_signed_t<T>(std::make_unsigned_t<T>(1) << (Bits - 1)) <= delta)
156 delta -= std::make_signed_t<T>(std::make_unsigned_t<T>(1) << Bits);
157 else if (-std::make_signed_t<T>(std::make_unsigned_t<T>(1) << (Bits - 1)) >= delta)
158 delta += std::make_signed_t<T>(std::make_unsigned_t<T>(1) << Bits);
159 val = updated;
160 return delta;
161 }
162
163
164 template <typename T>
report_axis(T & delta,T low,T high)165 uint8_t report_axis(T &delta, T low, T high)
166 {
167 T const result(std::min<T>(std::max<T>(delta, low), high));
168 delta -= result;
169 return uint8_t(int8_t(result));
170 }
171
172 } // anonymous namespace
173
174
175 //**************************************************
176 // Microsoft mouse base
177 //**************************************************
178
INPUT_CHANGED_MEMBER(hle_msmouse_device_base::input_changed)179 INPUT_CHANGED_MEMBER(hle_msmouse_device_base::input_changed)
180 {
181 if (fifo_empty() && is_transmit_register_empty())
182 check_inputs();
183 }
184
hle_msmouse_device_base(machine_config const & mconfig,device_type type,char const * tag,device_t * owner,uint32_t clock)185 hle_msmouse_device_base::hle_msmouse_device_base(
186 machine_config const &mconfig,
187 device_type type,
188 char const *tag,
189 device_t *owner,
190 uint32_t clock)
191 : buffered_rs232_device<8>(mconfig, type, tag, owner, clock)
192 , m_buttons(*this, "BTN")
193 , m_x_axis(*this, "X")
194 , m_y_axis(*this, "Y")
195 , m_x_delta(0)
196 , m_y_delta(0)
197 , m_x_val(0U)
198 , m_y_val(0U)
199 , m_btn_val(0x00U)
200 , m_btn_sent(0x00U)
201 , m_dtr(0U)
202 , m_rts(0U)
203 , m_enable(0U)
204 {
205 }
206
device_resolve_objects()207 void hle_msmouse_device_base::device_resolve_objects()
208 {
209 buffered_rs232_device<8>::device_resolve_objects();
210
211 m_dtr = 0U;
212 m_rts = 0U;
213 }
214
device_start()215 void hle_msmouse_device_base::device_start()
216 {
217 buffered_rs232_device<8>::device_start();
218
219 save_item(NAME(m_x_delta));
220 save_item(NAME(m_y_delta));
221 save_item(NAME(m_x_val));
222 save_item(NAME(m_y_val));
223 save_item(NAME(m_btn_val));
224 save_item(NAME(m_btn_sent));
225 save_item(NAME(m_dtr));
226 save_item(NAME(m_rts));
227 save_item(NAME(m_enable));
228
229 set_data_frame(1, 7, PARITY_NONE, STOP_BITS_2);
230 set_rate(1'200);
231 receive_register_reset();
232 transmit_register_reset();
233
234 m_x_delta = m_y_delta = 0;
235 m_x_val = m_y_val = 0U;
236 m_btn_val = m_btn_sent = 0x00U;
237 m_enable = 0U;
238
239 machine().scheduler().synchronize(timer_expired_delegate(FUNC(hle_msmouse_device_base::start_mouse), this));
240 }
241
WRITE_LINE_MEMBER(hle_msmouse_device_base::input_dtr)242 WRITE_LINE_MEMBER(hle_msmouse_device_base::input_dtr)
243 {
244 m_dtr = state ? 1U : 0U;
245 check_enable();
246 }
247
WRITE_LINE_MEMBER(hle_msmouse_device_base::input_rts)248 WRITE_LINE_MEMBER(hle_msmouse_device_base::input_rts)
249 {
250 m_rts = state ? 1U : 0U;
251 check_enable();
252 }
253
tra_complete()254 void hle_msmouse_device_base::tra_complete()
255 {
256 buffered_rs232_device<8>::tra_complete();
257 if (fifo_empty() && is_transmit_register_empty())
258 check_inputs();
259 }
260
received_byte(u8 byte)261 void hle_msmouse_device_base::received_byte(u8 byte)
262 {
263 }
264
265
TIMER_CALLBACK_MEMBER(hle_msmouse_device_base::start_mouse)266 TIMER_CALLBACK_MEMBER(hle_msmouse_device_base::start_mouse)
267 {
268 check_enable();
269 }
270
check_enable()271 void hle_msmouse_device_base::check_enable()
272 {
273 bool const enable(!m_dtr && !m_rts);
274 if (bool(m_enable) != enable)
275 {
276 m_enable = enable ? 1U : 0U;
277 clear_fifo();
278 receive_register_reset();
279 transmit_register_reset();
280 if (enable)
281 {
282 read_inputs();
283 m_x_delta = m_y_delta = 0;
284 m_btn_sent = m_btn_val;
285 reset_and_identify();
286 }
287 }
288 }
289
check_inputs()290 void hle_msmouse_device_base::check_inputs()
291 {
292 if (m_enable && read_inputs())
293 {
294 uint8_t const x(report_axis<int16_t>(m_x_delta, -128, 127));
295 uint8_t const y(report_axis<int16_t>(m_y_delta, -128, 127));
296 transmit_byte(0x40U | ((m_btn_val << 4) & 0x30U) | ((y >> 4) & 0x0cU) | ((x >> 6) & 0x03U));
297 transmit_byte(x & 0x3fU);
298 transmit_byte(y & 0x3fU);
299 transmit_extensions(m_btn_val, m_btn_sent);
300 m_btn_sent = m_btn_val;
301 }
302 }
303
read_inputs()304 bool hle_msmouse_device_base::read_inputs()
305 {
306 m_x_delta += read_axis<12>(*m_x_axis, m_x_val);
307 m_y_delta += read_axis<12>(*m_y_axis, m_y_val);
308 m_btn_val = m_buttons->read();
309 return m_x_delta || m_y_delta || (m_btn_val != m_btn_sent);
310 }
311
312
313 //**************************************************
314 // Microsoft 2-button mouse
315 //**************************************************
316
hle_msft_mouse_device(machine_config const & mconfig,char const * tag,device_t * owner,uint32_t clock)317 hle_msft_mouse_device::hle_msft_mouse_device(
318 machine_config const &mconfig,
319 char const *tag,
320 device_t *owner,
321 uint32_t clock)
322 : hle_msmouse_device_base(mconfig, MSFT_HLE_SERIAL_MOUSE, tag, owner, clock)
323 {
324 }
325
device_input_ports() const326 ioport_constructor hle_msft_mouse_device::device_input_ports() const
327 {
328 return INPUT_PORTS_NAME(msft);
329 }
330
reset_and_identify()331 void hle_msft_mouse_device::reset_and_identify()
332 {
333 // assume ASCII host system
334 transmit_byte('M');
335 }
336
transmit_extensions(uint8_t btn_val,uint8_t btn_sent)337 void hle_msft_mouse_device::transmit_extensions(uint8_t btn_val, uint8_t btn_sent)
338 {
339 }
340
341
342 //**************************************************
343 // Logitech 3-button mouse
344 //**************************************************
345
hle_logitech_mouse_device(machine_config const & mconfig,char const * tag,device_t * owner,uint32_t clock)346 hle_logitech_mouse_device::hle_logitech_mouse_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock)
347 : hle_msmouse_device_base(mconfig, LOGITECH_HLE_SERIAL_MOUSE, tag, owner, clock)
348 {
349 }
350
device_input_ports() const351 ioport_constructor hle_logitech_mouse_device::device_input_ports() const
352 {
353 return INPUT_PORTS_NAME(logitech);
354 }
355
reset_and_identify()356 void hle_logitech_mouse_device::reset_and_identify()
357 {
358 // assume ASCII host system
359 transmit_byte('M');
360 transmit_byte('3');
361 }
362
transmit_extensions(uint8_t btn_val,uint8_t btn_sent)363 void hle_logitech_mouse_device::transmit_extensions(uint8_t btn_val, uint8_t btn_sent)
364 {
365 if (BIT(btn_val | btn_sent, 2))
366 transmit_byte(BIT(btn_val, 2) << 5);
367 }
368
369
370
371 //**************************************************
372 // Microsoft wheel mouse
373 //**************************************************
374
hle_wheel_mouse_device(machine_config const & mconfig,char const * tag,device_t * owner,uint32_t clock)375 hle_wheel_mouse_device::hle_wheel_mouse_device(
376 machine_config const &mconfig,
377 char const *tag,
378 device_t *owner,
379 uint32_t clock)
380 : hle_msmouse_device_base(mconfig, WHEEL_HLE_SERIAL_MOUSE, tag, owner, clock)
381 , m_wheel(*this, "WHEEL")
382 , m_wheel_delta(0)
383 , m_wheel_val(0U)
384 {
385 }
386
device_input_ports() const387 ioport_constructor hle_wheel_mouse_device::device_input_ports() const
388 {
389 return INPUT_PORTS_NAME(wheel);
390 }
391
device_start()392 void hle_wheel_mouse_device::device_start()
393 {
394 hle_msmouse_device_base::device_start();
395
396 save_item(NAME(m_wheel_delta));
397 save_item(NAME(m_wheel_val));
398
399 m_wheel_delta = 0;
400 m_wheel_val = 0U;
401 }
402
read_inputs()403 bool hle_wheel_mouse_device::read_inputs()
404 {
405 m_wheel_delta += read_axis<12>(*m_wheel, m_wheel_val);
406 return hle_msmouse_device_base::read_inputs() || m_wheel_delta;
407 }
408
reset_and_identify()409 void hle_wheel_mouse_device::reset_and_identify()
410 {
411 m_wheel_delta = 0;
412
413 // assume ASCII host system
414 transmit_byte('M');
415 transmit_byte('Z');
416 transmit_byte('@');
417 transmit_byte('\0');
418 transmit_byte('\0');
419 transmit_byte('\0');
420 }
421
transmit_extensions(uint8_t btn_val,uint8_t btn_sent)422 void hle_wheel_mouse_device::transmit_extensions(uint8_t btn_val, uint8_t btn_sent)
423 {
424 if (BIT(btn_val | btn_sent, 2) || m_wheel_delta)
425 transmit_byte((BIT(btn_val, 2) << 4) | (report_axis<int16_t>(m_wheel_delta, -8, 7) & 0x0fU));
426 }
427
428
429 //**************************************************
430 // Mouse Systems mouse base
431 //**************************************************
432
INPUT_CHANGED_MEMBER(hle_msystems_device_base::input_changed)433 INPUT_CHANGED_MEMBER(hle_msystems_device_base::input_changed)
434 {
435 if (is_transmit_register_empty())
436 {
437 assert(0U == m_phase);
438 tra_complete();
439 }
440 }
441
hle_msystems_device_base(machine_config const & mconfig,device_type type,char const * tag,device_t * owner,uint32_t clock)442 hle_msystems_device_base::hle_msystems_device_base(
443 machine_config const &mconfig,
444 device_type type,
445 char const *tag,
446 device_t *owner,
447 uint32_t clock)
448 : device_t(mconfig, type, tag, owner, clock)
449 , device_rs232_port_interface(mconfig, *this)
450 , device_serial_interface(mconfig, *this)
451 , m_phase(0U)
452 {
453 }
454
device_start()455 void hle_msystems_device_base::device_start()
456 {
457 save_item(NAME(m_phase));
458
459 set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1);
460 set_rate(1'200);
461 receive_register_reset();
462 transmit_register_reset();
463
464 m_phase = 0U;
465
466 machine().scheduler().synchronize(timer_expired_delegate(FUNC(hle_msystems_device_base::start_mouse), this));
467 }
468
tra_callback()469 void hle_msystems_device_base::tra_callback()
470 {
471 output_rxd(transmit_register_get_data_bit());
472 }
473
tra_complete()474 void hle_msystems_device_base::tra_complete()
475 {
476 if (4U <= m_phase)
477 m_phase = 0U;
478 else
479 ++m_phase;
480
481 bool const dirty(read_inputs());
482 switch (m_phase)
483 {
484 case 0U:
485 if (dirty)
486 transmit_register_setup((report_buttons() & 0x07U) | 0x80U);
487 break;
488 case 1U:
489 transmit_register_setup(report_x1_delta());
490 break;
491 case 2U:
492 transmit_register_setup(report_y1_delta());
493 break;
494 case 3U:
495 transmit_register_setup(report_x2_delta());
496 break;
497 case 4U:
498 transmit_register_setup(report_y2_delta());
499 break;
500 };
501 }
502
TIMER_CALLBACK_MEMBER(hle_msystems_device_base::start_mouse)503 TIMER_CALLBACK_MEMBER(hle_msystems_device_base::start_mouse)
504 {
505 if (is_transmit_register_empty())
506 {
507 assert(0U == m_phase);
508 tra_complete();
509 }
510 }
511
512
513 //**************************************************
514 // Mouse Systems non-rotatable mouse
515 //**************************************************
516
hle_msystems_mouse_device(machine_config const & mconfig,device_type type,char const * tag,device_t * owner,uint32_t clock)517 hle_msystems_mouse_device::hle_msystems_mouse_device(
518 machine_config const &mconfig,
519 device_type type,
520 char const *tag,
521 device_t *owner,
522 uint32_t clock)
523 : hle_msystems_device_base(mconfig, type, tag, owner, clock)
524 , m_buttons(*this, "BTN")
525 , m_x_axis(*this, "X")
526 , m_y_axis(*this, "Y")
527 , m_x_delta(0)
528 , m_y_delta(0)
529 , m_x_val(0U)
530 , m_y_val(0U)
531 , m_btn_val(0x00U)
532 , m_btn_sent(0x00U)
533 {
534 }
535
hle_msystems_mouse_device(machine_config const & mconfig,char const * tag,device_t * owner,uint32_t clock)536 hle_msystems_mouse_device::hle_msystems_mouse_device(
537 machine_config const &mconfig,
538 char const *tag,
539 device_t *owner,
540 uint32_t clock)
541 : hle_msystems_mouse_device(mconfig, MSYSTEMS_HLE_SERIAL_MOUSE, tag, owner, clock)
542 {
543 }
544
device_input_ports() const545 ioport_constructor hle_msystems_mouse_device::device_input_ports() const
546 {
547 return INPUT_PORTS_NAME(msystems);
548 }
549
device_start()550 void hle_msystems_mouse_device::device_start()
551 {
552 hle_msystems_device_base::device_start();
553
554 save_item(NAME(m_x_delta));
555 save_item(NAME(m_y_delta));
556 save_item(NAME(m_x_val));
557 save_item(NAME(m_y_val));
558 save_item(NAME(m_btn_val));
559 save_item(NAME(m_btn_sent));
560
561 m_x_delta = m_y_delta = 0;
562 m_x_val = m_y_val = 0U;
563 m_btn_val = m_btn_sent = 0x00U;
564 }
565
read_inputs()566 bool hle_msystems_mouse_device::read_inputs()
567 {
568 m_x_delta += read_axis<12>(*m_x_axis, m_x_val);
569 m_y_delta -= read_axis<12>(*m_y_axis, m_y_val);
570 m_btn_val = m_buttons->read();
571 return m_x_delta || m_y_delta || (m_btn_val != m_btn_sent);
572 }
573
report_buttons()574 uint8_t hle_msystems_mouse_device::report_buttons()
575 {
576 m_btn_sent = m_btn_val;
577 return m_btn_sent;
578 }
579
report_x1_delta()580 uint8_t hle_msystems_mouse_device::report_x1_delta()
581 {
582 return report_axis<int16_t>(m_x_delta, -120, 127);
583 }
584
report_y1_delta()585 uint8_t hle_msystems_mouse_device::report_y1_delta()
586 {
587 return report_axis<int16_t>(m_y_delta, -120, 127);
588 }
589
report_x2_delta()590 uint8_t hle_msystems_mouse_device::report_x2_delta()
591 {
592 return report_axis<int16_t>(m_x_delta, -120, 127);
593 }
594
report_y2_delta()595 uint8_t hle_msystems_mouse_device::report_y2_delta()
596 {
597 return report_axis<int16_t>(m_y_delta, -120, 127);
598 }
599
600
601 //**************************************************
602 // Mouse Systems rotatable mouse
603 //**************************************************
604
hle_rotatable_mouse_device(machine_config const & mconfig,char const * tag,device_t * owner,uint32_t clock)605 hle_rotatable_mouse_device::hle_rotatable_mouse_device(
606 machine_config const &mconfig,
607 char const *tag,
608 device_t *owner,
609 uint32_t clock)
610 : hle_msystems_device_base(mconfig, ROTATABLE_HLE_SERIAL_MOUSE, tag, owner, clock)
611 , m_buttons(*this, "BTN")
612 , m_x_axis(*this, "X")
613 , m_y_axis(*this, "Y")
614 , m_rotation(*this, "ROT")
615 , m_x_delta{ 0, 0 }
616 , m_y_delta{ 0, 0 }
617 , m_x_val(0U)
618 , m_y_val(0U)
619 , m_rot_val(0U)
620 , m_btn_val(0x00U)
621 , m_btn_sent(0x00U)
622 {
623 }
624
device_input_ports() const625 ioport_constructor hle_rotatable_mouse_device::device_input_ports() const
626 {
627 return INPUT_PORTS_NAME(rotatable);
628 }
629
device_start()630 void hle_rotatable_mouse_device::device_start()
631 {
632 hle_msystems_device_base::device_start();
633
634 save_item(NAME(m_x_delta));
635 save_item(NAME(m_y_delta));
636 save_item(NAME(m_x_val));
637 save_item(NAME(m_y_val));
638 save_item(NAME(m_rot_val));
639 save_item(NAME(m_btn_val));
640 save_item(NAME(m_btn_sent));
641
642 m_x_delta[0] = m_x_delta[1] = m_y_delta[0] = m_y_delta[1] = 0;
643 m_x_val = m_y_val = m_rot_val = 0U;
644 m_btn_val = m_btn_sent = 0x00U;
645 }
646
read_inputs()647 bool hle_rotatable_mouse_device::read_inputs()
648 {
649 // translation is straighforward
650 int16_t const x_delta(read_axis<12>(*m_x_axis, m_x_val));
651 int16_t const y_delta(read_axis<12>(*m_y_axis, m_y_val));
652 m_x_delta[0] += x_delta;
653 m_x_delta[1] += x_delta;
654 m_y_delta[0] -= y_delta;
655 m_y_delta[1] -= y_delta;
656
657 // there are two sensors 100 counts apart, one inch below the centre of the mouse
658 // for simplicity, assume the mouse is rotated around the point midway the sensors
659 int16_t const rot_delta(read_axis<12>(*m_rotation, m_rot_val));
660 if (rot_delta)
661 {
662 double const rot_angle(-0.15 * rot_delta);
663 long const x_diff(std::lround((1 - std::cos(rot_angle)) * 100));
664 long const y_diff(std::lround(std::sin(rot_angle) * 100));
665 m_x_delta[0] -= x_diff / 2;
666 m_x_delta[1] += x_diff - (x_diff / 2);
667 m_y_delta[0] += y_diff / 2;
668 m_y_delta[1] -= y_diff - (y_diff / 2);
669 }
670
671 // this is straightforward, too
672 m_btn_val = m_buttons->read();
673 return m_x_delta[0] || m_x_delta[1] || m_y_delta[0] || m_y_delta[1] || (m_btn_val != m_btn_sent);
674 }
675
report_buttons()676 uint8_t hle_rotatable_mouse_device::report_buttons()
677 {
678 m_btn_sent = m_btn_val;
679 return m_btn_sent;
680 }
681
report_x1_delta()682 uint8_t hle_rotatable_mouse_device::report_x1_delta()
683 {
684 return report_axis<int16_t>(m_x_delta[0], -120, 127);
685 }
686
report_y1_delta()687 uint8_t hle_rotatable_mouse_device::report_y1_delta()
688 {
689 return report_axis<int16_t>(m_y_delta[0], -120, 127);
690 }
691
report_x2_delta()692 uint8_t hle_rotatable_mouse_device::report_x2_delta()
693 {
694 return report_axis<int16_t>(m_x_delta[1], -120, 127);
695 }
696
report_y2_delta()697 uint8_t hle_rotatable_mouse_device::report_y2_delta()
698 {
699 return report_axis<int16_t>(m_y_delta[1], -120, 127);
700 }
701
702 //**************************************************
703 // SGI IRIS Indigo mouse
704 //**************************************************
705
hle_sgi_mouse_device(machine_config const & mconfig,char const * tag,device_t * owner,uint32_t clock)706 hle_sgi_mouse_device::hle_sgi_mouse_device(
707 machine_config const &mconfig,
708 char const *tag,
709 device_t *owner,
710 uint32_t clock)
711 : hle_msystems_mouse_device(mconfig, SGI_HLE_SERIAL_MOUSE, tag, owner, clock)
712 {
713 }
714
device_start()715 void hle_sgi_mouse_device::device_start()
716 {
717 hle_msystems_mouse_device::device_start();
718 set_rate(4'800);
719 receive_register_reset();
720 transmit_register_reset();
721 }
722
723 } } // namespace bus::rs232
724