diff --git a/build-scripts/gen-layout.py b/build-scripts/gen-layout.py deleted file mode 100755 index fd5e54c..0000000 --- a/build-scripts/gen-layout.py +++ /dev/null @@ -1,423 +0,0 @@ -#! /usr/bin/env python3 -# ----------------------------------------------------------------------------- -# Copyright (c) 2012 Ben Blazak -# Released under The MIT License (MIT) (see "license.md") -# Project located at -# ----------------------------------------------------------------------------- - -""" -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 = (""" - - - - - - - - - -

Firmware Layout

- - - -

Notes

- - - -
- -""")[1:-1] - - # suffix - doc.suffix = (""" - - - -""")[1:-1] - - # substitute into template - # ------- - # note: this is not general enough to handle any possible layout well, at - # the moment. but it should handle more standard ones well. (hopefully - # minor) modifications may be necessary on a case by case basis - # ------- - layer_number = -1 - for (layout, layer) in zip( info.matrix_layout, - range(len(info.matrix_layout))): - layer_number += 1 - svg = template.svg - for (name, (code, press, release)) \ - in zip(info.matrix_positions, layout): - replace = '' - if press == 'kbfun_transparent': - replace = '' - elif press == 'kbfun_shift_press_release': - replace = 'sh ' + keycode_to_string.get(code, '[n/a]') - elif press == 'kbfun_jump_to_bootloader': - replace = '[btldr]' - elif press == 'NULL' and release == 'NULL': - replace = '(null)' - elif re.search(r'numpad', press+release): - replace = '[num]' - elif re.search(r'layer', press+release): - replace = 'la ' + re.findall(r'\d+', press+release)[0] + ' ' - if re.search(r'push', press+release): - replace += '+' - if re.search(r'pop', press+release): - replace += '-' - replace += ' ' + str(code) - 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 += '

Layer ' + str(layer_number) + '

\n' + svg - - # change the font size - doc.main = re.sub(r'22.5px', '15px', doc.main) - - 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() - diff --git a/build-scripts/gen-ui-info.py b/build-scripts/gen-ui-info.py deleted file mode 100755 index 1c93d32..0000000 --- a/build-scripts/gen-ui-info.py +++ /dev/null @@ -1,477 +0,0 @@ -#! /usr/bin/env python3 -# ----------------------------------------------------------------------------- -# Copyright (c) 2012 Ben Blazak -# Released under The MIT License (MIT) (see "license.md") -# Project located at -# ----------------------------------------------------------------------------- - -""" -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": "", - "date-generated": "", // format: RFC 3339 - "description": "", - }, - "keyboard-functions": { - "<(function name)>": { - "position": "", // as given by the .map file - "length": "", // as given by the .map file - "comments": { - "name": "", // more user friendly name - "description": "", - "notes": [ - "", - "..." - ], - "..." - } - }, - "..." - }, - "layout-matrices": { - "<(matrix name)>": { - "position": "", // as given by the .map file - "length": "" // 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 - "", "..." - ], - "matrix-positions": [ // list of key-ids - "", "..." - ], - "matrix-layout": [ - [ // begin layer - [ // begin key - "", // keycode - "", // press function name (ex: 'kbfun_...') - "" // release function name (ex: 'NULL') - ], - "..." // more keys - ], - "..." // more layers - ] - }, - "miscellaneous": { - "git-commit-date": "", // format: RFC 3339 - "git-commit-id": "", - "number-of-layers": "" - } -} -""")[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): - return {} # don't really need this info anymore -# """ -# 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): - return {} # don't really need this info anymore -# """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() - diff --git a/build-scripts/gen_layout/template.js b/build-scripts/gen_layout/template.js deleted file mode 100644 index c3690d0..0000000 --- a/build-scripts/gen_layout/template.js +++ /dev/null @@ -1,3 +0,0 @@ -function keyclick(position, layer) { -} - diff --git a/build-scripts/gen_layout/template.svg b/build-scripts/gen_layout/template.svg deleted file mode 100644 index 373da08..0000000 --- a/build-scripts/gen_layout/template.svg +++ /dev/null @@ -1,2109 +0,0 @@ - - - - - - - - - - - - - - - - image/svg+xml - - - - - - - k57 - k58 - k59 - k5A - k5B - k5C - k5D - k4D - k3D - k2D - k4C - k3C - k2C - k1C - k1D - k4B - k3B - k2B - k1B - k4A - k3A - k2A - k1A - k49 - k39 - k29 - k19 - k48 - k38 - k28 - k47 - k27 - k08 - k07 - k09 - k0C - k56 - k55 - k54 - k52 - k51 - k40 - k30 - k20 - k41 - k31 - k21 - k11 - k10 - k42 - k32 - k22 - k12 - k43 - k33 - k23 - k13 - k44 - k34 - k24 - k14 - k45 - k35 - k25 - k46 - k26 - k05 - k06 - k04 - k01 - k50 - k53 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - k0B - k0A - k02 - k03 - - - - - - - - - - diff --git a/contrib/readme.md b/contrib/readme.md deleted file mode 100644 index ff0a5fb..0000000 --- a/contrib/readme.md +++ /dev/null @@ -1,2 +0,0 @@ -This directory is for projects closely related to the firmware. -