4 #include <avr/interrupt.h>
5 #include <util/delay.h>
6 #include <avr/pgmspace.h>
13 PROGMEM char usbHidReportDescriptor[28] = {
14 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
15 0x09, 0x05, // USAGE (Game Pad)
16 0xa1, 0x01, // COLLECTION (Application)
17 0x09, 0x05, // USAGE (Game Pad)
18 0xa1, 0x00, // COLLECTION (Physical)
19 0x05, 0x09, // USAGE_PAGE (Button)
20 0x19, 0x01, // USAGE_MINIMUM (Button 1)
21 0x29, 0x10, // USAGE_MAXIMUM (Button 16)
22 0x15, 0x00, // LOGICAL MINIMUM (0)
23 0x25, 0x01, // LOGICAL MAXIMUM (1)
24 0x95, 0x10, // REPORT_COUNT (16)
25 0x75, 0x01, // REPORT_SIZE (1)
26 0x81, 0x02, // INPUT (Data, Var, Abs)
27 0xc0, // END_COLLECTION
28 0xc0 // END_COLLECTION
39 static report_t buttonState;
40 static report_t reportBuffer;
42 usbMsgLen_t usbFunctionSetup(uchar data[8]) {
43 usbRequest_t *rq = (void *)data;
45 /* The following requests are never used. But since they are required by
46 * the specification, we implement them in this example.
48 if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */
49 //DBG1(0x50, &rq->bRequest, 1); /* debug output: print our request */
50 if(rq->bRequest == USBRQ_HID_GET_REPORT){ /* wValue: ReportType (highbyte), ReportID (lowbyte) */
51 /* we only have one report type, so don't look at wValue */
52 usbMsgPtr = (void *)&reportBuffer;
53 return sizeof(reportBuffer);
56 /* no vendor specific requests implemented */
58 return 0; /* default for not implemented requests: return no data back to host */
61 ISR(TIMER1_COMPA_vect) {
62 buttonState.buttons = pollSnes();
66 // See section 15.11 for reference
67 // Using CTC mode (non-PWM)
69 // TCCR1A = 0b00000000 (No timer output, no PWM)
70 // TCCR1B = 0b00001010 (CTC mode, ckli_o/8)
71 // TCCR1C = 0b00000000 (No output compare)
75 // {OCR1AH, OCR1AL} = 37500 = 10010010 01111100
76 // 37500 * 8 * 60 = 18MHz
79 // TIMSK1 = 0b00000010 (Enable interrupt on Output Compare A Match)
86 wdt_enable(WDTO_1S); // Enable watchdog with 1s reset time
87 /* Even if you don't use the watchdog, turn it off here. On newer devices,
88 * the status of the watchdog (on/off, period) is PRESERVED OVER RESET!
91 //DBG1(0x00, 0, 0); /* debug output: main starts */
93 /* RESET status: all port bits are inputs without pull-up.
94 * That's the way we need D+ and D-. Therefore we don't need any
95 * additional hardware initialization on the USB side.
98 // We need to setup the pin configuration for D3, which is an output pin
101 // Set up the clock prescaler to CLKI_O/8, which gives us 2250000 ticks per second
102 // This makes 37500 such ticks give us a 60Hz signal, which is exactly how we set up
103 // the timer interrupt to poll the SNES controller
110 usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */
112 while(--i){ /* fake USB disconnect for > 250 ms */
117 sei(); // Enable interrupts
118 //DBG1(0x01, 0, 0); /* debug output: main loop starts */
119 for(;;){ /* main event loop */
120 //DBG1(0x02, 0, 0); /* debug output: main loop iterates */
123 if(usbInterruptIsReady()){
124 reportBuffer.buttons = buttonState.buttons;
125 /* called after every poll of the interrupt endpoint */
126 //advanceCircleByFixedAngle();
127 //DBG1(0x03, 0, 0); /* debug output: interrupt report prepared */
128 usbSetInterrupt((void *)&reportBuffer, sizeof(reportBuffer));