From 62aff1f2a1a6d4306116d47fd9c48aef34cc117f Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Sun, 24 Jul 2016 17:06:28 +0200 Subject: [PATCH 1/2] onepad 1.3: import lilypad state machine into onepad Not tested * rumble Save/load state will be implemented in the next commit v2: * Print current deteced pad mode * fix dpad button tranmission close #366 --- plugins/onepad/CMakeLists.txt | 16 +- plugins/onepad/Linux/linux.cpp | 3 + plugins/onepad/onepad.cpp | 378 ++-------------------- plugins/onepad/onepad.h | 18 +- plugins/onepad/state_management.cpp | 465 ++++++++++++++++++++++++++++ plugins/onepad/state_management.h | 115 +++++++ 6 files changed, 621 insertions(+), 374 deletions(-) create mode 100644 plugins/onepad/state_management.cpp create mode 100644 plugins/onepad/state_management.h diff --git a/plugins/onepad/CMakeLists.txt b/plugins/onepad/CMakeLists.txt index 2ac186408c..613270e239 100644 --- a/plugins/onepad/CMakeLists.txt +++ b/plugins/onepad/CMakeLists.txt @@ -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() diff --git a/plugins/onepad/Linux/linux.cpp b/plugins/onepad/Linux/linux.cpp index c0dc6d3336..fa30c2f1e1 100644 --- a/plugins/onepad/Linux/linux.cpp +++ b/plugins/onepad/Linux/linux.cpp @@ -22,6 +22,7 @@ #include "GamePad.h" #include "onepad.h" #include "keyboard.h" +#include "state_management.h" #include #include @@ -188,6 +189,8 @@ EXPORT_C_(void) PADupdate(int pad) key_status->commit_status(cpad); } + + Pad::rumble_all(); } EXPORT_C_(void) PADconfigure() diff --git a/plugins/onepad/onepad.cpp b/plugins/onepad/onepad.cpp index ebaed83eee..3b3d8db706 100644 --- a/plugins/onepad/onepad.cpp +++ b/plugins/onepad/onepad.cpp @@ -27,6 +27,7 @@ #include "onepad.h" #include "svnrev.h" +#include "state_management.h" #ifdef __linux__ #include @@ -47,79 +48,8 @@ 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 -// 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 +58,6 @@ KeyStatus* key_status = NULL; queue 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 +162,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 +229,27 @@ 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; - - case 1: // analog - padID[pad] = 0x73; - break; - } - break; - - case 1: // dualshock2 - switch (mode) - { - case 0: // digital - padID[pad] = 0x41; - break; - - case 1: // analog - padID[pad] = 0x79; - break; - } - 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; + + return 1; } 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) diff --git a/plugins/onepad/onepad.h b/plugins/onepad/onepad.h index 235d62eb13..d3ba8d93ea 100644 --- a/plugins/onepad/onepad.h +++ b/plugins/onepad/onepad.h @@ -84,17 +84,17 @@ extern bool toggleAutoRepeat; enum PadCommands { - CMD_SET_VREF_PARAM = 0x40, + CMD_SET_VREF_PARAM = 0x40, CMD_QUERY_DS2_ANALOG_MODE = 0x41, CMD_READ_DATA_AND_VIBRATE = 0x42, - CMD_CONFIG_MODE = 0x43, - CMD_SET_MODE_AND_LOCK = 0x44, - CMD_QUERY_MODEL_AND_MODE = 0x45, - CMD_QUERY_ACT = 0x46, // ?? - CMD_QUERY_COMB = 0x47, // ?? - CMD_QUERY_MODE = 0x4C, // QUERY_MODE ?? - CMD_VIBRATION_TOGGLE = 0x4D, - CMD_SET_DS2_NATIVE_MODE = 0x4F // SET_DS2_NATIVE_MODE + CMD_CONFIG_MODE = 0x43, + CMD_SET_MODE_AND_LOCK = 0x44, + CMD_QUERY_MODEL_AND_MODE = 0x45, + CMD_QUERY_ACT = 0x46, // ?? + CMD_QUERY_COMB = 0x47, // ?? + CMD_QUERY_MODE = 0x4C, // QUERY_MODE ?? + CMD_VIBRATION_TOGGLE = 0x4D, + CMD_SET_DS2_NATIVE_MODE = 0x4F // SET_DS2_NATIVE_MODE }; enum gamePadValues diff --git a/plugins/onepad/state_management.cpp b/plugins/onepad/state_management.cpp new file mode 100644 index 0000000000..e2eb19c638 --- /dev/null +++ b/plugins/onepad/state_management.cpp @@ -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]; + } +} diff --git a/plugins/onepad/state_management.h b/plugins/onepad/state_management.h new file mode 100644 index 0000000000..1fe117210b --- /dev/null +++ b/plugins/onepad/state_management.h @@ -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 + void set_result(const u8 (&rsp)[S]) + { + memcpy(response+2, rsp, S); + numBytes = 2 + S; + } + + template + 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); From 48c4d54a6cb569dc363796c441e0e00f16016491 Mon Sep 17 00:00:00 2001 From: Gregory Hainaut Date: Sun, 24 Jul 2016 18:21:19 +0200 Subject: [PATCH 2/2] onepad: support load/save state for the plugin close #205 close #1375 close #1465 v2: don't bump PCSX2 savestate version --- plugins/onepad/onepad.cpp | 68 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/plugins/onepad/onepad.cpp b/plugins/onepad/onepad.cpp index 3b3d8db706..14b1cf4184 100644 --- a/plugins/onepad/onepad.cpp +++ b/plugins/onepad/onepad.cpp @@ -49,6 +49,7 @@ bool toggleAutoRepeat = false; const u32 version = PS2E_PAD_VERSION; const u32 revision = 1; const u32 build = 3; // increase that with each version +#define PAD_SAVE_STATE_VERSION ((revision << 8) | (build << 0)) FILE *padLog = NULL; @@ -242,6 +243,73 @@ EXPORT_C_(s32) PADsetSlot(u8 port, u8 slot) 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; + } + + memcpy(&pads[port][slot], &pdata->padData[port][slot], sizeof(PadFreezeData)); + } + + if (pdata->slot[port] < 4) + slots[port] = pdata->slot[port]; + } + + } 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) { return pad_start_poll(pad);