it supports four keyboards and two cascaded hubstags/v2.9
@@ -110,7 +110,7 @@ OPT_DEFS += -DBOOTLOADER_SIZE=4096 | |||
SRC = \ | |||
keymap_common.c \ | |||
matrix.c \ | |||
usb_usb.cpp \ | |||
main.cpp | |||
ifdef KEYMAP |
@@ -3,17 +3,9 @@ | |||
#include <avr/power.h> | |||
#include <util/delay.h> | |||
// USB HID host | |||
#include "Usb.h" | |||
#include "usbhub.h" | |||
#include "hid.h" | |||
#include "hidboot.h" | |||
#include "parser.h" | |||
// LUFA | |||
#include "lufa.h" | |||
#include "timer.h" | |||
#include "sendchar.h" | |||
#include "debug.h" | |||
#include "keyboard.h" | |||
@@ -64,22 +56,6 @@ static void LUFA_setup(void) | |||
/* | |||
* USB Host Shield HID keyboard | |||
*/ | |||
USB usb_host; | |||
USBHub hub1(&usb_host); | |||
HIDBoot<HID_PROTOCOL_KEYBOARD> kbd(&usb_host); | |||
KBDReportParser kbd_parser; | |||
void led_set(uint8_t usb_led) | |||
{ | |||
kbd.SetReport(0, 0, 2, 0, 1, &usb_led); | |||
} | |||
int main(void) | |||
{ | |||
// LED for debug | |||
@@ -94,10 +70,6 @@ int main(void) | |||
LUFA_setup(); | |||
// USB Host Shield setup | |||
usb_host.Init(); | |||
kbd.SetReportParser(0, (HIDReportParser*)&kbd_parser); | |||
/* NOTE: Don't insert time consuming job here. | |||
* It'll cause unclear initialization failure when DFU reset(worm start). | |||
*/ | |||
@@ -111,17 +83,9 @@ int main(void) | |||
debug("init: done\n"); | |||
uint16_t timer; | |||
for (;;) { | |||
keyboard_task(); | |||
timer = timer_read(); | |||
usb_host.Task(); | |||
timer = timer_elapsed(timer); | |||
if (timer > 100) { | |||
debug("host.Task: "); debug_hex16(timer); debug("\n"); | |||
} | |||
#if !defined(INTERRUPT_CONTROL_ENDPOINT) | |||
// LUFA Task for control request | |||
USB_USBTask(); |
@@ -1,133 +0,0 @@ | |||
/* | |||
Copyright 2011 Jun Wako <[email protected]> | |||
This program is free software: you can redistribute it and/or modify | |||
it under the terms of the GNU General Public License as published by | |||
the Free Software Foundation, either version 2 of the License, or | |||
(at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU General Public License for more details. | |||
You should have received a copy of the GNU General Public License | |||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include <stdint.h> | |||
#include <stdbool.h> | |||
#include "usb_hid.h" | |||
#include "keycode.h" | |||
#include "util.h" | |||
#include "print.h" | |||
#include "debug.h" | |||
#include "matrix.h" | |||
/* KEY CODE to Matrix | |||
* | |||
* HID keycode(1 byte): | |||
* Higher 5 bits indicates ROW and lower 3 bits COL. | |||
* | |||
* 7 6 5 4 3 2 1 0 | |||
* +---------------+ | |||
* | ROW | COL | | |||
* +---------------+ | |||
* | |||
* Matrix space(16 * 16): | |||
* r\c0123456789ABCDEF | |||
* 0 +----------------+ | |||
* : | | | |||
* : | | | |||
* 16 +----------------+ | |||
*/ | |||
#define ROW_MASK 0xF0 | |||
#define COL_MASK 0x0F | |||
#define CODE(row, col) (((row) << 4) | (col)) | |||
#define ROW(code) (((code) & ROW_MASK) >> 4) | |||
#define COL(code) ((code) & COL_MASK) | |||
#define ROW_BITS(code) (1 << COL(code)) | |||
uint8_t matrix_rows(void) { return MATRIX_ROWS; } | |||
uint8_t matrix_cols(void) { return MATRIX_COLS; } | |||
void matrix_init(void) {} | |||
bool matrix_has_ghost(void) { return false; } | |||
static bool matrix_is_mod =false; | |||
uint8_t matrix_scan(void) { | |||
static uint16_t last_time_stamp = 0; | |||
if (last_time_stamp != usb_hid_time_stamp) { | |||
last_time_stamp = usb_hid_time_stamp; | |||
matrix_is_mod = true; | |||
} else { | |||
matrix_is_mod = false; | |||
} | |||
return 1; | |||
} | |||
bool matrix_is_modified(void) { | |||
return matrix_is_mod; | |||
} | |||
bool matrix_is_on(uint8_t row, uint8_t col) { | |||
uint8_t code = CODE(row, col); | |||
if (IS_MOD(code)) { | |||
if (usb_hid_keyboard_report.mods & ROW_BITS(code)) { | |||
return true; | |||
} | |||
} | |||
for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { | |||
if (usb_hid_keyboard_report.keys[i] == code) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
matrix_row_t matrix_get_row(uint8_t row) { | |||
uint16_t row_bits = 0; | |||
if (IS_MOD(CODE(row, 0)) && usb_hid_keyboard_report.mods) { | |||
row_bits |= usb_hid_keyboard_report.mods; | |||
} | |||
for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { | |||
if (IS_ANY(usb_hid_keyboard_report.keys[i])) { | |||
if (row == ROW(usb_hid_keyboard_report.keys[i])) { | |||
row_bits |= ROW_BITS(usb_hid_keyboard_report.keys[i]); | |||
} | |||
} | |||
} | |||
return row_bits; | |||
} | |||
uint8_t matrix_key_count(void) { | |||
uint8_t count = 0; | |||
count += bitpop(usb_hid_keyboard_report.mods); | |||
for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { | |||
if (IS_ANY(usb_hid_keyboard_report.keys[i])) { | |||
count++; | |||
} | |||
} | |||
return count; | |||
} | |||
void matrix_print(void) { | |||
print("\nr/c 01234567\n"); | |||
for (uint8_t row = 0; row < matrix_rows(); row++) { | |||
phex(row); print(": "); | |||
pbin_reverse(matrix_get_row(row)); | |||
#ifdef MATRIX_HAS_GHOST | |||
if (matrix_has_ghost_in_row(row)) { | |||
print(" <ghost"); | |||
} | |||
#endif | |||
print("\n"); | |||
} | |||
} |
@@ -0,0 +1,221 @@ | |||
/* | |||
Copyright 2016 Jun Wako <[email protected]> | |||
This program is free software: you can redistribute it and/or modify | |||
it under the terms of the GNU General Public License as published by | |||
the Free Software Foundation, either version 2 of the License, or | |||
(at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU General Public License for more details. | |||
You should have received a copy of the GNU General Public License | |||
along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include <stdint.h> | |||
#include <stdbool.h> | |||
// USB HID host | |||
#include "Usb.h" | |||
#include "usbhub.h" | |||
#include "hid.h" | |||
#include "hidboot.h" | |||
#include "parser.h" | |||
#include "keycode.h" | |||
#include "util.h" | |||
#include "print.h" | |||
#include "debug.h" | |||
#include "timer.h" | |||
#include "matrix.h" | |||
#include "led.h" | |||
/* KEY CODE to Matrix | |||
* | |||
* HID keycode(1 byte): | |||
* Higher 5 bits indicates ROW and lower 3 bits COL. | |||
* | |||
* 7 6 5 4 3 2 1 0 | |||
* +---------------+ | |||
* | ROW | COL | | |||
* +---------------+ | |||
* | |||
* Matrix space(16 * 16): | |||
* r\c0123456789ABCDEF | |||
* 0 +----------------+ | |||
* : | | | |||
* : | | | |||
* 16 +----------------+ | |||
*/ | |||
#define ROW_MASK 0xF0 | |||
#define COL_MASK 0x0F | |||
#define CODE(row, col) (((row) << 4) | (col)) | |||
#define ROW(code) (((code) & ROW_MASK) >> 4) | |||
#define COL(code) ((code) & COL_MASK) | |||
#define ROW_BITS(code) (1 << COL(code)) | |||
// Integrated key state of all keyboards | |||
static report_keyboard_t keyboard_report; | |||
static bool matrix_is_mod =false; | |||
/* | |||
* USB Host Shield HID keyboards | |||
* This supports two cascaded hubs and four keyboards | |||
*/ | |||
USB usb_host; | |||
USBHub hub1(&usb_host); | |||
USBHub hub2(&usb_host); | |||
HIDBoot<HID_PROTOCOL_KEYBOARD> kbd1(&usb_host); | |||
HIDBoot<HID_PROTOCOL_KEYBOARD> kbd2(&usb_host); | |||
HIDBoot<HID_PROTOCOL_KEYBOARD> kbd3(&usb_host); | |||
HIDBoot<HID_PROTOCOL_KEYBOARD> kbd4(&usb_host); | |||
KBDReportParser kbd_parser1; | |||
KBDReportParser kbd_parser2; | |||
KBDReportParser kbd_parser3; | |||
KBDReportParser kbd_parser4; | |||
uint8_t matrix_rows(void) { return MATRIX_ROWS; } | |||
uint8_t matrix_cols(void) { return MATRIX_COLS; } | |||
bool matrix_has_ghost(void) { return false; } | |||
void matrix_init(void) { | |||
// USB Host Shield setup | |||
usb_host.Init(); | |||
kbd1.SetReportParser(0, (HIDReportParser*)&kbd_parser1); | |||
kbd2.SetReportParser(0, (HIDReportParser*)&kbd_parser2); | |||
kbd3.SetReportParser(0, (HIDReportParser*)&kbd_parser3); | |||
kbd4.SetReportParser(0, (HIDReportParser*)&kbd_parser4); | |||
} | |||
static void or_report(report_keyboard_t report) { | |||
// integrate reports into keyboard_report | |||
keyboard_report.mods |= report.mods; | |||
for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { | |||
if (IS_ANY(report.keys[i])) { | |||
for (uint8_t j = 0; j < KEYBOARD_REPORT_KEYS; j++) { | |||
if (! keyboard_report.keys[j]) { | |||
keyboard_report.keys[j] = report.keys[i]; | |||
break; | |||
} | |||
} | |||
} | |||
} | |||
} | |||
uint8_t matrix_scan(void) { | |||
static uint16_t last_time_stamp1 = 0; | |||
static uint16_t last_time_stamp2 = 0; | |||
static uint16_t last_time_stamp3 = 0; | |||
static uint16_t last_time_stamp4 = 0; | |||
// check report came from keyboards | |||
if (kbd_parser1.time_stamp != last_time_stamp1 || | |||
kbd_parser2.time_stamp != last_time_stamp2 || | |||
kbd_parser3.time_stamp != last_time_stamp3 || | |||
kbd_parser4.time_stamp != last_time_stamp4) { | |||
last_time_stamp1 = kbd_parser1.time_stamp; | |||
last_time_stamp2 = kbd_parser2.time_stamp; | |||
last_time_stamp3 = kbd_parser3.time_stamp; | |||
last_time_stamp4 = kbd_parser4.time_stamp; | |||
// clear and integrate all reports | |||
keyboard_report = {}; | |||
or_report(kbd_parser1.report); | |||
or_report(kbd_parser2.report); | |||
or_report(kbd_parser3.report); | |||
or_report(kbd_parser4.report); | |||
matrix_is_mod = true; | |||
dprintf("state: %02X %02X", keyboard_report.mods, keyboard_report.reserved); | |||
for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { | |||
dprintf(" %02X", keyboard_report.keys[i]); | |||
} | |||
dprint("\r\n"); | |||
} else { | |||
matrix_is_mod = false; | |||
} | |||
uint16_t timer; | |||
timer = timer_read(); | |||
usb_host.Task(); | |||
timer = timer_elapsed(timer); | |||
if (timer > 100) { | |||
dprintf("host.Task: %d\n", timer); | |||
} | |||
return 1; | |||
} | |||
bool matrix_is_modified(void) { | |||
return matrix_is_mod; | |||
} | |||
bool matrix_is_on(uint8_t row, uint8_t col) { | |||
uint8_t code = CODE(row, col); | |||
if (IS_MOD(code)) { | |||
if (keyboard_report.mods & ROW_BITS(code)) { | |||
return true; | |||
} | |||
} | |||
for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { | |||
if (keyboard_report.keys[i] == code) { | |||
return true; | |||
} | |||
} | |||
return false; | |||
} | |||
matrix_row_t matrix_get_row(uint8_t row) { | |||
uint16_t row_bits = 0; | |||
if (IS_MOD(CODE(row, 0)) && keyboard_report.mods) { | |||
row_bits |= keyboard_report.mods; | |||
} | |||
for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { | |||
if (IS_ANY(keyboard_report.keys[i])) { | |||
if (row == ROW(keyboard_report.keys[i])) { | |||
row_bits |= ROW_BITS(keyboard_report.keys[i]); | |||
} | |||
} | |||
} | |||
return row_bits; | |||
} | |||
uint8_t matrix_key_count(void) { | |||
uint8_t count = 0; | |||
count += bitpop(keyboard_report.mods); | |||
for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { | |||
if (IS_ANY(keyboard_report.keys[i])) { | |||
count++; | |||
} | |||
} | |||
return count; | |||
} | |||
void matrix_print(void) { | |||
print("\nr/c 0123456789ABCDEF\n"); | |||
for (uint8_t row = 0; row < matrix_rows(); row++) { | |||
xprintf("%02d: ", row); | |||
print_bin_reverse16(matrix_get_row(row)); | |||
print("\n"); | |||
} | |||
} | |||
void led_set(uint8_t usb_led) | |||
{ | |||
kbd1.SetReport(0, 0, 2, 0, 1, &usb_led); | |||
kbd2.SetReport(0, 0, 2, 0, 1, &usb_led); | |||
kbd3.SetReport(0, 0, 2, 0, 1, &usb_led); | |||
kbd4.SetReport(0, 0, 2, 0, 1, &usb_led); | |||
} |
@@ -28,6 +28,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#define XSTR(s) #s | |||
#ifdef __cplusplus | |||
extern "C" { | |||
#endif | |||
uint8_t bitpop(uint8_t bits); | |||
uint8_t bitpop16(uint16_t bits); | |||
uint8_t bitpop32(uint32_t bits); | |||
@@ -40,4 +44,8 @@ uint8_t bitrev(uint8_t bits); | |||
uint16_t bitrev16(uint16_t bits); | |||
uint32_t bitrev32(uint32_t bits); | |||
#ifdef __cplusplus | |||
} | |||
#endif | |||
#endif |
@@ -4,30 +4,14 @@ | |||
#include "debug.h" | |||
report_keyboard_t usb_hid_keyboard_report; | |||
uint16_t usb_hid_time_stamp; | |||
void KBDReportParser::Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf) | |||
{ | |||
bool is_error = false; | |||
report_keyboard_t *report = (report_keyboard_t *)buf; | |||
::memcpy(&report, buf, sizeof(report_keyboard_t)); | |||
time_stamp = millis(); | |||
dprintf("keyboard input: %02X %02X", report->mods, report->reserved); | |||
dprintf("input %d: %02X %02X", hid->GetAddress(), report.mods, report.reserved); | |||
for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) { | |||
if (IS_ERROR(report->keys[i])) { | |||
is_error = true; | |||
} | |||
dprintf(" %02X", report->keys[i]); | |||
dprintf(" %02X", report.keys[i]); | |||
} | |||
dprint("\r\n"); | |||
// ignore error and not send report to computer | |||
if (is_error) { | |||
dprint("Error usage! \r\n"); | |||
return; | |||
} | |||
::memcpy(&usb_hid_keyboard_report, buf, sizeof(report_keyboard_t)); | |||
usb_hid_time_stamp = millis(); | |||
} |
@@ -2,11 +2,14 @@ | |||
#define PARSER_H | |||
#include "hid.h" | |||
#include "report.h" | |||
class KBDReportParser : public HIDReportParser | |||
{ | |||
public: | |||
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); | |||
report_keyboard_t report; | |||
uint16_t time_stamp; | |||
virtual void Parse(HID *hid, bool is_rpt_id, uint8_t len, uint8_t *buf); | |||
}; | |||
#endif |