Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
156 changes: 156 additions & 0 deletions PSXControllerUSB/Gamepad.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/* Gamepad.cpp
*
* Based on the advanced HID library for Arduino:
* https://github.com/NicoHood/HID
* Copyright (c) 2014-2015 NicoHood
*
* Copyright (c) 2021 Hendrik Osterholz
*
* GNU GENERAL PUBLIC LICENSE
* Version 3, 29 June 2007
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*
*/
#include "Gamepad.h"

static const uint8_t _hidReportDescriptor[] PROGMEM = {
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x04, // USAGE (Joystick) (Maybe change to gamepad? I don't think so but...)
0xa1, 0x01, // COLLECTION (Application)
0xa1, 0x00, // COLLECTION (Physical)

0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x0c, // USAGE_MAXIMUM (Button 12)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x95, 0x0c, // REPORT_COUNT (12)
0x75, 0x01, // REPORT_SIZE (1)
0x81, 0x02, // INPUT (Data,Var,Abs)

0x95, 0x01, // REPORT_COUNT (1) ; pad out the bits into a number divisible by 8
0x75, 0x04, // REPORT_SIZE (4)
0x81, 0x03, // INPUT (Const,Var,Abs)

0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x01, // USAGE (pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x15, 0xff, // LOGICAL_MINIMUM (-1)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x95, 0x02, // REPORT_COUNT (2)
0x75, 0x08, // REPORT_SIZE (8)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION

0xc0, // END_COLLECTION
0xc0, // END_COLLECTION
};

Gamepad_::Gamepad_(void) : PluggableUSBModule(1, 1, epType), protocol(HID_REPORT_PROTOCOL), idle(1)
{
epType[0] = EP_TYPE_INTERRUPT_IN;
PluggableUSB().plug(this);
}

int Gamepad_::getInterface(uint8_t* interfaceCount)
{
*interfaceCount += 1; // uses 1
HIDDescriptor hidInterface = {
D_INTERFACE(pluggedInterface, 1, USB_DEVICE_CLASS_HUMAN_INTERFACE, HID_SUBCLASS_NONE, HID_PROTOCOL_NONE),
D_HIDREPORT(sizeof(_hidReportDescriptor)),
D_ENDPOINT(USB_ENDPOINT_IN(pluggedEndpoint), USB_ENDPOINT_TYPE_INTERRUPT, USB_EP_SIZE, 0x01)
};
return USB_SendControl(0, &hidInterface, sizeof(hidInterface));
}

int Gamepad_::getDescriptor(USBSetup& setup)
{
// Check if this is a HID Class Descriptor request
if (setup.bmRequestType != REQUEST_DEVICETOHOST_STANDARD_INTERFACE) { return 0; }
if (setup.wValueH != HID_REPORT_DESCRIPTOR_TYPE) { return 0; }

// In a HID Class Descriptor wIndex cointains the interface number
if (setup.wIndex != pluggedInterface) { return 0; }

// Reset the protocol on reenumeration. Normally the host should not assume the state of the protocol
// due to the USB specs, but Windows and Linux just assumes its in report mode.
protocol = HID_REPORT_PROTOCOL;

return USB_SendControl(TRANSFER_PGM, _hidReportDescriptor, sizeof(_hidReportDescriptor));
}

bool Gamepad_::setup(USBSetup& setup)
{
if (pluggedInterface != setup.wIndex) {
return false;
}

uint8_t request = setup.bRequest;
uint8_t requestType = setup.bmRequestType;

if (requestType == REQUEST_DEVICETOHOST_CLASS_INTERFACE)
{
if (request == HID_GET_REPORT) {
// TODO: HID_GetReport();
return true;
}
if (request == HID_GET_PROTOCOL) {
// TODO: Send8(protocol);
return true;
}
}

if (requestType == REQUEST_HOSTTODEVICE_CLASS_INTERFACE)
{
if (request == HID_SET_PROTOCOL) {
protocol = setup.wValueL;
return true;
}
if (request == HID_SET_IDLE) {
idle = setup.wValueL;
return true;
}
if (request == HID_SET_REPORT)
{
}
}

return false;
}

void Gamepad_::reset()
{
_GamepadReport.X = 0;
_GamepadReport.Y = 0;
_GamepadReport.buttons = 0;
this->send();
}

