aboutsummaryrefslogtreecommitdiffstats
path: root/examples/custom-class
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/custom-class
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/custom-class')
-rw-r--r--examples/custom-class/Readme.txt64
-rw-r--r--examples/custom-class/commandline/set-led.c84
-rw-r--r--examples/custom-class/firmware/Makefile164
-rw-r--r--examples/custom-class/firmware/main.c91
-rw-r--r--examples/custom-class/firmware/requests.h32
-rwxr-xr-xexamples/custom-class/make-files.sh44
6 files changed, 479 insertions, 0 deletions
diff --git a/examples/custom-class/Readme.txt b/examples/custom-class/Readme.txt
new file mode 100644
index 0000000..82b1b3e
--- /dev/null
+++ b/examples/custom-class/Readme.txt
@@ -0,0 +1,64 @@
+This is the Readme file for the custom-class example. In this example, we
+show how an LED can be controlled via USB.
+
+
+WHAT IS DEMONSTRATED?
+=====================
+This example shows how small amounts of data (several bytes) can be
+transferred between the device and the host. In addition to a very basic
+USB device, it demonstrates how to build a host side driver application
+using libusb or libusb-win32. It does NOT show how usbFunctionWrite() and
+usbFunctionRead() are used. See the hid-data example if you want to learn
+about these functions.
+
+
+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. See the top level
+Readme file, section Prerequisites for more information.
+
+
+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. You should have wired an LED with a
+current limiting resistor of ca. 270 Ohm to a free I/O pin. Change the
+defines in main.c to match the port and bit number.
+
+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
+==========================
+Since the host software is based on libusb or libusb-win32, make sure that
+this library is installed. On Unix, ensure that libusb-config is in your
+search PATH. On Windows, edit Makefile.windows and set the library path
+appropriately. Then type "make" on Unix or "make -f Makefile.windows" on
+Windows to build the command line tool.
+
+
+USING THE COMMAND LINE TOOL
+===========================
+The command line tool has three valid arguments: "status" to query the
+current LED status, "on" to turn on the LED and "off" to turn it off.
+
+
+----------------------------------------------------------------------------
+(c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH.
+http://www.obdev.at/
diff --git a/examples/custom-class/commandline/set-led.c b/examples/custom-class/commandline/set-led.c
new file mode 100644
index 0000000..07ba094
--- /dev/null
+++ b/examples/custom-class/commandline/set-led.c
@@ -0,0 +1,84 @@
+/* Name: set-led.c
+ * Project: custom-class, a basic USB example
+ * Author: Christian Starkjohann
+ * Creation Date: 2008-04-10
+ * Tabsize: 4
+ * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
+ * License: GNU GPL v2 (see License.txt) or proprietary (CommercialLicense.txt)
+ * This Revision: $Id$
+ */
+
+/*
+General Description:
+This is the host-side driver for the custom-class example device. It searches
+the USB for the LEDControl device and sends the requests understood by this
+device.
+This program must be linked with libusb on Unix and libusb-win32 on Windows.
+See http://libusb.sourceforge.net/ or http://libusb-win32.sourceforge.net/
+respectively.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <usb.h> /* this is libusb */
+#include "opendevice.h" /* common code moved to separate module */
+
+#include "../firmware/requests.h" /* custom request numbers */
+#include "../firmware/usbconfig.h" /* device's VID/PID and names */
+
+static void usage(char *name)
+{
+ fprintf(stderr, "usage:\n");
+ fprintf(stderr, " %s on ....... turn on LED\n", name);
+ fprintf(stderr, " %s off ...... turn off LED\n", name);
+ fprintf(stderr, " %s status ... ask current status of LED\n", name);
+}
+
+int main(int argc, char **argv)
+{
+usb_dev_handle *handle = NULL;
+const unsigned char rawVid[2] = {USB_CFG_VENDOR_ID}, rawPid[2] = {USB_CFG_DEVICE_ID};
+char vendor[] = {USB_CFG_VENDOR_NAME, 0}, product[] = {USB_CFG_DEVICE_NAME, 0};
+char buffer[1];
+int cnt, vid, pid, isOn;
+
+ usb_init();
+ if(argc < 2){ /* we need at least one argument */
+ usage(argv[0]);
+ exit(1);
+ }
+ /* compute VID/PID from usbconfig.h so that there is a central source of information */
+ vid = rawVid[1] * 256 + rawVid[0];
+ pid = rawPid[1] * 256 + rawPid[0];
+ /* The following function is in opendevice.c: */
+ if(usbOpenDevice(&handle, vid, vendor, pid, product, NULL, NULL, NULL) != 0){
+ fprintf(stderr, "Could not find USB device \"%s\" with vid=0x%x pid=0x%x\n", product, vid, pid);
+ exit(1);
+ }
+ /* Since we use only control endpoint 0, we don't need to choose a
+ * configuration and interface.
+ */
+ if(strcasecmp(argv[1], "status") == 0){
+ cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CUSTOM_RQ_GET_STATUS, 0, 0, buffer, sizeof(buffer), 5000);
+ if(cnt < 1){
+ if(cnt < 0){
+ fprintf(stderr, "USB error: %s\n", usb_strerror());
+ }else{
+ fprintf(stderr, "only %d bytes received.\n", cnt);
+ }
+ }else{
+ printf("LED is %s\n", buffer[0] ? "on" : "off");
+ }
+ }else if((isOn = (strcasecmp(argv[1], "on") == 0)) || strcasecmp(argv[1], "off") == 0){
+ cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, CUSTOM_RQ_SET_STATUS, isOn, 0, buffer, 0, 5000);
+ if(cnt < 0){
+ fprintf(stderr, "USB error: %s\n", usb_strerror());
+ }
+ }else{
+ usage(argv[0]);
+ exit(1);
+ }
+ usb_close(handle);
+ return 0;
+}
diff --git a/examples/custom-class/firmware/Makefile b/examples/custom-class/firmware/Makefile
new file mode 100644
index 0000000..51474ba
--- /dev/null
+++ b/examples/custom-class/firmware/Makefile
@@ -0,0 +1,164 @@
+# Name: Makefile
+# Project: custom-class 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$
+
+DEVICE = atmega168
+F_CPU = 16000000 # in Hz
+FUSE_L = # see below for fuse values for particular devices
+FUSE_H =
+AVRDUDE = avrdude -c usbasp -p $(DEVICE) # edit this line for your programmer
+
+CFLAGS = -Iusbdrv -I. -DDEBUG_LEVEL=0
+OBJECTS = usbdrv/usbdrv.o usbdrv/usbdrvasm.o usbdrv/oddebug.o main.o
+
+COMPILE = avr-gcc -Wall -Os -DF_CPU=$(F_CPU) $(CFLAGS) -mmcu=$(DEVICE)
+
+##############################################################################
+# Fuse values for particular devices
+##############################################################################
+# If your device is not listed here, go to
+# http://palmavr.sourceforge.net/cgi-bin/fc.cgi
+# and choose options for external crystal clock and no clock divider
+#
+################################## ATMega8 ##################################
+# ATMega8 FUSE_L (Fuse low byte):
+# 0x9f = 1 0 0 1 1 1 1 1
+# ^ ^ \ / \--+--/
+# | | | +------- CKSEL 3..0 (external >8M crystal)
+# | | +--------------- SUT 1..0 (crystal osc, BOD enabled)
+# | +------------------ BODEN (BrownOut Detector enabled)
+# +-------------------- BODLEVEL (2.7V)
+# ATMega8 FUSE_H (Fuse high byte):
+# 0xc9 = 1 1 0 0 1 0 0 1 <-- BOOTRST (boot reset vector at 0x0000)
+# ^ ^ ^ ^ ^ ^ ^------ BOOTSZ0
+# | | | | | +-------- BOOTSZ1
+# | | | | + --------- EESAVE (don't preserve EEPROM over chip erase)
+# | | | +-------------- CKOPT (full output swing)
+# | | +---------------- SPIEN (allow serial programming)
+# | +------------------ WDTON (WDT not always on)
+# +-------------------- RSTDISBL (reset pin is enabled)
+#
+############################## ATMega48/88/168 ##############################
+# ATMega*8 FUSE_L (Fuse low byte):
+# 0xdf = 1 1 0 1 1 1 1 1
+# ^ ^ \ / \--+--/
+# | | | +------- CKSEL 3..0 (external >8M crystal)
+# | | +--------------- SUT 1..0 (crystal osc, BOD enabled)
+# | +------------------ CKOUT (if 0: Clock output enabled)
+# +-------------------- CKDIV8 (if 0: divide by 8)
+# ATMega*8 FUSE_H (Fuse high byte):
+# 0xde = 1 1 0 1 1 1 1 0
+# ^ ^ ^ ^ ^ \-+-/
+# | | | | | +------ BODLEVEL 0..2 (110 = 1.8 V)
+# | | | | + --------- EESAVE (preserve EEPROM over chip erase)
+# | | | +-------------- WDTON (if 0: watchdog always on)
+# | | +---------------- SPIEN (allow serial programming)
+# | +------------------ DWEN (debug wire enable)
+# +-------------------- RSTDISBL (reset pin is enabled)
+#
+############################## ATTiny25/45/85 ###############################
+# ATMega*5 FUSE_L (Fuse low byte):
+# 0xef = 1 1 1 0 1 1 1 1
+# ^ ^ \+/ \--+--/
+# | | | +------- CKSEL 3..0 (clock selection -> crystal @ 12 MHz)
+# | | +--------------- SUT 1..0 (BOD enabled, fast rising power)
+# | +------------------ CKOUT (clock output on CKOUT pin -> disabled)
+# +-------------------- CKDIV8 (divide clock by 8 -> don't divide)
+# ATMega*5 FUSE_H (Fuse high byte):
+# 0xdd = 1 1 0 1 1 1 0 1
+# ^ ^ ^ ^ ^ \-+-/
+# | | | | | +------ BODLEVEL 2..0 (brownout trigger level -> 2.7V)
+# | | | | +---------- EESAVE (preserve EEPROM on Chip Erase -> not preserved)
+# | | | +-------------- WDTON (watchdog timer always on -> disable)
+# | | +---------------- SPIEN (enable serial programming -> enabled)
+# | +------------------ DWEN (debug wire enable)
+# +-------------------- RSTDISBL (disable external reset -> enabled)
+#
+################################ ATTiny2313 #################################
+# ATTiny2313 FUSE_L (Fuse low byte):
+# 0xef = 1 1 1 0 1 1 1 1
+# ^ ^ \+/ \--+--/
+# | | | +------- CKSEL 3..0 (clock selection -> crystal @ 12 MHz)
+# | | +--------------- SUT 1..0 (BOD enabled, fast rising power)
+# | +------------------ CKOUT (clock output on CKOUT pin -> disabled)
+# +-------------------- CKDIV8 (divide clock by 8 -> don't divide)
+# ATTiny2313 FUSE_H (Fuse high byte):
+# 0xdb = 1 1 0 1 1 0 1 1
+# ^ ^ ^ ^ \-+-/ ^
+# | | | | | +---- RSTDISBL (disable external reset -> enabled)
+# | | | | +-------- BODLEVEL 2..0 (brownout trigger level -> 2.7V)
+# | | | +-------------- WDTON (watchdog timer always on -> disable)
+# | | +---------------- SPIEN (enable serial programming -> enabled)
+# | +------------------ EESAVE (preserve EEPROM on Chip Erase -> not preserved)
+# +-------------------- DWEN (debug wire enable)
+
+
+# symbolic targets:
+help:
+ @echo "This Makefile has no default rule. Use one of the following:"
+ @echo "make hex ....... to build main.hex"
+ @echo "make program ... to flash fuses and firmware"
+ @echo "make fuse ...... to flash the fuses"
+ @echo "make flash ..... to flash the firmware (use this on metaboard)"
+ @echo "make clean ..... to delete objects and hex file"
+
+hex: main.hex
+
+program: flash fuse
+
+# rule for programming fuse bits:
+fuse:
+ @[ "$(FUSE_H)" != "" -a "$(FUSE_L)" != "" ] || \
+ { echo "*** Edit Makefile and choose values for FUSE_L and FUSE_H!"; exit 1; }
+ $(AVRDUDE) -U hfuse:w:$(FUSE_H):m -U lfuse:w:$(FUSE_L):m
+
+# rule for uploading firmware:
+flash: main.hex
+ $(AVRDUDE) -U flash:w:main.hex:i
+
+# rule for deleting dependent files (those which can be built by Make):
+clean:
+ rm -f main.hex main.lst main.obj main.cof main.list main.map main.eep.hex main.elf *.o usbdrv/*.o main.s usbdrv/oddebug.s usbdrv/usbdrv.s
+
+# Generic rule for compiling C files:
+.c.o:
+ $(COMPILE) -c $< -o $@
+
+# Generic rule for assembling Assembler source files:
+.S.o:
+ $(COMPILE) -x assembler-with-cpp -c $< -o $@
+# "-x assembler-with-cpp" should not be necessary since this is the default
+# file type for the .S (with capital S) extension. However, upper case
+# characters are not always preserved on Windows. To ensure WinAVR
+# compatibility define the file type manually.
+
+# Generic rule for compiling C to assembler, used for debugging only.
+.c.s:
+ $(COMPILE) -S $< -o $@
+
+# file targets:
+
+# Since we don't want to ship the driver multipe times, we copy it into this project:
+usbdrv:
+ cp -r ../../../usbdrv .
+
+main.elf: usbdrv $(OBJECTS) # usbdrv dependency only needed because we copy it
+ $(COMPILE) -o main.elf $(OBJECTS)
+
+main.hex: main.elf
+ rm -f main.hex main.eep.hex
+ avr-objcopy -j .text -j .data -O ihex main.elf main.hex
+ avr-size main.hex
+
+# debugging targets:
+
+disasm: main.elf
+ avr-objdump -d main.elf
+
+cpp:
+ $(COMPILE) -E main.c
diff --git a/examples/custom-class/firmware/main.c b/examples/custom-class/firmware/main.c
new file mode 100644
index 0000000..2d93db9
--- /dev/null
+++ b/examples/custom-class/firmware/main.c
@@ -0,0 +1,91 @@
+/* Name: main.c
+ * Project: custom-class, a basic USB example
+ * Author: Christian Starkjohann
+ * Creation Date: 2008-04-09
+ * 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 assume that an LED is connected to port B bit 0. If you connect it to a
+different port or bit, change the macros below:
+*/
+#define LED_PORT_DDR DDRB
+#define LED_PORT_OUTPUT PORTB
+#define LED_BIT 0
+
+#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 */
+#include "requests.h" /* The custom request numbers we use */
+
+/* ------------------------------------------------------------------------- */
+/* ----------------------------- USB interface ----------------------------- */
+/* ------------------------------------------------------------------------- */
+
+uchar usbFunctionSetup(uchar data[8])
+{
+usbRequest_t *rq = (void *)data;
+
+ if(rq->bRequest == CUSTOM_RQ_SET_STATUS){
+ if(rq->wValue.bytes[0] & 1){ /* set LED */
+ LED_PORT_OUTPUT |= _BV(LED_BIT);
+ }else{ /* clear LED */
+ LED_PORT_OUTPUT &= ~_BV(LED_BIT);
+ }
+ }else if(rq->bRequest == CUSTOM_RQ_GET_STATUS){
+ static uchar dataBuffer[1]; /* buffer must stay valid when usbFunctionSetup returns */
+ dataBuffer[0] = ((LED_PORT_OUTPUT & _BV(LED_BIT)) != 0);
+ usbMsgPtr = dataBuffer; /* tell the driver which data to return */
+ return 1; /* tell the driver to send 1 byte */
+ }
+ 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();
+ LED_PORT_DDR |= _BV(LED_BIT); /* make the LED bit an output */
+ 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/custom-class/firmware/requests.h b/examples/custom-class/firmware/requests.h
new file mode 100644
index 0000000..b6a3c2b
--- /dev/null
+++ b/examples/custom-class/firmware/requests.h
@@ -0,0 +1,32 @@
+/* Name: requests.h
+ * Project: custom-class, a basic USB example
+ * Author: Christian Starkjohann
+ * Creation Date: 2008-04-09
+ * 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 header is shared between the firmware and the host software. It
+ * defines the USB request numbers (and optionally data types) used to
+ * communicate between the host and the device.
+ */
+
+#ifndef __REQUESTS_H_INCLUDED__
+#define __REQUESTS_H_INCLUDED__
+
+#define CUSTOM_RQ_SET_STATUS 1
+/* Set the LED status. Control-OUT.
+ * The requested status is passed in the "wValue" field of the control
+ * transfer. No OUT data is sent. Bit 0 of the low byte of wValue controls
+ * the LED.
+ */
+
+#define CUSTOM_RQ_GET_STATUS 2
+/* Get the current LED status. Control-IN.
+ * This control transfer involves a 1 byte data phase where the device sends
+ * the current status to the host. The status is in bit 0 of the byte.
+ */
+
+#endif /* __REQUESTS_H_INCLUDED__ */
diff --git a/examples/custom-class/make-files.sh b/examples/custom-class/make-files.sh
new file mode 100755
index 0000000..f6670fa
--- /dev/null
+++ b/examples/custom-class/make-files.sh
@@ -0,0 +1,44 @@
+#!/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 commandline/Makefile.windows
+ rm -f commandline/Makefile
+ rm -f commandline/opendevice.[ch]
+ 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_DEVICE_NAME .*$/#define USB_CFG_DEVICE_NAME 'L', 'E', 'D', 'C', 'o', 'n', 't', 'r', 'o', 'l'/g
+s/^#define USB_CFG_DEVICE_NAME_LEN .*$/#define USB_CFG_DEVICE_NAME_LEN 10/g
+
+s/^#define USB_CFG_MAX_BUS_POWER .*$/#define USB_CFG_MAX_BUS_POWER 40/g
+p
+EOF
+
+cat << \EOF | sed -n -f /dev/stdin ../usbtool/Makefile.windows >commandline/Makefile.windows
+/^\( [*] \)\{0,1\}[+].*$/ d
+s/^# Project: .*$/# Project: custom-class example/g
+p
+EOF
+
+cat << \EOF | sed -n -f /dev/stdin ../usbtool/Makefile >commandline/Makefile
+/^\( [*] \)\{0,1\}[+].*$/ d
+s/^# Project: .*$/# Project: custom-class example/g
+s/^NAME = .*$/NAME = set-led/g
+p
+EOF
+
+cp ../../libs-host/opendevice.[ch] commandline/