UART - > Hidkeys

General discussions about V-USB, our firmware-only implementation of a low speed USB device on Atmel's AVR microcontrollers
Post Reply
ps1x
Posts: 7
Joined: Wed Apr 09, 2008 8:13 am

UART - > Hidkeys

Post by ps1x » Fri Jan 30, 2009 11:20 am

Hello!

I'm trying to make UART to HID keyboard translator based on HIDKeys example. Also we recive numbers (ASCII from 0x30 to 0x39) or Carrige Return (0x0D) and tranclate it to USB hid where only difference is CR (Enter) is 0x40;
I probably have error somwhere in my code, couse when i attach it send 0,1,2,3,4,5,6,7,8,9, CR i recieve in my PC strange symbols like "v","m" or even it swithces Keyboard language. I am bad in AVR-GCC and i promise you can help me with following code:

Code: Select all


#define F_CPU   12000000L

#define BAUDRATE 600
//calculate UBRR value
#define UBRRVAL ((F_CPU/(BAUDRATE*16UL))-1)

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <avr/wdt.h>

#include "usbdrv.h"
#include "oddebug.h"

volatile uchar nextDigit;


static void hardwareInit(void)
{
uchar   i, j;
 
//REMOVED SOME INITIALISATION OF PORTS HERE

    PORTD = 0xfa;   /* 1111 1010 bin: activate pull-ups except on USB lines */
    DDRD = 0x07;    /* 0000 0111 bin: all pins input except USB (-> USB reset) */
   j = 0;
   while(--j){     /* USB Reset by device only required on Watchdog Reset */
      i = 0;
      while(--i); /* delay >10ms for USB reset */
   }
    DDRD = 0x02;    /* 0000 0010 bin: remove USB reset condition */


   //Set baud rate
   UBRRL=(uint8_t)UBRRVAL;      //low byte
   UBRRH=(UBRRVAL>>8);   //high byte
   //Set data frame format: asynchronous mode,no parity, 1 stop bit, 8 bit size
   UCSRC=(1<<URSEL)|(0<<UMSEL)|(0<<UPM1)|(0<<UPM0)|
      (0<<USBS)|(0<<UCSZ2)|(1<<UCSZ1)|(1<<UCSZ0);   
   //Enable Transmitter and Receiver and Interrupt on receive complete
   UCSRB=(1<<RXEN)|(1<<RXCIE);//|(1<<TXEN);
   //enable global interrupts
}

/* ------------------------------------------------------------------------- */


uint8_t USART_vReceiveByte(void)  //receive one byte
{
    // Wait until a byte has been received
    while((UCSRA&(1<<RXC)) == 0);
    // Return received data
    return UDR;
}

ISR(USART_RXC_vect) //uart interrupt routine
{
uchar dat;
   //receive destination address
   dat=USART_vReceiveByte();
   //receive data
   if ((0x2f<dat)& (dat<0x40)){  // if we have number, just paste it to output
      nextDigit = dat;
   }
   else if (dat == 0x0d){  //else if we have CR put Enter key
      nextDigit = 0x40;
   }

            // OTHER KEYS SHOULD BE IGNORED
}

/* ------------------------------------------------------------------------- */
/* ----------------------------- USB interface ----------------------------- */
/* ------------------------------------------------------------------------- */

static uchar    reportBuffer[2];    /* buffer for HID reports */
static uchar    idleRate;           /* in 4 ms units */

PROGMEM char usbHidReportDescriptor[35] = { /* USB report descriptor */
    0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    0x09, 0x06,                    // USAGE (Keyboard)
    0xa1, 0x01,                    // COLLECTION (Application)
    0x05, 0x07,                    //   USAGE_PAGE (Keyboard)
    0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)
    0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)
    0x15, 0x00,                    //   LOGICAL_MINIMUM (0)
    0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)
    0x75, 0x01,                    //   REPORT_SIZE (1)
    0x95, 0x08,                    //   REPORT_COUNT (8)
    0x81, 0x02,                    //   INPUT (Data,Var,Abs)
    0x95, 0x01,                    //   REPORT_COUNT (1)
    0x75, 0x08,                    //   REPORT_SIZE (8)
    0x25, 0x65,                    //   LOGICAL_MAXIMUM (101)
    0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated))
    0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)
    0x81, 0x00,                    //   INPUT (Data,Ary,Abs)
    0xc0                           // END_COLLECTION
};
/* We use a simplifed keyboard report descriptor which does not support the
 * boot protocol. We don't allow setting status LEDs and we only allow one
 * simultaneous key press (except modifiers). We can therefore use short
 * 2 byte input reports.
 * The report descriptor has been created with usb.org's "HID Descriptor Tool"
 * which can be downloaded from http://www.usb.org/developers/hidpage/.
 * Redundant entries (such as LOGICAL_MINIMUM and USAGE_PAGE) have been omitted
 * for the second INPUT item.
 */

/* Keyboard usage values, see usb.org's HID-usage-tables document, chapter
 * 10 Keyboard/Keypad Page for more codes.
 */
#define MOD_CONTROL_LEFT    (1<<0)
#define MOD_SHIFT_LEFT      (1<<1)
#define MOD_ALT_LEFT        (1<<2)
#define MOD_GUI_LEFT        (1<<3)
#define MOD_CONTROL_RIGHT   (1<<4)
#define MOD_SHIFT_RIGHT     (1<<5)
#define MOD_ALT_RIGHT       (1<<6)
#define MOD_GUI_RIGHT       (1<<7)

#define KEY_1       30
#define KEY_2       31
#define KEY_3       32
#define KEY_4       33
#define KEY_5       34
#define KEY_6       35
#define KEY_7       36
#define KEY_8       37
#define KEY_9       38
#define KEY_0       39
#define KEY_ENTER 40

