Compare commits
70 Commits
Author | SHA1 | Date | |
---|---|---|---|
c2bcad5149 | |||
11db1e1a9f | |||
|
d831eb699b | ||
|
a77a1d2289 | ||
|
6d45e05ede | ||
|
47da6bf7d4 | ||
|
98edc2fcbc | ||
|
af85b6bba6 | ||
|
74f7e19863 | ||
|
068c31a7ba | ||
|
61e12a3157 | ||
|
a6b31e950f | ||
|
b0b6c33332 | ||
|
5de62e26a0 | ||
|
13e4662bae | ||
|
cec2549505 | ||
|
1a7c3585ed | ||
|
258fd3c368 | ||
|
00350c180d | ||
|
d2b9489a5e | ||
|
60052acc0f | ||
|
c958b2d19b | ||
|
fb8d23c60c | ||
|
47f5d8b545 | ||
|
239bdbf419 | ||
|
3015f191a5 | ||
|
9a938eecbd | ||
|
2b8cd88ab1 | ||
|
acc974c64b | ||
|
5552b5afea | ||
|
04f351b802 | ||
|
0632618d29 | ||
|
4f5f1a53d4 | ||
|
c07408a447 | ||
|
cf95d8308f | ||
|
a96085faf6 | ||
|
5bc29b50ef | ||
|
23c686ad46 | ||
|
a28a2a6a5e | ||
|
bf1a37ba71 | ||
|
7ad93f7850 | ||
|
849b10e921 | ||
|
16be834617 | ||
|
06db39583f | ||
|
40c24dc89a | ||
|
c5b9f2b02b | ||
|
56e098d76e | ||
|
1f5cd6d7dc | ||
|
035b286b24 | ||
|
3e56e80c7d | ||
|
fd49c69d1a | ||
|
590235d4bc | ||
|
6b0c939d72 | ||
|
7272c65d3d | ||
|
2a562a4191 | ||
|
1ed336a064 | ||
|
51f17f0231 | ||
|
66ece29b0e | ||
|
37ced39ae2 | ||
|
d6da554687 | ||
|
9019c901dd | ||
|
02d955e9fe | ||
|
8240e606d4 | ||
|
8fc6c265d1 | ||
|
2ca3ab18a2 | ||
|
74b3e591fc | ||
|
89feab2301 | ||
|
a31b31e717 | ||
|
45d4a7a898 | ||
|
6c3b9a2ded |
649
Makefile.common
@ -1,636 +1,35 @@
|
|||||||
# Hey Emacs, this is a -*- makefile -*-
|
SRC += host.c \
|
||||||
#----------------------------------------------------------------------------
|
keyboard.c \
|
||||||
# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al.
|
command.c \
|
||||||
#
|
layer.c \
|
||||||
# Released to the Public Domain
|
timer.c \
|
||||||
#
|
|
||||||
# Additional material for this makefile was written by:
|
|
||||||
# Peter Fleury
|
|
||||||
# Tim Henigan
|
|
||||||
# Colin O'Flynn
|
|
||||||
# Reiner Patommel
|
|
||||||
# Markus Pfaff
|
|
||||||
# Sander Pool
|
|
||||||
# Frederik Rouleau
|
|
||||||
# Carlos Lamas
|
|
||||||
#
|
|
||||||
#----------------------------------------------------------------------------
|
|
||||||
# On command line:
|
|
||||||
#
|
|
||||||
# make all = Make software.
|
|
||||||
#
|
|
||||||
# make clean = Clean out built project files.
|
|
||||||
#
|
|
||||||
# make coff = Convert ELF to AVR COFF.
|
|
||||||
#
|
|
||||||
# make extcoff = Convert ELF to AVR Extended COFF.
|
|
||||||
#
|
|
||||||
# make program = Download the hex file to the device, using avrdude.
|
|
||||||
# Please customize the avrdude settings below first!
|
|
||||||
#
|
|
||||||
# make debug = Start either simulavr or avarice as specified for debugging,
|
|
||||||
# with avr-gdb or avr-insight as the front end for debugging.
|
|
||||||
#
|
|
||||||
# make filename.s = Just compile filename.c into the assembler code only.
|
|
||||||
#
|
|
||||||
# make filename.i = Create a preprocessed source file for use in submitting
|
|
||||||
# bug reports to the GCC project.
|
|
||||||
#
|
|
||||||
# To rebuild project do "make clean" then "make all".
|
|
||||||
#----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
# Following variables need to be set in <target>/Makefile:
|
|
||||||
# TARGET
|
|
||||||
# COMMON_DIR
|
|
||||||
# TARGET_DIR
|
|
||||||
# TARGET_SRC
|
|
||||||
# MCU
|
|
||||||
# F_CPU
|
|
||||||
|
|
||||||
|
|
||||||
# List C source files here. (C dependencies are automatically generated.)
|
|
||||||
SRC = tmk.c \
|
|
||||||
key_process.c \
|
|
||||||
usb_keyboard.c \
|
|
||||||
usb_mouse.c \
|
|
||||||
usb_debug.c \
|
|
||||||
usb.c \
|
|
||||||
jump_bootloader.c \
|
|
||||||
print.c \
|
print.c \
|
||||||
util.c
|
util.c
|
||||||
SRC += $(TARGET_SRC)
|
|
||||||
|
|
||||||
# C source file search path
|
|
||||||
VPATH = $(TARGET_DIR):$(COMMON_DIR)
|
|
||||||
|
|
||||||
|
|
||||||
# Output format. (can be srec, ihex, binary)
|
# Option modules
|
||||||
FORMAT = ihex
|
ifdef MOUSEKEY_ENABLE
|
||||||
|
SRC += mousekey.c
|
||||||
|
OPT_DEFS += -DMOUSEKEY_ENABLE
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef PS2_MOUSE_ENABLE
|
||||||
|
SRC += ps2.c \
|
||||||
|
ps2_mouse.c
|
||||||
|
OPT_DEFS += -DPS2_MOUSE_ENABLE
|
||||||
|
endif
|
||||||
|
|
||||||
# Object files directory
|
ifdef USB_EXTRA_ENABLE
|
||||||
# To put object files in current directory, use a dot (.), do NOT make
|
OPT_DEFS += -DUSB_EXTRA_ENABLE
|
||||||
# this an empty or blank macro!
|
endif
|
||||||
OBJDIR = .
|
|
||||||
|
|
||||||
|
ifdef USB_NKRO_ENABLE
|
||||||
|
OPT_DEFS += -DUSB_NKRO_ENABLE
|
||||||
|
endif
|
||||||
|
|
||||||
# List C++ source files here. (C dependencies are automatically generated.)
|
ifdef $(or MOUSEKEY_ENABLE, PS2_MOUSE_ENABLE)
|
||||||
CPPSRC =
|
OPT_DEFS += -DUSB_MOUSE_ENABLE
|
||||||
|
|
||||||
|
|
||||||
# List Assembler source files here.
|
|
||||||
# Make them always end in a capital .S. Files ending in a lowercase .s
|
|
||||||
# will not be considered source files but generated files (assembler
|
|
||||||
# output from the compiler), and will be deleted upon "make clean"!
|
|
||||||
# Even though the DOS/Win* filesystem matches both .s and .S the same,
|
|
||||||
# it will preserve the spelling of the filenames, and gcc itself does
|
|
||||||
# care about how the name is spelled on its command-line.
|
|
||||||
ASRC =
|
|
||||||
|
|
||||||
|
|
||||||
# Optimization level, can be [0, 1, 2, 3, s].
|
|
||||||
# 0 = turn off optimization. s = optimize for size.
|
|
||||||
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
|
|
||||||
OPT = s
|
|
||||||
|
|
||||||
|
|
||||||
# Debugging format.
|
|
||||||
# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
|
|
||||||
# AVR Studio 4.10 requires dwarf-2.
|
|
||||||
# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
|
|
||||||
DEBUG = dwarf-2
|
|
||||||
|
|
||||||
|
|
||||||
# List any extra directories to look for include files here.
|
|
||||||
# Each directory must be seperated by a space.
|
|
||||||
# Use forward slashes for directory separators.
|
|
||||||
# For a directory that has spaces, enclose it in quotes.
|
|
||||||
EXTRAINCDIRS = $(TARGET_DIR) $(COMMON_DIR)
|
|
||||||
|
|
||||||
|
|
||||||
# Compiler flag to set the C Standard level.
|
|
||||||
# c89 = "ANSI" C
|
|
||||||
# gnu89 = c89 plus GCC extensions
|
|
||||||
# c99 = ISO C99 standard (not yet fully implemented)
|
|
||||||
# gnu99 = c99 plus GCC extensions
|
|
||||||
CSTANDARD = -std=gnu99
|
|
||||||
|
|
||||||
|
|
||||||
# Place -D or -U options here for C sources
|
|
||||||
CDEFS = -DF_CPU=$(F_CPU)UL
|
|
||||||
CDEFS += -DDESCRIPTION=$(DESCRIPTION)
|
|
||||||
CDEFS += -DVENDOR_ID=$(VENDOR_ID)
|
|
||||||
CDEFS += -DPRODUCT_ID=$(PRODUCT_ID)
|
|
||||||
CDEFS += -DMANUFACTURER=$(MANUFACTURER)
|
|
||||||
CDEFS += -DPRODUCT=$(PRODUCT)
|
|
||||||
ifdef MOUSE_DELAY_TIME
|
|
||||||
CDEFS += -DMOUSE_DELAY_TIME=$(MOUSE_DELAY_TIME)
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
# Place -D or -U options here for ASM sources
|
include $(COMMON_DIR)/Makefile.rules
|
||||||
ADEFS = -DF_CPU=$(F_CPU)
|
|
||||||
ADEFS += -DDESCRIPTION=$(DESCRIPTION)
|
|
||||||
ADEFS += -DVENDOR_ID=$(VENDOR_ID)
|
|
||||||
ADEFS += -DPRODUCT_ID=$(PRODUCT_ID)
|
|
||||||
ADEFS += -DMANUFACTURER=$(MANUFACTURER)
|
|
||||||
ADEFS += -DPRODUCT=$(PRODUCT)
|
|
||||||
ifdef MOUSE_DELAY_TIME
|
|
||||||
ADEFS += -DMOUSE_DELAY_TIME=$(MOUSE_DELAY_TIME)
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
# Place -D or -U options here for C++ sources
|
|
||||||
CPPDEFS = -DF_CPU=$(F_CPU)UL -DDESCRIPTION=$(DESCRIPTION) -DVENDOR_ID=$(VENDOR_ID) -DPRODUCT_ID=$(PRODUCT_ID)
|
|
||||||
#CPPDEFS += -D__STDC_LIMIT_MACROS
|
|
||||||
#CPPDEFS += -D__STDC_CONSTANT_MACROS
|
|
||||||
CPPDEFS += -DDESCRIPTION=$(DESCRIPTION)
|
|
||||||
CPPDEFS += -DVENDOR_ID=$(VENDOR_ID)
|
|
||||||
CPPDEFS += -DPRODUCT_ID=$(PRODUCT_ID)
|
|
||||||
CPPDEFS += -DMANUFACTURER=$(MANUFACTURER)
|
|
||||||
CPPDEFS += -DPRODUCT=$(PRODUCT)
|
|
||||||
ifdef MOUSE_DELAY_TIME
|
|
||||||
CPPDEFS += -DMOUSE_DELAY_TIME=$(MOUSE_DELAY_TIME)
|
|
||||||
endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#---------------- Compiler Options C ----------------
|
|
||||||
# -g*: generate debugging information
|
|
||||||
# -O*: optimization level
|
|
||||||
# -f...: tuning, see GCC manual and avr-libc documentation
|
|
||||||
# -Wall...: warning level
|
|
||||||
# -Wa,...: tell GCC to pass this to the assembler.
|
|
||||||
# -adhlns...: create assembler listing
|
|
||||||
CFLAGS = -g$(DEBUG)
|
|
||||||
CFLAGS += $(CDEFS)
|
|
||||||
CFLAGS += -O$(OPT)
|
|
||||||
CFLAGS += -funsigned-char
|
|
||||||
CFLAGS += -funsigned-bitfields
|
|
||||||
CFLAGS += -ffunction-sections
|
|
||||||
CFLAGS += -fpack-struct
|
|
||||||
CFLAGS += -fshort-enums
|
|
||||||
CFLAGS += -Wall
|
|
||||||
CFLAGS += -Wstrict-prototypes
|
|
||||||
#CFLAGS += -mshort-calls
|
|
||||||
#CFLAGS += -fno-unit-at-a-time
|
|
||||||
#CFLAGS += -Wundef
|
|
||||||
#CFLAGS += -Wunreachable-code
|
|
||||||
#CFLAGS += -Wsign-compare
|
|
||||||
CFLAGS += -Wa,-adhlns=$(@:%.o=$(OBJDIR)/%.lst)
|
|
||||||
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
|
|
||||||
CFLAGS += $(CSTANDARD)
|
|
||||||
|
|
||||||
|
|
||||||
#---------------- Compiler Options C++ ----------------
|
|
||||||
# -g*: generate debugging information
|
|
||||||
# -O*: optimization level
|
|
||||||
# -f...: tuning, see GCC manual and avr-libc documentation
|
|
||||||
# -Wall...: warning level
|
|
||||||
# -Wa,...: tell GCC to pass this to the assembler.
|
|
||||||
# -adhlns...: create assembler listing
|
|
||||||
CPPFLAGS = -g$(DEBUG)
|
|
||||||
CPPFLAGS += $(CPPDEFS)
|
|
||||||
CPPFLAGS += -O$(OPT)
|
|
||||||
CPPFLAGS += -funsigned-char
|
|
||||||
CPPFLAGS += -funsigned-bitfields
|
|
||||||
CPPFLAGS += -fpack-struct
|
|
||||||
CPPFLAGS += -fshort-enums
|
|
||||||
CPPFLAGS += -fno-exceptions
|
|
||||||
CPPFLAGS += -Wall
|
|
||||||
CPPFLAGS += -Wundef
|
|
||||||
#CPPFLAGS += -mshort-calls
|
|
||||||
#CPPFLAGS += -fno-unit-at-a-time
|
|
||||||
#CPPFLAGS += -Wstrict-prototypes
|
|
||||||
#CPPFLAGS += -Wunreachable-code
|
|
||||||
#CPPFLAGS += -Wsign-compare
|
|
||||||
CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst)
|
|
||||||
CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
|
|
||||||
#CPPFLAGS += $(CSTANDARD)
|
|
||||||
|
|
||||||
|
|
||||||
#---------------- Assembler Options ----------------
|
|
||||||
# -Wa,...: tell GCC to pass this to the assembler.
|
|
||||||
# -adhlns: create listing
|
|
||||||
# -gstabs: have the assembler create line number information; note that
|
|
||||||
# for use in COFF files, additional information about filenames
|
|
||||||
# and function names needs to be present in the assembler source
|
|
||||||
# files -- see avr-libc docs [FIXME: not yet described there]
|
|
||||||
# -listing-cont-lines: Sets the maximum number of continuation lines of hex
|
|
||||||
# dump that will be displayed for a given single line of source input.
|
|
||||||
ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100
|
|
||||||
|
|
||||||
|
|
||||||
#---------------- Library Options ----------------
|
|
||||||
# Minimalistic printf version
|
|
||||||
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
|
|
||||||
|
|
||||||
# Floating point printf version (requires MATH_LIB = -lm below)
|
|
||||||
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
|
|
||||||
|
|
||||||
# If this is left blank, then it will use the Standard printf version.
|
|
||||||
PRINTF_LIB =
|
|
||||||
#PRINTF_LIB = $(PRINTF_LIB_MIN)
|
|
||||||
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)
|
|
||||||
|
|
||||||
|
|
||||||
# Minimalistic scanf version
|
|
||||||
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
|
|
||||||
|
|
||||||
# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
|
|
||||||
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
|
|
||||||
|
|
||||||
# If this is left blank, then it will use the Standard scanf version.
|
|
||||||
SCANF_LIB =
|
|
||||||
#SCANF_LIB = $(SCANF_LIB_MIN)
|
|
||||||
#SCANF_LIB = $(SCANF_LIB_FLOAT)
|
|
||||||
|
|
||||||
|
|
||||||
MATH_LIB = -lm
|
|
||||||
|
|
||||||
|
|
||||||
# List any extra directories to look for libraries here.
|
|
||||||
# Each directory must be seperated by a space.
|
|
||||||
# Use forward slashes for directory separators.
|
|
||||||
# For a directory that has spaces, enclose it in quotes.
|
|
||||||
EXTRALIBDIRS =
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#---------------- External Memory Options ----------------
|
|
||||||
|
|
||||||
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
|
|
||||||
# used for variables (.data/.bss) and heap (malloc()).
|
|
||||||
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
|
|
||||||
|
|
||||||
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
|
|
||||||
# only used for heap (malloc()).
|
|
||||||
#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
|
|
||||||
|
|
||||||
EXTMEMOPTS =
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#---------------- Linker Options ----------------
|
|
||||||
# -Wl,...: tell GCC to pass this to linker.
|
|
||||||
# -Map: create map file
|
|
||||||
# --cref: add cross reference to map file
|
|
||||||
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
|
|
||||||
LDFLAGS += -Wl,--relax
|
|
||||||
LDFLAGS += -Wl,--gc-sections
|
|
||||||
LDFLAGS += $(EXTMEMOPTS)
|
|
||||||
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
|
|
||||||
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
|
|
||||||
#LDFLAGS += -T linker_script.x
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#---------------- Programming Options (avrdude) ----------------
|
|
||||||
|
|
||||||
# Programming hardware
|
|
||||||
# Type: avrdude -c ?
|
|
||||||
# to get a full listing.
|
|
||||||
#
|
|
||||||
AVRDUDE_PROGRAMMER = stk500v2
|
|
||||||
|
|
||||||
# com1 = serial port. Use lpt1 to connect to parallel port.
|
|
||||||
AVRDUDE_PORT = com1 # programmer connected to serial device
|
|
||||||
|
|
||||||
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 $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
|
|
||||||
AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY)
|
|
||||||
AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE)
|
|
||||||
AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#---------------- Debugging Options ----------------
|
|
||||||
|
|
||||||
# For simulavr only - target MCU frequency.
|
|
||||||
DEBUG_MFREQ = $(F_CPU)
|
|
||||||
|
|
||||||
# Set the DEBUG_UI to either gdb or insight.
|
|
||||||
# DEBUG_UI = gdb
|
|
||||||
DEBUG_UI = insight
|
|
||||||
|
|
||||||
# Set the debugging back-end to either avarice, simulavr.
|
|
||||||
DEBUG_BACKEND = avarice
|
|
||||||
#DEBUG_BACKEND = simulavr
|
|
||||||
|
|
||||||
# GDB Init Filename.
|
|
||||||
GDBINIT_FILE = __avr_gdbinit
|
|
||||||
|
|
||||||
# When using avarice settings for the JTAG
|
|
||||||
JTAG_DEV = /dev/com1
|
|
||||||
|
|
||||||
# Debugging port used to communicate between GDB / avarice / simulavr.
|
|
||||||
DEBUG_PORT = 4242
|
|
||||||
|
|
||||||
# Debugging host used to communicate between GDB / avarice / simulavr, normally
|
|
||||||
# just set to localhost unless doing some sort of crazy debugging when
|
|
||||||
# avarice is running on a different computer.
|
|
||||||
DEBUG_HOST = localhost
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#============================================================================
|
|
||||||
|
|
||||||
|
|
||||||
# Define programs and commands.
|
|
||||||
SHELL = sh
|
|
||||||
CC = avr-gcc
|
|
||||||
OBJCOPY = avr-objcopy
|
|
||||||
OBJDUMP = avr-objdump
|
|
||||||
SIZE = avr-size
|
|
||||||
AR = avr-ar rcs
|
|
||||||
NM = avr-nm
|
|
||||||
AVRDUDE = avrdude
|
|
||||||
REMOVE = rm -f
|
|
||||||
REMOVEDIR = rm -rf
|
|
||||||
COPY = cp
|
|
||||||
WINSHELL = cmd
|
|
||||||
|
|
||||||
|
|
||||||
# Define Messages
|
|
||||||
# English
|
|
||||||
MSG_ERRORS_NONE = Errors: none
|
|
||||||
MSG_BEGIN = -------- begin --------
|
|
||||||
MSG_END = -------- end --------
|
|
||||||
MSG_SIZE_BEFORE = Size before:
|
|
||||||
MSG_SIZE_AFTER = Size after:
|
|
||||||
MSG_COFF = Converting to AVR COFF:
|
|
||||||
MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
|
|
||||||
MSG_FLASH = Creating load file for Flash:
|
|
||||||
MSG_EEPROM = Creating load file for EEPROM:
|
|
||||||
MSG_EXTENDED_LISTING = Creating Extended Listing:
|
|
||||||
MSG_SYMBOL_TABLE = Creating Symbol Table:
|
|
||||||
MSG_LINKING = Linking:
|
|
||||||
MSG_COMPILING = Compiling C:
|
|
||||||
MSG_COMPILING_CPP = Compiling C++:
|
|
||||||
MSG_ASSEMBLING = Assembling:
|
|
||||||
MSG_CLEANING = Cleaning project:
|
|
||||||
MSG_CREATING_LIBRARY = Creating library:
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Define all object files.
|
|
||||||
OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o)
|
|
||||||
|
|
||||||
# Define all listing files.
|
|
||||||
LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst)
|
|
||||||
|
|
||||||
|
|
||||||
# Compiler flags to generate dependency files.
|
|
||||||
GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d
|
|
||||||
|
|
||||||
|
|
||||||
# Combine all necessary flags and optional flags.
|
|
||||||
# Add target processor to flags.
|
|
||||||
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
|
|
||||||
ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)
|
|
||||||
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Default target.
|
|
||||||
all: begin gccversion sizebefore build sizeafter end
|
|
||||||
|
|
||||||
# Change the build target to build a HEX file or a library.
|
|
||||||
build: elf hex eep lss sym
|
|
||||||
#build: lib
|
|
||||||
|
|
||||||
|
|
||||||
elf: $(TARGET).elf
|
|
||||||
hex: $(TARGET).hex
|
|
||||||
eep: $(TARGET).eep
|
|
||||||
lss: $(TARGET).lss
|
|
||||||
sym: $(TARGET).sym
|
|
||||||
LIBNAME=lib$(TARGET).a
|
|
||||||
lib: $(LIBNAME)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Eye candy.
|
|
||||||
# AVR Studio 3.x does not check make's exit code but relies on
|
|
||||||
# the following magic strings to be generated by the compile job.
|
|
||||||
begin:
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_BEGIN)
|
|
||||||
|
|
||||||
end:
|
|
||||||
@echo $(MSG_END)
|
|
||||||
@echo
|
|
||||||
|
|
||||||
|
|
||||||
# Display size of file.
|
|
||||||
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
|
|
||||||
#ELFSIZE = $(SIZE) --mcu=$(MCU) --format=avr $(TARGET).elf
|
|
||||||
ELFSIZE = $(SIZE) $(TARGET).elf
|
|
||||||
|
|
||||||
sizebefore:
|
|
||||||
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \
|
|
||||||
2>/dev/null; echo; fi
|
|
||||||
|
|
||||||
sizeafter:
|
|
||||||
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \
|
|
||||||
2>/dev/null; echo; fi
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Display compiler version information.
|
|
||||||
gccversion :
|
|
||||||
@$(CC) --version
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Program the device.
|
|
||||||
program: $(TARGET).hex $(TARGET).eep
|
|
||||||
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM)
|
|
||||||
|
|
||||||
|
|
||||||
# Generate avr-gdb config/init file which does the following:
|
|
||||||
# define the reset signal, load the target file, connect to target, and set
|
|
||||||
# a breakpoint at main().
|
|
||||||
gdb-config:
|
|
||||||
@$(REMOVE) $(GDBINIT_FILE)
|
|
||||||
@echo define reset >> $(GDBINIT_FILE)
|
|
||||||
@echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
|
|
||||||
@echo end >> $(GDBINIT_FILE)
|
|
||||||
@echo file $(TARGET).elf >> $(GDBINIT_FILE)
|
|
||||||
@echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
|
|
||||||
ifeq ($(DEBUG_BACKEND),simulavr)
|
|
||||||
@echo load >> $(GDBINIT_FILE)
|
|
||||||
endif
|
|
||||||
@echo break main >> $(GDBINIT_FILE)
|
|
||||||
|
|
||||||
debug: gdb-config $(TARGET).elf
|
|
||||||
ifeq ($(DEBUG_BACKEND), avarice)
|
|
||||||
@echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
|
|
||||||
@$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
|
|
||||||
$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
|
|
||||||
@$(WINSHELL) /c pause
|
|
||||||
|
|
||||||
else
|
|
||||||
@$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
|
|
||||||
$(DEBUG_MFREQ) --port $(DEBUG_PORT)
|
|
||||||
endif
|
|
||||||
@$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
|
|
||||||
COFFCONVERT = $(OBJCOPY) --debugging
|
|
||||||
COFFCONVERT += --change-section-address .data-0x800000
|
|
||||||
COFFCONVERT += --change-section-address .bss-0x800000
|
|
||||||
COFFCONVERT += --change-section-address .noinit-0x800000
|
|
||||||
COFFCONVERT += --change-section-address .eeprom-0x810000
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
coff: $(TARGET).elf
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_COFF) $(TARGET).cof
|
|
||||||
$(COFFCONVERT) -O coff-avr $< $(TARGET).cof
|
|
||||||
|
|
||||||
|
|
||||||
extcoff: $(TARGET).elf
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_EXTENDED_COFF) $(TARGET).cof
|
|
||||||
$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Create final output files (.hex, .eep) from ELF output file.
|
|
||||||
%.hex: %.elf
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_FLASH) $@
|
|
||||||
$(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature $< $@
|
|
||||||
|
|
||||||
%.eep: %.elf
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_EEPROM) $@
|
|
||||||
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
|
|
||||||
--change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0
|
|
||||||
|
|
||||||
# Create extended listing file from ELF output file.
|
|
||||||
%.lss: %.elf
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_EXTENDED_LISTING) $@
|
|
||||||
$(OBJDUMP) -h -S -z $< > $@
|
|
||||||
|
|
||||||
# Create a symbol table from ELF output file.
|
|
||||||
%.sym: %.elf
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_SYMBOL_TABLE) $@
|
|
||||||
$(NM) -n $< > $@
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# Create library from object files.
|
|
||||||
.SECONDARY : $(TARGET).a
|
|
||||||
.PRECIOUS : $(OBJ)
|
|
||||||
%.a: $(OBJ)
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_CREATING_LIBRARY) $@
|
|
||||||
$(AR) $@ $(OBJ)
|
|
||||||
|
|
||||||
|
|
||||||
# Link: create ELF output file from object files.
|
|
||||||
.SECONDARY : $(TARGET).elf
|
|
||||||
.PRECIOUS : $(OBJ)
|
|
||||||
%.elf: $(OBJ)
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_LINKING) $@
|
|
||||||
$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)
|
|
||||||
|
|
||||||
|
|
||||||
# Compile: create object files from C source files.
|
|
||||||
$(OBJDIR)/%.o : %.c
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_COMPILING) $<
|
|
||||||
$(CC) -c $(ALL_CFLAGS) $< -o $@
|
|
||||||
|
|
||||||
|
|
||||||
# Compile: create object files from C++ source files.
|
|
||||||
$(OBJDIR)/%.o : %.cpp
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_COMPILING_CPP) $<
|
|
||||||
$(CC) -c $(ALL_CPPFLAGS) $< -o $@
|
|
||||||
|
|
||||||
|
|
||||||
# Compile: create assembler files from C source files.
|
|
||||||
%.s : %.c
|
|
||||||
$(CC) -S $(ALL_CFLAGS) $< -o $@
|
|
||||||
|
|
||||||
|
|
||||||
# Compile: create assembler files from C++ source files.
|
|
||||||
%.s : %.cpp
|
|
||||||
$(CC) -S $(ALL_CPPFLAGS) $< -o $@
|
|
||||||
|
|
||||||
|
|
||||||
# Assemble: create object files from assembler source files.
|
|
||||||
$(OBJDIR)/%.o : %.S
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_ASSEMBLING) $<
|
|
||||||
$(CC) -c $(ALL_ASFLAGS) $< -o $@
|
|
||||||
|
|
||||||
|
|
||||||
# Create preprocessed source for use in sending a bug report.
|
|
||||||
%.i : %.c
|
|
||||||
$(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@
|
|
||||||
|
|
||||||
|
|
||||||
# Target: clean project.
|
|
||||||
clean: begin clean_list end
|
|
||||||
|
|
||||||
clean_list :
|
|
||||||
@echo
|
|
||||||
@echo $(MSG_CLEANING)
|
|
||||||
$(REMOVE) $(TARGET).hex
|
|
||||||
$(REMOVE) $(TARGET).eep
|
|
||||||
$(REMOVE) $(TARGET).cof
|
|
||||||
$(REMOVE) $(TARGET).elf
|
|
||||||
$(REMOVE) $(TARGET).map
|
|
||||||
$(REMOVE) $(TARGET).sym
|
|
||||||
$(REMOVE) $(TARGET).lss
|
|
||||||
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o)
|
|
||||||
$(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst)
|
|
||||||
$(REMOVE) $(SRC:.c=.s)
|
|
||||||
$(REMOVE) $(SRC:.c=.d)
|
|
||||||
$(REMOVE) $(SRC:.c=.i)
|
|
||||||
$(REMOVEDIR) .dep
|
|
||||||
|
|
||||||
|
|
||||||
# Create object files directory
|
|
||||||
$(shell mkdir $(OBJDIR) 2>/dev/null)
|
|
||||||
|
|
||||||
|
|
||||||
# Include the dependency files.
|
|
||||||
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
|
|
||||||
|
|
||||||
|
|
||||||
# Listing of phony targets.
|
|
||||||
.PHONY : all begin finish end sizebefore sizeafter gccversion \
|
|
||||||
build elf hex eep lss sym coff extcoff \
|
|
||||||
clean clean_list program debug gdb-config
|
|
||||||
|
21
Makefile.pjrc
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
OPT_DEFS += -DHOST_PJRC
|
||||||
|
|
||||||
|
SRC = usb_keyboard.c \
|
||||||
|
usb_debug.c \
|
||||||
|
usb.c \
|
||||||
|
jump_bootloader.c
|
||||||
|
SRC += $(TARGET_SRC)
|
||||||
|
|
||||||
|
|
||||||
|
# C source file search path
|
||||||
|
VPATH = $(TARGET_DIR):$(COMMON_DIR):$(COMMON_DIR)/pjrc
|
||||||
|
|
||||||
|
|
||||||
|
# Option modules
|
||||||
|
ifdef $(or MOUSEKEY_ENABLE, PS2_MOUSE_ENABLE)
|
||||||
|
SRC += usb_mouse.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef USB_EXTRA_ENABLE
|
||||||
|
SRC += usb_extra.c
|
||||||
|
endif
|
547
Makefile.rules
Normal file
@ -0,0 +1,547 @@
|
|||||||
|
# Hey Emacs, this is a -*- makefile -*-
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
# WinAVR Makefile Template written by Eric B. Weddington, Jg Wunsch, et al.
|
||||||
|
#
|
||||||
|
# Released to the Public Domain
|
||||||
|
#
|
||||||
|
# Additional material for this makefile was written by:
|
||||||
|
# Peter Fleury
|
||||||
|
# Tim Henigan
|
||||||
|
# Colin O'Flynn
|
||||||
|
# Reiner Patommel
|
||||||
|
# Markus Pfaff
|
||||||
|
# Sander Pool
|
||||||
|
# Frederik Rouleau
|
||||||
|
# Carlos Lamas
|
||||||
|
#
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
# On command line:
|
||||||
|
#
|
||||||
|
# make all = Make software.
|
||||||
|
#
|
||||||
|
# make clean = Clean out built project files.
|
||||||
|
#
|
||||||
|
# make coff = Convert ELF to AVR COFF.
|
||||||
|
#
|
||||||
|
# make extcoff = Convert ELF to AVR Extended COFF.
|
||||||
|
#
|
||||||
|
# make program = Download the hex file to the device, using avrdude.
|
||||||
|
# Please customize the avrdude settings below first!
|
||||||
|
#
|
||||||
|
# make debug = Start either simulavr or avarice as specified for debugging,
|
||||||
|
# with avr-gdb or avr-insight as the front end for debugging.
|
||||||
|
#
|
||||||
|
# make filename.s = Just compile filename.c into the assembler code only.
|
||||||
|
#
|
||||||
|
# make filename.i = Create a preprocessed source file for use in submitting
|
||||||
|
# bug reports to the GCC project.
|
||||||
|
#
|
||||||
|
# To rebuild project do "make clean" then "make all".
|
||||||
|
#----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
# Output format. (can be srec, ihex, binary)
|
||||||
|
FORMAT = ihex
|
||||||
|
|
||||||
|
|
||||||
|
# Object files directory
|
||||||
|
# To put object files in current directory, use a dot (.), do NOT make
|
||||||
|
# this an empty or blank macro!
|
||||||
|
OBJDIR = obj_$(TARGET)
|
||||||
|
|
||||||
|
|
||||||
|
# Optimization level, can be [0, 1, 2, 3, s].
|
||||||
|
# 0 = turn off optimization. s = optimize for size.
|
||||||
|
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
|
||||||
|
OPT = s
|
||||||
|
|
||||||
|
|
||||||
|
# Debugging format.
|
||||||
|
# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs.
|
||||||
|
# AVR Studio 4.10 requires dwarf-2.
|
||||||
|
# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run.
|
||||||
|
DEBUG = dwarf-2
|
||||||
|
|
||||||
|
|
||||||
|
# List any extra directories to look for include files here.
|
||||||
|
# Each directory must be seperated by a space.
|
||||||
|
# Use forward slashes for directory separators.
|
||||||
|
# For a directory that has spaces, enclose it in quotes.
|
||||||
|
EXTRAINCDIRS = $(subst :, ,$(VPATH))
|
||||||
|
|
||||||
|
|
||||||
|
# Compiler flag to set the C Standard level.
|
||||||
|
# c89 = "ANSI" C
|
||||||
|
# gnu89 = c89 plus GCC extensions
|
||||||
|
# c99 = ISO C99 standard (not yet fully implemented)
|
||||||
|
# gnu99 = c99 plus GCC extensions
|
||||||
|
CSTANDARD = -std=gnu99
|
||||||
|
|
||||||
|
|
||||||
|
# Place -D or -U options here for C sources
|
||||||
|
CDEFS = -DF_CPU=$(F_CPU)UL
|
||||||
|
CDEFS += $(OPT_DEFS)
|
||||||
|
|
||||||
|
|
||||||
|
# Place -D or -U options here for ASM sources
|
||||||
|
ADEFS = -DF_CPU=$(F_CPU)
|
||||||
|
ADEFS += $(OPT_DEFS)
|
||||||
|
|
||||||
|
|
||||||
|
# Place -D or -U options here for C++ sources
|
||||||
|
CPPDEFS = -DF_CPU=$(F_CPU)UL
|
||||||
|
#CPPDEFS += -D__STDC_LIMIT_MACROS
|
||||||
|
#CPPDEFS += -D__STDC_CONSTANT_MACROS
|
||||||
|
CPPDEFS += $(OPT_DEFS)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- Compiler Options C ----------------
|
||||||
|
# -g*: generate debugging information
|
||||||
|
# -O*: optimization level
|
||||||
|
# -f...: tuning, see GCC manual and avr-libc documentation
|
||||||
|
# -Wall...: warning level
|
||||||
|
# -Wa,...: tell GCC to pass this to the assembler.
|
||||||
|
# -adhlns...: create assembler listing
|
||||||
|
CFLAGS = -g$(DEBUG)
|
||||||
|
CFLAGS += $(CDEFS)
|
||||||
|
CFLAGS += -O$(OPT)
|
||||||
|
CFLAGS += -funsigned-char
|
||||||
|
CFLAGS += -funsigned-bitfields
|
||||||
|
CFLAGS += -ffunction-sections
|
||||||
|
CFLAGS += -fpack-struct
|
||||||
|
CFLAGS += -fshort-enums
|
||||||
|
CFLAGS += -Wall
|
||||||
|
CFLAGS += -Wstrict-prototypes
|
||||||
|
#CFLAGS += -mshort-calls
|
||||||
|
#CFLAGS += -fno-unit-at-a-time
|
||||||
|
#CFLAGS += -Wundef
|
||||||
|
#CFLAGS += -Wunreachable-code
|
||||||
|
#CFLAGS += -Wsign-compare
|
||||||
|
CFLAGS += -Wa,-adhlns=$(@:%.o=%.lst)
|
||||||
|
CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
|
||||||
|
CFLAGS += $(CSTANDARD)
|
||||||
|
CFLAGS += -include $(CONFIG_H)
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- Compiler Options C++ ----------------
|
||||||
|
# -g*: generate debugging information
|
||||||
|
# -O*: optimization level
|
||||||
|
# -f...: tuning, see GCC manual and avr-libc documentation
|
||||||
|
# -Wall...: warning level
|
||||||
|
# -Wa,...: tell GCC to pass this to the assembler.
|
||||||
|
# -adhlns...: create assembler listing
|
||||||
|
CPPFLAGS = -g$(DEBUG)
|
||||||
|
CPPFLAGS += $(CPPDEFS)
|
||||||
|
CPPFLAGS += -O$(OPT)
|
||||||
|
CPPFLAGS += -funsigned-char
|
||||||
|
CPPFLAGS += -funsigned-bitfields
|
||||||
|
CPPFLAGS += -fpack-struct
|
||||||
|
CPPFLAGS += -fshort-enums
|
||||||
|
CPPFLAGS += -fno-exceptions
|
||||||
|
CPPFLAGS += -Wall
|
||||||
|
CPPFLAGS += -Wundef
|
||||||
|
#CPPFLAGS += -mshort-calls
|
||||||
|
#CPPFLAGS += -fno-unit-at-a-time
|
||||||
|
#CPPFLAGS += -Wstrict-prototypes
|
||||||
|
#CPPFLAGS += -Wunreachable-code
|
||||||
|
#CPPFLAGS += -Wsign-compare
|
||||||
|
CPPFLAGS += -Wa,-adhlns=$(@:%.o=%.lst)
|
||||||
|
CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS))
|
||||||
|
#CPPFLAGS += $(CSTANDARD)
|
||||||
|
CPPFLAGS += -include $(CONFIG_H)
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- Assembler Options ----------------
|
||||||
|
# -Wa,...: tell GCC to pass this to the assembler.
|
||||||
|
# -adhlns: create listing
|
||||||
|
# -gstabs: have the assembler create line number information; note that
|
||||||
|
# for use in COFF files, additional information about filenames
|
||||||
|
# and function names needs to be present in the assembler source
|
||||||
|
# files -- see avr-libc docs [FIXME: not yet described there]
|
||||||
|
# -listing-cont-lines: Sets the maximum number of continuation lines of hex
|
||||||
|
# dump that will be displayed for a given single line of source input.
|
||||||
|
ASFLAGS = $(ADEFS) -Wa,-adhlns=$(@:%.o=%.lst),-gstabs,--listing-cont-lines=100
|
||||||
|
ASFLAGS += -include $(CONFIG_H)
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- Library Options ----------------
|
||||||
|
# Minimalistic printf version
|
||||||
|
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
|
||||||
|
|
||||||
|
# Floating point printf version (requires MATH_LIB = -lm below)
|
||||||
|
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
|
||||||
|
|
||||||
|
# If this is left blank, then it will use the Standard printf version.
|
||||||
|
PRINTF_LIB =
|
||||||
|
#PRINTF_LIB = $(PRINTF_LIB_MIN)
|
||||||
|
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)
|
||||||
|
|
||||||
|
|
||||||
|
# Minimalistic scanf version
|
||||||
|
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
|
||||||
|
|
||||||
|
# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
|
||||||
|
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
|
||||||
|
|
||||||
|
# If this is left blank, then it will use the Standard scanf version.
|
||||||
|
SCANF_LIB =
|
||||||
|
#SCANF_LIB = $(SCANF_LIB_MIN)
|
||||||
|
#SCANF_LIB = $(SCANF_LIB_FLOAT)
|
||||||
|
|
||||||
|
|
||||||
|
MATH_LIB = -lm
|
||||||
|
|
||||||
|
|
||||||
|
# List any extra directories to look for libraries here.
|
||||||
|
# Each directory must be seperated by a space.
|
||||||
|
# Use forward slashes for directory separators.
|
||||||
|
# For a directory that has spaces, enclose it in quotes.
|
||||||
|
EXTRALIBDIRS =
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- External Memory Options ----------------
|
||||||
|
|
||||||
|
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
|
||||||
|
# used for variables (.data/.bss) and heap (malloc()).
|
||||||
|
#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff
|
||||||
|
|
||||||
|
# 64 KB of external RAM, starting after internal RAM (ATmega128!),
|
||||||
|
# only used for heap (malloc()).
|
||||||
|
#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff
|
||||||
|
|
||||||
|
EXTMEMOPTS =
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- Linker Options ----------------
|
||||||
|
# -Wl,...: tell GCC to pass this to linker.
|
||||||
|
# -Map: create map file
|
||||||
|
# --cref: add cross reference to map file
|
||||||
|
#
|
||||||
|
# Comennt out "--relax" option to avoid a error such:
|
||||||
|
# (.vectors+0x30): relocation truncated to fit: R_AVR_13_PCREL against symbol `__vector_12'
|
||||||
|
#
|
||||||
|
LDFLAGS = -Wl,-Map=$(TARGET).map,--cref
|
||||||
|
LDFLAGS += -Wl,--relax
|
||||||
|
LDFLAGS += -Wl,--gc-sections
|
||||||
|
LDFLAGS += $(EXTMEMOPTS)
|
||||||
|
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
|
||||||
|
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
|
||||||
|
#LDFLAGS += -T linker_script.x
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- Debugging Options ----------------
|
||||||
|
|
||||||
|
# For simulavr only - target MCU frequency.
|
||||||
|
DEBUG_MFREQ = $(F_CPU)
|
||||||
|
|
||||||
|
# Set the DEBUG_UI to either gdb or insight.
|
||||||
|
# DEBUG_UI = gdb
|
||||||
|
DEBUG_UI = insight
|
||||||
|
|
||||||
|
# Set the debugging back-end to either avarice, simulavr.
|
||||||
|
DEBUG_BACKEND = avarice
|
||||||
|
#DEBUG_BACKEND = simulavr
|
||||||
|
|
||||||
|
# GDB Init Filename.
|
||||||
|
GDBINIT_FILE = __avr_gdbinit
|
||||||
|
|
||||||
|
# When using avarice settings for the JTAG
|
||||||
|
JTAG_DEV = /dev/com1
|
||||||
|
|
||||||
|
# Debugging port used to communicate between GDB / avarice / simulavr.
|
||||||
|
DEBUG_PORT = 4242
|
||||||
|
|
||||||
|
# Debugging host used to communicate between GDB / avarice / simulavr, normally
|
||||||
|
# just set to localhost unless doing some sort of crazy debugging when
|
||||||
|
# avarice is running on a different computer.
|
||||||
|
DEBUG_HOST = localhost
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
# Define programs and commands.
|
||||||
|
SHELL = sh
|
||||||
|
CC = avr-gcc
|
||||||
|
OBJCOPY = avr-objcopy
|
||||||
|
OBJDUMP = avr-objdump
|
||||||
|
SIZE = avr-size
|
||||||
|
AR = avr-ar rcs
|
||||||
|
NM = avr-nm
|
||||||
|
REMOVE = rm -f
|
||||||
|
REMOVEDIR = rmdir
|
||||||
|
COPY = cp
|
||||||
|
WINSHELL = cmd
|
||||||
|
|
||||||
|
|
||||||
|
# Define Messages
|
||||||
|
# English
|
||||||
|
MSG_ERRORS_NONE = Errors: none
|
||||||
|
MSG_BEGIN = -------- begin --------
|
||||||
|
MSG_END = -------- end --------
|
||||||
|
MSG_SIZE_BEFORE = Size before:
|
||||||
|
MSG_SIZE_AFTER = Size after:
|
||||||
|
MSG_COFF = Converting to AVR COFF:
|
||||||
|
MSG_EXTENDED_COFF = Converting to AVR Extended COFF:
|
||||||
|
MSG_FLASH = Creating load file for Flash:
|
||||||
|
MSG_EEPROM = Creating load file for EEPROM:
|
||||||
|
MSG_EXTENDED_LISTING = Creating Extended Listing:
|
||||||
|
MSG_SYMBOL_TABLE = Creating Symbol Table:
|
||||||
|
MSG_LINKING = Linking:
|
||||||
|
MSG_COMPILING = Compiling C:
|
||||||
|
MSG_COMPILING_CPP = Compiling C++:
|
||||||
|
MSG_ASSEMBLING = Assembling:
|
||||||
|
MSG_CLEANING = Cleaning project:
|
||||||
|
MSG_CREATING_LIBRARY = Creating library:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Define all object files.
|
||||||
|
OBJ = $(patsubst %.c,$(OBJDIR)/%.o,$(patsubst %.cpp,$(OBJDIR)/%.o,$(patsubst %.S,$(OBJDIR)/%.o,$(SRC))))
|
||||||
|
|
||||||
|
# Define all listing files.
|
||||||
|
LST = $(patsubst %.c,$(OBJDIR)/%.lst,$(patsubst %.cpp,$(OBJDIR)/%.lst,$(patsubst %.S,$(OBJDIR)/%.lst,$(SRC))))
|
||||||
|
|
||||||
|
|
||||||
|
# Compiler flags to generate dependency files.
|
||||||
|
GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d
|
||||||
|
|
||||||
|
|
||||||
|
# Combine all necessary flags and optional flags.
|
||||||
|
# Add target processor to flags.
|
||||||
|
ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS)
|
||||||
|
ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS)
|
||||||
|
ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Default target.
|
||||||
|
all: begin gccversion sizebefore build sizeafter end
|
||||||
|
|
||||||
|
# Change the build target to build a HEX file or a library.
|
||||||
|
build: elf hex eep lss sym
|
||||||
|
#build: lib
|
||||||
|
|
||||||
|
|
||||||
|
elf: $(TARGET).elf
|
||||||
|
hex: $(TARGET).hex
|
||||||
|
eep: $(TARGET).eep
|
||||||
|
lss: $(TARGET).lss
|
||||||
|
sym: $(TARGET).sym
|
||||||
|
LIBNAME=lib$(TARGET).a
|
||||||
|
lib: $(LIBNAME)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Eye candy.
|
||||||
|
# AVR Studio 3.x does not check make's exit code but relies on
|
||||||
|
# the following magic strings to be generated by the compile job.
|
||||||
|
begin:
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_BEGIN)
|
||||||
|
|
||||||
|
end:
|
||||||
|
@echo $(MSG_END)
|
||||||
|
@echo
|
||||||
|
|
||||||
|
|
||||||
|
# Display size of file.
|
||||||
|
HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex
|
||||||
|
#ELFSIZE = $(SIZE) --mcu=$(MCU) --format=avr $(TARGET).elf
|
||||||
|
ELFSIZE = $(SIZE) $(TARGET).elf
|
||||||
|
|
||||||
|
sizebefore:
|
||||||
|
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \
|
||||||
|
2>/dev/null; echo; fi
|
||||||
|
|
||||||
|
sizeafter:
|
||||||
|
@if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \
|
||||||
|
2>/dev/null; echo; fi
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Display compiler version information.
|
||||||
|
gccversion :
|
||||||
|
@$(CC) --version
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Program the device.
|
||||||
|
program: $(TARGET).hex $(TARGET).eep
|
||||||
|
$(PROGRAM_CMD)
|
||||||
|
|
||||||
|
|
||||||
|
# Generate avr-gdb config/init file which does the following:
|
||||||
|
# define the reset signal, load the target file, connect to target, and set
|
||||||
|
# a breakpoint at main().
|
||||||
|
gdb-config:
|
||||||
|
@$(REMOVE) $(GDBINIT_FILE)
|
||||||
|
@echo define reset >> $(GDBINIT_FILE)
|
||||||
|
@echo SIGNAL SIGHUP >> $(GDBINIT_FILE)
|
||||||
|
@echo end >> $(GDBINIT_FILE)
|
||||||
|
@echo file $(TARGET).elf >> $(GDBINIT_FILE)
|
||||||
|
@echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE)
|
||||||
|
ifeq ($(DEBUG_BACKEND),simulavr)
|
||||||
|
@echo load >> $(GDBINIT_FILE)
|
||||||
|
endif
|
||||||
|
@echo break main >> $(GDBINIT_FILE)
|
||||||
|
|
||||||
|
debug: gdb-config $(TARGET).elf
|
||||||
|
ifeq ($(DEBUG_BACKEND), avarice)
|
||||||
|
@echo Starting AVaRICE - Press enter when "waiting to connect" message displays.
|
||||||
|
@$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \
|
||||||
|
$(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT)
|
||||||
|
@$(WINSHELL) /c pause
|
||||||
|
|
||||||
|
else
|
||||||
|
@$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \
|
||||||
|
$(DEBUG_MFREQ) --port $(DEBUG_PORT)
|
||||||
|
endif
|
||||||
|
@$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB.
|
||||||
|
COFFCONVERT = $(OBJCOPY) --debugging
|
||||||
|
COFFCONVERT += --change-section-address .data-0x800000
|
||||||
|
COFFCONVERT += --change-section-address .bss-0x800000
|
||||||
|
COFFCONVERT += --change-section-address .noinit-0x800000
|
||||||
|
COFFCONVERT += --change-section-address .eeprom-0x810000
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
coff: $(TARGET).elf
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_COFF) $(TARGET).cof
|
||||||
|
$(COFFCONVERT) -O coff-avr $< $(TARGET).cof
|
||||||
|
|
||||||
|
|
||||||
|
extcoff: $(TARGET).elf
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_EXTENDED_COFF) $(TARGET).cof
|
||||||
|
$(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Create final output files (.hex, .eep) from ELF output file.
|
||||||
|
%.hex: %.elf
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_FLASH) $@
|
||||||
|
$(OBJCOPY) -O $(FORMAT) -R .eeprom -R .fuse -R .lock -R .signature $< $@
|
||||||
|
|
||||||
|
%.eep: %.elf
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_EEPROM) $@
|
||||||
|
-$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \
|
||||||
|
--change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0
|
||||||
|
|
||||||
|
# Create extended listing file from ELF output file.
|
||||||
|
%.lss: %.elf
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_EXTENDED_LISTING) $@
|
||||||
|
$(OBJDUMP) -h -S -z $< > $@
|
||||||
|
|
||||||
|
# Create a symbol table from ELF output file.
|
||||||
|
%.sym: %.elf
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_SYMBOL_TABLE) $@
|
||||||
|
$(NM) -n $< > $@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Create library from object files.
|
||||||
|
.SECONDARY : $(TARGET).a
|
||||||
|
.PRECIOUS : $(OBJ)
|
||||||
|
%.a: $(OBJ)
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_CREATING_LIBRARY) $@
|
||||||
|
$(AR) $@ $(OBJ)
|
||||||
|
|
||||||
|
|
||||||
|
# Link: create ELF output file from object files.
|
||||||
|
.SECONDARY : $(TARGET).elf
|
||||||
|
.PRECIOUS : $(OBJ)
|
||||||
|
%.elf: $(OBJ)
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_LINKING) $@
|
||||||
|
$(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS)
|
||||||
|
|
||||||
|
|
||||||
|
# Compile: create object files from C source files.
|
||||||
|
$(OBJDIR)/%.o : %.c
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_COMPILING) $<
|
||||||
|
$(CC) -c $(ALL_CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
|
||||||
|
# Compile: create object files from C++ source files.
|
||||||
|
$(OBJDIR)/%.o : %.cpp
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_COMPILING_CPP) $<
|
||||||
|
$(CC) -c $(ALL_CPPFLAGS) $< -o $@
|
||||||
|
|
||||||
|
|
||||||
|
# Compile: create assembler files from C source files.
|
||||||
|
%.s : %.c
|
||||||
|
$(CC) -S $(ALL_CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
|
||||||
|
# Compile: create assembler files from C++ source files.
|
||||||
|
%.s : %.cpp
|
||||||
|
$(CC) -S $(ALL_CPPFLAGS) $< -o $@
|
||||||
|
|
||||||
|
|
||||||
|
# Assemble: create object files from assembler source files.
|
||||||
|
$(OBJDIR)/%.o : %.S
|
||||||
|
@echo
|
||||||
|
@echo $(MSG_ASSEMBLING) $<
|
||||||
|
$(CC) -c $(ALL_ASFLAGS) $< -o $@
|
||||||
|
|
||||||
|
|
||||||
|
# Create preprocessed source for use in sending a bug report.
|
||||||
|
%.i : %.c
|
||||||
|
$(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@
|
||||||
|
|
||||||
|
|
||||||
|
# Target: clean project.
|
||||||
|
clean: begin clean_list end
|
||||||
|
|
||||||
|
clean_list :
|
||||||
|
@echo
|
||||||
|
$(REMOVE) $(TARGET).hex
|
||||||
|
$(REMOVE) $(TARGET).eep
|
||||||
|
$(REMOVE) $(TARGET).cof
|
||||||
|
$(REMOVE) $(TARGET).elf
|
||||||
|
$(REMOVE) $(TARGET).map
|
||||||
|
$(REMOVE) $(TARGET).sym
|
||||||
|
$(REMOVE) $(TARGET).lss
|
||||||
|
$(REMOVE) $(OBJ)
|
||||||
|
$(REMOVE) $(LST)
|
||||||
|
$(REMOVE) $(OBJ:.o=.s)
|
||||||
|
$(REMOVE) $(OBJ:.o=.i)
|
||||||
|
$(REMOVE) -r .dep
|
||||||
|
$(REMOVEDIR) $(OBJDIR)
|
||||||
|
|
||||||
|
|
||||||
|
# Create object files directory
|
||||||
|
$(shell mkdir $(OBJDIR) 2>/dev/null)
|
||||||
|
|
||||||
|
|
||||||
|
# Include the dependency files.
|
||||||
|
-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*)
|
||||||
|
|
||||||
|
|
||||||
|
# Listing of phony targets.
|
||||||
|
.PHONY : all begin finish end sizebefore sizeafter gccversion \
|
||||||
|
build elf hex eep lss sym coff extcoff \
|
||||||
|
clean clean_list program debug gdb-config
|
||||||
|
|
11
Makefile.vusb
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
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
|
194
README
@ -1,63 +1,128 @@
|
|||||||
t.m.k. Keyboard Firmware
|
t.m.k. Keyboard Firmware
|
||||||
========================
|
========================
|
||||||
|
This is keyboard firmware for Teensy(AVR USB MCU) and V-USB board.
|
||||||
|
|
||||||
|
source code repository:
|
||||||
http://github.com/tmk/tmk_keyboard
|
http://github.com/tmk/tmk_keyboard
|
||||||
|
|
||||||
This is keyboard firmware for PFU HHKB style keyboard and Teensy/Teensy++ 2.0.
|
This firmware is used in following projects:
|
||||||
OS see this as composite device which has keyboard and mouse.
|
HHKB mod: http://geekhack.org/showwiki.php?title=Island:12047
|
||||||
|
Macway mod: http://geekhack.org/showwiki.php?title=Island:11930
|
||||||
|
PS2 to USB: http://geekhack.org/showwiki.php?title=Island:14618
|
||||||
|
ADB to USB: http://geekhack.org/showwiki.php?title=Island:14290
|
||||||
|
|
||||||
The project is heavily based on PJRC USB Keyboard/Mouse Example and
|
The project is heavily based on PJRC USB Keyboard/Mouse Example and
|
||||||
owes a debt to preceding keyboard firmware projects.
|
owes a debt to preceding keyboard firmware projects.
|
||||||
|
http://www.pjrc.com/teensy
|
||||||
|
|
||||||
|
|
||||||
Version
|
Features
|
||||||
-------
|
--------
|
||||||
0.1 2010/08/23
|
Mouse key
|
||||||
It works as normal keyboard.
|
control mouse cursor from keyboard.
|
||||||
It is for modified Macway keyboard(TP-999KB-E).
|
System Control Key
|
||||||
|
Power Down, Sleep, Wake Up & USB Remote Wake up
|
||||||
|
Media Control Key
|
||||||
|
Volume Down/Up, Mute
|
||||||
|
USB NKRO
|
||||||
|
send 120 keys(+ 8 modifiers) at most simultaneously.
|
||||||
|
PS/2 mouse support
|
||||||
|
integrate PS/2 mouse(TrackPoint) into keyboard as composite device.
|
||||||
|
|
||||||
1.0 2010/10/02
|
|
||||||
keyboard has mouse key now.
|
|
||||||
keyboard with layers.(see keymap.c)
|
|
||||||
FN_1(right cmd):
|
|
||||||
vi style layer
|
|
||||||
FN_2(next to right shift):
|
|
||||||
HHKB style layer
|
|
||||||
FN_3(left bottom):
|
|
||||||
h j k l: mouse move
|
|
||||||
a s d spc: mouse buttons
|
|
||||||
m ,: mouse wheel
|
|
||||||
|
|
||||||
1.1 2010/10/08
|
Limitations
|
||||||
Matrix wiring changed for casing.
|
-----------
|
||||||
(and my Teensy PD3 seems to be latchuped and unusable. :<)
|
|
||||||
|
|
||||||
1.2 2010/10/13
|
|
||||||
HHKB support
|
|
||||||
horizontal mouse wheel support
|
|
||||||
change keymaps
|
|
||||||
|
|
||||||
2.0 2010/10/27
|
Files & Directories
|
||||||
HHKB/Macway support merged
|
-------------------
|
||||||
|
Target:
|
||||||
|
hhkb/ keyboard controller for PFU HHKB pro
|
||||||
|
macway/ keyboard controller for Macway mod
|
||||||
|
ps2_usb/ PS2 to USB keyboard converter
|
||||||
|
adb_usb/ ADB to USB keyboard converter
|
||||||
|
|
||||||
|
USB Protocol Stack:
|
||||||
|
pjrc/ PJRC USB stack
|
||||||
|
vusb/ V-USB USB stack
|
||||||
|
ps2.[ch] PS/2 protocol
|
||||||
|
adb.[ch] ADB protocol
|
||||||
|
|
||||||
|
|
||||||
Build
|
Build
|
||||||
-----
|
-----
|
||||||
Compiling sources need AVR GCC, AVR Libc and GNU make.(You can use WinAVR on Windows.)
|
To compile needs AVR GCC, AVR Libc and GNU make.
|
||||||
|
You can use WinAVR on Windows. http://winavr.sourceforge.net/
|
||||||
|
|
||||||
$ cd <target> (hhkb or macway)
|
$ cd <target>
|
||||||
$ make
|
$ make
|
||||||
|
|
||||||
|
The firmware will be compiled as a file tmk_<target>.hex.
|
||||||
|
|
||||||
Debuging
|
|
||||||
--------
|
Build your own firmware
|
||||||
Debug print is on if 4 keys are pressed during booting.
|
-----------------------
|
||||||
|
Copying exsistent target(macway) is easy way.
|
||||||
|
1. Copy contens of macway/ to your own target directory.
|
||||||
|
2. Edit Makefile. See next section.
|
||||||
|
3. Edit config.h. See next section.
|
||||||
|
4. Edit matrix.c. You will need to fix followings at least.
|
||||||
|
matrix_init()
|
||||||
|
matrix_scan()
|
||||||
|
read_col()
|
||||||
|
unselect_rows()
|
||||||
|
select_row()
|
||||||
|
5. Edit keymap.c. NOTE: It is not final design and a bit messy.
|
||||||
|
You will need to fix followings at least.
|
||||||
|
KEYMAP
|
||||||
|
fn_layer[]
|
||||||
|
fn_keycode[]
|
||||||
|
keymaps[]
|
||||||
|
6. Build.
|
||||||
|
|
||||||
|
If you have a build error like following, comment out "--relax" option in Makefile.common.
|
||||||
|
(.vectors+0x30): relocation truncated to fit: R_AVR_13_PCREL against symbol `__vector_12'
|
||||||
|
|
||||||
|
|
||||||
|
Build Options
|
||||||
|
-------------
|
||||||
|
<target>/Makefile:
|
||||||
|
1. Set target name for your firmware.
|
||||||
|
TARGET = tmk_<target>
|
||||||
|
2. Choose a MCU and its frequency.
|
||||||
|
MCU = atmega32u4 # Teensy 2.0
|
||||||
|
#MCU = at90usb1286 # Teensy++ 2.0
|
||||||
|
F_CPU = 16000000
|
||||||
|
3. Choose optional modules as needed. Comment out to disable optional modules.
|
||||||
|
MOUSEKEY_ENABLE = yes # Mouse keys
|
||||||
|
PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support
|
||||||
|
USB_EXTRA_ENABLE = yes # Enhanced feature for Windows(Audio control and System control)
|
||||||
|
USB_NKRO_ENABLE = yes # USB Nkey Rollover
|
||||||
|
|
||||||
|
<target>/config.h:
|
||||||
|
1. USB vendor/product ID and device description
|
||||||
|
#define VENDOR_ID 0xFEED
|
||||||
|
#define PRODUCT_ID 0xBEEF
|
||||||
|
/* device description */
|
||||||
|
#define MANUFACTURER t.m.k.
|
||||||
|
#define PRODUCT Macway mod
|
||||||
|
#define DESCRIPTION t.m.k. keyboard firmware for Macway mod
|
||||||
|
2. Keyboard matrix configuration
|
||||||
|
#define MATRIX_ROWS 8
|
||||||
|
#define MATRIX_COLS 8
|
||||||
|
#define MATRIX_HAS_GHOST
|
||||||
|
3. Mouse keys configuration if needed.
|
||||||
|
4. PS/2 mouse configuration if needed.
|
||||||
|
|
||||||
|
|
||||||
|
Debuging & Rescue
|
||||||
|
-----------------
|
||||||
Use PJRC's hid_listen.exe to see debug messages.
|
Use PJRC's hid_listen.exe to see debug messages.
|
||||||
|
Press <COMMAND> + H to debug menu.
|
||||||
|
(see config.h for <COMMAND> key combination.)
|
||||||
|
|
||||||
|
Pressing any 3 keys when connected enables debug output.
|
||||||
AVR Target board
|
Pressing any 4 keys when connected makes bootloader comes up.
|
||||||
----------------
|
|
||||||
Teensy/Teensy++
|
|
||||||
http://www.pjrc.com/teensy
|
|
||||||
|
|
||||||
|
|
||||||
Projects related
|
Projects related
|
||||||
@ -83,59 +148,4 @@ ps2avr
|
|||||||
http://sourceforge.net/projects/ps2avr/
|
http://sourceforge.net/projects/ps2avr/
|
||||||
|
|
||||||
|
|
||||||
TODO & ideas
|
|
||||||
------------
|
|
||||||
licensing notes(GPL)
|
|
||||||
I think GPL is not infringement of PJRC license.
|
|
||||||
souce code cleaning
|
|
||||||
sleep&wakeup
|
|
||||||
debouncing logic
|
|
||||||
will be coded when bouncing occurs.
|
|
||||||
bouncing doesnt occur on my ALPS switch so far.
|
|
||||||
scan rate is too slow?(to be measure)
|
|
||||||
layer switching
|
|
||||||
time before switching
|
|
||||||
timeout when not used during specific time
|
|
||||||
|
|
||||||
Trackpoint(PS/2)
|
|
||||||
receive PS/2 signal from TrackPoint
|
|
||||||
send USB HID report
|
|
||||||
Thinkpad keyboard support
|
|
||||||
turn keyboard to USB keyboard/mouse composite device
|
|
||||||
setting menu(configure without changing firmware)
|
|
||||||
console for display
|
|
||||||
keymap/layer setting
|
|
||||||
mouse speed/acceleration
|
|
||||||
matrix display
|
|
||||||
PS/2 keyboard mode
|
|
||||||
with USB to PS/2 dumb adapter(possible?)
|
|
||||||
AT90USBKEY support
|
|
||||||
and other AVR USB boards
|
|
||||||
|
|
||||||
DONE:
|
|
||||||
support for HHKB pro matrix signal
|
|
||||||
exchange controller board with teensy
|
|
||||||
2010/10/11
|
|
||||||
keymap
|
|
||||||
Matias half keyboard style
|
|
||||||
2010/10/23
|
|
||||||
souce code cleaning
|
|
||||||
2010/10/23
|
|
||||||
debug on/off
|
|
||||||
debug off by default
|
|
||||||
pressing keys during booting
|
|
||||||
2010/10/23
|
|
||||||
mouse horizontal wheel
|
|
||||||
http://www.microchip.com/forums/tm.aspx?high=&m=391435&mpage=1#391521
|
|
||||||
http://www.keil.com/forum/15671/
|
|
||||||
http://www.microsoft.com/whdc/device/input/wheel.mspx
|
|
||||||
2010/10/13
|
|
||||||
debug on/off
|
|
||||||
Fn key conbination during normal operation
|
|
||||||
matrix print on/off
|
|
||||||
key print on/off
|
|
||||||
mouse print on/off
|
|
||||||
2010/10/26
|
|
||||||
|
|
||||||
|
|
||||||
EOF
|
EOF
|
||||||
|
160
USB_NKRO.txt
Normal file
@ -0,0 +1,160 @@
|
|||||||
|
USB NKRO MEMO
|
||||||
|
=============
|
||||||
|
2010/12/09
|
||||||
|
|
||||||
|
|
||||||
|
References
|
||||||
|
----------
|
||||||
|
USB - boot mode, NKRO, compatibility, etc...
|
||||||
|
http://geekhack.org/showthread.php?t=13162
|
||||||
|
NKey Rollover - Overview, Testing Methodology, and Results
|
||||||
|
http://geekhack.org/showwiki.php?title=NKey+Rollover+-+Overview+Testing+Methodology+and+Results
|
||||||
|
dfj's NKRO(2010/06)
|
||||||
|
http://geekhack.org/showpost.php?p=191195&postcount=251
|
||||||
|
http://geekhack.org/showthread.php?p=204389#post204389
|
||||||
|
|
||||||
|
|
||||||
|
Terminogy
|
||||||
|
---------
|
||||||
|
NKRO
|
||||||
|
ghost
|
||||||
|
matrix
|
||||||
|
mechanical with diodes
|
||||||
|
membrane
|
||||||
|
|
||||||
|
|
||||||
|
OS Support Status
|
||||||
|
-----------------
|
||||||
|
USB NKRO is possible *without* a custom driver.
|
||||||
|
At least following OSes supports.
|
||||||
|
Windows7 64bit
|
||||||
|
WindowsXP
|
||||||
|
Windows2000 SP4
|
||||||
|
Ubuntu10.4(Linux 2.6)
|
||||||
|
MacOSX(To be tested)
|
||||||
|
|
||||||
|
|
||||||
|
Custom Driver for USB NKRO
|
||||||
|
--------------------------
|
||||||
|
NOT NEEDED
|
||||||
|
at least when using fllowing report formats on Windows, Linux or MacOSX.
|
||||||
|
|
||||||
|
|
||||||
|
USB NKRO methods
|
||||||
|
----------------
|
||||||
|
1. Virtual keyboards
|
||||||
|
Keyboard can increase its KRO by using virtual keyboards with Standard or Extended report.
|
||||||
|
If the keyboard has 2 virtual keyboard with Standard report(6KRO), it gets 12KRO.
|
||||||
|
Using this method means the keyboard is a composite device.
|
||||||
|
|
||||||
|
2. Exteded report
|
||||||
|
It needs large report size for this method to achive NKRO.
|
||||||
|
If a keyboard has 101keys, it needs 103byte report. It seems to be inefficient.
|
||||||
|
|
||||||
|
3. Bitmap report
|
||||||
|
If the keyboard has less than 128keys, 16byte report will be enough for NKRO.
|
||||||
|
The 16byte report seems to be reasonable cost to get NKRO.
|
||||||
|
|
||||||
|
|
||||||
|
Report Format
|
||||||
|
-------------
|
||||||
|
Other report formats than followings are possible, though these format are typical one.
|
||||||
|
|
||||||
|
1. Standard 8bytes
|
||||||
|
modifiers(bitmap) 1byte
|
||||||
|
reserved 1byte(not used)
|
||||||
|
keys(array) 1byte*6
|
||||||
|
Standard report can send 6keys plus 8modifiers simultaneously.
|
||||||
|
Standard report is used by most keyboards in the marketplace.
|
||||||
|
Standard report is identical to boot protocol report.
|
||||||
|
Standard report is hard to suffer from compatibility problems.
|
||||||
|
|
||||||
|
2. Extended standard 16,32,64bytes
|
||||||
|
modifiers(bitmap) 1byte
|
||||||
|
reserved 1byte(not used)
|
||||||
|
keys(array) 1byte*(14,32,62)
|
||||||
|
Extended report can send N-keys by using N+2bytes.
|
||||||
|
Extended report is expected to be compatible with boot protocol.
|
||||||
|
|
||||||
|
3. Bitmap 16,32,64bytes
|
||||||
|
keys(bitmap) (16,32)bytes
|
||||||
|
Bitmap report can send at most 128keys by 16bytes and 256keys by 32bytes.
|
||||||
|
Bitmap report can achieve USB NKRO efficiently in terms of report size.
|
||||||
|
Bitmap report needs a deliberation for boot protocol implementation.
|
||||||
|
Bitmap report descriptor sample:
|
||||||
|
0x05, 0x01, // Usage Page (Generic Desktop),
|
||||||
|
0x09, 0x06, // Usage (Keyboard),
|
||||||
|
0xA1, 0x01, // Collection (Application),
|
||||||
|
// bitmap of modifiers
|
||||||
|
0x75, 0x01, // Report Size (1),
|
||||||
|
0x95, 0x08, // Report Count (8),
|
||||||
|
0x05, 0x07, // Usage Page (Key Codes),
|
||||||
|
0x19, 0xE0, // Usage Minimum (224),
|
||||||
|
0x29, 0xE7, // Usage Maximum (231),
|
||||||
|
0x15, 0x00, // Logical Minimum (0),
|
||||||
|
0x25, 0x01, // Logical Maximum (1),
|
||||||
|
0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte
|
||||||
|
// LED output report
|
||||||
|
0x95, 0x05, // Report Count (5),
|
||||||
|
0x75, 0x01, // Report Size (1),
|
||||||
|
0x05, 0x08, // Usage Page (LEDs),
|
||||||
|
0x19, 0x01, // Usage Minimum (1),
|
||||||
|
0x29, 0x05, // Usage Maximum (5),
|
||||||
|
0x91, 0x02, // Output (Data, Variable, Absolute),
|
||||||
|
0x95, 0x01, // Report Count (1),
|
||||||
|
0x75, 0x03, // Report Size (3),
|
||||||
|
0x91, 0x03, // Output (Constant),
|
||||||
|
// bitmap of keys
|
||||||
|
0x95, (REPORT_BYTES-1)*8, // Report Count (),
|
||||||
|
0x75, 0x01, // Report Size (1),
|
||||||
|
0x15, 0x00, // Logical Minimum (0),
|
||||||
|
0x25, 0x01, // Logical Maximum(1),
|
||||||
|
0x05, 0x07, // Usage Page (Key Codes),
|
||||||
|
0x19, 0x00, // Usage Minimum (0),
|
||||||
|
0x29, (REPORT_BYTES-1)*8-1, // Usage Maximum (),
|
||||||
|
0x81, 0x02, // Input (Data, Variable, Absolute),
|
||||||
|
0xc0 // End Collection
|
||||||
|
where REPORT_BYTES is a report size in bytes.
|
||||||
|
|
||||||
|
|
||||||
|
Considerations
|
||||||
|
--------------
|
||||||
|
Compatibility
|
||||||
|
boot protocol
|
||||||
|
minor/old system
|
||||||
|
Some BIOS doesn't send SET_PROTCOL request, a keyboard can't switch to boot protocol mode.
|
||||||
|
This may cuase a problem on a keyboard which uses other report than Standard.
|
||||||
|
Reactivity
|
||||||
|
USB polling time
|
||||||
|
OS/Driver processing time
|
||||||
|
|
||||||
|
|
||||||
|
Windows Problem
|
||||||
|
---------------
|
||||||
|
1. Windows accepts only 6keys in case of Standard report.
|
||||||
|
It should be able to send 6keys plus 8modifiers.
|
||||||
|
2. Windows accepts only 10keys in case of 16bytes Extended report.
|
||||||
|
It should be able to send 14keys plus 8modifiers.
|
||||||
|
3. Windows accepts only 18keys in case of 32bytes Extended report.
|
||||||
|
It should be able to send 30keys plus 8modifiers.
|
||||||
|
If keys are pressed in excess of the number, wrong keys are registered on Windows.
|
||||||
|
|
||||||
|
This problem will be reportedly fixed soon.(2010/12/05)
|
||||||
|
http://forums.anandtech.com/showpost.php?p=30873364&postcount=17
|
||||||
|
|
||||||
|
|
||||||
|
Tools for testing NKRO
|
||||||
|
----------------------
|
||||||
|
Browser App:
|
||||||
|
http://www.microsoft.com/appliedsciences/content/projects/KeyboardGhostingDemo.aspx
|
||||||
|
http://random.xem.us/rollover.html
|
||||||
|
|
||||||
|
Windows:
|
||||||
|
AquaKeyTest.exe http://geekhack.org/showthread.php?t=6643
|
||||||
|
|
||||||
|
Linux:
|
||||||
|
xkeycaps
|
||||||
|
xev
|
||||||
|
showkeys
|
||||||
|
|
||||||
|
EOF
|
406
adb.c
Normal file
@ -0,0 +1,406 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2011 Jun WAKO <wakojun@gmail.com>
|
||||||
|
|
||||||
|
This software is licensed with a Modified BSD License.
|
||||||
|
All of this is supposed to be Free Software, Open Source, DFSG-free,
|
||||||
|
GPL-compatible, and OK to use in both free and proprietary applications.
|
||||||
|
Additions and corrections to this file are welcome.
|
||||||
|
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
* Neither the name of the copyright holders nor the names of
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include "adb.h"
|
||||||
|
|
||||||
|
|
||||||
|
static inline void data_lo(void);
|
||||||
|
static inline void data_hi(void);
|
||||||
|
static inline bool data_in(void);
|
||||||
|
#ifdef ADB_PSW_BIT
|
||||||
|
static inline void psw_lo(void);
|
||||||
|
static inline void psw_hi(void);
|
||||||
|
static inline bool psw_in(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void attention(void);
|
||||||
|
static inline void place_bit0(void);
|
||||||
|
static inline void place_bit1(void);
|
||||||
|
static inline void send_byte(uint8_t data);
|
||||||
|
static inline bool read_bit(void);
|
||||||
|
static inline uint8_t read_byte(void);
|
||||||
|
static inline uint8_t wait_data_lo(uint8_t us);
|
||||||
|
static inline uint8_t wait_data_hi(uint8_t us);
|
||||||
|
|
||||||
|
|
||||||
|
void adb_host_init(void)
|
||||||
|
{
|
||||||
|
data_hi();
|
||||||
|
#ifdef ADB_PSW_BIT
|
||||||
|
psw_hi();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ADB_PSW_BIT
|
||||||
|
bool adb_host_psw(void)
|
||||||
|
{
|
||||||
|
return psw_in();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint16_t adb_host_kbd_recv(void)
|
||||||
|
{
|
||||||
|
uint16_t data = 0;
|
||||||
|
attention();
|
||||||
|
send_byte(0x2C); // Addr:Keyboard(0010), Cmd:Talk(11), Register0(00)
|
||||||
|
place_bit0(); // Stopbit(0)
|
||||||
|
if (!wait_data_lo(0xFF)) // Tlt/Stop to Start(140-260us)
|
||||||
|
return 0; // No data to send
|
||||||
|
if (!read_bit()) // Startbit(1)
|
||||||
|
return -2;
|
||||||
|
data = read_byte();
|
||||||
|
data = (data<<8) | read_byte();
|
||||||
|
if (read_bit()) // Stopbit(0)
|
||||||
|
return -3;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send state of LEDs
|
||||||
|
void adb_host_kbd_led(uint8_t led)
|
||||||
|
{
|
||||||
|
attention();
|
||||||
|
send_byte(0x2A); // Addr:Keyboard(0010), Cmd:Listen(10), Register2(10)
|
||||||
|
place_bit0(); // Stopbit(0)
|
||||||
|
_delay_us(200); // Tlt/Stop to Start
|
||||||
|
place_bit1(); // Startbit(1)
|
||||||
|
send_byte(0); // send upper byte (not used)
|
||||||
|
send_byte(led&0x07); // send lower byte (bit2: ScrollLock, bit1: CapsLock, bit0: NumLock)
|
||||||
|
place_bit0(); // Stopbit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void data_lo()
|
||||||
|
{
|
||||||
|
ADB_DDR |= (1<<ADB_DATA_BIT);
|
||||||
|
ADB_PORT &= ~(1<<ADB_DATA_BIT);
|
||||||
|
}
|
||||||
|
static inline void data_hi()
|
||||||
|
{
|
||||||
|
ADB_PORT |= (1<<ADB_DATA_BIT);
|
||||||
|
ADB_DDR &= ~(1<<ADB_DATA_BIT);
|
||||||
|
}
|
||||||
|
static inline bool data_in()
|
||||||
|
{
|
||||||
|
ADB_PORT |= (1<<ADB_DATA_BIT);
|
||||||
|
ADB_DDR &= ~(1<<ADB_DATA_BIT);
|
||||||
|
return ADB_PIN&(1<<ADB_DATA_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ADB_PSW_BIT
|
||||||
|
static inline void psw_lo()
|
||||||
|
{
|
||||||
|
ADB_DDR |= (1<<ADB_PSW_BIT);
|
||||||
|
ADB_PORT &= ~(1<<ADB_PSW_BIT);
|
||||||
|
}
|
||||||
|
static inline void psw_hi()
|
||||||
|
{
|
||||||
|
ADB_PORT |= (1<<ADB_PSW_BIT);
|
||||||
|
ADB_DDR &= ~(1<<ADB_PSW_BIT);
|
||||||
|
}
|
||||||
|
static inline bool psw_in()
|
||||||
|
{
|
||||||
|
ADB_PORT |= (1<<ADB_PSW_BIT);
|
||||||
|
ADB_DDR &= ~(1<<ADB_PSW_BIT);
|
||||||
|
return ADB_PIN&(1<<ADB_PSW_BIT);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void attention(void)
|
||||||
|
{
|
||||||
|
data_lo();
|
||||||
|
_delay_us(700);
|
||||||
|
place_bit1();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void place_bit0(void)
|
||||||
|
{
|
||||||
|
data_lo();
|
||||||
|
_delay_us(65);
|
||||||
|
data_hi();
|
||||||
|
_delay_us(35);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void place_bit1(void)
|
||||||
|
{
|
||||||
|
data_lo();
|
||||||
|
_delay_us(35);
|
||||||
|
data_hi();
|
||||||
|
_delay_us(65);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void send_byte(uint8_t data)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
if (data&(0x80>>i))
|
||||||
|
place_bit1();
|
||||||
|
else
|
||||||
|
place_bit0();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool read_bit(void)
|
||||||
|
{
|
||||||
|
// ADB Bit Cells
|
||||||
|
//
|
||||||
|
// bit0: ______~~~
|
||||||
|
// 65 :35us
|
||||||
|
//
|
||||||
|
// bit1: ___~~~~~~
|
||||||
|
// 35 :65us
|
||||||
|
//
|
||||||
|
// bit0 low time: 60-70% of bit cell(42-91us)
|
||||||
|
// bit1 low time: 30-40% of bit cell(21-52us)
|
||||||
|
// bit cell time: 70-130us
|
||||||
|
// [from Apple IIgs Hardware Reference Second Edition]
|
||||||
|
//
|
||||||
|
// After 55us if data line is low/high then bit is 0/1.
|
||||||
|
// Too simple to rely on?
|
||||||
|
bool bit;
|
||||||
|
wait_data_lo(75); // wait the beginning of bit cell
|
||||||
|
_delay_us(55);
|
||||||
|
bit = data_in();
|
||||||
|
wait_data_hi(36); // wait high part of bit cell
|
||||||
|
return bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t read_byte(void)
|
||||||
|
{
|
||||||
|
uint8_t data = 0;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
data <<= 1;
|
||||||
|
if (read_bit())
|
||||||
|
data = data | 1;
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t wait_data_lo(uint8_t us)
|
||||||
|
{
|
||||||
|
while (data_in() && us) {
|
||||||
|
_delay_us(1);
|
||||||
|
us--;
|
||||||
|
}
|
||||||
|
return us;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t wait_data_hi(uint8_t us)
|
||||||
|
{
|
||||||
|
while (!data_in() && us) {
|
||||||
|
_delay_us(1);
|
||||||
|
us--;
|
||||||
|
}
|
||||||
|
return us;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
ADB Protocol
|
||||||
|
============
|
||||||
|
|
||||||
|
Resources
|
||||||
|
---------
|
||||||
|
ADB - The Untold Story: Space Aliens Ate My Mouse
|
||||||
|
http://developer.apple.com/legacy/mac/library/#technotes/hw/hw_01.html
|
||||||
|
Apple IIgs Hardware Reference Second Edition [p80(Chapter6 p121)]
|
||||||
|
ftp://ftp.apple.asimov.net/pub/apple_II/documentation/Apple%20IIgs%20Hardware%20Reference.pdf
|
||||||
|
ADB Keycode
|
||||||
|
http://72.0.193.250/Documentation/macppc/adbkeycodes/
|
||||||
|
http://m0115.web.fc2.com/m0115.jpg
|
||||||
|
[Inside Macintosh volume V, pages 191-192]
|
||||||
|
ADB Signaling
|
||||||
|
http://kbdbabel.sourceforge.net/doc/kbd_signaling_pcxt_ps2_adb.pdf
|
||||||
|
ADB Overview & History
|
||||||
|
http://en.wikipedia.org/wiki/Apple_Desktop_Bus
|
||||||
|
Microchip Application Note: ADB device(with code for PIC16C)
|
||||||
|
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=1824&appnote=en011062
|
||||||
|
AVR ATtiny2131 ADB to PS/2 converter(Japanese)
|
||||||
|
http://hp.vector.co.jp/authors/VA000177/html/KeyBoardA5DEA5CBA5A2II.html
|
||||||
|
|
||||||
|
|
||||||
|
Pinouts
|
||||||
|
-------
|
||||||
|
ADB female socket from the front:
|
||||||
|
__________
|
||||||
|
| | <--- top
|
||||||
|
| 4o o3 |
|
||||||
|
|2o o1|
|
||||||
|
| == |
|
||||||
|
|________| <--- bottom
|
||||||
|
| | <--- 4pins
|
||||||
|
|
||||||
|
|
||||||
|
ADB female socket from bottom:
|
||||||
|
|
||||||
|
========== <--- front
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
|2o o1|
|
||||||
|
|4o o3|
|
||||||
|
---------- <--- back
|
||||||
|
|
||||||
|
1: Data
|
||||||
|
2: Power SW(low when press Power key)
|
||||||
|
3: Vcc(5V)
|
||||||
|
4: GND
|
||||||
|
|
||||||
|
|
||||||
|
Commands
|
||||||
|
--------
|
||||||
|
ADB command is 1byte and consists of 4bit-address, 2bit-command
|
||||||
|
type and 2bit-register. The commands are always sent by Host.
|
||||||
|
|
||||||
|
Command format:
|
||||||
|
7 6 5 4 3 2 1 0
|
||||||
|
| | | |------------ address
|
||||||
|
| |-------- command type
|
||||||
|
| |---- register
|
||||||
|
|
||||||
|
bits commands
|
||||||
|
------------------------------------------------------
|
||||||
|
- - - - 0 0 0 0 Send Request(reset all devices)
|
||||||
|
A A A A 0 0 0 1 Flush(reset a device)
|
||||||
|
- - - - 0 0 1 0 Reserved
|
||||||
|
- - - - 0 0 1 1 Reserved
|
||||||
|
- - - - 0 1 - - Reserved
|
||||||
|
A A A A 1 0 R R Listen(write to a device)
|
||||||
|
A A A A 1 1 R R Talk(read from a device)
|
||||||
|
|
||||||
|
The command to read keycodes from keyboard is 0x2C which
|
||||||
|
consist of keyboard address 2 and Talk against register 0.
|
||||||
|
|
||||||
|
Address:
|
||||||
|
2: keyboard
|
||||||
|
3: mice
|
||||||
|
|
||||||
|
Registers:
|
||||||
|
0: application(keyobard uses this to store its data.)
|
||||||
|
1: application
|
||||||
|
2: application(keyboard uses this for LEDs and state of modifiers)
|
||||||
|
3: status and command
|
||||||
|
|
||||||
|
|
||||||
|
Communication
|
||||||
|
-------------
|
||||||
|
This is a minimum information for keyboard communication.
|
||||||
|
See "Resources" for detail.
|
||||||
|
|
||||||
|
Signaling:
|
||||||
|
|
||||||
|
~~~~____________~~||||||||||||__~~~~~_~~|||||||||||||||__~~~~
|
||||||
|
|
||||||
|
|800us | |7 Command 0| | | |15-64 Data 0|Stopbit(0)
|
||||||
|
+Attention | | | +Startbit(1)
|
||||||
|
+Startbit(1) | +Tlt(140-260us)
|
||||||
|
+stopbit(0)
|
||||||
|
|
||||||
|
Bit cells:
|
||||||
|
|
||||||
|
bit0: ______~~~
|
||||||
|
65 :35us
|
||||||
|
|
||||||
|
bit1: ___~~~~~~
|
||||||
|
35 :65us
|
||||||
|
|
||||||
|
bit0 low time: 60-70% of bit cell(42-91us)
|
||||||
|
bit1 low time: 30-40% of bit cell(21-52us)
|
||||||
|
bit cell time: 70-130us
|
||||||
|
[from Apple IIgs Hardware Reference Second Edition]
|
||||||
|
|
||||||
|
Criterion for bit0/1:
|
||||||
|
After 55us if line is low/high then bit is 0/1.
|
||||||
|
|
||||||
|
Attention & start bit:
|
||||||
|
Host asserts low in 560-1040us then places start bit(1).
|
||||||
|
|
||||||
|
Tlt(Stop to Start):
|
||||||
|
Bus stays high in 140-260us then device places start bit(1).
|
||||||
|
|
||||||
|
Global reset:
|
||||||
|
Host asserts low in 2.8-5.2ms. All devices are forced to reset.
|
||||||
|
|
||||||
|
Send request from device(Srq):
|
||||||
|
Device can request to send at commad(Global only?) stop bit.
|
||||||
|
keep low for 300us to request.
|
||||||
|
|
||||||
|
|
||||||
|
Keyboard Data(Register0)
|
||||||
|
This 16bit data can contains two keycodes and two released flags.
|
||||||
|
First keycode is palced in upper byte. When one keyocode is sent,
|
||||||
|
lower byte is 0xFF.
|
||||||
|
Release flag is 1 when key is released.
|
||||||
|
|
||||||
|
1514 . . . . . 8 7 6 . . . . . 0
|
||||||
|
| | | | | | | | | +-+-+-+-+-+-+- Keycode2
|
||||||
|
| | | | | | | | +--------------- Released2(1 when the key is released)
|
||||||
|
| +-+-+-+-+-+-+----------------- Keycode1
|
||||||
|
+------------------------------- Released1(1 when the key is released)
|
||||||
|
|
||||||
|
Keycodes:
|
||||||
|
Scancode consists of 7bit keycode and 1bit release flag.
|
||||||
|
Device can send two keycodes at once. If just one keycode is sent
|
||||||
|
keycode1 contains it and keyocode2 is 0xFF.
|
||||||
|
|
||||||
|
Power switch:
|
||||||
|
You can read the state from PSW line(active low) however
|
||||||
|
the switch has a special scancode 0x7F7F, so you can
|
||||||
|
also read from Data line. It uses 0xFFFF for release scancode.
|
||||||
|
Release code seems to delay about some 100ms. Due to Mac soft power?
|
||||||
|
|
||||||
|
Keyboard LEDs & state of keys(Register2)
|
||||||
|
This register hold current state of three LEDs and nine keys.
|
||||||
|
The state of LEDs can be changed by sending Listen command.
|
||||||
|
|
||||||
|
1514 . . . . . . 7 6 5 . 3 2 1 0
|
||||||
|
| | | | | | | | | | | | | | | +- LED1(NumLock)
|
||||||
|
| | | | | | | | | | | | | | +--- LED2(CapsLock)
|
||||||
|
| | | | | | | | | | | | | +----- LED3(ScrollLock)
|
||||||
|
| | | | | | | | | | +-+-+------- Reserved
|
||||||
|
| | | | | | | | | +------------- ScrollLock
|
||||||
|
| | | | | | | | +--------------- NumLock
|
||||||
|
| | | | | | | +----------------- Apple/Command
|
||||||
|
| | | | | | +------------------- Option
|
||||||
|
| | | | | +--------------------- Shift
|
||||||
|
| | | | +----------------------- Control
|
||||||
|
| | | +------------------------- Reset/Power
|
||||||
|
| | +--------------------------- CapsLock
|
||||||
|
| +----------------------------- Delete
|
||||||
|
+------------------------------- Reserved
|
||||||
|
|
||||||
|
END_OF_ADB
|
||||||
|
*/
|
19
adb.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef ADB_H
|
||||||
|
#define ADB_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#if !(defined(ADB_PORT) && \
|
||||||
|
defined(ADB_PIN) && \
|
||||||
|
defined(ADB_DDR) && \
|
||||||
|
defined(ADB_DATA_BIT))
|
||||||
|
# error "ADB port setting is required in config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// ADB host
|
||||||
|
void adb_host_init(void);
|
||||||
|
bool adb_host_psw(void);
|
||||||
|
uint16_t adb_host_kbd_recv(void);
|
||||||
|
void adb_host_kbd_led(uint8_t led);
|
||||||
|
|
||||||
|
#endif
|
52
adb_usb/Makefile
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
# Target file name (without extension).
|
||||||
|
TARGET = adb_usb
|
||||||
|
|
||||||
|
# Directory common source filess exist
|
||||||
|
COMMON_DIR = ..
|
||||||
|
|
||||||
|
# Directory keyboard dependent files exist
|
||||||
|
TARGET_DIR = .
|
||||||
|
|
||||||
|
# keyboard dependent files
|
||||||
|
TARGET_SRC = main_pjrc.c \
|
||||||
|
keymap.c \
|
||||||
|
matrix.c \
|
||||||
|
led.c \
|
||||||
|
adb.c
|
||||||
|
|
||||||
|
CONFIG_H = config.h
|
||||||
|
|
||||||
|
|
||||||
|
# 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 = at90usb162 # Teensy 1.0
|
||||||
|
MCU = atmega32u4 # Teensy 2.0
|
||||||
|
#MCU = at90usb646 # Teensy++ 1.0
|
||||||
|
#MCU = at90usb1286 # Teensy++ 2.0
|
||||||
|
|
||||||
|
|
||||||
|
# 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 = 16000000
|
||||||
|
|
||||||
|
|
||||||
|
# Build Options
|
||||||
|
# comment out to disable the options.
|
||||||
|
#
|
||||||
|
MOUSEKEY_ENABLE = yes # Mouse keys
|
||||||
|
#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support
|
||||||
|
USB_EXTRA_ENABLE = yes # Audio control and System control
|
||||||
|
#USB_NKRO_ENABLE = yes # USB Nkey Rollover
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- Programming Options --------------------------
|
||||||
|
PROGRAM_CMD = teensy_loader_cli -mmcu=$(MCU) -w -v $(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
include $(COMMON_DIR)/Makefile.pjrc
|
||||||
|
include $(COMMON_DIR)/Makefile.common
|
62
adb_usb/README
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
ADB to USB keyboard converter
|
||||||
|
=============================
|
||||||
|
http://geekhack.org/showwiki.php?title=Island:14290
|
||||||
|
|
||||||
|
This firmware converts ADB keyboard protocol to USB.
|
||||||
|
|
||||||
|
|
||||||
|
Build
|
||||||
|
-----
|
||||||
|
0. Connect ADB keyboard to Teensy by 3 lines(Vcc, GND, Data).
|
||||||
|
You need a external pull-up resistor on DATA line in most case,
|
||||||
|
in particular when you want to use a long or coiled cable.
|
||||||
|
This converter uses AVR's internal pull-up, but it seems to be too weak.
|
||||||
|
The external pull-up resistor is strongly recommended.
|
||||||
|
PSW line is optional. See ADB.txt for details.
|
||||||
|
1. Define following macros for ADB connection in config.h:
|
||||||
|
ADB_PORT
|
||||||
|
ADB_PIN
|
||||||
|
ADB_DDR
|
||||||
|
ADB_DATA_BIT
|
||||||
|
ADB_PSW_BIT
|
||||||
|
2. make
|
||||||
|
3. program Teensy.
|
||||||
|
|
||||||
|
|
||||||
|
Keymap
|
||||||
|
------
|
||||||
|
You can change a keymap by editing code of keymap.c like following.
|
||||||
|
This is a keymap for AEK, however, also used for other keyboards.
|
||||||
|
How to define the keymap is probably obvious. You can find key
|
||||||
|
symbols in usb_keycodes.h.
|
||||||
|
If you want to define some keymaps than just one, see hhkb/keymap.c and
|
||||||
|
macway/keymap.c as examples. Keymap(layer) switching may needs a bit of
|
||||||
|
effort at this time.
|
||||||
|
|
||||||
|
/* Default Layer: plain keymap
|
||||||
|
* ,---. ,---------------. ,---------------. ,---------------. ,-----------. ,---.
|
||||||
|
* |Esc| |F1 |F2 |F3 |F4 | |F5 |F6 |F7 |F8 | |F9 |F10|F11|F12| |PrS|ScL|Pau| |Pwr|
|
||||||
|
* `---' `---------------' `---------------' `---------------' `-----------' `---'
|
||||||
|
* ,-----------------------------------------------------------. ,-----------. ,---------------.
|
||||||
|
* | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backspa| |Ins|Hom|PgU| |NmL| =| /| *|
|
||||||
|
* |-----------------------------------------------------------| |-----------| |---------------|
|
||||||
|
* |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| |Del|End|PgD| | 7| 8| 9| -|
|
||||||
|
* |-----------------------------------------------------------| `-----------' |---------------|
|
||||||
|
* |CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Return | | 4| 5| 6| +|
|
||||||
|
* |-----------------------------------------------------------| ,---. |---------------|
|
||||||
|
* |Shift | Z| X| C| V| B| N| M| ,| ,| /|Shift | |Up | | 1| 2| 3| |
|
||||||
|
* |-----------------------------------------------------------| ,-----------. |-----------|Ent|
|
||||||
|
* |Ctrl |Gui |Alt | Space | | | | |Lef|Dow|Rig| | 0| .| |
|
||||||
|
* `-----------------------------------------------------------' `-----------' `---------------'
|
||||||
|
*/
|
||||||
|
KEYMAP(
|
||||||
|
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, PWR,
|
||||||
|
GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,EQL, PSLS,PAST,
|
||||||
|
TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, DEL, END, PGDN, P7, P8, P9, PMNS,
|
||||||
|
CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT, ENT, P4, P5, P6, PPLS,
|
||||||
|
LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, UP, P1, P2, P3,
|
||||||
|
LCTL,LGUI,LALT, SPC, LEFT,DOWN,RGHT, P0, PDOT,PENT
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
EOF
|
51
adb_usb/config.h
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#ifndef CONFIG_H
|
||||||
|
#define CONFIG_H
|
||||||
|
|
||||||
|
/* controller configuration */
|
||||||
|
#include "controller_teensy.h"
|
||||||
|
|
||||||
|
#define VENDOR_ID 0xFEED
|
||||||
|
#define PRODUCT_ID 0x0ADB
|
||||||
|
#define MANUFACTURER t.m.k.
|
||||||
|
#define PRODUCT ADB keyboard converter
|
||||||
|
#define DESCRIPTION convert ADB keyboard to USB
|
||||||
|
|
||||||
|
/* matrix size */
|
||||||
|
#define MATRIX_ROWS 16 // keycode bit: 3-0
|
||||||
|
#define MATRIX_COLS 8 // keycode bit: 6-4
|
||||||
|
|
||||||
|
|
||||||
|
/* key combination for command */
|
||||||
|
#define IS_COMMAND() ( \
|
||||||
|
keyboard_report->mods == (BIT_LSHIFT | BIT_LCTRL | BIT_LALT | BIT_LGUI) || \
|
||||||
|
keyboard_report->mods == (BIT_LSHIFT | BIT_RSHIFT) \
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
/* mouse keys */
|
||||||
|
#ifdef MOUSEKEY_ENABLE
|
||||||
|
# define MOUSEKEY_DELAY_TIME 192
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* PS/2 mouse */
|
||||||
|
#ifdef PS2_MOUSE_ENABLE
|
||||||
|
# define PS2_CLOCK_PORT PORTF
|
||||||
|
# define PS2_CLOCK_PIN PINF
|
||||||
|
# define PS2_CLOCK_DDR DDRF
|
||||||
|
# define PS2_CLOCK_BIT 0
|
||||||
|
# define PS2_DATA_PORT PORTF
|
||||||
|
# define PS2_DATA_PIN PINF
|
||||||
|
# define PS2_DATA_DDR DDRF
|
||||||
|
# define PS2_DATA_BIT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* ADB port setting */
|
||||||
|
#define ADB_PORT PORTF
|
||||||
|
#define ADB_PIN PINF
|
||||||
|
#define ADB_DDR DDRF
|
||||||
|
#define ADB_DATA_BIT 0
|
||||||
|
//#define ADB_PSW_BIT 1 // optional
|
||||||
|
|
||||||
|
#endif
|
133
adb_usb/keymap.c
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* Keymap for ADB keyboard
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#include "usb_keyboard.h"
|
||||||
|
#include "usb_keycodes.h"
|
||||||
|
#include "print.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "keymap.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)]))
|
||||||
|
|
||||||
|
// Convert physical keyboard layout to matrix array.
|
||||||
|
// This is a macro to define keymap easily in keyboard layout form.
|
||||||
|
/* Apple Extended Keyboard */
|
||||||
|
#define KEYMAP( \
|
||||||
|
K35, K7A,K78,K63,K76, K60,K61,K62,K64, K65,K6D,K67,K6F, K69,K6B,K71, K7F, \
|
||||||
|
K32,K12,K13,K14,K15,K17,K16,K1A,K1C,K19,K1D,K1B,K18,K33, K72,K73,K74, K47,K51,K4B,K43, \
|
||||||
|
K30,K0C,K0D,K0E,K0F,K11,K10,K20,K22,K1F,K23,K21,K1E,K2A, K75,K77,K79, K59,K5B,K5C,K4E, \
|
||||||
|
K39,K00,K01,K02,K03,K05,K04,K26,K28,K25,K29,K27, K24, K56,K57,K58,K45, \
|
||||||
|
K38,K06,K07,K08,K09,K0B,K2D,K2E,K2B,K2F,K2C, K7B, K3E, K53,K54,K55, \
|
||||||
|
K36,K3A,K37, K31, K3B,K3D,K3C, K52, K41,K4C \
|
||||||
|
) { \
|
||||||
|
{ KB_##K00, KB_##K01, KB_##K02, KB_##K03, KB_##K04, KB_##K05, KB_##K06, KB_##K07 }, \
|
||||||
|
{ KB_##K08, KB_##K09, KB_NO, KB_##K0B, KB_##K0C, KB_##K0D, KB_##K0E, KB_##K0F }, \
|
||||||
|
{ KB_##K10, KB_##K11, KB_##K12, KB_##K13, KB_##K14, KB_##K15, KB_##K16, KB_##K17 }, \
|
||||||
|
{ KB_##K18, KB_##K19, KB_##K1A, KB_##K1B, KB_##K1C, KB_##K1D, KB_##K1E, KB_##K1F }, \
|
||||||
|
{ KB_##K20, KB_##K21, KB_##K22, KB_##K23, KB_##K24, KB_##K25, KB_##K26, KB_##K27 }, \
|
||||||
|
{ KB_##K28, KB_##K29, KB_##K2A, KB_##K2B, KB_##K2C, KB_##K2D, KB_##K2E, KB_##K2F }, \
|
||||||
|
{ KB_##K30, KB_##K31, KB_##K32, KB_##K33, KB_NO, KB_##K35, KB_##K36, KB_##K37 }, \
|
||||||
|
{ KB_##K38, KB_##K39, KB_##K3A, KB_##K3B, KB_##K3C, KB_##K3D, KB_##K3E, KB_NO }, \
|
||||||
|
{ KB_NO, KB_##K41, KB_NO, KB_##K43, KB_NO, KB_##K45, KB_NO, KB_##K47 }, \
|
||||||
|
{ KB_NO, KB_NO, KB_NO, KB_##K4B, KB_##K4C, KB_NO, KB_##K4E, KB_NO }, \
|
||||||
|
{ KB_NO, KB_##K51, KB_##K52, KB_##K53, KB_##K54, KB_##K55, KB_##K56, KB_##K57 }, \
|
||||||
|
{ KB_##K58, KB_##K59, KB_NO, KB_##K5B, KB_##K5C, KB_NO, KB_NO, KB_NO }, \
|
||||||
|
{ KB_##K60, KB_##K61, KB_##K62, KB_##K63, KB_##K64, KB_##K65, KB_NO, KB_##K67 }, \
|
||||||
|
{ KB_NO, KB_##K69, KB_NO, KB_##K6B, KB_NO, KB_##K6D, KB_NO, KB_##K6F }, \
|
||||||
|
{ KB_NO, KB_##K71, KB_##K72, KB_##K73, KB_##K74, KB_##K75, KB_##K76, KB_##K77 }, \
|
||||||
|
{ KB_##K78, KB_##K79, KB_##K7A, KB_##K7B, KB_NO, KB_NO, KB_NO, KB_##K7F } \
|
||||||
|
}
|
||||||
|
/* plain keymap
|
||||||
|
{
|
||||||
|
{ KB_A, KB_S, KB_D, KB_F, KB_H, KB_G, KB_Z, KB_X }, // 00-07
|
||||||
|
{ KB_C, KB_V, KB_NO, KB_B, KB_Q, KB_W, KB_E, KB_R }, // 08-0F
|
||||||
|
{ KB_Y, KB_T, KB_1, KB_2, KB_3, KB_4, KB_6, KB_5 }, // 10-17
|
||||||
|
{ KB_EQL, KB_9, KB_7, KB_MINS,KB_8, KB_0, KB_RBRC,KB_O }, // 18-1F
|
||||||
|
{ KB_U, KB_LBRC,KB_I, KB_P, KB_ENT, KB_L, KB_J, KB_QUOT}, // 20-27
|
||||||
|
{ KB_K, KB_SCLN,KB_BSLS,KB_COMM,KB_SLSH,KB_N, KB_M, KB_DOT }, // 28-2F
|
||||||
|
{ KB_TAB, KB_SPC, KB_GRV, KB_BSPC,KB_NO, KB_ESC, KB_LCTL,KB_LGUI}, // 30-37
|
||||||
|
{ KB_LSFT,KB_CAPS,KB_LALT,KB_LEFT,KB_RGHT,KB_DOWN,KB_UP, KB_NO }, // 38-3F
|
||||||
|
{ KB_NO, KB_PDOT,KB_NO, KB_PAST,KB_NO, KB_PPLS,KB_NO, KB_NLCK}, // 40-47
|
||||||
|
{ KB_NO, KB_NO, KB_NO, KB_PSLS,KB_PENT,KB_NO, KB_PMNS,KB_NO }, // 48-4F
|
||||||
|
{ KB_NO, KB_PEQL,KB_P0, KB_P1, KB_P2, KB_P3, KB_P4, KB_P5 }, // 50-57
|
||||||
|
{ KB_P6, KB_P7, KB_NO, KB_P8, KB_P9, KB_NO, KB_NO, KB_NO }, // 58-5F
|
||||||
|
{ KB_F5, KB_F6, KB_F7, KB_F3, KB_F8, KB_F9, KB_NO, KB_F11 }, // 60-67
|
||||||
|
{ KB_NO, KB_PSCR,KB_NO, KB_SLCK,KB_NO, KB_F10, KB_NO, KB_F12 }, // 68-6F
|
||||||
|
{ KB_NO, KB_BRK, KB_INS, KB_HOME,KB_PGUP,KB_DEL, KB_F4, KB_END }, // 70-77
|
||||||
|
{ KB_F2, KB_PGDN,KB_F1, KB_RSFT,KB_NO, KB_NO, KB_NO, KB_PWR }, // 78-7F
|
||||||
|
},
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
// Assign Fn key(0-7) to a layer to which switch with the Fn key pressed.
|
||||||
|
static const uint8_t PROGMEM fn_layer[] = {
|
||||||
|
0, // Fn0
|
||||||
|
0, // Fn1
|
||||||
|
0, // Fn2
|
||||||
|
0, // Fn3
|
||||||
|
0, // Fn4
|
||||||
|
0, // Fn5
|
||||||
|
0, // Fn6
|
||||||
|
0 // Fn7
|
||||||
|
};
|
||||||
|
|
||||||
|
// Assign Fn key(0-7) to a keycode sent when release Fn key without use of the layer.
|
||||||
|
// See layer.c for details.
|
||||||
|
static const uint8_t PROGMEM fn_keycode[] = {
|
||||||
|
KB_NO, // Fn0
|
||||||
|
KB_NO, // Fn1
|
||||||
|
KB_NO, // Fn2
|
||||||
|
KB_NO, // Fn3
|
||||||
|
KB_NO, // Fn4
|
||||||
|
KB_NO, // Fn5
|
||||||
|
KB_NO, // Fn6
|
||||||
|
KB_NO // Fn7
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||||
|
/* Default Layer: plain keymap
|
||||||
|
* ,---. ,---------------. ,---------------. ,---------------. ,-----------. ,---.
|
||||||
|
* |Esc| |F1 |F2 |F3 |F4 | |F5 |F6 |F7 |F8 | |F9 |F10|F11|F12| |PrS|ScL|Pau| |Pwr|
|
||||||
|
* `---' `---------------' `---------------' `---------------' `-----------' `---'
|
||||||
|
* ,-----------------------------------------------------------. ,-----------. ,---------------.
|
||||||
|
* | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backspa| |Ins|Hom|PgU| |NmL| =| /| *|
|
||||||
|
* |-----------------------------------------------------------| |-----------| |---------------|
|
||||||
|
* |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| |Del|End|PgD| | 7| 8| 9| -|
|
||||||
|
* |-----------------------------------------------------------| `-----------' |---------------|
|
||||||
|
* |CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Return | | 4| 5| 6| +|
|
||||||
|
* |-----------------------------------------------------------| ,---. |---------------|
|
||||||
|
* |Shift | Z| X| C| V| B| N| M| ,| ,| /|Shift | |Up | | 1| 2| 3| |
|
||||||
|
* |-----------------------------------------------------------| ,-----------. |-----------|Ent|
|
||||||
|
* |Ctrl |Gui |Alt | Space | | | | |Lef|Dow|Rig| | 0| .| |
|
||||||
|
* `-----------------------------------------------------------' `-----------' `---------------'
|
||||||
|
*/
|
||||||
|
KEYMAP(
|
||||||
|
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, PWR,
|
||||||
|
GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,EQL, PSLS,PAST,
|
||||||
|
TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, DEL, END, PGDN, P7, P8, P9, PMNS,
|
||||||
|
CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT, ENT, P4, P5, P6, PPLS,
|
||||||
|
LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, UP, P1, P2, P3,
|
||||||
|
LCTL,LGUI,LALT, SPC, LEFT,DOWN,RGHT, P0, PDOT,PENT
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col)
|
||||||
|
{
|
||||||
|
return KEYCODE(layer, row, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t keymap_fn_layer(uint8_t fn_bits)
|
||||||
|
{
|
||||||
|
return pgm_read_byte(&fn_layer[biton(fn_bits)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t keymap_fn_keycode(uint8_t fn_bits)
|
||||||
|
{
|
||||||
|
return pgm_read_byte(&fn_keycode[(biton(fn_bits))]);
|
||||||
|
}
|
9
adb_usb/led.c
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#include "stdint.h"
|
||||||
|
#include "adb.h"
|
||||||
|
#include "led.h"
|
||||||
|
|
||||||
|
|
||||||
|
void led_set(uint8_t usb_led)
|
||||||
|
{
|
||||||
|
adb_host_kbd_led(~usb_led);
|
||||||
|
}
|
193
adb_usb/matrix.c
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
/*
|
||||||
|
* scan matrix
|
||||||
|
*/
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include "print.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "adb.h"
|
||||||
|
#include "matrix.h"
|
||||||
|
|
||||||
|
|
||||||
|
#if (MATRIX_COLS > 16)
|
||||||
|
# error "MATRIX_COLS must not exceed 16"
|
||||||
|
#endif
|
||||||
|
#if (MATRIX_ROWS > 255)
|
||||||
|
# error "MATRIX_ROWS must not exceed 255"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static bool _matrix_is_modified = false;
|
||||||
|
|
||||||
|
// matrix state buffer(1:on, 0:off)
|
||||||
|
#if (MATRIX_COLS <= 8)
|
||||||
|
static uint8_t *matrix;
|
||||||
|
static uint8_t _matrix0[MATRIX_ROWS];
|
||||||
|
#else
|
||||||
|
static uint16_t *matrix;
|
||||||
|
static uint16_t _matrix0[MATRIX_ROWS];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MATRIX_HAS_GHOST
|
||||||
|
static bool matrix_has_ghost_in_row(uint8_t row);
|
||||||
|
#endif
|
||||||
|
static void _register_key(uint8_t key);
|
||||||
|
|
||||||
|
|
||||||
|
inline
|
||||||
|
uint8_t matrix_rows(void)
|
||||||
|
{
|
||||||
|
return MATRIX_ROWS;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
uint8_t matrix_cols(void)
|
||||||
|
{
|
||||||
|
return MATRIX_COLS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void matrix_init(void)
|
||||||
|
{
|
||||||
|
adb_host_init();
|
||||||
|
|
||||||
|
// initialize matrix state: all keys off
|
||||||
|
for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00;
|
||||||
|
matrix = _matrix0;
|
||||||
|
|
||||||
|
print_enable = true;
|
||||||
|
debug_enable = true;
|
||||||
|
debug_matrix = true;
|
||||||
|
debug_keyboard = true;
|
||||||
|
debug_mouse = true;
|
||||||
|
print("debug enabled.\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t matrix_scan(void)
|
||||||
|
{
|
||||||
|
uint16_t codes;
|
||||||
|
uint8_t key0, key1;
|
||||||
|
|
||||||
|
_matrix_is_modified = false;
|
||||||
|
codes = adb_host_kbd_recv();
|
||||||
|
key0 = codes>>8;
|
||||||
|
key1 = codes&0xFF;
|
||||||
|
|
||||||
|
if (codes == 0) { // no keys
|
||||||
|
return 0;
|
||||||
|
} else if (key0 == 0xFF && key1 != 0xFF) { // error
|
||||||
|
return codes&0xFF;
|
||||||
|
} else {
|
||||||
|
_matrix_is_modified = true;
|
||||||
|
_register_key(key0);
|
||||||
|
if (key1 != 0xFF) // key1 is 0xFF when no second key.
|
||||||
|
_register_key(key1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (debug_enable) {
|
||||||
|
print("adb_host_kbd_recv: "); phex16(codes); print("\n");
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool matrix_is_modified(void)
|
||||||
|
{
|
||||||
|
return _matrix_is_modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
bool matrix_has_ghost(void)
|
||||||
|
{
|
||||||
|
#ifdef MATRIX_HAS_GHOST
|
||||||
|
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
|
||||||
|
if (matrix_has_ghost_in_row(i))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
bool matrix_is_on(uint8_t row, uint8_t col)
|
||||||
|
{
|
||||||
|
return (matrix[row] & (1<<col));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
#if (MATRIX_COLS <= 8)
|
||||||
|
uint8_t matrix_get_row(uint8_t row)
|
||||||
|
#else
|
||||||
|
uint16_t matrix_get_row(uint8_t row)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
return matrix[row];
|
||||||
|
}
|
||||||
|
|
||||||
|
void matrix_print(void)
|
||||||
|
{
|
||||||
|
#if (MATRIX_COLS <= 8)
|
||||||
|
print("\nr/c 01234567\n");
|
||||||
|
#else
|
||||||
|
print("\nr/c 0123456789ABCDEF\n");
|
||||||
|
#endif
|
||||||
|
for (uint8_t row = 0; row < matrix_rows(); row++) {
|
||||||
|
phex(row); print(": ");
|
||||||
|
#if (MATRIX_COLS <= 8)
|
||||||
|
pbin_reverse(matrix_get_row(row));
|
||||||
|
#else
|
||||||
|
pbin_reverse16(matrix_get_row(row));
|
||||||
|
#endif
|
||||||
|
#ifdef MATRIX_HAS_GHOST
|
||||||
|
if (matrix_has_ghost_in_row(row)) {
|
||||||
|
print(" <ghost");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
print("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t matrix_key_count(void)
|
||||||
|
{
|
||||||
|
uint8_t count = 0;
|
||||||
|
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
|
||||||
|
#if (MATRIX_COLS <= 8)
|
||||||
|
count += bitpop(matrix[i]);
|
||||||
|
#else
|
||||||
|
count += bitpop16(matrix[i]);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MATRIX_HAS_GHOST
|
||||||
|
inline
|
||||||
|
static bool matrix_has_ghost_in_row(uint8_t row)
|
||||||
|
{
|
||||||
|
// no ghost exists in case less than 2 keys on
|
||||||
|
if (((matrix[row] - 1) & matrix[row]) == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// ghost exists in case same state as other row
|
||||||
|
for (uint8_t i=0; i < MATRIX_ROWS; i++) {
|
||||||
|
if (i != row && (matrix[i] & matrix[row]) == matrix[row])
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline
|
||||||
|
static void _register_key(uint8_t key)
|
||||||
|
{
|
||||||
|
uint8_t col, row;
|
||||||
|
col = key&0x07;
|
||||||
|
row = (key>>3)&0x0F;
|
||||||
|
if (key&0x80) {
|
||||||
|
matrix[row] &= ~(1<<col);
|
||||||
|
} else {
|
||||||
|
matrix[row] |= (1<<col);
|
||||||
|
}
|
||||||
|
}
|
211
command.c
Normal file
@ -0,0 +1,211 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include "usb_keycodes.h"
|
||||||
|
#include "host.h"
|
||||||
|
#include "print.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "timer.h"
|
||||||
|
#include "layer.h"
|
||||||
|
#include "matrix.h"
|
||||||
|
#include "command.h"
|
||||||
|
|
||||||
|
#ifdef HOST_PJRC
|
||||||
|
# include "jump_bootloader.h"
|
||||||
|
# include "usb_keyboard.h"
|
||||||
|
# ifdef USB_EXTRA_ENABLE
|
||||||
|
# include "usb_extra.h"
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static void help(void);
|
||||||
|
static uint8_t switch_layer(uint8_t layer);
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t command_proc(void)
|
||||||
|
{
|
||||||
|
// check if we just want to swap from qwerty->dvorak and back
|
||||||
|
if(IS_SWAP()){
|
||||||
|
return switch_layer(current_layer > 0 ? 0 : 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IS_COMMAND())
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint8_t processed = 1;
|
||||||
|
bool last_print_enable = print_enable;
|
||||||
|
print_enable = true;
|
||||||
|
switch (host_get_first_key()) {
|
||||||
|
case KB_H:
|
||||||
|
help();
|
||||||
|
break;
|
||||||
|
case KB_B:
|
||||||
|
#ifdef HOST_PJRC
|
||||||
|
host_clear_keyboard_report();
|
||||||
|
host_send_keyboard_report();
|
||||||
|
print("jump to bootloader...\n");
|
||||||
|
_delay_ms(1000);
|
||||||
|
jump_bootloader(); // not return
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
case KB_D:
|
||||||
|
debug_enable = !debug_enable;
|
||||||
|
if (debug_enable) {
|
||||||
|
last_print_enable = true;
|
||||||
|
print("debug enabled.\n");
|
||||||
|
debug_matrix = true;
|
||||||
|
debug_keyboard = true;
|
||||||
|
debug_mouse = true;
|
||||||
|
} else {
|
||||||
|
print("debug disabled.\n");
|
||||||
|
last_print_enable = false;
|
||||||
|
debug_matrix = false;
|
||||||
|
debug_keyboard = false;
|
||||||
|
debug_mouse = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KB_X: // debug matrix toggle
|
||||||
|
debug_matrix = !debug_matrix;
|
||||||
|
if (debug_matrix)
|
||||||
|
print("debug matrix enabled.\n");
|
||||||
|
else
|
||||||
|
print("debug matrix disabled.\n");
|
||||||
|
break;
|
||||||
|
case KB_K: // debug keyboard toggle
|
||||||
|
debug_keyboard = !debug_keyboard;
|
||||||
|
if (debug_keyboard)
|
||||||
|
print("debug keyboard enabled.\n");
|
||||||
|
else
|
||||||
|
print("debug keyboard disabled.\n");
|
||||||
|
break;
|
||||||
|
case KB_M: // debug mouse toggle
|
||||||
|
debug_mouse = !debug_mouse;
|
||||||
|
if (debug_mouse)
|
||||||
|
print("debug mouse enabled.\n");
|
||||||
|
else
|
||||||
|
print("debug mouse disabled.\n");
|
||||||
|
break;
|
||||||
|
case KB_V: // print version & information
|
||||||
|
print(STR(DESCRIPTION) "\n");
|
||||||
|
break;
|
||||||
|
case KB_T: // print timer
|
||||||
|
print("timer: "); phex16(timer_count); print("\n");
|
||||||
|
break;
|
||||||
|
case KB_P: // print toggle
|
||||||
|
if (last_print_enable) {
|
||||||
|
print("print disabled.\n");
|
||||||
|
last_print_enable = false;
|
||||||
|
} else {
|
||||||
|
last_print_enable = true;
|
||||||
|
print("print enabled.\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case KB_S:
|
||||||
|
#ifdef HOST_PJRC
|
||||||
|
print("UDCON: "); phex(UDCON); print("\n");
|
||||||
|
print("UDIEN: "); phex(UDIEN); print("\n");
|
||||||
|
print("UDINT: "); phex(UDINT); print("\n");
|
||||||
|
print("usb_keyboard_leds:"); phex(usb_keyboard_leds); 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_count:"); phex(usb_keyboard_idle_count); print("\n");
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
#ifdef USB_NKRO_ENABLE
|
||||||
|
case KB_N:
|
||||||
|
// send empty report before change
|
||||||
|
host_clear_keyboard_report();
|
||||||
|
host_send_keyboard_report();
|
||||||
|
keyboard_nkro = !keyboard_nkro;
|
||||||
|
if (keyboard_nkro)
|
||||||
|
print("USB_NKRO: enabled\n");
|
||||||
|
else
|
||||||
|
print("USB_NKRO: disabled\n");
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
#ifdef USB_EXTRA_ENABLE
|
||||||
|
case KB_ESC:
|
||||||
|
#ifdef HOST_PJRC
|
||||||
|
if (suspend && remote_wakeup) {
|
||||||
|
usb_remote_wakeup();
|
||||||
|
} else {
|
||||||
|
host_system_send(SYSTEM_POWER_DOWN);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
host_system_send(SYSTEM_POWER_DOWN);
|
||||||
|
#endif
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
case KB_BSPC:
|
||||||
|
matrix_init();
|
||||||
|
print("clear matrix\n");
|
||||||
|
break;
|
||||||
|
case KB_0:
|
||||||
|
return switch_layer(0);
|
||||||
|
case KB_1:
|
||||||
|
return switch_layer(1);
|
||||||
|
case KB_2:
|
||||||
|
return switch_layer(2);
|
||||||
|
case KB_3:
|
||||||
|
return switch_layer(3);
|
||||||
|
case KB_4:
|
||||||
|
return switch_layer(4);
|
||||||
|
case KB_5:
|
||||||
|
return switch_layer(5);
|
||||||
|
case KB_6:
|
||||||
|
return switch_layer(2);
|
||||||
|
default:
|
||||||
|
processed = 0;
|
||||||
|
}
|
||||||
|
//if (processed)
|
||||||
|
// _delay_ms(500);
|
||||||
|
print_enable = last_print_enable;
|
||||||
|
return processed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void help(void)
|
||||||
|
{
|
||||||
|
print("b: jump to bootloader\n");
|
||||||
|
print("d: toggle debug enable\n");
|
||||||
|
print("x: toggle matrix debug\n");
|
||||||
|
print("k: toggle keyboard debug\n");
|
||||||
|
print("m: toggle mouse debug\n");
|
||||||
|
print("p: toggle print enable\n");
|
||||||
|
print("v: print version\n");
|
||||||
|
print("t: print timer count\n");
|
||||||
|
print("s: print status\n");
|
||||||
|
#ifdef USB_NKRO_ENABLE
|
||||||
|
print("n: toggle USB_NKRO\n");
|
||||||
|
#endif
|
||||||
|
print("Backspace: clear matrix\n");
|
||||||
|
print("ESC: power down/wake up\n");
|
||||||
|
print("0: switch to Layer0 \n");
|
||||||
|
print("1: switch to Layer1 \n");
|
||||||
|
print("2: switch to Layer2 \n");
|
||||||
|
print("3: switch to Layer3 \n");
|
||||||
|
print("4: switch to Layer4 \n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t switch_layer(uint8_t layer)
|
||||||
|
{
|
||||||
|
print("current_layer: "); phex(current_layer); print("\n");
|
||||||
|
print("default_layer: "); phex(default_layer); print("\n");
|
||||||
|
uint8_t ret = 1;
|
||||||
|
if(layer == 0 && current_layer != 0){
|
||||||
|
DEBUG_LED_OFF;
|
||||||
|
ret = SCROLL_LOCK_TOGGLE;
|
||||||
|
//led_set(USB_LED_SCROLL_LOCK);
|
||||||
|
}
|
||||||
|
else if(current_layer == 0 && layer != 0){
|
||||||
|
DEBUG_LED_ON;
|
||||||
|
ret = SCROLL_LOCK_TOGGLE;
|
||||||
|
//led_set(USB_LED_SCROLL_LOCK);
|
||||||
|
}
|
||||||
|
current_layer = layer;
|
||||||
|
default_layer = layer;
|
||||||
|
print("switch to Layer: "); phex(layer); print("\n");
|
||||||
|
//_delay_ms(500); // now done in keyboard.c
|
||||||
|
return ret;
|
||||||
|
}
|
8
command.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#ifndef COMMAND_H
|
||||||
|
#define COMMAND
|
||||||
|
|
||||||
|
#define SCROLL_LOCK_TOGGLE 5
|
||||||
|
|
||||||
|
uint8_t command_proc(void);
|
||||||
|
|
||||||
|
#endif
|
@ -2,7 +2,7 @@
|
|||||||
#define TEENSY_H 1
|
#define TEENSY_H 1
|
||||||
|
|
||||||
// for Teensy/Teensy++ 2.0
|
// for Teensy/Teensy++ 2.0
|
||||||
#define DEBUG_LED 1
|
//#define DEBUG_LED 1
|
||||||
#define DEBUG_LED_CONFIG (DDRD |= (1<<6))
|
#define DEBUG_LED_CONFIG (DDRD |= (1<<6))
|
||||||
#define DEBUG_LED_ON (PORTD |= (1<<6))
|
#define DEBUG_LED_ON (PORTD |= (1<<6))
|
||||||
#define DEBUG_LED_OFF (PORTD &= ~(1<<6))
|
#define DEBUG_LED_OFF (PORTD &= ~(1<<6))
|
||||||
|
2
debug.h
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
#define debug(s) if(debug_enable) print(s)
|
#define debug(s) if(debug_enable) print(s)
|
||||||
#define debug_hex(c) if(debug_enable) phex(c)
|
#define debug_hex(c) if(debug_enable) phex(c)
|
||||||
#define debug_hex16(i) if(debug_enable) phex(i)
|
#define debug_hex16(i) if(debug_enable) phex16(i)
|
||||||
#define debug_bin(c) if(debug_enable) pbin(c)
|
#define debug_bin(c) if(debug_enable) pbin(c)
|
||||||
#define debug_bin_reverse(c) if(debug_enable) pbin_reverse(c)
|
#define debug_bin_reverse(c) if(debug_enable) pbin_reverse(c)
|
||||||
|
|
||||||
|
@ -1,54 +1,10 @@
|
|||||||
# Hey Emacs, this is a -*- makefile -*-
|
|
||||||
#----------------------------------------------------------------------------
|
|
||||||
# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al.
|
|
||||||
#
|
#
|
||||||
# Released to the Public Domain
|
# Makefile for PJRC Teensy
|
||||||
#
|
#
|
||||||
# Additional material for this makefile was written by:
|
|
||||||
# Peter Fleury
|
|
||||||
# Tim Henigan
|
|
||||||
# Colin O'Flynn
|
|
||||||
# Reiner Patommel
|
|
||||||
# Markus Pfaff
|
|
||||||
# Sander Pool
|
|
||||||
# Frederik Rouleau
|
|
||||||
# Carlos Lamas
|
|
||||||
#
|
|
||||||
#----------------------------------------------------------------------------
|
|
||||||
# On command line:
|
|
||||||
#
|
|
||||||
# make all = Make software.
|
|
||||||
#
|
|
||||||
# make clean = Clean out built project files.
|
|
||||||
#
|
|
||||||
# make coff = Convert ELF to AVR COFF.
|
|
||||||
#
|
|
||||||
# make extcoff = Convert ELF to AVR Extended COFF.
|
|
||||||
#
|
|
||||||
# make program = Download the hex file to the device, using avrdude.
|
|
||||||
# Please customize the avrdude settings below first!
|
|
||||||
#
|
|
||||||
# make debug = Start either simulavr or avarice as specified for debugging,
|
|
||||||
# with avr-gdb or avr-insight as the front end for debugging.
|
|
||||||
#
|
|
||||||
# make filename.s = Just compile filename.c into the assembler code only.
|
|
||||||
#
|
|
||||||
# make filename.i = Create a preprocessed source file for use in submitting
|
|
||||||
# bug reports to the GCC project.
|
|
||||||
#
|
|
||||||
# To rebuild project do "make clean" then "make all".
|
|
||||||
#----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
VENDOR_ID = 0xFEED
|
|
||||||
PRODUCT_ID = 0xCAFE
|
|
||||||
MANUFACTURER = 't.m.k.'
|
|
||||||
PRODUCT = 't.m.k. HHKB pro'
|
|
||||||
DESCRIPTION = 't.m.k. firmware for HHKB pro'
|
|
||||||
|
|
||||||
MOUSE_DELAY_TIME = 127
|
|
||||||
|
|
||||||
# Target file name (without extension).
|
# Target file name (without extension).
|
||||||
TARGET = tmk_hhkb
|
TARGET = hhkb_pjrc
|
||||||
|
|
||||||
# Directory common source filess exist
|
# Directory common source filess exist
|
||||||
COMMON_DIR = ..
|
COMMON_DIR = ..
|
||||||
@ -57,8 +13,12 @@ COMMON_DIR = ..
|
|||||||
TARGET_DIR = .
|
TARGET_DIR = .
|
||||||
|
|
||||||
# keyboard dependent files
|
# keyboard dependent files
|
||||||
TARGET_SRC = keymap.c \
|
TARGET_SRC = main_pjrc.c \
|
||||||
matrix.c
|
keymap.c \
|
||||||
|
matrix.c \
|
||||||
|
led.c
|
||||||
|
|
||||||
|
CONFIG_H = config_pjrc.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
|
||||||
@ -76,4 +36,20 @@ MCU = at90usb1286 # Teensy++ 2.0
|
|||||||
# 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 = 16000000
|
F_CPU = 16000000
|
||||||
|
|
||||||
|
|
||||||
|
# Build Options
|
||||||
|
# comment out to disable the options.
|
||||||
|
MOUSEKEY_ENABLE = yes # Mouse keys
|
||||||
|
#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support
|
||||||
|
USB_EXTRA_ENABLE = yes # Audio control and System control
|
||||||
|
USB_NKRO_ENABLE = yes # USB Nkey Rollover
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- Programming Options --------------------------
|
||||||
|
PROGRAM_CMD = teensy_loader_cli -mmcu=$(MCU) -w -v $(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
include $(COMMON_DIR)/Makefile.pjrc
|
||||||
include $(COMMON_DIR)/Makefile.common
|
include $(COMMON_DIR)/Makefile.common
|
||||||
|
84
hhkb/Makefile.vusb
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
#
|
||||||
|
# Makefile for V-USB
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
# Target file name (without extension).
|
||||||
|
TARGET = hhkb_vusb
|
||||||
|
|
||||||
|
# Directory common source filess exist
|
||||||
|
COMMON_DIR = ..
|
||||||
|
|
||||||
|
# Directory keyboard dependent files exist
|
||||||
|
TARGET_DIR = .
|
||||||
|
|
||||||
|
# keyboard dependent files
|
||||||
|
TARGET_SRC = main_vusb.c \
|
||||||
|
keymap.c \
|
||||||
|
matrix.c \
|
||||||
|
led.c
|
||||||
|
|
||||||
|
CONFIG_H = config_vusb.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 = 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 = 20000000
|
||||||
|
|
||||||
|
|
||||||
|
# Build Options
|
||||||
|
# comment out to disable the options.
|
||||||
|
#
|
||||||
|
MOUSEKEY_ENABLE = yes # Mouse keys
|
||||||
|
USB_EXTRA_ENABLE = yes # Audio control and System control
|
||||||
|
#USB_NKRO_ENABLE = yes # USB Nkey Rollover
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- 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 $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
|
||||||
|
AVRDUDE_FLAGS = -p $(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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
include $(COMMON_DIR)/Makefile.vusb
|
||||||
|
include $(COMMON_DIR)/Makefile.common
|
80
hhkb/README
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
Alternative Controller for HHKB
|
||||||
|
===============================
|
||||||
|
|
||||||
|
Feature
|
||||||
|
-------
|
||||||
|
- Mouse Keys
|
||||||
|
- NKRO on USB
|
||||||
|
- Keymap Layers
|
||||||
|
|
||||||
|
|
||||||
|
Customize Keymap
|
||||||
|
----------------
|
||||||
|
see keymap.c.
|
||||||
|
|
||||||
|
|
||||||
|
Build for Teensy
|
||||||
|
----------------
|
||||||
|
0. Edit matrix.c.
|
||||||
|
adjust scan code to your pin configuration.(see doc/HHKB.txt for pinouts)
|
||||||
|
1. Define macros in config_pjrc.h.(Optional)
|
||||||
|
VENDOR_ID, PRODUCT_ID and string descriptor.
|
||||||
|
IS_COMMAND
|
||||||
|
2. Edit Makefile for MCU setting and build options.
|
||||||
|
MCU, F_CPU
|
||||||
|
MOUSEKEY_ENABLE, USB_EXTRA_ENABLE, USB_NKRO_ENABLE
|
||||||
|
3. Build hex file.
|
||||||
|
$ make
|
||||||
|
4. Program MCU.
|
||||||
|
$ make program
|
||||||
|
|
||||||
|
|
||||||
|
Build for V-USB
|
||||||
|
---------------
|
||||||
|
0. Edit matrix.c and usbconfig.h.
|
||||||
|
adjust scan code to your pin configuration.(see doc/HHKB.txt for pinouts)
|
||||||
|
define macros for V-USB in usbconfig.h.
|
||||||
|
1. Define macros in config_vusb.h.(Optional)
|
||||||
|
IS_COMMAND
|
||||||
|
2. Edit Makefile.vusb for MCU setting and build options.
|
||||||
|
MCU, F_CPU
|
||||||
|
MOUSEKEY_ENABLE, USB_EXTRA_ENABLE, USB_NKRO_ENABLE
|
||||||
|
3. Build hex file.
|
||||||
|
$ make -f Makefile.vusb
|
||||||
|
4. Program MCU.
|
||||||
|
$ make -f Makefile.vusb program
|
||||||
|
|
||||||
|
Using a bootloader to program for convenience is recommended.
|
||||||
|
Once program this V-USB bootloader at first, you can program MCU without
|
||||||
|
extra programmer. You should have reset switch to start up as bootloader
|
||||||
|
mode in this case.
|
||||||
|
USBaspLoader:
|
||||||
|
http://www.obdev.at/products/vusb/usbasploader.html
|
||||||
|
|
||||||
|
|
||||||
|
V-USB Circuit
|
||||||
|
-------------
|
||||||
|
+---+ +---------------+
|
||||||
|
USB GND | | ATmega168 |
|
||||||
|
=== C3 | |
|
||||||
|
5V <-------+--------+---|Vcc,AVCC | HHKB
|
||||||
|
R1 | | ====
|
||||||
|
D- <----+--+-----R2-----|INT1 PB0-2|------->ROW
|
||||||
|
D+ <----|---+----R3-----|INT0 PB3-5|------->COL
|
||||||
|
Z1 Z2 | PB6|------->ENABLE
|
||||||
|
GND<----+---+--+--+-----|GND PE6|------->KEY
|
||||||
|
| | | PE7|------->PREV
|
||||||
|
| C2-+--|XTAL1 | (see doc/HHKB.txt for pinouts)
|
||||||
|
| X1 | |
|
||||||
|
+--C3-+--|XTAL2 RST|---SW--+GND
|
||||||
|
+---------------+
|
||||||
|
R1: 1.5K Ohm
|
||||||
|
R2,R3: 68 Ohm
|
||||||
|
Z1,Z2: Zener 3.6V
|
||||||
|
C1,C2: 22pF
|
||||||
|
C3: 0.1uF
|
||||||
|
X1: Crystal 20MHz(16MHz/12MHz)
|
||||||
|
SW: Push Switch(Optional for bootloader)
|
||||||
|
|
||||||
|
|
||||||
|
EOF
|
48
hhkb/config_pjrc.h
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#ifndef CONFIG_H
|
||||||
|
#define CONFIG_H
|
||||||
|
|
||||||
|
/* controller configuration */
|
||||||
|
#include "controller_teensy.h"
|
||||||
|
|
||||||
|
#define VENDOR_ID 0xFEED
|
||||||
|
#define PRODUCT_ID 0xCAFE
|
||||||
|
#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
|
||||||
|
/* define if matrix has ghost */
|
||||||
|
//#define MATRIX_HAS_GHOST
|
||||||
|
|
||||||
|
|
||||||
|
/* key combination for command */
|
||||||
|
#define IS_COMMAND() ( \
|
||||||
|
keyboard_report->mods == (BIT_LSHIFT | BIT_RSHIFT) || \
|
||||||
|
keyboard_report->mods == (BIT_LCTRL | BIT_RSHIFT) \
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
/* mouse keys */
|
||||||
|
#ifdef MOUSEKEY_ENABLE
|
||||||
|
# define MOUSEKEY_DELAY_TIME 192
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* PS/2 mouse */
|
||||||
|
#ifdef PS2_MOUSE_ENABLE
|
||||||
|
/*
|
||||||
|
# define PS2_CLOCK_PORT PORTF
|
||||||
|
# define PS2_CLOCK_PIN PINF
|
||||||
|
# define PS2_CLOCK_DDR DDRF
|
||||||
|
# define PS2_CLOCK_BIT 0
|
||||||
|
# define PS2_DATA_PORT PORTF
|
||||||
|
# define PS2_DATA_PIN PINF
|
||||||
|
# define PS2_DATA_DDR DDRF
|
||||||
|
# define PS2_DATA_BIT 1
|
||||||
|
*/
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
32
hhkb/config_vusb.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef CONFIG_H
|
||||||
|
#define CONFIG_H
|
||||||
|
|
||||||
|
|
||||||
|
#define VENDOR_ID 0xFEED
|
||||||
|
#define PRODUCT_ID 0xC0FE
|
||||||
|
// 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 == (BIT_LSHIFT | BIT_RSHIFT) || \
|
||||||
|
keyboard_report->mods == (BIT_LCTRL | BIT_RSHIFT) \
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
/* mouse keys */
|
||||||
|
#ifdef MOUSEKEY_ENABLE
|
||||||
|
# define MOUSEKEY_DELAY_TIME 255
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
@ -1,6 +0,0 @@
|
|||||||
#ifndef CONTROLLER_H
|
|
||||||
#define CONTROLLER_H 1
|
|
||||||
|
|
||||||
#include "controller_teensy.h"
|
|
||||||
|
|
||||||
#endif
|
|
@ -8,7 +8,7 @@ Teensy++ has clean pinout and it makes programing and wiring easier.
|
|||||||
This is just a proof of concept for replacing controller of HHKB, not a complete firmware.
|
This is just a proof of concept for replacing controller of HHKB, not a complete firmware.
|
||||||
|
|
||||||
My prototype firmware source tree is here:
|
My prototype firmware source tree is here:
|
||||||
branch: hhkb(http://github.com/tmk/tmk_keyboard/tree/hhkb)
|
github(http://github.com/tmk/tmk_keyboard)
|
||||||
This firmware is a port of my previous project:
|
This firmware is a port of my previous project:
|
||||||
HHKB style Mod(http://geekhack.org/showwiki.php?title=Island:11930)
|
HHKB style Mod(http://geekhack.org/showwiki.php?title=Island:11930)
|
||||||
PJRC:
|
PJRC:
|
||||||
@ -68,7 +68,7 @@ Keyswitch PCB:
|
|||||||
http://www.alldatasheet.com/datasheet-pdf/pdf/27373/TI/SN74LS145D.html
|
http://www.alldatasheet.com/datasheet-pdf/pdf/27373/TI/SN74LS145D.html
|
||||||
BU9831 Non-volatile electronic potentiometer: for calibration?
|
BU9831 Non-volatile electronic potentiometer: for calibration?
|
||||||
http://www.alldatasheet.com/datasheet-pdf/pdf/36387/ROHM/BU9831.html
|
http://www.alldatasheet.com/datasheet-pdf/pdf/36387/ROHM/BU9831.html
|
||||||
TP1684 Capacitive Sensing controller: no datasheet available.
|
TP1683/4 Capacitive Sensing controller: no datasheet available.
|
||||||
|
|
||||||
(HHKB_keyswitch.jpg)
|
(HHKB_keyswitch.jpg)
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ Two PCBs are connected by 15 lines. Vcc and GND use 3 lines each, other 9 lines
|
|||||||
2 Vcc(5V)
|
2 Vcc(5V)
|
||||||
3 Vcc(5V)
|
3 Vcc(5V)
|
||||||
4 TP1684 KEY: Low(0) when key pressed PE6 input(with pullup)
|
4 TP1684 KEY: Low(0) when key pressed PE6 input(with pullup)
|
||||||
5 TP1684 unknown:how to use PE7 input(with pullup)
|
5 TP1684 KEY_PREV: assert previous key state??? PE7 output
|
||||||
6 HC4051 A(bit0) select 8 rows(0 to 7) PB0 output
|
6 HC4051 A(bit0) select 8 rows(0 to 7) PB0 output
|
||||||
7 HC4051 B(bit1) PB1 output
|
7 HC4051 B(bit1) PB1 output
|
||||||
8 HC4051 C(bit2) PB2 output
|
8 HC4051 C(bit2) PB2 output
|
||||||
@ -120,16 +120,16 @@ Matrix diagram:
|
|||||||
|bias control? - - - - - - - - ---
|
|bias control? - - - - - - - - ---
|
||||||
| 3.9K*8 R R R R R R R R |
|
| 3.9K*8 R R R R R R R R |
|
||||||
+--------^+ +--------+ - - - - - - - - |
|
+--------^+ +--------+ - - - - - - - - |
|
||||||
| TP 1684 | | HC4051 <0-------|-|-|-|-|-|-|-|--|R|-+
|
| 2| | HC4051 <0-------|-|-|-|-|-|-|-|--|R|-+
|
||||||
| |capa. | <1-------|-|-|-|-|-|-|-|--|R|-+
|
| |capa. | <1-------|-|-|-|-|-|-|-|--|R|-+
|
||||||
| |sense | <2-------|-|-|-|-|-|-|-|--|R|-+
|
| TP1684 |sense | <2-------|-|-|-|-|-|-|-|--|R|-+
|
||||||
| <------| <3-------|-|-|-|-|-|-|-|--|R|-+
|
| 11<------| <3-------|-|-|-|-|-|-|-|--|R|-+
|
||||||
| | | <4-------|-|-|-|-|-|-|-|--|R|-+
|
| | | <4-------|-|-|-|-|-|-|-|--|R|-+
|
||||||
| | | <5-------|-|-|-|-|-|-|-|--|R|-+
|
| | | <5-------|-|-|-|-|-|-|-|--|R|-+
|
||||||
| |calib.| <6-------|-|-|-|-|-|-|-|--|R|-+
|
| <-+ | <6-------|-|-|-|-|-|-|-|--|R|-+
|
||||||
| <-+? | <7-------|-|-|-|-|-|-|-|--|R|-+
|
| 1 4 | | | <7-------|-|-|-|-|-|-|-|--|R|-+
|
||||||
+---V-----+ | +-^-^-^--+ 0 1 2 3 4 5 6 7 33K*8
|
+---V---^-+ | +-^-^-^--+ 0 1 2 3 4 5 6 7 33K*8
|
||||||
KEY ??? | A B C +-----------------+
|
KEY PREV | A B C +-----------------+
|
||||||
| | +-^----+ | | | | LS145 |
|
| | +-^----+ | | | | LS145 |
|
||||||
Vcc | | |BU9831| | | | +-^--^--^--^------+
|
Vcc | | |BU9831| | | | +-^--^--^--^------+
|
||||||
--- | | +------+ | | | A B C D +------+
|
--- | | +------+ | | | A B C D +------+
|
||||||
@ -148,9 +148,11 @@ Signals charts:
|
|||||||
|
|
||||||
(HHKB_chart1.jpg)
|
(HHKB_chart1.jpg)
|
||||||
|
|
||||||
Space bar locate at ROW:3 COL:7. Key are selected by HC4051(C,B,A) and LS145(C,B,A).
|
Space bar locate at ROW:3 COL:7. A key is selected by HC4051(C,B,A) and LS145(C,B,A).
|
||||||
Key state can be read on TP1684(4/KEY) while asserting low on LS145(D).
|
Key state can be read on TP1684(4/KEY) while asserting low on LS145(D).
|
||||||
Usage of TP1684(5) is unknown. Key state can be read without using this signal.
|
|
||||||
|
Usage of TP1684(5) is not clear. Controller seemed to output previous key state on this line.
|
||||||
|
However key state can be read without using this signal.
|
||||||
|
|
||||||
(HHKB_chart2.jpg)
|
(HHKB_chart2.jpg)
|
||||||
|
|
||||||
@ -162,7 +164,13 @@ Matrix scan pseudo code:
|
|||||||
for (col: 0-7) {
|
for (col: 0-7) {
|
||||||
SELECT_COL(col); // set LS145(A,B,C)
|
SELECT_COL(col); // set LS145(A,B,C)
|
||||||
|
|
||||||
_delay_us(50);
|
_delay_us(40);
|
||||||
|
|
||||||
|
if (prev_key_state(row, col)) {
|
||||||
|
KEY_PREV_ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
_delay_us(7);
|
||||||
|
|
||||||
ENALBLE_COL(); // set LS145(D) to low
|
ENALBLE_COL(); // set LS145(D) to low
|
||||||
|
|
||||||
@ -173,13 +181,18 @@ Matrix scan pseudo code:
|
|||||||
} else {
|
} else {
|
||||||
// not pressed
|
// not pressed
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KEY_PREV_OFF;
|
||||||
|
UNALBLE_COL(); // set LS145(D) to high
|
||||||
|
|
||||||
|
_delay_us(150);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Keymap layers
|
Keymap layers
|
||||||
-------------
|
-------------
|
||||||
Followings are added layers with additional Fn keys. They are not final decision.
|
Followings are added layers with additional Fn keys.
|
||||||
|
|
||||||
see keymap.c
|
see keymap.c
|
||||||
|
|
||||||
|
0
hhkb/doc/HHKB_TP1684.jpg
Executable file → Normal file
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 146 KiB |
0
hhkb/doc/HHKB_chart1.jpg
Executable file → Normal file
Before Width: | Height: | Size: 152 KiB After Width: | Height: | Size: 152 KiB |
0
hhkb/doc/HHKB_chart2.jpg
Executable file → Normal file
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 145 KiB |
0
hhkb/doc/HHKB_connector.jpg
Executable file → Normal file
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 189 KiB |
0
hhkb/doc/HHKB_controller.jpg
Executable file → Normal file
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 132 KiB |
0
hhkb/doc/HHKB_keyswitch.jpg
Executable file → Normal file
Before Width: | Height: | Size: 168 KiB After Width: | Height: | Size: 168 KiB |
0
hhkb/doc/connector_contact.jpg
Executable file → Normal file
Before Width: | Height: | Size: 188 KiB After Width: | Height: | Size: 188 KiB |
0
hhkb/doc/logic_analyzer.jpg
Executable file → Normal file
Before Width: | Height: | Size: 166 KiB After Width: | Height: | Size: 166 KiB |
0
hhkb/doc/probe_contact.jpg
Executable file → Normal file
Before Width: | Height: | Size: 204 KiB After Width: | Height: | Size: 204 KiB |
0
hhkb/doc/teensy_install.jpg
Executable file → Normal file
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 133 KiB |
0
hhkb/doc/teensy_wiring.jpg
Executable file → Normal file
Before Width: | Height: | Size: 151 KiB After Width: | Height: | Size: 151 KiB |
167
hhkb/keymap.c
@ -4,18 +4,16 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#include "usb_keyboard.h"
|
#include "host.h"
|
||||||
#include "usb_keycodes.h"
|
#include "usb_keycodes.h"
|
||||||
#include "matrix.h"
|
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "keymap.h"
|
#include "keymap.h"
|
||||||
|
|
||||||
|
|
||||||
#define FN_KEYCODE(fn) (pgm_read_byte(&fn_keycode[(fn)]))
|
// Convert physical keyboard layout to matrix array.
|
||||||
#define FN_LAYER(fn) (pgm_read_byte(&fn_layer[(fn)]))
|
// This is a macro to define keymap easily in keyboard layout form.
|
||||||
#define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)]))
|
|
||||||
#define KEYMAP( \
|
#define KEYMAP( \
|
||||||
R3C1, R3C0, R0C0, R1C0, R1C1, R2C0, R2C1, R4C0, R4C1, R6C0, R6C1, R7C0, R7C1, R5C0, R5C1, \
|
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, \
|
R3C2, R0C1, R0C2, R1C3, R1C2, R2C3, R2C2, R4C2, R4C3, R6C2, R6C3, R7C3, R7C2, R5C2, \
|
||||||
@ -34,24 +32,32 @@
|
|||||||
{ R7C0, R7C1, R7C2, R7C3, R7C4, R7C5, R7C6, KB_NO } \
|
{ R7C0, R7C1, R7C2, R7C3, R7C4, R7C5, R7C6, KB_NO } \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)]))
|
||||||
static int current_layer = 0;
|
|
||||||
static bool layer_used = false;
|
|
||||||
|
|
||||||
|
|
||||||
/* layer to change into while Fn key pressed */
|
// Assign Fn key(0-7) to a layer to which switch with the Fn key pressed.
|
||||||
static const int PROGMEM fn_layer[] = { 0, 1, 2, 3, 4, 0, 0, 0 };
|
static const uint8_t PROGMEM fn_layer[] = {
|
||||||
|
0, // Fn0
|
||||||
|
1, // Fn1
|
||||||
|
2, // Fn2
|
||||||
|
3, // Fn3
|
||||||
|
4, // Fn4
|
||||||
|
0, // Fn5
|
||||||
|
0, // Fn6
|
||||||
|
0 // Fn7
|
||||||
|
};
|
||||||
|
|
||||||
/* keycode to sent when Fn key released without using layer keys. */
|
// Assign Fn key(0-7) to a keycode sent when release Fn key without use of the layer.
|
||||||
|
// See layer.c for details.
|
||||||
static const uint8_t PROGMEM fn_keycode[] = {
|
static const uint8_t PROGMEM fn_keycode[] = {
|
||||||
KB_NO, // FN_0 [NOT USED]
|
KB_NO, // Fn0
|
||||||
KB_NO, // FN_1 layer 1
|
KB_NO, // Fn1
|
||||||
KB_QUOTE, // FN_2 layer 2
|
KB_SLSH, // Fn2
|
||||||
KB_SCOLON, // FN_3 layer 3
|
KB_SCLN, // Fn3
|
||||||
KB_SPACE, // FN_4 layer 4 [NOT USED]
|
KB_SPC, // Fn4
|
||||||
KB_NO, // FN_5 [NOT USED]
|
KB_NO, // Fn5
|
||||||
KB_NO, // FN_6 [NOT USED]
|
KB_NO, // Fn6
|
||||||
KB_NO // FN_7 [NOT USED]
|
KB_NO // Fn7
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||||
@ -61,76 +67,76 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
|||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]|Backs|
|
* |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]|Backs|
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Contro| A| S| D| F| G| H| J| K| L|Fn3|Fn2|Return |
|
* |Contro| A| S| D| F| G| H| J| K| L|Fn3| '|Return |
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift |Fn1|
|
* |Shift | Z| X| C| V| B| N| M| ,| .|Fn2|Shift |Fn1|
|
||||||
* `-----------------------------------------------------------'
|
* `-----------------------------------------------------------'
|
||||||
* |Gui|Alt |Space |Alt |Gui|
|
* |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, \
|
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_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, FN_3, FN_2, KB_ENT, \
|
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_SLSH,KB_RSFT,FN_1, \
|
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_SPC, KB_RALT,KB_RGUI),
|
KB_LGUI,KB_LALT,KB_FN4, KB_RALT,KB_RGUI),
|
||||||
|
|
||||||
/* Layer 1: HHKB mode (HHKB Fn)
|
/* Layer 1: HHKB mode (HHKB Fn)
|
||||||
* ,-----------------------------------------------------------.
|
* ,-----------------------------------------------------------.
|
||||||
* |Pow| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del|
|
* |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del|
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Caps | | | | | | | |Psc|Slk|Pus|Up | |Backs|
|
* |Caps | | | | | | | |Psc|Slk|Pus|Up | |Backs|
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Contro| | | | | | *| /|Hom|PgU|Lef|Rig|Enter |
|
* |Contro|VoD|VoU|Mut| | | *| /|Hom|PgU|Lef|Rig|Enter |
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Shift | | | | | | +| -|End|PgD|Dow|Shift |xxx|
|
* |Shift | | | | | | +| -|End|PgD|Dow|Shift |xxx|
|
||||||
* `-----------------------------------------------------------'
|
* `-----------------------------------------------------------'
|
||||||
* |Gui |Alt |Space |Alt |Gui|
|
* |Gui |Alt |Space |Alt |xxx|
|
||||||
* `--------------------------------------------'
|
* `--------------------------------------------'
|
||||||
*/
|
*/
|
||||||
KEYMAP(KB_PWR, 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, \
|
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_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_NO, KB_NO, KB_NO, KB_NO, KB_NO, KP_ASTR,KP_SLSH,KB_HOME,KB_PGUP,KB_LEFT,KB_RGHT,KB_ENT, \
|
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, KP_PLUS,KP_MINS,KB_END, KB_PGDN,KB_DOWN,KB_RSFT,FN_1, \
|
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_RGUI),
|
KB_LGUI,KB_LALT,KB_SPC, KB_RALT,KB_FN7),
|
||||||
|
|
||||||
/* Layer 2: Vi mode (Quote/Rmeta)
|
/* Layer 2: Vi mode (Slash)
|
||||||
* ,-----------------------------------------------------------.
|
* ,-----------------------------------------------------------.
|
||||||
* |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del|
|
* |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del|
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Tab |Hom|PgD|Up |PgU|End|Hom|PgD|PgUlEnd| | | |Backs|
|
* |Tab |Hom|PgD|Up |PgU|End|Hom|PgD|PgUlEnd| | | |Backs|
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Contro| |Lef|Dow|Rig| |Lef|Dow|Up |Rig| |xxx|Return |
|
* |Contro| |Lef|Dow|Rig| |Lef|Dow|Up |Rig| | |Return |
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Shift | | | | | | | | | | |Shift | |
|
* |Shift | | | | | |Hom|PgD|PgUlEnd|xxx|Shift | |
|
||||||
* `-----------------------------------------------------------'
|
* `-----------------------------------------------------------'
|
||||||
* |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, \
|
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_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, FN_2, KB_ENT, \
|
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_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_RSFT,KB_NO, \
|
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),
|
KB_LGUI,KB_LALT,KB_SPC, KB_RALT,KB_RGUI),
|
||||||
|
|
||||||
/* Layer 3: Mouse mode (Semicolon)
|
/* Layer 3: Mouse mode (Semicolon)
|
||||||
* ,-----------------------------------------------------------.
|
* ,-----------------------------------------------------------.
|
||||||
* |Esc| | | | | | | | | | | | | | |
|
* |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Ins|Del|
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Tab |MwL|MwU|McU|MwD|MwL|MwR|MwD|MwU|MwR| | | |Backs|
|
* |Tab |MwL|MwU|McU|MwD|MwR|MwL|MwD|MwU|MwR| | | |Backs|
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Contro| |McL|McD|McR| |McL|McD|McU|McR|xxx| |Return |
|
* |Contro| |McL|McD|McR| |McL|McD|McU|McR|xxx| |Return |
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Shift | | | | | |Mb2|Mb1|Mb2|Mb3| |Shift | |
|
* |Shift |Mb4|Mb5|Mb1|Mb2|Mb3|Mb2|Mb1|Mb4|Mb5| |Shift | |
|
||||||
* `-----------------------------------------------------------'
|
* `-----------------------------------------------------------'
|
||||||
* |Gui |Alt |Mb1 |Alt |Gui|
|
* |Gui |Alt |Mb1 |Alt |Gui|
|
||||||
* `--------------------------------------------'
|
* `--------------------------------------------'
|
||||||
* 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, \
|
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, MS_WH_L,MS_WH_U,MS_UP, MS_WH_D,MS_WH_R,MS_WH_L,MS_WH_D,MS_WH_U,MS_WH_R,KB_NO, KB_NO, KB_NO, KB_BSPC, \
|
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, MS_LEFT,MS_DOWN,MS_RGHT,KB_NO, MS_LEFT,MS_DOWN,MS_UP, MS_RGHT,FN_3, KB_NO, KB_ENT, \
|
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_NO, MS_DOWN,KB_NO, KB_NO, KB_NO, MS_BTN2,MS_BTN1,MS_BTN2,MS_BTN3,KB_NO, KB_RSFT,KB_NO, \
|
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,MS_BTN1,KB_RALT,KB_RGUI),
|
KB_LGUI,KB_LALT,KB_BTN1,KB_RALT,KB_RGUI),
|
||||||
|
|
||||||
/* Layer 4: Matias half keyboard style (Space)
|
/* Layer 4: Matias half keyboard style (Space)
|
||||||
* ,-----------------------------------------------------------.
|
* ,-----------------------------------------------------------.
|
||||||
@ -149,80 +155,21 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
|||||||
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_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_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_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,FN_4, KB_RALT,KB_RGUI)
|
KB_LGUI,KB_LALT,KB_FN4, KB_RALT,KB_RGUI)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
uint8_t keymap_get_keycode(int row, int col)
|
uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col)
|
||||||
{
|
{
|
||||||
return keymap_get_keycodel(current_layer, row, col);
|
return KEYCODE(layer, row, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t keymap_get_keycodel(int layer, int row, int col)
|
uint8_t keymap_fn_layer(uint8_t fn_bits)
|
||||||
{
|
{
|
||||||
uint8_t code = KEYCODE(layer, row, col);
|
return pgm_read_byte(&fn_layer[biton(fn_bits)]);
|
||||||
// normal key or mouse key
|
|
||||||
if (IS_KEY(code) || IS_MOUSE(code))
|
|
||||||
layer_used = true;
|
|
||||||
return code;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
uint8_t keymap_fn_keycode(uint8_t fn_bits)
|
||||||
int keymap_get_layer(void)
|
|
||||||
{
|
{
|
||||||
return current_layer;
|
return pgm_read_byte(&fn_keycode[(biton(fn_bits))]);
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
int keymap_set_layer(int layer)
|
|
||||||
{
|
|
||||||
current_layer = layer;
|
|
||||||
return current_layer;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
bool keymap_is_special_mode(int fn_bits)
|
|
||||||
{
|
|
||||||
return (keyboard_modifier_keys == (BIT_LCTRL | BIT_LSHIFT | BIT_LALT | BIT_LGUI));
|
|
||||||
}
|
|
||||||
|
|
||||||
void keymap_fn_proc(int fn_bits)
|
|
||||||
{
|
|
||||||
// layer switching
|
|
||||||
static int last_bits = 0;
|
|
||||||
static uint8_t last_mod = 0;
|
|
||||||
|
|
||||||
if (usb_keyboard_has_key() || fn_bits == last_bits) {
|
|
||||||
// do nothing during press other than Fn key
|
|
||||||
return;
|
|
||||||
} else if (fn_bits == 0) {
|
|
||||||
// send key when Fn key is released without using the layer
|
|
||||||
if (!layer_used) {
|
|
||||||
uint8_t code = FN_KEYCODE(biton(last_bits));
|
|
||||||
if (code != KB_NO) {
|
|
||||||
if (IS_MOD(code)) {
|
|
||||||
keyboard_modifier_keys = last_mod | 1<<(code & 0x07);
|
|
||||||
} else {
|
|
||||||
keyboard_keys[0] = code;
|
|
||||||
keyboard_modifier_keys = last_mod;
|
|
||||||
}
|
|
||||||
usb_keyboard_send();
|
|
||||||
usb_keyboard_print();
|
|
||||||
usb_keyboard_clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
last_bits = 0;
|
|
||||||
last_mod = 0;
|
|
||||||
layer_used = false;
|
|
||||||
keymap_set_layer(0); // default layer
|
|
||||||
} else if ((fn_bits & (fn_bits - 1)) == 0) {
|
|
||||||
// switch layer when just one Fn Key is pressed
|
|
||||||
last_bits = fn_bits;
|
|
||||||
last_mod = keyboard_modifier_keys;
|
|
||||||
layer_used = false;
|
|
||||||
keymap_set_layer(FN_LAYER(biton(fn_bits)));
|
|
||||||
debug("layer: "); phex(current_layer); debug("(");
|
|
||||||
debug_bin(last_bits); debug(")\n");
|
|
||||||
debug("last_mod: "); debug_hex(last_mod); debug("\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
#ifndef KEYMAP_H
|
|
||||||
#define KEYMAP_H 1
|
|
||||||
|
|
||||||
#include "usb_keycodes.h"
|
|
||||||
#include "keymap_skel.h"
|
|
||||||
|
|
||||||
#endif
|
|
9
hhkb/led.c
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#include "stdint.h"
|
||||||
|
#include "led.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* HHKB has no LEDs */
|
||||||
|
void led_set(uint8_t usb_led)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
210
hhkb/matrix.c
@ -4,65 +4,116 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
#include <util/delay.h>
|
#include <util/delay.h>
|
||||||
#include "matrix.h"
|
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "matrix.h"
|
||||||
|
|
||||||
// matrix is active low. (key on: 0/key off: 1)
|
|
||||||
//
|
|
||||||
// HHKB has no ghost and no bounce.
|
|
||||||
// row: HC4051 select input channel(0-8)
|
|
||||||
// PB0, PB1, PB2(A, B, C)
|
|
||||||
// col: LS145 select low output line(0-8)
|
|
||||||
// PB3, PB4, PB5, PB6(A, B, C, D)
|
|
||||||
// use D as ENABLE: (enable: 0/unenable: 1)
|
|
||||||
// key: KEY: (on: 0/ off:1)
|
|
||||||
// UNKNOWN: unknown whether input or output
|
|
||||||
// PE6,PE7(KEY, UNKNOWN)
|
|
||||||
#define COL_ENABLE (1<<6)
|
|
||||||
#define KEY_SELELCT(ROW, COL) (PORTB = COL_ENABLE|(((COL)&0x07)<<3)|((ROW)&0x07))
|
|
||||||
#define KEY_ENABLE (PORTB &= ~COL_ENABLE)
|
|
||||||
#define KEY_UNABLE (PORTB |= COL_ENABLE)
|
|
||||||
#define KEY_ON ((PINE&(1<<6)) ? false : true)
|
|
||||||
|
|
||||||
// matrix state buffer
|
#if (MATRIX_COLS > 16)
|
||||||
uint8_t *matrix;
|
# error "MATRIX_COLS must not exceed 16"
|
||||||
uint8_t *matrix_prev;
|
#endif
|
||||||
|
#if (MATRIX_ROWS > 255)
|
||||||
|
# error "MATRIX_ROWS must not exceed 255"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// matrix state buffer(1:on, 0:off)
|
||||||
|
#if (MATRIX_COLS <= 8)
|
||||||
|
static uint8_t *matrix;
|
||||||
|
static uint8_t *matrix_prev;
|
||||||
static uint8_t _matrix0[MATRIX_ROWS];
|
static uint8_t _matrix0[MATRIX_ROWS];
|
||||||
static uint8_t _matrix1[MATRIX_ROWS];
|
static uint8_t _matrix1[MATRIX_ROWS];
|
||||||
|
#else
|
||||||
|
static uint16_t *matrix;
|
||||||
|
static uint16_t *matrix_prev;
|
||||||
|
static uint16_t _matrix0[MATRIX_ROWS];
|
||||||
|
static uint16_t _matrix1[MATRIX_ROWS];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// HHKB has no ghost and no bounce.
|
||||||
|
#ifdef MATRIX_HAS_GHOST
|
||||||
|
static bool matrix_has_ghost_in_row(uint8_t row);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Matrix I/O ports
|
||||||
|
//
|
||||||
|
// row: HC4051[A,B,C] selects scan row0-7
|
||||||
|
// col: LS145[A,B,C,D] selects scan col0-7 and enable(D)
|
||||||
|
// key: on: 0/off: 1
|
||||||
|
// prev: unknown: output previous key state(negated)?
|
||||||
|
|
||||||
|
#ifdef HOST_PJRC
|
||||||
|
// Ports for Teensy
|
||||||
|
// row: PB0-2
|
||||||
|
// col: PB3-5,6
|
||||||
|
// key: PE6(pull-uped)
|
||||||
|
// prev: PE7
|
||||||
|
#define KEY_INIT() do { \
|
||||||
|
DDRB |= 0x7F; \
|
||||||
|
DDRE |= (1<<7); \
|
||||||
|
DDRE &= ~(1<<6); \
|
||||||
|
PORTE |= (1<<6); \
|
||||||
|
} while (0)
|
||||||
|
#define KEY_SELECT(ROW, COL) (PORTB = (PORTB & 0xC0) | \
|
||||||
|
(((COL) & 0x07)<<3) | \
|
||||||
|
((ROW) & 0x07))
|
||||||
|
#define KEY_ENABLE() (PORTB &= ~(1<<6))
|
||||||
|
#define KEY_UNABLE() (PORTB |= (1<<6))
|
||||||
|
#define KEY_STATE() (PINE & (1<<6))
|
||||||
|
#define KEY_PREV_ON() (PORTE |= (1<<7))
|
||||||
|
#define KEY_PREV_OFF() (PORTE &= ~(1<<7))
|
||||||
|
|
||||||
|
#else
|
||||||
|
// Ports for V-USB
|
||||||
|
// key: PB0(pull-uped)
|
||||||
|
// prev: PB1
|
||||||
|
// row: PB2-4
|
||||||
|
// col: PC0-2,3
|
||||||
|
#define KEY_INIT() do { \
|
||||||
|
DDRB |= 0x1E; \
|
||||||
|
DDRB &= ~(1<<0); \
|
||||||
|
PORTB |= (1<<0); \
|
||||||
|
DDRC |= 0x0F; \
|
||||||
|
} while (0)
|
||||||
|
#define KEY_SELECT(ROW, COL) do { \
|
||||||
|
PORTB = (PORTB & 0xE3) | ((ROW) & 0x07)<<2; \
|
||||||
|
PORTC = (PORTC & 0xF8) | ((COL) & 0x07); \
|
||||||
|
} while (0)
|
||||||
|
#define KEY_ENABLE() (PORTC &= ~(1<<3))
|
||||||
|
#define KEY_UNABLE() (PORTC |= (1<<3))
|
||||||
|
#define KEY_STATE() (PINB & (1<<0))
|
||||||
|
#define KEY_PREV_ON() (PORTB |= (1<<1))
|
||||||
|
#define KEY_PREV_OFF() (PORTB &= ~(1<<1))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
inline
|
inline
|
||||||
int matrix_rows(void)
|
uint8_t matrix_rows(void)
|
||||||
{
|
{
|
||||||
return MATRIX_ROWS;
|
return MATRIX_ROWS;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
int matrix_cols(void)
|
uint8_t matrix_cols(void)
|
||||||
{
|
{
|
||||||
return MATRIX_COLS;
|
return MATRIX_COLS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this must be called once before matrix_scan.
|
|
||||||
void matrix_init(void)
|
void matrix_init(void)
|
||||||
{
|
{
|
||||||
// row & col output(PB0-6)
|
KEY_INIT();
|
||||||
DDRB = 0xFF;
|
|
||||||
PORTB = KEY_SELELCT(0, 0);
|
|
||||||
// KEY & VALID input with pullup(PE6,7)
|
|
||||||
DDRE = 0x3F;
|
|
||||||
PORTE = 0xC0;
|
|
||||||
|
|
||||||
// initialize matrix state: all keys off
|
// initialize matrix state: all keys off
|
||||||
for (int i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00;
|
for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00;
|
||||||
for (int i=0; i < MATRIX_ROWS; i++) _matrix1[i] = 0x00;
|
for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix1[i] = 0x00;
|
||||||
matrix = _matrix0;
|
matrix = _matrix0;
|
||||||
matrix_prev = _matrix1;
|
matrix_prev = _matrix1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int matrix_scan(void)
|
uint8_t matrix_scan(void)
|
||||||
{
|
{
|
||||||
uint8_t *tmp;
|
uint8_t *tmp;
|
||||||
|
|
||||||
@ -70,18 +121,33 @@ int matrix_scan(void)
|
|||||||
matrix_prev = matrix;
|
matrix_prev = matrix;
|
||||||
matrix = tmp;
|
matrix = tmp;
|
||||||
|
|
||||||
for (int row = 0; row < MATRIX_ROWS; row++) {
|
for (uint8_t row = 0; row < MATRIX_ROWS; row++) {
|
||||||
for (int col = 0; col < MATRIX_COLS; col++) {
|
for (uint8_t col = 0; col < MATRIX_COLS; col++) {
|
||||||
KEY_SELELCT(row, col);
|
KEY_SELECT(row, col);
|
||||||
_delay_us(50); // from logic analyzer chart
|
_delay_us(40); // from logic analyzer chart
|
||||||
KEY_ENABLE;
|
if (matrix_prev[row] & (1<<col)) {
|
||||||
_delay_us(10); // from logic analyzer chart
|
KEY_PREV_ON();
|
||||||
if (KEY_ON) {
|
|
||||||
matrix[row] |= (1<<col);
|
|
||||||
} else {
|
|
||||||
matrix[row] &= ~(1<<col);
|
|
||||||
}
|
}
|
||||||
KEY_UNABLE;
|
_delay_us(7); // from logic analyzer chart
|
||||||
|
|
||||||
|
#if HOST_VUSB
|
||||||
|
// to avoid V-USB interrupt during read key state
|
||||||
|
uint8_t sreg = SREG;
|
||||||
|
cli();
|
||||||
|
#endif
|
||||||
|
KEY_ENABLE();
|
||||||
|
_delay_us(10); // from logic analyzer chart
|
||||||
|
if (KEY_STATE()) {
|
||||||
|
matrix[row] &= ~(1<<col);
|
||||||
|
} else {
|
||||||
|
matrix[row] |= (1<<col);
|
||||||
|
}
|
||||||
|
#if HOST_VUSB
|
||||||
|
SREG = sreg;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
KEY_PREV_OFF();
|
||||||
|
KEY_UNABLE();
|
||||||
_delay_us(150); // from logic analyzer chart
|
_delay_us(150); // from logic analyzer chart
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -90,7 +156,7 @@ int matrix_scan(void)
|
|||||||
|
|
||||||
bool matrix_is_modified(void)
|
bool matrix_is_modified(void)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MATRIX_ROWS; i++) {
|
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
|
||||||
if (matrix[i] != matrix_prev[i])
|
if (matrix[i] != matrix_prev[i])
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -100,36 +166,80 @@ bool matrix_is_modified(void)
|
|||||||
inline
|
inline
|
||||||
bool matrix_has_ghost(void)
|
bool matrix_has_ghost(void)
|
||||||
{
|
{
|
||||||
|
#ifdef MATRIX_HAS_GHOST
|
||||||
|
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
|
||||||
|
if (matrix_has_ghost_in_row(i))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
bool matrix_is_on(int row, int col)
|
bool matrix_is_on(uint8_t row, uint8_t col)
|
||||||
{
|
{
|
||||||
return (matrix[row] & (1<<col));
|
return (matrix[row] & (1<<col));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
uint16_t matrix_get_row(int row)
|
#if (MATRIX_COLS <= 8)
|
||||||
|
uint8_t matrix_get_row(uint8_t row)
|
||||||
|
#else
|
||||||
|
uint16_t matrix_get_row(uint8_t row)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
return matrix[row];
|
return matrix[row];
|
||||||
}
|
}
|
||||||
|
|
||||||
void matrix_print(void)
|
void matrix_print(void)
|
||||||
{
|
{
|
||||||
|
#if (MATRIX_COLS <= 8)
|
||||||
print("\nr/c 01234567\n");
|
print("\nr/c 01234567\n");
|
||||||
for (int row = 0; row < matrix_rows(); row++) {
|
#else
|
||||||
|
print("\nr/c 0123456789ABCDEF\n");
|
||||||
|
#endif
|
||||||
|
for (uint8_t row = 0; row < matrix_rows(); row++) {
|
||||||
phex(row); print(": ");
|
phex(row); print(": ");
|
||||||
|
#if (MATRIX_COLS <= 8)
|
||||||
pbin_reverse(matrix_get_row(row));
|
pbin_reverse(matrix_get_row(row));
|
||||||
|
#else
|
||||||
|
pbin_reverse16(matrix_get_row(row));
|
||||||
|
#endif
|
||||||
|
#ifdef MATRIX_HAS_GHOST
|
||||||
|
if (matrix_has_ghost_in_row(row)) {
|
||||||
|
print(" <ghost");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
print("\n");
|
print("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int matrix_key_count(void)
|
uint8_t matrix_key_count(void)
|
||||||
{
|
{
|
||||||
int count = 0;
|
uint8_t count = 0;
|
||||||
for (int i = 0; i < MATRIX_ROWS; i++) {
|
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
|
||||||
|
#if (MATRIX_COLS <= 8)
|
||||||
count += bitpop(matrix[i]);
|
count += bitpop(matrix[i]);
|
||||||
|
#else
|
||||||
|
count += bitpop16(matrix[i]);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MATRIX_HAS_GHOST
|
||||||
|
inline
|
||||||
|
static bool matrix_has_ghost_in_row(uint8_t row)
|
||||||
|
{
|
||||||
|
// no ghost exists in case less than 2 keys on
|
||||||
|
if (((matrix[row] - 1) & matrix[row]) == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// ghost exists in case same state as other row
|
||||||
|
for (uint8_t i=0; i < MATRIX_ROWS; i++) {
|
||||||
|
if (i != row && (matrix[i] & matrix[row]) == matrix[row])
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
#ifndef MATRIX_H
|
|
||||||
#define MATRIX_H 1
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include "matrix_skel.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define MATRIX_ROWS 8
|
|
||||||
#define MATRIX_COLS 8
|
|
||||||
|
|
||||||
|
|
||||||
extern uint8_t *matrix;
|
|
||||||
extern uint8_t *matrix_prev;
|
|
||||||
|
|
||||||
#endif
|
|
378
hhkb/usbconfig.h
Normal file
@ -0,0 +1,378 @@
|
|||||||
|
/* Name: usbconfig.h
|
||||||
|
* Project: V-USB, virtual USB port for Atmel's(r) AVR(r) microcontrollers
|
||||||
|
* Author: Christian Starkjohann
|
||||||
|
* Creation Date: 2005-04-01
|
||||||
|
* Tabsize: 4
|
||||||
|
* Copyright: (c) 2005 by OBJECTIVE DEVELOPMENT Software GmbH
|
||||||
|
* License: GNU GPL v2 (see License.txt), GNU GPL v3 or proprietary (CommercialLicense.txt)
|
||||||
|
* This Revision: $Id: usbconfig-prototype.h 785 2010-05-30 17:57:07Z cs $
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __usbconfig_h_included__
|
||||||
|
#define __usbconfig_h_included__
|
||||||
|
|
||||||
|
#include "config_vusb.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
General Description:
|
||||||
|
This file is an example configuration (with inline documentation) for the USB
|
||||||
|
driver. It configures V-USB for USB D+ connected to Port D bit 2 (which is
|
||||||
|
also hardware interrupt 0 on many devices) and USB D- to Port D bit 4. You may
|
||||||
|
wire the lines to any other port, as long as D+ is also wired to INT0 (or any
|
||||||
|
other hardware interrupt, as long as it is the highest level interrupt, see
|
||||||
|
section at the end of this file).
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ---------------------------- Hardware Config ---------------------------- */
|
||||||
|
|
||||||
|
#define USB_CFG_IOPORTNAME D
|
||||||
|
/* This is the port where the USB bus is connected. When you configure it to
|
||||||
|
* "B", the registers PORTB, PINB and DDRB will be used.
|
||||||
|
*/
|
||||||
|
#define USB_CFG_DMINUS_BIT 3
|
||||||
|
/* This is the bit number in USB_CFG_IOPORT where the USB D- line is connected.
|
||||||
|
* This may be any bit in the port.
|
||||||
|
*/
|
||||||
|
#define USB_CFG_DPLUS_BIT 2
|
||||||
|
/* This is the bit number in USB_CFG_IOPORT where the USB D+ line is connected.
|
||||||
|
* This may be any bit in the port. Please note that D+ must also be connected
|
||||||
|
* to interrupt pin INT0! [You can also use other interrupts, see section
|
||||||
|
* "Optional MCU Description" below, or you can connect D- to the interrupt, as
|
||||||
|
* it is required if you use the USB_COUNT_SOF feature. If you use D- for the
|
||||||
|
* interrupt, the USB interrupt will also be triggered at Start-Of-Frame
|
||||||
|
* markers every millisecond.]
|
||||||
|
*/
|
||||||
|
#define USB_CFG_CLOCK_KHZ (F_CPU/1000)
|
||||||
|
/* Clock rate of the AVR in kHz. Legal values are 12000, 12800, 15000, 16000,
|
||||||
|
* 16500, 18000 and 20000. The 12.8 MHz and 16.5 MHz versions of the code
|
||||||
|
* require no crystal, they tolerate +/- 1% deviation from the nominal
|
||||||
|
* frequency. All other rates require a precision of 2000 ppm and thus a
|
||||||
|
* crystal!
|
||||||
|
* Since F_CPU should be defined to your actual clock rate anyway, you should
|
||||||
|
* not need to modify this setting.
|
||||||
|
*/
|
||||||
|
#define USB_CFG_CHECK_CRC 0
|
||||||
|
/* Define this to 1 if you want that the driver checks integrity of incoming
|
||||||
|
* data packets (CRC checks). CRC checks cost quite a bit of code size and are
|
||||||
|
* currently only available for 18 MHz crystal clock. You must choose
|
||||||
|
* USB_CFG_CLOCK_KHZ = 18000 if you enable this option.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ----------------------- Optional Hardware Config ------------------------ */
|
||||||
|
|
||||||
|
/* #define USB_CFG_PULLUP_IOPORTNAME D */
|
||||||
|
/* If you connect the 1.5k pullup resistor from D- to a port pin instead of
|
||||||
|
* V+, you can connect and disconnect the device from firmware by calling
|
||||||
|
* the macros usbDeviceConnect() and usbDeviceDisconnect() (see usbdrv.h).
|
||||||
|
* This constant defines the port on which the pullup resistor is connected.
|
||||||
|
*/
|
||||||
|
/* #define USB_CFG_PULLUP_BIT 4 */
|
||||||
|
/* This constant defines the bit number in USB_CFG_PULLUP_IOPORT (defined
|
||||||
|
* above) where the 1.5k pullup resistor is connected. See description
|
||||||
|
* above for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* --------------------------- Functional Range ---------------------------- */
|
||||||
|
|
||||||
|
#define USB_CFG_HAVE_INTRIN_ENDPOINT 1
|
||||||
|
/* Define this to 1 if you want to compile a version with two endpoints: The
|
||||||
|
* default control endpoint 0 and an interrupt-in endpoint (any other endpoint
|
||||||
|
* number).
|
||||||
|
*/
|
||||||
|
#define USB_CFG_HAVE_INTRIN_ENDPOINT3 1
|
||||||
|
/* Define this to 1 if you want to compile a version with three endpoints: The
|
||||||
|
* default control endpoint 0, an interrupt-in endpoint 3 (or the number
|
||||||
|
* configured below) and a catch-all default interrupt-in endpoint as above.
|
||||||
|
* You must also define USB_CFG_HAVE_INTRIN_ENDPOINT to 1 for this feature.
|
||||||
|
*/
|
||||||
|
#define USB_CFG_EP3_NUMBER 3
|
||||||
|
/* If the so-called endpoint 3 is used, it can now be configured to any other
|
||||||
|
* endpoint number (except 0) with this macro. Default if undefined is 3.
|
||||||
|
*/
|
||||||
|
/* #define USB_INITIAL_DATATOKEN USBPID_DATA1 */
|
||||||
|
/* The above macro defines the startup condition for data toggling on the
|
||||||
|
* interrupt/bulk endpoints 1 and 3. Defaults to USBPID_DATA1.
|
||||||
|
* Since the token is toggled BEFORE sending any data, the first packet is
|
||||||
|
* sent with the oposite value of this configuration!
|
||||||
|
*/
|
||||||
|
#define USB_CFG_IMPLEMENT_HALT 0
|
||||||
|
/* Define this to 1 if you also want to implement the ENDPOINT_HALT feature
|
||||||
|
* for endpoint 1 (interrupt endpoint). Although you may not need this feature,
|
||||||
|
* it is required by the standard. We have made it a config option because it
|
||||||
|
* bloats the code considerably.
|
||||||
|
*/
|
||||||
|
#define USB_CFG_SUPPRESS_INTR_CODE 0
|
||||||
|
/* Define this to 1 if you want to declare interrupt-in endpoints, but don't
|
||||||
|
* want to send any data over them. If this macro is defined to 1, functions
|
||||||
|
* usbSetInterrupt() and usbSetInterrupt3() are omitted. This is useful if
|
||||||
|
* you need the interrupt-in endpoints in order to comply to an interface
|
||||||
|
* (e.g. HID), but never want to send any data. This option saves a couple
|
||||||
|
* of bytes in flash memory and the transmit buffers in RAM.
|
||||||
|
*/
|
||||||
|
#define USB_CFG_INTR_POLL_INTERVAL 10
|
||||||
|
/* If you compile a version with endpoint 1 (interrupt-in), this is the poll
|
||||||
|
* interval. The value is in milliseconds and must not be less than 10 ms for
|
||||||
|
* low speed devices.
|
||||||
|
*/
|
||||||
|
#define USB_CFG_IS_SELF_POWERED 0
|
||||||
|
/* Define this to 1 if the device has its own power supply. Set it to 0 if the
|
||||||
|
* device is powered from the USB bus.
|
||||||
|
*/
|
||||||
|
#define USB_CFG_MAX_BUS_POWER 100
|
||||||
|
/* Set this variable to the maximum USB bus power consumption of your device.
|
||||||
|
* The value is in milliamperes. [It will be divided by two since USB
|
||||||
|
* communicates power requirements in units of 2 mA.]
|
||||||
|
*/
|
||||||
|
#define USB_CFG_IMPLEMENT_FN_WRITE 1
|
||||||
|
/* Set this to 1 if you want usbFunctionWrite() to be called for control-out
|
||||||
|
* transfers. Set it to 0 if you don't need it and want to save a couple of
|
||||||
|
* bytes.
|
||||||
|
*/
|
||||||
|
#define USB_CFG_IMPLEMENT_FN_READ 0
|
||||||
|
/* Set this to 1 if you need to send control replies which are generated
|
||||||
|
* "on the fly" when usbFunctionRead() is called. If you only want to send
|
||||||
|
* data from a static buffer, set it to 0 and return the data from
|
||||||
|
* usbFunctionSetup(). This saves a couple of bytes.
|
||||||
|
*/
|
||||||
|
#define USB_CFG_IMPLEMENT_FN_WRITEOUT 0
|
||||||
|
/* Define this to 1 if you want to use interrupt-out (or bulk out) endpoints.
|
||||||
|
* You must implement the function usbFunctionWriteOut() which receives all
|
||||||
|
* interrupt/bulk data sent to any endpoint other than 0. The endpoint number
|
||||||
|
* can be found in 'usbRxToken'.
|
||||||
|
*/
|
||||||
|
#define USB_CFG_HAVE_FLOWCONTROL 0
|
||||||
|
/* Define this to 1 if you want flowcontrol over USB data. See the definition
|
||||||
|
* of the macros usbDisableAllRequests() and usbEnableAllRequests() in
|
||||||
|
* usbdrv.h.
|
||||||
|
*/
|
||||||
|
#define USB_CFG_DRIVER_FLASH_PAGE 0
|
||||||
|
/* If the device has more than 64 kBytes of flash, define this to the 64 k page
|
||||||
|
* where the driver's constants (descriptors) are located. Or in other words:
|
||||||
|
* Define this to 1 for boot loaders on the ATMega128.
|
||||||
|
*/
|
||||||
|
#define USB_CFG_LONG_TRANSFERS 0
|
||||||
|
/* Define this to 1 if you want to send/receive blocks of more than 254 bytes
|
||||||
|
* in a single control-in or control-out transfer. Note that the capability
|
||||||
|
* for long transfers increases the driver size.
|
||||||
|
*/
|
||||||
|
/* #define USB_RX_USER_HOOK(data, len) if(usbRxToken == (uchar)USBPID_SETUP) blinkLED(); */
|
||||||
|
/* This macro is a hook if you want to do unconventional things. If it is
|
||||||
|
* defined, it's inserted at the beginning of received message processing.
|
||||||
|
* If you eat the received message and don't want default processing to
|
||||||
|
* proceed, do a return after doing your things. One possible application
|
||||||
|
* (besides debugging) is to flash a status LED on each packet.
|
||||||
|
*/
|
||||||
|
/* #define USB_RESET_HOOK(resetStarts) if(!resetStarts){hadUsbReset();} */
|
||||||
|
/* This macro is a hook if you need to know when an USB RESET occurs. It has
|
||||||
|
* one parameter which distinguishes between the start of RESET state and its
|
||||||
|
* end.
|
||||||
|
*/
|
||||||
|
/* #define USB_SET_ADDRESS_HOOK() hadAddressAssigned(); */
|
||||||
|
/* This macro (if defined) is executed when a USB SET_ADDRESS request was
|
||||||
|
* received.
|
||||||
|
*/
|
||||||
|
#define USB_COUNT_SOF 0
|
||||||
|
/* define this macro to 1 if you need the global variable "usbSofCount" which
|
||||||
|
* counts SOF packets. This feature requires that the hardware interrupt is
|
||||||
|
* connected to D- instead of D+.
|
||||||
|
*/
|
||||||
|
/* #ifdef __ASSEMBLER__
|
||||||
|
* macro myAssemblerMacro
|
||||||
|
* in YL, TCNT0
|
||||||
|
* sts timer0Snapshot, YL
|
||||||
|
* endm
|
||||||
|
* #endif
|
||||||
|
* #define USB_SOF_HOOK myAssemblerMacro
|
||||||
|
* This macro (if defined) is executed in the assembler module when a
|
||||||
|
* Start Of Frame condition is detected. It is recommended to define it to
|
||||||
|
* the name of an assembler macro which is defined here as well so that more
|
||||||
|
* than one assembler instruction can be used. The macro may use the register
|
||||||
|
* YL and modify SREG. If it lasts longer than a couple of cycles, USB messages
|
||||||
|
* immediately after an SOF pulse may be lost and must be retried by the host.
|
||||||
|
* What can you do with this hook? Since the SOF signal occurs exactly every
|
||||||
|
* 1 ms (unless the host is in sleep mode), you can use it to tune OSCCAL in
|
||||||
|
* designs running on the internal RC oscillator.
|
||||||
|
* Please note that Start Of Frame detection works only if D- is wired to the
|
||||||
|
* interrupt, not D+. THIS IS DIFFERENT THAN MOST EXAMPLES!
|
||||||
|
*/
|
||||||
|
#define USB_CFG_CHECK_DATA_TOGGLING 0
|
||||||
|
/* define this macro to 1 if you want to filter out duplicate data packets
|
||||||
|
* sent by the host. Duplicates occur only as a consequence of communication
|
||||||
|
* errors, when the host does not receive an ACK. Please note that you need to
|
||||||
|
* implement the filtering yourself in usbFunctionWriteOut() and
|
||||||
|
* usbFunctionWrite(). Use the global usbCurrentDataToken and a static variable
|
||||||
|
* for each control- and out-endpoint to check for duplicate packets.
|
||||||
|
*/
|
||||||
|
#define USB_CFG_HAVE_MEASURE_FRAME_LENGTH 0
|
||||||
|
/* define this macro to 1 if you want the function usbMeasureFrameLength()
|
||||||
|
* compiled in. This function can be used to calibrate the AVR's RC oscillator.
|
||||||
|
*/
|
||||||
|
#define USB_USE_FAST_CRC 0
|
||||||
|
/* The assembler module has two implementations for the CRC algorithm. One is
|
||||||
|
* faster, the other is smaller. This CRC routine is only used for transmitted
|
||||||
|
* messages where timing is not critical. The faster routine needs 31 cycles
|
||||||
|
* per byte while the smaller one needs 61 to 69 cycles. The faster routine
|
||||||
|
* may be worth the 32 bytes bigger code size if you transmit lots of data and
|
||||||
|
* run the AVR close to its limit.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* -------------------------- Device Description --------------------------- */
|
||||||
|
|
||||||
|
#define USB_CFG_VENDOR_ID (VENDOR_ID & 0xFF), ((VENDOR_ID >> 8) & 0xFF)
|
||||||
|
/* USB vendor ID for the device, low byte first. If you have registered your
|
||||||
|
* own Vendor ID, define it here. Otherwise you may use one of obdev's free
|
||||||
|
* shared VID/PID pairs. Be sure to read USB-IDs-for-free.txt for rules!
|
||||||
|
* *** IMPORTANT NOTE ***
|
||||||
|
* This template uses obdev's shared VID/PID pair for Vendor Class devices
|
||||||
|
* with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand
|
||||||
|
* the implications!
|
||||||
|
*/
|
||||||
|
#define USB_CFG_DEVICE_ID (PRODUCT_ID & 0xFF), ((PRODUCT_ID >> 8) & 0xFF)
|
||||||
|
/* This is the ID of the product, low byte first. It is interpreted in the
|
||||||
|
* scope of the vendor ID. If you have registered your own VID with usb.org
|
||||||
|
* or if you have licensed a PID from somebody else, define it here. Otherwise
|
||||||
|
* you may use one of obdev's free shared VID/PID pairs. See the file
|
||||||
|
* USB-IDs-for-free.txt for details!
|
||||||
|
* *** IMPORTANT NOTE ***
|
||||||
|
* This template uses obdev's shared VID/PID pair for Vendor Class devices
|
||||||
|
* with libusb: 0x16c0/0x5dc. Use this VID/PID pair ONLY if you understand
|
||||||
|
* the implications!
|
||||||
|
*/
|
||||||
|
#define USB_CFG_DEVICE_VERSION 0x00, 0x01
|
||||||
|
/* Version number of the device: Minor number first, then major number.
|
||||||
|
*/
|
||||||
|
#define USB_CFG_VENDOR_NAME 't', '.', 'm', '.', 'k', '.'
|
||||||
|
#define USB_CFG_VENDOR_NAME_LEN 6
|
||||||
|
/* These two values define the vendor name returned by the USB device. The name
|
||||||
|
* must be given as a list of characters under single quotes. The characters
|
||||||
|
* are interpreted as Unicode (UTF-16) entities.
|
||||||
|
* If you don't want a vendor name string, undefine these macros.
|
||||||
|
* ALWAYS define a vendor name containing your Internet domain name if you use
|
||||||
|
* obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for
|
||||||
|
* details.
|
||||||
|
*/
|
||||||
|
#define USB_CFG_DEVICE_NAME 'H', 'H', 'K', 'B', ' ', 'm', 'o', 'd'
|
||||||
|
#define USB_CFG_DEVICE_NAME_LEN 8
|
||||||
|
/* Same as above for the device name. If you don't want a device name, undefine
|
||||||
|
* the macros. See the file USB-IDs-for-free.txt before you assign a name if
|
||||||
|
* you use a shared VID/PID.
|
||||||
|
*/
|
||||||
|
/*#define USB_CFG_SERIAL_NUMBER 'N', 'o', 'n', 'e' */
|
||||||
|
/*#define USB_CFG_SERIAL_NUMBER_LEN 0 */
|
||||||
|
/* Same as above for the serial number. If you don't want a serial number,
|
||||||
|
* undefine the macros.
|
||||||
|
* It may be useful to provide the serial number through other means than at
|
||||||
|
* compile time. See the section about descriptor properties below for how
|
||||||
|
* to fine tune control over USB descriptors such as the string descriptor
|
||||||
|
* for the serial number.
|
||||||
|
*/
|
||||||
|
#define USB_CFG_DEVICE_CLASS 0
|
||||||
|
#define USB_CFG_DEVICE_SUBCLASS 0
|
||||||
|
/* See USB specification if you want to conform to an existing device class.
|
||||||
|
* Class 0xff is "vendor specific".
|
||||||
|
*/
|
||||||
|
#define USB_CFG_INTERFACE_CLASS 3 /* HID */
|
||||||
|
#define USB_CFG_INTERFACE_SUBCLASS 1 /* Boot */
|
||||||
|
#define USB_CFG_INTERFACE_PROTOCOL 1 /* Keyboard */
|
||||||
|
/* See USB specification if you want to conform to an existing device class or
|
||||||
|
* protocol. The following classes must be set at interface level:
|
||||||
|
* HID class is 3, no subclass and protocol required (but may be useful!)
|
||||||
|
* CDC class is 2, use subclass 2 and protocol 1 for ACM
|
||||||
|
*/
|
||||||
|
#define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH 0
|
||||||
|
/* Define this to the length of the HID report descriptor, if you implement
|
||||||
|
* an HID device. Otherwise don't define it or define it to 0.
|
||||||
|
* If you use this define, you must add a PROGMEM character array named
|
||||||
|
* "usbHidReportDescriptor" to your code which contains the report descriptor.
|
||||||
|
* Don't forget to keep the array and this define in sync!
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* #define USB_PUBLIC static */
|
||||||
|
/* Use the define above if you #include usbdrv.c instead of linking against it.
|
||||||
|
* This technique saves a couple of bytes in flash memory.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* ------------------- Fine Control over USB Descriptors ------------------- */
|
||||||
|
/* If you don't want to use the driver's default USB descriptors, you can
|
||||||
|
* provide our own. These can be provided as (1) fixed length static data in
|
||||||
|
* flash memory, (2) fixed length static data in RAM or (3) dynamically at
|
||||||
|
* runtime in the function usbFunctionDescriptor(). See usbdrv.h for more
|
||||||
|
* information about this function.
|
||||||
|
* Descriptor handling is configured through the descriptor's properties. If
|
||||||
|
* no properties are defined or if they are 0, the default descriptor is used.
|
||||||
|
* Possible properties are:
|
||||||
|
* + USB_PROP_IS_DYNAMIC: The data for the descriptor should be fetched
|
||||||
|
* at runtime via usbFunctionDescriptor(). If the usbMsgPtr mechanism is
|
||||||
|
* used, the data is in FLASH by default. Add property USB_PROP_IS_RAM if
|
||||||
|
* you want RAM pointers.
|
||||||
|
* + USB_PROP_IS_RAM: The data returned by usbFunctionDescriptor() or found
|
||||||
|
* in static memory is in RAM, not in flash memory.
|
||||||
|
* + USB_PROP_LENGTH(len): If the data is in static memory (RAM or flash),
|
||||||
|
* the driver must know the descriptor's length. The descriptor itself is
|
||||||
|
* found at the address of a well known identifier (see below).
|
||||||
|
* List of static descriptor names (must be declared PROGMEM if in flash):
|
||||||
|
* char usbDescriptorDevice[];
|
||||||
|
* char usbDescriptorConfiguration[];
|
||||||
|
* char usbDescriptorHidReport[];
|
||||||
|
* char usbDescriptorString0[];
|
||||||
|
* int usbDescriptorStringVendor[];
|
||||||
|
* int usbDescriptorStringDevice[];
|
||||||
|
* int usbDescriptorStringSerialNumber[];
|
||||||
|
* Other descriptors can't be provided statically, they must be provided
|
||||||
|
* dynamically at runtime.
|
||||||
|
*
|
||||||
|
* Descriptor properties are or-ed or added together, e.g.:
|
||||||
|
* #define USB_CFG_DESCR_PROPS_DEVICE (USB_PROP_IS_RAM | USB_PROP_LENGTH(18))
|
||||||
|
*
|
||||||
|
* The following descriptors are defined:
|
||||||
|
* USB_CFG_DESCR_PROPS_DEVICE
|
||||||
|
* USB_CFG_DESCR_PROPS_CONFIGURATION
|
||||||
|
* USB_CFG_DESCR_PROPS_STRINGS
|
||||||
|
* USB_CFG_DESCR_PROPS_STRING_0
|
||||||
|
* USB_CFG_DESCR_PROPS_STRING_VENDOR
|
||||||
|
* USB_CFG_DESCR_PROPS_STRING_PRODUCT
|
||||||
|
* USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER
|
||||||
|
* USB_CFG_DESCR_PROPS_HID
|
||||||
|
* USB_CFG_DESCR_PROPS_HID_REPORT
|
||||||
|
* USB_CFG_DESCR_PROPS_UNKNOWN (for all descriptors not handled by the driver)
|
||||||
|
*
|
||||||
|
* Note about string descriptors: String descriptors are not just strings, they
|
||||||
|
* are Unicode strings prefixed with a 2 byte header. Example:
|
||||||
|
* int serialNumberDescriptor[] = {
|
||||||
|
* USB_STRING_DESCRIPTOR_HEADER(6),
|
||||||
|
* 'S', 'e', 'r', 'i', 'a', 'l'
|
||||||
|
* };
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define USB_CFG_DESCR_PROPS_DEVICE 0
|
||||||
|
#define USB_CFG_DESCR_PROPS_CONFIGURATION USB_PROP_IS_DYNAMIC
|
||||||
|
//#define USB_CFG_DESCR_PROPS_CONFIGURATION 0
|
||||||
|
#define USB_CFG_DESCR_PROPS_STRINGS 0
|
||||||
|
#define USB_CFG_DESCR_PROPS_STRING_0 0
|
||||||
|
#define USB_CFG_DESCR_PROPS_STRING_VENDOR 0
|
||||||
|
#define USB_CFG_DESCR_PROPS_STRING_PRODUCT 0
|
||||||
|
#define USB_CFG_DESCR_PROPS_STRING_SERIAL_NUMBER 0
|
||||||
|
//#define USB_CFG_DESCR_PROPS_HID USB_PROP_IS_DYNAMIC
|
||||||
|
#define USB_CFG_DESCR_PROPS_HID 0
|
||||||
|
#define USB_CFG_DESCR_PROPS_HID_REPORT USB_PROP_IS_DYNAMIC
|
||||||
|
//#define USB_CFG_DESCR_PROPS_HID_REPORT 0
|
||||||
|
#define USB_CFG_DESCR_PROPS_UNKNOWN 0
|
||||||
|
|
||||||
|
/* ----------------------- Optional MCU Description ------------------------ */
|
||||||
|
|
||||||
|
/* The following configurations have working defaults in usbdrv.h. You
|
||||||
|
* usually don't need to set them explicitly. Only if you want to run
|
||||||
|
* the driver on a device which is not yet supported or with a compiler
|
||||||
|
* which is not fully supported (such as IAR C) or if you use a differnt
|
||||||
|
* interrupt than INT0, you may have to define some of these.
|
||||||
|
*/
|
||||||
|
/* #define USB_INTR_CFG MCUCR */
|
||||||
|
/* #define USB_INTR_CFG_SET ((1 << ISC00) | (1 << ISC01)) */
|
||||||
|
/* #define USB_INTR_CFG_CLR 0 */
|
||||||
|
/* #define USB_INTR_ENABLE GIMSK */
|
||||||
|
/* #define USB_INTR_ENABLE_BIT INT0 */
|
||||||
|
/* #define USB_INTR_PENDING GIFR */
|
||||||
|
/* #define USB_INTR_PENDING_BIT INTF0 */
|
||||||
|
/* #define USB_INTR_VECTOR INT0_vect */
|
||||||
|
|
||||||
|
#endif /* __usbconfig_h_included__ */
|
116
host.h
Normal file
@ -0,0 +1,116 @@
|
|||||||
|
#ifndef HOST_H
|
||||||
|
#define HOST_H
|
||||||
|
|
||||||
|
#include <stdint.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
|
||||||
|
extern bool keyboard_nkro;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern report_keyboard_t *keyboard_report;
|
||||||
|
extern report_keyboard_t *keyboard_report_prev;
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t host_keyboard_leds(void);
|
||||||
|
|
||||||
|
/* keyboard report operations */
|
||||||
|
void host_add_key(uint8_t key);
|
||||||
|
void host_add_mod_bit(uint8_t mod);
|
||||||
|
void host_set_mods(uint8_t mods);
|
||||||
|
void host_add_code(uint8_t code);
|
||||||
|
void host_swap_keyboard_report(void);
|
||||||
|
void host_clear_keyboard_report(void);
|
||||||
|
uint8_t host_has_anykey(void);
|
||||||
|
uint8_t host_get_first_key(void);
|
||||||
|
|
||||||
|
|
||||||
|
void host_send_keyboard_report(void);
|
||||||
|
#if defined(MOUSEKEY_ENABLE) || defined(PS2_MOUSE_ENABLE)
|
||||||
|
void host_mouse_send(report_mouse_t *report);
|
||||||
|
#endif
|
||||||
|
#ifdef USB_EXTRA_ENABLE
|
||||||
|
void host_system_send(uint16_t data);
|
||||||
|
void host_consumer_send(uint16_t data);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -1,35 +0,0 @@
|
|||||||
// this code from:
|
|
||||||
// http://www.pjrc.com/teensy/jump_to_bootloader.html
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <avr/interrupt.h>
|
|
||||||
#include <util/delay.h>
|
|
||||||
|
|
||||||
void jump_bootloader(void) {
|
|
||||||
cli();
|
|
||||||
// disable watchdog, if enabled
|
|
||||||
// disable all peripherals
|
|
||||||
UDCON = 1;
|
|
||||||
USBCON = (1<<FRZCLK); // disable USB
|
|
||||||
UCSR1B = 0;
|
|
||||||
_delay_ms(5);
|
|
||||||
#if defined(__AVR_AT90USB162__) // Teensy 1.0
|
|
||||||
DDRB = 0; DDRC = 0; DDRD = 0;
|
|
||||||
TIMSK0 = 0; TIMSK1 = 0;
|
|
||||||
asm volatile("jmp 0x1F00");
|
|
||||||
#elif defined(__AVR_ATmega32U4__) // Teensy 2.0
|
|
||||||
DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
|
|
||||||
TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0;
|
|
||||||
ADCSRA = 0;
|
|
||||||
asm volatile("jmp 0x3F00");
|
|
||||||
#elif defined(__AVR_AT90USB646__) // Teensy++ 1.0
|
|
||||||
DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
|
|
||||||
TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0;
|
|
||||||
ADCSRA = 0;
|
|
||||||
asm volatile("jmp 0x7E00");
|
|
||||||
#elif defined(__AVR_AT90USB1286__) // Teensy++ 2.0
|
|
||||||
DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
|
|
||||||
TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0;
|
|
||||||
ADCSRA = 0;
|
|
||||||
asm volatile("jmp 0xFE00");
|
|
||||||
#endif
|
|
||||||
}
|
|
200
key_process.c
@ -1,200 +0,0 @@
|
|||||||
#include <stdbool.h>
|
|
||||||
#include <avr/io.h>
|
|
||||||
#include <util/delay.h>
|
|
||||||
#include "usb_keyboard.h"
|
|
||||||
#include "usb_mouse.h"
|
|
||||||
#include "usb_keycodes.h"
|
|
||||||
#include "print.h"
|
|
||||||
#include "debug.h"
|
|
||||||
#include "util.h"
|
|
||||||
#include "jump_bootloader.h"
|
|
||||||
#include "matrix_skel.h"
|
|
||||||
#include "keymap_skel.h"
|
|
||||||
#include "controller.h"
|
|
||||||
|
|
||||||
#include "key_process.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define MOUSE_MOVE_UNIT 10
|
|
||||||
#define MOUSE_MOVE_ACCEL (mouse_repeat < 50 ? mouse_repeat/5 : 10)
|
|
||||||
|
|
||||||
#ifndef MOUSE_DELAY_TIME
|
|
||||||
# define MOUSE_DELAY_TIME 255
|
|
||||||
#endif
|
|
||||||
#define MOUSE_DELAY_MS (MOUSE_DELAY_TIME >> (mouse_repeat < 5 ? mouse_repeat : 4))
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: refactoring
|
|
||||||
void proc_matrix(void) {
|
|
||||||
static int mouse_repeat = 0;
|
|
||||||
|
|
||||||
bool modified = false;
|
|
||||||
//bool has_ghost = false;
|
|
||||||
int key_index = 0;
|
|
||||||
uint8_t mouse_btn = 0;
|
|
||||||
int8_t mouse_x = 0;
|
|
||||||
int8_t mouse_y = 0;
|
|
||||||
int8_t mouse_vwheel = 0;
|
|
||||||
int8_t mouse_hwheel = 0;
|
|
||||||
int fn_bits = 0;
|
|
||||||
|
|
||||||
matrix_scan();
|
|
||||||
modified = matrix_is_modified();
|
|
||||||
|
|
||||||
if (modified) {
|
|
||||||
if (debug_matrix) matrix_print();
|
|
||||||
#ifdef DEBUG_LED
|
|
||||||
// LED flash for debug
|
|
||||||
DEBUG_LED_CONFIG;
|
|
||||||
DEBUG_LED_ON;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
if (matrix_has_ghost()) {
|
|
||||||
// should send error?
|
|
||||||
debug("matrix has ghost!!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
usb_keyboard_clear();
|
|
||||||
for (int row = 0; row < matrix_rows(); row++) {
|
|
||||||
for (int col = 0; col < matrix_cols(); col++) {
|
|
||||||
if (!matrix_is_on(row, col)) continue;
|
|
||||||
|
|
||||||
uint8_t code = keymap_get_keycode(row, col);
|
|
||||||
if (code == KB_NO) {
|
|
||||||
// do nothing
|
|
||||||
} else if (IS_MOD(code)) {
|
|
||||||
keyboard_modifier_keys |= MOD_BIT(code);
|
|
||||||
} else if (IS_MOUSE(code)) {
|
|
||||||
// mouse
|
|
||||||
if (code == MS_UP)
|
|
||||||
mouse_y -= MOUSE_MOVE_UNIT + MOUSE_MOVE_ACCEL;
|
|
||||||
if (code == MS_DOWN)
|
|
||||||
mouse_y += MOUSE_MOVE_UNIT + MOUSE_MOVE_ACCEL;
|
|
||||||
if (code == MS_LEFT)
|
|
||||||
mouse_x -= MOUSE_MOVE_UNIT + MOUSE_MOVE_ACCEL;
|
|
||||||
if (code == MS_RIGHT)
|
|
||||||
mouse_x += MOUSE_MOVE_UNIT + MOUSE_MOVE_ACCEL;
|
|
||||||
if (code == MS_BTN1) mouse_btn |= BIT_BTN1;
|
|
||||||
if (code == MS_BTN2) mouse_btn |= BIT_BTN2;
|
|
||||||
if (code == MS_BTN3) mouse_btn |= BIT_BTN3;
|
|
||||||
if (code == MS_BTN4) mouse_btn |= BIT_BTN4;
|
|
||||||
if (code == MS_BTN5) mouse_btn |= BIT_BTN5;
|
|
||||||
if (code == MS_WH_UP) mouse_vwheel += 1;
|
|
||||||
if (code == MS_WH_DOWN) mouse_vwheel -= 1;
|
|
||||||
if (code == MS_WH_LEFT) mouse_hwheel -= 1;
|
|
||||||
if (code == MS_WH_RIGHT) mouse_hwheel += 1;
|
|
||||||
} else if (IS_FN(code)) {
|
|
||||||
fn_bits |= FN_BIT(code);
|
|
||||||
} else {
|
|
||||||
// normal keys
|
|
||||||
if (key_index < 6)
|
|
||||||
keyboard_keys[key_index] = code;
|
|
||||||
key_index++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
keymap_fn_proc(fn_bits);
|
|
||||||
|
|
||||||
// when 4 left modifier keys down
|
|
||||||
if (keymap_is_special_mode(fn_bits)) {
|
|
||||||
switch (keyboard_keys[0]) {
|
|
||||||
case KB_B: // bootloader
|
|
||||||
usb_keyboard_clear();
|
|
||||||
usb_keyboard_send();
|
|
||||||
print_enable = true;
|
|
||||||
print("jump to bootloader...\n");
|
|
||||||
_delay_ms(1000);
|
|
||||||
jump_bootloader(); // not return
|
|
||||||
break;
|
|
||||||
case KB_D: // debug all toggle
|
|
||||||
usb_keyboard_clear();
|
|
||||||
usb_keyboard_send();
|
|
||||||
debug_enable = !debug_enable;
|
|
||||||
if (debug_enable) {
|
|
||||||
print("debug enabled.\n");
|
|
||||||
print_enable = true;
|
|
||||||
debug_matrix = true;
|
|
||||||
debug_keyboard = true;
|
|
||||||
debug_mouse = true;
|
|
||||||
} else {
|
|
||||||
print("debug disabled.\n");
|
|
||||||
print_enable = false;
|
|
||||||
debug_matrix = false;
|
|
||||||
debug_keyboard = false;
|
|
||||||
debug_mouse = false;
|
|
||||||
}
|
|
||||||
_delay_ms(1000);
|
|
||||||
break;
|
|
||||||
case KB_X: // debug matrix toggle
|
|
||||||
usb_keyboard_clear();
|
|
||||||
usb_keyboard_send();
|
|
||||||
debug_matrix = !debug_matrix;
|
|
||||||
if (debug_matrix)
|
|
||||||
print("debug matrix enabled.\n");
|
|
||||||
else
|
|
||||||
print("debug matrix disabled.\n");
|
|
||||||
_delay_ms(1000);
|
|
||||||
break;
|
|
||||||
case KB_K: // debug keyboard toggle
|
|
||||||
usb_keyboard_clear();
|
|
||||||
usb_keyboard_send();
|
|
||||||
debug_keyboard = !debug_keyboard;
|
|
||||||
if (debug_keyboard)
|
|
||||||
print("debug keyboard enabled.\n");
|
|
||||||
else
|
|
||||||
print("debug keyboard disabled.\n");
|
|
||||||
_delay_ms(1000);
|
|
||||||
break;
|
|
||||||
case KB_M: // debug mouse toggle
|
|
||||||
usb_keyboard_clear();
|
|
||||||
usb_keyboard_send();
|
|
||||||
debug_mouse = !debug_mouse;
|
|
||||||
if (debug_mouse)
|
|
||||||
print("debug mouse enabled.\n");
|
|
||||||
else
|
|
||||||
print("debug mouse disabled.\n");
|
|
||||||
_delay_ms(1000);
|
|
||||||
break;
|
|
||||||
case KB_V: // print version & information
|
|
||||||
usb_keyboard_clear();
|
|
||||||
usb_keyboard_send();
|
|
||||||
print(STR(DESCRIPTION) "\n");
|
|
||||||
_delay_ms(1000);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// send mouse packet to host
|
|
||||||
if (mouse_x || mouse_y || mouse_vwheel || mouse_hwheel || mouse_btn != mouse_buttons) {
|
|
||||||
mouse_buttons = mouse_btn;
|
|
||||||
if (mouse_x && mouse_y)
|
|
||||||
usb_mouse_move(mouse_x*0.7, mouse_y*0.7, mouse_vwheel, mouse_hwheel);
|
|
||||||
else
|
|
||||||
usb_mouse_move(mouse_x, mouse_y, mouse_vwheel, mouse_hwheel);
|
|
||||||
usb_mouse_print(mouse_x, mouse_y, mouse_vwheel, mouse_hwheel);
|
|
||||||
|
|
||||||
// acceleration
|
|
||||||
_delay_ms(MOUSE_DELAY_MS);
|
|
||||||
mouse_repeat++;
|
|
||||||
} else {
|
|
||||||
mouse_repeat = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// send key packet to host
|
|
||||||
if (modified) {
|
|
||||||
if (key_index > 6) {
|
|
||||||
//Rollover
|
|
||||||
}
|
|
||||||
usb_keyboard_send();
|
|
||||||
usb_keyboard_print();
|
|
||||||
#ifdef DEBUG_LED
|
|
||||||
// LED flash for debug
|
|
||||||
DEBUG_LED_CONFIG;
|
|
||||||
DEBUG_LED_OFF;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +0,0 @@
|
|||||||
#ifndef KEY_PROCESS_H
|
|
||||||
#define KEY_PROCESS_H 1
|
|
||||||
|
|
||||||
|
|
||||||
void proc_matrix(void);
|
|
||||||
|
|
||||||
#endif
|
|
196
keyboard.c
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
#include "keyboard.h"
|
||||||
|
#include "host.h"
|
||||||
|
#include "layer.h"
|
||||||
|
#include "matrix.h"
|
||||||
|
#include "led.h"
|
||||||
|
#include "usb_keycodes.h"
|
||||||
|
#include "timer.h"
|
||||||
|
#include "print.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "command.h"
|
||||||
|
#ifdef MOUSEKEY_ENABLE
|
||||||
|
#include "mousekey.h"
|
||||||
|
#endif
|
||||||
|
#ifdef USB_EXTRA_ENABLE
|
||||||
|
#include <util/delay.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t last_leds = 0;
|
||||||
|
static bool scroll_lock = false;
|
||||||
|
|
||||||
|
|
||||||
|
void keyboard_init(void)
|
||||||
|
{
|
||||||
|
timer_init();
|
||||||
|
matrix_init();
|
||||||
|
#ifdef PS2_MOUSE_ENABLE
|
||||||
|
ps2_mouse_init();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void keyboard_proc(void)
|
||||||
|
{
|
||||||
|
uint8_t fn_bits = 0;
|
||||||
|
#ifdef USB_EXTRA_ENABLE
|
||||||
|
uint16_t consumer_code = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
matrix_scan();
|
||||||
|
|
||||||
|
if (matrix_is_modified()) {
|
||||||
|
if (debug_matrix) matrix_print();
|
||||||
|
#ifdef DEBUG_LED
|
||||||
|
// LED flash for debug
|
||||||
|
DEBUG_LED_CONFIG;
|
||||||
|
DEBUG_LED_ON;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (matrix_has_ghost()) {
|
||||||
|
// should send error?
|
||||||
|
debug("matrix has ghost!!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
host_swap_keyboard_report();
|
||||||
|
host_clear_keyboard_report();
|
||||||
|
for (int row = 0; row < matrix_rows(); row++) {
|
||||||
|
for (int col = 0; col < matrix_cols(); col++) {
|
||||||
|
if (!matrix_is_on(row, col)) continue;
|
||||||
|
//print("row,col: "); pdec(row); print(","); pdec(col); print("\n");
|
||||||
|
uint8_t code = layer_get_keycode(row, col);
|
||||||
|
//print("keycode: "); pdec(code); print("\n");
|
||||||
|
if (code == KB_NO) {
|
||||||
|
// do nothing
|
||||||
|
print("KB_NO: "); pdec(row); print(","); pdec(col); print("\n");
|
||||||
|
} else if (IS_MOD(code)) {
|
||||||
|
host_add_mod_bit(MOD_BIT(code));
|
||||||
|
} else if (IS_FN(code)) {
|
||||||
|
fn_bits |= FN_BIT(code);
|
||||||
|
}
|
||||||
|
#ifdef USB_EXTRA_ENABLE
|
||||||
|
// System Control
|
||||||
|
else if (code == KB_SYSTEM_POWER) {
|
||||||
|
#ifdef HOST_PJRC
|
||||||
|
if (suspend && remote_wakeup) {
|
||||||
|
usb_remote_wakeup();
|
||||||
|
} else {
|
||||||
|
host_system_send(SYSTEM_POWER_DOWN);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
host_system_send(SYSTEM_POWER_DOWN);
|
||||||
|
#endif
|
||||||
|
host_system_send(0);
|
||||||
|
_delay_ms(500);
|
||||||
|
} else if (code == KB_SYSTEM_SLEEP) {
|
||||||
|
host_system_send(SYSTEM_SLEEP);
|
||||||
|
host_system_send(0);
|
||||||
|
_delay_ms(500);
|
||||||
|
} else if (code == KB_SYSTEM_WAKE) {
|
||||||
|
host_system_send(SYSTEM_WAKE_UP);
|
||||||
|
host_system_send(0);
|
||||||
|
_delay_ms(500);
|
||||||
|
}
|
||||||
|
// Consumer Page
|
||||||
|
else if (code == KB_AUDIO_MUTE) {
|
||||||
|
consumer_code = AUDIO_MUTE;
|
||||||
|
} else if (code == KB_AUDIO_VOL_UP) {
|
||||||
|
consumer_code = AUDIO_VOL_UP;
|
||||||
|
} else if (code == KB_AUDIO_VOL_DOWN) {
|
||||||
|
consumer_code = AUDIO_VOL_DOWN;
|
||||||
|
}
|
||||||
|
else if (code == KB_MEDIA_NEXT_TRACK) {
|
||||||
|
consumer_code = TRANSPORT_NEXT_TRACK;
|
||||||
|
} else if (code == KB_MEDIA_PREV_TRACK) {
|
||||||
|
consumer_code = TRANSPORT_PREV_TRACK;
|
||||||
|
} else if (code == KB_MEDIA_STOP) {
|
||||||
|
consumer_code = TRANSPORT_STOP;
|
||||||
|
} else if (code == KB_MEDIA_PLAY_PAUSE) {
|
||||||
|
consumer_code = TRANSPORT_PLAY_PAUSE;
|
||||||
|
} else if (code == KB_MEDIA_SELECT) {
|
||||||
|
consumer_code = AL_CC_CONFIG;
|
||||||
|
}
|
||||||
|
else if (code == KB_MAIL) {
|
||||||
|
consumer_code = AL_EMAIL;
|
||||||
|
} else if (code == KB_CALCULATOR) {
|
||||||
|
consumer_code = AL_CALCULATOR;
|
||||||
|
} else if (code == KB_MY_COMPUTER) {
|
||||||
|
consumer_code = AL_LOCAL_BROWSER;
|
||||||
|
}
|
||||||
|
else if (code == KB_WWW_SEARCH) {
|
||||||
|
consumer_code = AC_SEARCH;
|
||||||
|
} else if (code == KB_WWW_HOME) {
|
||||||
|
consumer_code = AC_HOME;
|
||||||
|
} else if (code == KB_WWW_BACK) {
|
||||||
|
consumer_code = AC_BACK;
|
||||||
|
} else if (code == KB_WWW_FORWARD) {
|
||||||
|
consumer_code = AC_FORWARD;
|
||||||
|
} else if (code == KB_WWW_STOP) {
|
||||||
|
consumer_code = AC_STOP;
|
||||||
|
} else if (code == KB_WWW_REFRESH) {
|
||||||
|
consumer_code = AC_REFRESH;
|
||||||
|
} else if (code == KB_WWW_FAVORITES) {
|
||||||
|
consumer_code = AC_BOOKMARKS;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (IS_KEY(code)) {
|
||||||
|
host_add_key(code);
|
||||||
|
}
|
||||||
|
#ifdef MOUSEKEY_ENABLE
|
||||||
|
else if (IS_MOUSEKEY(code)) {
|
||||||
|
mousekey_decode(code);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else {
|
||||||
|
debug("ignore keycode: "); debug_hex(code); debug("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
layer_switching(fn_bits);
|
||||||
|
uint8_t ret = command_proc();
|
||||||
|
if (ret != 0 && ret != SCROLL_LOCK_TOGGLE) {
|
||||||
|
_delay_ms(500);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ret == SCROLL_LOCK_TOGGLE){
|
||||||
|
scroll_lock = !scroll_lock;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: should send only when changed from last report
|
||||||
|
if (matrix_is_modified()) {
|
||||||
|
host_send_keyboard_report();
|
||||||
|
#ifdef USB_EXTRA_ENABLE
|
||||||
|
host_consumer_send(consumer_code);
|
||||||
|
#endif
|
||||||
|
#ifdef DEBUG_LED
|
||||||
|
// LED flash for debug
|
||||||
|
DEBUG_LED_CONFIG;
|
||||||
|
DEBUG_LED_OFF;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef MOUSEKEY_ENABLE
|
||||||
|
mousekey_send();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef PS2_MOUSE_ENABLE
|
||||||
|
// TODO: should comform new API
|
||||||
|
if (ps2_mouse_read() == 0)
|
||||||
|
ps2_mouse_usb_send();
|
||||||
|
#endif
|
||||||
|
uint8_t current_leds = (scroll_lock || IS_SHORTCUT()) ? (host_keyboard_leds() | (1<<USB_LED_SCROLL_LOCK)) : host_keyboard_leds();
|
||||||
|
if (last_leds != current_leds) {
|
||||||
|
keyboard_set_leds(current_leds);
|
||||||
|
last_leds = current_leds;
|
||||||
|
if(ret == SCROLL_LOCK_TOGGLE)
|
||||||
|
_delay_ms(500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void keyboard_set_leds(uint8_t leds)
|
||||||
|
{
|
||||||
|
led_set(leds);
|
||||||
|
}
|
11
keyboard.h
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef KEYBOARD_H
|
||||||
|
#define KEYBOARD_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
|
||||||
|
void keyboard_init(void);
|
||||||
|
void keyboard_proc(void);
|
||||||
|
void keyboard_set_leds(uint8_t leds);
|
||||||
|
|
||||||
|
#endif
|
18
keymap.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#ifndef KEYMAP_H
|
||||||
|
#define KEYMAP_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "usb_keycodes.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* keycode in specific layer */
|
||||||
|
uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col);
|
||||||
|
|
||||||
|
/* layer to move during press Fn key */
|
||||||
|
uint8_t keymap_fn_layer(uint8_t fn_bits);
|
||||||
|
|
||||||
|
/* keycode to send when release Fn key without using */
|
||||||
|
uint8_t keymap_fn_keycode(uint8_t fn_bits);
|
||||||
|
|
||||||
|
#endif
|
@ -1,18 +0,0 @@
|
|||||||
#ifndef KEYMAP_SKEL_H
|
|
||||||
#define KEYMAP_SKEL_H 1
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include "usb_keycodes.h"
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t keymap_get_keycode(int row, int col);
|
|
||||||
uint8_t keymap_get_keycodel(int layer, int row, int col);
|
|
||||||
int keymap_get_layer(void);
|
|
||||||
int keymap_set_layer(int layer);
|
|
||||||
|
|
||||||
bool keymap_is_special_mode(int fn_bits);
|
|
||||||
/* process Fn keys. This.should be called every scan. */
|
|
||||||
void keymap_fn_proc(int fn_bits);
|
|
||||||
|
|
||||||
#endif
|
|
183
layer.c
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
#include "keymap.h"
|
||||||
|
#include "host.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "timer.h"
|
||||||
|
#include "layer.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Parameters:
|
||||||
|
* ENTER_DELAY |=======|
|
||||||
|
* SEND_FN_TERM |================|
|
||||||
|
*
|
||||||
|
* Fn key processing cases:
|
||||||
|
* 1. release Fn after SEND_FN_TERM.
|
||||||
|
* Layer sw ___________|~~~~~~~~~~~|___
|
||||||
|
* Fn press ___|~~~~~~~~~~~~~~~~~~~|___
|
||||||
|
* Fn send ___________________________
|
||||||
|
*
|
||||||
|
* 2. release Fn during SEND_FN_TERM.(not layer used)
|
||||||
|
* Layer sw ___________|~~~~~~|________
|
||||||
|
* Fn press ___|~~~~~~~~~~~~~~|________
|
||||||
|
* Fn key send __________________|~|______
|
||||||
|
* other key press ___________________________
|
||||||
|
* other key send ___________________________
|
||||||
|
*
|
||||||
|
* 3. release Fn during SEND_FN_TERM.(layer used)
|
||||||
|
* Layer sw ___________|~~~~~~|________
|
||||||
|
* Fn press ___|~~~~~~~~~~~~~~|________
|
||||||
|
* Fn key send ___________________________
|
||||||
|
* Fn send ___________________________
|
||||||
|
* other key press _____________|~~|__________
|
||||||
|
* other key send _____________|~~|__________
|
||||||
|
*
|
||||||
|
* 4. press other key during ENTER_DELAY.
|
||||||
|
* Layer sw ___________________________
|
||||||
|
* Fn key press ___|~~~~~~~~~|_____________
|
||||||
|
* Fn key send ______|~~~~~~|_____________
|
||||||
|
* other key press ______|~~~|________________
|
||||||
|
* other key send _______|~~|________________
|
||||||
|
*
|
||||||
|
* 5. press Fn while press other key.
|
||||||
|
* Layer sw ___________________________
|
||||||
|
* Fn key press ___|~~~~~~~~~|_____________
|
||||||
|
* Fn key send ___|~~~~~~~~~|_____________
|
||||||
|
* other key press ~~~~~~~|___________________
|
||||||
|
* other key send ~~~~~~~|___________________
|
||||||
|
*
|
||||||
|
* 6. press Fn twice quickly and keep holding down.(repeat)
|
||||||
|
* Layer sw ___________________________
|
||||||
|
* Fn key press ___|~|____|~~~~~~~~~~~~~~~~
|
||||||
|
* Fn key send _____|~|__|~~~~~~~~~~~~~~~~
|
||||||
|
*/
|
||||||
|
|
||||||
|
// LAYER_ENTER_DELAY: prevent from moving new layer
|
||||||
|
#define LAYER_ENTER_DELAY 5
|
||||||
|
|
||||||
|
// LAYER_SEND_FN_TERM: send keycode if release key in this term
|
||||||
|
#define LAYER_SEND_FN_TERM 40
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t default_layer = 0;
|
||||||
|
uint8_t current_layer = 0;
|
||||||
|
|
||||||
|
static bool layer_used = false;
|
||||||
|
static uint8_t new_layer(uint8_t fn_bits);
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t layer_get_keycode(uint8_t row, uint8_t col)
|
||||||
|
{
|
||||||
|
uint8_t code = keymap_get_keycode(IS_SHORTCUT() ? SHORTCUT_LAYOUT : current_layer, row, col);
|
||||||
|
// normal key or mouse key
|
||||||
|
if ((IS_KEY(code) || IS_MOUSEKEY(code))) {
|
||||||
|
layer_used = true;
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bit substract b from a
|
||||||
|
#define BIT_SUBST(a, b) (a&(a^b))
|
||||||
|
void layer_switching(uint8_t fn_bits)
|
||||||
|
{
|
||||||
|
// layer switching
|
||||||
|
static uint8_t last_fn = 0;
|
||||||
|
static uint8_t last_mods = 0;
|
||||||
|
static uint16_t last_timer = 0;
|
||||||
|
static uint8_t sent_fn = 0;
|
||||||
|
|
||||||
|
if (fn_bits == last_fn) { // Fn state is not changed
|
||||||
|
if (fn_bits == 0) {
|
||||||
|
// do nothing
|
||||||
|
} else {
|
||||||
|
if (timer_elapsed(last_timer) > LAYER_ENTER_DELAY) {
|
||||||
|
uint8_t _layer_to_switch = new_layer(BIT_SUBST(fn_bits, sent_fn));
|
||||||
|
if (current_layer != _layer_to_switch) { // not switch layer yet
|
||||||
|
debug("Fn case: 1,2,3(LAYER_ENTER_DELAY passed)\n");
|
||||||
|
debug("Switch Layer: "); debug_hex(current_layer);
|
||||||
|
current_layer = _layer_to_switch;
|
||||||
|
layer_used = false;
|
||||||
|
debug(" -> "); debug_hex(current_layer); debug("\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (host_has_anykey()) { // other keys is pressed
|
||||||
|
uint8_t _fn_to_send = BIT_SUBST(fn_bits, sent_fn);
|
||||||
|
if (_fn_to_send) {
|
||||||
|
debug("Fn case: 4(send Fn before other key pressed)\n");
|
||||||
|
// send only Fn key first
|
||||||
|
host_swap_keyboard_report();
|
||||||
|
host_clear_keyboard_report();
|
||||||
|
host_set_mods(last_mods);
|
||||||
|
host_add_code(keymap_fn_keycode(_fn_to_send)); // TODO: do all Fn keys
|
||||||
|
host_send_keyboard_report();
|
||||||
|
host_swap_keyboard_report();
|
||||||
|
sent_fn |= _fn_to_send;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// add Fn keys to send
|
||||||
|
//host_add_code(keymap_fn_keycode(fn_bits&sent_fn)); // TODO: do all Fn keys
|
||||||
|
}
|
||||||
|
} else { // Fn state is changed(edge)
|
||||||
|
uint8_t fn_changed = 0;
|
||||||
|
|
||||||
|
debug("fn_bits: "); debug_bin(fn_bits); debug("\n");
|
||||||
|
debug("sent_fn: "); debug_bin(sent_fn); debug("\n");
|
||||||
|
debug("last_fn: "); debug_bin(last_fn); debug("\n");
|
||||||
|
debug("last_mods: "); debug_hex(last_mods); debug("\n");
|
||||||
|
debug("last_timer: "); debug_hex16(last_timer); debug("\n");
|
||||||
|
|
||||||
|
// pressed Fn
|
||||||
|
if ((fn_changed = BIT_SUBST(fn_bits, last_fn))) {
|
||||||
|
debug("fn_changed: "); debug_bin(fn_changed); debug("\n");
|
||||||
|
if (host_has_anykey()) {
|
||||||
|
debug("Fn case: 5(pressed Fn with other key)\n");
|
||||||
|
sent_fn |= fn_changed;
|
||||||
|
} else if (fn_changed & sent_fn) { // pressed same Fn in a row
|
||||||
|
if (timer_elapsed(last_timer) > LAYER_ENTER_DELAY) {
|
||||||
|
debug("Fn case: 6(not repeat)\n");
|
||||||
|
// time passed: not repeate
|
||||||
|
sent_fn &= ~fn_changed;
|
||||||
|
} else {
|
||||||
|
debug("Fn case: 6(repeat)\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// released Fn
|
||||||
|
if ((fn_changed = BIT_SUBST(last_fn, fn_bits))) {
|
||||||
|
debug("fn_changed: "); debug_bin(fn_changed); debug("\n");
|
||||||
|
if (timer_elapsed(last_timer) < LAYER_SEND_FN_TERM) {
|
||||||
|
if (!layer_used && BIT_SUBST(fn_changed, sent_fn)) {
|
||||||
|
debug("Fn case: 2(send Fn one shot: released Fn during LAYER_SEND_FN_TERM)\n");
|
||||||
|
// send only Fn key first
|
||||||
|
host_swap_keyboard_report();
|
||||||
|
host_clear_keyboard_report();
|
||||||
|
host_set_mods(last_mods);
|
||||||
|
host_add_code(keymap_fn_keycode(fn_changed)); // TODO: do all Fn keys
|
||||||
|
host_send_keyboard_report();
|
||||||
|
host_swap_keyboard_report();
|
||||||
|
sent_fn |= fn_changed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug("Switch Layer(released Fn): "); debug_hex(current_layer);
|
||||||
|
current_layer = new_layer(BIT_SUBST(fn_bits, sent_fn));
|
||||||
|
debug(" -> "); debug_hex(current_layer); debug("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
layer_used = false;
|
||||||
|
last_fn = fn_bits;
|
||||||
|
last_mods = keyboard_report->mods;
|
||||||
|
last_timer = timer_read();
|
||||||
|
}
|
||||||
|
// send Fn keys
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
if ((sent_fn & fn_bits) & (1<<i)) {
|
||||||
|
host_add_code(keymap_fn_keycode(1<<i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
|
static uint8_t new_layer(uint8_t fn_bits)
|
||||||
|
{
|
||||||
|
return (fn_bits ? keymap_fn_layer(fn_bits) : default_layer);
|
||||||
|
}
|
15
layer.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#ifndef LAYER_H
|
||||||
|
#define LAYER_H 1
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
extern uint8_t default_layer;
|
||||||
|
extern uint8_t current_layer;
|
||||||
|
|
||||||
|
/* return keycode for switch */
|
||||||
|
uint8_t layer_get_keycode(uint8_t row, uint8_t col);
|
||||||
|
|
||||||
|
/* process layer switching */
|
||||||
|
void layer_switching(uint8_t fn_bits);
|
||||||
|
|
||||||
|
#endif
|
16
led.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef LED_H
|
||||||
|
#define LED_H
|
||||||
|
#include "stdint.h"
|
||||||
|
|
||||||
|
|
||||||
|
/* keyboard LEDs */
|
||||||
|
#define USB_LED_NUM_LOCK 0
|
||||||
|
#define USB_LED_CAPS_LOCK 1
|
||||||
|
#define USB_LED_SCROLL_LOCK 2
|
||||||
|
#define USB_LED_COMPOSE 3
|
||||||
|
#define USB_LED_KANA 4
|
||||||
|
|
||||||
|
|
||||||
|
void led_set(uint8_t usb_led);
|
||||||
|
|
||||||
|
#endif
|
@ -1,52 +1,5 @@
|
|||||||
# Hey Emacs, this is a -*- makefile -*-
|
|
||||||
#----------------------------------------------------------------------------
|
|
||||||
# WinAVR Makefile Template written by Eric B. Weddington, Jörg Wunsch, et al.
|
|
||||||
#
|
|
||||||
# Released to the Public Domain
|
|
||||||
#
|
|
||||||
# Additional material for this makefile was written by:
|
|
||||||
# Peter Fleury
|
|
||||||
# Tim Henigan
|
|
||||||
# Colin O'Flynn
|
|
||||||
# Reiner Patommel
|
|
||||||
# Markus Pfaff
|
|
||||||
# Sander Pool
|
|
||||||
# Frederik Rouleau
|
|
||||||
# Carlos Lamas
|
|
||||||
#
|
|
||||||
#----------------------------------------------------------------------------
|
|
||||||
# On command line:
|
|
||||||
#
|
|
||||||
# make all = Make software.
|
|
||||||
#
|
|
||||||
# make clean = Clean out built project files.
|
|
||||||
#
|
|
||||||
# make coff = Convert ELF to AVR COFF.
|
|
||||||
#
|
|
||||||
# make extcoff = Convert ELF to AVR Extended COFF.
|
|
||||||
#
|
|
||||||
# make program = Download the hex file to the device, using avrdude.
|
|
||||||
# Please customize the avrdude settings below first!
|
|
||||||
#
|
|
||||||
# make debug = Start either simulavr or avarice as specified for debugging,
|
|
||||||
# with avr-gdb or avr-insight as the front end for debugging.
|
|
||||||
#
|
|
||||||
# make filename.s = Just compile filename.c into the assembler code only.
|
|
||||||
#
|
|
||||||
# make filename.i = Create a preprocessed source file for use in submitting
|
|
||||||
# bug reports to the GCC project.
|
|
||||||
#
|
|
||||||
# To rebuild project do "make clean" then "make all".
|
|
||||||
#----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
VENDOR_ID = 0xFEED
|
|
||||||
PRODUCT_ID = 0xBEEF
|
|
||||||
MANUFACTURER = 't.m.k.'
|
|
||||||
PRODUCT = 't.m.k. Macway mod'
|
|
||||||
DESCRIPTION = 't.m.k. firmware for Macway mod'
|
|
||||||
|
|
||||||
# Target file name (without extension).
|
# Target file name (without extension).
|
||||||
TARGET = tmk_macway
|
TARGET = macway
|
||||||
|
|
||||||
# Directory common source filess exist
|
# Directory common source filess exist
|
||||||
COMMON_DIR = ..
|
COMMON_DIR = ..
|
||||||
@ -55,8 +8,12 @@ COMMON_DIR = ..
|
|||||||
TARGET_DIR = .
|
TARGET_DIR = .
|
||||||
|
|
||||||
# keyboard dependent files
|
# keyboard dependent files
|
||||||
TARGET_SRC = keymap.c \
|
TARGET_SRC = main_pjrc.c \
|
||||||
matrix.c
|
keymap.c \
|
||||||
|
matrix.c \
|
||||||
|
led.c
|
||||||
|
|
||||||
|
CONFIG_H = config.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
|
||||||
@ -74,4 +31,21 @@ MCU = atmega32u4 # Teensy 2.0
|
|||||||
# 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 = 16000000
|
F_CPU = 16000000
|
||||||
|
|
||||||
|
|
||||||
|
# Build Options
|
||||||
|
# comment out to disable the options.
|
||||||
|
#
|
||||||
|
MOUSEKEY_ENABLE = yes # Mouse keys
|
||||||
|
#PS2_MOUSE_ENABLE = yes # PS/2 mouse(TrackPoint) support
|
||||||
|
USB_EXTRA_ENABLE = yes # Audio control and System control
|
||||||
|
#USB_NKRO_ENABLE = yes # USB Nkey Rollover
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- Programming Options --------------------------
|
||||||
|
PROGRAM_CMD = teensy_loader_cli -mmcu=$(MCU) -w -v $(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
include $(COMMON_DIR)/Makefile.pjrc
|
||||||
include $(COMMON_DIR)/Makefile.common
|
include $(COMMON_DIR)/Makefile.common
|
||||||
|
46
macway/config.h
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
#ifndef CONFIG_H
|
||||||
|
#define CONFIG_H
|
||||||
|
|
||||||
|
/* controller configuration */
|
||||||
|
#include "controller_teensy.h"
|
||||||
|
|
||||||
|
#define VENDOR_ID 0xFEED
|
||||||
|
#define PRODUCT_ID 0xBEE0
|
||||||
|
#define MANUFACTURER t.m.k.
|
||||||
|
#define PRODUCT Macway mod
|
||||||
|
#define DESCRIPTION t.m.k. keyboard firmware for Macway mod
|
||||||
|
|
||||||
|
|
||||||
|
/* matrix size */
|
||||||
|
#define MATRIX_ROWS 9
|
||||||
|
#define MATRIX_COLS 8
|
||||||
|
/* define if matrix has ghost */
|
||||||
|
#define MATRIX_HAS_GHOST
|
||||||
|
|
||||||
|
|
||||||
|
/* key combination for command */
|
||||||
|
#define IS_COMMAND() ( \
|
||||||
|
keyboard_report->mods == (BIT_LSHIFT | BIT_RSHIFT) || \
|
||||||
|
keyboard_report->mods == (BIT_LCTRL | BIT_RSHIFT) \
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
/* mouse keys */
|
||||||
|
#ifdef MOUSEKEY_ENABLE
|
||||||
|
# define MOUSEKEY_DELAY_TIME 192
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* PS/2 mouse */
|
||||||
|
#ifdef PS2_MOUSE_ENABLE
|
||||||
|
# define PS2_CLOCK_PORT PORTF
|
||||||
|
# define PS2_CLOCK_PIN PINF
|
||||||
|
# define PS2_CLOCK_DDR DDRF
|
||||||
|
# define PS2_CLOCK_BIT 0
|
||||||
|
# define PS2_DATA_PORT PORTF
|
||||||
|
# define PS2_DATA_PIN PINF
|
||||||
|
# define PS2_DATA_DDR DDRF
|
||||||
|
# define PS2_DATA_BIT 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -1,6 +0,0 @@
|
|||||||
#ifndef CONTROLLER_H
|
|
||||||
#define CONTROLLER_H 1
|
|
||||||
|
|
||||||
#include "controller_teensy.h"
|
|
||||||
|
|
||||||
#endif
|
|
BIN
macway/doc/back.jpg
Executable file
After Width: | Height: | Size: 119 KiB |
BIN
macway/doc/case.jpg
Executable file
After Width: | Height: | Size: 143 KiB |
BIN
macway/doc/keys.jpg
Executable file
After Width: | Height: | Size: 114 KiB |
BIN
macway/doc/side.jpg
Executable file
After Width: | Height: | Size: 107 KiB |
BIN
macway/doc/switch.jpg
Executable file
After Width: | Height: | Size: 113 KiB |
BIN
macway/doc/teensy.jpg
Executable file
After Width: | Height: | Size: 162 KiB |
BIN
macway/doc/wiring.jpg
Executable file
After Width: | Height: | Size: 162 KiB |
BIN
macway/doc/withHHKB.jpg
Executable file
After Width: | Height: | Size: 149 KiB |
BIN
macway/doc/withThinkPad.jpg
Executable file
After Width: | Height: | Size: 116 KiB |
177
macway/keymap.c
@ -4,18 +4,15 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#include "usb_keyboard.h"
|
|
||||||
#include "usb_keycodes.h"
|
#include "usb_keycodes.h"
|
||||||
#include "matrix.h"
|
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "keymap.h"
|
#include "keymap.h"
|
||||||
|
|
||||||
|
|
||||||
#define FN_KEYCODE(fn) (pgm_read_byte(&fn_keycode[(fn)]))
|
// Convert physical keyboard layout to matrix array.
|
||||||
#define FN_LAYER(fn) (pgm_read_byte(&fn_layer[(fn)]))
|
// This is a macro to define keymap easily in keyboard layout form.
|
||||||
#define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)]))
|
|
||||||
#define KEYMAP( \
|
#define KEYMAP( \
|
||||||
R1C1, R1C0, R2C0, R3C0, R4C0, R4C1, R5C1, R5C0, R6C0, R7C0, R8C0, R8C1, R6C1, R0C2, \
|
R1C1, R1C0, R2C0, R3C0, R4C0, R4C1, R5C1, R5C0, R6C0, R7C0, R8C0, R8C1, R6C1, R0C2, \
|
||||||
R1C2, R1C3, R2C3, R3C3, R4C3, R4C2, R5C2, R5C3, R6C3, R7C3, R8C3, R8C2, R6C2, \
|
R1C2, R1C3, R2C3, R3C3, R4C3, R4C2, R5C2, R5C3, R6C3, R7C3, R8C3, R8C2, R6C2, \
|
||||||
@ -34,23 +31,32 @@
|
|||||||
{ R8C0, R8C1, R8C2, R8C3, R8C4, R8C5, KB_NO, R8C7 } \
|
{ R8C0, R8C1, R8C2, R8C3, R8C4, R8C5, KB_NO, R8C7 } \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define KEYCODE(layer, row, col) (pgm_read_byte(&keymaps[(layer)][(row)][(col)]))
|
||||||
|
|
||||||
static int current_layer = 0;
|
|
||||||
static bool layer_used = false;
|
|
||||||
|
|
||||||
/* layer to change into while Fn key pressed */
|
// Assign Fn key(0-7) to a layer to which switch with the Fn key pressed.
|
||||||
static const int PROGMEM fn_layer[] = { 0, 1, 2, 3, 4, 0, 2, 3 };
|
static const uint8_t PROGMEM fn_layer[] = {
|
||||||
|
0, // Fn0
|
||||||
|
1, // Fn1
|
||||||
|
2, // Fn2
|
||||||
|
3, // Fn3
|
||||||
|
4, // Fn4
|
||||||
|
0, // Fn5
|
||||||
|
2, // Fn6
|
||||||
|
3 // Fn7
|
||||||
|
};
|
||||||
|
|
||||||
/* keycode to sent when Fn key released without using layer keys. */
|
// Assign Fn key(0-7) to a keycode sent when release Fn key without use of the layer.
|
||||||
|
// See layer.c for details.
|
||||||
static const uint8_t PROGMEM fn_keycode[] = {
|
static const uint8_t PROGMEM fn_keycode[] = {
|
||||||
KB_NO, // FN_0 [NOT USED]
|
KB_NO, // Fn0
|
||||||
KB_NO, // FN_1 layer 1
|
KB_NO, // Fn1
|
||||||
KB_QUOTE, // FN_2 layer 2
|
KB_SLSH, // Fn2
|
||||||
KB_SCOLON, // FN_3 layer 3
|
KB_SCLN, // Fn3
|
||||||
KB_SPACE, // FN_4 layer 4 [NOT USED]
|
KB_SPC, // Fn4
|
||||||
KB_NO, // FN_5 [NOT USED]
|
KB_NO, // Fn5
|
||||||
KB_NO, // FN_6 layer 2
|
KB_NO, // Fn6
|
||||||
KB_NO // FN_7 layer 3
|
KB_NO // Fn7
|
||||||
};
|
};
|
||||||
|
|
||||||
static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||||
@ -60,37 +66,39 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
|||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| |
|
* |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| |
|
||||||
* |-----------------------------------------------------' |
|
* |-----------------------------------------------------' |
|
||||||
* |Contro| A| S| D| F| G| H| J| K| L|Fn3|Fn2|Return |
|
* |Contro| A| S| D| F| G| H| J| K| L|Fn3| '|Return |
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift |Fn1|
|
* |Shift | Z| X| C| V| B| N| M| ,| .| /|Shift |Fn1|
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Fn7|Gui |Alt |Space |Fn6 |\ |` | | |
|
* |Fn7|Gui |Alt |Fn4 |Alt |Gui|Fn6|Fn6|Ctr|
|
||||||
* `-----------------------------------------------------------'
|
* `-----------------------------------------------------------'
|
||||||
*/
|
*/
|
||||||
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_BSPC, \
|
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_BSPC, \
|
||||||
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_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_LCTL,KB_A, KB_S, KB_D, KB_F, KB_G, KB_H, KB_J, KB_K, KB_L, FN_3, FN_2, KB_ENT, \
|
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_SLSH,KB_RSFT,FN_1, \
|
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, \
|
||||||
FN_7, KB_LGUI,KB_LALT,KB_SPC, FN_6, KB_BSLS,KB_GRV, KB_NO, KB_NO),
|
KB_FN7, KB_LGUI,KB_LALT,KB_FN4, KB_RALT,KB_RGUI,KB_FN6, KB_FN6, KB_RCTL),
|
||||||
|
|
||||||
|
|
||||||
/* Layer 1: HHKB mode (HHKB Fn)
|
/* Layer 1: HHKB mode (HHKB Fn)
|
||||||
* ,-----------------------------------------------------------.
|
* ,-----------------------------------------------------------.
|
||||||
* |Pow| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Delete |
|
* |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Delete |
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Caps | | | | | | | |Psc|Slk|Pus|Up | | |
|
* |Caps | | | | | | | |Psc|Slk|Pus|Up | | |
|
||||||
* |-----------------------------------------------------' |
|
* |-----------------------------------------------------' |
|
||||||
* |Contro| | | | | | *| /|Hom|PgU|Lef|Rig|Enter |
|
* |Contro|VoD|VoU|Mut| | | *| /|Hom|PgU|Lef|Rig|Enter |
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Shift | | | | | | +| -|End|PgD|Dow|Shift |xxx|
|
* |Shift | | | | | | +| -|End|PgD|Dow|Shift |xxx|
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* | |Gui |Alt | |Alt | | | | |
|
* | |Gui |Alt | |Alt |Gui| | |Ctr|
|
||||||
* `-----------------------------------------------------------'
|
* `-----------------------------------------------------------'
|
||||||
*/
|
*/
|
||||||
KEYMAP(KB_PWR, 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_DEL, \
|
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_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_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_LCTL,KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KP_ASTR,KP_SLSH,KB_HOME,KB_PGUP,KB_LEFT,KB_RGHT,KB_ENT, \
|
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, KP_PLUS,KP_MINS,KB_END, KB_PGDN,KB_DOWN,KB_RSFT,FN_1, \
|
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_NO, KB_LGUI,KB_LALT,KB_SPC, KB_RALT,KB_NO, KB_NO, KB_NO, KB_NO),
|
KB_NO, KB_LGUI,KB_LALT,KB_SPC, KB_RALT,KB_NO, KB_NO, KB_NO, KB_RCTL),
|
||||||
|
|
||||||
|
|
||||||
/* Layer 2: Vi mode (Quote/Rmeta)
|
/* Layer 2: Vi mode (Quote/Rmeta)
|
||||||
* ,-----------------------------------------------------------.
|
* ,-----------------------------------------------------------.
|
||||||
@ -98,38 +106,40 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
|||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* | \ |Hom|PgD|Up |PgU|End|Hom|PgD|PgU|End| | | | |
|
* | \ |Hom|PgD|Up |PgU|End|Hom|PgD|PgU|End| | | | |
|
||||||
* |-----------------------------------------------------' |
|
* |-----------------------------------------------------' |
|
||||||
* |Contro| |Lef|Dow|Rig| |Lef|Dow|Up |Rig| |xxx| \ |
|
* |Contro| |Lef|Dow|Rig| |Lef|Dow|Up |Rig| | | \ |
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Shift | | | | | |Hom|PgD|PgU|End| |Shift | |
|
* |Shift | | | | | |Hom|PgD|PgU|End|xxx|Shift | |
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* | |Gui |Alt |Space |xxxxx| | | | |
|
* | |Gui |Alt |Space |Alt |Gui|Fn6|Fn6|Ctr|
|
||||||
* `-----------------------------------------------------------'
|
* `-----------------------------------------------------------'
|
||||||
*/
|
*/
|
||||||
KEYMAP(KB_GRV, 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_GRV, \
|
KEYMAP(KB_GRV, 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_GRV, \
|
||||||
KB_BSLS,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_BSLS,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_LCTL,KB_NO, KB_LEFT,KB_DOWN,KB_RGHT,KB_NO, KB_LEFT,KB_DOWN,KB_UP, KB_RGHT,KB_NO, FN_2, KB_BSLS, \
|
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_BSLS, \
|
||||||
KB_LSFT,KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_RSFT,KB_NO, \
|
KB_LSFT,KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_NO, KB_FN2, KB_RSFT,KB_NO, \
|
||||||
KB_NO, KB_LGUI,KB_LALT,KB_SPC, FN_6, KB_NO, KB_NO, KB_NO, KB_NO),
|
KB_NO, KB_LGUI,KB_LALT,KB_SPC, KB_RALT,KB_RGUI,KB_FN6, KB_FN6, KB_RCTL),
|
||||||
|
|
||||||
|
|
||||||
/* Layer 3: Mouse mode (Semicolon)
|
/* Layer 3: Mouse mode (Semicolon)
|
||||||
* ,-------------------------------------------------------- --.
|
* ,-----------------------------------------------------------.
|
||||||
* |Esc| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12|Delete |
|
* | `| F1| F2| F3| F4| F5| F6| F7| F8| F9|F10|F11|F12| ` |
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Tab |MwL|MwU|McU|MwD|MwR|MwL|MwD|MwU|MwR| | | | |
|
* | \ |MwL|MwD|McU|MwU|MwR|MwL|MwD|MwU|MwR| | | | |
|
||||||
* |-----------------------------------------------------' |
|
* |-----------------------------------------------------' |
|
||||||
* |Contro|Mb1|Mb2|Mb3| | |McL|McD|McU|McR|xxx| |Return |
|
* |Contro| |McL|McD|McR| |McL|McD|McU|McR|xxx| | \ |
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Shift | | | | | |MwL|MwD|MwU|MwR| |Shift | |
|
* |Shift | | |Mb1|Mb2|Mb3|Mb2|Mb1| | | |Shift | |
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |xxx|Gui |Alt |Mb1 |Alt | | | | |
|
* |xxx|Gui |Alt |Mb1 |Alt | | | | |
|
||||||
* `-----------------------------------------------------------'
|
* `-----------------------------------------------------------'
|
||||||
* 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_DEL, \
|
KEYMAP(KB_GRV, 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_GRV, \
|
||||||
KB_TAB, MS_WH_L,MS_WH_U,MS_UP, MS_WH_D,MS_WH_R,MS_WH_L,MS_WH_D,MS_WH_U,MS_WH_R,KB_NO, KB_NO, KB_NO, \
|
KB_BSLS,KB_WH_L,KB_WH_D,KB_MS_U,KB_WH_U,KB_WH_R,KB_WH_L,KB_WH_D,KB_WH_U,KB_WH_R,KB_NO, KB_NO, KB_NO, \
|
||||||
KB_LCTL,KB_NO, MS_LEFT,MS_DOWN,MS_RGHT,KB_NO, MS_LEFT,MS_DOWN,MS_UP, MS_RGHT,FN_3, KB_NO, KB_ENT, \
|
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_BSLS, \
|
||||||
KB_LSFT,KB_NO, MS_DOWN,KB_NO, KB_NO, KB_NO, MS_BTN2,MS_BTN1,MS_BTN2,MS_BTN3,KB_NO, KB_RSFT,KB_NO, \
|
KB_LSFT,KB_NO, KB_NO, KB_BTN1,KB_BTN2,KB_BTN3,KB_BTN2,KB_BTN1,KB_NO, KB_NO, KB_NO, KB_RSFT,KB_NO, \
|
||||||
FN_7, KB_LGUI,KB_LALT,MS_BTN1,KB_RALT,KB_NO, KB_NO, KB_NO, KB_NO),
|
KB_FN7, KB_LGUI,KB_LALT,KB_BTN1,KB_RALT,KB_NO, KB_NO, KB_NO, KB_NO),
|
||||||
|
|
||||||
|
|
||||||
/* Layer 4: Matias half keyboard style (Space)
|
/* Layer 4: Matias half keyboard style (Space)
|
||||||
* ,-----------------------------------------------------------.
|
* ,-----------------------------------------------------------.
|
||||||
@ -141,87 +151,28 @@ static const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
|||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* |Shift | /| .| ,| M| N| B| V| C| X| Z|Shift | |
|
* |Shift | /| .| ,| M| N| B| V| C| X| Z|Shift | |
|
||||||
* |-----------------------------------------------------------|
|
* |-----------------------------------------------------------|
|
||||||
* | |Gui |Alt |xxxxxxxxxxxxxxxxxxxxxx|Alt | | | | |
|
* | |Gui |Alt |xxxxxxxxxxxxxxxxxxxxxx|Alt |Gui| | |Ctr|
|
||||||
* `-----------------------------------------------------------'
|
* `-----------------------------------------------------------'
|
||||||
*/
|
*/
|
||||||
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_ESC, \
|
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_ESC, \
|
||||||
KB_BSPC,KB_P, KB_O, KB_I, KB_U, KB_Y, KB_T, KB_R, KB_E, KB_W, KB_Q, KB_TAB, KB_TAB, \
|
KB_BSPC,KB_P, KB_O, KB_I, KB_U, KB_Y, KB_T, KB_R, KB_E, KB_W, KB_Q, KB_TAB, 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_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_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_NO, KB_LGUI,KB_LALT,FN_4, KB_RALT,KB_NO, KB_NO, KB_NO, KB_NO),
|
KB_NO, KB_LGUI,KB_LALT,KB_FN4, KB_RALT,KB_RGUI,KB_NO, KB_NO, KB_RCTL),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
uint8_t keymap_get_keycode(int row, int col)
|
uint8_t keymap_get_keycode(uint8_t layer, uint8_t row, uint8_t col)
|
||||||
{
|
{
|
||||||
return keymap_get_keycodel(current_layer, row, col);
|
return KEYCODE(layer, row, col);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t keymap_get_keycodel(int layer, int row, int col)
|
uint8_t keymap_fn_layer(uint8_t fn_bits)
|
||||||
{
|
{
|
||||||
uint8_t code = KEYCODE(layer, row, col);
|
return pgm_read_byte(&fn_layer[biton(fn_bits)]);
|
||||||
// normal key or mouse key
|
|
||||||
if (IS_KEY(code) || IS_MOUSE(code))
|
|
||||||
layer_used = true;
|
|
||||||
return code;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
uint8_t keymap_fn_keycode(uint8_t fn_bits)
|
||||||
int keymap_get_layer(void)
|
|
||||||
{
|
{
|
||||||
return current_layer;
|
return pgm_read_byte(&fn_keycode[(biton(fn_bits))]);
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
int keymap_set_layer(int layer)
|
|
||||||
{
|
|
||||||
current_layer = layer;
|
|
||||||
return current_layer;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
bool keymap_is_special_mode(int fn_bits)
|
|
||||||
{
|
|
||||||
return (keyboard_modifier_keys == (BIT_LCTRL | BIT_LSHIFT | BIT_LALT | BIT_LGUI));
|
|
||||||
}
|
|
||||||
|
|
||||||
void keymap_fn_proc(int fn_bits)
|
|
||||||
{
|
|
||||||
// layer switching
|
|
||||||
static int last_bits = 0;
|
|
||||||
static uint8_t last_mod = 0;
|
|
||||||
|
|
||||||
if (usb_keyboard_has_key() || fn_bits == last_bits) {
|
|
||||||
// do nothing during press other than Fn key
|
|
||||||
return;
|
|
||||||
} else if (fn_bits == 0) {
|
|
||||||
// send key when Fn key is released without using the layer
|
|
||||||
if (!layer_used) {
|
|
||||||
uint8_t code = FN_KEYCODE(biton(last_bits));
|
|
||||||
if (code != KB_NO) {
|
|
||||||
if (IS_MOD(code)) {
|
|
||||||
keyboard_modifier_keys = last_mod | 1<<(code & 0x07);
|
|
||||||
} else {
|
|
||||||
keyboard_keys[0] = code;
|
|
||||||
keyboard_modifier_keys = last_mod;
|
|
||||||
}
|
|
||||||
usb_keyboard_send();
|
|
||||||
usb_keyboard_print();
|
|
||||||
usb_keyboard_clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
last_bits = 0;
|
|
||||||
last_mod = 0;
|
|
||||||
layer_used = false;
|
|
||||||
keymap_set_layer(0); // default layer
|
|
||||||
} else if ((fn_bits & (fn_bits - 1)) == 0) {
|
|
||||||
// switch layer when just one Fn Key is pressed
|
|
||||||
last_bits = fn_bits;
|
|
||||||
last_mod = keyboard_modifier_keys;
|
|
||||||
layer_used = false;
|
|
||||||
keymap_set_layer(FN_LAYER(biton(fn_bits)));
|
|
||||||
debug("layer: "); phex(current_layer); debug("(");
|
|
||||||
debug_bin(last_bits); debug(")\n");
|
|
||||||
debug("last_mod: "); debug_hex(last_mod); debug("\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
#ifndef KEYMAP_H
|
|
||||||
#define KEYMAP_H 1
|
|
||||||
|
|
||||||
#include "usb_keycodes.h"
|
|
||||||
#include "keymap_skel.h"
|
|
||||||
|
|
||||||
#endif
|
|
7
macway/led.c
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#include "stdint.h"
|
||||||
|
#include "led.h"
|
||||||
|
|
||||||
|
|
||||||
|
void led_set(uint8_t usb_led)
|
||||||
|
{
|
||||||
|
}
|
176
macway/matrix.c
@ -5,56 +5,68 @@
|
|||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
#include <util/delay.h>
|
#include <util/delay.h>
|
||||||
#include "matrix.h"
|
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "matrix.h"
|
||||||
|
|
||||||
// matrix is active low. (key on: 0/key off: 1)
|
|
||||||
// row: Hi-Z(unselected)/low output(selected)
|
|
||||||
// PD0, PC7, PD7, PF6, PD6, PD1, PD2, PC6, PF7
|
|
||||||
// col: input w/pullup
|
|
||||||
// PB0-PB7
|
|
||||||
|
|
||||||
// matrix state buffer
|
#if (MATRIX_COLS > 16)
|
||||||
uint8_t *matrix;
|
# error "MATRIX_COLS must not exceed 16"
|
||||||
uint8_t *matrix_prev;
|
#endif
|
||||||
|
#if (MATRIX_ROWS > 255)
|
||||||
|
# error "MATRIX_ROWS must not exceed 255"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// matrix state buffer(1:on, 0:off)
|
||||||
|
#if (MATRIX_COLS <= 8)
|
||||||
|
static uint8_t *matrix;
|
||||||
|
static uint8_t *matrix_prev;
|
||||||
static uint8_t _matrix0[MATRIX_ROWS];
|
static uint8_t _matrix0[MATRIX_ROWS];
|
||||||
static uint8_t _matrix1[MATRIX_ROWS];
|
static uint8_t _matrix1[MATRIX_ROWS];
|
||||||
|
#else
|
||||||
|
static uint16_t *matrix;
|
||||||
|
static uint16_t *matrix_prev;
|
||||||
|
static uint16_t _matrix0[MATRIX_ROWS];
|
||||||
|
static uint16_t _matrix1[MATRIX_ROWS];
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MATRIX_HAS_GHOST
|
||||||
static bool matrix_has_ghost_in_row(uint8_t row);
|
static bool matrix_has_ghost_in_row(uint8_t row);
|
||||||
|
#endif
|
||||||
static uint8_t read_col(void);
|
static uint8_t read_col(void);
|
||||||
static void unselect_rows(void);
|
static void unselect_rows(void);
|
||||||
static void select_row(uint8_t row);
|
static void select_row(uint8_t row);
|
||||||
|
|
||||||
|
|
||||||
inline
|
inline
|
||||||
int matrix_rows(void)
|
uint8_t matrix_rows(void)
|
||||||
{
|
{
|
||||||
return MATRIX_ROWS;
|
return MATRIX_ROWS;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
int matrix_cols(void)
|
uint8_t matrix_cols(void)
|
||||||
{
|
{
|
||||||
return MATRIX_COLS;
|
return MATRIX_COLS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// this must be called once before matrix_scan.
|
|
||||||
void matrix_init(void)
|
void matrix_init(void)
|
||||||
{
|
{
|
||||||
// initialize row and col
|
// initialize row and col
|
||||||
unselect_rows();
|
unselect_rows();
|
||||||
|
// Input with pull-up(DDR:0, PORT:1)
|
||||||
DDRB = 0x00;
|
DDRB = 0x00;
|
||||||
PORTB = 0xFF;
|
PORTB = 0xFF;
|
||||||
|
|
||||||
// initialize matrix state: all keys off
|
// initialize matrix state: all keys off
|
||||||
for (int i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00;
|
for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix0[i] = 0x00;
|
||||||
for (int i=0; i < MATRIX_ROWS; i++) _matrix1[i] = 0x00;
|
for (uint8_t i=0; i < MATRIX_ROWS; i++) _matrix1[i] = 0x00;
|
||||||
matrix = _matrix0;
|
matrix = _matrix0;
|
||||||
matrix_prev = _matrix1;
|
matrix_prev = _matrix1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int matrix_scan(void)
|
uint8_t matrix_scan(void)
|
||||||
{
|
{
|
||||||
uint8_t *tmp;
|
uint8_t *tmp;
|
||||||
|
|
||||||
@ -62,41 +74,49 @@ int matrix_scan(void)
|
|||||||
matrix_prev = matrix;
|
matrix_prev = matrix;
|
||||||
matrix = tmp;
|
matrix = tmp;
|
||||||
|
|
||||||
for (int i = 0; i < MATRIX_ROWS; i++) {
|
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
|
||||||
|
unselect_rows();
|
||||||
select_row(i);
|
select_row(i);
|
||||||
_delay_us(30); // without this wait read unstable value.
|
_delay_us(30); // without this wait read unstable value.
|
||||||
matrix[i] = ~read_col();
|
matrix[i] = ~read_col();
|
||||||
unselect_rows();
|
|
||||||
}
|
}
|
||||||
|
unselect_rows();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool matrix_is_modified(void)
|
bool matrix_is_modified(void)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MATRIX_ROWS; i++) {
|
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
|
||||||
if (matrix[i] != matrix_prev[i])
|
if (matrix[i] != matrix_prev[i])
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
bool matrix_has_ghost(void)
|
bool matrix_has_ghost(void)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < MATRIX_ROWS; i++) {
|
#ifdef MATRIX_HAS_GHOST
|
||||||
|
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
|
||||||
if (matrix_has_ghost_in_row(i))
|
if (matrix_has_ghost_in_row(i))
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
bool matrix_is_on(int row, int col)
|
bool matrix_is_on(uint8_t row, uint8_t col)
|
||||||
{
|
{
|
||||||
return (matrix[row] & (1<<col));
|
return (matrix[row] & (1<<col));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline
|
inline
|
||||||
uint16_t matrix_get_row(int row)
|
#if (MATRIX_COLS <= 8)
|
||||||
|
uint8_t matrix_get_row(uint8_t row)
|
||||||
|
#else
|
||||||
|
uint16_t matrix_get_row(uint8_t row)
|
||||||
|
#endif
|
||||||
{
|
{
|
||||||
return matrix[row];
|
return matrix[row];
|
||||||
}
|
}
|
||||||
@ -104,25 +124,37 @@ uint16_t matrix_get_row(int row)
|
|||||||
void matrix_print(void)
|
void matrix_print(void)
|
||||||
{
|
{
|
||||||
print("\nr/c 01234567\n");
|
print("\nr/c 01234567\n");
|
||||||
for (int row = 0; row < matrix_rows(); row++) {
|
for (uint8_t row = 0; row < matrix_rows(); row++) {
|
||||||
phex(row); print(": ");
|
phex(row); print(": ");
|
||||||
|
#if (MATRIX_COLS <= 8)
|
||||||
pbin_reverse(matrix_get_row(row));
|
pbin_reverse(matrix_get_row(row));
|
||||||
|
#else
|
||||||
|
pbin_reverse16(matrix_get_row(row));
|
||||||
|
#endif
|
||||||
|
#ifdef MATRIX_HAS_GHOST
|
||||||
if (matrix_has_ghost_in_row(row)) {
|
if (matrix_has_ghost_in_row(row)) {
|
||||||
print(" <ghost");
|
print(" <ghost");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
print("\n");
|
print("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int matrix_key_count(void)
|
uint8_t matrix_key_count(void)
|
||||||
{
|
{
|
||||||
int count = 0;
|
uint8_t count = 0;
|
||||||
for (int i = 0; i < MATRIX_ROWS; i++) {
|
for (uint8_t i = 0; i < MATRIX_ROWS; i++) {
|
||||||
|
#if (MATRIX_COLS <= 8)
|
||||||
count += bitpop(matrix[i]);
|
count += bitpop(matrix[i]);
|
||||||
|
#else
|
||||||
|
count += bitpop16(matrix[i]);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef MATRIX_HAS_GHOST
|
||||||
|
inline
|
||||||
static bool matrix_has_ghost_in_row(uint8_t row)
|
static bool matrix_has_ghost_in_row(uint8_t row)
|
||||||
{
|
{
|
||||||
// no ghost exists in case less than 2 keys on
|
// no ghost exists in case less than 2 keys on
|
||||||
@ -130,102 +162,74 @@ static bool matrix_has_ghost_in_row(uint8_t row)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// ghost exists in case same state as other row
|
// ghost exists in case same state as other row
|
||||||
for (int i=0; i < MATRIX_ROWS; i++) {
|
for (uint8_t i=0; i < MATRIX_ROWS; i++) {
|
||||||
if (i != row && (matrix[i] & matrix[row]) == matrix[row])
|
if (i != row && (matrix[i] & matrix[row]) == matrix[row])
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
inline
|
||||||
static uint8_t read_col(void)
|
static uint8_t read_col(void)
|
||||||
{
|
{
|
||||||
return PINB;
|
return PINB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
static void unselect_rows(void)
|
static void unselect_rows(void)
|
||||||
{
|
{
|
||||||
DDRD = 0x00;
|
// Hi-Z(DDR:0, PORT:0) to unselect
|
||||||
PORTD = 0x00;
|
DDRC &= ~0b11000000; // PC: 7,6
|
||||||
DDRC = 0x00;
|
PORTC &= ~0b11000000;
|
||||||
PORTC = 0x00;
|
DDRD &= ~0b11000111; // PD: 7,6,2,1,0
|
||||||
DDRF = 0x00;
|
PORTD &= ~0b11000111;
|
||||||
PORTF = 0x00;
|
DDRF &= ~0b11000000; // PF: 7,6
|
||||||
|
PORTF &= ~0b11000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline
|
||||||
static void select_row(uint8_t row)
|
static void select_row(uint8_t row)
|
||||||
{
|
{
|
||||||
|
// Output low(DDR:1, PORT:0) to select
|
||||||
|
// row: 0 1 2 3 4 5 6 7 8
|
||||||
|
// pin: PD0, PC7, PD7, PF6, PD6, PD1, PD2, PC6, PF7
|
||||||
switch (row) {
|
switch (row) {
|
||||||
case 0:
|
case 0:
|
||||||
DDRD = (1<<0);
|
DDRD |= (1<<0);
|
||||||
PORTD = 0x00;
|
PORTD &= ~(1<<0);
|
||||||
DDRC = 0x00;
|
|
||||||
PORTC = 0x00;
|
|
||||||
DDRF = 0x00;
|
|
||||||
PORTF = 0x00;
|
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
DDRD = 0x00;
|
DDRC |= (1<<7);
|
||||||
PORTD = 0x00;
|
PORTC &= ~(1<<7);
|
||||||
DDRC = (1<<7);
|
|
||||||
PORTC = 0x00;
|
|
||||||
DDRF = 0x00;
|
|
||||||
PORTF = 0x00;
|
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
DDRD = (1<<7);
|
DDRD |= (1<<7);
|
||||||
PORTD = 0x00;
|
PORTD &= ~(1<<7);
|
||||||
DDRC = 0x00;
|
|
||||||
PORTC = 0x00;
|
|
||||||
DDRF = 0x00;
|
|
||||||
PORTF = 0x00;
|
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
DDRD = 0x00;
|
DDRF |= (1<<6);
|
||||||
PORTD = 0x00;
|
PORTF &= ~(1<<6);
|
||||||
DDRC = 0x00;
|
|
||||||
PORTC = 0x00;
|
|
||||||
DDRF = (1<<6);
|
|
||||||
PORTF = 0x00;
|
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
DDRD = (1<<6);
|
DDRD |= (1<<6);
|
||||||
PORTD = 0x00;
|
PORTD &= ~(1<<6);
|
||||||
DDRC = 0x00;
|
|
||||||
PORTC = 0x00;
|
|
||||||
DDRF = 0x00;
|
|
||||||
PORTF = 0x00;
|
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
DDRD = (1<<1);
|
DDRD |= (1<<1);
|
||||||
PORTD = 0x00;
|
PORTD &= ~(1<<1);
|
||||||
DDRC = 0x00;
|
|
||||||
PORTC = 0x00;
|
|
||||||
DDRF = 0x00;
|
|
||||||
PORTF = 0x00;
|
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
DDRD = (1<<2);
|
DDRD |= (1<<2);
|
||||||
PORTD = 0x00;
|
PORTD &= ~(1<<2);
|
||||||
DDRC = 0x00;
|
|
||||||
PORTC = 0x00;
|
|
||||||
DDRF = 0x00;
|
|
||||||
PORTF = 0x00;
|
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
DDRD = 0x00;
|
DDRC |= (1<<6);
|
||||||
PORTD = 0x00;
|
PORTC &= ~(1<<6);
|
||||||
DDRC = (1<<6);
|
|
||||||
PORTC = 0x00;
|
|
||||||
DDRF = 0x00;
|
|
||||||
PORTF = 0x00;
|
|
||||||
break;
|
break;
|
||||||
case 8:
|
case 8:
|
||||||
DDRD = 0x00;
|
DDRF |= (1<<7);
|
||||||
PORTD = 0x00;
|
PORTF &= ~(1<<7);
|
||||||
DDRC = 0x00;
|
|
||||||
PORTC = 0x00;
|
|
||||||
DDRF = (1<<7);
|
|
||||||
PORTF = 0x00;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +0,0 @@
|
|||||||
#ifndef MATRIX_H
|
|
||||||
#define MATRIX_H 1
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "matrix_skel.h"
|
|
||||||
|
|
||||||
|
|
||||||
#define MATRIX_ROWS 9
|
|
||||||
#define MATRIX_COLS 8
|
|
||||||
|
|
||||||
|
|
||||||
extern uint8_t *matrix;
|
|
||||||
extern uint8_t *matrix_prev;
|
|
||||||
|
|
||||||
#endif
|
|
@ -28,27 +28,32 @@
|
|||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
#include <avr/interrupt.h>
|
#include <avr/interrupt.h>
|
||||||
#include <util/delay.h>
|
#include <util/delay.h>
|
||||||
|
#include "keyboard.h"
|
||||||
#include "usb.h"
|
#include "usb.h"
|
||||||
#include "matrix_skel.h"
|
#include "matrix.h"
|
||||||
#include "key_process.h"
|
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "controller.h"
|
#include "jump_bootloader.h"
|
||||||
|
#ifdef PS2_MOUSE_ENABLE
|
||||||
|
# include "ps2_mouse.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
|
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
|
||||||
|
|
||||||
|
|
||||||
bool debug_enable = false;
|
bool debug_enable = false;
|
||||||
bool debug_matrix = false;
|
bool debug_matrix = false;
|
||||||
bool debug_keyboard = false;
|
bool debug_keyboard = false;
|
||||||
bool debug_mouse = false;
|
bool debug_mouse = false;
|
||||||
|
|
||||||
uint16_t idle_count=0;
|
|
||||||
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
|
DEBUG_LED_CONFIG;
|
||||||
|
DEBUG_LED_OFF;
|
||||||
|
|
||||||
// set for 16 MHz clock
|
// set for 16 MHz clock
|
||||||
CPU_PRESCALE(0);
|
CPU_PRESCALE(0);
|
||||||
|
|
||||||
@ -58,25 +63,9 @@ int main(void)
|
|||||||
usb_init();
|
usb_init();
|
||||||
while (!usb_configured()) /* wait */ ;
|
while (!usb_configured()) /* wait */ ;
|
||||||
|
|
||||||
// Configure timer 0 to generate a timer overflow interrupt every
|
keyboard_init();
|
||||||
// 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.
|
|
||||||
TCCR0A = 0x00;
|
|
||||||
TCCR0B = 0x05;
|
|
||||||
TIMSK0 = (1<<TOIE0);
|
|
||||||
|
|
||||||
|
|
||||||
matrix_init();
|
|
||||||
matrix_scan();
|
matrix_scan();
|
||||||
// debug on by pressing down any 4 or more keys during boot time.
|
if (matrix_key_count() >= 3) {
|
||||||
if (matrix_key_count() >= 4) {
|
|
||||||
print_enable = true;
|
|
||||||
debug_enable = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* wait for debug pipe ready */
|
|
||||||
if (print_enable) {
|
|
||||||
#ifdef DEBUG_LED
|
#ifdef DEBUG_LED
|
||||||
for (int i = 0; i < 6; i++) {
|
for (int i = 0; i < 6; i++) {
|
||||||
DEBUG_LED_CONFIG;
|
DEBUG_LED_CONFIG;
|
||||||
@ -86,24 +75,23 @@ int main(void)
|
|||||||
_delay_ms(500);
|
_delay_ms(500);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
_delay_ms(6000);
|
_delay_ms(5000);
|
||||||
#endif
|
#endif
|
||||||
|
print_enable = true;
|
||||||
|
debug_enable = true;
|
||||||
|
debug_matrix = true;
|
||||||
|
debug_keyboard = true;
|
||||||
|
debug_mouse = true;
|
||||||
|
print("debug enabled.\n");
|
||||||
}
|
}
|
||||||
// print description
|
if (matrix_key_count() >= 4) {
|
||||||
print(STR(DESCRIPTION) "\n");
|
print("jump to bootloader...\n");
|
||||||
|
_delay_ms(1000);
|
||||||
|
jump_bootloader(); // not return
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
proc_matrix();
|
keyboard_proc();
|
||||||
_delay_ms(2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 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)
|
|
||||||
{
|
|
||||||
idle_count++;
|
|
||||||
}
|
|
62
main_vusb.c
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/* PS/2 to USB keyboard converter
|
||||||
|
* 2011/02/20
|
||||||
|
* Copyright (c) 2011 tmk
|
||||||
|
*/
|
||||||
|
/* 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();
|
||||||
|
}
|
||||||
|
}
|
@ -1,26 +1,30 @@
|
|||||||
#ifndef MATRIX_SKEL_H
|
#ifndef MATRIX_H
|
||||||
#define MATRIX_SKEL_H 1
|
#define MATRIX_H
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
/* number of matrix rows */
|
/* number of matrix rows */
|
||||||
int matrix_rows(void);
|
uint8_t matrix_rows(void);
|
||||||
/* number of matrix columns */
|
/* number of matrix columns */
|
||||||
int matrix_cols(void);
|
uint8_t matrix_cols(void);
|
||||||
/* intialize matrix for scaning. should be called once. */
|
/* intialize matrix for scaning. should be called once. */
|
||||||
void matrix_init(void);
|
void matrix_init(void);
|
||||||
/* scan all key states on matrix */
|
/* scan all key states on matrix */
|
||||||
int matrix_scan(void);
|
uint8_t matrix_scan(void);
|
||||||
/* whether modified from previous scan. used after matrix_scan. */
|
/* whether modified from previous scan. used after matrix_scan. */
|
||||||
bool matrix_is_modified(void);
|
bool matrix_is_modified(void);
|
||||||
/* whether ghosting occur on matrix. */
|
/* whether ghosting occur on matrix. */
|
||||||
bool matrix_has_ghost(void);
|
bool matrix_has_ghost(void);
|
||||||
/* whether a swtich is on */
|
/* whether a swtich is on */
|
||||||
bool matrix_is_on(int row, int col);
|
bool matrix_is_on(uint8_t row, uint8_t col);
|
||||||
/* matrix state on row */
|
/* matrix state on row */
|
||||||
uint16_t matrix_get_row(int row);
|
#if (MATRIX_COLS <= 8)
|
||||||
|
uint8_t matrix_get_row(uint8_t row);
|
||||||
|
#else
|
||||||
|
uint16_t matrix_get_row(uint8_t row);
|
||||||
|
#endif
|
||||||
/* count keys pressed */
|
/* count keys pressed */
|
||||||
int matrix_key_count(void);
|
uint8_t matrix_key_count(void);
|
||||||
/* print matrix for debug */
|
/* print matrix for debug */
|
||||||
void matrix_print(void);
|
void matrix_print(void);
|
||||||
|
|
115
mousekey.c
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include "usb_keycodes.h"
|
||||||
|
#include "host.h"
|
||||||
|
#include "timer.h"
|
||||||
|
#include "print.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "mousekey.h"
|
||||||
|
|
||||||
|
|
||||||
|
static report_mouse_t report;
|
||||||
|
static report_mouse_t report_prev;
|
||||||
|
|
||||||
|
static uint8_t mousekey_repeat = 0;
|
||||||
|
|
||||||
|
static void mousekey_debug(void);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: fix acceleration algorithm
|
||||||
|
* see wikipedia http://en.wikipedia.org/wiki/Mouse_keys
|
||||||
|
*/
|
||||||
|
#ifndef MOUSEKEY_DELAY_TIME
|
||||||
|
# define MOUSEKEY_DELAY_TIME 255
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// acceleration parameters
|
||||||
|
uint8_t mousekey_move_unit = 2;
|
||||||
|
uint8_t mousekey_resolution = 5;
|
||||||
|
|
||||||
|
|
||||||
|
static inline uint8_t move_unit(void)
|
||||||
|
{
|
||||||
|
uint16_t unit = 5 + mousekey_repeat*2;
|
||||||
|
return (unit > 63 ? 63 : unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mousekey_decode(uint8_t code)
|
||||||
|
{
|
||||||
|
if (code == KB_MS_UP) report.y = -move_unit();
|
||||||
|
else if (code == KB_MS_DOWN) report.y = move_unit();
|
||||||
|
else if (code == KB_MS_LEFT) report.x = -move_unit();
|
||||||
|
else if (code == KB_MS_RIGHT) report.x = move_unit();
|
||||||
|
else if (code == KB_MS_BTN1) report.buttons |= MOUSE_BTN1;
|
||||||
|
else if (code == KB_MS_BTN2) report.buttons |= MOUSE_BTN2;
|
||||||
|
else if (code == KB_MS_BTN3) report.buttons |= MOUSE_BTN3;
|
||||||
|
else if (code == KB_MS_BTN4) report.buttons |= MOUSE_BTN4;
|
||||||
|
else if (code == KB_MS_BTN5) report.buttons |= MOUSE_BTN5;
|
||||||
|
else if (code == KB_MS_WH_UP) report.v += 1;
|
||||||
|
else if (code == KB_MS_WH_DOWN) report.v -= 1;
|
||||||
|
else if (code == KB_MS_WH_LEFT) report.h -= 1;
|
||||||
|
else if (code == KB_MS_WH_RIGHT)report.h += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mousekey_changed(void)
|
||||||
|
{
|
||||||
|
return (report.buttons != report_prev.buttons ||
|
||||||
|
report.x || report.y || report.v || report.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mousekey_send(void)
|
||||||
|
{
|
||||||
|
static uint16_t last_timer = 0;
|
||||||
|
|
||||||
|
if (!mousekey_changed()) {
|
||||||
|
mousekey_repeat = 0;
|
||||||
|
mousekey_clear_report();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send immediately when buttun state is changed
|
||||||
|
if (report.buttons == report_prev.buttons) {
|
||||||
|
if (timer_elapsed(last_timer) < 5) {
|
||||||
|
mousekey_clear_report();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mousekey_repeat != 0xFF) {
|
||||||
|
mousekey_repeat++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (report.x && report.y) {
|
||||||
|
report.x *= 0.7;
|
||||||
|
report.y *= 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
mousekey_debug();
|
||||||
|
host_mouse_send(&report);
|
||||||
|
report_prev = report;
|
||||||
|
last_timer = timer_read();
|
||||||
|
mousekey_clear_report();
|
||||||
|
}
|
||||||
|
|
||||||
|
void mousekey_clear_report(void)
|
||||||
|
{
|
||||||
|
report.buttons = 0;
|
||||||
|
report.x = 0;
|
||||||
|
report.y = 0;
|
||||||
|
report.v = 0;
|
||||||
|
report.h = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mousekey_debug(void)
|
||||||
|
{
|
||||||
|
if (!debug_mouse) return;
|
||||||
|
print("mousekey[btn|x y v h]: ");
|
||||||
|
phex(report.buttons); print("|");
|
||||||
|
phex(report.x); print(" ");
|
||||||
|
phex(report.y); print(" ");
|
||||||
|
phex(report.v); print(" ");
|
||||||
|
phex(report.h);
|
||||||
|
phex(mousekey_repeat);
|
||||||
|
print("\n");
|
||||||
|
}
|
75
mousekey.c.bak
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include "usb_keycodes.h"
|
||||||
|
#include "usb_mouse.h"
|
||||||
|
#include "mousekey.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int8_t mousekey_x = 0;
|
||||||
|
static int8_t mousekey_y = 0;
|
||||||
|
static int8_t mousekey_v = 0;
|
||||||
|
static int8_t mousekey_h = 0;
|
||||||
|
static uint8_t mousekey_btn = 0;
|
||||||
|
static uint8_t mousekey_btn_prev = 0;
|
||||||
|
static uint8_t mousekey_repeat = 0;
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TODO: fix acceleration algorithm
|
||||||
|
* see wikipedia http://en.wikipedia.org/wiki/Mouse_keys
|
||||||
|
*/
|
||||||
|
#ifndef MOUSEKEY_DELAY_TIME
|
||||||
|
# define MOUSEKEY_DELAY_TIME 255
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static inline uint8_t move_unit(void)
|
||||||
|
{
|
||||||
|
return 10 + (mousekey_repeat < 50 ? mousekey_repeat/5 : 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mousekey_decode(uint8_t code)
|
||||||
|
{
|
||||||
|
if (code == KB_MS_UP) mousekey_y -= move_unit();
|
||||||
|
else if (code == KB_MS_DOWN) mousekey_y += move_unit();
|
||||||
|
else if (code == KB_MS_LEFT) mousekey_x -= move_unit();
|
||||||
|
else if (code == KB_MS_RIGHT) mousekey_x += move_unit();
|
||||||
|
else if (code == KB_MS_BTN1) mousekey_btn |= MOUSE_BTN1;
|
||||||
|
else if (code == KB_MS_BTN2) mousekey_btn |= MOUSE_BTN2;
|
||||||
|
else if (code == KB_MS_BTN3) mousekey_btn |= MOUSE_BTN3;
|
||||||
|
else if (code == KB_MS_BTN4) mousekey_btn |= MOUSE_BTN4;
|
||||||
|
else if (code == KB_MS_BTN5) mousekey_btn |= MOUSE_BTN5;
|
||||||
|
else if (code == KB_MS_WH_UP) mousekey_v += 1;
|
||||||
|
else if (code == KB_MS_WH_DOWN) mousekey_v -= 1;
|
||||||
|
else if (code == KB_MS_WH_LEFT) mousekey_h -= 1;
|
||||||
|
else if (code == KB_MS_WH_RIGHT) mousekey_h += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mousekey_changed(void)
|
||||||
|
{
|
||||||
|
return (mousekey_x || mousekey_y || mousekey_v || mousekey_h || mousekey_btn != mousekey_btn_prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void mousekey_usb_send(void)
|
||||||
|
{
|
||||||
|
if (mousekey_changed()) {
|
||||||
|
mousekey_btn_prev = mousekey_btn;
|
||||||
|
if (mousekey_x && mousekey_y)
|
||||||
|
usb_mouse_send(mousekey_x*0.7, mousekey_y*0.7, mousekey_v, mousekey_h, mousekey_btn);
|
||||||
|
else
|
||||||
|
usb_mouse_send(mousekey_x, mousekey_y, mousekey_v, mousekey_h, mousekey_btn);
|
||||||
|
|
||||||
|
usb_mouse_print(mousekey_x, mousekey_y, mousekey_v, mousekey_h, mousekey_btn);
|
||||||
|
|
||||||
|
if (mousekey_x || mousekey_y || mousekey_v || mousekey_h)
|
||||||
|
_delay_ms(MOUSEKEY_DELAY_TIME >> (mousekey_repeat < 5 ? mousekey_repeat : 4));
|
||||||
|
mousekey_repeat++;
|
||||||
|
} else {
|
||||||
|
mousekey_repeat = 0;
|
||||||
|
}
|
||||||
|
mousekey_x = 0;
|
||||||
|
mousekey_y = 0;
|
||||||
|
mousekey_v = 0;
|
||||||
|
mousekey_h = 0;
|
||||||
|
mousekey_btn = 0;
|
||||||
|
}
|
12
mousekey.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef MOUSEKEY_H
|
||||||
|
#define MOUSEKEY_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "host.h"
|
||||||
|
|
||||||
|
void mousekey_decode(uint8_t code);
|
||||||
|
bool mousekey_changed(void);
|
||||||
|
void mousekey_send(void);
|
||||||
|
void mousekey_clear_report(void);
|
||||||
|
|
||||||
|
#endif
|
11
mousekey.h.bak
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
#ifndef MOUSEKEY_H
|
||||||
|
#define MOUSEKEY_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
void mousekey_decode(uint8_t code);
|
||||||
|
bool mousekey_changed(void);
|
||||||
|
void mousekey_usb_send(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
166
pjrc/host.c
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include "usb_keycodes.h"
|
||||||
|
#include "usb_keyboard.h"
|
||||||
|
#if defined(MOUSEKEY_ENABLE) || defined(PS2_MOUSE_ENABLE)
|
||||||
|
#include "usb_mouse.h"
|
||||||
|
#endif
|
||||||
|
#ifdef USB_EXTRA_ENABLE
|
||||||
|
#include "usb_extra.h"
|
||||||
|
#endif
|
||||||
|
#include "debug.h"
|
||||||
|
#include "host.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef USB_NKRO_ENABLE
|
||||||
|
bool keyboard_nkro = false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t host_keyboard_leds(void)
|
||||||
|
{
|
||||||
|
return usb_keyboard_leds;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* keyboard report operations */
|
||||||
|
void host_add_key(uint8_t key)
|
||||||
|
{
|
||||||
|
#ifdef USB_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 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]);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return keyboard_report->keys[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void host_send_keyboard_report(void)
|
||||||
|
{
|
||||||
|
usb_keyboard_send_report(keyboard_report);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(MOUSEKEY_ENABLE) || defined(PS2_MOUSE_ENABLE)
|
||||||
|
void host_mouse_send(report_mouse_t *report)
|
||||||
|
{
|
||||||
|
usb_mouse_send(report->x, report->y, report->v, report->h, report->buttons);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USB_EXTRA_ENABLE
|
||||||
|
void host_system_send(uint16_t data)
|
||||||
|
{
|
||||||
|
usb_extra_system_send(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void host_consumer_send(uint16_t data)
|
||||||
|
{
|
||||||
|
static uint16_t last_data = 0;
|
||||||
|
if (data == last_data) return;
|
||||||
|
last_data = data;
|
||||||
|
|
||||||
|
usb_extra_consumer_send(data);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
}
|
40
pjrc/jump_bootloader.c
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// this code from:
|
||||||
|
// http://www.pjrc.com/teensy/jump_to_bootloader.html
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
|
||||||
|
void jump_bootloader(void) {
|
||||||
|
cli();
|
||||||
|
// disable watchdog, if enabled
|
||||||
|
// disable all peripherals
|
||||||
|
UDCON = 1;
|
||||||
|
USBCON = (1<<FRZCLK); // disable USB
|
||||||
|
UCSR1B = 0;
|
||||||
|
_delay_ms(5);
|
||||||
|
#if defined(__AVR_AT90USB162__) // Teensy 1.0
|
||||||
|
EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0;
|
||||||
|
TIMSK0 = 0; TIMSK1 = 0; UCSR1B = 0;
|
||||||
|
DDRB = 0; DDRC = 0; DDRD = 0;
|
||||||
|
PORTB = 0; PORTC = 0; PORTD = 0;
|
||||||
|
asm volatile("jmp 0x3E00");
|
||||||
|
#elif defined(__AVR_ATmega32U4__) // Teensy 2.0
|
||||||
|
EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
|
||||||
|
TIMSK0 = 0; TIMSK1 = 0; TIMSK3 = 0; TIMSK4 = 0; UCSR1B = 0; TWCR = 0;
|
||||||
|
DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0; TWCR = 0;
|
||||||
|
PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
|
||||||
|
asm volatile("jmp 0x7E00");
|
||||||
|
#elif defined(__AVR_AT90USB646__) // Teensy++ 1.0
|
||||||
|
EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
|
||||||
|
TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0;
|
||||||
|
DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
|
||||||
|
PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
|
||||||
|
asm volatile("jmp 0xFC00");
|
||||||
|
#elif defined(__AVR_AT90USB1286__) // Teensy++ 2.0
|
||||||
|
EIMSK = 0; PCICR = 0; SPCR = 0; ACSR = 0; EECR = 0; ADCSRA = 0;
|
||||||
|
TIMSK0 = 0; TIMSK1 = 0; TIMSK2 = 0; TIMSK3 = 0; UCSR1B = 0; TWCR = 0;
|
||||||
|
DDRA = 0; DDRB = 0; DDRC = 0; DDRD = 0; DDRE = 0; DDRF = 0;
|
||||||
|
PORTA = 0; PORTB = 0; PORTC = 0; PORTD = 0; PORTE = 0; PORTF = 0;
|
||||||
|
asm volatile("jmp 0x1FC00");
|
||||||
|
#endif
|
||||||
|
}
|
@ -21,6 +21,8 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#include <avr/interrupt.h>
|
#include <avr/interrupt.h>
|
||||||
@ -28,6 +30,7 @@
|
|||||||
#include "usb_keyboard.h"
|
#include "usb_keyboard.h"
|
||||||
#include "usb_mouse.h"
|
#include "usb_mouse.h"
|
||||||
#include "usb_debug.h"
|
#include "usb_debug.h"
|
||||||
|
#include "usb_extra.h"
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
@ -81,15 +84,30 @@
|
|||||||
|
|
||||||
#define ENDPOINT0_SIZE 32
|
#define ENDPOINT0_SIZE 32
|
||||||
|
|
||||||
|
bool remote_wakeup = false;
|
||||||
|
bool suspend = false;
|
||||||
|
|
||||||
// 0:control endpoint is enabled automatically by controller.
|
// 0:control endpoint is enabled automatically by controller.
|
||||||
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(KEYBOARD_SIZE) | KEYBOARD_BUFFER, // 1
|
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KBD_SIZE) | KBD_BUFFER, // 1
|
||||||
|
#ifdef USB_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
|
||||||
|
0, // 2
|
||||||
|
#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
|
||||||
0, // 4
|
#ifdef USB_EXTRA_ENABLE
|
||||||
0, // 5
|
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(EXTRA_SIZE) | EXTRA_BUFFER, // 4
|
||||||
0, // 6
|
#else
|
||||||
|
0, // 4
|
||||||
|
#endif
|
||||||
|
#ifdef USB_NKRO_ENABLE
|
||||||
|
1, EP_TYPE_INTERRUPT_IN, EP_SIZE(KBD2_SIZE) | KBD2_BUFFER, // 5
|
||||||
|
#else
|
||||||
|
0, // 5
|
||||||
|
#endif
|
||||||
|
0, // 6
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -106,7 +124,7 @@ static const uint8_t PROGMEM endpoint_config_table[] = {
|
|||||||
// spec and relevant portions of any USB class specifications!
|
// spec and relevant portions of any USB class specifications!
|
||||||
|
|
||||||
|
|
||||||
static uint8_t PROGMEM device_descriptor[] = {
|
const static uint8_t PROGMEM device_descriptor[] = {
|
||||||
18, // bLength
|
18, // bLength
|
||||||
1, // bDescriptorType
|
1, // bDescriptorType
|
||||||
0x00, 0x02, // bcdUSB
|
0x00, 0x02, // bcdUSB
|
||||||
@ -124,7 +142,7 @@ static uint8_t PROGMEM device_descriptor[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60
|
// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60
|
||||||
static uint8_t PROGMEM keyboard_hid_report_desc[] = {
|
const static uint8_t PROGMEM keyboard_hid_report_desc[] = {
|
||||||
0x05, 0x01, // Usage Page (Generic Desktop),
|
0x05, 0x01, // Usage Page (Generic Desktop),
|
||||||
0x09, 0x06, // Usage (Keyboard),
|
0x09, 0x06, // Usage (Keyboard),
|
||||||
0xA1, 0x01, // Collection (Application),
|
0xA1, 0x01, // Collection (Application),
|
||||||
@ -148,95 +166,110 @@ static uint8_t PROGMEM keyboard_hid_report_desc[] = {
|
|||||||
0x95, 0x01, // Report Count (1),
|
0x95, 0x01, // Report Count (1),
|
||||||
0x75, 0x03, // Report Size (3),
|
0x75, 0x03, // Report Size (3),
|
||||||
0x91, 0x03, // Output (Constant), ;LED report padding
|
0x91, 0x03, // Output (Constant), ;LED report padding
|
||||||
0x95, 0x06, // Report Count (6),
|
0x95, KBD_REPORT_KEYS, // Report Count (),
|
||||||
0x75, 0x08, // Report Size (8),
|
0x75, 0x08, // Report Size (8),
|
||||||
0x15, 0x00, // Logical Minimum (0),
|
0x15, 0x00, // Logical Minimum (0),
|
||||||
0x25, 0x68, // Logical Maximum(104),
|
0x25, 0xFF, // Logical Maximum(255),
|
||||||
0x05, 0x07, // Usage Page (Key Codes),
|
0x05, 0x07, // Usage Page (Key Codes),
|
||||||
0x19, 0x00, // Usage Minimum (0),
|
0x19, 0x00, // Usage Minimum (0),
|
||||||
0x29, 0x68, // Usage Maximum (104),
|
0x29, 0xFF, // Usage Maximum (255),
|
||||||
0x81, 0x00, // Input (Data, Array),
|
0x81, 0x00, // Input (Data, Array),
|
||||||
0xc0 // End Collection
|
0xc0 // End Collection
|
||||||
};
|
};
|
||||||
|
#ifdef USB_NKRO_ENABLE
|
||||||
|
const static uint8_t PROGMEM keyboard2_hid_report_desc[] = {
|
||||||
|
0x05, 0x01, // Usage Page (Generic Desktop),
|
||||||
|
0x09, 0x06, // Usage (Keyboard),
|
||||||
|
0xA1, 0x01, // Collection (Application),
|
||||||
|
// bitmap of modifiers
|
||||||
|
0x75, 0x01, // Report Size (1),
|
||||||
|
0x95, 0x08, // Report Count (8),
|
||||||
|
0x05, 0x07, // Usage Page (Key Codes),
|
||||||
|
0x19, 0xE0, // Usage Minimum (224),
|
||||||
|
0x29, 0xE7, // Usage Maximum (231),
|
||||||
|
0x15, 0x00, // Logical Minimum (0),
|
||||||
|
0x25, 0x01, // Logical Maximum (1),
|
||||||
|
0x81, 0x02, // Input (Data, Variable, Absolute), ;Modifier byte
|
||||||
|
// LED output report
|
||||||
|
0x95, 0x05, // Report Count (5),
|
||||||
|
0x75, 0x01, // Report Size (1),
|
||||||
|
0x05, 0x08, // Usage Page (LEDs),
|
||||||
|
0x19, 0x01, // Usage Minimum (1),
|
||||||
|
0x29, 0x05, // Usage Maximum (5),
|
||||||
|
0x91, 0x02, // Output (Data, Variable, Absolute),
|
||||||
|
0x95, 0x01, // Report Count (1),
|
||||||
|
0x75, 0x03, // Report Size (3),
|
||||||
|
0x91, 0x03, // Output (Constant),
|
||||||
|
// bitmap of keys
|
||||||
|
0x95, KBD2_REPORT_KEYS*8, // Report Count (),
|
||||||
|
0x75, 0x01, // Report Size (1),
|
||||||
|
0x15, 0x00, // Logical Minimum (0),
|
||||||
|
0x25, 0x01, // Logical Maximum(1),
|
||||||
|
0x05, 0x07, // Usage Page (Key Codes),
|
||||||
|
0x19, 0x00, // Usage Minimum (0),
|
||||||
|
0x29, KBD2_REPORT_KEYS*8-1, // Usage Maximum (),
|
||||||
|
0x81, 0x02, // Input (Data, Variable, Absolute),
|
||||||
|
0xc0 // End Collection
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USB_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/
|
||||||
// http://www.microsoft.com/whdc/device/input/wheel.mspx
|
// http://www.microsoft.com/whdc/device/input/wheel.mspx
|
||||||
static uint8_t PROGMEM mouse_hid_report_desc[] = {
|
const static uint8_t PROGMEM mouse_hid_report_desc[] = {
|
||||||
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
|
/* mouse */
|
||||||
0x09, 0x02, // USAGE (Mouse)
|
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
|
||||||
0xa1, 0x01, // COLLECTION (Application)
|
0x09, 0x02, // USAGE (Mouse)
|
||||||
0x09, 0x02, // USAGE (Mouse)
|
0xa1, 0x01, // COLLECTION (Application)
|
||||||
0xa1, 0x02, // COLLECTION (Logical)
|
//0x85, REPORT_ID_MOUSE, // REPORT_ID (1)
|
||||||
0x09, 0x01, // USAGE (Pointer)
|
0x09, 0x01, // USAGE (Pointer)
|
||||||
0xa1, 0x00, // COLLECTION (Physical)
|
0xa1, 0x00, // COLLECTION (Physical)
|
||||||
// ------------------------------ Buttons
|
// ---------------------------- Buttons
|
||||||
0x05, 0x09, // USAGE_PAGE (Button)
|
0x05, 0x09, // USAGE_PAGE (Button)
|
||||||
0x19, 0x01, // USAGE_MINIMUM (Button 1)
|
0x19, 0x01, // USAGE_MINIMUM (Button 1)
|
||||||
0x29, 0x05, // USAGE_MAXIMUM (Button 5)
|
0x29, 0x05, // USAGE_MAXIMUM (Button 5)
|
||||||
0x15, 0x00, // LOGICAL_MINIMUM (0)
|
0x15, 0x00, // LOGICAL_MINIMUM (0)
|
||||||
0x25, 0x01, // LOGICAL_MAXIMUM (1)
|
0x25, 0x01, // LOGICAL_MAXIMUM (1)
|
||||||
0x75, 0x01, // REPORT_SIZE (1)
|
0x75, 0x01, // REPORT_SIZE (1)
|
||||||
0x95, 0x05, // REPORT_COUNT (5)
|
0x95, 0x05, // REPORT_COUNT (5)
|
||||||
0x81, 0x02, // INPUT (Data,Var,Abs)
|
0x81, 0x02, // INPUT (Data,Var,Abs)
|
||||||
// ------------------------------ Padding
|
0x75, 0x03, // REPORT_SIZE (3)
|
||||||
0x75, 0x03, // REPORT_SIZE (3)
|
0x95, 0x01, // REPORT_COUNT (1)
|
||||||
0x95, 0x01, // REPORT_COUNT (1)
|
0x81, 0x03, // INPUT (Cnst,Var,Abs)
|
||||||
0x81, 0x03, // INPUT (Cnst,Var,Abs)
|
// ---------------------------- X,Y position
|
||||||
// ------------------------------ X,Y position
|
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
|
||||||
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
|
0x09, 0x30, // USAGE (X)
|
||||||
0x09, 0x30, // USAGE (X)
|
0x09, 0x31, // USAGE (Y)
|
||||||
0x09, 0x31, // USAGE (Y)
|
0x15, 0x81, // LOGICAL_MINIMUM (-127)
|
||||||
0x15, 0x81, // LOGICAL_MINIMUM (-127)
|
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
|
||||||
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
|
0x75, 0x08, // REPORT_SIZE (8)
|
||||||
0x75, 0x08, // REPORT_SIZE (8)
|
0x95, 0x02, // REPORT_COUNT (2)
|
||||||
0x95, 0x02, // REPORT_COUNT (2)
|
0x81, 0x06, // INPUT (Data,Var,Rel)
|
||||||
0x81, 0x06, // INPUT (Data,Var,Rel)
|
// ---------------------------- Vertical wheel
|
||||||
0xa1, 0x02, // COLLECTION (Logical)
|
0x09, 0x38, // USAGE (Wheel)
|
||||||
// ------------------------------ Vertical wheel res multiplier
|
0x15, 0x81, // LOGICAL_MINIMUM (-127)
|
||||||
0x09, 0x48, // USAGE (Resolution Multiplier)
|
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
|
||||||
0x15, 0x00, // LOGICAL_MINIMUM (0)
|
0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical
|
||||||
0x25, 0x01, // LOGICAL_MAXIMUM (1)
|
0x45, 0x00, // PHYSICAL_MAXIMUM (0)
|
||||||
0x35, 0x01, // PHYSICAL_MINIMUM (1)
|
0x75, 0x08, // REPORT_SIZE (8)
|
||||||
0x45, 0x04, // PHYSICAL_MAXIMUM (4)
|
0x95, 0x01, // REPORT_COUNT (1)
|
||||||
0x75, 0x02, // REPORT_SIZE (2)
|
0x81, 0x06, // INPUT (Data,Var,Rel)
|
||||||
0x95, 0x01, // REPORT_COUNT (1)
|
// ---------------------------- Horizontal wheel
|
||||||
0xa4, // PUSH
|
0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
|
||||||
0xb1, 0x02, // FEATURE (Data,Var,Abs)
|
0x0a, 0x38, 0x02, // USAGE (AC Pan)
|
||||||
// ------------------------------ Vertical wheel
|
0x15, 0x81, // LOGICAL_MINIMUM (-127)
|
||||||
0x09, 0x38, // USAGE (Wheel)
|
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
|
||||||
0x15, 0x81, // LOGICAL_MINIMUM (-127)
|
0x75, 0x08, // REPORT_SIZE (8)
|
||||||
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
|
0x95, 0x01, // REPORT_COUNT (1)
|
||||||
0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical
|
0x81, 0x06, // INPUT (Data,Var,Rel)
|
||||||
0x45, 0x00, // PHYSICAL_MAXIMUM (0)
|
0xc0, // END_COLLECTION
|
||||||
0x75, 0x08, // REPORT_SIZE (8)
|
0xc0, // END_COLLECTION
|
||||||
0x81, 0x06, // INPUT (Data,Var,Rel)
|
|
||||||
0xc0, // END_COLLECTION
|
|
||||||
0xa1, 0x02, // COLLECTION (Logical)
|
|
||||||
// ------------------------------ Horizontal wheel res multiplier
|
|
||||||
0x09, 0x48, // USAGE (Resolution Multiplier)
|
|
||||||
0xb4, // POP
|
|
||||||
0xb1, 0x02, // FEATURE (Data,Var,Abs)
|
|
||||||
// ------------------------------ Padding for Feature report
|
|
||||||
0x35, 0x00, // PHYSICAL_MINIMUM (0) - reset physical
|
|
||||||
0x45, 0x00, // PHYSICAL_MAXIMUM (0)
|
|
||||||
0x75, 0x04, // REPORT_SIZE (4)
|
|
||||||
0xb1, 0x03, // FEATURE (Cnst,Var,Abs)
|
|
||||||
// ------------------------------ Horizontal wheel
|
|
||||||
0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
|
|
||||||
0x0a, 0x38, 0x02, // USAGE (AC Pan)
|
|
||||||
0x15, 0x81, // LOGICAL_MINIMUM (-127)
|
|
||||||
0x25, 0x7f, // LOGICAL_MAXIMUM (127)
|
|
||||||
0x75, 0x08, // REPORT_SIZE (8)
|
|
||||||
0x81, 0x06, // INPUT (Data,Var,Rel)
|
|
||||||
0xc0, // END_COLLECTION
|
|
||||||
0xc0, // END_COLLECTION
|
|
||||||
0xc0, // END_COLLECTION
|
|
||||||
0xc0 // END_COLLECTION
|
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
static uint8_t PROGMEM debug_hid_report_desc[] = {
|
const static uint8_t PROGMEM debug_hid_report_desc[] = {
|
||||||
0x06, 0x31, 0xFF, // Usage Page 0xFF31 (vendor defined)
|
0x06, 0x31, 0xFF, // Usage Page 0xFF31 (vendor defined)
|
||||||
0x09, 0x74, // Usage 0x74
|
0x09, 0x74, // Usage 0x74
|
||||||
0xA1, 0x53, // Collection 0x53
|
0xA1, 0x53, // Collection 0x53
|
||||||
@ -249,26 +282,84 @@ static uint8_t PROGMEM debug_hid_report_desc[] = {
|
|||||||
0xC0 // end collection
|
0xC0 // end collection
|
||||||
};
|
};
|
||||||
|
|
||||||
#define CONFIG1_DESC_SIZE (9+(9+9+7)+(9+9+7)+(9+9+7))
|
#ifdef USB_EXTRA_ENABLE
|
||||||
#define KEYBOARD_HID_DESC_OFFSET (9+9)
|
// audio controls & system controls
|
||||||
#define MOUSE_HID_DESC_OFFSET (9+(9+9+7)+9)
|
// http://www.microsoft.com/whdc/archive/w2kbd.mspx
|
||||||
#define DEBUG_HID_DESC_OFFSET (9+(9+9+7)+(9+9+7)+9)
|
const static uint8_t PROGMEM extra_hid_report_desc[] = {
|
||||||
static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
|
/* system control */
|
||||||
|
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
|
||||||
|
0x09, 0x80, // USAGE (System Control)
|
||||||
|
0xa1, 0x01, // COLLECTION (Application)
|
||||||
|
0x85, REPORT_ID_SYSTEM, // REPORT_ID (2)
|
||||||
|
0x15, 0x01, // LOGICAL_MINIMUM (0x1)
|
||||||
|
0x25, 0xb7, // LOGICAL_MAXIMUM (0xb7)
|
||||||
|
0x19, 0x01, // USAGE_MINIMUM (0x1)
|
||||||
|
0x29, 0xb7, // USAGE_MAXIMUM (0xb7)
|
||||||
|
0x75, 0x10, // REPORT_SIZE (16)
|
||||||
|
0x95, 0x01, // REPORT_COUNT (1)
|
||||||
|
0x81, 0x00, // INPUT (Data,Array,Abs)
|
||||||
|
0xc0, // END_COLLECTION
|
||||||
|
/* consumer */
|
||||||
|
0x05, 0x0c, // USAGE_PAGE (Consumer Devices)
|
||||||
|
0x09, 0x01, // USAGE (Consumer Control)
|
||||||
|
0xa1, 0x01, // COLLECTION (Application)
|
||||||
|
0x85, REPORT_ID_CONSUMER, // REPORT_ID (3)
|
||||||
|
0x15, 0x01, // LOGICAL_MINIMUM (0x1)
|
||||||
|
0x26, 0x9c, 0x02, // LOGICAL_MAXIMUM (0x29c)
|
||||||
|
0x19, 0x01, // USAGE_MINIMUM (0x1)
|
||||||
|
0x2a, 0x9c, 0x02, // USAGE_MAXIMUM (0x29c)
|
||||||
|
0x75, 0x10, // REPORT_SIZE (16)
|
||||||
|
0x95, 0x01, // REPORT_COUNT (1)
|
||||||
|
0x81, 0x00, // INPUT (Data,Array,Abs)
|
||||||
|
0xc0, // END_COLLECTION
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define KBD_HID_DESC_NUM 0
|
||||||
|
#define KBD_HID_DESC_OFFSET (9+(9+9+7)*KBD_HID_DESC_NUM+9)
|
||||||
|
|
||||||
|
#ifdef USB_MOUSE_ENABLE
|
||||||
|
# define MOUSE_HID_DESC_NUM (KBD_HID_DESC_NUM + 1)
|
||||||
|
# define MOUSE_HID_DESC_OFFSET (9+(9+9+7)*MOUSE_HID_DESC_NUM+9)
|
||||||
|
#else
|
||||||
|
# define MOUSE_HID_DESC_NUM (KBD_HID_DESC_NUM + 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define DEBUG_HID_DESC_NUM (MOUSE_HID_DESC_NUM + 1)
|
||||||
|
#define DEBUG_HID_DESC_OFFSET (9+(9+9+7)*DEBUG_HID_DESC_NUM+9)
|
||||||
|
|
||||||
|
#ifdef USB_EXTRA_ENABLE
|
||||||
|
# define EXTRA_HID_DESC_NUM (DEBUG_HID_DESC_NUM + 1)
|
||||||
|
# define EXTRA_HID_DESC_OFFSET (9+(9+9+7)*EXTRA_HID_DESC_NUM+9)
|
||||||
|
#else
|
||||||
|
# define EXTRA_HID_DESC_NUM (DEBUG_HID_DESC_NUM + 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USB_NKRO_ENABLE
|
||||||
|
# define KBD2_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 1)
|
||||||
|
# define KBD2_HID_DESC_OFFSET (9+(9+9+7)*EXTRA_HID_DESC_NUM+9)
|
||||||
|
#else
|
||||||
|
# define KBD2_HID_DESC_NUM (EXTRA_HID_DESC_NUM + 0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define NUM_INTERFACES (KBD2_HID_DESC_NUM + 1)
|
||||||
|
#define CONFIG1_DESC_SIZE (9+(9+9+7)*NUM_INTERFACES)
|
||||||
|
const static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
|
||||||
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
|
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
|
||||||
9, // bLength;
|
9, // bLength;
|
||||||
2, // bDescriptorType;
|
2, // bDescriptorType;
|
||||||
LSB(CONFIG1_DESC_SIZE), // wTotalLength
|
LSB(CONFIG1_DESC_SIZE), // wTotalLength
|
||||||
MSB(CONFIG1_DESC_SIZE),
|
MSB(CONFIG1_DESC_SIZE),
|
||||||
3, // bNumInterfaces
|
NUM_INTERFACES, // bNumInterfaces
|
||||||
1, // bConfigurationValue
|
1, // bConfigurationValue
|
||||||
0, // iConfiguration
|
0, // iConfiguration
|
||||||
0xC0, // bmAttributes
|
0xA0, // bmAttributes
|
||||||
50, // bMaxPower
|
50, // bMaxPower
|
||||||
|
|
||||||
// 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
|
||||||
KEYBOARD_INTERFACE, // bInterfaceNumber
|
KBD_INTERFACE, // bInterfaceNumber
|
||||||
0, // bAlternateSetting
|
0, // bAlternateSetting
|
||||||
1, // bNumEndpoints
|
1, // bNumEndpoints
|
||||||
0x03, // bInterfaceClass (0x03 = HID)
|
0x03, // bInterfaceClass (0x03 = HID)
|
||||||
@ -287,11 +378,12 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
|
|||||||
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
|
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
|
||||||
7, // bLength
|
7, // bLength
|
||||||
5, // bDescriptorType
|
5, // bDescriptorType
|
||||||
KEYBOARD_ENDPOINT | 0x80, // bEndpointAddress
|
KBD_ENDPOINT | 0x80, // bEndpointAddress
|
||||||
0x03, // bmAttributes (0x03=intr)
|
0x03, // bmAttributes (0x03=intr)
|
||||||
KEYBOARD_SIZE, 0, // wMaxPacketSize
|
KBD_SIZE, 0, // wMaxPacketSize
|
||||||
1, // bInterval
|
10, // bInterval
|
||||||
|
|
||||||
|
#ifdef USB_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
|
||||||
@ -299,8 +391,13 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
|
|||||||
0, // bAlternateSetting
|
0, // bAlternateSetting
|
||||||
1, // bNumEndpoints
|
1, // bNumEndpoints
|
||||||
0x03, // bInterfaceClass (0x03 = HID)
|
0x03, // bInterfaceClass (0x03 = HID)
|
||||||
|
// ThinkPad T23 BIOS doesn't work with boot mouse.
|
||||||
|
0x00, // bInterfaceSubClass (0x01 = Boot)
|
||||||
|
0x00, // bInterfaceProtocol (0x02 = Mouse)
|
||||||
|
/*
|
||||||
0x01, // bInterfaceSubClass (0x01 = Boot)
|
0x01, // bInterfaceSubClass (0x01 = Boot)
|
||||||
0x02, // bInterfaceProtocol (0x02 = Mouse)
|
0x02, // bInterfaceProtocol (0x02 = Mouse)
|
||||||
|
*/
|
||||||
0, // iInterface
|
0, // iInterface
|
||||||
// HID descriptor, HID 1.11 spec, section 6.2.1
|
// HID descriptor, HID 1.11 spec, section 6.2.1
|
||||||
9, // bLength
|
9, // bLength
|
||||||
@ -318,6 +415,7 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
|
|||||||
0x03, // bmAttributes (0x03=intr)
|
0x03, // bmAttributes (0x03=intr)
|
||||||
MOUSE_SIZE, 0, // wMaxPacketSize
|
MOUSE_SIZE, 0, // wMaxPacketSize
|
||||||
1, // bInterval
|
1, // bInterval
|
||||||
|
#endif
|
||||||
|
|
||||||
// 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
|
||||||
@ -344,7 +442,65 @@ static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
|
|||||||
DEBUG_TX_ENDPOINT | 0x80, // bEndpointAddress
|
DEBUG_TX_ENDPOINT | 0x80, // bEndpointAddress
|
||||||
0x03, // bmAttributes (0x03=intr)
|
0x03, // bmAttributes (0x03=intr)
|
||||||
DEBUG_TX_SIZE, 0, // wMaxPacketSize
|
DEBUG_TX_SIZE, 0, // wMaxPacketSize
|
||||||
1 // bInterval
|
1, // bInterval
|
||||||
|
|
||||||
|
#ifdef USB_EXTRA_ENABLE
|
||||||
|
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
|
||||||
|
9, // bLength
|
||||||
|
4, // bDescriptorType
|
||||||
|
EXTRA_INTERFACE, // bInterfaceNumber
|
||||||
|
0, // bAlternateSetting
|
||||||
|
1, // bNumEndpoints
|
||||||
|
0x03, // bInterfaceClass (0x03 = HID)
|
||||||
|
0x00, // bInterfaceSubClass
|
||||||
|
0x00, // bInterfaceProtocol
|
||||||
|
0, // iInterface
|
||||||
|
// HID descriptor, HID 1.11 spec, section 6.2.1
|
||||||
|
9, // bLength
|
||||||
|
0x21, // bDescriptorType
|
||||||
|
0x11, 0x01, // bcdHID
|
||||||
|
0, // bCountryCode
|
||||||
|
1, // bNumDescriptors
|
||||||
|
0x22, // bDescriptorType
|
||||||
|
sizeof(extra_hid_report_desc), // wDescriptorLength
|
||||||
|
0,
|
||||||
|
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
|
||||||
|
7, // bLength
|
||||||
|
5, // bDescriptorType
|
||||||
|
EXTRA_ENDPOINT | 0x80, // bEndpointAddress
|
||||||
|
0x03, // bmAttributes (0x03=intr)
|
||||||
|
EXTRA_SIZE, 0, // wMaxPacketSize
|
||||||
|
10, // bInterval
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef USB_NKRO_ENABLE
|
||||||
|
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
|
||||||
|
9, // bLength
|
||||||
|
4, // bDescriptorType
|
||||||
|
KBD2_INTERFACE, // bInterfaceNumber
|
||||||
|
0, // bAlternateSetting
|
||||||
|
1, // bNumEndpoints
|
||||||
|
0x03, // bInterfaceClass (0x03 = HID)
|
||||||
|
0x00, // bInterfaceSubClass (0x01 = Boot)
|
||||||
|
0x00, // bInterfaceProtocol (0x01 = Keyboard)
|
||||||
|
0, // iInterface
|
||||||
|
// HID descriptor, HID 1.11 spec, section 6.2.1
|
||||||
|
9, // bLength
|
||||||
|
0x21, // bDescriptorType
|
||||||
|
0x11, 0x01, // bcdHID
|
||||||
|
0, // bCountryCode
|
||||||
|
1, // bNumDescriptors
|
||||||
|
0x22, // bDescriptorType
|
||||||
|
sizeof(keyboard2_hid_report_desc), // wDescriptorLength
|
||||||
|
0,
|
||||||
|
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
|
||||||
|
7, // bLength
|
||||||
|
5, // bDescriptorType
|
||||||
|
KBD2_ENDPOINT | 0x80, // bEndpointAddress
|
||||||
|
0x03, // bmAttributes (0x03=intr)
|
||||||
|
KBD2_SIZE, 0, // wMaxPacketSize
|
||||||
|
1, // bInterval
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
// If you're desperate for a little extra code memory, these strings
|
// If you're desperate for a little extra code memory, these strings
|
||||||
@ -355,17 +511,17 @@ struct usb_string_descriptor_struct {
|
|||||||
uint8_t bDescriptorType;
|
uint8_t bDescriptorType;
|
||||||
int16_t wString[];
|
int16_t wString[];
|
||||||
};
|
};
|
||||||
static struct usb_string_descriptor_struct PROGMEM string0 = {
|
const static struct usb_string_descriptor_struct PROGMEM string0 = {
|
||||||
4,
|
4,
|
||||||
3,
|
3,
|
||||||
{0x0409}
|
{0x0409}
|
||||||
};
|
};
|
||||||
static struct usb_string_descriptor_struct PROGMEM string1 = {
|
const static struct usb_string_descriptor_struct PROGMEM string1 = {
|
||||||
sizeof(STR_MANUFACTURER),
|
sizeof(STR_MANUFACTURER),
|
||||||
3,
|
3,
|
||||||
STR_MANUFACTURER
|
STR_MANUFACTURER
|
||||||
};
|
};
|
||||||
static struct usb_string_descriptor_struct PROGMEM string2 = {
|
const static struct usb_string_descriptor_struct PROGMEM string2 = {
|
||||||
sizeof(STR_PRODUCT),
|
sizeof(STR_PRODUCT),
|
||||||
3,
|
3,
|
||||||
STR_PRODUCT
|
STR_PRODUCT
|
||||||
@ -378,21 +534,29 @@ static struct descriptor_list_struct {
|
|||||||
uint16_t wIndex;
|
uint16_t wIndex;
|
||||||
const uint8_t *addr;
|
const uint8_t *addr;
|
||||||
uint8_t length;
|
uint8_t length;
|
||||||
} PROGMEM descriptor_list[] = {
|
} const PROGMEM descriptor_list[] = {
|
||||||
// DEVICE descriptor
|
// DEVICE descriptor
|
||||||
{0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
|
{0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
|
||||||
// CONFIGURATION descriptor
|
// CONFIGURATION descriptor
|
||||||
{0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
|
{0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
|
||||||
// HID REPORT
|
// HID/REPORT descriptors
|
||||||
{0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)},
|
{0x2100, KBD_INTERFACE, config1_descriptor+KBD_HID_DESC_OFFSET, 9},
|
||||||
{0x2100, KEYBOARD_INTERFACE, config1_descriptor+KEYBOARD_HID_DESC_OFFSET, 9},
|
{0x2200, KBD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)},
|
||||||
// HID REPORT
|
#ifdef USB_MOUSE_ENABLE
|
||||||
{0x2200, MOUSE_INTERFACE, mouse_hid_report_desc, sizeof(mouse_hid_report_desc)},
|
|
||||||
{0x2100, MOUSE_INTERFACE, config1_descriptor+MOUSE_HID_DESC_OFFSET, 9},
|
{0x2100, MOUSE_INTERFACE, config1_descriptor+MOUSE_HID_DESC_OFFSET, 9},
|
||||||
// HID REPORT
|
{0x2200, MOUSE_INTERFACE, mouse_hid_report_desc, sizeof(mouse_hid_report_desc)},
|
||||||
{0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)},
|
#endif
|
||||||
{0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9},
|
{0x2100, DEBUG_INTERFACE, config1_descriptor+DEBUG_HID_DESC_OFFSET, 9},
|
||||||
// STRING descriptor
|
{0x2200, DEBUG_INTERFACE, debug_hid_report_desc, sizeof(debug_hid_report_desc)},
|
||||||
|
#ifdef USB_EXTRA_ENABLE
|
||||||
|
{0x2100, EXTRA_INTERFACE, config1_descriptor+EXTRA_HID_DESC_OFFSET, 9},
|
||||||
|
{0x2200, EXTRA_INTERFACE, extra_hid_report_desc, sizeof(extra_hid_report_desc)},
|
||||||
|
#endif
|
||||||
|
#ifdef USB_NKRO_ENABLE
|
||||||
|
{0x2100, KBD2_INTERFACE, config1_descriptor+KBD2_HID_DESC_OFFSET, 9},
|
||||||
|
{0x2200, KBD2_INTERFACE, keyboard2_hid_report_desc, sizeof(keyboard2_hid_report_desc)},
|
||||||
|
#endif
|
||||||
|
// STRING descriptors
|
||||||
{0x0300, 0x0000, (const uint8_t *)&string0, 4},
|
{0x0300, 0x0000, (const uint8_t *)&string0, 4},
|
||||||
{0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_MANUFACTURER)},
|
{0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_MANUFACTURER)},
|
||||||
{0x0302, 0x0409, (const uint8_t *)&string2, sizeof(STR_PRODUCT)}
|
{0x0302, 0x0409, (const uint8_t *)&string2, sizeof(STR_PRODUCT)}
|
||||||
@ -427,7 +591,7 @@ void usb_init(void)
|
|||||||
USB_CONFIG(); // start USB clock
|
USB_CONFIG(); // start USB clock
|
||||||
UDCON = 0; // enable attach resistor
|
UDCON = 0; // enable attach resistor
|
||||||
usb_configuration = 0;
|
usb_configuration = 0;
|
||||||
UDIEN = (1<<EORSTE)|(1<<SOFE);
|
UDIEN = (1<<EORSTE)|(1<<SOFE)|(1<<SUSPE);
|
||||||
sei();
|
sei();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,7 +599,12 @@ void usb_init(void)
|
|||||||
// number selected by the HOST
|
// number selected by the HOST
|
||||||
uint8_t usb_configured(void)
|
uint8_t usb_configured(void)
|
||||||
{
|
{
|
||||||
return usb_configuration;
|
return usb_configuration && !suspend;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_remote_wakeup(void)
|
||||||
|
{
|
||||||
|
UDCON |= (1<<RMWKUP);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -458,6 +627,11 @@ ISR(USB_GEN_vect)
|
|||||||
|
|
||||||
intbits = UDINT;
|
intbits = UDINT;
|
||||||
UDINT = 0;
|
UDINT = 0;
|
||||||
|
if (intbits & (1<<SUSPI)) {
|
||||||
|
suspend = true;
|
||||||
|
} else {
|
||||||
|
suspend = false;
|
||||||
|
}
|
||||||
if (intbits & (1<<EORSTI)) {
|
if (intbits & (1<<EORSTI)) {
|
||||||
UENUM = 0;
|
UENUM = 0;
|
||||||
UECONX = 1;
|
UECONX = 1;
|
||||||
@ -478,16 +652,22 @@ ISR(USB_GEN_vect)
|
|||||||
UEINTX = 0x3A;
|
UEINTX = 0x3A;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (keyboard_idle_config && (++div4 & 3) == 0) {
|
/* TODO: should keep IDLE rate on each keyboard interface */
|
||||||
UENUM = KEYBOARD_ENDPOINT;
|
#ifdef USB_NKRO_ENABLE
|
||||||
|
if (!keyboard_nkro && usb_keyboard_idle_config && (++div4 & 3) == 0) {
|
||||||
|
#else
|
||||||
|
if (usb_keyboard_idle_config && (++div4 & 3) == 0) {
|
||||||
|
#endif
|
||||||
|
UENUM = KBD_ENDPOINT;
|
||||||
if (UEINTX & (1<<RWAL)) {
|
if (UEINTX & (1<<RWAL)) {
|
||||||
keyboard_idle_count++;
|
usb_keyboard_idle_count++;
|
||||||
if (keyboard_idle_count == keyboard_idle_config) {
|
if (usb_keyboard_idle_count == usb_keyboard_idle_config) {
|
||||||
keyboard_idle_count = 0;
|
usb_keyboard_idle_count = 0;
|
||||||
UEDATX = keyboard_modifier_keys;
|
UEDATX = keyboard_report_prev->mods;
|
||||||
UEDATX = 0;
|
UEDATX = 0;
|
||||||
for (i=0; i<6; i++) {
|
uint8_t keys = usb_keyboard_protocol ? KBD_REPORT_KEYS : 6;
|
||||||
UEDATX = keyboard_keys[i];
|
for (i=0; i<keys; i++) {
|
||||||
|
UEDATX = keyboard_report_prev->keys[i];
|
||||||
}
|
}
|
||||||
UEINTX = 0x3A;
|
UEINTX = 0x3A;
|
||||||
}
|
}
|
||||||
@ -604,10 +784,12 @@ ISR(USB_COM_vect)
|
|||||||
for (i=1; i<=6; i++) {
|
for (i=1; i<=6; i++) {
|
||||||
UENUM = i;
|
UENUM = i;
|
||||||
en = pgm_read_byte(cfg++);
|
en = pgm_read_byte(cfg++);
|
||||||
UECONX = en;
|
if (en) {
|
||||||
if (en) {
|
UECONX = (1<<EPEN);
|
||||||
UECFG0X = pgm_read_byte(cfg++);
|
UECFG0X = pgm_read_byte(cfg++);
|
||||||
UECFG1X = pgm_read_byte(cfg++);
|
UECFG1X = pgm_read_byte(cfg++);
|
||||||
|
} else {
|
||||||
|
UECONX = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UERST = 0x7E;
|
UERST = 0x7E;
|
||||||
@ -636,9 +818,9 @@ ISR(USB_COM_vect)
|
|||||||
usb_send_in();
|
usb_send_in();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#ifdef SUPPORT_ENDPOINT_HALT
|
if (bRequest == CLEAR_FEATURE || bRequest == SET_FEATURE) {
|
||||||
if ((bRequest == CLEAR_FEATURE || bRequest == SET_FEATURE)
|
#ifdef SUPPORT_ENDPOINT_HALT
|
||||||
&& bmRequestType == 0x02 && wValue == 0) {
|
if (bmRequestType == 0x02 && wValue == ENDPOINT_HALT) {
|
||||||
i = wIndex & 0x7F;
|
i = wIndex & 0x7F;
|
||||||
if (i >= 1 && i <= MAX_ENDPOINT) {
|
if (i >= 1 && i <= MAX_ENDPOINT) {
|
||||||
usb_send_in();
|
usb_send_in();
|
||||||
@ -652,29 +834,39 @@ ISR(USB_COM_vect)
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (bmRequestType == 0x00 && wValue == DEVICE_REMOTE_WAKEUP) {
|
||||||
|
if (bRequest == SET_FEATURE) {
|
||||||
|
remote_wakeup = true;
|
||||||
|
} else {
|
||||||
|
remote_wakeup = false;
|
||||||
|
}
|
||||||
|
usb_send_in();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
if (wIndex == KBD_INTERFACE) {
|
||||||
if (wIndex == KEYBOARD_INTERFACE) {
|
|
||||||
if (bmRequestType == 0xA1) {
|
if (bmRequestType == 0xA1) {
|
||||||
if (bRequest == HID_GET_REPORT) {
|
if (bRequest == HID_GET_REPORT) {
|
||||||
usb_wait_in_ready();
|
usb_wait_in_ready();
|
||||||
UEDATX = keyboard_modifier_keys;
|
UEDATX = keyboard_report->mods;
|
||||||
UEDATX = 0;
|
UEDATX = 0;
|
||||||
for (i=0; i<6; i++) {
|
for (i=0; i<6; i++) {
|
||||||
UEDATX = keyboard_keys[i];
|
UEDATX = keyboard_report->keys[i];
|
||||||
}
|
}
|
||||||
usb_send_in();
|
usb_send_in();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (bRequest == HID_GET_IDLE) {
|
if (bRequest == HID_GET_IDLE) {
|
||||||
usb_wait_in_ready();
|
usb_wait_in_ready();
|
||||||
UEDATX = keyboard_idle_config;
|
UEDATX = usb_keyboard_idle_config;
|
||||||
usb_send_in();
|
usb_send_in();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (bRequest == HID_GET_PROTOCOL) {
|
if (bRequest == HID_GET_PROTOCOL) {
|
||||||
usb_wait_in_ready();
|
usb_wait_in_ready();
|
||||||
UEDATX = keyboard_protocol;
|
UEDATX = usb_keyboard_protocol;
|
||||||
usb_send_in();
|
usb_send_in();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -682,32 +874,33 @@ ISR(USB_COM_vect)
|
|||||||
if (bmRequestType == 0x21) {
|
if (bmRequestType == 0x21) {
|
||||||
if (bRequest == HID_SET_REPORT) {
|
if (bRequest == HID_SET_REPORT) {
|
||||||
usb_wait_receive_out();
|
usb_wait_receive_out();
|
||||||
keyboard_leds = UEDATX;
|
usb_keyboard_leds = UEDATX;
|
||||||
usb_ack_out();
|
usb_ack_out();
|
||||||
usb_send_in();
|
usb_send_in();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (bRequest == HID_SET_IDLE) {
|
if (bRequest == HID_SET_IDLE) {
|
||||||
keyboard_idle_config = (wValue >> 8);
|
usb_keyboard_idle_config = (wValue >> 8);
|
||||||
keyboard_idle_count = 0;
|
usb_keyboard_idle_count = 0;
|
||||||
//usb_wait_in_ready();
|
//usb_wait_in_ready();
|
||||||
usb_send_in();
|
usb_send_in();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (bRequest == HID_SET_PROTOCOL) {
|
if (bRequest == HID_SET_PROTOCOL) {
|
||||||
keyboard_protocol = wValue;
|
usb_keyboard_protocol = wValue;
|
||||||
//usb_wait_in_ready();
|
//usb_wait_in_ready();
|
||||||
usb_send_in();
|
usb_send_in();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef USB_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) {
|
||||||
if (wValue == HID_REPORT_INPUT) {
|
if (wValue == HID_REPORT_INPUT) {
|
||||||
usb_wait_in_ready();
|
usb_wait_in_ready();
|
||||||
UEDATX = mouse_buttons;
|
UEDATX = 0;
|
||||||
UEDATX = 0;
|
UEDATX = 0;
|
||||||
UEDATX = 0;
|
UEDATX = 0;
|
||||||
UEDATX = 0;
|
UEDATX = 0;
|
||||||
@ -723,19 +916,20 @@ ISR(USB_COM_vect)
|
|||||||
}
|
}
|
||||||
if (bRequest == HID_GET_PROTOCOL) {
|
if (bRequest == HID_GET_PROTOCOL) {
|
||||||
usb_wait_in_ready();
|
usb_wait_in_ready();
|
||||||
UEDATX = mouse_protocol;
|
UEDATX = usb_mouse_protocol;
|
||||||
usb_send_in();
|
usb_send_in();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (bmRequestType == 0x21) {
|
if (bmRequestType == 0x21) {
|
||||||
if (bRequest == HID_SET_PROTOCOL) {
|
if (bRequest == HID_SET_PROTOCOL) {
|
||||||
mouse_protocol = wValue;
|
usb_mouse_protocol = wValue;
|
||||||
usb_send_in();
|
usb_send_in();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
if (wIndex == DEBUG_INTERFACE) {
|
if (wIndex == DEBUG_INTERFACE) {
|
||||||
if (bRequest == HID_GET_REPORT && bmRequestType == 0xA1) {
|
if (bRequest == HID_GET_REPORT && bmRequestType == 0xA1) {
|
||||||
len = wLength;
|
len = wLength;
|
@ -2,13 +2,16 @@
|
|||||||
#define USB_H 1
|
#define USB_H 1
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
|
|
||||||
|
|
||||||
|
extern bool remote_wakeup;
|
||||||
|
extern bool suspend;
|
||||||
|
|
||||||
void usb_init(void); // initialize everything
|
void usb_init(void); // initialize everything
|
||||||
uint8_t usb_configured(void); // is the USB port configured
|
uint8_t usb_configured(void); // is the USB port configured
|
||||||
|
void usb_remote_wakeup(void);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define EP_TYPE_CONTROL 0x00
|
#define EP_TYPE_CONTROL 0x00
|
||||||
@ -78,5 +81,28 @@ uint8_t usb_configured(void); // is the USB port configured
|
|||||||
#define CDC_SET_LINE_CODING 0x20
|
#define CDC_SET_LINE_CODING 0x20
|
||||||
#define CDC_GET_LINE_CODING 0x21
|
#define CDC_GET_LINE_CODING 0x21
|
||||||
#define CDC_SET_CONTROL_LINE_STATE 0x22
|
#define CDC_SET_CONTROL_LINE_STATE 0x22
|
||||||
|
// HID feature selectors
|
||||||
|
#define DEVICE_REMOTE_WAKEUP 1
|
||||||
|
#define ENDPOINT_HALT 0
|
||||||
|
#define TEST_MODE 2
|
||||||
|
|
||||||
|
|
||||||
|
/*------------------------------------------------------------------*
|
||||||
|
* Keyboard descriptor setting
|
||||||
|
*------------------------------------------------------------------*/
|
||||||
|
#define KBD_INTERFACE 0
|
||||||
|
#define KBD_ENDPOINT 1
|
||||||
|
#define KBD_SIZE 8
|
||||||
|
#define KBD_BUFFER EP_DOUBLE_BUFFER
|
||||||
|
#define KBD_REPORT_KEYS (KBD_SIZE - 2)
|
||||||
|
|
||||||
|
// secondary keyboard
|
||||||
|
#ifdef USB_NKRO_ENABLE
|
||||||
|
#define KBD2_INTERFACE 4
|
||||||
|
#define KBD2_ENDPOINT 5
|
||||||
|
#define KBD2_SIZE 16
|
||||||
|
#define KBD2_BUFFER EP_DOUBLE_BUFFER
|
||||||
|
#define KBD2_REPORT_KEYS (KBD2_SIZE - 1)
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,4 +1,5 @@
|
|||||||
#include <avr/interrupt.h>
|
#include <avr/interrupt.h>
|
||||||
|
#include "sendchar.h"
|
||||||
#include "usb_debug.h"
|
#include "usb_debug.h"
|
||||||
|
|
||||||
|
|
||||||
@ -7,8 +8,7 @@
|
|||||||
volatile uint8_t debug_flush_timer=0;
|
volatile uint8_t debug_flush_timer=0;
|
||||||
|
|
||||||
|
|
||||||
// transmit a character. 0 returned on success, -1 on error
|
int8_t sendchar(uint8_t c)
|
||||||
int8_t usb_debug_putchar(uint8_t c)
|
|
||||||
{
|
{
|
||||||
static uint8_t previous_timeout=0;
|
static uint8_t previous_timeout=0;
|
||||||
uint8_t timeout, intr_state;
|
uint8_t timeout, intr_state;
|
||||||
@ -60,7 +60,6 @@ int8_t usb_debug_putchar(uint8_t c)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// immediately transmit any buffered output.
|
// immediately transmit any buffered output.
|
||||||
void usb_debug_flush_output(void)
|
void usb_debug_flush_output(void)
|
||||||
{
|
{
|
@ -14,7 +14,6 @@
|
|||||||
extern volatile uint8_t debug_flush_timer;
|
extern volatile uint8_t debug_flush_timer;
|
||||||
|
|
||||||
|
|
||||||
int8_t usb_debug_putchar(uint8_t c); // transmit a character
|
|
||||||
void usb_debug_flush_output(void); // immediately transmit any buffered output
|
void usb_debug_flush_output(void); // immediately transmit any buffered output
|
||||||
|
|
||||||
#endif
|
#endif
|
47
pjrc/usb_extra.c
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#include <util/delay.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include "host.h"
|
||||||
|
#include "usb_extra.h"
|
||||||
|
|
||||||
|
|
||||||
|
int8_t usb_extra_send(uint8_t report_id, uint16_t data)
|
||||||
|
{
|
||||||
|
uint8_t intr_state, timeout;
|
||||||
|
|
||||||
|
if (!usb_configured()) return -1;
|
||||||
|
intr_state = SREG;
|
||||||
|
cli();
|
||||||
|
UENUM = EXTRA_ENDPOINT;
|
||||||
|
timeout = UDFNUML + 50;
|
||||||
|
while (1) {
|
||||||
|
// are we ready to transmit?
|
||||||
|
if (UEINTX & (1<<RWAL)) break;
|
||||||
|
SREG = intr_state;
|
||||||
|
// has the USB gone offline?
|
||||||
|
if (!usb_configured()) return -1;
|
||||||
|
// have we waited too long?
|
||||||
|
if (UDFNUML == timeout) return -1;
|
||||||
|
// get ready to try checking again
|
||||||
|
intr_state = SREG;
|
||||||
|
cli();
|
||||||
|
UENUM = EXTRA_ENDPOINT;
|
||||||
|
}
|
||||||
|
|
||||||
|
UEDATX = report_id;
|
||||||
|
UEDATX = data&0xFF;
|
||||||
|
UEDATX = (data>>8)&0xFF;
|
||||||
|
|
||||||
|
UEINTX = 0x3A;
|
||||||
|
SREG = intr_state;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t usb_extra_consumer_send(uint16_t bits)
|
||||||
|
{
|
||||||
|
return usb_extra_send(REPORT_ID_CONSUMER, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
int8_t usb_extra_system_send(uint16_t bits)
|
||||||
|
{
|
||||||
|
return usb_extra_send(REPORT_ID_SYSTEM, bits);
|
||||||
|
}
|
23
pjrc/usb_extra.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef USB_EXTRA_H
|
||||||
|
#define USB_EXTRA_H 1
|
||||||
|
/*
|
||||||
|
* Enhanced keyboard features for Windows:
|
||||||
|
* Audio control and System control
|
||||||
|
*
|
||||||
|
* http://www.microsoft.com/whdc/archive/w2kbd.mspx
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "usb.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define EXTRA_INTERFACE 3
|
||||||
|
#define EXTRA_ENDPOINT 4
|
||||||
|
#define EXTRA_SIZE 8
|
||||||
|
#define EXTRA_BUFFER EP_DOUBLE_BUFFER
|
||||||
|
|
||||||
|
|
||||||
|
int8_t usb_extra_consumer_send(uint16_t bits);
|
||||||
|
int8_t usb_extra_system_send(uint16_t bits);
|
||||||
|
|
||||||
|
#endif
|
97
pjrc/usb_keyboard.c
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <avr/pgmspace.h>
|
||||||
|
#include "usb_keycodes.h"
|
||||||
|
#include "usb_keyboard.h"
|
||||||
|
#include "print.h"
|
||||||
|
#include "debug.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "host.h"
|
||||||
|
|
||||||
|
|
||||||
|
// protocol setting from the host. We use exactly the same report
|
||||||
|
// either way, so this variable only stores the setting since we
|
||||||
|
// are required to be able to report which setting is in use.
|
||||||
|
uint8_t usb_keyboard_protocol=1;
|
||||||
|
|
||||||
|
// the idle configuration, how often we send the report to the
|
||||||
|
// host (ms * 4) even when it hasn't changed
|
||||||
|
// Windows and Linux set 0 while OS X sets 6(24ms) by SET_IDLE request.
|
||||||
|
uint8_t usb_keyboard_idle_config=125;
|
||||||
|
|
||||||
|
// count until idle timeout
|
||||||
|
uint8_t usb_keyboard_idle_count=0;
|
||||||
|
|
||||||
|
// 1=num lock, 2=caps lock, 4=scroll lock, 8=compose, 16=kana
|
||||||
|
volatile uint8_t usb_keyboard_leds=0;
|
||||||
|
|
||||||
|
|
||||||
|
static inline int8_t send_report(report_keyboard_t *report, uint8_t endpoint, uint8_t keys_start, uint8_t keys_end);
|
||||||
|
|
||||||
|
|
||||||
|
int8_t usb_keyboard_send_report(report_keyboard_t *report)
|
||||||
|
{
|
||||||
|
int8_t result = 0;
|
||||||
|
|
||||||
|
#ifdef USB_NKRO_ENABLE
|
||||||
|
if (keyboard_nkro)
|
||||||
|
result = send_report(report, KBD2_ENDPOINT, 0, KBD2_REPORT_KEYS);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (usb_keyboard_protocol)
|
||||||
|
result = send_report(report, KBD_ENDPOINT, 0, KBD_REPORT_KEYS);
|
||||||
|
else
|
||||||
|
result = send_report(report, KBD_ENDPOINT, 0, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result) return result;
|
||||||
|
usb_keyboard_idle_count = 0;
|
||||||
|
usb_keyboard_print_report(report);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_keyboard_print_report(report_keyboard_t *report)
|
||||||
|
{
|
||||||
|
if (!debug_keyboard) return;
|
||||||
|
print("keys: ");
|
||||||
|
for (int i = 0; i < REPORT_KEYS; i++) { phex(report->keys[i]); print(" "); }
|
||||||
|
print(" mods: "); phex(report->mods); print("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline int8_t send_report(report_keyboard_t *report, uint8_t endpoint, uint8_t keys_start, uint8_t keys_end)
|
||||||
|
{
|
||||||
|
uint8_t intr_state, timeout;
|
||||||
|
|
||||||
|
if (!usb_configured()) return -1;
|
||||||
|
intr_state = SREG;
|
||||||
|
cli();
|
||||||
|
UENUM = endpoint;
|
||||||
|
timeout = UDFNUML + 50;
|
||||||
|
while (1) {
|
||||||
|
// are we ready to transmit?
|
||||||
|
if (UEINTX & (1<<RWAL)) break;
|
||||||
|
SREG = intr_state;
|
||||||
|
// has the USB gone offline?
|
||||||
|
if (!usb_configured()) return -1;
|
||||||
|
// have we waited too long?
|
||||||
|
if (UDFNUML == timeout) return -1;
|
||||||
|
// get ready to try checking again
|
||||||
|
intr_state = SREG;
|
||||||
|
cli();
|
||||||
|
UENUM = endpoint;
|
||||||
|
}
|
||||||
|
UEDATX = report->mods;
|
||||||
|
#ifdef USB_NKRO_ENABLE
|
||||||
|
if (!keyboard_nkro)
|
||||||
|
UEDATX = 0;
|
||||||
|
#else
|
||||||
|
UEDATX = 0;
|
||||||
|
#endif
|
||||||
|
for (uint8_t i = keys_start; i < keys_end; i++) {
|
||||||
|
UEDATX = report->keys[i];
|
||||||
|
}
|
||||||
|
UEINTX = 0x3A;
|
||||||
|
SREG = intr_state;
|
||||||
|
return 0;
|
||||||
|
}
|
19
pjrc/usb_keyboard.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#ifndef USB_KEYBOARD_H
|
||||||
|
#define USB_KEYBOARD_H 1
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "usb.h"
|
||||||
|
#include "host.h"
|
||||||
|
|
||||||
|
|
||||||
|
extern uint8_t usb_keyboard_protocol;
|
||||||
|
extern uint8_t usb_keyboard_idle_config;
|
||||||
|
extern uint8_t usb_keyboard_idle_count;
|
||||||
|
extern volatile uint8_t usb_keyboard_leds;
|
||||||
|
|
||||||
|
|
||||||
|
int8_t usb_keyboard_send_report(report_keyboard_t *report);
|
||||||
|
void usb_keyboard_print_report(report_keyboard_t *report);
|
||||||
|
|
||||||
|
#endif
|
58
pjrc/usb_mouse.c
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include "usb_mouse.h"
|
||||||
|
#include "print.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t usb_mouse_protocol=1;
|
||||||
|
|
||||||
|
|
||||||
|
int8_t usb_mouse_send(int8_t x, int8_t y, int8_t wheel_v, int8_t wheel_h, uint8_t buttons)
|
||||||
|
{
|
||||||
|
uint8_t intr_state, timeout;
|
||||||
|
|
||||||
|
if (!usb_configured()) return -1;
|
||||||
|
if (x == -128) x = -127;
|
||||||
|
if (y == -128) y = -127;
|
||||||
|
if (wheel_v == -128) wheel_v = -127;
|
||||||
|
if (wheel_h == -128) wheel_h = -127;
|
||||||
|
intr_state = SREG;
|
||||||
|
cli();
|
||||||
|
UENUM = MOUSE_ENDPOINT;
|
||||||
|
timeout = UDFNUML + 50;
|
||||||
|
while (1) {
|
||||||
|
// are we ready to transmit?
|
||||||
|
if (UEINTX & (1<<RWAL)) break;
|
||||||
|
SREG = intr_state;
|
||||||
|
// has the USB gone offline?
|
||||||
|
if (!usb_configured()) return -1;
|
||||||
|
// have we waited too long?
|
||||||
|
if (UDFNUML == timeout) return -1;
|
||||||
|
// get ready to try checking again
|
||||||
|
intr_state = SREG;
|
||||||
|
cli();
|
||||||
|
UENUM = MOUSE_ENDPOINT;
|
||||||
|
}
|
||||||
|
UEDATX = buttons;
|
||||||
|
UEDATX = x;
|
||||||
|
UEDATX = y;
|
||||||
|
if (usb_mouse_protocol) {
|
||||||
|
UEDATX = wheel_v;
|
||||||
|
UEDATX = wheel_h;
|
||||||
|
}
|
||||||
|
|
||||||
|
UEINTX = 0x3A;
|
||||||
|
SREG = intr_state;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void usb_mouse_print(int8_t x, int8_t y, int8_t wheel_v, int8_t wheel_h, uint8_t buttons) {
|
||||||
|
if (!debug_mouse) return;
|
||||||
|
print("usb_mouse[btn|x y v h]: ");
|
||||||
|
phex(buttons); print("|");
|
||||||
|
phex(x); print(" ");
|
||||||
|
phex(y); print(" ");
|
||||||
|
phex(wheel_v); print(" ");
|
||||||
|
phex(wheel_h); print("\n");
|
||||||
|
}
|
27
pjrc/usb_mouse.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef USB_MOUSE_H
|
||||||
|
#define USB_MOUSE_H 1
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "usb.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define MOUSE_INTERFACE 1
|
||||||
|
#define MOUSE_ENDPOINT 2
|
||||||
|
#define MOUSE_SIZE 8
|
||||||
|
#define MOUSE_BUFFER EP_DOUBLE_BUFFER
|
||||||
|
|
||||||
|
#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)
|
||||||
|
|
||||||
|
|
||||||
|
extern uint8_t usb_mouse_protocol;
|
||||||
|
|
||||||
|
|
||||||
|
int8_t usb_mouse_send(int8_t x, int8_t y, int8_t wheel_v, int8_t wheel_h, uint8_t buttons);
|
||||||
|
void usb_mouse_print(int8_t x, int8_t y, int8_t wheel_v, int8_t wheel_h, uint8_t buttons);
|
||||||
|
|
||||||
|
#endif
|
30
print.c
@ -1,17 +1,17 @@
|
|||||||
/* Very basic print functions, intended to be used with usb_debug_only.c
|
/* Very basic print functions, intended to be used with usb_debug_only.c
|
||||||
* http://www.pjrc.com/teensy/
|
* http://www.pjrc.com/teensy/
|
||||||
* Copyright (c) 2008 PJRC.COM, LLC
|
* Copyright (c) 2008 PJRC.COM, LLC
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
* of this software and associated documentation files (the "Software"), to deal
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
* in the Software without restriction, including without limitation the rights
|
* in the Software without restriction, including without limitation the rights
|
||||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
* copies of the Software, and to permit persons to whom the Software is
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
* furnished to do so, subject to the following conditions:
|
* furnished to do so, subject to the following conditions:
|
||||||
*
|
*
|
||||||
* The above copyright notice and this permission notice shall be included in
|
* The above copyright notice and this permission notice shall be included in
|
||||||
* all copies or substantial portions of the Software.
|
* all copies or substantial portions of the Software.
|
||||||
*
|
*
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
@ -21,11 +21,11 @@
|
|||||||
* THE SOFTWARE.
|
* THE SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Version 1.0: Initial Release
|
//#include <stdio.h>
|
||||||
|
|
||||||
#include <avr/io.h>
|
#include <avr/io.h>
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
|
#include "sendchar.h"
|
||||||
|
|
||||||
|
|
||||||
bool print_enable = false;
|
bool print_enable = false;
|
||||||
@ -38,15 +38,25 @@ void print_P(const char *s)
|
|||||||
while (1) {
|
while (1) {
|
||||||
c = pgm_read_byte(s++);
|
c = pgm_read_byte(s++);
|
||||||
if (!c) break;
|
if (!c) break;
|
||||||
if (c == '\n') usb_debug_putchar('\r');
|
if (c == '\n') sendchar('\r');
|
||||||
usb_debug_putchar(c);
|
sendchar(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void pdec(const int x)
|
||||||
|
{
|
||||||
|
if (!print_enable) return;
|
||||||
|
char ascii[32];
|
||||||
|
sprintf(ascii,"%i",x);
|
||||||
|
for (int i = 0; i < 32 && ascii[i] != 0; ++i) {
|
||||||
|
sendchar(ascii[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void phex1(unsigned char c)
|
void phex1(unsigned char c)
|
||||||
{
|
{
|
||||||
if (!print_enable) return;
|
if (!print_enable) return;
|
||||||
usb_debug_putchar(c + ((c < 10) ? '0' : 'A' - 10));
|
sendchar(c + ((c < 10) ? '0' : 'A' - 10));
|
||||||
}
|
}
|
||||||
|
|
||||||
void phex(unsigned char c)
|
void phex(unsigned char c)
|
||||||
@ -68,7 +78,7 @@ void pbin(unsigned char c)
|
|||||||
{
|
{
|
||||||
if (!print_enable) return;
|
if (!print_enable) return;
|
||||||
for (int i = 7; i >= 0; i--) {
|
for (int i = 7; i >= 0; i--) {
|
||||||
usb_debug_putchar((c & (1<<i)) ? '1' : '0');
|
sendchar((c & (1<<i)) ? '1' : '0');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,6 +86,6 @@ void pbin_reverse(unsigned char c)
|
|||||||
{
|
{
|
||||||
if (!print_enable) return;
|
if (!print_enable) return;
|
||||||
for (int i = 0; i < 8; i++) {
|
for (int i = 0; i < 8; i++) {
|
||||||
usb_debug_putchar((c & (1<<i)) ? '1' : '0');
|
sendchar((c & (1<<i)) ? '1' : '0');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
5
print.h
@ -3,17 +3,16 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <avr/pgmspace.h>
|
#include <avr/pgmspace.h>
|
||||||
#include "usb_debug.h"
|
|
||||||
|
|
||||||
|
|
||||||
bool print_enable;
|
extern bool print_enable;
|
||||||
|
|
||||||
// this macro allows you to write print("some text") and
|
// this macro allows you to write print("some text") and
|
||||||
// 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))
|
||||||
#define pchar(c) usb_debug_putchar(c)
|
|
||||||
|
|
||||||
void print_P(const char *s);
|
void print_P(const char *s);
|
||||||
|
void pdec(const int x);
|
||||||
void phex(unsigned char c);
|
void phex(unsigned char c);
|
||||||
void phex16(unsigned int i);
|
void phex16(unsigned int i);
|
||||||
void pbin(unsigned char c);
|
void pbin(unsigned char c);
|
||||||
|
433
ps2.c
Normal file
@ -0,0 +1,433 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2010,2011 Jun WAKO <wakojun@gmail.com>
|
||||||
|
|
||||||
|
This software is licensed with a Modified BSD License.
|
||||||
|
All of this is supposed to be Free Software, Open Source, DFSG-free,
|
||||||
|
GPL-compatible, and OK to use in both free and proprietary applications.
|
||||||
|
Additions and corrections to this file are welcome.
|
||||||
|
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
* Neither the name of the copyright holders nor the names of
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include "ps2.h"
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t recv_data(void);
|
||||||
|
static inline void clock_lo(void);
|
||||||
|
static inline void clock_hi(void);
|
||||||
|
static inline bool clock_in(void);
|
||||||
|
static inline void data_lo(void);
|
||||||
|
static inline void data_hi(void);
|
||||||
|
static inline bool data_in(void);
|
||||||
|
static inline uint16_t wait_clock_lo(uint16_t us);
|
||||||
|
static inline uint16_t wait_clock_hi(uint16_t us);
|
||||||
|
static inline uint16_t wait_data_lo(uint16_t us);
|
||||||
|
static inline uint16_t wait_data_hi(uint16_t us);
|
||||||
|
static inline void idle(void);
|
||||||
|
static inline void inhibit(void);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Primitive PS/2 Library for AVR
|
||||||
|
==============================
|
||||||
|
Host side is only supported now.
|
||||||
|
|
||||||
|
|
||||||
|
I/O control
|
||||||
|
-----------
|
||||||
|
High state is asserted by input with pull up.
|
||||||
|
|
||||||
|
|
||||||
|
PS/2 References
|
||||||
|
---------------
|
||||||
|
http://www.computer-engineering.org/ps2protocol/
|
||||||
|
http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#define WAIT(stat, us, err) do { \
|
||||||
|
if (!wait_##stat(us)) { \
|
||||||
|
ps2_error = err; \
|
||||||
|
goto ERROR; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t ps2_error = PS2_ERR_NONE;
|
||||||
|
|
||||||
|
|
||||||
|
void ps2_host_init(void)
|
||||||
|
{
|
||||||
|
#ifdef PS2_INT_ENABLE
|
||||||
|
PS2_INT_ENABLE();
|
||||||
|
idle();
|
||||||
|
#else
|
||||||
|
inhibit();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: send using interrupt if available
|
||||||
|
uint8_t ps2_host_send(uint8_t data)
|
||||||
|
{
|
||||||
|
uint8_t res = 0;
|
||||||
|
bool parity = true;
|
||||||
|
ps2_error = PS2_ERR_NONE;
|
||||||
|
#ifdef PS2_INT_DISABLE
|
||||||
|
PS2_INT_DISABLE();
|
||||||
|
#endif
|
||||||
|
/* terminate a transmission if we have */
|
||||||
|
inhibit();
|
||||||
|
_delay_us(100);
|
||||||
|
|
||||||
|
/* start bit [1] */
|
||||||
|
data_lo();
|
||||||
|
clock_hi();
|
||||||
|
WAIT(clock_lo, 15000, 1);
|
||||||
|
/* data [2-9] */
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
_delay_us(15);
|
||||||
|
if (data&(1<<i)) {
|
||||||
|
parity = !parity;
|
||||||
|
data_hi();
|
||||||
|
} else {
|
||||||
|
data_lo();
|
||||||
|
}
|
||||||
|
WAIT(clock_hi, 50, 2);
|
||||||
|
WAIT(clock_lo, 50, 3);
|
||||||
|
}
|
||||||
|
/* parity [10] */
|
||||||
|
_delay_us(15);
|
||||||
|
if (parity) { data_hi(); } else { data_lo(); }
|
||||||
|
WAIT(clock_hi, 50, 4);
|
||||||
|
WAIT(clock_lo, 50, 5);
|
||||||
|
/* stop bit [11] */
|
||||||
|
_delay_us(15);
|
||||||
|
data_hi();
|
||||||
|
/* ack [12] */
|
||||||
|
WAIT(data_lo, 50, 6);
|
||||||
|
WAIT(clock_lo, 50, 7);
|
||||||
|
|
||||||
|
/* wait for idle state */
|
||||||
|
WAIT(clock_hi, 50, 8);
|
||||||
|
WAIT(data_hi, 50, 9);
|
||||||
|
|
||||||
|
res = ps2_host_recv_response();
|
||||||
|
ERROR:
|
||||||
|
#ifdef PS2_INT_ENABLE
|
||||||
|
PS2_INT_ENABLE();
|
||||||
|
idle();
|
||||||
|
#else
|
||||||
|
inhibit();
|
||||||
|
#endif
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* receive data when host want else inhibit communication */
|
||||||
|
uint8_t ps2_host_recv_response(void)
|
||||||
|
{
|
||||||
|
uint8_t data = 0;
|
||||||
|
|
||||||
|
/* terminate a transmission if we have */
|
||||||
|
inhibit();
|
||||||
|
_delay_us(100);
|
||||||
|
|
||||||
|
/* release lines(idle state) */
|
||||||
|
idle();
|
||||||
|
|
||||||
|
/* wait start bit */
|
||||||
|
wait_clock_lo(2000);
|
||||||
|
data = recv_data();
|
||||||
|
|
||||||
|
inhibit();
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef PS2_INT_VECT
|
||||||
|
uint8_t ps2_host_recv(void)
|
||||||
|
{
|
||||||
|
return ps2_host_recv_response();
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
/* ring buffer to store ps/2 key data */
|
||||||
|
#define PBUF_SIZE 8
|
||||||
|
static uint8_t pbuf[PBUF_SIZE];
|
||||||
|
static uint8_t pbuf_head = 0;
|
||||||
|
static uint8_t pbuf_tail = 0;
|
||||||
|
static inline void pbuf_enqueue(uint8_t data)
|
||||||
|
{
|
||||||
|
if (!data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint8_t sreg = SREG;
|
||||||
|
cli();
|
||||||
|
uint8_t next = (pbuf_head + 1) % PBUF_SIZE;
|
||||||
|
if (next != pbuf_tail) {
|
||||||
|
pbuf[pbuf_head] = data;
|
||||||
|
pbuf_head = next;
|
||||||
|
} else {
|
||||||
|
debug("pbuf: full\n");
|
||||||
|
}
|
||||||
|
SREG = sreg;
|
||||||
|
}
|
||||||
|
static inline uint8_t pbuf_dequeue(void)
|
||||||
|
{
|
||||||
|
uint8_t val = 0;
|
||||||
|
|
||||||
|
uint8_t sreg = SREG;
|
||||||
|
cli();
|
||||||
|
if (pbuf_head != pbuf_tail) {
|
||||||
|
val = pbuf[pbuf_tail];
|
||||||
|
pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE;
|
||||||
|
}
|
||||||
|
SREG = sreg;
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get data received by interrupt */
|
||||||
|
uint8_t ps2_host_recv(void)
|
||||||
|
{
|
||||||
|
if (ps2_error) {
|
||||||
|
print("x");
|
||||||
|
phex(ps2_error);
|
||||||
|
ps2_host_send(0xFE); // request to resend
|
||||||
|
ps2_error = PS2_ERR_NONE;
|
||||||
|
}
|
||||||
|
idle();
|
||||||
|
return pbuf_dequeue();
|
||||||
|
}
|
||||||
|
|
||||||
|
#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
|
||||||
|
ISR(PS2_INT_VECT)
|
||||||
|
{
|
||||||
|
static enum {
|
||||||
|
INIT,
|
||||||
|
START,
|
||||||
|
BIT0, BIT1, BIT2, BIT3, BIT4, BIT5, BIT6, BIT7,
|
||||||
|
PARITY,
|
||||||
|
STOP,
|
||||||
|
} state = INIT;
|
||||||
|
static uint8_t data = 0;
|
||||||
|
static uint8_t parity = 1;
|
||||||
|
|
||||||
|
// TODO: abort if elapse 100us from previous interrupt
|
||||||
|
|
||||||
|
// return unless falling edge
|
||||||
|
if (clock_in()) {
|
||||||
|
goto RETURN;
|
||||||
|
}
|
||||||
|
|
||||||
|
state++;
|
||||||
|
DEBUGP(state);
|
||||||
|
switch (state) {
|
||||||
|
case START:
|
||||||
|
if (data_in())
|
||||||
|
goto ERROR;
|
||||||
|
break;
|
||||||
|
case BIT0:
|
||||||
|
case BIT1:
|
||||||
|
case BIT2:
|
||||||
|
case BIT3:
|
||||||
|
case BIT4:
|
||||||
|
case BIT5:
|
||||||
|
case BIT6:
|
||||||
|
case BIT7:
|
||||||
|
data >>= 1;
|
||||||
|
if (data_in()) {
|
||||||
|
data |= 0x80;
|
||||||
|
parity++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PARITY:
|
||||||
|
if (data_in()) {
|
||||||
|
if (!(parity & 0x01))
|
||||||
|
goto ERROR;
|
||||||
|
} else {
|
||||||
|
if (parity & 0x01)
|
||||||
|
goto ERROR;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case STOP:
|
||||||
|
if (!data_in())
|
||||||
|
goto ERROR;
|
||||||
|
pbuf_enqueue(data);
|
||||||
|
goto DONE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto ERROR;
|
||||||
|
}
|
||||||
|
goto RETURN;
|
||||||
|
ERROR:
|
||||||
|
DEBUGP(0x0F);
|
||||||
|
inhibit();
|
||||||
|
ps2_error = state;
|
||||||
|
DONE:
|
||||||
|
state = INIT;
|
||||||
|
data = 0;
|
||||||
|
parity = 1;
|
||||||
|
RETURN:
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static void ps2_reset(void)
|
||||||
|
{
|
||||||
|
ps2_host_send(0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send LED state to keyboard */
|
||||||
|
void ps2_host_set_led(uint8_t led)
|
||||||
|
{
|
||||||
|
ps2_host_send(0xED);
|
||||||
|
ps2_host_send(led);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* called after start bit comes */
|
||||||
|
static uint8_t recv_data(void)
|
||||||
|
{
|
||||||
|
uint8_t data = 0;
|
||||||
|
bool parity = true;
|
||||||
|
ps2_error = PS2_ERR_NONE;
|
||||||
|
|
||||||
|
/* start bit [1] */
|
||||||
|
WAIT(clock_lo, 1, 1);
|
||||||
|
WAIT(data_lo, 1, 2);
|
||||||
|
WAIT(clock_hi, 50, 3);
|
||||||
|
|
||||||
|
/* data [2-9] */
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
WAIT(clock_lo, 50, 4);
|
||||||
|
if (data_in()) {
|
||||||
|
parity = !parity;
|
||||||
|
data |= (1<<i);
|
||||||
|
}
|
||||||
|
WAIT(clock_hi, 50, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* parity [10] */
|
||||||
|
WAIT(clock_lo, 50, 6);
|
||||||
|
if (data_in() != parity) {
|
||||||
|
ps2_error = PS2_ERR_PARITY;
|
||||||
|
goto ERROR;
|
||||||
|
}
|
||||||
|
WAIT(clock_hi, 50, 7);
|
||||||
|
|
||||||
|
/* stop bit [11] */
|
||||||
|
WAIT(clock_lo, 50, 8);
|
||||||
|
WAIT(data_hi, 1, 9);
|
||||||
|
WAIT(clock_hi, 50, 10);
|
||||||
|
|
||||||
|
return data;
|
||||||
|
ERROR:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void clock_lo()
|
||||||
|
{
|
||||||
|
PS2_CLOCK_PORT &= ~(1<<PS2_CLOCK_BIT);
|
||||||
|
PS2_CLOCK_DDR |= (1<<PS2_CLOCK_BIT);
|
||||||
|
}
|
||||||
|
static inline void clock_hi()
|
||||||
|
{
|
||||||
|
/* input with pull up */
|
||||||
|
PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
|
||||||
|
PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
|
||||||
|
}
|
||||||
|
static inline bool clock_in()
|
||||||
|
{
|
||||||
|
PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
|
||||||
|
PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
|
||||||
|
_delay_us(1);
|
||||||
|
return PS2_CLOCK_PIN&(1<<PS2_CLOCK_BIT);
|
||||||
|
}
|
||||||
|
static inline void data_lo()
|
||||||
|
{
|
||||||
|
PS2_DATA_PORT &= ~(1<<PS2_DATA_BIT);
|
||||||
|
PS2_DATA_DDR |= (1<<PS2_DATA_BIT);
|
||||||
|
}
|
||||||
|
static inline void data_hi()
|
||||||
|
{
|
||||||
|
/* input with pull up */
|
||||||
|
PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
|
||||||
|
PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
|
||||||
|
}
|
||||||
|
static inline bool data_in()
|
||||||
|
{
|
||||||
|
PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
|
||||||
|
PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
|
||||||
|
_delay_us(1);
|
||||||
|
return PS2_DATA_PIN&(1<<PS2_DATA_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint16_t wait_clock_lo(uint16_t us)
|
||||||
|
{
|
||||||
|
while (clock_in() && us) { asm(""); _delay_us(1); us--; }
|
||||||
|
return us;
|
||||||
|
}
|
||||||
|
static inline uint16_t wait_clock_hi(uint16_t us)
|
||||||
|
{
|
||||||
|
while (!clock_in() && us) { asm(""); _delay_us(1); us--; }
|
||||||
|
return us;
|
||||||
|
}
|
||||||
|
static inline uint16_t wait_data_lo(uint16_t us)
|
||||||
|
{
|
||||||
|
while (data_in() && us) { asm(""); _delay_us(1); us--; }
|
||||||
|
return us;
|
||||||
|
}
|
||||||
|
static inline uint16_t wait_data_hi(uint16_t us)
|
||||||
|
{
|
||||||
|
while (!data_in() && us) { asm(""); _delay_us(1); us--; }
|
||||||
|
return us;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* idle state that device can send */
|
||||||
|
static inline void idle(void)
|
||||||
|
{
|
||||||
|
clock_hi();
|
||||||
|
data_hi();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inhibit device to send */
|
||||||
|
static inline void inhibit(void)
|
||||||
|
{
|
||||||
|
clock_lo();
|
||||||
|
data_hi();
|
||||||
|
}
|
82
ps2.h
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2010,2011 Jun WAKO <wakojun@gmail.com>
|
||||||
|
|
||||||
|
This software is licensed with a Modified BSD License.
|
||||||
|
All of this is supposed to be Free Software, Open Source, DFSG-free,
|
||||||
|
GPL-compatible, and OK to use in both free and proprietary applications.
|
||||||
|
Additions and corrections to this file are welcome.
|
||||||
|
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
* Neither the name of the copyright holders nor the names of
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef PS2_H
|
||||||
|
#define PS2_H
|
||||||
|
/*
|
||||||
|
* Primitive PS/2 Library for AVR
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/* port settings for clock and data line */
|
||||||
|
#if !(defined(PS2_CLOCK_PORT) && \
|
||||||
|
defined(PS2_CLOCK_PIN) && \
|
||||||
|
defined(PS2_CLOCK_DDR) && \
|
||||||
|
defined(PS2_CLOCK_BIT))
|
||||||
|
# error "PS/2 clock port setting is required in config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !(defined(PS2_DATA_PORT) && \
|
||||||
|
defined(PS2_DATA_PIN) && \
|
||||||
|
defined(PS2_DATA_DDR) && \
|
||||||
|
defined(PS2_DATA_BIT))
|
||||||
|
# error "PS/2 data port setting is required in config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define PS2_ACK 0xFA
|
||||||
|
#define PS2_RESEND 0xFE
|
||||||
|
#define PS2_SET_LED 0xED
|
||||||
|
|
||||||
|
#define PS2_ERR_NONE 0
|
||||||
|
#define PS2_ERR_PARITY 0x10
|
||||||
|
|
||||||
|
#define PS2_LED_SCROLL_LOCK 0
|
||||||
|
#define PS2_LED_NUM_LOCK 1
|
||||||
|
#define PS2_LED_CAPS_LOCK 2
|
||||||
|
|
||||||
|
|
||||||
|
extern uint8_t ps2_error;
|
||||||
|
|
||||||
|
/* host role */
|
||||||
|
void ps2_host_init(void);
|
||||||
|
uint8_t ps2_host_send(uint8_t data);
|
||||||
|
uint8_t ps2_host_recv_response(void);
|
||||||
|
uint8_t ps2_host_recv(void);
|
||||||
|
void ps2_host_set_led(uint8_t usb_led);
|
||||||
|
|
||||||
|
/* device role */
|
||||||
|
|
||||||
|
#endif
|
201
ps2_mouse.c
Normal file
@ -0,0 +1,201 @@
|
|||||||
|
#include <stdbool.h>
|
||||||
|
#include<avr/io.h>
|
||||||
|
#include<util/delay.h>
|
||||||
|
#include "ps2.h"
|
||||||
|
#include "ps2_mouse.h"
|
||||||
|
#include "usb_mouse.h"
|
||||||
|
|
||||||
|
#define PS2_MOUSE_DEBUG
|
||||||
|
#ifdef PS2_MOUSE_DEBUG
|
||||||
|
# include "print.h"
|
||||||
|
# include "debug.h"
|
||||||
|
#else
|
||||||
|
# define print(s)
|
||||||
|
# define phex(h)
|
||||||
|
# define phex16(h)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// disable when errors occur 255 times.
|
||||||
|
#define ERROR_RETURN() do { \
|
||||||
|
if (ps2_error) { \
|
||||||
|
if (ps2_mouse_error_count < 255) { \
|
||||||
|
ps2_mouse_error_count++; \
|
||||||
|
} else { \
|
||||||
|
ps2_mouse_error_count = 0; \
|
||||||
|
ps2_mouse_enable = false; \
|
||||||
|
} \
|
||||||
|
return ps2_error; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO
|
||||||
|
----
|
||||||
|
- Stream mode
|
||||||
|
- Tracpoint command support: needed
|
||||||
|
- Middle button + move = Wheel traslation
|
||||||
|
*/
|
||||||
|
bool ps2_mouse_enable = true;
|
||||||
|
uint8_t ps2_mouse_x = 0;
|
||||||
|
uint8_t ps2_mouse_y = 0;
|
||||||
|
uint8_t ps2_mouse_btn = 0;
|
||||||
|
uint8_t ps2_mouse_error_count = 0;
|
||||||
|
|
||||||
|
static uint8_t ps2_mouse_btn_prev = 0;
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t ps2_mouse_init(void) {
|
||||||
|
uint8_t rcv;
|
||||||
|
|
||||||
|
if (!ps2_mouse_enable) return 1;
|
||||||
|
|
||||||
|
ps2_host_init();
|
||||||
|
|
||||||
|
// Reset
|
||||||
|
rcv = ps2_host_send(0xFF);
|
||||||
|
print("ps2_mouse_init: send 0xFF: ");
|
||||||
|
phex(ps2_error); print("\n");
|
||||||
|
ERROR_RETURN();
|
||||||
|
|
||||||
|
// ACK
|
||||||
|
rcv = ps2_host_recv();
|
||||||
|
print("ps2_mouse_init: read ACK: ");
|
||||||
|
phex(rcv); phex(ps2_error); print("\n");
|
||||||
|
ERROR_RETURN();
|
||||||
|
|
||||||
|
// BAT takes some time
|
||||||
|
_delay_ms(100);
|
||||||
|
rcv = ps2_host_recv();
|
||||||
|
print("ps2_mouse_init: read BAT: ");
|
||||||
|
phex(rcv); phex(ps2_error); print("\n");
|
||||||
|
ERROR_RETURN();
|
||||||
|
|
||||||
|
// Device ID
|
||||||
|
rcv = ps2_host_recv();
|
||||||
|
print("ps2_mouse_init: read DevID: ");
|
||||||
|
phex(rcv); phex(ps2_error); print("\n");
|
||||||
|
ERROR_RETURN();
|
||||||
|
|
||||||
|
// Enable data reporting
|
||||||
|
ps2_host_send(0xF4);
|
||||||
|
print("ps2_mouse_init: send 0xF4: ");
|
||||||
|
phex(ps2_error); print("\n");
|
||||||
|
ERROR_RETURN();
|
||||||
|
|
||||||
|
// ACK
|
||||||
|
rcv = ps2_host_recv();
|
||||||
|
print("ps2_mouse_init: read ACK: ");
|
||||||
|
phex(rcv); phex(ps2_error); print("\n");
|
||||||
|
ERROR_RETURN();
|
||||||
|
|
||||||
|
// Set Remote mode
|
||||||
|
ps2_host_send(0xF0);
|
||||||
|
print("ps2_mouse_init: send 0xF0: ");
|
||||||
|
phex(ps2_error); print("\n");
|
||||||
|
ERROR_RETURN();
|
||||||
|
|
||||||
|
// ACK
|
||||||
|
rcv = ps2_host_recv();
|
||||||
|
print("ps2_mouse_init: read ACK: ");
|
||||||
|
phex(rcv); phex(ps2_error); print("\n");
|
||||||
|
ERROR_RETURN();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Data format:
|
||||||
|
bit: 7 6 5 4 3 2 1 0
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
0 btn: Yovflw Xovflw Ysign Xsign 1 Middle Right Left
|
||||||
|
1 x: X movement(0-255)
|
||||||
|
2 y: Y movement(0-255)
|
||||||
|
*/
|
||||||
|
uint8_t ps2_mouse_read(void)
|
||||||
|
{
|
||||||
|
uint8_t rcv;
|
||||||
|
|
||||||
|
if (!ps2_mouse_enable) return 1;
|
||||||
|
|
||||||
|
ps2_host_send(0xEB);
|
||||||
|
ERROR_RETURN();
|
||||||
|
|
||||||
|
rcv=ps2_host_recv();
|
||||||
|
ERROR_RETURN();
|
||||||
|
|
||||||
|
if(rcv==0xFA) {
|
||||||
|
ps2_mouse_btn = ps2_host_recv();
|
||||||
|
ERROR_RETURN();
|
||||||
|
ps2_mouse_x = ps2_host_recv();
|
||||||
|
ERROR_RETURN();
|
||||||
|
ps2_mouse_y = ps2_host_recv();
|
||||||
|
ERROR_RETURN();
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ps2_mouse_changed(void)
|
||||||
|
{
|
||||||
|
return (ps2_mouse_x || ps2_mouse_y || (ps2_mouse_btn & PS2_MOUSE_BTN_MASK) != ps2_mouse_btn_prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define PS2_MOUSE_SCROLL_BUTTON 0x04
|
||||||
|
void ps2_mouse_usb_send(void)
|
||||||
|
{
|
||||||
|
static bool scrolled = false;
|
||||||
|
|
||||||
|
if (!ps2_mouse_enable) return;
|
||||||
|
|
||||||
|
if (ps2_mouse_changed()) {
|
||||||
|
int8_t x, y, v, h;
|
||||||
|
x = y = v = h = 0;
|
||||||
|
|
||||||
|
// convert scale of X, Y: PS/2(-256/255) -> USB(-127/127)
|
||||||
|
if (ps2_mouse_btn & (1<<PS2_MOUSE_X_SIGN))
|
||||||
|
x = ps2_mouse_x > 128 ? (int8_t)ps2_mouse_x : -127;
|
||||||
|
else
|
||||||
|
x = ps2_mouse_x < 128 ? (int8_t)ps2_mouse_x : 127;
|
||||||
|
|
||||||
|
if (ps2_mouse_btn & (1<<PS2_MOUSE_Y_SIGN))
|
||||||
|
y = ps2_mouse_y > 128 ? (int8_t)ps2_mouse_y : -127;
|
||||||
|
else
|
||||||
|
y = ps2_mouse_y < 128 ? (int8_t)ps2_mouse_y : 127;
|
||||||
|
|
||||||
|
// Y is needed to reverse
|
||||||
|
y = -y;
|
||||||
|
|
||||||
|
if (ps2_mouse_btn & PS2_MOUSE_SCROLL_BUTTON) {
|
||||||
|
// scroll
|
||||||
|
if (x > 0 || x < 0) h = (x > 64 ? 64 : (x < -64 ? -64 :x));
|
||||||
|
if (y > 0 || y < 0) v = (y > 64 ? 64 : (y < -64 ? -64 :y));
|
||||||
|
if (h || v) {
|
||||||
|
scrolled = true;
|
||||||
|
usb_mouse_send(0,0, -v/16, h/16, 0);
|
||||||
|
_delay_ms(100);
|
||||||
|
}
|
||||||
|
} else if (!scrolled && (ps2_mouse_btn_prev & PS2_MOUSE_SCROLL_BUTTON)) {
|
||||||
|
usb_mouse_send(0,0,0,0, PS2_MOUSE_SCROLL_BUTTON);
|
||||||
|
_delay_ms(100);
|
||||||
|
usb_mouse_send(0,0,0,0, 0);
|
||||||
|
} else {
|
||||||
|
scrolled = false;
|
||||||
|
usb_mouse_send(x, y, 0, 0, ps2_mouse_btn & PS2_MOUSE_BTN_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
ps2_mouse_btn_prev = (ps2_mouse_btn & PS2_MOUSE_BTN_MASK);
|
||||||
|
ps2_mouse_print();
|
||||||
|
}
|
||||||
|
ps2_mouse_x = 0;
|
||||||
|
ps2_mouse_y = 0;
|
||||||
|
ps2_mouse_btn = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ps2_mouse_print(void)
|
||||||
|
{
|
||||||
|
if (!debug_mouse) return;
|
||||||
|
print("ps2_mouse[btn|x y]: ");
|
||||||
|
phex(ps2_mouse_btn); print("|");
|
||||||
|
phex(ps2_mouse_x); print(" ");
|
||||||
|
phex(ps2_mouse_y); print("\n");
|
||||||
|
}
|
27
ps2_mouse.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef PS2_MOUSE_H
|
||||||
|
#define PS2_MOUSE_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define PS2_MOUSE_BTN_MASK 0x07
|
||||||
|
#define PS2_MOUSE_BTN_LEFT 0
|
||||||
|
#define PS2_MOUSE_BTN_RIGHT 1
|
||||||
|
#define PS2_MOUSE_BTN_MIDDLE 2
|
||||||
|
#define PS2_MOUSE_X_SIGN 4
|
||||||
|
#define PS2_MOUSE_Y_SIGN 5
|
||||||
|
#define PS2_MOUSE_X_OVFLW 6
|
||||||
|
#define PS2_MOUSE_Y_OVFLW 7
|
||||||
|
|
||||||
|
bool ps2_mouse_enable;
|
||||||
|
extern uint8_t ps2_mouse_x;
|
||||||
|
extern uint8_t ps2_mouse_y;
|
||||||
|
extern uint8_t ps2_mouse_btn;
|
||||||
|
extern uint8_t ps2_mouse_error_count;
|
||||||
|
|
||||||
|
uint8_t ps2_mouse_init(void);
|
||||||
|
uint8_t ps2_mouse_read(void);
|
||||||
|
bool ps2_mouse_changed(void);
|
||||||
|
void ps2_mouse_usb_send(void);
|
||||||
|
void ps2_mouse_print(void);
|
||||||
|
|
||||||
|
#endif
|
325
ps2_usart.c
Normal file
@ -0,0 +1,325 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2010,2011 Jun WAKO <wakojun@gmail.com>
|
||||||
|
|
||||||
|
This software is licensed with a Modified BSD License.
|
||||||
|
All of this is supposed to be Free Software, Open Source, DFSG-free,
|
||||||
|
GPL-compatible, and OK to use in both free and proprietary applications.
|
||||||
|
Additions and corrections to this file are welcome.
|
||||||
|
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
|
||||||
|
* Neither the name of the copyright holders nor the names of
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
Primitive PS/2 Library for AVR
|
||||||
|
==============================
|
||||||
|
Host side is only supported now.
|
||||||
|
Synchronous USART is used to receive data by hardware process
|
||||||
|
rather than interrupt. During V-USB interrupt runs, CLOCK interrupt
|
||||||
|
cannot interpose. In the result it is prone to lost CLOCK edge.
|
||||||
|
|
||||||
|
|
||||||
|
I/O control
|
||||||
|
-----------
|
||||||
|
High state is asserted by internal pull-up.
|
||||||
|
If you have a signaling problem, you may need to have
|
||||||
|
external pull-up resisters on CLOCK and DATA line.
|
||||||
|
|
||||||
|
|
||||||
|
PS/2 References
|
||||||
|
---------------
|
||||||
|
http://www.computer-engineering.org/ps2protocol/
|
||||||
|
http://www.mcamafia.de/pdf/ibm_hitrc07.pdf
|
||||||
|
*/
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <avr/io.h>
|
||||||
|
#include <avr/interrupt.h>
|
||||||
|
#include <util/delay.h>
|
||||||
|
#include "ps2.h"
|
||||||
|
#include "debug.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
|
||||||
|
|
||||||
|
#define WAIT(stat, us, err) do { \
|
||||||
|
if (!wait_##stat(us)) { \
|
||||||
|
ps2_error = err; \
|
||||||
|
goto ERROR; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t ps2_error = PS2_ERR_NONE;
|
||||||
|
|
||||||
|
|
||||||
|
static inline void clock_lo(void);
|
||||||
|
static inline void clock_hi(void);
|
||||||
|
static inline bool clock_in(void);
|
||||||
|
static inline void data_lo(void);
|
||||||
|
static inline void data_hi(void);
|
||||||
|
static inline bool data_in(void);
|
||||||
|
static inline uint16_t wait_clock_lo(uint16_t us);
|
||||||
|
static inline uint16_t wait_clock_hi(uint16_t us);
|
||||||
|
static inline uint16_t wait_data_lo(uint16_t us);
|
||||||
|
static inline uint16_t wait_data_hi(uint16_t us);
|
||||||
|
static inline void idle(void);
|
||||||
|
static inline void inhibit(void);
|
||||||
|
#if defined PS2_USE_INT || defined PS2_USE_USART
|
||||||
|
static inline uint8_t pbuf_dequeue(void);
|
||||||
|
static inline void pbuf_enqueue(uint8_t data);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
void ps2_host_init(void)
|
||||||
|
{
|
||||||
|
DEBUGP_INIT();
|
||||||
|
DEBUGP(0x1);
|
||||||
|
idle();
|
||||||
|
PS2_USART_INIT();
|
||||||
|
PS2_USART_RX_INT_ON();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ps2_host_send(uint8_t data)
|
||||||
|
{
|
||||||
|
uint8_t res = 0;
|
||||||
|
bool parity = true;
|
||||||
|
ps2_error = PS2_ERR_NONE;
|
||||||
|
|
||||||
|
DEBUGP(0x6);
|
||||||
|
PS2_USART_OFF();
|
||||||
|
|
||||||
|
/* terminate a transmission if we have */
|
||||||
|
inhibit();
|
||||||
|
_delay_us(100);
|
||||||
|
|
||||||
|
/* start bit [1] */
|
||||||
|
data_lo();
|
||||||
|
clock_hi();
|
||||||
|
WAIT(clock_lo, 15000, 1);
|
||||||
|
/* data [2-9] */
|
||||||
|
for (uint8_t i = 0; i < 8; i++) {
|
||||||
|
_delay_us(15);
|
||||||
|
if (data&(1<<i)) {
|
||||||
|
parity = !parity;
|
||||||
|
data_hi();
|
||||||
|
} else {
|
||||||
|
data_lo();
|
||||||
|
}
|
||||||
|
WAIT(clock_hi, 50, 2);
|
||||||
|
WAIT(clock_lo, 50, 3);
|
||||||
|
}
|
||||||
|
/* parity [10] */
|
||||||
|
_delay_us(15);
|
||||||
|
if (parity) { data_hi(); } else { data_lo(); }
|
||||||
|
WAIT(clock_hi, 50, 4);
|
||||||
|
WAIT(clock_lo, 50, 5);
|
||||||
|
/* stop bit [11] */
|
||||||
|
_delay_us(15);
|
||||||
|
data_hi();
|
||||||
|
/* ack [12] */
|
||||||
|
WAIT(data_lo, 50, 6);
|
||||||
|
WAIT(clock_lo, 50, 7);
|
||||||
|
|
||||||
|
/* wait for idle state */
|
||||||
|
WAIT(clock_hi, 50, 8);
|
||||||
|
WAIT(data_hi, 50, 9);
|
||||||
|
|
||||||
|
res = ps2_host_recv_response();
|
||||||
|
ERROR:
|
||||||
|
idle();
|
||||||
|
PS2_USART_INIT();
|
||||||
|
PS2_USART_RX_INT_ON();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do polling data from keyboard to get response to last command.
|
||||||
|
uint8_t ps2_host_recv_response(void)
|
||||||
|
{
|
||||||
|
uint8_t data = 0;
|
||||||
|
PS2_USART_INIT();
|
||||||
|
PS2_USART_RX_POLL_ON();
|
||||||
|
while (!PS2_USART_RX_READY)
|
||||||
|
;
|
||||||
|
data = PS2_USART_RX_DATA;
|
||||||
|
PS2_USART_OFF();
|
||||||
|
DEBUGP(0x9);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ps2_host_recv(void)
|
||||||
|
{
|
||||||
|
return pbuf_dequeue();
|
||||||
|
}
|
||||||
|
|
||||||
|
ISR(PS2_USART_RX_VECT)
|
||||||
|
{
|
||||||
|
DEBUGP(0x7);
|
||||||
|
uint8_t error = PS2_USART_ERROR;
|
||||||
|
uint8_t data = PS2_USART_RX_DATA;
|
||||||
|
if (error) {
|
||||||
|
DEBUGP(error>>2);
|
||||||
|
} else {
|
||||||
|
pbuf_enqueue(data);
|
||||||
|
}
|
||||||
|
DEBUGP(0x8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* send LED state to keyboard */
|
||||||
|
void ps2_host_set_led(uint8_t led)
|
||||||
|
{
|
||||||
|
// send 0xED then keyboard keeps waiting for next LED data
|
||||||
|
// and keyboard does not send any scan codes during waiting.
|
||||||
|
// If fail to send LED data keyboard looks like being freezed.
|
||||||
|
uint8_t retry = 3;
|
||||||
|
while (retry-- && ps2_host_send(PS2_SET_LED) != PS2_ACK)
|
||||||
|
;
|
||||||
|
retry = 3;
|
||||||
|
while (retry-- && ps2_host_send(led) != PS2_ACK)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------
|
||||||
|
* static functions
|
||||||
|
*------------------------------------------------------------------*/
|
||||||
|
static inline void clock_lo()
|
||||||
|
{
|
||||||
|
PS2_CLOCK_PORT &= ~(1<<PS2_CLOCK_BIT);
|
||||||
|
PS2_CLOCK_DDR |= (1<<PS2_CLOCK_BIT);
|
||||||
|
}
|
||||||
|
static inline void clock_hi()
|
||||||
|
{
|
||||||
|
/* input with pull up */
|
||||||
|
PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
|
||||||
|
PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
|
||||||
|
}
|
||||||
|
static inline bool clock_in()
|
||||||
|
{
|
||||||
|
PS2_CLOCK_DDR &= ~(1<<PS2_CLOCK_BIT);
|
||||||
|
PS2_CLOCK_PORT |= (1<<PS2_CLOCK_BIT);
|
||||||
|
_delay_us(1);
|
||||||
|
return PS2_CLOCK_PIN&(1<<PS2_CLOCK_BIT);
|
||||||
|
}
|
||||||
|
static inline void data_lo()
|
||||||
|
{
|
||||||
|
PS2_DATA_PORT &= ~(1<<PS2_DATA_BIT);
|
||||||
|
PS2_DATA_DDR |= (1<<PS2_DATA_BIT);
|
||||||
|
}
|
||||||
|
static inline void data_hi()
|
||||||
|
{
|
||||||
|
/* input with pull up */
|
||||||
|
PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
|
||||||
|
PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
|
||||||
|
}
|
||||||
|
static inline bool data_in()
|
||||||
|
{
|
||||||
|
PS2_DATA_DDR &= ~(1<<PS2_DATA_BIT);
|
||||||
|
PS2_DATA_PORT |= (1<<PS2_DATA_BIT);
|
||||||
|
_delay_us(1);
|
||||||
|
return PS2_DATA_PIN&(1<<PS2_DATA_BIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint16_t wait_clock_lo(uint16_t us)
|
||||||
|
{
|
||||||
|
while (clock_in() && us) { asm(""); _delay_us(1); us--; }
|
||||||
|
return us;
|
||||||
|
}
|
||||||
|
static inline uint16_t wait_clock_hi(uint16_t us)
|
||||||
|
{
|
||||||
|
while (!clock_in() && us) { asm(""); _delay_us(1); us--; }
|
||||||
|
return us;
|
||||||
|
}
|
||||||
|
static inline uint16_t wait_data_lo(uint16_t us)
|
||||||
|
{
|
||||||
|
while (data_in() && us) { asm(""); _delay_us(1); us--; }
|
||||||
|
return us;
|
||||||
|
}
|
||||||
|
static inline uint16_t wait_data_hi(uint16_t us)
|
||||||
|
{
|
||||||
|
while (!data_in() && us) { asm(""); _delay_us(1); us--; }
|
||||||
|
return us;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* idle state that device can send */
|
||||||
|
static inline void idle(void)
|
||||||
|
{
|
||||||
|
clock_hi();
|
||||||
|
data_hi();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* inhibit device to send */
|
||||||
|
static inline void inhibit(void)
|
||||||
|
{
|
||||||
|
clock_lo();
|
||||||
|
data_hi();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------
|
||||||
|
* Ring buffer to store scan codes from keyboard
|
||||||
|
*------------------------------------------------------------------*/
|
||||||
|
#define PBUF_SIZE 8
|
||||||
|
static uint8_t pbuf[PBUF_SIZE];
|
||||||
|
static uint8_t pbuf_head = 0;
|
||||||
|
static uint8_t pbuf_tail = 0;
|
||||||
|
static inline void pbuf_enqueue(uint8_t data)
|
||||||
|
{
|
||||||
|
if (!data)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint8_t sreg = SREG;
|
||||||
|
cli();
|
||||||
|
uint8_t next = (pbuf_head + 1) % PBUF_SIZE;
|
||||||
|
if (next != pbuf_tail) {
|
||||||
|
pbuf[pbuf_head] = data;
|
||||||
|
pbuf_head = next;
|
||||||
|
} else {
|
||||||
|
debug("pbuf: full\n");
|
||||||
|
}
|
||||||
|
SREG = sreg;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline uint8_t pbuf_dequeue(void)
|
||||||
|
{
|
||||||
|
uint8_t val = 0;
|
||||||
|
|
||||||
|
uint8_t sreg = SREG;
|
||||||
|
cli();
|
||||||
|
if (pbuf_head != pbuf_tail) {
|
||||||
|
val = pbuf[pbuf_tail];
|
||||||
|
pbuf_tail = (pbuf_tail + 1) % PBUF_SIZE;
|
||||||
|
}
|
||||||
|
SREG = sreg;
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
56
ps2_usb/Makefile
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#
|
||||||
|
# Makefile for PJRC Teensy
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
# Target file name (without extension).
|
||||||
|
TARGET = ps2_usb_pjrc
|
||||||
|
|
||||||
|
# Directory common source filess exist
|
||||||
|
COMMON_DIR = ..
|
||||||
|
|
||||||
|
# Directory keyboard dependent files exist
|
||||||
|
TARGET_DIR = .
|
||||||
|
|
||||||
|
# keyboard dependent files
|
||||||
|
TARGET_SRC = main_pjrc.c \
|
||||||
|
keymap.c \
|
||||||
|
matrix.c \
|
||||||
|
led.c \
|
||||||
|
ps2.c
|
||||||
|
|
||||||
|
CONFIG_H = config_pjrc.h
|
||||||
|
|
||||||
|
|
||||||
|
# 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 = at90usb162 # Teensy 1.0
|
||||||
|
#MCU = atmega32u4 # Teensy 2.0
|
||||||
|
#MCU = at90usb646 # Teensy++ 1.0
|
||||||
|
MCU = at90usb1286 # Teensy++ 2.0
|
||||||
|
|
||||||
|
|
||||||
|
# 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 = 16000000
|
||||||
|
|
||||||
|
|
||||||
|
# Build Options
|
||||||
|
# comment out to disable the options.
|
||||||
|
#
|
||||||
|
MOUSEKEY_ENABLE = yes # Mouse keys
|
||||||
|
USB_EXTRA_ENABLE = yes # Audio control and System control
|
||||||
|
USB_NKRO_ENABLE = yes # USB Nkey Rollover
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- Programming Options --------------------------
|
||||||
|
PROGRAM_CMD = teensy_loader_cli -mmcu=$(MCU) -w -v $(TARGET).hex
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
include $(COMMON_DIR)/Makefile.pjrc
|
||||||
|
include $(COMMON_DIR)/Makefile.common
|
89
ps2_usb/Makefile.vusb
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
#
|
||||||
|
# Makefile for V-USB
|
||||||
|
#
|
||||||
|
|
||||||
|
|
||||||
|
# Target file name (without extension).
|
||||||
|
TARGET = ps2_usb_vusb
|
||||||
|
|
||||||
|
# Directory common source filess exist
|
||||||
|
COMMON_DIR = ..
|
||||||
|
|
||||||
|
# Directory keyboard dependent files exist
|
||||||
|
TARGET_DIR = .
|
||||||
|
|
||||||
|
# keyboard dependent files
|
||||||
|
TARGET_SRC = main_vusb.c \
|
||||||
|
keymap.c \
|
||||||
|
matrix.c \
|
||||||
|
led.c \
|
||||||
|
ps2_usart.c
|
||||||
|
|
||||||
|
CONFIG_H = config_vusb.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 = at90usb162 # Teensy 1.0
|
||||||
|
#MCU = atmega32u4 # Teensy 2.0
|
||||||
|
#MCU = at90usb646 # Teensy++ 1.0
|
||||||
|
#MCU = at90usb1286 # Teensy++ 2.0
|
||||||
|
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 = 20000000
|
||||||
|
|
||||||
|
|
||||||
|
# Build Options
|
||||||
|
# comment out to disable the options.
|
||||||
|
#
|
||||||
|
MOUSEKEY_ENABLE = yes # Mouse keys
|
||||||
|
USB_EXTRA_ENABLE = yes # Audio control and System control
|
||||||
|
#USB_NKRO_ENABLE = yes # USB Nkey Rollover
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#---------------- 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 $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER)
|
||||||
|
AVRDUDE_FLAGS = -p $(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)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
include $(COMMON_DIR)/Makefile.vusb
|
||||||
|
include $(COMMON_DIR)/Makefile.common
|
173
ps2_usb/README
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
PS/2 to USB Dvorak/Qwerty keyboard converter
|
||||||
|
==============================
|
||||||
|
|
||||||
|
This firmware converts PS/2 keyboard protocol to USB,
|
||||||
|
and is specially suited for users who use the Dvorak
|
||||||
|
keyboard layout, but want to easily switch between
|
||||||
|
layouts and keep Qwerty shortcuts (like Ctrl+c).
|
||||||
|
|
||||||
|
|
||||||
|
Demostration build
|
||||||
|
------------------
|
||||||
|
In this demo build, you can try several layouts,
|
||||||
|
mouse keys and USB NKRO.
|
||||||
|
|
||||||
|
Special keys:
|
||||||
|
Magic+0: Dvorak (default)
|
||||||
|
Magic+1: Qwerty
|
||||||
|
Magic+2: Dvorak with mouse keys
|
||||||
|
Magic+3: Qwerty with mouse keys
|
||||||
|
Magic+N: toggles NKRO/6KRO(6KRO by default)
|
||||||
|
Magic+Esc: sends Power Event
|
||||||
|
where Magic=(LShift+RShift)
|
||||||
|
|
||||||
|
LCtrl+LShift+RCtrl+RShift swaps between layout
|
||||||
|
0 (Dvorak) and 1 (Qwerty), the scroll lock LED,
|
||||||
|
and the LED on the Teensy indicates this change
|
||||||
|
by being on for Qwerty, and off for Dvorak.
|
||||||
|
|
||||||
|
Keybinds: (keys are specified in qwerty layout)
|
||||||
|
Fn0+(hjkl): Mouse key move(vi cursor)
|
||||||
|
Fn0+(yuio): Mouse wheel(left,down,up,right)
|
||||||
|
Fn0+space: Mouse button1
|
||||||
|
Fn0+(mnb): Mouse buttons(1,2,3)
|
||||||
|
Fn0+(zxc): Media control(Volup, Voldown, Mute)
|
||||||
|
Fn1+(hjkl): Cursor move(vi cursor)
|
||||||
|
Fn1+(nm,.): Cursor move(Home,PageDown,PageUp,End)
|
||||||
|
|
||||||
|
Fn2+(esdf): Mouse key move(invert T cursor)
|
||||||
|
Fn2+(qwrt): Mouse wheel(left,down,up,right)
|
||||||
|
Fn2+space: Mouse button1
|
||||||
|
Fn2+(,./): Media control(Volup, Voldown, Mute)
|
||||||
|
where Fn0=;, Fn1=/, Fn2=a
|
||||||
|
|
||||||
|
|
||||||
|
Features
|
||||||
|
--------
|
||||||
|
Mouse keys
|
||||||
|
You can emulates mouse move and button click using keyboard.
|
||||||
|
System/Media control
|
||||||
|
You can sends Power event, Volume down/up and Mute.
|
||||||
|
USB NKRO(actually 120KRO+8Modifiers)
|
||||||
|
You can tolggles NKRO/6KRO.(Not tested on Mac.)
|
||||||
|
Keymap customization
|
||||||
|
You can customize keymaps easily by editing source code.
|
||||||
|
|
||||||
|
|
||||||
|
Build for Teensy
|
||||||
|
----------------
|
||||||
|
0. Connect PS/2 keyboard to Teensy by 4 lines(Vcc, GND, Data, Clock).
|
||||||
|
1. Define following macros for PS/2 connection in config_pjrc.h:
|
||||||
|
PS2_DATA_PORT
|
||||||
|
PS2_DATA_PIN
|
||||||
|
PS2_DATA_DDR
|
||||||
|
PS2_DATA_BIT
|
||||||
|
PS2_CLOCK_PORT
|
||||||
|
PS2_CLOCK_PIN
|
||||||
|
PS2_CLOCK_DDR
|
||||||
|
PS2_CLOCK_BIT
|
||||||
|
2. Edit Makefile for build options and MCU setting.
|
||||||
|
2. make
|
||||||
|
3. program Teensy.
|
||||||
|
http://www.pjrc.com/teensy/loader.html
|
||||||
|
|
||||||
|
|
||||||
|
Build for V-USB
|
||||||
|
---------------
|
||||||
|
0. Build V-USB controller board and connect PS/2 keyboard.
|
||||||
|
1. Define macros in config_vusb.h if needed.
|
||||||
|
2. Edit Makefile.vusb for build options and MCU setting.
|
||||||
|
3. make -f Makefile.vusb
|
||||||
|
4. program your V-USB controller.
|
||||||
|
|
||||||
|
|
||||||
|
V-USB Circuit
|
||||||
|
-------------
|
||||||
|
+---+ +---------------+
|
||||||
|
USB GND | | ATmega168 |
|
||||||
|
=== C3 | |
|
||||||
|
5V <-------+--------+---|Vcc,AVCC | PS/2
|
||||||
|
R1 | | ====
|
||||||
|
D- <----+--+-----R2-----|INT1 RXD|------->DATA
|
||||||
|
D+ <----|---+----R3-----|INT0 XCK|------->CLOCK
|
||||||
|
Z1 Z2 | | ->5V
|
||||||
|
GND<----+---+--+--+-----|GND | ->GND
|
||||||
|
| | | |
|
||||||
|
| C2-+--|XTAL1 |
|
||||||
|
| X1 | |
|
||||||
|
+--C3-+--|XTAL2 |
|
||||||
|
+---------------+
|
||||||
|
R1: 1.5K Ohm
|
||||||
|
R2,R3: 68 Ohm
|
||||||
|
Z1,Z2: Zenner 3.6V
|
||||||
|
C1,C2: 22pF
|
||||||
|
C3: 0.1uF
|
||||||
|
X1: Crystal 20MHz(16MHz/12MHz)
|
||||||
|
|
||||||
|
|
||||||
|
Keymap
|
||||||
|
------
|
||||||
|
You can change a keymap by editing code of keymap.c like following.
|
||||||
|
How to define the keymap is probably obvious. You can find key
|
||||||
|
symbols in usb_keycodes.h.
|
||||||
|
If you want to define more than one keymap, see hhkb/keymap.c and
|
||||||
|
macway/keymap.c as examples. To define keymap(layer) switching may
|
||||||
|
needs a bit of your effort at this time.
|
||||||
|
|
||||||
|
/* Default Layer: plain keymap
|
||||||
|
* ,---. ,---------------. ,---------------. ,---------------. ,-----------. ,-----------.
|
||||||
|
* |Esc| |F1 |F2 |F3 |F4 | |F5 |F6 |F7 |F8 | |F9 |F10|F11|F12| |PrS|ScL|Pau| |Pwr|Slp|Wak|
|
||||||
|
* `---' `---------------' `---------------' `---------------' `-----------' `-----------'
|
||||||
|
* ,-----------------------------------------------------------. ,-----------. ,---------------.
|
||||||
|
* | `| 1| 2| 3| 4| 5| 6| 7| 8| 9| 0| -| =|Backspa| |Ins|Hom|PgU| |NmL| /| *| -|
|
||||||
|
* |-----------------------------------------------------------| |-----------| |---------------|
|
||||||
|
* |Tab | Q| W| E| R| T| Y| U| I| O| P| [| ]| \| |Del|End|PgD| | 7| 8| 9| |
|
||||||
|
* |-----------------------------------------------------------| `-----------' |-----------| +|
|
||||||
|
* |CapsLo| A| S| D| F| G| H| J| K| L| ;| '|Return | | 4| 5| 6| |
|
||||||
|
* |-----------------------------------------------------------| ,---. |---------------|
|
||||||
|
* |Shift | Z| X| C| V| B| N| M| ,| ,| /|Shift | |Up | | 1| 2| 3| |
|
||||||
|
* |-----------------------------------------------------------| ,-----------. |-----------|Ent|
|
||||||
|
* |Ctrl |Gui |Alt | Space |Alt |Gui |Menu|Ctrl| |Lef|Dow|Rig| | 0| .| |
|
||||||
|
* `-----------------------------------------------------------' `-----------' `---------------'
|
||||||
|
*/
|
||||||
|
KEYMAP(
|
||||||
|
ESC, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, PSCR,SLCK,BRK, PWR, F13, F14,
|
||||||
|
GRV, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, MINS,EQL, BSPC, INS, HOME,PGUP, NLCK,PSLS,PAST,PMNS,
|
||||||
|
TAB, Q, W, E, R, T, Y, U, I, O, P, LBRC,RBRC,BSLS, DEL, END, PGDN, P7, P8, P9,
|
||||||
|
CAPS,A, S, D, F, G, H, J, K, L, SCLN,QUOT, ENT, P4, P5, P6, PPLS,
|
||||||
|
LSFT,Z, X, C, V, B, N, M, COMM,DOT, SLSH, RSFT, UP, P1, P2, P3,
|
||||||
|
LCTL,LGUI,LALT, SPC, RALT,RGUI,APP, RCTL, LEFT,DOWN,RGHT, P0, PDOT,PENT
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
Multimedia keys
|
||||||
|
---------------
|
||||||
|
Following lists PS/2 special keys supported by Windows.
|
||||||
|
http://msdn.microsoft.com/en-us/windows/hardware/gg463372.aspx
|
||||||
|
|
||||||
|
Key PS/2(Set2) HID
|
||||||
|
---------------------------------------------------
|
||||||
|
System Power E0 37 01 0081
|
||||||
|
System Sleep E0 3F 01 0082
|
||||||
|
System Wake E0 5E 01 0083
|
||||||
|
System Mute E0 23 0C 00E2
|
||||||
|
Volume Up E0 32 0C 00E9
|
||||||
|
Volume Down E0 21 0C 00EA
|
||||||
|
Scan Next Track E0 4D 0C 00B5
|
||||||
|
Scan Previous Track E0 15 0C 00B6
|
||||||
|
Stop E0 3B 0C 00B7
|
||||||
|
Play/Pause E0 34 0C 00CD
|
||||||
|
Media Select E0 50 0C 0183
|
||||||
|
Mail E0 48 0C 018A
|
||||||
|
Calculator E0 2B 0C 0192
|
||||||
|
My Computer E0 40 0C 0194
|
||||||
|
WWW Search E0 10 0C 0221
|
||||||
|
WWW Home E0 3A 0C 0223
|
||||||
|
WWW Back E0 38 0C 0224
|
||||||
|
WWW Forward E0 30 0C 0225
|
||||||
|
WWW Stop E0 28 0C 0226
|
||||||
|
WWW Refresh E0 20 0C 0227
|
||||||
|
WWW Favorites E0 18 0C 022A
|
||||||
|
|
||||||
|
|
||||||
|
EOF
|