menelaus/test.rkt

152 lines
4.9 KiB
Racket

#lang racket
;; this file simulates the hardware necessary to test the keyboard firmware,
;; because doing actual development on an atmega32u4 is nightmarishly tedious.
(define pins (make-vector 20))
(define keys (make-vector 44 #f))
(define output void) ; don't bother to simulate pin modes
(define input void)
(define pause void)
(define (high pin) (vector-set! pins pin #t))
(define (low pin) (vector-set! pins pin #f))
;; microscheme has this as a separate form
(define (for-each-vector v f) (vector-map v f) (void))
(define last-usb-frame #f) ; save this off so we can test it
(define (mods-list mods)
(filter symbol? (list (if (positive? (bitwise-and mods 1)) 'ctrl 0)
(if (positive? (bitwise-and mods 2)) 'shift 0)
(if (positive? (bitwise-and mods 4)) 'alt 0)
(if (positive? (bitwise-and mods 8)) 'super 0)
(if (positive? (bitwise-and mods 64)) altgr 0))))
(define (usb-save mods . args)
(set! last-usb-frame (cons (mods-list mods) args)))
(define (call-c-func f-name . args)
(when (equal? f-name "usb_send")
(apply usb-save args)))
(define (active-row)
;; hypothetically we could have multiple active rows but we just assume one
(for/first ([pin row-pins]
[row (range (length rows))]
#:when (not (vector-ref pins pin)))
row))
(define (col-for pin)
(for/first ([c-pin column-pins]
[col (range (length columns))]
#:when (= c-pin pin))
col))
(define (low? pin)
;; (when (vector-ref keys (offset-for (active-row) (col-for pin)))
;; (printf "lookup ~s ~s ~n" pin (offset-for (active-row) (col-for pin)))
;; (printf "Keys ~s~n" keys))
(vector-ref keys (offset-for (active-row) (col-for pin))))
(define (make-test-data)
;; have to put this in a function so we can internal-define; eww
(include "keycodes.scm")
;; each test case is a pair of inputs->outputs
;; inputs are a list of keys (by offset), outputs are elements of a USB frame
`(;; single key
((3) . (() ,key-r))
;; another single key
((2) . (() ,key-e))
;; the first key in the whole layout
((0) . (() ,key-q))
;; multiple normal keys
((2 3) . (() ,key-e ,key-r))
;; modifier keys (ctrl)
((27) . ((ctrl)))
;; two modifiers (shift+ctrl) get ORed together
((27 36) . ((ctrl shift)))
;; modifier (shift) and normal key
((36 4) . ((shift) ,key-t))
;; modifier and multiple normal keys
((36 4 6) . ((shift) ,key-t ,key-y))
;; fn key alone
((40) . (()))
;; fn key and normal key
((40 1) . ((shift) ,key-2))
;; fn key and modifier and normal key
((40 35 2) . ((super) ,key-up))
;; releasing fn should leave the previously-pressed key on the fn layer!!!
((2) . (() ,key-up))
;; fn key alone
((40) . (()))
;; fn key and *
((40 28) . ((shift) ,key-8))
;; fn is released
((28) . ((shift) ,key-8))
;; * is released
(() . (()))
;; normal key doesn't leave shift down
((0) . (() ,key-q))
;; changing to L2 (fn+esc)
((40) . (()))
((40 33) . (()))
;; fn+esc should stay on L2 across multiple scans
((40 33) . (()))
;; release fn to disable momentary
(() . (()))
;; hitting an L2 key
((1) . (() ,key-home))
;; L2 two keys and mod
((36 39 18) . ((shift) ,key-f4 ,key-space))
;; back to base (fn)
((40) . (()))
;; base layer key
((2) . (() ,key-e))
;; seven keys down
((1 2 3 4 7 8 9) . (() ,key-e ,key-w ,key-r ,key-t ,key-u ,key-i))
;; shift combo and shift key simultaneously
((40) . (()))
((40 1 36) . ((shift) ,key-2))
((40 1) . (() ,key-2))
((40) . (()))
(() . (()))))
(define test-data (make-test-data))
(define failures '())
(define (fail expected actual)
(printf "F")
(set! failures
(cons (format "Expected ~s, got ~s~n" expected actual) failures)))
(define (finish)
(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.
(define-syntax free!
(syntax-rules ()
[(free! body) (if (empty? test-data)
(finish)
(let ([test-case (car test-data)])
(for ([i (vector-length keys)])
(vector-set! keys i
(and (member i (car test-case)) #t)))
body
(let ((actual (cons (car last-usb-frame)
(remove-all
0 (cdr last-usb-frame)))))
(if (equal? (cdr test-case) actual)
(printf ".")
(fail (cdr test-case) actual)))
(set! test-data (cdr test-data))))]))
(include "multidvorak.scm")