candidate for release with keyboard :)

Merge branch 'dev'

- changed the way layers are handled!
- reorganized a bunch
- updated some documentation and such
- updated USB IDs
- now compiling in OS X (though it *should* still work in linux and
  windows (except the toplevel build script is unix only) - it's a bug
  if it doens't)
- toplevel build script now generates a lot more, including a bunch of
  information in JSON meant for the UI, and an html file thats a
  currently-very-bad picture of the layout that was compiled
f13
Ben Blazak 2012-12-06 12:29:00 -08:00
commit 11c77a15f7
62 changed files with 6159 additions and 2208 deletions

351
build-scripts/gen-layout.py Executable file
View File

@ -0,0 +1,351 @@
#! /usr/bin/env python3
# -----------------------------------------------------------------------------
# Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
# Released under The MIT License (MIT) (see "license.md")
# Project located at <https://github.com/benblazak/ergodox-firmware>
# -----------------------------------------------------------------------------
"""
Generate a depiction of the layout (in html + svg)
Depends on:
- the UI info file (in JSON)
"""
# -----------------------------------------------------------------------------
import argparse
import json
import os
import re
import sys
# -----------------------------------------------------------------------------
class Namespace():
pass
template = Namespace()
doc = Namespace()
info = Namespace()
# -----------------------------------------------------------------------------
def main():
arg_parser = argparse.ArgumentParser(
description = "Generate a picture of the firmware's "
+ "keyboard layout" )
arg_parser.add_argument(
'--ui-info-file',
required = True )
args = arg_parser.parse_args(sys.argv[1:])
# constant file paths
args.template_svg_file = './build-scripts/gen_layout/template.svg'
args.template_js_file = './build-scripts/gen_layout/template.js'
# normalize paths
args.ui_info_file = os.path.abspath(args.ui_info_file)
args.template_svg_file = os.path.abspath(args.template_svg_file)
args.template_js_file = os.path.abspath(args.template_js_file)
# set vars
doc.main = '' # to store the html document we're generating
template.svg = open(args.template_svg_file).read()
template.js = open(args.template_js_file).read()
info.all = json.loads(open(args.ui_info_file).read())
info.matrix_positions = info.all['mappings']['matrix-positions']
info.matrix_layout = info.all['mappings']['matrix-layout']
# prefix
doc.prefix = ("""
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<html>
<head>
<script>
"""
+ template.js +
""" </script>
</head>
<body>
""")[1:-1]
# suffix
doc.suffix = ("""
</body>
</html>
""")[1:-1]
# substitute into template
for (layout, layer) in zip( info.matrix_layout,
range(len(info.matrix_layout))):
svg = template.svg
for (name, (code, press, release)) \
in zip(info.matrix_positions, layout):
replace = ''
if press == 'kbfun_jump_to_bootloader':
replace = '[btldr]'
elif re.search(r'layer', press):
replace = '[layer]'
else:
replace = keycode_to_string.get(code, '[n/a]')
svg = re.sub(
'>'+name+'<', '>'+replace+'<', svg )
svg = re.sub(
r"\('(" + name + r".*)'\)",
r"('\1', " + str(layer) + r")",
svg )
doc.main += svg
print(doc.prefix + doc.main + doc.suffix)
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
keycode_to_string = {
0x01: "Error", # ErrorRollOver
0x02: "POSTFail",
0x03: "Error", # ErrorUndefined
0x04: "a A",
0x05: "b B",
0x06: "c C",
0x07: "d D",
0x08: "e E",
0x09: "f F",
0x0A: "g G",
0x0B: "h H",
0x0C: "i I",
0x0D: "j J",
0x0E: "k K",
0x0F: "l L",
0x10: "m M",
0x11: "n N",
0x12: "o O",
0x13: "p P",
0x14: "q Q",
0x15: "r R",
0x16: "s S",
0x17: "t T",
0x18: "u U",
0x19: "v V",
0x1A: "w W",
0x1B: "x X",
0x1C: "y Y",
0x1D: "z Z",
0x1E: "1 !",
0x1F: "2 @",
0x20: "3 #",
0x21: "4 $",
0x22: "5 %",
0x23: "6 ^",
0x24: "7 &",
0x25: "8 *",
0x26: "9 (",
0x27: "0 )",
0x28: "Return",
0x29: "Esc",
0x2A: "Backspace",
0x2B: "Tab",
0x2C: "Space",
0x2D: "- _",
0x2E: "= +",
0x2F: "[ {",
0x30: "] }",
0x31: "\ |",
0x32: "# ~",
0x33: "; :",
0x34: "\' \"",
0x35: "` ~",
0x36: ", <",
0x37: ". >",
0x38: "/ ?",
0x39: "Caps",
0x3A: "F1",
0x3B: "F2",
0x3C: "F3",
0x3D: "F4",
0x3E: "F5",
0x3F: "F6",
0x40: "F7",
0x41: "F8",
0x42: "F9",
0x43: "F10",
0x44: "F11",
0x45: "F12",
0x46: "PrintScreen",
0x47: "ScrollLock",
0x48: "Pause",
0x49: "Ins", # Insert
0x4A: "Hm", # Home
0x4B: "Pg\u2191", # up arrow
0x4C: "Delete",
0x4D: "End",
0x4E: "Pg\u2193", # down arrow
0x4F: "\u2192", # right arrow
0x50: "\u2190", # left arrow
0x51: "\u2193", # down arrow
0x52: "\u2191", # up arrow
0x53: "Num",
0x54: "/",
0x55: "*",
0x56: "-",
0x57: "+",
0x58: "Enter",
0x59: "1 End",
0x5A: "2 \u2193", # down arrow
0x5B: "3 Pg\u2193", # down arrow
0x5C: "4 \u2190", # left arrow
0x5D: "5",
0x5E: "6 \u2192", # right arrow
0x5F: "7 Hm", # Home
0x60: "8 \u2191", # up arrow
0x61: "9 Pg\u2191", # up arrow
0x62: "0 Ins", # Insert
0x63: ". Del",
0x64: "\ |",
0x65: "App",
0x66: "Power",
0x67: "=",
0x68: "F13",
0x69: "F14",
0x6A: "F15",
0x6B: "F16",
0x6C: "F17",
0x6D: "F18",
0x6E: "F19",
0x6F: "F20",
0x70: "F21",
0x71: "F22",
0x72: "F23",
0x73: "F24",
0x74: "Exec",
0x75: "Help",
0x76: "Menu",
0x77: "Select",
0x78: "Stop",
0x79: "Again",
0x7A: "Undo",
0x7B: "Cut",
0x7C: "Copy",
0x7D: "Paste",
0x7E: "Find",
0x7F: "Mute",
0x80: "VolUp",
0x81: "VolDown",
0x82: "LockingCapsLock",
0x83: "LockingNumLock",
0x84: "LockingScrollLock",
0x85: ",",
0x86: "=",
0x87: "Int1",
0x88: "Int2",
0x89: "Int3",
0x8A: "Int4",
0x8B: "Int5",
0x8C: "Int6",
0x8D: "Int7",
0x8E: "Int8",
0x8F: "Int9",
0x90: "LANG1",
0x91: "LANG2",
0x92: "LANG3",
0x93: "LANG4",
0x94: "LANG5",
0x95: "LANG6",
0x96: "LANG7",
0x97: "LANG8",
0x98: "LANG9",
0x99: "AlternateErase",
0x9A: "SysReq_Attention",
0x9B: "Cancel",
0x9C: "Clear",
0x9D: "Prior",
0x9E: "Return",
0x9F: "Separator",
0xA0: "Out",
0xA1: "Oper",
0xA2: "Clear_Again",
0xA3: "CrSel_Props",
0xA4: "ExSel",
0xB0: "00",
0xB1: "000",
0xB2: "Thousands_Sep",
0xB3: "Decimal_Sep",
0xB4: "$",
0xB5: "Currency_Subunit",
0xB6: "(",
0xB7: ")",
0xB8: "{",
0xB9: "}",
0xBA: "Tab",
0xBB: "Backspace",
0xBC: "A",
0xBD: "B",
0xBE: "C",
0xBF: "D",
0xC0: "E",
0xC1: "F",
0xC2: "XOR",
0xC3: "^",
0xC4: "%",
0xC5: "<",
0xC6: ">",
0xC7: "&",
0xC8: "&&",
0xC9: "|",
0xCA: "||",
0xCB: ":",
0xCC: "#",
0xCD: "Space",
0xCE: "@",
0xCF: "!",
0xD0: "Mem_Store",
0xD1: "Mem_Recall",
0xD2: "Mem_Clear",
0xD3: "Mem_+",
0xD4: "Mem_-",
0xD5: "Mem_*",
0xD6: "Mem_/",
0xD7: "+-",
0xD8: "Clear",
0xD9: "ClearEntry",
0xDA: "Binary",
0xDB: "Octal",
0xDC: ".",
0xDD: "Hexadecimal",
0xE0: "L-Ctrl",
0xE1: "L-Shift",
0xE2: "L-Alt",
0xE3: "L-GUI",
0xE4: "R-Ctrl",
0xE5: "R-Shift",
0xE6: "R-Alt",
0xE7: "R-GUI",
}
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
if __name__ == '__main__':
main()

474
build-scripts/gen-ui-info.py Executable file
View File

@ -0,0 +1,474 @@
#! /usr/bin/env python3
# -----------------------------------------------------------------------------
# Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
# Released under The MIT License (MIT) (see "license.md")
# Project located at <https://github.com/benblazak/ergodox-firmware>
# -----------------------------------------------------------------------------
"""
Generate UI info file (in JSON)
Depends on:
- the project source code
- the project '.map' file (generated by the compiler)
"""
_FORMAT_DESCRIPTION = ("""
/* ----------------------------------------------------------------------------
* Version 0
* ----------------------------------------------------------------------------
* Hopefully the add-hoc conventions are clear enough... I didn't feel like
* investing the time in making it a real JSON Schema when there aren't many
* validators, and the most current completed draft at the moment (draft 3) is
* expired...
* ----------------------------------------------------------------------------
* Please note that in general, fields may be added without changing the
* version number, and that programs using this format are not required to fill
* (or read) any of the given fields.
* ------------------------------------------------------------------------- */
var ui_info = {
".meta-data": { // for the JSON file
"version": "<number>",
"date-generated": "<string>", // format: RFC 3339
},
"keyboard-functions": {
"<(function name)>": {
"position": "<number>", // as given by the .map file
"length": "<number>", // as given by the .map file
"comments": {
"name": "<string>", // more user friendly name
"description": "<string>",
"notes": [
"<string>",
"..."
],
"..."
}
},
"..."
},
"layout-matrices": {
"<(matrix name)>": {
"position": "<number>", // as given by the .map file
"length": "<number>" // as given by the .map file
},
"..."
},
"mappings": {
/*
* The mappings prefixed with 'matrix' have their elements in the same
* order as the .hex file (whatever order that is). The mappings
* prefixed with 'physical' will have their elements in an order
* corresponding to thier physical position on the keyboard. You can
* convert between the two using the relative positions of the key-ids
* in 'physical-positions' and 'matrix-positions'.
*
* The current order of 'physical' mappings is:
* --------------------------------------------
* // left hand, spatial positions
* 00, 01, 02, 03, 04, 05, 06,
* 07, 08, 09, 10, 11, 12, 13,
* 14, 15, 16, 17, 18, 19,
* 20, 21, 22, 23, 24, 25, 26,
* 27, 28, 29, 30, 31,
* 32, 33,
* 34, 35, 36,
* 37, 38, 39,
* // right hand, spatial positions
* 40, 41, 42, 43, 44, 45, 46,
* 47, 48, 49, 50, 51, 52, 53,
* 54, 55, 56, 57, 58, 59,
* 60, 61, 62, 63, 64, 65, 66,
* 67, 68, 69, 70, 71,
* 72, 73,
* 74, 75, 76,
* 77, 78, 79,
* --------------------------------------------
*/
"physical-positions": [ // list of key-ids
"<string>", "..."
],
"matrix-positions": [ // list of key-ids
"<string>", "..."
],
"matrix-layout": [
[ // begin layer
[ // begin key
"<number>", // keycode
"<string>", // press function name (ex: 'kbfun_...')
"<string>" // release function name (ex: 'NULL')
],
"..." // more keys
],
"..." // more layers
]
},
"miscellaneous": {
"git-commit-date": "<string>", // format: RFC 3339
"git-commit-id": "<string>",
"number-of-layers": "<number>"
}
}
""")[1:-1]
# -----------------------------------------------------------------------------
import argparse
import json
import os
import re
import subprocess
import sys
# -----------------------------------------------------------------------------
def gen_static(current_date=None, git_commit_date=None, git_commit_id=None):
"""Generate static information"""
return {
'.meta-data': {
'version': 0, # the format version number
'date-generated': current_date,
'description': _FORMAT_DESCRIPTION,
},
'miscellaneous': {
'git-commit-date': git_commit_date, # should be passed by makefile
'git-commit-id': git_commit_id, # should be passed by makefile
},
}
def gen_derived(data):
"""
Generate derived information
Should be called last
"""
return {
'miscellaneous': {
'number-of-layers':
int( data['layout-matrices']['_kb_layout']['length']/(6*14) ),
# because 6*14 is the number of bytes/layer for '_kb_layout'
# (which is a uint8_t matrix)
},
}
# -----------------------------------------------------------------------------
def parse_mapfile(map_file_path):
"""Parse the '.map' file"""
def parse_keyboard_function(f, line):
"""Parse keyboard-functions in the '.map' file"""
search = re.search(r'(0x\S+)\s+(0x\S+)', next(f))
position = int( search.group(1), 16 )
length = int( search.group(2), 16 )
search = re.search(r'0x\S+\s+(\S+)', next(f))
name = search.group(1)
return {
'keyboard-functions': {
name: {
'position': position,
'length': length,
},
},
}
def parse_layout_matrices(f, line):
"""Parse layout matrix information in the '.map' file"""
name = re.search(r'.progmem.data.(_kb_layout\S*)', line).group(1)
search = re.search(r'(0x\S+)\s+(0x\S+)', next(f))
position = int( search.group(1), 16 )
length = int( search.group(2), 16 )
return {
'layout-matrices': {
name: {
'position': position,
'length': length,
},
},
}
# --- parse_mapfile() ---
# normalize paths
map_file_path = os.path.abspath(map_file_path)
# check paths
if not os.path.exists(map_file_path):
raise ValueError("invalid 'map_file_path' given")
output = {}
f = open(map_file_path)
for line in f:
if re.search(r'^\s*\.text\.kbfun_', line):
dict_merge(output, parse_keyboard_function(f, line))
elif re.search(r'^\s*\.progmem\.data.*layout', line):
dict_merge(output, parse_layout_matrices(f, line))
return output
def find_keyboard_functions(source_code_path):
"""Parse all files in the source directory"""
def read_comments(f, line):
"""
Read in properly formatted multi-line comments
- Comments must start with '/*' and end with '*/', each on their own
line
"""
comments = ''
while(line.strip() != r'*/'):
comments += line[2:].strip()+'\n'
line = next(f)
return comments
def parse_comments(comments):
"""
Parse an INI style comment string
- Fields begin with '[field-name]', and continue until the next field,
or the end of the comment
- Fields '[name]', '[description]', and '[note]' are treated specially
"""
def add_field(output, field, value):
"""Put a field+value pair in 'output', the way we want it, if the
pair is valid"""
value = value.strip()
if field is not None:
if field in ('name', 'description'):
if field not in output:
output[field] = value
else:
if field == 'note':
field = 'notes'
if field not in output:
output[field] = []
output[field] += [value]
# --- parse_comments() ---
output = {}
field = None
value = None
for line in comments.split('\n'):
line = line.strip()
if re.search(r'^\[.*\]$', line):
add_field(output, field, value)
field = line[1:-1]
value = None
else:
if value is None:
value = ''
if len(value) > 0 and value[-1] == '.':
line = ' '+line
value += ' '+line
add_field(output, field, value)
return output
def parse_keyboard_function(f, line, comments):
"""Parse keyboard-functions in the source code"""
search = re.search(r'void\s+(kbfun_\S+)\s*\(void\)', line)
name = search.group(1)
return {
'keyboard-functions': {
name: {
'comments': parse_comments(comments),
},
},
}
# --- find_keyboard_functions() ---
# normalize paths
source_code_path = os.path.abspath(source_code_path)
# check paths
if not os.path.exists(source_code_path):
raise ValueError("invalid 'source_code_path' given")
output = {}
for tup in os.walk(source_code_path):
for file_name in tup[2]:
# normalize paths
file_name = os.path.abspath( os.path.join( tup[0], file_name ) )
# ignore non '.c' files
if file_name[-2:] != '.c':
continue
f = open(file_name)
comments = ''
for line in f:
if line.strip() == r'/*':
comments = read_comments(f, line)
elif re.search(r'void\s+kbfun_\S+\s*\(void\)', line):
dict_merge(
output,
parse_keyboard_function(f, line, comments) )
return output
def gen_mappings(matrix_file_path, layout_file_path):
# normalize paths
matrix_file_path = os.path.abspath(matrix_file_path)
layout_file_path = os.path.abspath(layout_file_path)
def parse_matrix_file(matrix_file_path):
match = re.search( # find the whole 'KB_MATRIX_LAYER' macro
r'#define\s+KB_MATRIX_LAYER\s*\(([^)]+)\)[^{]*\{\{([^#]+)\}\}',
open(matrix_file_path).read() )
return {
"mappings": {
"physical-positions": re.findall(r'k..', match.group(1)),
"matrix-positions": re.findall(r'k..|na', match.group(2)),
},
}
def parse_layout_file(layout_file_path):
match = re.findall( # find each whole '_kb_layout*' matrix definition
r'(_kb_layout\w*)[^=]*=((?:[^{}]*\{){3}[^=]*(?:[^{}]*\}){3})',
subprocess.getoutput("gcc -E '"+layout_file_path+"'") )
layout = {}
# collect all the values
for (name, matrix) in match:
layout[name] = [
re.findall( # find all numbers and function pointers
r'[x0-9A-F]+|&\w+|NULL',
re.sub( # replace '((void *) 0)' with 'NULL'
r'\(\s*\(\s*void\s*\*\s*\)\s*0\s*\)',
'NULL',
el ) )
for el in
re.findall( # find each whole layer
r'(?:[^{}]*\{){2}((?:[^}]|\}\s*,)+)(?:[^{}]*\}){2}',
matrix ) ]
# make the numbers into actual numbers
layout['_kb_layout'] = \
[[eval(el) for el in layer] for layer in layout['_kb_layout']]
# remove the preceeding '&' from function pointers
for matrix in ('_kb_layout_press', '_kb_layout_release'):
layout[matrix] = \
[ [re.sub(r'&', '', el) for el in layer]
for layer in layout[matrix] ]
return {
"mappings": {
"matrix-layout":
# group them all properly
[ [[c, p, r] for (c, p, r) in zip(code, press, release)]
for (code, press, release) in
zip( layout['_kb_layout'],
layout['_kb_layout_press'],
layout['_kb_layout_release'] ) ]
},
}
return dict_merge(
parse_matrix_file(matrix_file_path),
parse_layout_file(layout_file_path) )
# -----------------------------------------------------------------------------
def dict_merge(a, b):
"""
Recursively merge two dictionaries
- I was looking around for an easy way to do this, and found something
[here]
(http://www.xormedia.com/recursively-merge-dictionaries-in-python.html).
This is pretty close, but i didn't copy it exactly.
"""
if not isinstance(a, dict) or not isinstance(b, dict):
return b
for (key, value) in b.items():
if key in a:
a[key] = dict_merge(a[key], value)
else:
a[key] = value
return a
# -----------------------------------------------------------------------------
def main():
arg_parser = argparse.ArgumentParser(
description = 'Generate project data for use with the UI' )
arg_parser.add_argument(
'--current-date',
help = ( "should be in the format rfc-3339 "
+ "(e.g. 2006-08-07 12:34:56-06:00)" ),
required = True )
arg_parser.add_argument(
'--git-commit-date',
help = ( "should be in the format rfc-3339 "
+ "(e.g. 2006-08-07 12:34:56-06:00)" ),
required = True )
arg_parser.add_argument(
'--git-commit-id',
help = "the git commit ID",
required = True )
arg_parser.add_argument(
'--map-file-path',
help = "the path to the '.map' file",
required = True )
arg_parser.add_argument(
'--source-code-path',
help = "the path to the source code directory",
required = True )
arg_parser.add_argument(
'--matrix-file-path',
help = "the path to the matrix file we're using",
required = True )
arg_parser.add_argument(
'--layout-file-path',
help = "the path to the layout file we're using",
required = True )
args = arg_parser.parse_args(sys.argv[1:])
output = {}
dict_merge( output, gen_static( args.current_date,
args.git_commit_date,
args.git_commit_id ) )
dict_merge(output, parse_mapfile(args.map_file_path))
dict_merge(output, find_keyboard_functions(args.source_code_path))
dict_merge(output, gen_mappings( args.matrix_file_path,
args.layout_file_path ))
dict_merge(output, gen_derived(output))
print(json.dumps(output, sort_keys=True, indent=4))
# -----------------------------------------------------------------------------
if __name__ == '__main__':
main()

View File

@ -0,0 +1,3 @@
function keyclick(position, layer) {
}

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 94 KiB

View File

@ -1,9 +1,13 @@
# The MIT License (MIT)
Taken from <http://www.opensource.org/licenses/MIT> on 2012-03-10
Retrieved from <http://www.opensource.org/licenses/MIT> on 2012-03-10
This copyright and licence apply to all files in this project, except where
otherwise noted. If you feel that this infringes on any existing intellectual
property, please email me at the address below.
-------------------------------------------------------------------------------
Copyright &copy; 2012 Ben Blazak
Copyright &copy; 2012 Ben Blazak <benblazak.dev@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in

View File

@ -4,9 +4,10 @@
# This should produce a single file (probably in an archive format) for
# distribution, containing everything people will need to use the software.
#
# DEPENDENCIES: This is unabashedly dependant on various Unix commands, and
# therefore probably won't work in a Windows environment. I'm sorry... I
# don't know a good portable way to write it.
# DEPENDENCIES: This is unabashedly dependant on (the GNU implementation of)
# various Unix commands, and therefore probably won't work in a Windows
# environment (besides maybe cygwin). Sorry... I don't know a good portable
# way to write it.
#
# TODO:
# - include doc files (and maybe render them in html)
@ -18,23 +19,35 @@
# -----------------------------------------------------------------------------
# the base name of the file or package to distribute
NAME := ergodox-firmware
# the branch of the git repo we're currently on
BRANCH := $(shell git branch -l | grep '*' | cut -c 3-)
# a version identifier
VERSION := $(shell git log -n 1 | grep 'commit' | cut -c 8-14)--$(shell date +'%Y%m%dT%H%M%S')
include src/makefile-options
# system specific stuff
UNAME := $(shell uname)
ifeq ($(UNAME),Darwin)
DATE_PROG := gdate
else
DATE_PROG := date
endif
CURRENT_DATE := $(shell $(DATE_PROG) --rfc-3339 s)
# git info
GIT_BRANCH := $(shell git branch -l | grep '*' | cut -c 3-)
GIT_COMMIT_DATE := $(shell git log -n 1 --pretty --date=iso | grep 'Date' | cut -c 9- )
GIT_COMMIT_ID := $(shell git log -n 1 | grep 'commit' | cut -c 8-)
# name to use for the final distribution file or package
TARGET := $(NAME)--$(BRANCH)--$(VERSION)
TARGET := ergodox-firmware--$(GIT_BRANCH)--$(shell $(DATE_PROG) -d "$(GIT_COMMIT_DATE)" +'%Y%m%dT%H%M%S')--$(shell echo $(GIT_COMMIT_ID) | cut -c 1-7)
# the build dir
# directories
BUILD := build
ROOT := $(BUILD)/$(TARGET)
SCRIPTS := build-scripts
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
.PHONY: all clean dist
.PHONY: all clean checkin build-dir firmware dist zip
all: dist
@ -42,18 +55,51 @@ clean:
git clean -dX # remove ignored files and directories
-rm -r '$(BUILD)'
dist:
# set up the build dir
checkin:
-git commit -a
build-dir:
-rm -r '$(BUILD)/$(TARGET)'*
-mkdir -p '$(BUILD)/$(TARGET)'
# make all subprojects
firmware:
cd src; $(MAKE) all
# copy stuff to build dir
# --- from src
( cd src; \
cp firmware.hex firmware.eep firmware.map \
'../$(BUILD)/$(TARGET)' )
# make into a zip archive
$(ROOT)/firmware.%: firmware
cp 'src/firmware.$*' '$@'
$(ROOT)/firmware--ui-info.json: $(SCRIPTS)/gen-ui-info.py checkin
( ./'$<' \
--current-date '$(shell $(DATE_PROG) --rfc-3339 s)' \
--git-commit-date '$(GIT_COMMIT_DATE)' \
--git-commit-id '$(GIT_COMMIT_ID)' \
--map-file-path '$(BUILD)/$(TARGET)/firmware.map' \
--source-code-path 'src' \
--matrix-file-path 'src/keyboard/$(KEYBOARD)/matrix.h' \
--layout-file-path \
'src/keyboard/$(KEYBOARD)/layout/$(LAYOUT).c' \
) > '$@'
$(ROOT)/firmware--layout.html: \
$(SCRIPTS)/gen-layout.py \
$(ROOT)/firmware--ui-info.json
\
( ./'$<' \
--ui-info-file '$(ROOT)/firmware--ui-info.json' \
) > '$@'
dist: \
checkin \
build-dir \
$(ROOT)/firmware.hex \
$(ROOT)/firmware.eep \
$(ROOT)/firmware.map \
$(ROOT)/firmware--ui-info.json \
$(ROOT)/firmware--layout.html
zip: dist
( cd '$(BUILD)/$(TARGET)'; \
zip '../$(TARGET).zip' \
-r * .* \

View File

@ -1,7 +1,13 @@
# [ergodox-firmware][]: Firmware for the [ergoDOX keyboard][]
# [ergodox-firmware][]: Firmware for the [ErgoDox keyboard][]
Also see the [geekhack]
(http://geekhack.org/showthread.php?22780-Interest-Check-Custom-split-ergo-keyboard)
and [deskthority]
(http://deskthority.net/workshop-f7/split-ergonomic-keyboard-project-t1753.html)
discussion threads.
[ergodox-firmware]: https://github.com/benblazak/ergodox-firmware
[ergodox keyboard]: http://geekhack.org/showthread.php?22780-Interest-Check-Custom-split-ergo-keyboard
[ergodox keyboard]: http://ergodox.org/
## About this File
@ -40,38 +46,17 @@ started this project), but for now:
matrix to hardware matrix mapping, and hardware specific documentation.
* [src/main.c] (src/main.c) ties it all together.
Open issues and such are tracked [on github]
Open issues, feature requests, and such are tracked [on github]
(/benblazak/ergodox-firmware/issues).
## Notes
### (2012-04-11) (first major release on branch 'main')
As of now, it looks like we have a working 6-KRO keyboard firmware for a Teensy
2.0 with a MCP23018 I/O expander. It's scanning at ~167 Hz, most of which is
spent communicating over I&sup2;C. This should be fast enough, I think.
Slight improvements might be possible (without finding a microprocessor capable
of > 400 kHz I&sup2;C or using SPI, that is, which I imagine would speed things
up a lot - but it'd also be much less convenient). I'll attempt them if I see
the need.
Also, layers are implemented, but untested, as no keymaps are written to use
them yet. Implementing on-keyboard hardware remapping seems like it'd be very
possible too, but I'd need to try it (and learn how to programmatically store
stuff in program space) to see if it'd work; and I'm not sure of a good way to
do the interface, since different people will likely have different keycap
layouts on the ergoDOX.
Getting to N-KRO is a goal, but I honestly have no idea whether it'll be
accomplished. Ideally, I'd like a variable-KRO, where the keyboard is 6-KRO
till you press the 7th key (so if you're worried about compatibility, just
don't press more than 6 keys at a time). From what I've read, it might be
possible, but I just finished everything else (so I'm slightly tired), and the
USB spec is scary.
Discussions about the project as a whole are going on at the forum page (linked
in the title) so if you have any imput (or want to participate in the group
buy!), please stop by. :) .
### Features as of 2012-04-11 : first major release on branch 'main'
* 6KRO
* Teensy 2.0, MCP23018 I/O expander
* ~167 Hz scan rate (most of which is spent communicating via I&sup2;C)
* firmware level layers
## Dependencies (for building from source)

View File

@ -21,7 +21,7 @@
: column by Kevin Ross for Encoder
Includes a short thing about pull-up resistors.
* [Powering Light Emitting Diodes(LEDs)]
* [Powering Light Emitting Diodes (LEDs)]
(http://wolfstone.halloweenhost.com/Lighting/litlpo_PoweringLEDs.html)
Can you use one resistor for multiple parallel LEDs? No. Or, you can, but
it's not the best idea.
@ -35,6 +35,11 @@
-> [powering LEDs]
(http://wolfstone.halloweenhost.com/Lighting/litlpo_PoweringLEDs.html)
* [Notes on LEDs]
(http://www.gizmology.net/LEDs.htm)
Talks about different types of LEDs, mentioning typical brightnesses,
voltages, and other intersting stuff.
* [All About Circuits : Reference]
(http://www.allaboutcircuits.com/vol_5/index.html)
Looks like a great collection of info; didn't get to read much of it.

View File

@ -1,22 +0,0 @@
/* ----------------------------------------------------------------------------
* keyboard specific exports
*
* Different keyboards are included by modifying a variable in the makefile.
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#undef _str
#undef _expstr
#undef _inc
#define _str(s) #s // stringify
#define _expstr(s) _str(s) // expand -> stringify
#define _inc _expstr(keyboard/MAKEFILE_KEYBOARD.h) // inc(lude)
#include _inc
#undef _str
#undef _expstr
#undef _inc

View File

@ -1,5 +1,8 @@
/* ----------------------------------------------------------------------------
* ergoDOX controller: Teensy 2.0 specific exports : private
* controller specific exports
*
* Files for different keyboards are used by modifying a variable in the
* Makefile
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
@ -7,13 +10,7 @@
* ------------------------------------------------------------------------- */
#ifndef TEENSY_2_0_h_PRIVATE
#define TEENSY_2_0_h_PRIVATE
#include "matrix.h"
uint8_t teensy_init(void);
uint8_t teensy_update_matrix( bool matrix[KB_ROWS][KB_COLUMNS] );
#endif
#include "../lib/variable-include.h"
#define INCLUDE EXP_STR( ./MAKEFILE_KEYBOARD/controller.h )
#include INCLUDE

View File

@ -1,36 +0,0 @@
/* ----------------------------------------------------------------------------
* ergoDOX specific exports
* includes (for centralization) the public exports from all subfiles
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#ifndef ERGODOX_h
#define ERGODOX_h
#include "lib/data-types.h"
#include "ergodox/layout.h" // number of layers, layout
#include "ergodox/led.h" // logical led controls
#include "ergodox/matrix.h" // kb dimensions, matrix status
#include "ergodox/teensy-2-0.h" // LED controls
// note:
// - see your keyswitch specification for the necessary value. for
// cherry mx switches, the switch bounce time is speced to be <= 5ms.
// it looks like most switches are speced to be between 5 and 8 ms.
// - if timing is important, balance this value with the main() loop
// run time (~5ms, last i checked, nearly all of it in the i2c
// update() function)
#define KB_DEBOUNCE_TIME 5 // in ms
uint8_t kb_init(void);
uint8_t kb_update_matrix(bool matrix[KB_ROWS][KB_COLUMNS]);
#endif

View File

@ -26,31 +26,33 @@
inkscape:pageopacity="1"
inkscape:pageshadow="2"
inkscape:zoom="1.4142136"
inkscape:cx="464.65225"
inkscape:cy="203.44926"
inkscape:cx="455.81585"
inkscape:cy="210.83562"
inkscape:document-units="px"
inkscape:current-layer="layer7"
showgrid="true"
inkscape:snap-global="false"
inkscape:snap-bbox="false"
inkscape:snap-bbox="true"
inkscape:snap-nodes="false"
inkscape:bbox-nodes="false"
inkscape:bbox-nodes="true"
inkscape:snap-bbox-edge-midpoints="false"
inkscape:bbox-paths="false"
inkscape:window-width="1920"
inkscape:window-height="997"
inkscape:window-width="1440"
inkscape:window-height="852"
inkscape:window-x="0"
inkscape:window-y="30"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:snap-bbox-midpoints="false"
inkscape:snap-bbox-midpoints="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:object-nodes="true"
inkscape:object-nodes="false"
fit-margin-top="15"
fit-margin-left="15"
fit-margin-bottom="15"
fit-margin-right="15"
inkscape:snap-page="true">
inkscape:snap-page="true"
inkscape:snap-object-midpoints="false"
inkscape:snap-center="true">
<inkscape:grid
id="grid3799"
type="xygrid"
@ -719,6 +721,146 @@
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.4,0,0,0.4,2.96,0.4)" />
</marker>
<marker
inkscape:stockid="DotM"
orient="auto"
refY="0"
refX="0"
id="marker11070-18"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path11072-9"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.4,0,0,0.4,2.96,0.4)" />
</marker>
<marker
inkscape:stockid="DotM"
orient="auto"
refY="0"
refX="0"
id="marker11070-95"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path11072-70"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.4,0,0,0.4,2.96,0.4)" />
</marker>
<marker
inkscape:stockid="DotM"
orient="auto"
refY="0"
refX="0"
id="DotM-10-7-8"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path4023-3-6-7"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.4,0,0,0.4,2.96,0.4)" />
</marker>
<marker
inkscape:stockid="DotM"
orient="auto"
refY="0"
refX="0"
id="marker3526"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3528"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.4,0,0,0.4,2.96,0.4)" />
</marker>
<marker
inkscape:stockid="DotM"
orient="auto"
refY="0"
refX="0"
id="marker11070-72"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path11072-54"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.4,0,0,0.4,2.96,0.4)" />
</marker>
<marker
inkscape:stockid="DotM"
orient="auto"
refY="0"
refX="0"
id="marker11070-51"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path11072-99"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.4,0,0,0.4,2.96,0.4)" />
</marker>
<marker
inkscape:stockid="DotM"
orient="auto"
refY="0"
refX="0"
id="marker11070-99"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path11072-09"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.4,0,0,0.4,2.96,0.4)" />
</marker>
<marker
inkscape:stockid="DotM"
orient="auto"
refY="0"
refX="0"
id="marker3618"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3620"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.4,0,0,0.4,2.96,0.4)" />
</marker>
<marker
inkscape:stockid="DotM"
orient="auto"
refY="0"
refX="0"
id="DotM-10-7-82"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path4023-3-6-5"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.4,0,0,0.4,2.96,0.4)" />
</marker>
<marker
inkscape:stockid="DotM"
orient="auto"
refY="0"
refX="0"
id="marker3665"
style="overflow:visible">
<path
inkscape:connector-curvature="0"
id="path3667"
d="m -2.5,-1 c 0,2.76 -2.24,5 -5,5 -2.76,0 -5,-2.24 -5,-5 0,-2.76 2.24,-5 5,-5 2.76,0 5,2.24 5,5 z"
style="fill-rule:evenodd;stroke:#000000;stroke-width:1pt;marker-start:none;marker-end:none"
transform="matrix(0.4,0,0,0.4,2.96,0.4)" />
</marker>
</defs>
<metadata
id="metadata7">
@ -1696,7 +1838,7 @@
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000077;stroke-width:0.95463163;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#DotM);marker-end:none;display:inline"
d="m 381.70056,355.17608 0.005,-8.45211 -6.22824,-2.5329 12.3705,-2.8149 -12.29462,-2.60895 12.14284,-2.74624 -11.99105,-2.81491 11.91516,-2.81491 -5.91963,-2.60894 0,-8.37607 0,-208.83524"
d="m 381.70056,356.94385 0.005,-10.21988 -6.22824,-2.5329 12.3705,-2.8149 -12.29462,-2.60895 12.14284,-2.74624 -11.99105,-2.81491 11.91516,-2.81491 -5.91963,-2.60894 0,-8.37607 0,-208.83524"
id="path6326-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccc" />
@ -1768,7 +1910,7 @@
</g>
<path
style="fill:none;stroke:#000077;stroke-width:0.95463163;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#DotM);marker-end:none;display:inline"
d="m 403.37542,355.17608 0.005,-8.45211 -6.22824,-2.5329 12.3705,-2.8149 -12.29462,-2.60895 12.14284,-2.74624 -11.99105,-2.81491 11.91516,-2.81491 -5.91963,-2.60894 0,-8.37607 0,-208.83524"
d="m 403.37542,356.76707 0.005,-10.0431 -6.22824,-2.5329 12.3705,-2.8149 -12.29462,-2.60895 12.14284,-2.74624 -11.99105,-2.81491 11.91516,-2.81491 -5.91963,-2.60894 0,-8.37607 0,-208.83524"
id="path6326-2-6"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccc" />
@ -1840,7 +1982,7 @@
</g>
<path
style="fill:none;stroke:#000077;stroke-width:0.95463163;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-start:url(#DotM);marker-end:none;display:inline"
d="m 423.37542,355.17608 0.005,-8.45211 -6.22824,-2.5329 12.3705,-2.8149 -12.29462,-2.60895 12.14284,-2.74624 -11.99105,-2.81491 11.91516,-2.81491 -5.91963,-2.60894 0,-8.37607 0,-208.83524"
d="m 423.37542,356.94385 0.005,-10.21988 -6.22824,-2.5329 12.3705,-2.8149 -12.29462,-2.60895 12.14284,-2.74624 -11.99105,-2.81491 11.91516,-2.81491 -5.91963,-2.60894 0,-8.37607 0,-208.83524"
id="path6326-2-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccccccccccc" />
@ -1924,22 +2066,22 @@
sodipodi:nodetypes="ccccccccccccc" />
<path
style="fill:none;stroke:#007700;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotM-10)"
d="M 255,127.36218 C 297.1005,68.254966 399.98689,51.202007 403.41299,89.442314 l 0.023,4.815736"
d="M 255,127.36218 C 297.1005,68.254966 382.48689,65.827007 382.16299,88.692314 l -0.102,5.940736"
id="path7504"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;stroke:#007700;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotM-10);display:inline"
d="M 234.96647,127.29296 C 305.92363,44.536037 388.15055,41.329164 381.99597,85.946323 l 0.023,8.346065"
d="M 234.96647,127.29296 C 297.17363,43.911037 403.52555,52.704164 403.49597,88.696323 l 0.023,5.721065"
id="path7504-3"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccc" />
<path
style="fill:none;stroke:#007700;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotM-10-7)"
d="m 195,247.36218 c -4.32571,23.55176 70.95424,57.80762 144.21458,54.72312 9.45484,-5.50003 -1.67061,-20.3897 5.26135,-28.19694 38.00964,-42.80905 6.84799,-181.553227 13.02147,-196.245847 6.17348,-14.69262 -2.21854,-13.634877 3.33961,-21.779094 5.55815,-8.144217 62.33333,-4.615397 62.61183,28.039681 l -0.0815,10.708503"
d="m 195,247.36218 c -4.32571,23.55176 70.95424,57.80762 144.21458,54.72312 9.45484,-5.50003 -1.20117,-19.99688 5.26135,-28.19694 25.0471,-31.78137 -5.00774,-173.86807 10.07621,-195.922273 5.69158,-6.64719 1.79635,-9.549128 3.28486,-15.352668 0.97604,-14.654625 65.33333,-6.490397 65.61183,26.164681 l -0.0815,5.833503"
id="path7758"
inkscape:connector-curvature="0"
sodipodi:nodetypes="ccszzcc" />
sodipodi:nodetypes="ccscccc" />
<path
style="fill:none;stroke:#000077;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotM-10-7);marker-end:url(#DotM-10-7)"
d="m 95.105862,247.67467 c -2.592497,38.06584 1.233202,73.99227 7.071068,109.24799"
@ -1987,14 +2129,14 @@
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ff7700;fill-opacity:1;stroke:none;font-family:Sans"
x="433.5"
y="341.86218"
x="429.96448"
y="346.10483"
id="text9042"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
id="tspan9044"
x="433.5"
y="341.86218">R = 220 Ω</tspan></text>
x="429.96448"
y="346.10483">R = (match to LEDs)</tspan></text>
<text
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ff7700;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
@ -2079,32 +2221,32 @@
y="176.07817"
id="tspan9630">PWM</tspan></text>
<text
inkscape:transform-center-y="-8.1837146"
inkscape:transform-center-x="5.960441"
transform="matrix(0.7776191,-0.62873566,0.62873566,0.7776191,0,0)"
inkscape:transform-center-y="-8.3061223"
inkscape:transform-center-x="5.7886394"
transform="matrix(0.79055013,-0.61239733,0.61239733,0.79055013,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ff7700;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="135.67398"
y="246.92535"
x="140.45497"
y="243.17465"
id="text9938"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="135.67398"
y="246.92535"
x="140.45497"
y="243.17465"
id="tspan9636">PWM</tspan></text>
<text
inkscape:transform-center-y="-3.7250803"
inkscape:transform-center-x="-6.0517844"
transform="matrix(0.89909256,-0.43775858,0.43775858,0.89909256,0,0)"
inkscape:transform-center-y="-3.6387754"
inkscape:transform-center-x="-6.1040665"
transform="matrix(0.90521688,-0.42494988,0.42494988,0.90521688,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#ff7700;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="227.65367"
y="215.32523"
x="221.5656"
y="212.97839"
id="text9941"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="227.65367"
y="215.32523"
x="221.5656"
y="212.97839"
id="tspan9632">PWM</tspan></text>
<text
xml:space="preserve"
@ -2172,7 +2314,7 @@
sodipodi:role="line"
x="-103.45203"
y="119.83008"
id="tspan12234">row 0</tspan></text>
id="tspan12234">row 5</tspan></text>
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
@ -2184,7 +2326,7 @@
sodipodi:role="line"
x="-103.45203"
y="139.83008"
id="tspan12238">row 1</tspan></text>
id="tspan12238">row 4</tspan></text>
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
@ -2196,7 +2338,7 @@
sodipodi:role="line"
x="-103.45203"
y="159.83008"
id="tspan12240">row 2</tspan></text>
id="tspan12240">row 3</tspan></text>
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
@ -2208,7 +2350,7 @@
sodipodi:role="line"
x="-103.45203"
y="179.83008"
id="tspan12242">row 3</tspan></text>
id="tspan12242">row 2</tspan></text>
<text
inkscape:transform-center-y="10.541016"
inkscape:transform-center-x="-20.767578"
@ -2222,7 +2364,7 @@
sodipodi:role="line"
x="-103.45203"
y="199.83008"
id="tspan12244">row 4</tspan></text>
id="tspan12244">row 1</tspan></text>
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
@ -2234,19 +2376,7 @@
sodipodi:role="line"
x="-103.45203"
y="219.83008"
id="tspan12248">row 5</tspan></text>
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;font-family:Sans"
x="-63.024292"
y="279.83008"
id="text12501"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-63.024292"
y="279.83008"
id="tspan12252">col 0</tspan></text>
id="tspan12248">row 0</tspan></text>
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
@ -2258,19 +2388,7 @@
sodipodi:role="line"
x="-339.98328"
y="299.83008"
id="tspan12254">col 1</tspan></text>
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;font-family:Sans"
x="-339.88953"
y="319.83008"
id="text12507"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-339.88953"
y="319.83008"
id="tspan12256">col 2</tspan></text>
id="tspan12254">col D</tspan></text>
<text
inkscape:transform-center-y="-4.6435547"
transform="matrix(0,-1,1,0,0,0)"
@ -2283,7 +2401,7 @@
sodipodi:role="line"
x="-340.12976"
y="259.83008"
id="tspan12258">col 3</tspan></text>
id="tspan12258">col B</tspan></text>
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
@ -2295,19 +2413,7 @@
sodipodi:role="line"
x="-340.41687"
y="279.83008"
id="tspan12260">col 4</tspan></text>
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;font-family:Sans"
x="-63.024292"
y="299.83008"
id="text12516"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-63.024292"
y="299.83008"
id="tspan12262">col 5</tspan></text>
id="tspan12260">col C</tspan></text>
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
@ -2319,7 +2425,7 @@
sodipodi:role="line"
x="-300.33484"
y="119.83008"
id="tspan12264">col 6</tspan></text>
id="tspan12264">col 7</tspan></text>
<path
style="fill:none;stroke:#aaaa00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker11070);display:inline"
d="m 135,127.11218 0,-20.5"
@ -2372,170 +2478,158 @@
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-280.29382"
x="-335.29382"
y="539.83008"
id="text12519-4"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-280.29382"
x="-335.29382"
y="539.83008"
id="tspan12264-1">col 0</tspan></text>
id="tspan12264-1">row 5</tspan></text>
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-279.98328"
x="-334.98328"
y="559.83008"
id="text13816"
sodipodi:linespacing="125%"><tspan
id="tspan13492"
sodipodi:role="line"
x="-279.98328"
y="559.83008">col 1</tspan></text>
x="-334.98328"
y="559.83008">row 4</tspan></text>
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-279.88953"
x="-334.88953"
y="579.83008"
id="text13819"
sodipodi:linespacing="125%"><tspan
id="tspan13494"
sodipodi:role="line"
x="-279.88953"
y="579.83008">col 2</tspan></text>
x="-334.88953"
y="579.83008">row 3</tspan></text>
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-280.12976"
x="-335.12976"
y="599.83008"
id="text13822"
sodipodi:linespacing="125%"><tspan
id="tspan13496"
sodipodi:role="line"
x="-280.12976"
y="599.83008">col 3</tspan></text>
x="-335.12976"
y="599.83008">row 2</tspan></text>
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-280.41687"
x="-335.41687"
y="619.83008"
id="text13825"
sodipodi:linespacing="125%"><tspan
id="tspan13498"
sodipodi:role="line"
x="-280.41687"
y="619.83008">col 4</tspan></text>
x="-335.41687"
y="619.83008">row 1</tspan></text>
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-280.04187"
x="-335.04187"
y="639.83008"
id="text13828"
sodipodi:linespacing="125%"><tspan
id="tspan13502"
sodipodi:role="line"
x="-280.04187"
y="639.83008">col 5</tspan></text>
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-280.33484"
y="659.83008"
id="text13831"
sodipodi:linespacing="125%"><tspan
id="tspan13508"
sodipodi:role="line"
x="-280.33484"
y="659.83008">col 6</tspan></text>
x="-335.04187"
y="639.83008">row 0</tspan></text>
<text
inkscape:transform-center-y="-3"
inkscape:transform-center-x="-20.5"
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-112.36218"
y="560"
x="-112.33308"
y="558.26935"
id="text12230-8"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-112.36218"
y="560"
id="tspan12234-5">row B</tspan></text>
x="-112.33308"
y="558.26935"
id="tspan12234-5">col 5</tspan></text>
<text
inkscape:transform-center-y="-3"
inkscape:transform-center-x="-20.5"
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-113.45203"
y="579.83008"
x="-113.42294"
y="578.09943"
id="text13836"
sodipodi:linespacing="125%"><tspan
id="tspan13461"
sodipodi:role="line"
x="-113.45203"
y="579.83008">row A</tspan></text>
x="-113.42294"
y="578.09943">col 4</tspan></text>
<text
inkscape:transform-center-y="-3"
inkscape:transform-center-x="-20.5"
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-113.45203"
y="599.83008"
x="-113.42294"
y="598.09943"
id="text13839"
sodipodi:linespacing="125%"><tspan
id="tspan13463"
sodipodi:role="line"
x="-113.45203"
y="599.83008">row 9</tspan></text>
x="-113.42294"
y="598.09943">col 3</tspan></text>
<text
inkscape:transform-center-y="-3"
inkscape:transform-center-x="-20.5"
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-113.45203"
y="619.83008"
x="-113.42294"
y="618.09943"
id="text13842"
sodipodi:linespacing="125%"><tspan
id="tspan13465"
sodipodi:role="line"
x="-113.45203"
y="619.83008">row 8</tspan></text>
x="-113.42294"
y="618.09943">col 2</tspan></text>
<text
inkscape:transform-center-y="-3"
inkscape:transform-center-x="-20.5"
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-113.45203"
y="639.83008"
x="-113.42294"
y="638.09943"
id="text13845"
sodipodi:linespacing="125%"><tspan
id="tspan13467"
sodipodi:role="line"
x="-113.45203"
y="639.83008">row 7</tspan></text>
x="-113.42294"
y="638.09943">col 1</tspan></text>
<text
inkscape:transform-center-y="-3"
inkscape:transform-center-x="-20.5"
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-112.36218"
y="660"
x="-112.33308"
y="658.26935"
id="text13848"
sodipodi:linespacing="125%"><tspan
id="tspan13469"
sodipodi:role="line"
x="-112.36218"
y="660">row 6</tspan></text>
x="-112.33308"
y="658.26935">col 0</tspan></text>
<path
style="fill:none;stroke:#aaaa00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker11070);display:inline"
d="m 275,247.36218 0,59.74443"
@ -2548,24 +2642,6 @@
id="path11780-7-1-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#aaaa00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker11070);display:inline"
d="m 315,247.36218 0,59.74443"
id="path11780-7-1-05"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#aaaa00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker11070);display:inline"
d="m 275,127.36218 0,-59.744424"
id="path11780-7-1-05-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#aaaa00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker11070);display:inline"
d="m 295,127.36218 0,-59.744424"
id="path11780-7-1-05-0-0"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#aaaa00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker11070);display:inline"
d="m 575,137.36218 0,-20.49999"
@ -2598,46 +2674,40 @@
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#aaaa00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker11070);display:inline"
d="m 575,227.36218 0,20.5"
d="m 575,227.36218 0,71.05813"
id="path11780-1-5-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#aaaa00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker11070);display:inline"
d="m 555,227.36218 0,20.49999"
d="m 555,227.36218 0,71.05812"
id="path11780-1-5-9-4"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#aaaa00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker11070);display:inline"
d="m 535,227.36218 0,20.49999"
d="m 535,227.36218 0,71.05812"
id="path11780-1-5-4-5"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#aaaa00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker11070);display:inline"
d="m 635,227.36218 0,20.5"
d="m 635,227.36218 0,71.05813"
id="path11780-1-5-2-8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#aaaa00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker11070);display:inline"
d="m 615,227.36218 0,20.49999"
d="m 615,227.36218 0,71.05812"
id="path11780-1-5-9-4-1"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#aaaa00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker11070);display:inline"
d="m 595,227.36218 0,20.49999"
d="m 595,227.36218 0,71.05812"
id="path11780-1-5-4-5-8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#aaaa00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker11070);display:inline"
d="m 655,227.36218 0,20.5"
id="path11780-1-5-2-8-7"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
inkscape:transform-center-y="-7.0750605"
inkscape:transform-center-x="0.66599259"
@ -2697,7 +2767,93 @@
sodipodi:role="line"
x="37.24189"
y="405.93091"
id="tspan3451">- Row and column assignments are to matrix positions, not physical positions</tspan></text>
id="tspan3450">- Row and column assignments are to matrix positions, not physical positions</tspan></text>
<path
style="fill:none;stroke:#aaaa00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker11070);display:inline"
d="m 534.99275,137.36829 0,-20.5"
id="path11780-1-5-8"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
inkscape:transform-center-y="-3"
inkscape:transform-center-x="-20.5"
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-112.3392"
y="538.26208"
id="text12230-8-3"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-112.3392"
y="538.26208"
id="tspan12234-5-3">col 6</tspan></text>
<path
style="fill:none;stroke:#770000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotM-10-7);marker-end:url(#DotM-10-7);display:inline"
d="m 275.03546,127.24605 c 0.90412,-34.974223 19.03956,-22.61202 7.77819,-102.530485"
id="path8368-9"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-300.46454"
y="139.9549"
id="text12519-7"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-300.46454"
y="139.9549"
id="tspan12264-7">col 8</tspan></text>
<path
style="fill:none;stroke:#aaaa00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker11070);display:inline"
d="m 135.12482,247.5319 0,20.5"
id="path11780-7-17"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-300.39969"
y="159.94453"
id="text12519-9"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-300.39969"
y="159.94453"
id="tspan12264-5">col 9</tspan></text>
<path
style="fill:none;stroke:#aaaa00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker11070);display:inline"
d="m 155.11445,247.46705 0,20.5"
id="path11780-7-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<text
transform="matrix(0,-1,1,0,0,0)"
xml:space="preserve"
style="font-size:12px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#aaaa00;fill-opacity:1;stroke:none;display:inline;font-family:Sans"
x="-300.52939"
y="180.06935"
id="text12519-7-1"
sodipodi:linespacing="125%"><tspan
sodipodi:role="line"
x="-300.52939"
y="180.06935"
id="tspan12264-7-6">col A</tspan></text>
<path
style="fill:none;stroke:#aaaa00;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#marker11070);display:inline"
d="m 175.23927,247.59677 0,20.5"
id="path11780-7-17-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cc" />
<path
style="fill:none;stroke:#000077;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;marker-start:url(#DotM-10-7);marker-end:url(#DotM-10-7);display:inline"
d="m 368.80181,357.18442 c -5.63959,-38.02199 1.04897,-157.80012 0.47542,-235.71113 -0.23179,-31.485746 -54.84564,-32.329723 -54.21554,6.07822"
id="path7962-2"
inkscape:connector-curvature="0"
sodipodi:nodetypes="csc" />
</g>
<g
inkscape:groupmode="layer"

Before

Width:  |  Height:  |  Size: 152 KiB

After

Width:  |  Height:  |  Size: 158 KiB

View File

@ -1,5 +1,5 @@
/* ----------------------------------------------------------------------------
* ergoDOX specific code: tying it all together
* ergoDOX : controller specific code
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
@ -7,12 +7,13 @@
* ------------------------------------------------------------------------- */
#include "lib/data-types.h"
#include "ergodox/matrix.h"
#include "ergodox/mcp23018--private.h"
#include "ergodox/teensy-2-0--private.h"
#include <stdbool.h>
#include <stdint.h>
#include "./matrix.h"
#include "./controller/mcp23018--functions.h"
#include "./controller/teensy-2-0--functions.h"
// ----------------------------------------------------------------------------
/* returns
* - success: 0

View File

@ -0,0 +1,27 @@
/* ----------------------------------------------------------------------------
* ergoDOX : controller specific exports
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#ifndef KEYBOARD__ERGODOX__CONTROLLER_h
#define KEYBOARD__ERGODOX__CONTROLLER_h
#include <stdbool.h>
#include <stdint.h>
#include "./matrix.h"
// --------------------------------------------------------------------
#include "./controller/teensy-2-0--led.h"
// --------------------------------------------------------------------
uint8_t kb_init(void);
uint8_t kb_update_matrix(bool matrix[KB_ROWS][KB_COLUMNS]);
#endif

View File

@ -1,5 +1,5 @@
/* ----------------------------------------------------------------------------
* ergoDOX controller: MCP23018 specific exports : private
* ergoDOX : controller : MCP23018 specific exports : functions
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
@ -7,14 +7,19 @@
* ------------------------------------------------------------------------- */
#ifndef MCP23018_h_PRIVATE
#define MCP23018_h_PRIVATE
#ifndef KEYBOARD__ERGODOX__CONTROLLER__MCP23018__FUNCTIONS_h
#define KEYBOARD__ERGODOX__CONTROLLER__MCP23018__FUNCTIONS_h
#include "lib/data-types.h"
#include "matrix.h"
#include <stdbool.h>
#include <stdint.h>
#include "../matrix.h"
// --------------------------------------------------------------------
#define MCP23018_TWI_ADDRESS 0b0100000
// --------------------------------------------------------------------
uint8_t mcp23018_init(void);
uint8_t mcp23018_update_matrix( bool matrix[KB_ROWS][KB_COLUMNS] );

View File

@ -0,0 +1,206 @@
/* ----------------------------------------------------------------------------
* ergoDOX : controller: MCP23018 specific code
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#include <stdbool.h>
#include <stdint.h>
#include <util/twi.h>
#include "../../../lib/twi.h" // `TWI_FREQ` defined in "teensy-2-0.c"
#include "../options.h"
#include "../matrix.h"
#include "./mcp23018--functions.h"
// ----------------------------------------------------------------------------
// check options
#if (MCP23018__DRIVE_ROWS && MCP23018__DRIVE_COLUMNS) \
|| !(MCP23018__DRIVE_ROWS || MCP23018__DRIVE_COLUMNS)
#error "See 'Pin drive direction' in 'options.h'"
#endif
// ----------------------------------------------------------------------------
// register addresses (see "mcp23018.md")
#define IODIRA 0x00 // i/o direction register
#define IODIRB 0x01
#define GPPUA 0x0C // GPIO pull-up resistor register
#define GPPUB 0x0D
#define GPIOA 0x12 // general purpose i/o port register (write modifies OLAT)
#define GPIOB 0x13
#define OLATA 0x14 // output latch register
#define OLATB 0x15
// TWI aliases
#define TWI_ADDR_WRITE ( (MCP23018_TWI_ADDRESS<<1) | TW_WRITE )
#define TWI_ADDR_READ ( (MCP23018_TWI_ADDRESS<<1) | TW_READ )
// ----------------------------------------------------------------------------
/* returns:
* - success: 0
* - failure: twi status code
*
* notes:
* - `twi_stop()` must be called *exactly once* for each twi block, the way
* things are currently set up. this may change in the future.
*/
uint8_t mcp23018_init(void) {
uint8_t ret;
// set pin direction
// - unused : input : 1
// - input : input : 1
// - driving : output : 0
twi_start();
ret = twi_send(TWI_ADDR_WRITE);
if (ret) goto out; // make sure we got an ACK
twi_send(IODIRA);
#if MCP23018__DRIVE_ROWS
twi_send(0b11111111); // IODIRA
twi_send(0b11000000); // IODIRB
#elif MCP23018__DRIVE_COLUMNS
twi_send(0b10000000); // IODIRA
twi_send(0b11111111); // IODIRB
#endif
twi_stop();
// set pull-up
// - unused : on : 1
// - input : on : 1
// - driving : off : 0
twi_start();
ret = twi_send(TWI_ADDR_WRITE);
if (ret) goto out; // make sure we got an ACK
twi_send(GPPUA);
#if MCP23018__DRIVE_ROWS
twi_send(0b11111111); // GPPUA
twi_send(0b11000000); // GPPUB
#elif MCP23018__DRIVE_COLUMNS
twi_send(0b10000000); // GPPUA
twi_send(0b11111111); // GPPUB
#endif
twi_stop();
// set logical value (doesn't matter on inputs)
// - unused : hi-Z : 1
// - input : hi-Z : 1
// - driving : hi-Z : 1
twi_start();
ret = twi_send(TWI_ADDR_WRITE);
if (ret) goto out; // make sure we got an ACK
twi_send(OLATA);
twi_send(0b11111111); //OLATA
twi_send(0b11111111); //OLATB
out:
twi_stop();
return ret;
}
/* returns:
* - success: 0
* - failure: twi status code
*/
#if KB_ROWS != 6 || KB_COLUMNS != 14
#error "Expecting different keyboard dimensions"
#endif
uint8_t mcp23018_update_matrix(bool matrix[KB_ROWS][KB_COLUMNS]) {
uint8_t ret, data;
// initialize things, just to make sure
// - it's not appreciably faster to skip this, and it takes care of the
// case when the i/o expander isn't plugged in during the first
// init()
ret = mcp23018_init();
// if there was an error
if (ret) {
// clear our part of the matrix
for (uint8_t row=0; row<=5; row++)
for (uint8_t col=0; col<=6; col++)
matrix[row][col] = 0;
return ret;
}
// --------------------------------------------------------------------
// update our part of the matrix
#if MCP23018__DRIVE_ROWS
for (uint8_t row=0; row<=5; row++) {
// set active row low : 0
// set other rows hi-Z : 1
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPIOB);
twi_send( 0xFF & ~(1<<(5-row)) );
twi_stop();
// read column data
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPIOA);
twi_start();
twi_send(TWI_ADDR_READ);
twi_read(&data);
twi_stop();
// update matrix
for (uint8_t col=0; col<=6; col++) {
matrix[row][col] = !( data & (1<<col) );
}
}
// set all rows hi-Z : 1
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPIOB);
twi_send(0xFF);
twi_stop();
#elif MCP23018__DRIVE_COLUMNS
for (uint8_t col=0; col<=6; col++) {
// set active column low : 0
// set other columns hi-Z : 1
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPIOA);
twi_send( 0xFF & ~(1<<col) );
twi_stop();
// read row data
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPIOB);
twi_start();
twi_send(TWI_ADDR_READ);
twi_read(&data);
twi_stop();
// update matrix
for (uint8_t row=0; row<=5; row++) {
matrix[row][col] = !( data & (1<<(5-row)) );
}
}
// set all columns hi-Z : 1
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPIOA);
twi_send(0xFF);
twi_stop();
#endif
// /update our part of the matrix
// --------------------------------------------------------------------
return ret; // success
}

View File

@ -2,10 +2,10 @@
## Pinout and Pin assignments
* `+` indicates pin
* `o` indicates unused pin
* `+` indicates connected pin
* `o` indicates unconnected pin
* `=` is used to list other things the pin is connected to
* `-`s inserted between some of the pin functions for readability
* `OC**` pins enclosed in parenthesis had lines over them in the pinout
### MCP23018
Vss(GND) +01---.---28+ NC
@ -27,25 +27,26 @@
power_negative Vss(GND) +01---.---28o NC
NC o02 27o GPA7
column0 GPB0 +03 26o GPA6
column1 GPB1 +04 25+ GPA5 rowB
column2 GPB2 +05 24+ GPA4 rowA
column3 GPB3 +06 23+ GPA3 row9
column4 GPB4 +07 22+ GPA2 row8
column5 GPB5 +08 21+ GPA1 row7
column6 GPB6 +09 20+ GPA0 row6
row_5 GPB0 +03 26+ GPA6 column_6
row_4 GPB1 +04 25+ GPA5 column_5
row_3 GPB2 +05 24+ GPA4 column_4
row_2 GPB3 +06 23+ GPA3 column_3
row_1 GPB4 +07 22+ GPA2 column_2
row_0 GPB5 +08 21+ GPA1 column_1
GPB6 o09 20+ GPA0 column_0
GPB7 o10 19o INTA
power_positive Vdd(Vcc) +11 18o INTB
I2C SCL +12 17o NC
I2C SDA +13 16+ RESET (see note)
NC o14-------15+ ADDR (see note)
I2C SDA +13 16+ RESET = Vdd(Vcc) (see note)
NC o14-------15+ ADDR = Vss(GND) (see note)
* notes:
* Row and column assignments are to matrix positions, which may or may
correspond to the physical position of the key: e.g. the key where `row4`
and `column2` cross will be scanned into the matrix at `[4][2]`, wherever
it happens to be located on the keyboard. Mapping from one to the other
(which only matters for defining layouts) is handled elsewhere.
or may not correspond to the physical position of the key: e.g. the key
where `row_4` and `column_2` cross will be scanned into the matrix at
`[4][2]`, wherever it happens to be located on the keyboard. Mapping
from one to the other (which only matters for defining layouts) is
handled elsewhere.
* ADDR (pin15): Set slave address to `0b0100000` by connecting to Vss(GND).
* The user-defined bits are the three least significant
* I2C addresses are 7 bits long (the last bit in the byte is used for
@ -85,10 +86,10 @@
* notes:
* All addresses given for IOCON.BANK = 0, since that's the default value of
the bit, and that's what we'll be using.
* We want the column pins set as output high (hi-Z) without pull-ups
initially, and the row pins set as input with pull-ups. We'll cycle
through driving the column pins low and checking the row pins in the
update function.
* Initially, we want either columns or rows (see <../options.h>) set as
hi-Z without pull-ups, and the other set of pins set as input with
pull-ups. During the update function, we'll cycle through setting the
first set low and checking each pin in the second set.
* abbreviations:
* IODIR = I/O Direction Register

View File

@ -0,0 +1,23 @@
/* ----------------------------------------------------------------------------
* ergoDOX : controller : Teensy 2.0 specific exports : functions
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#ifndef KEYBOARD__ERGODOX__CONTROLLER__TEENSY_2_0__FUNCTIONS_h
#define KEYBOARD__ERGODOX__CONTROLLER__TEENSY_2_0__FUNCTIONS_h
#include <stdbool.h>
#include <stdint.h>
#include "../matrix.h"
// --------------------------------------------------------------------
uint8_t teensy_init(void);
uint8_t teensy_update_matrix( bool matrix[KB_ROWS][KB_COLUMNS] );
#endif

View File

@ -1,5 +1,5 @@
/* ----------------------------------------------------------------------------
* ergoDOX controller: Teensy 2.0 specific exports
* ergoDOX : controller : Teensy 2.0 specific exports : LED control
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
@ -7,48 +7,52 @@
* ------------------------------------------------------------------------- */
#ifndef TEENSY_2_0_h
#define TEENSY_2_0_h
#ifndef KEYBOARD__ERGODOX__CONTROLLER__TEENSY_2_0__LED_h
#define KEYBOARD__ERGODOX__CONTROLLER__TEENSY_2_0__LED_h
#include <stdint.h>
#include <avr/io.h> // for the register macros
#include "lib/data-types.h"
// --------------------------------------------------------------------
#define _kb_led_1_on() (DDRB |= (1<<5))
#define _kb_led_1_off() (DDRB &= ~(1<<5))
#define _kb_led_1_set(n) (OCR1A = (uint8_t)(n))
#define _kb_led_1_set_percent(n) (OCR1A = (uint8_t)((n) * 0xFF))
#define _kb_led_2_on() (DDRB |= (1<<6))
#define _kb_led_2_off() (DDRB &= ~(1<<6))
#define _kb_led_2_set(n) (OCR1B = (uint8_t)(n))
#define _kb_led_2_set_percent(n) (OCR1B = (uint8_t)((n) * 0xFF))
// LED control
#define _kb_led_1_on() (DDRB |= (1<<6))
#define _kb_led_1_off() (DDRB &= ~(1<<6))
#define _kb_led_1_set(n) (OCR1B = (uint8_t)(n))
#define _kb_led_1_set_percent(n) (OCR1B = (uint8_t)((n) * 0xFF))
//
#define _kb_led_2_on() (DDRB |= (1<<5))
#define _kb_led_2_off() (DDRB &= ~(1<<5))
#define _kb_led_2_set(n) (OCR1A = (uint8_t)(n))
#define _kb_led_2_set_percent(n) (OCR1A = (uint8_t)((n) * 0xFF))
//
#define _kb_led_3_on() (DDRB |= (1<<7))
#define _kb_led_3_off() (DDRB &= ~(1<<7))
#define _kb_led_3_set(n) (OCR1C = (uint8_t)(n))
#define _kb_led_3_set_percent(n) (OCR1C = (uint8_t)((n) * 0xFF))
// ---
#define _kb_led_all_on() do { \
_kb_led_1_on(); \
_kb_led_2_on(); \
_kb_led_3_on(); \
} while(0)
#define _kb_led_all_off() do { \
_kb_led_1_off(); \
_kb_led_2_off(); \
_kb_led_3_off(); \
_kb_led_1_off(); \
_kb_led_2_off(); \
_kb_led_3_off(); \
} while(0)
#define _kb_led_all_set(n) do { \
_kb_led_1_set(n); \
_kb_led_2_set(n); \
_kb_led_3_set(n); \
_kb_led_1_set(n); \
_kb_led_2_set(n); \
_kb_led_3_set(n); \
} while(0)
#define _kb_led_all_set_percent(n) do { \
_kb_led_1_set_percent(n); \
_kb_led_2_set_percent(n); \
_kb_led_3_set_percent(n); \
_kb_led_1_set_percent(n); \
_kb_led_2_set_percent(n); \
_kb_led_3_set_percent(n); \
} while(0)
#endif

