diff options
Diffstat (limited to 'examples/hid-data')
-rw-r--r-- | examples/hid-data/Readme.txt | 75 | ||||
-rw-r--r-- | examples/hid-data/commandline/Makefile | 42 | ||||
-rw-r--r-- | examples/hid-data/commandline/Makefile.windows | 18 | ||||
-rw-r--r-- | examples/hid-data/commandline/hidtool.c | 127 | ||||
-rw-r--r-- | examples/hid-data/firmware/main.c | 141 | ||||
-rwxr-xr-x | examples/hid-data/make-files.sh | 45 |
6 files changed, 448 insertions, 0 deletions
diff --git a/examples/hid-data/Readme.txt b/examples/hid-data/Readme.txt new file mode 100644 index 0000000..4f925a8 --- /dev/null +++ b/examples/hid-data/Readme.txt @@ -0,0 +1,75 @@ +This is the Readme file for the hid-data example. In this example, we show +how blocks of data can be exchanged with the device using only functionality +compliant to the HID class. Since class drivers for HID are included with +Windows, you don't need to install drivers on Windows. + + +WHAT IS DEMONSTRATED? +===================== +This example demonstrates how the HID class can be misused to transfer fixed +size blocks of data (up to the driver's transfer size limit) over HID feature +reports. This technique is of great value on Windows because no driver DLLs +are needed (the hid-custom-rq example still requires the libusb-win32 DLL, +although it may be in the program's directory). The host side application +requires no installation, it can even be started directly from a CD. This +example also demonstrates how to transfer data using usbFunctionWrite() and +usbFunctionRead(). + + +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. + +Host development environment: A C compiler and libusb on Unix. On Windows +you need the Driver Development Kit (DDK) Instead of libusb. MinGW ships +with a free version of the DDK. + + +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. + + +BUILDING THE HOST SOFTWARE +========================== +Make sure that you have libusb (on Unix) or the DDK (on Windows) installed. +We recommend MinGW on Windows since it includes a free version of the DDK. +Then change to directory "commandline" and run "make" on Unix or +"make -f Makefile.windows" on Windows. + + +USING THE COMMAND LINE TOOL +=========================== +The device implements a data store of 128 bytes in EEPROM. You can send a +block of 128 bytes to the device or read the block using the command line +tool. + +To send a block to the device, use e.g. + + hidtool write 0x01,0x02,0x03,0x04,... + +and to receive the block, use + + hidtool read + + +---------------------------------------------------------------------------- +(c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH. +http://www.obdev.at/ diff --git a/examples/hid-data/commandline/Makefile b/examples/hid-data/commandline/Makefile new file mode 100644 index 0000000..97c6b06 --- /dev/null +++ b/examples/hid-data/commandline/Makefile @@ -0,0 +1,42 @@ +# Name: Makefile +# Project: hid-data example +# Author: Christian Starkjohann +# Creation Date: 2008-04-11 +# Tabsize: 4 +# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) +# This Revision: $Id$ + +# Please read the definitions below and edit them as appropriate for your +# system: + +# Use the following 3 lines on Unix and Mac OS X: +USBFLAGS= `libusb-config --cflags` +USBLIBS= `libusb-config --libs` +EXE_SUFFIX= + +# Use the following 3 lines on Windows and comment out the 3 above: +#USBFLAGS= +#USBLIBS= -lhid -lusb -lsetupapi +#EXE_SUFFIX= .exe + +CC= gcc +CFLAGS= -O -Wall $(USBFLAGS) +LIBS= $(USBLIBS) + +OBJ= hidtool.o hiddata.o +PROGRAM= hidtool$(EXE_SUFFIX) + +all: $(PROGRAM) + +$(PROGRAM): $(OBJ) + $(CC) -o $(PROGRAM) $(OBJ) $(LIBS) + +strip: $(PROGRAM) + strip $(PROGRAM) + +clean: + rm -f $(OBJ) $(PROGRAM) + +.c.o: + $(CC) $(ARCH_COMPILE) $(CFLAGS) -c $*.c -o $*.o diff --git a/examples/hid-data/commandline/Makefile.windows b/examples/hid-data/commandline/Makefile.windows new file mode 100644 index 0000000..f0e6cfa --- /dev/null +++ b/examples/hid-data/commandline/Makefile.windows @@ -0,0 +1,18 @@ +# Name: Makefile.windows +# Project: hid-data example +# Author: Christian Starkjohann +# Creation Date: 2008-04-11 +# Tabsize: 4 +# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH +# License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) +# This Revision: $Id$ + +# You may use this file with +# make -f Makefile.windows +# on Windows with MinGW instead of editing the main Makefile. + +include Makefile + +USBFLAGS= +USBLIBS= -lhid -lusb -lsetupapi +EXE_SUFFIX= .exe diff --git a/examples/hid-data/commandline/hidtool.c b/examples/hid-data/commandline/hidtool.c new file mode 100644 index 0000000..d03bca8 --- /dev/null +++ b/examples/hid-data/commandline/hidtool.c @@ -0,0 +1,127 @@ +/* Name: hidtool.c + * Project: hid-data example + * Author: Christian Starkjohann + * Creation Date: 2008-04-11 + * Tabsize: 4 + * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH + * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt) + * This Revision: $Id$ + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "hiddata.h" +#include "../firmware/usbconfig.h" /* for device VID, PID, vendor name and product name */ + +/* ------------------------------------------------------------------------- */ + +static char *usbErrorMessage(int errCode) +{ +static char buffer[80]; + + switch(errCode){ + case USBOPEN_ERR_ACCESS: return "Access to device denied"; + case USBOPEN_ERR_NOTFOUND: return "The specified device was not found"; + case USBOPEN_ERR_IO: return "Communication error with device"; + default: + sprintf(buffer, "Unknown USB error %d", errCode); + return buffer; + } + return NULL; /* not reached */ +} + +static usbDevice_t *openDevice(void) +{ +usbDevice_t *dev = NULL; +unsigned char rawVid[2] = {USB_CFG_VENDOR_ID}, rawPid[2] = {USB_CFG_DEVICE_ID}; +char vendorName[] = {USB_CFG_VENDOR_NAME, 0}, productName[] = {USB_CFG_DEVICE_NAME, 0}; +int vid = rawVid[0] + 256 * rawVid[1]; +int pid = rawPid[0] + 256 * rawPid[1]; +int err; + + if((err = usbhidOpenDevice(&dev, vid, vendorName, pid, productName, 0)) != 0){ + fprintf(stderr, "error finding %s: %s\n", productName, usbErrorMessage(err)); + return NULL; + } + return dev; +} + +/* ------------------------------------------------------------------------- */ + +static void hexdump(char *buffer, int len) +{ +int i; +FILE *fp = stdout; + + for(i = 0; i < len; i++){ + if(i != 0){ + if(i % 16 == 0){ + fprintf(fp, "\n"); + }else{ + fprintf(fp, " "); + } + } + fprintf(fp, "0x%02x", buffer[i] & 0xff); + } + if(i != 0) + fprintf(fp, "\n"); +} + +static int hexread(char *buffer, char *string, int buflen) +{ +char *s; +int pos = 0; + + while((s = strtok(string, ", ")) != NULL && pos < buflen){ + string = NULL; + buffer[pos++] = (char)strtol(s, NULL, 0); + } + return pos; +} + +/* ------------------------------------------------------------------------- */ + +static void usage(char *myName) +{ + fprintf(stderr, "usage:\n"); + fprintf(stderr, " %s read\n", myName); + fprintf(stderr, " %s write <listofbytes>\n", myName); +} + +int main(int argc, char **argv) +{ +usbDevice_t *dev; +char buffer[129]; /* room for dummy report ID */ +int err; + + if(argc < 2){ + usage(argv[0]); + exit(1); + } + if((dev = openDevice()) == NULL) + exit(1); + if(strcasecmp(argv[1], "read") == 0){ + int len = sizeof(buffer); + if((err = usbhidGetReport(dev, 0, buffer, &len)) != 0){ + fprintf(stderr, "error reading data: %s\n", usbErrorMessage(err)); + }else{ + hexdump(buffer + 1, sizeof(buffer) - 1); + } + }else if(strcasecmp(argv[1], "write") == 0){ + int i, pos; + bzero(buffer, sizeof(buffer)); + for(pos = 1, i = 2; i < argc && pos < sizeof(buffer); i++){ + pos += hexread(buffer + pos, argv[i], sizeof(buffer) - pos); + } + if((err = usbhidSetReport(dev, buffer, sizeof(buffer))) != 0) /* add a dummy report ID */ + fprintf(stderr, "error writing data: %s\n", usbErrorMessage(err)); + }else{ + usage(argv[0]); + exit(1); + } + usbhidCloseDevice(dev); + return 0; +} + +/* ------------------------------------------------------------------------- */ diff --git a/examples/hid-data/firmware/main.c b/examples/hid-data/firmware/main.c new file mode 100644 index 0000000..3ef68d5 --- /dev/null +++ b/examples/hid-data/firmware/main.c @@ -0,0 +1,141 @@ +/* Name: main.c + * Project: hid-data, example how to use HID for data transfer + * Author: Christian Starkjohann + * Creation Date: 2008-04-11 + * 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. +*/ + +#include <avr/io.h> +#include <avr/wdt.h> +#include <avr/interrupt.h> /* for sei() */ +#include <util/delay.h> /* for _delay_ms() */ +#include <avr/eeprom.h> + +#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[22] = { /* USB report descriptor */ + 0x06, 0x00, 0xff, // USAGE_PAGE (Generic Desktop) + 0x09, 0x01, // USAGE (Vendor Usage 1) + 0xa1, 0x01, // COLLECTION (Application) + 0x15, 0x00, // LOGICAL_MINIMUM (0) + 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) + 0x75, 0x08, // REPORT_SIZE (8) + 0x95, 0x80, // REPORT_COUNT (128) + 0x09, 0x00, // USAGE (Undefined) + 0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf) + 0xc0 // END_COLLECTION +}; +/* Since we define only one feature report, we don't use report-IDs (which + * would be the first byte of the report). The entire report consists of 128 + * opaque data bytes. + */ + +/* The following variables store the status of the current data transfer */ +static uchar currentAddress; +static uchar bytesRemaining; + +/* ------------------------------------------------------------------------- */ + +/* usbFunctionRead() is called when the host requests a chunk of data from + * the device. For more information see the documentation in usbdrv/usbdrv.h. + */ +uchar usbFunctionRead(uchar *data, uchar len) +{ + if(len > bytesRemaining) + len = bytesRemaining; + eeprom_read_block(data, (uchar *)0 + currentAddress, len); + currentAddress += len; + bytesRemaining -= len; + return len; +} + +/* usbFunctionWrite() is called when the host sends a chunk of data to the + * device. For more information see the documentation in usbdrv/usbdrv.h. + */ +uchar usbFunctionWrite(uchar *data, uchar len) +{ + if(bytesRemaining == 0) + return 1; /* end of transfer */ + if(len > bytesRemaining) + len = bytesRemaining; + eeprom_write_block(data, (uchar *)0 + currentAddress, len); + currentAddress += len; + bytesRemaining -= len; + return bytesRemaining == 0; /* return 1 if this was the last chunk */ +} + +/* ------------------------------------------------------------------------- */ + +uchar usbFunctionSetup(uchar data[8]) +{ +usbRequest_t *rq = (void *)data; + + if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* HID class request */ + if(rq->bRequest == USBRQ_HID_GET_REPORT){ /* wValue: ReportType (highbyte), ReportID (lowbyte) */ + /* since we have only one report type, we can ignore the report-ID */ + bytesRemaining = 128; + currentAddress = 0; + return 0xff; /* use usbFunctionRead() to obtain data */ + }else if(rq->bRequest == USBRQ_HID_SET_REPORT){ + /* since we have only one report type, we can ignore the report-ID */ + bytesRemaining = 128; + currentAddress = 0; + return 0xff; /* use usbFunctionWrite() to receive data from host */ + } + }else{ + /* ignore vendor type requests, we don't use any */ + } + return 0; +} + +/* ------------------------------------------------------------------------- */ + +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(); + } + return 0; +} + +/* ------------------------------------------------------------------------- */ diff --git a/examples/hid-data/make-files.sh b/examples/hid-data/make-files.sh new file mode 100755 index 0000000..a8d524c --- /dev/null +++ b/examples/hid-data/make-files.sh @@ -0,0 +1,45 @@ +#!/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 + rm -f commandline/hiddata.[ch] + rm -f commandline/hidsdi.h + 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_IMPLEMENT_FN_WRITE .*$/#define USB_CFG_IMPLEMENT_FN_WRITE 1/g +s/^#define USB_CFG_IMPLEMENT_FN_READ .*$/#define USB_CFG_IMPLEMENT_FN_READ 1/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 22/g +p +EOF + +cat << \EOF | sed -n -f /dev/stdin ../custom-class/firmware/Makefile >firmware/Makefile +/^\( [*] \)\{0,1\}[+].*$/ d +s/^# Project: .*$/# Project: hid-data example/g +p +EOF + +cp ../../libs-host/hiddata.[ch] ../../libs-host/hidsdi.h commandline |