~technomancy/menelaus

9584e11c6b41ccacf30d95c43f176306a7d97450 — Phil Hagelberg 8 months ago 3f11913
Turn the layout/driver inside out.

The layout is now the entry point file rather than
menelaus.scm. Layout files load keycodes, define layouts, and then
load the firmware driver bits in menelaus.scm at the very end.
6 files changed, 80 insertions(+), 48 deletions(-)

M Makefile
M README.md
M menelaus.scm
R layout.scm => multidvorak.scm
M qwerty.scm
M test.rkt
M Makefile => Makefile +12 -13
@@ 1,32 1,31 @@
MCU=atmega32u4

F_CPU=16000000

TARGET=menelaus
LAYOUT?=qwerty

USB=/dev/ttyACM0

build: $(TARGET).hex
build: $(LAYOUT).hex

upload: $(TARGET).hex
upload: $(LAYOUT).hex
	while [ ! -r $(USB) ]; do sleep 1; done; \
	avrdude -p $(MCU) -c avr109 -U flash:w:$(TARGET).hex -P $(USB)
	avrdude -p $(MCU) -c avr109 -U flash:w:$(LAYOUT).hex -P $(USB)

test: ; racket test.rkt

clean: ; -rm -f $(TARGET){,.hex} *.o *.elf *.s
clean: ; -rm -f $(LAYOUT){,.hex} *.o *.elf *.s

count: ; cloc menelaus.scm keycodes.scm layout.scm
count: ; cloc menelaus.scm keycodes.scm $(LAYOUT).scm

$(TARGET).hex: $(TARGET).elf
	avr-size $(TARGET).elf
	avr-objcopy --output-target=ihex $(TARGET).elf $(TARGET).hex
$(LAYOUT).hex: $(LAYOUT).elf
	avr-size $(LAYOUT).elf
	avr-objcopy --output-target=ihex $(LAYOUT).elf $(LAYOUT).hex

$(TARGET).s: $(TARGET).scm layout.scm keycodes.scm
	microscheme -m LEO $(TARGET).scm
$(LAYOUT).s: $(LAYOUT).scm menelaus.scm keycodes.scm
	microscheme -m LEO $(LAYOUT).scm

%.elf: %.s usb_keyboard.s
	avr-gcc -mmcu=$(MCU) -o $(TARGET).elf $(TARGET).s usb_keyboard.s
	avr-gcc -mmcu=$(MCU) -o $(LAYOUT).elf $(LAYOUT).s usb_keyboard.s

usb_keyboard.s: usb_keyboard.h usb_keyboard.c
	avr-gcc -std=gnu99 -S -D F_CPU=$(F_CPU)UL -mmcu=$(MCU) -c \

