ref: 2b36a055e337aace2c8b31a27d2a4bc2e77d7b49
dir: /psx/input/guncon.c/
/*
This file is part of the PSXE Emulator Project
Sony PlayStation Standard Digital/Analog Controller Emulator
*/
#include "guncon.h"
#include "../log.h"
#include <stdlib.h>
#include <string.h>
const char* states[] = {
"HIZ",
"IDL",
"IDH",
"SWL",
"SWH",
"XPL",
"XPH",
"YPL",
"YPH"
};
psxi_guncon_t* psxi_guncon_create(void) {
return (psxi_guncon_t*)malloc(sizeof(psxi_guncon_t));
}
void psxi_guncon_init(psxi_guncon_t* guncon) {
memset(guncon, 0, sizeof(psxi_guncon_t));
guncon->tx_data = 0xff;
guncon->tx_data_ready = 1;
guncon->state = GUNCON_STATE_TX_HIZ;
guncon->sw = 0xffff;
guncon->x = 0x4d;
guncon->y = 0x19;
guncon->sx = 384;
guncon->sy = 240;
}
uint32_t psxi_guncon_read(void* udata) {
psxi_guncon_t* guncon = (psxi_guncon_t*)udata;
switch (guncon->state) {
case GUNCON_STATE_TX_HIZ: guncon->tx_data = 0xff; break;
case GUNCON_STATE_TX_IDL: guncon->tx_data = GUNCON_IDL; break;
case GUNCON_STATE_TX_IDH: guncon->tx_data = GUNCON_IDH; break;
case GUNCON_STATE_TX_SWL: guncon->tx_data = guncon->sw & 0xff; break;
case GUNCON_STATE_TX_SWH: guncon->tx_data = guncon->sw >> 8; break;
case GUNCON_STATE_TX_XPL: guncon->tx_data = guncon->x & 0xff; break;
case GUNCON_STATE_TX_XPH: guncon->tx_data = guncon->x >> 8; break;
case GUNCON_STATE_TX_YPL: guncon->tx_data = guncon->y & 0xff; break;
case GUNCON_STATE_TX_YPH: {
// printf("guncon: read state %u (%s) -> %02x\n", guncon->state, states[guncon->state], guncon->y >> 8);
guncon->tx_data_ready = 0;
guncon->state = GUNCON_STATE_TX_HIZ;
return guncon->y >> 8;
} break;
}
// printf("guncon: read state %u (%s) -> %02x\n", guncon->state, states[guncon->state], guncon->tx_data);
guncon->tx_data_ready = 1;
guncon->state++;
return guncon->tx_data;
}
void psxi_guncon_write(void* udata, uint16_t data) {
psxi_guncon_t* guncon = (psxi_guncon_t*)udata;
// printf("guncon: write %02x\n", data);
(void)guncon;
}
void psxi_guncon_on_button_press(void* udata, uint32_t data) {
psxi_guncon_t* guncon = (psxi_guncon_t*)udata;
guncon->sw &= ~data;
}
void psxi_guncon_on_button_release(void* udata, uint32_t data) {
psxi_guncon_t* guncon = (psxi_guncon_t*)udata;
guncon->sw |= data;
}
void psxi_guncon_on_analog_change(void* udata, uint32_t axis, uint16_t data) {
psxi_guncon_t* guncon = (psxi_guncon_t*)udata;
switch (axis) {
case PSXI_AX_GUNCON_X: {
data *= (461.0f - 77.0f) / (float)guncon->sx;
data += 77;
guncon->x = data;
} break;
case PSXI_AX_GUNCON_Y: {
data *= (248.0f - 25.0f) / (float)guncon->sy;
data += 25;
guncon->y = data;
} break;
case PSXI_AX_GUNCON_SX: {
guncon->sx = data;
} break;
case PSXI_AX_GUNCON_SY: {
guncon->sy = data;
} break;
}
}
int psxi_guncon_query_fifo(void* udata) {
psxi_guncon_t* guncon = (psxi_guncon_t*)udata;
return guncon->tx_data_ready;
}
void psxi_guncon_init_input(psxi_guncon_t* guncon, psx_input_t* input) {
input->udata = guncon;
input->write_func = psxi_guncon_write;
input->read_func = psxi_guncon_read;
input->on_button_press_func = psxi_guncon_on_button_press;
input->on_button_release_func = psxi_guncon_on_button_release;
input->on_analog_change_func = psxi_guncon_on_analog_change;
input->query_fifo_func = psxi_guncon_query_fifo;
}
void psxi_guncon_destroy(psxi_guncon_t* guncon) {
free(guncon);
}