[4b06930] | 1 | #include <avr/io.h>
|
---|
| 2 | #include <avr/interrupt.h>
|
---|
| 3 | #include <avr/wdt.h>
|
---|
| 4 | #include <avr/pgmspace.h>
|
---|
| 5 | #include <util/delay.h>
|
---|
| 6 |
|
---|
| 7 | #include <string.h>
|
---|
| 8 | #include <stdbool.h>
|
---|
| 9 |
|
---|
| 10 | #include "usbdrv/usbdrv.h"
|
---|
| 11 |
|
---|
[bf42f57] | 12 | static uint8_t reportBuffer[5];
|
---|
[4b06930] | 13 | static uint8_t idleRate;
|
---|
| 14 |
|
---|
[bf42f57] | 15 | void main() {
|
---|
[4b06930] | 16 | uint8_t idleCounter = 0;
|
---|
| 17 |
|
---|
| 18 | wdt_enable(WDTO_2S);
|
---|
| 19 |
|
---|
| 20 | // USB
|
---|
| 21 | usbInit();
|
---|
| 22 | sei();
|
---|
[bf42f57] | 23 | bool doReport;
|
---|
| 24 |
|
---|
| 25 | DDRB = 0; // Keyboard matrix out
|
---|
| 26 | PORTB = 255; // Enable pull up
|
---|
| 27 | // We put all pins as input then output a 0 in only one at a time.
|
---|
| 28 | // All the other pins are high-Z to avoid short circuits when many buttons are pressed.
|
---|
| 29 | DDRC = 0; // Keyboard matrix in
|
---|
| 30 | PORTC = 255; // Enable pull up
|
---|
[4b06930] | 31 |
|
---|
[bf42f57] | 32 | // configure timer 0 for a rate of 16M/(256 * 256) = ~244Hz
|
---|
| 33 | TCCR0 = 4; // timer 0 prescaler: 256
|
---|
| 34 |
|
---|
[4b06930] | 35 | while(1) {
|
---|
| 36 | wdt_reset();
|
---|
| 37 | usbPoll();
|
---|
| 38 |
|
---|
[bf42f57] | 39 | doReport = false;
|
---|
| 40 | for(int i=0; i < 5; i++) {
|
---|
| 41 | DDRB = ~(1<<i);
|
---|
| 42 | PORTB = ~(1<<i);
|
---|
| 43 | reportBuffer[i] = (~PINC)&0x3F;
|
---|
[4b06930] | 44 | }
|
---|
| 45 |
|
---|
[bf42f57] | 46 | DDRB = ~(1<<5);
|
---|
| 47 | PORTB = ~(1<<5);
|
---|
| 48 | reportBuffer[0] |= (~PINC)<<6 & 0xC0;
|
---|
| 49 | reportBuffer[1] |= (~PINC)<<4 & 0xC0;
|
---|
| 50 | reportBuffer[2] |= (~PINC)<<2 & 0xC0;
|
---|
| 51 | // reportBuffer[3] |= (~PINC)<<0 & 0xC0; // These are not existing pins...
|
---|
| 52 |
|
---|
| 53 | DDRB = 255;
|
---|
| 54 | PORTB = 255;
|
---|
| 55 |
|
---|
| 56 | if (usbInterruptIsReady()) {
|
---|
[4b06930] | 57 | usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
|
---|
[bf42f57] | 58 | // LEDOFF;
|
---|
[4b06930] | 59 | doReport = false;
|
---|
| 60 | }
|
---|
| 61 |
|
---|
| 62 | if (TIFR & (1 << TOV0)) {
|
---|
| 63 | TIFR = (1 << TOV0); // reset flag
|
---|
| 64 |
|
---|
[bf42f57] | 65 | if(++idleCounter > 4){ // yes, but not yet
|
---|
[4b06930] | 66 | idleCounter -= 5; // 22ms in units of 4ms
|
---|
| 67 | } else { // yes, it is time now
|
---|
| 68 | idleCounter = idleRate;
|
---|
[bf42f57] | 69 | if (usbInterruptIsReady()) {
|
---|
[4b06930] | 70 | usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
|
---|
| 71 | }
|
---|
| 72 | }
|
---|
| 73 | }
|
---|
| 74 | }
|
---|
| 75 | }
|
---|
| 76 |
|
---|
[bf42f57] | 77 |
|
---|
[4b06930] | 78 | static uint8_t protocolVer = 1;
|
---|
| 79 | uint8_t expectReport = 0;
|
---|
| 80 |
|
---|
| 81 |
|
---|
| 82 | char PROGMEM usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {
|
---|
[bf42f57] | 83 | 0x05, 0x01, // USAGE_PAGE (Generic Desktop)
|
---|
| 84 | 0x09, 0x05, // USAGE (Game Pad)
|
---|
| 85 | 0xa1, 0x01, // COLLECTION (Application)
|
---|
| 86 | 0x09, 0x01, // USAGE (Pointer)
|
---|
| 87 | 0xa1, 0x00, // COLLECTION (Physical)
|
---|
| 88 | 0x09, 0x30, // USAGE (X)
|
---|
| 89 | 0x09, 0x31, // USAGE (Y)
|
---|
| 90 | 0x15, 0xff, // LOGICAL_MINIMUM (-1)
|
---|
| 91 | 0x25, 0x01, // LOGICAL_MAXIMUM (1)
|
---|
| 92 | 0x75, 0x02, // REPORT_SIZE (2)
|
---|
| 93 | 0x95, 0x02, // REPORT_COUNT (2)
|
---|
| 94 | 0x81, 0x02, // INPUT (Data,Var,Abs)
|
---|
| 95 | 0xc0, // END_COLLECTION
|
---|
| 96 | 0x05, 0x09, // USAGE_PAGE (Button)
|
---|
| 97 | 0x19, 0x01, // USAGE_MINIMUM (Button 1)
|
---|
| 98 | 0x29, 0x24, // USAGE_MAXIMUM (Button 36)
|
---|
| 99 | 0x15, 0x00, // LOGICAL_MINIMUM (0)
|
---|
| 100 | 0x25, 0x01, // LOGICAL_MAXIMUM (1)
|
---|
| 101 | 0x75, 0x01, // REPORT_SIZE (1)
|
---|
| 102 | 0x95, 0x24, // REPORT_COUNT (36)
|
---|
| 103 | 0x81, 0x02, // INPUT (Data,Var,Abs)
|
---|
| 104 | 0xc0 // END_COLLECTION
|
---|
[4b06930] | 105 | };
|
---|
| 106 |
|
---|
| 107 |
|
---|
| 108 | uint8_t usbFunctionSetup(uint8_t data[8]) {
|
---|
| 109 | usbRequest_t *rq = (void *)data;
|
---|
| 110 | usbMsgPtr = reportBuffer;
|
---|
| 111 | if ((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS) {
|
---|
| 112 | // class request type
|
---|
| 113 | if (rq->bRequest == USBRQ_HID_GET_REPORT) {
|
---|
| 114 | // wValue: ReportType (highbyte), ReportID (lowbyte)
|
---|
| 115 | // we only have one report type, so don't look at wValue
|
---|
| 116 | return sizeof(reportBuffer);
|
---|
| 117 | } else if (rq->bRequest == USBRQ_HID_SET_REPORT) {
|
---|
| 118 | if (rq->wLength.word == 1) {
|
---|
| 119 | // We expect one byte reports
|
---|
| 120 | expectReport = 1;
|
---|
| 121 | return 0xff; // Call usbFunctionWrite with data
|
---|
| 122 | }
|
---|
| 123 | } else if (rq->bRequest == USBRQ_HID_GET_IDLE) {
|
---|
| 124 | usbMsgPtr = &idleRate;
|
---|
| 125 | return 1;
|
---|
| 126 | } else if (rq->bRequest == USBRQ_HID_SET_IDLE) {
|
---|
| 127 | idleRate = rq->wValue.bytes[1];
|
---|
| 128 | } else if (rq->bRequest == USBRQ_HID_GET_PROTOCOL) {
|
---|
| 129 | if (rq->wValue.bytes[1] < 1) {
|
---|
| 130 | protocolVer = rq->wValue.bytes[1];
|
---|
| 131 | }
|
---|
| 132 | } else if(rq->bRequest == USBRQ_HID_SET_PROTOCOL) {
|
---|
| 133 | usbMsgPtr = &protocolVer;
|
---|
| 134 | return 1;
|
---|
| 135 | }
|
---|
| 136 | } else {
|
---|
| 137 | // no vendor specific requests implemented
|
---|
| 138 | }
|
---|
| 139 | return 0;
|
---|
| 140 | }
|
---|
| 141 |
|
---|
| 142 | uint8_t usbFunctionWrite(uchar *data, uchar len) {
|
---|
| 143 | expectReport = 0;
|
---|
| 144 | return 0x01;
|
---|
| 145 | }
|
---|
| 146 |
|
---|