@@ -1,11 +0,0 @@ | |||
OPT_DEFS += -DHOST_VUSB | |||
SRC = usbdrv.c \ | |||
usbdrvasm.S \ | |||
oddebug.c \ | |||
sendchar_usart.c | |||
SRC += $(TARGET_SRC) | |||
# C source file search path | |||
VPATH = $(TARGET_DIR):$(COMMON_DIR):$(COMMON_DIR)/vusb:$(COMMON_DIR)/vusb/usbdrv |
@@ -0,0 +1,62 @@ | |||
Time to Sleep | |||
============= | |||
USB suspend no activity on USB line for 3ms | |||
No Interaction no user interaction | |||
matrix has no change | |||
matrix has no switch on | |||
AVR Power Management | |||
==================== | |||
V-USB suspend | |||
USB suspend | |||
http://vusb.wikidot.com/examples | |||
MCUSR MCU Status Register | |||
WDRF Watchdog Reset Flag | |||
BORF | |||
EXTRF | |||
PORF Power-on Reset Flag | |||
SMCR Sleep Mode Control Register | |||
SE Sleep Enable | |||
SM2:0 | |||
#define set_sleep_mode(mode) \ | |||
#define SLEEP_MODE_IDLE (0) | |||
#define SLEEP_MODE_ADC _BV(SM0) | |||
#define SLEEP_MODE_PWR_DOWN _BV(SM1) | |||
#define SLEEP_MODE_PWR_SAVE (_BV(SM0) | _BV(SM1)) | |||
#define SLEEP_MODE_STANDBY (_BV(SM1) | _BV(SM2)) | |||
#define SLEEP_MODE_EXT_STANDBY (_BV(SM0) | _BV(SM1) | _BV(SM2)) | |||
ACSR Analog Comparator Control and Status Register | |||
To disable Analog Comparator | |||
ACSR = 0x80; | |||
or | |||
ACSR &= ~_BV(ACIE); | |||
ACSR |= _BV(ACD); | |||
ACD: Analog Comparator Disable | |||
When this bit is written logic one, the power to the Analog Comparator is | |||
switched off. This bit can be set at any time to turn off the Analog | |||
Comparator. This will reduce power consumption in Active and Idle mode. | |||
When changing the ACD bit, the Analog Comparator Interrupt must be disabled | |||
by clearing the ACIE bit in ACSR. Otherwise an interrupt can occur when | |||
the bit is changed. | |||
DIDR1 Digital Input Disable Register 1 | |||
AIN1D | |||
AIN0D | |||
When this bit is written logic one, the digital input buffer on the AIN1/0 pin is disabled. The corresponding PIN Register bit will always read as zero when this bit is set. When an analog signal is applied to the AIN1/0 pin and the digital input from this pin is not needed, this bit should be written logic one to reduce power consumption in the digital input buffer. | |||
PRR Power Reduction Register | |||
PRTWI | |||
PRTIM2 | |||
PRTIM0 | |||
PRTIM1 | |||
PRSPI | |||
PRUSART0 | |||
PRADC |
@@ -96,8 +96,8 @@ Build Options | |||
3. Choose optional modules as needed. Comment out to disable optional modules. | |||
MOUSEKEY_ENABLE = yes # Mouse keys | |||
PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support | |||
USB_EXTRA_ENABLE = yes # Enhanced feature for Windows(Audio control and System control) | |||
USB_NKRO_ENABLE = yes # USB Nkey Rollover | |||
EXTRAKEY_ENABLE = yes # Enhanced feature for Windows(Audio control and System control) | |||
NKRO_ENABLE = yes # USB Nkey Rollover | |||
<target>/config.h: | |||
1. USB vendor/product ID and device description |
@@ -8,11 +8,11 @@ COMMON_DIR = .. | |||
TARGET_DIR = . | |||
# keyboard dependent files | |||
TARGET_SRC = main_pjrc.c \ | |||
keymap.c \ | |||
matrix.c \ | |||
led.c \ | |||
adb.c | |||
SRC = main.c \ | |||
keymap.c \ | |||
matrix.c \ | |||
led.c \ | |||
adb.c | |||
CONFIG_H = config.h | |||
@@ -36,10 +36,10 @@ F_CPU = 16000000 | |||
# Build Options | |||
# comment out to disable the options. | |||
# | |||
MOUSEKEY_ENABLE = yes # Mouse keys | |||
#MOUSEKEY_ENABLE = yes # Mouse keys | |||
#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support | |||
USB_EXTRA_ENABLE = yes # Audio control and System control | |||
#USB_NKRO_ENABLE = yes # USB Nkey Rollover | |||
#EXTRAKEY_ENABLE = yes # Audio control and System control | |||
#NKRO_ENABLE = yes # USB Nkey Rollover | |||
@@ -48,5 +48,5 @@ PROGRAM_CMD = teensy_loader_cli -mmcu=$(MCU) -w -v $(TARGET).hex | |||
include $(COMMON_DIR)/Makefile.pjrc | |||
include $(COMMON_DIR)/Makefile.common | |||
include $(COMMON_DIR)/pjrc.mk | |||
include $(COMMON_DIR)/common.mk |
@@ -59,4 +59,12 @@ effort at this time. | |||
), | |||
Notes | |||
----- | |||
Many ADB keyboards has no discrimination between right modifier and left one, | |||
you will always see left control even if you press right control key. | |||
Apple Extended Keyboard and Apple Extended Keyboard II are the examples. | |||
Though ADB protocol itsef has the ability of distinction between right and left. | |||
And most ADB keyboard has no NKRO functionality, though ADB protocol itsef has that. | |||
EOF |
@@ -37,8 +37,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
/* key combination for command */ | |||
#define IS_COMMAND() ( \ | |||
keyboard_report->mods == (BIT_LSHIFT | BIT_LCTRL | BIT_LALT | BIT_LGUI) || \ | |||
keyboard_report->mods == (BIT_LSHIFT | BIT_RSHIFT) \ | |||
keyboard_report->mods == (MOD_BIT(KB_LSHIFT) | MOD_BIT(KB_LCTRL) | MOD_BIT(KB_LALT) | MOD_BIT(KB_LGUI)) || \ | |||
keyboard_report->mods == (MOD_BIT(KB_LSHIFT) | MOD_BIT(KB_RSHIFT)) \ | |||
) | |||
@@ -30,24 +30,49 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#ifdef HOST_PJRC | |||
# include "jump_bootloader.h" | |||
# include "usb_keyboard.h" | |||
# ifdef USB_EXTRA_ENABLE | |||
# ifdef EXTRAKEY_ENABLE | |||
# include "usb_extra.h" | |||
# endif | |||
#endif | |||
#ifdef HOST_VUSB | |||
# include "usbdrv.h" | |||
#endif | |||
static uint8_t command_common(void); | |||
static void help(void); | |||
static void switch_layer(uint8_t layer); | |||
static bool last_print_enable; | |||
uint8_t command_proc(void) | |||
{ | |||
uint8_t processed = 0; | |||
last_print_enable = print_enable; | |||
if (!IS_COMMAND()) | |||
return 0; | |||
uint8_t processed = 1; | |||
bool last_print_enable = print_enable; | |||
print_enable = true; | |||
if (command_extra() || command_common()) { | |||
processed = 1; | |||
_delay_ms(500); | |||
} | |||
print_enable = last_print_enable; | |||
return processed; | |||
} | |||
/* This allows to define extra commands. return 0 when not processed. */ | |||
uint8_t command_extra(void) __attribute__ ((weak)); | |||
uint8_t command_extra(void) | |||
{ | |||
return 0; | |||
} | |||
static uint8_t command_common(void) | |||
{ | |||
switch (host_get_first_key()) { | |||
case KB_H: | |||
help(); | |||
@@ -122,21 +147,27 @@ uint8_t command_proc(void) | |||
print("usb_keyboard_protocol: "); phex(usb_keyboard_protocol); print("\n"); | |||
print("usb_keyboard_idle_config:"); phex(usb_keyboard_idle_config); print("\n"); | |||
print("usb_keyboard_idle_count:"); phex(usb_keyboard_idle_count); print("\n"); | |||
#endif | |||
#ifdef HOST_VUSB | |||
# if USB_COUNT_SOF | |||
print("usbSofCount: "); phex(usbSofCount); print("\n"); | |||
# endif | |||
#endif | |||
break; | |||
#ifdef USB_NKRO_ENABLE | |||
#ifdef NKRO_ENABLE | |||
case KB_N: | |||
// send empty report before change | |||
host_clear_keyboard_report(); | |||
host_send_keyboard_report(); | |||
keyboard_nkro = !keyboard_nkro; | |||
if (keyboard_nkro) | |||
print("USB_NKRO: enabled\n"); | |||
print("NKRO: enabled\n"); | |||
else | |||
print("USB_NKRO: disabled\n"); | |||
print("NKRO: disabled\n"); | |||
break; | |||
#endif | |||
#ifdef USB_EXTRA_ENABLE | |||
#ifdef EXTRAKEY_ENABLE | |||
case KB_ESC: | |||
host_clear_keyboard_report(); | |||
host_send_keyboard_report(); | |||
@@ -175,12 +206,9 @@ uint8_t command_proc(void) | |||
switch_layer(4); | |||
break; | |||
default: | |||
processed = 0; | |||
return 0; | |||
} | |||
if (processed) | |||
_delay_ms(500); | |||
print_enable = last_print_enable; | |||
return processed; | |||
return 1; | |||
} | |||
static void help(void) | |||
@@ -194,8 +222,8 @@ static void help(void) | |||
print("v: print version\n"); | |||
print("t: print timer count\n"); | |||
print("s: print status\n"); | |||
#ifdef USB_NKRO_ENABLE | |||
print("n: toggle USB_NKRO\n"); | |||
#ifdef NKRO_ENABLE | |||
print("n: toggle NKRO\n"); | |||
#endif | |||
print("Backspace: clear matrix\n"); | |||
print("ESC: power down/wake up\n"); |
@@ -19,5 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#define COMMAND | |||
uint8_t command_proc(void); | |||
/* This allows to extend commands. Return 0 when command is not processed. */ | |||
uint8_t command_extra(void); | |||
#endif |
@@ -19,17 +19,20 @@ ifdef PS2_MOUSE_ENABLE | |||
OPT_DEFS += -DPS2_MOUSE_ENABLE | |||
endif | |||
ifdef USB_EXTRA_ENABLE | |||
OPT_DEFS += -DUSB_EXTRA_ENABLE | |||
ifdef EXTRAKEY_ENABLE | |||
OPT_DEFS += -DEXTRAKEY_ENABLE | |||
endif | |||
ifdef USB_NKRO_ENABLE | |||
OPT_DEFS += -DUSB_NKRO_ENABLE | |||
ifdef NKRO_ENABLE | |||
OPT_DEFS += -DNKRO_ENABLE | |||
endif | |||
ifdef $(or MOUSEKEY_ENABLE, PS2_MOUSE_ENABLE) | |||
OPT_DEFS += -DUSB_MOUSE_ENABLE | |||
OPT_DEFS += -DMOUSE_ENABLE | |||
endif | |||
# Search Path | |||
VPATH += $(COMMON_DIR) | |||
include $(COMMON_DIR)/Makefile.rules | |||
include $(COMMON_DIR)/rules.mk |
@@ -0,0 +1,40 @@ | |||
ATMega168P Fuse/Lock Bits | |||
========================= | |||
This configuration is from usbasploader's Makefile. | |||
HFUSE 0xD6 | |||
LFUSE 0xDF | |||
EFUSE 0x00 | |||
LOCK 0x3F(intact) | |||
#--------------------------------------------------------------------- | |||
# ATMega168P | |||
#--------------------------------------------------------------------- | |||
# Fuse extended byte: | |||
# 0x00 = 0 0 0 0 0 0 0 0 <-- BOOTRST (boot reset vector at 0x1800) | |||
# \+/ | |||
# +------- BOOTSZ (00 = 2k bytes) | |||
# Fuse high byte: | |||
# 0xd6 = 1 1 0 1 0 1 1 0 | |||
# ^ ^ ^ ^ ^ \-+-/ | |||
# | | | | | +------ BODLEVEL 0..2 (110 = 1.8 V) | |||
# | | | | + --------- EESAVE (preserve EEPROM over chip erase) | |||
# | | | +-------------- WDTON (if 0: watchdog always on) | |||
# | | +---------------- SPIEN (allow serial programming) | |||
# | +------------------ DWEN (debug wire enable) | |||
# +-------------------- RSTDISBL (reset pin is enabled) | |||
# Fuse low byte: | |||
# 0xdf = 1 1 0 1 1 1 1 1 | |||
# ^ ^ \ / \--+--/ | |||
# | | | +------- CKSEL 3..0 (external >8M crystal) | |||
# | | +--------------- SUT 1..0 (crystal osc, BOD enabled) | |||
# | +------------------ CKOUT (if 0: Clock output enabled) | |||
# +-------------------- CKDIV8 (if 0: divide by 8) | |||
# Lock Bits | |||
# 0x3f = - - 1 1 1 1 1 1 | |||
# \ / \-/ \-/ | |||
# | | +----- LB 2..1 (No memory lock features enabled) | |||
# | +--------- BLB0 2..1 (No restrictions for SPM or LPM accessing the Application section) | |||
# +--------------- BLB1 2..1 (No restrictions for SPM or LPM accessing the Boot Loader section) |
@@ -0,0 +1,91 @@ | |||
# | |||
# Makefile for iWRAP | |||
# | |||
# Target file name (without extension). | |||
TARGET = hhkb_iwrap | |||
# Directory common source filess exist | |||
COMMON_DIR = .. | |||
# Directory keyboard dependent files exist | |||
TARGET_DIR = . | |||
# keyboard dependent files | |||
SRC = main.c \ | |||
keymap.c \ | |||
matrix.c \ | |||
led.c | |||
CONFIG_H = config_iwrap.h | |||
# V-USB debug level: To use ps2_usart.c level must be 0 | |||
# ps2_usart.c requires USART to receive PS/2 signal. | |||
OPT_DEFS = -DDEBUG_LEVEL=0 | |||
# MCU name, you MUST set this to match the board you are using | |||
# type "make clean" after changing this, so all files will be rebuilt | |||
MCU = atmega168p | |||
# avrdude doesn't know atmega168p | |||
AVRDUDE_MCU = atmega168 | |||
# Processor frequency. | |||
# Normally the first thing your program should do is set the clock prescaler, | |||
# so your program will run at the correct speed. You should also set this | |||
# variable to same clock speed. The _delay_ms() macro uses this, and many | |||
# examples use this variable to calculate timings. Do not add a "UL" here. | |||
F_CPU = 12000000 | |||
# Build Options | |||
# comment out to disable the options. | |||
# | |||
MOUSEKEY_ENABLE = yes # Mouse keys | |||
EXTRAKEY_ENABLE = yes # Audio control and System control | |||
#NKRO_ENABLE = yes # USB Nkey Rollover | |||
#---------------- Programming Options -------------------------- | |||
AVRDUDE = avrdude | |||
# Type: avrdude -c ? to get a full listing. | |||
AVRDUDE_PROGRAMMER = usbasp | |||
AVRDUDE_PORT = | |||
AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex | |||
#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep | |||
# Uncomment the following if you want avrdude's erase cycle counter. | |||
# Note that this counter needs to be initialized first using -Yn, | |||
# see avrdude manual. | |||
#AVRDUDE_ERASE_COUNTER = -y | |||
# Uncomment the following if you do /not/ wish a verification to be | |||
# performed after programming the device. | |||
#AVRDUDE_NO_VERIFY = -V | |||
# Increase verbosity level. Please use this when submitting bug | |||
# reports about avrdude. See <http://savannah.nongnu.org/projects/avrdude> | |||
# to submit bug reports. | |||
#AVRDUDE_VERBOSE = -v -v | |||
#AVRDUDE_FLAGS = -p $(AVRDUDE_MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) | |||
AVRDUDE_FLAGS = -p $(AVRDUDE_MCU) -c $(AVRDUDE_PROGRAMMER) | |||
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY) | |||
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE) | |||
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER) | |||
PROGRAM_CMD = $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) | |||
# Search Path | |||
VPATH = $(TARGET_DIR) | |||
include $(COMMON_DIR)/iwrap.mk | |||
# To be swatchable btween Bluetooth and USB. Comment out if you don't need USB. | |||
include $(COMMON_DIR)/vusb.mk | |||
include $(COMMON_DIR)/common.mk |
@@ -13,10 +13,10 @@ COMMON_DIR = .. | |||
TARGET_DIR = . | |||
# keyboard dependent files | |||
TARGET_SRC = main_pjrc.c \ | |||
keymap.c \ | |||
matrix.c \ | |||
led.c | |||
SRC = main.c \ | |||
keymap.c \ | |||
matrix.c \ | |||
led.c | |||
CONFIG_H = config_pjrc.h | |||
@@ -41,8 +41,8 @@ F_CPU = 16000000 | |||
# comment out to disable the options. | |||
MOUSEKEY_ENABLE = yes # Mouse keys | |||
#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support | |||
USB_EXTRA_ENABLE = yes # Audio control and System control | |||
USB_NKRO_ENABLE = yes # USB Nkey Rollover | |||
EXTRAKEY_ENABLE = yes # Audio control and System control | |||
NKRO_ENABLE = yes # USB Nkey Rollover | |||
@@ -51,5 +51,8 @@ PROGRAM_CMD = teensy_loader_cli -mmcu=$(MCU) -w -v $(TARGET).hex | |||
include $(COMMON_DIR)/Makefile.pjrc | |||
include $(COMMON_DIR)/Makefile.common | |||
# Search Path | |||
VPATH = $(TARGET_DIR) | |||
include $(COMMON_DIR)/pjrc.mk | |||
include $(COMMON_DIR)/common.mk |
@@ -13,10 +13,10 @@ COMMON_DIR = .. | |||
TARGET_DIR = . | |||
# keyboard dependent files | |||
TARGET_SRC = main_vusb.c \ | |||
keymap.c \ | |||
matrix.c \ | |||
led.c | |||
SRC = main.c \ | |||
keymap.c \ | |||
matrix.c \ | |||
led.c | |||
CONFIG_H = config_vusb.h | |||
@@ -28,7 +28,9 @@ OPT_DEFS = -DDEBUG_LEVEL=0 | |||
# MCU name, you MUST set this to match the board you are using | |||
# type "make clean" after changing this, so all files will be rebuilt | |||
MCU = atmega168 | |||
MCU = atmega168p | |||
# avrdude doesn't know atmega168p | |||
AVRDUDE_MCU = atmega168 | |||
# Processor frequency. | |||
@@ -36,15 +38,15 @@ MCU = atmega168 | |||
# so your program will run at the correct speed. You should also set this | |||
# variable to same clock speed. The _delay_ms() macro uses this, and many | |||
# examples use this variable to calculate timings. Do not add a "UL" here. | |||
F_CPU = 20000000 | |||
F_CPU = 12000000 | |||
# Build Options | |||
# comment out to disable the options. | |||
# | |||
MOUSEKEY_ENABLE = yes # Mouse keys | |||
USB_EXTRA_ENABLE = yes # Audio control and System control | |||
#USB_NKRO_ENABLE = yes # USB Nkey Rollover | |||
EXTRAKEY_ENABLE = yes # Audio control and System control | |||
#NKRO_ENABLE = yes # USB Nkey Rollover | |||
@@ -70,8 +72,8 @@ AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex | |||
# to submit bug reports. | |||
#AVRDUDE_VERBOSE = -v -v | |||
#AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) | |||
AVRDUDE_FLAGS = -p $(MCU) -c $(AVRDUDE_PROGRAMMER) | |||
#AVRDUDE_FLAGS = -p $(AVRDUDE_MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) | |||
AVRDUDE_FLAGS = -p $(AVRDUDE_MCU) -c $(AVRDUDE_PROGRAMMER) | |||
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY) | |||
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE) | |||
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER) | |||
@@ -80,5 +82,8 @@ PROGRAM_CMD = $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE | |||
include $(COMMON_DIR)/Makefile.vusb | |||
include $(COMMON_DIR)/Makefile.common | |||
# Search Path | |||
VPATH = $(TARGET_DIR) | |||
include $(COMMON_DIR)/vusb.mk | |||
include $(COMMON_DIR)/common.mk |
@@ -4,7 +4,7 @@ Alternative Controller for HHKB | |||
Feature | |||
------- | |||
- Mouse Keys | |||
- NKRO on USB | |||
- NKRO on USB(PJRC Tennsy only) | |||
- Keymap Layers | |||
@@ -13,8 +13,11 @@ Customize Keymap | |||
see keymap.c. | |||
Build for Teensy | |||
---------------- | |||
Build | |||
===== | |||
PJRC Teensy | |||
----------- | |||
0. Edit matrix.c. | |||
adjust scan code to your pin configuration.(see doc/HHKB.txt for pinouts) | |||
1. Define macros in config_pjrc.h.(Optional) | |||
@@ -22,15 +25,15 @@ Build for Teensy | |||
IS_COMMAND | |||
2. Edit Makefile for MCU setting and build options. | |||
MCU, F_CPU | |||
MOUSEKEY_ENABLE, USB_EXTRA_ENABLE, USB_NKRO_ENABLE | |||
MOUSEKEY_ENABLE, EXTRAKEY_ENABLE, NKRO_ENABLE | |||
3. Build hex file. | |||
$ make | |||
$ make -f Makefile.pjrc | |||
4. Program MCU. | |||
$ make program | |||
$ make -f Makefile.pjrc program | |||
Build for V-USB | |||
--------------- | |||
V-USB | |||
----- | |||
0. Edit matrix.c and usbconfig.h. | |||
adjust scan code to your pin configuration.(see doc/HHKB.txt for pinouts) | |||
define macros for V-USB in usbconfig.h. | |||
@@ -38,7 +41,7 @@ Build for V-USB | |||
IS_COMMAND | |||
2. Edit Makefile.vusb for MCU setting and build options. | |||
MCU, F_CPU | |||
MOUSEKEY_ENABLE, USB_EXTRA_ENABLE, USB_NKRO_ENABLE | |||
MOUSEKEY_ENABLE, EXTRAKEY_ENABLE | |||
3. Build hex file. | |||
$ make -f Makefile.vusb | |||
4. Program MCU. | |||
@@ -52,21 +55,59 @@ Build for V-USB | |||
http://www.obdev.at/products/vusb/usbasploader.html | |||
V-USB Circuit | |||
------------- | |||
iWRAP | |||
----- | |||
0. Edit matrix.c and usbconfig.h. | |||
adjust scan code to your pin configuration.(see doc/HHKB.txt for pinouts) | |||
define macros for V-USB in usbconfig.h. | |||
1. Define macros in config_iwrap.h.(Optional) | |||
IS_COMMAND | |||
2. Edit Makefile.iwrap for MCU setting and build options. | |||
MCU, F_CPU | |||
MOUSEKEY_ENABLE, EXTRAKEY_ENABLE | |||
3. Build hex file. | |||
$ make -f Makefile.iwrap | |||
4. Program MCU. | |||
$ make -f Makefile.iwrap program | |||
Hardware | |||
======== | |||
PJRC Teensy | |||
----------- | |||
+---------------+ | |||
| Teensy++ | | |||
| | | |||
| | HHKB | |||
| | ~~~~ | |||
| PB0-2|------->ROW(6-8) | |||
| PB3-5|------->COL(9-11) | |||
| PB6|------->ENABLE(12) | |||
| PE6|<-------KEY(4) | |||
| PE7|------->PREV(5) | |||
| | | |||
| | | |||
| | | |||
+---------------+ | |||
V-USB | |||
----- | |||
+---+ +---------------+ | |||
USB GND | | ATmega168 | | |||
=== C3 | | | |||
~~~ C3 | | | |||
5V <-------+--------+---|Vcc,AVCC | HHKB | |||
R1 | | ==== | |||
D- <----+--+-----R2-----|INT1 PB0-2|------->ROW | |||
D+ <----|---+----R3-----|INT0 PB3-5|------->COL | |||
Z1 Z2 | PB6|------->ENABLE | |||
GND<----+---+--+--+-----|GND PE6|------->KEY | |||
| | | PE7|------->PREV | |||
| C2-+--|XTAL1 | (see doc/HHKB.txt for pinouts) | |||
| X1 | | | |||
+--C3-+--|XTAL2 RST|---SW--+GND | |||
R1 | | ~~~~ | |||
D- <----+--+-----R2-----|INT1 PB2-4|------->ROW(6-8) | |||
D+ <----|---+----R3-----|INT0 PC0-2|------->COL(9-11) | |||
Z1 Z2 | PC3|------->ENABLE(12) | |||
GND<----+---+-----------|GND PB0|<-------KEY(4) | |||
| PB1|------->PREV(5) | |||
| | | |||
GND+-C2--+--|XTAL1 RXD|------->Debug Console | |||
X1 | TXD|<-------Debug Console | |||
GND+-C3--+--|XTAL2 RST|---SW--+GND | |||
+---------------+ | |||
R1: 1.5K Ohm | |||
R2,R3: 68 Ohm | |||
@@ -77,4 +118,34 @@ X1: Crystal 20MHz(16MHz/12MHz) | |||
SW: Push Switch(Optional for bootloader) | |||
iWRAP | |||
----- | |||
+---------------+ WT12 | |||
5V | ATmega168 | 5V/3.3V~~~~ | |||
+-----+---|Vcc,AVCC PC4|---/--->iWRAP(RxD) | |||
USB | C3 | PC5|<--/----iWRAP(TxD) | |||
~~~ | + | | | |||
5V <--BATT + GND | | HHKB | |||
R1 | | ~~~~ | |||
D- <----+-----+--R2-----|INT1 PB2-4|------->ROW(6-8) | |||
D+ <----|---+----R3-----|INT0 PC0-2|------->COL(9-11) | |||
Z1 Z2 | PC3|------->ENABLE(12) | |||
GND<----+---+-----------|GND PB0|<-------KEY(4) | |||
| PB1|------->PREV(5) | |||
| | | |||
GND+-C2--+--|XTAL1 RXD|------->Debug Console | |||
X1 | TXD|<-------Debug Console | |||
GND+-C3--+--|XTAL2 RST|---SW--+GND | |||
+---------------+ | |||
R1: 1.5K Ohm | |||
R2,R3: 68 Ohm | |||
Z1,Z2: Zener 3.6V | |||
C1,C2: 22pF | |||
C3: 0.1uF | |||
X1: Crystal 12MHz | |||
SW: Push Switch(Optional) | |||
BATT: Li-Po Battery, Battery Charger and Voltage Regulator(5V and 3.3V). | |||
EOF |
@@ -0,0 +1,55 @@ | |||
/* | |||
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/>. | |||
*/ | |||
#ifndef CONFIG_H | |||
#define CONFIG_H | |||
#define VENDOR_ID 0xFEED | |||
#define PRODUCT_ID 0xBEEA | |||
// TODO: share these strings with usbconfig.h | |||
// Edit usbconfig.h to change these. | |||
#define MANUFACTURER t.m.k. | |||
#define PRODUCT HHKB mod | |||
#define DESCRIPTION t.m.k. keyboard firmware for HHKB mod | |||
/* matrix size */ | |||
#define MATRIX_ROWS 8 | |||
#define MATRIX_COLS 8 | |||
/* key combination for command */ | |||
#define IS_COMMAND() (keyboard_report->mods == (MOD_BIT(KB_LSHIFT) | MOD_BIT(KB_RSHIFT))) | |||
/* mouse keys */ | |||
#ifdef MOUSEKEY_ENABLE | |||
# define MOUSEKEY_DELAY_TIME 255 | |||
#endif | |||
/* pins for Software UART */ | |||
#define SUART_IN_PIN PINC | |||
#define SUART_IN_BIT 5 | |||
#define SUART_OUT_PORT PORTC | |||
#define SUART_OUT_BIT 4 | |||
#define DEBUG_LED 1 | |||
#define DEBUG_LED_CONFIG (DDRD |= (1<<4)) | |||
#define DEBUG_LED_OFF (PORTD |= (1<<4)) | |||
#define DEBUG_LED_ON (PORTD &= ~(1<<4)) | |||
#endif |
@@ -36,11 +36,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
/* key combination for command */ | |||
#define IS_COMMAND() ( \ | |||
keyboard_report->mods == (BIT_LSHIFT | BIT_RSHIFT) || \ | |||
keyboard_report->mods == (BIT_LCTRL | BIT_RSHIFT) \ | |||
) | |||
#define IS_COMMAND() (keyboard_report->mods == (MOD_BIT(KB_LSHIFT) | MOD_BIT(KB_RSHIFT))) | |||
/* mouse keys */ | |||
#ifdef MOUSEKEY_ENABLE |
@@ -18,7 +18,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#ifndef CONFIG_H | |||
#define CONFIG_H | |||
#define VENDOR_ID 0xFEED | |||
#define PRODUCT_ID 0xC0FE | |||
// TODO: share these strings with usbconfig.h | |||
@@ -34,11 +33,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
/* key combination for command */ | |||
#define IS_COMMAND() ( \ | |||
keyboard_report->mods == (BIT_LSHIFT | BIT_RSHIFT) || \ | |||
keyboard_report->mods == (BIT_LCTRL | BIT_RSHIFT) \ | |||
) | |||
#define IS_COMMAND() (keyboard_report->mods == (MOD_BIT(KB_LSHIFT) | MOD_BIT(KB_RSHIFT))) | |||
/* mouse keys */ | |||
#ifdef MOUSEKEY_ENABLE | |||
@@ -46,4 +41,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#endif | |||
#define DEBUG_LED 1 | |||
#define DEBUG_LED_CONFIG (DDRD |= (1<<4)) | |||
#define DEBUG_LED_OFF (PORTD |= (1<<4)) | |||
#define DEBUG_LED_ON (PORTD &= ~(1<<4)) | |||
#endif |
@@ -0,0 +1,4 @@ | |||
HHKB Bluetooth mod | |||
================== | |||
See this article: | |||
http://geekhack.org/showwiki.php?title=Island:20851 |
@@ -0,0 +1,2 @@ | |||
[Picasa] | |||
name=Bluetooth_img |
@@ -32,21 +32,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
// Convert physical keyboard layout to matrix array. | |||
// This is a macro to define keymap easily in keyboard layout form. | |||
#define KEYMAP( \ | |||
R3C1, R3C0, R0C0, R1C0, R1C1, R2C0, R2C1, R4C0, R4C1, R6C0, R6C1, R7C0, R7C1, R5C0, R5C1, \ | |||
R3C2, R0C1, R0C2, R1C3, R1C2, R2C3, R2C2, R4C2, R4C3, R6C2, R6C3, R7C3, R7C2, R5C2, \ | |||
R3C3, R0C4, R0C3, R1C4, R1C5, R2C4, R2C5, R4C5, R4C4, R6C5, R6C4, R7C4, R5C3, \ | |||
R3C4, R0C5, R0C6, R0C7, R1C6, R1C7, R2C6, R4C6, R6C6, R7C6, R7C5, R5C5, R5C4, \ | |||
R3C5, R3C6, R3C7, R5C7, R5C6 \ | |||
K31, K30, K00, K10, K11, K20, K21, K40, K41, K60, K61, K70, K71, K50, K51, \ | |||
K32, K01, K02, K13, K12, K23, K22, K42, K43, K62, K63, K73, K72, K52, \ | |||
K33, K04, K03, K14, K15, K24, K25, K45, K44, K65, K64, K74, K53, \ | |||
K34, K05, K06, K07, K16, K17, K26, K46, K66, K76, K75, K55, K54, \ | |||
K35, K36, K37, K57, K56 \ | |||
) \ | |||
{ \ | |||
{ R0C0, R0C1, R0C2, R0C3, R0C4, R0C5, R0C6, R0C7 }, \ | |||
{ R1C0, R1C1, R1C2, R1C3, R1C4, R1C5, R1C6, R1C7 }, \ | |||
{ R2C0, R2C1, R2C2, R2C3, R2C4, R2C5, R2C6, KB_NO }, \ | |||
{ R3C0, R3C1, R3C2, R3C3, R3C4, R3C5, R3C6, R3C7 }, \ | |||
{ R4C0, R4C1, R4C2, R4C3, R4C4, R4C5, R4C6, KB_NO }, \ | |||
{ R5C0, R5C1, R5C2, R5C3, R5C4, R5C5, R5C6, R5C7 }, \ | |||
{ R6C0, R6C1, R6C2, R6C3, R6C4, R6C5, R6C6, KB_NO }, \ | |||
{ R7C0, R7C1, R7C2, R7C3, R7C4, R7C5, R7C6, KB_NO } \ | |||
{ KB_##K00, KB_##K01, KB_##K02, KB_##K03, KB_##K04, KB_##K05, KB_##K06, KB_##K07 }, \ | |||
{ KB_##K10, KB_##K11, KB_##K12, KB_##K13, KB_##K14, KB_##K15, KB_##K16, KB_##K17 }, \ | |||
{ KB_##K20, KB_##K21, KB_##K22, KB_##K23, KB_##K24, KB_##K25, KB_##K26, KB_NO }, \ | |||
{ KB_##K30, KB_##K31, KB_##K32, KB_##K33, KB_##K34, KB_##K35, KB_##K36, KB_##K37 }, \ | |||
{ KB_##K40, KB_##K41, KB_##K42, KB_##K43, KB_##K44, KB_##K45, KB_##K46, KB_NO }, \ | |||
{ KB_##K50, KB_##K51, KB_##K52, KB_##K53, KB_##K54, KB_##K55, KB_##K56, KB_##K57 }, \ | |||
{ KB_##K60, KB_##K61, KB_##K62, KB_##K63, KB_##K64, KB_##K65, KB_##K66, KB_NO }, \ | |||
{ KB_##K70, KB_##K71, KB_##K72, KB_##K73, KB_##K74, KB_##K75, KB_##K76, KB_NO } \ | |||
} | |||
#define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)])) | |||
@@ -58,8 +58,8 @@ static const uint8_t PROGMEM fn_layer[] = { | |||
1, // Fn1 | |||
2, // Fn2 | |||
3, // Fn3 | |||
4, // Fn4 | |||
0, // Fn5 | |||
3, // Fn4 | |||
4, // Fn5 | |||
0, // Fn6 | |||
0 // Fn7 | |||
}; | |||
@@ -71,8 +71,8 @@ static const uint8_t PROGMEM fn_keycode[] = { | |||
KB_NO, // Fn1 | |||
KB_SLSH, // Fn2 | |||
KB_SCLN, // Fn3 | |||
KB_SPC, // Fn4 | |||
KB_NO, // Fn5 | |||
KB_NO, // Fn4 | |||
KB_SPC, // Fn5 | |||
KB_NO, // Fn6 | |||
KB_NO // Fn7 | |||
}; | |||
@@ -91,11 +91,11 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | |||
* |Gui|Alt |Fn5 |Alt |Fn4| | |||
* `-------------------------------------------' | |||
*/ | |||
KEYMAP(KB_ESC, KB_1, KB_2, KB_3, KB_4, KB_5, KB_6, KB_7, KB_8, KB_9, KB_0, KB_MINS,KB_EQL, KB_BSLS,KB_GRV, \ | |||
KB_TAB, KB_Q, KB_W, KB_E, KB_R, KB_T, KB_Y, KB_U, KB_I, KB_O, KB_P, KB_LBRC,KB_RBRC,KB_BSPC, \ | |||
KB_LCTL,KB_A, KB_S, KB_D, KB_F, KB_G, KB_H, KB_J, KB_K, KB_L, KB_FN3, KB_QUOT,KB_ENT, \ | |||
KB_LSFT,KB_Z, KB_X, KB_C, KB_V, KB_B, KB_N, KB_M, KB_COMM,KB_DOT, KB_FN2, KB_RSFT,KB_FN1, \ | |||
KB_LGUI,KB_LALT,KB_FN4, KB_RALT,KB_RGUI), | |||
KEYMAP(ESC, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSLS,GRV, \ | |||
TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSPC, \ | |||
LCTL,A, S, D, F, G, H, J, K, L, FN3, QUOT,ENT, \ | |||
LSFT,Z, X, C, V, B, N, M, COMM,DOT, FN2, RSFT,FN1, \ | |||
LGUI,LALT, FN5, RALT,FN4), | |||
/* Layer 1: HHKB mode (HHKB Fn) | |||
* ,-----------------------------------------------------------. | |||
@@ -110,11 +110,11 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | |||
* |Gui |Alt |Space |Alt |xxx| | |||
* `--------------------------------------------' | |||
*/ | |||
KEYMAP(KB_ESC, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10, KB_F11, KB_F12, KB_INS, KB_DEL, \ | |||
KB_CAPS,KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_PSCR,KB_SLCK,KB_BRK, KB_UP, KB_NO, KB_BSPC, \ | |||
KB_LCTL,KB_VOLD,KB_VOLU,KB_MUTE,KB_NO, KB_NO, KB_PAST,KB_PSLS,KB_HOME,KB_PGUP,KB_LEFT,KB_RGHT,KB_ENT, \ | |||
KB_LSFT,KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_PPLS,KB_PMNS,KB_END, KB_PGDN,KB_DOWN,KB_RSFT,KB_FN1, \ | |||
KB_LGUI,KB_LALT,KB_SPC, KB_RALT,KB_FN7), | |||
KEYMAP(ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \ | |||
CAPS,NO, NO, NO, NO, NO, NO, NO, PSCR,SLCK,BRK, UP, NO, BSPC, \ | |||
LCTL,VOLD,VOLU,MUTE,NO, NO, PAST,PSLS,HOME,PGUP,LEFT,RGHT,ENT, \ | |||
LSFT,NO, NO, NO, NO, NO, PPLS,PMNS,END, PGDN,DOWN,RSFT,FN1, \ | |||
LGUI,LALT, SPC, RALT,FN7), | |||
/* Layer 2: Vi mode (Slash) | |||
* ,-----------------------------------------------------------. | |||
@@ -129,11 +129,11 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | |||
* |Gui|Alt |Space |Alt |Gui| | |||
* `-------------------------------------------' | |||
*/ | |||
KEYMAP(KB_ESC, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10, KB_F11, KB_F12, KB_INS, KB_DEL, \ | |||
KB_TAB, KB_HOME,KB_PGDN,KB_UP, KB_PGUP,KB_END, KB_HOME,KB_PGDN,KB_PGUP,KB_END, KB_NO, KB_NO, KB_NO, KB_BSPC, \ | |||
KB_LCTL,KB_NO, KB_LEFT,KB_DOWN,KB_RGHT,KB_NO, KB_LEFT,KB_DOWN,KB_UP, KB_RGHT,KB_NO, KB_NO, KB_ENT, \ | |||
KB_LSFT,KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_HOME,KB_PGDN,KB_PGUP,KB_END, KB_FN2, KB_RSFT,KB_NO, \ | |||
KB_LGUI,KB_LALT,KB_SPC, KB_RALT,KB_RGUI), | |||
KEYMAP(ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \ | |||
TAB, HOME,PGDN,UP, PGUP,END, HOME,PGDN,PGUP,END, NO, NO, NO, BSPC, \ | |||
LCTL,NO, LEFT,DOWN,RGHT,NO, LEFT,DOWN,UP, RGHT,NO, NO, ENT, \ | |||
LSFT,NO, NO, NO, NO, NO, HOME,PGDN,PGUP,END, FN2, RSFT,NO, \ | |||
LGUI,LALT, SPC, RALT,RGUI), | |||
/* Layer 3: Mouse mode (Semicolon) | |||
* ,-----------------------------------------------------------. | |||
@@ -149,11 +149,24 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | |||
* `--------------------------------------------' | |||
* Mc: Mouse Cursor / Mb: Mouse Button / Mw: Mouse Wheel | |||
*/ | |||
KEYMAP(KB_ESC, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10, KB_F11, KB_F12, KB_INS, KB_DEL, \ | |||
KB_TAB, KB_WH_L,KB_WH_U,KB_MS_U,KB_WH_D,KB_WH_R,KB_WH_L,KB_WH_D,KB_WH_U,KB_WH_R,KB_NO, KB_NO, KB_NO, KB_BSPC, \ | |||
KB_LCTL,KB_NO, KB_MS_L,KB_MS_D,KB_MS_R,KB_NO, KB_MS_L,KB_MS_D,KB_MS_U,KB_MS_R,KB_FN3, KB_NO, KB_ENT, \ | |||
KB_LSFT,KB_BTN4,KB_BTN5,KB_BTN1,KB_BTN2,KB_BTN3,KB_BTN2,KB_BTN1,KB_BTN4,KB_BTN5,KB_NO, KB_RSFT,KB_NO, \ | |||
KB_LGUI,KB_LALT,KB_BTN1,KB_RALT,KB_RGUI), | |||
#ifdef HOST_IWRAP | |||
// iWRAP does not support mouse wheel, use these keycodes to remap as wheel | |||
#define KB_KPPL KB_KP_PLUS | |||
#define KB_KPMI KB_KP_MINUS | |||
#define KB_KPAS KB_KP_ASTERISK | |||
#define KB_KPSL KB_KP_SLASH | |||
KEYMAP(ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \ | |||
TAB, KPAS,KPPL,MS_U,KPMI,KPSL,KPAS,KPPL,KPMI,KPSL,NO, NO, NO, BSPC, \ | |||
LCTL,NO, MS_L,MS_D,MS_R,NO, MS_L,MS_D,MS_U,MS_R,FN3, NO, ENT, \ | |||
LSFT,BTN4,BTN5,BTN1,BTN2,BTN3,BTN2,BTN1,NO, NO, NO, RSFT,NO, \ | |||
LGUI,LALT, BTN1, RALT,FN4), | |||
#else | |||
KEYMAP(ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \ | |||
TAB, WH_L,WH_U,MS_U,WH_D,WH_R,WH_L,WH_D,WH_U,WH_R,NO, NO, NO, BSPC, \ | |||
LCTL,NO, MS_L,MS_D,MS_R,NO, MS_L,MS_D,MS_U,MS_R,FN3, NO, ENT, \ | |||
LSFT,BTN4,BTN5,BTN1,BTN2,BTN3,BTN2,BTN1,BTN4,BTN5,NO, RSFT,NO, \ | |||
LGUI,LALT, BTN1, RALT,FN4), | |||
#endif | |||
/* Layer 4: Matias half keyboard style (Space) | |||
* ,-----------------------------------------------------------. | |||
@@ -169,18 +182,26 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | |||
* `--------------------------------------------' | |||
*/ | |||
/* | |||
KEYMAP(KB_MINS,KB_0, KB_9, KB_8, KB_7, KB_6, KB_5, KB_4, KB_3, KB_2, KB_1, KB_NO, KB_NO, KB_NO, KB_ESC, \ | |||
KB_BSPC,KB_P, KB_O, KB_I, KB_U, KB_Y, KB_T, KB_R, KB_E, KB_W, KB_Q, KB_NO, KB_NO, KB_TAB, \ | |||
KB_LCTL,KB_SCLN,KB_L, KB_K, KB_J, KB_H, KB_G, KB_F, KB_D, KB_S, KB_A, KB_RCTL,KB_RCTL, \ | |||
KB_LSFT,KB_SLSH,KB_DOT, KB_COMM,KB_M, KB_N, KB_B, KB_V, KB_C, KB_X, KB_Z, KB_RSFT,KB_NO, \ | |||
KB_LGUI,KB_LALT,KB_FN4, KB_RALT,KB_RGUI) | |||
KEYMAP(MINS,0, 9, 8, 7, 6, 5, 4, 3, 2, 1, NO, NO, NO, ESC, \ | |||
BSPC,P, O, I, U, Y, T, R, E, W, Q, NO, NO, TAB, \ | |||
LCTL,SCLN,L, K, J, H, G, F, D, S, A, RCTL,RCTL, \ | |||
LSFT,SLSH,DOT, COMM,M, N, B, V, C, X, Z, RSFT,NO, \ | |||
LGUI,LALT, FN5, RALT,RGUI) | |||
*/ | |||
/* Mouse mode (Space) */ | |||
KEYMAP(KB_ESC, KB_F1, KB_F2, KB_F3, KB_F4, KB_F5, KB_F6, KB_F7, KB_F8, KB_F9, KB_F10, KB_F11, KB_F12, KB_INS, KB_DEL, \ | |||
KB_TAB, KB_WH_L,KB_WH_U,KB_MS_U,KB_WH_D,KB_WH_R,KB_WH_L,KB_WH_D,KB_WH_U,KB_WH_R,KB_NO, KB_NO, KB_NO, KB_BSPC, \ | |||
KB_LCTL,KB_NO, KB_MS_L,KB_MS_D,KB_MS_R,KB_NO, KB_MS_L,KB_MS_D,KB_MS_U,KB_MS_R,KB_FN3, KB_NO, KB_ENT, \ | |||
KB_LSFT,KB_BTN4,KB_BTN5,KB_BTN1,KB_BTN2,KB_BTN3,KB_BTN2,KB_BTN1,KB_BTN4,KB_BTN5,KB_NO, KB_RSFT,KB_NO, \ | |||
KB_LGUI,KB_LALT,KB_FN4, KB_RALT,KB_RGUI), | |||
#ifdef HOST_IWRAP | |||
KEYMAP(ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \ | |||
TAB, KPAS,KPPL,MS_U,KPMI,KPSL,KPAS,KPPL,KPMI,KPSL,NO, NO, NO, BSPC, \ | |||
LCTL,NO, MS_L,MS_D,MS_R,NO, MS_L,MS_D,MS_U,MS_R,FN3, NO, ENT, \ | |||
LSFT,BTN4,BTN5,BTN1,BTN2,BTN3,BTN2,BTN1,BTN4,BTN5,NO, RSFT,NO, \ | |||
LGUI,LALT, FN5, RALT,RGUI), | |||
#else | |||
KEYMAP(ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, INS, DEL, \ | |||
TAB, WH_L,WH_U,MS_U,WH_D,WH_R,WH_L,WH_D,WH_U,WH_R,NO, NO, NO, BSPC, \ | |||
LCTL,NO, MS_L,MS_D,MS_R,NO, MS_L,MS_D,MS_U,MS_R,FN3, NO, ENT, \ | |||
LSFT,BTN4,BTN5,BTN1,BTN2,BTN3,BTN2,BTN1,BTN4,BTN5,NO, RSFT,NO, \ | |||
LGUI,LALT, FN5, RALT,RGUI), | |||
#endif | |||
}; | |||
@@ -25,9 +25,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#include <util/delay.h> | |||
#include "print.h" | |||
#include "util.h" | |||
#include "timer.h" | |||
#include "matrix.h" | |||
// Timer resolution check | |||
#if (1000000/TIMER_RAW_FREQ > 20) | |||
# error "Timer resolution(>20us) is not enough for HHKB matrix scan tweak on V-USB." | |||
#endif | |||
#if (MATRIX_COLS > 16) | |||
# error "MATRIX_COLS must not exceed 16" | |||
#endif | |||
@@ -82,18 +88,22 @@ static bool matrix_has_ghost_in_row(uint8_t row); | |||
#define KEY_STATE() (PINE & (1<<6)) | |||
#define KEY_PREV_ON() (PORTE |= (1<<7)) | |||
#define KEY_PREV_OFF() (PORTE &= ~(1<<7)) | |||
#define KEY_POWER_ON() | |||
#define KEY_POWER_OFF() | |||
#else | |||
// Ports for V-USB | |||
// key: PB0(pull-uped) | |||
// prev: PB1 | |||
// row: PB2-4 | |||
// col: PC0-2,3 | |||
// power: PB5(Low:on/Hi-z:off) | |||
#define KEY_INIT() do { \ | |||
DDRB |= 0x1E; \ | |||
DDRB &= ~(1<<0); \ | |||
PORTB |= (1<<0); \ | |||
DDRC |= 0x0F; \ | |||
DDRB |= 0x3E; \ | |||
DDRB &= ~(1<<0); \ | |||
PORTB |= 1<<0; \ | |||
DDRC |= 0x0F; \ | |||
KEY_UNABLE(); \ | |||
KEY_PREV_OFF(); \ | |||
} while (0) | |||
#define KEY_SELECT(ROW, COL) do { \ | |||
PORTB = (PORTB & 0xE3) | ((ROW) & 0x07)<<2; \ | |||
@@ -104,6 +114,18 @@ static bool matrix_has_ghost_in_row(uint8_t row); | |||
#define KEY_STATE() (PINB & (1<<0)) | |||
#define KEY_PREV_ON() (PORTB |= (1<<1)) | |||
#define KEY_PREV_OFF() (PORTB &= ~(1<<1)) | |||
// Power supply switching | |||
#define KEY_POWER_ON() do { \ | |||
KEY_INIT(); \ | |||
PORTB &= ~(1<<5); \ | |||
_delay_us(200); \ | |||
} while (0) | |||
#define KEY_POWER_OFF() do { \ | |||
DDRB &= ~0x3F; \ | |||
PORTB &= ~0x3F; \ | |||
DDRC &= ~0x0F; \ | |||
PORTC &= ~0x0F; \ | |||
} while (0) | |||
#endif | |||
@@ -138,36 +160,46 @@ uint8_t matrix_scan(void) | |||
matrix_prev = matrix; | |||
matrix = tmp; | |||
KEY_POWER_ON(); | |||
for (uint8_t row = 0; row < MATRIX_ROWS; row++) { | |||
for (uint8_t col = 0; col < MATRIX_COLS; col++) { | |||
KEY_SELECT(row, col); | |||
_delay_us(40); // from logic analyzer chart | |||
_delay_us(40); | |||
// Not sure this is needed. This just emulates HHKB controller's behaviour. | |||
if (matrix_prev[row] & (1<<col)) { | |||
KEY_PREV_ON(); | |||
} | |||
_delay_us(7); // from logic analyzer chart | |||
_delay_us(7); | |||
// NOTE: KEY_STATE is valid only in 20us after KEY_ENABLE. | |||
// If V-USB interrupts in this section we could lose 40us or so | |||
// and would read invalid value from KEY_STATE. | |||
uint8_t last = TIMER_RAW; | |||
#if HOST_VUSB | |||
// to avoid V-USB interrupt during read key state | |||
uint8_t sreg = SREG; | |||
cli(); | |||
#endif | |||
KEY_ENABLE(); | |||
_delay_us(10); // from logic analyzer chart | |||
// Wait for KEY_STATE outputs its value. | |||
// 1us was ok on one HHKB, but not worked on another. | |||
_delay_us(10); | |||
if (KEY_STATE()) { | |||
matrix[row] &= ~(1<<col); | |||
} else { | |||
matrix[row] |= (1<<col); | |||
} | |||
#if HOST_VUSB | |||
SREG = sreg; | |||
#endif | |||
// Ignore if this code region execution time elapses more than 20us. | |||
if (TIMER_DIFF_RAW(TIMER_RAW, last) > 20/(1000000/TIMER_RAW_FREQ)) { | |||
matrix[row] = matrix_prev[row]; | |||
} | |||
KEY_PREV_OFF(); | |||
KEY_UNABLE(); | |||
_delay_us(150); // from logic analyzer chart | |||
// NOTE: KEY_STATE keep its state in 20us after KEY_ENABLE. | |||
// This takes 25us or more to make sure KEY_STATE returns to idle state. | |||
_delay_us(150); | |||
} | |||
} | |||
KEY_POWER_OFF(); | |||
return 1; | |||
} | |||
@@ -171,7 +171,7 @@ section at the end of this file). | |||
/* This macro (if defined) is executed when a USB SET_ADDRESS request was | |||
* received. | |||
*/ | |||
#define USB_COUNT_SOF 0 | |||
#define USB_COUNT_SOF 1 | |||
/* define this macro to 1 if you need the global variable "usbSofCount" which | |||
* counts SOF packets. This feature requires that the hardware interrupt is | |||
* connected to D- instead of D+. | |||
@@ -352,8 +352,8 @@ section at the end of this file). | |||
#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 USB_PROP_IS_DYNAMIC | |||
//#define USB_CFG_DESCR_PROPS_HID 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 | |||
@@ -375,4 +375,14 @@ section at the end of this file). | |||
/* #define USB_INTR_PENDING_BIT INTF0 */ | |||
/* #define USB_INTR_VECTOR INT0_vect */ | |||
/* Set INT1 for D- falling edge to count SOF */ | |||
/* #define USB_INTR_CFG EICRA */ | |||
#define USB_INTR_CFG_SET ((1 << ISC11) | (0 << ISC10)) | |||
/* #define USB_INTR_CFG_CLR 0 */ | |||
/* #define USB_INTR_ENABLE EIMSK */ | |||
#define USB_INTR_ENABLE_BIT INT1 | |||
/* #define USB_INTR_PENDING EIFR */ | |||
#define USB_INTR_PENDING_BIT INTF1 | |||
#define USB_INTR_VECTOR INT1_vect | |||
#endif /* __usbconfig_h_included__ */ |
@@ -0,0 +1,190 @@ | |||
/* | |||
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 <avr/interrupt.h> | |||
#include "usb_keycodes.h" | |||
#include "host.h" | |||
#include "util.h" | |||
#include "debug.h" | |||
#ifdef NKRO_ENABLE | |||
bool keyboard_nkro = false; | |||
#endif | |||
static host_driver_t *driver; | |||
static report_keyboard_t report0; | |||
static report_keyboard_t report1; | |||
report_keyboard_t *keyboard_report = &report0; | |||
report_keyboard_t *keyboard_report_prev = &report1; | |||
static inline void add_key_byte(uint8_t code); | |||
static inline void add_key_bit(uint8_t code); | |||
void host_set_driver(host_driver_t *d) | |||
{ | |||
driver = d; | |||
} | |||
host_driver_t *host_get_driver(void) | |||
{ | |||
return driver; | |||
} | |||
uint8_t host_keyboard_leds(void) | |||
{ | |||
if (!driver) return 0; | |||
return (*driver->keyboard_leds)(); | |||
} | |||
/* keyboard report operations */ | |||
void host_add_key(uint8_t key) | |||
{ | |||
#ifdef NKRO_ENABLE | |||
if (keyboard_nkro) { | |||
add_key_bit(key); | |||
return; | |||
} | |||
#endif | |||
add_key_byte(key); | |||
} | |||
void host_add_mod_bit(uint8_t mod) | |||
{ | |||
keyboard_report->mods |= mod; | |||
} | |||
void host_set_mods(uint8_t mods) | |||
{ | |||
keyboard_report->mods = mods; | |||
} | |||
void host_add_code(uint8_t code) | |||
{ | |||
if (IS_MOD(code)) { | |||
host_add_mod_bit(MOD_BIT(code)); | |||
} else { | |||
host_add_key(code); | |||
} | |||
} | |||
void host_swap_keyboard_report(void) | |||
{ | |||
uint8_t sreg = SREG; | |||
cli(); | |||
report_keyboard_t *tmp = keyboard_report_prev; | |||
keyboard_report_prev = keyboard_report; | |||
keyboard_report = tmp; | |||
SREG = sreg; | |||
} | |||
void host_clear_keyboard_report(void) | |||
{ | |||
keyboard_report->mods = 0; | |||
for (int8_t i = 0; i < REPORT_KEYS; i++) { | |||
keyboard_report->keys[i] = 0; | |||
} | |||
} | |||
uint8_t host_has_anykey(void) | |||
{ | |||
uint8_t cnt = 0; | |||
for (int i = 0; i < REPORT_KEYS; i++) { | |||
if (keyboard_report->keys[i]) | |||
cnt++; | |||
} | |||
return cnt; | |||
} | |||
uint8_t host_get_first_key(void) | |||
{ | |||
#ifdef NKRO_ENABLE | |||
if (keyboard_nkro) { | |||
uint8_t i = 0; | |||
for (; i < REPORT_KEYS && !keyboard_report->keys[i]; i++) | |||
; | |||
return i<<3 | biton(keyboard_report->keys[i]); | |||
} | |||
#endif | |||
return keyboard_report->keys[0]; | |||
} | |||
void host_send_keyboard_report(void) | |||
{ | |||
if (!driver) return; | |||
(*driver->send_keyboard)(keyboard_report); | |||
} | |||
void host_mouse_send(report_mouse_t *report) | |||
{ | |||
if (!driver) return; | |||
(*driver->send_mouse)(report); | |||
} | |||
void host_system_send(uint16_t data) | |||
{ | |||
if (!driver) return; | |||
(*driver->send_consumer)(data); | |||
} | |||
void host_consumer_send(uint16_t data) | |||
{ | |||
// TODO: this is needed? | |||
static uint16_t last_data = 0; | |||
if (data == last_data) return; | |||
last_data = data; | |||
if (!driver) return; | |||
(*driver->send_consumer)(data); | |||
} | |||
static inline void add_key_byte(uint8_t code) | |||
{ | |||
// TODO: fix ugly code | |||
int8_t i = 0; | |||
int8_t empty = -1; | |||
for (; i < REPORT_KEYS; i++) { | |||
if (keyboard_report_prev->keys[i] == code) { | |||
keyboard_report->keys[i] = code; | |||
break; | |||
} | |||
if (empty == -1 && | |||
keyboard_report_prev->keys[i] == 0 && | |||
keyboard_report->keys[i] == 0) { | |||
empty = i; | |||
} | |||
} | |||
if (i == REPORT_KEYS) { | |||
if (empty != -1) { | |||
keyboard_report->keys[empty] = code; | |||
} | |||
} | |||
} | |||
static inline void add_key_bit(uint8_t code) | |||
{ | |||
if ((code>>3) < REPORT_KEYS) { | |||
keyboard_report->keys[code>>3] |= 1<<(code&7); | |||
} else { | |||
debug("add_key_bit: can't add: "); phex(code); debug("\n"); | |||
} | |||
} |
@@ -19,88 +19,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#define HOST_H | |||
#include <stdint.h> | |||
#include "report.h" | |||
#include "host_driver.h" | |||
/* report id */ | |||
#define REPORT_ID_MOUSE 1 | |||
#define REPORT_ID_SYSTEM 2 | |||
#define REPORT_ID_CONSUMER 3 | |||
/* keyboard Modifiers in boot protocol report */ | |||
#define BIT_LCTRL (1<<0) | |||
#define BIT_LSHIFT (1<<1) | |||
#define BIT_LALT (1<<2) | |||
#define BIT_LGUI (1<<3) | |||
#define BIT_RCTRL (1<<4) | |||
#define BIT_RSHIFT (1<<5) | |||
#define BIT_RALT (1<<6) | |||
#define BIT_RGUI (1<<7) | |||
#define BIT_LCTL BIT_LCTRL | |||
#define BIT_RCTL BIT_RCTRL | |||
#define BIT_LSFT BIT_LSHIFT | |||
#define BIT_RSFT BIT_RSHIFT | |||
/* mouse buttons */ | |||
#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) | |||
// Consumer Page(0x0C) | |||
#define AUDIO_MUTE 0x00E2 | |||
#define AUDIO_VOL_UP 0x00E9 | |||
#define AUDIO_VOL_DOWN 0x00EA | |||
#define TRANSPORT_NEXT_TRACK 0x00B5 | |||
#define TRANSPORT_PREV_TRACK 0x00B6 | |||
#define TRANSPORT_STOP 0x00B7 | |||
#define TRANSPORT_PLAY_PAUSE 0x00CD | |||
#define AL_CC_CONFIG 0x0183 | |||
#define AL_EMAIL 0x018A | |||
#define AL_CALCULATOR 0x0192 | |||
#define AL_LOCAL_BROWSER 0x0194 | |||
#define AC_SEARCH 0x0221 | |||
#define AC_HOME 0x0223 | |||
#define AC_BACK 0x0224 | |||
#define AC_FORWARD 0x0225 | |||
#define AC_STOP 0x0226 | |||
#define AC_REFRESH 0x0227 | |||
#define AC_BOOKMARKS 0x022A | |||
// Generic Desktop Page(0x01) | |||
#define SYSTEM_POWER_DOWN 0x0081 | |||
#define SYSTEM_SLEEP 0x0082 | |||
#define SYSTEM_WAKE_UP 0x0083 | |||
#if defined(HOST_PJRC) | |||
# include "usb.h" | |||
# if defined(KBD2_REPORT_KEYS) && KBD2_REPORT_KEYS > KBD_REPORT_KEYS | |||
# define REPORT_KEYS KBD2_REPORT_KEYS | |||
# else | |||
# define REPORT_KEYS KBD_REPORT_KEYS | |||
# endif | |||
#elif defined(HOST_VUSB) | |||
# define REPORT_KEYS 6 | |||
#endif | |||
typedef struct { | |||
uint8_t mods; | |||
uint8_t rserved; | |||
uint8_t keys[REPORT_KEYS]; | |||
} report_keyboard_t; | |||
typedef struct { | |||
uint8_t report_id; | |||
uint8_t buttons; | |||
int8_t x; | |||
int8_t y; | |||
int8_t v; | |||
int8_t h; | |||
} report_mouse_t; | |||
#ifdef USB_NKRO_ENABLE | |||
#ifdef NKRO_ENABLE | |||
extern bool keyboard_nkro; | |||
#endif | |||
@@ -108,6 +31,8 @@ extern report_keyboard_t *keyboard_report; | |||
extern report_keyboard_t *keyboard_report_prev; | |||
void host_set_driver(host_driver_t *driver); | |||
host_driver_t *host_get_driver(void); | |||
uint8_t host_keyboard_leds(void); | |||
/* keyboard report operations */ | |||
@@ -122,12 +47,8 @@ uint8_t host_get_first_key(void); | |||
void host_send_keyboard_report(void); | |||
#if defined(MOUSEKEY_ENABLE) || defined(PS2_MOUSE_ENABLE) | |||
void host_mouse_send(report_mouse_t *report); | |||
#endif | |||
#ifdef USB_EXTRA_ENABLE | |||
void host_system_send(uint16_t data); | |||
void host_consumer_send(uint16_t data); | |||
#endif | |||
#endif |
@@ -0,0 +1,33 @@ | |||
/* | |||
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/>. | |||
*/ | |||
#ifndef HOST_DRIVER_H | |||
#define HOST_DRIVER_H | |||
#include <stdint.h> | |||
#include "report.h" | |||
typedef struct { | |||
uint8_t (*keyboard_leds)(void); | |||
void (*send_keyboard)(report_keyboard_t *); | |||
void (*send_mouse)(report_mouse_t *); | |||
void (*send_system)(uint16_t); | |||
void (*send_consumer)(uint16_t); | |||
} host_driver_t; | |||
#endif |
@@ -0,0 +1,10 @@ | |||
OPT_DEFS += -DHOST_IWRAP | |||
SRC += iwrap.c \ | |||
suart.S \ | |||
sendchar_uart.c \ | |||
uart.c | |||
# Search Path | |||
VPATH += $(COMMON_DIR)/iwrap |
@@ -0,0 +1,376 @@ | |||
Bulegiga WT12 | |||
============= | |||
WT12 is a bluetooth module from Bluegiga. http://www.bluegiga.com/ | |||
iWRAP | |||
higher layer interface for bluetooth firmware | |||
communicate with UART | |||
iWRAP HID | |||
default setting | |||
115200 8bit/n/1/n | |||
TODO | |||
---- | |||
KiCAD circuit/PCB design | |||
power saving | |||
AVR sleep(15ms by watch dog timer) | |||
WT12 sleep | |||
measuring current consumption | |||
measuring battery life of normal usage/idle/intensive usage | |||
software reset/bootloarder | |||
LED indicator(chaging/paring/connecting) | |||
license confirmation of suart.c | |||
consumer page is not working | |||
authenticate method/SSP | |||
SPP keyboard support | |||
SPP debug console support | |||
mouse wheel feature request to Bluegiga | |||
Problems | |||
-------- | |||
power consumption | |||
no consumer page support(bug?) | |||
no mouse wheel support | |||
no paring management | |||
no interactive auth method | |||
UART hardware flow control | |||
-------------------------- | |||
(iWRAP4 User Guide 9.5) | |||
Hardware flow control is enabled by default and it should not be disabled unless mandatory, because without the hardware flow control the data transmission may not be reliable. | |||
If the hardware flow control is enabled from PS-keys, but no flow control is used, the following steps should be implemented in the hardware design: | |||
- CTS pin must be grounded | |||
- RTS pin must be left floating | |||
Power Saving | |||
------------ | |||
power consume | |||
without opimization: 4hr to shutdown(310mAh) | |||
2011/08/25: 9hr(310mAh) SNIFF MASTER sleep/WDTO_120MS | |||
measure current consumption | |||
HHKB keyswitch matrix board | |||
idle | |||
scanning | |||
Bluegiga WT12 module | |||
SLEEP command | |||
deep sleep on/off in config bits | |||
HHKB keyswich | |||
how to power off | |||
I/O pin configuration when sleeping | |||
FET switch for 5V regulator | |||
Bluetooth module | |||
power off when in USB mode | |||
power off by FET switch | |||
AVR configuration | |||
unused pins | |||
ADC | |||
SET CONTROL CONFIG | |||
------------------ | |||
SET CONTROL CONFIG 4810 | |||
SET CONTROL CONFIG LIST | |||
SET CONTROL CONFIG 0000 0000 4910 DEEP_SLEEP KLUDGE INTERACTIVE_PIN UART_LATENCY | |||
Bit14 UART low latency | |||
Bit11 Interactive pairing mode | |||
Bit04 Deep sleep | |||
Reconnection | |||
------------ | |||
SET CONTROL AUTOCALL 1124 5000 HID | |||
1124 HID service class | |||
5000 interval ms | |||
HID profile | |||
----------- | |||
This is needed to configure only once. | |||
SET PROFILE HID ON | |||
RESET | |||
HID class | |||
--------- | |||
SET BT CLASS 005C0 // keyboard/mouse combined devie | |||
Pairing Security | |||
---------------- | |||
Secure Simple Pairing(SSP) | |||
SET BT SSP 2 0 // Enables SSP for keyboard and Man-in-the-middle protection | |||
SET BT SSP 3 0 // Enables SSP just works mode | |||
for keyboard with SSP | |||
SET BT AUTH * 0000 | |||
SET BT SSP 2 0 | |||
SET CONTROL CONFIG 800 | |||
RESET | |||
for keyboard without SSP | |||
SET BT AUTH * 0000 | |||
SET CONTROL CONFIG 800 | |||
RESET | |||
AUTH | |||
AUTH xx:xx:xx:xx:xx:xx? // Pairing request event | |||
AUTH xx:xx:xx:xx:xx:xx 0000 | |||
SSP PASSKEY 78:dd:08:b7:e4:a2 ? | |||
SSP PASSKEY 78:dd:08:b7:e4:a2 xxxxx | |||
(SSP COMPLETE 78:dd:08:b7:e4:a2 HCI_ERROR_AUTH_FAIL // failed) | |||
RING 0 78:dd:08:b7:e4:a2 11 HID | |||
Connecton | |||
RING xx:xx:xx:xx:xx:xx xx HID // connection event | |||
KILL xx:xx:xx:xx:xx:xx | |||
Mode | |||
---- | |||
Command mode | |||
Data mode | |||
Raw mode | |||
(Simple mode not for a real keyboard) | |||
Raw mode | |||
Keyboard: | |||
0x9f, length(10), 0xa1, 0x01, mods, 0x00, key1, key2, key3, key4, key5, key6 | |||
Mouse: | |||
0x9f, length(5), 0xa1, 0x02, buttons, X, Y | |||
Consumer page: | |||
0x9f, length(5), 0xa1, 0x03, bitfield1, bitfield2, bitfield3 | |||
consumer page suage | |||
Bitfield 1: | |||
0x01 Volume Increment | |||
0x02 Volume Decrement | |||
0x04 Mute | |||
0x08 Play/Pause | |||
0x10 Scan Next Track | |||
0x20 Scan Previous Track | |||
0x40 Stop | |||
0x80 Eject | |||
Bitfield 2: | |||
0x01 Email Reader | |||
0x02 Application Control Search | |||
0x04 AC Bookmarks | |||
0x08 AC Home | |||
0x10 AC Back | |||
0x20 AC Forward | |||
0x40 AC Stop | |||
0x80 AC Refresh | |||
Bitfield 3: | |||
0x01 Application Launch Generic Consumer Control | |||
0x02 AL Internet Browser | |||
0x04 AL Calculator | |||
0x08 AL Terminal Lock / Screensaver | |||
0x10 AL Local Machine Browser | |||
0x20 AC Minimize | |||
0x40 Record | |||
0x80 Rewind | |||
2011/07/13 | |||
set | |||
SET BT BDADDR 00:07:80:47:22:14 | |||
SET BT NAME HHKB pro BT | |||
SET BT CLASS 0005c0 | |||
SET BT AUTH * 0000 | |||
SET BT IDENT BT:47 f000 4.1.0 Bluegiga iWRAP | |||
SET BT LAP 9e8b33 | |||
SET BT PAGEMODE 4 2000 1 | |||
SET BT PAIR 78:dd:08:b7:e4:a2 a191189cd7e51030ad6a07848ce879bb | |||
SET BT POWER 3 3 3 | |||
SET BT ROLE 0 f 7d00 | |||
SET BT SNIFF 0 20 1 8 | |||
SET BT SSP 2 1 | |||
SET BT MTU 667 | |||
SET CONTROL AUTOCALL 1124 3000 HID | |||
SET CONTROL BAUD 38400,8n1 | |||
SET CONTROL CD 00 0 | |||
SET CONTROL ECHO 7 | |||
SET CONTROL ESCAPE 43 00 1 | |||
SET CONTROL GAIN 0 5 | |||
SET CONTROL INIT SET CONTROL MUX 0 | |||
SET CONTROL MSC DTE 00 00 00 00 00 00 | |||
SET CONTROL MUX 1 | |||
SET CONTROL PIO 00 00 | |||
SET CONTROL READY 00 | |||
SET PROFILE HID f HID | |||
SET | |||
info config | |||
!!! THIS IS BETA RELEASE AND MAY BE USED FOR EVALUATION PURPOSES ONLY !!! | |||
WRAP THOR AI (4.1.0 build 435) | |||
Copyright (c) 2003-2011 Bluegiga Technologies Inc. | |||
Compiled on Jun 28 2011 17:19:51, running on WT12-A module, psr v31 | |||
AVRCP BGIO FTP HFP HFP_AG HID HID_CONSUMER_PAGE HSP LEDS MAP OTA PBAP PIO=0x00fc SSP SUBRATE TEST VOLUME | |||
- BOCK3 version 435 (Jun 28 2011 17:19:37) (max acl/sco 7/1) | |||
- Bluetooth version 2.1, Power class 2 | |||
- Loader 4279, firmware 6297 (56-bit encryption), native execution mode | |||
- up 0 days, 06:23, 2 connections (pool 2) | |||
- User configuration: | |||
&028a = 0001 0000 0000 0011 0024 0000 0000 0010 0000 0080 0000 0000 0080 005f 009b 0034 00fb 0006 | |||
&028b = 0000 0bb8 | |||
&028d = 0001 | |||
&0295 = 0000 0005 000b 0000 0003 0000 0000 0000 0000 0000 0000 | |||
&0298 = a006 | |||
&0299 = 0000 0000 | |||
&02a3 = 0030 0030 0030 0030 | |||
&02a4 = 009d 0000 | |||
&02a5 = 0053 0045 0054 0020 0043 004f 004e 0054 0052 004f 004c 0020 004d 0055 0058 0020 0030 | |||
&02a7 = 0000 05c0 | |||
&02a8 = 4910 0000 0000 | |||
&02aa = 0004 2000 0001 0033 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 | |||
&02ac = 0000 0000 002b 0000 0000 0000 0000 0000 0000 0000 0002 0000 0000 0000 0010 0000 0000 0000 0000 029b 0000 0000 0000 0000 | |||
&02ad = 4848 424b 7020 6f72 4220 0054 | |||
&02b3 = 0005 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 | |||
&02b7 = 000f 4948 0044 | |||
&02bb = 8000 | |||
READY. | |||
2011/07/07 settings: | |||
set | |||
SET BT BDADDR 00:07:80:47:22:14 | |||
SET BT NAME HHKB Pro BT | |||
SET BT CLASS 0005c0 | |||
SET BT AUTH * 000 | |||
SET BT IDENT BT:47 f000 4.0.0 Bluegiga iWRAP | |||
SET BT LAP 9e8b33 | |||
SET BT PAGEMODE 4 2000 1 | |||
SET BT PAIR 78:dd:08:b7:e4:a2 9e54d0aabb1b4d73cfccddb1ea4ef2d6 | |||
SET BT POWER 3 3 3 | |||
SET BT ROLE 0 f 7d00 | |||
SET BT SNIFF 0 20 1 8 | |||
SET BT SSP 3 0 | |||
SET BT MTU 667 | |||
SET CONTROL BAUD 38400,8n1 | |||
SET CONTROL CD 00 0 | |||
SET CONTROL ECHO 7 | |||
SET CONTROL ESCAPE 255 00 1 | |||
SET CONTROL GAIN 0 5 | |||
SET CONTROL INIT set control mux 0 | |||
SET CONTROL MSC DTE 00 00 00 00 00 00 | |||
SET CONTROL PREAMP 1 1 | |||
SET CONTROL READY 00 | |||
SET PROFILE HID HID | |||
SET PROFILE SPP Bluetooth Serial Port | |||
SET | |||
info config | |||
WRAP THOR AI (4.0.0 build 317) | |||
Copyright (c) 2003-2010 Bluegiga Technologies Inc. | |||
Compiled on Apr 20 2010 16:44:28, running on WT12-A module, psr v31 | |||
AVRCP FTP PBAP PIO=0x00fc SSP SUBRATE VOLUME | |||
- BOCK3 version 317 (Apr 20 2010 16:44:21) (max acl/sco 7/1) | |||
- Bluetooth version 2.1, Power class 2 | |||
- Loader 4279, firmware 6297 (56-bit encryption), native execution mode | |||
- up 0 days, 00:00, 0 connections (pool 1) | |||
- User configuration: | |||
&028c = 0001 0020 0000 0001 0008 0000 | |||
&028d = 0000 | |||
&0296 = 0047 0001 f000 0400 6c42 6575 6967 6167 6920 5257 5041 | |||
&0298 = c006 | |||
&02a3 = 0030 0030 0030 | |||
&02a4 = 009d 0000 | |||
&02a5 = 0073 0065 0074 0020 0063 006f 006e 0074 0072 006f 006c 0020 006d 0075 0078 0020 0030 | |||
&02a7 = 0000 05c0 | |||
&02a8 = 0800 0000 0000 | |||
&02ac = 0000 0000 00ff 0000 0000 0000 0000 0000 0000 0000 0002 0000 0000 0000 0010 0000 0000 0000 0000 029b 0000 0000 0000 0000 | |||
&02ad = 4848 424b 5020 6f72 4220 0054 | |||
&02b3 = 0004 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 0003 | |||
&02b7 = 0000 | |||
&02bb = 6c42 6575 6f74 746f 2068 6553 6972 6c61 5020 726f 0074 | |||
READY. | |||
2011/08/23: | |||
SET BT BDADDR 00:07:80:47:22:14 | |||
SET BT NAME HHKB pro BT | |||
SET BT CLASS 0005c0 | |||
SET BT AUTH * 0000 | |||
SET BT IDENT BT:47 f000 4.1.0 Bluegiga iWRAP | |||
SET BT LAP 9e8b33 | |||
SET BT PAGEMODE 4 2000 1 | |||
SET BT PAIRCOUNT 4 | |||
SET BT POWER 3 3 3 | |||
SET BT ROLE 1 f 12c0 | |||
SET BT SNIFF 10 2 1 8 | |||
SET BT SSP 3 0 | |||
SET BT MTU 667 | |||
SET CONTROL BAUD 38400,8n1 | |||
SET CONTROL CD 00 0 | |||
SET CONTROL ECHO 7 | |||
SET CONTROL ESCAPE 43 00 1 | |||
SET CONTROL GAIN 0 5 | |||
SET CONTROL INIT SET CONTROL MUX 0 | |||
SET CONTROL MSC DTE 00 00 00 00 00 00 | |||
SET CONTROL MUX 1 | |||
SET CONTROL PIO 00 00 | |||
SET CONTROL READY 00 | |||
SET PROFILE HID 7 HIDKeyboardMouse | |||
SET | |||
SET CONTROL CONFIG 0000 0004 481e CLOCK_CACHE INTERLACED_INQ INTERLACED_PAGE DEEP_SLEEP INTERACTIVE_PIN UART_LATENCY 23D_NOKLUDGE | |||
2011/08/25: | |||
SET BT BDADDR 00:07:80:47:22:14 | |||
SET BT NAME HHKB pro BT | |||
SET BT CLASS 0005c0 | |||
SET BT IDENT BT:47 f000 4.1.0 Bluegiga iWRAP | |||
SET BT LAP 9e8b33 | |||
SET BT PAGEMODE 4 2000 1 | |||
SET BT PAIRCOUNT 4 | |||
SET BT PAIR 78:dd:08:b7:e4:a2 0be83335a03fed8ededae42e99554e28 | |||
SET BT POWER 3 3 3 | |||
SET BT ROLE 1 f 12c0 | |||
SET BT SNIFF 100 20 1 8 | |||
SET BT SSP 3 0 | |||
SET BT MTU 667 | |||
SET CONTROL BAUD 38400,8n1 | |||
SET CONTROL CD 00 0 | |||
SET CONTROL ECHO 7 | |||
SET CONTROL ESCAPE - 20 1 | |||
SET CONTROL GAIN 0 5 | |||
SET CONTROL INIT SET CONTROL MUX 0 | |||
SET CONTROL MSC DTE 00 00 00 00 00 00 | |||
SET CONTROL MUX 1 | |||
SET CONTROL PIO 00 00 | |||
SET CONTROL READY 00 | |||
SET PROFILE HID f HIDKeyboardMouse | |||
SET | |||
SET CONTROL CONFIG 0000 0000 490e CLOCK_CACHE INTERLACED_INQ INTERLACED_PAGE KLUDGE INTERACTIVE_PIN UART_LATENCY | |||
2011/09/08: | |||
SET CONTROL CONFIG 0000 0000 410e CLOCK_CACHE INTERLACED_INQ INTERLACED_PAGE KLUDGE UART_LATENCY | |||
Removed INTERACTIVE_PIN to avoid interactive auth and use SET BT AUTH pin(0000). | |||
EOF |
@@ -0,0 +1,467 @@ | |||
/* | |||
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/>. | |||
*/ | |||
/* host driver for Bulegiga iWRAP */ | |||
/* Bluegiga BT12 | |||
* Connections | |||
* Hardware UART Software UART BlueTooth | |||
* PC=====UART=======AVR=====SUART====iWRAP(BT12)-----------PC | |||
* | |||
* - Hardware UART for Debug Console to communicate iWRAP | |||
* - Software UART for iWRAP control to send keyboard/mouse data | |||
*/ | |||
#include <stdint.h> | |||
#include <string.h> | |||
#include <avr/interrupt.h> | |||
#include <util/delay.h> | |||
#include "usb_keycodes.h" | |||
#include "suart.h" | |||
#include "uart.h" | |||
#include "report.h" | |||
#include "host_driver.h" | |||
#include "iwrap.h" | |||
#include "print.h" | |||
/* iWRAP MUX mode utils. 3.10 HID raw mode(iWRAP_HID_Application_Note.pdf) */ | |||
#define MUX_HEADER(LINK, LENGTH) do { \ | |||
xmit(0xbf); /* SOF */ \ | |||
xmit(LINK); /* Link */ \ | |||
xmit(0x00); /* Flags */ \ | |||
xmit(LENGTH); /* Length */ \ | |||
} while (0) | |||
#define MUX_FOOTER(LINK) xmit(LINK^0xff) | |||
static uint8_t connected = 0; | |||
//static uint8_t channel = 1; | |||
/* iWRAP buffer */ | |||
#define MUX_BUF_SIZE 64 | |||
static char buf[MUX_BUF_SIZE]; | |||
static uint8_t snd_pos = 0; | |||
#define MUX_RCV_BUF_SIZE 256 | |||
static char rcv_buf[MUX_RCV_BUF_SIZE]; | |||
static uint8_t rcv_head = 0; | |||
static uint8_t rcv_tail = 0; | |||
/* receive buffer */ | |||
static void rcv_enq(char c) | |||
{ | |||
uint8_t next = (rcv_head + 1) % MUX_RCV_BUF_SIZE; | |||
if (next != rcv_tail) { | |||
rcv_buf[rcv_head] = c; | |||
rcv_head = next; | |||
} | |||
} | |||
static char rcv_deq(void) | |||
{ | |||
char c = 0; | |||
if (rcv_head != rcv_tail) { | |||
c = rcv_buf[rcv_tail++]; | |||
rcv_tail %= MUX_RCV_BUF_SIZE; | |||
} | |||
return c; | |||
} | |||
/* | |||
static char rcv_peek(void) | |||
{ | |||
if (rcv_head == rcv_tail) | |||
return 0; | |||
return rcv_buf[rcv_tail]; | |||
} | |||
*/ | |||
static void rcv_clear(void) | |||
{ | |||
rcv_tail = rcv_head = 0; | |||
} | |||
/* iWRAP response */ | |||
ISR(PCINT1_vect, ISR_BLOCK) // recv() runs away in case of ISR_NOBLOCK | |||
{ | |||
if ((SUART_IN_PIN & (1<<SUART_IN_BIT))) | |||
return; | |||
static volatile uint8_t mux_state = 0xff; | |||
static volatile uint8_t mux_link = 0xff; | |||
uint8_t c = recv(); | |||
switch (mux_state) { | |||
case 0xff: // SOF | |||
if (c == 0xbf) | |||
mux_state--; | |||
break; | |||
case 0xfe: // Link | |||
mux_state--; | |||
mux_link = c; | |||
break; | |||
case 0xfd: // Flags | |||
mux_state--; | |||
break; | |||
case 0xfc: // Length | |||
mux_state = c; | |||
break; | |||
case 0x00: | |||
mux_state = 0xff; | |||
mux_link = 0xff; | |||
break; | |||
default: | |||
if (mux_state--) { | |||
uart_putchar(c); | |||
rcv_enq(c); | |||
} | |||
} | |||
} | |||
/*------------------------------------------------------------------* | |||
* iWRAP communication | |||
*------------------------------------------------------------------*/ | |||
void iwrap_init(void) | |||
{ | |||
// reset iWRAP if in already MUX mode after AVR software-reset | |||
iwrap_send("RESET"); | |||
iwrap_mux_send("RESET"); | |||
_delay_ms(3000); | |||
iwrap_send("\r\nSET CONTROL MUX 1\r\n"); | |||
_delay_ms(500); | |||
iwrap_check_connection(); | |||
} | |||
void iwrap_mux_send(const char *s) | |||
{ | |||
rcv_clear(); | |||
MUX_HEADER(0xff, strlen((char *)s)); | |||
iwrap_send(s); | |||
MUX_FOOTER(0xff); | |||
} | |||
void iwrap_send(const char *s) | |||
{ | |||
while (*s) | |||
xmit(*s++); | |||
} | |||
/* send buffer */ | |||
void iwrap_buf_add(uint8_t c) | |||
{ | |||
// need space for '\0' | |||
if (snd_pos < MUX_BUF_SIZE-1) | |||
buf[snd_pos++] = c; | |||
} | |||
void iwrap_buf_del(void) | |||
{ | |||
if (snd_pos) | |||
snd_pos--; | |||
} | |||
void iwrap_buf_send(void) | |||
{ | |||
buf[snd_pos] = '\0'; | |||
snd_pos = 0; | |||
iwrap_mux_send(buf); | |||
} | |||
void iwrap_call(void) | |||
{ | |||
char *p; | |||
iwrap_mux_send("SET BT PAIR"); | |||
_delay_ms(500); | |||
p = rcv_buf + rcv_tail; | |||
while (!strncmp(p, "SET BT PAIR", 11)) { | |||
p += 7; | |||
strncpy(p, "CALL", 4); | |||
strncpy(p+22, " 11 HID\n\0", 9); | |||
print_S(p); | |||
iwrap_mux_send(p); | |||
// TODO: skip to next line | |||
p += 57; | |||
DEBUG_LED_CONFIG; | |||
DEBUG_LED_ON; | |||
_delay_ms(500); | |||
DEBUG_LED_OFF; | |||
_delay_ms(500); | |||
DEBUG_LED_ON; | |||
_delay_ms(500); | |||
DEBUG_LED_OFF; | |||
_delay_ms(500); | |||
DEBUG_LED_ON; | |||
_delay_ms(500); | |||
DEBUG_LED_OFF; | |||
_delay_ms(500); | |||
DEBUG_LED_ON; | |||
_delay_ms(500); | |||
DEBUG_LED_OFF; | |||
_delay_ms(500); | |||
DEBUG_LED_ON; | |||
_delay_ms(500); | |||
DEBUG_LED_OFF; | |||
_delay_ms(500); | |||
} | |||
iwrap_check_connection(); | |||
} | |||
void iwrap_kill(void) | |||
{ | |||
char c; | |||
iwrap_mux_send("LIST"); | |||
_delay_ms(500); | |||
while ((c = rcv_deq()) && c != '\n') ; | |||
if (strncmp(rcv_buf + rcv_tail, "LIST ", 5)) { | |||
print("no connection to kill.\n"); | |||
return; | |||
} | |||
// skip 10 'space' chars | |||
for (uint8_t i = 10; i; i--) | |||
while ((c = rcv_deq()) && c != ' ') ; | |||
char *p = rcv_buf + rcv_tail - 5; | |||
strncpy(p, "KILL ", 5); | |||
strncpy(p + 22, "\n\0", 2); | |||
print_S(p); | |||
iwrap_mux_send(p); | |||
_delay_ms(500); | |||
iwrap_check_connection(); | |||
} | |||
void iwrap_unpair(void) | |||
{ | |||
iwrap_mux_send("SET BT PAIR"); | |||
_delay_ms(500); | |||
char *p = rcv_buf + rcv_tail; | |||
if (!strncmp(p, "SET BT PAIR", 11)) { | |||
strncpy(p+29, "\n\0", 2); | |||
print_S(p); | |||
iwrap_mux_send(p); | |||
} | |||
} | |||
void iwrap_sleep(void) | |||
{ | |||
iwrap_mux_send("SLEEP"); | |||
} | |||
void iwrap_sniff(void) | |||
{ | |||
} | |||
void iwrap_subrate(void) | |||
{ | |||
} | |||
bool iwrap_failed(void) | |||
{ | |||
if (strncmp(rcv_buf, "SYNTAX ERROR", 12)) | |||
return true; | |||
else | |||
return false; | |||
} | |||
uint8_t iwrap_connected(void) | |||
{ | |||
return connected; | |||
} | |||
uint8_t iwrap_check_connection(void) | |||
{ | |||
iwrap_mux_send("LIST"); | |||
_delay_ms(100); | |||
if (strncmp(rcv_buf, "LIST ", 5) || !strncmp(rcv_buf, "LIST 0", 6)) | |||
connected = 0; | |||
else | |||
connected = 1; | |||
return connected; | |||
} | |||
/*------------------------------------------------------------------* | |||
* Host driver | |||
*------------------------------------------------------------------*/ | |||
static uint8_t keyboard_leds(void); | |||
static void send_keyboard(report_keyboard_t *report); | |||
static void send_mouse(report_mouse_t *report); | |||
static void send_system(uint16_t data); | |||
static void send_consumer(uint16_t data); | |||
static host_driver_t driver = { | |||
keyboard_leds, | |||
send_keyboard, | |||
send_mouse, | |||
send_system, | |||
send_consumer | |||
}; | |||
host_driver_t *iwrap_driver(void) | |||
{ | |||
return &driver; | |||
} | |||
static uint8_t keyboard_leds(void) { | |||
return 0; | |||
} | |||
static void send_keyboard(report_keyboard_t *report) | |||
{ | |||
if (!iwrap_connected() && !iwrap_check_connection()) return; | |||
MUX_HEADER(0x01, 0x0c); | |||
// HID raw mode header | |||
xmit(0x9f); | |||
xmit(0x0a); // Length | |||
xmit(0xa1); // keyboard report | |||
xmit(0x01); | |||
xmit(report->mods); | |||
xmit(0x00); // reserved byte(always 0) | |||
xmit(report->keys[0]); | |||
xmit(report->keys[1]); | |||
xmit(report->keys[2]); | |||
xmit(report->keys[3]); | |||
xmit(report->keys[4]); | |||
xmit(report->keys[5]); | |||
MUX_FOOTER(0x01); | |||
} | |||
static void send_mouse(report_mouse_t *report) | |||
{ | |||
#if defined(MOUSEKEY_ENABLE) || defined(PS2_MOUSE_ENABLE) | |||
if (!iwrap_connected() && !iwrap_check_connection()) return; | |||
MUX_HEADER(0x01, 0x07); | |||
// HID raw mode header | |||
xmit(0x9f); | |||
xmit(0x05); // Length | |||
xmit(0xa1); // mouse report | |||
xmit(0x02); | |||
xmit(report->buttons); | |||
xmit(report->x); | |||
xmit(report->y); | |||
MUX_FOOTER(0x01); | |||
#endif | |||
} | |||
static void send_system(uint16_t data) | |||
{ | |||
/* not supported */ | |||
} | |||
static void send_consumer(uint16_t data) | |||
{ | |||
#ifdef EXTRAKEY_ENABLE | |||
static uint16_t last_data = 0; | |||
uint8_t bits1 = 0; | |||
uint8_t bits2 = 0; | |||
uint8_t bits3 = 0; | |||
if (!iwrap_connected() && !iwrap_check_connection()) return; | |||
if (data == last_data) return; | |||
last_data = data; | |||
// 3.10 HID raw mode(iWRAP_HID_Application_Note.pdf) | |||
switch (data) { | |||
case AUDIO_VOL_UP: | |||
bits1 = 0x01; | |||
break; | |||
case AUDIO_VOL_DOWN: | |||
bits1 = 0x02; | |||
break; | |||
case AUDIO_MUTE: | |||
bits1 = 0x04; | |||
break; | |||
case TRANSPORT_PLAY_PAUSE: | |||
bits1 = 0x08; | |||
break; | |||
case TRANSPORT_NEXT_TRACK: | |||
bits1 = 0x10; | |||
break; | |||
case TRANSPORT_PREV_TRACK: | |||
bits1 = 0x20; | |||
break; | |||
case TRANSPORT_STOP: | |||
bits1 = 0x40; | |||
break; | |||
case TRANSPORT_EJECT: | |||
bits1 = 0x80; | |||
break; | |||
case AL_EMAIL: | |||
bits2 = 0x01; | |||
break; | |||
case AC_SEARCH: | |||
bits2 = 0x02; | |||
break; | |||
case AC_BOOKMARKS: | |||
bits2 = 0x04; | |||
break; | |||
case AC_HOME: | |||
bits2 = 0x08; | |||
break; | |||
case AC_BACK: | |||
bits2 = 0x10; | |||
break; | |||
case AC_FORWARD: | |||
bits2 = 0x20; | |||
break; | |||
case AC_STOP: | |||
bits2 = 0x40; | |||
break; | |||
case AC_REFRESH: | |||
bits2 = 0x80; | |||
break; | |||
case AL_CC_CONFIG: | |||
bits3 = 0x01; | |||
break; | |||
case AL_CALCULATOR: | |||
bits3 = 0x04; | |||
break; | |||
case AL_LOCK: | |||
bits3 = 0x08; | |||
break; | |||
case AL_LOCAL_BROWSER: | |||
bits3 = 0x10; | |||
break; | |||
case AC_MINIMIZE: | |||
bits3 = 0x20; | |||
break; | |||
case TRANSPORT_RECORD: | |||
bits3 = 0x40; | |||
break; | |||
case TRANSPORT_REWIND: | |||
bits3 = 0x80; | |||
break; | |||
} | |||
MUX_HEADER(0x01, 0x07); | |||
xmit(0x9f); | |||
xmit(0x05); // Length | |||
xmit(0xa1); // consumer report | |||
xmit(0x03); | |||
xmit(bits1); | |||
xmit(bits2); | |||
xmit(bits3); | |||
MUX_FOOTER(0x01); | |||
#endif | |||
} |
@@ -0,0 +1,49 @@ | |||
/* | |||
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/>. | |||
*/ | |||
#ifndef IWRAP_H | |||
#define IWRAP_H | |||
#include <stdint.h> | |||
#include <stdbool.h> | |||
#include "host_driver.h" | |||
/* enable iWRAP MUX mode */ | |||
#define MUX_MODE | |||
host_driver_t *iwrap_driver(void); | |||
void iwrap_init(void); | |||
void iwrap_send(const char *s); | |||
void iwrap_mux_send(const char *s); | |||
void iwrap_buf_send(void); | |||
void iwrap_buf_add(uint8_t c); | |||
void iwrap_buf_del(void); | |||
void iwrap_call(void); | |||
void iwrap_kill(void); | |||
void iwrap_unpair(void); | |||
void iwrap_sleep(void); | |||
void iwrap_sniff(void); | |||
void iwrap_subrate(void); | |||
bool iwrap_failed(void); | |||
uint8_t iwrap_connected(void); | |||
uint8_t iwrap_check_connection(void); | |||
#endif |
@@ -0,0 +1,378 @@ | |||
/* | |||
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 <avr/interrupt.h> | |||
#include <avr/io.h> | |||
//#include <avr/wdt.h> | |||
#include "wd.h" // in order to use watchdog in interrupt mode | |||
#include <avr/sleep.h> | |||
#include <util/delay.h> | |||
#include <avr/power.h> | |||
#include "keyboard.h" | |||
#include "matrix.h" | |||
#include "host.h" | |||
#include "iwrap.h" | |||
#ifdef HOST_VUSB | |||
# include "vusb.h" | |||
# include "usbdrv.h" | |||
#endif | |||
#include "uart.h" | |||
#include "suart.h" | |||
#include "timer.h" | |||
#include "debug.h" | |||
#include "usb_keycodes.h" | |||
#include "command.h" | |||
static void sleep(uint8_t term); | |||
static bool console(void); | |||
static uint8_t console_command(uint8_t c); | |||
static uint8_t key2asc(uint8_t key); | |||
/* | |||
static void set_prr(void) | |||
{ | |||
power_adc_disable(); | |||
power_spi_disable(); | |||
power_twi_disable(); | |||
#ifndef TIMER_H | |||
//power_timer0_disable(); // used in timer.c | |||
#endif | |||
power_timer1_disable(); | |||
power_timer2_disable(); | |||
} | |||
*/ | |||
/* | |||
static void pullup_pins(void) | |||
{ | |||
// DDRs are set to 0(input) by default. | |||
#ifdef PORTA | |||
PORTA = 0xFF; | |||
#endif | |||
PORTB = 0xFF; | |||
PORTC = 0xFF; | |||
PORTD = 0xFF; | |||
#ifdef PORTE | |||
PORTE = 0xFF; | |||
#endif | |||
#ifdef PORTE | |||
PORTF = 0xFF; | |||
#endif | |||
} | |||
*/ | |||
#ifdef HOST_VUSB | |||
static void disable_vusb(void) | |||
{ | |||
// disable interrupt & disconnect to prevent host from enumerating | |||
USB_INTR_ENABLE &= ~(1 << USB_INTR_ENABLE_BIT); | |||
usbDeviceDisconnect(); | |||
} | |||
static void enable_vusb(void) | |||
{ | |||
USB_INTR_ENABLE |= (1 << USB_INTR_ENABLE_BIT); | |||
usbDeviceConnect(); | |||
} | |||
static void init_vusb(void) | |||
{ | |||
uint8_t i = 0; | |||
usbInit(); | |||
disable_vusb(); | |||
/* fake USB disconnect for > 250 ms */ | |||
while(--i){ | |||
_delay_ms(1); | |||
} | |||
enable_vusb(); | |||
} | |||
#endif | |||
void change_driver(host_driver_t *driver) | |||
{ | |||
host_clear_keyboard_report(); | |||
host_swap_keyboard_report(); | |||
host_clear_keyboard_report(); | |||
host_send_keyboard_report(); | |||
_delay_ms(1000); | |||
host_set_driver(driver); | |||
} | |||
static bool sleeping = false; | |||
static bool insomniac = false; // TODO: should be false for power saving | |||
static uint16_t last_timer = 0; | |||
int main(void) | |||
{ | |||
MCUSR = 0; | |||
clock_prescale_set(clock_div_1); | |||
WD_SET(WD_OFF); | |||
// power saving: the result is worse than nothing... why? | |||
//pullup_pins(); | |||
//set_prr(); | |||
print_enable = true; | |||
debug_enable = false; | |||
#ifdef HOST_VUSB | |||
disable_vusb(); | |||
#endif | |||
uart_init(115200); | |||
keyboard_init(); | |||
print("\nSend BREAK for UART Console Commands.\n"); | |||
// TODO: move to iWRAP/suart file | |||
print("suart init\n"); | |||
// suart init | |||
// PC4: Tx Output IDLE(Hi) | |||
PORTC |= (1<<4); | |||
DDRC |= (1<<4); | |||
// PC5: Rx Input(pull-up) | |||
PORTC |= (1<<5); | |||
DDRC &= ~(1<<5); | |||
// suart receive interrut(PC5/PCINT13) | |||
PCMSK1 = 0b00100000; | |||
PCICR = 0b00000010; | |||
host_set_driver(iwrap_driver()); | |||
print("iwrap_init()\n"); | |||
iwrap_init(); | |||
iwrap_call(); | |||
last_timer = timer_read(); | |||
while (true) { | |||
#ifdef HOST_VUSB | |||
if (host_get_driver() == vusb_driver()) | |||
usbPoll(); | |||
#endif | |||
keyboard_proc(); | |||
#ifdef HOST_VUSB | |||
if (host_get_driver() == vusb_driver()) | |||
vusb_transfer_keyboard(); | |||
#endif | |||
if (matrix_is_modified() || console()) { | |||
last_timer = timer_read(); | |||
sleeping = false; | |||
} else if (!sleeping && timer_elapsed(last_timer) > 4000) { | |||
sleeping = true; | |||
iwrap_check_connection(); | |||
} | |||
if (host_get_driver() == iwrap_driver()) { | |||
if (sleeping && !insomniac) { | |||
_delay_ms(1); // wait for UART to send | |||
iwrap_sleep(); | |||
sleep(WDTO_60MS); | |||
} | |||
} | |||
} | |||
} | |||
static void sleep(uint8_t term) | |||
{ | |||
WD_SET(WD_IRQ, term); | |||
cli(); | |||
set_sleep_mode(SLEEP_MODE_PWR_DOWN); | |||
sleep_enable(); | |||
sleep_bod_disable(); | |||
sei(); | |||
sleep_cpu(); | |||
sleep_disable(); | |||
WD_SET(WD_OFF); | |||
} | |||
ISR(WDT_vect) | |||
{ | |||
// wake up | |||
} | |||
static bool console(void) | |||
{ | |||
// Send to Bluetoot module WT12 | |||
static bool breaked = false; | |||
if (!uart_available()) | |||
return false; | |||
else { | |||
uint8_t c; | |||
c = uart_getchar(); | |||
uart_putchar(c); | |||
switch (c) { | |||
case 0x00: // BREAK signal | |||
if (!breaked) { | |||
print("break(? for help): "); | |||
breaked = true; | |||
} | |||
break; | |||
case '\r': | |||
uart_putchar('\n'); | |||
iwrap_buf_send(); | |||
break; | |||
case '\b': | |||
iwrap_buf_del(); | |||
break; | |||
default: | |||
if (breaked) { | |||
print("\n"); | |||
console_command(c); | |||
breaked = false; | |||
} else { | |||
iwrap_buf_add(c); | |||
} | |||
break; | |||
} | |||
return true; | |||
} | |||
} | |||
uint8_t command_extra() | |||
{ | |||
return console_command(key2asc(host_get_first_key())); | |||
} | |||
static uint8_t console_command(uint8_t c) | |||
{ | |||
switch (c) { | |||
case 'h': | |||
case '?': | |||
print("\nCommands for Bluetooth(WT12/iWRAP):\n"); | |||
print("r: reset. software reset by watchdog\n"); | |||
print("i: insomniac. prevent KB from sleeping\n"); | |||
print("c: iwrap_call. CALL for BT connection.\n"); | |||
#ifdef HOST_VUSB | |||
print("u: USB mode. switch to USB.\n"); | |||
print("w: BT mode. switch to Bluetooth.\n"); | |||
#endif | |||
print("k: kill first connection.\n"); | |||
print("Del: unpair first pairing.\n"); | |||
print("\n"); | |||
return 0; | |||
case 'r': | |||
print("reset\n"); | |||
WD_AVR_RESET(); | |||
return 1; | |||
case 'i': | |||
insomniac = !insomniac; | |||
if (insomniac) | |||
print("insomniac\n"); | |||
else | |||
print("not insomniac\n"); | |||
return 1; | |||
case 'c': | |||
print("iwrap_call()\n"); | |||
iwrap_call(); | |||
return 1; | |||
#ifdef HOST_VUSB | |||
case 'u': | |||
print("USB mode\n"); | |||
init_vusb(); | |||
change_driver(vusb_driver()); | |||
//iwrap_kill(); | |||
//iwrap_sleep(); | |||
// disable suart receive interrut(PC5/PCINT13) | |||
PCMSK1 &= ~(0b00100000); | |||
PCICR &= ~(0b00000010); | |||
return 1; | |||
case 'w': | |||
print("iWRAP mode\n"); | |||
change_driver(iwrap_driver()); | |||
disable_vusb(); | |||
// enable suart receive interrut(PC5/PCINT13) | |||
PCMSK1 |= 0b00100000; | |||
PCICR |= 0b00000010; | |||
return 1; | |||
#endif | |||
case 'k': | |||
print("kill\n"); | |||
iwrap_kill(); | |||
return 1; | |||
case 0x7F: // DELETE | |||
print("unpair\n"); | |||
iwrap_unpair(); | |||
return 1; | |||
} | |||
return 0; | |||
} | |||
// convert keycode into ascii charactor | |||
static uint8_t key2asc(uint8_t key) | |||
{ | |||
switch (key) { | |||
case KB_A: return 'a'; | |||
case KB_B: return 'b'; | |||
case KB_C: return 'c'; | |||
case KB_D: return 'd'; | |||
case KB_E: return 'e'; | |||
case KB_F: return 'f'; | |||
case KB_G: return 'g'; | |||
case KB_H: return 'h'; | |||
case KB_I: return 'i'; | |||
case KB_J: return 'j'; | |||
case KB_K: return 'k'; | |||
case KB_L: return 'l'; | |||
case KB_M: return 'm'; | |||
case KB_N: return 'n'; | |||
case KB_O: return 'o'; | |||
case KB_P: return 'p'; | |||
case KB_Q: return 'q'; | |||
case KB_R: return 'r'; | |||
case KB_S: return 's'; | |||
case KB_T: return 't'; | |||
case KB_U: return 'u'; | |||
case KB_V: return 'v'; | |||
case KB_W: return 'w'; | |||
case KB_X: return 'x'; | |||
case KB_Y: return 'y'; | |||
case KB_Z: return 'z'; | |||
case KB_1: return '1'; | |||
case KB_2: return '2'; | |||
case KB_3: return '3'; | |||
case KB_4: return '4'; | |||
case KB_5: return '5'; | |||
case KB_6: return '6'; | |||
case KB_7: return '7'; | |||
case KB_8: return '8'; | |||
case KB_9: return '9'; | |||
case KB_0: return '0'; | |||
case KB_ENTER: return '\n'; | |||
case KB_ESCAPE: return 0x1B; | |||
case KB_BSPACE: return '\b'; | |||
case KB_TAB: return '\t'; | |||
case KB_SPACE: return ' '; | |||
case KB_MINUS: return '-'; | |||
case KB_EQUAL: return '='; | |||
case KB_LBRACKET: return '['; | |||
case KB_RBRACKET: return ']'; | |||
case KB_BSLASH: return '\\'; | |||
case KB_NONUS_HASH: return '\\'; | |||
case KB_SCOLON: return ';'; | |||
case KB_QUOTE: return '\''; | |||
case KB_GRAVE: return '`'; | |||
case KB_COMMA: return ','; | |||
case KB_DOT: return '.'; | |||
case KB_SLASH: return '/'; | |||
default: return 0x00; | |||
} | |||
} |
@@ -0,0 +1,156 @@ | |||
;---------------------------------------------------------------------------; | |||
; Software implemented UART module ; | |||
; (C)ChaN, 2005 (http://elm-chan.org/) ; | |||
;---------------------------------------------------------------------------; | |||
; Bit rate settings: | |||
; | |||
; 1MHz 2MHz 4MHz 6MHz 8MHz 10MHz 12MHz 16MHz 20MHz | |||
; 2.4kbps 138 - - - - - - - - | |||
; 4.8kbps 68 138 - - - - - - - | |||
; 9.6kbps 33 68 138 208 - - - - - | |||
; 19.2kbps - 33 68 102 138 173 208 - - | |||
; 38.4kbps - - 33 50 68 85 102 138 172 | |||
; 57.6kbps - - 21 33 44 56 68 91 114 | |||
; 115.2kbps - - - - 21 27 33 44 56 | |||
.nolist | |||
#include <avr/io.h> | |||
.list | |||
#define BPS 102 /* Bit delay. (see above table) */ | |||
#define BIDIR 0 /* 0:Separated Tx/Rx, 1:Shared Tx/Rx */ | |||
#define OUT_1 sbi _SFR_IO_ADDR(SUART_OUT_PORT), SUART_OUT_BIT /* Output 1 */ | |||
#define OUT_0 cbi _SFR_IO_ADDR(SUART_OUT_PORT), SUART_OUT_BIT /* Output 0 */ | |||
#define SKIP_IN_1 sbis _SFR_IO_ADDR(SUART_IN_PIN), SUART_IN_BIT /* Skip if 1 */ | |||
#define SKIP_IN_0 sbic _SFR_IO_ADDR(SUART_IN_PIN), SUART_IN_BIT /* Skip if 0 */ | |||
#ifdef SPM_PAGESIZE | |||
.macro _LPMI reg | |||
lpm \reg, Z+ | |||
.endm | |||
.macro _MOVW dh,dl, sh,sl | |||
movw \dl, \sl | |||
.endm | |||
#else | |||
.macro _LPMI reg | |||
lpm | |||
mov \reg, r0 | |||
adiw ZL, 1 | |||
.endm | |||
.macro _MOVW dh,dl, sh,sl | |||
mov \dl, \sl | |||
mov \dh, \sh | |||
.endm | |||
#endif | |||
;---------------------------------------------------------------------------; | |||
; Transmit a byte in serial format of N81 | |||
; | |||
;Prototype: void xmit (uint8_t data); | |||
;Size: 16 words | |||
.global xmit | |||
.func xmit | |||
xmit: | |||
#if BIDIR | |||
ldi r23, BPS-1 ;Pre-idle time for bidirectional data line | |||
5: dec r23 ; | |||
brne 5b ;/ | |||
#endif | |||
in r0, _SFR_IO_ADDR(SREG) ;Save flags | |||
com r24 ;C = start bit | |||
ldi r25, 10 ;Bit counter | |||
cli ;Start critical section | |||
1: ldi r23, BPS-1 ;----- Bit transferring loop | |||
2: dec r23 ;Wait for a bit time | |||
brne 2b ;/ | |||
brcs 3f ;MISO = bit to be sent | |||
OUT_1 ; | |||
3: brcc 4f ; | |||
OUT_0 ;/ | |||
4: lsr r24 ;Get next bit into C | |||
dec r25 ;All bits sent? | |||
brne 1b ; no, coutinue | |||
out _SFR_IO_ADDR(SREG), r0 ;End of critical section | |||
ret | |||
.endfunc | |||
;---------------------------------------------------------------------------; | |||
; Receive a byte | |||
; | |||
;Prototype: uint8_t rcvr (void); | |||
;Size: 19 words | |||
.global rcvr | |||
.func rcvr | |||
rcvr: | |||
in r0, _SFR_IO_ADDR(SREG) ;Save flags | |||
ldi r24, 0x80 ;Receiving shift reg | |||
cli ;Start critical section | |||
1: SKIP_IN_1 ;Wait for idle | |||
rjmp 1b | |||
2: SKIP_IN_0 ;Wait for start bit | |||
rjmp 2b | |||
ldi r25, BPS/2 ;Wait for half bit time | |||
3: dec r25 | |||
brne 3b | |||
4: ldi r25, BPS ;----- Bit receiving loop | |||
5: dec r25 ;Wait for a bit time | |||
brne 5b ;/ | |||
lsr r24 ;Next bit | |||
SKIP_IN_0 ;Get a data bit into r24.7 | |||
ori r24, 0x80 | |||
brcc 4b ;All bits received? no, continue | |||
out _SFR_IO_ADDR(SREG), r0 ;End of critical section | |||
ret | |||
.endfunc | |||
; Not wait for start bit. This should be called after detecting start bit. | |||
.global recv | |||
.func recv | |||
recv: | |||
in r0, _SFR_IO_ADDR(SREG) ;Save flags | |||
ldi r24, 0x80 ;Receiving shift reg | |||
cli ;Start critical section | |||
;1: SKIP_IN_1 ;Wait for idle | |||
; rjmp 1b | |||
;2: SKIP_IN_0 ;Wait for start bit | |||
; rjmp 2b | |||
ldi r25, BPS/2 ;Wait for half bit time | |||
3: dec r25 | |||
brne 3b | |||
4: ldi r25, BPS ;----- Bit receiving loop | |||
5: dec r25 ;Wait for a bit time | |||
brne 5b ;/ | |||
lsr r24 ;Next bit | |||
SKIP_IN_0 ;Get a data bit into r24.7 | |||
ori r24, 0x80 | |||
brcc 4b ;All bits received? no, continue | |||
ldi r25, BPS/2 ;Wait for half bit time | |||
6: dec r25 | |||
brne 6b | |||
7: SKIP_IN_1 ;Wait for stop bit | |||
rjmp 7b | |||
out _SFR_IO_ADDR(SREG), r0 ;End of critical section | |||
ret | |||
.endfunc |
@@ -0,0 +1,8 @@ | |||
#ifndef SUART | |||
#define SUART | |||
void xmit(uint8_t); | |||
uint8_t rcvr(void); | |||
uint8_t recv(void); | |||
#endif /* SUART */ |
@@ -0,0 +1,159 @@ | |||
/* This is from http://www.mtcnet.net/~henryvm/wdt/ */ | |||
#ifndef _AVR_WD_H_ | |||
#define _AVR_WD_H_ | |||
#include <avr/io.h> | |||
/* | |||
Copyright (c) 2009, Curt Van Maanen | |||
Permission to use, copy, modify, and/or distribute this software for any | |||
purpose with or without fee is hereby granted, provided that the above | |||
copyright notice and this permission notice appear in all copies. | |||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
include usage- | |||
#include "wd.h" //if in same directory as project | |||
#include <avr/wd.h> //if wd.h is in avr directory | |||
set watchdog modes and prescale | |||
usage- | |||
WD_SET(mode,[timeout]); //prescale always set | |||
modes- | |||
WD_OFF disabled | |||
WD_RST normal reset mode | |||
WD_IRQ interrupt only mode (if supported) | |||
WD_RST_IRQ interrupt+reset mode (if supported) | |||
timeout- | |||
WDTO_15MS default if no timeout provided | |||
WDTO_30MS | |||
WDTO_60MS | |||
WDTO_120MS | |||
WDTO_250MS | |||
WDTO_500MS | |||
WDTO_1S | |||
WDTO_2S | |||
WDTO_4S (if supported) | |||
WDTO_8S (if supported) | |||
examples- | |||
WD_SET(WD_RST,WDTO_1S); //reset mode, 1s timeout | |||
WD_SET(WD_OFF); //watchdog disabled (if not fused on) | |||
WD_SET(WD_RST); //reset mode, 15ms (default timeout) | |||
WD_SET(WD_IRQ,WDTO_120MS); //interrupt only mode, 120ms timeout | |||
WD_SET(WD_RST_IRQ,WDTO_2S); //interrupt+reset mode, 2S timeout | |||
for enhanced watchdogs, if the watchdog is not being used WDRF should be | |||
cleared on every power up or reset, along with disabling the watchdog- | |||
WD_DISABLE(); //clear WDRF, then turn off watchdog | |||
*/ | |||
//reset registers to the same name (MCUCSR) | |||
#if !defined(MCUCSR) | |||
#define MCUCSR MCUSR | |||
#endif | |||
//watchdog registers to the same name (WDTCSR) | |||
#if !defined(WDTCSR) | |||
#define WDTCSR WDTCR | |||
#endif | |||
//if enhanced watchdog, define irq values, create disable macro | |||
#if defined(WDIF) | |||
#define WD_IRQ 0xC0 | |||
#define WD_RST_IRQ 0xC8 | |||
#define WD_DISABLE() do{ \ | |||
MCUCSR &= ~(1<<WDRF); \ | |||
WD_SET(WD_OFF); \ | |||
}while(0) | |||
#endif | |||
//all watchdogs | |||
#define WD_RST 8 | |||
#define WD_OFF 0 | |||
//prescale values | |||
#define WDTO_15MS 0 | |||
#define WDTO_30MS 1 | |||
#define WDTO_60MS 2 | |||
#define WDTO_120MS 3 | |||
#define WDTO_250MS 4 | |||
#define WDTO_500MS 5 | |||
#define WDTO_1S 6 | |||
#define WDTO_2S 7 | |||
//prescale values for avrs with WDP3 | |||
#if defined(WDP3) | |||
#define WDTO_4S 0x20 | |||
#define WDTO_8S 0x21 | |||
#endif | |||
//watchdog reset | |||
#define WDR() __asm__ __volatile__("wdr") | |||
//avr reset using watchdog | |||
#define WD_AVR_RESET() do{ \ | |||
__asm__ __volatile__("cli"); \ | |||
WD_SET_UNSAFE(WD_RST); \ | |||
while(1); \ | |||
}while(0) | |||
/*set the watchdog- | |||
1. save SREG | |||
2. turn off irq's | |||
3. reset watchdog timer | |||
4. enable watchdog change | |||
5. write watchdog value | |||
6. restore SREG (restoring irq status) | |||
*/ | |||
#define WD_SET(val,...) \ | |||
__asm__ __volatile__( \ | |||
"in __tmp_reg__,__SREG__" "\n\t" \ | |||
"cli" "\n\t" \ | |||
"wdr" "\n\t" \ | |||
"sts %[wdreg],%[wden]" "\n\t" \ | |||
"sts %[wdreg],%[wdval]" "\n\t" \ | |||
"out __SREG__,__tmp_reg__" "\n\t" \ | |||
: \ | |||
: [wdreg] "M" (&WDTCSR), \ | |||
[wden] "r" ((uint8_t)(0x18)), \ | |||
[wdval] "r" ((uint8_t)(val|(__VA_ARGS__+0))) \ | |||
: "r0" \ | |||
) | |||
/*set the watchdog when I bit in SREG known to be clear- | |||
1. reset watchdog timer | |||
2. enable watchdog change | |||
5. write watchdog value | |||
*/ | |||
#define WD_SET_UNSAFE(val,...) \ | |||
__asm__ __volatile__( \ | |||
"wdr" "\n\t" \ | |||
"sts %[wdreg],%[wden]" "\n\t" \ | |||
"sts %[wdreg],%[wdval]" "\n\t" \ | |||
: \ | |||
: [wdreg] "M" (&WDTCSR), \ | |||
[wden] "r" ((uint8_t)(0x18)), \ | |||
[wdval] "r" ((uint8_t)(val|(__VA_ARGS__+0))) \ | |||
) | |||
//for compatibility with avr/wdt.h | |||
#define wdt_enable(val) WD_SET(WD_RST,val) | |||
#define wdt_disable() WD_SET(WD_OFF) | |||
#endif /* _AVR_WD_H_ */ |
@@ -27,7 +27,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#ifdef MOUSEKEY_ENABLE | |||
#include "mousekey.h" | |||
#endif | |||
#ifdef USB_EXTRA_ENABLE | |||
#ifdef EXTRAKEY_ENABLE | |||
#include <util/delay.h> | |||
#endif | |||
@@ -47,7 +47,7 @@ void keyboard_init(void) | |||
void keyboard_proc(void) | |||
{ | |||
uint8_t fn_bits = 0; | |||
#ifdef USB_EXTRA_ENABLE | |||
#ifdef EXTRAKEY_ENABLE | |||
uint16_t consumer_code = 0; | |||
#endif | |||
@@ -82,7 +82,8 @@ void keyboard_proc(void) | |||
} else if (IS_FN(code)) { | |||
fn_bits |= FN_BIT(code); | |||
} | |||
#ifdef USB_EXTRA_ENABLE | |||
// TODO: use table or something | |||
#ifdef EXTRAKEY_ENABLE | |||
// System Control | |||
else if (code == KB_SYSTEM_POWER) { | |||
#ifdef HOST_PJRC | |||
@@ -170,7 +171,7 @@ void keyboard_proc(void) | |||
// TODO: should send only when changed from last report | |||
if (matrix_is_modified()) { | |||
host_send_keyboard_report(); | |||
#ifdef USB_EXTRA_ENABLE | |||
#ifdef EXTRAKEY_ENABLE | |||
host_consumer_send(consumer_code); | |||
#endif | |||
#ifdef DEBUG_LED |
@@ -69,10 +69,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
// LAYER_ENTER_DELAY: prevent from moving new layer | |||
#define LAYER_ENTER_DELAY 10 | |||
#define LAYER_ENTER_DELAY 150 | |||
// LAYER_SEND_FN_TERM: send keycode if release key in this term | |||
#define LAYER_SEND_FN_TERM 40 | |||
#define LAYER_SEND_FN_TERM 500 | |||
uint8_t default_layer = 0; |
@@ -8,10 +8,10 @@ COMMON_DIR = .. | |||
TARGET_DIR = . | |||
# keyboard dependent files | |||
TARGET_SRC = main_pjrc.c \ | |||
keymap.c \ | |||
matrix.c \ | |||
led.c | |||
SRC = main.c \ | |||
keymap.c \ | |||
matrix.c \ | |||
led.c | |||
CONFIG_H = config.h | |||
@@ -37,8 +37,8 @@ F_CPU = 16000000 | |||
# | |||
MOUSEKEY_ENABLE = yes # Mouse keys | |||
#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support | |||
USB_EXTRA_ENABLE = yes # Audio control and System control | |||
#USB_NKRO_ENABLE = yes # USB Nkey Rollover | |||
EXTRAKEY_ENABLE = yes # Audio control and System control | |||
#NKRO_ENABLE = yes # USB Nkey Rollover | |||
@@ -47,5 +47,5 @@ PROGRAM_CMD = teensy_loader_cli -mmcu=$(MCU) -w -v $(TARGET).hex | |||
include $(COMMON_DIR)/Makefile.pjrc | |||
include $(COMMON_DIR)/Makefile.common | |||
include $(COMMON_DIR)/pjrc.mk | |||
include $(COMMON_DIR)/common.mk |
@@ -37,8 +37,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
/* key combination for command */ | |||
#define IS_COMMAND() ( \ | |||
keyboard_report->mods == (BIT_LSHIFT | BIT_RSHIFT) || \ | |||
keyboard_report->mods == (BIT_LCTRL | BIT_RSHIFT) \ | |||
keyboard_report->mods == (MOD_BIT(KB_LSHIFT) | MOD_BIT(KB_LCTRL) | MOD_BIT(KB_LALT) | MOD_BIT(KB_LGUI)) || \ | |||
keyboard_report->mods == (MOD_BIT(KB_LSHIFT) | MOD_BIT(KB_RSHIFT)) \ | |||
) | |||
@@ -1,58 +0,0 @@ | |||
/* Name: main.c | |||
* Project: hid-mouse, a very simple HID example | |||
* Author: Christian Starkjohann | |||
* Creation Date: 2008-04-07 | |||
* Tabsize: 4 | |||
* Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH | |||
* 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 $ | |||
*/ | |||
#include <stdint.h> | |||
#include <avr/wdt.h> | |||
#include <avr/interrupt.h> | |||
#include <util/delay.h> | |||
#include "usbdrv.h" | |||
#include "oddebug.h" | |||
#include "host_vusb.h" | |||
#include "keyboard.h" | |||
#if 0 | |||
#define DEBUGP_INIT() do { DDRC = 0xFF; } while (0) | |||
#define DEBUGP(x) do { PORTC = x; } while (0) | |||
#else | |||
#define DEBUGP_INIT() | |||
#define DEBUGP(x) | |||
#endif | |||
int main(void) | |||
{ | |||
DEBUGP_INIT(); | |||
wdt_enable(WDTO_1S); | |||
odDebugInit(); | |||
usbInit(); | |||
/* enforce re-enumeration, do this while interrupts are disabled! */ | |||
usbDeviceDisconnect(); | |||
uint8_t i = 0; | |||
/* fake USB disconnect for > 250 ms */ | |||
while(--i){ | |||
wdt_reset(); | |||
_delay_ms(1); | |||
} | |||
usbDeviceConnect(); | |||
keyboard_init(); | |||
sei(); | |||
while (1) { | |||
DEBUGP(0x1); | |||
wdt_reset(); | |||
usbPoll(); | |||
DEBUGP(0x2); | |||
keyboard_proc(); | |||
DEBUGP(0x3); | |||
host_vusb_keyboard_send(); | |||
} | |||
} |
@@ -63,10 +63,10 @@ void mousekey_decode(uint8_t code) | |||
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; | |||
else if (code == KB_MS_WH_UP) report.v += move_unit()/4; | |||
else if (code == KB_MS_WH_DOWN) report.v -= move_unit()/4; | |||
else if (code == KB_MS_WH_LEFT) report.h -= move_unit()/4; | |||
else if (code == KB_MS_WH_RIGHT)report.h += move_unit()/4; | |||
} | |||
bool mousekey_changed(void) | |||
@@ -87,7 +87,7 @@ void mousekey_send(void) | |||
// send immediately when buttun state is changed | |||
if (report.buttons == report_prev.buttons) { | |||
if (timer_elapsed(last_timer) < 5) { | |||
if (timer_elapsed(last_timer) < 100) { | |||
mousekey_clear_report(); | |||
return; | |||
} |
@@ -1,14 +1,14 @@ | |||
OPT_DEFS += -DHOST_PJRC | |||
SRC = usb_keyboard.c \ | |||
SRC += pjrc.c \ | |||
usb_keyboard.c \ | |||
usb_debug.c \ | |||
usb.c \ | |||
jump_bootloader.c | |||
SRC += $(TARGET_SRC) | |||
# C source file search path | |||
VPATH = $(TARGET_DIR):$(COMMON_DIR):$(COMMON_DIR)/pjrc | |||
# Search Path | |||
VPATH += $(COMMON_DIR):$(COMMON_DIR)/pjrc | |||
# Option modules | |||
@@ -16,6 +16,6 @@ ifdef $(or MOUSEKEY_ENABLE, PS2_MOUSE_ENABLE) | |||
SRC += usb_mouse.c | |||
endif | |||
ifdef USB_EXTRA_ENABLE | |||
ifdef EXTRAKEY_ENABLE | |||
SRC += usb_extra.c | |||
endif |
@@ -22,7 +22,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#if defined(MOUSEKEY_ENABLE) || defined(PS2_MOUSE_ENABLE) | |||
#include "usb_mouse.h" | |||
#endif | |||
#ifdef USB_EXTRA_ENABLE | |||
#ifdef EXTRAKEY_ENABLE | |||
#include "usb_extra.h" | |||
#endif | |||
#include "debug.h" | |||
@@ -30,7 +30,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#include "util.h" | |||
#ifdef USB_NKRO_ENABLE | |||
#ifdef NKRO_ENABLE | |||
bool keyboard_nkro = false; | |||
#endif | |||
@@ -51,7 +51,7 @@ uint8_t host_keyboard_leds(void) | |||
/* keyboard report operations */ | |||
void host_add_key(uint8_t key) | |||
{ | |||
#ifdef USB_NKRO_ENABLE | |||
#ifdef NKRO_ENABLE | |||
if (keyboard_nkro) { | |||
add_key_bit(key); | |||
return; | |||
@@ -109,7 +109,7 @@ uint8_t host_has_anykey(void) | |||
uint8_t host_get_first_key(void) | |||
{ | |||
#ifdef USB_NKRO_ENABLE | |||
#ifdef NKRO_ENABLE | |||
if (keyboard_nkro) { | |||
uint8_t i = 0; | |||
for (; i < REPORT_KEYS && !keyboard_report->keys[i]; i++) | |||
@@ -133,7 +133,7 @@ void host_mouse_send(report_mouse_t *report) | |||
} | |||
#endif | |||
#ifdef USB_EXTRA_ENABLE | |||
#ifdef EXTRAKEY_ENABLE | |||
void host_system_send(uint16_t data) | |||
{ | |||
usb_extra_system_send(data); |
@@ -35,6 +35,8 @@ | |||
#ifdef PS2_MOUSE_ENABLE | |||
# include "ps2_mouse.h" | |||
#endif | |||
#include "host.h" | |||
#include "pjrc.h" | |||
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n)) | |||
@@ -88,6 +90,7 @@ int main(void) | |||
} | |||
host_set_driver(pjrc_driver()); | |||
while (1) { | |||
keyboard_proc(); | |||
} |
@@ -0,0 +1,76 @@ | |||
/* | |||
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 "usb_keyboard.h" | |||
#include "usb_mouse.h" | |||
#include "usb_extra.h" | |||
#include "host_driver.h" | |||
#include "pjrc.h" | |||
/*------------------------------------------------------------------* | |||
* Host driver | |||
*------------------------------------------------------------------*/ | |||
static uint8_t keyboard_leds(void); | |||
static void send_keyboard(report_keyboard_t *report); | |||
static void send_mouse(report_mouse_t *report); | |||
static void send_system(uint16_t data); | |||
static void send_consumer(uint16_t data); | |||
static host_driver_t driver = { | |||
keyboard_leds, | |||
send_keyboard, | |||
send_mouse, | |||
send_system, | |||
send_consumer | |||
}; | |||
host_driver_t *pjrc_driver(void) | |||
{ | |||
return &driver; | |||
} | |||
static uint8_t keyboard_leds(void) { | |||
return usb_keyboard_leds; | |||
} | |||
static void send_keyboard(report_keyboard_t *report) | |||
{ | |||
usb_keyboard_send_report(report); | |||
} | |||
static void send_mouse(report_mouse_t *report) | |||
{ | |||
#ifdef MOUSE_ENABLE | |||
usb_mouse_send(report->x, report->y, report->v, report->h, report->buttons); | |||
#endif | |||
} | |||
static void send_system(uint16_t data) | |||
{ | |||
#ifdef EXTRAKEY_ENABLE | |||
usb_extra_system_send(data); | |||
#endif | |||
} | |||
static void send_consumer(uint16_t data) | |||
{ | |||
#ifdef EXTRAKEY_ENABLE | |||
usb_extra_consumer_send(data); | |||
#endif | |||
} |
@@ -0,0 +1,26 @@ | |||
/* | |||
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/>. | |||
*/ | |||
#ifndef PJRC_H | |||
#define PJRC_H | |||
#include "host_driver.h" | |||
host_driver_t *pjrc_driver(void); | |||
#endif |
@@ -91,18 +91,18 @@ bool suspend = false; | |||
static const uint8_t PROGMEM endpoint_config_table[] = { | |||
// enable, UECFG0X(type, direction), UECFG1X(size, bank, allocation) | |||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KBD_SIZE) | KBD_BUFFER, // 1 | |||
#ifdef USB_MOUSE_ENABLE | |||
#ifdef MOUSE_ENABLE | |||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(MOUSE_SIZE) | MOUSE_BUFFER, // 2 | |||
#else | |||
0, // 2 | |||
#endif | |||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER, // 3 | |||
#ifdef USB_EXTRA_ENABLE | |||
#ifdef EXTRAKEY_ENABLE | |||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(EXTRA_SIZE) | EXTRA_BUFFER, // 4 | |||
#else | |||
0, // 4 | |||
#endif | |||
#ifdef USB_NKRO_ENABLE | |||
#ifdef NKRO_ENABLE | |||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KBD2_SIZE) | KBD2_BUFFER, // 5 | |||
#else | |||
0, // 5 | |||
@@ -176,7 +176,7 @@ static uint8_t PROGMEM keyboard_hid_report_desc[] = { | |||
0x81, 0x00, // Input (Data, Array), | |||
0xc0 // End Collection | |||
}; | |||
#ifdef USB_NKRO_ENABLE | |||
#ifdef NKRO_ENABLE | |||
static uint8_t PROGMEM keyboard2_hid_report_desc[] = { | |||
0x05, 0x01, // Usage Page (Generic Desktop), | |||
0x09, 0x06, // Usage (Keyboard), | |||
@@ -213,7 +213,7 @@ static uint8_t PROGMEM keyboard2_hid_report_desc[] = { | |||
}; | |||
#endif | |||
#ifdef USB_MOUSE_ENABLE | |||
#ifdef MOUSE_ENABLE | |||
// 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/ | |||
@@ -282,7 +282,7 @@ static uint8_t PROGMEM debug_hid_report_desc[] = { | |||
0xC0 // end collection | |||
}; | |||
#ifdef USB_EXTRA_ENABLE | |||
#ifdef EXTRAKEY_ENABLE | |||
// audio controls & system controls | |||
// http://www.microsoft.com/whdc/archive/w2kbd.mspx | |||
static uint8_t PROGMEM extra_hid_report_desc[] = { | |||
@@ -318,7 +318,7 @@ static uint8_t PROGMEM extra_hid_report_desc[] = { | |||
#define KBD_HID_DESC_NUM 0 | |||
#define KBD_HID_DESC_OFFSET (9+(9+9+7)*KBD_HID_DESC_NUM+9) | |||
#ifdef USB_MOUSE_ENABLE | |||
#ifdef MOUSE_ENABLE | |||
# define MOUSE_HID_DESC_NUM (KBD_HID_DESC_NUM + 1) | |||
# define MOUSE_HID_DESC_OFFSET (9+(9+9+7)*MOUSE_HID_DESC_NUM+9) | |||
#else | |||
@@ -328,14 +328,14 @@ static uint8_t PROGMEM extra_hid_report_desc[] = { | |||
#define DEBUG_HID_DESC_NUM (MOUSE_HID_DESC_NUM + 1) | |||
#define DEBUG_HID_DESC_OFFSET (9+(9+9+7)*DEBUG_HID_DESC_NUM+9) | |||
#ifdef USB_EXTRA_ENABLE | |||
#ifdef EXTRAKEY_ENABLE | |||
# define EXTRA_HID_DESC_NUM (DEBUG_HID_DESC_NUM + 1) | |||
# define EXTRA_HID_DESC_OFFSET (9+(9+9+7)*EXTRA_HID_DESC_NUM+9) | |||
#else | |||
# define EXTRA_HID_DESC_NUM (DEBUG_HID_DESC_NUM + 0) | |||
#endif | |||
#ifdef USB_NKRO_ENABLE | |||
#ifdef NKRO_ENABLE | |||
# define KBD2_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 1) | |||
# define KBD2_HID_DESC_OFFSET (9+(9+9+7)*EXTRA_HID_DESC_NUM+9) | |||
#else | |||
@@ -383,7 +383,7 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { | |||
KBD_SIZE, 0, // wMaxPacketSize | |||
10, // bInterval | |||
#ifdef USB_MOUSE_ENABLE | |||
#ifdef MOUSE_ENABLE | |||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||
9, // bLength | |||
4, // bDescriptorType | |||
@@ -444,7 +444,7 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { | |||
DEBUG_TX_SIZE, 0, // wMaxPacketSize | |||
1, // bInterval | |||
#ifdef USB_EXTRA_ENABLE | |||
#ifdef EXTRAKEY_ENABLE | |||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||
9, // bLength | |||
4, // bDescriptorType | |||
@@ -473,7 +473,7 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = { | |||
10, // bInterval | |||
#endif | |||
#ifdef USB_NKRO_ENABLE | |||
#ifdef NKRO_ENABLE | |||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | |||
9, // bLength | |||
4, // bDescriptorType | |||
@@ -542,17 +542,17 @@ static struct descriptor_list_struct { | |||
// HID/REPORT descriptors | |||
{0x2100, KBD_INTERFACE, config1_descriptor+KBD_HID_DESC_OFFSET, 9}, | |||
{0x2200, KBD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)}, | |||
#ifdef USB_MOUSE_ENABLE | |||
#ifdef MOUSE_ENABLE | |||
{0x2100, MOUSE_INTERFACE, config1_descriptor+MOUSE_HID_DESC_OFFSET, 9}, | |||
{0x2200, MOUSE_INTERFACE, mouse_hid_report_desc, sizeof(mouse_hid_report_desc)}, | |||
#endif | |||
{0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9}, | |||
{0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)}, | |||
#ifdef USB_EXTRA_ENABLE | |||
#ifdef EXTRAKEY_ENABLE | |||
{0x2100, EXTRA_INTERFACE, config1_descriptor+EXTRA_HID_DESC_OFFSET, 9}, | |||
{0x2200, EXTRA_INTERFACE, extra_hid_report_desc, sizeof(extra_hid_report_desc)}, | |||
#endif | |||
#ifdef USB_NKRO_ENABLE | |||
#ifdef NKRO_ENABLE | |||
{0x2100, KBD2_INTERFACE, config1_descriptor+KBD2_HID_DESC_OFFSET, 9}, | |||
{0x2200, KBD2_INTERFACE, keyboard2_hid_report_desc, sizeof(keyboard2_hid_report_desc)}, | |||
#endif | |||
@@ -653,7 +653,7 @@ ISR(USB_GEN_vect) | |||
} | |||
} | |||
/* TODO: should keep IDLE rate on each keyboard interface */ | |||
#ifdef USB_NKRO_ENABLE | |||
#ifdef NKRO_ENABLE | |||
if (!keyboard_nkro && usb_keyboard_idle_config && (++div4 & 3) == 0) { | |||
#else | |||
if (usb_keyboard_idle_config && (++div4 & 3) == 0) { | |||
@@ -894,7 +894,7 @@ ISR(USB_COM_vect) | |||
} | |||
} | |||
} | |||
#ifdef USB_MOUSE_ENABLE | |||
#ifdef MOUSE_ENABLE | |||
if (wIndex == MOUSE_INTERFACE) { | |||
if (bmRequestType == 0xA1) { | |||
if (bRequest == HID_GET_REPORT) { |
@@ -120,7 +120,7 @@ void usb_remote_wakeup(void); | |||
#define KBD_REPORT_KEYS (KBD_SIZE - 2) | |||
// secondary keyboard | |||
#ifdef USB_NKRO_ENABLE | |||
#ifdef NKRO_ENABLE | |||
#define KBD2_INTERFACE 4 | |||
#define KBD2_ENDPOINT 5 | |||
#define KBD2_SIZE 16 |
@@ -55,7 +55,7 @@ int8_t usb_keyboard_send_report(report_keyboard_t *report) | |||
{ | |||
int8_t result = 0; | |||
#ifdef USB_NKRO_ENABLE | |||
#ifdef NKRO_ENABLE | |||
if (keyboard_nkro) | |||
result = send_report(report, KBD2_ENDPOINT, 0, KBD2_REPORT_KEYS); | |||
else | |||
@@ -105,7 +105,7 @@ static inline int8_t send_report(report_keyboard_t *report, uint8_t endpoint, ui | |||
UENUM = endpoint; | |||
} | |||
UEDATX = report->mods; | |||
#ifdef USB_NKRO_ENABLE | |||
#ifdef NKRO_ENABLE | |||
if (!keyboard_nkro) | |||
UEDATX = 0; | |||
#else |
@@ -29,6 +29,19 @@ | |||
bool print_enable = false; | |||
void print_S(const char *s) | |||
{ | |||
if (!print_enable) return; | |||
char c; | |||
while (1) { | |||
c = *s++; | |||
if (!c) break; | |||
if (c == '\n') sendchar('\r'); | |||
sendchar(c); | |||
} | |||
} | |||
void print_P(const char *s) | |||
{ | |||
if (!print_enable) return; |
@@ -24,6 +24,7 @@ | |||
#ifndef PRINT_H__ | |||
#define PRINT_H__ 1 | |||
#include <stdint.h> | |||
#include <stdbool.h> | |||
#include <avr/pgmspace.h> | |||
@@ -34,6 +35,7 @@ extern bool print_enable; | |||
// the string is automatically placed into flash memory :) | |||
#define print(s) print_P(PSTR(s)) | |||
void print_S(const char *s); | |||
void print_P(const char *s); | |||
void phex(unsigned char c); | |||
void phex16(unsigned int i); |
@@ -13,11 +13,11 @@ COMMON_DIR = .. | |||
TARGET_DIR = . | |||
# keyboard dependent files | |||
TARGET_SRC = main_pjrc.c \ | |||
keymap.c \ | |||
matrix.c \ | |||
led.c \ | |||
ps2.c | |||
SRC = main.c \ | |||
keymap.c \ | |||
matrix.c \ | |||
led.c \ | |||
ps2.c | |||
CONFIG_H = config_pjrc.h | |||
@@ -42,8 +42,8 @@ F_CPU = 16000000 | |||
# comment out to disable the options. | |||
# | |||
MOUSEKEY_ENABLE = yes # Mouse keys | |||
USB_EXTRA_ENABLE = yes # Audio control and System control | |||
USB_NKRO_ENABLE = yes # USB Nkey Rollover | |||
EXTRAKEY_ENABLE = yes # Audio control and System control | |||
NKRO_ENABLE = yes # USB Nkey Rollover | |||
@@ -52,5 +52,5 @@ PROGRAM_CMD = teensy_loader_cli -mmcu=$(MCU) -w -v $(TARGET).hex | |||
include $(COMMON_DIR)/Makefile.pjrc | |||
include $(COMMON_DIR)/Makefile.common | |||
include $(COMMON_DIR)/pjrc.mk | |||
include $(COMMON_DIR)/common.mk |
@@ -13,11 +13,11 @@ COMMON_DIR = .. | |||
TARGET_DIR = . | |||
# keyboard dependent files | |||
TARGET_SRC = main_vusb.c \ | |||
keymap.c \ | |||
matrix.c \ | |||
led.c \ | |||
ps2_usart.c | |||
SRC = main.c \ | |||
keymap.c \ | |||
matrix.c \ | |||
led.c \ | |||
ps2_usart.c | |||
CONFIG_H = config_vusb.h | |||
@@ -48,8 +48,9 @@ F_CPU = 20000000 | |||
# comment out to disable the options. | |||
# | |||
MOUSEKEY_ENABLE = yes # Mouse keys | |||
USB_EXTRA_ENABLE = yes # Audio control and System control | |||
#USB_NKRO_ENABLE = yes # USB Nkey Rollover | |||
EXTRAKEY_ENABLE = yes # Audio control and System control | |||
#NKRO_ENABLE = yes # USB Nkey Rollover | |||
NO_UART = yes # UART is unavailable | |||
@@ -85,5 +86,5 @@ PROGRAM_CMD = $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE | |||
include $(COMMON_DIR)/Makefile.vusb | |||
include $(COMMON_DIR)/Makefile.common | |||
include $(COMMON_DIR)/vusb.mk | |||
include $(COMMON_DIR)/common.mk |
@@ -35,8 +35,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
/* key combination for command */ | |||
#define IS_COMMAND() ( \ | |||
keyboard_report->mods == (BIT_LSHIFT | BIT_RSHIFT) || \ | |||
keyboard_report->mods == (BIT_LCTRL | BIT_RSHIFT) \ | |||
keyboard_report->mods == (MOD_BIT(KB_LSHIFT) | MOD_BIT(KB_RSHIFT)) || \ | |||
keyboard_report->mods == (MOD_BIT(KB_LCTRL) | MOD_BIT(KB_RSHIFT)) \ | |||
) | |||
@@ -35,8 +35,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
/* key combination for command */ | |||
#define IS_COMMAND() ( \ | |||
keyboard_report->mods == (BIT_LSHIFT | BIT_RSHIFT) || \ | |||
keyboard_report->mods == (BIT_LCTRL | BIT_RSHIFT) \ | |||
keyboard_report->mods == (MOD_BIT(KB_LSHIFT) | MOD_BIT(KB_RSHIFT)) || \ | |||
keyboard_report->mods == (MOD_BIT(KB_LCTRL) | MOD_BIT(KB_RSHIFT)) \ | |||
) | |||
@@ -124,7 +124,7 @@ static const uint8_t PROGMEM fn_layer[] = { | |||
static const uint8_t PROGMEM fn_keycode[] = { | |||
KB_SCLN, // Fn0 | |||
KB_SLSH, // Fn1 | |||
KB_A, // Fn2 | |||
KB_NO, // Fn2 | |||
KB_NO, // Fn3 | |||
KB_NO, // Fn4 | |||
KB_NO, // Fn5 | |||
@@ -154,7 +154,7 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | |||
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, | |||
GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, | |||
TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, DEL, END, PGDN, P7, P8, P9, | |||
CAPS,FN2, S, D, F, G, H, J, K, L, FN0, QUOT, ENT, P4, P5, P6, PPLS, | |||
CAPS,A, S, D, F, G, H, J, K, L, FN0, QUOT, ENT, P4, P5, P6, PPLS, | |||
LSFT,Z, X, C, V, B, N, M, COMM,DOT, FN1, RSFT, UP, P1, P2, P3, | |||
LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT | |||
), | |||
@@ -204,7 +204,7 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = { | |||
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, | |||
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F8, F10, F11, F12, BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS, | |||
TAB, WH_L,WH_D,MS_U,WH_U,WH_R,WH_L,WH_D,WH_U,WH_R,NO, NO, NO, BSLS, DEL, END, PGDN, P7, P8, P9, | |||
CAPS,FN2, MS_L,MS_D,MS_R,NO, MS_L,MS_D,MS_U,MS_R,FN0, NO, ENT, P4, P5, P6, PPLS, | |||
CAPS,NO, MS_L,MS_D,MS_R,NO, MS_L,MS_D,MS_U,MS_R,FN0, NO, ENT, P4, P5, P6, PPLS, | |||
LSFT,VOLD,VOLU,MUTE,BTN2,BTN3,BTN2,BTN1,VOLD,VOLU,MUTE, RSFT, UP, P1, P2, P3, | |||
LCTL,LGUI,LALT, BTN1, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT | |||
), |
@@ -349,6 +349,7 @@ uint8_t matrix_scan(void) | |||
default: | |||
state = INIT; | |||
} | |||
phex(code); | |||
} | |||
return 1; | |||
} |
@@ -0,0 +1,96 @@ | |||
/* | |||
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/>. | |||
*/ | |||
#ifndef REPORT_H | |||
#define REPORT_H | |||
#include <stdint.h> | |||
/* report id */ | |||
#define REPORT_ID_MOUSE 1 | |||
#define REPORT_ID_SYSTEM 2 | |||
#define REPORT_ID_CONSUMER 3 | |||
/* mouse buttons */ | |||
#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) | |||
// Consumer Page(0x0C) | |||
// following are supported by Windows: http://msdn.microsoft.com/en-us/windows/hardware/gg463372.aspx | |||
#define AUDIO_MUTE 0x00E2 | |||
#define AUDIO_VOL_UP 0x00E9 | |||
#define AUDIO_VOL_DOWN 0x00EA | |||
#define TRANSPORT_NEXT_TRACK 0x00B5 | |||
#define TRANSPORT_PREV_TRACK 0x00B6 | |||
#define TRANSPORT_STOP 0x00B7 | |||
#define TRANSPORT_PLAY_PAUSE 0x00CD | |||
#define AL_CC_CONFIG 0x0183 | |||
#define AL_EMAIL 0x018A | |||
#define AL_CALCULATOR 0x0192 | |||
#define AL_LOCAL_BROWSER 0x0194 | |||
#define AC_SEARCH 0x0221 | |||
#define AC_HOME 0x0223 | |||
#define AC_BACK 0x0224 | |||
#define AC_FORWARD 0x0225 | |||
#define AC_STOP 0x0226 | |||
#define AC_REFRESH 0x0227 | |||
#define AC_BOOKMARKS 0x022A | |||
// supplement for Bluegiga iWRAP HID(not supported by Windows?) | |||
#define AL_LOCK 0x019E | |||
#define TRANSPORT_RECORD 0x00B2 | |||
#define TRANSPORT_REWIND 0x00B4 | |||
#define TRANSPORT_EJECT 0x00B8 | |||
#define AC_MINIMIZE 0x0206 | |||
// Generic Desktop Page(0x01) | |||
#define SYSTEM_POWER_DOWN 0x0081 | |||
#define SYSTEM_SLEEP 0x0082 | |||
#define SYSTEM_WAKE_UP 0x0083 | |||
// key report size(NKRO or boot mode) | |||
#if defined(HOST_PJRC) | |||
# include "usb.h" | |||
# if defined(KBD2_REPORT_KEYS) && KBD2_REPORT_KEYS > KBD_REPORT_KEYS | |||
# define REPORT_KEYS KBD2_REPORT_KEYS | |||
# else | |||
# define REPORT_KEYS KBD_REPORT_KEYS | |||
# endif | |||
#else | |||
# define REPORT_KEYS 6 | |||
#endif | |||
typedef struct { | |||
uint8_t mods; | |||
uint8_t rserved; | |||
uint8_t keys[REPORT_KEYS]; | |||
} report_keyboard_t; | |||
typedef struct { | |||
uint8_t report_id; | |||
uint8_t buttons; | |||
int8_t x; | |||
int8_t y; | |||
int8_t v; | |||
int8_t h; | |||
} report_mouse_t; | |||
#endif |
@@ -18,8 +18,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#ifndef SENDCHAR_H | |||
#define SENDCHAR_H | |||
#include <stdint.h> | |||
/* transmit a character. return 0 on success, -1 on error. */ | |||
int8_t sendchar(uint8_t c); | |||
#endif | |||
@@ -14,10 +14,10 @@ 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 "sendchar.h" | |||
#ifndef HOST_VUSB_H | |||
#define HOST_VUSB_H | |||
void host_vusb_keyboard_send(void); | |||
#endif | |||
int8_t sendchar(uint8_t c) | |||
{ | |||
return 0; | |||
} |
@@ -0,0 +1,25 @@ | |||
/* | |||
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 "uart.h" | |||
#include "sendchar.h" | |||
int8_t sendchar(uint8_t c) | |||
{ | |||
uart_putchar(c); | |||
return 0; | |||
} |
@@ -20,17 +20,31 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#include <stdint.h> | |||
#include "timer.h" | |||
// counter resolution 1ms | |||
volatile uint16_t timer_count = 0; | |||
// Configure timer 0 to generate a timer overflow interrupt every | |||
// 256*1024 clock cycles, or approx 61 Hz when using 16 MHz clock | |||
// This demonstrates how to use interrupts to implement a simple | |||
// inactivity timeout. | |||
void timer_init(void) | |||
{ | |||
TCCR0A = 0x00; | |||
// Timer0 CTC mode | |||
TCCR0A = 0x02; | |||
#if TIMER_PRESCALER == 1 | |||
TCCR0B = 0x01; | |||
#elif TIMER_PRESCALER == 8 | |||
TCCR0B = 0x02; | |||
#elif TIMER_PRESCALER == 64 | |||
TCCR0B = 0x03; | |||
#elif TIMER_PRESCALER == 256 | |||
TCCR0B = 0x04; | |||
#elif TIMER_PRESCALER == 1024 | |||
TCCR0B = 0x05; | |||
TIMSK0 = (1<<TOIE0); | |||
#else | |||
# error "Timer prescaler value is NOT vaild." | |||
#endif | |||
OCR0A = TIMER_RAW_TOP; | |||
TIMSK0 = (1<<OCIE0A); | |||
} | |||
inline | |||
@@ -65,14 +79,11 @@ uint16_t timer_elapsed(uint16_t last) | |||
t = timer_count; | |||
SREG = sreg; | |||
return TIMER_DIFF(t, last); | |||
return TIMER_DIFF_MS(t, last); | |||
} | |||
// This interrupt routine is run approx 61 times per second. | |||
// A very simple inactivity timeout is implemented, where we | |||
// will send a space character and print a message to the | |||
// hid_listen debug message window. | |||
ISR(TIMER0_OVF_vect) | |||
// excecuted once per 1ms.(excess for just timer count?) | |||
ISR(TIMER0_COMPA_vect) | |||
{ | |||
timer_count++; | |||
} |
@@ -20,7 +20,26 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
#include <stdint.h> | |||
#define TIMER_DIFF(a, b) ((a) >= (b) ? (a) - (b) : UINT16_MAX - (b) + (a)) | |||
#ifndef TIMER_PRESCALER | |||
# if F_CPU > 16000000 | |||
# define TIMER_PRESCALER 256 | |||
# elif F_CPU >= 4000000 | |||
# define TIMER_PRESCALER 64 | |||
# else | |||
# define TIMER_PRESCALER 8 | |||
# endif | |||
#endif | |||
#define TIMER_RAW_FREQ (F_CPU/TIMER_PRESCALER) | |||
#define TIMER_RAW TCNT0 | |||
#define TIMER_RAW_TOP (TIMER_RAW_FREQ/1000) | |||
#if (TIMER_RAW_TOP > 255) | |||
# error "Timer0 can't count 1ms at this clock freq. Use larger prescaler." | |||
#endif | |||
#define TIMER_DIFF(a, b, max) ((a) >= (b) ? (a) - (b) : (max) - (b) + (a)) | |||
#define TIMER_DIFF_RAW(a, b) TIMER_DIFF(a, b, UINT8_MAX) | |||
#define TIMER_DIFF_MS(a, b) TIMER_DIFF(a, b, UINT16_MAX) | |||
extern volatile uint16_t timer_count; |
@@ -0,0 +1,129 @@ | |||
// TODO: Teensy support(ATMega32u4/AT90USB128) | |||
// Fixed for Arduino Duemilanove ATmega168p by Jun Wako | |||
/* UART Example for Teensy USB Development Board | |||
* http://www.pjrc.com/teensy/ | |||
* Copyright (c) 2009 PJRC.COM, LLC | |||
* | |||
* Permission is hereby granted, free of charge, to any person obtaining a copy | |||
* of this software and associated documentation files (the "Software"), to deal | |||
* in the Software without restriction, including without limitation the rights | |||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |||
* copies of the Software, and to permit persons to whom the Software is | |||
* furnished to do so, subject to the following conditions: | |||
* | |||
* The above copyright notice and this permission notice shall be included in | |||
* all copies or substantial portions of the Software. | |||
* | |||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |||
* THE SOFTWARE. | |||
*/ | |||
// Version 1.0: Initial Release | |||
// Version 1.1: Add support for Teensy 2.0, minor optimizations | |||
#include <avr/io.h> | |||
#include <avr/interrupt.h> | |||
#include "uart.h" | |||
// These buffers may be any size from 2 to 256 bytes. | |||
#define RX_BUFFER_SIZE 64 | |||
#define TX_BUFFER_SIZE 40 | |||
static volatile uint8_t tx_buffer[TX_BUFFER_SIZE]; | |||
static volatile uint8_t tx_buffer_head; | |||
static volatile uint8_t tx_buffer_tail; | |||
static volatile uint8_t rx_buffer[RX_BUFFER_SIZE]; | |||
static volatile uint8_t rx_buffer_head; | |||
static volatile uint8_t rx_buffer_tail; | |||
// Initialize the UART | |||
void uart_init(uint32_t baud) | |||
{ | |||
cli(); | |||
UBRR0 = (F_CPU / 4 / baud - 1) / 2; | |||
UCSR0A = (1<<U2X0); | |||
UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0); | |||
UCSR0C = (1<<UCSZ01) | (1<<UCSZ00); | |||
tx_buffer_head = tx_buffer_tail = 0; | |||
rx_buffer_head = rx_buffer_tail = 0; | |||
sei(); | |||
} | |||
// Transmit a byte | |||
void uart_putchar(uint8_t c) | |||
{ | |||
uint8_t i; | |||
i = tx_buffer_head + 1; | |||
if (i >= TX_BUFFER_SIZE) i = 0; | |||
while (tx_buffer_tail == i) ; // wait until space in buffer | |||
//cli(); | |||
tx_buffer[i] = c; | |||
tx_buffer_head = i; | |||
UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0) | (1<<UDRIE0); | |||
//sei(); | |||
} | |||
// Receive a byte | |||
uint8_t uart_getchar(void) | |||
{ | |||
uint8_t c, i; | |||
while (rx_buffer_head == rx_buffer_tail) ; // wait for character | |||
i = rx_buffer_tail + 1; | |||
if (i >= RX_BUFFER_SIZE) i = 0; | |||
c = rx_buffer[i]; | |||
rx_buffer_tail = i; | |||
return c; | |||
} | |||
// Return the number of bytes waiting in the receive buffer. | |||
// Call this before uart_getchar() to check if it will need | |||
// to wait for a byte to arrive. | |||
uint8_t uart_available(void) | |||
{ | |||
uint8_t head, tail; | |||
head = rx_buffer_head; | |||
tail = rx_buffer_tail; | |||
if (head >= tail) return head - tail; | |||
return RX_BUFFER_SIZE + head - tail; | |||
} | |||
// Transmit Interrupt | |||
ISR(USART_UDRE_vect) | |||
{ | |||
uint8_t i; | |||
if (tx_buffer_head == tx_buffer_tail) { | |||
// buffer is empty, disable transmit interrupt | |||
UCSR0B = (1<<RXEN0) | (1<<TXEN0) | (1<<RXCIE0); | |||
} else { | |||
i = tx_buffer_tail + 1; | |||
if (i >= TX_BUFFER_SIZE) i = 0; | |||
UDR0 = tx_buffer[i]; | |||
tx_buffer_tail = i; | |||
} | |||
} | |||
// Receive Interrupt | |||
ISR(USART_RX_vect) | |||
{ | |||
uint8_t c, i; | |||
c = UDR0; | |||
i = rx_buffer_head + 1; | |||
if (i >= RX_BUFFER_SIZE) i = 0; | |||
if (i != rx_buffer_tail) { | |||
rx_buffer[i] = c; | |||
rx_buffer_head = i; | |||
} | |||
} | |||
@@ -0,0 +1,11 @@ | |||
#ifndef _uart_included_h_ | |||
#define _uart_included_h_ | |||
#include <stdint.h> | |||
void uart_init(uint32_t baud); | |||
void uart_putchar(uint8_t c); | |||
uint8_t uart_getchar(void); | |||
uint8_t uart_available(void); | |||
#endif |
@@ -16,7 +16,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
/* | |||
* Key codes from HID Keyboard/Keypad Page | |||
* Key codes: HID Keyboard/Keypad Page(0x07) | |||
* http://www.usb.org/developers/devclass_docs/Hut1_12.pdf | |||
*/ | |||
#ifndef USB_KEYCODES_H | |||
@@ -353,7 +353,8 @@ enum keycodes { | |||
KB_CRSEL, | |||
KB_EXSEL, | |||
/* NOTE: uses 0xB0-DF for special keycodes */ | |||
/* NOTE: 0xB0-DF are used as special_keycodes */ | |||
#if 0 | |||
KB_KP_00 = 0xB0, | |||
KB_KP_000, | |||
KB_THOUSANDS_SEPARATOR, | |||
@@ -400,6 +401,7 @@ enum keycodes { | |||
KB_KP_OCTAL, | |||
KB_KP_DECIMAL, | |||
KB_KP_HEXADECIMAL, | |||
#endif | |||
/* Modifiers */ | |||
KB_LCTRL = 0xE0, | |||
@@ -411,7 +413,7 @@ enum keycodes { | |||
KB_RALT, | |||
KB_RGUI, | |||
/* NOTE: uses 0xE8-FF for special keycodes */ | |||
/* NOTE: 0xE8-FF are used as special_keycodes */ | |||
}; | |||
#endif /* USB_KEYCODES_H */ |
@@ -0,0 +1,17 @@ | |||
OPT_DEFS += -DHOST_VUSB | |||
SRC += vusb.c \ | |||
usbdrv.c \ | |||
usbdrvasm.S \ | |||
oddebug.c | |||
ifdef NO_UART | |||
SRC += sendchar_null.c | |||
else | |||
SRC += sendchar_uart.c \ | |||
uart.c | |||
endif | |||
# Search Path | |||
VPATH += $(COMMON_DIR)/vusb:$(COMMON_DIR)/vusb/usbdrv |
@@ -0,0 +1,99 @@ | |||
/* Name: main.c | |||
* Project: hid-mouse, a very simple HID example | |||
* Author: Christian Starkjohann | |||
* Creation Date: 2008-04-07 | |||
* Tabsize: 4 | |||
* Copyright: (c) 2008 by OBJECTIVE DEVELOPMENT Software GmbH | |||
* 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 $ | |||
*/ | |||
#include <stdint.h> | |||
#include <avr/interrupt.h> | |||
#include <avr/wdt.h> | |||
#include <avr/sleep.h> | |||
#include <util/delay.h> | |||
#include "usbdrv.h" | |||
#include "oddebug.h" | |||
#include "vusb.h" | |||
#include "keyboard.h" | |||
#include "host.h" | |||
#include "timer.h" | |||
#include "uart.h" | |||
#include "debug.h" | |||
#define UART_BAUD_RATE 115200 | |||
/* This is from main.c of USBaspLoader */ | |||
static void initForUsbConnectivity(void) | |||
{ | |||
uint8_t i = 0; | |||
usbInit(); | |||
/* enforce USB re-enumerate: */ | |||
usbDeviceDisconnect(); /* do this while interrupts are disabled */ | |||
while(--i){ /* fake USB disconnect for > 250 ms */ | |||
wdt_reset(); | |||
_delay_ms(1); | |||
} | |||
usbDeviceConnect(); | |||
sei(); | |||
} | |||
int main(void) | |||
{ | |||
bool suspended = false; | |||
#if USB_COUNT_SOF | |||
uint16_t last_timer = timer_read(); | |||
#endif | |||
CLKPR = 0x80, CLKPR = 0; | |||
#ifndef PS2_USE_USART | |||
uart_init(UART_BAUD_RATE); | |||
#endif | |||
debug_enable = true; | |||
print_enable = true; | |||
debug("keyboard_init()\n"); | |||
keyboard_init(); | |||
host_set_driver(vusb_driver()); | |||
debug("initForUsbConnectivity()\n"); | |||
initForUsbConnectivity(); | |||
debug("main loop\n"); | |||
while (1) { | |||
#if USB_COUNT_SOF | |||
if (usbSofCount != 0) { | |||
suspended = false; | |||
usbSofCount = 0; | |||
last_timer = timer_read(); | |||
} else { | |||
// Suspend when no SOF in 3ms-10ms(7.1.7.4 Suspending of USB1.1) | |||
if (timer_elapsed(last_timer) > 5) { | |||
suspended = true; | |||
/* | |||
uart_putchar('S'); | |||
_delay_ms(1); | |||
cli(); | |||
set_sleep_mode(SLEEP_MODE_PWR_DOWN); | |||
sleep_enable(); | |||
sleep_bod_disable(); | |||
sei(); | |||
sleep_cpu(); | |||
sleep_disable(); | |||
_delay_ms(10); | |||
uart_putchar('W'); | |||
*/ | |||
} | |||
} | |||
#endif | |||
if (!suspended) | |||
usbPoll(); | |||
keyboard_proc(); | |||
if (!suspended) | |||
vusb_transfer_keyboard(); | |||
} | |||
} |
@@ -16,133 +16,69 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. | |||
*/ | |||
#include <stdint.h> | |||
#include <avr/interrupt.h> | |||
#include "usbdrv.h" | |||
#include "usbconfig.h" | |||
#include "print.h" | |||
#include "usb_keycodes.h" | |||
#include "host.h" | |||
#include "host_vusb.h" | |||
#include "report.h" | |||
#include "print.h" | |||
#include "debug.h" | |||
#include "host_driver.h" | |||
#include "vusb.h" | |||
static report_keyboard_t report0; | |||
static report_keyboard_t report1; | |||
report_keyboard_t *keyboard_report = &report0; | |||
report_keyboard_t *keyboard_report_prev = &report1; | |||
static uint8_t keyboard_leds = 0; | |||
static uchar idleRate = 0; | |||
uint8_t host_keyboard_leds(void) | |||
{ | |||
return keyboard_leds; | |||
} | |||
/*------------------------------------------------------------------* | |||
* Keyboard report operations | |||
*------------------------------------------------------------------*/ | |||
void host_add_key(uint8_t code) | |||
{ | |||
int8_t i = 0; | |||
int8_t empty = -1; | |||
for (; i < REPORT_KEYS; i++) { | |||
if (keyboard_report_prev->keys[i] == code) { | |||
keyboard_report->keys[i] = code; | |||
break; | |||
} | |||
if (empty == -1 && keyboard_report_prev->keys[i] == KB_NO && keyboard_report->keys[i] == KB_NO) { | |||
empty = i; | |||
} | |||
} | |||
if (i == REPORT_KEYS && empty != -1) { | |||
keyboard_report->keys[empty] = code; | |||
} | |||
} | |||
void host_add_mod_bit(uint8_t mod) | |||
{ | |||
keyboard_report->mods |= mod; | |||
} | |||
void host_set_mods(uint8_t mods) | |||
{ | |||
keyboard_report->mods = mods; | |||
} | |||
void host_add_code(uint8_t code) | |||
{ | |||
if (IS_MOD(code)) { | |||
host_add_mod_bit(MOD_BIT(code)); | |||
} else { | |||
host_add_key(code); | |||
} | |||
} | |||
void host_swap_keyboard_report(void) | |||
{ | |||
uint8_t sreg = SREG; | |||
cli(); | |||
report_keyboard_t *tmp = keyboard_report_prev; | |||
keyboard_report_prev = keyboard_report; | |||
keyboard_report = tmp; | |||
SREG = sreg; | |||
} | |||
static uint8_t vusb_keyboard_leds = 0; | |||
static uint8_t vusb_idle_rate = 0; | |||
void host_clear_keyboard_report(void) | |||
{ | |||
keyboard_report->mods = 0; | |||
for (int8_t i = 0; i < REPORT_KEYS; i++) { | |||
keyboard_report->keys[i] = 0; | |||
} | |||
} | |||
/* Keyboard report send buffer */ | |||
#define KBUF_SIZE 16 | |||
static report_keyboard_t kbuf[KBUF_SIZE]; | |||
static uint8_t kbuf_head = 0; | |||
static uint8_t kbuf_tail = 0; | |||
uint8_t host_has_anykey(void) | |||
{ | |||
uint8_t cnt = 0; | |||
for (int i = 0; i < REPORT_KEYS; i++) { | |||
if (keyboard_report->keys[i]) | |||
cnt++; | |||
} | |||
return cnt; | |||
} | |||
uint8_t host_get_first_key(void) | |||
/* transfer keyboard report from buffer */ | |||
void vusb_transfer_keyboard(void) | |||
{ | |||
#ifdef USB_NKRO_ENABLE | |||
if (keyboard_nkro) { | |||
uint8_t i = 0; | |||
for (; i < REPORT_KEYS && !keyboard_report->keys[i]; i++) | |||
; | |||
return i<<3 | biton(keyboard_report->keys[i]); | |||
if (usbInterruptIsReady()) { | |||
if (kbuf_head != kbuf_tail) { | |||
usbSetInterrupt((void *)&kbuf[kbuf_tail], sizeof(report_keyboard_t)); | |||
kbuf_tail = (kbuf_tail + 1) % KBUF_SIZE; | |||
} | |||
} | |||
#endif | |||
return keyboard_report->keys[0]; | |||
} | |||
/*------------------------------------------------------------------* | |||
* Keyboard report send buffer | |||
* Host driver | |||
*------------------------------------------------------------------*/ | |||
#define KBUF_SIZE 16 | |||
static report_keyboard_t kbuf[KBUF_SIZE]; | |||
static uint8_t kbuf_head = 0; | |||
static uint8_t kbuf_tail = 0; | |||
static uint8_t keyboard_leds(void); | |||
static void send_keyboard(report_keyboard_t *report); | |||
static void send_mouse(report_mouse_t *report); | |||
static void send_system(uint16_t data); | |||
static void send_consumer(uint16_t data); | |||
static host_driver_t driver = { | |||
keyboard_leds, | |||
send_keyboard, | |||
send_mouse, | |||
send_system, | |||
send_consumer | |||
}; | |||
void host_vusb_keyboard_send(void) | |||
host_driver_t *vusb_driver(void) | |||
{ | |||
if (usbInterruptIsReady() && kbuf_head != kbuf_tail) { | |||
usbSetInterrupt((void *)&kbuf[kbuf_tail], sizeof(report_keyboard_t)); | |||
kbuf_tail = (kbuf_tail + 1) % KBUF_SIZE; | |||
} | |||
return &driver; | |||
} | |||
void host_send_keyboard_report(void) | |||
static uint8_t keyboard_leds(void) { | |||
return vusb_keyboard_leds; | |||
} | |||
static void send_keyboard(report_keyboard_t *report) | |||
{ | |||
uint8_t next = (kbuf_head + 1) % KBUF_SIZE; | |||
if (next != kbuf_tail) { | |||
kbuf[kbuf_head] = *keyboard_report; | |||
kbuf[kbuf_head] = *report; | |||
kbuf_head = next; | |||
} else { | |||
debug("kbuf: full\n"); | |||
@@ -150,20 +86,15 @@ void host_send_keyboard_report(void) | |||
} | |||
#if defined(MOUSEKEY_ENABLE) || defined(PS2_MOUSE_ENABLE) | |||
void host_mouse_send(report_mouse_t *report) | |||
static void send_mouse(report_mouse_t *report) | |||
{ | |||
report->report_id = REPORT_ID_MOUSE; | |||
if (usbInterruptIsReady3()) { | |||
usbSetInterrupt3((void *)report, sizeof(*report)); | |||
} else { | |||
debug("Int3 not ready\n"); | |||
} | |||
} | |||
#endif | |||
#ifdef USB_EXTRA_ENABLE | |||
void host_system_send(uint16_t data) | |||
static void send_system(uint16_t data) | |||
{ | |||
// Not need static? | |||
static uint8_t report[] = { REPORT_ID_SYSTEM, 0, 0 }; | |||
@@ -171,12 +102,10 @@ void host_system_send(uint16_t data) | |||
report[2] = (data>>8)&0xFF; | |||
if (usbInterruptIsReady3()) { | |||
usbSetInterrupt3((void *)&report, sizeof(report)); | |||
} else { | |||
debug("Int3 not ready\n"); | |||
} | |||
} | |||
void host_consumer_send(uint16_t data) | |||
static void send_consumer(uint16_t data) | |||
{ | |||
static uint16_t last_data = 0; | |||
if (data == last_data) return; | |||
@@ -188,11 +117,8 @@ void host_consumer_send(uint16_t data) | |||
report[2] = (data>>8)&0xFF; | |||
if (usbInterruptIsReady3()) { | |||
usbSetInterrupt3((void *)&report, sizeof(report)); | |||
} else { | |||
debug("Int3 not ready\n"); | |||
} | |||
} | |||
#endif | |||
@@ -213,32 +139,36 @@ usbRequest_t *rq = (void *)data; | |||
if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */ | |||
if(rq->bRequest == USBRQ_HID_GET_REPORT){ | |||
debug(" GET_REPORT"); | |||
debug("GET_REPORT:"); | |||
/* we only have one report type, so don't look at wValue */ | |||
usbMsgPtr = (void *)keyboard_report_prev; | |||
return sizeof(*keyboard_report_prev); | |||
}else if(rq->bRequest == USBRQ_HID_GET_IDLE){ | |||
debug(" GET_IDLE: "); | |||
debug_hex(idleRate); | |||
usbMsgPtr = &idleRate; | |||
debug("GET_IDLE: "); | |||
//debug_hex(vusb_idle_rate); | |||
usbMsgPtr = &vusb_idle_rate; | |||
return 1; | |||
}else if(rq->bRequest == USBRQ_HID_SET_IDLE){ | |||
idleRate = rq->wValue.bytes[1]; | |||
debug(" SET_IDLE: "); | |||
debug_hex(idleRate); | |||
vusb_idle_rate = rq->wValue.bytes[1]; | |||
debug("SET_IDLE: "); | |||
debug_hex(vusb_idle_rate); | |||
}else if(rq->bRequest == USBRQ_HID_SET_REPORT){ | |||
//debug(" SET_REPORT: "); | |||
debug("SET_REPORT: "); | |||
// Report Type: 0x02(Out)/ReportID: 0x00(none) && Interface: 0(keyboard) | |||
if (rq->wValue.word == 0x0200 && rq->wIndex.word == 0) { | |||
debug("SET_LED: "); | |||
last_req.kind = SET_LED; | |||
last_req.len = rq->wLength.word; | |||
} | |||
return USB_NO_MSG; // to get data in usbFunctionWrite | |||
} else { | |||
debug("UNKNOWN:"); | |||
} | |||
debug("\n"); | |||
}else{ | |||
debug("VENDOR\n"); | |||
debug("VENDOR:"); | |||
/* no vendor specific requests implemented */ | |||
} | |||
debug("\n"); | |||
return 0; /* default for not implemented requests: return no data back to host */ | |||
} | |||
@@ -249,8 +179,10 @@ uchar usbFunctionWrite(uchar *data, uchar len) | |||
} | |||
switch (last_req.kind) { | |||
case SET_LED: | |||
//debug("SET_LED\n"); | |||
keyboard_leds = data[0]; | |||
debug("SET_LED: "); | |||
debug_hex(data[0]); | |||
debug("\n"); | |||
vusb_keyboard_leds = data[0]; | |||
last_req.len = 0; | |||
return 1; | |||
break; | |||
@@ -484,13 +416,14 @@ USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) | |||
{ | |||
usbMsgLen_t len = 0; | |||
/* | |||
debug("usbFunctionDescriptor: "); | |||
debug_hex(rq->bmRequestType); debug(" "); | |||
debug_hex(rq->bRequest); debug(" "); | |||
debug_hex16(rq->wValue.word); debug(" "); | |||
debug_hex16(rq->wIndex.word); debug(" "); | |||
debug_hex16(rq->wLength.word); debug("\n"); | |||
*/ | |||
switch (rq->wValue.bytes[1]) { | |||
#if USB_CFG_DESCR_PROPS_CONFIGURATION | |||
case USBDESCR_CONFIG: | |||
@@ -499,8 +432,16 @@ USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) | |||
break; | |||
#endif | |||
case USBDESCR_HID: | |||
usbMsgPtr = (unsigned char *)(usbDescriptorConfiguration + 18); | |||
len = 9; | |||
switch (rq->wValue.bytes[0]) { | |||
case 0: | |||
usbMsgPtr = (unsigned char *)(usbDescriptorConfiguration + 9 + 9); | |||
len = 9; | |||
break; | |||
case 1: | |||
usbMsgPtr = (unsigned char *)(usbDescriptorConfiguration + 9 + (9 + 9 + 7) + 9); | |||
len = 9; | |||
break; | |||
} | |||
break; | |||
case USBDESCR_HID_REPORT: | |||
/* interface index */ | |||
@@ -516,6 +457,6 @@ USB_PUBLIC usbMsgLen_t usbFunctionDescriptor(struct usbRequest *rq) | |||
} | |||
break; | |||
} | |||
debug("desc len: "); debug_hex(len); debug("\n"); | |||
//debug("desc len: "); debug_hex(len); debug("\n"); | |||
return len; | |||
} |
@@ -0,0 +1,27 @@ | |||
/* | |||
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/>. | |||
*/ | |||
#ifndef VUSB_H | |||
#define VUSB_H | |||
#include "host_driver.h" | |||
host_driver_t *vusb_driver(void); | |||
void vusb_transfer_keyboard(void); | |||
#endif |