Hi,
i'm completely new to v-usb (and only got realy small knowledge to AVR)
I've a Curcuit for USB Generic Hid (including an ISP-Port) and try to
make a Generic HID device, to get the status of a potentiometer.
I managed to get the "hid-custom-rq" example to work and now i'm trying
to add a new request.
The problem is, that i wanted to test multiple byte answer (to report
back the value from the potentiometer) so i added the request id 3
(CUSTOM_RQ_GET_POTI) and set the dataBuffer to the size of 4 and then to
[0] = 0 ; [1] = 1 ; [2] = 1. All works fine i think, but on the client
side, i only get the first byte and the others are random (or zero if i
first clear the buffer)
could anybody give me a hint what i#m doing wrong?
here is the code for the usb device
request.h 1 | /* Name: requests.h
| 2 | * Project: custom-class, a basic USB example
| 3 | * Author: Christian Starkjohann
| 4 | * Creation Date: 2008-04-09
| 5 | * Tabsize: 4
| 6 | * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
| 7 | * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
| 8 | * This Revision: $Id: requests.h 692 2008-11-07 15:07:40Z cs $
| 9 | */
| 10 |
| 11 | /* This header is shared between the firmware and the host software. It
| 12 | * defines the USB request numbers (and optionally data types) used to
| 13 | * communicate between the host and the device.
| 14 | */
| 15 |
| 16 | #ifndef __REQUESTS_H_INCLUDED__
| 17 | #define __REQUESTS_H_INCLUDED__
| 18 |
| 19 | #define CUSTOM_RQ_SET_STATUS 1
| 20 | /* Set the LED status. Control-OUT.
| 21 | * The requested status is passed in the "wValue" field of the control
| 22 | * transfer. No OUT data is sent. Bit 0 of the low byte of wValue controls
| 23 | * the LED.
| 24 | */
| 25 |
| 26 | #define CUSTOM_RQ_GET_STATUS 2
| 27 | /* Get the current LED status. Control-IN.
| 28 | * This control transfer involves a 1 byte data phase where the device sends
| 29 | * the current status to the host. The status is in bit 0 of the byte.
| 30 | */
| 31 |
| 32 | #define CUSTOM_RQ_GET_POTI 3
| 33 |
| 34 |
| 35 | #endif /* __REQUESTS_H_INCLUDED__ */
|
main.c 1 | /* Name: main.c
| 2 | * Project: hid-custom-rq example
| 3 | * Author: Christian Starkjohann
| 4 | * Creation Date: 2008-04-07
| 5 | * Tabsize: 4
| 6 | * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
| 7 | * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
| 8 | * This Revision: $Id: main.c 790 2010-05-30 21:00:26Z cs $
| 9 | */
| 10 |
| 11 | /*
| 12 | This example should run on most AVRs with only little changes. No special
| 13 | hardware resources except INT0 are used. You may have to change usbconfig.h for
| 14 | different I/O pins for USB. Please note that USB D+ must be the INT0 pin, or
| 15 | at least be connected to INT0 as well.
| 16 | We assume that an LED is connected to port B bit 0. If you connect it to a
| 17 | different port or bit, change the macros below:
| 18 | */
| 19 | #define LED_PORT_DDR DDRB
| 20 | #define LED_PORT_OUTPUT PORTB
| 21 | #define LED_BIT 0
| 22 |
| 23 | #include <avr/io.h>
| 24 | #include <avr/wdt.h>
| 25 | #include <avr/interrupt.h> /* for sei() */
| 26 | #include <util/delay.h> /* for _delay_ms() */
| 27 |
| 28 | #include <avr/pgmspace.h> /* required by usbdrv.h */
| 29 | #include "usbdrv.h"
| 30 | #include "oddebug.h" /* This is also an example for using debug macros */
| 31 | #include "requests.h" /* The custom request numbers we use */
| 32 |
| 33 | /* ------------------------------------------------------------------------- */
| 34 | /* ----------------------------- USB interface ----------------------------- */
| 35 | /* ------------------------------------------------------------------------- */
| 36 |
| 37 | PROGMEM char usbHidReportDescriptor[22] = { /* USB report descriptor */
| 38 | 0x06, 0x00, 0xff, // USAGE_PAGE (Generic Desktop)
| 39 | 0x09, 0x01, // USAGE (Vendor Usage 1)
| 40 | 0xa1, 0x01, // COLLECTION (Application)
| 41 | 0x15, 0x00, // LOGICAL_MINIMUM (0)
| 42 | 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255)
| 43 | 0x75, 0x08, // REPORT_SIZE (8)
| 44 | 0x95, 0x01, // REPORT_COUNT (1)
| 45 | 0x09, 0x00, // USAGE (Undefined)
| 46 | 0xb2, 0x02, 0x01, // FEATURE (Data,Var,Abs,Buf)
| 47 | 0xc0 // END_COLLECTION
| 48 | };
| 49 | /* The descriptor above is a dummy only, it silences the drivers. The report
| 50 | * it describes consists of one byte of undefined data.
| 51 | * We don't transfer our data through HID reports, we use custom requests
| 52 | * instead.
| 53 | */
| 54 |
| 55 | /* ------------------------------------------------------------------------- */
| 56 |
| 57 | usbMsgLen_t usbFunctionSetup(uchar data[8])
| 58 | {
| 59 | usbRequest_t *rq = (void *)data;
| 60 |
| 61 | if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_VENDOR){
| 62 | DBG1(0x50, &rq->bRequest, 1); /* debug output: print our request */
| 63 | if(rq->bRequest == CUSTOM_RQ_SET_STATUS){
| 64 | if(rq->wValue.bytes[0] & 1){ /* set LED */
| 65 | LED_PORT_OUTPUT |= _BV(LED_BIT);
| 66 | }else{ /* clear LED */
| 67 | LED_PORT_OUTPUT &= ~_BV(LED_BIT);
| 68 | }
| 69 | }else if(rq->bRequest == CUSTOM_RQ_GET_STATUS){
| 70 | static uchar dataBuffer[1]; /* buffer must stay valid when usbFunctionSetup returns */
| 71 | dataBuffer[0] = ((LED_PORT_OUTPUT & _BV(LED_BIT)) != 0);
| 72 | usbMsgPtr = dataBuffer; /* tell the driver which data to return */
| 73 | return 1; /* tell the driver to send 1 byte */
| 74 | }else if(rq->bRequest == CUSTOM_RQ_GET_POTI) {
| 75 | static uchar dataBuffer[3]; /* buffer must stay valid when usbFunctionSetup returns */
| 76 | //dataBuffer[0] = ((LED_PORT_OUTPUT & _BV(LED_BIT)) != 0);
| 77 |
| 78 | dataBuffer[0] = 0;
| 79 | dataBuffer[1] = 1;
| 80 | dataBuffer[2] = 1;
| 81 | usbMsgPtr = dataBuffer; /* tell the driver which data to return */
| 82 | return 1; /* tell the driver to send 1 byte */
| 83 | }
| 84 | }else{
| 85 | /* calss requests USBRQ_HID_GET_REPORT and USBRQ_HID_SET_REPORT are
| 86 | * not implemented since we never call them. The operating system
| 87 | * won't call them either because our descriptor defines no meaning.
| 88 | */
| 89 | }
| 90 | return 0; /* default for not implemented requests: return no data back to host */
| 91 | }
| 92 |
| 93 | /* ------------------------------------------------------------------------- */
| 94 |
| 95 | int __attribute__((noreturn)) main(void)
| 96 | {
| 97 | uchar i;
| 98 |
| 99 | wdt_enable(WDTO_1S);
| 100 | /* Even if you don't use the watchdog, turn it off here. On newer devices,
| 101 | * the status of the watchdog (on/off, period) is PRESERVED OVER RESET!
| 102 | */
| 103 | /* RESET status: all port bits are inputs without pull-up.
| 104 | * That's the way we need D+ and D-. Therefore we don't need any
| 105 | * additional hardware initialization.
| 106 | */
| 107 | odDebugInit();
| 108 | DBG1(0x00, 0, 0); /* debug output: main starts */
| 109 | usbInit();
| 110 | usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */
| 111 | i = 0;
| 112 | while(--i){ /* fake USB disconnect for > 250 ms */
| 113 | wdt_reset();
| 114 | _delay_ms(1);
| 115 | }
| 116 | usbDeviceConnect();
| 117 | LED_PORT_DDR |= _BV(LED_BIT); /* make the LED bit an output */
| 118 | sei();
| 119 | DBG1(0x01, 0, 0); /* debug output: main loop starts */
| 120 | for(;;){ /* main event loop */
| 121 | #if 0 /* this is a bit too aggressive for a debug output */
| 122 | DBG2(0x02, 0, 0); /* debug output: main loop iterates */
| 123 | #endif
| 124 | wdt_reset();
| 125 | usbPoll();
| 126 | }
| 127 | }
| 128 |
| 129 | /* ------------------------------------------------------------------------- */
|
and here the code for the client.
set_led.cpp 1 | /* Name: set-led.c
| 2 | * Project: hid-custom-rq example
| 3 | * Author: Christian Starkjohann
| 4 | * Creation Date: 2008-04-10
| 5 | * Tabsize: 4
| 6 | * Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH
| 7 | * License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
| 8 | * This Revision: $Id: set-led.c 692 2008-11-07 15:07:40Z cs $
| 9 | */
| 10 |
| 11 | /*
| 12 | General Description:
| 13 | This is the host-side driver for the custom-class example device. It searches
| 14 | the USB for the LEDControl device and sends the requests understood by this
| 15 | device.
| 16 | This program must be linked with libusb on Unix and libusb-win32 on Windows.
| 17 | See http://libusb.sourceforge.net/ or http://libusb-win32.sourceforge.net/
| 18 | respectively.
| 19 | */
| 20 |
| 21 | #include <stdio.h>
| 22 | #include <stdlib.h>
| 23 | #include <string.h>
| 24 | //#include <usb.h> /* this is libusb */
| 25 | #include <lusb0_usb.h>
| 26 | #include "opendevice.h" /* common code moved to separate module */
| 27 |
| 28 | #include "requests.h" /* custom request numbers */
| 29 | #include "usbconfig.h" /* device's VID/PID and names */
| 30 |
| 31 | static void usage(char *name)
| 32 | {
| 33 | fprintf(stderr, "usage:\n");
| 34 | fprintf(stderr, " %s on ....... turn on LED\n", name);
| 35 | fprintf(stderr, " %s off ...... turn off LED\n", name);
| 36 | fprintf(stderr, " %s status ... ask current status of LED\n", name);
| 37 | #if ENABLE_TEST
| 38 | fprintf(stderr, " %s test ..... run driver reliability test\n", name);
| 39 | #endif /* ENABLE_TEST */
| 40 | }
| 41 |
| 42 | int main(int argc, char **argv)
| 43 | {
| 44 | usb_dev_handle *handle = NULL;
| 45 | const unsigned char rawVid[2] = {USB_CFG_VENDOR_ID}, rawPid[2] = {USB_CFG_DEVICE_ID};
| 46 | char vendor[] = {USB_CFG_VENDOR_NAME, 0}, product[] = {USB_CFG_DEVICE_NAME, 0};
| 47 | char buffer[4];
| 48 | int cnt, vid, pid, isOn;
| 49 | buffer[0] = 0;
| 50 | buffer[1] = 0;
| 51 | buffer[2] = 0;
| 52 | buffer[3] = 0;
| 53 | usb_init();
| 54 | if(argc < 2){ /* we need at least one argument */
| 55 | usage(argv[0]);
| 56 | exit(1);
| 57 | }
| 58 | /* compute VID/PID from usbconfig.h so that there is a central source of information */
| 59 | vid = rawVid[1] * 256 + rawVid[0];
| 60 | pid = rawPid[1] * 256 + rawPid[0];
| 61 | /* The following function is in opendevice.c: */
| 62 | if(usbOpenDevice(&handle, vid, vendor, pid, product, NULL, NULL, NULL) != 0){
| 63 | fprintf(stderr, "Could not find USB device \"%s\" with vid=0x%x pid=0x%x\n", product, vid, pid);
| 64 | exit(1);
| 65 | }
| 66 | /* Since we use only control endpoint 0, we don't need to choose a
| 67 | * configuration and interface. Reading device descriptor and setting a
| 68 | * configuration and interface is done through endpoint 0 after all.
| 69 | * However, newer versions of Linux require that we claim an interface
| 70 | * even for endpoint 0. Enable the following code if your operating system
| 71 | * needs it: */
| 72 | #if 0
| 73 | int retries = 1, usbConfiguration = 1, usbInterface = 0;
| 74 | if(usb_set_configuration(handle, usbConfiguration) && showWarnings){
| 75 | fprintf(stderr, "Warning: could not set configuration: %s\n", usb_strerror());
| 76 | }
| 77 | /* now try to claim the interface and detach the kernel HID driver on
| 78 | * Linux and other operating systems which support the call. */
| 79 | while((len = usb_claim_interface(handle, usbInterface)) != 0 && retries-- > 0){
| 80 | #ifdef LIBUSB_HAS_DETACH_KERNEL_DRIVER_NP
| 81 | if(usb_detach_kernel_driver_np(handle, 0) < 0 && showWarnings){
| 82 | fprintf(stderr, "Warning: could not detach kernel driver: %s\n", usb_strerror());
| 83 | }
| 84 | #endif
| 85 | }
| 86 | #endif
| 87 |
| 88 | //if(strcasecmp(argv[1], "status") == 0){
| 89 | if(_stricmp(argv[1], "status") == 0){
| 90 | cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CUSTOM_RQ_GET_STATUS, 0, 0, buffer, sizeof(buffer), 5000);
| 91 | if(cnt < 1){
| 92 | if(cnt < 0){
| 93 | fprintf(stderr, "USB error: %s\n", usb_strerror());
| 94 | }else{
| 95 | fprintf(stderr, "only %d bytes received.\n", cnt);
| 96 | }
| 97 | }else{
| 98 | printf("LED is %s\n", buffer[0] ? "on" : "off");
| 99 | }
| 100 | }else if(_stricmp(argv[1], "poti") == 0){
| 101 | cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, 3, 0, 0, buffer, sizeof(buffer), 5000);
| 102 | if(cnt < 1){
| 103 | if(cnt < 0){
| 104 | fprintf(stderr, "USB error: %s\n", usb_strerror());
| 105 | }else{
| 106 | fprintf(stderr, "only %d bytes received.\n", cnt);
| 107 | }
| 108 | }else{
| 109 | printf("LED is %d %d %d\n", buffer[0],buffer[1],buffer[2]);
| 110 | }
| 111 | // }else if((isOn = (strcasecmp(argv[1], "on") == 0)) || strcasecmp(argv[1], "off") == 0){
| 112 | }else if((isOn = (_stricmp(argv[1], "on") == 0)) || _stricmp(argv[1], "off") == 0){
| 113 | cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_OUT, CUSTOM_RQ_SET_STATUS, isOn, 0, buffer, 0, 5000);
| 114 | if(cnt < 0){
| 115 | fprintf(stderr, "USB error: %s\n", usb_strerror());
| 116 | }
| 117 | #if ENABLE_TEST
| 118 | }else if(strcasecmp(argv[1], "test") == 0){
| 119 | int i;
| 120 | srandomdev();
| 121 | for(i = 0; i < 50000; i++){
| 122 | int value = random() & 0xffff, index = random() & 0xffff;
| 123 | int rxValue, rxIndex;
| 124 | if((i+1) % 100 == 0){
| 125 | fprintf(stderr, "\r%05d", i+1);
| 126 | fflush(stderr);
| 127 | }
| 128 | cnt = usb_control_msg(handle, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_ENDPOINT_IN, CUSTOM_RQ_ECHO, value, index, buffer, sizeof(buffer), 5000);
| 129 | if(cnt < 0){
| 130 | fprintf(stderr, "\nUSB error in iteration %d: %s\n", i, usb_strerror());
| 131 | break;
| 132 | }else if(cnt != 4){
| 133 | fprintf(stderr, "\nerror in iteration %d: %d bytes received instead of 4\n", i, cnt);
| 134 | break;
| 135 | }
| 136 | rxValue = ((int)buffer[0] & 0xff) | (((int)buffer[1] & 0xff) << 8);
| 137 | rxIndex = ((int)buffer[2] & 0xff) | (((int)buffer[3] & 0xff) << 8);
| 138 | if(rxValue != value || rxIndex != index){
| 139 | fprintf(stderr, "\ndata error in iteration %d:\n", i);
| 140 | fprintf(stderr, "rxValue = 0x%04x value = 0x%04x\n", rxValue, value);
| 141 | fprintf(stderr, "rxIndex = 0x%04x index = 0x%04x\n", rxIndex, index);
| 142 | }
| 143 | }
| 144 | fprintf(stderr, "\nTest completed.\n");
| 145 | #endif /* ENABLE_TEST */
| 146 | }else{
| 147 | usage(argv[0]);
| 148 | exit(1);
| 149 | }
| 150 | usb_close(handle);
| 151 | return 0;
| 152 | }
|
Please log in before posting. Registration is free and takes only a minute.
|