Quantcast
Channel: Objective Development Forums
Viewing all articles
Browse latest Browse all 4524

USB Combodevice (Keyboard & Joystick) - problems with report

$
0
0
Hi all,

this is more or less a followup question to my previous thread http://forums.obdev.at/viewtopic.php?f=8&t=9311.
How does a combo-device that registers itself as keyboard (REPORT_ID = 1) and joystick (REPORT_ID = 2) have to send the usb reports in order to be working properly?

A bit of background: My goal is to develop a custom control panel (for flight simulators and the like) that is recognized by the OS as keyboard and as joystick.
The hardware part for the "keyboard" consists of 32 hardware-debounced buttons read into the microcontroller (ATMega328p) through four shift registers (74HC165N). I have the C code for a USB-keyboard working.
The hardware part for the "joystick" consists of 6 analog axis (ADC0-ADC5 on the ATMega), plus four hardware-debounced buttons (PB0, PD7, PD6, PD5). I have the C code for a USB-joystick working as well.

Now, combining these two software parts (the hardware is a single circuit anyway) I do get a device that is recognized by Windows correctly and the keyboard part works correctly. However sending the joystick report (URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER) yields an URB_FUNCTION_ABORT_PIPE from the OS to the device. Naturally, Windows fails to recognize the inputs from the joystick report.

Inside main() my report-sending routine looks like this:
    while (1) {
        wdt_reset(); // keep the watchdog happy
        usbPoll();
      
        keyboardUpdateNeeded |= readKeys(); // keyboard key presses
        joystickUpdateNeeded |= readButtons(); // joystick buttons
        // joystick analogue axis are being updated via ISR(ADC_vect) below
      
        if (keyboardUpdateNeeded && usbInterruptIsReady()) {
            usbSetInterrupt((void *) &keyboardReport, 8);
            while ( !usbInterruptIsReady() ) {usbPoll();}
            usbSetInterrupt((void *) &keyboardReport + 8, sizeof(keyboardReport) - 8);
            keyboardUpdateNeeded = 0;
        }
        if (joystickUpdateNeeded && usbInterruptIsReady()) {
            usbSetInterrupt((void *) &joystickReport, sizeof(joystickReport));
            joystickUpdateNeeded = 0;
        }
    }


My USB sniffer tells me that the joystick report (REPORT_ID=2) is indeed send correctly but as said above, Windows doesn't recognize it properly.

I tried to always send both reports when any one of them required sending like this:
    while (1) {
        wdt_reset(); // keep the watchdog happy
        usbPoll();
      
        keyboardUpdateNeeded |= readKeys(); // keyboard key presses
        joystickUpdateNeeded |= readButtons(); // joystick buttons
        // joystick analogue axis are being updated via ISR(ADC_vect) below
      
        if ((keyboardUpdateNeeded || joystickUpdateNeeded) && usbInterruptIsReady()) {
            usbSetInterrupt((void *) &keyboardReport, 8);
            while ( !usbInterruptIsReady() ) {usbPoll();}
            usbSetInterrupt((void *) &keyboardReport + 8, sizeof(keyboardReport) - 8);
            keyboardUpdateNeeded = 0;
         
            while ( !usbInterruptIsReady() ) {usbPoll();}
            usbSetInterrupt((void *) &joystickReport, sizeof(joystickReport));
            joystickUpdateNeeded = 0;
        }
    }


But doing so yields an incorrectly recognized device in Windows (yellow exclamation mark).

Any ideas? Thanks a ton :)

Viewing all articles
Browse latest Browse all 4524

Trending Articles