Added joystick support

It is limited for now, hard coded to mine. Still need some sort of way
to specify which button to map to the emulated joytick. Same with the
axis, currently default to 0,1

Signed-off-by: Michel Pollet <buserror@gmail.com>
This commit is contained in:
Michel Pollet 2023-10-28 16:59:08 +01:00
parent 08e1ff861e
commit d53b0bceff
6 changed files with 193 additions and 7 deletions

View File

@ -32,6 +32,7 @@ I wanted something:
* Adds a small 'attack' filter when playing back to soften the often annoying 'click' of typical audio effects from the apple II.
* Mouse Card -- mouse isn't captured like in some other emulators.
* No Slot Clock
* Joystick (in a limited way...)
* Smartport DMA 'hard drive' card
* "Titan Accelerator //e" simulation, to turn on/off fast mode.
* Terence's J Boldt [1MB ROM card](https://github.com/tjboldt/ProDOS-ROM-Drive), also because I own a couple!
@ -127,6 +128,7 @@ There are just a few keys that are mapped for anything useful.
* A2Desktop PT3 player doesn't see keypresses.
* Sometimes the emulator goes in 'slow mode', ie 0.2MHz. Likely the frame scheduler playing up.
* Thats' about it really, all the other things I tried work
* Joystick support is a bit limited, no 'mapping' I used a (USB) 8bitdo NES30 Pro, and it works, but it's not perfect. But, I can play choplifter with it, so it's good enough for now...
## What it could do with
* Not sure about keeping Nuklear, it does a lot bit it's hard work customizing anything

View File