#define KEY_F1      58
#define KEY_F2      59
#define KEY_F3      60
#define KEY_F4      61
#define KEY_F5      62
#define KEY_F6      63
#define KEY_F7      64
#define KEY_F8      65
#define KEY_F9      66
#define KEY_F10     67
#define KEY_F11     68
#define KEY_F12     69

static const uchar  keyReport[NUM_KEYS + 1][2] PROGMEM = {
/* none */  {0, 0},                     /* no key pressed */
/*  1 */    {MOD_SHIFT_LEFT, KEY_A},
/*  2 */    {MOD_SHIFT_LEFT, KEY_B},
/*  3 */    {MOD_SHIFT_LEFT, KEY_C},
/*  4 */    {MOD_SHIFT_LEFT, KEY_D},
/*  5 */    {MOD_SHIFT_LEFT, KEY_E},
/*  6 */    {MOD_SHIFT_LEFT, KEY_F},
/*  7 */    {MOD_SHIFT_LEFT, KEY_G},
/*  8 */    {MOD_SHIFT_LEFT, KEY_H},
/*  9 */    {MOD_SHIFT_LEFT, KEY_I},
/* 10 */    {MOD_SHIFT_LEFT, KEY_J},
/* 11 */    {MOD_SHIFT_LEFT, KEY_K},
/* 12 */    {MOD_SHIFT_LEFT, KEY_L},
/* 13 */    {MOD_SHIFT_LEFT, KEY_M},
/* 14 */    {MOD_SHIFT_LEFT, KEY_N},
/* 15 */    {MOD_SHIFT_LEFT, KEY_O},
/* 16 */    {MOD_SHIFT_LEFT, KEY_P},
/* 17 */    {MOD_SHIFT_LEFT, KEY_Q},
};

static void buildReport(uchar key)
{
/* This (not so elegant) cast saves us 10 bytes of program memory */
    *(int *)reportBuffer = pgm_read_word(keyReport[key]);
}

uchar   usbFunctionSetup(uchar data[8])
{
usbRequest_t    *rq = (void *)data;

    usbMsgPtr = reportBuffer;
    if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){    /* class request type */
        if(rq->bRequest == USBRQ_HID_GET_REPORT){  /* wValue: ReportType (highbyte), ReportID (lowbyte) */
            /* we only have one report type, so don't look at wValue */
            buildReport(nextDigit);
            return sizeof(reportBuffer);
        }else if(rq->bRequest == USBRQ_HID_GET_IDLE){
            usbMsgPtr = &idleRate;
            return 1;
        }else if(rq->bRequest == USBRQ_HID_SET_IDLE){
            idleRate = rq->wValue.bytes[1];
        }
    }else{
        /* no vendor specific requests implemented */
    }
   return 0;
}

/* ------------------------------------------------------------------------- */

int   main(void)
{
uchar   key, lastKey = 0, keyDidChange = 0;

   wdt_enable(WDTO_2S);
    hardwareInit();
   odDebugInit();
   usbInit();
   sei();
    for(;;){   /* main event loop */
      wdt_reset();
      usbPoll();
        key = nextDigit;
      nextDigit=0;
        if(lastKey != key){
            lastKey = key;
            keyDidChange = 1;
        }
        if(keyDidChange && usbInterruptIsReady()){
            keyDidChange = 0;
            /* use last key and not current key status in order to avoid lost
               changes in key status. */
            buildReport(lastKey);
            usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
        }
   }
   return 0;
}

/* ------------------------------------------------------------------------- */


Thank you!

Grendel
Rank 4
Rank 4
Posts: 167
Joined: Sat Dec 16, 2006 9:53 pm
Location: Oregon, USA
Contact:

Post by Grendel » Tue Feb 03, 2009 3:28 am

I don't see the defines for KEY_A..KEY_Q. Assuming they ae correct, I bet the index you pass into buildReport() isn't in the range 0..17.

ps1x
Posts: 7
Joined: Wed Apr 09, 2008 8:13 am

Post by ps1x » Tue Feb 03, 2009 11:03 am

Grendel wrote:I don't see the defines for KEY_A..KEY_Q. Assuming they ae correct, I bet the index you pass into buildReport() isn't in the range 0..17.

I dont use letters, as you see in recieving routine i only accept numbers and CR. And i think there is nowhere to change them during programm flow, so i dont have idea.

hogeman

Post by hogeman » Wed Feb 04, 2009 12:10 pm

usage id is decimal, ascii character code is hex.

and...
my project
http://gis.sakura.ne.jp/sunkey/sunkey_e.html
converts UART to HID keys.

Grendel
Rank 4
Rank 4
Posts: 167
Joined: Sat Dec 16, 2006 9:53 pm
Location: Oregon, USA
Contact:

Post by Grendel » Thu Feb 05, 2009 1:15 am

ps1x wrote:
Grendel wrote:I don't see the defines for KEY_A..KEY_Q. Assuming they ae correct, I bet the index you pass into buildReport() isn't in the range 0..17.

I dont use letters, as you see in recieving routine i only accept numbers and CR. And i think there is nowhere to change them during programm flow, so i dont have idea.

They are used in the keyReport array. So either 1. these values are not what they claim to be or 2. the index value used to pull these values out of the array is too big (ie. > 17). If you receive an ASCII code and use that to pull something out of the array you'll see all kinds of interesting, undefined results.

Edit: yep, 2. is what happens. You need to map the '0'-'9' and 'CR' codes to array indexes or change buildReport() entirely.

Guest

Post by Guest » Thu Feb 05, 2009 7:54 am

hogeman wrote:usage id is decimal, ascii character code is hex.

really, so i try to equal 0x40 and 40 :P thank you

Post Reply