Merge pull request #1476 from PCSX2/onepad-input-state

onepad 1.3: import lilypad state machine into onepad
This commit is contained in:
Gregory Hainaut 2016-08-02 15:01:42 +02:00 committed by GitHub
commit f19da94bfd
6 changed files with 689 additions and 374 deletions

View File

@ -38,7 +38,7 @@ set(onepadGuiResources
)
# plugin name
set(Output onepad-1.2.0)
set(Output onepad-1.3.0)
set(onepadFinalFlags "")
# onepad sources
@ -48,7 +48,8 @@ set(onepadSources
SDL/joystick.cpp
keyboard.cpp
KeyStatus.cpp
onepad.cpp)
onepad.cpp
state_management.cpp)
# onepad headers
set(onepadHeaders
@ -58,7 +59,8 @@ set(onepadHeaders
SDL/joystick.h
keyboard.h
KeyStatus.h
onepad.h)
onepad.h
state_management.h)
# onepad Linux sources
set(onepadLinuxSources
@ -85,14 +87,10 @@ set(onepadWindowsHeaders
)
if (SDL2_API)
set(onepadFinalLibs
${SDL2_LIBRARIES}
)
set(onepadFinalLibs ${SDL2_LIBRARIES})
add_definitions(-DSDL_BUILD)
else()
set(onepadFinalLibs
${SDL_LIBRARY}
)
set(onepadFinalLibs ${SDL_LIBRARY})
add_definitions(-DSDL_BUILD)
endif()

View File

@ -22,6 +22,7 @@
#include "GamePad.h"
#include "onepad.h"
#include "keyboard.h"
#include "state_management.h"
#include <string.h>
#include <gtk/gtk.h>
@ -188,6 +189,8 @@ EXPORT_C_(void) PADupdate(int pad)
key_status->commit_status(cpad);
}
Pad::rumble_all();
}
EXPORT_C_(void) PADconfigure()

View File

