]> git.zarvox.org Git - usbsnes.git/blob - main.c
aee88a4680165f62a8f4dd2645d3660734e26a59
[usbsnes.git] / main.c
1
2 #include <avr/io.h>
3 #include <avr/wdt.h>
4 #include <avr/interrupt.h>
5 #include <util/delay.h>
6 #include <avr/pgmspace.h>
7
8 #include "usbconfig.h"
9 #include "usbdrv.h"
10
11 uint16_t pollSnes();
12
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
29 };
30 /*
31 typedef struct {
32         uchar buttons[2];
33 } report_t;
34 */
35 typedef struct {
36         uint16_t buttons;
37 } report_t;
38
39 static report_t buttonState;
40 static report_t reportBuffer;
41
42 usbMsgLen_t usbFunctionSetup(uchar data[8]) {
43         usbRequest_t    *rq = (void *)data;
44
45         /* The following requests are never used. But since they are required by
46          * the specification, we implement them in this example.
47          */
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);
54                 }
55         }else{
56                 /* no vendor specific requests implemented */
57         }
58         return 0;   /* default for not implemented requests: return no data back to host */
59 }
60
61 ISR(TIMER1_COMPA_vect) {
62         buttonState.buttons = pollSnes();
63 }
64
65 void initTimer() {
66         // See section 15.11 for reference
67         // Using CTC mode (non-PWM)
68
69         // TCCR1A = 0b00000000 (No timer output, no PWM)
70         // TCCR1B = 0b00001010 (CTC mode, ckli_o/8)
71         // TCCR1C = 0b00000000 (No output compare)
72         TCCR1A = 0b00000000;
73         TCCR1B = 0b00001010;
74         TCCR1C = 0b00000000;
75         // {OCR1AH, OCR1AL} = 37500 = 10010010 01111100
76         // 37500 * 8 * 60 = 18MHz
77         OCR1AH = 0b10010010;
78         OCR1AL = 0b01111000;
79         // TIMSK1 = 0b00000010 (Enable interrupt on Output Compare A Match)
80         TIMSK1 = 0b00000010;
81 }
82
83 int main(void)
84 {
85         uchar i;
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!
89          */
90         
91         //DBG1(0x00, 0, 0);       /* debug output: main starts */
92         
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.
96          */
97         
98         // We need to setup the pin configuration for D3, which is an output pin 
99         
100
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
104         
105
106
107         //odDebugInit();
108         
109         usbInit();
110         usbDeviceDisconnect();  /* enforce re-enumeration, do this while interrupts are disabled! */
111         i = 0;
112         while(--i){             /* fake USB disconnect for > 250 ms */
113                 wdt_reset();
114                 _delay_ms(1);
115         }
116         usbDeviceConnect();
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 */
121                 wdt_reset();
122                 usbPoll();
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));
129                 }
130         }
131         return 0;
132 }
133