@@ -65,7 +65,7 @@ FORMAT = ihex | |||
# Object files directory | |||
# To put object files in current directory, use a dot (.), do NOT make | |||
# this an empty or blank macro! | |||
OBJDIR = . | |||
OBJDIR = obj | |||
# Optimization level, can be [0, 1, 2, 3, s]. | |||
@@ -347,7 +347,7 @@ AR = avr-ar rcs | |||
NM = avr-nm | |||
AVRDUDE = avrdude | |||
REMOVE = rm -f | |||
REMOVEDIR = rm -rf | |||
REMOVEDIR = rmdir | |||
COPY = cp | |||
WINSHELL = cmd | |||
@@ -601,7 +601,8 @@ clean_list : | |||
$(REMOVE) $(LST) | |||
$(REMOVE) $(OBJ:.o=.s) | |||
$(REMOVE) $(OBJ:.o=.i) | |||
$(REMOVEDIR) .dep | |||
$(REMOVE) -r .dep | |||
$(REMOVEDIR) $(OBJDIR) | |||
# Create object files directory |
@@ -9,11 +9,13 @@ TARGET_DIR = . | |||
# keyboard dependent files | |||
TARGET_SRC = main.c \ | |||
keyboard_vusb.c \ | |||
keyboard.c \ | |||
mousekey.c \ | |||
layer.c \ | |||
keymap.c \ | |||
matrix.c \ | |||
ps2.c \ | |||
host_vusb.c \ | |||
print.c \ | |||
util.c \ | |||
timer.c \ |
@@ -0,0 +1,35 @@ | |||
#ifndef HOST_H | |||
#define HOST_H | |||
#include <stdint.h> | |||
#define REPORT_KEYS 6 | |||
#define MOUSE_BTN1 (1<<0) | |||
#define MOUSE_BTN2 (1<<1) | |||
#define MOUSE_BTN3 (1<<2) | |||
#define MOUSE_BTN4 (1<<3) | |||
#define MOUSE_BTN5 (1<<4) | |||
typedef struct { | |||
uint8_t mods; | |||
uint8_t rserved; // not used | |||
uint8_t keys[REPORT_KEYS]; | |||
} report_keyboard_t; | |||
typedef struct { | |||
uint8_t buttons; | |||
int8_t x; | |||
int8_t y; | |||
/* | |||
int8_t v; | |||
int8_t h; | |||
*/ | |||
} report_mouse_t; | |||
void host_keyboard_send(report_keyboard_t *report); | |||
void host_mouse_send(report_mouse_t *report); | |||
#endif |
@@ -0,0 +1,345 @@ | |||
#include "usbdrv.h" | |||
#include "usbconfig.h" | |||
#include "keyboard.h" | |||
#include "print.h" | |||
#include "host.h" | |||
#include "host_vusb.h" | |||
#define KBUF_SIZE 8 | |||
static report_keyboard_t kbuf[KBUF_SIZE]; | |||
static uint8_t kbuf_head = 0; | |||
static uint8_t kbuf_tail = 0; | |||
void host_vusb_keyboard_send() | |||
{ | |||
if (kbuf_head != kbuf_tail) { | |||
if (usbInterruptIsReady()) { | |||
usbSetInterrupt((void *)&kbuf[kbuf_tail], sizeof(report_keyboard_t)); | |||
kbuf_tail = (kbuf_tail + 1) % KBUF_SIZE; | |||
} | |||
} | |||
} | |||
void host_keyboard_send(report_keyboard_t *report) | |||
{ | |||
uint8_t next = (kbuf_head + 1) % KBUF_SIZE; | |||
if (next != kbuf_tail) { | |||
kbuf[kbuf_head] = *report; | |||
kbuf_head = next; | |||
} | |||
} | |||
void host_mouse_send(report_mouse_t *report) | |||
{ | |||
// dirty hack to send twice a loop :( | |||
//while (!usbInterruptIsReady3()) usbPoll(); | |||
if (usbInterruptIsReady3()) { | |||
usbSetInterrupt3((void *)report, sizeof(*report)); | |||
} else { | |||
print("Int3 not ready\n"); | |||
} | |||
} | |||
static uchar idleRate; /* repeat rate for keyboards, never used for mice */ | |||
usbMsgLen_t usbFunctionSetup(uchar data[8]) | |||
{ | |||
usbRequest_t *rq = (void *)data; | |||
print("Setup: "); | |||
if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */ | |||
print("CLASS: "); | |||
phex(rq->bRequest); | |||
if(rq->bRequest == USBRQ_HID_GET_REPORT){ | |||
print("GET_REPORT"); | |||
/* we only have one report type, so don't look at wValue */ | |||
usbMsgPtr = (void *)keyboard_report; | |||
return sizeof(*keyboard_report); | |||
}else if(rq->bRequest == USBRQ_HID_GET_IDLE){ | |||
print("GET_IDLE: "); | |||
phex(idleRate); | |||
usbMsgPtr = &idleRate; | |||
return 1; | |||
}else if(rq->bRequest == USBRQ_HID_SET_IDLE){ | |||
idleRate = rq->wValue.bytes[1]; | |||
print("SET_IDLE: "); | |||
phex(idleRate); | |||
} | |||
print("\n"); | |||
}else{ | |||
print("VENDOR\n"); | |||
/* no vendor specific requests implemented */ | |||
} | |||
return 0; /* default for not implemented requests: return no data back to host */ | |||
} | |||
PROGMEM uchar keyboard_hid_report[] = { | |||
0x05, 0x01, // Usage Page (Generic Desktop), | |||
0x09, 0x06, // Usage (Keyboard), | |||
0xA1, 0x01, // Collection (Application), | |||
0x75, 0x01, // Report Size (1), | |||
0x95, 0x08, // Report Count (8), | |||
0x05, 0x07, // Usage Page (Key Codes), | |||
0x19, 0xE0, // Usage Minimum (224), | |||
0x29, 0xE7, // Usage Maximum (231), | |||
0x15, 0x00, // Logical Minimum (0), | |||
0x25, 0x01, // Logical Maximum (1), | |||
0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte | |||
0x95, 0x01, // Report Count (1), | |||
0x75, 0x08, // Report Size (8), | |||
0x81, 0x03, // Input (Constant), ;Reserved byte | |||
0x95, 0x05, // Report Count (5), | |||
0x75, 0x01, // Report Size (1), | |||
0x05, 0x08, // Usage Page (LEDs), | |||
0x19, 0x01, // Usage Minimum (1), | |||
0x29, 0x05, // Usage Maximum (5), | |||
0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report | |||
0x95, 0x01, // Report Count (1), | |||
0x75, 0x03, // Report Size (3), | |||
0x91, 0x03, // Output (Constant), ;LED report padding | |||
0x95, 0x06, // Report Count (6), | |||
0x75, 0x08, // Report Size (8), | |||
0x15, 0x00, // Logical Minimum (0), | |||
0x25, 0xFF, // Logical Maximum(255), | |||
0x05, 0x07, // Usage Page (Key Codes), | |||
0x19, 0x00, // Usage Minimum (0), | |||
0x29, 0xFF, // Usage Maximum (255), | |||
0x81, 0x00, // Input (Data, Array), | |||
0xc0 // End Collection | |||
}; | |||
// Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension | |||
// http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521 | |||
// http://www.keil.com/forum/15671/ | |||
// http://www.microsoft.com/whdc/device/input/wheel.mspx | |||
PROGMEM uchar mouse_hid_report[] = { | |||
/* from HID 1.11 spec example */ | |||
0x05, 0x01, // Usage Page (Generic Desktop), | |||
0x09, 0x02, // Usage (Mouse), | |||
0xA1, 0x01, // Collection (Application), | |||
0x09, 0x01, // Usage (Pointer), | |||
0xA1, 0x00, // Collection (Physical), | |||
0x05, 0x09, // Usage Page (Buttons), | |||
0x19, 0x01, // Usage Minimum (01), | |||
0x29, 0x03, // Usage Maximun (03), | |||
0x15, 0x00, // Logical Minimum (0), | |||
0x25, 0x01, // Logical Maximum (1), | |||
0x95, 0x03, // Report Count (3), | |||
0x75, 0x01, // Report Size (1), | |||
0x81, 0x02, // Input (Data, Variable, Absolute), ;3 button bits | |||
0x95, 0x01, // Report Count (1), | |||
0x75, 0x05, // Report Size (5), | |||
0x81, 0x01, // Input (Constant), ;5 bit padding | |||
0x05, 0x01, // Usage Page (Generic Desktop), | |||
0x09, 0x30, // Usage (X), | |||
0x09, 0x31, // Usage (Y), | |||
0x15, 0x81, // Logical Minimum (-127), | |||
0x25, 0x7F, // Logical Maximum (127), | |||
0x75, 0x08, // Report Size (8), | |||
0x95, 0x02, // Report Count (2), | |||
0x81, 0x06, // Input (Data, Variable, Relative), ;2 position bytes (X & Y) | |||
0xC0, // End Collection, | |||
0xC0, // End Collection | |||
/* | |||
0x05, 0x01, // USAGE_PAGE (Generic Desktop) | |||
0x09, 0x02, // USAGE (Mouse) | |||
0xa1, 0x01, // COLLECTION (Application) | |||
0x09, 0x02, // USAGE (Mouse) | |||
0xa1, 0x02, // COLLECTION (Logical) | |||
0x09, 0x01, // USAGE (Pointer) | |||
0xa1, 0x00, // COLLECTION (Physical) | |||
// ------------------------------ Buttons | |||
0x05, 0x09, // USAGE_PAGE (Button) | |||
0x19, 0x01, // USAGE_MINIMUM (Button 1) | |||
0x29, 0x05, // USAGE_MAXIMUM (Button 5) | |||
0x15, 0x00, // LOGICAL_MINIMUM (0) | |||
0x25, 0x01, // LOGICAL_MAXIMUM (1) | |||
0x75, 0x01, // REPORT_SIZE (1) | |||
0x95, 0x05, // REPORT_COUNT (5) | |||
0x81, 0x02, // INPUT (Data,Var,Abs) | |||
// ------------------------------ Padding | |||
0x75, 0x03, // REPORT_SIZE (3) | |||
0x95, 0x01, // REPORT_COUNT (1) | |||
0x81, 0x03, // INPUT (Cnst,Var,Abs) | |||
// ------------------------------ X,Y position | |||
0x05, 0x01, // USAGE_PAGE (Generic Desktop) | |||
0x09, 0x30, // USAGE (X) | |||
0x09, 0x31, // USAGE (Y) | |||
0x15, 0x81, // LOGICAL_MINIMUM (-127) | |||
0x25, 0x7f, // LOGICAL_MAXIMUM (127) | |||
0x75, 0x08, // REPORT_SIZE (8) | |||
0x95, 0x02, // REPORT_COUNT (2) | |||
0x81, 0x06, // INPUT (Data,Var,Rel) | |||
0xa1, 0x02, // COLLECTION (Logical) | |||
// ------------------------------ Vertical wheel res multiplier | |||
0x09, 0x48, // USAGE (Resolution Multiplier) | |||
0x15, 0x00, // LOGICAL_MINIMUM (0) | |||
0x25, 0x01, // LOGICAL_MAXIMUM (1) | |||
0x35, 0x01, // PHYSICAL_MINIMUM (1) | |||
0x45, 0x04, // PHYSICAL_MAXIMUM (4) | |||
0x75, 0x02, // REPORT_SIZE (2) | |||
0x95, 0x01, // REPORT_COUNT (1) | |||
0xa4, // PUSH | |||
0xb1, 0x02, // FEATURE (Data,Var,Abs) | |||
// ------------------------------ Vertical wheel | |||
0x09, 0x38, // USAGE (Wheel) | |||
0x15, 0x81, // LOGICAL_MINIMUM (-127) | |||
0x25, 0x7f, // LOGICAL_MAXIMUM (127) | |||
0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical | |||
0x45, 0x00, // PHYSICAL_MAXIMUM (0) | |||
0x75, 0x08, // REPORT_SIZE (8) | |||
0x81, 0x06, // INPUT (Data,Var,Rel) | |||
0xc0, // END_COLLECTION | |||
0xa1, 0x02, // COLLECTION (Logical) | |||
// ------------------------------ Horizontal wheel res multiplier | |||
0x09, 0x48, // USAGE (Resolution Multiplier) | |||
0xb4, // POP | |||
0xb1, 0x02, // FEATURE (Data,Var,Abs) | |||
// ------------------------------ Padding for Feature report | |||
0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical | |||
0x45, 0x00, // PHYSICAL_MAXIMUM (0) | |||
0x75, 0x04, // REPORT_SIZE (4) | |||
0xb1, 0x03, // FEATURE (Cnst,Var,Abs) | |||
// ------------------------------ Horizontal wheel | |||
0x05, 0x0c, // USAGE_PAGE (Consumer Devices) | |||
0x0a, 0x38, 0x02, // USAGE (AC Pan) | |||
0x15, 0x81, // LOGICAL_MINIMUM (-127) | |||
0x25, 0x7f, // LOGICAL_MAXIMUM (127) | |||
0x75, 0x08, // REPORT_SIZE (8) | |||
0x81, 0x06, // INPUT (Data,Var,Rel) | |||
0xc0, // END_COLLECTION | |||
0xc0, // END_COLLECTION | |||
0xc0, // END_COLLECTION | |||
0xc0 // END_COLLECTION | |||
*/ | |||
}; | |||
/* Descriptor for compite device: Keyboard + Mouse */ | |||
#if USB_CFG_DESCR_PROPS_CONFIGURATION | |||
PROGMEM char usbDescriptorConfiguration[] = { /* USB configuration descriptor */ | |||
9, /* sizeof(usbDescriptorConfiguration): length of descriptor in bytes */ | |||
USBDESCR_CONFIG, /* descriptor type */ | |||
9 + (9 + 9 + 7) + (9 + 9 + 7), 0, | |||
//18 + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT + 7 * USB_CFG_HAVE_INTRIN_ENDPOINT3 + 9, 0, | |||
/* total length of data returned (including inlined descriptors) */ | |||
2, /* number of interfaces in this configuration */ | |||
1, /* index of this configuration */ | |||
0, /* configuration name string index */ | |||
#if USB_CFG_IS_SELF_POWERED | |||
(1 << 7) | USBATTR_SELFPOWER, /* attributes */ | |||
#else | |||
(1 << 7), /* attributes */ | |||
#endif | |||
USB_CFG_MAX_BUS_POWER/2, /* max USB current in 2mA units */ | |||
/* | |||
* Keyboard interface | |||
*/ | |||
/* Interface descriptor */ | |||
9, /* sizeof(usbDescrInterface): length of descriptor in bytes */ | |||
USBDESCR_INTERFACE, /* descriptor type */ | |||
0, /* index of this interface */ | |||
0, /* alternate setting for this interface */ | |||
USB_CFG_HAVE_INTRIN_ENDPOINT, /* endpoints excl 0: number of endpoint descriptors to follow */ | |||
USB_CFG_INTERFACE_CLASS, | |||
USB_CFG_INTERFACE_SUBCLASS, | |||
USB_CFG_INTERFACE_PROTOCOL, | |||
0, /* string index for interface */ | |||
/* HID descriptor */ | |||
9, /* sizeof(usbDescrHID): length of descriptor in bytes */ | |||
USBDESCR_HID, /* descriptor type: HID */ | |||
0x01, 0x01, /* BCD representation of HID version */ | |||
0x00, /* target country code */ | |||
0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */ | |||
0x22, /* descriptor type: report */ | |||
sizeof(keyboard_hid_report), 0, /* total length of report descriptor */ | |||
/* Endpoint descriptor */ | |||
#if USB_CFG_HAVE_INTRIN_ENDPOINT /* endpoint descriptor for endpoint 1 */ | |||
7, /* sizeof(usbDescrEndpoint) */ | |||
USBDESCR_ENDPOINT, /* descriptor type = endpoint */ | |||
(char)0x81, /* IN endpoint number 1 */ | |||
0x03, /* attrib: Interrupt endpoint */ | |||
8, 0, /* maximum packet size */ | |||
USB_CFG_INTR_POLL_INTERVAL, /* in ms */ | |||
#endif | |||
/* | |||
* Mouse interface | |||
*/ | |||
/* Interface descriptor */ | |||
9, /* sizeof(usbDescrInterface): length of descriptor in bytes */ | |||
USBDESCR_INTERFACE, /* descriptor type */ | |||
1, /* index of this interface */ | |||
0, /* alternate setting for this interface */ | |||
USB_CFG_HAVE_INTRIN_ENDPOINT3, /* endpoints excl 0: number of endpoint descriptors to follow */ | |||
0x03, /* CLASS: HID */ | |||
0, /* SUBCLASS: none */ | |||
0, /* PROTOCOL: none */ | |||
0, /* string index for interface */ | |||
/* HID descriptor */ | |||
9, /* sizeof(usbDescrHID): length of descriptor in bytes */ | |||
USBDESCR_HID, /* descriptor type: HID */ | |||
0x01, 0x01, /* BCD representation of HID version */ | |||
0x00, /* target country code */ | |||
0x01, /* number of HID Report (or other HID class) Descriptor infos to follow */ | |||
0x22, /* descriptor type: report */ | |||
sizeof(mouse_hid_report), 0, /* total length of report descriptor */ | |||
#if USB_CFG_HAVE_INTRIN_ENDPOINT3 /* endpoint descriptor for endpoint 3 */ | |||
/* Endpoint descriptor */ | |||
7, /* sizeof(usbDescrEndpoint) */ | |||
USBDESCR_ENDPOINT, /* descriptor type = endpoint */ | |||
(char)(0x80 | USB_CFG_EP3_NUMBER), /* IN endpoint number 3 */ | |||
0x03, /* attrib: Interrupt endpoint */ | |||
8, 0, /* maximum packet size */ | |||
USB_CFG_INTR_POLL_INTERVAL, /* in ms */ | |||
#endif | |||
}; | |||
#endif | |||
USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) | |||
{ | |||
usbMsgLen_t len = 0; | |||
print("usbFunctionDescriptor: "); | |||
phex(rq->bmRequestType); print(" "); | |||
phex(rq->bRequest); print(" "); | |||
phex16(rq->wValue.word); print(" "); | |||
phex16(rq->wIndex.word); print(" "); | |||
phex16(rq->wLength.word); print("\n"); | |||
switch (rq->wValue.bytes[1]) { | |||
#if USB_CFG_DESCR_PROPS_CONFIGURATION | |||
case USBDESCR_CONFIG: | |||
usbMsgPtr = (unsigned char *)usbDescriptorConfiguration; | |||
len = sizeof(usbDescriptorConfiguration); | |||
break; | |||
#endif | |||
case USBDESCR_HID: | |||
usbMsgPtr = (unsigned char *)(usbDescriptorConfiguration + 18); | |||
len = 9; | |||
break; | |||
case USBDESCR_HID_REPORT: | |||
/* interface index */ | |||
switch (rq->wIndex.word) { | |||
case 0: | |||
usbMsgPtr = keyboard_hid_report; | |||
len = sizeof(keyboard_hid_report); | |||
break; | |||
case 1: | |||
usbMsgPtr = mouse_hid_report; | |||
len = sizeof(mouse_hid_report); | |||
break; | |||
} | |||
break; | |||
} | |||
print("desc len: "); phex(len); print("\n"); | |||
return len; | |||
} |
@@ -0,0 +1,7 @@ | |||
#ifndef HOST_VUSB_H | |||
#define HOST_VUSB_H | |||
void host_vusb_keyboard_send(void); | |||
#endif | |||
@@ -0,0 +1,79 @@ | |||
#include "usb_keycodes.h" | |||
#include "host.h" | |||
#include "keyboard.h" | |||
static report_keyboard_t report0; | |||
static report_keyboard_t report1; | |||
static report_keyboard_t *report = &report0; | |||
static report_keyboard_t *report_prev = &report1; | |||
void keyboard_send(void) | |||
{ | |||
host_keyboard_send(report); | |||
} | |||
bool keyboard_has_key(void) | |||
{ | |||
for (int i = 0; i < REPORT_KEYS; i++) { | |||
if (report->keys[i]) | |||
return true; | |||
} | |||
return false; | |||
} | |||
void keyboard_add_mod(uint8_t mod) | |||
{ | |||
report->mods |= mod; | |||
} | |||
void keyboard_add_key(uint8_t code) | |||
{ | |||
int8_t i = 0; | |||
int8_t empty = -1; | |||
for (; i < REPORT_KEYS; i++) { | |||
if (report_prev->keys[i] == code) { | |||
report->keys[i] = code; | |||
break; | |||
} | |||
if (empty == -1 && report_prev->keys[i] == KB_NO && report->keys[i] == KB_NO) { | |||
empty = i; | |||
} | |||
} | |||
if (i == REPORT_KEYS && empty != -1) { | |||
report->keys[empty] = code; | |||
} | |||
} | |||
void keyboard_add_code(uint8_t code) | |||
{ | |||
if (IS_MOD(code)) { | |||
keyboard_add_mod(code); | |||
} else { | |||
keyboard_add_key(code); | |||
} | |||
} | |||
void keyboard_swap_report(void) | |||
{ | |||
report_keyboard_t *tmp = report_prev; | |||
report_prev = report; | |||
report = tmp; | |||
} | |||
void keyboard_clear_report(void) | |||
{ | |||
report->mods = 0; | |||
for (int8_t i = 0; i < REPORT_KEYS; i++) { | |||
report->keys[i] = 0; | |||
} | |||
} | |||
report_keyboard_t *keyboard_report(void) | |||
{ | |||
return report; | |||
} | |||
report_keyboard_t *keyboard_report_prev(void) | |||
{ | |||
return report_prev; | |||
} |
@@ -1,27 +1,21 @@ | |||
#ifndef KEYBOARD_H | |||
#define KEYBOARD_H | |||
#include "stdbool.h" | |||
#include <stdint.h> | |||
#include <stdbool.h> | |||
#include "host.h" | |||
#define REPORT_KEYS 6 | |||
typedef struct{ | |||
uint8_t mods; | |||
uint8_t rserved; // not used | |||
uint8_t keys[REPORT_KEYS]; | |||
}report_t; | |||
void keyboard_send(void); | |||
bool keyboard_has_key(void); | |||
void keyboard_add_mod(uint8_t mod); | |||
void keyboard_add_key(uint8_t key); | |||
void keyboard_add_code(uint8_t code); | |||
void keyboard_swap_report(void); | |||
void keyboard_clear_report(void); | |||
report_keyboard_t *keyboard_report(void); | |||
report_keyboard_t *keyboard_report_prev(void); | |||
#endif | |||
//extern report_t *report; | |||
//extern report_t *report_prev; | |||
report_t *report_get(void); | |||
bool report_has_key(void); | |||
void report_send(void); | |||
void report_add_mod(uint8_t mod); | |||
void report_add_key(uint8_t key); | |||
void report_add_code(uint8_t code); | |||
void report_swap(void); | |||
void report_clear(void); | |||
#endif |
@@ -1,156 +0,0 @@ | |||
#include "usbdrv.h" | |||
#include "usb_keycodes.h" | |||
#include "keyboard.h" | |||
#include "print.h" | |||
static report_t report0; | |||
static report_t report1; | |||
static report_t *report = &report0; | |||
static report_t *report_prev = &report1; | |||
void report_send(void) | |||
{ | |||
if (usbInterruptIsReady()){ | |||
usbSetInterrupt((void *)report, sizeof(*report)); | |||
} | |||
} | |||
report_t *report_get(void) | |||
{ | |||
return report; | |||
} | |||
uint8_t report_mods(void) | |||
{ | |||
return report->mods; | |||
} | |||
uint8_t *report_keys(void) | |||
{ | |||
return report->keys; | |||
} | |||
bool report_has_key(void) | |||
{ | |||
for (int i = 0; i < REPORT_KEYS; i++) { | |||
if (report->keys[i]) | |||
return true; | |||
} | |||
return false; | |||
} | |||
void report_add_mod(uint8_t mod) | |||
{ | |||
report->mods |= mod; | |||
} | |||
void report_add_key(uint8_t code) | |||
{ | |||
int8_t i = 0; | |||
int8_t empty = -1; | |||
for (; i < REPORT_KEYS; i++) { | |||
if (report_prev->keys[i] == code) { | |||
report->keys[i] = code; | |||
break; | |||
} | |||
if (empty == -1 && report_prev->keys[i] == KB_NO && report->keys[i] == KB_NO) { | |||
empty = i; | |||
} | |||
} | |||
if (i == REPORT_KEYS && empty != -1) { | |||
report->keys[empty] = code; | |||
} | |||
} | |||
void report_add_code(uint8_t code) | |||
{ | |||
if (IS_MOD(code)) { | |||
report_add_mod(code); | |||
} else { | |||
report_add_key(code); | |||
} | |||
} | |||
void report_swap(void) | |||
{ | |||
report_t *tmp = report_prev; | |||
report_prev = report; | |||
report = tmp; | |||
} | |||
void report_clear(void) | |||
{ | |||
report->mods = 0; | |||
for (int8_t i = 0; i < REPORT_KEYS; i++) { | |||
report->keys[i] = 0; | |||
} | |||
} | |||
static uchar idleRate; /* repeat rate for keyboards, never used for mice */ | |||
usbMsgLen_t usbFunctionSetup(uchar data[8]) | |||
{ | |||
usbRequest_t *rq = (void *)data; | |||
print("Setup: "); | |||
if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */ | |||
print("CLASS: "); | |||
phex(rq->bRequest); | |||
if(rq->bRequest == USBRQ_HID_GET_REPORT){ | |||
print("GET_REPORT"); | |||
/* we only have one report type, so don't look at wValue */ | |||
usbMsgPtr = (void *)report; | |||
return sizeof(*report); | |||
}else if(rq->bRequest == USBRQ_HID_GET_IDLE){ | |||
print("GET_IDLE: "); | |||
phex(idleRate); | |||
usbMsgPtr = &idleRate; | |||
return 1; | |||
}else if(rq->bRequest == USBRQ_HID_SET_IDLE){ | |||
idleRate = rq->wValue.bytes[1]; | |||
print("SET_IDLE: "); | |||
phex(idleRate); | |||
} | |||
print("\n"); | |||
}else{ | |||
print("VENDOR\n"); | |||
/* no vendor specific requests implemented */ | |||
} | |||
return 0; /* default for not implemented requests: return no data back to host */ | |||
} | |||
PROGMEM char usbHidReportDescriptor[USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH] = { | |||
0x05, 0x01, // Usage Page (Generic Desktop), | |||
0x09, 0x06, // Usage (Keyboard), | |||
0xA1, 0x01, // Collection (Application), | |||
0x75, 0x01, // Report Size (1), | |||
0x95, 0x08, // Report Count (8), | |||
0x05, 0x07, // Usage Page (Key Codes), | |||
0x19, 0xE0, // Usage Minimum (224), | |||
0x29, 0xE7, // Usage Maximum (231), | |||
0x15, 0x00, // Logical Minimum (0), | |||
0x25, 0x01, // Logical Maximum (1), | |||
0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte | |||
0x95, 0x01, // Report Count (1), | |||
0x75, 0x08, // Report Size (8), | |||
0x81, 0x03, // Input (Constant), ;Reserved byte | |||
0x95, 0x05, // Report Count (5), | |||
0x75, 0x01, // Report Size (1), | |||
0x05, 0x08, // Usage Page (LEDs), | |||
0x19, 0x01, // Usage Minimum (1), | |||
0x29, 0x05, // Usage Maximum (5), | |||
0x91, 0x02, // Output (Data, Variable, Absolute), ;LED report | |||
0x95, 0x01, // Report Count (1), | |||
0x75, 0x03, // Report Size (3), | |||
0x91, 0x03, // Output (Constant), ;LED report padding | |||
0x95, 0x06, // Report Count (6), | |||
0x75, 0x08, // Report Size (8), | |||
0x15, 0x00, // Logical Minimum (0), | |||
0x25, 0xFF, // Logical Maximum(255), | |||
0x05, 0x07, // Usage Page (Key Codes), | |||
0x19, 0x00, // Usage Minimum (0), | |||
0x29, 0xFF, // Usage Maximum (255), | |||
0x81, 0x00, // Input (Data, Array), | |||
0xc0 // End Collection | |||
}; |
@@ -98,23 +98,23 @@ void layer_switching(uint8_t fn_bits) | |||
debug(" -> "); debug_hex(current_layer); debug("\n"); | |||
} | |||
} else { | |||
if (report_has_key()) { // other keys is pressed | |||
if (keyboard_has_key()) { // other keys is pressed | |||
uint8_t _fn_to_send = BIT_SUBT(fn_bits, sent_fn); | |||
if (_fn_to_send) { | |||
debug("Fn case: 4(send Fn before other key pressed)\n"); | |||
// send only Fn key first | |||
report_swap(); | |||
report_clear(); | |||
report_add_code(keymap_fn_keycode(_fn_to_send)); // TODO: do all Fn keys | |||
report_add_mod(last_mods); | |||
report_send(); | |||
report_swap(); | |||
keyboard_swap_report(); | |||
keyboard_clear_report(); | |||
keyboard_add_code(keymap_fn_keycode(_fn_to_send)); // TODO: do all Fn keys | |||
keyboard_add_mod(last_mods); | |||
keyboard_send(); | |||
keyboard_swap_report(); | |||
sent_fn |= _fn_to_send; | |||
} | |||
} | |||
} | |||
// add Fn keys to send | |||
//report_add_code(keymap_fn_keycode(fn_bits&sent_fn)); // TODO: do all Fn keys | |||
//keyboard_add_code(keymap_fn_keycode(fn_bits&sent_fn)); // TODO: do all Fn keys | |||
} | |||
} else { // Fn state is changed(edge) | |||
uint8_t fn_changed = 0; | |||
@@ -128,7 +128,7 @@ void layer_switching(uint8_t fn_bits) | |||
// pressed Fn | |||
if ((fn_changed = BIT_SUBT(fn_bits, last_fn))) { | |||
debug("fn_changed: "); debug_bin(fn_changed); debug("\n"); | |||
if (report_has_key()) { | |||
if (keyboard_has_key()) { | |||
debug("Fn case: 5(pressed Fn with other key)\n"); | |||
sent_fn |= fn_changed; | |||
} else if (fn_changed & sent_fn) { // pressed same Fn in a row | |||
@@ -149,12 +149,12 @@ void layer_switching(uint8_t fn_bits) | |||
if (BIT_SUBT(fn_changed, sent_fn)) { // layer not used && Fn not sent | |||
debug("Fn case: 2(send Fn one shot: released Fn during LAYER_SEND_FN_TERM)\n"); | |||
// send only Fn key first | |||
report_swap(); | |||
report_clear(); | |||
report_add_code(keymap_fn_keycode(fn_changed)); // TODO: do all Fn keys | |||
report_add_mod(last_mods); | |||
report_send(); | |||
report_swap(); | |||
keyboard_swap_report(); | |||
keyboard_clear_report(); | |||
keyboard_add_code(keymap_fn_keycode(fn_changed)); // TODO: do all Fn keys | |||
keyboard_add_mod(last_mods); | |||
keyboard_send(); | |||
keyboard_swap_report(); | |||
sent_fn |= fn_changed; | |||
} | |||
} | |||
@@ -165,13 +165,13 @@ void layer_switching(uint8_t fn_bits) | |||
} | |||
last_fn = fn_bits; | |||
last_mods = report_get()->mods; | |||
last_mods = keyboard_report()->mods; | |||
last_timer = timer_read(); | |||
} | |||
// send Fn keys | |||
for (uint8_t i = 0; i < 8; i++) { | |||
if ((sent_fn & fn_bits) & (1<<i)) { | |||
report_add_code(keymap_fn_keycode(1<<i)); | |||
keyboard_add_code(keymap_fn_keycode(1<<i)); | |||
} | |||
} | |||
} |
@@ -7,68 +7,50 @@ | |||
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt) | |||
* This Revision: $Id: main.c 790 2010-05-30 21:00:26Z cs $ | |||
*/ | |||
/* | |||
This example should run on most AVRs with only little changes. No special | |||
hardware resources except INT0 are used. You may have to change usbconfig.h for | |||
different I/O pins for USB. Please note that USB D+ must be the INT0 pin, or | |||
at least be connected to INT0 as well. | |||
We use VID/PID 0x046D/0xC00E which is taken from a Logitech mouse. Don't | |||
publish any hardware using these IDs! This is for demonstration only! | |||
*/ | |||
#include <stdint.h> | |||
#include <avr/io.h> | |||
#include <avr/wdt.h> | |||
#include <avr/interrupt.h> /* for sei() */ | |||
#include <util/delay.h> /* for _delay_ms() */ | |||
#include <avr/pgmspace.h> /* required by usbdrv.h */ | |||
#include <util/delay.h> /* for _delay_ms() */ | |||
#include "usbdrv.h" | |||
#include "usart_print.h" /* This is also an example for using debug macros */ | |||
#include "ps2.h" | |||
#include "usb_keycodes.h" | |||
#include "matrix_skel.h" | |||
#include "keymap_skel.h" | |||
#include "mousekey.h" | |||
#include "keyboard.h" | |||
#include "layer.h" | |||
#include "print.h" | |||
#include "debug.h" | |||
#include "sendchar.h" | |||
#include "keyboard.h" | |||
#include "host.h" | |||
#include "host_vusb.h" | |||
#include "timer.h" | |||
/* ------------------------------------------------------------------------- */ | |||
/* ----------------------------- USB interface ----------------------------- */ | |||
/* ------------------------------------------------------------------------- */ | |||
int main(void) | |||
{ | |||
uchar i; | |||
print_enable = true; | |||
debug_enable = true; | |||
timer_init(); | |||
matrix_init(); | |||
wdt_enable(WDTO_1S); | |||
/* Even if you don't use the watchdog, turn it off here. On newer devices, | |||
* the status of the watchdog (on/off, period) is PRESERVED OVER RESET! | |||
*/ | |||
/* RESET status: all port bits are inputs without pull-up. | |||
* That's the way we need D+ and D-. Therefore we don't need any | |||
* additional hardware initialization. | |||
*/ | |||
odDebugInit(); | |||
DBG1(0x00, 0, 0); /* debug output: main starts */ | |||
usbInit(); | |||
usbDeviceDisconnect(); /* enforce re-enumeration, do this while interrupts are disabled! */ | |||
i = 0; | |||
print_enable = true; | |||
//debug_enable = true; | |||
timer_init(); | |||
matrix_init(); | |||
/* enforce re-enumeration, do this while interrupts are disabled! */ | |||
usbDeviceDisconnect(); | |||
uint8_t i = 0; | |||
while(--i){ /* fake USB disconnect for > 250 ms */ | |||
wdt_reset(); | |||
_delay_ms(1); | |||
@@ -78,49 +60,44 @@ matrix_init(); | |||
uint8_t fn_bits = 0; | |||
while (1) { /* main event loop */ | |||
DBG1(0x02, 0, 0); /* debug output: main loop iterates */ | |||
wdt_reset(); | |||
usbPoll(); | |||
host_vusb_keyboard_send(); | |||
/* | |||
static uint8_t code = 0; | |||
code = ps2_host_recv(); | |||
if (code) { | |||
odDebug(0x05, &code, 1); | |||
} | |||
*/ | |||
matrix_scan(); | |||
if (matrix_is_modified()) { | |||
//matrix_print(); // too heavy on USART | |||
fn_bits = 0; | |||
report_swap(); | |||
report_clear(); | |||
for (int row = 0; row < matrix_rows(); row++) { | |||
for (int col = 0; col < matrix_cols(); col++) { | |||
if (!matrix_is_on(row, col)) continue; | |||
uint8_t code = layer_get_keycode(row, col); | |||
if (code == KB_NO) { | |||
// do nothing | |||
} | |||
else if (IS_MOD(code)) { | |||
report_add_mod(MOD_BIT(code)); | |||
} | |||
else if (IS_KEY(code)) { | |||
report_add_key(code); | |||
} | |||
else if (IS_FN(code)) { | |||
fn_bits |= FN_BIT(code); | |||
} | |||
else { | |||
debug("ignore keycode: "); debug_hex(code); debug("\n"); | |||
} | |||
fn_bits = 0; | |||
keyboard_swap_report(); | |||
keyboard_clear_report(); | |||
mousekey_clear_report(); | |||
for (int row = 0; row < matrix_rows(); row++) { | |||
for (int col = 0; col < matrix_cols(); col++) { | |||
if (!matrix_is_on(row, col)) continue; | |||
uint8_t code = layer_get_keycode(row, col); | |||
if (code == KB_NO) { | |||
// do nothing | |||
} | |||
else if (IS_MOD(code)) { | |||
keyboard_add_mod(MOD_BIT(code)); | |||
} | |||
else if (IS_KEY(code)) { | |||
keyboard_add_key(code); | |||
} | |||
else if (IS_FN(code)) { | |||
fn_bits |= FN_BIT(code); | |||
} | |||
else if (IS_MOUSEKEY(code)) { | |||
mousekey_decode(code); | |||
} | |||
else { | |||
debug("ignore keycode: "); debug_hex(code); debug("\n"); | |||
} | |||
} | |||
} | |||
layer_switching(fn_bits); | |||
if (matrix_is_modified()) { | |||
report_send(); | |||
keyboard_send(); | |||
} | |||
mousekey_send(); | |||
} | |||
} |
@@ -190,8 +190,10 @@ uint8_t matrix_scan(void) | |||
} | |||
uint8_t code; | |||
while ((code = ps2_host_recv())) { | |||
//debug_hex(code); debug(" "); | |||
code = ps2_host_recv(); | |||
if (code == 0x00) return 0; | |||
//while ((code = ps2_host_recv())) { | |||
//phex(code); print(" "); | |||
switch (state) { | |||
case INIT: | |||
switch (code) { | |||
@@ -348,7 +350,8 @@ uint8_t matrix_scan(void) | |||
default: | |||
state = INIT; | |||
} | |||
} | |||
//} | |||
//print("|"); | |||
// handle LED indicators | |||
/* | |||
@@ -463,6 +466,7 @@ static void matrix_make(uint8_t code) | |||
if (!matrix_is_on(ROW(code), COL(code))) { | |||
matrix[ROW(code)] |= 1<<COL(code); | |||
is_modified = true; | |||
//print("matrix_make: "); phex(code); print("\n"); | |||
} | |||
} | |||
@@ -472,6 +476,7 @@ static void matrix_break(uint8_t code) | |||
if (matrix_is_on(ROW(code), COL(code))) { | |||
matrix[ROW(code)] &= ~(1<<COL(code)); | |||
is_modified = true; | |||
//print("matrix_break: "); phex(code); print("\n"); | |||
} | |||
} | |||
@@ -0,0 +1,102 @@ | |||
#include <stdint.h> | |||
#include <util/delay.h> | |||
#include "usb_keycodes.h" | |||
#include "host.h" | |||
#include "timer.h" | |||
#include "print.h" | |||
#include "mousekey.h" | |||
static report_mouse_t report; | |||
static report_mouse_t report_prev; | |||
static uint8_t mousekey_repeat = 0; | |||
/* | |||
* TODO: fix acceleration algorithm | |||
* see wikipedia http://en.wikipedia.org/wiki/Mouse_keys | |||
*/ | |||
#ifndef MOUSEKEY_DELAY_TIME | |||
# define MOUSEKEY_DELAY_TIME 255 | |||
#endif | |||
static inline uint8_t move_unit(void) | |||
{ | |||
uint8_t unit = (10 + (mousekey_repeat)); | |||
return unit > 127 ? 127 : unit; | |||
} | |||
void mousekey_decode(uint8_t code) | |||
{ | |||
if (code == KB_MS_UP) report.y -= move_unit(); | |||
else if (code == KB_MS_DOWN) report.y += move_unit(); | |||
else if (code == KB_MS_LEFT) report.x -= move_unit(); | |||
else if (code == KB_MS_RIGHT) report.x += move_unit(); | |||
else if (code == KB_MS_BTN1) report.buttons |= MOUSE_BTN1; | |||
else if (code == KB_MS_BTN2) report.buttons |= MOUSE_BTN2; | |||
else if (code == KB_MS_BTN3) report.buttons |= MOUSE_BTN3; | |||
/* | |||
else if (code == KB_MS_BTN4) report.buttons |= MOUSE_BTN4; | |||
else if (code == KB_MS_BTN5) report.buttons |= MOUSE_BTN5; | |||
else if (code == KB_MS_WH_UP) report.v += 1; | |||
else if (code == KB_MS_WH_DOWN) report.v -= 1; | |||
else if (code == KB_MS_WH_LEFT) report.h -= 1; | |||
else if (code == KB_MS_WH_RIGHT)report.h += 1; | |||
*/ | |||
} | |||
bool mousekey_changed(void) | |||
{ | |||
return (report.buttons != report_prev.buttons || | |||
report.x != report_prev.x || | |||
report.y != report_prev.y || | |||
report.x || report.y); | |||
//return (report.buttons != report_prev.buttons || report.x || report.y); | |||
} | |||
void mousekey_send(void) | |||
{ | |||
static uint16_t last_timer = 0; | |||
if (!mousekey_changed()) { | |||
mousekey_repeat = 0; | |||
return; | |||
} | |||
// send immediately when buttun state is changed | |||
if (report.buttons == report_prev.buttons) { | |||
// TODO: delay parameter setting | |||
if ((timer_elapsed(last_timer) < (mousekey_repeat == 1 ? 20 : 5))) { | |||
return; | |||
} | |||
} | |||
if (report.x && report.y) { | |||
report.x *= 0.7; | |||
report.y *= 0.7; | |||
} | |||
/* | |||
print("mousekey_repeat: "); phex(mousekey_repeat); print("\n"); | |||
print("timer: "); phex16(timer_read()); print("\n"); | |||
print("last_timer: "); phex16(last_timer); print("\n"); | |||
print("mousekey: "); phex(report.buttons); print(" "); phex(report.x); print(" "); phex(report.y); print("\n"); | |||
*/ | |||
host_mouse_send(&report); | |||
report_prev.buttons = report.buttons; | |||
report_prev.x = report.x; | |||
report_prev.y = report.y; | |||
if (mousekey_repeat != 0xFF) mousekey_repeat++; | |||
last_timer = timer_read(); | |||
mousekey_clear_report(); | |||
} | |||
void mousekey_clear_report(void) | |||
{ | |||
report.buttons = 0; | |||
report.x = 0; | |||
report.y = 0; | |||
} |
@@ -0,0 +1,12 @@ | |||
#ifndef MOUSEKEY_H | |||
#define MOUSEKEY_H | |||
#include <stdbool.h> | |||
#include "host.h" | |||
void mousekey_decode(uint8_t code); | |||
bool mousekey_changed(void); | |||
void mousekey_send(void); | |||
void mousekey_clear_report(void); | |||
#endif |
@@ -77,7 +77,7 @@ section at the end of this file). | |||
* default control endpoint 0 and an interrupt-in endpoint (any other endpoint | |||
* number). | |||
*/ | |||
#define USB_CFG_HAVE_INTRIN_ENDPOINT3 0 | |||
#define USB_CFG_HAVE_INTRIN_ENDPOINT3 1 | |||
/* Define this to 1 if you want to compile a version with three endpoints: The | |||
* default control endpoint 0, an interrupt-in endpoint 3 (or the number | |||
* configured below) and a catch-all default interrupt-in endpoint as above. | |||
@@ -277,7 +277,7 @@ section at the end of this file). | |||
* HID class is 3, no subclass and protocol required (but may be useful!) | |||
* CDC class is 2, use subclass 2 and protocol 1 for ACM | |||
*/ | |||
#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 63 | |||
#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 0 | |||
/* Define this to the length of the HID report descriptor, if you implement | |||
* an HID device. Otherwise don't define it or define it to 0. | |||
* If you use this define, you must add a PROGMEM character array named | |||
@@ -343,14 +343,17 @@ section at the end of this file). | |||
*/ | |||
#define USB_CFG_DESCR_PROPS_DEVICE 0 | |||
#define USB_CFG_DESCR_PROPS_CONFIGURATION 0 | |||
#define USB_CFG_DESCR_PROPS_CONFIGURATION USB_PROP_IS_DYNAMIC | |||
//#define USB_CFG_DESCR_PROPS_CONFIGURATION 0 | |||
#define USB_CFG_DESCR_PROPS_STRINGS 0 | |||
#define USB_CFG_DESCR_PROPS_STRING_0 0 | |||
#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0 | |||
#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0 | |||
#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0 | |||
//#define USB_CFG_DESCR_PROPS_HID USB_PROP_IS_DYNAMIC | |||
#define USB_CFG_DESCR_PROPS_HID 0 | |||
#define USB_CFG_DESCR_PROPS_HID_REPORT 0 | |||
#define USB_CFG_DESCR_PROPS_HID_REPORT USB_PROP_IS_DYNAMIC | |||
//#define USB_CFG_DESCR_PROPS_HID_REPORT 0 | |||
#define USB_CFG_DESCR_PROPS_UNKNOWN 0 | |||
/* ----------------------- Optional MCU Description ------------------------ */ |