#include #include /* for sei() */ #include #include /* for _delay_ms() */ #include /* required by usbdrv.h */ #include "usbdrv.h" #include "oddebug.h" /* This is also an example for using debug macros */ #include "Wheel.h" /* ------------------------------------------------------------------------- */ /* ----------------------------- USB interface ----------------------------- */ /* ------------------------------------------------------------------------- */ PROGMEM const char usbHidReportDescriptor[52] = { /* USB report descriptor, size must match usbconfig.h */ 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x02, // USAGE (Mouse) 0xa1, 0x01, // COLLECTION (Application) 0x09, 0x01, // USAGE (Pointer) 0xA1, 0x00, // COLLECTION (Physical) 0x05, 0x09, // USAGE_PAGE (Button) 0x19, 0x01, // USAGE_MINIMUM 0x29, 0x03, // USAGE_MAXIMUM 0x15, 0x00, // LOGICAL_MINIMUM (0) 0x25, 0x01, // LOGICAL_MAXIMUM (1) 0x95, 0x03, // REPORT_COUNT (3) 0x75, 0x01, // REPORT_SIZE (1) 0x81, 0x02, // INPUT (Data,Var,Abs) 0x95, 0x01, // REPORT_COUNT (1) 0x75, 0x05, // REPORT_SIZE (5) 0x81, 0x03, // INPUT (Const,Var,Abs) 0x05, 0x01, // USAGE_PAGE (Generic Desktop) 0x09, 0x30, // USAGE (X) 0x09, 0x31, // USAGE (Y) 0x09, 0x38, // USAGE (Wheel) 0x15, 0x81, // LOGICAL_MINIMUM (-127) 0x25, 0x7F, // LOGICAL_MAXIMUM (127) 0x75, 0x08, // REPORT_SIZE (8) 0x95, 0x03, // REPORT_COUNT (3) 0x81, 0x06, // INPUT (Data,Var,Rel) 0xC0, // END_COLLECTION 0xC0, // END COLLECTION }; /* This is the same report descriptor as seen in a Logitech mouse. The data * described by this descriptor consists of 4 bytes: * . . . . . B2 B1 B0 .... one byte with mouse button states * X7 X6 X5 X4 X3 X2 X1 X0 .... 8 bit signed relative coordinate x * Y7 Y6 Y5 Y4 Y3 Y2 Y1 Y0 .... 8 bit signed relative coordinate y * W7 W6 W5 W4 W3 W2 W1 W0 .... 8 bit signed relative coordinate wheel */ typedef struct{ uchar buttonMask; char dx; char dy; char dWheel; }report_t; static report_t reportBuffer; static uchar idleRate; /* repeat rate for keyboards, never used for mice */ /* The following function advances sin/cos by a fixed angle * and stores the difference to the previous coordinates in the report * descriptor. * The algorithm is the simulation of a second order differential equation. */ // static void advanceCircleByFixedAngle(void) // { // char d; // #define DIVIDE_BY_64(val) (val + (val > 0 ? 32 : -32)) >> 6 /* rounding divide */ // reportBuffer.dx = d = DIVIDE_BY_64(cosinus); // sinus += d; // reportBuffer.dy = d = DIVIDE_BY_64(sinus); // cosinus -= d; // } static void read_Wheel(void) { reportBuffer.dx = 0; reportBuffer.dy = 0; reportBuffer.dWheel = 0; int Direction = (AnalogIn < 512) ? -1 : 1; // PORTD = 0; if (AnalogIn < LowerDead[Debounce] || AnalogIn > UpperDead[Debounce]) { if (Debounce == 1 || ticktock >= timing) { reportBuffer.dWheel = Direction; Debounce = 0; // ticktock = 0; // LEDs_ToggleLEDs(LEDS_LED2); } } else { if (Debounce == 0) { // PORTD = (1< timingtable_in[index]) { index++; } return timingtable_out[index]; } /* ------------------------------------------------------------------------- */ ISR(ADC_vect) { AnalogIn = ADC; timing = get_timing(ADC); } ISR(TIMER1_COMPA_vect) { // PINB |= _BV(PB1); if (ticktock > 0) { PINB |= _BV(PB1); usbPoll(); if(usbInterruptIsReady()) { // PINB |= (1< 250 ms */ wdt_reset(); _delay_ms(2); } usbDeviceConnect(); sei(); wdt_enable(WDTO_1S); } usbMsgLen_t usbFunctionSetup(uchar data[8]) { usbRequest_t *rq = (void *)data; /* The following requests are never used. But since they are required by * the specification, we implement them in this example. */ if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */ DBG1(0x50, &rq->bRequest, 1); /* debug output: print our request */ if(rq->bRequest == USBRQ_HID_GET_REPORT){ /* wValue: ReportType (highbyte), ReportID (lowbyte) */ /* we only have one report type, so don't look at wValue */ usbMsgPtr = (void *)&reportBuffer; return sizeof(reportBuffer); }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]; } }else{ /* no vendor specific requests implemented */ } return 0; /* default for not implemented requests: return no data back to host */ } // Called by V-USB after device reset void hadUsbReset() { int frameLength, targetLength = (unsigned)(1499 * (double)F_CPU / 10.5e6 + 0.5); int bestDeviation = 9999; uchar trialCal, bestCal, step, region; bestCal = 0; // do a binary search in regions 0-127 and 128-255 to get optimum OSCCAL for(region = 0; region <= 1; region++) { frameLength = 0; trialCal = (region == 0) ? 0 : 128; for(step = 64; step > 0; step >>= 1) { if(frameLength < targetLength) // true for initial iteration trialCal += step; // frequency too low else trialCal -= step; // frequency too high OSCCAL = trialCal; frameLength = usbMeasureFrameLength(); if(abs(frameLength-targetLength) < bestDeviation) { bestCal = trialCal; // new optimum found bestDeviation = abs(frameLength -targetLength); } } } OSCCAL = bestCal; } /* ------------------------------------------------------------------------- */ int main(void) { // uchar i; SetupHardware(); /* If you don't use the watchdog, replace the call above with a wdt_disable(). * On newer devices, the status of the watchdog (on/off, period) is PRESERVED * OVER RESET! */ /* RESET status: all port bits are inputs without pull-up. * That's the way we need D+ and D-. Therefore we don't need any * additional hardware initialization. */ // for (int a = 0; a<6; a++) // { // PINB |= _BV(PB1); // _delay_ms(500); // } for(;;){ /* main event loop */ // DBG1(0x02, 0, 0); /* debug output: main loop iterates */ // wdt_reset(); } return 0; } /* ------------------------------------------------------------------------- */