1use core::str::FromStr;
10use core::convert::TryFrom;
11use core::num::NonZeroU16;
12use core::fmt;
13use core::marker::PhantomData;
14use core::ops::{Deref, DerefMut};
15use std::borrow::Cow;
16
17#[cfg(feature = "snapshot")]
18use serde::{Serialize, Deserialize};
19
20use spectrusty_core::{
21 bus::{BusDevice, PortAddress}
22};
23
24use super::ay::PassByAyAudioBusDevice;
25
26pub use crate::joystick::{
27 JoystickDevice, JoystickInterface, NullJoystickDevice,
28 kempston::*, fuller::*, sinclair::*, cursor::*
29};
30
31pub type KempstonJoystick<D> = JoystickBusDevice<
33 KempstonJoyPortAddress,
34 KempstonJoystickDevice,
35 D>;
36pub type FullerJoystick<D> = JoystickBusDevice<
38 FullerJoyPortAddress,
39 FullerJoystickDevice,
40 D>;
41pub type SinclairJoystick<D> = SinclairLeftJoystick<SinclairRightJoystick<D>>;
43pub type SinclairRightJoystick<D> = JoystickBusDevice<
45 SinclairRightJoyPortAddress,
46 SinclairJoystickDevice<SinclairJoyRightMap>,
47 D>;
48pub type SinclairLeftJoystick<D> = JoystickBusDevice<
50 SinclairLeftJoyPortAddress,
51 SinclairJoystickDevice<SinclairJoyLeftMap>,
52 D>;
53pub type CursorJoystick<D> = JoystickBusDevice<
55 CursorJoyPortAddress,
56 CursorJoystickDevice,
57 D>;
58macro_rules! joystick_names {
59 ($($ty:ty: $name:expr),*) => { $(
60 impl<D> fmt::Display for $ty {
61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
62 f.write_str($name)
63 }
64 }
65 )*};
66}
67
68joystick_names! {
69 KempstonJoystick<D>: "Kempston Joystick",
70 FullerJoystick<D>: "Fuller Joystick",
71 SinclairRightJoystick<D>: "Sinclair #1 Joystick",
72 SinclairLeftJoystick<D>: "Sinclair #2 Joystick",
73 CursorJoystick<D>: "Cursor Joystick"
74}
75
76#[derive(Clone, Default, Debug)]
78#[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
79pub struct JoystickBusDevice<P, J, D>
80{
81 #[cfg_attr(feature = "snapshot", serde(skip))]
84 pub joystick: J,
85 #[cfg_attr(feature = "snapshot", serde(default))]
86 bus: D,
87 #[cfg_attr(feature = "snapshot", serde(skip))]
88 _port_decode: PhantomData<P>,
89}
90
91#[derive(Clone, Copy, Default, Debug)]
93pub struct KempstonJoyPortAddress;
94impl PortAddress for KempstonJoyPortAddress {
95 const ADDRESS_MASK: u16 = 0x0020;
96 const ADDRESS_BITS: u16 = 0x001f;
97}
98#[derive(Clone, Copy, Default, Debug)]
100pub struct FullerJoyPortAddress;
101impl PortAddress for FullerJoyPortAddress {
102 const ADDRESS_MASK: u16 = 0x00ff;
103 const ADDRESS_BITS: u16 = 0x007f;
104}
105#[derive(Clone, Copy, Default, Debug)]
107pub struct SinclairLeftJoyPortAddress;
108impl PortAddress for SinclairLeftJoyPortAddress {
109 const ADDRESS_MASK: u16 = 0x0800;
110 const ADDRESS_BITS: u16 = 0xf7fe;
111}
112#[derive(Clone, Copy, Default, Debug)]
114pub struct SinclairRightJoyPortAddress;
115impl PortAddress for SinclairRightJoyPortAddress {
116 const ADDRESS_MASK: u16 = 0x1000;
117 const ADDRESS_BITS: u16 = 0xeffe;
118}
119#[derive(Clone, Copy, Default, Debug)]
121pub struct CursorJoyPortAddress;
122impl PortAddress for CursorJoyPortAddress {
123 const ADDRESS_MASK: u16 = 0x1800;
124 const ADDRESS_BITS: u16 = 0xe7fe;
125 #[inline]
127 fn match_port(address: u16) -> bool {
128 address & Self::ADDRESS_MASK != Self::ADDRESS_MASK
129 }
130}
131
132impl<P, J: JoystickInterface, D> Deref for JoystickBusDevice<P, J, D> {
133 type Target = J;
134 fn deref(&self) -> &Self::Target {
135 &self.joystick
136 }
137}
138
139impl<P, J: JoystickInterface, D> DerefMut for JoystickBusDevice<P, J, D> {
140 fn deref_mut(&mut self) -> &mut Self::Target {
141 &mut self.joystick
142 }
143}
144
145impl<P, J, D> PassByAyAudioBusDevice for JoystickBusDevice<P, J, D> {}
146
147impl<P, J, D> BusDevice for JoystickBusDevice<P, J, D>
148 where P: PortAddress,
149 D: BusDevice,
150 J: JoystickDevice
151{
152 type Timestamp = D::Timestamp;
153 type NextDevice = D;
154
155 #[inline]
156 fn next_device_mut(&mut self) -> &mut Self::NextDevice {
157 &mut self.bus
158 }
159
160 #[inline]
161 fn next_device_ref(&self) -> &Self::NextDevice {
162 &self.bus
163 }
164
165 #[inline]
166 fn into_next_device(self) -> Self::NextDevice {
167 self.bus
168 }
169
170 #[inline]
171 fn read_io(&mut self, port: u16, timestamp: Self::Timestamp) -> Option<(u8, Option<NonZeroU16>)> {
172 let bus_data = self.bus.read_io(port, timestamp);
173 if P::match_port(port) {
174 let joy_data = self.joystick.port_read(port);
175 if let Some((data, ws)) = bus_data {
176 return Some((data & joy_data, ws))
177 }
178 return Some((joy_data, None))
179 }
180 bus_data
181 }
182
183 #[inline]
184 fn write_io(&mut self, port: u16, data: u8, timestamp: Self::Timestamp) -> Option<u16> {
185 if P::match_port(port) && self.joystick.port_write(port, data) {
186 return Some(0);
187 }
188 self.bus.write_io(port, data, timestamp)
189 }
190}
191
192#[derive(Clone, Copy, Default, Debug)]
196#[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
197pub struct MultiJoystickBusDevice<D> {
198 #[cfg_attr(feature = "snapshot", serde(default))]
199 pub joystick: JoystickSelect,
200 #[cfg_attr(feature = "snapshot", serde(default))]
201 bus: D
202}
203
204impl<D: Default> MultiJoystickBusDevice<D> {
205 pub fn new_with(joystick: JoystickSelect) -> Self {
206 MultiJoystickBusDevice {
207 joystick, bus: Default::default()
208 }
209 }
210}
211
212impl<D> Deref for MultiJoystickBusDevice<D> {
213 type Target = JoystickSelect;
214 fn deref(&self) -> &Self::Target {
215 &self.joystick
216 }
217}
218
219impl<D> DerefMut for MultiJoystickBusDevice<D> {
220 fn deref_mut(&mut self) -> &mut Self::Target {
221 &mut self.joystick
222 }
223}
224
225#[derive(Clone, Copy, Debug)]
229#[cfg_attr(feature = "snapshot", derive(Serialize, Deserialize))]
230#[cfg_attr(feature = "snapshot", serde(try_from = "Cow<str>", into = "&str"))]
231pub enum JoystickSelect {
232 Kempston(KempstonJoystickDevice),
233 Fuller(FullerJoystickDevice),
234 Sinclair(SinclairJoystickDevice<SinclairJoyRightMap>,
235 SinclairJoystickDevice<SinclairJoyLeftMap>),
236 Cursor(CursorJoystickDevice),
237}
238
239impl Default for JoystickSelect {
240 fn default() -> Self {
241 JoystickSelect::Kempston(Default::default())
242 }
243}
244
245impl fmt::Display for JoystickSelect {
246 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
247 <&str>::from(self).fmt(f)
248 }
249}
250
251impl From<&JoystickSelect> for &str {
252 fn from(joy: &JoystickSelect) -> Self {
253 <&str>::from(*joy)
254 }
255 }
256
257impl From<JoystickSelect> for &str {
258 fn from(joy: JoystickSelect) -> Self {
259 use JoystickSelect::*;
260 match joy {
261 Kempston(..) => "Kempston",
262 Fuller(..) => "Fuller",
263 Sinclair(..) => "Sinclair",
264 Cursor(..) => "Cursor",
265 }
266 }
267}
268
269#[derive(Debug, Clone, PartialEq, Eq)]
271pub struct ParseJoystickSelectError;
272
273impl fmt::Display for ParseJoystickSelectError {
274 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
275 "unrecognized joystick name".fmt(f)
276 }
277}
278
279impl std::error::Error for ParseJoystickSelectError {}
280
281impl FromStr for JoystickSelect {
282 type Err = ParseJoystickSelectError;
283
284 fn from_str(name: &str) -> Result<Self, Self::Err> {
285 match JoystickSelect::new_from_name(name) {
286 Some((joy, _)) => Ok(joy),
287 None => Err(ParseJoystickSelectError)
288 }
289 }
290}
291
292#[derive(Debug, Clone, PartialEq, Eq)]
294pub struct TryFromStrJoystickSelectError<'a>(pub Cow<'a, str>);
295
296impl fmt::Display for TryFromStrJoystickSelectError<'_> {
297 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
298 write!(f, "unrecognized joystick name: {}", self.0)
299 }
300}
301
302impl std::error::Error for TryFromStrJoystickSelectError<'_> {}
303
304impl<'a> TryFrom<&'a str> for JoystickSelect {
305 type Error = TryFromStrJoystickSelectError<'a>;
306 fn try_from(name: &'a str) -> Result<Self, Self::Error> {
307 match JoystickSelect::new_from_name(name) {
308 Some((joy, _)) => Ok(joy),
309 None => Err(TryFromStrJoystickSelectError(name.into()))
310 }
311 }
312}
313
314impl<'a> TryFrom<Cow<'a, str>> for JoystickSelect {
315 type Error = TryFromStrJoystickSelectError<'a>;
316 fn try_from(name: Cow<'a, str>) -> Result<Self, Self::Error> {
317 match JoystickSelect::new_from_name(&name) {
318 Some((joy, _)) => Ok(joy),
319 None => Err(TryFromStrJoystickSelectError(name))
320 }
321 }
322}
323
324#[allow(clippy::len_without_is_empty)]
325impl JoystickSelect {
326 pub const MAX_GLOBAL_INDEX: usize = 4;
328 pub fn new_from_name<S: AsRef<str>>(name: S) -> Option<(Self, usize)> {
333 let name = name.as_ref();
334 use JoystickSelect::*;
335 if name.eq_ignore_ascii_case("Kempston") {
336 Some((Kempston(Default::default()), 1))
337 }
338 else if name.eq_ignore_ascii_case("Fuller") {
339 Some((Fuller(Default::default()), 1))
340 }
341 else if name.eq_ignore_ascii_case("Cursor")
342 ||name.eq_ignore_ascii_case("Protek")
343 ||name.eq_ignore_ascii_case("AGF") {
344 Some((Cursor(Default::default()), 1))
345 }
346 else if name.eq_ignore_ascii_case("Sinclair")
347 ||name.eq_ignore_ascii_case("Interface II")
348 ||name.eq_ignore_ascii_case("Interface 2")
349 ||name.eq_ignore_ascii_case("IF II")
350 ||name.eq_ignore_ascii_case("IF 2") {
351 Some((Sinclair(Default::default(), Default::default()), 2))
352 }
353 else {
354 None
355 }
356 }
357 pub fn new_with_index(global_index: usize) -> Option<(Self, usize)> {
367 use JoystickSelect::*;
368 match global_index {
369 0 => Some((Kempston(Default::default()), 0)),
370 1 => Some((Fuller(Default::default()), 0)),
371 i@2|i@3 => Some((Sinclair(Default::default(), Default::default()), i-2)),
372 4 => Some((Cursor(Default::default()), 0)),
373 _ => None
374 }
375 }
376 pub fn len(&self) -> usize {
378 if let JoystickSelect::Sinclair(..) = self {
379 return 2
380 }
381 1
382 }
383 pub fn joystick_interface(&mut self, index: usize) -> Option<&mut (dyn JoystickInterface + 'static)>
390 {
391 match self {
392 JoystickSelect::Kempston(ref mut joy) if index == 0 => Some(joy),
393 JoystickSelect::Fuller(ref mut joy) if index == 0 => Some(joy),
394 JoystickSelect::Sinclair(ref mut joy, _) if index == 0 => Some(joy),
395 JoystickSelect::Sinclair(_, ref mut joy) if index == 1 => Some(joy),
396 JoystickSelect::Cursor(ref mut joy) if index == 0 => Some(joy),
397 _ => None
398 }
399 }
400 pub fn select_next_joystick(&mut self, index: usize) -> usize {
407 use JoystickSelect::*;
408 *self = match self {
409 Kempston(..) => Fuller(Default::default()),
410 Fuller(..) => Sinclair(Default::default(), Default::default()),
411 Sinclair(..) if index == 0 => return 1,
412 Sinclair(..) => Cursor(Default::default()),
413 Cursor(..) => Kempston(Default::default()),
414 };
415 0
416 }
417 #[inline]
418 pub fn is_last(&self) -> bool {
419 self.is_cursor()
420 }
421 #[inline]
422 pub fn is_kempston(&self) -> bool {
423 if let JoystickSelect::Kempston(..) = self {
424 return true
425 }
426 false
427 }
428 #[inline]
429 pub fn is_fuller(&self) -> bool {
430 if let JoystickSelect::Fuller(..) = self {
431 return true
432 }
433 false
434 }
435 #[inline]
436 pub fn is_sinclair(&self) -> bool {
437 if let JoystickSelect::Sinclair(..) = self {
438 return true
439 }
440 false
441 }
442 #[inline]
443 pub fn is_cursor(&self) -> bool {
444 if let JoystickSelect::Cursor(..) = self {
445 return true
446 }
447 false
448 }
449}
450
451impl<D> PassByAyAudioBusDevice for MultiJoystickBusDevice<D> {}
452
453impl<D> BusDevice for MultiJoystickBusDevice<D>
454 where D: BusDevice
455{
456 type Timestamp = D::Timestamp;
457 type NextDevice = D;
458
459 #[inline(always)]
460 fn next_device_mut(&mut self) -> &mut Self::NextDevice {
461 &mut self.bus
462 }
463
464 #[inline(always)]
465 fn next_device_ref(&self) -> &Self::NextDevice {
466 &self.bus
467 }
468
469 #[inline]
470 fn into_next_device(self) -> Self::NextDevice {
471 self.bus
472 }
473
474 #[inline(always)]
475 fn read_io(&mut self, port: u16, timestamp: Self::Timestamp) -> Option<(u8, Option<NonZeroU16>)> {
476 use JoystickSelect::*;
477 let bus_data = self.bus.read_io(port, timestamp);
478 let joy_data = match self.joystick {
479 Kempston(joystick) if KempstonJoyPortAddress::match_port(port) => {
480 Some(joystick.port_read(port))
481 }
482 Fuller(joystick) if FullerJoyPortAddress::match_port(port) => {
483 Some(joystick.port_read(port))
484 }
485 Sinclair(joy1, joy2) => {
486 let joy_data1 = if SinclairRightJoyPortAddress::match_port(port) {
487 Some(joy1.port_read(port))
488 }
489 else {
490 None
491 };
492 let joy_data2 = if SinclairLeftJoyPortAddress::match_port(port) {
493 Some(joy2.port_read(port))
494 }
495 else {
496 None
497 };
498 match (joy_data1, joy_data2) {
499 (Some(data1), Some(data2)) => Some(data1 & data2),
500 (Some(data1), None) => Some(data1),
501 (None, Some(data2)) => Some(data2),
502 _ => None
503 }
504 }
505 Cursor(joystick) if CursorJoyPortAddress::match_port(port) => {
506 Some(joystick.port_read(port))
507 }
508 _ => None
509 };
510 if let Some(joy_data) = joy_data {
511 if let Some((data, ws)) = bus_data {
512 return Some((data & joy_data, ws))
513 }
514 Some((joy_data, None))
515 }
516 else {
517 bus_data
518 }
519 }
520}
521
522#[cfg(test)]
523#[cfg(feature = "snapshot")]
524mod tests {
525 use super::*;
526
527 #[test]
528 fn joystick_select_snapshot() {
529 let (joy, len) = JoystickSelect::new_from_name("Sinclair").unwrap();
530 assert_eq!(len, 2);
531 assert!(joy.is_sinclair());
532 assert_eq!(joy.len(), len);
533 assert_eq!(<&str>::from(joy), "Sinclair");
534 let json = r#""Sinclair""#;
535 assert_eq!(serde_json::to_string(&joy).unwrap(), json);
536 let joy0: JoystickSelect = serde_json::from_str(json).unwrap();
537 let joy1: JoystickSelect = serde_json::from_reader(json.as_bytes()).unwrap();
538 assert!(joy0.is_sinclair());
539 assert!(joy1.is_sinclair());
540 assert_eq!(format!("{}", joy0), "Sinclair");
541 }
542}