HID keyboard atmega168p - Solved

General discussions about V-USB, our firmware-only implementation of a low speed USB device on Atmel's AVR microcontrollers
Post Reply
subnex
Posts: 1
Joined: Tue May 03, 2011 12:35 am

HID keyboard atmega168p - Solved

Post by subnex » Tue May 03, 2011 12:42 am

I am working on a HID keyboard on the atmega 168p running at 16 MHz.
So far, i've successfully transmittd keycommands to my computer, so that part is working.

My problem is, that once i send a command, the avr just keeps transmitting the same command to the computer. I can't really figure out what is wrong.
My code is heavily inspired from the HID keyboard examples from the obdev.at site.

My main looks like the following:

Code: Select all

#include "common.h"
#include "keycodes.h"

#include "avr/pgmspace.h"
#include "usbdrv/usbdrv.h"
#include "usbdrv/oddebug.h"

#define ReportDescriptor usbHidReportDescriptor

PROGMEM
#include "ir_keyboard_2.hid.h" // reportdescriptor
#define STATIC_ASSERT(expr) extern char static_assert[ (!!(expr))*2 - 1]

STATIC_ASSERT(sizeof(usbHidReportDescriptor) == USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH);

static uchar reportBuffer[2] = {0,0};
static uchar idleRate;
static uchar irKey = 0;
static uchar ir_key_pressed = 0;

uchar irKeyLookup(uchar irkey){
  volatile uchar key = 0;
  switch(irkey){
  case 0x60: //prev
    key = 1;
    break;
  case 0xA0: // next
    key = 2;
    break;
  case 0x40: // stop
    key = 8;
    break;
  case 0x80: // play
    key = 4;
    break;
  default:
    key = 0;
    break;
  }
  return key;
}

typedef enum{
  reportid_none = 0,
  reportid_key = 1
} report_id_t;

static void buildReport(report_id_t id,  uchar key)
{
  reportBuffer[0] = id;
  if (id == reportid_key){
    reportBuffer[1] = key;
  }
}

usbMsgLen_t 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(rq->wValue.bytes[0], ir_key_pressed);
      DBG1(0x50, &rq->bRequest, 1);
      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){
  cli(); // Disable interrupts

  usbDeviceDisconnect();  /* enforce re-enumeration, do this while interrupts are disabled! */   
  usbInit();
  odDebugInit();
  IR_init();
   
  /* Port initiation*/
  bs(DDRC,3);
  bs(DDRC,4);
  bs(DDRC,5);
  PORTC &= ~(1<<3);
  PORTC = ~PORTC;

  /* Timer 0 initiation */
  TCCR0B = _BV(2) | _BV(0); // 16E6/(1024*256) = 61 ~ 16 ms

  /* Variable initiation */
  char buf[64];
  uchar idleCounter = 0;
  static report_id_t keyPressed = reportid_none;

  _delay_ms(250);

  usbDeviceConnect();

  sei(); // Reenable interrupts

  DBG1(0x00, 0, 0);       /* debug output: main starts */
   
  while(1){
    usbPoll(); // must be called at least every 50 ms
    bs(PORTC,5); // Clear the indicator led

    if(IR_packetReady()){ // check for packets from remote
      irKey = IR_getCode();
      keyPressed = reportid_key;
    }

    if(TIFR0 & (1<<TOV0)){   // 16 ms timer
   
      TIFR0 = 1<<TOV0;
      if(idleRate != 0){
   if(idleCounter > 4){
     idleCounter -= 5;   // 16 ms in units of 4 ms
   }else{
     idleCounter = idleRate;
     //            keyPressed = reportid_none;
   }
      }
    }

    if(keyPressed && usbInterruptIsReady()){
      DBG1(0x19, &irKey,1); // debug output
      ir_key_pressed = irKeyLookup(irKey);
      buildReport(keyPressed , ir_key_pressed);
      usbSetInterrupt((void *)&reportBuffer, sizeof(reportBuffer));
      keyPressed = reportid_none;
    }
  }
   
}
 
Last edited by subnex on Sat Jan 21, 2012 3:26 pm, edited 1 time in total.

todor_kt

Re: HID keyboard atmega168p

Post by todor_kt » Tue Jun 21, 2011 10:02 am

When a keyboard key is pressed, you send its code to the PC. Once sent, the code should be "terminated", so the PC knows, that the key is released. So when the key is released, you should send to the PC 0x00 once in the keycode array index, that was used to send the key active.

Post Reply