This commit is contained in:
2025-05-13 02:03:18 +03:00
parent 72860c7968
commit 90ef6120fd
463 changed files with 380758 additions and 2 deletions
+32
View File
@@ -0,0 +1,32 @@
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
+16
View File
@@ -0,0 +1,16 @@
add_library(LibPad INTERFACE)
target_include_directories(LibPad
INTERFACE
Src
)
target_sources(LibPad
INTERFACE
Src/LibPad/PsIoPhy.h
Src/LibPad/PsIo.h
Src/LibPad/PsMemCard.h
Src/LibPad/PsPad.h
)
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Sergey Serb
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+8
View File
@@ -0,0 +1,8 @@
SOURCES += $$files($$PWD/src/*.cpp, true) \
$$PWD/src/LibPad/PsPad.c
SOURCES += $$files($$PWD/src/*.c, true)
HEADERS += $$files($$PWD/src/*.h, true) \
$$PWD/src/LibPad/PsIo.h \
$$PWD/src/LibPad/PsMemCard.h \
$$PWD/src/LibPad/PsPad.h
INCLUDEPATH += $$PWD/Src
+19
View File
@@ -0,0 +1,19 @@
# LibPad
Low-level PS1/PS2 gamepad communication library (mostly for embedded usage)
## Data interface
It is just SPI: LSB first, CPOL=1, CPHA=1
## Pad pinout
| Pin number | Pin name | Meaning |
| ------------- | ------------------ |------------------------------------------------|
| 1 | DATA [Open-drain!] | Data from joypad/memory card (SPI_MISO on MCU). Open drain (requires pull-up) |
| 2 | CMD | Data to joypad/memory card (SPI_MOSI on MCU) |
| 3 | +7.6V | Power supply for vibration motors |
| 4 | GND | Ground |
| 5 | VCC | 3.6V (should work fine with 3.3V) |
| 6 | ATT | Attention (SPI_CS on MCU) |
| 7 | CLK | Clock (SPI_CLK on MCU) PS1: 250KHz for controller and memory card, 500KHz or 1MHz for multitap. PS2: 250KHz for controller, 25MHz for memory card |
| 8 | N/C [IRQ10] | Joy only (Konami Justifier). Typically not connected |
| 9 | Ack [IRQ7] [Open-drain!]| Goes low for at least 1 clock after each 8 bits transmitted with 60us timeout . Open drain (requires pull-up)|
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#include <stdint.h>
#include "PsIoPhy.h"
struct PsIoBuffer {
uint8_t size;
uint8_t data[200] = {};
};
struct PsIoPort {
uint8_t id;
PsIoPhy* phy;
PsIoBuffer rxBuffer;
inline bool psIoPortExecuteCommand(uint8_t* cmd, uint8_t cmdSize) {
uint8_t i;
if(!phy->begin()){
return false;
}
rxBuffer.size = 0;
for(i = 0; i < cmdSize; ++i){
if(!phy->shift(cmd[i], &rxBuffer.data[i])){
break;
}
rxBuffer.size = i + 1;
}
phy->end();
return true;
}
};
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include <cstdint>
struct PsIoPhy {
virtual ~PsIoPhy() = default;
virtual bool begin() = 0;
virtual bool shift(uint8_t txData, uint8_t* rxData) = 0;
virtual void end() = 0;
};
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include "PsIo.h"
#include <string.h>
#define PS_MEM_CARD_BLOCK_STATE_BEGIN 0xA1
#define PS_MEM_CARD_BLOCK_STATE_MIDDLE 0xA2
#define PS_MEM_CARD_BLOCK_STATE_END 0xA2
#define PS_MEM_CARD_BLOCK_STATE_FORMATTED 0xA0
#define PS_MEM_CARD_BLOCK_STATE_BEGIN_DELETED 0xA1
#define PS_MEM_CARD_BLOCK_STATE_MIDDLE_DELETED 0xA2
#define PS_MEM_CARD_BLOCK_STATE_END_DELETED 0xA2
struct PsMemCard {
uint8_t slot;
struct PsIoPort* port;
};
int psMemCardReadId(struct PsMemCard* memcard){
uint8_t cmd[] = { memcard->slot, 0x53, 0, 0, 0, 0, 0, 0, 0, 0 };
return psIoPortExecuteCommand(memcard->port, cmd, sizeof(cmd));
}
int psMemCardRead(struct PsMemCard* memcard, uint16_t addr, uint8_t* rxBuffer128){ //Addr: 0..3FFh
int error;
uint8_t cmd[10 + 128 + 2];
memset(cmd, 0, sizeof(cmd));
cmd[0] = memcard->slot;
cmd[1] = 0x52;
cmd[4] = (uint8_t)((addr & 0xff00) >> 8);
cmd[5] = (uint8_t)(addr & 0xff);
error = psIoPortExecuteCommand(memcard->port, cmd, sizeof(cmd));
if(!error){
memcpy(rxBuffer128, &memcard->port->rxBuffer.data[10], 128);
}
return error;
}
+73
View File
@@ -0,0 +1,73 @@
#pragma once
#include "PsIo.h"
struct PsPad {
uint8_t slot = 0x01;
struct PsIoPort* port;
//(SCPH-1010)
inline bool psPadPollDigital(){
uint8_t cmd[5] = {slot, 0x42, 0x00, 0x00, 0x00};
return port->psIoPortExecuteCommand(cmd, sizeof(cmd));
}
// (SCPH-1110) or (SCPH-1180)
inline bool psPadPollAnalog(){
uint8_t cmd[9] = {slot, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
return port->psIoPortExecuteCommand(cmd, sizeof(cmd));
}
// DualShock 1,2 (SCPH-1180, SCPH-1200, SCPH-10010)
inline bool psPadPollAnalogRumble(std::uint8_t rightMotor, std::uint8_t leftMotor){
uint8_t cmd[9] = {slot, 0x42, 0x00, 0x00, 0x00, rightMotor, leftMotor, 0x00, 0x00};
return port->psIoPortExecuteCommand(cmd, sizeof(cmd));
}
// DualShock 2 SCPH-10010
inline bool psPadPollDualshock2(){
uint8_t cmd[21] = {slot, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
return port->psIoPortExecuteCommand(cmd, sizeof(cmd));
}
inline int psPadSetDataMask(uint8_t b0, uint8_t b1, uint8_t b2) {
uint8_t cmd[] = { slot, 0x4F, 0x00, b0, b1, b2, 0x00, 0x00, 0x00 };
return port->psIoPortExecuteCommand(cmd, sizeof(cmd));
}
inline int psPadConfigEnter() {
uint8_t cmd[] = { slot, 0x43, 0x00, 0x01, 0x00};
return port->psIoPortExecuteCommand(cmd, sizeof(cmd));
}
inline int psPadConfigExit() {
uint8_t cmd[] = { slot, 0x43, 0x00, 0x00, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A };
return port->psIoPortExecuteCommand(cmd, sizeof(cmd));
}
inline int psPadConfigQueryModel() { //no args 100%
uint8_t cmd[9] = { slot, 0x45, 0x00, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A };
return port->psIoPortExecuteCommand(cmd, sizeof(cmd));
}
inline int psPadConfigQueryAct(uint8_t b1) { //b1 = index
uint8_t cmd[9] = { slot, 0x46, 0x00, b1, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A };
return port->psIoPortExecuteCommand(cmd, sizeof(cmd));
}
inline int psPadConfigQueryComb(uint8_t b1) { //b1 - maybe index, not failed but single record
uint8_t cmd[9] = { slot, 0x47, 0x00, b1, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A };
return port->psIoPortExecuteCommand(cmd, sizeof(cmd));
}
inline int psPadConfigQueryMode(uint8_t b1) { //byte #6 - supported mode, b1 = index
uint8_t cmd[9] = { slot, 0x4c, 0x00, b1, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A };
return port->psIoPortExecuteCommand(cmd, sizeof(cmd));
}
inline int psPadSetControllerMode(uint8_t analog, uint8_t lockMode) {
uint8_t cmd[] = { slot, 0x44, 0x00, (uint8_t)(analog ? 0x01 : 0x00), (uint8_t)(lockMode ? 0x03 : 0x5A), 0x00, 0x00, 0x00, 0x00 };
return port->psIoPortExecuteCommand(cmd, sizeof(cmd));
}
};