Merging PS2USB with C64 Code
Posted: Mon Mar 01, 2010 5:59 am
My project requires reading a Playstation Controller and translating that into Keyboard inputs (ie pressing up on the controller makes the AVR send a U keystroke, pressing the circle makes the avr type o etc). I've successfully loaded the PS2USB code and the C64 code and tested them individually, but I cannot seem to merge them correctly. I use the C64 code, usb descriptor, and everything else USB related, and my avr shows up fine as the C64 keyboard. I set up the hardware as the schematics for the PS2USB show. No matter how many times I've tried, I cannot get the code I've tried to merge together to work. The most confusion I have is in translating the PSX controller codes to USB keycodes. Can anyone help?
Here is my pathetic attempt at the code, after hours of getting nowhere.
Here is my pathetic attempt at the code, after hours of getting nowhere.
Code: Select all
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>
#include "usbdrv.h"
#include "oddebug.h"
#include <util/delay.h>
static uchar ps2buffer[9]={0,0,0,0,0,0,0,0,0};
static uchar type=0;
static uchar type1=0; // 0=Normal digital, >200 = DDR Pad
static uchar type2=0;
static uchar outBuffer1[8];
static uchar outBuffer2[8];
/* ----------------------- hardware I/O abstraction ------------------------ */
/* ------------------------------------------------------------------------- */
static void hardwareInit(void)
{
uchar i, j;
DDRB = 0x2F; // PORTB; everythin output, except MISO
PORTB = 0x04; // ATT lines, uses CS and another pin
PORTC = 0; // Don't need these atm.
DDRC = 0; // Don't need these atm.
PORTD = 0xfa; /* 1111 1010 bin: activate pull-ups except on USB lines */
DDRD = 0x07; /* 0000 0111 bin: all pins input except USB (-> USB reset) */
j = 0;
while(--j){ /* USB Reset by device only required on Watchdog Reset */
i = 0;
while(--i); /* delay >10ms for USB reset */
}
DDRD = 0x02; /* 0000 0010 bin: remove USB reset condition */
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
/* ----------------------Atmega8 SPI, master, 93.75khz---------------------- */
/* ------------------------------------------------------------------------- */
void spi_mInit()
{
// SPI, master, clock/128 = 93.75khz (187.5 didn't work...)
SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR1)|(1<<SPR0)|(1<<DORD)|(1<<CPHA)|(1<<CPOL);
}
unsigned char spi_mSend(unsigned char podatek) //straight from documentation
{
// Gets information, sends it, waits untill it's sent, then reads the same register (used for both Input and Output) and returns it
/* Start transmission */
SPDR = podatek;
while(!(SPSR & (1<<SPIF)));
return SPDR;
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
/* ----------------------------- USB interface ----------------------------- */
/* ------------------------------------------------------------------------- */
static uchar reportBuffer[8]; /* buffer for HID reports */
static uchar idleRate; // Unused
PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { /* USB report descriptor */
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x04, // USAGE (Joystick)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x85, 0x01, // REPORT_ID (1)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x0f, // LOGICAL_MAXIMUM (15)
0x75, 0x04, // REPORT_SIZE (4)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x32, // USAGE (Z)
0x09, 0x33, // USAGE (Rx)
0x09, 0x34, // USAGE (Ry)
0x09, 0x35, // USAGE (Rz)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x04, // REPORT_COUNT (4)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x10, // USAGE_MAXIMUM (Button 16)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x10, // REPORT_COUNT (16)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x04, // USAGE (Joystick)
0xa1, 0x01, // COLLECTION (Application)
0x09, 0x01, // USAGE (Pointer)
0xa1, 0x00, // COLLECTION (Physical)
0x85, 0x02, // REPORT_ID (1)
0x09, 0x30, // USAGE (X)
0x09, 0x31, // USAGE (Y)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x0f, // LOGICAL_MAXIMUM (15)
0x75, 0x04, // REPORT_SIZE (4)
0x95, 0x02, // REPORT_COUNT (2)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x09, 0x32, // USAGE (Z)
0x09, 0x33, // USAGE (Rx)
0x09, 0x34, // USAGE (Ry)
0x09, 0x35, // USAGE (Rz)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
0x75, 0x08, // REPORT_SIZE (8)
0x95, 0x04, // REPORT_COUNT (4)
0x81, 0x02, // INPUT (Data,Var,Abs)
0x05, 0x09, // USAGE_PAGE (Button)
0x19, 0x01, // USAGE_MINIMUM (Button 1)
0x29, 0x10, // USAGE_MAXIMUM (Button 16)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x01, // LOGICAL_MAXIMUM (1)
0x75, 0x01, // REPORT_SIZE (1)
0x95, 0x10, // REPORT_COUNT (16)
0x81, 0x02, // INPUT (Data,Var,Abs)
0xc0, // END_COLLECTION
0xc0, // END_COLLECTION
};
/* ------------------------------------------------------------------------- */
// Delays
void wait100us(){
_delay_us(100);
}
/* ------------------------------------------------------------------------- */
/* ------------------------------- Get data! ------------------------------- */
/* ------------------------------------------------------------------------- */
void get_data(int c) {
if (c==0){
PORTB=0x02;
}
else if(c==1){
PORTB=0x04;
}
_delay_ms(1);
ps2buffer[0]=spi_mSend(0x01); // We want data!
wait100us();
ps2buffer[1]=spi_mSend(0x42); // What's your model? (use later)
wait100us();
if (ps2buffer[1]==0x41){ // Digital pad, possibly DDR Pad
ps2buffer[2]=spi_mSend(0x00);
wait100us();
ps2buffer[3]=spi_mSend(0x00);
wait100us();
ps2buffer[4]=spi_mSend(0x00);
wait100us();
ps2buffer[5]=spi_mSend(0x00);
wait100us();
ps2buffer[6]=spi_mSend(0x00);
wait100us();
ps2buffer[7]=spi_mSend(0x00);
wait100us();
ps2buffer[8]=spi_mSend(0x00);
} else if (ps2buffer[1]==0x73){// Standard Analog pad in RED mode
ps2buffer[2]=spi_mSend(0x00);
wait100us();
ps2buffer[3]=spi_mSend(0x00);
wait100us();
ps2buffer[4]=spi_mSend(0x00);
wait100us();
ps2buffer[5]=spi_mSend(0x00);
wait100us();
ps2buffer[6]=spi_mSend(0x00);
wait100us();
ps2buffer[7]=spi_mSend(0x00);
wait100us();
ps2buffer[8]=spi_mSend(0x00);
} else {
ps2buffer[2]=0;
ps2buffer[3]=0;
ps2buffer[4]=0;
ps2buffer[5]=0;
ps2buffer[6]=0;
ps2buffer[7]=0;
ps2buffer[8]=0;
}
PORTB = 0x06;
_delay_ms(1);
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
/* ----------------------- Make sense from the data! ----------------------- */
/* ------------------------------------------------------------------------- */
// Is the controller digital, analog, dance pad,...
void make_sense(int t) {
if (t==0){
type=type1;
}
else if (t==1){
type=type2;
}
int temp1=255-ps2buffer[3];
int temp2=255-ps2buffer[4];
if (ps2buffer[1]==0x41){ // Digital pad
// Zero the unused axes
reportBuffer[2]=0x80;
reportBuffer[3]=0x80;
reportBuffer[4]=0x80;
reportBuffer[5]=0x80;
// Buttons!
reportBuffer[6]=((temp1 & 0x01) << 0) | ((temp1 & 0x08) >> 2) | ((temp2 & 0x01) << 2) | ((temp2 & 0x02) << 2) | ((temp2 & 0x04) << 2) | ((temp2 & 0x08) << 2) | ((temp2 & 0x10) << 2) | ((temp2 & 0x20) << 2);
reportBuffer[7]=((temp2 & 0x40) >> 6) | ((temp2 & 0x80) >> 6) | ((temp1 & 0x02) << 1) | ((temp1 & 0x04) << 1);
if (type < 200){
// Up, Down - Y! Axis
if (temp1 & 0x10){
reportBuffer[1]=0x00;
}
else if (temp1 & 0x40){
reportBuffer[1]=0xF0;
}
else {
reportBuffer[1]=0x80;
}
// Right, Left - X! Axis
if (temp1 & 0x20){
reportBuffer[1]=reportBuffer[1]+0x0F;
}
else if (temp1 & 0x80){
reportBuffer[1]=reportBuffer[1]+0x00;
}
else {
reportBuffer[1]=reportBuffer[1]+0x08;
}
reportBuffer[7] &= ~0x10 | ~0x20 | ~0x40 | ~0x80;
} else {
reportBuffer[7] = ((temp2 & 0x40) >> 6) | ((temp2 & 0x80) >> 6) | ((temp1 & 0x02) << 1) | ((temp1 & 0x04) << 1) | (temp1 & 0x10) | (temp1 & 0x20) |(temp1 & 0x40) | (temp1 & 0x80);
reportBuffer[1]=0x88;
type = 222;
}
if ((temp1 & 0x01) && (temp1 & 0x08) && (temp1 & 0x10) ){
type++;
if (t==0){
type1=type;
}
else if (t==1){
type2=type;
}
}
}
else if (ps2buffer[1]==0x73){ // Decode analog pad
// Right stick, X axis
reportBuffer[2]=ps2buffer[5];
// Right stick, Y axis
reportBuffer[3]=ps2buffer[6];
// Left stick, X axis
reportBuffer[4]=ps2buffer[7];
// Left stick, Y axis
reportBuffer[5]=ps2buffer[8];
//Buttons, buttons, so many buttons!
// Up, Down - Y! Axis
if (temp1 & 0x10){
reportBuffer[1]=0x00;
}
else if (temp1 & 0x40){
reportBuffer[1]=0xF0;
}
else {
reportBuffer[1]=0x80;
}
// Right, Left - X! Axis
if (temp1 & 0x20){
reportBuffer[1]=reportBuffer[1]+0x0F;
}
else if (temp1 & 0x80){
reportBuffer[1]=reportBuffer[1]+0x00;
}
else {
reportBuffer[1]=reportBuffer[1]+0x08;
}
reportBuffer[6]=((temp1 & 0x01) << 0) | ((temp1 & 0x08) >> 2) | ((temp2 & 0x01) << 2) | ((temp2 & 0x02) << 2) | ((temp2 & 0x04) << 2) | ((temp2 & 0x08) << 2) | ((temp2 & 0x10) << 2) | ((temp2 & 0x20) << 2);
reportBuffer[7]=((temp2 & 0x40) >> 6) | ((temp2 & 0x80) >> 6) | ((temp1 & 0x02) << 1) | ((temp1 & 0x04) << 1);
reportBuffer[7] &= ~0x10 | ~0x20 | ~0x40 | ~0x80;
} else { // If there isn't a pad connected, or if it is an unsupported one, zero the axes and the buttons
reportBuffer[1]= 0x88;
reportBuffer[2]= 0x80;
reportBuffer[3]= 0x80;
reportBuffer[4]= 0x80;
reportBuffer[5]= 0x80;
reportBuffer[6]= 0;
reportBuffer[7]= 0;
}
}
/* ------------------------------------------------------------------------- */
uchar usbFunctionSetup(uchar data[8])
{
usbRequest_t *rq = (void *)data;
if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */
if(rq->bRequest == USBRQ_HID_GET_REPORT){ /* wValue: ReportType (highbyte), ReportID (lowbyte) */
reportBuffer[0]= 0;
reportBuffer[1]= 0;
reportBuffer[2]= 0;
reportBuffer[3]= 0;
reportBuffer[4]= 0;
reportBuffer[5]= 0;
reportBuffer[6]= 0;
reportBuffer[7]= 0;
usbMsgPtr = reportBuffer;
return sizeof (reportBuffer);
}else if(rq->bRequest == USBRQ_HID_GET_IDLE){
usbMsgPtr = &idleRate;
return 1;
}else if(rq->bRequest == USBRQ_HID_SET_IDLE){
idleRate = rq->wValue.bytes[1];
}
}else{
/* no vendor specific requests implemented */
}
return 0;
}
/* ------------------------------------------------------------------------- */
int main(void)
{
uchar idleCounter = 0;
wdt_enable(WDTO_2S);
hardwareInit();
odDebugInit();
usbInit();
sei();
spi_mInit(); // SPI
int x=0;
int changed=0;
// Tell the computer we're here, make prerequisites for later
// 1st gamepad
wdt_reset();
usbPoll();
get_data(0);
make_sense(0);
reportBuffer[0]= 0x01;
for (x=0; x<8; x++) {
outBuffer1[x]=reportBuffer[x];
}
while (!usbInterruptIsReady()) { wdt_reset(); usbPoll(); }
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
// 2nd gamepad
get_data(1);
make_sense(1);
reportBuffer[0]= 0x02;
for (x=0; x<8; x++) {
outBuffer2[x]=reportBuffer[x];
}
while (!usbInterruptIsReady()) { wdt_reset(); usbPoll(); }
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
changed=0;
// Main loop
// This loop checks one gamepad, if the state of buttons changed, it waits untill it can send the data and then send it,
// otherwise it checks the other gamepad and does the same thing (this approach saves time)
for(;;){
// 1st gamepad
wdt_reset();
usbPoll();
get_data(0);
make_sense(0);
reportBuffer[0]= 0x01;
for (x=0; x<8; x++) {
if (outBuffer1[x]!=reportBuffer[x]){
changed=1;
}
}
if (changed==1){
while (!usbInterruptIsReady()) { wdt_reset(); usbPoll(); }
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
for (x=0; x<8; x++) {
outBuffer1[x]=reportBuffer[x];
}
changed=0;
}
// 2nd gamepad
wdt_reset();
usbPoll();
get_data(1);
make_sense(1);
reportBuffer[0]= 0x02;
for (x=0; x<8; x++) {
if (outBuffer2[x]!=reportBuffer[x]){
changed=1;
}
}
if (changed==1){
while (!usbInterruptIsReady()) { wdt_reset(); usbPoll(); }
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
for (x=0; x<8; x++) {
outBuffer2[x]=reportBuffer[x];
}
changed=0;
}
wdt_reset();
usbPoll();
}
return 0;
}
/* ------------------------------------------------------------------------- */