|
1 /* Name: main.c |
|
2 * Project: hid-data, example how to use HID for data transfer |
|
3 * Author: Christian Starkjohann |
|
4 * Creation Date: 2008-04-11 |
|
5 * Tabsize: 4 |
|
6 * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH |
|
7 * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) |
|
8 */ |
|
9 |
|
10 /* |
|
11 This example should run on most AVRs with only little changes. No special |
|
12 hardware resources except INT0 are used. You may have to change usbconfig.h for |
|
13 different I/O pins for USB. Please note that USB D+ must be the INT0 pin, or |
|
14 at least be connected to INT0 as well. |
|
15 */ |
|
16 |
|
17 #include <avr/io.h> |
|
18 #include <avr/wdt.h> |
|
19 #include <avr/interrupt.h> /* for sei() */ |
|
20 #include <util/delay.h> /* for _delay_ms() */ |
|
21 #include <avr/eeprom.h> |
|
22 |
|
23 #include <avr/pgmspace.h> /* required by usbdrv.h */ |
|
24 #include "usbdrv.h" |
|
25 #include "oddebug.h" /* This is also an example for using debug macros */ |
|
26 |
|
27 /* ------------------------------------------------------------------------- */ |
|
28 /* ----------------------------- USB interface ----------------------------- */ |
|
29 /* ------------------------------------------------------------------------- */ |
|
30 |
|
31 PROGMEM const char usbHidReportDescriptor[22] = { /* USB report descriptor */ |
|
32 0x06, 0x00, 0xff, // USAGE_PAGE (Generic Desktop) |
|
33 0x09, 0x01, // USAGE (Vendor Usage 1) |
|
34 0xa1, 0x01, // COLLECTION (Application) |
|
35 0x15, 0x00, // LOGICAL_MINIMUM (0) |
|
36 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) |
|
37 0x75, 0x08, // REPORT_SIZE (8) |
|
38 0x95, 0x80, // REPORT_COUNT (128) |
|
39 0x09, 0x00, // USAGE (Undefined) |
|
40 0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf) |
|
41 0xc0 // END_COLLECTION |
|
42 }; |
|
43 /* Since we define only one feature report, we don't use report-IDs (which |
|
44 * would be the first byte of the report). The entire report consists of 128 |
|
45 * opaque data bytes. |
|
46 */ |
|
47 |
|
48 /* The following variables store the status of the current data transfer */ |
|
49 static uchar currentAddress; |
|
50 static uchar bytesRemaining; |
|
51 |
|
52 /* ------------------------------------------------------------------------- */ |
|
53 |
|
54 /* usbFunctionRead() is called when the host requests a chunk of data from |
|
55 * the device. For more information see the documentation in usbdrv/usbdrv.h. |
|
56 */ |
|
57 uchar usbFunctionRead(uchar *data, uchar len) |
|
58 { |
|
59 if(len > bytesRemaining) |
|
60 len = bytesRemaining; |
|
61 // eeprom_read_block(data, (uchar *)0 + currentAddress, len); |
|
62 currentAddress += len; |
|
63 bytesRemaining -= len; |
|
64 return len; |
|
65 } |
|
66 /* usbFunctionWrite() is called when the host sends a chunk of data to the |
|
67 * device. For more information see the documentation in usbdrv/usbdrv.h. |
|
68 */ |
|
69 uchar usbFunctionWrite(uchar *data, uchar len) |
|
70 { |
|
71 if(bytesRemaining == 0) |
|
72 return 1; /* end of transfer */ |
|
73 if(len > bytesRemaining) |
|
74 len = bytesRemaining; |
|
75 |
|
76 // eeprom_write_block(data, (uchar *)0 + currentAddress, len); |
|
77 uint8_t *tmp = data; |
|
78 OCR0A = *tmp; |
|
79 |
|
80 |
|
81 currentAddress += len; |
|
82 bytesRemaining -= len; |
|
83 return bytesRemaining == 0; /* return 1 if this was the last chunk */ |
|
84 } |
|
85 |
|
86 /* ------------------------------------------------------------------------- */ |
|
87 |
|
88 usbMsgLen_t usbFunctionSetup(uchar data[8]) |
|
89 { |
|
90 usbRequest_t *rq = (void *)data; |
|
91 |
|
92 if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* HID class request */ |
|
93 |
|
94 // if(rq->bRequest == USBRQ_HID_GET_REPORT){ /* wValue: ReportType (highbyte), ReportID (lowbyte) */ |
|
95 /* since we have only one report type, we can ignore the report-ID */ |
|
96 // bytesRemaining = 128; |
|
97 // currentAddress = 0; |
|
98 // return USB_NO_MSG; /* use usbFunctionRead() to obtain data */ |
|
99 // }else |
|
100 |
|
101 if(rq->bRequest == USBRQ_HID_SET_REPORT){ |
|
102 /* since we have only one report type, we can ignore the report-ID */ |
|
103 bytesRemaining = 1; |
|
104 currentAddress = 0; |
|
105 return USB_NO_MSG; /* use usbFunctionWrite() to receive data from host */ |
|
106 } |
|
107 }else{ |
|
108 /* ignore vendor type requests, we don't use any */ |
|
109 } |
|
110 return 0; |
|
111 } |
|
112 |
|
113 /* ------------------------------------------------------------------------- */ |
|
114 |
|
115 int main(void) |
|
116 { |
|
117 uchar i; |
|
118 |
|
119 wdt_enable(WDTO_1S); |
|
120 /* Even if you don't use the watchdog, turn it off here. On newer devices, |
|
121 * the status of the watchdog (on/off, period) is PRESERVED OVER RESET! |
|
122 */ |
|
123 /* RESET status: all port bits are inputs without pull-up. |
|
124 * That's the way we need D+ and D-. Therefore we don't need any |
|
125 * additional hardware initialization. |
|
126 */ |
|
127 //odDebugInit(); |
|
128 //DBG1(0x00, 0, 0); /* debug output: main starts */ |
|
129 usbInit(); |
|
130 usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */ |
|
131 i = 0; |
|
132 while(--i){ /* fake USB disconnect for > 250 ms */ |
|
133 wdt_reset(); |
|
134 _delay_ms(1); |
|
135 } |
|
136 usbDeviceConnect(); |
|
137 |
|
138 DDRB |= (1 << PB2); // PWM output on PB2 |
|
139 TCCR0A = (1 << COM0A1) | (1 << WGM00); // phase correct PWM mode |
|
140 OCR0A = 0x10; // initial PWM pulse width |
|
141 TCCR0B = (1 << CS01); // clock source = CLK/8, start PWM |
|
142 |
|
143 sei(); |
|
144 //DBG1(0x01, 0, 0); /* debug output: main loop starts */ |
|
145 for(;;){ /* main event loop */ |
|
146 //DBG1(0x02, 0, 0); /* debug output: main loop iterates */ |
|
147 wdt_reset(); |
|
148 usbPoll(); |
|
149 } |
|
150 return 0; |
|
151 } |
|
152 |
|
153 /* ------------------------------------------------------------------------- */ |