aboutsummaryrefslogtreecommitdiffstats
path: root/examples/hid-mouse
diff options
context:
space:
mode:
authorChristian Starkjohann <cs+github@obdev.at>2008-04-17 19:00:20 +0000
committerChristian Starkjohann <cs+github@obdev.at>2008-04-17 19:00:20 +0000
commit95ca3f5bd696b5450820929e1b1a444d02f0bd1e (patch)
tree70ac0161a0e4548acaf2f89d2ecb77132579ff7a /examples/hid-mouse
parent2f465daef9e6c5a6b7bda3074c050cd7e8515770 (diff)
downloadv-usb-95ca3f5bd696b5450820929e1b1a444d02f0bd1e.tar.gz
v-usb-95ca3f5bd696b5450820929e1b1a444d02f0bd1e.tar.bz2
v-usb-95ca3f5bd696b5450820929e1b1a444d02f0bd1e.zip
- imported new files into project
Diffstat (limited to 'examples/hid-mouse')
-rw-r--r--examples/hid-mouse/Readme.txt48
-rw-r--r--examples/hid-mouse/firmware/main.c165
-rwxr-xr-xexamples/hid-mouse/make-files.sh39
3 files changed, 252 insertions, 0 deletions
diff --git a/examples/hid-mouse/Readme.txt b/examples/hid-mouse/Readme.txt
new file mode 100644
index 0000000..1e269dc
--- /dev/null
+++ b/examples/hid-mouse/Readme.txt
@@ -0,0 +1,48 @@
+This is the Readme file for hid-mouse, an example of a USB mouse device. In
+order to have as little dependencies on hardware and architecture as
+possible, mouse movements are computed internally so that the mouse pointer
+moves in a circle.
+
+
+WHAT IS DEMONSTRATED?
+=====================
+This example demonstrates how HID class devices are implemented. The example
+is kept as simple as possible, except the report descriptor which is taken
+from a real-world mouse.
+
+It does NOT include a host side driver because all modern operating systems
+include one. It does NOT implement USBRQ_HID_SET_REPORT and report-IDs. See
+the "hid-data" example for this topic. It does NOT implement any special
+features such as suspend mode etc.
+
+
+PREREQUISITES
+=============
+Target hardware: You need an AVR based circuit based on one of the examples
+(see the "circuits" directory at the top level of this package), e.g. the
+metaboard (http://metalab.at/wiki/Metaboard).
+
+AVR development environment: You need the gcc tool chain for the AVR, see
+the Prerequisites section in the top level Readme file for how to obtain it.
+
+
+BUILDING THE FIRMWARE
+=====================
+Change to the "firmware" directory and modify Makefile according to your
+architecture (CPU clock, target device, fuse values) and ISP programmer. Then
+edit usbconfig.h according to your pin assignments for D+ and D-. The default
+settings are for the metaboard hardware.
+
+Type "make hex" to build main.hex, then "make flash" to upload the firmware
+to the device. Don't forget to run "make fuse" once to program the fuses. If
+you use a prototyping board with boot loader, follow the instructions of the
+boot loader instead.
+
+Please note that the first "make hex" copies the driver from the top level
+into the firmware directory. If you use a different build system than our
+Makefile, you must copy the driver by hand.
+
+
+----------------------------------------------------------------------------
+(c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH.
+http://www.obdev.at/
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;
+}
+
+/* ------------------------------------------------------------------------- */
diff --git a/examples/hid-mouse/make-files.sh b/examples/hid-mouse/make-files.sh
new file mode 100755
index 0000000..557350b
--- /dev/null
+++ b/examples/hid-mouse/make-files.sh
@@ -0,0 +1,39 @@
+#!/bin/sh
+# Author: Christian Starkjohann
+# Creation Date: 2008-04-17
+# Tabsize: 4
+# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
+# License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
+# This Revision: $Id$
+
+
+if [ "$1" = remove ]; then
+ (cd firmware; make clean)
+ rm -f firmware/usbconfig.h
+ rm -rf firmware/usbdrv
+ rm -f firmware/Makefile
+ exit
+fi
+
+cat << \EOF | sed -n -f /dev/stdin ../../usbdrv/usbconfig-prototype.h >firmware/usbconfig.h
+/^\( [*] \)\{0,1\}[+].*$/ d
+s/^#define USB_CFG_DMINUS_BIT .*$/#define USB_CFG_DMINUS_BIT 4/g
+s|^.*#define USB_CFG_CLOCK_KHZ.*$|#define USB_CFG_CLOCK_KHZ (F_CPU/1000)|g
+s/^#define USB_CFG_HAVE_INTRIN_ENDPOINT .*$/#define USB_CFG_HAVE_INTRIN_ENDPOINT 1/g
+s|^#define USB_CFG_DEVICE_ID .*$|#define USB_CFG_DEVICE_ID 0xdf, 0x05 /* obdev's shared PID for HIDs */|g
+s/^#define USB_CFG_DEVICE_NAME .*$/#define USB_CFG_DEVICE_NAME 'D', 'a', 't', 'a', 'S', 't', 'o', 'r', 'e'/g
+s/^#define USB_CFG_DEVICE_NAME_LEN .*$/#define USB_CFG_DEVICE_NAME_LEN 9/g
+
+s/^#define USB_CFG_INTR_POLL_INTERVAL .*$/#define USB_CFG_INTR_POLL_INTERVAL 100/g
+s/^#define USB_CFG_MAX_BUS_POWER .*$/#define USB_CFG_MAX_BUS_POWER 20/g
+s/^#define USB_CFG_DEVICE_CLASS .*$/#define USB_CFG_DEVICE_CLASS 0/g
+s/^#define USB_CFG_INTERFACE_CLASS .*$/#define USB_CFG_INTERFACE_CLASS 3/g
+s/^.*#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH.*$/#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 52/g
+p
+EOF
+
+cat << \EOF | sed -n -f /dev/stdin ../custom-class/firmware/Makefile >firmware/Makefile
+/^\( [*] \)\{0,1\}[+].*$/ d
+s/^# Project: .*$/# Project: hid-mouse example/g
+p
+EOF