I really can't figure this one out. Been trying various options, updated to the latest version of VUSB etc. I can't see why one some keypresses are being reported, and why it works normally if plugged in after the machine has booted. Anyone got any ideas? Hardware problems seem unlikely.
Any help would be greatly appreciated.
I have attached the copy of the source code (GPLv3):
Code: Select all
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include <util/delay.h>
#include <string.h>
#include "usbdrv.h"
#include "keyboard.h"
void setCol(uchar col);
/* LED PW C1 01 - 02 C6 Column
Row C2 03 - 04 C7 Break
Row C3 05 - 06 E2 Row
Column C4 07 - 08 E1 Row
Column C5 09 - 10 E0 Column
Column C0 11 - 12 A7 Column
Column D5 13 - 14 A6 Column
Column D4 15 - 16 A5 Column
Column B4 17 - 18 A4 Column
Row B3 19 - 20 A3 SHIFT+CTRL
Row B2 21 - 22 A2 Column
LED CA B1 23 - 24 A1 Column
LED A B0 25 - 26 A0 LED SH
*/
#define LED_CAB 1
#define LED_CAP PORTB
#define LED_SHB 0
#define LED_SHP PORTA
#define LED_PWB 1
#define LED_PWP PORTC
#define NUMROWS 7
#define NUMCOLS 13
static uchar reportBuffer[8]; /* buffer for HID reports */
static uchar idleRate; /* in 4 ms units */
static uchar LEDstate = 0;
static uchar expectReport = 0;
static uchar protocolVer = 1; /* 0 is boot protocol, 1 is report protocol */
static uchar cache[NUMCOLS+1];
//static uchar testkey = K_A;
const uchar bitmask[8] = {
0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80
};
/*
{ N8 W 9 N9 T 7 0 _ I DN F10 E } // 0 E1
{ N+ 2 O N- R 6 Ne P [ U UP 1 D } // 1 E2
{ N4 F1 F8 N5 F3 F5 N2 F9 << F6 RT ESC F2 } // 2 B3
{ N6 3 F7 N7 5 F4 - ^ 8 LF Q 4 } // 3 B4
{ # S L Na G H N, ; ] N BKS SL C } // 4 D4
{ N0 Z , N1 V B N3 . / M CPY TAB SPC } // 5 C3
{ N/ A K DEL F Y Nd [] : J ENT CL X } // 6 C2
*/
const unsigned char keymap[NUMROWS][NUMCOLS] PROGMEM = {
// E0 A1 A2 C4 A4 A5 A6 A7 C0 D5 C5 B2 C6
// 0 1 2 3 4 5 6 7 8 9 A B C
{ K_NUM8, K_W, K_9, K_NUM9, K_T, K_7, K_NON, K_0, S_UND, K_I, K_DARR, K_F10, K_E }, // 0 E1
{ K_NUMp, K_2, K_O, K_NUMm, K_R, K_6, K_NUMe, K_P, K_LSQB, K_U, K_UARR, K_1, K_D }, // 1 E2
{ K_NUM4, K_F1, K_F8, K_NUM5, K_F3, K_F5, K_NUM2, K_F9, S_BKSL, K_F6, K_RARR, K_ESC, K_F2 }, // 2 B3
{ K_NUM6, K_3, K_F7, K_NUM7, K_5, K_F4, K_NON, K_MIN, S_KARA, K_8, K_LARR, K_Q, K_4 }, // 3 B4
{ S_NUMH, K_S, K_L, K_NUMa, K_G, K_H, S_NUMc, K_SCOL, K_RSQB, K_N, K_BKS, S_SLK, K_C }, // 4 D4
{ K_NUM0, K_Z, K_COMM, K_NUM1, K_V, K_B, K_NUM3, K_DOT, K_SLSH, K_M, S_COPY, K_TAB, K_SPC }, // 5 C3
{ K_NUMs, K_A, K_K, S_DEL, K_F, K_Y, S_NUMd, S_CODE, S_COL, K_J, K_ENT, K_CPSL, K_X }, // 6 C2
//{ K_NON, M_CTRL, K_NON, K_NON, K_NON, K_NON, K_NON, K_NON, K_NON, K_NON, K_NON, M_SHIFT,K_NON } // 7 A3
};
// SHIFT BREAK CTRL
uchar reportcount;
void addKey(uchar key)
{
if ((reportcount < 8) && (key != 0))
{
if (key > K_Modifiers)
{
switch (key)
{
case M_SHIFT:
reportBuffer[0] |= MOD_SHIFT_LEFT;
break;
case M_CTRL:
reportBuffer[0] |= MOD_CONTROL_LEFT;
break;
case M_ALT:
reportBuffer[0] |= MOD_ALT_LEFT;
break;
}
}
else
{
reportBuffer[reportcount] = key;
reportcount++;
}
}
}
static uchar scanKeys(void)
{
//uchar temp;
uchar i;
uchar bitmap[NUMCOLS+1];
uchar changed = 0;
memset(reportBuffer, 0, sizeof(reportBuffer));
memset(bitmap, 0xff, sizeof(bitmap));
for (i = 0; i < NUMCOLS; i++)
{
setCol(i);
if (!(PINE & (1<<1))) bitmap[i] &= ~(1<<0);
if (!(PINE & (1<<2))) bitmap[i] &= ~(1<<1);
if (!(PINB & (1<<3))) bitmap[i] &= ~(1<<2);
if (!(PINB & (1<<4))) bitmap[i] &= ~(1<<3);
if (!(PIND & (1<<4))) bitmap[i] &= ~(1<<4);
if (!(PINC & (1<<3))) bitmap[i] &= ~(1<<5);
if (!(PINC & (1<<2))) bitmap[i] &= ~(1<<6);
if (bitmap[i] ^ cache[i]) changed = 1;
}
// CTRL
setCol(1);
if (!(PINA & (1<<3)))
{
bitmap[NUMCOLS] &= ~(1<<2);
}
// SHIFT
setCol(11);
if (!(PINA & (1<<3)))
{
bitmap[NUMCOLS] &= ~(1<<0);
}
// BREAK
LED_PWP &= ~(1<<LED_PWB);
if (!(PINC & (1<<7)))
{
bitmap[NUMCOLS] &= ~(1<<1);
}
if (LEDstate & LED_SCROLL) // reset power LED state
LED_PWP |= (1<<LED_PWB);
else
LED_PWP &= ~(1<<LED_PWB);
if (bitmap[NUMCOLS] ^ cache[NUMCOLS]) changed = 1;
if (changed)
{
reportcount = 1;
for (i = 0; i < NUMCOLS; i++)
{
//if (!(bitmap[i])){ addKey(testkey); testkey++; }
if (!(bitmap[i] & (1<<0))) addKey(pgm_read_byte(&keymap[0][i]));
if (!(bitmap[i] & (1<<1))) addKey(pgm_read_byte(&keymap[1][i]));
if (!(bitmap[i] & (1<<2))) addKey(pgm_read_byte(&keymap[2][i]));
if (!(bitmap[i] & (1<<3))) addKey(pgm_read_byte(&keymap[3][i]));
if (!(bitmap[i] & (1<<4))) addKey(pgm_read_byte(&keymap[4][i]));
if (!(bitmap[i] & (1<<5))) addKey(pgm_read_byte(&keymap[5][i]));
if (!(bitmap[i] & (1<<6))) addKey(pgm_read_byte(&keymap[6][i]));
}
if (!(bitmap[NUMCOLS] & (1<<0))) addKey(M_SHIFT);
if (!(bitmap[NUMCOLS] & (1<<2))) addKey(M_CTRL);
if (!(bitmap[NUMCOLS] & (1<<1))) addKey(K_F12); // K_BREAK
memcpy(cache, bitmap, sizeof(bitmap));
return 1;
}
else
return 0;
}
void setCol(uchar col)
{
PORTA |= 0b11110110;
DDRA &= ~0b11110110;
PORTB |= (1<<2);
DDRB &= ~(1<<2);
PORTC |= 0b01110001;
DDRC &= ~0b01110001;
PORTD |= (1<<5);
DDRD &= ~(1<<5);
PORTE |= (1<<0);
DDRE &= ~(1<<0);
switch (col)
{
case 0:
PORTE &= ~(1<<0);
DDRE |= (1<<0);
break;
case 1:
PORTA &= ~(1<<1);
DDRA |= (1<<1);
break;
case 2:
PORTA &= ~(1<<2);
DDRA |= (1<<2);
break;
case 3:
PORTC &= ~(1<<4);
DDRC |= (1<<4);
break;
case 4:
PORTA &= ~(1<<4);
DDRA |= (1<<4);
break;
case 5:
PORTA &= ~(1<<5);
DDRA |= (1<<5);
break;
case 6:
PORTA &= ~(1<<6);
DDRA |= (1<<6);
break;
case 7:
PORTA &= ~(1<<7);
DDRA |= (1<<7);
break;
case 8:
PORTC &= ~(1<<0);
DDRC |= (1<<0);
break;
case 9:
PORTD &= ~(1<<5);
DDRD |= (1<<5);
break;
case 10:
PORTC &= ~(1<<5);
DDRC |= (1<<5);
break;
case 11:
PORTB &= ~(1<<2);
DDRB |= (1<<2);
break;
case 12:
PORTC &= ~(1<<6);
DDRC |= (1<<6);
break;
}
_delay_us(100);
}
/* ----------------------- hardware I/O abstraction ------------------------ */
static void hardwareInit(void)
{
PORTA = 0b11111110;
DDRA = 0b00000001;
PORTB = 0b11111111;
DDRB = 0b00000011;
PORTC = 0b11111111;
DDRC = 0b00000010;
PORTD = 0b11110011;
DDRD = 0b00000000;
PORTE = 0b11111111;
DDRE = 0b00000000;
TCCR0 = 5; // timer 0 prescaler: 1024, 45.78Hz
memset(cache, 0xff, sizeof(cache));
}
/* ------------------------------------------------------------------------- */
PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = {
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)
0x81, 0x03, // INPUT (Cnst,Var,Abs)
0x95, 0x05, // REPORT_COUNT (5)
0x75, 0x01, // REPORT_SIZE (1)
0x05, 0x08, // USAGE_PAGE (LEDs)
0x19, 0x01, // USAGE_MINIMUM (Num Lock)
0x29, 0x05, // USAGE_MAXIMUM (Kana)
0x91, 0x02, // OUTPUT (Data,Var,Abs)
0x95, 0x01, // REPORT_COUNT (1)
0x75, 0x03, // REPORT_SIZE (3)
0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
0x95, 0x06, // REPORT_COUNT (6)
0x75, 0x08, // REPORT_SIZE (8)
0x15, 0x00, // LOGICAL_MINIMUM (0)
0x25, 0x65, // LOGICAL_MAXIMUM (101)
0x05, 0x07, // USAGE_PAGE (Keyboard)
0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
0x81, 0x00, // INPUT (Data,Ary,Abs)
0xc0 // END_COLLECTION
};
/* ------------------------------------------------------------------------- */
uchar usbFunctionSetup(uchar data[8])
{
usbRequest_t *rq = (void *)data;
usbMsgPtr = reportBuffer;
if((rq->bmRequestType & USBRQ_TYPE_MASK) != USBRQ_TYPE_CLASS)
return 0;
switch (rq->bRequest)
{
case USBRQ_HID_GET_REPORT:
return sizeof(reportBuffer);
case USBRQ_HID_SET_REPORT:
if (rq->wLength.word == 1)
{
expectReport = 1;
return 0xFF;
}
return 0;
case USBRQ_HID_GET_IDLE:
usbMsgPtr = &idleRate;
return 1;
case USBRQ_HID_SET_IDLE:
idleRate = rq->wValue.bytes[1];
return 0;
case USBRQ_HID_GET_PROTOCOL:
if (rq->wValue.bytes[1] < 1)
protocolVer = rq->wValue.bytes[1];
return 0;
case USBRQ_HID_SET_PROTOCOL:
usbMsgPtr = &protocolVer;
return 1;
default:
return 0;
}
}
/* ------------------------------------------------------------------------- */
uchar usbFunctionWrite(uchar *data, uchar len) {
if ((expectReport) && (len == 1)) {
// Set the state of all 5 LEDs
LEDstate = data[0];
if (LEDstate & LED_CAPS)
LED_CAP &= ~(1<<LED_CAB);
else
LED_CAP |= (1<<LED_CAB);
// Shift Lock LED is reversed Num Lock
if (LEDstate & LED_NUM)
LED_SHP |= (1<<LED_SHB);
else
LED_SHP &= ~(1<<LED_SHB);
// Power LED is reversed Scroll Lock
if (LEDstate & LED_SCROLL)
LED_PWP |= (1<<LED_PWB);
else
LED_PWP &= ~(1<<LED_PWB);
}
expectReport = 0;
return 0x01;
}
/* ------------------------------------------------------------------------- */
int main(void)
{
uchar updateNeeded = 0;
uchar idleCounter = 0;
hardwareInit();
usbInit();
cli(); // disable interrupts
usbDeviceDisconnect();
DDRD |= (1<<2) | (1<<3); // USB reset
_delay_ms(255); // disconnect for >250ms
usbDeviceConnect();
DDRD &= ~((1<<2) | (1<<3)); // clear reset
sei(); // restart interrupts
LED_PWP &= ~(1<<LED_PWB);
LED_CAP |= (1<<LED_CAB);
//LED_SHP |= (1<<LED_SHB);
LED_SHP &= ~(1<<LED_SHB);
for(;;)
{
usbPoll();
updateNeeded = scanKeys();
// Check timer if we need periodic reports
if (TIFR & (1 << TOV0))
{
// Reset flag
TIFR = 1 << TOV0;
// Do we need periodic reports?
if (idleRate != 0)
{
if (idleCounter > 4)
{
// Yes, but not yet
// 22 ms in units of 4 ms
idleCounter -= 5;
}
else
{
// Yes, it is time now
updateNeeded = 1;
idleCounter = idleRate;
}
}
}
if (updateNeeded && usbInterruptIsReady())
{
updateNeeded = 0;
usbSetInterrupt(reportBuffer, sizeof(reportBuffer));
}
}
return 0;
}