diff options
Diffstat (limited to 'examples/hid-mouse/firmware')
-rw-r--r-- | examples/hid-mouse/firmware/main.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/examples/hid-mouse/firmware/main.c b/examples/hid-mouse/firmware/main.c new file mode 100644 index 0000000..0f3fd42 --- /dev/null +++ b/examples/hid-mouse/firmware/main.c @@ -0,0 +1,165 @@ +/* Name: main.c + * Project: hid-mouse, a very simple HID example + * Author: Christian Starkjohann + * Creation Date: 2008-04-07 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) + * This Revision: $Id$ + */ + +/* +This example should run on most AVRs with only little changes. No special +hardware resources except INT0 are used. You may have to change usbconfig.h for +different I/O pins for USB. Please note that USB D+ must be the INT0 pin, or +at least be connected to INT0 as well. + +We use VID/PID 0x046D/0xC00E which is taken from a Logitech mouse. Don't +publish any hardware using these IDs! This is for demonstration only! +*/ + +#include <avr/io.h> +#include <avr/wdt.h> +#include <avr/interrupt.h> /* for sei() */ +#include <util/delay.h> /* for _delay_ms() */ + +#include <avr/pgmspace.h> /* required by usbdrv.h */ +#include "usbdrv.h" +#include "oddebug.h" /* This is also an example for using debug macros */ + +/* ------------------------------------------------------------------------- */ +/* ----------------------------- USB interface ----------------------------- */ +/* ------------------------------------------------------------------------- */ + +PROGMEM 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 int sinus = 7 << 6, cosinus = 0; +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; +} + +/* ------------------------------------------------------------------------- */ + +uchar 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 */ +} + +/* ------------------------------------------------------------------------- */ + +int main(void) +{ +uchar i; + + wdt_enable(WDTO_1S); + /* Even if you don't use the watchdog, turn it off here. On newer devices, + * the status of the watchdog (on/off, period) is PRESERVED OVER RESET! + */ + DBG1(0x00, 0, 0); /* debug output: main starts */ + /* 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. + */ + odDebugInit(); + usbInit(); + usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */ + i = 0; + while(--i){ /* fake USB disconnect for > 250 ms */ + wdt_reset(); + _delay_ms(1); + } + usbDeviceConnect(); + sei(); + DBG1(0x01, 0, 0); /* debug output: main loop starts */ + for(;;){ /* main event loop */ + DBG1(0x02, 0, 0); /* debug output: main loop iterates */ + wdt_reset(); + usbPoll(); + if(usbInterruptIsReady()){ + /* called after every poll of the interrupt endpoint */ + advanceCircleByFixedAngle(); + DBG1(0x03, 0, 0); /* debug output: interrupt report prepared */ + usbSetInterrupt((void *)&reportBuffer, sizeof(reportBuffer)); + } + } + return 0; +} + +/* ------------------------------------------------------------------------- */ |