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