From df7bb3a7d209c52ccd760d21a6855b23ae4bf420 Mon Sep 17 00:00:00 2001 From: Ben Blazak Date: Mon, 8 Oct 2012 18:01:06 -0700 Subject: [PATCH] working on layout graphic generator; almost there! - also, additions to the ui-info.json file generator - and probably some other small but useful things --- ...-template.svg => gen-layout--template.svg} | 0 .../{gen-layout-graphic.py => gen-layout.py} | 50 ++++++++--- build-scripts/gen-ui-info.py | 76 +++++++++++++--- makefile | 90 ++++++++++++------- src/makefile | 20 ++--- src/makefile-options | 24 +++++ 6 files changed, 188 insertions(+), 72 deletions(-) rename build-scripts/{gen-layout-graphic--template.svg => gen-layout--template.svg} (100%) rename build-scripts/{gen-layout-graphic.py => gen-layout.py} (82%) mode change 100644 => 100755 create mode 100644 src/makefile-options diff --git a/build-scripts/gen-layout-graphic--template.svg b/build-scripts/gen-layout--template.svg similarity index 100% rename from build-scripts/gen-layout-graphic--template.svg rename to build-scripts/gen-layout--template.svg diff --git a/build-scripts/gen-layout-graphic.py b/build-scripts/gen-layout.py old mode 100644 new mode 100755 similarity index 82% rename from build-scripts/gen-layout-graphic.py rename to build-scripts/gen-layout.py index a93e116..eb856ca --- a/build-scripts/gen-layout-graphic.py +++ b/build-scripts/gen-layout.py @@ -1,7 +1,9 @@ -!# /usr/bin/env python3 +#! /usr/bin/env python3 import argparse import json +import os +import re import sys # ----------------------------------------------------------------------------- @@ -12,24 +14,38 @@ def main(): + "keyboard layout" ) arg_parser.add_argument( - '--map-file', - required = True ) - - arg_parser.add_argument( - '--hex-file', - required = True ) - - arg_parser.add_argument( - '--eep-file', + '--ui-info-file', required = True ) args = arg_parser.parse_args(sys.argv[1:]) + args.template_file = './build-scripts/gen-layout--template.svg' + + # normalize paths + args.ui_info_file = os.path.abspath(args.ui_info_file) + + # do stuff + doc = '' # to store the html document we're generating + template = open(args.template_file).read() + info = json.loads(open(args.ui_info_file).read()) + + matrix_positions = info['mappings']['matrix-positions'] + matrix_layout = info['mappings']['matrix-layout'] + + # only consider keycodes, for now + for layout in matrix_layout: + template_copy = template + for (name, (code, press, release)) \ + in zip(matrix_positions, layout): + template_copy = re.sub( name, + keycode_to_string.get(code, '[n/a]'), + template_copy ) + + doc += template_copy + + print(doc) + # ----------------------------------------------------------------------------- - -if __name__ == '__main__': - main() - # ----------------------------------------------------------------------------- keycode_to_string = { @@ -264,3 +280,9 @@ keycode_to_string = { 0xE7: "RightGUI", } +# ----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- + +if __name__ == '__main__': + main() + diff --git a/build-scripts/gen-ui-info.py b/build-scripts/gen-ui-info.py index a6df601..30dd2f1 100755 --- a/build-scripts/gen-ui-info.py +++ b/build-scripts/gen-ui-info.py @@ -39,6 +39,10 @@ The file will contain: ], "matrix-positions": [ , ... + ], + "matrix-layout": [ + [ [ , , ], ... ], + ... ] }, "miscellaneous": { @@ -274,22 +278,63 @@ def find_keyboard_functions(source_code_path): return output -def find_mappings(matrix_file_path): +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) - match = re.search( - r'#define\s+KB_MATRIX_LAYER\s*\(([^)]+)\)[^{]*\{\{([^#]+)\}\}', - open(matrix_file_path).read(), - re.MULTILINE ) + 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']] + + 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) ) - return { - "mappings": { - "physical-positions": re.findall(r'k..', match.group(1)), - "matrix-positions": re.findall(r'k..|na', match.group(2)), - }, - } - # ----------------------------------------------------------------------------- @@ -345,6 +390,10 @@ def main(): '--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:]) @@ -354,7 +403,8 @@ def main(): 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, find_mappings(args.matrix_file_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)) diff --git a/makefile b/makefile index 9fb19f0..11ffeb6 100644 --- a/makefile +++ b/makefile @@ -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,32 +19,35 @@ # ----------------------------------------------------------------------------- -# the base name of the file or package to distribute -NAME := ergodox-firmware -# the name of the keyboard we're building -# - must match the same variable in src/makefile -KEYBOARD := ergodox +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-) -UNAME := $(shell uname) -ifeq ($(UNAME),Darwin) - DATE := gdate -else - DATE := date -endif # name to use for the final distribution file or package -TARGET := $(NAME)--$(GIT_BRANCH)--$(shell $(DATE) -d "$(GIT_COMMIT_DATE)" +'%Y%m%dT%H%M%S')--$(shell echo $(GIT_COMMIT_ID) | cut -c 1-7) +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 @@ -51,29 +55,51 @@ clean: git clean -dX # remove ignored files and directories -rm -r '$(BUILD)' -dist: - # make sure we're checked in - -git commit -a - # 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)' ) - # run secondary build scripts - ( ./build-scripts/gen-ui-info.py \ - --current-date '$(shell $(DATE) --rfc-3339 s)' \ + +$(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' \ - ) > '$(BUILD)/$(TARGET)/firmware--ui-info.json' - # make into a zip archive + --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 * .* \ diff --git a/src/makefile b/src/makefile index 70bd3d3..1a9e914 100644 --- a/src/makefile +++ b/src/makefile @@ -13,18 +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 - -DEBOUNCE_TIME := 5 # in ms; see keyswitch spec for necessary value; 5ms should - # be good for cherry mx switches +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) @@ -98,10 +92,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)) + # ----------------------------------------------------------------------------- # ----------------------------------------------------------------------------- diff --git a/src/makefile-options b/src/makefile-options new file mode 100644 index 0000000..0c80e80 --- /dev/null +++ b/src/makefile-options @@ -0,0 +1,24 @@ +# ----------------------------------------------------------------------------- +# certain compilations options +# ----------------------------------------------------------------------------- +# Copyright (c) 2012 Ben Blazak +# Released under The MIT License (MIT) (see "license.md") +# Project located at +# ----------------------------------------------------------------------------- + + +TARGET := firmware # the name we want for our program binary +KEYBOARD := ergodox # keyboard model; see "src/keyboard" for what's available +LAYOUT := qwerty # keyboard layout; see "src/keyboard/*/layout" for what's + # available + +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)) +