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 |
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 |
3. Choose optional modules as needed. Comment out to disable optional modules. | 3. Choose optional modules as needed. Comment out to disable optional modules. | ||||
MOUSEKEY_ENABLE = yes # Mouse keys | MOUSEKEY_ENABLE = yes # Mouse keys | ||||
PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support | 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: | <target>/config.h: | ||||
1. USB vendor/product ID and device description | 1. USB vendor/product ID and device description |
TARGET_DIR = . | TARGET_DIR = . | ||||
# keyboard dependent files | # 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 | CONFIG_H = config.h | ||||
# Build Options | # Build Options | ||||
# comment out to disable the 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 | #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 | |||||
include $(COMMON_DIR)/Makefile.pjrc | |||||
include $(COMMON_DIR)/Makefile.common | |||||
include $(COMMON_DIR)/pjrc.mk | |||||
include $(COMMON_DIR)/common.mk |
), | ), | ||||
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 | EOF |
/* key combination for command */ | /* key combination for command */ | ||||
#define IS_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)) \ | |||||
) | ) | ||||
#ifdef HOST_PJRC | #ifdef HOST_PJRC | ||||
# include "jump_bootloader.h" | # include "jump_bootloader.h" | ||||
# include "usb_keyboard.h" | # include "usb_keyboard.h" | ||||
# ifdef USB_EXTRA_ENABLE | |||||
# ifdef EXTRAKEY_ENABLE | |||||
# include "usb_extra.h" | # include "usb_extra.h" | ||||
# endif | # endif | ||||
#endif | #endif | ||||
#ifdef HOST_VUSB | |||||
# include "usbdrv.h" | |||||
#endif | |||||
static uint8_t command_common(void); | |||||
static void help(void); | static void help(void); | ||||
static void switch_layer(uint8_t layer); | static void switch_layer(uint8_t layer); | ||||
static bool last_print_enable; | |||||
uint8_t command_proc(void) | uint8_t command_proc(void) | ||||
{ | { | ||||
uint8_t processed = 0; | |||||
last_print_enable = print_enable; | |||||
if (!IS_COMMAND()) | if (!IS_COMMAND()) | ||||
return 0; | return 0; | ||||
uint8_t processed = 1; | |||||
bool last_print_enable = print_enable; | |||||
print_enable = true; | 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()) { | switch (host_get_first_key()) { | ||||
case KB_H: | case KB_H: | ||||
help(); | help(); | ||||
print("usb_keyboard_protocol: "); phex(usb_keyboard_protocol); print("\n"); | 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_config:"); phex(usb_keyboard_idle_config); print("\n"); | ||||
print("usb_keyboard_idle_count:"); phex(usb_keyboard_idle_count); 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 | #endif | ||||
break; | break; | ||||
#ifdef USB_NKRO_ENABLE | |||||
#ifdef NKRO_ENABLE | |||||
case KB_N: | case KB_N: | ||||
// send empty report before change | // send empty report before change | ||||
host_clear_keyboard_report(); | host_clear_keyboard_report(); | ||||
host_send_keyboard_report(); | host_send_keyboard_report(); | ||||
keyboard_nkro = !keyboard_nkro; | keyboard_nkro = !keyboard_nkro; | ||||
if (keyboard_nkro) | if (keyboard_nkro) | ||||
print("USB_NKRO: enabled\n"); | |||||
print("NKRO: enabled\n"); | |||||
else | else | ||||
print("USB_NKRO: disabled\n"); | |||||
print("NKRO: disabled\n"); | |||||
break; | break; | ||||
#endif | #endif | ||||
#ifdef USB_EXTRA_ENABLE | |||||
#ifdef EXTRAKEY_ENABLE | |||||
case KB_ESC: | case KB_ESC: | ||||
host_clear_keyboard_report(); | host_clear_keyboard_report(); | ||||
host_send_keyboard_report(); | host_send_keyboard_report(); | ||||
switch_layer(4); | switch_layer(4); | ||||
break; | break; | ||||
default: | default: | ||||
processed = 0; | |||||
return 0; | |||||
} | } | ||||
if (processed) | |||||
_delay_ms(500); | |||||
print_enable = last_print_enable; | |||||
return processed; | |||||
return 1; | |||||
} | } | ||||
static void help(void) | static void help(void) | ||||
print("v: print version\n"); | print("v: print version\n"); | ||||
print("t: print timer count\n"); | print("t: print timer count\n"); | ||||
print("s: print status\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 | #endif | ||||
print("Backspace: clear matrix\n"); | print("Backspace: clear matrix\n"); | ||||
print("ESC: power down/wake up\n"); | print("ESC: power down/wake up\n"); |
#define COMMAND | #define COMMAND | ||||
uint8_t command_proc(void); | uint8_t command_proc(void); | ||||
/* This allows to extend commands. Return 0 when command is not processed. */ | |||||
uint8_t command_extra(void); | |||||
#endif | #endif |
OPT_DEFS += -DPS2_MOUSE_ENABLE | OPT_DEFS += -DPS2_MOUSE_ENABLE | ||||
endif | endif | ||||
ifdef USB_EXTRA_ENABLE | |||||
OPT_DEFS += -DUSB_EXTRA_ENABLE | |||||
ifdef EXTRAKEY_ENABLE | |||||
OPT_DEFS += -DEXTRAKEY_ENABLE | |||||
endif | endif | ||||
ifdef USB_NKRO_ENABLE | |||||
OPT_DEFS += -DUSB_NKRO_ENABLE | |||||
ifdef NKRO_ENABLE | |||||
OPT_DEFS += -DNKRO_ENABLE | |||||
endif | endif | ||||
ifdef $(or MOUSEKEY_ENABLE, PS2_MOUSE_ENABLE) | ifdef $(or MOUSEKEY_ENABLE, PS2_MOUSE_ENABLE) | ||||
OPT_DEFS += -DUSB_MOUSE_ENABLE | |||||
OPT_DEFS += -DMOUSE_ENABLE | |||||
endif | endif | ||||
# Search Path | |||||
VPATH += $(COMMON_DIR) | |||||
include $(COMMON_DIR)/Makefile.rules | |||||
include $(COMMON_DIR)/rules.mk |
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) |
# | |||||
# 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 |
TARGET_DIR = . | TARGET_DIR = . | ||||
# keyboard dependent files | # 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 | CONFIG_H = config_pjrc.h | ||||
# comment out to disable the 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 | #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 | |||||
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 |
TARGET_DIR = . | TARGET_DIR = . | ||||
# keyboard dependent files | # 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 | CONFIG_H = config_vusb.h | ||||
# MCU name, you MUST set this to match the board you are using | # 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 | # 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. | # Processor frequency. | ||||
# so your program will run at the correct speed. You should also set this | # 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 | # 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. | # examples use this variable to calculate timings. Do not add a "UL" here. | ||||
F_CPU = 20000000 | |||||
F_CPU = 12000000 | |||||
# Build Options | # Build Options | ||||
# comment out to disable the options. | # comment out to disable the options. | ||||
# | # | ||||
MOUSEKEY_ENABLE = yes # Mouse keys | 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 | |||||
# to submit bug reports. | # to submit bug reports. | ||||
#AVRDUDE_VERBOSE = -v -v | #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_NO_VERIFY) | ||||
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE) | AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE) | ||||
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER) | AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER) | ||||
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 |
Feature | Feature | ||||
------- | ------- | ||||
- Mouse Keys | - Mouse Keys | ||||
- NKRO on USB | |||||
- NKRO on USB(PJRC Tennsy only) | |||||
- Keymap Layers | - Keymap Layers | ||||
see keymap.c. | see keymap.c. | ||||
Build for Teensy | |||||
---------------- | |||||
Build | |||||
===== | |||||
PJRC Teensy | |||||
----------- | |||||
0. Edit matrix.c. | 0. Edit matrix.c. | ||||
adjust scan code to your pin configuration.(see doc/HHKB.txt for pinouts) | adjust scan code to your pin configuration.(see doc/HHKB.txt for pinouts) | ||||
1. Define macros in config_pjrc.h.(Optional) | 1. Define macros in config_pjrc.h.(Optional) | ||||
IS_COMMAND | IS_COMMAND | ||||
2. Edit Makefile for MCU setting and build options. | 2. Edit Makefile for MCU setting and build options. | ||||
MCU, F_CPU | MCU, F_CPU | ||||
MOUSEKEY_ENABLE, USB_EXTRA_ENABLE, USB_NKRO_ENABLE | |||||
MOUSEKEY_ENABLE, EXTRAKEY_ENABLE, NKRO_ENABLE | |||||
3. Build hex file. | 3. Build hex file. | ||||
$ make | |||||
$ make -f Makefile.pjrc | |||||
4. Program MCU. | 4. Program MCU. | ||||
$ make program | |||||
$ make -f Makefile.pjrc program | |||||
Build for V-USB | |||||
--------------- | |||||
V-USB | |||||
----- | |||||
0. Edit matrix.c and usbconfig.h. | 0. Edit matrix.c and usbconfig.h. | ||||
adjust scan code to your pin configuration.(see doc/HHKB.txt for pinouts) | adjust scan code to your pin configuration.(see doc/HHKB.txt for pinouts) | ||||
define macros for V-USB in usbconfig.h. | define macros for V-USB in usbconfig.h. | ||||
IS_COMMAND | IS_COMMAND | ||||
2. Edit Makefile.vusb for MCU setting and build options. | 2. Edit Makefile.vusb for MCU setting and build options. | ||||
MCU, F_CPU | MCU, F_CPU | ||||
MOUSEKEY_ENABLE, USB_EXTRA_ENABLE, USB_NKRO_ENABLE | |||||
MOUSEKEY_ENABLE, EXTRAKEY_ENABLE | |||||
3. Build hex file. | 3. Build hex file. | ||||
$ make -f Makefile.vusb | $ make -f Makefile.vusb | ||||
4. Program MCU. | 4. Program MCU. | ||||
http://www.obdev.at/products/vusb/usbasploader.html | 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 | | USB GND | | ATmega168 | | ||||
=== C3 | | | |||||
~~~ C3 | | | |||||
5V <-------+--------+---|Vcc,AVCC | HHKB | 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 | R1: 1.5K Ohm | ||||
R2,R3: 68 Ohm | R2,R3: 68 Ohm | ||||
SW: Push Switch(Optional for bootloader) | 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 | EOF |
/* | |||||
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 |
/* key combination for command */ | /* 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 */ | /* mouse keys */ | ||||
#ifdef MOUSEKEY_ENABLE | #ifdef MOUSEKEY_ENABLE |
#ifndef CONFIG_H | #ifndef CONFIG_H | ||||
#define CONFIG_H | #define CONFIG_H | ||||
#define VENDOR_ID 0xFEED | #define VENDOR_ID 0xFEED | ||||
#define PRODUCT_ID 0xC0FE | #define PRODUCT_ID 0xC0FE | ||||
// TODO: share these strings with usbconfig.h | // TODO: share these strings with usbconfig.h | ||||
/* key combination for command */ | /* 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 */ | /* mouse keys */ | ||||
#ifdef MOUSEKEY_ENABLE | #ifdef MOUSEKEY_ENABLE | ||||
#endif | #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 | #endif |
HHKB Bluetooth mod | |||||
================== | |||||
See this article: | |||||
http://geekhack.org/showwiki.php?title=Island:20851 |
[Picasa] | |||||
name=Bluetooth_img |
// Convert physical keyboard layout to matrix array. | // Convert physical keyboard layout to matrix array. | ||||
// This is a macro to define keymap easily in keyboard layout form. | // This is a macro to define keymap easily in keyboard layout form. | ||||
#define KEYMAP( \ | #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)])) | #define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)])) | ||||
1, // Fn1 | 1, // Fn1 | ||||
2, // Fn2 | 2, // Fn2 | ||||
3, // Fn3 | 3, // Fn3 | ||||
4, // Fn4 | |||||
0, // Fn5 | |||||
3, // Fn4 | |||||
4, // Fn5 | |||||
0, // Fn6 | 0, // Fn6 | ||||
0 // Fn7 | 0 // Fn7 | ||||
}; | }; | ||||
KB_NO, // Fn1 | KB_NO, // Fn1 | ||||
KB_SLSH, // Fn2 | KB_SLSH, // Fn2 | ||||
KB_SCLN, // Fn3 | KB_SCLN, // Fn3 | ||||
KB_SPC, // Fn4 | |||||
KB_NO, // Fn5 | |||||
KB_NO, // Fn4 | |||||
KB_SPC, // Fn5 | |||||
KB_NO, // Fn6 | KB_NO, // Fn6 | ||||
KB_NO // Fn7 | KB_NO // Fn7 | ||||
}; | }; | ||||
* |Gui|Alt |Fn5 |Alt |Fn4| | * |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) | /* Layer 1: HHKB mode (HHKB Fn) | ||||
* ,-----------------------------------------------------------. | * ,-----------------------------------------------------------. | ||||
* |Gui |Alt |Space |Alt |xxx| | * |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) | /* Layer 2: Vi mode (Slash) | ||||
* ,-----------------------------------------------------------. | * ,-----------------------------------------------------------. | ||||
* |Gui|Alt |Space |Alt |Gui| | * |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) | /* Layer 3: Mouse mode (Semicolon) | ||||
* ,-----------------------------------------------------------. | * ,-----------------------------------------------------------. | ||||
* `--------------------------------------------' | * `--------------------------------------------' | ||||
* Mc: Mouse Cursor / Mb: Mouse Button / Mw: Mouse Wheel | * 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) | /* Layer 4: Matias half keyboard style (Space) | ||||
* ,-----------------------------------------------------------. | * ,-----------------------------------------------------------. | ||||
* `--------------------------------------------' | * `--------------------------------------------' | ||||
*/ | */ | ||||
/* | /* | ||||
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) */ | /* 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 | |||||
}; | }; | ||||
#include <util/delay.h> | #include <util/delay.h> | ||||
#include "print.h" | #include "print.h" | ||||
#include "util.h" | #include "util.h" | ||||
#include "timer.h" | |||||
#include "matrix.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) | #if (MATRIX_COLS > 16) | ||||
# error "MATRIX_COLS must not exceed 16" | # error "MATRIX_COLS must not exceed 16" | ||||
#endif | #endif | ||||
#define KEY_STATE() (PINE & (1<<6)) | #define KEY_STATE() (PINE & (1<<6)) | ||||
#define KEY_PREV_ON() (PORTE |= (1<<7)) | #define KEY_PREV_ON() (PORTE |= (1<<7)) | ||||
#define KEY_PREV_OFF() (PORTE &= ~(1<<7)) | #define KEY_PREV_OFF() (PORTE &= ~(1<<7)) | ||||
#define KEY_POWER_ON() | |||||
#define KEY_POWER_OFF() | |||||
#else | #else | ||||
// Ports for V-USB | // Ports for V-USB | ||||
// key: PB0(pull-uped) | // key: PB0(pull-uped) | ||||
// prev: PB1 | // prev: PB1 | ||||
// row: PB2-4 | // row: PB2-4 | ||||
// col: PC0-2,3 | // col: PC0-2,3 | ||||
// power: PB5(Low:on/Hi-z:off) | |||||
#define KEY_INIT() do { \ | #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) | } while (0) | ||||
#define KEY_SELECT(ROW, COL) do { \ | #define KEY_SELECT(ROW, COL) do { \ | ||||
PORTB = (PORTB & 0xE3) | ((ROW) & 0x07)<<2; \ | PORTB = (PORTB & 0xE3) | ((ROW) & 0x07)<<2; \ | ||||
#define KEY_STATE() (PINB & (1<<0)) | #define KEY_STATE() (PINB & (1<<0)) | ||||
#define KEY_PREV_ON() (PORTB |= (1<<1)) | #define KEY_PREV_ON() (PORTB |= (1<<1)) | ||||
#define KEY_PREV_OFF() (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 | #endif | ||||
matrix_prev = matrix; | matrix_prev = matrix; | ||||
matrix = tmp; | matrix = tmp; | ||||
KEY_POWER_ON(); | |||||
for (uint8_t row = 0; row < MATRIX_ROWS; row++) { | for (uint8_t row = 0; row < MATRIX_ROWS; row++) { | ||||
for (uint8_t col = 0; col < MATRIX_COLS; col++) { | for (uint8_t col = 0; col < MATRIX_COLS; col++) { | ||||
KEY_SELECT(row, 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)) { | if (matrix_prev[row] & (1<<col)) { | ||||
KEY_PREV_ON(); | 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(); | 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()) { | if (KEY_STATE()) { | ||||
matrix[row] &= ~(1<<col); | matrix[row] &= ~(1<<col); | ||||
} else { | } else { | ||||
matrix[row] |= (1<<col); | 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_PREV_OFF(); | ||||
KEY_UNABLE(); | 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; | return 1; | ||||
} | } | ||||
/* This macro (if defined) is executed when a USB SET_ADDRESS request was | /* This macro (if defined) is executed when a USB SET_ADDRESS request was | ||||
* received. | * received. | ||||
*/ | */ | ||||
#define USB_COUNT_SOF 0 | |||||
#define USB_COUNT_SOF 1 | |||||
/* define this macro to 1 if you need the global variable "usbSofCount" which | /* define this macro to 1 if you need the global variable "usbSofCount" which | ||||
* counts SOF packets. This feature requires that the hardware interrupt is | * counts SOF packets. This feature requires that the hardware interrupt is | ||||
* connected to D- instead of D+. | * connected to D- instead of D+. | ||||
#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0 | #define USB_CFG_DESCR_PROPS_STRING_VENDOR 0 | ||||
#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0 | #define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0 | ||||
#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 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 USB_PROP_IS_DYNAMIC | ||||
//#define USB_CFG_DESCR_PROPS_HID_REPORT 0 | //#define USB_CFG_DESCR_PROPS_HID_REPORT 0 | ||||
#define USB_CFG_DESCR_PROPS_UNKNOWN 0 | #define USB_CFG_DESCR_PROPS_UNKNOWN 0 | ||||
/* #define USB_INTR_PENDING_BIT INTF0 */ | /* #define USB_INTR_PENDING_BIT INTF0 */ | ||||
/* #define USB_INTR_VECTOR INT0_vect */ | /* #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__ */ | #endif /* __usbconfig_h_included__ */ |
/* | |||||
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"); | |||||
} | |||||
} |
#define HOST_H | #define HOST_H | ||||
#include <stdint.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; | extern bool keyboard_nkro; | ||||
#endif | #endif | ||||
extern report_keyboard_t *keyboard_report_prev; | 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); | uint8_t host_keyboard_leds(void); | ||||
/* keyboard report operations */ | /* keyboard report operations */ | ||||
void host_send_keyboard_report(void); | void host_send_keyboard_report(void); | ||||
#if defined(MOUSEKEY_ENABLE) || defined(PS2_MOUSE_ENABLE) | |||||
void host_mouse_send(report_mouse_t *report); | void host_mouse_send(report_mouse_t *report); | ||||
#endif | |||||
#ifdef USB_EXTRA_ENABLE | |||||
void host_system_send(uint16_t data); | void host_system_send(uint16_t data); | ||||
void host_consumer_send(uint16_t data); | void host_consumer_send(uint16_t data); | ||||
#endif | |||||
#endif | #endif |
/* | |||||
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 |
OPT_DEFS += -DHOST_IWRAP | |||||
SRC += iwrap.c \ | |||||
suart.S \ | |||||
sendchar_uart.c \ | |||||
uart.c | |||||
# Search Path | |||||
VPATH += $(COMMON_DIR)/iwrap |
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 |
/* | |||||
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 | |||||
} |
/* | |||||
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 |
/* | |||||
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; | |||||
} | |||||
} |
;---------------------------------------------------------------------------; | |||||
; 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 |
#ifndef SUART | |||||
#define SUART | |||||
void xmit(uint8_t); | |||||
uint8_t rcvr(void); | |||||
uint8_t recv(void); | |||||
#endif /* SUART */ |
/* 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_ */ |
#ifdef MOUSEKEY_ENABLE | #ifdef MOUSEKEY_ENABLE | ||||
#include "mousekey.h" | #include "mousekey.h" | ||||
#endif | #endif | ||||
#ifdef USB_EXTRA_ENABLE | |||||
#ifdef EXTRAKEY_ENABLE | |||||
#include <util/delay.h> | #include <util/delay.h> | ||||
#endif | #endif | ||||
void keyboard_proc(void) | void keyboard_proc(void) | ||||
{ | { | ||||
uint8_t fn_bits = 0; | uint8_t fn_bits = 0; | ||||
#ifdef USB_EXTRA_ENABLE | |||||
#ifdef EXTRAKEY_ENABLE | |||||
uint16_t consumer_code = 0; | uint16_t consumer_code = 0; | ||||
#endif | #endif | ||||
} else if (IS_FN(code)) { | } else if (IS_FN(code)) { | ||||
fn_bits |= FN_BIT(code); | fn_bits |= FN_BIT(code); | ||||
} | } | ||||
#ifdef USB_EXTRA_ENABLE | |||||
// TODO: use table or something | |||||
#ifdef EXTRAKEY_ENABLE | |||||
// System Control | // System Control | ||||
else if (code == KB_SYSTEM_POWER) { | else if (code == KB_SYSTEM_POWER) { | ||||
#ifdef HOST_PJRC | #ifdef HOST_PJRC | ||||
// TODO: should send only when changed from last report | // TODO: should send only when changed from last report | ||||
if (matrix_is_modified()) { | if (matrix_is_modified()) { | ||||
host_send_keyboard_report(); | host_send_keyboard_report(); | ||||
#ifdef USB_EXTRA_ENABLE | |||||
#ifdef EXTRAKEY_ENABLE | |||||
host_consumer_send(consumer_code); | host_consumer_send(consumer_code); | ||||
#endif | #endif | ||||
#ifdef DEBUG_LED | #ifdef DEBUG_LED |
*/ | */ | ||||
// LAYER_ENTER_DELAY: prevent from moving new layer | // 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 | // 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; | uint8_t default_layer = 0; |
TARGET_DIR = . | TARGET_DIR = . | ||||
# keyboard dependent files | # 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 | CONFIG_H = config.h | ||||
# | # | ||||
MOUSEKEY_ENABLE = yes # Mouse keys | MOUSEKEY_ENABLE = yes # Mouse keys | ||||
#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support | #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 | |||||
include $(COMMON_DIR)/Makefile.pjrc | |||||
include $(COMMON_DIR)/Makefile.common | |||||
include $(COMMON_DIR)/pjrc.mk | |||||
include $(COMMON_DIR)/common.mk |
/* key combination for command */ | /* key combination for command */ | ||||
#define IS_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)) \ | |||||
) | ) | ||||
/* 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(); | |||||
} | |||||
} |
else if (code == KB_MS_BTN3) report.buttons |= MOUSE_BTN3; | 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_BTN4) report.buttons |= MOUSE_BTN4; | ||||
else if (code == KB_MS_BTN5) report.buttons |= MOUSE_BTN5; | 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) | bool mousekey_changed(void) | ||||
// send immediately when buttun state is changed | // send immediately when buttun state is changed | ||||
if (report.buttons == report_prev.buttons) { | if (report.buttons == report_prev.buttons) { | ||||
if (timer_elapsed(last_timer) < 5) { | |||||
if (timer_elapsed(last_timer) < 100) { | |||||
mousekey_clear_report(); | mousekey_clear_report(); | ||||
return; | return; | ||||
} | } |
OPT_DEFS += -DHOST_PJRC | OPT_DEFS += -DHOST_PJRC | ||||
SRC = usb_keyboard.c \ | |||||
SRC += pjrc.c \ | |||||
usb_keyboard.c \ | |||||
usb_debug.c \ | usb_debug.c \ | ||||
usb.c \ | usb.c \ | ||||
jump_bootloader.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 | # Option modules | ||||
SRC += usb_mouse.c | SRC += usb_mouse.c | ||||
endif | endif | ||||
ifdef USB_EXTRA_ENABLE | |||||
ifdef EXTRAKEY_ENABLE | |||||
SRC += usb_extra.c | SRC += usb_extra.c | ||||
endif | endif |
#if defined(MOUSEKEY_ENABLE) || defined(PS2_MOUSE_ENABLE) | #if defined(MOUSEKEY_ENABLE) || defined(PS2_MOUSE_ENABLE) | ||||
#include "usb_mouse.h" | #include "usb_mouse.h" | ||||
#endif | #endif | ||||
#ifdef USB_EXTRA_ENABLE | |||||
#ifdef EXTRAKEY_ENABLE | |||||
#include "usb_extra.h" | #include "usb_extra.h" | ||||
#endif | #endif | ||||
#include "debug.h" | #include "debug.h" | ||||
#include "util.h" | #include "util.h" | ||||
#ifdef USB_NKRO_ENABLE | |||||
#ifdef NKRO_ENABLE | |||||
bool keyboard_nkro = false; | bool keyboard_nkro = false; | ||||
#endif | #endif | ||||
/* keyboard report operations */ | /* keyboard report operations */ | ||||
void host_add_key(uint8_t key) | void host_add_key(uint8_t key) | ||||
{ | { | ||||
#ifdef USB_NKRO_ENABLE | |||||
#ifdef NKRO_ENABLE | |||||
if (keyboard_nkro) { | if (keyboard_nkro) { | ||||
add_key_bit(key); | add_key_bit(key); | ||||
return; | return; | ||||
uint8_t host_get_first_key(void) | uint8_t host_get_first_key(void) | ||||
{ | { | ||||
#ifdef USB_NKRO_ENABLE | |||||
#ifdef NKRO_ENABLE | |||||
if (keyboard_nkro) { | if (keyboard_nkro) { | ||||
uint8_t i = 0; | uint8_t i = 0; | ||||
for (; i < REPORT_KEYS && !keyboard_report->keys[i]; i++) | for (; i < REPORT_KEYS && !keyboard_report->keys[i]; i++) | ||||
} | } | ||||
#endif | #endif | ||||
#ifdef USB_EXTRA_ENABLE | |||||
#ifdef EXTRAKEY_ENABLE | |||||
void host_system_send(uint16_t data) | void host_system_send(uint16_t data) | ||||
{ | { | ||||
usb_extra_system_send(data); | usb_extra_system_send(data); |
#ifdef PS2_MOUSE_ENABLE | #ifdef PS2_MOUSE_ENABLE | ||||
# include "ps2_mouse.h" | # include "ps2_mouse.h" | ||||
#endif | #endif | ||||
#include "host.h" | |||||
#include "pjrc.h" | |||||
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n)) | #define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n)) | ||||
} | } | ||||
host_set_driver(pjrc_driver()); | |||||
while (1) { | while (1) { | ||||
keyboard_proc(); | keyboard_proc(); | ||||
} | } |
/* | |||||
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 | |||||
} |
/* | |||||
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 |
static const uint8_t PROGMEM endpoint_config_table[] = { | static const uint8_t PROGMEM endpoint_config_table[] = { | ||||
// enable, UECFG0X(type, direction), UECFG1X(size, bank, allocation) | // enable, UECFG0X(type, direction), UECFG1X(size, bank, allocation) | ||||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KBD_SIZE) | KBD_BUFFER, // 1 | 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 | 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(MOUSE_SIZE) | MOUSE_BUFFER, // 2 | ||||
#else | #else | ||||
0, // 2 | 0, // 2 | ||||
#endif | #endif | ||||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(DEBUG_TX_SIZE) | DEBUG_TX_BUFFER, // 3 | 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 | 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(EXTRA_SIZE) | EXTRA_BUFFER, // 4 | ||||
#else | #else | ||||
0, // 4 | 0, // 4 | ||||
#endif | #endif | ||||
#ifdef USB_NKRO_ENABLE | |||||
#ifdef NKRO_ENABLE | |||||
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KBD2_SIZE) | KBD2_BUFFER, // 5 | 1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KBD2_SIZE) | KBD2_BUFFER, // 5 | ||||
#else | #else | ||||
0, // 5 | 0, // 5 | ||||
0x81, 0x00, // Input (Data, Array), | 0x81, 0x00, // Input (Data, Array), | ||||
0xc0 // End Collection | 0xc0 // End Collection | ||||
}; | }; | ||||
#ifdef USB_NKRO_ENABLE | |||||
#ifdef NKRO_ENABLE | |||||
static uint8_t PROGMEM keyboard2_hid_report_desc[] = { | static uint8_t PROGMEM keyboard2_hid_report_desc[] = { | ||||
0x05, 0x01, // Usage Page (Generic Desktop), | 0x05, 0x01, // Usage Page (Generic Desktop), | ||||
0x09, 0x06, // Usage (Keyboard), | 0x09, 0x06, // Usage (Keyboard), | ||||
}; | }; | ||||
#endif | #endif | ||||
#ifdef USB_MOUSE_ENABLE | |||||
#ifdef MOUSE_ENABLE | |||||
// Mouse Protocol 1, HID 1.11 spec, Appendix B, page 59-60, with wheel extension | // 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.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521 | ||||
// http://www.keil.com/forum/15671/ | // http://www.keil.com/forum/15671/ | ||||
0xC0 // end collection | 0xC0 // end collection | ||||
}; | }; | ||||
#ifdef USB_EXTRA_ENABLE | |||||
#ifdef EXTRAKEY_ENABLE | |||||
// audio controls & system controls | // audio controls & system controls | ||||
// http://www.microsoft.com/whdc/archive/w2kbd.mspx | // http://www.microsoft.com/whdc/archive/w2kbd.mspx | ||||
static uint8_t PROGMEM extra_hid_report_desc[] = { | static uint8_t PROGMEM extra_hid_report_desc[] = { | ||||
#define KBD_HID_DESC_NUM 0 | #define KBD_HID_DESC_NUM 0 | ||||
#define KBD_HID_DESC_OFFSET (9+(9+9+7)*KBD_HID_DESC_NUM+9) | #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_NUM (KBD_HID_DESC_NUM + 1) | ||||
# define MOUSE_HID_DESC_OFFSET (9+(9+9+7)*MOUSE_HID_DESC_NUM+9) | # define MOUSE_HID_DESC_OFFSET (9+(9+9+7)*MOUSE_HID_DESC_NUM+9) | ||||
#else | #else | ||||
#define DEBUG_HID_DESC_NUM (MOUSE_HID_DESC_NUM + 1) | #define DEBUG_HID_DESC_NUM (MOUSE_HID_DESC_NUM + 1) | ||||
#define DEBUG_HID_DESC_OFFSET (9+(9+9+7)*DEBUG_HID_DESC_NUM+9) | #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_NUM (DEBUG_HID_DESC_NUM + 1) | ||||
# define EXTRA_HID_DESC_OFFSET (9+(9+9+7)*EXTRA_HID_DESC_NUM+9) | # define EXTRA_HID_DESC_OFFSET (9+(9+9+7)*EXTRA_HID_DESC_NUM+9) | ||||
#else | #else | ||||
# define EXTRA_HID_DESC_NUM (DEBUG_HID_DESC_NUM + 0) | # define EXTRA_HID_DESC_NUM (DEBUG_HID_DESC_NUM + 0) | ||||
#endif | #endif | ||||
#ifdef USB_NKRO_ENABLE | |||||
#ifdef NKRO_ENABLE | |||||
# define KBD2_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 1) | # define KBD2_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 1) | ||||
# define KBD2_HID_DESC_OFFSET (9+(9+9+7)*EXTRA_HID_DESC_NUM+9) | # define KBD2_HID_DESC_OFFSET (9+(9+9+7)*EXTRA_HID_DESC_NUM+9) | ||||
#else | #else | ||||
KBD_SIZE, 0, // wMaxPacketSize | KBD_SIZE, 0, // wMaxPacketSize | ||||
10, // bInterval | 10, // bInterval | ||||
#ifdef USB_MOUSE_ENABLE | |||||
#ifdef MOUSE_ENABLE | |||||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | ||||
9, // bLength | 9, // bLength | ||||
4, // bDescriptorType | 4, // bDescriptorType | ||||
DEBUG_TX_SIZE, 0, // wMaxPacketSize | DEBUG_TX_SIZE, 0, // wMaxPacketSize | ||||
1, // bInterval | 1, // bInterval | ||||
#ifdef USB_EXTRA_ENABLE | |||||
#ifdef EXTRAKEY_ENABLE | |||||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | ||||
9, // bLength | 9, // bLength | ||||
4, // bDescriptorType | 4, // bDescriptorType | ||||
10, // bInterval | 10, // bInterval | ||||
#endif | #endif | ||||
#ifdef USB_NKRO_ENABLE | |||||
#ifdef NKRO_ENABLE | |||||
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 | ||||
9, // bLength | 9, // bLength | ||||
4, // bDescriptorType | 4, // bDescriptorType | ||||
// HID/REPORT descriptors | // HID/REPORT descriptors | ||||
{0x2100, KBD_INTERFACE, config1_descriptor+KBD_HID_DESC_OFFSET, 9}, | {0x2100, KBD_INTERFACE, config1_descriptor+KBD_HID_DESC_OFFSET, 9}, | ||||
{0x2200, KBD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)}, | {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}, | {0x2100, MOUSE_INTERFACE, config1_descriptor+MOUSE_HID_DESC_OFFSET, 9}, | ||||
{0x2200, MOUSE_INTERFACE, mouse_hid_report_desc, sizeof(mouse_hid_report_desc)}, | {0x2200, MOUSE_INTERFACE, mouse_hid_report_desc, sizeof(mouse_hid_report_desc)}, | ||||
#endif | #endif | ||||
{0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9}, | {0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9}, | ||||
{0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)}, | {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}, | {0x2100, EXTRA_INTERFACE, config1_descriptor+EXTRA_HID_DESC_OFFSET, 9}, | ||||
{0x2200, EXTRA_INTERFACE, extra_hid_report_desc, sizeof(extra_hid_report_desc)}, | {0x2200, EXTRA_INTERFACE, extra_hid_report_desc, sizeof(extra_hid_report_desc)}, | ||||
#endif | #endif | ||||
#ifdef USB_NKRO_ENABLE | |||||
#ifdef NKRO_ENABLE | |||||
{0x2100, KBD2_INTERFACE, config1_descriptor+KBD2_HID_DESC_OFFSET, 9}, | {0x2100, KBD2_INTERFACE, config1_descriptor+KBD2_HID_DESC_OFFSET, 9}, | ||||
{0x2200, KBD2_INTERFACE, keyboard2_hid_report_desc, sizeof(keyboard2_hid_report_desc)}, | {0x2200, KBD2_INTERFACE, keyboard2_hid_report_desc, sizeof(keyboard2_hid_report_desc)}, | ||||
#endif | #endif | ||||
} | } | ||||
} | } | ||||
/* TODO: should keep IDLE rate on each keyboard interface */ | /* 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) { | if (!keyboard_nkro && usb_keyboard_idle_config && (++div4 & 3) == 0) { | ||||
#else | #else | ||||
if (usb_keyboard_idle_config && (++div4 & 3) == 0) { | if (usb_keyboard_idle_config && (++div4 & 3) == 0) { | ||||
} | } | ||||
} | } | ||||
} | } | ||||
#ifdef USB_MOUSE_ENABLE | |||||
#ifdef MOUSE_ENABLE | |||||
if (wIndex == MOUSE_INTERFACE) { | if (wIndex == MOUSE_INTERFACE) { | ||||
if (bmRequestType == 0xA1) { | if (bmRequestType == 0xA1) { | ||||
if (bRequest == HID_GET_REPORT) { | if (bRequest == HID_GET_REPORT) { |
#define KBD_REPORT_KEYS (KBD_SIZE - 2) | #define KBD_REPORT_KEYS (KBD_SIZE - 2) | ||||
// secondary keyboard | // secondary keyboard | ||||
#ifdef USB_NKRO_ENABLE | |||||
#ifdef NKRO_ENABLE | |||||
#define KBD2_INTERFACE 4 | #define KBD2_INTERFACE 4 | ||||
#define KBD2_ENDPOINT 5 | #define KBD2_ENDPOINT 5 | ||||
#define KBD2_SIZE 16 | #define KBD2_SIZE 16 |
{ | { | ||||
int8_t result = 0; | int8_t result = 0; | ||||
#ifdef USB_NKRO_ENABLE | |||||
#ifdef NKRO_ENABLE | |||||
if (keyboard_nkro) | if (keyboard_nkro) | ||||
result = send_report(report, KBD2_ENDPOINT, 0, KBD2_REPORT_KEYS); | result = send_report(report, KBD2_ENDPOINT, 0, KBD2_REPORT_KEYS); | ||||
else | else | ||||
UENUM = endpoint; | UENUM = endpoint; | ||||
} | } | ||||
UEDATX = report->mods; | UEDATX = report->mods; | ||||
#ifdef USB_NKRO_ENABLE | |||||
#ifdef NKRO_ENABLE | |||||
if (!keyboard_nkro) | if (!keyboard_nkro) | ||||
UEDATX = 0; | UEDATX = 0; | ||||
#else | #else |
bool print_enable = false; | 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) | void print_P(const char *s) | ||||
{ | { | ||||
if (!print_enable) return; | if (!print_enable) return; |
#ifndef PRINT_H__ | #ifndef PRINT_H__ | ||||
#define PRINT_H__ 1 | #define PRINT_H__ 1 | ||||
#include <stdint.h> | |||||
#include <stdbool.h> | #include <stdbool.h> | ||||
#include <avr/pgmspace.h> | #include <avr/pgmspace.h> | ||||
// the string is automatically placed into flash memory :) | // the string is automatically placed into flash memory :) | ||||
#define print(s) print_P(PSTR(s)) | #define print(s) print_P(PSTR(s)) | ||||
void print_S(const char *s); | |||||
void print_P(const char *s); | void print_P(const char *s); | ||||
void phex(unsigned char c); | void phex(unsigned char c); | ||||
void phex16(unsigned int i); | void phex16(unsigned int i); |
TARGET_DIR = . | TARGET_DIR = . | ||||
# keyboard dependent files | # 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 | CONFIG_H = config_pjrc.h | ||||
# comment out to disable the options. | # comment out to disable the options. | ||||
# | # | ||||
MOUSEKEY_ENABLE = yes # Mouse keys | 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 | |||||
include $(COMMON_DIR)/Makefile.pjrc | |||||
include $(COMMON_DIR)/Makefile.common | |||||
include $(COMMON_DIR)/pjrc.mk | |||||
include $(COMMON_DIR)/common.mk |
TARGET_DIR = . | TARGET_DIR = . | ||||
# keyboard dependent files | # 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 | CONFIG_H = config_vusb.h | ||||
# comment out to disable the options. | # comment out to disable the options. | ||||
# | # | ||||
MOUSEKEY_ENABLE = yes # Mouse keys | 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 | |||||
include $(COMMON_DIR)/Makefile.vusb | |||||
include $(COMMON_DIR)/Makefile.common | |||||
include $(COMMON_DIR)/vusb.mk | |||||
include $(COMMON_DIR)/common.mk |
/* key combination for command */ | /* key combination for command */ | ||||
#define IS_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)) \ | |||||
) | ) | ||||
/* key combination for command */ | /* key combination for command */ | ||||
#define IS_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)) \ | |||||
) | ) | ||||
static const uint8_t PROGMEM fn_keycode[] = { | static const uint8_t PROGMEM fn_keycode[] = { | ||||
KB_SCLN, // Fn0 | KB_SCLN, // Fn0 | ||||
KB_SLSH, // Fn1 | KB_SLSH, // Fn1 | ||||
KB_A, // Fn2 | |||||
KB_NO, // Fn2 | |||||
KB_NO, // Fn3 | KB_NO, // Fn3 | ||||
KB_NO, // Fn4 | KB_NO, // Fn4 | ||||
KB_NO, // Fn5 | KB_NO, // Fn5 | ||||
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, 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, | 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, | 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, | 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 | LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT | ||||
), | ), | ||||
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, 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, | 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, | 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, | 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 | LCTL,LGUI,LALT, BTN1, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT | ||||
), | ), |
default: | default: | ||||
state = INIT; | state = INIT; | ||||
} | } | ||||
phex(code); | |||||
} | } | ||||
return 1; | return 1; | ||||
} | } |
/* | |||||
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 |
#ifndef SENDCHAR_H | #ifndef SENDCHAR_H | ||||
#define SENDCHAR_H | #define SENDCHAR_H | ||||
#include <stdint.h> | |||||
/* transmit a character. return 0 on success, -1 on error. */ | /* transmit a character. return 0 on success, -1 on error. */ | ||||
int8_t sendchar(uint8_t c); | int8_t sendchar(uint8_t c); | ||||
#endif | #endif | ||||
You should have received a copy of the GNU General Public License | You should have received a copy of the GNU General Public License | ||||
along with this program. If not, see <http://www.gnu.org/licenses/>. | 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; | |||||
} |
/* | |||||
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; | |||||
} |
#include <stdint.h> | #include <stdint.h> | ||||
#include "timer.h" | #include "timer.h" | ||||
// counter resolution 1ms | |||||
volatile uint16_t timer_count = 0; | 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) | 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; | TCCR0B = 0x05; | ||||
TIMSK0 = (1<<TOIE0); | |||||
#else | |||||
# error "Timer prescaler value is NOT vaild." | |||||
#endif | |||||
OCR0A = TIMER_RAW_TOP; | |||||
TIMSK0 = (1<<OCIE0A); | |||||
} | } | ||||
inline | inline | ||||
t = timer_count; | t = timer_count; | ||||
SREG = sreg; | 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++; | timer_count++; | ||||
} | } |
#include <stdint.h> | #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; | extern volatile uint16_t timer_count; |
// 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; | |||||
} | |||||
} | |||||
#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 |
*/ | */ | ||||
/* | /* | ||||
* Key codes from HID Keyboard/Keypad Page | |||||
* Key codes: HID Keyboard/Keypad Page(0x07) | |||||
* http://www.usb.org/developers/devclass_docs/Hut1_12.pdf | * http://www.usb.org/developers/devclass_docs/Hut1_12.pdf | ||||
*/ | */ | ||||
#ifndef USB_KEYCODES_H | #ifndef USB_KEYCODES_H | ||||
KB_CRSEL, | KB_CRSEL, | ||||
KB_EXSEL, | 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_00 = 0xB0, | ||||
KB_KP_000, | KB_KP_000, | ||||
KB_THOUSANDS_SEPARATOR, | KB_THOUSANDS_SEPARATOR, | ||||
KB_KP_OCTAL, | KB_KP_OCTAL, | ||||
KB_KP_DECIMAL, | KB_KP_DECIMAL, | ||||
KB_KP_HEXADECIMAL, | KB_KP_HEXADECIMAL, | ||||
#endif | |||||
/* Modifiers */ | /* Modifiers */ | ||||
KB_LCTRL = 0xE0, | KB_LCTRL = 0xE0, | ||||
KB_RALT, | KB_RALT, | ||||
KB_RGUI, | KB_RGUI, | ||||
/* NOTE: uses 0xE8-FF for special keycodes */ | |||||
/* NOTE: 0xE8-FF are used as special_keycodes */ | |||||
}; | }; | ||||
#endif /* USB_KEYCODES_H */ | #endif /* USB_KEYCODES_H */ |
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 |
/* 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(); | |||||
} | |||||
} |
*/ | */ | ||||
#include <stdint.h> | #include <stdint.h> | ||||
#include <avr/interrupt.h> | |||||
#include "usbdrv.h" | #include "usbdrv.h" | ||||
#include "usbconfig.h" | #include "usbconfig.h" | ||||
#include "print.h" | |||||
#include "usb_keycodes.h" | |||||
#include "host.h" | #include "host.h" | ||||
#include "host_vusb.h" | |||||
#include "report.h" | |||||
#include "print.h" | |||||
#include "debug.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; | uint8_t next = (kbuf_head + 1) % KBUF_SIZE; | ||||
if (next != kbuf_tail) { | if (next != kbuf_tail) { | ||||
kbuf[kbuf_head] = *keyboard_report; | |||||
kbuf[kbuf_head] = *report; | |||||
kbuf_head = next; | kbuf_head = next; | ||||
} else { | } else { | ||||
debug("kbuf: full\n"); | debug("kbuf: full\n"); | ||||
} | } | ||||
#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; | report->report_id = REPORT_ID_MOUSE; | ||||
if (usbInterruptIsReady3()) { | if (usbInterruptIsReady3()) { | ||||
usbSetInterrupt3((void *)report, sizeof(*report)); | 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? | // Not need static? | ||||
static uint8_t report[] = { REPORT_ID_SYSTEM, 0, 0 }; | static uint8_t report[] = { REPORT_ID_SYSTEM, 0, 0 }; | ||||
report[2] = (data>>8)&0xFF; | report[2] = (data>>8)&0xFF; | ||||
if (usbInterruptIsReady3()) { | if (usbInterruptIsReady3()) { | ||||
usbSetInterrupt3((void *)&report, sizeof(report)); | 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; | static uint16_t last_data = 0; | ||||
if (data == last_data) return; | if (data == last_data) return; | ||||
report[2] = (data>>8)&0xFF; | report[2] = (data>>8)&0xFF; | ||||
if (usbInterruptIsReady3()) { | if (usbInterruptIsReady3()) { | ||||
usbSetInterrupt3((void *)&report, sizeof(report)); | usbSetInterrupt3((void *)&report, sizeof(report)); | ||||
} else { | |||||
debug("Int3 not ready\n"); | |||||
} | } | ||||
} | } | ||||
#endif | |||||
if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */ | if((rq->bmRequestType & USBRQ_TYPE_MASK) == USBRQ_TYPE_CLASS){ /* class request type */ | ||||
if(rq->bRequest == USBRQ_HID_GET_REPORT){ | 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 */ | /* we only have one report type, so don't look at wValue */ | ||||
usbMsgPtr = (void *)keyboard_report_prev; | usbMsgPtr = (void *)keyboard_report_prev; | ||||
return sizeof(*keyboard_report_prev); | return sizeof(*keyboard_report_prev); | ||||
}else if(rq->bRequest == USBRQ_HID_GET_IDLE){ | }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; | return 1; | ||||
}else if(rq->bRequest == USBRQ_HID_SET_IDLE){ | }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){ | }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) { | if (rq->wValue.word == 0x0200 && rq->wIndex.word == 0) { | ||||
debug("SET_LED: "); | |||||
last_req.kind = SET_LED; | last_req.kind = SET_LED; | ||||
last_req.len = rq->wLength.word; | last_req.len = rq->wLength.word; | ||||
} | } | ||||
return USB_NO_MSG; // to get data in usbFunctionWrite | return USB_NO_MSG; // to get data in usbFunctionWrite | ||||
} else { | |||||
debug("UNKNOWN:"); | |||||
} | } | ||||
debug("\n"); | |||||
}else{ | }else{ | ||||
debug("VENDOR\n"); | |||||
debug("VENDOR:"); | |||||
/* no vendor specific requests implemented */ | /* no vendor specific requests implemented */ | ||||
} | } | ||||
debug("\n"); | |||||
return 0; /* default for not implemented requests: return no data back to host */ | return 0; /* default for not implemented requests: return no data back to host */ | ||||
} | } | ||||
} | } | ||||
switch (last_req.kind) { | switch (last_req.kind) { | ||||
case SET_LED: | 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; | last_req.len = 0; | ||||
return 1; | return 1; | ||||
break; | break; | ||||
{ | { | ||||
usbMsgLen_t len = 0; | usbMsgLen_t len = 0; | ||||
/* | |||||
debug("usbFunctionDescriptor: "); | debug("usbFunctionDescriptor: "); | ||||
debug_hex(rq->bmRequestType); debug(" "); | debug_hex(rq->bmRequestType); debug(" "); | ||||
debug_hex(rq->bRequest); debug(" "); | debug_hex(rq->bRequest); debug(" "); | ||||
debug_hex16(rq->wValue.word); debug(" "); | debug_hex16(rq->wValue.word); debug(" "); | ||||
debug_hex16(rq->wIndex.word); debug(" "); | debug_hex16(rq->wIndex.word); debug(" "); | ||||
debug_hex16(rq->wLength.word); debug("\n"); | debug_hex16(rq->wLength.word); debug("\n"); | ||||
*/ | |||||
switch (rq->wValue.bytes[1]) { | switch (rq->wValue.bytes[1]) { | ||||
#if USB_CFG_DESCR_PROPS_CONFIGURATION | #if USB_CFG_DESCR_PROPS_CONFIGURATION | ||||
case USBDESCR_CONFIG: | case USBDESCR_CONFIG: | ||||
break; | break; | ||||
#endif | #endif | ||||
case USBDESCR_HID: | 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; | break; | ||||
case USBDESCR_HID_REPORT: | case USBDESCR_HID_REPORT: | ||||
/* interface index */ | /* interface index */ | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
debug("desc len: "); debug_hex(len); debug("\n"); | |||||
//debug("desc len: "); debug_hex(len); debug("\n"); | |||||
return len; | return len; | ||||
} | } |
/* | |||||
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 |