diff --git a/Makefile b/Makefile index 2faf4af..412f8b3 100644 --- a/Makefile +++ b/Makefile @@ -16,13 +16,13 @@ test: ; racket test.rkt clean: ; -rm -f $(TARGET){,.hex} *.o *.elf *.s -count: ; cloc *.scm +count: ; cloc menelaus.scm keycodes.scm $(TARGET).hex: $(TARGET).elf avr-size $(TARGET).elf avr-objcopy --output-target=ihex $(TARGET).elf $(TARGET).hex -%.s: %.scm +$(TARGET).s: $(TARGET).scm layout.scm keycodes.scm microscheme -m LEO $(TARGET).scm %.elf: %.s usb_keyboard.s diff --git a/README.md b/README.md index 4983f62..9b84ac4 100644 --- a/README.md +++ b/README.md @@ -11,13 +11,15 @@ A firmware for the * Multiple layers, momentary and sticky (limited only by memory) * Combo keys (a single keystroke can send a modifier and a non-modifier) * Bind arbitrary Scheme functions to a key -* ~255 lines of code +* ~200 lines of code ## Usage This currently requires Microscheme with the addition of -`vector-copy!` which at the time of this writing is only available on -[this branch](https://github.com/ryansuchocki/microscheme/pull/31). +`vector-copy!` which at the time of this writing is only on the master branch. + +Also requires [avrdude](https://www.nongnu.org/avrdude/) for uploading +to the device. Replace `/dev/ttyACM0` with the path your OS assigns to the USB bootloader of the microcontroller: @@ -38,6 +40,8 @@ into Racket and simulates the GPIO functions with a test harness: ## Known bugs +Still working out some quirks with sticky layers. + If you hold the fn key, press a button (say Q) and then release fn without releasing Q, it will send a keycode for Q rather than simply leaving the previous fn+Q keycodes as held down. diff --git a/layout.scm b/layout.scm index 1c5a1e8..9b62313 100644 --- a/layout.scm +++ b/layout.scm @@ -1,29 +1,22 @@ ;;; this is the multidvorak layout ;; we have to declare this up front and set it later because of circularity -(define layers (vector #f #f #f)) +(define layers #f) (define current-layer #f) (define momentary-layer #f) (define (fn) (set! momentary-layer (vector-ref layers 1))) -(define (set-layer-2) - (set! current-layer (vector-ref layers 2))) - -(define (set-layer-0) - (set! current-layer (vector-ref layers 0))) - -(define (set-layer-hard) - (set! current-layer (vector-ref layers 3))) +(define (set-layer n) + (lambda () (set! current-layer (vector-ref layers n)))) (define (reset) #f) ;; TODO: uh, seriously. I need this. how. ;;;; layers -(vector-set! ; base - layers 0 +(define base-layer (vector key-q key-w key-e key-r key-t key-backslash key-y key-u key-i key-o key-p @@ -36,8 +29,7 @@ key-esc key-tab mod-super mod-shift key-backspace mod-alt key-space fn key-quote key-left-bracket key-enter)) -(vector-set! ; fn - layers 1 +(define fn-layer (vector (sft key-1) (sft key-2) key-up (sft key-dash) (sft key-equal) 0 key-page-up key-7 key-8 key-9 (sft key-8) @@ -47,25 +39,25 @@ key-dash key-equal (sft key-9) (sft key-0) (sft key-7) mod-ctrl key-backtick key-1 key-2 key-3 key-backslash - set-layer-2 key-insert mod-super mod-shift key-backspace mod-alt + ;; still got some bugs in layering to work out! make this reset for now + reset ;; (set-layer 2) + key-insert mod-super mod-shift key-backspace mod-alt key-space fn key-e key-0 key-right-bracket)) -(vector-set! ; l2 (function keys, etc) - layers 2 +(define l2-layer (vector key-insert key-home key-up key-end key-page-up 0 key-up key-f7 key-f8 key-f9 key-f10 key-delete key-left key-down key-right key-page-down 0 key-down key-f4 key-f5 key-f6 key-f11 - 0 key-vol-up 0 0 reset mod-ctrl - set-layer-hard key-f1 key-f2 key-f3 key-f12 + (set-layer 0) key-vol-up 0 0 reset mod-ctrl + (set-layer 4) key-f1 key-f2 key-f3 key-f12 0 key-vol-down mod-super mod-shift key-backspace mod-alt - key-space set-layer-0 key-printscreen key-scroll-lock key-pause)) + key-space 0 key-printscreen key-scroll-lock key-pause)) -(vector-set! ; hard dvorak - layers 3 +(define hard-dvorak-layer (vector key-quote key-comma key-period key-p key-y key-backslash key-f key-g key-c key-r key-l @@ -78,8 +70,7 @@ key-esc key-tab mod-super mod-shift key-backspace mod-alt key-space fn key-quote key-left-bracket key-enter)) -(vector-set! ; hard dvorak fn - layers 4 +(define hard-dvorak-fn-layer (vector (sft key-1) (sft key-2) key-up (sft key-left-bracket) (sft key-right-bracket) 0 key-page-up key-7 key-8 key-9 (sft key-8) @@ -89,5 +80,8 @@ key-left-bracket key-right-bracket (sft key-9) (sft key-0) (sft key-7) mod-ctrl key-backtick key-1 key-2 key-3 key-backslash - set-layer-2 key-insert mod-super mod-shift key-backspace mod-alt + (set-layer 2) key-insert mod-super mod-shift key-backspace mod-alt key-space fn key-e key-0 key-right-bracket)) + +(set! layers (vector base-layer fn-layer l2-layer + hard-dvorak-layer hard-dvorak-fn-layer)) diff --git a/menelaus.scm b/menelaus.scm index fe9a0f1..76193be 100644 --- a/menelaus.scm +++ b/menelaus.scm @@ -16,11 +16,11 @@ (define (scan-key keys-pressed key-count row col) ;; pullup resistors mean a closed circuit is low rather than high (if (low? (vector-ref column-pins col)) - (begin - (if (<= key-count max-keys) + (if (<= key-count max-keys) + (begin (vector-set! keys-pressed key-count (offset-for row col)) - #f) - (+ key-count 1)) + (+ key-count 1)) + key-count) key-count)) (define (scan-column keys-pressed key-count row columns-left) @@ -47,7 +47,7 @@ (define this-scan (vector 0 0 0 0 0 0 0)) (define last-scan (vector 0 0 0 0 0 0 0)) -(define debounce-passes 8) +(define debounce-passes 4) (define (debounce-matrix keys-pressed last-count passes-left) ;; older versions of microscheme don't have vector-copy!, only vector-copy @@ -80,9 +80,7 @@ (define (call-functions keys-pressed key-count) (if (< 0 key-count) (let ((code (lookup keys-pressed key-count))) - (if (procedure? code) - (code) - #f) + (and (procedure? code) (code)) (call-functions keys-pressed (- key-count 1))) #f)) @@ -93,15 +91,14 @@ (if (= 0 key-count) (vector->list keycodes) (let ((keycode (keycode-for keys-pressed key-count keycodes))) - (if keycode - (vector-set! keycodes key-count keycode) - #f) + (and keycode + (vector-set! keycodes key-count keycode)) (keycodes-for keys-pressed (- key-count 1) keycodes)))) ;;;;;;;;;;;;;;;;;;; showtime (define (init) - (set-layer-0) + (set! current-layer (vector-ref layers 0)) (for-each-vector output row-pins) (for-each-vector high row-pins) (for-each-vector input column-pins) diff --git a/test.rkt b/test.rkt index 8a17fd3..6cfc2f0 100644 --- a/test.rkt +++ b/test.rkt @@ -68,6 +68,16 @@ ((40 35 2) . (8 ,key-up 0 0 0 0 0)) ;; releasing fn should leave the previously-pressed key on the fn layer!!! ;; ((2) . (0 ,key-up 0 0 0 0 0)) + ;; changing to L2 (fn+esc) + ((40 33) . (0 0 0 0 0 0 0)) + ;; fn+esc should stay on L2 across multiple scans + ((40 33) . (0 0 0 0 0 0 0)) + ;; hitting an L2 key + ;; ((1) . (0 ,key-home 0 0 0 0 0)) + ;; back to base (key above esc) + ;; ((22) . (0 0 0 0 0 0 0)) + ;; base layer key + ((2) . (0 ,key-e 0 0 0 0 0)) )) (define test-data (make-test-data)) @@ -80,7 +90,8 @@ (cons (format "Expected ~s, got ~s~n" expected actual) failures))) (define (finish) - (printf (string-join failures "~n" #:before-first "~n" #:after-last "~n")) + (printf (string-join (reverse failures) + "~n" #:before-first "~n" #:after-last "~n")) (exit (if (empty? failures) 0 1))) ;; we can perform our checks here and make changes to the pin state.