µC & Digital Electronics
›
Thread
[hid-custom-rq] add new Request with multiple Byte return
TG
Tobias G.
(kubax)
OP
2011-10-17 16:39
#2384934
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 }
Reply
Please log in before posting.
No account?
Registration is free and takes only a minute.
Register now