M README.md => README.md +9 -11
@@ 14,12 14,13 @@ See [this article about how it works](https://atreus.technomancy.us/firmware).
* Combo keys (a single keystroke can send a modifier and a non-modifier)
* Bind arbitrary Microscheme functions to a key
* ~300 lines of code
* Qwerty and Dvorak layouts; easy to add more

## Usage

Install [microscheme](https://github.com/ryansuchocki/microscheme/)
from source; place `microscheme` executable on your `$PATH`. Version
823c5d9 from February 2020 is known to work.
3bc5611 from March 2020 is known to work.

Requires [avrdude](https://www.nongnu.org/avrdude/) for uploading
to the controller on the keyboard; install with your package manager


@@ 50,18 51,15 @@ used to flash a new firmware once this is uploaded.

## Layout

By default you get the "multidvorak" layout which is designed to send
the right keycodes with the assumption that the OS is set to use
Dvorak, but it also includes layers for "hard Dvorak". But you can
also build a qwerty layout:
By default you get the qwerty layout. You can copy `qwerty.scm` to
`mylayout.scm` and make changes, (you can see a list of available
keycodes in `keycodes.scm`) then upload with:

    $ cp qwerty.scm layout.scm
    $ make upload USB=/dev/ttyACM0
    $ make upload USB=/dev/ttyACM0 LAYOUT=multidvorak

Or edit `layout.scm` to your liking; you can see a list of available
keycodes in `keycodes.scm`. The default layout works for 42-key Atreus
kits and the 44-key Keyboardio Atreus, but you will have to uncomment
a few things for the full 44-key support.
There is also a `multidvorak` layout which is designed to send
the right keycodes with the assumption that the OS is set to use
Dvorak, but it also includes layers for "hard Dvorak".

## Development


M menelaus.scm => menelaus.scm +4 -21
@@ 25,29 25,12 @@
;; steps thru a vector/list with the initial arguments calculated by its
;; non-aux equivalent. The -aux function is never called directly.

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(include "keycodes.scm")
(include "layout.scm")

;; What are the rows and columns we care about?
(define rows (list 0 1 2 3))
(define columns (list 0 1 2 3 4 5 6 7 8 9 10))
;; This file should be loaded by your main layout code; see qwerty.scm
;; for an example. It assumes that keycodes, layouts, and pinout have already
;; been defined.

;; Which GPIO pins are responsible for each row or column?
(define row-pins (vector 3 2 1 0))
(define column-pins (vector 6 5 9 8 7 4 10 19 18 12 11))

;; If you have a kit where the PCB is installed upside-down, uncomment this:
;; (set! column-pins (vector 11 12 18 19 10 4 7 8 9 5 6))
;; ;; Upside-down PCB makes the columns backwards but also trades ctrl and alt;
;; ;; this hack only works for layouts where ctrl and alt are in standard place.
;; (set! mod-alt (modify 1))
;; (set! mod-ctrl (modify 3))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

;; The above should be handled by a compile-time environment variable but that
;; isn't yet part of Microscheme:
;; https://github.com/ryansuchocki/microscheme/issues/32

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Utility functions


R layout.scm => multidvorak.scm +25 -0
@@ 2,6 2,8 @@

;; It will work for the 44-key Atreus 2 or the 42-key Atreus 1.

(include "keycodes.scm")

;; We have to declare this up front and set it later because of circularity.
(define layers #f)
(define current-layer #f)


@@ 115,3 117,26 @@
(set! layers (vector base-layer fn-layer l2-layer
                     hard-dvorak-layer hard-dvorak-fn-layer))
(set! current-layer (vector-ref layers 0))

;; What are the rows and columns we care about?
(define rows (list 0 1 2 3))
(define columns (list 0 1 2 3 4 5 6 7 8 9 10))

;; Which GPIO pins are responsible for each row or column?
;; These are the pins used by the kit-based Atreus; the Keyboardio Atreus uses
;; a different set of pins.
(define row-pins (vector 3 2 1 0))
(define column-pins (vector 6 5 9 8 7 4 10 19 18 12 11))

;; If you have a kit where the PCB is installed upside-down, uncomment this:
;; (set! column-pins (vector 11 12 18 19 10 4 7 8 9 5 6))
;; ;; Upside-down PCB makes the columns backwards but also trades ctrl and alt;
;; ;; this hack only works for layouts where ctrl and alt are in standard place.
;; (set! mod-alt (modify 1))
;; (set! mod-ctrl (modify 3))

;; The above should be handled by a compile-time environment variable but that
;; isn't yet part of Microscheme:
;; https://github.com/ryansuchocki/microscheme/issues/32

(include "menelaus.scm")

M qwerty.scm => qwerty.scm +28 -1
@@ 1,5 1,6 @@
;;; this is the qwerty layout
;; copy this file to layout.scm and build

(include "keycodes.scm")

;; we have to declare this up front and set it later because of circularity
(define layers #f)


@@ 53,3 54,29 @@

         0 key-vol-down mod-super mod-shift key-backspace mod-alt
         key-space (set-layer 0) key-printscreen key-scroll-lock key-pause))

(set! layers (vector base-layer fn-layer l2-layer))
(set! current-layer (vector-ref layers 0))

;; What are the rows and columns we care about?
(define rows (list 0 1 2 3))
(define columns (list 0 1 2 3 4 5 6 7 8 9 10))

;; Which GPIO pins are responsible for each row or column?
;; These are the pins used by the kit-based Atreus; the Keyboardio Atreus uses
;; a different set of pins.
(define row-pins (vector 3 2 1 0))
(define column-pins (vector 6 5 9 8 7 4 10 19 18 12 11))

;; If you have a kit where the PCB is installed upside-down, uncomment this:
;; (set! column-pins (vector 11 12 18 19 10 4 7 8 9 5 6))
;; ;; Upside-down PCB makes the columns backwards but also trades ctrl and alt;
;; ;; this hack only works for layouts where ctrl and alt are in standard place.
;; (set! mod-alt (modify 1))
;; (set! mod-ctrl (modify 3))

;; The above should be handled by a compile-time environment variable but that
;; isn't yet part of Microscheme:
;; https://github.com/ryansuchocki/microscheme/issues/32

(include "menelaus.scm")

M test.rkt => test.rkt +2 -2
@@ 14,7 14,7 @@
(define (low pin) (vector-set! pins pin #f))

;; microscheme has this as a separate form
(define for-each-vector vector-map)
(define (for-each-vector v f) (vector-map v f) (void))

(define last-usb-frame #f) ; save this off so we can test it



@@ 147,4 147,4 @@
                              (fail (cdr test-case) actual)))
                        (set! test-data (cdr test-data))))]))

(include "menelaus.scm")
(include "multidvorak.scm")