EmbDev.net

Forum: µC & Digital Electronics [hid-custom-rq] add new Request with multiple Byte return


von Tobias G. (kubax)


Rate this post
useful
not useful
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.
Existing account
Do you have a Google/GoogleMail account? No registration required!
Log in with Google account
No account? Register here.