@ -27,6 +27,7 @@
#include "onepad.h"
#include "svnrev.h"
#include "state_management.h"
#ifdef __linux__
#include <unistd.h>
@ -47,79 +48,9 @@ bool toggleAutoRepeat = false;
const u32 version = PS2E_PAD_VERSION;
const u32 revision = 1;
const u32 build = 2; // increase that with each version
const u32 build = 3; // increase that with each version
#define PAD_SAVE_STATE_VERSION ((revision << 8) | (build << 0))
// Useless variable ...
//int PadEnum[2][2] = {{0, 2}, {1, 3}};
u8 stdpar[2][20] = {
{0xff, 0x5a, 0xff, 0xff, 0x80, 0x80, 0x80, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00},
{0xff, 0x5a, 0xff, 0xff, 0x80, 0x80, 0x80, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00}
};
u8 cmd40[2][8] = {
{0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5a},
{0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5a}
};
u8 cmd41[2][8] = {
{0xff, 0x5a, 0xff, 0xff, 0x03, 0x00, 0x00, 0x5a},
{0xff, 0x5a, 0xff, 0xff, 0x03, 0x00, 0x00, 0x5a}
};
u8 unk46[2][8] = {
{0xFF, 0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A},
{0xFF, 0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A}
};
u8 unk47[2][8] = {
{0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00},
{0xff, 0x5a, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00}
};
u8 unk4c[2][8] = {
{0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};
u8 unk4d[2][8] = {
{0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
{0xff, 0x5a, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
};
u8 cmd4f[2][8] = {
{0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a},
{0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5a}
};
u8 stdcfg[2][8] = {
{0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
}; // 2 & 3 = 0
u8 stdmode[2][8] = {
{0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xff, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
};
u8 stdmodel[2][8] = {
{0xff,
0x5a,
0x03, // 03 - dualshock2, 01 - dualshock
0x02, // number of modes
0x01, // current mode: 01 - analog, 00 - digital
0x02,
0x01,
0x00},
{0xff,
0x5a,
0x03, // 03 - dualshock2, 01 - dualshock
0x02, // number of modes
0x01, // current mode: 01 - analog, 00 - digital
0x02,
0x01,
0x00}
};
u8 *buf;
int padID[2];
int padMode[2];
int curPad, curByte, curCmd, cmdLen;
int ds2mode = 0; // DS Mode at start
FILE *padLog = NULL;
pthread_spinlock_t mutex_KeyEvent;
@ -128,11 +59,6 @@ KeyStatus* key_status = NULL;
queue<keyEvent> ev_fifo;
static int padVib0[2];
static int padVib1[2];
//static int padVibC[2];
static int padVibF[2][4];
static void InitLibraryName()
{
#ifdef PUBLIC
@ -237,19 +163,25 @@ EXPORT_C_(s32) PADinit(u32 flags)
LoadConfig();
PADsetMode(0, 0);
PADsetMode(1, 0);
key_status = new KeyStatus();
Pad::reset_all();
query.reset();
for (int port = 0; port < 2; port++)
slots[port] = 0;
return 0;
}
EXPORT_C_(void) PADshutdown()
{
CloseLogging();
delete conf;
conf = nullptr;
delete key_status;
key_status = nullptr;
}
@ -298,292 +230,94 @@ EXPORT_C_(u32) PADquery()
return 3; // both
}
void PADsetMode(int pad, int mode)
EXPORT_C_(s32) PADsetSlot(u8 port, u8 slot)
{
padMode[pad] = mode;
padVib0[pad] = 0;
padVib1[pad] = 0;
padVibF[pad][0] = 0;
padVibF[pad][1] = 0;
switch (ds2mode)
{
case 0: // dualshock
switch (mode)
{
case 0: // digital
padID[pad] = 0x41;
break;
port--;
slot--;
if (port > 1 || slot > 3) {
return 0;
}
// Even if no pad there, record the slot, as it is the active slot regardless.
slots[port] = slot;
case 1: // analog
padID[pad] = 0x73;
return 1;
}
EXPORT_C_(s32) PADfreeze(int mode, freezeData *data)
{
if (!data)
return -1;
if (mode == FREEZE_SIZE) {
data->size = sizeof(PadPluginFreezeData);
} else if (mode == FREEZE_LOAD) {
PadPluginFreezeData* pdata = (PadPluginFreezeData*)(data->data);
Pad::stop_vibrate_all();
if (data->size != sizeof(PadPluginFreezeData) || pdata->version != PAD_SAVE_STATE_VERSION ||
strncmp(pdata->format, "OnePad", sizeof(pdata->format)))
return 0;
query = pdata->query;
if (pdata->query.slot < 4) {
query = pdata->query;
}
// Tales of the Abyss - pad fix
// - restore data for both ports
for (int port=0; port<2; port++) {
for (int slot=0; slot<4; slot++) {
u8 mode = pdata->padData[port][slot].mode;
if (mode != MODE_DIGITAL && mode != MODE_ANALOG && mode != MODE_DS2_NATIVE) {
break;
}
break;
case 1: // dualshock2
switch (mode)
{
case 0: // digital
padID[pad] = 0x41;
break;
memcpy(&pads[port][slot], &pdata->padData[port][slot], sizeof(PadFreezeData));
}
case 1: // analog
padID[pad] = 0x79;
break;
if (pdata->slot[port] < 4)
slots[port] = pdata->slot[port];
}
break;
} else if (mode == FREEZE_SAVE) {
if (data->size != sizeof(PadPluginFreezeData)) return 0;
PadPluginFreezeData* pdata = (PadPluginFreezeData*)(data->data);
// Tales of the Abyss - pad fix
// - PCSX2 only saves port0 (save #1), then port1 (save #2)
memset(pdata, 0, data->size);
strncpy(pdata->format, "OnePad", sizeof(pdata->format));
pdata->version = PAD_SAVE_STATE_VERSION;
pdata->query = query;
for (int port=0; port<2; port++) {
for (int slot=0; slot<4; slot++) {
pdata->padData[port][slot] = pads[port][slot];
}
pdata->slot[port] = slots[port];
}
} else {
return -1;
}
return 0;
}
EXPORT_C_(u8) PADstartPoll(int pad)
{
//PAD_LOG("PADstartPoll: %d\n", pad);
curPad = pad - 1;
curByte = 0;
return 0xff;
}
u8 _PADpoll(u8 value)
{
u8 button_check = 0;
int vib_small;
int vib_big;
if (curByte == 0)
{
curByte++;
//PAD_LOG("PADpoll: cmd: %x\n", value);
curCmd = value;
switch (value)
{
case CMD_SET_VREF_PARAM: // DUALSHOCK2 ENABLER
cmdLen = 8;
buf = cmd40[curPad];
return 0xf3;
case CMD_QUERY_DS2_ANALOG_MODE: // QUERY_DS2_ANALOG_MODE
cmdLen = 8;
buf = cmd41[curPad];
return 0xf3;
case CMD_READ_DATA_AND_VIBRATE: // READ_DATA
stdpar[curPad][2] = key_status->get(curPad) >> 8;
stdpar[curPad][3] = key_status->get(curPad) & 0xff;
stdpar[curPad][4] = key_status->get(curPad, PAD_R_RIGHT);
stdpar[curPad][5] = key_status->get(curPad, PAD_R_UP);
stdpar[curPad][6] = key_status->get(curPad, PAD_L_RIGHT);
stdpar[curPad][7] = key_status->get(curPad, PAD_L_UP);
if (padMode[curPad] == 1)
cmdLen = 20;
else
cmdLen = 4;
// Square
stdpar[curPad][15] = !test_bit(stdpar[curPad][3], 7) ? key_status->get(curPad, PAD_SQUARE) : 0;
// X
stdpar[curPad][14] = !test_bit(stdpar[curPad][3], 6) ? key_status->get(curPad, PAD_CROSS) : 0;
// Circle
stdpar[curPad][13] = !test_bit(stdpar[curPad][3], 5) ? key_status->get(curPad, PAD_CIRCLE) : 0;
// Triangle
stdpar[curPad][12] = !test_bit(stdpar[curPad][3], 4) ? key_status->get(curPad, PAD_TRIANGLE) : 0;
// R1
stdpar[curPad][17] = !test_bit(stdpar[curPad][3], 3) ? key_status->get(curPad, PAD_R1) : 0;
// L1
stdpar[curPad][16] = !test_bit(stdpar[curPad][3], 2) ? key_status->get(curPad, PAD_L1) : 0;
// R2
stdpar[curPad][19] = !test_bit(stdpar[curPad][3], 1) ? key_status->get(curPad, PAD_R2) : 0;
// L2
stdpar[curPad][18] = !test_bit(stdpar[curPad][3], 0) ? key_status->get(curPad, PAD_L2) : 0;
button_check = stdpar[curPad][2] >> 4;
// LEFT
stdpar[curPad][9] = !test_bit(button_check, 3) ? key_status->get(curPad, PAD_LEFT) : 0;
// DOWN
stdpar[curPad][11] = !test_bit(button_check, 2) ? key_status->get(curPad, PAD_DOWN) : 0;
// RIGHT
stdpar[curPad][8] = !test_bit(button_check, 1) ? key_status->get(curPad, PAD_RIGHT) : 0;
// UP
stdpar[curPad][10] = !test_bit(button_check, 0) ? key_status->get(curPad, PAD_UP) : 0;
buf = stdpar[curPad];
/* Small Motor */
vib_small = padVibF[curPad][0] ? 2000 : 0;
// if ((padVibF[curPad][2] != vib_small) && (padVibC[curPad] >= 0))
if (padVibF[curPad][2] != vib_small)
{
padVibF[curPad][2] = vib_small;
GamePad::DoRumble(0, curPad);
}
/* Big Motor */
vib_big = padVibF[curPad][1] ? 500 + 37*padVibF[curPad][1] : 0;
// if ((padVibF[curPad][3] != vib_big) && (padVibC[curPad] >= 0))
if (padVibF[curPad][3] != vib_big)
{
padVibF[curPad][3] = vib_big;
GamePad::DoRumble(1, curPad);
}
return padID[curPad];
case CMD_CONFIG_MODE: // CONFIG_MODE
cmdLen = 8;
buf = stdcfg[curPad];
if (stdcfg[curPad][3] == 0xff)
return 0xf3;
else
return padID[curPad];
case CMD_SET_MODE_AND_LOCK: // SET_MODE_AND_LOCK
cmdLen = 8;
buf = stdmode[curPad];
return 0xf3;
case CMD_QUERY_MODEL_AND_MODE: // QUERY_MODEL_AND_MODE
cmdLen = 8;
buf = stdmodel[curPad];
buf[4] = padMode[curPad];
return 0xf3;
case CMD_QUERY_ACT: // ??
cmdLen = 8;
buf = unk46[curPad];
return 0xf3;
case CMD_QUERY_COMB: // ??
cmdLen = 8;
buf = unk47[curPad];
return 0xf3;
case CMD_QUERY_MODE: // QUERY_MODE ??
cmdLen = 8;
buf = unk4c[curPad];
return 0xf3;
case CMD_VIBRATION_TOGGLE:
cmdLen = 8;
buf = unk4d[curPad];
return 0xf3;
case CMD_SET_DS2_NATIVE_MODE: // SET_DS2_NATIVE_MODE
cmdLen = 8;
padID[curPad] = 0x79; // setting ds2 mode
ds2mode = 1; // Set DS2 Mode
buf = cmd4f[curPad];
return 0xf3;
default:
PAD_LOG("*PADpoll*: unknown cmd %x\n", value);
break;
}
}
switch (curCmd)
{
case CMD_READ_DATA_AND_VIBRATE:
if (curByte == padVib0[curPad])
padVibF[curPad][0] = value&1;
if (curByte == padVib1[curPad])
padVibF[curPad][1] = value;
break;
case CMD_CONFIG_MODE:
if (curByte == 2)
{
switch (value)
{
case 0:
buf[2] = 0;
buf[3] = 0;
break;
case 1:
buf[2] = 0xff;
buf[3] = 0xff;
break;
}
}
break;
case CMD_SET_MODE_AND_LOCK:
if (curByte == 2)
{
PADsetMode(curPad, value);
}
break;
case CMD_QUERY_ACT:
if (curByte == 2)
{
switch (value)
{
case 0: // default
buf[5] = 0x2;
buf[6] = 0x0;
buf[7] = 0xA;
break;
case 1: // Param std conf change
buf[5] = 0x1;
buf[6] = 0x1;
buf[7] = 0x14;
break;
}
}
break;
case CMD_QUERY_MODE:
if (curByte == 2)
{
switch (value)
{
case 0: // mode 0 - digital mode
buf[5] = 0x4;
break;
case 1: // mode 1 - analog mode
buf[5] = 0x7;
break;
}
}
break;
case CMD_VIBRATION_TOGGLE:
if (curByte >= 2)
{
if (curByte == padVib0[curPad])
buf[curByte] = 0x00;
if (curByte == padVib1[curPad])
buf[curByte] = 0x01;
if (value == 0x00)
{
padVib0[curPad] = curByte;
}
else if (value == 0x01)
{
padVib1[curPad] = curByte;
}
}
break;
}
if (curByte >= cmdLen) return 0;
return buf[curByte++];
return pad_start_poll(pad);
}
EXPORT_C_(u8) PADpoll(u8 value)
{
u8 ret;
ret = _PADpoll(value);
//PAD_LOG("PADpoll: %x (%d: %x)\n", value, curByte, ret);
return ret;
return pad_poll(value);
}
// PADkeyEvent is called every vsync (return NULL if no event)

View File

@ -0,0 +1,465 @@
/* OnePAD
* Copyright (C) 2016
*
* Based on LilyPad
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "state_management.h"
// Typical packet response on the bus
static const u8 ConfigExit[7] = {0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const u8 noclue[7] = {0x5A, 0x00, 0x00, 0x02, 0x00, 0x00, 0x5A};
static const u8 setMode[7] = {0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const u8 queryModelDS2[7] = {0x5A, 0x03, 0x02, 0x00, 0x02, 0x01, 0x00};
static const u8 queryModelDS1[7] = {0x5A, 0x01, 0x02, 0x00, 0x02, 0x01, 0x00};
static const u8 queryComb[7] = {0x5A, 0x00, 0x00, 0x02, 0x00, 0x01, 0x00};
static const u8 queryMode[7] = {0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const u8 setNativeMode[7] = {0x5A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5A};
static u8 queryMaskMode[7] = {0x5A, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x5A};
static const u8 queryAct[2][7] = {
{0x5A, 0x00, 0x00, 0x01, 0x02, 0x00, 0x0A},
{0x5A, 0x00, 0x00, 0x01, 0x01, 0x01, 0x14}};
QueryInfo query;
Pad pads[2][4];
int slots[2] = {0, 0};
//////////////////////////////////////////////////////////////////////
// QueryInfo implementation
//////////////////////////////////////////////////////////////////////
void QueryInfo::reset()
{
port = 0;
slot = 0;
lastByte = 1;
currentCommand = 0;
numBytes = 0;
queryDone = 1;
memset(response, 0xF3, sizeof(response));
}
u8 QueryInfo::start_poll(int _port)
{
if (port > 1) {
reset();
return 0;
}
queryDone = 0;
port = _port;
slot = slots[port];
numBytes = 2;
lastByte = 0;
return 0xFF;
}
//////////////////////////////////////////////////////////////////////
// Pad implementation
//////////////////////////////////////////////////////////////////////
void Pad::set_mode(int _mode)
{
mode = _mode;
fprintf(stdout, "OnePad: set new pad mode=");
if (mode == MODE_DIGITAL)
fprintf(stdout, "DIGITAL\n");
else if (mode == MODE_ANALOG)
fprintf(stdout, "ANALOG\n");
else if (mode == MODE_DS2_NATIVE)
fprintf(stdout, "DS2 NATIVE\n");
else
fprintf(stdout, "??? 0x%x\n", mode);
}
void Pad::set_vibrate(int motor, u8 val)
{
nextVibrate[motor] = val;
}
void Pad::reset_vibrate()
{
set_vibrate(0, 0);
set_vibrate(1, 0);
memset(vibrate, 0xFF, sizeof(vibrate));
vibrate[0] = 0x5A;
}
void Pad::reset()
{
memset(this, 0, sizeof(PadFreezeData));
set_mode(MODE_DIGITAL);
umask[0] = umask[1] = 0xFF;
// Sets up vibrate variable.
reset_vibrate();
}
void Pad::rumble(int port)
{
for (int motor=0; motor<2; motor++) {
// TODO: Probably be better to send all of these at once.
if (nextVibrate[motor] | currentVibrate[motor]) {
currentVibrate[motor] = nextVibrate[motor];
GamePad::DoRumble(motor, port);
}
}
}
void Pad::stop_vibrate_all()
{
#if 0
for (int i=0; i<8; i++) {
SetVibrate(i&1, i>>1, 0, 0);
SetVibrate(i&1, i>>1, 1, 0);
}
#endif
// FIXME equivalent ?
for (int port = 0; port < 2; port++)
for (int slot = 0; slot < 4; slot++)
pads[port][slot].reset_vibrate();
}
void Pad::reset_all()
{
for (int port = 0; port < 2; port++)
for (int slot = 0; slot < 4; slot++)
pads[port][slot].reset();
}
void Pad::rumble_all()
{
for (int port=0; port<2; port++)
for (int slot=0; slot<4; slot++)
pads[port][slot].rumble(port);
}
//////////////////////////////////////////////////////////////////////
// Pad implementation
//////////////////////////////////////////////////////////////////////
inline bool IsDualshock2() {
// FIXME
#if 0
return config.padConfigs[query.port][query.slot].type == Dualshock2Pad ||
(config.padConfigs[query.port][query.slot].type == GuitarPad && config.GH2);
#else
return true;
#endif
}
u8 pad_start_poll(u8 pad)
{
return query.start_poll(pad - 1);
}
u8 pad_poll(u8 value)
{
if (query.lastByte+1 >= query.numBytes) {
return 0;
}
if (query.lastByte && query.queryDone) {
return query.response[++query.lastByte];
}
int i;
Pad *pad = &pads[query.port][query.slot];
if (query.lastByte == 0) {
query.lastByte++;
query.currentCommand = value;
switch(value) {
case CMD_CONFIG_MODE:
if (pad->config) {
// In config mode. Might not actually be leaving it.
query.set_result(ConfigExit);
return 0xF3;
}
case CMD_READ_DATA_AND_VIBRATE:
{
query.response[2] = 0x5A;
#if 0
Update(query.port, query.slot);
ButtonSum *sum = &pad->sum;
u8 b1 = 0xFF, b2 = 0xFF;
for (i = 0; i<4; i++) {
b1 -= (sum->buttons[i] > 0) << i;
}
for (i = 0; i<8; i++) {
b2 -= (sum->buttons[i+4] > 0) << i;
}
#endif
// FIXME
#if 0
if (config.padConfigs[query.port][query.slot].type == GuitarPad && !config.GH2) {
sum->buttons[15] = 255;
// Not sure about this. Forces wammy to be from 0 to 0x7F.
// if (sum->sticks[2].vert > 0) sum->sticks[2].vert = 0;
}
#endif
#if 0
for (i = 4; i<8; i++) {
b1 -= (sum->buttons[i+8] > 0) << i;
}
#endif
// FIXME
#if 0
//Left, Right and Down are always pressed on Pop'n Music controller.
if (config.padConfigs[query.port][query.slot].type == PopnPad)
b1=b1 & 0x1f;
#endif
uint16_t buttons = key_status->get(query.port);
query.numBytes = 5;
query.response[3] = (buttons >> 8) & 0xFF;
query.response[4] = (buttons >> 0) & 0xFF;
if (pad->mode != MODE_DIGITAL) { // ANALOG || DS2 native
query.numBytes = 9;
query.response[5] = key_status->get(query.port, PAD_R_RIGHT);
query.response[6] = key_status->get(query.port, PAD_R_UP);
query.response[7] = key_status->get(query.port, PAD_L_RIGHT);
query.response[8] = key_status->get(query.port, PAD_L_UP);
if (pad->mode != MODE_ANALOG) { // DS2 native
query.numBytes = 21;
query.response[9] = !test_bit(buttons, 13) ? key_status->get(query.port, PAD_RIGHT) : 0;
query.response[10] = !test_bit(buttons, 15) ? key_status->get(query.port, PAD_LEFT) : 0;
query.response[11] = !test_bit(buttons, 12) ? key_status->get(query.port, PAD_UP) : 0;
query.response[12] = !test_bit(buttons, 14) ? key_status->get(query.port, PAD_DOWN) : 0;
query.response[13] = !test_bit(buttons, 4) ? key_status->get(query.port, PAD_TRIANGLE) : 0;
query.response[14] = !test_bit(buttons, 5) ? key_status->get(query.port, PAD_CIRCLE) : 0;
query.response[15] = !test_bit(buttons, 6) ? key_status->get(query.port, PAD_CROSS) : 0;
query.response[16] = !test_bit(buttons, 7) ? key_status->get(query.port, PAD_SQUARE) : 0;
query.response[17] = !test_bit(buttons, 2) ? key_status->get(query.port, PAD_L1) : 0;
query.response[18] = !test_bit(buttons, 3) ? key_status->get(query.port, PAD_R1) : 0;
query.response[19] = !test_bit(buttons, 0) ? key_status->get(query.port, PAD_L2) : 0;
query.response[20] = !test_bit(buttons, 1) ? key_status->get(query.port, PAD_R2) : 0;
}
}
#if 0
query.response[3] = b1;
query.response[4] = b2;
query.numBytes = 5;
if (pad->mode != MODE_DIGITAL) {
query.response[5] = Cap((sum->sticks[0].horiz+255)/2);
query.response[6] = Cap((sum->sticks[0].vert+255)/2);
query.response[7] = Cap((sum->sticks[1].horiz+255)/2);
query.response[8] = Cap((sum->sticks[1].vert+255)/2);
query.numBytes = 9;
if (pad->mode != MODE_ANALOG) {
// Good idea? No clue.
//query.response[3] &= pad->mask[0];
//query.response[4] &= pad->mask[1];
// No need to cap these, already done int CapSum().
query.response[9] = (unsigned char)sum->buttons[13]; //D-pad right
query.response[10] = (unsigned char)sum->buttons[15]; //D-pad left
query.response[11] = (unsigned char)sum->buttons[12]; //D-pad up
query.response[12] = (unsigned char)sum->buttons[14]; //D-pad down
query.response[13] = (unsigned char) sum->buttons[8];
query.response[14] = (unsigned char) sum->buttons[9];
query.response[15] = (unsigned char) sum->buttons[10];
query.response[16] = (unsigned char) sum->buttons[11];
query.response[17] = (unsigned char) sum->buttons[6];
query.response[18] = (unsigned char) sum->buttons[7];
query.response[19] = (unsigned char) sum->buttons[4];
query.response[20] = (unsigned char) sum->buttons[5];
query.numBytes = 21;
}
}
#endif
}
query.lastByte=1;
return pad->mode;
case CMD_SET_VREF_PARAM:
query.set_final_result(noclue);
break;
case CMD_QUERY_DS2_ANALOG_MODE:
// Right? Wrong? No clue.
if (pad->mode == MODE_DIGITAL) {
queryMaskMode[1] = queryMaskMode[2] = queryMaskMode[3] = 0;
queryMaskMode[6] = 0x00;
}
else {
queryMaskMode[1] = pad->umask[0];
queryMaskMode[2] = pad->umask[1];
queryMaskMode[3] = 0x03;
// Not entirely sure about this.
//queryMaskMode[3] = 0x01 | (pad->mode == MODE_DS2_NATIVE)*2;
queryMaskMode[6] = 0x5A;
}
query.set_final_result(queryMaskMode);
break;
case CMD_SET_MODE_AND_LOCK:
query.set_result(setMode);
pad->reset_vibrate();
break;
case CMD_QUERY_MODEL_AND_MODE:
if (IsDualshock2()) {
query.set_final_result(queryModelDS2);
} else {
query.set_final_result(queryModelDS1);
}
// Not digital mode.
query.response[5] = (pad->mode & 0xF) != 1;
break;
case CMD_QUERY_ACT:
query.set_result(queryAct[0]);
break;
case CMD_QUERY_COMB:
query.set_final_result(queryComb);
break;
case CMD_QUERY_MODE:
query.set_result(queryMode);
break;
case CMD_VIBRATION_TOGGLE:
memcpy(query.response+2, pad->vibrate, 7);
query.numBytes = 9;
//query.set_result(pad->vibrate); // warning copy 7b not 8 (but it is really important?)
pad->reset_vibrate();
break;
case CMD_SET_DS2_NATIVE_MODE:
if (IsDualshock2()) {
query.set_result(setNativeMode);
} else {
query.set_final_result(setNativeMode);
}
break;
default:
query.numBytes = 0;
query.queryDone = 1;
break;
}
return 0xF3;
} else {
query.lastByte++;
switch (query.currentCommand) {
case CMD_READ_DATA_AND_VIBRATE:
if (query.lastByte == pad->vibrateI[0])
pad->set_vibrate(1, 255*(value&1));
else if (query.lastByte == pad->vibrateI[1])
pad->set_vibrate(0, value);
break;
case CMD_CONFIG_MODE:
if (query.lastByte == 3) {
query.queryDone = 1;
pad->config = value;
}
break;
case CMD_SET_MODE_AND_LOCK:
if (query.lastByte == 3 && value < 2) {
pad->set_mode(value ? MODE_ANALOG : MODE_DIGITAL);
} else if (query.lastByte == 4) {
if (value == 3)
pad->modeLock = 3;
else
pad->modeLock = 0;
query.queryDone = 1;
}
break;
case CMD_QUERY_ACT:
if (query.lastByte == 3) {
if (value<2) query.set_result(queryAct[value]);
// bunch of 0's
// else query.set_result(setMode);
query.queryDone = 1;
}
break;
case CMD_QUERY_MODE:
if (query.lastByte == 3 && value<2) {
query.response[6] = 4+value*3;
query.queryDone = 1;
}
// bunch of 0's
//else data = setMode;
break;
case CMD_VIBRATION_TOGGLE:
if (query.lastByte>=3) {
if (value == 0) {
pad->vibrateI[0] = (u8)query.lastByte;
}
else if (value == 1) {
pad->vibrateI[1] = (u8)query.lastByte;
}
pad->vibrate[query.lastByte-2] = value;
}
break;
case CMD_SET_DS2_NATIVE_MODE:
if (query.lastByte == 3 || query.lastByte == 4) {
pad->umask[query.lastByte-3] = value;
} else if (query.lastByte == 5) {
if (!(value & 1))
pad->set_mode(MODE_DIGITAL);
else if (!(value & 2))
pad->set_mode(MODE_ANALOG);
else
pad->set_mode(MODE_DS2_NATIVE);
}
break;
default:
return 0;
}
return query.response[query.lastByte];
}
}

View File

@ -0,0 +1,115 @@
/* OnePAD
* Copyright (C) 2016
*
* Based on LilyPad
* Copyright (C) 2002-2014 PCSX2 Dev Team/ChickenLiver
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "onepad.h"
#define MODE_DIGITAL 0x41
#define MODE_ANALOG 0x73
#define MODE_DS2_NATIVE 0x79
// The state of the PS2 bus
struct QueryInfo {
u8 port;
u8 slot;
u8 lastByte;
u8 currentCommand;
u8 numBytes;
u8 queryDone;
u8 response[42];
void reset();
u8 start_poll(int port);
template<size_t S>
void set_result(const u8 (&rsp)[S])
{
memcpy(response+2, rsp, S);
numBytes = 2 + S;
}
template<size_t S>
void set_final_result(const u8 (&rsp)[S])
{
set_result(rsp);
queryDone = 1;
}
};
// Freeze data, for a single pad. Basically has all pad state that
// a PS2 can set.
struct PadFreezeData {
// Digital / Analog / DS2 Native
u8 mode;
u8 modeLock;
// In config mode
u8 config;
u8 vibrate[8];
u8 umask[2];
// Vibration indices.
u8 vibrateI[2];
// Last vibration value sent to controller.
// Only used so as not to call vibration
// functions when old and new values are both 0.
u8 currentVibrate[2];
// Next vibrate val to send to controller. If next and current are
// both 0, nothing is sent to the controller. Otherwise, it's sent
// on every update.
u8 nextVibrate[2];
};
class Pad : public PadFreezeData {
public:
// Lilypad store here the state of PC pad
void rumble(int port);
void set_vibrate(int motor, u8 val);
void reset_vibrate();
void reset();
void set_mode(int mode);
static void reset_all();
static void stop_vibrate_all();
static void rumble_all();
};
// Full state to manage save state
struct PadPluginFreezeData {
char format[8];
u32 version;
// active slot for port
u8 slot[2];
PadFreezeData padData[2][4];
QueryInfo query;
};
extern QueryInfo query;
extern Pad pads[2][4];
extern int slots[2];
extern u8 pad_start_poll(u8 pad);
extern u8 pad_poll(u8 value);