@ -86,6 +86,12 @@ show_state:
}
return;
}
if (!strcmp(argv[1], "analog")) {
printf("analog: %3d %3d %3d %3d\n", mii->analog.v[0].value,
mii->analog.v[1].value, mii->analog.v[2].value,
mii->analog.v[3].value);
return;
}
if (!strcmp(argv[1], "trace")) {
mii->trace_cpu = !mii->trace_cpu;
printf("trace_cpu %d\n", mii->trace_cpu);

View File

@ -12,6 +12,15 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
// probably should wrap these into a HAVE_JOYSTICK define for non-linux
#ifndef HAVE_JOYSTICK
#define HAVE_JOYSTICK 1
#endif
#include "mii.h"
#include "mii_thread.h"
@ -31,19 +40,17 @@ mii_get_time()
return time;
}
static pthread_t mii_thread;
static bool mii_thread_running = false;
static float default_fps = 60;
mii_th_fifo_t signal_fifo;
static void *
mii_thread_func(
mii_thread_cpu_regulator(
void *arg)
{
mii_t *mii = (mii_t *) arg;
mii_thread_running = true;
__uint128_t last_cycles = mii->cycles;
mii_cycles_t last_cycles = mii->cycles;
uint32_t running = 1;
unsigned long target_fps_us = 1000000 / default_fps;
long sleep_time = target_fps_us;
@ -117,8 +124,8 @@ mii_thread_func(
last_frame_stamp += target_fps_us;
// calculate the MHz
__uint128_t cycles = mii->cycles;
__uint128_t delta_cycles = cycles - last_cycles;
mii_cycles_t cycles = mii->cycles;
mii_cycles_t delta_cycles = cycles - last_cycles;
last_cycles = cycles;
mii->speed_current = delta_cycles / (float)target_fps_us;
}
@ -129,13 +136,87 @@ mii_thread_func(
return NULL;
}
#if HAVE_JOYSTICK
#include <linux/joystick.h>
static void *
mii_thread_joystick(
void *arg)
{
int fd = open("/dev/input/js0", O_RDONLY);
if (fd < 0) {
printf("No joystick found\n");
return NULL;
}
uint8_t axes, buttons;
if (ioctl(fd, JSIOCGAXES, &axes) == -1 ||
ioctl(fd, JSIOCGBUTTONS, &buttons) == -1) {
perror(__func__);
return NULL;
}
struct js_event event;
mii_t *mii = (mii_t *)arg;
mii->analog.v[0].value = 127;
mii->analog.v[1].value = 127;
do {
ssize_t rd = read(fd, &event, sizeof(event));
if (rd != sizeof(event)) {
perror(__func__);
break;
}
switch (event.type) {
case JS_EVENT_BUTTON:
// printf("button %u %s\n", event.number, event.value ? "pressed" : "released");
switch (event.number) {
case 2 ... 3:
mii_bank_poke(&mii->bank[MII_BANK_MAIN],
0xc061 + (event.number - 2),
event.value ? 0x80 : 0);
break;
case 4 ... 5:
mii_bank_poke(&mii->bank[MII_BANK_MAIN],
0xc061 + (event.number - 4),
event.value ? 0x80 : 0);
break;
}
break;
case JS_EVENT_AXIS:
switch (event.number) {
case 0 ... 1: {// X
uint32_t v = (event.value + 0x8000) / 256;
if (v > 255)
v = 255;
mii->analog.v[event.number ? 1 : 0].value = v;
// printf("axis %u %6d %3dx%3d\n"
// event.number, event.value,
// mii->analog.v[0].value, mii->analog.v[1].value);
} break;
}
break;
default:
/* Ignore init events. */
break;
}
} while (1);
close(fd);
printf("Joystick thread terminated\n");
return NULL;
}
#endif
void
mii_thread_start(
mii_t *mii)
{
const mii_th_fifo_t zero = {};
signal_fifo = zero;
pthread_create(&mii_thread, NULL, mii_thread_func, mii);
pthread_t thread;
pthread_create(&thread, NULL, mii_thread_cpu_regulator, mii);
#if HAVE_JOYSTICK
pthread_create(&thread, NULL, mii_thread_joystick, mii);
#endif
}
struct mii_th_fifo_t*

View File

@ -313,6 +313,11 @@ mii_access_soft_switches(
res = true;
mii_speaker_click(&mii->speaker);
break;
case 0xc064 ... 0xc067: // Joystick, buttons
case 0xc070: // Analog reset
res = true;
mii_analog_access(mii, &mii->analog, addr, byte, write);
break;
case 0xc068:
res = true;
// IIgs register, read by prodos tho

59
src/mii_analog.c Normal file
View File

@ -0,0 +1,59 @@
/*
* mii_analog.c
*
* Copyright (C) 2023 Michel Pollet <buserror@gmail.com>
*
* SPDX-License-Identifier: MIT
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "mii.h"
#include "mii_analog.h"
void
mii_analog_init(
struct mii_t *mii,
mii_analog_t * a )
{
memset(a, 0, sizeof(*a));
}
/*
* https://retrocomputing.stackexchange.com/questions/15093/how-do-i-read-the-position-of-an-apple-ii-joystick
*/
void
mii_analog_access(
mii_t *mii,
mii_analog_t * a,
uint16_t addr,
uint8_t * byte,
bool write)
{
if (write)
return;
switch (addr) {
case 0xc070: {
// multiplying by mii->speed allows reading joystick in 'fast' mode,
// this basically simulate slowing down just for the joystick reading
/* TODO: According to various artivles, the multiplier ought
* to be 11, but we're not making the count here, which means it's
* likely the emulated core is missing a cycle for one instruction
* somewhere... */
for (int i = 0; i < 4; i++) {
a->v[i].decay = mii->cycles +
((a->v[i].value * 10.10) * mii->speed);
// printf("joystick %d: %d\n", i, a->v[i].value);
}
} break;
case 0xc064 ... 0xc067: {
addr -= 0xc064;
*byte = mii->cycles <= a->v[addr].decay ? 0x80 : 0x00;
} break;
}
}

33
src/mii_analog.h Normal file
View File

@ -0,0 +1,33 @@
/*
* mii_analog.h
*
* Copyright (C) 2023 Michel Pollet <buserror@gmail.com>
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "mii_types.h"
typedef struct mii_analog_t {
struct {
uint8_t value;
mii_cycles_t decay;
} v[4];
} mii_analog_t;
struct mii_t;
void
mii_analog_init(
struct mii_t *mii,
mii_analog_t * analog );
void
mii_analog_access(
mii_t *mii,
mii_analog_t * analog,
uint16_t addr,
uint8_t * byte,
bool write);