generated from macoy/gamelib-project-template
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
166 lines
5.5 KiB
166 lines
5.5 KiB
(add-build-config-label "Keypad")
|
|
|
|
(set-cakelisp-option cakelisp-src-dir "Dependencies/cakelisp/src")
|
|
(add-cakelisp-search-directory "Dependencies/gamelib/src")
|
|
(add-cakelisp-search-directory "Dependencies/cakelisp/runtime")
|
|
(add-cakelisp-search-directory "src")
|
|
|
|
(import "CHelpers.cake")
|
|
|
|
(c-import
|
|
;; sdk
|
|
"<stdio.h>"
|
|
"pico/stdlib.h"
|
|
"bsp/board.h"
|
|
"tusb.h"
|
|
;; Our stuff
|
|
"usb_descriptors.h"
|
|
"stdint.h")
|
|
|
|
(var row-pins (array (const int)) ;; Samples. Yellow wires.
|
|
(array 29 28 27 26)) ;; A3 A2 A1 A0
|
|
|
|
(var column-pins (array (const int)) ;; Sends power. White wires.
|
|
(array 2 3 4 5 6)) ;; 2 3 4 5 6
|
|
|
|
(var last-scan-matrix (array 4 (array 5 int)) (array 0))
|
|
(var matrix (array 4 (array 5 int)) (array 0))
|
|
|
|
(var matrix-to-keys (array 4 (array 5 char))
|
|
(array
|
|
(array 'n' '7' '4' '1' '0') ;; a3
|
|
(array '/' '8' '5' '2' '_') ;; a2
|
|
(array '*' '9' '6' '3' '.') ;; a1
|
|
(array '+' 'b' '_' '_' 'e'))) ;; a0
|
|
|
|
(var keycode-unused (const uint8_t) 0)
|
|
|
|
(var matrix-to-keycodes (array 4 (array 5 uint8_t))
|
|
(array
|
|
(array HID_KEY_NUM_LOCK HID_KEY_KEYPAD_7 HID_KEY_KEYPAD_4 HID_KEY_KEYPAD_1 HID_KEY_KEYPAD_0) ;; a3
|
|
(array HID_KEY_KEYPAD_DIVIDE HID_KEY_KEYPAD_8 HID_KEY_KEYPAD_5 HID_KEY_KEYPAD_2 keycode-unused) ;; a2
|
|
(array HID_KEY_KEYPAD_MULTIPLY HID_KEY_KEYPAD_9 HID_KEY_KEYPAD_6 HID_KEY_KEYPAD_3 HID_KEY_KEYPAD_DECIMAL) ;; a1
|
|
(array HID_KEY_KEYPAD_SUBTRACT HID_KEY_KEYPAD_ADD keycode-unused keycode-unused HID_KEY_KEYPAD_ENTER))) ;; a0
|
|
|
|
(defmacro print-line (line any)
|
|
;; (tokenize-push output (call-on println Serial (token-splice line)))
|
|
(return true))
|
|
|
|
(defun main (&return int)
|
|
(board_init)
|
|
(tusb_init)
|
|
|
|
(each-item-in-array row-pins row row-pin int
|
|
(gpio_init row-pin)
|
|
(gpio_set_dir row-pin GPIO_IN)
|
|
(gpio_pull_up row-pin))
|
|
(each-item-in-array column-pins column col-pin int
|
|
(gpio_init col-pin)
|
|
(gpio_set_dir col-pin GPIO_OUT))
|
|
|
|
(while true
|
|
(tud_task)
|
|
(hid-task))
|
|
;; Should never happen
|
|
(return 1))
|
|
|
|
(defun hid-task ()
|
|
(var poll-interval-ms uint32_t 1)
|
|
(var-static start-ms uint32_t 0)
|
|
(when (< (- (board_millis) start-ms) poll-interval-ms)
|
|
;; (todo feature) Should this actually delay to save power?
|
|
(return))
|
|
(set start-ms (+ start-ms poll-interval-ms))
|
|
|
|
(scan-matrix)
|
|
(var any-key-pressed bool false)
|
|
(each-in-range (array-size row-pins) row
|
|
(each-in-range (array-size column-pins) column
|
|
(when (and (at row column matrix)
|
|
(not (at row column last-scan-matrix)))
|
|
(set any-key-pressed true))))
|
|
;; Wake up host if we are in suspend mode
|
|
;; and REMOTE_WAKEUP feature is enabled by host
|
|
(cond
|
|
((and any-key-pressed (tud_suspended))
|
|
(tud_remote_wakeup))
|
|
(true ;; Host is awake and should receive our report
|
|
(send-keyboard-report))))
|
|
|
|
(defun send-keyboard-report ()
|
|
(unless (tud_hid_ready)
|
|
(return))
|
|
(var num-keys-reported int 0)
|
|
;; We are limited here in the number of keys we can send at once. It should be possible to roll
|
|
;; them over or use a different API to send more keys.
|
|
(var keycodes (array 6 uint8_t) (array 0))
|
|
(var key-just-pressed bool false)
|
|
(var key-just-released bool false)
|
|
|
|
(ignore ;; Sanity check (press boot button)
|
|
(var-static has-key bool false)
|
|
(var button-pressed uint32_t (board_button_read))
|
|
(if button-pressed
|
|
(scope
|
|
(set (at 0 keycodes) HID_KEY_A)
|
|
(set has-key true)
|
|
(set key-just-pressed true))
|
|
(scope
|
|
(set key-just-released has-key)
|
|
(set has-key false))))
|
|
|
|
(each-in-range (array-size row-pins) row
|
|
(each-in-range (array-size column-pins) column
|
|
(when (and (at row column matrix)
|
|
(not (at row column last-scan-matrix))
|
|
(< num-keys-reported (array-size keycodes)))
|
|
(var key-code uint8_t (at row column matrix-to-keycodes))
|
|
(unless (= key-code keycode-unused)
|
|
(set (at num-keys-reported keycodes) key-code)
|
|
(incr num-keys-reported)
|
|
(set key-just-pressed true)))
|
|
(when (and (at row column last-scan-matrix)
|
|
(not (at row column matrix)))
|
|
(set key-just-released true))
|
|
(set (at row column last-scan-matrix)
|
|
(at row column matrix))))
|
|
|
|
;; Avoid sending multiple empty key reports if nothing changed
|
|
(when (or key-just-pressed key-just-released)
|
|
(tud_hid_keyboard_report
|
|
REPORT_ID_KEYBOARD
|
|
0 ;; modifier
|
|
keycodes)))
|
|
|
|
(defun scan-matrix ()
|
|
(each-item-in-array column-pins column col-pin int
|
|
(gpio_set_dir col-pin GPIO_OUT)
|
|
(gpio_put col-pin 0)
|
|
(sleep_us 1) ;; Seems necessary to prevent extraneous key presses.
|
|
(each-item-in-array row-pins row row-pin int
|
|
(set (at row column matrix) (= 0 (gpio_get row-pin))))
|
|
(gpio_put col-pin 1)))
|
|
|
|
;; Invoked when received SET_REPORT control request or
|
|
;; received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
|
;; In other words, the computer is telling US to do something (e.g. set caps lock LED)
|
|
(defun-nodecl tud_hid_set_report_cb
|
|
(instance uint8_t
|
|
report_id uint8_t
|
|
report_type hid_report_type_t
|
|
buffer (addr (const uint8_t))
|
|
bufsize uint16_t)
|
|
(ignore))
|
|
|
|
;; Invoked when received GET_REPORT control request
|
|
;; Application must fill buffer report's content and return its length.
|
|
;; Return zero will cause the stack to STALL request
|
|
(defun-nodecl tud_hid_get_report_cb
|
|
(instance uint8_t
|
|
report_id uint8_t
|
|
report_type hid_report_type_t
|
|
buffer (addr uint8_t)
|
|
reqlen uint16_t
|
|
&return uint16_t)
|
|
;; (todo robustness) I think I need to implement this...
|
|
(return 0))
|
|
|