Files

512 lines
12 KiB
C++
Raw Permalink Normal View History

2025-05-13 00:37:35 +03:00
#include <Device/UsbDBulkInterface.h>
#include <FreeRTOS.h>
#include <task.h>
#include <stm32f7xx_hal.h>
#include <main.h>
#include <LFramework/USB/Device/USBDevice.h>
#include <LFramework/Debug.h>
#include <LFramework/IO/Terminal/TerminalAnsi.h>
#include <LFramework/Thread/Thread.h>
#include <cstring>
#include <usart.h>
using namespace LFramework;
using namespace LFramework::USB;
__attribute__((used)) UsbDBulkInterface usbInterface;
__attribute__((used)) UsbDDeviceContext usbContext(&usbInterface);
class PollingTransfer : public LFramework::USB::UsbDTransfer {
public:
enum class State {
Pending,
Success,
Fail
};
PollingTransfer(){
callbackIsr = &PollingTransfer::transferComleteCallbackStatic;
}
void reset(){
_state = State::Pending;
size = 0;
actualSize = 0;
}
State getState() const {
return _state;
}
private:
State _state = State::Pending;
void transferComleteCallback(bool success){
_state = success ? State::Success : State::Fail;
}
static void transferComleteCallbackStatic(LFramework::USB::UsbDTransfer* _this, bool success){
static_cast<PollingTransfer*>(_this)->transferComleteCallback(success);
}
};
__STATIC_INLINE void DWT_Delay_us(volatile uint32_t microseconds)
{
/* Go to number of cycles for system */
microseconds *= (HAL_RCC_GetHCLKFreq() / 1000000);
DWT->CYCCNT = 0;
/* Delay till end */
while (DWT->CYCCNT < microseconds);
}
int eventId = 0;
void printState(bool oldState, bool newState, const char* name){
if(oldState != newState){
lfDebug() << eventId << ":" << name << (newState ? " pressed" : " released");
eventId++;
}
}
extern SPI_HandleTypeDef hspi2;
class Ps1Gamepad {
public:
static constexpr size_t HeaderSize = 3;
static constexpr size_t MaxDataSize = 9 * 2;
struct Type {
static constexpr uint8_t Digital = 4;
static constexpr uint8_t Negcon = 2;
static constexpr uint8_t AnalogueRed = 7;
static constexpr uint8_t AnalogueGreen = 5;
};
struct Response {
uint8_t dummy;
uint8_t id;
uint8_t padID;
uint8_t buttons0;
uint8_t buttons1;
uint8_t analogRX;
uint8_t analogRY;
uint8_t analogLX;
uint8_t analogLY;
struct {
uint8_t right;
uint8_t left;
uint8_t up;
uint8_t down;
uint8_t triangle;
uint8_t circle;
uint8_t cross;
uint8_t square;
uint8_t l1;
uint8_t r1;
uint8_t l2;
uint8_t r2;
}pressure;
bool hasAnalogJoyData() {
return (id & 0xf) >=3;
}
bool select() {
return (buttons0 & (1 << 0)) == 0;
}
bool l3() {
return (buttons0 & (1 << 1)) == 0;
}
bool r3() {
return (buttons0 & (1 << 2)) == 0;
}
bool start() {
return (buttons0 & (1 << 3)) == 0;
}
bool up() {
return (buttons0 & (1 << 4)) == 0;
}
bool right() {
return (buttons0 & (1 << 5)) == 0;
}
bool down() {
return (buttons0 & (1 << 6)) == 0;
}
bool left() {
return (buttons0 & (1 << 7)) == 0;
}
bool l2() {
return (buttons1 & (1 << 0)) == 0;
}
bool r2() {
return (buttons1 & (1 << 1)) == 0;
}
bool l1() {
return (buttons1 & (1 << 2)) == 0;
}
bool r1() {
return (buttons1 & (1 << 3)) == 0;
}
bool triangle() {
return (buttons1 & (1 << 4)) == 0;
}
bool circle() {
return (buttons1 & (1 << 5)) == 0;
}
bool cross() {
return (buttons1 & (1 << 6)) == 0;
}
bool square() {
return (buttons1 & (1 << 7)) == 0;
}
};
/* const Response& read() {
uint8_t txBuffer[5] = {0x01, 0x42, 0x00, 0x00, 0x00};
executeCommand(txBuffer, sizeof(txBuffer));
return *(Response*)&rxBuffer[0];
}
void enterConfigMode() {
uint8_t cmd[]={ 0x01,0x43,0x00,0x01,0x00};
executeCommand(cmd, sizeof(cmd));
}*/
/*void setControllerMode(bool analog, bool lockMode) {
uint8_t cmd[]={ 0x01, 0x44, 0x00, (analog ? 0x01 : 0x00), (lockMode ? 0x03 : 0x5A), 0x00, 0x00, 0x00, 0x00 };
executeCommand(cmd, sizeof(cmd));
}*/
/*struct DataMask {
struct {
uint8_t b0;
uint8_t b1;
uint8_t b2;
} value;
constexpr DataMask operator | (const DataMask& other) const{
return {{value.b0 | other.value.b0, value.b1 | other.value.b1, value.b2 | other.value.b2,}};
}
static constexpr DataMask digitalB0() { return {{0x01, 0x00, 0x00}}; }
static constexpr DataMask digitalB1() { return {{0x02, 0x00, 0x00}}; }
static constexpr DataMask allDigital() { return digitalB0() | digitalB1();}
static constexpr DataMask analogJoyRx() { return {{0x04, 0x00, 0x00}}; }
static constexpr DataMask analogJoyRy() { return {{0x08, 0x00, 0x00}}; }
static constexpr DataMask analogJoyLx() { return {{0x10, 0x00, 0x00}}; }
static constexpr DataMask analogJoyLy() { return {{0x20, 0x00, 0x00}}; }
static constexpr DataMask leftAnalogJoy() { return analogJoyLx() | analogJoyLy(); }
static constexpr DataMask rightAnalogJoy() { return analogJoyRx() | analogJoyRy(); }
static constexpr DataMask allAnalogJoy() { return leftAnalogJoy() | rightAnalogJoy(); }
static constexpr DataMask pressureR() { return {{0x40, 0x00, 0x00}}; }
static constexpr DataMask pressureL() { return {{0x80, 0x00, 0x00}}; }
static constexpr DataMask pressureU() { return {{0x00, 0x01, 0x00}}; }
static constexpr DataMask pressureD() { return {{0x00, 0x02, 0x00}}; }
static constexpr DataMask pressureTriangle() { return {{0x00, 0x04, 0x00}}; }
static constexpr DataMask pressureCircle() { return {{0x00, 0x08, 0x00}}; }
static constexpr DataMask pressureCross() { return {{0x00, 0x10, 0x00}}; }
static constexpr DataMask pressureSquare() { return {{0x00, 0x20, 0x00}}; }
static constexpr DataMask pressureL1() { return {{0x00, 0x40, 0x00}}; }
static constexpr DataMask pressureR1() { return {{0x00, 0x80, 0x00}}; }
static constexpr DataMask pressureL2() { return {{0x00, 0x00, 0x01}}; }
static constexpr DataMask pressureR2() { return {{0x00, 0x00, 0x02}}; }
static constexpr DataMask allPressure() {
return
pressureR() | pressureL() | pressureU() | pressureD() |
pressureTriangle() | pressureCircle() | pressureCross() | pressureSquare() |
pressureL1() | pressureR1() | pressureL2() | pressureR2();
}
static constexpr DataMask allDigitalAndAnalogJoy() {
return allDigital() | allAnalogJoy();
}
static constexpr DataMask all() {
return allDigitalAndAnalogJoy() | allPressure();
}
static constexpr DataMask none() {
return allDigitalAndAnalogJoy() | allPressure();
}
constexpr DataMask operator ~() {
return {{static_cast<uint8_t>(~value.b0 & 0xff), static_cast<uint8_t>(~value.b1 & 0xff), static_cast<uint8_t>(~value.b2 & 0x03)}};
}
};*/
void byteDelay() {
DWT_Delay_us(28);
}
bool polling = false;
uint32_t pollBytesDone = 0;
uint32_t pollTotalSizeExpected = 0;
void beginPoll() {
if(polling){
endPoll();
}
polling = true;
pollBytesDone = 0;
selectDevice();
byteDelay();
//lfDebug() << "[!] Begin poll";
//auto result = poll(data);
}
uint8_t poll(uint8_t data) {
uint8_t result = 0xFF;
if(!polling){
lfDebug() << "Error: Not polling";
return result;
}
HAL_SPI_TransmitReceive(&hspi2, &data, &result, 1, HAL_MAX_DELAY);
byteDelay();
lfDebug() << "Poll: in=" << (int)data << " out: " << (int)result;
// pollBytesDone++;
/* if(pollBytesDone == 2){
pollTotalSizeExpected = HeaderSize + (result & 0x0f) * 2;
}*/
//lfDebug() << "Poll: " << (int)result;
/*if(pollTotalSizeExpected == pollBytesDone){
endPoll();
}*/
return result;
}
void endPoll() {
lfDebug() << "End poll";
polling = false;
deselectDevice();
byteDelay();
}
//All buttons
/*void setDataMask(DataMask mask) {
uint8_t cmd[]={ 0x01, 0x4F, 0x00, mask.value.b0, mask.value.b1, mask.value.b2, 0x00, 0x00, 0x00 };
executeCommand(cmd, sizeof(cmd));
}*/
/*void exitConfigMode() {
uint8_t cmd[]={ 0x01, 0x43, 0x00, 0x00, 0x5A, 0x5A, 0x5A, 0x5A, 0x5A };
executeCommand(cmd, sizeof(cmd));
}*/
/*uint8_t shift(uint8_t data){
uint8_t result = 0xff;
HAL_SPI_TransmitReceive(&hspi2, &data, &result, 1, HAL_MAX_DELAY);
byteDelay();
return result;
}
bool executeCommand(uint8_t* txBuffer, uint8_t size){
selectDevice();
int byteDelay = 1;
DWT_Delay_us(byteDelay);
//transfer header
for(uint8_t i = 0; i < HeaderSize; ++i){
HAL_SPI_TransmitReceive(&hspi2, &txBuffer[i], &rxBuffer[i], 1, HAL_MAX_DELAY);
DWT_Delay_us(byteDelay);
}
auto expectedDataLength = (rxBuffer[1] & 0x0f) * 2;
//transfer data
for(uint8_t i = HeaderSize; i < size; ++i){
HAL_SPI_TransmitReceive(&hspi2, &txBuffer[i], &rxBuffer[i], 1, HAL_MAX_DELAY);
DWT_Delay_us(byteDelay);
}
//push zeroes if user issued incorrect length command
for(uint8_t i = size; i < (HeaderSize + expectedDataLength); ++i){
uint8_t zero = 0;
HAL_SPI_TransmitReceive(&hspi2, &zero, &rxBuffer[i], 1, HAL_MAX_DELAY);
DWT_Delay_us(byteDelay);
}
deselectDevice();
return true;
}*/
void selectDevice() {
HAL_GPIO_WritePin(GAMEPAD_CS_GPIO_Port, GAMEPAD_CS_Pin, GPIO_PIN_RESET);
DWT_Delay_us(100);
}
void deselectDevice() {
HAL_GPIO_WritePin(GAMEPAD_CS_GPIO_Port, GAMEPAD_CS_Pin, GPIO_PIN_SET);
DWT_Delay_us(100);
}
private:
uint8_t rxBuffer[HeaderSize + MaxDataSize];
};
enum class UsbRequestType : uint8_t {
PollBegin,
Poll,
EndPoll
};
struct UsbRequest {
UsbRequestType type;
uint8_t data;
};
struct UsbResponse {
uint8_t data;
};
extern"C" void StartDefaultTask(void const * argument){
Terminal::out << Terminal::Ansi::Cursor::MoveHome() << Terminal::Ansi::Viewport::ClearScreen();
Debug::Log() << "Hello !";
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->LAR = 0xC5ACCE55;
DWT->CYCCNT = 0;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
usbContext.configurationStringDescriptor = "RealPad";
usbContext.interfaceStringDescriptor = "RealPad";
usbContext.productStringDescriptor = "RealPad DualShock Device";
usbContext.manufacturerStringDescriptor = "L";
usbContext.serialStringDescriptor = "123456";
UsbDevice::start(&usbContext);
auto usbInterface = usbContext.getInterface(0);
while(!usbInterface->isOpen()){
vTaskDelay(1);
}
auto txEp = static_cast<UsbDEndpoint*>(usbInterface->getEndpoint(true, 0));
auto rxEp = static_cast<UsbDEndpoint*>(usbInterface->getEndpoint(false, 0));
Ps1Gamepad gamepad;
/*while(true){
auto& val = gamepad.read();
lfDebug() << "0x" << hex(val.dummy)<< " 0x" << hex(val.id) << " 0x" << hex(val.padID);
vTaskDelay(1000);
}*/
uint8_t rxBuffer[64];
/*uint8_t txBuffer[5] = {0x01, 0x42, 0x00, 0x00, 0x00};
while(true){
gamepad.selectDevice();
lfDebug() << "Begin";
auto log = Debug::Info();
for(int i = 0; i < sizeof(txBuffer); ++i){
auto b = gamepad.shift(txBuffer[i]);
log << "0x" << hex(b) << ", ";
}
gamepad.deselectDevice();
vTaskDelay(100);
}*/
while(true){
//receive packet
PollingTransfer rxTransfer{};
rxTransfer.buffer = rxBuffer;
rxTransfer.size = sizeof(rxBuffer);
rxEp->transferAsync(&rxTransfer);
while(rxTransfer.getState() == PollingTransfer::State::Pending){
portYIELD();
}
if(rxTransfer.actualSize == 0){ //Zero length packet == new session! Reset device to default digital state.
//gamepad.setControllerMode(false, false); //DO NOT DO SUCH THINGS! Multitap detect failed because of this crap!
//Send zero response
PollingTransfer txTransfer;
txTransfer.buffer = nullptr;
txTransfer.size = 0;
txEp->transferAsync(&txTransfer);
while(txTransfer.getState() == PollingTransfer::State::Pending){
portYIELD();
}
}else{
if(rxTransfer.actualSize == sizeof(UsbRequest)){
const UsbRequest& request = *(const UsbRequest*)&rxBuffer[0];
UsbResponse response{0xff};
if(request.type == UsbRequestType::PollBegin){
DWT_Delay_us(100);
gamepad.beginPoll();
}else if(request.type == UsbRequestType::Poll){
response.data = gamepad.poll(request.data);
}else if(request.type == UsbRequestType::EndPoll){
gamepad.endPoll();
}
//Send poll response
PollingTransfer txTransfer;
txTransfer.buffer = &response;
txTransfer.size = sizeof(response);
txEp->transferAsync(&txTransfer);
while(txTransfer.getState() == PollingTransfer::State::Pending){
portYIELD();
}
}
}
}
}
extern "C" void vApplicationStackOverflowHook(xTaskHandle xTask, signed char *pcTaskName){
Debug::Log() << "Stack overflow in task " << (const char*)pcTaskName;
for(;;);
}
extern "C" void vApplicationMallocFailedHook(void){
Debug::Log() << "Malloc failed";
for(;;);
}