multiply keypresses in USBkeyboard

General discussions about V-USB, our firmware-only implementation of a low speed USB device on Atmel's AVR microcontrollers
Post Reply
Mr Onak

multiply keypresses in USBkeyboard

Post by Mr Onak » Sun Sep 07, 2014 11:41 am

Hi all,

I've successfully taken the keyboard example code and modified it to run on an ATTiny2313 with keys being read through shiftregisters instead of connecting them directly to IO pins.

What I'm struggling with however is to send multiple pressed keys to the computer in a single report. I've checked the code for the C64 keyboard and although the code is very different from mine I don't see something I'm missing. My software doesn't work with modifier keys though since I'm not implementing a full keyboard but a custom game panel.

Any hints would be greatly appreciated...

Trying to keep the pasted code short here, let me know if you want me to post the whole script:

Code: Select all

#define KEYCODE_NUM 6
typedef struct {
    uint8_t modifier;
    uint8_t reserved;
    uint8_t keycode[KEYCODE_NUM];
} keyboard_report_t;

static keyboard_report_t keyboard_report; // sent to PC

#define KEY_A                      4
#define KEY_B                      5
#define KEY_C                      6
#define KEY_D                      7
#define KEY_E                      8
#define KEY_F                      9
#define KEY_G                   10
#define KEY_H                   11
// [...]

#define NUMBER_OF_BUTTONS 8
// data type to use for storing the shift register data - make sure the datatype has >= bits than NUMBER_OF_BUTTONS
#define KEYS_DATATYPE uint8_t

uchar buttonCodes[NUMBER_OF_BUTTONS] = {KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H};

#define STATE_WAIT 0
#define STATE_SEND_KEY 1
#define STATE_RELEASE_KEY 2
uchar state       = STATE_WAIT;

// this reads the shift registers and fills the report buffer for USB directly to save some bytes
void readShiftRegisters() {
    uchar i;
    uchar offset = 0;
   
    // Trigger a parallel load to latch the state of the data lines
    PORT_SHIFTREG &= ~(1 << PIN_SHLD);
    // the SN74HCT165N is fast enough so we don't need a delay, this saves a few bytes
    //_delay_us(PULSE_WIDTH_USEC);
    PORT_SHIFTREG |= (1 << PIN_SHLD);

    // Loop to read each bit value from the serial out line of the shift register
    // we forge the keyboard report directly, to safe some memory
    for (i = 0; i < NUMBER_OF_BUTTONS; i++) {
        if (PORT_IN_SHIFTREG & (1 << PIN_QH) && offset < KEYCODE_NUM) {
            state       = STATE_SEND_KEY;
            keyboard_report.keycode[offset] = buttonCodes[i];
            offset++;
        }

        // Pulse the clock (rising edge shifts the next bit).
        PORT_SHIFTREG |= (1 << PIN_CLK);
        // the SN74HCT165N is fast enough so we don't need a delay, this saves a few bytes
        //_delay_us(PULSE_WIDTH_USEC);
        PORT_SHIFTREG &= ~(1 << PIN_CLK);
    }
}

int main() {
    // ...
    while (1) {
        wdt_reset(); // keep the watchdog happy
        usbPoll();
      
        // clear the USB report
        for (i = 0; i<sizeof (keyboard_report); i++) {
            ((uchar *) & keyboard_report)[i] = 0;
        }     
        keyboard_report.modifier = 0;

        // this fills the keyboard register directly
        readShiftRegisters();
   
        // characters are sent when messageState == STATE_SEND
        if (usbInterruptIsReady() && state != STATE_WAIT) {
            // we need this simple state-machine to send a single empty report (for "keyUp") when all buttons are unpressed
            switch (state) {
                case STATE_SEND_KEY:
                    state = STATE_RELEASE_KEY;
                    break;
                case STATE_RELEASE_KEY:
                default:
                    state = STATE_WAIT;
            }

            usbSetInterrupt((void *) &keyboard_report, sizeof (keyboard_report));
        }
    }

    return 0;
}


Thanks a lot for any hints :)

Mr Onak

Re: multiply keypresses in USBkeyboard

Post by Mr Onak » Sun Sep 07, 2014 1:01 pm

Okay after using an USB analyzer this gets even more confusing.

When I press two buttons on the custom controller that equal the keys 'A' and 'D' then the device sends this:
00 00 04 07 00 00 00 00

In my eyes that's correct: No modifier, 2nd byte is null, first key is 04 (a), second key is 07 (d), all other keys are null.

What am I missing?

Mr Onak

Re: multiply keypresses in USBkeyboard

Post by Mr Onak » Sun Sep 07, 2014 1:08 pm

Argh... never mind. The code is fine, I had a floating GPIO somewhere that messed it up.

Its working now :)

Post Reply