o cleanup
This commit is contained in:
48
tools/avrusb/examples/usbtool/Makefile
Normal file
48
tools/avrusb/examples/usbtool/Makefile
Normal file
@@ -0,0 +1,48 @@
|
||||
# Name: Makefile
|
||||
# Project: usbtool
|
||||
# Author: Christian Starkjohann
|
||||
# Creation Date: 2008-04-06
|
||||
# Tabsize: 4
|
||||
# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||
# License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
|
||||
# This Revision: $Id: Makefile 692 2008-11-07 15:07:40Z cs $
|
||||
|
||||
|
||||
# Concigure the following definitions according to your system.
|
||||
# This Makefile has been tested on Mac OS X, Linux and Windows.
|
||||
|
||||
# Use the following 3 lines on Unix (uncomment the framework on 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. You may
|
||||
# have to change the include paths to where you installed libusb-win32
|
||||
#USBFLAGS = -I/usr/local/include
|
||||
#USBLIBS = -L/usr/local/lib -lusb
|
||||
#EXE_SUFFIX = .exe
|
||||
|
||||
NAME = usbtool
|
||||
|
||||
OBJECTS = opendevice.o $(NAME).o
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = $(CPPFLAGS) $(USBFLAGS) -O -g -Wall
|
||||
LIBS = $(USBLIBS)
|
||||
|
||||
PROGRAM = $(NAME)$(EXE_SUFFIX)
|
||||
|
||||
|
||||
all: $(PROGRAM)
|
||||
|
||||
.c.o:
|
||||
$(CC) $(CFLAGS) -c $<
|
||||
|
||||
$(PROGRAM): $(OBJECTS)
|
||||
$(CC) -o $(PROGRAM) $(OBJECTS) $(LIBS)
|
||||
|
||||
strip: $(PROGRAM)
|
||||
strip $(PROGRAM)
|
||||
|
||||
clean:
|
||||
rm -f *.o $(PROGRAM)
|
||||
18
tools/avrusb/examples/usbtool/Makefile.windows
Normal file
18
tools/avrusb/examples/usbtool/Makefile.windows
Normal file
@@ -0,0 +1,18 @@
|
||||
# Name: Makefile.windows
|
||||
# Project: usbtool
|
||||
# Author: Christian Starkjohann
|
||||
# Creation Date: 2008-04-06
|
||||
# Tabsize: 4
|
||||
# Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||
# License: GNU GPL v2 (see License.txt), GNU GPL v3 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 = -I/usr/local/mingw/include
|
||||
USBLIBS = -L/usr/local/mingw/lib -lusb
|
||||
EXE_SUFFIX = .exe
|
||||
209
tools/avrusb/examples/usbtool/Readme.txt
Normal file
209
tools/avrusb/examples/usbtool/Readme.txt
Normal file
@@ -0,0 +1,209 @@
|
||||
This is the Readme file for usbtool, a general purpose command line utility
|
||||
which can send USB requests to arbitrary devices. Usbtool is based on libusb.
|
||||
|
||||
|
||||
WHAT IS USBTOOL GOOD FOR?
|
||||
=========================
|
||||
When you implement a communication protocol like USB, you must usually write
|
||||
two programs: one on each end of the communication. For USB, this means that
|
||||
you must write a firmware for the device and driver software for the host.
|
||||
|
||||
Usbtool can save you the work of writing the host software, at least during
|
||||
firmware development and testing. Usbtool can send control-in and -out
|
||||
requests to arbitrary devices and send and receive data on interrupt- and
|
||||
bulk-endpoints.
|
||||
|
||||
Usbtool is not only a useful developer tool, it's also an example for using
|
||||
libusb for communication with the device.
|
||||
|
||||
|
||||
SYNOPSIS
|
||||
========
|
||||
usbtool [options] <command>
|
||||
|
||||
|
||||
COMMANDS
|
||||
========
|
||||
list
|
||||
This command prints a list of devices found on all available USB busses.
|
||||
Options -v, -V, -p and -P can be used to filter the list.
|
||||
|
||||
control in|out <type> <recipient> <request> <value> <index>
|
||||
Sends a control-in or control-out request to the device. The request
|
||||
parameters are:
|
||||
type ........ Type of request, can be "standard", "class", "vendor" or
|
||||
"reserved". The type determines which software module in
|
||||
the device is responsible for answering the request:
|
||||
Standard requests are answered by the driver, class
|
||||
requests by the class implementation (e.g. HID, CDC) and
|
||||
vendor requests by custom code.
|
||||
recipient ... Recipient of the request in the device. Can be "device",
|
||||
"interface", "endpoint" or "other". For standard and
|
||||
class requests, the specification defines a recipient for
|
||||
each request. For vendor requests, choose whatever your
|
||||
code expects.
|
||||
request ..... 8 bit numeric value identifying the request.
|
||||
value ....... 16 bit numeric value passed to the device.
|
||||
index ....... another 16 bit numeric value passed to the device.
|
||||
Use options -v, -V, -p and -P to single out a particular device. Use
|
||||
options -d or -D to to send data in an OUT request. Use options -n, -O
|
||||
and -b to determine what to do with data received in an IN request.
|
||||
|
||||
interrupt in|out
|
||||
Sends or receives data on an interrupt-out resp. -in endpoint.
|
||||
Use options -v, -V, -p and -P to single out a particular device. Use
|
||||
options -d or -D to to send data to an OUT endpoint. Use options -n, -O
|
||||
and -b to determine what to do with data received from an IN endpoint.
|
||||
Use option -e to set the endpoint number, -c to choose a configuration
|
||||
-i to claim a particular interface.
|
||||
|
||||
bulk in|out
|
||||
Same as "interrupt in" and "interrupt out", but for bulk endpoints.
|
||||
|
||||
|
||||
OPTIONS
|
||||
=======
|
||||
Most options have already been mentioned at the commands which use them.
|
||||
here is a complete list:
|
||||
|
||||
-h or -?
|
||||
Prints a short help.
|
||||
|
||||
-v <vendor-id>
|
||||
Numeric vendor ID, can be "*" to allow any VID. Take only devices with
|
||||
matching vendor ID into account.
|
||||
|
||||
-p <product-id>
|
||||
Numeric product ID, can be "*" to allow any PID. Take only devices with
|
||||
matching product ID into account.
|
||||
|
||||
-V <vendor-name-pattern>
|
||||
Shell style matching pattern for vendor name. Take only devices into
|
||||
account which have a vendor name that matches this pattern.
|
||||
|
||||
-P <product-name-pattern>
|
||||
Shell style matching pattern for product name. Take only devices into
|
||||
account which have a product name that matches this pattern.
|
||||
|
||||
-S <serial-pattern>
|
||||
Shell style matching pattern for serial number. Take only devices into
|
||||
account which have a serial number that matches this pattern.
|
||||
|
||||
-d <databytes>
|
||||
Data bytes to send to the device, comma separated list of numeric values.
|
||||
E.g.: "1,2,3,4,5".
|
||||
|
||||
-D <file>
|
||||
Binary data sent to the device should be taken from this file.
|
||||
|
||||
-O <file>
|
||||
Write received data bytes to the given file. Format is either hex or
|
||||
binary, depending on the -b flag. By default, received data is printed
|
||||
to standard output.
|
||||
|
||||
-b
|
||||
Request binary output format for files and standard output. Default is
|
||||
a hexadecimal listing.
|
||||
|
||||
-n <count>
|
||||
Numeric value: Maximum number of bytes to receive. This value is passed
|
||||
directly to the libusb API functions.
|
||||
|
||||
-e <endpoint>
|
||||
Numeric value: Endpoint number for interrupt and bulk commands.
|
||||
|
||||
-t <timeout>
|
||||
Numeric value: Timeout in milliseconds for the request. This value is
|
||||
passed directly to the libusb API functions.
|
||||
|
||||
-c <configuration>
|
||||
Numeric value: Interrupt and bulk endpoints can usually only be used if
|
||||
a configuration and an interface has been chosen. Use -c and -i to
|
||||
specify configuration and interface values.
|
||||
|
||||
-i <interface>
|
||||
Numeric value: Interrupt and bulk endpoints can usually only be used if
|
||||
a configuration and an interface has been chosen. Use -c and -i to
|
||||
specify configuration and interface values.
|
||||
|
||||
-w
|
||||
Usbtool may be too verbose with warnings for some applications. Use this
|
||||
option to suppress USB warnings.
|
||||
|
||||
|
||||
NUMERIC VALUES
|
||||
==============
|
||||
All numeric values can be given in hexadecimal, decimal or octal. Hex values
|
||||
are identified by their 0x or 0X prefix, octal values by a leading "0" (the
|
||||
digit zero) and decimal values because they start with a non-zero digit. An
|
||||
optional sign character is allowed. The special value "*" is translated to
|
||||
zero and stands for "any value" in some contexts.
|
||||
|
||||
|
||||
SHELL STYLE MATCHING PATTERNS
|
||||
=============================
|
||||
Some options take shell style matching patterns as an argument. This refers
|
||||
to Unix shells and their file wildcard operations:
|
||||
+ "*" (asterisk character) matches any number (0 to infinite) of any
|
||||
characters.
|
||||
+ "?" matches exactly one arbitrary character.
|
||||
+ A list of characters in square brackets (e.g. "[abc]") matches any of the
|
||||
characters in the list. If a dash ("-") is in the list, it must be the
|
||||
first or the last character. If a caret ("^") is in the list, it must
|
||||
not be the first character. A closing square bracket ("]") must be the
|
||||
first character in the list. A range of characters can be specified in
|
||||
the way "[a-z]". This matches all characters with numeric representation
|
||||
(usually ASCII) starting with "a" and ending with "z". The entire
|
||||
construct matches only one character.
|
||||
+ A list of characters in square brackets starting with a caret ("^"), e.g.
|
||||
("[^abc]") matches any character NOT in the list. The other rules are as
|
||||
above.
|
||||
+ "\" (backslash) followed by any character matches that following
|
||||
character. This can be used to escape "*", "?", "[" and "\".
|
||||
|
||||
|
||||
BUILDING USBTOOL
|
||||
================
|
||||
Usbtool uses libusb on Unix and libusb-win32 on Windows. These libraries can
|
||||
be obtained from http://libusb.sourceforge.net/ and
|
||||
http://libusb-win32.sourceforge.net/ respectively. On Unix, a simple "make"
|
||||
should compile the sources (although you may have to edit Makefile to
|
||||
include or remove additional libraries). On Windows, we recommend that you
|
||||
use MinGW and MSYS. See the top level Readme file for details. Edit
|
||||
Makefile.windows according to your library installation paths and build with
|
||||
"make -f Makefile.windows".
|
||||
|
||||
|
||||
EXAMPLES
|
||||
========
|
||||
To list all devices connected to your computer, do
|
||||
|
||||
usbtool -w list
|
||||
|
||||
To check whether our selection options single out the desired device, use eg.
|
||||
|
||||
usbtool -w -P LEDControl list
|
||||
|
||||
This command shows all LEDControl devices connected or prints nothing if
|
||||
none is found. LEDControl is the device from the "custom-class" example.
|
||||
|
||||
You can also send commands to the LEDControl device using usbtool. From
|
||||
the file requests.h in custom-class/firmware, we know that the set-status
|
||||
request has numeric value 1 and the get-status request is 2. See this file
|
||||
for details of the protocol used. We can therefore query the status with
|
||||
|
||||
usbtool -w -P LEDControl control in vendor device 2 0 0
|
||||
|
||||
This command prints 0x00 if the LED is off or 0x01 if it is on. To turn the
|
||||
LED on, use
|
||||
|
||||
usbtool -w -P LEDControl control out vendor device 1 1 0
|
||||
|
||||
and to turn it off, use
|
||||
|
||||
usbtool -w -P LEDControl control out vendor device 1 0 0
|
||||
|
||||
|
||||
----------------------------------------------------------------------------
|
||||
(c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH.
|
||||
http://www.obdev.at/
|
||||
203
tools/avrusb/examples/usbtool/opendevice.c
Normal file
203
tools/avrusb/examples/usbtool/opendevice.c
Normal file
@@ -0,0 +1,203 @@
|
||||
/* Name: opendevice.c
|
||||
* Project: AVR-USB host-side library
|
||||
* 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), GNU GPL v3 or proprietary (CommercialLicense.txt)
|
||||
* This Revision: $Id: opendevice.c 692 2008-11-07 15:07:40Z cs $
|
||||
*/
|
||||
|
||||
/*
|
||||
General Description:
|
||||
The functions in this module can be used to find and open a device based on
|
||||
libusb or libusb-win32.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "opendevice.h"
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define MATCH_SUCCESS 1
|
||||
#define MATCH_FAILED 0
|
||||
#define MATCH_ABORT -1
|
||||
|
||||
/* private interface: match text and p, return MATCH_SUCCESS, MATCH_FAILED, or MATCH_ABORT. */
|
||||
static int _shellStyleMatch(char *text, char *p)
|
||||
{
|
||||
int last, matched, reverse;
|
||||
|
||||
for(; *p; text++, p++){
|
||||
if(*text == 0 && *p != '*')
|
||||
return MATCH_ABORT;
|
||||
switch(*p){
|
||||
case '\\':
|
||||
/* Literal match with following character. */
|
||||
p++;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
if(*text != *p)
|
||||
return MATCH_FAILED;
|
||||
continue;
|
||||
case '?':
|
||||
/* Match anything. */
|
||||
continue;
|
||||
case '*':
|
||||
while(*++p == '*')
|
||||
/* Consecutive stars act just like one. */
|
||||
continue;
|
||||
if(*p == 0)
|
||||
/* Trailing star matches everything. */
|
||||
return MATCH_SUCCESS;
|
||||
while(*text)
|
||||
if((matched = _shellStyleMatch(text++, p)) != MATCH_FAILED)
|
||||
return matched;
|
||||
return MATCH_ABORT;
|
||||
case '[':
|
||||
reverse = p[1] == '^';
|
||||
if(reverse) /* Inverted character class. */
|
||||
p++;
|
||||
matched = MATCH_FAILED;
|
||||
if(p[1] == ']' || p[1] == '-')
|
||||
if(*++p == *text)
|
||||
matched = MATCH_SUCCESS;
|
||||
for(last = *p; *++p && *p != ']'; last = *p)
|
||||
if (*p == '-' && p[1] != ']' ? *text <= *++p && *text >= last : *text == *p)
|
||||
matched = MATCH_SUCCESS;
|
||||
if(matched == reverse)
|
||||
return MATCH_FAILED;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return *text == 0;
|
||||
}
|
||||
|
||||
/* public interface for shell style matching: returns 0 if fails, 1 if matches */
|
||||
static int shellStyleMatch(char *text, char *pattern)
|
||||
{
|
||||
if(pattern == NULL) /* NULL pattern is synonymous to "*" */
|
||||
return 1;
|
||||
return _shellStyleMatch(text, pattern) == MATCH_SUCCESS;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen)
|
||||
{
|
||||
char buffer[256];
|
||||
int rval, i;
|
||||
|
||||
if((rval = usb_get_string_simple(dev, index, buf, buflen)) >= 0) /* use libusb version if it works */
|
||||
return rval;
|
||||
if((rval = usb_control_msg(dev, USB_ENDPOINT_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) + index, 0x0409, buffer, sizeof(buffer), 5000)) < 0)
|
||||
return rval;
|
||||
if(buffer[1] != USB_DT_STRING){
|
||||
*buf = 0;
|
||||
return 0;
|
||||
}
|
||||
if((unsigned char)buffer[0] < rval)
|
||||
rval = (unsigned char)buffer[0];
|
||||
rval /= 2;
|
||||
/* lossy conversion to ISO Latin1: */
|
||||
for(i=1;i<rval;i++){
|
||||
if(i > buflen) /* destination buffer overflow */
|
||||
break;
|
||||
buf[i-1] = buffer[2 * i];
|
||||
if(buffer[2 * i + 1] != 0) /* outside of ISO Latin1 range */
|
||||
buf[i-1] = '?';
|
||||
}
|
||||
buf[i-1] = 0;
|
||||
return i-1;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
int usbOpenDevice(usb_dev_handle **device, int vendorID, char *vendorNamePattern, int productID, char *productNamePattern, char *serialNamePattern, FILE *printMatchingDevicesFp, FILE *warningsFp)
|
||||
{
|
||||
struct usb_bus *bus;
|
||||
struct usb_device *dev;
|
||||
usb_dev_handle *handle = NULL;
|
||||
int errorCode = USBOPEN_ERR_NOTFOUND;
|
||||
|
||||
usb_find_busses();
|
||||
usb_find_devices();
|
||||
for(bus = usb_get_busses(); bus; bus = bus->next){
|
||||
for(dev = bus->devices; dev; dev = dev->next){ /* iterate over all devices on all busses */
|
||||
if((vendorID == 0 || dev->descriptor.idVendor == vendorID)
|
||||
&& (productID == 0 || dev->descriptor.idProduct == productID)){
|
||||
char vendor[256], product[256], serial[256];
|
||||
int len;
|
||||
handle = usb_open(dev); /* we need to open the device in order to query strings */
|
||||
if(!handle){
|
||||
errorCode = USBOPEN_ERR_ACCESS;
|
||||
if(warningsFp != NULL)
|
||||
fprintf(warningsFp, "Warning: cannot open VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
|
||||
continue;
|
||||
}
|
||||
/* now check whether the names match: */
|
||||
len = vendor[0] = 0;
|
||||
if(dev->descriptor.iManufacturer > 0){
|
||||
len = usbGetStringAscii(handle, dev->descriptor.iManufacturer, vendor, sizeof(vendor));
|
||||
}
|
||||
if(len < 0){
|
||||
errorCode = USBOPEN_ERR_ACCESS;
|
||||
if(warningsFp != NULL)
|
||||
fprintf(warningsFp, "Warning: cannot query manufacturer for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
|
||||
}else{
|
||||
errorCode = USBOPEN_ERR_NOTFOUND;
|
||||
/* printf("seen device from vendor ->%s<-\n", vendor); */
|
||||
if(shellStyleMatch(vendor, vendorNamePattern)){
|
||||
len = product[0] = 0;
|
||||
if(dev->descriptor.iProduct > 0){
|
||||
len = usbGetStringAscii(handle, dev->descriptor.iProduct, product, sizeof(product));
|
||||
}
|
||||
if(len < 0){
|
||||
errorCode = USBOPEN_ERR_ACCESS;
|
||||
if(warningsFp != NULL)
|
||||
fprintf(warningsFp, "Warning: cannot query product for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
|
||||
}else{
|
||||
errorCode = USBOPEN_ERR_NOTFOUND;
|
||||
/* printf("seen product ->%s<-\n", product); */
|
||||
if(shellStyleMatch(product, productNamePattern)){
|
||||
len = serial[0] = 0;
|
||||
if(dev->descriptor.iSerialNumber > 0){
|
||||
len = usbGetStringAscii(handle, dev->descriptor.iSerialNumber, serial, sizeof(serial));
|
||||
}
|
||||
if(len < 0){
|
||||
errorCode = USBOPEN_ERR_ACCESS;
|
||||
if(warningsFp != NULL)
|
||||
fprintf(warningsFp, "Warning: cannot query serial for VID=0x%04x PID=0x%04x: %s\n", dev->descriptor.idVendor, dev->descriptor.idProduct, usb_strerror());
|
||||
}
|
||||
if(shellStyleMatch(serial, serialNamePattern)){
|
||||
if(printMatchingDevicesFp != NULL){
|
||||
if(serial[0] == 0){
|
||||
fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product);
|
||||
}else{
|
||||
fprintf(printMatchingDevicesFp, "VID=0x%04x PID=0x%04x vendor=\"%s\" product=\"%s\" serial=\"%s\"\n", dev->descriptor.idVendor, dev->descriptor.idProduct, vendor, product, serial);
|
||||
}
|
||||
}else{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
usb_close(handle);
|
||||
handle = NULL;
|
||||
}
|
||||
}
|
||||
if(handle) /* we have found a deice */
|
||||
break;
|
||||
}
|
||||
if(handle != NULL){
|
||||
errorCode = 0;
|
||||
*device = handle;
|
||||
}
|
||||
if(printMatchingDevicesFp != NULL) /* never return an error for listing only */
|
||||
errorCode = 0;
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
77
tools/avrusb/examples/usbtool/opendevice.h
Normal file
77
tools/avrusb/examples/usbtool/opendevice.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/* Name: opendevice.h
|
||||
* Project: AVR-USB host-side library
|
||||
* 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), GNU GPL v3 or proprietary (CommercialLicense.txt)
|
||||
* This Revision: $Id: opendevice.h 692 2008-11-07 15:07:40Z cs $
|
||||
*/
|
||||
|
||||
/*
|
||||
General Description:
|
||||
This module offers additional functionality for host side drivers based on
|
||||
libusb or libusb-win32. It includes a function to find and open a device
|
||||
based on numeric IDs and textual description. It also includes a function to
|
||||
obtain textual descriptions from a device.
|
||||
|
||||
To use this functionality, simply copy opendevice.c and opendevice.h into your
|
||||
project and add them to your Makefile. You may modify and redistribute these
|
||||
files according to the GNU General Public License (GPL) version 2 or 3.
|
||||
*/
|
||||
|
||||
#ifndef __OPENDEVICE_H_INCLUDED__
|
||||
#define __OPENDEVICE_H_INCLUDED__
|
||||
|
||||
#include <usb.h> /* this is libusb, see http://libusb.sourceforge.net/ */
|
||||
#include <stdio.h>
|
||||
|
||||
int usbGetStringAscii(usb_dev_handle *dev, int index, char *buf, int buflen);
|
||||
/* This function gets a string descriptor from the device. 'index' is the
|
||||
* string descriptor index. The string is returned in ISO Latin 1 encoding in
|
||||
* 'buf' and it is terminated with a 0-character. The buffer size must be
|
||||
* passed in 'buflen' to prevent buffer overflows. A libusb device handle
|
||||
* must be given in 'dev'.
|
||||
* Returns: The length of the string (excluding the terminating 0) or
|
||||
* a negative number in case of an error. If there was an error, use
|
||||
* usb_strerror() to obtain the error message.
|
||||
*/
|
||||
|
||||
int usbOpenDevice(usb_dev_handle **device, int vendorID, char *vendorNamePattern, int productID, char *productNamePattern, char *serialNamePattern, FILE *printMatchingDevicesFp, FILE *warningsFp);
|
||||
/* This function iterates over all devices on all USB busses and searches for
|
||||
* a device. Matching is done first by means of Vendor- and Product-ID (passed
|
||||
* in 'vendorID' and 'productID'. An ID of 0 matches any numeric ID (wildcard).
|
||||
* When a device matches by its IDs, matching by names is performed. Name
|
||||
* matching can be done on textual vendor name ('vendorNamePattern'), product
|
||||
* name ('productNamePattern') and serial number ('serialNamePattern'). A
|
||||
* device matches only if all non-null pattern match. If you don't care about
|
||||
* a string, pass NULL for the pattern. Patterns are Unix shell style pattern:
|
||||
* '*' stands for 0 or more characters, '?' for one single character, a list
|
||||
* of characters in square brackets for a single character from the list
|
||||
* (dashes are allowed to specify a range) and if the lis of characters begins
|
||||
* with a caret ('^'), it matches one character which is NOT in the list.
|
||||
* Other parameters to the function: If 'warningsFp' is not NULL, warning
|
||||
* messages are printed to this file descriptor with fprintf(). If
|
||||
* 'printMatchingDevicesFp' is not NULL, no device is opened but matching
|
||||
* devices are printed to the given file descriptor with fprintf().
|
||||
* If a device is opened, the resulting USB handle is stored in '*device'. A
|
||||
* pointer to a "usb_dev_handle *" type variable must be passed here.
|
||||
* Returns: 0 on success, an error code (see defines below) on failure.
|
||||
*/
|
||||
|
||||
/* usbOpenDevice() error codes: */
|
||||
#define USBOPEN_SUCCESS 0 /* no error */
|
||||
#define USBOPEN_ERR_ACCESS 1 /* not enough permissions to open device */
|
||||
#define USBOPEN_ERR_IO 2 /* I/O error */
|
||||
#define USBOPEN_ERR_NOTFOUND 3 /* device not found */
|
||||
|
||||
|
||||
/* Obdev's free USB IDs, see USBID-License.txt for details */
|
||||
|
||||
#define USB_VID_OBDEV_SHARED 5824 /* obdev's shared vendor ID */
|
||||
#define USB_PID_OBDEV_SHARED_CUSTOM 1500 /* shared PID for custom class devices */
|
||||
#define USB_PID_OBDEV_SHARED_HID 1503 /* shared PID for HIDs except mice & keyboards */
|
||||
#define USB_PID_OBDEV_SHARED_CDCACM 1505 /* shared PID for CDC Modem devices */
|
||||
#define USB_PID_OBDEV_SHARED_MIDI 1508 /* shared PID for MIDI class devices */
|
||||
|
||||
#endif /* __OPENDEVICE_H_INCLUDED__ */
|
||||
356
tools/avrusb/examples/usbtool/usbtool.c
Normal file
356
tools/avrusb/examples/usbtool/usbtool.c
Normal file
@@ -0,0 +1,356 @@
|
||||
/* Name: usbtool.c
|
||||
* Project: AVR-USB examples, host side
|
||||
* Author: Christian Starkjohann
|
||||
* Creation Date: 2008-04-06
|
||||
* Tabsize: 4
|
||||
* Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
|
||||
* This Revision: $Id: usbtool.c 692 2008-11-07 15:07:40Z cs $
|
||||
*/
|
||||
|
||||
/*
|
||||
General Description:
|
||||
This command line tool can perform various USB requests at arbitrary
|
||||
USB devices. It is intended as universal host side tool for experimentation
|
||||
and debugging purposes. It must be linked with libusb, a library for accessing
|
||||
the USB bus from Linux, FreeBSD, Mac OS X and other Unix operating systems.
|
||||
Libusb can be obtained from http://libusb.sourceforge.net/.
|
||||
On Windows use libusb-win32 from http://libusb-win32.sourceforge.net/.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <usb.h> /* this is libusb, see http://libusb.sourceforge.net/ */
|
||||
#include "opendevice.h" /* common code moved to separate module */
|
||||
|
||||
#define DEFAULT_USB_VID 0 /* any */
|
||||
#define DEFAULT_USB_PID 0 /* any */
|
||||
|
||||
static void usage(char *name)
|
||||
{
|
||||
fprintf(stderr, "usage: %s [options] <command>\n", name);
|
||||
fprintf(stderr,
|
||||
"Options are:\n"
|
||||
" -h or -? (print this help and exit)\n"
|
||||
" -v <vendor-id> (defaults to 0x%x, can be '*' for any VID)\n"
|
||||
" -p <product-id> (defaults to 0x%x, can be '*' for any PID)\n"
|
||||
" -V <vendor-name-pattern> (shell style matching, defaults to '*')\n"
|
||||
" -P <product-name-pattern> (shell style matching, defaults to '*')\n"
|
||||
" -S <serial-pattern> (shell style matching, defaults to '*')\n"
|
||||
" -d <databytes> (data byte for request, comma separated list)\n"
|
||||
" -D <file> (binary data for request taken from file)\n"
|
||||
" -O <file> (write received data bytes to file)\n"
|
||||
" -b (binary output format, default is hex)\n"
|
||||
" -n <count> (maximum number of bytes to receive)\n"
|
||||
" -e <endpoint> (specify endpoint for some commands)\n"
|
||||
" -t <timeout> (specify USB timeout in milliseconds)\n"
|
||||
" -c <configuration> (device configuration to choose)\n"
|
||||
" -i <interface> (configuration interface to claim)\n"
|
||||
" -w (suppress USB warnings, default is verbose)\n"
|
||||
"\n"
|
||||
"Commands are:\n"
|
||||
" list (list all matching devices by name)\n"
|
||||
" control in|out <type> <recipient> <request> <value> <index> (send control request)\n"
|
||||
" interrupt in|out (send or receive interrupt data)\n"
|
||||
" bulk in|out (send or receive bulk data)\n"
|
||||
"For valid enum values for <type> and <recipient> pass \"x\" for the value.\n"
|
||||
"Objective Development's free VID/PID pairs are:\n"
|
||||
" 5824/1500 for vendor class devices\n"
|
||||
" 5824/1503 for HID class devices excluding mice and keyboards\n"
|
||||
" 5824/1505 for CDC-ACM class devices\n"
|
||||
" 5824/1508 for MIDI class devices\n"
|
||||
, DEFAULT_USB_VID, DEFAULT_USB_PID
|
||||
);
|
||||
|
||||
|
||||
}
|
||||
|
||||
static int vendorID = DEFAULT_USB_VID;
|
||||
static int productID = DEFAULT_USB_PID;
|
||||
static char *vendorNamePattern = "*";
|
||||
static char *productNamePattern = "*";
|
||||
static char *serialPattern = "*";
|
||||
static char *sendBytes = NULL;
|
||||
static int sendByteCount;
|
||||
static char *outputFile = NULL;
|
||||
static int endpoint = 0;
|
||||
static int outputFormatIsBinary = 0;
|
||||
static int showWarnings = 1;
|
||||
static int usbTimeout = 5000;
|
||||
static int usbCount = 128;
|
||||
static int usbConfiguration = 1;
|
||||
static int usbInterface = 0;
|
||||
|
||||
static int usbDirection, usbType, usbRecipient, usbRequest, usbValue, usbIndex; /* arguments of control transfer */
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* ASCII to integer (number parsing) which allows hex (0x prefix),
|
||||
* octal (0 prefix) and decimal (1-9 prefix) input.
|
||||
*/
|
||||
static int myAtoi(char *text)
|
||||
{
|
||||
long l;
|
||||
char *endPtr;
|
||||
|
||||
if(strcmp(text, "*") == 0)
|
||||
return 0;
|
||||
l = strtol(text, &endPtr, 0);
|
||||
if(endPtr == text){
|
||||
fprintf(stderr, "warning: can't parse numeric parameter ->%s<-, defaults to 0.\n", text);
|
||||
l = 0;
|
||||
}else if(*endPtr != 0){
|
||||
fprintf(stderr, "warning: numeric parameter ->%s<- only partially parsed.\n", text);
|
||||
}
|
||||
return l;
|
||||
}
|
||||
|
||||
static int parseEnum(char *text, ...)
|
||||
{
|
||||
va_list vlist;
|
||||
char *entries[64];
|
||||
int i, numEntries;
|
||||
|
||||
va_start(vlist, text);
|
||||
for(i = 0; i < 64; i++){
|
||||
entries[i] = va_arg(vlist, char *);
|
||||
if(entries[i] == NULL)
|
||||
break;
|
||||
}
|
||||
numEntries = i;
|
||||
va_end(vlist);
|
||||
for(i = 0; i < numEntries; i++){
|
||||
if(strcasecmp(text, entries[i]) == 0)
|
||||
return i;
|
||||
}
|
||||
if(isdigit(*text)){
|
||||
return myAtoi(text);
|
||||
}
|
||||
fprintf(stderr, "Enum value \"%s\" not allowed. Allowed values are:\n", text);
|
||||
for(i = 0; i < numEntries; i++){
|
||||
fprintf(stderr, " %s\n", entries[i]);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define ACTION_LIST 0
|
||||
#define ACTION_CONTROL 1
|
||||
#define ACTION_INTERRUPT 2
|
||||
#define ACTION_BULK 3
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
usb_dev_handle *handle = NULL;
|
||||
int opt, len, action, argcnt;
|
||||
char *myName = argv[0], *s, *rxBuffer = NULL;
|
||||
FILE *fp;
|
||||
|
||||
while((opt = getopt(argc, argv, "?hv:p:V:P:S:d:D:O:e:n:tbw")) != -1){
|
||||
switch(opt){
|
||||
case 'h':
|
||||
case '?': /* -h or -? (print this help and exit) */
|
||||
usage(myName);
|
||||
exit(1);
|
||||
case 'v': /* -v <vendor-id> (defaults to 0x%x, can be '*' for any VID) */
|
||||
vendorID = myAtoi(optarg);
|
||||
break;
|
||||
case 'p': /* -p <product-id> (defaults to 0x%x, can be '*' for any PID) */
|
||||
productID = myAtoi(optarg);
|
||||
break;
|
||||
case 'V': /* -V <vendor-name-pattern> (shell style matching, defaults to '*') */
|
||||
vendorNamePattern = optarg;
|
||||
break;
|
||||
case 'P': /* -P <product-name-pattern> (shell style matching, defaults to '*') */
|
||||
productNamePattern = optarg;
|
||||
break;
|
||||
case 'S': /* -S <serial-pattern> (shell style matching, defaults to '*') */
|
||||
serialPattern = optarg;
|
||||
break;
|
||||
case 'd': /* -d <databytes> (data bytes for requests given on command line) */
|
||||
while((s = strtok(optarg, ", ")) != NULL){
|
||||
optarg = NULL;
|
||||
if(sendBytes != NULL){
|
||||
sendBytes = realloc(sendBytes, sendByteCount + 1);
|
||||
}else{
|
||||
sendBytes = malloc(sendByteCount + 1);
|
||||
}
|
||||
sendBytes[sendByteCount++] = myAtoi(s);
|
||||
}
|
||||
break;
|
||||
case 'D': /* -D <file> (data bytes for request taken from file) */
|
||||
if((fp = fopen(optarg, "rb")) == NULL){
|
||||
fprintf(stderr, "error opening %s: %s\n", optarg, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
fseek(fp, 0, SEEK_END);
|
||||
len = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
if(sendBytes != NULL){
|
||||
sendBytes = realloc(sendBytes, sendByteCount + len);
|
||||
}else{
|
||||
sendBytes = malloc(sendByteCount + len);
|
||||
}
|
||||
fread(sendBytes + sendByteCount, 1, len, fp); /* would need error checking */
|
||||
sendByteCount += len;
|
||||
fclose(fp);
|
||||
break;
|
||||
case 'O': /* -O <file> (write received data bytes to file) */
|
||||
outputFile = optarg;
|
||||
break;
|
||||
case 'e': /* -e <endpoint> (specify endpoint for some commands) */
|
||||
endpoint = myAtoi(optarg);
|
||||
break;
|
||||
case 't': /* -t <timeout> (specify USB timeout in milliseconds) */
|
||||
usbTimeout = myAtoi(optarg);
|
||||
break;
|
||||
case 'b': /* -b (binary output format, default is hex) */
|
||||
outputFormatIsBinary = 1;
|
||||
break;
|
||||
case 'n': /* -n <count> (maximum number of bytes to receive) */
|
||||
usbCount = myAtoi(optarg);
|
||||
break;
|
||||
case 'c': /* -c <configuration> (device configuration to choose) */
|
||||
usbConfiguration = myAtoi(optarg);
|
||||
break;
|
||||
case 'i': /* -i <interface> (configuration interface to claim) */
|
||||
usbInterface = myAtoi(optarg);
|
||||
break;
|
||||
case 'w': /* -w (suppress USB warnings, default is verbose) */
|
||||
showWarnings = 0;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Option -%c unknown\n", opt);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
if(argc < 1){
|
||||
usage(myName);
|
||||
exit(1);
|
||||
}
|
||||
argcnt = 2;
|
||||
if(strcasecmp(argv[0], "list") == 0){
|
||||
action = ACTION_LIST;
|
||||
argcnt = 1;
|
||||
}else if(strcasecmp(argv[0], "control") == 0){
|
||||
action = ACTION_CONTROL;
|
||||
argcnt = 7;
|
||||
}else if(strcasecmp(argv[0], "interrupt") == 0){
|
||||
action = ACTION_INTERRUPT;
|
||||
}else if(strcasecmp(argv[0], "bulk") == 0){
|
||||
action = ACTION_BULK;
|
||||
}else{
|
||||
fprintf(stderr, "command %s not known\n", argv[0]);
|
||||
usage(myName);
|
||||
exit(1);
|
||||
}
|
||||
if(argc < argcnt){
|
||||
fprintf(stderr, "Not enough arguments.\n");
|
||||
usage(myName);
|
||||
exit(1);
|
||||
}
|
||||
if(argc > argcnt){
|
||||
fprintf(stderr, "Warning: only %d arguments expected, rest ignored.\n", argcnt);
|
||||
}
|
||||
usb_init();
|
||||
if(usbOpenDevice(&handle, vendorID, vendorNamePattern, productID, productNamePattern, serialPattern, action == ACTION_LIST ? stdout : NULL, showWarnings ? stderr : NULL) != 0){
|
||||
fprintf(stderr, "Could not find USB device with VID=0x%x PID=0x%x Vname=%s Pname=%s Serial=%s\n", vendorID, productID, vendorNamePattern, productNamePattern, serialPattern);
|
||||
exit(1);
|
||||
}
|
||||
if(action == ACTION_LIST)
|
||||
exit(0); /* we've done what we were asked to do already */
|
||||
usbDirection = parseEnum(argv[1], "out", "in", NULL);
|
||||
if(usbDirection){ /* IN transfer */
|
||||
rxBuffer = malloc(usbCount);
|
||||
}
|
||||
if(action == ACTION_CONTROL){
|
||||
int requestType;
|
||||
usbType = parseEnum(argv[2], "standard", "class", "vendor", "reserved", NULL);
|
||||
usbRecipient = parseEnum(argv[3], "device", "interface", "endpoint", "other", NULL);
|
||||
usbRequest = myAtoi(argv[4]);
|
||||
usbValue = myAtoi(argv[5]);
|
||||
usbIndex = myAtoi(argv[6]);
|
||||
requestType = ((usbDirection & 1) << 7) | ((usbType & 3) << 5) | (usbRecipient & 0x1f);
|
||||
if(usbDirection){ /* IN transfer */
|
||||
len = usb_control_msg(handle, requestType, usbRequest, usbValue, usbIndex, rxBuffer, usbCount, usbTimeout);
|
||||
}else{ /* OUT transfer */
|
||||
len = usb_control_msg(handle, requestType, usbRequest, usbValue, usbIndex, sendBytes, sendByteCount, usbTimeout);
|
||||
}
|
||||
}else{ /* must be ACTION_INTERRUPT or ACTION_BULK */
|
||||
int retries = 1;
|
||||
if(usb_set_configuration(handle, usbConfiguration) && showWarnings){
|
||||
fprintf(stderr, "Warning: could not set configuration: %s\n", usb_strerror());
|
||||
}
|
||||
/* now try to claim the interface and detach the kernel HID driver on
|
||||
* linux and other operating systems which support the call.
|
||||
*/
|
||||
while((len = usb_claim_interface(handle, usbInterface)) != 0 && retries-- > 0){
|
||||
#ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
|
||||
if(usb_detach_kernel_driver_np(handle, 0) < 0 && showWarnings){
|
||||
fprintf(stderr, "Warning: could not detach kernel driver: %s\n", usb_strerror());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(len != 0 && showWarnings)
|
||||
fprintf(stderr, "Warning: could not claim interface: %s\n", usb_strerror());
|
||||
if(action == ACTION_INTERRUPT){
|
||||
if(usbDirection){ /* IN transfer */
|
||||
len = usb_interrupt_read(handle, endpoint, rxBuffer, usbCount, usbTimeout);
|
||||
}else{
|
||||
len = usb_interrupt_write(handle, endpoint, sendBytes, sendByteCount, usbTimeout);
|
||||
}
|
||||
}else{
|
||||
if(usbDirection){ /* IN transfer */
|
||||
len = usb_bulk_read(handle, endpoint, rxBuffer, usbCount, usbTimeout);
|
||||
}else{
|
||||
len = usb_bulk_write(handle, endpoint, sendBytes, sendByteCount, usbTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(len < 0){
|
||||
fprintf(stderr, "USB error: %s\n", usb_strerror());
|
||||
exit(1);
|
||||
}
|
||||
if(usbDirection == 0) /* OUT */
|
||||
printf("%d bytes sent.\n", len);
|
||||
if(rxBuffer != NULL){
|
||||
FILE *fp = stdout;
|
||||
if(outputFile != NULL){
|
||||
fp = fopen(outputFile, outputFormatIsBinary ? "wb" : "w");
|
||||
if(fp == NULL){
|
||||
fprintf(stderr, "Error writing \"%s\": %s\n", outputFile, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if(outputFormatIsBinary){
|
||||
fwrite(rxBuffer, 1, len, fp);
|
||||
}else{
|
||||
int i;
|
||||
for(i = 0; i < len; i++){
|
||||
if(i != 0){
|
||||
if(i % 16 == 0){
|
||||
fprintf(fp, "\n");
|
||||
}else{
|
||||
fprintf(fp, " ");
|
||||
}
|
||||
}
|
||||
fprintf(fp, "0x%02x", rxBuffer[i] & 0xff);
|
||||
}
|
||||
if(i != 0)
|
||||
fprintf(fp, "\n");
|
||||
}
|
||||
}
|
||||
usb_close(handle);
|
||||
if(rxBuffer != NULL)
|
||||
free(rxBuffer);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user