From ec9d9997ab18a8310c72d83e2baca16c75a1e53a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rapha=C3=ABl=20Ass=C3=A9nat?= Date: Wed, 18 Apr 2007 23:58:01 +0000 Subject: [PATCH] fixes --- Changelog.txt | 7 ++ Readme.txt | 4 +- gamepad.h | 11 ++- main.c | 180 ++++++++++++++++++++----------------------- snes.c | 209 ++++++++++++++++++++++++++++++++------------------ usbconfig.h | 16 ++-- 6 files changed, 240 insertions(+), 187 deletions(-) diff --git a/Changelog.txt b/Changelog.txt index 16970f4..1d2a441 100644 --- a/Changelog.txt +++ b/Changelog.txt @@ -1,2 +1,9 @@ +--- v1.1 (18 Apr 2007) +- Changed report descriptor. There are now four separate report IDs, one +per controller. This was necessary because even though all axis and buttons +were perfectly functional in 'control panel -> game controllers', it was not +the case in many games, including zsnes and snes9x! +- Changed device id to 0x0A9D + --- v1.0 (24 Mar 2007) Initial release. diff --git a/Readme.txt b/Readme.txt index 35d1327..2ed4933 100644 --- a/Readme.txt +++ b/Readme.txt @@ -57,9 +57,9 @@ Table of contents: http://www.mecanique.co.uk/products/usb/pid.html -6) Where do I get more information and updates? +6) Where can I get more information and updates? -------------------------------------------- - Visit 4nes4snes page: + Visit the 4nes4snes webpage: http://www.raphnet.net/electronique/4nes4snes/index_en.php you may also contact me by email: Raphael Assenat diff --git a/gamepad.h b/gamepad.h index 95eb401..5b07963 100644 --- a/gamepad.h +++ b/gamepad.h @@ -3,7 +3,7 @@ typedef struct { // size of reports built by buildReport - int report_size; + char num_reports; int reportDescriptorSize; void *reportDescriptor; // must be in flash @@ -13,8 +13,13 @@ typedef struct { void (*init)(void); void (*update)(void); - char (*changed)(void); - void (*buildReport)(unsigned char *buf); + + char (*changed)(char id); + /** + * \param id Controller id (starting at 1 to match report IDs) + * \return The number of bytes written to buf. + * */ + char (*buildReport)(unsigned char *buf, char id); } Gamepad; #endif // _gamepad_h__ diff --git a/main.c b/main.c index ff38097..5bc9afb 100644 --- a/main.c +++ b/main.c @@ -25,6 +25,9 @@ #include "leds.h" #include "devdesc.h" +/* The maximum number of independent reports that are supported. */ +#define MAX_REPORTS 8 + int usbCfgSerialNumberStringDescriptor[] PROGMEM = { USB_STRING_DESCRIPTOR_HEADER(USB_CFG_SERIAL_NUMBER_LENGTH), '1', '0', '0', '0' @@ -78,76 +81,61 @@ static uchar reportBuffer[12]; /* buffer for HID reports */ /* ----------------------------- USB interface ----------------------------- */ /* ------------------------------------------------------------------------- */ -static uchar idleRate; /* in 4 ms units */ +static uchar idleRates[MAX_REPORTS]; /* in 4 ms units */ static uchar reportPos=0; uchar usbFunctionSetup(uchar data[8]) { usbRequest_t *rq = (void *)data; + int i; usbMsgPtr = reportBuffer; - if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */ - if(rq->bRequest == USBRQ_HID_GET_REPORT){ /* wValue: ReportType (highbyte), ReportID (lowbyte) */ - /* we only have one report type, so don't look at wValue */ - reportPos=0; - //curGamepad->buildReport(reportBuffer); - //return curGamepad->report_size; - return 0xff; - }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]; + + /* class request type */ + if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ + switch (rq->bRequest) + { + case USBRQ_HID_GET_REPORT: + /* wValue: ReportType (highbyte), ReportID (lowbyte) */ + reportPos=0; + return curGamepad->buildReport(reportBuffer, rq->wValue.bytes[0]); + + case USBRQ_HID_GET_IDLE: + if (rq->wValue.bytes[0] > 0 && rq->wValue.bytes[0] <= MAX_REPORTS) { + usbMsgPtr = idleRates + (rq->wValue.bytes[0] - 1); + return 1; + } + break; + + case USBRQ_HID_SET_IDLE: + if (rq->wValue.bytes[0]==0) { + for (i=0; iwValue.bytes[1]; + } + else { + if (rq->wValue.bytes[0] > 0 && rq->wValue.bytes[0] <= MAX_REPORTS) { + idleRates[rq->wValue.bytes[0]-1] = rq->wValue.bytes[1]; + } + } + break; } - }else{ - /* no vendor specific requests implemented */ + } else { + /* no vendor specific requests implemented */ } return 0; } -uchar usbFunctionRead(uchar *data, uchar len) -{ - char i,c; - for (c=0; reportPos < sizeof(reportBuffer) && c>1; - - switch(run_mode) - { - default: - case 3: - curGamepad = snesGetGamepad(); - break; - } -#endif - curGamepad = snesGetGamepad(); // configure report descriptor according to @@ -173,6 +161,9 @@ int main(void) curGamepad->init(); odDebugInit(); usbInit(); + + curGamepad->update(); + sei(); DBG1(0x00, 0, 0); @@ -183,71 +174,66 @@ int main(void) // this must be called at each 50 ms or less usbPoll(); - if (first_run) { - curGamepad->update(); - first_run = 0; - } - - if(TIFR & (1< 4){ - idleCounter -= 5; /* 22 ms in units of 4 ms */ - }else{ - idleCounter = idleRate; - must_report = 1; - } - } - } - + /* Read the controllers at 60hz */ if (TIFR & (1<update(); - if (curGamepad->changed()) { - must_report = 1; + + curGamepad->update(); + + /* Check what will have to be reported */ + for (i=0; inum_reports; i++) { + if (curGamepad->changed(i+1)) { + must_report |= (1<num_reports; i++) + { + // 0 means + if(idleRates[i] != 0){ + if (idleCounters[i] > 4) { + idleCounters[i] -= 5; /* 22 ms in units of 4 ms */ + } else { + // reset the counter and schedule a report for this + idleCounters[i] = idleRates[i]; + must_report |= (1<num_reports; i++) + { + if ((must_report & (1<buildReport(reportBuffer); - reportPos = 0; + if (usbInterruptIsReady()) + { + char len; - while (reported < curGamepad->report_size) - { - int cur_report_siz; - - - if (curGamepad->report_size - reported >= 8) - cur_report_siz = 8; - else - cur_report_siz = curGamepad->report_size - reported; - - usbSetInterrupt(&reportBuffer[reported], cur_report_siz); + len = curGamepad->buildReport(reportBuffer, i+1); + usbSetInterrupt(reportBuffer, len); while (!usbInterruptIsReady()) { usbPoll(); wdt_reset(); } - - reported += cur_report_siz; } - - usbSetInterrupt(&empty, 0); - must_report = 0; } + + must_report = 0; } } return 0; diff --git a/snes.c b/snes.c index 75c365e..5671fe5 100644 --- a/snes.c +++ b/snes.c @@ -16,7 +16,6 @@ #include "leds.h" #include "snes.h" -#define REPORT_SIZE 12 #define GAMEPAD_BYTES 8 /* 2 byte per snes controller * 4 controllers */ /******** IO port definitions **************/ @@ -50,8 +49,8 @@ /*********** prototypes *************/ static void snesInit(void); static void snesUpdate(void); -static char snesChanged(void); -static void snesBuildReport(unsigned char *reportBuffer); +static char snesChanged(char report_id); +static char snesBuildReport(unsigned char *reportBuffer, char report_id); // the most recent bytes we fetched from the controller @@ -205,13 +204,13 @@ static void snesUpdate(void) } -static char snesChanged(void) +static char snesChanged(char report_id) { - static int first = 1; - if (first) { first = 0; return 1; } - - return memcmp(last_read_controller_bytes, - last_reported_controller_bytes, GAMEPAD_BYTES); + report_id--; // first report is 1 + + return memcmp( &last_read_controller_bytes[report_id<<1], + &last_reported_controller_bytes[report_id<<1], + 2); } static char getX(unsigned char nesByte1) @@ -245,8 +244,13 @@ static unsigned char snesReorderButtons(unsigned char bytes[2]) return v; } -static void snesBuildReport(unsigned char *reportBuffer) +static char snesBuildReport(unsigned char *reportBuffer, char id) { + char idx; + + if (id < 0 || id > 4) + return 0; + /* last_read_controller_bytes[] structure: * * [0] : controller 1, 8 first bits (dpad + start + sel + y|a + b) @@ -262,86 +266,139 @@ static void snesBuildReport(unsigned char *reportBuffer) * [7] : controller 4, 4 extra snes buttons */ + idx = id - 1; if (reportBuffer != NULL) { - reportBuffer[0]=getX(last_read_controller_bytes[0]); - reportBuffer[1]=getY(last_read_controller_bytes[0]); - reportBuffer[2]=getX(last_read_controller_bytes[2]); - reportBuffer[3]=getY(last_read_controller_bytes[2]); - reportBuffer[4]=getX(last_read_controller_bytes[4]); - reportBuffer[5]=getY(last_read_controller_bytes[4]); - reportBuffer[6]=getX(last_read_controller_bytes[6]); - reportBuffer[7]=getY(last_read_controller_bytes[6]); + reportBuffer[0]=id; + reportBuffer[1]=getX(last_read_controller_bytes[idx*2]); + reportBuffer[2]=getY(last_read_controller_bytes[idx*2]); - if (nesMode & 0x01) - reportBuffer[8] = last_read_controller_bytes[0] & 0xf0; + if (nesMode & (0x01<