View File

@ -0,0 +1,234 @@
/* ----------------------------------------------------------------------------
* ergoDOX : controller: Teensy 2.0 specific code
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
// for "lib/twi.h"
#define TWI_FREQ 400000
#include <stdbool.h>
#include <stdint.h>
#include <avr/io.h>
#include <util/delay.h>
#include "../../../lib/twi.h"
#include "../options.h"
#include "../matrix.h"
#include "./teensy-2-0--functions.h"
#include "./teensy-2-0--led.h"
// ----------------------------------------------------------------------------
// check options
#if (TEENSY__DRIVE_ROWS && TEENSY__DRIVE_COLUMNS) \
|| !(TEENSY__DRIVE_ROWS || TEENSY__DRIVE_COLUMNS)
#error "See 'Pin drive direction' in 'options.h'"
#endif
// ----------------------------------------------------------------------------
// processor frequency (from <http://www.pjrc.com/teensy/prescaler.html>)
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
#define CPU_16MHz 0x00
#define CPU_8MHz 0x01
#define CPU_4MHz 0x02
#define CPU_2MHz 0x03
#define CPU_1MHz 0x04
#define CPU_500kHz 0x05
#define CPU_250kHz 0x06
#define CPU_125kHz 0x07
#define CPU_62kHz 0x08
/*
* pin macros
* - note: you can move the `UNUSED`, `ROW`, and `COLUMN` pins around, but be
* sure to keep the set of all the pins listed constant. other pins are not
* movable, and either are referenced explicitly or have macros defined for
* them elsewhere.
* - note: if you change pin assignments, please be sure to update
* "teensy-2-0.md", and the '.svg' circuit diagram.
*/
// --- unused
#define UNUSED_0 C, 7
#define UNUSED_1 D, 7
#define UNUSED_2 D, 4 // hard to use with breadboard (on the end)
#define UNUSED_3 D, 5 // hard to use with breadboard (on the end)
#define UNUSED_4 E, 6 // hard to use with breadboard (internal)
// --- rows
#define ROW_0 F, 7
#define ROW_1 F, 6
#define ROW_2 F, 5
#define ROW_3 F, 4
#define ROW_4 F, 1
#define ROW_5 F, 0
// --- columns
#define COLUMN_7 B, 0
#define COLUMN_8 B, 1
#define COLUMN_9 B, 2
#define COLUMN_A B, 3
#define COLUMN_B D, 2
#define COLUMN_C D, 3
#define COLUMN_D C, 6
// --- helpers
#define SET |=
#define CLEAR &=~
#define _teensypin_write(register, operation, pin_letter, pin_number) \
do { \
((register##pin_letter) operation (1<<(pin_number))); \
_delay_us(1); /* allow pins time to stabilize */ \
} while(0)
#define teensypin_write(register, operation, pin) \
_teensypin_write(register, operation, pin)
#define _teensypin_read(pin_letter, pin_number) \
((PIN##pin_letter) & (1<<(pin_number)))
#define teensypin_read(pin) \
_teensypin_read(pin)
#define teensypin_write_all_unused(register, operation) \
do { \
teensypin_write(register, operation, UNUSED_0); \
teensypin_write(register, operation, UNUSED_1); \
teensypin_write(register, operation, UNUSED_2); \
teensypin_write(register, operation, UNUSED_3); \
teensypin_write(register, operation, UNUSED_4); } \
while(0)
#define teensypin_write_all_row(register, operation) \
do { \
teensypin_write(register, operation, ROW_0); \
teensypin_write(register, operation, ROW_1); \
teensypin_write(register, operation, ROW_2); \
teensypin_write(register, operation, ROW_3); \
teensypin_write(register, operation, ROW_4); \
teensypin_write(register, operation, ROW_5); } \
while(0)
#define teensypin_write_all_column(register, operation) \
do { \
teensypin_write(register, operation, COLUMN_7); \
teensypin_write(register, operation, COLUMN_8); \
teensypin_write(register, operation, COLUMN_9); \
teensypin_write(register, operation, COLUMN_A); \
teensypin_write(register, operation, COLUMN_B); \
teensypin_write(register, operation, COLUMN_C); \
teensypin_write(register, operation, COLUMN_D); } \
while(0)
/*
* update macros
*/
#define update_rows_for_column(matrix, column) \
do { \
/* set column low (set as output) */ \
teensypin_write(DDR, SET, COLUMN_##column); \
/* read rows 0..5 and update matrix */ \
matrix[0x0][0x##column] = ! teensypin_read(ROW_0); \
matrix[0x1][0x##column] = ! teensypin_read(ROW_1); \
matrix[0x2][0x##column] = ! teensypin_read(ROW_2); \
matrix[0x3][0x##column] = ! teensypin_read(ROW_3); \
matrix[0x4][0x##column] = ! teensypin_read(ROW_4); \
matrix[0x5][0x##column] = ! teensypin_read(ROW_5); \
/* set column hi-Z (set as input) */ \
teensypin_write(DDR, CLEAR, COLUMN_##column); \
} while(0)
#define update_columns_for_row(matrix, row) \
do { \
/* set row low (set as output) */ \
teensypin_write(DDR, SET, ROW_##row); \
/* read columns 7..D and update matrix */ \
matrix[0x##row][0x7] = ! teensypin_read(COLUMN_7); \
matrix[0x##row][0x8] = ! teensypin_read(COLUMN_8); \
matrix[0x##row][0x9] = ! teensypin_read(COLUMN_9); \
matrix[0x##row][0xA] = ! teensypin_read(COLUMN_A); \
matrix[0x##row][0xB] = ! teensypin_read(COLUMN_B); \
matrix[0x##row][0xC] = ! teensypin_read(COLUMN_C); \
matrix[0x##row][0xD] = ! teensypin_read(COLUMN_D); \
/* set row hi-Z (set as input) */ \
teensypin_write(DDR, CLEAR, ROW_##row); \
} while(0)
// ----------------------------------------------------------------------------
/* returns
* - success: 0
*/
uint8_t teensy_init(void) {
// CPU speed : should match F_CPU in makefile
#if F_CPU != 16000000
#error "Expecting different CPU frequency"
#endif
CPU_PRESCALE(CPU_16MHz);
// onboard LED
// (tied to GND for hardware convenience)
DDRD &= ~(1<<6); // set D(6) as input
PORTD &= ~(1<<6); // set D(6) internal pull-up disabled
// (tied to Vcc for hardware convenience)
DDRB &= ~(1<<4); // set B(4) as input
PORTB &= ~(1<<4); // set B(4) internal pull-up disabled
// keyboard LEDs (see "PWM on ports OC1(A|B|C)" in "teensy-2-0.md")
_kb_led_all_off(); // (just to put the pins in a known state)
TCCR1A = 0b10101001; // set and configure fast PWM
TCCR1B = 0b00001001; // set and configure fast PWM
// I2C (TWI)
twi_init(); // on pins D(1,0)
// unused pins
teensypin_write_all_unused(DDR, CLEAR); // set as input
teensypin_write_all_unused(PORT, SET); // set internal pull-up enabled
// rows and columns
teensypin_write_all_row(DDR, CLEAR); // set as input (hi-Z)
teensypin_write_all_column(DDR, CLEAR); // set as input (hi-Z)
#if TEENSY__DRIVE_ROWS
teensypin_write_all_row(PORT, CLEAR); // pull-up disabled
teensypin_write_all_column(PORT, SET); // pull-up enabled
#elif TEENSY__DRIVE_COLUMNS
teensypin_write_all_row(PORT, SET); // pull-up enabled
teensypin_write_all_column(PORT, CLEAR); // pull-up disabled
#endif
return 0; // success
}
/* returns
* - success: 0
*/
#if KB_ROWS != 6 || KB_COLUMNS != 14
#error "Expecting different keyboard dimensions"
#endif
uint8_t teensy_update_matrix(bool matrix[KB_ROWS][KB_COLUMNS]) {
#if TEENSY__DRIVE_ROWS
update_columns_for_row(matrix, 0);
update_columns_for_row(matrix, 1);
update_columns_for_row(matrix, 2);
update_columns_for_row(matrix, 3);
update_columns_for_row(matrix, 4);
update_columns_for_row(matrix, 5);
#elif TEENSY__DRIVE_COLUMNS
update_rows_for_column(matrix, 7);
update_rows_for_column(matrix, 8);
update_rows_for_column(matrix, 9);
update_rows_for_column(matrix, A);
update_rows_for_column(matrix, B);
update_rows_for_column(matrix, C);
update_rows_for_column(matrix, D);
#endif
return 0; // success
}

View File

@ -2,8 +2,9 @@
## Pinout and Pin assignments
* `+` indicates pin
* `o` indicates unused pin
* `+` indicates connected pin
* `o` indicates unconnected pin
* `=` is used to list other things the pin is connected to
* `-`s inserted between some of the pin functions for readability
* `OC**` pins enclosed in parenthesis had lines over them in the pinout
@ -28,27 +29,30 @@
### Teensy 2.0 Pin Assignments
power_negative GND +---.....---+ Vcc power_positive
column6 PB0 + + PF0 row0
PB1 o + PF1 row1
PB2 o + PF4 row2
PB3 o o o + PF5 row3
(OC1C) LED3 PB7 + PE6 AREF + PF6 row4
(SCL) I2C PD0 + + PF7 row5
(SDA) I2C PD1 + + PB6 LED1 (OC1B)
column3 PD2 + + PB5 LED2 (OC1A)
column4 PD3 + + PB4 column0
column1 PC6 + + PD7 column5
column2 PC7 +-o-o-o-o-o-+ PD6 onboardLED
column_7 PB0 + + PF0 row_5
column_8 PB1 + + PF1 row_4
column_9 PB2 + + PF4 row_3
column_A PB3 + o o + PF5 row_2
(OC1C) LED_3 PB7 + PE6 AREF + PF6 row_1
(SCL) I2C PD0 + + PF7 row_0
(SDA) I2C PD1 + + PB6 LED_2 (OC1B)
column_B PD2 + + PB5 LED_1 (OC1A)
column_C PD3 + + PB4 = Vcc
column_D PC6 + o PD7
PC7 o-o-o-o-o-o-+ PD6 onboardLED = GND
PD5 --/ | | | \-- PD4
Vcc ----/ | \---- RST
GND-------/
* notes:
* Row and column assignments are to matrix positions, which may or may
correspond to the physical position of the key: e.g. the key where `row4`
and `column2` cross will be scanned into the matrix at `[4][2]`, wherever
it happens to be located on the keyboard. Mapping from one to the other
(which only matters for defining layouts) is handled elsewhere.
or may not correspond to the physical position of the key: e.g. the key
where `row_4` and `column_2` cross will be scanned into the matrix at
`[4][2]`, wherever it happens to be located on the keyboard. Mapping
from one to the other (which only matters for defining layouts) is
handled elsewhere.
* LEDs are labeled using numbers (starting with '1') instead of letters
(starting with 'A') as on the PCB.
* SCL and SDA: Need external pull-up resistors. Sometimes the Teensy
internal pull-ups are enough (see datasheet section 20.5.1), but i think
for this project we'll want external ones. The general recommendation
@ -75,14 +79,16 @@
* PD6 (the onboard LED) already has a defined level (low), so there's no
reason to set internal pull-up enabled on it. If we do, it will source
current to the LED, which is fine, but unnecessary.
* We want the columns to be hi-Z when that column's not being scanned,
drive low when it is, and the rows to be input with pull-up enabled.
We'll cycle through driving the columns low and scanning all rows.
* Initially, we want either columns or rows (see <../options.h>) set as
hi-Z without pull-ups, and the other set of pins set as input with
pull-ups. During the update function, we'll cycle through setting the
first set low and checking each pin in the second set.
* To set a pin hi-Z on this board, set it as input with pull-up
disabled.
* Switching the row pins between hi-Z and drive low (treating them as
if they were open drain) seems just as good as, and a little safer
than, driving them high when the row's not active.
* Switching the driving pins (the first set of pins) between hi-Z and
drive low (treating them as if they were open drain) seems just as
good as, and a little safer than, driving them high when they're not
active.
* We need to delay for at least 1 μs between changing the column pins and
reading the row pins. I would assume this is to allow the pins time to
stabalize.

View File

@ -1,5 +1,5 @@
/* ----------------------------------------------------------------------------
* ergoDOX layout : exports
* ergoDOX : layout exports
*
* Different layouts are included by modifying a variable in the makefile.
* ----------------------------------------------------------------------------
@ -8,121 +8,16 @@
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#ifndef LAYOUT_h
#define LAYOUT_h
#include <avr/pgmspace.h>
#include "lib/data-types.h"
#include "lib/key-functions.h" // for `kbfun_funptr_t`
#ifndef KEYBOARD__ERGODOX__LAYOUT_h
#define KEYBOARD__ERGODOX__LAYOUT_h
#include "matrix.h" // for number of rows and columns
// --------------------------------------------------------------------
// include the appropriate keyboard layout header
// for:
// - possible non-default number of layers
// - possible non-default layout matrix definitions
// - possible non-default layout 'get' and 'set' definitions
#undef _str
#undef _expstr
#undef _inc
#define _str(s) #s // stringify
#define _expstr(s) _str(s) // expand -> stringify
#define _inc _expstr(layout/MAKEFILE_KEYBOARD_LAYOUT.h) // inc(lude)
#include _inc
#undef _str
#undef _expstr
#undef _inc
// default number of layers
#ifndef KB_LAYERS
#define KB_LAYERS 10
#endif
// default layout 'get' macros and `extern` matrix declarations
//
// these are for when the matrices are stored solely in Flash. layouts
// may redefine them if they wish and use RAM, EEPROM, or any
// combination of the three, as long as they maintain the same
// interface.
//
// - if the macro is overridden, the matrix declaration must be too,
// and vice versa.
//
// - 'set' functions are optional, and should be defined in the layout
// specific '.h'. they'll require the use of the EEPROM, possibly in
// clever conjunction with one of the other two memories (since the
// EEPROM is small). custom key functions will also need to be
// written.
//
// - to override these macros with real functions, set the macro equal
// to itself (e.g. `#define kb_layout_get kb_layout_get`) and provide
// function prototypes in the layout specific '.h'
#ifndef kb_layout_get
extern uint8_t PROGMEM \
_kb_layout[KB_LAYERS][KB_ROWS][KB_COLUMNS];
#define kb_layout_get(layer,row,column) \
( (uint8_t) \
pgm_read_byte(&( \
_kb_layout[layer][row][column] )) )
#endif
#ifndef kb_layout_press_get
extern kbfun_funptr_t PROGMEM \
_kb_layout_press[KB_LAYERS][KB_ROWS][KB_COLUMNS];
#define kb_layout_press_get(layer,row,column) \
( (kbfun_funptr_t) \
pgm_read_word(&( \
_kb_layout_press[layer][row][column] )) )
#endif
#ifndef kb_layout_release_get
extern kbfun_funptr_t PROGMEM \
_kb_layout_release[KB_LAYERS][KB_ROWS][KB_COLUMNS];
#define kb_layout_release_get(layer,row,column) \
( (kbfun_funptr_t) \
pgm_read_word(&( \
_kb_layout_release[layer][row][column] )) )
#endif
// default logical LED macros (all defined to nothing)
#ifndef kb_led_num_on
#define kb_led_num_on()
#endif
#ifndef kb_led_num_off
#define kb_led_num_off()
#endif
#ifndef kb_led_caps_on
#define kb_led_caps_on()
#endif
#ifndef kb_led_caps_off
#define kb_led_caps_off()
#endif
#ifndef kb_led_scroll_on
#define kb_led_scroll_on()
#endif
#ifndef kb_led_scroll_off
#define kb_led_scroll_off()
#endif
#ifndef kb_led_compose_on
#define kb_led_compose_on()
#endif
#ifndef kb_led_compose_off
#define kb_led_compose_off()
#endif
#ifndef kb_led_kana_on
#define kb_led_kana_on()
#endif
#ifndef kb_led_kana_off
#define kb_led_kana_off()
#endif
#include "../../lib/variable-include.h"
#define INCLUDE EXP_STR( ./layout/MAKEFILE_KEYBOARD_LAYOUT.h )
#include INCLUDE
#endif

View File

@ -3,33 +3,22 @@
Different layouts are included by modifying a variable in the makefile.
To write a new one:
* You must implement everything defined in [layout.h] (layout.h). Take a look
at existing layouts in the 'layout' subdir.
* Currently, see [qwerty.c] (layout/qwerty.c) and [qwerty.h]
(layout/qwerty.h). The latter is only important if you want more than
one layer. And I still need to write the functions to make that possible
(though that shouldn't be hard, I just haven't gotten to it yet). But
(at least for the QWERTY and Dvorak layouts I'd really like to include)
if you indicate it clealy in the layout, and provide complete
initializations for `kb_layout[][][]`, `kb_layout_press[][][]`, and
`kb_layout_release[][][]`, I'll make sure it gets working.
* The number of layers must be defined in the layout *.h file.
* Create new layout files under [layout] (layout) (see [qwerty.h]
(layout/qwerty.h) and [qwerty.c] (layout/qwerty.c)).
* Use `0` for no-operation (unused) keys, and `NULL` for no-operation (unused)
functions.
* See [matrix.md] (matrix.md) for how the key matrix maps to hardware.
* See [matrix/mapping.h] (matrix/mapping.h) for how the key matrix maps to
hardware.
* See [keyboard-usage-page--short-names.h]
(../../lib/_usb/keyboard-usage-page--short-names.h) for available keycodes.
* See [key-functions.c] (../../lib/_key-functions.c) for what functions keys
* See [key-functions.c] (../../lib/key-functions.c) for what functions keys
can call.
* See [_defaults.h] (layout/_defaults.h) for default function layers and
aliases.
## notes
* Each full layer takes 420 bytes of memory, wherever it's stored. (The matrix
size is 12x7, keycodes are 1 byte each, and function pointers are 2 bytes
each.)
* Each full layer takes 420 bytes of memory (the matrix size is 12x7, keycodes
are 1 byte each, and function pointers are 2 bytes each).
-------------------------------------------------------------------------------

View File

@ -0,0 +1,86 @@
/* ----------------------------------------------------------------------------
* ergoDOX : layout : default LED control
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#ifndef KEYBOARD__ERGODOX__LAYOUT__DEFAULT__LED_CONTROL_h
#define KEYBOARD__ERGODOX__LAYOUT__DEFAULT__LED_CONTROL_h
// --------------------------------------------------------------------
/*
* state and delay macros
*/
#ifndef kb_led_state_power_on
#define kb_led_state_power_on() do { \
_kb_led_all_set_percent(MAKEFILE_LED_BRIGHTNESS/10); \
_kb_led_all_on(); \
} while(0)
#endif
// note: need to delay for a total of ~1 second
#ifndef kb_led_delay_usb_init
#define kb_led_delay_usb_init() do { \
_kb_led_1_set_percent(MAKEFILE_LED_BRIGHTNESS); \
_delay_ms(333); \
_kb_led_2_set_percent(MAKEFILE_LED_BRIGHTNESS); \
_delay_ms(333); \
_kb_led_3_set_percent(MAKEFILE_LED_BRIGHTNESS); \
_delay_ms(333); \
} while(0)
#endif
#ifndef kb_led_state_ready
#define kb_led_state_ready() do { \
_kb_led_all_off(); \
_kb_led_all_set_percent(MAKEFILE_LED_BRIGHTNESS); \
} while(0)
#endif
/*
* logical LED macros
* - unused macros should be defined to nothing
* - they all are here, because they really need to be specified in
* the layout specific file
*/
#ifndef kb_led_num_on
#define kb_led_num_on()
#endif
#ifndef kb_led_num_off
#define kb_led_num_off()
#endif
#ifndef kb_led_caps_on
#define kb_led_caps_on()
#endif
#ifndef kb_led_caps_off
#define kb_led_caps_off()
#endif
#ifndef kb_led_scroll_on
#define kb_led_scroll_on()
#endif
#ifndef kb_led_scroll_off
#define kb_led_scroll_off()
#endif
#ifndef kb_led_compose_on
#define kb_led_compose_on()
#endif
#ifndef kb_led_compose_off
#define kb_led_compose_off()
#endif
#ifndef kb_led_kana_on
#define kb_led_kana_on()
#endif
#ifndef kb_led_kana_off
#define kb_led_kana_off()
#endif
#endif

View File

@ -0,0 +1,81 @@
/* ----------------------------------------------------------------------------
* ergoDOX : layout : default matrix control
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#ifndef KEYBOARD__ERGODOX__LAYOUT__DEFAULT__MATRIX_CONTROL_h
#define KEYBOARD__ERGODOX__LAYOUT__DEFAULT__MATRIX_CONTROL_h
#include <stdint.h>
#include <avr/pgmspace.h>
#include "../../../lib/data-types/misc.h"
#include "../../../lib/key-functions/public.h"
#include "../matrix.h"
// --------------------------------------------------------------------
#ifndef KB_LAYERS
#define KB_LAYERS 10
#endif
// --------------------------------------------------------------------
/*
* matrix 'get' macros, and `extern` matrix declarations
*
* These are written for when the matrices are stored solely in Flash.
* Layouts may redefine them if they wish and use Flash, RAM, EEPROM,
* or any combination of the three, as long as they maintain the same
* interface.
*
* - If the macro is overridden, the matrix declaration must be too,
* and vice versa.
*
* - 'set' functions are optional, and should be defined in the layout
* specific '.h'. They'll require the use of the EEPROM, possibly in
* clever conjunction with one of the other two memories (since the
* EEPROM is small). Custom key functions will also need to be
* written.
*
* - To override these macros with real functions, set the macro equal
* to itself (e.g. `#define kb_layout_get kb_layout_get`) and provide
* function prototypes, in the layout specific '.h'
*/
#ifndef kb_layout_get
extern const uint8_t PROGMEM \
_kb_layout[KB_LAYERS][KB_ROWS][KB_COLUMNS];
#define kb_layout_get(layer,row,column) \
( (uint8_t) \
pgm_read_byte(&( \
_kb_layout[layer][row][column] )) )
#endif
#ifndef kb_layout_press_get
extern const void_funptr_t PROGMEM \
_kb_layout_press[KB_LAYERS][KB_ROWS][KB_COLUMNS];
#define kb_layout_press_get(layer,row,column) \
( (void_funptr_t) \
pgm_read_word(&( \
_kb_layout_press[layer][row][column] )) )
#endif
#ifndef kb_layout_release_get
extern const void_funptr_t PROGMEM \
_kb_layout_release[KB_LAYERS][KB_ROWS][KB_COLUMNS];
#define kb_layout_release_get(layer,row,column) \
( (void_funptr_t) \
pgm_read_word(&( \
_kb_layout_release[layer][row][column] )) )
#endif
#endif

View File

@ -0,0 +1,371 @@
/* ----------------------------------------------------------------------------
* ergoDOX layout : QWERTY (modified from the Kinesis layout)
* TODO: rewrite for new kbfun's
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#include <stdint.h>
#include <stddef.h>
#include <avr/pgmspace.h>
#include "../../../lib/data-types/misc.h"
#include "../../../lib/usb/usage-page/keyboard--short-names.h"
#include "../../../lib/key-functions/public.h"
#include "../matrix.h"
#include "../layout.h"
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
const uint8_t PROGMEM _kb_layout[KB_LAYERS][KB_ROWS][KB_COLUMNS] = {
KB_MATRIX_LAYER( // layout: layer 0: default
// unused
0,
// left hand
_equal, _1, _2, _3, _4, _5, _esc,
_backslash, _quote, _comma, _period, _P, _Y, 1,
_tab, _A, _O, _E, _U, _I,
_shiftL, _semicolon, _Q, _J, _K, _X, 1,
_guiL, _grave, _backslash, _arrowL, _arrowR,
_bs, 0,
_del, 0, _ctrlL,
_end, _home, _altL,
// right hand
3, _6, _7, _8, _9, _0, _dash,
_bracketL, _F, _G, _C, _R, _L, _bracketR,
_D, _H, _T, _N, _S, _slash,
1, _B, _M, _W, _V, _Z, _shiftR,
_arrowL, _arrowD, _arrowU, _arrowR, _guiR,
0, _space,
_ctrlR, 0, _enter,
_altR, _pageU, _pageD ),
KB_MATRIX_LAYER( // layout: layer 1: function and symbol keys
// unused
0,
// left hand
0, _F1, _F2, _F3, _F4, _F5, _F11,
0, _bracketL, _bracketR, _bracketL, _bracketR, 0, 1,
0, _semicolon, _slash, _dash, _0_kp,_semicolon,
0, _6_kp, _7_kp, _8_kp, _9_kp, _equal, 2,
0, 0, 0, 0, 0,
0, 0,
0, 0, 0,
0, 0, 0,
// right hand
_F12, _F6, _F7, _F8, _F9, _F10, _power,
0, 0, _dash, _comma, _period,_currencyUnit, _volumeU,
_backslash, _1_kp, _9, _0, _equal, _volumeD,
2, _8, _2_kp, _3_kp, _4_kp, _5_kp, _mute,
0, 0, 0, 0, 0,
0, 0,
0, 0, 0,
0, 0, 0 ),
KB_MATRIX_LAYER( // layout: layer 2: keyboard functions
// unused
0,
// left hand
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0,
0, 0, 0,
0, 0, 0,
// right hand
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0,
0, 0, 0,
0, 0, 0 ),
KB_MATRIX_LAYER( // layout: layer 3: numpad
// unused
0,
// left hand
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, _insert, 0, 0, 0,
0, 0,
0, 0, 0,
0, 0, 0,
// right hand
3, 0, 3, _equal_kp, _div_kp, _mul_kp, 0,
0, 0, _7_kp, _8_kp, _9_kp, _sub_kp, 0,
0, _4_kp, _5_kp, _6_kp, _add_kp, 0,
0, 0, _1_kp, _2_kp, _3_kp, _enter_kp, 0,
0, 0, _dec_kp, _enter_kp, 0,
0, _0_kp,
0, 0, 0,
0, 0, 0 ),
};
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// aliases
// basic
#define kprrel &kbfun_press_release
#define ktog &kbfun_toggle
#define ktrans &kbfun_transparent
// --- layer push/pop functions
#define lpush1 &kbfun_layer_push_1
#define lpush2 &kbfun_layer_push_2
#define lpush3 &kbfun_layer_push_3
#define lpush4 &kbfun_layer_push_4
#define lpush5 &kbfun_layer_push_5
#define lpush6 &kbfun_layer_push_6
#define lpush7 &kbfun_layer_push_7
#define lpush8 &kbfun_layer_push_8
#define lpush9 &kbfun_layer_push_9
#define lpush10 &kbfun_layer_push_10
#define lpop1 &kbfun_layer_pop_1
#define lpop2 &kbfun_layer_pop_2
#define lpop3 &kbfun_layer_pop_3
#define lpop4 &kbfun_layer_pop_4
#define lpop5 &kbfun_layer_pop_5
#define lpop6 &kbfun_layer_pop_6
#define lpop7 &kbfun_layer_pop_7
#define lpop8 &kbfun_layer_pop_8
#define lpop9 &kbfun_layer_pop_9
#define lpop10 &kbfun_layer_pop_10
// ---
// device
#define dbtldr &kbfun_jump_to_bootloader
// special
#define sshprre &kbfun_shift_press_release
#define s2kcap &kbfun_2_keys_capslock_press_release
#define slpunum &kbfun_layer_push_numpad
#define slponum &kbfun_layer_pop_numpad
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
const void_funptr_t PROGMEM _kb_layout_press[KB_LAYERS][KB_ROWS][KB_COLUMNS] = {
KB_MATRIX_LAYER( // press: layer 0: default
// unused
NULL,
// left hand
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel, lpush1,
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
s2kcap, kprrel, kprrel, kprrel, kprrel, kprrel, lpush1,
kprrel, kprrel, kprrel, kprrel, kprrel,
kprrel, NULL,
kprrel, NULL, kprrel,
kprrel, kprrel, kprrel,
// right hand
slpunum, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
lpush1, kprrel, kprrel, kprrel, kprrel, kprrel, s2kcap,
kprrel, kprrel, kprrel, kprrel, kprrel,
NULL, kprrel,
kprrel, NULL, kprrel,
kprrel, kprrel, kprrel ),
KB_MATRIX_LAYER( // press: layer 1: function and symbol keys
// unused
NULL,
// left hand
NULL, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
ktrans,sshprre,sshprre, kprrel, kprrel, NULL, lpop1,
ktrans, kprrel, kprrel, kprrel, kprrel,sshprre,
ktrans, kprrel, kprrel, kprrel, kprrel,sshprre, lpush2,
ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans,
ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans,
// right hand
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
ktrans, NULL, kprrel,sshprre,sshprre, kprrel, kprrel,
kprrel, kprrel,sshprre,sshprre,sshprre, kprrel,
lpush2,sshprre, kprrel, kprrel, kprrel, kprrel, kprrel,
ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans,
ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans ),
KB_MATRIX_LAYER( // press: layer 2: keyboard functions
// unused
NULL,
// left hand
dbtldr, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
// right hand
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL ),
KB_MATRIX_LAYER( // press: layer 3: numpad
// unused
NULL,
// left hand
ktrans, ktrans, ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, kprrel, ktrans, ktrans, ktrans,
ktrans, ktrans,
ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans,
// right hand
slponum, ktrans,slponum, kprrel, kprrel, kprrel, ktrans,
ktrans, ktrans, kprrel, kprrel, kprrel, kprrel, ktrans,
ktrans, kprrel, kprrel, kprrel, kprrel, ktrans,
ktrans, ktrans, kprrel, kprrel, kprrel, kprrel, ktrans,
ktrans, ktrans, kprrel, kprrel, ktrans,
ktrans, kprrel,
ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans ),
};
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
const void_funptr_t PROGMEM _kb_layout_release[KB_LAYERS][KB_ROWS][KB_COLUMNS] = {
KB_MATRIX_LAYER( // release: layer 0: default
// unused
NULL,
// left hand
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel, NULL,
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
s2kcap, kprrel, kprrel, kprrel, kprrel, kprrel, lpop1,
kprrel, kprrel, kprrel, kprrel, kprrel,
kprrel, NULL,
kprrel, NULL, kprrel,
kprrel, kprrel, kprrel,
// right hand
NULL, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
lpop1, kprrel, kprrel, kprrel, kprrel, kprrel, s2kcap,
kprrel, kprrel, kprrel, kprrel, kprrel,
NULL, kprrel,
kprrel, NULL, kprrel,
kprrel, kprrel, kprrel ),
KB_MATRIX_LAYER( // release: layer 1: function and symbol keys
// unused
NULL,
// left hand
NULL, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
ktrans,sshprre,sshprre, kprrel, kprrel, NULL, NULL,
ktrans, kprrel, kprrel, kprrel, kprrel,sshprre,
ktrans, kprrel, kprrel, kprrel, kprrel,sshprre, lpop2,
ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans,
ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans,
// right hand
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
ktrans, NULL, kprrel,sshprre,sshprre, kprrel, kprrel,
kprrel, kprrel,sshprre,sshprre,sshprre, kprrel,
lpop2,sshprre, kprrel, kprrel, kprrel, kprrel, kprrel,
ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans,
ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans ),
KB_MATRIX_LAYER( // release: layer 2: keyboard functions
// unused
NULL,
// left hand
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
// right hand
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL ),
KB_MATRIX_LAYER( // release: layer 3: numpad
// unused
NULL,
// left hand
ktrans, ktrans, ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, kprrel, ktrans, ktrans, ktrans,
ktrans, ktrans,
ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans,
// right hand
NULL, ktrans, NULL, kprrel, kprrel, kprrel, ktrans,
ktrans, ktrans, kprrel, kprrel, kprrel, kprrel, ktrans,
ktrans, kprrel, kprrel, kprrel, kprrel, ktrans,
ktrans, ktrans, kprrel, kprrel, kprrel, kprrel, ktrans,
ktrans, ktrans, kprrel, kprrel, ktrans,
ktrans, kprrel,
ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans ),
KB_MATRIX_LAYER( // release: layer 3: nothing (just making sure unused
// functions don't get compiled out)
// unused
NULL,
// other
kprrel, lpush8, lpop8, NULL, NULL, NULL, NULL, NULL,
ktog, lpush9, lpop9, NULL, NULL, NULL, NULL, NULL,
ktrans,lpush10, lpop10, NULL, NULL, NULL, NULL, NULL,
lpush1, lpop1, NULL, NULL, NULL, NULL, NULL, NULL,
lpush2, lpop2, dbtldr, NULL, NULL, NULL, NULL, NULL,
lpush3, lpop3, NULL, NULL, NULL, NULL, NULL, NULL,
lpush4, lpop4, s2kcap, NULL, NULL, NULL, NULL, NULL,
lpush5, lpop5,slpunum, NULL, NULL, NULL, NULL, NULL,
lpush6, lpop6,slponum, NULL, NULL, NULL, NULL, NULL,
lpush7, lpop7, NULL, NULL, NULL, NULL, NULL, NULL )
};

View File

@ -1,5 +1,5 @@
/* ----------------------------------------------------------------------------
* ergoDOX layout : QWERTY : exports
* ergoDOX : layout : Dvorak : exports
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
@ -7,11 +7,12 @@
* ------------------------------------------------------------------------- */
#ifndef LAYOUT_QWERTY_h
#define LAYOUT_QWERTY_h
#ifndef KEYBOARD__ERGODOX__LAYOUT__DVORAK_h
#define KEYBOARD__ERGODOX__LAYOUT__DVORAK_h
#include "../led.h"
#include "../controller.h"
// --------------------------------------------------------------------
#define kb_led_num_on() _kb_led_1_on()
#define kb_led_num_off() _kb_led_1_off()
@ -20,5 +21,10 @@
#define kb_led_scroll_on() _kb_led_3_on()
#define kb_led_scroll_off() _kb_led_3_off()
// --------------------------------------------------------------------
#include "./default--led-control.h"
#include "./default--matrix-control.h"
#endif

View File

@ -0,0 +1,371 @@
/* ----------------------------------------------------------------------------
* ergoDOX layout : QWERTY (modified from the Kinesis layout)
* TODO: rewrite for new kbfun's
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#include <stdint.h>
#include <stddef.h>
#include <avr/pgmspace.h>
#include "../../../lib/data-types/misc.h"
#include "../../../lib/usb/usage-page/keyboard--short-names.h"
#include "../../../lib/key-functions/public.h"
#include "../matrix.h"
#include "../layout.h"
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
const uint8_t PROGMEM _kb_layout[KB_LAYERS][KB_ROWS][KB_COLUMNS] = {
KB_MATRIX_LAYER( // layout: layer 0: default
// unused
0,
// left hand
_equal, _1, _2, _3, _4, _5, _esc,
_backslash, _Q, _W, _E, _R, _T, 1,
_tab, _A, _S, _D, _F, _G,
_shiftL, _Z, _X, _C, _V, _B, 1,
_guiL, _grave, _backslash, _arrowL, _arrowR,
_bs, 0,
_del, 0, _ctrlL,
_end, _home, _altL,
// right hand
3, _6, _7, _8, _9, _0, _dash,
_bracketL, _Y, _U, _I, _O, _P, _bracketR,
_H, _J, _K, _L, _semicolon, _quote,
1, _N, _M, _comma, _period, _slash, _shiftR,
_arrowL, _arrowD, _arrowU, _arrowR, _guiR,
0, _space,
_ctrlR, 0, _enter,
_altR, _pageU, _pageD ),
KB_MATRIX_LAYER( // layout: layer 1: function and symbol keys
// unused
0,
// left hand
0, _F1, _F2, _F3, _F4, _F5, _F11,
0, _bracketL, _bracketR, _bracketL, _bracketR, 0, 1,
0, _semicolon, _slash, _dash, _0_kp,_semicolon,
0, _6_kp, _7_kp, _8_kp, _9_kp, _equal, 2,
0, 0, 0, 0, 0,
0, 0,
0, 0, 0,
0, 0, 0,
// right hand
_F12, _F6, _F7, _F8, _F9, _F10, _power,
0, 0, _dash, _comma, _period,_currencyUnit, _volumeU,
_backslash, _1_kp, _9, _0, _equal, _volumeD,
2, _8, _2_kp, _3_kp, _4_kp, _5_kp, _mute,
0, 0, 0, 0, 0,
0, 0,
0, 0, 0,
0, 0, 0 ),
KB_MATRIX_LAYER( // layout: layer 2: keyboard functions
// unused
0,
// left hand
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0,
0, 0, 0,
0, 0, 0,
// right hand
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0,
0, 0, 0,
0, 0, 0 ),
KB_MATRIX_LAYER( // layout: layer 3: numpad
// unused
0,
// left hand
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, _insert, 0, 0, 0,
0, 0,
0, 0, 0,
0, 0, 0,
// right hand
3, 0, 3, _equal_kp, _div_kp, _mul_kp, 0,
0, 0, _7_kp, _8_kp, _9_kp, _sub_kp, 0,
0, _4_kp, _5_kp, _6_kp, _add_kp, 0,
0, 0, _1_kp, _2_kp, _3_kp, _enter_kp, 0,
0, 0, _dec_kp, _enter_kp, 0,
0, _0_kp,
0, 0, 0,
0, 0, 0 ),
};
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
// aliases
// basic
#define kprrel &kbfun_press_release
#define ktog &kbfun_toggle
#define ktrans &kbfun_transparent
// --- layer push/pop functions
#define lpush1 &kbfun_layer_push_1
#define lpush2 &kbfun_layer_push_2
#define lpush3 &kbfun_layer_push_3
#define lpush4 &kbfun_layer_push_4
#define lpush5 &kbfun_layer_push_5
#define lpush6 &kbfun_layer_push_6
#define lpush7 &kbfun_layer_push_7
#define lpush8 &kbfun_layer_push_8
#define lpush9 &kbfun_layer_push_9
#define lpush10 &kbfun_layer_push_10
#define lpop1 &kbfun_layer_pop_1
#define lpop2 &kbfun_layer_pop_2
#define lpop3 &kbfun_layer_pop_3
#define lpop4 &kbfun_layer_pop_4
#define lpop5 &kbfun_layer_pop_5
#define lpop6 &kbfun_layer_pop_6
#define lpop7 &kbfun_layer_pop_7
#define lpop8 &kbfun_layer_pop_8
#define lpop9 &kbfun_layer_pop_9
#define lpop10 &kbfun_layer_pop_10
// ---
// device
#define dbtldr &kbfun_jump_to_bootloader
// special
#define sshprre &kbfun_shift_press_release
#define s2kcap &kbfun_2_keys_capslock_press_release
#define slpunum &kbfun_layer_push_numpad
#define slponum &kbfun_layer_pop_numpad
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
const void_funptr_t PROGMEM _kb_layout_press[KB_LAYERS][KB_ROWS][KB_COLUMNS] = {
KB_MATRIX_LAYER( // press: layer 0: default
// unused
NULL,
// left hand
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel, lpush1,
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
s2kcap, kprrel, kprrel, kprrel, kprrel, kprrel, lpush1,
kprrel, kprrel, kprrel, kprrel, kprrel,
kprrel, NULL,
kprrel, NULL, kprrel,
kprrel, kprrel, kprrel,
// right hand
slpunum, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
lpush1, kprrel, kprrel, kprrel, kprrel, kprrel, s2kcap,
kprrel, kprrel, kprrel, kprrel, kprrel,
NULL, kprrel,
kprrel, NULL, kprrel,
kprrel, kprrel, kprrel ),
KB_MATRIX_LAYER( // press: layer 1: function and symbol keys
// unused
NULL,
// left hand
NULL, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
ktrans,sshprre,sshprre, kprrel, kprrel, NULL, lpop1,
ktrans, kprrel, kprrel, kprrel, kprrel,sshprre,
ktrans, kprrel, kprrel, kprrel, kprrel,sshprre, lpush2,
ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans,
ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans,
// right hand
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
ktrans, NULL, kprrel,sshprre,sshprre, kprrel, kprrel,
kprrel, kprrel,sshprre,sshprre,sshprre, kprrel,
lpush2,sshprre, kprrel, kprrel, kprrel, kprrel, kprrel,
ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans,
ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans ),
KB_MATRIX_LAYER( // press: layer 2: keyboard functions
// unused
NULL,
// left hand
dbtldr, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
// right hand
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL ),
KB_MATRIX_LAYER( // press: layer 3: numpad
// unused
NULL,
// left hand
ktrans, ktrans, ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, kprrel, ktrans, ktrans, ktrans,
ktrans, ktrans,
ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans,
// right hand
slponum, ktrans,slponum, kprrel, kprrel, kprrel, ktrans,
ktrans, ktrans, kprrel, kprrel, kprrel, kprrel, ktrans,
ktrans, kprrel, kprrel, kprrel, kprrel, ktrans,
ktrans, ktrans, kprrel, kprrel, kprrel, kprrel, ktrans,
ktrans, ktrans, kprrel, kprrel, ktrans,
ktrans, kprrel,
ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans ),
};
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------
const void_funptr_t PROGMEM _kb_layout_release[KB_LAYERS][KB_ROWS][KB_COLUMNS] = {
KB_MATRIX_LAYER( // release: layer 0: default
// unused
NULL,
// left hand
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel, NULL,
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
s2kcap, kprrel, kprrel, kprrel, kprrel, kprrel, lpop1,
kprrel, kprrel, kprrel, kprrel, kprrel,
kprrel, NULL,
kprrel, NULL, kprrel,
kprrel, kprrel, kprrel,
// right hand
NULL, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
lpop1, kprrel, kprrel, kprrel, kprrel, kprrel, s2kcap,
kprrel, kprrel, kprrel, kprrel, kprrel,
NULL, kprrel,
kprrel, NULL, kprrel,
kprrel, kprrel, kprrel ),
KB_MATRIX_LAYER( // release: layer 1: function and symbol keys
// unused
NULL,
// left hand
NULL, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
ktrans,sshprre,sshprre, kprrel, kprrel, NULL, NULL,
ktrans, kprrel, kprrel, kprrel, kprrel,sshprre,
ktrans, kprrel, kprrel, kprrel, kprrel,sshprre, lpop2,
ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans,
ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans,
// right hand
kprrel, kprrel, kprrel, kprrel, kprrel, kprrel, kprrel,
ktrans, NULL, kprrel,sshprre,sshprre, kprrel, kprrel,
kprrel, kprrel,sshprre,sshprre,sshprre, kprrel,
lpop2,sshprre, kprrel, kprrel, kprrel, kprrel, kprrel,
ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans,
ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans ),
KB_MATRIX_LAYER( // release: layer 2: keyboard functions
// unused
NULL,
// left hand
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL,
// right hand
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL, NULL,
NULL, NULL, NULL,
NULL, NULL, NULL ),
KB_MATRIX_LAYER( // release: layer 3: numpad
// unused
NULL,
// left hand
ktrans, ktrans, ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans, ktrans, ktrans, ktrans, ktrans,
ktrans, kprrel, ktrans, ktrans, ktrans,
ktrans, ktrans,
ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans,
// right hand
NULL, ktrans, NULL, kprrel, kprrel, kprrel, ktrans,
ktrans, ktrans, kprrel, kprrel, kprrel, kprrel, ktrans,
ktrans, kprrel, kprrel, kprrel, kprrel, ktrans,
ktrans, ktrans, kprrel, kprrel, kprrel, kprrel, ktrans,
ktrans, ktrans, kprrel, kprrel, ktrans,
ktrans, kprrel,
ktrans, ktrans, ktrans,
ktrans, ktrans, ktrans ),
KB_MATRIX_LAYER( // release: layer 3: nothing (just making sure unused
// functions don't get compiled out)
// unused
NULL,
// other
kprrel, lpush8, lpop8, NULL, NULL, NULL, NULL, NULL,
ktog, lpush9, lpop9, NULL, NULL, NULL, NULL, NULL,
ktrans,lpush10, lpop10, NULL, NULL, NULL, NULL, NULL,
lpush1, lpop1, NULL, NULL, NULL, NULL, NULL, NULL,
lpush2, lpop2, dbtldr, NULL, NULL, NULL, NULL, NULL,
lpush3, lpop3, NULL, NULL, NULL, NULL, NULL, NULL,
lpush4, lpop4, s2kcap, NULL, NULL, NULL, NULL, NULL,
lpush5, lpop5,slpunum, NULL, NULL, NULL, NULL, NULL,
lpush6, lpop6,slponum, NULL, NULL, NULL, NULL, NULL,
lpush7, lpop7, NULL, NULL, NULL, NULL, NULL, NULL )
};

View File

@ -0,0 +1,30 @@
/* ----------------------------------------------------------------------------
* ergoDOX : layout : QWERTY : exports
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#ifndef KEYBOARD__ERGODOX__LAYOUT__QWERTY_h
#define KEYBOARD__ERGODOX__LAYOUT__QWERTY_h
#include "../controller.h"
// --------------------------------------------------------------------
#define kb_led_num_on() _kb_led_1_on()
#define kb_led_num_off() _kb_led_1_off()
#define kb_led_caps_on() _kb_led_2_on()
#define kb_led_caps_off() _kb_led_2_off()
#define kb_led_scroll_on() _kb_led_3_on()
#define kb_led_scroll_off() _kb_led_3_off()
// --------------------------------------------------------------------
#include "./default--led-control.h"
#include "./default--matrix-control.h"
#endif

View File

@ -1,265 +0,0 @@
/* ----------------------------------------------------------------------------
* ergoDOX layout : QWERTY
*
* This is an overly basic implementation. It needs to be replaced.
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#include <avr/pgmspace.h>
#include "lib/data-types.h"
#include "lib/usb/usage-page/keyboard--short-names.h"
#include "lib/key-functions.h"
#include "../matrix.h"
#include "../layout.h"
// aliases
#define f_prrel &kbfun_press_release
#define f_toggl &kbfun_toggle
#define f_l_inc &kbfun_layer_inc
#define f_l_dec &kbfun_layer_dec
#define f_l_iex &kbfun_layer_inc_exec
#define f_l_dex &kbfun_layer_dec_exec
#define f_2kcap &kbfun_2_keys_capslock_press_release
#define f_np_to &kbfun_layermask_numpad_toggle
#define f_np_on &kbfun_layermask_numpad_on
#define f_np_of &kbfun_layermask_numpad_off
#define f_btldr &kbfun_jump_to_bootloader
uint8_t PROGMEM _kb_layout[KB_LAYERS][KB_ROWS][KB_COLUMNS] = {
// ----------------------------------------------------------------------------
MATRIX_LAYER( // layer 0: default
// unused
0,
// left hand
_grave, _1, _2, _3, _4, _5, _equal,
_bracketL, _Q, _W, _E, _R, _T, _esc,
_tab, _A, _S, _D, _F, _G,
_shiftL, _Z, _X, _C, _V, _B, 1,
_guiL, _arrowL, _arrowU, _arrowD, _arrowR,
_bs,
_del, _ctrlL,
_end, _home, _altL,
// right hand
_backslash, _6, _7, _8, _9, _0, _dash,
_bracketL, _Y, _U, _I, _O, _P, _bracketR,
_H, _J, _K, _L, _semicolon, _quote,
1, _N, _M, _comma, _period, _slash, _shiftR,
_arrowL, _arrowD, _arrowU, _arrowR, _guiR,
_space,
_ctrlR, _enter,
_altR, _pageU, _pageD ),
// ----------------------------------------------------------------------------
MATRIX_LAYER( // layer 1: function and symbol keys
// unused
0,
// left hand
-1, _F1, _F2, _F3, _F4, _F5, _F11,
0, _braceL_kp, _braceR_kp, _bracketL, _bracketR, 0, _esc,
0, _semicolon, _slash, _dash, 0, _colon_kp,
2, 0, 0, 0, 0, 0, 0,
0, _arrowL, _arrowU, _arrowD, _arrowR,
_bs,
_del, _ctrlL,
_end, _home, _altL,
// right hand
_F12, _F6, _F7, _F8, _F9, _F10, 0,
2, 0, _dash, _lt_kp, _gt_kp, _currencyUnit, 0,
_backslash, 0, _parenL_kp, _parenR_kp, _equal, 0,
0, _mul_kp, 0, 0, 0, 0, 0,
_arrowL, _arrowD, _arrowU, _arrowR, 0,
_space,
_ctrlR, _enter,
_altR, _pageU, _pageD ),
// ----------------------------------------------------------------------------
MATRIX_LAYER( // layer 2: numpad
// unused
0,
// left hand
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0,
0, 0,
0, 0, 0,
// right hand
//------- ------- ------- ------- ------- ------- -------
0, 0, _7_kp, _8_kp, _9_kp, _div_kp, 0,
0, 0, _4_kp, _5_kp, _6_kp, _mul_kp, 0,
0, _1_kp, _2_kp, _3_kp, _sub_kp, 0,
0, 0, _0_kp, _period, 0, _add_kp, 0,
0, 0, 0, 0, 0,
0,
0, 0,
0, 0, 0 )
// ----------------------------------------------------------------------------
};
kbfun_funptr_t PROGMEM _kb_layout_press[KB_LAYERS][KB_ROWS][KB_COLUMNS] = {
// ----------------------------------------------------------------------------
MATRIX_LAYER( // layer 0: default
// unused
NULL,
// left hand
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_2kcap,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_l_inc,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,
f_prrel, f_prrel,
f_prrel,f_prrel,f_prrel,
// right hand
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_l_inc,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_2kcap,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,
f_prrel, f_prrel,
f_prrel,f_prrel,f_prrel ),
// ----------------------------------------------------------------------------
MATRIX_LAYER( // layer 1: function and symbol keys
// unused
NULL,
// left hand
f_btldr,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_np_on,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel, NULL,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,
f_prrel, f_prrel,
f_prrel,f_prrel,f_prrel,
// right hand
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_np_to,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
NULL,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,
f_prrel, f_prrel,
f_prrel,f_prrel,f_prrel ),
// ----------------------------------------------------------------------------
MATRIX_LAYER( // layer 2: numpad
// unused
NULL,
// left hand
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL,
NULL, NULL,
NULL, NULL, NULL,
// right hand
NULL, NULL,f_prrel,f_prrel,f_prrel,f_prrel, NULL,
NULL, NULL,f_prrel,f_prrel,f_prrel,f_prrel, NULL,
NULL,f_prrel,f_prrel,f_prrel,f_prrel, NULL,
NULL, NULL,f_prrel,f_prrel,f_prrel,f_prrel, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL,
NULL, NULL,
NULL, NULL, NULL )
// ----------------------------------------------------------------------------
};
kbfun_funptr_t PROGMEM _kb_layout_release[KB_LAYERS][KB_ROWS][KB_COLUMNS] = {
// ----------------------------------------------------------------------------
MATRIX_LAYER( // layer 0: default
// unused
NULL,
// left hand
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_2kcap,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_l_dec,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,
f_prrel, f_prrel,
f_prrel,f_prrel,f_prrel,
// right hand
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_l_dec,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_2kcap,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,
f_prrel, f_prrel,
f_prrel,f_prrel,f_prrel ),
// ----------------------------------------------------------------------------
MATRIX_LAYER( // layer 1: function and symbol keys
// unused
NULL,
// left hand
NULL,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_np_of,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel, NULL,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,
f_prrel, f_prrel,
f_prrel,f_prrel,f_prrel,
// right hand
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
NULL,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
NULL,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,f_prrel,f_prrel,f_prrel,f_prrel,
f_prrel,
f_prrel, f_prrel,
f_prrel,f_prrel,f_prrel ),
// ----------------------------------------------------------------------------
MATRIX_LAYER( // layer 2: numpad
// unused
NULL,
// left hand
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL,
NULL, NULL,
NULL, NULL, NULL,
// right hand
NULL, NULL,f_prrel,f_prrel,f_prrel,f_prrel, NULL,
NULL, NULL,f_prrel,f_prrel,f_prrel,f_prrel, NULL,
NULL,f_prrel,f_prrel,f_prrel,f_prrel, NULL,
NULL, NULL,f_prrel,f_prrel,f_prrel,f_prrel, NULL,
NULL, NULL, NULL, NULL, NULL,
NULL,
NULL, NULL,
NULL, NULL, NULL ),
// ----------------------------------------------------------------------------
MATRIX_LAYER( // layer 3: nothing (just making sure unused functions
// don't get compiled out)
// unused
NULL,
// other
f_prrel, NULL, NULL, NULL, NULL, NULL, NULL,
f_toggl, NULL, NULL, NULL, NULL, NULL, NULL,
f_l_inc, NULL, NULL, NULL, NULL, NULL, NULL,
f_l_dec, NULL, NULL, NULL, NULL, NULL, NULL,
f_l_iex, NULL, NULL, NULL, NULL, NULL, NULL,
f_l_dex, NULL, NULL, NULL, NULL, NULL, NULL,
f_2kcap, NULL, NULL, NULL, NULL, NULL, NULL,
f_np_to, NULL, NULL, NULL, NULL, NULL, NULL,
f_np_on, NULL, NULL, NULL, NULL, NULL, NULL,
f_np_of, NULL, NULL, NULL, NULL, NULL, NULL,
f_btldr, NULL, NULL, NULL, NULL, NULL )
// ----------------------------------------------------------------------------
};

View File

@ -1,46 +0,0 @@
/* ----------------------------------------------------------------------------
* led stuff that isn't microprocessor or layout specific
*
* you should also include this file for low-level led macros, as it will
* always include the file(s) containing those
*
* - low level LED macros (that have to be shared, but aren't really public)
* should all start with '_kb_led_'
* - public LED macros should start with 'kb_led_'
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#ifndef LED_h
#define LED_h
#include <util/delay.h>
#include "teensy-2-0.h" // for low-level led macros
#define kb_led_state_power_on() do { \
_kb_led_all_set_percent(0.05); \
_kb_led_all_on(); \
} while(0)
// note: need to delay for a total of ~1 second
#define kb_led_delay_usb_init() do { \
_kb_led_1_set_percent(0.5); \
_delay_ms(333); \
_kb_led_2_set_percent(0.5); \
_delay_ms(333); \
_kb_led_3_set_percent(0.5); \
_delay_ms(333); \
} while(0)
#define kb_led_state_ready() do { \
_kb_led_all_off(); \
_kb_led_all_set_percent(0.5); \
} while(0)
#endif

View File

@ -1,5 +1,5 @@
/* ----------------------------------------------------------------------------
* ergoDOX: keyboard matrix specific exports
* ergoDOX : matrix specific exports
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
@ -7,17 +7,15 @@
* ------------------------------------------------------------------------- */
#ifndef MATRIX_h
#define MATRIX_h
#ifndef KEYBOARD__ERGODOX__MATRIX_h
#define KEYBOARD__ERGODOX__MATRIX_h
#include "lib/data-types.h"
// --------------------------------------------------------------------
#define KB_ROWS 12 // must match real life
#define KB_COLUMNS 7 // must match real life
extern bool (*kb_is_pressed)[KB_ROWS][KB_COLUMNS];
extern bool (*kb_was_pressed)[KB_ROWS][KB_COLUMNS];
#define KB_ROWS 6 // must match real life
#define KB_COLUMNS 14 // must match real life
// --------------------------------------------------------------------
/* mapping from spatial position to matrix position
* - spatial position: where the key is spatially, relative to other
@ -29,57 +27,58 @@
* and 'column' are single digit hex numbers corresponding to the
* matrix position (which also corresponds to the row and column pin
* labels used in the teensy and mcp23018 files)
* - coordinates not listed are unused
*
* - coordinates
* - optional keys
* k15, k16 (left hand thumb group)
* k17, k18 (right hand thumb group)
* - unused keys
* k36, k00 (left hand)
* k37, k0D (right hand)
*
* --- other info -----------------------------------------------------
* rows x columns = positions; assigned, unassigned
* per hand: 6 x 7 = 42; 38, 4
* total: 12 x 7 = 84; 76, 8
* rows x columns = positions; used, unused
* per hand: 6 x 7 = 42; 40, 2
* total: 6 x 14 = 84; 80, 4
*
* left hand : cols 0..6, rows 6..B
* right hand : cols 0..6, rows 0..5
* left hand : rows 0..5, cols 0..6
* right hand : rows 0..5, cols 7..D
* --------------------------------------------------------------------
*/
#define MATRIX_LAYER( \
/* for unused positions */ \
na, \
\
/* left hand, spatial positions */ \
kB6,kB5,kB4,kB3,kB2,kB1,kB0, \
kA6,kA5,kA4,kA3,kA2,kA1,kA0, \
k96,k95,k94,k93,k92,k91, \
k86,k85,k84,k83,k82,k81,k80, \
k76,k75,k74,k73,k72, \
k64, \
k63, k60, \
k65,k62,k61, \
\
/* right hand, spatial positions */ \
k50,k51,k52,k53,k54,k55,k56, \
k40,k41,k42,k43,k44,k45,k46, \
k31,k32,k33,k34,k35,k36, \
k20,k21,k22,k23,k24,k25,k26, \
k12,k13,k14,k15,k16, \
k04, \
k00, k03, \
k01,k02,k05 ) \
\
/* matrix positions */ \
{ { k00,k01,k02,k03,k04,k05, na,}, \
{ na, na,k12,k13,k14,k15,k16,}, \
{ k20,k21,k22,k23,k24,k25,k26,}, \
{ na,k31,k32,k33,k34,k35,k36,}, \
{ k40,k41,k42,k43,k44,k45,k46,}, \
{ k50,k51,k52,k53,k54,k55,k56,}, \
{ k60,k61,k62,k63,k64,k65, na,}, \
{ na, na,k72,k73,k74,k75,k76,}, \
{ k80,k81,k82,k83,k84,k85,k86,}, \
{ na,k91,k92,k93,k94,k95,k96,}, \
{ kA0,kA1,kA2,kA3,kA4,kA5,kA6,}, \
{ kB0,kB1,kB2,kB3,kB4,kB5,kB6 } }
#define KB_MATRIX_LAYER( \
/* for unused positions */ \
na, \
\
/* left hand, spatial positions */ \
k50,k51,k52,k53,k54,k55,k56, \
k40,k41,k42,k43,k44,k45,k46, \
k30,k31,k32,k33,k34,k35, \
k20,k21,k22,k23,k24,k25,k26, \
k10,k11,k12,k13,k14, \
k03,k15, \
k02,k16,k05, \
k01,k04,k06, \
\
/* right hand, spatial positions */ \
k57,k58,k59,k5A,k5B,k5C,k5D, \
k47,k48,k49,k4A,k4B,k4C,k4D, \
k38,k39,k3A,k3B,k3C,k3D, \
k27,k28,k29,k2A,k2B,k2C,k2D, \
k19,k1A,k1B,k1C,k1D, \
k18,k0A, \
k08,k17,k0B, \
k07,k09,k0C ) \
\
/* matrix positions */ \
{{ na,k01,k02,k03,k04,k05,k06, k07,k08,k09,k0A,k0B,k0C, na }, \
{ k10,k11,k12,k13,k14,k15,k16, k17,k18,k19,k1A,k1B,k1C,k1D }, \
{ k20,k21,k22,k23,k24,k25,k26, k27,k28,k29,k2A,k2B,k2C,k2D }, \
{ k30,k31,k32,k33,k34,k35, na, na,k38,k39,k3A,k3B,k3C,k3D }, \
{ k40,k41,k42,k43,k44,k45,k46, k47,k48,k49,k4A,k4B,k4C,k4D }, \
{ k50,k51,k52,k53,k54,k55,k56, k57,k58,k59,k5A,k5B,k5C,k5D }}
#define MATRIX_LAYER_SET_ALL(na, kxx) \
#define KB_MATRIX_LAYER_SET_ALL(na, kxx) \
LAYER( \
na, \
\
@ -88,8 +87,8 @@
kxx,kxx,kxx,kxx,kxx,kxx, \
kxx,kxx,kxx,kxx,kxx,kxx,kxx, \
kxx,kxx,kxx,kxx,kxx, \
kxx, \
kxx, kxx, \
kxx,kxx, \
kxx,kxx,kxx, \
kxx,kxx,kxx, \
\
kxx,kxx,kxx,kxx,kxx,kxx,kxx, \
@ -97,10 +96,9 @@
kxx,kxx,kxx,kxx,kxx,kxx, \
kxx,kxx,kxx,kxx,kxx,kxx,kxx, \
kxx,kxx,kxx,kxx,kxx, \
kxx, \
kxx, kxx, \
kxx,kxx,kxx )
kxx,kxx, \
kxx,kxx,kxx, \
kxx,kxx,kxx ) \
#endif

View File

@ -1,143 +0,0 @@
/* ----------------------------------------------------------------------------
* ergoDOX controller: MCP23018 specific code
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#include <util/twi.h>
#include "lib/data-types.h"
#include "lib/twi.h" // `TWI_FREQ` defined in "teensy-2-0.c"
#include "matrix.h"
#include "mcp23018--private.h"
// register addresses (see "mcp23018.md")
#define IODIRA 0x00 // i/o direction register
#define IODIRB 0x01
#define GPPUA 0x0C // GPIO pull-up resistor register
#define GPPUB 0x0D
#define GPIOA 0x12 // general purpose i/o port register (write modifies OLAT)
#define GPIOB 0x13
#define OLATA 0x14 // output latch register
#define OLATB 0x15
// TWI aliases
#define TWI_ADDR_WRITE ( (MCP23018_TWI_ADDRESS<<1) | TW_WRITE )
#define TWI_ADDR_READ ( (MCP23018_TWI_ADDRESS<<1) | TW_READ )
/* returns:
* - success: 0
* - failure: twi status code
*
* notes:
* - `twi_stop()` must be called *exactly once* for each twi block, the way
* things are currently set up. this may change in the future.
*/
uint8_t mcp23018_init(void) {
uint8_t ret;
// set pin direction
// - unused : input : 1
// - row : input : 1
// - column : output : 0
twi_start();
ret = twi_send(TWI_ADDR_WRITE);
if (ret) goto out; // make sure we got an ACK
twi_send(IODIRA);
twi_send(0b11111111); // IODIRA
twi_send(0b10000000); // IODIRB
twi_stop();
// set pull-up
// - unused : on : 1
// - rows : on : 1
// - columns : off : 0
twi_start();
ret = twi_send(TWI_ADDR_WRITE);
if (ret) goto out; // make sure we got an ACK
twi_send(GPPUA);
twi_send(0b11111111); // GPPUA
twi_send(0b10000000); // GPPUB
twi_stop();
// set logical value (doesn't matter on inputs)
// - unused : high (hi-Z) : 1
// - rows : high (hi-Z) : 1
// - columns : high (hi-Z) : 1
twi_start();
ret = twi_send(TWI_ADDR_WRITE);
if (ret) goto out; // make sure we got an ACK
twi_send(OLATA);
twi_send(0b11111111); //OLATA
twi_send(0b11111111); //OLATB
out:
twi_stop();
return ret;
}
/* returns:
* - success: 0
* - failure: twi status code
*/
#if KB_ROWS != 12 || KB_COLUMNS != 7
#error "Expecting different keyboard dimensions"
#endif
uint8_t mcp23018_update_matrix(bool matrix[KB_ROWS][KB_COLUMNS]) {
uint8_t ret, data;
// initialize things, just to make sure
// - it's not appreciably faster to skip this, and it takes care of the
// case when the i/o expander isn't plugged in during the first
// init()
ret = mcp23018_init();
// if there was an error
if (ret) {
// clear our part of the matrix
for (uint8_t row=0x6; row<=0xB; row++)
for (uint8_t col=0; col<=6; col++)
matrix[row][col] = 0;
return ret;
}
// update our part of the matrix
for (uint8_t col=0; col<=6; col++) {
// set active column low : 0
// set other columns high (hi-Z) : 1
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(OLATB);
twi_send( 0xFF & ~(1<<col) );
twi_stop();
// read row data
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPIOA);
twi_start();
twi_send(TWI_ADDR_READ);
twi_read(&data);
twi_stop();
// update matrix
for (uint8_t row=0x6; row<=0xB; row++)
matrix[row][col] = !( data & (1<<(row-6)) );
}
// set all columns high (hi-Z) : 1
twi_start();
twi_send(TWI_ADDR_WRITE);
twi_send(GPIOB);
twi_send(0xFF);
twi_stop();
return ret; // success
}

View File

@ -0,0 +1,40 @@
/* ----------------------------------------------------------------------------
* ergoDOX : keyboard specific options
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#ifndef KEYBOARD__ERGODOX__OPTIONS_h
#define KEYBOARD__ERGODOX__OPTIONS_h
// --------------------------------------------------------------------
/*
* DRIVE_ROWS and DRIVE_COLUMNS
* - Select which pins will drive (alternate between hi-Z and drive
* low) and which will be inputs
*
* Notes
* - You must set exactly one of each 'TEENSY' macro, and of each
* 'MCP23018' macro
* - If you are using internal diodes (inside the key switches)... then
* i don't know what to tell you. You will set one chip to drive
* rows, and the other to drive columns, but i don't have a key
* switch to check which at the moment, and i couldn't seem to find
* it online.
* - If the diode cathode is towards the square solder pad, set
* #define TEENSY__DRIVE_COLUMNS 1
* #define MCP23018__DRIVE_COLUMNS 1
* - If the diode cathode is towards the circular solder pad, set
* #define TEENSY__DRIVE_ROWS 1
* #define MCP23018__DRIVE_ROWS 1
*/
#define TEENSY__DRIVE_ROWS 0
#define TEENSY__DRIVE_COLUMNS 1
#define MCP23018__DRIVE_ROWS 0
#define MCP23018__DRIVE_COLUMNS 1
#endif

View File

@ -1,195 +0,0 @@
/* ----------------------------------------------------------------------------
* ergoDOX controller: Teensy 2.0 specific code
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#include <avr/io.h>
#include <util/delay.h>
#include "lib/data-types.h"
#define TWI_FREQ 400000
#include "lib/twi.h"
#include "matrix.h"
#include "teensy-2-0.h"
#include "teensy-2-0--private.h"
// processor frequency (from <http://www.pjrc.com/teensy/prescaler.html>)
#define CPU_PRESCALE(n) (CLKPR = 0x80, CLKPR = (n))
#define CPU_16MHz 0x00
#define CPU_8MHz 0x01
#define CPU_4MHz 0x02
#define CPU_2MHz 0x03
#define CPU_1MHz 0x04
#define CPU_500kHz 0x05
#define CPU_250kHz 0x06
#define CPU_125kHz 0x07
#define CPU_62kHz 0x08
/* pin macros
* - note: you can move the `UNUSED`, `ROW`, and `COLUMN` pins around, but be
* sure to keep the set of all the pins listed constant. other pins are not
* movable, and either are referenced explicitly or have macros defined for
* them elsewhere.
* - note: if you change pin assignments, please be sure to update
* "teensy-2-0.md", and the '.svg' circuit diagram.
*/
// --- helpers
#define teensypin_write(register, operation, pin) do { \
_teensypin_write(register, operation, pin); \
_delay_us(1); /* allow pins time to stabalize */ \
} while(0)
#define _teensypin_write(register, operation, pin_letter, pin_number) \
((register##pin_letter) operation (1<<(pin_number)))
#define teensypin_read(pin) \
_teensypin_read(pin)
#define _teensypin_read(pin_letter, pin_number) \
((PIN##pin_letter) & (1<<(pin_number)))
#define teensypin_write_all_unused(register, operation) \
do { \
teensypin_write(register, operation, UNUSED_0); \
teensypin_write(register, operation, UNUSED_1); \
teensypin_write(register, operation, UNUSED_2); \
teensypin_write(register, operation, UNUSED_3); \
teensypin_write(register, operation, UNUSED_4); \
teensypin_write(register, operation, UNUSED_5); } \
while(0)
#define teensypin_write_all_row(register, operation) \
do { \
teensypin_write(register, operation, ROW_0); \
teensypin_write(register, operation, ROW_1); \
teensypin_write(register, operation, ROW_2); \
teensypin_write(register, operation, ROW_3); \
teensypin_write(register, operation, ROW_4); \
teensypin_write(register, operation, ROW_5); } \
while(0)
#define teensypin_write_all_column(register, operation) \
do { \
teensypin_write(register, operation, COLUMN_0); \
teensypin_write(register, operation, COLUMN_1); \
teensypin_write(register, operation, COLUMN_2); \
teensypin_write(register, operation, COLUMN_3); \
teensypin_write(register, operation, COLUMN_4); \
teensypin_write(register, operation, COLUMN_5); \
teensypin_write(register, operation, COLUMN_6); } \
while(0)
#define SET |=
#define CLEAR &=~
// --- unused
#define UNUSED_0 B, 1 // SPI pin
#define UNUSED_1 B, 2 // SPI pin
#define UNUSED_2 B, 3 // SPI pin
#define UNUSED_3 D, 4 // hard to use with breadboard (on the end)
#define UNUSED_4 D, 5 // hard to use with breadboard (on the end)
#define UNUSED_5 E, 6 // hard to use with breadboard (internal)
// --- rows
#define ROW_0 F, 0
#define ROW_1 F, 1
#define ROW_2 F, 4
#define ROW_3 F, 5
#define ROW_4 F, 6
#define ROW_5 F, 7
// --- columns
#define COLUMN_0 B, 4
#define COLUMN_1 C, 6
#define COLUMN_2 C, 7
#define COLUMN_3 D, 2
#define COLUMN_4 D, 3
#define COLUMN_5 D, 7
#define COLUMN_6 B, 0
/* returns
* - success: 0
*/
uint8_t teensy_init(void) {
CPU_PRESCALE(CPU_16MHz); // speed should match F_CPU in makefile
// onboard LED
DDRD &= ~(1<<6); // set D(6) as input
PORTD &= ~(1<<6); // set D(6) internal pull-up disabled
// keyboard LEDs (see "PWM on ports OC1(A|B|C)" in "teensy-2-0.md")
_kb_led_all_off(); // (just to put the pins in a known state)
TCCR1A = 0b10101001; // set and configure fast PWM
TCCR1B = 0b00001001; // set and configure fast PWM
// I2C (TWI)
twi_init(); // on pins D(1,0)
// unused pins
teensypin_write_all_unused(DDR, CLEAR); // set as input
teensypin_write_all_unused(PORT, SET); // set internal pull-up enabled
// rows
teensypin_write_all_row(DDR, CLEAR); // set as input
teensypin_write_all_row(PORT, SET); // set internal pull-up enabled
// columns
teensypin_write_all_column(DDR, CLEAR); // set as input (hi-Z)
teensypin_write_all_column(PORT, CLEAR); // set internal pull-up
// disabled
return 0; // success
}
/* returns
* - success: 0
*/
#if KB_ROWS != 12 || KB_COLUMNS != 7
#error "Expecting different keyboard dimensions"
#endif
static inline void _update_rows(
bool matrix[KB_ROWS][KB_COLUMNS], uint8_t column ) {
matrix[0][column] = ! teensypin_read(ROW_0);
matrix[1][column] = ! teensypin_read(ROW_1);
matrix[2][column] = ! teensypin_read(ROW_2);
matrix[3][column] = ! teensypin_read(ROW_3);
matrix[4][column] = ! teensypin_read(ROW_4);
matrix[5][column] = ! teensypin_read(ROW_5);
}
uint8_t teensy_update_matrix(bool matrix[KB_ROWS][KB_COLUMNS]) {
teensypin_write(DDR, SET, COLUMN_0); // set col low (set as output)
_update_rows(matrix, 0); // read row 0..5 & update matrix
teensypin_write(DDR, CLEAR, COLUMN_0); // set col hi-Z (set as input)
teensypin_write(DDR, SET, COLUMN_1);
_update_rows(matrix, 1);
teensypin_write(DDR, CLEAR, COLUMN_1);
teensypin_write(DDR, SET, COLUMN_2);
_update_rows(matrix, 2);
teensypin_write(DDR, CLEAR, COLUMN_2);
teensypin_write(DDR, SET, COLUMN_3);
_update_rows(matrix, 3);
teensypin_write(DDR, CLEAR, COLUMN_3);
teensypin_write(DDR, SET, COLUMN_4);
_update_rows(matrix, 4);
teensypin_write(DDR, CLEAR, COLUMN_4);
teensypin_write(DDR, SET, COLUMN_5);
_update_rows(matrix, 5);
teensypin_write(DDR, CLEAR, COLUMN_5);
teensypin_write(DDR, SET, COLUMN_6);
_update_rows(matrix, 6);
teensypin_write(DDR, CLEAR, COLUMN_6);
return 0; // success
}

View File

@ -1,5 +1,8 @@
/* ----------------------------------------------------------------------------
* ergoDOX: keyboard matrix specific code
* layout specific exports
*
* Files for different keyboards are used by modifying a variable in the
* Makefile
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
@ -7,14 +10,7 @@
* ------------------------------------------------------------------------- */
#include "lib/data-types.h"
#include "matrix.h"
static bool _kb_is_pressed[KB_ROWS][KB_COLUMNS];
static bool _kb_was_pressed[KB_ROWS][KB_COLUMNS];
bool (*kb_is_pressed)[KB_ROWS][KB_COLUMNS] = &_kb_is_pressed;
bool (*kb_was_pressed)[KB_ROWS][KB_COLUMNS] = &_kb_was_pressed;
#include "../lib/variable-include.h"
#define INCLUDE EXP_STR( ./MAKEFILE_KEYBOARD/layout.h )
#include INCLUDE

16
src/keyboard/matrix.h Normal file
View File

@ -0,0 +1,16 @@
/* ----------------------------------------------------------------------------
* matrix specific exports
*
* Files for different keyboards are used by modifying a variable in the
* Makefile
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#include "../lib/variable-include.h"
#define INCLUDE EXP_STR( ./MAKEFILE_KEYBOARD/matrix.h )
#include INCLUDE

View File

@ -34,16 +34,16 @@
**************************************************************************/
// You can change these to give your code its own name.
#define STR_MANUFACTURER L"MfgName"
#define STR_PRODUCT L"Keyboard"
#define STR_MANUFACTURER L"unspecified" // TODO
#define STR_PRODUCT L"ErgoDox ergonomic keyboard"
// Mac OS-X and Linux automatically load the correct drivers. On
// Windows, even though the driver is supplied by Microsoft, an
// INF file is needed to load the driver. These numbers need to
// match the INF file.
#define VENDOR_ID 0x16C0
#define PRODUCT_ID 0x047C
#define VENDOR_ID 0x1d50 // Openmoko, Inc.
#define PRODUCT_ID 0x6028 // ErgoDox ergonomic keyboard
// USB devices are supposed to implment a halt feature, which is
@ -89,7 +89,7 @@ static const uint8_t PROGMEM endpoint_config_table[] = {
// spec and relevant portions of any USB class specifications!
static uint8_t PROGMEM device_descriptor[] = {
static const uint8_t PROGMEM device_descriptor[] = {
18, // bLength
1, // bDescriptorType
0x00, 0x02, // bcdUSB
@ -107,7 +107,7 @@ static uint8_t PROGMEM device_descriptor[] = {
};
// Keyboard Protocol 1, HID 1.11 spec, Appendix B, page 59-60
static uint8_t PROGMEM keyboard_hid_report_desc[] = {
static const uint8_t PROGMEM keyboard_hid_report_desc[] = {
0x05, 0x01, // Usage Page (Generic Desktop),
0x09, 0x06, // Usage (Keyboard),
0xA1, 0x01, // Collection (Application),
@ -144,7 +144,7 @@ static uint8_t PROGMEM keyboard_hid_report_desc[] = {
#define CONFIG1_DESC_SIZE (9+9+9+7)
#define KEYBOARD_HID_DESC_OFFSET (9+9)
static uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
static const uint8_t PROGMEM config1_descriptor[CONFIG1_DESC_SIZE] = {
// configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10
9, // bLength;
2, // bDescriptorType;
@ -191,17 +191,17 @@ struct usb_string_descriptor_struct {
uint8_t bDescriptorType;
int16_t wString[];
};
static struct usb_string_descriptor_struct PROGMEM string0 = {
static const struct usb_string_descriptor_struct PROGMEM string0 = {
4,
3,
{0x0409}
};
static struct usb_string_descriptor_struct PROGMEM string1 = {
static const struct usb_string_descriptor_struct PROGMEM string1 = {
sizeof(STR_MANUFACTURER),
3,
STR_MANUFACTURER
};
static struct usb_string_descriptor_struct PROGMEM string2 = {
static const struct usb_string_descriptor_struct PROGMEM string2 = {
sizeof(STR_PRODUCT),
3,
STR_PRODUCT
@ -214,7 +214,7 @@ static struct descriptor_list_struct {
uint16_t wIndex;
const uint8_t *addr;
uint8_t length;
} PROGMEM descriptor_list[] = {
} const PROGMEM descriptor_list[] = {
{0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
{0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
{0x2200, KEYBOARD_INTERFACE, keyboard_hid_report_desc, sizeof(keyboard_hid_report_desc)},

View File

@ -1,240 +0,0 @@
/* ----------------------------------------------------------------------------
* linked list
*
* Notes:
* - When 'position' is used, it referes to the position of the node in the
* list, not the node's offset. E.g. the node with position == 1 is the
* first node in the list.
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#include <stdlib.h>
#include "lib/data-types.h"
#include "linked-list.h"
// local macros (undefined later)
#define _NEW_POINTER(type, name) type * name = (type *) malloc(sizeof(type))
#define _list_t linked_list_t
#define _node_t linked_list_node_t
#define _data_t LINKED_LIST_DATA_TYPE
/*
* new()
*
* Returns
* - success: a pointer to a new linked list
* - failure: NULL
*/
_list_t * linked_list_new(void) {
_NEW_POINTER(_list_t, list);
if (!list) return NULL;
list->head = NULL;
list->tail = NULL;
list->length = 0;
return list;
}
/*
* insert()
*
* Arguments
* - index: the index of the position that the new node will occupy. if index
* is negative, we set index += length (as in Python). so:
* - 0 => the first node in the list
* - 1 => the second node in the list
* - -1 => the last node in the list
* - -2 => the second from the last node in the list
* - '0' is undefined (returns 'failure')
* - out of bounds positions wrap around, so:
* - [length] => 0 => the first node in the list
* - -[length+1] => -1 => the last node in the list
*
* Returns
* - success: the pointer to the list that was passed
* - failure: NULL
*/
_list_t * linked_list_insert(_list_t * list, _data_t data, int index) {
_NEW_POINTER(_node_t, node);
if (!node) return NULL;
node->data = data;
if (list->length == 0) {
// insert as only node (no others exist yet)
list->head = node;
list->tail = node;
node->next = NULL;
} else {
// find positive, in-bounds index
index = index % list->length;
if (index < 0)
index += list->length;
if (index == 0) {
// insert as first node
node->next = list->head;
list->head = node;
} else if (index == list->length-1) {
// insert as last node
list->tail->next = node;
list->tail = node;
node->next = NULL;
} else {
// insert as other node
_node_t * previous = list->head;
for (int i=1; i<index; i++)
previous = previous->next;
node->next = previous->next;
previous->next = node;
}
}
list->length++;
return list;
}
/*
* peek()
*
* Arguments
* - index: [see 'insert()']
*
* Returns
* - success: the data field of the node at the given index
* - failure: (_data_t) 0
*/
_data_t linked_list_peek(_list_t * list, int index) {
// if: no nodes exist
if (list->length == 0)
return (_data_t) 0;
// find positive, in-bounds index
index = index % list->length;
if (index < 0)
index += list->length;
// if: last node
if (index == list->length-1)
return list->tail->data;
// else
_node_t * node = list->head;
for (int i=0; i<index; i++)
node = node->next;
return node->data;
}
/*
* pop()
*
* Arguments
* - index: [see 'insert()']
*
* Returns
* - success: the data field of the node at the given index
* - failure: (_data_t) 0
*/
_data_t linked_list_pop(_list_t * list, int index) {
// if: no nodes exist
if (list->length == 0)
return (_data_t) 0;
// find positive, in-bounds index
index = index % list->length;
if (index < 0)
index += list->length;
// vars
_data_t data;
_node_t * node;
if (index == 0) {
// pop first node
data = list->head->data;
node = list->head;
list->head = node->next;
} else {
// find the index-1'th node
_node_t * previous;
previous = list->head;
for (int i=1; i<index; i++)
previous = previous->next;
// if: last node
if (index == list->length-1)
list->tail = previous;
// pop the node at index
data = previous->next->data;
node = previous->next;
previous->next = node->next;
}
free(node);
list->length--;
return data;
}
/*
* find()
* TODO
*/
// TODO
/*
* copy()
*
* Returns
* - success: a new pointer to a (deep) copy of the list that was passed
* - failure: NULL
*/
_list_t * linked_list_copy(_list_t * list) {
_NEW_POINTER(_list_t, copy);
if (!copy) return NULL;
bool error;
_node_t * node = list->head;
for (uint8_t i=0; i<(list->length); i++) {
error = ! linked_list_insert(copy, node->data, -1);
if (error) {
linked_list_free(copy);
return NULL;
}
node = node->next;
}
return copy;
}
/*
* free()
* - Free the memory allocated to all the nodes, then free the memory allocated
* to the list.
*/
void linked_list_free(_list_t * list) {
_node_t * node;
for (uint8_t i=0; i<(list->length); i++) {
node = list->head;
list->head = list->head->next;
free(node);
}
free(list);
}
// local macros (undefined here)
#undef _NEW_POINTER
#undef _list_t
#undef _node_t
#undef _data_t

View File

@ -1,55 +0,0 @@
/* ----------------------------------------------------------------------------
* linked list : exports
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#ifndef LINKED_LIST_h
#define LINKED_LIST_h
#include "lib/data-types.h"
// default data type for the list
#ifndef LINKED_LIST_DATA_TYPE
#define LINKED_LIST_DATA_TYPE uint8_t
#endif
// structs
struct linked_list_node {
LINKED_LIST_DATA_TYPE data;
struct linked_list_node * next;
};
struct linked_list {
uint8_t length;
struct linked_list_node * head;
struct linked_list_node * tail;
};
// typedefs
typedef struct linked_list linked_list_t;
typedef struct linked_list_node linked_list_node_t;
// functions
#define _list_t linked_list_t
#define _data_t LINKED_LIST_DATA_TYPE
// TODO
_list_t * linked_list_new (void);
_list_t * linked_list_add_head (_list_t * list, _data_t data);
_list_t * linked_list_add_tail (_list_t * list, _data_t data);
_data_t linked_list_pop_head (_list_t * list);
_data_t linked_list_pop_tail (_list_t * list);
_data_t linked_list_read (_list_t * list, uint8_t position);
_list_t * linked_list_copy (_list_t * list);
void linked_list_free (_list_t * list);
// /TODO
#undef _list_t
#undef _data_t
#endif

View File

@ -1,5 +1,5 @@
/* ----------------------------------------------------------------------------
* Common data types
* miscellaneous data types
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
@ -7,13 +7,10 @@
* ------------------------------------------------------------------------- */
#ifndef DATA_TYPES_h
#define DATA_TYPES_h
#ifndef LIB__DATA_TYPES_h
#define LIB__DATA_TYPES_h
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include "data-types/linked-list.h"
typedef void (*void_funptr_t)(void);
#endif

View File

@ -1,28 +0,0 @@
/* ----------------------------------------------------------------------------
* key functions: private
*
* Things to be used only by keyfunctions. Exported any layouts would like to
* use these functions to help define their own.
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#ifndef KEY_FUNCTIONS_h_PRIVATE
#define KEY_FUNCTIONS_h_PRIVATE
void _press_release(bool pressed, uint8_t keycode);
void _layer_set_current(
uint8_t value,
uint8_t * current_layer,
uint8_t (*current_layers_)[KB_ROWS][KB_COLUMNS] );
void _layer_set_mask(
uint8_t layer,
bool positions[KB_ROWS][KB_COLUMNS],
uint8_t (*current_layers)[KB_ROWS][KB_COLUMNS] );
bool _is_pressed(uint8_t keycode);
#endif

View File

@ -1,510 +0,0 @@
/* ----------------------------------------------------------------------------
* key functions: code
*
* These functions may do.. pretty much anything rational that thay like. If
* they want keycodes to be sent to the host in an aggrate report, they're
* responsible for modifying the appropriate report variables.
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#include <avr/interrupt.h>
#include "lib-other/pjrc/usb_keyboard/usb_keyboard.h"
#include "lib/data-types.h"
#include "lib/usb/usage-page/keyboard.h"
#include "keyboard.h"
#include "key-functions.h"
#include "key-functions--private.h"
// ----------------------------------------------------------------------------
// public functions (not for keys)
// ----------------------------------------------------------------------------
/*
* Exec key
* - Execute the keypress or keyrelease function (if it exists) of the key at
* the current possition. Pass the keycode at the current position, and pass
* all other arguments as received
*/
void _kbfun_exec_key( KBFUN_FUNCTION_ARGS ) {
kbfun_funptr_t key_function =
( (pressed_)
? kb_layout_press_get(layer_, *row_, *col_)
: kb_layout_release_get(layer_, *row_, *col_) );
if (key_function)
(*key_function)(
pressed_,
kb_layout_get(layer_, *row_, *col_),
layer_,
row_,
col_,
current_layer_,
current_layers_,
pressed_layers_ );
}
// ----------------------------------------------------------------------------
// private functions
// ----------------------------------------------------------------------------
/*
* Generate a normal keypress or keyrelease
*
* Arguments
* - keycode: the keycode to use
* - pressed: whether to generate a keypress (true) or keyrelease (false)
*
* Note
* - Because of the way USB does things, what this actually does is either add
* or remove 'keycode' from the list of currently pressed keys, to be sent at
* the end of the current cycle (see main.c)
*/
void _press_release(bool pressed, uint8_t keycode) {
// no-op
if (keycode == 0)
return;
// modifier keys
switch (keycode) {
case KEY_LeftControl: (pressed)
? (keyboard_modifier_keys |= (1<<0))
: (keyboard_modifier_keys &= ~(1<<0));
return;
case KEY_LeftShift: (pressed)
? (keyboard_modifier_keys |= (1<<1))
: (keyboard_modifier_keys &= ~(1<<1));
return;
case KEY_LeftAlt: (pressed)
? (keyboard_modifier_keys |= (1<<2))
: (keyboard_modifier_keys &= ~(1<<2));
return;
case KEY_LeftGUI: (pressed)
? (keyboard_modifier_keys |= (1<<3))
: (keyboard_modifier_keys &= ~(1<<3));
return;
case KEY_RightControl: (pressed)
? (keyboard_modifier_keys |= (1<<4))
: (keyboard_modifier_keys &= ~(1<<4));
return;
case KEY_RightShift: (pressed)
? (keyboard_modifier_keys |= (1<<5))
: (keyboard_modifier_keys &= ~(1<<5));
return;
case KEY_RightAlt: (pressed)
? (keyboard_modifier_keys |= (1<<6))
: (keyboard_modifier_keys &= ~(1<<6));
return;
case KEY_RightGUI: (pressed)
? (keyboard_modifier_keys |= (1<<7))
: (keyboard_modifier_keys &= ~(1<<7));
return;
}
// all others
for (uint8_t i=0; i<6; i++) {
if (pressed) {
if (keyboard_keys[i] == 0) {
keyboard_keys[i] = keycode;
return;
}
} else {
if (keyboard_keys[i] == keycode) {
keyboard_keys[i] = 0;
return;
}
}
}
}
/*
* Set current layer
* - Sets any keys currently set to the overall current layer to the new layer,
* and then sets the overall current layer
*
* Arguments
* - layer: the new layer value
* - current_layer: (a pointer to) the overall current layer (see main.c)
* - current_layers: (a pointer to a matrix of) the current layer for each key
* (see main.c and lib/key-functions.h)
*
* Note
* - Leaving all non-current layer values alone allows changing layers while
* maintaining a possibly enabled layer mask (as might be used to implement
* firmware enabled numlock)
*/
void _layer_set_current(
uint8_t layer,
uint8_t * current_layer,
uint8_t (*current_layers)[KB_ROWS][KB_COLUMNS] ) {
// don't switch to out-of-bounds layers
if ( layer < 0 || layer >= KB_LAYERS )
return;
for (uint8_t row=0; row<KB_ROWS; row++)
for (uint8_t col=0; col<KB_COLUMNS; col++)
// if a key is set to a non-current layer, leave it
if ((*current_layers)[row][col] == *current_layer)
(*current_layers)[row][col] = layer;
(*current_layer) = layer;
}
/*
* Set layer mask
* - Sets the specified key positions to the specified layer
*/
void _layer_set_mask(
uint8_t layer,
bool positions[KB_ROWS][KB_COLUMNS],
uint8_t (*current_layers)[KB_ROWS][KB_COLUMNS] ) {
// don't switch to out-of-bounds layers
if ( layer < 0 || layer >= KB_LAYERS )
return;
for (uint8_t row=0; row<KB_ROWS; row++)
for (uint8_t col=0; col<KB_COLUMNS; col++)
if (positions[row][col])
(*current_layers)[row][col] = layer;
}
/*
* Is the given keycode pressed?
*/
bool _is_pressed(uint8_t keycode) {
// modifier keys
switch (keycode) {
case KEY_LeftControl: if (keyboard_modifier_keys & (1<<0))
return true;
case KEY_LeftShift: if (keyboard_modifier_keys & (1<<1))
return true;
case KEY_LeftAlt: if (keyboard_modifier_keys & (1<<2))
return true;
case KEY_LeftGUI: if (keyboard_modifier_keys & (1<<3))
return true;
case KEY_RightControl: if (keyboard_modifier_keys & (1<<4))
return true;
case KEY_RightShift: if (keyboard_modifier_keys & (1<<5))
return true;
case KEY_RightAlt: if (keyboard_modifier_keys & (1<<6))
return true;
case KEY_RightGUI: if (keyboard_modifier_keys & (1<<7))
return true;
}
// all others
for (uint8_t i=0; i<6; i++)
if (keyboard_keys[i] == keycode)
return true;
return false;
}
// ----------------------------------------------------------------------------
// public functions
// ----------------------------------------------------------------------------
/*
* Press|Release
* - Generate a normal keypress or keyrelease
*/
void kbfun_press_release( KBFUN_FUNCTION_ARGS ) {
_press_release(pressed_, keycode_);
}
/*
* Toggle
* - Toggle the key pressed or unpressed
*/
void kbfun_toggle( KBFUN_FUNCTION_ARGS ) {
if (_is_pressed(keycode_))
_press_release(false, keycode_);
else
_press_release(true, keycode_);
}
/*
* Increase layer
* - Increment the current layer by the value specified in the keymap (for all
* non-masked keys)
*/
void kbfun_layer_inc( KBFUN_FUNCTION_ARGS ) {
_layer_set_current(
(*current_layer_) + keycode_,
current_layer_,
current_layers_ );
}
/*
* Decrease layer
* - Decrement the current layer by the value specified in the keymap (for all
* non-masked keys)
*/
void kbfun_layer_dec( KBFUN_FUNCTION_ARGS ) {
_layer_set_current(
(*current_layer_) - keycode_,
current_layer_,
current_layers_ );
}
/*
* Increase layer, Execute key
* - Increment the current layer by the value specified in the keymap (for all
* non-masked keys), and execute (usually press|release) the key in the same
* position on that new layer
*
* Note
* - Meant to be paired with `kbfun_layer_dec_exec()`
*/
void kbfun_layer_inc_exec( KBFUN_FUNCTION_ARGS ) {
// switch layers
_layer_set_current(
(*current_layer_) + keycode_,
current_layer_,
current_layers_ );
// exececute second key (in the same position)
// - `layer_+keycode_` will be constant (under normal circumstances)
// between the press and release
_kbfun_exec_key(
pressed_, 0, layer_+keycode_,
row_, col_, current_layer_,
current_layers_, pressed_layers_ );
}
/*
* Decrease layer, Execute key
* - Decrement the current layer by the value specified in the keymap (for all
* non-masked keys), and execute (usually press|release) the key in the same
* position on that new layer
*
* Note
* - Meant to be paired with `kbfun_layer_inc_exec()`
*/
void kbfun_layer_dec_exec( KBFUN_FUNCTION_ARGS ) {
// switch layers
_layer_set_current(
(*current_layer_) - keycode_,
current_layer_,
current_layers_ );
// exececute second key (in the same position)
// - `layer_+keycode_` will be constant (under normal circumstances)
// between the press and release
_kbfun_exec_key(
pressed_, 0, layer_+keycode_,
row_, col_, current_layer_,
current_layers_, pressed_layers_ );
}
/*
* Two keys => capslock
* - When assigned to two keys (e.g. the physical left and right shift keys)
* (in both the press and release matrices), pressing and holding down one of
* the keys will make the second key toggle capslock
*
* Note
* - If either of the shifts are pressed when the second key is pressed, they
* wil be released so that capslock will register properly when pressed.
* Capslock will then be pressed and released, and the original state of the
* shifts will be restored
*/
void kbfun_2_keys_capslock_press_release( KBFUN_FUNCTION_ARGS ) {
static uint8_t keys_pressed;
static bool lshift_pressed;
static bool rshift_pressed;
if (!pressed_) keys_pressed--;
// take care of the key that was actually pressed
_press_release(pressed_, keycode_);
// take care of capslock (only on the press of the 2nd key)
if (keys_pressed == 1 && pressed_) {
// save the state of left and right shift
lshift_pressed = _is_pressed(KEY_LeftShift);
rshift_pressed = _is_pressed(KEY_RightShift);
// disable both
_press_release(false, KEY_LeftShift);
_press_release(false, KEY_RightShift);
// press capslock, then release it
_press_release(true, KEY_CapsLock);
usb_keyboard_send();
_press_release(false, KEY_CapsLock);
usb_keyboard_send();
// restore the state of left and right shift
if (lshift_pressed)
_press_release(true, KEY_LeftShift);
if (rshift_pressed)
_press_release(true, KEY_RightShift);
}
if (pressed_) keys_pressed++;
}
// TODO: maybe the numpad functions (and other logical sets of functions?) need
// to be in (a) seaparate file(s).
/* ----------------------------------------------------------------------------
* Numpad functions
* - Functions to implement an embedded numpad
*
* Notes
* - The numpad is toggled by shifting (without changing the overall current
* layer) the layer of the keys specified in this function to the value
* specified in the keymap
* - When the numpad is toggled, the numlock is set to on (for active) or off
* (for inactive) as well
* - All these functions cooperate, but if more than one layer mask of this
* type is used (by a different set of functions) at the same time, the
* second will override the first, and any keys covered by both will be reset
* to the overall current layer when either is released (even if the other is
* still pressed)
* ------------------------------------------------------------------------- */
// prefix function (undefined later)
// - to keep these names reasonable in this block, and obviously not global
// outside it
// - 'L' is for 'local'
#define L(name) _kbfun_layermask_numpad__##name
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
// vars
static bool L(numpad_activated) = false;
static bool L(layer_mask)[KB_ROWS][KB_COLUMNS] =
MATRIX_LAYER(
// unused
0,
// left hand
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0,
0, 0,
0, 0, 0,
// right hand
0, 0, 1, 1, 1, 1, 0,
0, 0, 1, 1, 1, 1, 0,
0, 1, 1, 1, 1, 0,
0, 0, 1, 1, 1, 1, 0,
0, 0, 0, 0, 0,
0,
0, 0,
0, 0, 0 );
// functions
static inline void L(toggle_numlock)(void) {
_press_release(true, KEYPAD_NumLock_Clear);
usb_keyboard_send();
_press_release(false, KEYPAD_NumLock_Clear);
usb_keyboard_send();
}
static void L(toggle_numpad)(
uint8_t numpad_layer,
uint8_t current_layer,
uint8_t (*current_layers)[KB_ROWS][KB_COLUMNS] ) {
if (L(numpad_activated)) {
// deactivate numpad
_layer_set_mask(current_layer, L(layer_mask), current_layers);
L(numpad_activated) = false;
// if: numlock on
if (keyboard_leds & (1<<0))
L(toggle_numlock)();
} else {
// activate numpad
_layer_set_mask(numpad_layer, L(layer_mask), current_layers);
L(numpad_activated) = true;
// if: numlock off
if (!(keyboard_leds & (1<<0)))
L(toggle_numlock)();
}
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
/*
* Numpad toggle
* - Toggles the numpad and sets numlock on (for active) or off (for inactive)
* with it, if it's not already in that state
*/
void kbfun_layermask_numpad_toggle( KBFUN_FUNCTION_ARGS ) {
L(toggle_numpad)(keycode_, *current_layer_, current_layers_);
}
/*
* Numpad on
* - Set the numpad on (along with numlock, if it's not already)
*/
void kbfun_layermask_numpad_on( KBFUN_FUNCTION_ARGS ) {
if (!L(numpad_activated))
L(toggle_numpad)(keycode_, *current_layer_, current_layers_);
}
/*
* Numpad off
* - Set the numpad off (along with numlock, if it's not already)
*/
void kbfun_layermask_numpad_off( KBFUN_FUNCTION_ARGS ) {
if (L(numpad_activated))
L(toggle_numpad)(keycode_, *current_layer_, current_layers_);
}
// . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
// prefix function (undefined here)
#undef L
/* ----------------------------------------------------------------------------
* ------------------------------------------------------------------------- */
// ----------------------------------------------------------------------------
// public functions (device specific)
// ----------------------------------------------------------------------------
void kbfun_jump_to_bootloader( KBFUN_FUNCTION_ARGS ) {
// from PJRC (slightly modified)
// <http://www.pjrc.com/teensy/jump_to_bootloader.html>
#if MAKEFILE_BOARD == teensy-2-0
// --- for all Teensy boards
cli();
// disable watchdog, if enabled
// disable all peripherals
UDCON = 1;
USBCON = (1<<FRZCLK); // disable USB
UCSR1B = 0;
_delay_ms(5);
// --- Teensy 2.0 specific
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");
#endif
// else, function does nothing
}

View File

@ -1,64 +0,0 @@
/* ----------------------------------------------------------------------------
* key functions: exports
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#ifndef KEY_FUNCTIONS_h
#define KEY_FUNCTIONS_h
#include "lib/data-types.h"
// --------------------------------------------------------------------
// include the appropriate 'matrix.h'
// -------
// we're not simply including 'keyboard.h' here because this header is
// meant to be included by 'keyboard/layout/*.c', which is indirectly
// included by 'keyboard.h'; and that would lead to a circular include,
// which gcc might (depending on the order of include statements it
// encounters) deal with by processing this file before 'matrix.h',
// which would give us undefined macros here
#undef _str
#undef _expstr
#undef _inc
#define _str(s) #s // stringify
#define _expstr(s) _str(s) // expand -> stringify
#define _inc _expstr(keyboard/MAKEFILE_KEYBOARD/matrix.h) // inc(lude)
#include _inc
#undef _str
#undef _expstr
#undef _inc
// --------------------------------------------------------------------
#define KBFUN_FUNCTION_ARGS \
bool pressed_, \
uint8_t keycode_, \
uint8_t layer_, \
uint8_t * row_, \
uint8_t * col_, \
uint8_t * current_layer_, \
uint8_t (*current_layers_)[KB_ROWS][KB_COLUMNS], \
uint8_t (*pressed_layers_)[KB_ROWS][KB_COLUMNS]
typedef void (*kbfun_funptr_t)( KBFUN_FUNCTION_ARGS );
void _kbfun_exec_key ( KBFUN_FUNCTION_ARGS );
void kbfun_press_release (KBFUN_FUNCTION_ARGS);
void kbfun_toggle (KBFUN_FUNCTION_ARGS);
void kbfun_layer_inc (KBFUN_FUNCTION_ARGS);
void kbfun_layer_dec (KBFUN_FUNCTION_ARGS);
void kbfun_layer_inc_exec (KBFUN_FUNCTION_ARGS);
void kbfun_layer_dec_exec (KBFUN_FUNCTION_ARGS);
void kbfun_2_keys_capslock_press_release (KBFUN_FUNCTION_ARGS);
void kbfun_layermask_numpad_toggle (KBFUN_FUNCTION_ARGS);
void kbfun_layermask_numpad_on (KBFUN_FUNCTION_ARGS);
void kbfun_layermask_numpad_off (KBFUN_FUNCTION_ARGS);
void kbfun_jump_to_bootloader (KBFUN_FUNCTION_ARGS);
#endif

View File

@ -0,0 +1,121 @@
/* ----------------------------------------------------------------------------
* key functions : private : code
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#include <stdbool.h>
#include <stdint.h>
#include "../../lib-other/pjrc/usb_keyboard/usb_keyboard.h"
#include "../../lib/usb/usage-page/keyboard.h"
#include "../../keyboard/layout.h"
#include "../../keyboard/matrix.h"
#include "../../main.h"
#include "./public.h"
// ----------------------------------------------------------------------------
/*
* Generate a normal keypress or keyrelease
*
* Arguments
* - press: whether to generate a keypress (true) or keyrelease (false)
* - keycode: the keycode to use
*
* Note
* - Because of the way USB does things, what this actually does is either add
* or remove 'keycode' from the list of currently pressed keys, to be sent at
* the end of the current cycle (see main.c)
*/
void _kbfun_press_release(bool press, uint8_t keycode) {
// no-op
if (keycode == 0)
return;
// modifier keys
switch (keycode) {
case KEY_LeftControl: (press)
? (keyboard_modifier_keys |= (1<<0))
: (keyboard_modifier_keys &= ~(1<<0));
return;
case KEY_LeftShift: (press)
? (keyboard_modifier_keys |= (1<<1))
: (keyboard_modifier_keys &= ~(1<<1));
return;
case KEY_LeftAlt: (press)
? (keyboard_modifier_keys |= (1<<2))
: (keyboard_modifier_keys &= ~(1<<2));
return;
case KEY_LeftGUI: (press)
? (keyboard_modifier_keys |= (1<<3))
: (keyboard_modifier_keys &= ~(1<<3));
return;
case KEY_RightControl: (press)
? (keyboard_modifier_keys |= (1<<4))
: (keyboard_modifier_keys &= ~(1<<4));
return;
case KEY_RightShift: (press)
? (keyboard_modifier_keys |= (1<<5))
: (keyboard_modifier_keys &= ~(1<<5));
return;
case KEY_RightAlt: (press)
? (keyboard_modifier_keys |= (1<<6))
: (keyboard_modifier_keys &= ~(1<<6));
return;
case KEY_RightGUI: (press)
? (keyboard_modifier_keys |= (1<<7))
: (keyboard_modifier_keys &= ~(1<<7));
return;
}
// all others
for (uint8_t i=0; i<6; i++) {
if (press) {
if (keyboard_keys[i] == 0) {
keyboard_keys[i] = keycode;
return;
}
} else {
if (keyboard_keys[i] == keycode) {
keyboard_keys[i] = 0;
return;
}
}
}
}
/*
* Is the given keycode pressed?
*/
bool _kbfun_is_pressed(uint8_t keycode) {
// modifier keys
switch (keycode) {
case KEY_LeftControl: if (keyboard_modifier_keys & (1<<0))
return true;
case KEY_LeftShift: if (keyboard_modifier_keys & (1<<1))
return true;
case KEY_LeftAlt: if (keyboard_modifier_keys & (1<<2))
return true;
case KEY_LeftGUI: if (keyboard_modifier_keys & (1<<3))
return true;
case KEY_RightControl: if (keyboard_modifier_keys & (1<<4))
return true;
case KEY_RightShift: if (keyboard_modifier_keys & (1<<5))
return true;
case KEY_RightAlt: if (keyboard_modifier_keys & (1<<6))
return true;
case KEY_RightGUI: if (keyboard_modifier_keys & (1<<7))
return true;
}
// all others
for (uint8_t i=0; i<6; i++)
if (keyboard_keys[i] == keycode)
return true;
return false;
}

View File

@ -0,0 +1,26 @@
/* ----------------------------------------------------------------------------
* key functions : private : exports
*
* Things to be used only by keyfunctions. Exported so layouts can use these
* functions to help define their own, if they like.
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#ifndef LIB__KEY_FUNCTIONS__INTERNAL_h
#define LIB__KEY_FUNCTIONS__INTERNAL_h
#include <stdbool.h>
#include <stdint.h>
#include "../../keyboard/matrix.h"
// --------------------------------------------------------------------
void _kbfun_press_release (bool press, uint8_t keycode);
bool _kbfun_is_pressed (uint8_t keycode);
#endif

View File

@ -0,0 +1,55 @@
/* ----------------------------------------------------------------------------
* key functions : public exports
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#ifndef LIB__KEY_FUNCTIONS__COMMON_h
#define LIB__KEY_FUNCTIONS__COMMON_h
#include <stdbool.h>
#include <stdint.h>
// --------------------------------------------------------------------
// basic
void kbfun_press_release (void);
void kbfun_toggle (void);
void kbfun_transparent (void);
// --- layer push/pop functions
void kbfun_layer_push_1 (void);
void kbfun_layer_push_2 (void);
void kbfun_layer_push_3 (void);
void kbfun_layer_push_4 (void);
void kbfun_layer_push_5 (void);
void kbfun_layer_push_6 (void);
void kbfun_layer_push_7 (void);
void kbfun_layer_push_8 (void);
void kbfun_layer_push_9 (void);
void kbfun_layer_push_10 (void);
void kbfun_layer_pop_1 (void);
void kbfun_layer_pop_2 (void);
void kbfun_layer_pop_3 (void);
void kbfun_layer_pop_4 (void);
void kbfun_layer_pop_5 (void);
void kbfun_layer_pop_6 (void);
void kbfun_layer_pop_7 (void);
void kbfun_layer_pop_8 (void);
void kbfun_layer_pop_9 (void);
void kbfun_layer_pop_10 (void);
// ---
// device
void kbfun_jump_to_bootloader (void);
// special
void kbfun_shift_press_release (void);
void kbfun_2_keys_capslock_press_release (void);
void kbfun_layer_push_numpad (void);
void kbfun_layer_pop_numpad (void);
#endif

View File

@ -0,0 +1,344 @@
/* ----------------------------------------------------------------------------
* key functions : basic : code
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#include "../../../main.h"
#include "../../../keyboard/layout.h"
#include "../public.h"
#include "../private.h"
// ----------------------------------------------------------------------------
#define MAX_LAYER_PUSH_POP_FUNCTIONS 10
// ----------------------------------------------------------------------------
// convenience macros
#define LAYER main_arg_layer
#define LAYER_OFFSET main_arg_layer_offset
#define ROW main_arg_row
#define COL main_arg_col
#define IS_PRESSED main_arg_is_pressed
#define WAS_PRESSED main_arg_was_pressed
// ----------------------------------------------------------------------------
/*
* [name]
* Press|Release
*
* [description]
* Generate a normal keypress or keyrelease
*/
void kbfun_press_release(void) {
uint8_t keycode = kb_layout_get(LAYER, ROW, COL);
_kbfun_press_release(IS_PRESSED, keycode);
}
/*
* [name]
* Toggle
*
* [description]
* Toggle the key pressed or unpressed
*/
void kbfun_toggle(void) {
uint8_t keycode = kb_layout_get(LAYER, ROW, COL);
if (_kbfun_is_pressed(keycode))
_kbfun_press_release(false, keycode);
else
_kbfun_press_release(true, keycode);
}
/*
* [name]
* Transparent
*
* [description]
* Execute the key that would have been executed if the current layer was not
* active
*/
void kbfun_transparent(void) {
LAYER_OFFSET++;
LAYER = main_layers_peek(LAYER_OFFSET);
main_layers_pressed[ROW][COL] = LAYER;
main_exec_key();
}
/* ----------------------------------------------------------------------------
* layer push/pop functions
* ------------------------------------------------------------------------- */
static layer_ids[MAX_LAYER_PUSH_POP_FUNCTIONS];
static void layer_push(uint8_t local_id) {
uint8_t keycode = kb_layout_get(LAYER, ROW, COL);
main_layers_pop_id(layer_ids[local_id]);
layer_ids[local_id] = main_layers_push(keycode);
}
static void layer_pop(uint8_t local_id) {
main_layers_pop_id(layer_ids[local_id]);
layer_ids[local_id] = 0;
}
/*
* [name]
* Layer push #1
*
* [description]
* Push a layer element containing the layer value specified in the keymap to
* the top of the stack, and record the id of that layer element
*/
void kbfun_layer_push_1(void) {
layer_push(1);
}
/*
* [name]
* Layer pop #1
*
* [description]
* Pop the layer element created by the corresponding "layer push" function
* out of the layer stack (no matter where it is in the stack, without
* touching any other elements)
*/
void kbfun_layer_pop_1(void) {
layer_pop(1);
}
/*
* [name]
* Layer push #2
*
* [description]
* Push a layer element containing the layer value specified in the keymap to
* the top of the stack, and record the id of that layer element
*/
void kbfun_layer_push_2(void) {
layer_push(2);
}
/*
* [name]
* Layer pop #2
*
* [description]
* Pop the layer element created by the corresponding "layer push" function
* out of the layer stack (no matter where it is in the stack, without
* touching any other elements)
*/
void kbfun_layer_pop_2(void) {
layer_pop(2);
}
/*
* [name]
* Layer push #3
*
* [description]
* Push a layer element containing the layer value specified in the keymap to
* the top of the stack, and record the id of that layer element
*/
void kbfun_layer_push_3(void) {
layer_push(3);
}
/*
* [name]
* Layer pop #3
*
* [description]
* Pop the layer element created by the corresponding "layer push" function
* out of the layer stack (no matter where it is in the stack, without
* touching any other elements)
*/
void kbfun_layer_pop_3(void) {
layer_pop(3);
}
/*
* [name]
* Layer push #4
*
* [description]
* Push a layer element containing the layer value specified in the keymap to
* the top of the stack, and record the id of that layer element
*/
void kbfun_layer_push_4(void) {
layer_push(4);
}
/*
* [name]
* Layer pop #4
*
* [description]
* Pop the layer element created by the corresponding "layer push" function
* out of the layer stack (no matter where it is in the stack, without
* touching any other elements)
*/
void kbfun_layer_pop_4(void) {
layer_pop(4);
}
/*
* [name]
* Layer push #5
*
* [description]
* Push a layer element containing the layer value specified in the keymap to
* the top of the stack, and record the id of that layer element
*/
void kbfun_layer_push_5(void) {
layer_push(5);
}
/*
* [name]
* Layer pop #5
*
* [description]
* Pop the layer element created by the corresponding "layer push" function
* out of the layer stack (no matter where it is in the stack, without
* touching any other elements)
*/
void kbfun_layer_pop_5(void) {
layer_pop(5);
}
/*
* [name]
* Layer push #6
*
* [description]
* Push a layer element containing the layer value specified in the keymap to
* the top of the stack, and record the id of that layer element
*/
void kbfun_layer_push_6(void) {
layer_push(6);
}
/*
* [name]
* Layer pop #6
*
* [description]
* Pop the layer element created by the corresponding "layer push" function
* out of the layer stack (no matter where it is in the stack, without
* touching any other elements)
*/
void kbfun_layer_pop_6(void) {
layer_pop(6);
}
/*
* [name]
* Layer push #7
*
* [description]
* Push a layer element containing the layer value specified in the keymap to
* the top of the stack, and record the id of that layer element
*/
void kbfun_layer_push_7(void) {
layer_push(7);
}
/*
* [name]
* Layer pop #7
*
* [description]
* Pop the layer element created by the corresponding "layer push" function
* out of the layer stack (no matter where it is in the stack, without
* touching any other elements)
*/
void kbfun_layer_pop_7(void) {
layer_pop(7);
}
/*
* [name]
* Layer push #8
*
* [description]
* Push a layer element containing the layer value specified in the keymap to
* the top of the stack, and record the id of that layer element
*/
void kbfun_layer_push_8(void) {
layer_push(8);
}
/*
* [name]
* Layer pop #8
*
* [description]
* Pop the layer element created by the corresponding "layer push" function
* out of the layer stack (no matter where it is in the stack, without
* touching any other elements)
*/
void kbfun_layer_pop_8(void) {
layer_pop(8);
}
/*
* [name]
* Layer push #9
*
* [description]
* Push a layer element containing the layer value specified in the keymap to
* the top of the stack, and record the id of that layer element
*/
void kbfun_layer_push_9(void) {
layer_push(9);
}
/*
* [name]
* Layer pop #9
*
* [description]
* Pop the layer element created by the corresponding "layer push" function
* out of the layer stack (no matter where it is in the stack, without
* touching any other elements)
*/
void kbfun_layer_pop_9(void) {
layer_pop(9);
}
/*
* [name]
* Layer push #10
*
* [description]
* Push a layer element containing the layer value specified in the keymap to
* the top of the stack, and record the id of that layer element
*/
void kbfun_layer_push_10(void) {
layer_push(10);
}
/*
* [name]
* Layer pop #10
*
* [description]
* Pop the layer element created by the corresponding "layer push" function
* out of the layer stack (no matter where it is in the stack, without
* touching any other elements)
*/
void kbfun_layer_pop_10(void) {
layer_pop(10);
}
/* ----------------------------------------------------------------------------
* ------------------------------------------------------------------------- */

View File

@ -0,0 +1,67 @@
/* ----------------------------------------------------------------------------
* key functions : device specific : code
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#include <avr/interrupt.h>
#include <util/delay.h>
#include "../public.h"
// ----------------------------------------------------------------------------
// descriptions
// ----------------------------------------------------------------------------
/*
* [name]
* Jump to Bootloader
*
* [description]
* For reflashing the controller
*/
void kbfun_jump_to_bootloader(void);
// ----------------------------------------------------------------------------
#if MAKEFILE_BOARD == teensy-2-0
// ----------------------------------------------------------------------------
// from PJRC (slightly modified)
// <http://www.pjrc.com/teensy/jump_to_bootloader.html>
void kbfun_jump_to_bootloader(void) {
// --- for all Teensy boards ---
cli();
// disable watchdog, if enabled
// disable all peripherals
UDCON = 1;
USBCON = (1<<FRZCLK); // disable USB
UCSR1B = 0;
_delay_ms(5);
// --- Teensy 2.0 specific ---
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");
}
// ----------------------------------------------------------------------------
#else
// ----------------------------------------------------------------------------
void kbfun_jump_to_bootloader(void) {}
// ----------------------------------------------------------------------------
#endif
// ----------------------------------------------------------------------------

View File

@ -0,0 +1,152 @@
/* ----------------------------------------------------------------------------
* key functions : special : code
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#include <stdbool.h>
#include <stdint.h>
#include "../../../lib-other/pjrc/usb_keyboard/usb_keyboard.h"
#include "../../../lib/usb/usage-page/keyboard.h"
#include "../../../keyboard/layout.h"
#include "../../../main.h"
#include "../public.h"
#include "../private.h"
// ----------------------------------------------------------------------------
// convenience macros
#define LAYER main_arg_layer
#define LAYER_OFFSET main_arg_layer_offset
#define ROW main_arg_row
#define COL main_arg_col
#define IS_PRESSED main_arg_is_pressed
#define WAS_PRESSED main_arg_was_pressed
// ----------------------------------------------------------------------------
/*
* [name]
* Shift + press|release
*
* [description]
* Generate a 'shift' press or release before the normal keypress or
* keyrelease
*/
void kbfun_shift_press_release(void) {
_kbfun_press_release(IS_PRESSED, KEY_LeftShift);
kbfun_press_release();
}
/*
* [name]
* Two keys => capslock
*
* [description]
* When assigned to two keys (e.g. the physical left and right shift keys)
* (in both the press and release matrices), pressing and holding down one of
* the keys will make the second key toggle capslock
*
* [note]
* If either of the shifts are pressed when the second key is pressed, they
* wil be released so that capslock will register properly when pressed.
* Capslock will then be pressed and released, and the original state of the
* shifts will be restored
*/
void kbfun_2_keys_capslock_press_release(void) {
static uint8_t keys_pressed;
static bool lshift_pressed;
static bool rshift_pressed;
uint8_t keycode = kb_layout_get(LAYER, ROW, COL);
if (!IS_PRESSED) keys_pressed--;
// take care of the key that was actually pressed
_kbfun_press_release(IS_PRESSED, keycode);
// take care of capslock (only on the press of the 2nd key)
if (keys_pressed == 1 && IS_PRESSED) {
// save the state of left and right shift
lshift_pressed = _kbfun_is_pressed(KEY_LeftShift);
rshift_pressed = _kbfun_is_pressed(KEY_RightShift);
// disable both
_kbfun_press_release(false, KEY_LeftShift);
_kbfun_press_release(false, KEY_RightShift);
// press capslock, then release it
_kbfun_press_release(true, KEY_CapsLock);
usb_keyboard_send();
_kbfun_press_release(false, KEY_CapsLock);
usb_keyboard_send();
// restore the state of left and right shift
if (lshift_pressed)
_kbfun_press_release(true, KEY_LeftShift);
if (rshift_pressed)
_kbfun_press_release(true, KEY_RightShift);
}
if (IS_PRESSED) keys_pressed++;
}
/* ----------------------------------------------------------------------------
* numpad functions
* ------------------------------------------------------------------------- */
static uint8_t numpad_layer_id;
static inline void numpad_toggle_numlock(void) {
_kbfun_press_release(true, KEY_LockingNumLock);
usb_keyboard_send();
_kbfun_press_release(false, KEY_LockingNumLock);
usb_keyboard_send();
}
/*
* [name]
* Numpad on
*
* [description]
* Set the numpad to on (put the numpad layer, specified in the keymap, in an
* element at the top of the layer stack, and record that element's id) and
* toggle numlock (regardless of whether or not numlock is currently on)
*
* [note]
* Meant to be assigned (along with "numpad off") instead of a normal numlock
* key
*/
void kbfun_layer_push_numpad(void) {
uint8_t keycode = kb_layout_get(LAYER, ROW, COL);
main_layers_pop_id(numpad_layer_id);
numpad_layer_id = main_layers_push(keycode);
numpad_toggle_numlock();
}
/*
* [name]
* Numpad off
*
* [description]
* Set the numpad to off (pop the layer element created by "numpad on" out of
* the stack) and toggle numlock (regardless of whether or not numlock is
* currently on)
*
* [note]
* Meant to be assigned (along with "numpad on") instead of a normal numlock
* key
*/
void kbfun_layer_pop_numpad(void) {
main_layers_pop_id(numpad_layer_id);
numpad_layer_id = 0;
numpad_toggle_numlock();
}
/* ----------------------------------------------------------------------------
* ------------------------------------------------------------------------- */

View File

@ -0,0 +1,12 @@
# src/lib/key-functions
These functions may do.. pretty much anything rational that they like. If they
want keycodes to be sent to the host in an aggregate report, they're responsible
for modifying the appropriate report variables.
-------------------------------------------------------------------------------
Copyright &copy; 2012 Ben Blazak <benblazak.dev@gmail.com>
Released under The MIT License (MIT) (see "license.md")
Project located at <https://github.com/benblazak/ergodox-firmware>

View File

@ -10,14 +10,7 @@
* ------------------------------------------------------------------------- */
#undef _str
#undef _expstr
#undef _inc
#define _str(s) #s // stringify
#define _expstr(s) _str(s) // expand -> stringify
#define _inc _expstr(twi/MAKEFILE_BOARD.h) // inc(lude)
#include _inc
#undef _str
#undef _expstr
#undef _inc
#include "../lib/variable-include.h"
#define INCLUDE EXP_STR( ./twi/MAKEFILE_BOARD.h )
#include INCLUDE

View File

@ -21,10 +21,17 @@
* ------------------------------------------------------------------------- */
#include <util/twi.h>
#include "lib/twi.h"
// ----------------------------------------------------------------------------
// conditional compile
#if MAKEFILE_BOARD == teensy-2-0
// ----------------------------------------------------------------------------
#include <util/twi.h>
#include "./teensy-2-0.h"
// ----------------------------------------------------------------------------
void twi_init(void) {
// set the prescaler value to 0
TWSR &= ~( (1<<TWPS1)|(1<<TWPS0) );
@ -81,3 +88,8 @@ uint8_t twi_read(uint8_t * data) {
return 0; // success
}
// ----------------------------------------------------------------------------
#endif
// ----------------------------------------------------------------------------

View File

@ -10,16 +10,19 @@
#ifndef TWI_h
#define TWI_h
// --------------------------------------------------------------------
#ifndef TWI_FREQ
#define TWI_FREQ 100000 // in Hz
#endif
// --------------------------------------------------------------------
void twi_init(void);
uint8_t twi_start(void);
void twi_stop(void);
uint8_t twi_send(uint8_t data);
uint8_t twi_read(uint8_t * data);
void twi_init (void);
uint8_t twi_start (void);
void twi_stop (void);
uint8_t twi_send (uint8_t data);
uint8_t twi_read (uint8_t * data);
#endif

View File

@ -39,6 +39,8 @@
// TODO
// - read the hid device class definition .pdf
// - set USB vendor ID = 0x1d50 // Openmoko, Inc.
// USB product ID = 0x6028 // ErgoDox ergonomic keyboard
// DONE
// - read the hid usage tables .pdf

View File

@ -36,7 +36,7 @@
// ----------------------------------------------------------------------------
#include "lib/data-types.h"
#include <stdint.h>
// ----------------------------------------------------------------------------

View File

@ -17,7 +17,7 @@
// ----------------------------------------------------------------------------
#include "keyboard.h"
#include "./keyboard.h"
// ----------------------------------------------------------------------------

View File

@ -0,0 +1,13 @@
/* ----------------------------------------------------------------------------
* Macros to help with conditional includes
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#undef INCLUDE
#define STR(s) #s // stringify
#define EXP_STR(s) STR(s) // expand -> stringify

View File

@ -8,14 +8,45 @@
* ------------------------------------------------------------------------- */
#include <stdbool.h>
#include <stdint.h>
#include <util/delay.h>
#include "lib-other/pjrc/usb_keyboard/usb_keyboard.h"
#include "lib/data-types.h"
#include "lib/key-functions.h"
#include "./lib-other/pjrc/usb_keyboard/usb_keyboard.h"
#include "./lib/key-functions/public.h"
#include "./keyboard/controller.h"
#include "./keyboard/layout.h"
#include "./keyboard/matrix.h"
#include "./main.h"
#include "keyboard.h"
// ----------------------------------------------------------------------------
#define MAX_ACTIVE_LAYERS 20
// ----------------------------------------------------------------------------
static bool _main_kb_is_pressed[KB_ROWS][KB_COLUMNS];
bool (*main_kb_is_pressed)[KB_ROWS][KB_COLUMNS] = &_main_kb_is_pressed;
static bool _main_kb_was_pressed[KB_ROWS][KB_COLUMNS];
bool (*main_kb_was_pressed)[KB_ROWS][KB_COLUMNS] = &_main_kb_was_pressed;
uint8_t main_layers_pressed[KB_ROWS][KB_COLUMNS];
uint8_t main_loop_row;
uint8_t main_loop_col;
uint8_t main_arg_layer;
uint8_t main_arg_layer_offset;
uint8_t main_arg_row;
uint8_t main_arg_col;
bool main_arg_is_pressed;
bool main_arg_was_pressed;
// ----------------------------------------------------------------------------
/*
* main()
*/
int main(void) {
kb_init(); // does controller initialization too
@ -28,24 +59,15 @@ int main(void) {
kb_led_state_ready();
for (;;) {
// the overall current layer
static uint8_t current_layer;
// the current layer for each key
static uint8_t current_layers[KB_ROWS][KB_COLUMNS];
// the layer each key was on when it was last pressed
static uint8_t pressed_layers[KB_ROWS][KB_COLUMNS];
// swap `main_kb_is_pressed` and `main_kb_was_pressed`, then update
bool (*temp)[KB_ROWS][KB_COLUMNS] = main_kb_was_pressed;
main_kb_was_pressed = main_kb_is_pressed;
main_kb_is_pressed = temp;
// swap `kb_is_pressed` and `kb_was_pressed`, then update
bool (*temp)[KB_ROWS][KB_COLUMNS] = kb_was_pressed;
kb_was_pressed = kb_is_pressed;
kb_is_pressed = temp;
kb_update_matrix(*kb_is_pressed);
kb_update_matrix(*main_kb_is_pressed);
// this loop is responsible to
// - "execute" keys when they change state (call `_kbfun_exec_key()`,
// which will call the appropriate function with the appropriate
// keycode argument from the kb_layout* matrices)
// - "execute" keys when they change state
// - keep track of which layers the keys were on when they were pressed
// (so they can be released using the function from that layer)
//
@ -53,34 +75,42 @@ int main(void) {
// - everything else is the key function's responsibility
// - see the keyboard layout file ("keyboard/ergodox/layout/*.c") for
// which key is assigned which function (per layer)
// - see "lib/key-functions.c" for the function definitions
// - anything passed to the key function by reference is fair game for
// that function to modify
for (uint8_t row=0; row<KB_ROWS; row++) {
for (uint8_t col=0; col<KB_COLUMNS; col++) {
bool is_pressed = (*kb_is_pressed)[row][col];
bool was_pressed = (*kb_was_pressed)[row][col];
// - see "lib/key-functions/public/*.c" for the function definitions
#define row main_loop_row
#define col main_loop_col
#define layer main_arg_layer
#define is_pressed main_arg_is_pressed
#define was_pressed main_arg_was_pressed
for (row=0; row<KB_ROWS; row++) {
for (col=0; col<KB_COLUMNS; col++) {
is_pressed = (*main_kb_is_pressed)[row][col];
was_pressed = (*main_kb_was_pressed)[row][col];
if (is_pressed != was_pressed) {
uint8_t layer = ( (is_pressed)
? current_layers[row][col]
: pressed_layers[row][col] );
if (is_pressed) {
layer = main_layers_peek(0);
main_layers_pressed[row][col] = layer;
} else {
layer = main_layers_pressed[row][col];
}
if (is_pressed)
pressed_layers[row][col] = layer;
_kbfun_exec_key(
is_pressed, 0, layer,
&row, &col, &current_layer,
&current_layers, &pressed_layers );
// set remaining vars, and "execute" key
main_arg_row = row;
main_arg_col = col;
main_arg_layer_offset = 0;
main_exec_key();
}
}
}
#undef row
#undef col
#undef layer
#undef is_pressed
#undef was_pressed
// send the USB report (even if nothing's changed)
usb_keyboard_send();
_delay_ms(KB_DEBOUNCE_TIME);
_delay_ms(MAKEFILE_DEBOUNCE_TIME);
// update LEDs
if (keyboard_leds & (1<<0)) { kb_led_num_on(); }
@ -98,3 +128,145 @@ int main(void) {
return 0;
}
// ----------------------------------------------------------------------------
// convenience macros (for the helper functions below)
#define layer main_arg_layer
#define row main_arg_row
#define col main_arg_col
#define is_pressed main_arg_is_pressed
#define was_pressed main_arg_was_pressed
// ----------------------------------------------------------------------------
/*
* Exec key
* - Execute the keypress or keyrelease function (if it exists) of the key at
* the current possition.
*/
void main_exec_key(void) {
void (*key_function)(void) =
( (is_pressed)
? kb_layout_press_get(layer, row, col)
: kb_layout_release_get(layer, row, col) );
if (key_function)
(*key_function)();
}
/* ----------------------------------------------------------------------------
* Layer Functions
* ----------------------------------------------------------------------------
* We keep track of which layer is foremost by placing it on a stack. Layers
* may appear in the stack more than once. The base layer will always be
* layer-0.
*
* Implemented as a fixed size stack.
* ------------------------------------------------------------------------- */
// ----------------------------------------------------------------------------
struct layers {
uint8_t layer;
uint8_t id;
};
// ----------------------------------------------------------------------------
struct layers layers[MAX_ACTIVE_LAYERS];
uint8_t layers_head = 0;
uint8_t layers_ids_in_use[MAX_ACTIVE_LAYERS] = {true};
/*
* peek()
*
* Arguments
* - 'offset': the offset (down the stack) from the head element
*
* Returns
* - success: the layer-number of the requested element (which may be 0)
* - failure: 0 (default) (out of bounds)
*/
uint8_t main_layers_peek(uint8_t offset) {
if (offset <= layers_head)
return layers[layers_head - offset].layer;
return 0; // default, or error
}
/*
* push()
*
* Arguments
* - 'layer': the layer-number to push to the top of the stack
*
* Returns
* - success: the id assigned to the newly added element
* - failure: 0 (the stack was already full)
*/
uint8_t main_layers_push(uint8_t layer) {
// look for an available id
for (uint8_t id=1; id<MAX_ACTIVE_LAYERS; id++)
// if one is found
if (layers_ids_in_use[id] == false) {
layers_ids_in_use[id] = true;
layers_head++;
layers[layers_head].layer = layer;
layers[layers_head].id = id;
return id;
}
return 0; // default, or error
}
/*
* pop_id()
*
* Arguments
* - 'id': the id of the element to pop from the stack
*/
void main_layers_pop_id(uint8_t id) {
// look for the element with the id we want to pop
for (uint8_t element=1; element<=layers_head; element++)
// if we find it
if (layers[element].id == id) {
// move all layers above it down one
for (; element<layers_head; element++) {
layers[element].layer = layers[element+1].layer;
layers[element].id = layers[element+1].id;
}
// reinitialize the topmost (now unused) slot
layers[layers_head].layer = 0;
layers[layers_head].id = 0;
// record keeping
layers_ids_in_use[id] = false;
layers_head--;
}
}
/*
* get_offset_id()
*
* Arguments
* - 'id': the id of the element you want the offset of
*
* Returns
* - success: the offset (down the stack from the head element) of the element
* with the given id
* - failure: 0 (default) (id unassigned)
*/
uint8_t main_layers_get_offset_id(uint8_t id) {
// look for the element with the id we want to get the offset of
for (uint8_t element=1; element<=layers_head; element++)
// if we find it
if (layers[element].id == id)
return (layers_head - element);
return 0; // default, or error
}
/* ----------------------------------------------------------------------------
* ------------------------------------------------------------------------- */

46
src/main.h Normal file
View File

@ -0,0 +1,46 @@
/* ----------------------------------------------------------------------------
* main() : functions and data that may be useful externally
* ----------------------------------------------------------------------------
* Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
* Released under The MIT License (MIT) (see "license.md")
* Project located at <https://github.com/benblazak/ergodox-firmware>
* ------------------------------------------------------------------------- */
#ifndef MAIN_h
#define MAIN_h
#include <stdbool.h>
#include <stdint.h>
#include "./lib/key-functions/public.h"
#include "./keyboard/matrix.h"
// --------------------------------------------------------------------
extern bool (*main_kb_is_pressed)[KB_ROWS][KB_COLUMNS];
extern bool (*main_kb_was_pressed)[KB_ROWS][KB_COLUMNS];
extern uint8_t main_layers_pressed[KB_ROWS][KB_COLUMNS];
extern uint8_t main_loop_row;
extern uint8_t main_loop_col;
extern uint8_t main_arg_layer;
extern uint8_t main_arg_layer_offset;
extern uint8_t main_arg_row;
extern uint8_t main_arg_col;
extern bool main_arg_is_pressed;
extern bool main_arg_was_pressed;
// --------------------------------------------------------------------
void main_exec_key (void);
uint8_t main_layers_peek (uint8_t offset);
uint8_t main_layers_push (uint8_t layer);
void main_layers_pop_id (uint8_t id);
uint8_t main_layers_get_offset_id (uint8_t id);
#endif

View File

@ -13,15 +13,12 @@
# -----------------------------------------------------------------------------
TARGET := firmware # the name we want for our program binary
FORMAT := ihex # the program binary's format
KEYBOARD := ergodox # keyboard model; see "src/keyboard" for what's available
LAYOUT := qwerty # keyboard layout; see "src/keyboard/*/layout" for what's
# available
include makefile-options
MCU := atmega32u4 # processor type (for teensy 2.0); must match real life
BOARD := teensy-2-0 # see the libraries you're using for what's available
F_CPU := 16000000 # processor speed, in Hz
FORMAT := ihex # the program binary's format
MCU := atmega32u4 # processor type (for teensy 2.0); must match real life
BOARD := teensy-2-0 # see the libraries you're using for what's available
F_CPU := 16000000 # processor speed, in Hz
# firmware stuff
SRC := $(wildcard *.c)
@ -32,8 +29,11 @@ LAYOUT := $(strip $(LAYOUT))
# --- include stuff
SRC += $(wildcard keyboard/$(KEYBOARD)*.c)
SRC += $(wildcard keyboard/$(KEYBOARD)/*.c)
SRC += $(wildcard keyboard/$(KEYBOARD)/controller/*.c)
SRC += $(wildcard keyboard/$(KEYBOARD)/layout/$(LAYOUT)*.c)
# library stuff
# - should be last in the list of files to compile, in case there are default
# macros that have to be overridden in other source files
# - add more "*/*/..."s as necessary to compile everything.
# - parts of the stuff under "lib" may not be necessary, depending on other
# options, but it's all included here. hopefully any unnecessary stuff gets
@ -48,15 +48,17 @@ SRC += $(wildcard lib-other/*/*/*.c)
OBJ = $(SRC:%.c=%.o)
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
CFLAGS := -mmcu=$(MCU) # processor type (teensy 2.0); must match real
# life
CFLAGS += -DF_CPU=$(F_CPU) # processor frequency; must match initialization
# in source
CFLAGS += -I. # search for includes in the current directory
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
CFLAGS += -DMAKEFILE_BOARD='$(strip $(BOARD))'
CFLAGS += -DMAKEFILE_KEYBOARD='$(strip $(KEYBOARD))'
CFLAGS += -DMAKEFILE_KEYBOARD_LAYOUT='$(strip $(LAYOUT))'
CFLAGS += -DMAKEFILE_DEBOUNCE_TIME='$(strip $(DEBOUNCE_TIME))'
CFLAGS += -DMAKEFILE_LED_BRIGHTNESS='$(strip $(LED_BRIGHTNESS))'
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
CFLAGS += -std=gnu99 # use C99 plus GCC extensions
CFLAGS += -Os # optimize for size
@ -83,6 +85,7 @@ LDFLAGS += -Wl,--gc-sections # discard unused functions and data
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
GENDEPFLAGS += -MMD -MP -MF $@.dep # generate dependency files
# . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
CC := avr-gcc
@ -90,10 +93,10 @@ OBJCOPY := avr-objcopy
SIZE := avr-size
# remove whitespace from some of the variables
TARGET := $(strip $(TARGET))
# remove whitespace from some of the options
FORMAT := $(strip $(FORMAT))
# -----------------------------------------------------------------------------
# -----------------------------------------------------------------------------
@ -108,11 +111,6 @@ all: $(TARGET).hex $(TARGET).eep
@echo
$(SIZE) --target=$(FORMAT) $(TARGET).eep
@echo
@echo '. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .'
@echo
$(SIZE) -C --mcu=atmega32u4 $(TARGET).elf
@echo '. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .'
@echo
@echo 'you can load "$(TARGET).hex" and "$(TARGET).eep" onto the'
@echo 'Teensy using the Teensy loader'
@echo

26
src/makefile-options Normal file
View File

@ -0,0 +1,26 @@
# -----------------------------------------------------------------------------
# certain compilations options
# -----------------------------------------------------------------------------
# Copyright (c) 2012 Ben Blazak <benblazak.dev@gmail.com>
# Released under The MIT License (MIT) (see "license.md")
# Project located at <https://github.com/benblazak/ergodox-firmware>
# -----------------------------------------------------------------------------
TARGET := firmware # the name we want for our program binary
KEYBOARD := ergodox # keyboard model; see "src/keyboard" for what's available
LAYOUT := qwerty-kinesis-mod # keyboard layout
# see "src/keyboard/*/layout" for what's
# available
LED_BRIGHTNESS := 0.5 # a multiplier, with 1 being the max
DEBOUNCE_TIME := 5 # in ms; see keyswitch spec for necessary value; 5ms should
# be good for cherry mx switches
# remove whitespace
TARGET := $(strip $(TARGET))
KEYBOARD := $(strip $(KEYBOARD))
LAYOUT := $(strip $(LAYOUT))
DEBOUNCE_TIME := $(strip $(DEBOUNCE_TIME))