void Gamepad_::send()
{
USB_Send(pluggedEndpoint | TRANSFER_RELEASE, &_GamepadReport, sizeof(GamepadReport));
}

uint8_t Gamepad_::getShortName(char *name)
{
if(!next)
{
strcpy(name, gp_serial);
return strlen(name);
}
return 0;
}
60 changes: 60 additions & 0 deletions PSXControllerUSB/Gamepad.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/* Gamepad.h
*
* Based on the advanced HID library for Arduino:
* https://github.com/NicoHood/HID
* Copyright (c) 2014-2015 NicoHood
*
* Copyright (c) 2021 Hendrik Osterholz
*
* GNU GENERAL PUBLIC LICENSE
* Version 3, 29 June 2007
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*
*/

#pragma once

#include "HID.h"

extern const char* gp_serial;

typedef struct {
uint16_t buttons;
int8_t X;
int8_t Y;
} GamepadReport;


class Gamepad_ : public PluggableUSBModule
{
private:
uint8_t reportId;

protected:
int getInterface(uint8_t* interfaceCount);
int getDescriptor(USBSetup& setup);
uint8_t getShortName(char *name);
bool setup(USBSetup& setup);

uint8_t epType[1];
uint8_t protocol;
uint8_t idle;

public:
GamepadReport _GamepadReport;
Gamepad_(void);
void reset(void);
void send();
};
99 changes: 99 additions & 0 deletions PSXControllerUSB/PSXControllerUSB.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/* DaemonBite PSX USB Adapter
* Author: Hendrik Osterholz
*
* Copyright (c) 2021 Hendrik Osterholz
*
* GNU GENERAL PUBLIC LICENSE
* Version 3, 29 June 2007
*
* 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 3 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, see <https://www.gnu.org/licenses/>.
*
*/

#include "Gamepad.h"

#define GAMEPAD_COUNT 1 // Set to 1 or 2 depending if you want to make a 1 or 2 port adapter
#define GAMEPAD_COUNT_MAX 4

// ATT: 20 chars max (including NULL at the end) according to Arduino source code.
// Additionally serial number is used to differentiate arduino projects to have different button maps!
const char *gp_serial = "PSX to USB";

#include "Psx.h"

#define dataPin 18
#define cmndPin 2
#define attPin 3
#define clockPin 4

/* -------------------------------------------------------------------------
PSX controller socket (looking face-on at the front of the socket):
_________________________
| 9 8 7 | 6 5 4 | 3 2 1 |
\_______________________/

PSX controller plug (looking face-on at the front of the controller plug):
_________________________
| 1 2 3 | 4 5 6 | 7 8 9 |
\_______________________/

PSX Arduino Pro Micro
--------------------------------------
1 DATA A0 PF7
2 CMD 2 PD1
3 +7.6V
4 GND GND
5 VCC VCC
6 ATT 3 PD0
7 CLK 4 PD4
8 N/C
9 ACK

------------------------------------------------------------------------- */

Psx Psx;

// Set up USB HID gamepads
Gamepad_ Gamepad[GAMEPAD_COUNT];

// Controllers
uint16_t buttons[GAMEPAD_COUNT_MAX] = {0,0,0,0};
uint16_t buttonsPrev[GAMEPAD_COUNT_MAX] = {0,0,0,0};
uint8_t gp = 0;

void setup()
{
Psx.setupPins(dataPin, cmndPin, attPin, clockPin, 10);
}

void loop() { while(1)
{
// Send data to USB if values have changed
for(gp=0; gp<GAMEPAD_COUNT; gp++)
{
buttons[gp] = 0;
buttons[gp] = Psx.read();

// Has any buttons changed state?
if (buttons[gp] != buttonsPrev[gp] || buttons[gp] != buttonsPrev[gp] )
{
Gamepad[gp]._GamepadReport.buttons = buttons[gp] >> 4;
Gamepad[gp]._GamepadReport.Y = ((buttons[gp] & psxDown) >> 1) - ((buttons[gp] & psxUp) >> 3);
Gamepad[gp]._GamepadReport.X = ((buttons[gp] & psxRight) >> 2) - (buttons[gp] & psxLeft);
buttonsPrev[gp] = buttons[gp];
Gamepad[gp].send();
}
}

}}
Loading