diff --git a/contrib/readme.md b/contrib/readme.md new file mode 100644 index 0000000..ff0a5fb --- /dev/null +++ b/contrib/readme.md @@ -0,0 +1,2 @@ +This directory is for projects closely related to the firmware. + diff --git a/makefile b/makefile new file mode 100644 index 0000000..2d03791 --- /dev/null +++ b/makefile @@ -0,0 +1,61 @@ +# ----------------------------------------------------------------------------- +# makefile for the ergoDOX project +# +# 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. +# +# TODO: +# - include doc files (and maybe render them in html) +# - include the UI stuff (once it's done) +# ----------------------------------------------------------------------------- +# Copyright (c) 2012 Ben Blazak +# Released under The MIT License (MIT) (see "license.md") +# Project located at +# ----------------------------------------------------------------------------- + + +# 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') + +# name to use for the final distribution file or package +TARGET := $(NAME)--$(BRANCH)--$(VERSION) + +# the build dir +BUILD := build + +# ----------------------------------------------------------------------------- +# ----------------------------------------------------------------------------- + +.PHONY: all clean dist + +all: dist + +clean: + git clean -dX # remove ignored files and directories + -rm -r '$(BUILD)' + +dist: + # set up the build dir + -rm -r '$(BUILD)/$(TARGET)'* + -mkdir -p '$(BUILD)/$(TARGET)' + # make all subprojects + 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 + ( cd '$(BUILD)/$(TARGET)'; \ + zip '../$(TARGET).zip' \ + -r * .* \ + -x '..*' ) + diff --git a/references.md b/references.md index c6b899c..c8c3bdb 100644 --- a/references.md +++ b/references.md @@ -377,6 +377,17 @@ ## Miscellaneous +### Keyboard Testing Tools + +* [Understanding Rollover] + (http://gadzikowski.com/nkeyrollover.html) + Includes 3 different tests (2 of which are web based) to see which keys are + actually registering as pressed. + + * mentioned on the [Default:NKey Rollover] + (http://geekhack.org/showwiki.php?title=NKey+Rollover+-+Overview+Testing+Methodology+and+Results) + page (on ) + ### Typical Keyboard Information * [Keyboard Scan Rates] diff --git a/.gitignore b/src/.gitignore similarity index 75% rename from .gitignore rename to src/.gitignore index b7bdca1..ec1ee50 100644 --- a/.gitignore +++ b/src/.gitignore @@ -1,9 +1,7 @@ -*~ -*.swp - -*.hex *.eep *.elf +*.hex +*.map *.o *.o.dep diff --git a/src/keyboard/ergodox.c b/src/keyboard/ergodox.c index 12b5f32..a55bfb9 100644 --- a/src/keyboard/ergodox.c +++ b/src/keyboard/ergodox.c @@ -9,10 +9,9 @@ #include "lib/data-types.h" -#define KEYBOARD_INCLUDE_PRIVATE #include "ergodox/matrix.h" -#include "ergodox/mcp23018.h" -#include "ergodox/teensy-2-0.h" +#include "ergodox/mcp23018--private.h" +#include "ergodox/teensy-2-0--private.h" /* returns diff --git a/src/keyboard/ergodox.h b/src/keyboard/ergodox.h index 5174f31..00ba51e 100644 --- a/src/keyboard/ergodox.h +++ b/src/keyboard/ergodox.h @@ -16,7 +16,6 @@ #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/mcp23018.h" // (nothing right now) #include "ergodox/teensy-2-0.h" // LED controls diff --git a/src/keyboard/ergodox/circuit-diagram.svg b/src/keyboard/ergodox/circuit-diagram.svg index ce67d59..da586fb 100644 --- a/src/keyboard/ergodox/circuit-diagram.svg +++ b/src/keyboard/ergodox/circuit-diagram.svg @@ -12,9 +12,9 @@ inkscape:version="0.48.2 r9819" version="1.1" id="svg2" - height="398.98083" + height="416.48083" width="950.8382" - sodipodi:docname="_circuit-diagram.svg" + sodipodi:docname="circuit-diagram.svg" inkscape:export-filename="/home/ben/Desktop/programs/20120227--ergodox-firmware--for-the-ergodox-keyboard/src/test - circuit diagram/inkscape/_circuit-diagram.png" inkscape:export-xdpi="150" inkscape:export-ydpi="150"> @@ -26,8 +26,8 @@ inkscape:pageopacity="1" inkscape:pageshadow="2" inkscape:zoom="1.4142136" - inkscape:cx="477.26232" - inkscape:cy="197.75046" + inkscape:cx="464.65225" + inkscape:cy="203.44926" inkscape:document-units="px" inkscape:current-layer="layer7" showgrid="true" @@ -1924,22 +1924,22 @@ sodipodi:nodetypes="ccccccccccccc" /> + sodipodi:nodetypes="ccszzcc" /> PWM PWM PWM - Please also see documentation (especially the notes) in the *.md files + y="388.43091">- Please also see documentation (especially the notes) in the *.md files- Row and column assignments are to matrix positions, not physical positions * Released under The MIT License (MIT) (see "license.md") @@ -22,23 +23,23 @@ #define kb_led_state_power_on() do { \ - _led_all_set_percent(0.05); \ - _led_all_on(); \ + _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 { \ - _led_1_set_percent(0.5); \ + _kb_led_1_set_percent(0.5); \ _delay_ms(333); \ - _led_2_set_percent(0.5); \ + _kb_led_2_set_percent(0.5); \ _delay_ms(333); \ - _led_3_set_percent(0.5); \ + _kb_led_3_set_percent(0.5); \ _delay_ms(333); \ } while(0) #define kb_led_state_ready() do { \ - _led_all_off(); \ - _led_all_set_percent(0.5); \ + _kb_led_all_off(); \ + _kb_led_all_set_percent(0.5); \ } while(0) #endif diff --git a/src/keyboard/ergodox/matrix.h b/src/keyboard/ergodox/matrix.h index ce499b5..1903a8f 100644 --- a/src/keyboard/ergodox/matrix.h +++ b/src/keyboard/ergodox/matrix.h @@ -19,92 +19,88 @@ extern bool (*kb_was_pressed)[KB_ROWS][KB_COLUMNS]; - #ifdef KEYBOARD_INCLUDE_PRIVATE - - /* mapping from spatial position to matrix position - * - spatial position: where the key is spatially, relative to - * other keys both on the keyboard and in the layout - * - matrix position: the coordinate in the matrix to which - * a key is scanned by the update functions - * - * - location numbers are in the format `row##column`, where - * both 'row' 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 - * - * --- other info --------------------------------------------- - * rows x columns = positions; assigned, unassigned - * per hand: 6 x 7 = 42; 38, 4 - * total: 12 x 7 = 84; 76, 8 - * - * left hand : cols 0..6, rows 6..B - * right hand : cols 0..6, rows 0..5 - * ------------------------------------------------------------ - */ - #define 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 } } + /* mapping from spatial position to matrix position + * - spatial position: where the key is spatially, relative to other + * keys both on the keyboard and in the layout + * - matrix position: the coordinate in the matrix to which a key is + * scanned by the update functions + * + * - location numbers are in the format `row##column`, where both 'row' + * 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 + * + * --- other info ----------------------------------------------------- + * rows x columns = positions; assigned, unassigned + * per hand: 6 x 7 = 42; 38, 4 + * total: 12 x 7 = 84; 76, 8 + * + * left hand : cols 0..6, rows 6..B + * right hand : cols 0..6, rows 0..5 + * -------------------------------------------------------------------- + */ + #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 LAYER_SET_ALL(na, kxx) \ - LAYER( \ - na, \ - \ - 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,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, kxx, \ - kxx,kxx,kxx ) + #define MATRIX_LAYER_SET_ALL(na, kxx) \ + LAYER( \ + na, \ + \ + 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,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, kxx, \ + kxx,kxx,kxx ) - #endif #endif diff --git a/src/keyboard/ergodox/mcp23018.h b/src/keyboard/ergodox/mcp23018--private.h similarity index 62% rename from src/keyboard/ergodox/mcp23018.h rename to src/keyboard/ergodox/mcp23018--private.h index ef29523..a48b9b4 100644 --- a/src/keyboard/ergodox/mcp23018.h +++ b/src/keyboard/ergodox/mcp23018--private.h @@ -1,5 +1,5 @@ /* ---------------------------------------------------------------------------- - * ergoDOX controller: MCP23018 specific exports + * ergoDOX controller: MCP23018 specific exports : private * ---------------------------------------------------------------------------- * Copyright (c) 2012 Ben Blazak * Released under The MIT License (MIT) (see "license.md") @@ -7,20 +7,16 @@ * ------------------------------------------------------------------------- */ -#ifndef MCP23018_h - #define MCP23018_h +#ifndef MCP23018_h_PRIVATE + #define MCP23018_h_PRIVATE #include "lib/data-types.h" + #include "matrix.h" - #ifdef KEYBOARD_INCLUDE_PRIVATE + #define MCP23018_TWI_ADDRESS 0b0100000 - #define MCP23018_TWI_ADDRESS 0b0100000 - - uint8_t mcp23018_init(void); - uint8_t mcp23018_update_matrix( - bool matrix[KB_ROWS][KB_COLUMNS] ); - - #endif + uint8_t mcp23018_init(void); + uint8_t mcp23018_update_matrix( bool matrix[KB_ROWS][KB_COLUMNS] ); #endif diff --git a/src/keyboard/ergodox/mcp23018.c b/src/keyboard/ergodox/mcp23018.c index ca960a1..793d332 100644 --- a/src/keyboard/ergodox/mcp23018.c +++ b/src/keyboard/ergodox/mcp23018.c @@ -11,9 +11,8 @@ #include "lib/data-types.h" #include "lib/twi.h" // `TWI_FREQ` defined in "teensy-2-0.c" -#define KEYBOARD_INCLUDE_PRIVATE #include "matrix.h" -#include "mcp23018.h" +#include "mcp23018--private.h" // register addresses (see "mcp23018.md") diff --git a/src/keyboard/ergodox/mcp23018.md b/src/keyboard/ergodox/mcp23018.md index 3a2ab07..f2e0b7d 100644 --- a/src/keyboard/ergodox/mcp23018.md +++ b/src/keyboard/ergodox/mcp23018.md @@ -41,6 +41,11 @@ NC o14-------15+ ADDR (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. * 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 diff --git a/src/keyboard/ergodox/teensy-2-0--private.h b/src/keyboard/ergodox/teensy-2-0--private.h new file mode 100644 index 0000000..231e608 --- /dev/null +++ b/src/keyboard/ergodox/teensy-2-0--private.h @@ -0,0 +1,19 @@ +/* ---------------------------------------------------------------------------- + * ergoDOX controller: Teensy 2.0 specific exports : private + * ---------------------------------------------------------------------------- + * Copyright (c) 2012 Ben Blazak + * Released under The MIT License (MIT) (see "license.md") + * Project located at + * ------------------------------------------------------------------------- */ + + +#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 + diff --git a/src/keyboard/ergodox/teensy-2-0.c b/src/keyboard/ergodox/teensy-2-0.c index f09d033..3f037f0 100644 --- a/src/keyboard/ergodox/teensy-2-0.c +++ b/src/keyboard/ergodox/teensy-2-0.c @@ -13,9 +13,9 @@ #define TWI_FREQ 400000 #include "lib/twi.h" -#define KEYBOARD_INCLUDE_PRIVATE #include "matrix.h" #include "teensy-2-0.h" +#include "teensy-2-0--private.h" // processor frequency (from ) @@ -123,7 +123,7 @@ uint8_t teensy_init(void) { 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") - _led_all_off(); // (just to put the pins in a known state) + _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 diff --git a/src/keyboard/ergodox/teensy-2-0.h b/src/keyboard/ergodox/teensy-2-0.h index 048072d..65fa67d 100644 --- a/src/keyboard/ergodox/teensy-2-0.h +++ b/src/keyboard/ergodox/teensy-2-0.h @@ -13,54 +13,43 @@ #include // for the register macros #include "lib/data-types.h" - #include "matrix.h" - // LED control - #define _led_1_on() (DDRB |= (1<<6)) - #define _led_1_off() (DDRB &= ~(1<<6)) - #define _led_1_set(n) (OCR1B = (uint8_t)(n)) - #define _led_1_set_percent(n) (OCR1B = (uint8_t)((n) * 0xFF)) + #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 _led_2_on() (DDRB |= (1<<5)) - #define _led_2_off() (DDRB &= ~(1<<5)) - #define _led_2_set(n) (OCR1A = (uint8_t)(n)) - #define _led_2_set_percent(n) (OCR1A = (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 _led_3_on() (DDRB |= (1<<7)) - #define _led_3_off() (DDRB &= ~(1<<7)) - #define _led_3_set(n) (OCR1C = (uint8_t)(n)) - #define _led_3_set_percent(n) (OCR1C = (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 _led_all_on() do { \ - _led_1_on(); \ - _led_2_on(); \ - _led_3_on(); \ + #define _kb_led_all_on() do { \ + _kb_led_1_on(); \ + _kb_led_2_on(); \ + _kb_led_3_on(); \ } while(0) - #define _led_all_off() do { \ - _led_1_off(); \ - _led_2_off(); \ - _led_3_off(); \ + #define _kb_led_all_off() do { \ + _kb_led_1_off(); \ + _kb_led_2_off(); \ + _kb_led_3_off(); \ } while(0) - #define _led_all_set(n) do { \ - _led_1_set(n); \ - _led_2_set(n); \ - _led_3_set(n); \ + #define _kb_led_all_set(n) do { \ + _kb_led_1_set(n); \ + _kb_led_2_set(n); \ + _kb_led_3_set(n); \ } while(0) - #define _led_all_set_percent(n) do { \ - _led_1_set_percent(n); \ - _led_2_set_percent(n); \ - _led_3_set_percent(n); \ + #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); \ } while(0) - - #ifdef KEYBOARD_INCLUDE_PRIVATE - - uint8_t teensy_init(void); - uint8_t teensy_update_matrix( - bool matrix[KB_ROWS][KB_COLUMNS] ); - - #endif - #endif diff --git a/src/keyboard/ergodox/teensy-2-0.md b/src/keyboard/ergodox/teensy-2-0.md index 180f147..61b47fd 100644 --- a/src/keyboard/ergodox/teensy-2-0.md +++ b/src/keyboard/ergodox/teensy-2-0.md @@ -44,6 +44,11 @@ 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. * 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 diff --git a/src/lib/data-types.h b/src/lib/data-types.h index 453dca1..4c625a4 100644 --- a/src/lib/data-types.h +++ b/src/lib/data-types.h @@ -10,12 +10,10 @@ #ifndef DATA_TYPES_h #define DATA_TYPES_h + #include #include #include - - #define bool _Bool - #define true ((bool)1) - #define false ((bool)0) + #include "data-types/linked-list.h" #endif diff --git a/src/lib/data-types/linked-list.c b/src/lib/data-types/linked-list.c new file mode 100644 index 0000000..97dc1f8 --- /dev/null +++ b/src/lib/data-types/linked-list.c @@ -0,0 +1,240 @@ +/* ---------------------------------------------------------------------------- + * 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 + * Released under The MIT License (MIT) (see "license.md") + * Project located at + * ------------------------------------------------------------------------- */ + + +#include +#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; inext; + 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; inext; + 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; inext; + + // 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 + diff --git a/src/lib/data-types/linked-list.h b/src/lib/data-types/linked-list.h new file mode 100644 index 0000000..a73ea82 --- /dev/null +++ b/src/lib/data-types/linked-list.h @@ -0,0 +1,55 @@ +/* ---------------------------------------------------------------------------- + * linked list : exports + * ---------------------------------------------------------------------------- + * Copyright (c) 2012 Ben Blazak + * Released under The MIT License (MIT) (see "license.md") + * Project located at + * ------------------------------------------------------------------------- */ + + +#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 + diff --git a/src/lib/key-functions--private.h b/src/lib/key-functions--private.h new file mode 100644 index 0000000..ee9c979 --- /dev/null +++ b/src/lib/key-functions--private.h @@ -0,0 +1,28 @@ +/* ---------------------------------------------------------------------------- + * 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 + * Released under The MIT License (MIT) (see "license.md") + * Project located at + * ------------------------------------------------------------------------- */ + + +#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 + diff --git a/src/lib/key-functions.c b/src/lib/key-functions.c index de037ef..c7f2e2c 100644 --- a/src/lib/key-functions.c +++ b/src/lib/key-functions.c @@ -11,108 +11,500 @@ * ------------------------------------------------------------------------- */ +#include #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) // ---------------------------------------------------------------------------- -#if 0 // not being used right now -static uint8_t _inc_current_layer(uint8_t * current_layer) { - if (*current_layer < (KB_LAYERS-1)) - (*current_layer)++; - else - return 1; // error: can't increase +/* + * 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_) ); - return 0; // success + if (key_function) + (*key_function)( + pressed_, + kb_layout_get(layer_, *row_, *col_), + layer_, + row_, + col_, + current_layer_, + current_layers_, + pressed_layers_ ); } -static uint8_t _dec_current_layer(uint8_t * current_layer) { - if (*current_layer > 0) - (*current_layer)--; - else - return 1; // error: can't decrease - return 0; // success +// ---------------------------------------------------------------------------- +// 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_LAYERS ) + return; + + for (uint8_t row=0; row 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) + // +#if MAKEFILE_BOARD == teensy-2-0 + // --- for all Teensy boards + cli(); + + // disable watchdog, if enabled + // disable all peripherals + UDCON = 1; + USBCON = (1< stringify + #define _inc _expstr(keyboard/MAKEFILE_KEYBOARD/matrix.h) // inc(lude) + #include _inc + #undef _str + #undef _expstr + #undef _inc + // -------------------------------------------------------------------- - void kbfun_press( - uint8_t keycode, uint8_t * current_layer, - uint8_t * row, uint8_t * col ); - void kbfun_release( - uint8_t keycode, uint8_t * current_layer, - uint8_t * row, uint8_t * col ); + + #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 diff --git a/src/lib/usb/TODO.c b/src/lib/usb/TODO.c index 0f6aec1..c0759df 100644 --- a/src/lib/usb/TODO.c +++ b/src/lib/usb/TODO.c @@ -38,6 +38,14 @@ // - spec sec 9.4.11 (Standard Device Requests / Synch Frame) (pg 260) // TODO -// - read the hid usage tables .pdf // - read the hid device class definition .pdf +// DONE +// - read the hid usage tables .pdf +// - i think this is more for reference and implementation than +// understanding. i've copied the relevant (i think) tables ones into +// headers. the unicode usage page, i'll have to look into more later: i'm +// not sure if it can be used with keyboards. if so though, i'll have to +// look on the unicode website, or elsewhere, coz this .pdf doesn't list +// anything about them out, it just references the unicode spec. + diff --git a/src/main.c b/src/main.c index eaa76d4..78ec964 100644 --- a/src/main.c +++ b/src/main.c @@ -11,6 +11,7 @@ #include #include "lib-other/pjrc/usb_keyboard/usb_keyboard.h" #include "lib/data-types.h" +#include "lib/key-functions.h" #include "keyboard.h" @@ -27,7 +28,12 @@ int main(void) { kb_led_state_ready(); for (;;) { - static uint8_t current_layer = 0; + // 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 `kb_is_pressed` and `kb_was_pressed`, then update bool (*temp)[KB_ROWS][KB_COLUMNS] = kb_was_pressed; @@ -36,41 +42,46 @@ int main(void) { kb_update_matrix(*kb_is_pressed); - // call the appropriate function for each key, then send the usb report - // if necessary - // - 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), and "lib/key-functions.c" - // for their definitions + // 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) + // - keep track of which layers the keys were on when they were pressed + // (so they can be released using the function from that layer) + // + // note + // - 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