Compare commits
624 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| da5cb5fd6f | |||
| 984481ff8e | |||
| 3b580de023 | |||
| f2c9fa81de | |||
| a2cfa23baf | |||
| d9238b7baf | |||
| b8deac707e | |||
| 1477440ba0 | |||
| 735fb8a8b6 | |||
| 8515d12e20 | |||
| 7b35dda31e | |||
| 658d211804 | |||
| 602472dbfa | |||
| e4afd371dc | |||
| 68473e66b6 | |||
| b56707a517 | |||
| 97ee1c0aee | |||
| a2ef11bb00 | |||
| d36c245400 | |||
| f404ec329f | |||
| a33dcb5a9a | |||
| 1571f8e258 | |||
| 59f37bb710 | |||
| 84b7fc364d | |||
| ae705e3e55 | |||
| 3fefaf7f6b | |||
| 6cb0e8924b | |||
| 2427678f7d | |||
| 2e052b87c4 | |||
| 4452be587b | |||
| 1111ff604d | |||
| 781cdde288 | |||
| 59ebe28cd5 | |||
| d1e1f95975 | |||
| 37093eb929 | |||
| 8116b2a15c | |||
| 7512e58cfe | |||
| 14c1bd3b93 | |||
| 4277dc3ac9 | |||
| 8ad59ec127 | |||
| 2e13f7d9f0 | |||
| 4297f0669b | |||
| c6a613ef7c | |||
| fc74d6b8d9 | |||
| bdca5132a4 | |||
| 9af9af73f4 | |||
| d1cf218b9d | |||
| b57f8a8b9f | |||
| 941b1d35b8 | |||
| 1be1bebc04 | |||
| 3555ee0555 | |||
| a1b39e6db2 | |||
| 07bb65384c | |||
| 51e99b562d | |||
| 211533c738 | |||
| b0da230213 | |||
| b4f124c78c | |||
| 03b1d9ef1f | |||
| 2d23516462 | |||
| b20bbc7152 | |||
| 56623a6224 | |||
| 0200020162 | |||
| 5576f641ce | |||
| 566f6e7b76 | |||
| cad8866db1 | |||
| 3f7da15bba | |||
| cffc3fcce5 | |||
| a78b80966b | |||
| dc816a98fe | |||
| a6a7b1ce8f | |||
| 62851b5abd | |||
| 7a81d5ee0d | |||
| 84c1fcef05 | |||
| 42ba4e8cae | |||
| 7d685956cc | |||
| 9f4769fbe6 | |||
| aee6ff5c08 | |||
| 749fa8b55f | |||
| 66c81ed82e | |||
| 02dff061db | |||
| e0de2b0279 | |||
| b001d9383a | |||
| bfc691eaab | |||
| 8696d93e96 | |||
| c2905437ea | |||
| c969d4ece3 | |||
| cabdef8395 | |||
| 8219472cc9 | |||
| 86bb162dd3 | |||
| 9482a097c8 | |||
| 67b001c737 | |||
| dd9bbd8d4a | |||
| 6c380e0eb1 | |||
| d59c982d17 | |||
| 38de0681ff | |||
| 2100a7ca7b | |||
| 3307a8e057 | |||
| d6abdda34f | |||
| d48bff8342 | |||
| d0faaa9c7c | |||
| cc6017517d | |||
| 9e79f27547 | |||
| b79b8dcdd0 | |||
| d700447dda | |||
| 8c1c377272 | |||
| 70b51dc1bf | |||
| 6991631385 | |||
| 59502f930e | |||
| 20fac523c7 | |||
| 002a1add8b | |||
| 1f59fe6d1b | |||
| 3e9551bcfa | |||
| 13e6517460 | |||
| aff9eafea5 | |||
| 1ca636819f | |||
| fee5950a5c | |||
| 1af65a2248 | |||
| 720ccf9559 | |||
| b2fcc923cb | |||
| 2f5074cf32 | |||
| dcff1a34c7 | |||
| 46e2caea78 | |||
| bd8e257f84 | |||
| 51ee8965a7 | |||
| db56db2f79 | |||
| 99478417ac | |||
| 0f0e90971b | |||
| 7c4992bce1 | |||
| d55337ba4d | |||
| 59f9703224 | |||
| f39e65493e | |||
| f25977bcd4 | |||
| b31f814e8c | |||
| 2ab685565a | |||
| f6d3bede9a | |||
| 5ee29dc000 | |||
| de3fdef2ca | |||
| 799de75b8b | |||
| a211887978 | |||
| be59e8af2b | |||
| ed8ab3e32c | |||
| 52e12588c9 | |||
| 9e6874bd4d | |||
| 2df420f1f4 | |||
| b39fc98b4d | |||
| 6a9ec74b32 | |||
| 9e5f8983ec | |||
| 8c56bfe854 | |||
| 7b31fc54df | |||
| c99cbd915f | |||
| 0a2a764155 | |||
| 4f6c0d0ea5 | |||
| 44e62a3634 | |||
| ca10e4d075 | |||
| efbfd30318 | |||
| 3e0ee6fb74 | |||
| 2da12182f3 | |||
| 7df371750f | |||
| 5f23345886 | |||
| bf9569db93 | |||
| c71c0fba90 | |||
| 5249a606f1 | |||
| 1d11ae3087 | |||
| 3340ca46e8 | |||
| 6cc4e32e61 | |||
| 8f22819d47 | |||
| 489c5ff4a2 | |||
| 0c3c34e589 | |||
| 939006d2e5 | |||
| 0015f15f9a | |||
| 95321fbc2c | |||
| 7d6e15423b | |||
| 77062e9a36 | |||
| 0f53e1333f | |||
| c30bdcbca8 | |||
| 812836e22f | |||
| 8776b4b088 | |||
| a8700404f7 | |||
| 8101a836a4 | |||
| eddd1c0567 | |||
| 6e83b44940 | |||
| 448a90f6b0 | |||
| 8ec18d1476 | |||
| 4ef11f0905 | |||
| 1bc1b1b313 | |||
| 8863e1f696 | |||
| 57d116796a | |||
| 82c194f86c | |||
| 25cffa2617 | |||
| 24eac9d3ce | |||
| c587df3b66 | |||
| 372f2b76aa | |||
| 489475814a | |||
| fa9afb9763 | |||
| fed36fc5f8 | |||
| 833f8db838 | |||
| fc914e617e | |||
| e137e39911 | |||
| 61246deec5 | |||
| b91efb896d | |||
| ef091d39d2 | |||
| 72dc5d5862 | |||
| 814821727e | |||
| 909003cce9 | |||
| 3a27f065b7 | |||
| b131ebb8dd | |||
| 102cec8241 | |||
| 7ecb47958c | |||
| ad702096a9 | |||
| b090ff03ed | |||
| b45a037c7e | |||
| c7f477bc59 | |||
| 8901c9eca1 | |||
| 2f5c70e834 | |||
| ad09160b03 | |||
| be6a4745ae | |||
| 94624d64ba | |||
| ecfa4172d0 | |||
| 2baca55cda | |||
| c9866313a7 | |||
| 682ccec853 | |||
| edf9d33e61 | |||
| fe1f53ce8f | |||
| 36b7a13be9 | |||
| 6ebb44f17e | |||
| 24324378a8 | |||
| d840ef2b28 | |||
| dcb0c4e51e | |||
| bb75c10e28 | |||
| 3a01f51063 | |||
| b825af0728 | |||
| 9a65cc39da | |||
| fb65f07832 | |||
| c72ed7c024 | |||
| 557fbbd6af | |||
| 217ad5cfc0 | |||
| 6a723c3571 | |||
| 069e232bab | |||
| 15290f4366 | |||
| 1d3c2ceded | |||
| 33384a3663 | |||
| 02637ec350 | |||
| 9cd2024814 | |||
| b8dbebec2d | |||
| f07ea255a9 | |||
| 08a42dc72c | |||
| 77eae62d62 | |||
| 90f2a03895 | |||
| 71a9384f49 | |||
| cfc136f198 | |||
| b7fb5f9987 | |||
| fba519116d | |||
| a7e1de81ff | |||
| 85743b9f32 | |||
| 7b75aa1818 | |||
| 15d385a862 | |||
| c93dc153f1 | |||
| 66ef608726 | |||
| 7cbada6902 | |||
| c02be0012e | |||
| 354eedae7a | |||
| 0d88d277e4 | |||
| 5c3f3e8332 | |||
| 50baf28386 | |||
| 3f5d47eae8 | |||
| 856f49cf48 | |||
| 4f79b57774 | |||
| 3058bf0f83 | |||
| 2b1f97dcc2 | |||
| a8482a4424 | |||
| bd2af5c556 | |||
| 69e4c18153 | |||
| 2609c49731 | |||
| 4eb284ef8d | |||
| b554d8d336 | |||
| 8b188e060c | |||
| ddc6601487 | |||
| 88630d4913 | |||
| 96209d7eba | |||
| 92b2738bbb | |||
| 5eb7eee560 | |||
| 99706e038b | |||
| cf954bbfd0 | |||
| 6e516ee89f | |||
| 42a49ba44f | |||
| 43d18321e3 | |||
| 58769a40de | |||
| 2842ab4052 | |||
| a7eb27b867 | |||
| 5e817664ad | |||
| fd98d78cd8 | |||
| 37d801776e | |||
| f0c14507a5 | |||
| 80e321f6ab | |||
| aebf17b7e2 | |||
| 52acb7dcac | |||
| 4187fc7fbb | |||
| be1dcb9185 | |||
| 012db45bfb | |||
| 75bba4522d | |||
| 113b0f04bc | |||
| dff6f23a1a | |||
| 461f279883 | |||
| 9b07108fbf | |||
| 8e1269617a | |||
| 92ec98d5ce | |||
| d4e05f6df3 | |||
| 0b9324f332 | |||
| c20522369b | |||
| cec35d2399 | |||
| 4b9f73d32e | |||
| a760168722 | |||
| c6277687b4 | |||
| 79f2fca1f9 | |||
| 34602f4b25 | |||
| 2b212cf692 | |||
| 65e7d0c01f | |||
| c08ed73216 | |||
| db608aae51 | |||
| bc617d8ad1 | |||
| a5a3918856 | |||
| 6ed4f51413 | |||
| d7d3839b8d | |||
| 184f4b38c8 | |||
| 93149711f6 | |||
| dfecad4362 | |||
| b1942d1d0c | |||
| 93bacff1a6 | |||
| 36ebc75e9a | |||
| a483ab3213 | |||
| ced6d835e8 | |||
| a2ddb44957 | |||
| 31a6401193 | |||
| ceea8ab5fe | |||
| f10285d800 | |||
| aafbe043f9 | |||
| 20e16bbcc4 | |||
| e6e6529b4a | |||
| 4cff18a705 | |||
| 1a4db497db | |||
| 5470e4a8ad | |||
| 5d0c92b40c | |||
| e014d9897d | |||
| ec7c3ac12d | |||
| 2fbdfae4b7 | |||
| 017c26c167 | |||
| 0b4afdf35b | |||
| 371fc8c062 | |||
| d52dca47e8 | |||
| 0c402157fc | |||
| 05b6fbb1f5 | |||
| b4b636112e | |||
| 5491385f3d | |||
| 437dad1b0e | |||
| 13a44b1fff | |||
| 89260bab86 | |||
| ceab485e58 | |||
| 9682abd5b8 | |||
| 21958a9343 | |||
| 69b211abb6 | |||
| 78dba27922 | |||
| 515eb94fab | |||
| 30d060417f | |||
| 9578b4b570 | |||
| a1ca14c1e1 | |||
| 7562f6644f | |||
| 82d3bdb733 | |||
| 98078f769d | |||
| de59dd1835 | |||
| e67ac61160 | |||
| a120a166b9 | |||
| 687d4772a7 | |||
| fea1a3d5c7 | |||
| 6332caef78 | |||
| ff878aa30c | |||
| 98aaf7dccd | |||
| 86fd95962c | |||
| 3c9ddf7c53 | |||
| 0a21929928 | |||
| 30c201e1c5 | |||
| 34dccc565e | |||
| 2093498425 | |||
| c3937de310 | |||
| bd63d91163 | |||
| bd07ae6713 | |||
| f9a39775fc | |||
| 6e8c3dfafc | |||
| ccd1839443 | |||
| b1c4d3322d | |||
| 03f2235bc5 | |||
| eada33b889 | |||
| d5293e1f43 | |||
| 005949ff25 | |||
| ac466c1571 | |||
| 8dbc8a802c | |||
| 2387a95be6 | |||
| ce8e5fb54e | |||
| d0063ea3e9 | |||
| 2b975f3f3a | |||
| 34592f225a | |||
| 49d8d9ebf2 | |||
| 5fb93934d0 | |||
| 99e11f4823 | |||
| c089541938 | |||
| 73e372d920 | |||
| 1f1d2ffd29 | |||
| 0a3452f307 | |||
| bfc8539d68 | |||
| c32a329583 | |||
| 668e6b8e92 | |||
| 89f7378569 | |||
| 8b44eaa63e | |||
| 367e2bb0ff | |||
| 6513e0cea3 | |||
| 5fcdff9935 | |||
| 4fe6f3cd7a | |||
| cbb51eacb0 | |||
| 602b0b14d5 | |||
| dde5cd1c54 | |||
| c8af82432d | |||
| f85b945c32 | |||
| 0d02af816b | |||
| 42caee329f | |||
| 6636c21453 | |||
| 7d6a7e195c | |||
| 967b3b351b | |||
| 9d801cb03d | |||
| db38fb1a60 | |||
| 98823ff8fc | |||
| 13e8fea023 | |||
| 60b4ee1df3 | |||
| 6151b365f9 | |||
| 14d5c3f2f1 | |||
| cd3db41d06 | |||
| 25707cad5c | |||
| c86baf3ece | |||
| 2689e360ce | |||
| d3952523fe | |||
| 0709d208db | |||
| be2265d0d1 | |||
| 1127e0da6b | |||
| f08824f6eb | |||
| 740c47d4d7 | |||
| c929b7aadf | |||
| 6f81880f17 | |||
| 6209122213 | |||
| 6bc870d899 | |||
| cffe143ca2 | |||
| ac31863021 | |||
| 4519af69a9 | |||
| 4d96e53222 | |||
| 8503c97b96 | |||
| c53ee0b3ce | |||
| fa1d3159af | |||
| e969420a85 | |||
| ba7243d409 | |||
| 2cd350d3f4 | |||
| cd62961392 | |||
| eadfcb9a40 | |||
| ed43450043 | |||
| 5df515c22d | |||
| 2d03a337ab | |||
| 111ee6cb91 | |||
| daf71c8d37 | |||
| ca5bd0aa2c | |||
| a1dd4f3c0f | |||
| c93935f243 | |||
| dfe5fe7181 | |||
| c20096c7aa | |||
| 79f2445414 | |||
| 25713dc222 | |||
| e15dbb49e0 | |||
| 3a3272a3d6 | |||
| 11d5ff415f | |||
| 672c6b4721 | |||
| f9cf09ebd1 | |||
| 7f7364c559 | |||
| 76a673233c | |||
| 0391801267 | |||
| 6e40dfa022 | |||
| f491e6b138 | |||
| 859e2aa86b | |||
| d6b9056d42 | |||
| c734e7c1bf | |||
| 407647d0d1 | |||
| bd1d41024b | |||
| 19abd80fb2 | |||
| 78b330c8b4 | |||
| e0490a24f2 | |||
| 53472a4e7b | |||
| e24fe0832b | |||
| 45731efcac | |||
| b7ed91f861 | |||
| 4582b1b41a | |||
| d737b4704c | |||
| 51bc051172 | |||
| df7fe3e2ac | |||
| e95156d4d8 | |||
| 96073e1368 | |||
| f5995901b0 | |||
| 77d3e564f7 | |||
| 78648b37e9 | |||
| 7b018f097d | |||
| b6bd01aa8b | |||
| 9a356ab943 | |||
| acf7824f9a | |||
| 3410b25cf8 | |||
| 560386461e | |||
| 8d61218abe | |||
| 6beca1c6c0 | |||
| aefa85162b | |||
| 4219508b42 | |||
| 1b29f98d99 | |||
| 4b185a52bc | |||
| 3a2d01df6a | |||
| 8fe49ebe0b | |||
| 9f72f27279 | |||
| c8fd62432a | |||
| b33ecce392 | |||
| 9d0b145007 | |||
| c12268807d | |||
| c0bb153151 | |||
| 3c5b9f70f5 | |||
| fce882f516 | |||
| 045977ea91 | |||
| 7e3dab79ad | |||
| a97da5a569 | |||
| 14d5e92da5 | |||
| 8b865a9d64 | |||
| ce5a2a7367 | |||
| f6be5773d5 | |||
| 757b42f2fb | |||
| c03859a3e4 | |||
| 415faebd65 | |||
| dd994e72ad | |||
| f92d153532 | |||
| 31bce31c74 | |||
| 6ef36482a2 | |||
| 46a74d820f | |||
| c394bf1c98 | |||
| 7aa466515e | |||
| ef847f8ef6 | |||
| 30f0bbe079 | |||
| 1259140d5a | |||
| 108684351e | |||
| af936c6ae6 | |||
| 26febb7c24 | |||
| fe2ef59240 | |||
| fc968fd473 | |||
| 0ea644a53b | |||
| 3c90a30fe7 | |||
| 6cc51eb9d9 | |||
| eecd22fbd4 | |||
| 9d7e64bcb3 | |||
| 0e52a84878 | |||
| fc51ce8304 | |||
| 1b67b14587 | |||
| 5f7c0e3097 | |||
| ce1ee47ef5 | |||
| 942b3cf16c | |||
| e8747e116f | |||
| 681f9f4ca6 | |||
| ae3219ae0e | |||
| 42a5742add | |||
| 590082520e | |||
| a299018824 | |||
| 12b9831eeb | |||
| 3c0a91059b | |||
| 3bf2403244 | |||
| 4466261895 | |||
| 4d55cde5a7 | |||
| d123364b32 | |||
| 0b241ea4f7 | |||
| 1493e6d3f0 | |||
| 3d06860f3c | |||
| 3716e02ff3 | |||
| 2726856cde | |||
| 3079fd0415 | |||
| 0e5fc86c68 | |||
| a1c39084a2 | |||
| 8879cdb250 | |||
| 75714ff123 | |||
| 4bc356711d | |||
| 12d26c1466 | |||
| 2445c1435a | |||
| 9204f8535b | |||
| 55a84843ea | |||
| a83731660d | |||
| d57ecaa9a6 | |||
| b5a5bb6d74 | |||
| fefcad3933 | |||
| 04d9c53c6e | |||
| c1556f7af0 | |||
| 25a0432228 | |||
| b7cdda7dcd | |||
| c1297ceb97 | |||
| a3e9b347ec | |||
| 5ebeb32ec0 | |||
| bee48ced71 | |||
| 852d3af0a1 | |||
| 1c1ba06cfb | |||
| 36d5ea8f85 | |||
| dcb20e55fc | |||
| 5bd3e9e806 | |||
| 7ac9d1abe4 | |||
| 696dea19f6 | |||
| 9215edde66 | |||
| 9d0373779c | |||
| 6779f847ea | |||
| e931ac57e1 | |||
| 42412d7272 | |||
| d558d10042 | |||
| 7f67504993 | |||
| 4461355cce | |||
| ccc2030bee | |||
| 6932e22dd8 | |||
| 69c341eb5c | |||
| 1f7faad37a | |||
| d41067f59b | |||
| 24d47dc631 | |||
| c99d2965a0 | |||
| 9a4a3517de | |||
| 4b1db46647 | |||
| 51db8baf77 |
@@ -19,6 +19,10 @@ endif
|
||||
# Otherwise the [OK], [ERROR] and [WARN] messages won't be displayed correctly
|
||||
override SILENT := false
|
||||
|
||||
ifdef SKIP_VERSION
|
||||
SKIP_GIT := yes
|
||||
endif
|
||||
|
||||
ifndef SUB_IS_SILENT
|
||||
ifndef SKIP_GIT
|
||||
QMK_VERSION := $(shell git describe --abbrev=0 --tags 2>/dev/null)
|
||||
@@ -50,48 +54,12 @@ ABS_ROOT_MAKEFILE := $(abspath $(ROOT_MAKEFILE))
|
||||
ABS_STARTING_DIR := $(dir $(ABS_STARTING_MAKEFILE))
|
||||
ABS_ROOT_DIR := $(dir $(ABS_ROOT_MAKEFILE))
|
||||
STARTING_DIR := $(subst $(ABS_ROOT_DIR),,$(ABS_STARTING_DIR))
|
||||
BUILD_DIR := $(ROOT_DIR)/.build
|
||||
TEST_DIR := $(BUILD_DIR)/test
|
||||
|
||||
include paths.mk
|
||||
|
||||
TEST_OUTPUT_DIR := $(BUILD_DIR)/test
|
||||
ERROR_FILE := $(BUILD_DIR)/error_occurred
|
||||
|
||||
# Helper function to process the newt element of a space separated path
|
||||
# It works a bit like the traditional functional head tail
|
||||
# so the CURRENT_PATH_ELEMENT will become the new head
|
||||
# and the PATH_ELEMENTS are the rest that are still unprocessed
|
||||
define NEXT_PATH_ELEMENT
|
||||
$$(eval CURRENT_PATH_ELEMENT := $$(firstword $$(PATH_ELEMENTS)))
|
||||
$$(eval PATH_ELEMENTS := $$(wordlist 2,9999,$$(PATH_ELEMENTS)))
|
||||
endef
|
||||
|
||||
# We change the / to spaces so that we more easily can work with the elements
|
||||
# separately
|
||||
PATH_ELEMENTS := $(subst /, ,$(STARTING_DIR))
|
||||
# Initialize the path elements list for further processing
|
||||
$(eval $(call NEXT_PATH_ELEMENT))
|
||||
|
||||
|
||||
# Phony targets to enable a few simple make commands outside the main processing below.
|
||||
.PHONY: list-keyboards
|
||||
list-keyboards:
|
||||
util/list_keyboards.sh | sort -u | tr '\n' ' '
|
||||
|
||||
.PHONY: generate-keyboards-file
|
||||
generate-keyboards-file:
|
||||
util/list_keyboards.sh | sort -u
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
echo -n 'Deleting .build/ ... '
|
||||
rm -rf $(BUILD_DIR)
|
||||
echo 'done.'
|
||||
|
||||
.PHONY: distclean
|
||||
distclean: clean
|
||||
echo -n 'Deleting *.bin, *.hex, and *.uf2 ... '
|
||||
rm -f *.bin *.hex *.uf2
|
||||
echo 'done.'
|
||||
|
||||
|
||||
.DEFAULT_GOAL := all:all
|
||||
|
||||
|
||||
@@ -119,53 +87,20 @@ endef
|
||||
# a function that returns the value
|
||||
COMPARE_AND_REMOVE_FROM_RULE = $(eval $(call COMPARE_AND_REMOVE_FROM_RULE_HELPER,$1))$(RULE_FOUND)
|
||||
|
||||
|
||||
# Recursively try to find a match for the start of the rule to be checked
|
||||
# $1 The list to be checked
|
||||
# If a match is found, then RULE_FOUND is set to true
|
||||
# and MATCHED_ITEM to the item that was matched
|
||||
define TRY_TO_MATCH_RULE_FROM_LIST_HELPER3
|
||||
ifneq ($1,)
|
||||
ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,$$(firstword $1)),true)
|
||||
MATCHED_ITEM := $$(firstword $1)
|
||||
else
|
||||
$$(eval $$(call TRY_TO_MATCH_RULE_FROM_LIST_HELPER3,$$(wordlist 2,9999,$1)))
|
||||
endif
|
||||
endif
|
||||
endef
|
||||
|
||||
# A recursive helper function for finding the longest match
|
||||
# $1 The list to be checked
|
||||
# It works by always removing the currently matched item from the list
|
||||
define TRY_TO_MATCH_RULE_FROM_LIST_HELPER2
|
||||
# Stop the recursion when the list is empty
|
||||
ifneq ($1,)
|
||||
RULE_BEFORE := $$(RULE)
|
||||
$$(eval $$(call TRY_TO_MATCH_RULE_FROM_LIST_HELPER3,$1))
|
||||
# If a match is found in the current list, otherwise just return what we had before
|
||||
ifeq ($$(RULE_FOUND),true)
|
||||
# Save the best match so far and call itself recursively
|
||||
BEST_MATCH := $$(MATCHED_ITEM)
|
||||
BEST_MATCH_RULE := $$(RULE)
|
||||
RULE_FOUND := false
|
||||
RULE := $$(RULE_BEFORE)
|
||||
$$(eval $$(call TRY_TO_MATCH_RULE_FROM_LIST_HELPER2,$$(filter-out $$(MATCHED_ITEM),$1)))
|
||||
endif
|
||||
endif
|
||||
endef
|
||||
|
||||
|
||||
# Recursively try to find the longest match for the start of the rule to be checked
|
||||
# Try to find a match for the start of the rule to be checked
|
||||
# $1 The list to be checked
|
||||
# If a match is found, then RULE_FOUND is set to true
|
||||
# and MATCHED_ITEM to the item that was matched
|
||||
define TRY_TO_MATCH_RULE_FROM_LIST_HELPER
|
||||
BEST_MATCH :=
|
||||
$$(eval $$(call TRY_TO_MATCH_RULE_FROM_LIST_HELPER2,$1))
|
||||
ifneq ($$(BEST_MATCH),)
|
||||
# Split on ":", padding with empty strings to avoid indexing issues
|
||||
TOKEN1:=$$(shell python3 -c "import sys; print((sys.argv[1].split(':',1)+[''])[0])" $$(RULE))
|
||||
TOKENr:=$$(shell python3 -c "import sys; print((sys.argv[1].split(':',1)+[''])[1])" $$(RULE))
|
||||
|
||||
FOUNDx:=$$(shell echo $1 | tr " " "\n" | grep -Fx $$(TOKEN1))
|
||||
ifneq ($$(FOUNDx),)
|
||||
RULE := $$(TOKENr)
|
||||
RULE_FOUND := true
|
||||
RULE := $$(BEST_MATCH_RULE)
|
||||
MATCHED_ITEM := $$(BEST_MATCH)
|
||||
MATCHED_ITEM := $$(TOKEN1)
|
||||
else
|
||||
RULE_FOUND := false
|
||||
MATCHED_ITEM :=
|
||||
@@ -387,7 +322,7 @@ define BUILD_TEST
|
||||
MAKE_MSG := $$(MSG_MAKE_TEST)
|
||||
$$(eval $$(call BUILD))
|
||||
ifneq ($$(MAKE_TARGET),clean)
|
||||
TEST_EXECUTABLE := $$(TEST_DIR)/$$(TEST_NAME).elf
|
||||
TEST_EXECUTABLE := $$(TEST_OUTPUT_DIR)/$$(TEST_NAME).elf
|
||||
TESTS += $$(TEST_NAME)
|
||||
TEST_MSG := $$(MSG_TEST)
|
||||
$$(TEST_NAME)_COMMAND := \
|
||||
@@ -404,6 +339,7 @@ define PARSE_TEST
|
||||
TESTS :=
|
||||
TEST_NAME := $$(firstword $$(subst :, ,$$(RULE)))
|
||||
TEST_TARGET := $$(subst $$(TEST_NAME),,$$(subst $$(TEST_NAME):,,$$(RULE)))
|
||||
include $(ROOT_DIR)/testlist.mk
|
||||
ifeq ($$(TEST_NAME),all)
|
||||
MATCHED_TESTS := $$(TEST_LIST)
|
||||
else
|
||||
@@ -426,7 +362,6 @@ define SET_SILENT_MODE
|
||||
endif
|
||||
endef
|
||||
|
||||
include paths.mk
|
||||
include $(BUILDDEFS_PATH)/message.mk
|
||||
|
||||
ifeq ($(strip $(BREAK_ON_ERRORS)), yes)
|
||||
@@ -496,14 +431,22 @@ git-submodule:
|
||||
git submodule sync --recursive
|
||||
git submodule update --init --recursive --progress
|
||||
|
||||
# Generate the version.h file
|
||||
ifdef SKIP_GIT
|
||||
VERSION_H_FLAGS := --skip-git
|
||||
endif
|
||||
ifdef SKIP_VERSION
|
||||
VERSION_H_FLAGS := --skip-all
|
||||
SKIP_GIT := yes
|
||||
endif
|
||||
$(shell $(QMK_BIN) generate-version-h $(VERSION_H_FLAGS) -q -o quantum/version.h)
|
||||
.PHONY: list-keyboards
|
||||
list-keyboards:
|
||||
util/list_keyboards.sh | sort -u | tr '\n' ' '
|
||||
|
||||
include $(ROOT_DIR)/testlist.mk
|
||||
.PHONY: generate-keyboards-file
|
||||
generate-keyboards-file:
|
||||
util/list_keyboards.sh | sort -u
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
echo -n 'Deleting .build/ ... '
|
||||
rm -rf $(BUILD_DIR)
|
||||
echo 'done.'
|
||||
|
||||
.PHONY: distclean
|
||||
distclean: clean
|
||||
echo -n 'Deleting *.bin, *.hex, and *.uf2 ... '
|
||||
rm -f *.bin *.hex *.uf2
|
||||
echo 'done.'
|
||||
|
||||
@@ -37,6 +37,15 @@ ifdef SKIP_VERSION
|
||||
OPT_DEFS += -DSKIP_VERSION
|
||||
endif
|
||||
|
||||
# Generate the version.h file
|
||||
ifdef SKIP_VERSION
|
||||
VERSION_H_FLAGS := --skip-all
|
||||
endif
|
||||
ifdef SKIP_GIT
|
||||
VERSION_H_FLAGS := --skip-git
|
||||
endif
|
||||
$(shell $(QMK_BIN) generate-version-h $(VERSION_H_FLAGS) -q -o quantum/version.h)
|
||||
|
||||
# Determine which subfolders exist.
|
||||
KEYBOARD_FOLDER_PATH_1 := $(KEYBOARD)
|
||||
KEYBOARD_FOLDER_PATH_2 := $(patsubst %/,%,$(dir $(KEYBOARD_FOLDER_PATH_1)))
|
||||
|
||||
@@ -43,6 +43,7 @@ all: elf
|
||||
VPATH += $(COMMON_VPATH)
|
||||
PLATFORM:=TEST
|
||||
PLATFORM_KEY:=test
|
||||
BOOTLOADER_TYPE:=none
|
||||
|
||||
ifeq ($(strip $(DEBUG)), 1)
|
||||
CONSOLE_ENABLE = yes
|
||||
|
||||
+38
-2
@@ -30,6 +30,7 @@
|
||||
# bootloadhid HIDBootFlash compatible (ATmega32A)
|
||||
# usbasploader USBaspLoader (ATmega328P)
|
||||
# ARM:
|
||||
# halfkay PJRC Teensy
|
||||
# kiibohd Input:Club Kiibohd bootloader (only used on their boards)
|
||||
# stm32duino STM32Duino (STM32F103x8)
|
||||
# stm32-dfu STM32 USB DFU in ROM
|
||||
@@ -43,6 +44,8 @@
|
||||
ifeq ($(strip $(BOOTLOADER)), atmel-dfu)
|
||||
OPT_DEFS += -DBOOTLOADER_ATMEL_DFU
|
||||
OPT_DEFS += -DBOOTLOADER_DFU
|
||||
BOOTLOADER_TYPE = dfu
|
||||
|
||||
ifneq (,$(filter $(MCU), at90usb162 atmega16u2 atmega32u2 atmega16u4 atmega32u4 at90usb646 at90usb647))
|
||||
BOOTLOADER_SIZE = 4096
|
||||
endif
|
||||
@@ -53,6 +56,8 @@ endif
|
||||
ifeq ($(strip $(BOOTLOADER)), lufa-dfu)
|
||||
OPT_DEFS += -DBOOTLOADER_LUFA_DFU
|
||||
OPT_DEFS += -DBOOTLOADER_DFU
|
||||
BOOTLOADER_TYPE = dfu
|
||||
|
||||
ifneq (,$(filter $(MCU), at90usb162 atmega16u2 atmega32u2 atmega16u4 atmega32u4 at90usb646 at90usb647))
|
||||
BOOTLOADER_SIZE ?= 4096
|
||||
endif
|
||||
@@ -63,6 +68,8 @@ endif
|
||||
ifeq ($(strip $(BOOTLOADER)), qmk-dfu)
|
||||
OPT_DEFS += -DBOOTLOADER_QMK_DFU
|
||||
OPT_DEFS += -DBOOTLOADER_DFU
|
||||
BOOTLOADER_TYPE = dfu
|
||||
|
||||
ifneq (,$(filter $(MCU), at90usb162 atmega16u2 atmega32u2 atmega16u4 atmega32u4 at90usb646 at90usb647))
|
||||
BOOTLOADER_SIZE ?= 4096
|
||||
endif
|
||||
@@ -73,10 +80,14 @@ endif
|
||||
ifeq ($(strip $(BOOTLOADER)), qmk-hid)
|
||||
OPT_DEFS += -DBOOTLOADER_QMK_HID
|
||||
OPT_DEFS += -DBOOTLOADER_HID
|
||||
BOOTLOADER_TYPE = dfu
|
||||
|
||||
BOOTLOADER_SIZE ?= 4096
|
||||
endif
|
||||
ifeq ($(strip $(BOOTLOADER)), halfkay)
|
||||
OPT_DEFS += -DBOOTLOADER_HALFKAY
|
||||
BOOTLOADER_TYPE = halfkay
|
||||
|
||||
ifeq ($(strip $(MCU)), atmega32u4)
|
||||
BOOTLOADER_SIZE = 512
|
||||
endif
|
||||
@@ -86,18 +97,26 @@ ifeq ($(strip $(BOOTLOADER)), halfkay)
|
||||
endif
|
||||
ifeq ($(strip $(BOOTLOADER)), caterina)
|
||||
OPT_DEFS += -DBOOTLOADER_CATERINA
|
||||
BOOTLOADER_TYPE = caterina
|
||||
|
||||
BOOTLOADER_SIZE = 4096
|
||||
endif
|
||||
ifneq (,$(filter $(BOOTLOADER), bootloadhid bootloadHID))
|
||||
OPT_DEFS += -DBOOTLOADER_BOOTLOADHID
|
||||
BOOTLOADER_TYPE = bootloadhid
|
||||
|
||||
BOOTLOADER_SIZE = 4096
|
||||
endif
|
||||
ifneq (,$(filter $(BOOTLOADER), usbasploader USBasp))
|
||||
OPT_DEFS += -DBOOTLOADER_USBASP
|
||||
BOOTLOADER_TYPE = usbasploader
|
||||
|
||||
BOOTLOADER_SIZE = 4096
|
||||
endif
|
||||
ifeq ($(strip $(BOOTLOADER)), lufa-ms)
|
||||
OPT_DEFS += -DBOOTLOADER_MS
|
||||
BOOTLOADER_TYPE = dfu
|
||||
|
||||
BOOTLOADER_SIZE ?= 8192
|
||||
FIRMWARE_FORMAT = bin
|
||||
cpfirmware: lufa_warning
|
||||
@@ -115,6 +134,7 @@ endif
|
||||
|
||||
ifeq ($(strip $(BOOTLOADER)), stm32-dfu)
|
||||
OPT_DEFS += -DBOOTLOADER_STM32_DFU
|
||||
BOOTLOADER_TYPE = stm32_dfu
|
||||
|
||||
# Options to pass to dfu-util when flashing
|
||||
DFU_ARGS ?= -d 0483:DF11 -a 0 -s 0x08000000:leave
|
||||
@@ -122,6 +142,7 @@ ifeq ($(strip $(BOOTLOADER)), stm32-dfu)
|
||||
endif
|
||||
ifeq ($(strip $(BOOTLOADER)), apm32-dfu)
|
||||
OPT_DEFS += -DBOOTLOADER_APM32_DFU
|
||||
BOOTLOADER_TYPE = stm32_dfu
|
||||
|
||||
# Options to pass to dfu-util when flashing
|
||||
DFU_ARGS ?= -d 314B:0106 -a 0 -s 0x08000000:leave
|
||||
@@ -129,6 +150,7 @@ ifeq ($(strip $(BOOTLOADER)), apm32-dfu)
|
||||
endif
|
||||
ifeq ($(strip $(BOOTLOADER)), gd32v-dfu)
|
||||
OPT_DEFS += -DBOOTLOADER_GD32V_DFU
|
||||
BOOTLOADER_TYPE = gd32v_dfu
|
||||
|
||||
# Options to pass to dfu-util when flashing
|
||||
DFU_ARGS ?= -d 28E9:0189 -a 0 -s 0x08000000:leave
|
||||
@@ -136,6 +158,8 @@ ifeq ($(strip $(BOOTLOADER)), gd32v-dfu)
|
||||
endif
|
||||
ifeq ($(strip $(BOOTLOADER)), kiibohd)
|
||||
OPT_DEFS += -DBOOTLOADER_KIIBOHD
|
||||
BOOTLOADER_TYPE = kiibohd
|
||||
|
||||
ifeq ($(strip $(MCU_ORIG)), MK20DX128)
|
||||
MCU_LDSCRIPT = MK20DX128BLDR4
|
||||
endif
|
||||
@@ -151,8 +175,7 @@ ifeq ($(strip $(BOOTLOADER)), stm32duino)
|
||||
OPT_DEFS += -DBOOTLOADER_STM32DUINO
|
||||
MCU_LDSCRIPT = STM32F103x8_stm32duino_bootloader
|
||||
BOARD = STM32_F103_STM32DUINO
|
||||
# STM32F103 does NOT have an USB bootloader in ROM (only serial), so setting anything here does not make much sense
|
||||
STM32_BOOTLOADER_ADDRESS = 0x80000000
|
||||
BOOTLOADER_TYPE = stm32duino
|
||||
|
||||
# Options to pass to dfu-util when flashing
|
||||
DFU_ARGS = -d 1EAF:0003 -a 2 -R
|
||||
@@ -160,4 +183,17 @@ ifeq ($(strip $(BOOTLOADER)), stm32duino)
|
||||
endif
|
||||
ifeq ($(strip $(BOOTLOADER)), tinyuf2)
|
||||
OPT_DEFS += -DBOOTLOADER_TINYUF2
|
||||
BOOTLOADER_TYPE = tinyuf2
|
||||
endif
|
||||
ifeq ($(strip $(BOOTLOADER)), halfkay)
|
||||
OPT_DEFS += -DBOOTLOADER_HALFKAY
|
||||
BOOTLOADER_TYPE = halfkay
|
||||
endif
|
||||
ifeq ($(strip $(BOOTLOADER)), md-boot)
|
||||
OPT_DEFS += -DBOOTLOADER_MD_BOOT
|
||||
BOOTLOADER_TYPE = md_boot
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(BOOTLOADER_TYPE)),)
|
||||
BOOTLOADER_TYPE = none
|
||||
endif
|
||||
|
||||
@@ -143,6 +143,9 @@ ifneq ($(findstring STM32F042, $(MCU)),)
|
||||
# This ensures that the EEPROM page buffer fits into RAM
|
||||
USE_PROCESS_STACKSIZE = 0x600
|
||||
USE_EXCEPTIONS_STACKSIZE = 0x300
|
||||
|
||||
# Bootloader address for STM32 DFU
|
||||
STM32_BOOTLOADER_ADDRESS ?= 0x1FFFC400
|
||||
endif
|
||||
|
||||
ifneq ($(findstring STM32F072, $(MCU)),)
|
||||
@@ -175,6 +178,9 @@ ifneq ($(findstring STM32F072, $(MCU)),)
|
||||
|
||||
# UF2 settings
|
||||
UF2_FAMILY ?= STM32F0
|
||||
|
||||
# Bootloader address for STM32 DFU
|
||||
STM32_BOOTLOADER_ADDRESS ?= 0x1FFFC800
|
||||
endif
|
||||
|
||||
ifneq ($(findstring STM32F103, $(MCU)),)
|
||||
@@ -239,6 +245,9 @@ ifneq ($(findstring STM32F303, $(MCU)),)
|
||||
|
||||
# UF2 settings
|
||||
UF2_FAMILY ?= STM32F3
|
||||
|
||||
# Bootloader address for STM32 DFU
|
||||
STM32_BOOTLOADER_ADDRESS ?= 0x1FFFD800
|
||||
endif
|
||||
|
||||
ifneq ($(findstring STM32F401, $(MCU)),)
|
||||
@@ -276,6 +285,9 @@ ifneq ($(findstring STM32F401, $(MCU)),)
|
||||
|
||||
# UF2 settings
|
||||
UF2_FAMILY ?= STM32F4
|
||||
|
||||
# Bootloader address for STM32 DFU
|
||||
STM32_BOOTLOADER_ADDRESS ?= 0x1FFF0000
|
||||
endif
|
||||
|
||||
ifneq ($(findstring STM32F405, $(MCU)),)
|
||||
@@ -308,6 +320,9 @@ ifneq ($(findstring STM32F405, $(MCU)),)
|
||||
|
||||
# UF2 settings
|
||||
UF2_FAMILY ?= STM32F4
|
||||
|
||||
# Bootloader address for STM32 DFU
|
||||
STM32_BOOTLOADER_ADDRESS ?= 0x1FFF0000
|
||||
endif
|
||||
|
||||
ifneq ($(findstring STM32F407, $(MCU)),)
|
||||
@@ -340,6 +355,9 @@ ifneq ($(findstring STM32F407, $(MCU)),)
|
||||
|
||||
# UF2 settings
|
||||
UF2_FAMILY ?= STM32F4
|
||||
|
||||
# Bootloader address for STM32 DFU
|
||||
STM32_BOOTLOADER_ADDRESS ?= 0x1FFF0000
|
||||
endif
|
||||
|
||||
ifneq ($(findstring STM32F411, $(MCU)),)
|
||||
@@ -377,6 +395,9 @@ ifneq ($(findstring STM32F411, $(MCU)),)
|
||||
|
||||
# UF2 settings
|
||||
UF2_FAMILY ?= STM32F4
|
||||
|
||||
# Bootloader address for STM32 DFU
|
||||
STM32_BOOTLOADER_ADDRESS ?= 0x1FFF0000
|
||||
endif
|
||||
|
||||
ifneq ($(findstring STM32F446, $(MCU)),)
|
||||
@@ -406,6 +427,9 @@ ifneq ($(findstring STM32F446, $(MCU)),)
|
||||
BOARD ?= GENERIC_STM32_F446XE
|
||||
|
||||
USE_FPU ?= yes
|
||||
|
||||
# Bootloader address for STM32 DFU
|
||||
STM32_BOOTLOADER_ADDRESS ?= 0x1FFF0000
|
||||
endif
|
||||
|
||||
ifneq ($(findstring STM32G431, $(MCU)),)
|
||||
@@ -438,6 +462,9 @@ ifneq ($(findstring STM32G431, $(MCU)),)
|
||||
|
||||
# UF2 settings
|
||||
UF2_FAMILY ?= STM32G4
|
||||
|
||||
# Bootloader address for STM32 DFU
|
||||
STM32_BOOTLOADER_ADDRESS ?= 0x1FFF0000
|
||||
endif
|
||||
|
||||
ifneq ($(findstring STM32G474, $(MCU)),)
|
||||
@@ -470,6 +497,46 @@ ifneq ($(findstring STM32G474, $(MCU)),)
|
||||
|
||||
# UF2 settings
|
||||
UF2_FAMILY ?= STM32G4
|
||||
|
||||
# Bootloader address for STM32 DFU
|
||||
STM32_BOOTLOADER_ADDRESS ?= 0x1FFF0000
|
||||
endif
|
||||
|
||||
ifneq (,$(filter $(MCU),STM32L432 STM32L442))
|
||||
# Cortex version
|
||||
MCU = cortex-m4
|
||||
|
||||
# ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
|
||||
ARMV = 7
|
||||
|
||||
## chip/board settings
|
||||
# - the next two should match the directories in
|
||||
# <chibios>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
|
||||
MCU_FAMILY = STM32
|
||||
MCU_SERIES = STM32L4xx
|
||||
|
||||
# Linker script to use
|
||||
# - it should exist either in <chibios>/os/common/startup/ARMCMx/compilers/GCC/ld/
|
||||
# or <keyboard_dir>/ld/
|
||||
MCU_LDSCRIPT ?= STM32L432xC
|
||||
|
||||
# Startup code to use
|
||||
# - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
|
||||
MCU_STARTUP ?= stm32l4xx
|
||||
|
||||
# Board: it should exist either in <chibios>/os/hal/boards/,
|
||||
# <keyboard_dir>/boards/, or drivers/boards/
|
||||
BOARD ?= GENERIC_STM32_L432XC
|
||||
|
||||
PLATFORM_NAME ?= platform_l432
|
||||
|
||||
USE_FPU ?= yes
|
||||
|
||||
# UF2 settings
|
||||
UF2_FAMILY ?= STM32L4
|
||||
|
||||
# Bootloader address for STM32 DFU
|
||||
STM32_BOOTLOADER_ADDRESS ?= 0x1FFF0000
|
||||
endif
|
||||
|
||||
ifneq (,$(filter $(MCU),STM32L433 STM32L443))
|
||||
@@ -504,6 +571,9 @@ ifneq (,$(filter $(MCU),STM32L433 STM32L443))
|
||||
|
||||
# UF2 settings
|
||||
UF2_FAMILY ?= STM32L4
|
||||
|
||||
# Bootloader address for STM32 DFU
|
||||
STM32_BOOTLOADER_ADDRESS ?= 0x1FFF0000
|
||||
endif
|
||||
|
||||
ifneq (,$(filter $(MCU),STM32L412 STM32L422))
|
||||
@@ -538,6 +608,9 @@ ifneq (,$(filter $(MCU),STM32L412 STM32L422))
|
||||
|
||||
# UF2 settings
|
||||
UF2_FAMILY ?= STM32L4
|
||||
|
||||
# Bootloader address for STM32 DFU
|
||||
STM32_BOOTLOADER_ADDRESS ?= 0x1FFF0000
|
||||
endif
|
||||
|
||||
ifneq ($(findstring WB32F3G71, $(MCU)),)
|
||||
@@ -567,6 +640,10 @@ ifneq ($(findstring WB32F3G71, $(MCU)),)
|
||||
BOARD ?= GENERIC_WB32_F3G71XX
|
||||
|
||||
USE_FPU ?= no
|
||||
|
||||
# Bootloader address for WB32 DFU
|
||||
STM32_BOOTLOADER_ADDRESS ?= 0x1FFFE000
|
||||
WB32_BOOTLOADER_ADDRESS ?= 0x1FFFE000
|
||||
endif
|
||||
|
||||
ifneq ($(findstring GD32VF103, $(MCU)),)
|
||||
|
||||
@@ -87,6 +87,7 @@ define GENERATE_MSG_AVAILABLE_KEYMAPS
|
||||
endef
|
||||
MSG_AVAILABLE_KEYMAPS = $(eval $(call GENERATE_MSG_AVAILABLE_KEYMAPS))$(MSG_AVAILABLE_KEYMAPS_ACTUAL)
|
||||
|
||||
MSG_BOOTLOADER_NOT_FOUND_BASE = Bootloader not found. Make sure the board is in bootloader mode. See https://docs.qmk.fm/\#/newbs_flashing\n
|
||||
MSG_CHECK_FILESIZE = Checking file size of $(TARGET).$(FIRMWARE_FORMAT)
|
||||
MSG_CHECK_FILESIZE_SKIPPED = (Firmware size check does not yet support $(MCU_ORIG); skipping)
|
||||
MSG_FILE_TOO_BIG = $(ERROR_COLOR)The firmware is too large!$(NO_COLOR) $(CURRENT_SIZE)/$(MAX_SIZE) ($(OVER_SIZE) bytes over)\n
|
||||
@@ -97,6 +98,6 @@ MSG_PYTHON_MISSING = $(ERROR_COLOR)ERROR:$(NO_COLOR) Cannot run \"qmk hello\"!\n
|
||||
Please run $(BOLD)qmk setup$(NO_COLOR) to install all the dependencies QMK requires.\n\n
|
||||
MSG_FLASH_BOOTLOADER = $(WARN_COLOR)WARNING:$(NO_COLOR) This board's bootloader is not specified or is not supported by the \":flash\" target at this time.\n\n
|
||||
MSG_FLASH_ARCH = $(WARN_COLOR)WARNING:$(NO_COLOR) This board's architecture is not supported by the \":flash\" target at this time.\n\n
|
||||
MSG_BOOTLOADER_NOT_FOUND = $(ERROR_COLOR)ERROR:$(NO_COLOR) Bootloader not found. Trying again in 5s (Ctrl+C to cancel)\n
|
||||
MSG_BOOTLOADER_NOT_FOUND = $(ERROR_COLOR)ERROR:$(NO_COLOR) $(MSG_BOOTLOADER_NOT_FOUND_BASE) Trying again in 5s (Ctrl+C to cancel)\n
|
||||
BOOTLOADER_RETRY_TIME ?= 0.5
|
||||
MSG_BOOTLOADER_NOT_FOUND_QUICK_RETRY = Bootloader not found. Trying again every $(BOOTLOADER_RETRY_TIME)s (Ctrl+C to cancel)
|
||||
MSG_BOOTLOADER_NOT_FOUND_QUICK_RETRY = $(MSG_BOOTLOADER_NOT_FOUND_BASE) Trying again every $(BOOTLOADER_RETRY_TIME)s (Ctrl+C to cancel)
|
||||
|
||||
+29
-11
@@ -20,7 +20,6 @@ QUANTUM_SRC += \
|
||||
$(QUANTUM_DIR)/led.c \
|
||||
$(QUANTUM_DIR)/action.c \
|
||||
$(QUANTUM_DIR)/action_layer.c \
|
||||
$(QUANTUM_DIR)/action_macro.c \
|
||||
$(QUANTUM_DIR)/action_tapping.c \
|
||||
$(QUANTUM_DIR)/action_util.c \
|
||||
$(QUANTUM_DIR)/eeconfig.c \
|
||||
@@ -109,7 +108,7 @@ ifeq ($(strip $(MOUSEKEY_ENABLE)), yes)
|
||||
SRC += $(QUANTUM_DIR)/mousekey.c
|
||||
endif
|
||||
|
||||
VALID_POINTING_DEVICE_DRIVER_TYPES := adns5050 adns9800 analog_joystick cirque_pinnacle_i2c cirque_pinnacle_spi pmw3360 pimoroni_trackball custom
|
||||
VALID_POINTING_DEVICE_DRIVER_TYPES := adns5050 adns9800 analog_joystick cirque_pinnacle_i2c cirque_pinnacle_spi pmw3360 pmw3389 pimoroni_trackball custom
|
||||
POINTING_DEVICE_DRIVER ?= custom
|
||||
ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes)
|
||||
ifeq ($(filter $(POINTING_DEVICE_DRIVER),$(VALID_POINTING_DEVICE_DRIVER_TYPES)),)
|
||||
@@ -144,6 +143,9 @@ ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes)
|
||||
else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), pmw3360)
|
||||
OPT_DEFS += -DSTM32_SPI -DHAL_USE_SPI=TRUE
|
||||
QUANTUM_LIB_SRC += spi_master.c
|
||||
else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), pmw3389)
|
||||
OPT_DEFS += -DSTM32_SPI -DHAL_USE_SPI=TRUE
|
||||
QUANTUM_LIB_SRC += spi_master.c
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@@ -155,47 +157,61 @@ ifeq ($(filter $(EEPROM_DRIVER),$(VALID_EEPROM_DRIVER_TYPES)),)
|
||||
else
|
||||
OPT_DEFS += -DEEPROM_ENABLE
|
||||
ifeq ($(strip $(EEPROM_DRIVER)), custom)
|
||||
# Custom EEPROM implementation -- only needs to implement init/erase/read_block/write_block
|
||||
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_CUSTOM
|
||||
COMMON_VPATH += $(DRIVER_PATH)/eeprom
|
||||
SRC += eeprom_driver.c
|
||||
else ifeq ($(strip $(EEPROM_DRIVER)), i2c)
|
||||
# External I2C EEPROM implementation
|
||||
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_I2C
|
||||
COMMON_VPATH += $(DRIVER_PATH)/eeprom
|
||||
QUANTUM_LIB_SRC += i2c_master.c
|
||||
SRC += eeprom_driver.c eeprom_i2c.c
|
||||
else ifeq ($(strip $(EEPROM_DRIVER)), spi)
|
||||
# External SPI EEPROM implementation
|
||||
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_SPI
|
||||
COMMON_VPATH += $(DRIVER_PATH)/eeprom
|
||||
QUANTUM_LIB_SRC += spi_master.c
|
||||
SRC += eeprom_driver.c eeprom_spi.c
|
||||
else ifeq ($(strip $(EEPROM_DRIVER)), transient)
|
||||
# Transient EEPROM implementation -- no data storage but provides runtime area for it
|
||||
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_TRANSIENT
|
||||
COMMON_VPATH += $(DRIVER_PATH)/eeprom
|
||||
SRC += eeprom_driver.c eeprom_transient.c
|
||||
else ifeq ($(strip $(EEPROM_DRIVER)), vendor)
|
||||
# Vendor-implemented EEPROM
|
||||
OPT_DEFS += -DEEPROM_VENDOR
|
||||
ifeq ($(PLATFORM),AVR)
|
||||
# Automatically provided by avr-libc, nothing required
|
||||
else ifeq ($(PLATFORM),CHIBIOS)
|
||||
ifneq ($(filter STM32F3xx_% STM32F1xx_% %_STM32F401xC %_STM32F401xE %_STM32F405xG %_STM32F411xE %_STM32F072xB %_STM32F042x6 %_GD32VF103xB %_GD32VF103x8, $(MCU_SERIES)_$(MCU_LDSCRIPT)),)
|
||||
# Emulated EEPROM
|
||||
OPT_DEFS += -DEEPROM_DRIVER
|
||||
COMMON_VPATH += $(DRIVER_PATH)/eeprom
|
||||
SRC += eeprom_driver.c
|
||||
SRC += $(PLATFORM_COMMON_DIR)/eeprom_stm32.c
|
||||
SRC += $(PLATFORM_COMMON_DIR)/flash_stm32.c
|
||||
else ifneq ($(filter $(MCU_SERIES),STM32L0xx STM32L1xx),)
|
||||
# True EEPROM on STM32L0xx, L1xx
|
||||
OPT_DEFS += -DEEPROM_DRIVER
|
||||
COMMON_VPATH += $(DRIVER_PATH)/eeprom
|
||||
COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/eeprom
|
||||
SRC += eeprom_driver.c
|
||||
SRC += eeprom_stm32_L0_L1.c
|
||||
else ifneq ($(filter $(MCU_SERIES),KL2x K20x),)
|
||||
# Teensy EEPROM implementations
|
||||
SRC += eeprom_teensy.c
|
||||
else
|
||||
# This will effectively work the same as "transient" if not supported by the chip
|
||||
SRC += $(PLATFORM_COMMON_DIR)/eeprom_teensy.c
|
||||
# Fall back to transient, i.e. non-persistent
|
||||
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_TRANSIENT
|
||||
COMMON_VPATH += $(DRIVER_PATH)/eeprom
|
||||
SRC += eeprom_driver.c eeprom_transient.c
|
||||
endif
|
||||
else ifeq ($(PLATFORM),ARM_ATSAM)
|
||||
# arm_atsam EEPROM
|
||||
SRC += $(PLATFORM_COMMON_DIR)/eeprom.c
|
||||
else ifeq ($(PLATFORM),TEST)
|
||||
# Test harness "EEPROM"
|
||||
SRC += $(PLATFORM_COMMON_DIR)/eeprom.c
|
||||
endif
|
||||
endif
|
||||
@@ -356,7 +372,7 @@ endif
|
||||
ifeq ($(strip $(PRINTING_ENABLE)), yes)
|
||||
OPT_DEFS += -DPRINTING_ENABLE
|
||||
SRC += $(QUANTUM_DIR)/process_keycode/process_printer.c
|
||||
SRC += $(TMK_DIR)/protocol/serial_uart.c
|
||||
QUANTUM_LIB_SRC += uart.c
|
||||
endif
|
||||
|
||||
VARIABLE_TRACE ?= no
|
||||
@@ -604,6 +620,7 @@ ifeq ($(strip $(UNICODE_ENABLE)), yes)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(UNICODE_COMMON)), yes)
|
||||
OPT_DEFS += -DUNICODE_COMMON_ENABLE
|
||||
SRC += $(QUANTUM_DIR)/process_keycode/process_unicode_common.c
|
||||
endif
|
||||
|
||||
@@ -700,7 +717,7 @@ ifeq ($(strip $(USBPD_ENABLE)), yes)
|
||||
endif
|
||||
|
||||
BLUETOOTH_ENABLE ?= no
|
||||
VALID_BLUETOOTH_DRIVER_TYPES := AdafruitBLE RN42 custom
|
||||
VALID_BLUETOOTH_DRIVER_TYPES := BluefruitLE RN42 custom
|
||||
ifeq ($(strip $(BLUETOOTH_ENABLE)), yes)
|
||||
ifeq ($(filter $(strip $(BLUETOOTH_DRIVER)),$(VALID_BLUETOOTH_DRIVER_TYPES)),)
|
||||
$(error "$(BLUETOOTH_DRIVER)" is not a valid Bluetooth driver type)
|
||||
@@ -710,15 +727,16 @@ ifeq ($(strip $(BLUETOOTH_ENABLE)), yes)
|
||||
COMMON_VPATH += $(DRIVER_PATH)/bluetooth
|
||||
SRC += outputselect.c
|
||||
|
||||
ifeq ($(strip $(BLUETOOTH_DRIVER)), AdafruitBLE)
|
||||
OPT_DEFS += -DMODULE_ADAFRUIT_BLE
|
||||
ifeq ($(strip $(BLUETOOTH_DRIVER)), BluefruitLE)
|
||||
OPT_DEFS += -DBLUETOOTH_BLUEFRUIT_LE
|
||||
SRC += analog.c
|
||||
SRC += $(DRIVER_PATH)/bluetooth/adafruit_ble.cpp
|
||||
SRC += $(DRIVER_PATH)/bluetooth/bluefruit_le.cpp
|
||||
QUANTUM_LIB_SRC += spi_master.c
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(BLUETOOTH_DRIVER)), RN42)
|
||||
OPT_DEFS += -DMODULE_RN42
|
||||
SRC += $(TMK_DIR)/protocol/serial_uart.c
|
||||
OPT_DEFS += -DBLUETOOTH_RN42
|
||||
SRC += $(DRIVER_PATH)/bluetooth/rn42.c
|
||||
QUANTUM_LIB_SRC += uart.c
|
||||
endif
|
||||
endif
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
"COMBO_TERM": {"info_key": "combo.term", "value_type": "int"},
|
||||
"DEBOUNCE": {"info_key": "debounce", "value_type": "int"},
|
||||
"DEVICE_VER": {"info_key": "usb.device_ver", "value_type": "hex"},
|
||||
# TODO: Replace ^^^ with vvv
|
||||
#"DEVICE_VER": {"info_key": "usb.device_version", "value_type": "bcd_version"},
|
||||
"DESCRIPTION": {"info_key": "keyboard_folder", "to_json": false},
|
||||
"DIODE_DIRECTION": {"info_key": "diode_direction"},
|
||||
"FORCE_NKRO": {"info_key": "usb.force_nkro", "value_type": "bool"},
|
||||
|
||||
@@ -41,8 +41,14 @@
|
||||
'atom47/rev3': {
|
||||
target: 'maartenwut/atom47/rev3'
|
||||
},
|
||||
bakeneko60: {
|
||||
target: 'kkatano/bakeneko60'
|
||||
},
|
||||
bakeneko65: {
|
||||
target: 'bakeneko65/rev2'
|
||||
target: 'kkatano/bakeneko65/rev2'
|
||||
},
|
||||
bakeneko80: {
|
||||
target: 'kkatano/bakeneko80'
|
||||
},
|
||||
bear_face: {
|
||||
target: 'bear_face/v1'
|
||||
@@ -215,6 +221,9 @@
|
||||
LAYOUT: 'LAYOUT_all'
|
||||
}
|
||||
},
|
||||
idobo: {
|
||||
target: 'idobao/id75'
|
||||
},
|
||||
'jj40': {
|
||||
target: 'kprepublic/jj40'
|
||||
},
|
||||
@@ -260,6 +269,9 @@
|
||||
'lfkeyboards/smk65': {
|
||||
target: 'lfkeyboards/smk65/revb'
|
||||
},
|
||||
m3v3van: {
|
||||
target: 'matthewdias/m3n3van'
|
||||
},
|
||||
'maartenwut/atom47/rev2': {
|
||||
target: 'evyd13/atom47/rev2'
|
||||
},
|
||||
@@ -353,9 +365,15 @@
|
||||
'mechlovin/hannah65': {
|
||||
target: 'mechlovin/hannah65/rev1'
|
||||
},
|
||||
minim: {
|
||||
target: 'matthewdias/minim'
|
||||
},
|
||||
model01: {
|
||||
target: 'keyboardio/model01'
|
||||
},
|
||||
model_v: {
|
||||
target: 'matthewdias/model_v'
|
||||
},
|
||||
m0lly: {
|
||||
target: 'tkc/m0lly'
|
||||
},
|
||||
@@ -498,6 +516,9 @@
|
||||
'tokyo60': {
|
||||
target: 'tokyokeyboard/tokyo60'
|
||||
},
|
||||
'txuu': {
|
||||
target: 'matthewdias/txuu'
|
||||
},
|
||||
underscore33: {
|
||||
target: 'underscore33/rev1'
|
||||
},
|
||||
@@ -550,7 +571,7 @@
|
||||
target: 'xelus/valor/rev1'
|
||||
},
|
||||
yd60mq: {
|
||||
target: 'yd60mq/12led'
|
||||
target: 'ymdk/yd60mq/12led'
|
||||
},
|
||||
ymd75: {
|
||||
target: 'ymd75/rev1'
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
"type": "string",
|
||||
"pattern": "^0x[0-9A-F]{4}$"
|
||||
},
|
||||
"bcd_version": {
|
||||
"type": "string",
|
||||
"pattern": "^[0-9]{1,2}\\.[0-9]\\.[0-9]$"
|
||||
},
|
||||
"text_identifier": {
|
||||
"type": "string",
|
||||
"minLength": 1,
|
||||
@@ -70,13 +74,13 @@
|
||||
"signed_int": {
|
||||
"type": "number",
|
||||
"multipleOf": 1
|
||||
}
|
||||
},
|
||||
"signed_int_8": {
|
||||
"type": "number",
|
||||
"min": -127,
|
||||
"max": 127,
|
||||
"multipleOf": 1
|
||||
}
|
||||
},
|
||||
"string_array": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -97,7 +101,7 @@
|
||||
"type": "number",
|
||||
"min": 0,
|
||||
"multipleOf": 1
|
||||
}
|
||||
},
|
||||
"unsigned_int_8": {
|
||||
"type": "number",
|
||||
"min": 0,
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
},
|
||||
"processor": {
|
||||
"type": "string",
|
||||
"enum": ["cortex-m0", "cortex-m0plus", "cortex-m3", "cortex-m4", "MKL26Z64", "MK20DX128", "MK20DX256", "MK66FX1M0", "STM32F042", "STM32F072", "STM32F103", "STM32F303", "STM32F401", "STM32F405", "STM32F407", "STM32F411", "STM32F446", "STM32G431", "STM32G474", "STM32L412", "STM32L422", "STM32L433", "STM32L443", "GD32VF103", "WB32F3G71", "atmega16u2", "atmega32u2", "atmega16u4", "atmega32u4", "at90usb162", "at90usb646", "at90usb647", "at90usb1286", "at90usb1287", "atmega32a", "atmega328p", "atmega328", "attiny85", "unknown"]
|
||||
"enum": ["cortex-m0", "cortex-m0plus", "cortex-m3", "cortex-m4", "MKL26Z64", "MK20DX128", "MK20DX256", "MK66FX1M0", "STM32F042", "STM32F072", "STM32F103", "STM32F303", "STM32F401", "STM32F405", "STM32F407", "STM32F411", "STM32F446", "STM32G431", "STM32G474", "STM32L412", "STM32L422", "STM32L432", "STM32L433", "STM32L442", "STM32L443", "GD32VF103", "WB32F3G71", "atmega16u2", "atmega32u2", "atmega16u4", "atmega32u4", "at90usb162", "at90usb646", "at90usb647", "at90usb1286", "at90usb1287", "atmega32a", "atmega328p", "atmega328", "attiny85", "unknown"]
|
||||
},
|
||||
"audio": {
|
||||
"type": "object",
|
||||
@@ -45,7 +45,7 @@
|
||||
"properties": {
|
||||
"driver": {
|
||||
"type": "string",
|
||||
"enum": ["AdafruitBLE", "RN42"]
|
||||
"enum": ["BluefruitLE", "RN42"]
|
||||
},
|
||||
"lto": {"type": "boolean"},
|
||||
}
|
||||
@@ -57,7 +57,7 @@
|
||||
},
|
||||
"bootloader": {
|
||||
"type": "string",
|
||||
"enum": ["atmel-dfu", "bootloadhid", "bootloadHID", "caterina", "halfkay", "kiibohd", "lufa-dfu", "lufa-ms", "micronucleus", "qmk-dfu", "qmk-hid", "stm32-dfu", "stm32duino", "gd32v-dfu", "wb32-dfu", "unknown", "usbasploader", "USBasp", "tinyuf2"],
|
||||
"enum": ["atmel-dfu", "bootloadhid", "bootloadHID", "caterina", "halfkay", "kiibohd", "lufa-dfu", "lufa-ms", "md-boot", "micronucleus", "qmk-dfu", "qmk-hid", "stm32-dfu", "stm32duino", "gd32v-dfu", "wb32-dfu", "unknown", "usbasploader", "USBasp", "tinyuf2"],
|
||||
},
|
||||
"bootloader_instructions": {
|
||||
"type": "string",
|
||||
@@ -69,7 +69,7 @@
|
||||
"properties": {
|
||||
"debounce_type": {
|
||||
"type": "string",
|
||||
"enum": ["custom", "eager_pk", "eager_pr", "sym_defer_pk", "sym_eager_pk"]
|
||||
"enum": ["custom", "eager_pk", "eager_pr", "sym_defer_pk", "sym_defer_pr", "sym_eager_pk"]
|
||||
},
|
||||
"firmware_format": {
|
||||
"type": "string",
|
||||
@@ -320,7 +320,8 @@
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"device_ver": {"$ref": "qmk.definitions.v1#/hex_number_4d"},
|
||||
"device_ver": {"$ref": "qmk.definitions.v1#/hex_number_4d"}, # Deprecated
|
||||
"device_version": {"$ref": "qmk.definitions.v1#/bcd_version"},
|
||||
"force_nkro": {"type": "boolean"},
|
||||
"pid": {"$ref": "qmk.definitions.v1#/hex_number_4d"},
|
||||
"vid": {"$ref": "qmk.definitions.v1#/hex_number_4d"},
|
||||
|
||||
@@ -129,10 +129,6 @@
|
||||
//#define NO_ACTION_TAPPING
|
||||
//#define NO_ACTION_ONESHOT
|
||||
|
||||
/* disable these deprecated features by default */
|
||||
#define NO_ACTION_MACRO
|
||||
#define NO_ACTION_FUNCTION
|
||||
|
||||
/* Bootmagic Lite key configuration */
|
||||
//#define BOOTMAGIC_LITE_ROW 0
|
||||
//#define BOOTMAGIC_LITE_COLUMN 0
|
||||
|
||||
@@ -119,10 +119,6 @@
|
||||
//#define NO_ACTION_TAPPING
|
||||
//#define NO_ACTION_ONESHOT
|
||||
|
||||
/* disable these deprecated features by default */
|
||||
#define NO_ACTION_MACRO
|
||||
#define NO_ACTION_FUNCTION
|
||||
|
||||
/* Bootmagic Lite key configuration */
|
||||
//#define BOOTMAGIC_LITE_ROW 0
|
||||
//#define BOOTMAGIC_LITE_COLUMN 0
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
### Split Common core now supports Pointing Devices ([#15304](https://github.com/qmk/qmk_firmware/pull/15304))
|
||||
|
||||
Pointing devices can now be shared across a split keyboard with support for a single pointing device or a pointing device on each side.
|
||||
|
||||
This feature can be enabled with `#define SPLIT_POINTING_ENABLE` and one of the following options:
|
||||
|
||||
| Setting | Description |
|
||||
|---------------------------|------------------------------------|
|
||||
|`POINTING_DEVICE_LEFT` | Pointing device on the left side |
|
||||
|`POINTING_DEVICE_RIGHT` | Pointing device on the right side |
|
||||
|`POINTING_DEVICE_COMBINED` | Pointing device on both sides |
|
||||
|
||||
See the [Pointing Device](../feature_pointing_device.md) documentation for further configuration options.
|
||||
@@ -1,6 +1,6 @@
|
||||
# Compatible Microcontrollers
|
||||
|
||||
QMK runs on any USB-capable AVR or ARM microcontroller with enough flash space - generally 32kB or more, though it will *just* squeeze into 16kB with most features disabled.
|
||||
QMK runs on any USB-capable AVR or ARM microcontroller with enough flash space - generally 32kB+ for AVR, and 64kB+ for ARM. With significant disabling of features, QMK may *just* squeeze into 16kB AVR MCUs.
|
||||
|
||||
## Atmel AVR
|
||||
|
||||
@@ -8,7 +8,11 @@ The following use [LUFA](https://www.fourwalledcubicle.com/LUFA.php) as the USB
|
||||
|
||||
* [ATmega16U2](https://www.microchip.com/wwwproducts/en/ATmega16U2) / [ATmega32U2](https://www.microchip.com/wwwproducts/en/ATmega32U2)
|
||||
* [ATmega16U4](https://www.microchip.com/wwwproducts/en/ATmega16U4) / [ATmega32U4](https://www.microchip.com/wwwproducts/en/ATmega32U4)
|
||||
* SparkFun Pro Micro (and clones)
|
||||
* PJRC Teensy 2.0
|
||||
* Adafruit Feather 32U4
|
||||
* [AT90USB64](https://www.microchip.com/wwwproducts/en/AT90USB646) / [AT90USB128](https://www.microchip.com/wwwproducts/en/AT90USB1286)
|
||||
* PJRC Teensy++ 2.0
|
||||
* [AT90USB162](https://www.microchip.com/wwwproducts/en/AT90USB162)
|
||||
|
||||
Certain MCUs which do not have native USB will use [V-USB](https://www.obdev.at/products/vusb/index.html) instead:
|
||||
@@ -25,17 +29,23 @@ You can also use any ARM chip with USB that [ChibiOS](https://www.chibios.org) s
|
||||
|
||||
* [STM32F0x2](https://www.st.com/en/microcontrollers-microprocessors/stm32f0x2.html)
|
||||
* [STM32F103](https://www.st.com/en/microcontrollers-microprocessors/stm32f103.html)
|
||||
* Bluepill (with STM32duino bootloader)
|
||||
* [STM32F303](https://www.st.com/en/microcontrollers-microprocessors/stm32f303.html)
|
||||
* QMK Proton-C
|
||||
* [STM32F401](https://www.st.com/en/microcontrollers-microprocessors/stm32f401.html)
|
||||
* WeAct Blackpill
|
||||
* [STM32F405](https://www.st.com/en/microcontrollers-microprocessors/stm32f405-415.html)
|
||||
* [STM32F407](https://www.st.com/en/microcontrollers-microprocessors/stm32f407-417.html)
|
||||
* [STM32F411](https://www.st.com/en/microcontrollers-microprocessors/stm32f411.html)
|
||||
* WeAct Blackpill
|
||||
* [STM32F446](https://www.st.com/en/microcontrollers-microprocessors/stm32f446.html)
|
||||
* [STM32G431](https://www.st.com/en/microcontrollers-microprocessors/stm32g4x1.html)
|
||||
* [STM32G474](https://www.st.com/en/microcontrollers-microprocessors/stm32g4x4.html)
|
||||
* [STM32L412](https://www.st.com/en/microcontrollers-microprocessors/stm32l4x2.html)
|
||||
* [STM32L422](https://www.st.com/en/microcontrollers-microprocessors/stm32l4x2.html)
|
||||
* [STM32L432](https://www.st.com/en/microcontrollers-microprocessors/stm32l4x2.html)
|
||||
* [STM32L433](https://www.st.com/en/microcontrollers-microprocessors/stm32l4x3.html)
|
||||
* [STM32L442](https://www.st.com/en/microcontrollers-microprocessors/stm32l4x2.html)
|
||||
* [STM32L443](https://www.st.com/en/microcontrollers-microprocessors/stm32l4x3.html)
|
||||
|
||||
### WestBerryTech (WB32)
|
||||
@@ -45,13 +55,16 @@ You can also use any ARM chip with USB that [ChibiOS](https://www.chibios.org) s
|
||||
### NXP (Kinetis)
|
||||
|
||||
* [MKL26Z64](https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/kl-series-cortex-m0-plus/kinetis-kl2x-72-96-mhz-usb-ultra-low-power-microcontrollers-mcus-based-on-arm-cortex-m0-plus-core:KL2x)
|
||||
* PJRC Teensy LC
|
||||
* [MK20DX128](https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/k-series-cortex-m4/k2x-usb/kinetis-k20-50-mhz-full-speed-usb-mixed-signal-integration-microcontrollers-based-on-arm-cortex-m4-core:K20_50)
|
||||
* [MK20DX256](https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/k-series-cortex-m4/k2x-usb/kinetis-k20-72-mhz-full-speed-usb-mixed-signal-integration-microcontrollers-mcus-based-on-arm-cortex-m4-core:K20_72)
|
||||
* PJRC Teensy 3.2
|
||||
* [MK66FX1M0](https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/k-series-cortex-m4/k6x-ethernet/kinetis-k66-180-mhz-dual-high-speed-full-speed-usbs-2mb-flash-microcontrollers-mcus-based-on-arm-cortex-m4-core:K66_180)
|
||||
* PJRC Teensy 3.6
|
||||
|
||||
## Atmel ATSAM
|
||||
|
||||
There is limited support for one of Atmel's ATSAM microcontrollers, that being the [ATSAMD51J18A](https://www.microchip.com/wwwproducts/en/ATSAMD51J18A) used by the [Massdrop keyboards](https://github.com/qmk/qmk_firmware/tree/master/keyboards/massdrop).
|
||||
There is limited support for one of Atmel's ATSAM microcontrollers, that being the [ATSAMD51J18A](https://www.microchip.com/wwwproducts/en/ATSAMD51J18A) used by the [Massdrop keyboards](https://github.com/qmk/qmk_firmware/tree/master/keyboards/massdrop). However, it is not recommended to design a board with this microcontroller as the support is quite specialized to Massdrop hardware.
|
||||
|
||||
## RISC-V
|
||||
|
||||
|
||||
@@ -124,10 +124,6 @@ If you define these options you will disable the associated feature, which can s
|
||||
* disable tap dance and other tapping features
|
||||
* `#define NO_ACTION_ONESHOT`
|
||||
* disable one-shot modifiers
|
||||
* `#define NO_ACTION_MACRO`
|
||||
* disable old-style macro handling using `MACRO()`, `action_get_macro()` _(deprecated)_
|
||||
* `#define NO_ACTION_FUNCTION`
|
||||
* disable old-style function handling using `fn_actions`, `action_function()` _(deprecated)_
|
||||
|
||||
## Features That Can Be Enabled
|
||||
|
||||
@@ -383,7 +379,6 @@ This is a [make](https://www.gnu.org/software/make/manual/make.html) file that i
|
||||
* A list of [layouts](feature_layouts.md) this keyboard supports.
|
||||
* `LTO_ENABLE`
|
||||
* Enables Link Time Optimization (LTO) when compiling the keyboard. This makes the process take longer, but it can significantly reduce the compiled size (and since the firmware is small, the added time is not noticeable).
|
||||
However, this will automatically disable the legacy TMK Macros and Functions features, as these break when LTO is enabled. It does this by automatically defining `NO_ACTION_MACRO` and `NO_ACTION_FUNCTION`. (Note: This does not affect QMK [Macros](feature_macros.md) and [Layers](feature_layers.md).)
|
||||
|
||||
## AVR MCU Options
|
||||
* `MCU = atmega32u4`
|
||||
@@ -434,8 +429,8 @@ Use these to enable or disable building certain features. The more you have enab
|
||||
* MIDI controls
|
||||
* `UNICODE_ENABLE`
|
||||
* Unicode
|
||||
* `BLUETOOTH`
|
||||
* Current options are AdafruitBLE, RN42
|
||||
* `BLUETOOTH_ENABLE`
|
||||
* Current options are BluefruitLE, RN42
|
||||
* `SPLIT_KEYBOARD`
|
||||
* Enables split keyboard support (dual MCU like the let's split and bakingpy's boards) and includes all necessary files located at quantum/split_common
|
||||
* `CUSTOM_MATRIX`
|
||||
|
||||
@@ -7,7 +7,7 @@ Currently Bluetooth support is limited to AVR based chips. For Bluetooth 2.1, QM
|
||||
|Board |Bluetooth Protocol |Connection Type|rules.mk |Bluetooth Chip|
|
||||
|----------------------------------------------------------------|--------------------|---------------|--------------------------------|--------------|
|
||||
|Roving Networks RN-42 (Sparkfun Bluesmirf) |Bluetooth Classic |UART |`BLUETOOTH_DRIVER = RN42` |RN-42 |
|
||||
|[Bluefruit LE SPI Friend](https://www.adafruit.com/product/2633)|Bluetooth Low Energy|SPI |`BLUETOOTH_DRIVER = AdafruitBLE`|nRF51822 |
|
||||
|[Bluefruit LE SPI Friend](https://www.adafruit.com/product/2633)|Bluetooth Low Energy|SPI |`BLUETOOTH_DRIVER = BluefruitLE`|nRF51822 |
|
||||
|
||||
Not Supported Yet but possible:
|
||||
* [Bluefruit LE UART Friend](https://www.adafruit.com/product/2479). [Possible tmk implementation found in](https://github.com/tmk/tmk_keyboard/issues/514)
|
||||
@@ -17,9 +17,9 @@ Not Supported Yet but possible:
|
||||
|
||||
### Adafruit BLE SPI Friend
|
||||
Currently The only bluetooth chipset supported by QMK is the Adafruit Bluefruit SPI Friend. It's a Nordic nRF51822 based chip running Adafruit's custom firmware. Data is transmitted via Adafruit's SDEP over Hardware SPI. The [Feather 32u4 Bluefruit LE](https://www.adafruit.com/product/2829) is supported as it's an AVR mcu connected via SPI to the Nordic BLE chip with Adafruit firmware. If Building a custom board with the SPI friend it would be easiest to just use the pin selection that the 32u4 feather uses but you can change the pins in the config.h options with the following defines:
|
||||
* `#define ADAFRUIT_BLE_RST_PIN D4`
|
||||
* `#define ADAFRUIT_BLE_CS_PIN B4`
|
||||
* `#define ADAFRUIT_BLE_IRQ_PIN E6`
|
||||
* `#define BLUEFRUIT_LE_RST_PIN D4`
|
||||
* `#define BLUEFRUIT_LE_CS_PIN B4`
|
||||
* `#define BLUEFRUIT_LE_IRQ_PIN E6`
|
||||
|
||||
A Bluefruit UART friend can be converted to an SPI friend, however this [requires](https://github.com/qmk/qmk_firmware/issues/2274) some reflashing and soldering directly to the MDBT40 chip.
|
||||
|
||||
@@ -32,7 +32,7 @@ Add the following to your `rules.mk`:
|
||||
|
||||
```make
|
||||
BLUETOOTH_ENABLE = yes
|
||||
BLUETOOTH_DRIVER = AdafruitBLE # or RN42
|
||||
BLUETOOTH_DRIVER = BluefruitLE # or RN42
|
||||
```
|
||||
|
||||
## Bluetooth Keycodes
|
||||
|
||||
+39
-3
@@ -141,10 +141,13 @@ Processing combos has two buffers, one for the key presses, another for the comb
|
||||
## Modifier Combos
|
||||
If a combo resolves to a Modifier, the window for processing the combo can be extended independently from normal combos. By default, this is disabled but can be enabled with `#define COMBO_MUST_HOLD_MODS`, and the time window can be configured with `#define COMBO_HOLD_TERM 150` (default: `TAPPING_TERM`). With `COMBO_MUST_HOLD_MODS`, you cannot tap the combo any more which makes the combo less prone to misfires.
|
||||
|
||||
## Per Combo Timing, Holding and Tapping
|
||||
For each combo, it is possible to configure the time window it has to pressed in, if it needs to be held down, or if it needs to be tapped.
|
||||
## Strict key press order
|
||||
By defining `COMBO_MUST_PRESS_IN_ORDER` combos only activate when the keys are pressed in the same order as they are defined in the key array.
|
||||
|
||||
For example, tap-only combos are useful if any (or all) of the underlying keys is a Mod-Tap or a Layer-Tap key. When you tap the combo, you get the combo result. When you press the combo and hold it down, the combo doesn't actually activate. Instead the keys are processed separately as if the combo wasn't even there.
|
||||
## Per Combo Timing, Holding, Tapping and Key Press Order
|
||||
For each combo, it is possible to configure the time window it has to pressed in, if it needs to be held down, if it needs to be tapped, or if its keys need to be pressed in order.
|
||||
|
||||
For example, tap-only combos are useful if any (or all) of the underlying keys are mod-tap or layer-tap keys. When you tap the combo, you get the combo result. When you press the combo and hold it down, the combo doesn't activate. Instead the keys are processed separately as if the combo wasn't even there.
|
||||
|
||||
In order to use these features, the following configuration options and functions need to be defined. Coming up with useful timings and configuration is left as an exercise for the reader.
|
||||
|
||||
@@ -153,6 +156,7 @@ In order to use these features, the following configuration options and function
|
||||
| `COMBO_TERM_PER_COMBO` | uint16_t get_combo_term(uint16_t index, combo_t \*combo) | Optional per-combo timeout window. (default: `COMBO_TERM`) |
|
||||
| `COMBO_MUST_HOLD_PER_COMBO` | bool get_combo_must_hold(uint16_t index, combo_t \*combo) | Controls if a given combo should fire immediately on tap or if it needs to be held. (default: `false`) |
|
||||
| `COMBO_MUST_TAP_PER_COMBO` | bool get_combo_must_tap(uint16_t index, combo_t \*combo) | Controls if a given combo should fire only if tapped within `COMBO_HOLD_TERM`. (default: `false`) |
|
||||
| `COMBO_MUST_PRESS_IN_ORDER_PER_COMBO` | bool get_combo_must_press_in_order(uint16_t index, combo_t \*combo) | Controls if a given combo should fire only if its keys are pressed in order. (default: `true`) |
|
||||
|
||||
Examples:
|
||||
```c
|
||||
@@ -216,6 +220,38 @@ bool get_combo_must_tap(uint16_t index, combo_t *combo) {
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
bool get_combo_must_press_in_order(uint16_t combo_index, combo_t *combo) {
|
||||
switch (combo_index) {
|
||||
/* List combos here that you want to only activate if their keys
|
||||
* are pressed in the same order as they are defined in the combo's key
|
||||
* array. */
|
||||
case COMBO_NAME_HERE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Generic hook to (dis)allow a combo activation
|
||||
|
||||
By defining `COMBO_SHOULD_TRIGGER` and its companying function `bool combo_should_trigger(uint16_t combo_index, combo_t *combo, uint16_t keycode, keyrecord_t *record)` you can block or allow combos to activate on the conditions of your choice.
|
||||
For example, you could disallow some combos on the base layer and allow them on another. Or disable combos on the home row when a timer is running.
|
||||
|
||||
Examples:
|
||||
```c
|
||||
bool combo_should_trigger(uint16_t combo_index, combo_t *combo, uint16_t keycode, keyrecord_t *record) {
|
||||
/* Disable combo `SOME_COMBO` on layer `_LAYER_A` */
|
||||
switch (combo_index) {
|
||||
case SOME_COMBO:
|
||||
if (layer_state_is(_LAYER_A)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
## Variable Length Combos
|
||||
|
||||
@@ -116,6 +116,7 @@ Where name of algorithm is one of:
|
||||
For use in keyboards where refreshing ```NUM_KEYS``` 8-bit counters is computationally expensive / low scan rate, and fingers usually only hit one row at a time. This could be
|
||||
appropriate for the ErgoDox models; the matrix is rotated 90°, and hence its "rows" are really columns, and each finger only hits a single "row" at a time in normal use.
|
||||
* ```sym_eager_pk``` - debouncing per key. On any state change, response is immediate, followed by ```DEBOUNCE``` milliseconds of no further input for that key
|
||||
* ```sym_defer_pr``` - debouncing per row. On any state change, a per-row timer is set. When ```DEBOUNCE``` milliseconds of no changes have occurred on that row, the entire row is pushed. Can improve responsiveness over `sym_defer_g` while being less susceptible than per-key debouncers to noise.
|
||||
* ```sym_defer_pk``` - debouncing per key. On any state change, a per-key timer is set. When ```DEBOUNCE``` milliseconds of no changes have occurred on that key, the key status change is pushed.
|
||||
* ```asym_eager_defer_pk``` - debouncing per key. On a key-down state change, response is immediate, followed by ```DEBOUNCE``` milliseconds of no further input for that key. On a key-up state change, a per-key timer is set. When ```DEBOUNCE``` milliseconds of no changes have occurred on that key, the key-up status change is pushed.
|
||||
|
||||
|
||||
@@ -132,7 +132,10 @@ The A an B lines of the encoders should be wired directly to the MCU, and the C/
|
||||
|
||||
## Multiple Encoders
|
||||
|
||||
Multiple encoders may share pins so long as each encoder has a distinct pair of pins.
|
||||
Multiple encoders may share pins so long as each encoder has a distinct pair of pins when the following conditions are met:
|
||||
- using detent encoders
|
||||
- pads must be high at the detent stability point which is called 'default position' in QMK
|
||||
- no more than two encoders sharing a pin can be turned at the same time
|
||||
|
||||
For example you can support two encoders using only 3 pins like this
|
||||
```
|
||||
|
||||
@@ -4,17 +4,17 @@ If you're using a 60% keyboard, or any other layout with no F-row, you will have
|
||||
|
||||
## Usage
|
||||
|
||||
Replace the `KC_GRV` key in your keymap (usually to the left of the `1` key) with `KC_GESC`. Most of the time this key will output `KC_ESC` when pressed. However, when Shift or GUI are held down it will output `KC_GRV` instead.
|
||||
Replace the `KC_GRV` key in your keymap (usually to the left of the `1` key) with `QK_GESC`. Most of the time this key will output `KC_ESC` when pressed. However, when Shift or GUI are held down it will output `KC_GRV` instead.
|
||||
|
||||
## What Your OS Sees
|
||||
|
||||
If Mary presses GESC on her keyboard, the OS will see an KC_ESC character. Now if Mary holds Shift down and presses GESC it will output `~`, or a shifted backtick. Now if she holds GUI/CMD/WIN, it will output a simple <code>`</code> character.
|
||||
If Mary presses `QK_GESC` on her keyboard, the OS will see an KC_ESC character. Now if Mary holds Shift down and presses `QK_GESC` it will output `~`, or a shifted backtick. Now if she holds GUI/CMD/WIN, it will output a simple <code>`</code> character.
|
||||
|
||||
## Keycodes
|
||||
|
||||
|Key |Aliases |Description |
|
||||
|---------|-----------|------------------------------------------------------------------|
|
||||
|`KC_GESC`|`GRAVE_ESC`|Escape when pressed, <code>`</code> when Shift or GUI are held|
|
||||
|Key |Aliases |Description |
|
||||
|-----------------|---------|------------------------------------------------------------------|
|
||||
|`QK_GRAVE_ESCAPE`|`QK_GESC`|Escape when pressed, <code>`</code> when Shift or GUI are held|
|
||||
|
||||
### Caveats
|
||||
|
||||
|
||||
@@ -167,7 +167,7 @@ List of waveform sequences from the datasheet:
|
||||
```
|
||||
#define DRV_GREETING *sequence name or number*
|
||||
```
|
||||
If haptic feedback is enabled, the keyboard will vibrate to a specific sqeuence during startup. That can be selected using the following define:
|
||||
If haptic feedback is enabled, the keyboard will vibrate to a specific sequence during startup. That can be selected using the following define:
|
||||
|
||||
```
|
||||
#define DRV_MODE_DEFAULT *sequence name or number*
|
||||
@@ -191,9 +191,6 @@ With the entry of `#define NO_HAPTIC_MOD` in config.h, the following keys will n
|
||||
* `TT()` layer tap toggle keys, when held to activate a layer. However when tapped `TAPPING_TOGGLE` times to permanently toggle the layer, on the last tap haptic feedback is still triggered.
|
||||
* `MT()` mod tap keys, when held to keep a usual modifier key pressed. However when tapped, and the key is quickly released, and sends a keycode, haptic feedback is still triggered. See also [Mod-Tap](mod_tap.md).
|
||||
|
||||
### NO_HAPTIC_FN
|
||||
With the entry of `#define NO_HAPTIC_FN` in config.h, deprecated `fn_actions` type function keys will not trigger a feedback.
|
||||
|
||||
### NO_HAPTIC_ALPHA
|
||||
With the entry of `#define NO_HAPTIC_ALPHA` in config.h, none of the alpha keys (A ... Z) will trigger a feedback.
|
||||
|
||||
@@ -207,4 +204,4 @@ With the entry of `#define NO_HAPTIC_LOCKKEYS` in config.h, none of the followin
|
||||
With the entry of `#define NO_HAPTIC_NAV` in config.h, none of the following keys will trigger a feedback: Print Screen, Pause, Insert, Delete, Page Down, Page Up, Left Arrow, Up Arrow, Right Arrow, Down Arrow, End, Home.
|
||||
|
||||
### NO_HAPTIC_NUMERIC
|
||||
With the entry of `#define NO_HAPTIC_NUMERIC` in config.h, none of the following keys between 0 and 9 (KC_1 ... KC_0) will trigger a feedback.
|
||||
With the entry of `#define NO_HAPTIC_NUMERIC` in config.h, none of the following keys between 0 and 9 (KC_1 ... KC_0) will trigger a feedback.
|
||||
|
||||
@@ -19,4 +19,5 @@ First, enable Key Lock by setting `KEY_LOCK_ENABLE = yes` in your `rules.mk`. Th
|
||||
Key Lock is only able to hold standard action keys and [One Shot modifier](one_shot_keys.md) keys (for example, if you have your Shift defined as `OSM(KC_LSFT)`).
|
||||
This does not include any of the QMK special functions (except One Shot modifiers), or shifted versions of keys such as `KC_LPRN`. If it's in the [Basic Keycodes](keycodes_basic.md) list, it can be held.
|
||||
|
||||
Switching layers will not cancel the Key Lock.
|
||||
Switching layers will not cancel the Key Lock. The Key Lock can be cancelled by calling the `cancel_key_lock()` function.
|
||||
|
||||
|
||||
@@ -333,7 +333,7 @@ Where `28` is an unused index from `eeconfig.h`.
|
||||
If you want to set custom indicators, such as an LED for Caps Lock, or layer indication, you can use the `led_matrix_indicators_kb` or `led_matrix_indicators_user` function for that:
|
||||
```c
|
||||
void led_matrix_indicators_kb(void) {
|
||||
led_matrix_set_color(index, value);
|
||||
led_matrix_set_value(index, value);
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -59,13 +59,13 @@ This is the default mode. You can adjust the cursor and scrolling acceleration u
|
||||
|
||||
|Define |Default|Description |
|
||||
|----------------------------|-------|---------------------------------------------------------|
|
||||
|`MOUSEKEY_DELAY` |300 |Delay between pressing a movement key and cursor movement|
|
||||
|`MOUSEKEY_INTERVAL` |50 |Time between cursor movements in milliseconds |
|
||||
|`MOUSEKEY_MOVE_DELTA` |5 |Step size |
|
||||
|`MOUSEKEY_DELAY` |10 |Delay between pressing a movement key and cursor movement|
|
||||
|`MOUSEKEY_INTERVAL` |20 |Time between cursor movements in milliseconds |
|
||||
|`MOUSEKEY_MOVE_DELTA` |8 |Step size |
|
||||
|`MOUSEKEY_MAX_SPEED` |10 |Maximum cursor speed at which acceleration stops |
|
||||
|`MOUSEKEY_TIME_TO_MAX` |20 |Time until maximum cursor speed is reached |
|
||||
|`MOUSEKEY_WHEEL_DELAY` |300 |Delay between pressing a wheel key and wheel movement |
|
||||
|`MOUSEKEY_WHEEL_INTERVAL` |100 |Time between wheel movements |
|
||||
|`MOUSEKEY_TIME_TO_MAX` |30 |Time until maximum cursor speed is reached |
|
||||
|`MOUSEKEY_WHEEL_DELAY` |10 |Delay between pressing a wheel key and wheel movement |
|
||||
|`MOUSEKEY_WHEEL_INTERVAL` |80 |Time between wheel movements |
|
||||
|`MOUSEKEY_WHEEL_MAX_SPEED` |8 |Maximum number of scroll steps per scroll action |
|
||||
|`MOUSEKEY_WHEEL_TIME_TO_MAX`|40 |Time until maximum scroll speed is reached |
|
||||
|
||||
@@ -85,9 +85,9 @@ This is an extension of the accelerated mode. The kinetic mode uses a quadratic
|
||||
|Define |Default |Description |
|
||||
|--------------------------------------|---------|---------------------------------------------------------------|
|
||||
|`MK_KINETIC_SPEED` |undefined|Enable kinetic mode |
|
||||
|`MOUSEKEY_DELAY` |8 |Delay between pressing a movement key and cursor movement |
|
||||
|`MOUSEKEY_INTERVAL` |8 |Time between cursor movements in milliseconds |
|
||||
|`MOUSEKEY_MOVE_DELTA` |25 |Step size for accelerating from initial to base speed |
|
||||
|`MOUSEKEY_DELAY` |5 |Delay between pressing a movement key and cursor movement |
|
||||
|`MOUSEKEY_INTERVAL` |10 |Time between cursor movements in milliseconds |
|
||||
|`MOUSEKEY_MOVE_DELTA` |5 |Step size for accelerating from initial to base speed |
|
||||
|`MOUSEKEY_INITIAL_SPEED` |100 |Initial speed of the cursor in pixel per second |
|
||||
|`MOUSEKEY_BASE_SPEED` |1000 |Maximum cursor speed at which acceleration stops |
|
||||
|`MOUSEKEY_DECELERATED_SPEED` |400 |Decelerated cursor speed |
|
||||
|
||||
@@ -84,6 +84,8 @@ static void render_logo(void) {
|
||||
}
|
||||
```
|
||||
|
||||
?> The default font file is located at `drivers/oled/glcdfont.c` and its location can be overwritten with the `OLED_FONT_H` configuration option. Font file content can be edited with external tools such as [Helix Font Editor](https://helixfonteditor.netlify.app/) and [Logo Editor](https://joric.github.io/qle/).
|
||||
|
||||
## Buffer Read Example
|
||||
For some purposes, you may need to read the current state of the OLED display
|
||||
buffer. The `oled_read_raw` function can be used to safely read bytes from the
|
||||
@@ -162,7 +164,7 @@ These configuration options should be placed in `config.h`. Example:
|
||||
|`OLED_FONT_END` |`223` |The ending character index for custom fonts |
|
||||
|`OLED_FONT_WIDTH` |`6` |The font width |
|
||||
|`OLED_FONT_HEIGHT` |`8` |The font height (untested) |
|
||||
|`OLED_TIMEOUT` |`60000` |Turns off the OLED screen after 60000ms of keyboard inactivity. Helps reduce OLED Burn-in. Set to 0 to disable. |
|
||||
|`OLED_TIMEOUT` |`60000` |Turns off the OLED screen after 60000ms of screen update inactivity. Helps reduce OLED Burn-in. Set to 0 to disable. |
|
||||
|`OLED_FADE_OUT` |*Not defined* |Enables fade out animation. Use together with `OLED_TIMEOUT`. |
|
||||
|`OLED_FADE_OUT_INTERVAL` |`0` |The speed of fade out animation, from 0 to 15. Larger values are slower. |
|
||||
|`OLED_SCROLL_TIMEOUT` |`0` |Scrolls the OLED screen after 0ms of OLED inactivity. Helps reduce OLED Burn-in. Set to 0 to disable. |
|
||||
|
||||
+145
-27
@@ -40,13 +40,13 @@ POINTING_DEVICE_DRIVER = adns9800
|
||||
|
||||
The ADNS 9800 is an SPI driven optical sensor, that uses laser output for surface tracking.
|
||||
|
||||
| Setting | Description | Default |
|
||||
|------------------------|------------------------------------------------------------------------|---------------|
|
||||
|`ADNS9800_CLOCK_SPEED` | (Optional) Sets the clock speed that the sensor runs at. | `2000000` |
|
||||
|`ADNS9800_SPI_LSBFIRST` | (Optional) Sets the Least/Most Significant Byte First setting for SPI. | `false` |
|
||||
|`ADNS9800_SPI_MODE` | (Optional) Sets the SPI Mode for the sensor. | `3` |
|
||||
|`ADNS9800_SPI_DIVISOR` | (Optional) Sets the SPI Divisor used for SPI communication. | _varies_ |
|
||||
|`ADNS9800_CS_PIN` | (Required) Sets the Cable Select pin connected to the sensor. | _not defined_ |
|
||||
| Setting | Description | Default |
|
||||
|--------------------------------|------------------------------------------------------------------------|---------------|
|
||||
|`ADNS9800_CLOCK_SPEED` | (Optional) Sets the clock speed that the sensor runs at. | `2000000` |
|
||||
|`ADNS9800_SPI_LSBFIRST` | (Optional) Sets the Least/Most Significant Byte First setting for SPI. | `false` |
|
||||
|`ADNS9800_SPI_MODE` | (Optional) Sets the SPI Mode for the sensor. | `3` |
|
||||
|`ADNS9800_SPI_DIVISOR` | (Optional) Sets the SPI Divisor used for SPI communication. | _varies_ |
|
||||
|`ADNS9800_CS_PIN` | (Required) Sets the Cable Select pin connected to the sensor. | _not defined_ |
|
||||
|
||||
|
||||
The CPI range is 800-8200, in increments of 200. Defaults to 1800 CPI.
|
||||
@@ -69,7 +69,7 @@ The Analog Joystick is an analog (ADC) driven sensor. There are a variety of jo
|
||||
|`ANALOG_JOYSTICK_AXIS_MAX` | (Optional) Sets the upper range to be considered movement. | `1023` |
|
||||
|`ANALOG_JOYSTICK_SPEED_REGULATOR` | (Optional) The divisor used to slow down movement. (lower makes it faster) | `20` |
|
||||
|`ANALOG_JOYSTICK_READ_INTERVAL` | (Optional) The interval in milliseconds between reads. | `10` |
|
||||
|`ANALOG_JOYSTICK_SPEED_MAX` | (Optional) The maxiumum value used for motion. | `2` |
|
||||
|`ANALOG_JOYSTICK_SPEED_MAX` | (Optional) The maximum value used for motion. | `2` |
|
||||
|`ANALOG_JOYSTICK_CLICK_PIN` | (Optional) The pin wired up to the press switch of the analog stick. | _not defined_ |
|
||||
|
||||
|
||||
@@ -127,11 +127,10 @@ The Pimoroni Trackball module is a I2C based breakout board with an RGB enable t
|
||||
| Setting | Description | Default |
|
||||
|-------------------------------------|------------------------------------------------------------------------------------|---------|
|
||||
|`PIMORONI_TRACKBALL_ADDRESS` | (Required) Sets the I2C Address for the Pimoroni Trackball. | `0x0A` |
|
||||
|`PIMORONI_TRACKBALL_TIMEOUT` | (Optional) The timeout for i2c communication with the trackpad in milliseconds. | `100` |
|
||||
|`PIMORONI_TRACKBALL_INTERVAL_MS` | (Optional) The update/read interval for the sensor in milliseconds. | `8` |
|
||||
|`PIMORONI_TRACKBALL_TIMEOUT` | (Optional) The timeout for i2c communication with the trackball in milliseconds. | `100` |
|
||||
|`PIMORONI_TRACKBALL_SCALE` | (Optional) The multiplier used to generate reports from the sensor. | `5` |
|
||||
|`PIMORONI_TRACKBALL_DEBOUNCE_CYCLES` | (Optional) The number of scan cycles used for debouncing on the ball press. | `20` |
|
||||
|`PIMORONI_TRACKBALL_ERROR_COUNT` | (Optional) Specifies the number of read/write errors until the sensor is disabled. | `10` |
|
||||
|`PIMORONI_TRACKBALL_ERROR_COUNT` | (Optional) Specifies the number of read/write errors until the sensor is disabled. | `10` |
|
||||
|
||||
### PMW 3360 Sensor
|
||||
|
||||
@@ -145,16 +144,40 @@ The PMW 3360 is an SPI driven optical sensor, that uses a built in IR LED for su
|
||||
|
||||
| Setting | Description | Default |
|
||||
|-----------------------------|--------------------------------------------------------------------------------------------|---------------|
|
||||
|`PMW3360_CS_PIN` | (Required) Sets the Cable Select pin connected to the sensor. | _not defined_ |
|
||||
|`PMW3360_CLOCK_SPEED` | (Optional) Sets the clock speed that the sensor runs at. | `2000000` |
|
||||
|`PMW3360_SPI_LSBFIRST` | (Optional) Sets the Least/Most Significant Byte First setting for SPI. | `false` |
|
||||
|`PMW3360_SPI_MODE` | (Optional) Sets the SPI Mode for the sensor. | `3` |
|
||||
|`PMW3360_SPI_DIVISOR` | (Optional) Sets the SPI Divisor used for SPI communication. | _varies_ |
|
||||
|`PMW3360_LIFTOFF_DISTANCE` | (Optional) Sets the lift off distance at run time | `0x02` |
|
||||
|`ROTATIONAL_TRANSFORM_ANGLE` | (Optional) Allows for the sensor data to be rotated +/- 30 degrees directly in the sensor. | `0` |
|
||||
|`PMW3360_CS_PIN` | (Required) Sets the Cable Select pin connected to the sensor. | _not defined_ |
|
||||
|`PMW3360_CLOCK_SPEED` | (Optional) Sets the clock speed that the sensor runs at. | `2000000` |
|
||||
|`PMW3360_SPI_LSBFIRST` | (Optional) Sets the Least/Most Significant Byte First setting for SPI. | `false` |
|
||||
|`PMW3360_SPI_MODE` | (Optional) Sets the SPI Mode for the sensor. | `3` |
|
||||
|`PMW3360_SPI_DIVISOR` | (Optional) Sets the SPI Divisor used for SPI communication. | _varies_ |
|
||||
|`PMW3360_LIFTOFF_DISTANCE` | (Optional) Sets the lift off distance at run time | `0x02` |
|
||||
|`ROTATIONAL_TRANSFORM_ANGLE` | (Optional) Allows for the sensor data to be rotated +/- 127 degrees directly in the sensor.| `0` |
|
||||
|`PMW3360_FIRMWARE_UPLOAD_FAST` | (Optional) Skips the 15us wait between firmware blocks. | _not defined_ |
|
||||
|
||||
The CPI range is 100-12000, in increments of 100. Defaults to 1600 CPI.
|
||||
|
||||
### PMW 3389 Sensor
|
||||
|
||||
To use the PMW 3389 sensor, add this to your `rules.mk`
|
||||
|
||||
```make
|
||||
POINTING_DEVICE_DRIVER = pmw3389
|
||||
```
|
||||
|
||||
The PMW 3389 is an SPI driven optical sensor, that uses a built in IR LED for surface tracking.
|
||||
|
||||
| Setting | Description | Default |
|
||||
|---------------------------------|--------------------------------------------------------------------------------------------|---------------|
|
||||
|`PMW3389_CS_PIN` | (Required) Sets the Cable Select pin connected to the sensor. | _not defined_ |
|
||||
|`PMW3389_CLOCK_SPEED` | (Optional) Sets the clock speed that the sensor runs at. | `2000000` |
|
||||
|`PMW3389_SPI_LSBFIRST` | (Optional) Sets the Least/Most Significant Byte First setting for SPI. | `false` |
|
||||
|`PMW3389_SPI_MODE` | (Optional) Sets the SPI Mode for the sensor. | `3` |
|
||||
|`PMW3389_SPI_DIVISOR` | (Optional) Sets the SPI Divisor used for SPI communication. | _varies_ |
|
||||
|`PMW3389_LIFTOFF_DISTANCE` | (Optional) Sets the lift off distance at run time | `0x02` |
|
||||
|`ROTATIONAL_TRANSFORM_ANGLE` | (Optional) Allows for the sensor data to be rotated +/- 30 degrees directly in the sensor. | `0` |
|
||||
|`PMW3389_FIRMWARE_UPLOAD_FAST` | (Optional) Skips the 15us wait between firmware blocks. | _not defined_ |
|
||||
|
||||
The CPI range is 50-16000, in increments of 50. Defaults to 2000 CPI.
|
||||
|
||||
|
||||
### Custom Driver
|
||||
|
||||
@@ -171,14 +194,35 @@ void pointing_device_driver_set_cpi(uint16_t cpi) {}
|
||||
|
||||
## Common Configuration
|
||||
|
||||
| Setting | Description | Default |
|
||||
|-------------------------------|-----------------------------------------------------------------------|---------------|
|
||||
|`POINTING_DEVICE_ROTATION_90` | (Optional) Rotates the X and Y data by 90 degrees. | _not defined_ |
|
||||
|`POINTING_DEVICE_ROTATION_180` | (Optional) Rotates the X and Y data by 180 degrees. | _not defined_ |
|
||||
|`POINTING_DEVICE_ROTATION_270` | (Optional) Rotates the X and Y data by 270 degrees. | _not defined_ |
|
||||
|`POINTING_DEVICE_INVERT_X` | (Optional) Inverts the X axis report. | _not defined_ |
|
||||
|`POINTING_DEVICE_INVERT_Y` | (Optional) Inverts the Y axis report. | _not defined_ |
|
||||
|`POINTING_DEVICE_MOTION_PIN` | (Optional) If supported, will only read from sensor if pin is active. | _not defined_ |
|
||||
| Setting | Description | Default |
|
||||
|----------------------------------|-----------------------------------------------------------------------|-------------------|
|
||||
|`POINTING_DEVICE_ROTATION_90` | (Optional) Rotates the X and Y data by 90 degrees. | _not defined_ |
|
||||
|`POINTING_DEVICE_ROTATION_180` | (Optional) Rotates the X and Y data by 180 degrees. | _not defined_ |
|
||||
|`POINTING_DEVICE_ROTATION_270` | (Optional) Rotates the X and Y data by 270 degrees. | _not defined_ |
|
||||
|`POINTING_DEVICE_INVERT_X` | (Optional) Inverts the X axis report. | _not defined_ |
|
||||
|`POINTING_DEVICE_INVERT_Y` | (Optional) Inverts the Y axis report. | _not defined_ |
|
||||
|`POINTING_DEVICE_MOTION_PIN` | (Optional) If supported, will only read from sensor if pin is active. | _not defined_ |
|
||||
|`POINTING_DEVICE_TASK_THROTTLE_MS` | (Optional) Limits the frequency that the sensor is polled for motion. | _not defined_ |
|
||||
|
||||
!> When using `SPLIT_POINTING_ENABLE` the `POINTING_DEVICE_MOTION_PIN` functionality is not supported and `POINTING_DEVICE_TASK_THROTTLE_MS` will default to `1`. Increasing this value will increase transport performance at the cost of possible mouse responsiveness.
|
||||
|
||||
|
||||
## Split Keyboard Configuration
|
||||
|
||||
The following configuration options are only available when using `SPLIT_POINTING_ENABLE` see [data sync options](feature_split_keyboard.md?id=data-sync-options). The rotation and invert `*_RIGHT` options are only used with `POINTING_DEVICE_COMBINED`. If using `POINTING_DEVICE_LEFT` or `POINTING_DEVICE_RIGHT` use the common configuration above to configure your pointing device.
|
||||
|
||||
| Setting | Description | Default |
|
||||
|----------------------------------------|-----------------------------------------------------------------------|---------------|
|
||||
|`POINTING_DEVICE_LEFT` | Pointing device on the left side (Required - pick one only) | _not defined_ |
|
||||
|`POINTING_DEVICE_RIGHT` | Pointing device on the right side (Required - pick one only) | _not defined_ |
|
||||
|`POINTING_DEVICE_COMBINED` | Pointing device on both sides (Required - pick one only) | _not defined_ |
|
||||
|`POINTING_DEVICE_ROTATION_90_RIGHT` | (Optional) Rotates the X and Y data by 90 degrees. | _not defined_ |
|
||||
|`POINTING_DEVICE_ROTATION_180_RIGHT` | (Optional) Rotates the X and Y data by 180 degrees. | _not defined_ |
|
||||
|`POINTING_DEVICE_ROTATION_270_RIGHT` | (Optional) Rotates the X and Y data by 270 degrees. | _not defined_ |
|
||||
|`POINTING_DEVICE_INVERT_X_RIGHT` | (Optional) Inverts the X axis report. | _not defined_ |
|
||||
|`POINTING_DEVICE_INVERT_Y_RIGHT` | (Optional) Inverts the Y axis report. | _not defined_ |
|
||||
|
||||
!> If there is a `_RIGHT` configuration option or callback, the [common configuration](feature_pointing_device.md?id=common-configuration) option will work for the left. For correct left/right detection you should setup a [handedness option](feature_split_keyboard?id=setting-handedness), `EE_HANDS` is usually a good option for an existing board that doesn't do handedness by hardware.
|
||||
|
||||
|
||||
## Callbacks and Functions
|
||||
@@ -188,7 +232,7 @@ void pointing_device_driver_set_cpi(uint16_t cpi) {}
|
||||
| `pointing_device_init_kb(void)` | Callback to allow for keyboard level initialization. Useful for additional hardware sensors. |
|
||||
| `pointing_device_init_user(void)` | Callback to allow for user level initialization. Useful for additional hardware sensors. |
|
||||
| `pointing_device_task_kb(mouse_report)` | Callback that sends sensor data, so keyboard code can intercept and modify the data. Returns a mouse report. |
|
||||
| `pointing_device_task_user(mouse_report)` | Callback that sends sensor data, so user coe can intercept and modify the data. Returns a mouse report. |
|
||||
| `pointing_device_task_user(mouse_report)` | Callback that sends sensor data, so user code can intercept and modify the data. Returns a mouse report. |
|
||||
| `pointing_device_handle_buttons(buttons, pressed, button)` | Callback to handle hardware button presses. Returns a `uint8_t`. |
|
||||
| `pointing_device_get_cpi(void)` | Gets the current CPI/DPI setting from the sensor, if supported. |
|
||||
| `pointing_device_set_cpi(uint16_t)` | Sets the CPI/DPI, if supported. |
|
||||
@@ -196,6 +240,21 @@ void pointing_device_driver_set_cpi(uint16_t cpi) {}
|
||||
| `pointing_device_set_report(mouse_report)` | Sets the mouse report to the assigned `mouse_report_t` data structured passed to the function. |
|
||||
| `pointing_device_send(void)` | Sends the current mouse report to the host system. Function can be replaced. |
|
||||
| `has_mouse_report_changed(old, new)` | Compares the old and new `mouse_report_t` data and returns true only if it has changed. |
|
||||
| `pointing_device_adjust_by_defines(mouse_report)` | Applies rotations and invert configurations to a raw mouse report. |
|
||||
|
||||
|
||||
## Split Keyboard Callbacks and Functions
|
||||
|
||||
The combined functions below are only available when using `SPLIT_POINTING_ENABLE` and `POINTING_DEVICE_COMBINED`. The 2 callbacks `pointing_device_task_combined_*` replace the single sided equivalents above. See the [combined pointing devices example](feature_pointing_device.md?id=combined-pointing-devices)
|
||||
|
||||
| Function | Description |
|
||||
|-----------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------|
|
||||
| `pointing_device_set_shared_report(mouse_report)` | Sets the shared mouse report to the assigned `mouse_report_t` data structured passed to the function. |
|
||||
| `pointing_device_set_cpi_on_side(bool, uint16_t)` | Sets the CPI/DPI of one side, if supported. Passing `true` will set the left and `false` the right` |
|
||||
| `pointing_device_combine_reports(left_report, right_report)` | Returns a combined mouse_report of left_report and right_report (as a `mouse_report_t` data structure) |
|
||||
| `pointing_device_task_combined_kb(left_report, right_report)` | Callback, so keyboard code can intercept and modify the data. Returns a combined mouse report. |
|
||||
| `pointing_device_task_combined_user(left_report, right_report)` | Callback, so user code can intercept and modify. Returns a combined mouse report using `pointing_device_combine_reports` |
|
||||
| `pointing_device_adjust_by_defines_right(mouse_report)` | Applies right side rotations and invert configurations to a raw mouse report. |
|
||||
|
||||
|
||||
# Manipulating Mouse Reports
|
||||
@@ -274,3 +333,62 @@ bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||
```
|
||||
|
||||
This allows you to toggle between scrolling and cursor movement by pressing the DRAG_SCROLL key.
|
||||
|
||||
## Split Examples
|
||||
|
||||
The following examples make use the `SPLIT_POINTING_ENABLE` functionality and show how to manipulate the mouse report for a scrolling mode.
|
||||
|
||||
### Single Pointing Device
|
||||
|
||||
The following example will work with either `POINTING_DEVICE_LEFT` or `POINTING_DEVICE_RIGHT` and enables scrolling mode while on a particular layer.
|
||||
|
||||
```c
|
||||
|
||||
static bool scrolling_mode = false;
|
||||
|
||||
layer_state_t layer_state_set_user(layer_state_t state) {
|
||||
switch (get_highest_layer(state)) {
|
||||
case _RAISE: // If we're on the _RAISE layer enable scrolling mode
|
||||
scrolling_mode = true;
|
||||
pointing_device_set_cpi(2000);
|
||||
break;
|
||||
default:
|
||||
if (scrolling_mode) { // check if we were scrolling before and set disable if so
|
||||
scrolling_mode = false;
|
||||
pointing_device_set_cpi(8000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
report_mouse_t pointing_device_task_user(report_mouse_t mouse_report) {
|
||||
if (scrolling_mode) {
|
||||
mouse_report.h = mouse_report.x;
|
||||
mouse_report.v = mouse_report.y;
|
||||
mouse_report.x = 0;
|
||||
mouse_report.y = 0;
|
||||
}
|
||||
return mouse_report;
|
||||
}
|
||||
```
|
||||
|
||||
### Combined Pointing Devices
|
||||
|
||||
The following example requires `POINTING_DEVICE_COMBINED` and sets the left side pointing device to scroll only.
|
||||
|
||||
```c
|
||||
void keyboard_post_init_user(void) {
|
||||
pointing_device_set_cpi_on_side(true, 1000); //Set cpi on left side to a low value for slower scrolling.
|
||||
pointing_device_set_cpi_on_side(false, 8000); //Set cpi on right side to a reasonable value for mousing.
|
||||
}
|
||||
|
||||
report_mouse_t pointing_device_task_combined_user(report_mouse_t left_report, report_mouse_t right_report) {
|
||||
left_report.h = left_report.x;
|
||||
left_report.v = left_report.y;
|
||||
left_report.x = 0;
|
||||
left_report.y = 0;
|
||||
return pointing_device_combine_reports(left_report, right_report);
|
||||
}
|
||||
```
|
||||
=======
|
||||
|
||||
@@ -849,6 +849,8 @@ void rgb_matrix_indicators_advanced_user(uint8_t led_min, uint8_t led_max) {
|
||||
}
|
||||
```
|
||||
|
||||
!> RGB indicators on split keyboards will require state information synced to the slave half (e.g. `#define SPLIT_LAYER_STATE_ENABLE`). See [data sync options](feature_split_keyboard.md#data-sync-options) for more details.
|
||||
|
||||
#### Indicators without RGB Matrix Effect
|
||||
|
||||
If you want to just use RGB indicators without RGB matrix effect, it is not possible to disable the latter because toggling RGB off will disable everything. You can workaround it with solid effect and colors off using this init function:
|
||||
|
||||
@@ -323,6 +323,8 @@ void post_process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||
```
|
||||
would turn the layer 0 (or 1) on and off again three times when `DEBUG` is pressed.
|
||||
|
||||
!> Lighting layers on split keyboards will require layer state synced to the slave half (e.g. `#define SPLIT_LAYER_STATE_ENABLE`). See [data sync options](feature_split_keyboard.md#data-sync-options) for more details.
|
||||
|
||||
### Overriding RGB Lighting on/off status
|
||||
|
||||
Normally lighting layers are not shown when RGB Lighting is disabled (e.g. with `RGB_TOG` keycode). If you would like lighting layers to work even when the RGB Lighting is otherwise off, add `#define RGBLIGHT_LAYERS_OVERRIDE_RGB_OFF` to your `config.h`.
|
||||
@@ -345,7 +347,7 @@ If you need to change your RGB lighting in code, for example in a macro to chang
|
||||
### Low level Functions
|
||||
|Function |Description |
|
||||
|--------------------------------------------|-------------------------------------------|
|
||||
|`rgblight_set()` |Flash out led buffers to LEDs |
|
||||
|`rgblight_set()` |Flush out led buffers to LEDs |
|
||||
|`rgblight_set_clipping_range(pos, num)` |Set clipping Range. see [Clipping Range](#clipping-range) |
|
||||
|
||||
Example:
|
||||
|
||||
@@ -273,6 +273,14 @@ This enables transmitting the current OLED on/off status to the slave side of th
|
||||
|
||||
This enables transmitting the current ST7565 on/off status to the slave side of the split keyboard. The purpose of this feature is to support state (on/off state only) syncing.
|
||||
|
||||
```c
|
||||
#define SPLIT_POINTING_ENABLE
|
||||
```
|
||||
|
||||
This enables transmitting the pointing device status to the master side of the split keyboard. The purpose of this feature is to enable use pointing devices on the slave side.
|
||||
|
||||
!> There is additional required configuration for `SPLIT_POINTING_ENABLE` outlined in the [pointing device documentation](feature_pointing_device.md?id=split-keyboard-configuration).
|
||||
|
||||
### Custom data sync between sides :id=custom-data-sync
|
||||
|
||||
QMK's split transport allows for arbitrary data transactions at both the keyboard and user levels. This is modelled on a remote procedure call, with the master invoking a function on the slave side, with the ability to send data from master to slave, process it slave side, and send data back from slave to master.
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ For split keyboards using soft serial, the computed WPM score will be available
|
||||
| `WPM_ALLOW_COUNT_REGRESSION` | _Not defined_ | If defined allows the WPM to be decreased when hitting Delete or Backspace |
|
||||
| `WPM_UNFILTERED` | _Not defined_ | If undefined (the default), WPM values will be smoothed to avoid sudden changes in value |
|
||||
| `WPM_SAMPLE_SECONDS` | `5` | This defines how many seconds of typing to average, when calculating WPM |
|
||||
| `WPM_SAMPLE_PERIODS` | `50` | This defines how many sampling periods to use when calculating WPM |
|
||||
| `WPM_SAMPLE_PERIODS` | `25` | This defines how many sampling periods to use when calculating WPM |
|
||||
| `WPM_LAUNCH_CONTROL` | _Not defined_ | If defined, WPM values will be calculated using partial buffers when typing begins |
|
||||
|
||||
'WPM_UNFILTERED' is potentially useful if you're filtering data in some other way (and also because it reduces the code required for the WPM feature), or if reducing measurement latency to a minimum is important for you.
|
||||
|
||||
@@ -6,17 +6,19 @@ QMK has a GPIO control abstraction layer which is microcontroller agnostic. This
|
||||
|
||||
The following functions provide basic control of GPIOs and are found in `platforms/<platform>/gpio.h`.
|
||||
|
||||
|Function |Description | Old AVR Examples | Old ChibiOS/ARM Examples |
|
||||
|------------------------|--------------------------------------------------|-------------------------------------------------|-------------------------------------------------|
|
||||
| `setPinInput(pin)` | Set pin as input with high impedance (High-Z) | `DDRB &= ~(1<<2)` | `palSetLineMode(pin, PAL_MODE_INPUT)` |
|
||||
| `setPinInputHigh(pin)` | Set pin as input with builtin pull-up resistor | `DDRB &= ~(1<<2); PORTB \|= (1<<2)` | `palSetLineMode(pin, PAL_MODE_INPUT_PULLUP)` |
|
||||
| `setPinInputLow(pin)` | Set pin as input with builtin pull-down resistor | N/A (Not supported on AVR) | `palSetLineMode(pin, PAL_MODE_INPUT_PULLDOWN)` |
|
||||
| `setPinOutput(pin)` | Set pin as output | `DDRB \|= (1<<2)` | `palSetLineMode(pin, PAL_MODE_OUTPUT_PUSHPULL)` |
|
||||
| `writePinHigh(pin)` | Set pin level as high, assuming it is an output | `PORTB \|= (1<<2)` | `palSetLine(pin)` |
|
||||
| `writePinLow(pin)` | Set pin level as low, assuming it is an output | `PORTB &= ~(1<<2)` | `palClearLine(pin)` |
|
||||
| `writePin(pin, level)` | Set pin level, assuming it is an output | `(level) ? PORTB \|= (1<<2) : PORTB &= ~(1<<2)` | `(level) ? palSetLine(pin) : palClearLine(pin)` |
|
||||
| `readPin(pin)` | Returns the level of the pin | `_SFR_IO8(pin >> 4) & _BV(pin & 0xF)` | `palReadLine(pin)` |
|
||||
| `togglePin(pin)` | Invert pin level, assuming it is an output | `PORTB ^= (1<<2)` | `palToggleLine(pin)` |
|
||||
| Function | Description | Old AVR Examples | Old ChibiOS/ARM Examples |
|
||||
|------------------------------|-----------------------------------------------------|-------------------------------------------------|--------------------------------------------------|
|
||||
| `setPinInput(pin)` | Set pin as input with high impedance (High-Z) | `DDRB &= ~(1<<2)` | `palSetLineMode(pin, PAL_MODE_INPUT)` |
|
||||
| `setPinInputHigh(pin)` | Set pin as input with builtin pull-up resistor | `DDRB &= ~(1<<2); PORTB \|= (1<<2)` | `palSetLineMode(pin, PAL_MODE_INPUT_PULLUP)` |
|
||||
| `setPinInputLow(pin)` | Set pin as input with builtin pull-down resistor | N/A (Not supported on AVR) | `palSetLineMode(pin, PAL_MODE_INPUT_PULLDOWN)` |
|
||||
| `setPinOutput(pin)` | Set pin as output (alias of `setPinOutputPushPull`) | `DDRB \|= (1<<2)` | `palSetLineMode(pin, PAL_MODE_OUTPUT_PUSHPULL)` |
|
||||
| `setPinOutputPushPull(pin)` | Set pin as output, push/pull mode | `DDRB \|= (1<<2)` | `palSetLineMode(pin, PAL_MODE_OUTPUT_PUSHPULL)` |
|
||||
| `setPinOutputOpenDrain(pin)` | Set pin as output, open-drain mode | N/A (Not implemented on AVR) | `palSetLineMode(pin, PAL_MODE_OUTPUT_OPENDRAIN)` |
|
||||
| `writePinHigh(pin)` | Set pin level as high, assuming it is an output | `PORTB \|= (1<<2)` | `palSetLine(pin)` |
|
||||
| `writePinLow(pin)` | Set pin level as low, assuming it is an output | `PORTB &= ~(1<<2)` | `palClearLine(pin)` |
|
||||
| `writePin(pin, level)` | Set pin level, assuming it is an output | `(level) ? PORTB \|= (1<<2) : PORTB &= ~(1<<2)` | `(level) ? palSetLine(pin) : palClearLine(pin)` |
|
||||
| `readPin(pin)` | Returns the level of the pin | `_SFR_IO8(pin >> 4) & _BV(pin & 0xF)` | `palReadLine(pin)` |
|
||||
| `togglePin(pin)` | Invert pin level, assuming it is an output | `PORTB ^= (1<<2)` | `palToggleLine(pin)` |
|
||||
|
||||
## Advanced Settings :id=advanced-settings
|
||||
|
||||
|
||||
@@ -57,13 +57,33 @@ To use a Teensy 2.0 as an ISP flashing tool, you will first need to load a [spec
|
||||
|
||||
!> Note that the `B0` pin on the Teensy should be wired to the `RESET` pin on the keyboard's controller. ***DO NOT*** connect the `RESET` pin on the Teensy to the `RESET` on the keyboard.
|
||||
|
||||
### SparkFun PocketAVR / USBtinyISP / USBasp
|
||||
### SparkFun PocketAVR / USBtinyISP
|
||||
|
||||
[SparkFun PocketAVR](https://www.sparkfun.com/products/9825)
|
||||
[Adafruit USBtinyISP](https://www.adafruit.com/product/46)
|
||||
|
||||
!> SparkFun PocketAVR and USBtinyISP **DO NOT support** AVR chips with more than 64 KiB of flash (e.g., the AT90USB128 series). This limitation is mentioned on the [shop page for SparkFun PocketAVR](https://www.sparkfun.com/products/9825) and in the [FAQ for USBtinyISP](https://learn.adafruit.com/usbtinyisp/f-a-q#faq-2270879). If you try to use one of these programmers with AT90USB128 chips, you will get verification errors from `avrdude`, and the bootloader won't be flashed properly (e.g., see the [issue #3286](https://github.com/qmk/qmk_firmware/issues/3286)).
|
||||
|
||||
**AVRDUDE Programmer**: `usbtiny`
|
||||
**AVRDUDE Port**: `usb`
|
||||
|
||||
#### Wiring
|
||||
|
||||
|ISP |Keyboard|
|
||||
|---------|--------|
|
||||
|`VCC` |`VCC` |
|
||||
|`GND` |`GND` |
|
||||
|`RST` |`RESET` |
|
||||
|`SCLK` |`SCLK` |
|
||||
|`MOSI` |`MOSI` |
|
||||
|`MISO` |`MISO` |
|
||||
|
||||
|
||||
### USBasp
|
||||
|
||||
[Thomas Fischl's USBasp](https://www.fischl.de/usbasp/)
|
||||
|
||||
**AVRDUDE Programmer**: `usbtiny` / `usbasp`
|
||||
**AVRDUDE Programmer**: `usbasp`
|
||||
**AVRDUDE Port**: `usb`
|
||||
|
||||
#### Wiring
|
||||
|
||||
+9
-8
@@ -219,11 +219,11 @@ See also: [Basic Keycodes](keycodes_basic.md)
|
||||
|
||||
See also: [Quantum Keycodes](quantum_keycodes.md#qmk-keycodes)
|
||||
|
||||
|Key |Aliases |Description |
|
||||
|--------------|---------|-------------------------------------------------------|
|
||||
|`RESET` | |Put the keyboard into bootloader mode for flashing |
|
||||
|`DEBUG` | |Toggle debug mode |
|
||||
|`EEPROM_RESET`|`EEP_RST`|Reinitializes the keyboard's EEPROM (persistent memory)|
|
||||
|Key |Aliases |Description |
|
||||
|-----------------|---------|-------------------------------------------------------|
|
||||
|`QK_BOOTLOADER` |`QK_BOOT`|Put the keyboard into bootloader mode for flashing |
|
||||
|`QK_DEBUG_TOGGLE`|`DB_TOGG`|Toggle debug mode |
|
||||
|`QK_CLEAR_EEPROM`|`EE_CLR` |Reinitializes the keyboard's EEPROM (persistent memory)|
|
||||
|
||||
## Audio Keys :id=audio-keys
|
||||
|
||||
@@ -283,9 +283,9 @@ See also: [Dynamic Macros](feature_dynamic_macros.md)
|
||||
|
||||
See also: [Grave Escape](feature_grave_esc.md)
|
||||
|
||||
|Key |Aliases |Description |
|
||||
|-----------|---------|------------------------------------------------------------------|
|
||||
|`GRAVE_ESC`|`KC_GESC`|Escape when pressed, <code>`</code> when Shift or GUI are held|
|
||||
|Key |Aliases |Description |
|
||||
|-----------------|---------|------------------------------------------------------------------|
|
||||
|`QK_GRAVE_ESCAPE`|`QK_GESC`|Escape when pressed, <code>`</code> when Shift or GUI are held|
|
||||
|
||||
## Key Lock :id=key-lock
|
||||
|
||||
@@ -326,6 +326,7 @@ See also: [Magic Keycodes](keycodes_magic.md)
|
||||
|----------------------------------|---------|--------------------------------------------------------------------------|
|
||||
|`MAGIC_SWAP_CONTROL_CAPSLOCK` |`CL_SWAP`|Swap Caps Lock and Left Control |
|
||||
|`MAGIC_UNSWAP_CONTROL_CAPSLOCK` |`CL_NORM`|Unswap Caps Lock and Left Control |
|
||||
|`MAGIC_TOGGLE_CONTROL_CAPSLOCK` |`CL_TOGG`|Toggle Caps Lock and Left Control swap |
|
||||
|`MAGIC_CAPSLOCK_TO_CONTROL` |`CL_CTRL`|Treat Caps Lock as Control |
|
||||
|`MAGIC_UNCAPSLOCK_TO_CONTROL` |`CL_CAPS`|Stop treating Caps Lock as Control |
|
||||
|`MAGIC_SWAP_LCTL_LGUI` |`LCG_SWP`|Swap Left Control and GUI |
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|----------------------------------|---------|--------------------------------------------------------------------------|
|
||||
|`MAGIC_SWAP_CONTROL_CAPSLOCK` |`CL_SWAP`|Swap Caps Lock and Left Control |
|
||||
|`MAGIC_UNSWAP_CONTROL_CAPSLOCK` |`CL_NORM`|Unswap Caps Lock and Left Control |
|
||||
|`MAGIC_TOGGLE_CONTROL_CAPSLOCK` |`CL_TOGG`|Toggle Caps Lock and Left Control swap |
|
||||
|`MAGIC_CAPSLOCK_TO_CONTROL` |`CL_CTRL`|Treat Caps Lock as Control |
|
||||
|`MAGIC_UNCAPSLOCK_TO_CONTROL` |`CL_CAPS`|Stop treating Caps Lock as Control |
|
||||
|`MAGIC_SWAP_LCTL_LGUI` |`LCG_SWP`|Swap Left Control and GUI |
|
||||
|
||||
+1
-1
@@ -136,7 +136,7 @@ After this you'll find a list of LAYOUT() macros. A LAYOUT() is simply a list of
|
||||
|
||||
`keymaps[][MATRIX_ROWS][MATRIX_COLS]` in QMK holds the 16 bit action code (sometimes referred as the quantum keycode) in it. For the keycode representing typical keys, its high byte is 0 and its low byte is the USB HID usage ID for keyboard.
|
||||
|
||||
> TMK from which QMK was forked uses `const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS]` instead and holds the 8 bit keycode. Some keycode values are reserved to induce execution of certain action codes via the `fn_actions[]` array.
|
||||
> TMK from which QMK was forked uses `const uint8_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS]` instead and holds the 8 bit keycode.
|
||||
|
||||
#### Base Layer
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ Not sure which text editor to use?
|
||||
Editors specifically made for code:
|
||||
* [Sublime Text](https://www.sublimetext.com/)
|
||||
* [VS Code](https://code.visualstudio.com/)
|
||||
* [Atom](https://atom.io/)
|
||||
|
||||
### Git resources
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ As such, if you wish to override this API consider limiting use to writing to lo
|
||||
| `config.h` override | Description | Default |
|
||||
|-----------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------|
|
||||
| `#define EARLY_INIT_PERFORM_BOOTLOADER_JUMP` | Whether or not bootloader is to be executed during the early initialisation code of QMK. | `FALSE` |
|
||||
| `#define STM32_BOOTLOADER_ADDRESS` | Relevant for single-bank STM32 MCUs, signifies the memory address to jump to bootloader. Consult [AN2606](https://www.st.com/content/st_com/en/search.html#q=an2606-t=resources-page=1) for the _System Memory_ address for your MCU. This value should be of the format `0x11111111`. | `<none>` |
|
||||
| `#define STM32_BOOTLOADER_DUAL_BANK` | Relevant for dual-bank STM32 MCUs, signifies that a GPIO is to be toggled in order to enter bootloader mode. | `FALSE` |
|
||||
| `#define STM32_BOOTLOADER_DUAL_BANK_GPIO` | Relevant for dual-bank STM32 MCUs, the pin to toggle when attempting to enter bootloader mode, e.g. `B8` | `<none>` |
|
||||
| `#define STM32_BOOTLOADER_DUAL_BANK_POLARITY` | Relevant for dual-bank STM32 MCUs, the value to set the pin to in order to trigger charging of the RC circuit. e.g. `0` or `1`. | `0` |
|
||||
|
||||
@@ -110,6 +110,8 @@ Also, specific to ChibiOS:
|
||||
- a lot of the time, an equivalent Nucleo board can be used with a different flash size or slightly different model in the same family
|
||||
- example: For an STM32L082KZ, given the similarity to an STM32L073RZ, you can use `BOARD = ST_NUCLEO64_L073RZ` in rules.mk
|
||||
- QMK is migrating to not having custom board definitions if at all possible, due to the ongoing maintenance burden when upgrading ChibiOS
|
||||
- New board definitions must not be embedded in a keyboard PR
|
||||
- See _Core PRs_ below for the procedure for adding a new board to QMK
|
||||
- if a board definition is unavoidable, `board.c` must have a standard `__early_init()` (as per normal ChibiOS board defs) and an empty `boardInit()`:
|
||||
- see Arm/ChibiOS [early initialization](https://docs.qmk.fm/#/platformdev_chibios_earlyinit?id=board-init)
|
||||
- `__early_init()` should be replaced by either `early_hardware_init_pre()` or `early_hardware_init_post()` as appropriate
|
||||
@@ -118,7 +120,7 @@ Also, specific to ChibiOS:
|
||||
## Core PRs
|
||||
|
||||
- must now target `develop` branch, which will subsequently be merged back to `master` on the breaking changes timeline
|
||||
- any support for new hardware now requires a corresponding test board under `keyboards/handwired/onekey`
|
||||
- any new boards adding support for new hardware now requires a corresponding test board under `keyboards/handwired/onekey`
|
||||
- for new MCUs, a new "child" keyboard should be added that targets your newly-added MCU, so that builds can be verified
|
||||
- for new hardware support such as display panels, core-side matrix implementations, or other peripherals, an associated keymap should be provided
|
||||
- if an existing keymap exists that can leverage this functionality this may not be required (e.g. a new RGB driver chip, supported by the `rgb` keymap) -- consult with the QMK Collaborators on Discord to determine if there is sufficient overlap already
|
||||
|
||||
@@ -8,8 +8,8 @@ On this page we have documented keycodes between `0x00FF` and `0xFFFF` which are
|
||||
|
||||
## QMK Keycodes :id=qmk-keycodes
|
||||
|
||||
|Key |Aliases |Description |
|
||||
|--------------|---------|-------------------------------------------------------|
|
||||
|`RESET` | |Put the keyboard into bootloader mode for flashing |
|
||||
|`DEBUG` | |Toggle debug mode |
|
||||
|`EEPROM_RESET`|`EEP_RST`|Reinitializes the keyboard's EEPROM (persistent memory)|
|
||||
|Key |Aliases |Description |
|
||||
|-----------------|---------|-------------------------------------------------------|
|
||||
|`QK_BOOTLOADER` |`QK_BOOT`|Put the keyboard into bootloader mode for flashing |
|
||||
|`QK_DEBUG_TOGGLE`|`DB_TOGG`|Toggle debug mode |
|
||||
|`QK_CLEAR_EEPROM`|`EE_CLR` |Reinitializes the keyboard's EEPROM (persistent memory)|
|
||||
|
||||
@@ -172,7 +172,7 @@ The following animations can be enabled:
|
||||
|
||||
### USB
|
||||
|
||||
Every USB keyboard needs to have its USB parmaters defined. At a minimum you need to set vid, pid, and device version.
|
||||
Every USB keyboard needs to have its USB parameters defined. At a minimum you need to set the Vendor ID, Product ID, and device version.
|
||||
|
||||
Example:
|
||||
|
||||
@@ -181,7 +181,9 @@ Example:
|
||||
"usb": {
|
||||
"vid": "0xC1ED",
|
||||
"pid": "0x23B0",
|
||||
"device_ver": "0x0001"
|
||||
"device_version": "1.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The device version is a BCD (binary coded decimal) value, in the format `MMmr`, so the below value would look like `0x0100` in the generated code. This also means the maximum valid values for each part are `99.9.9`, despite it being a hexadecimal value under the hood.
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
# 手工搭建指南
|
||||
|
||||
<!---
|
||||
original document: 0.15.17:docs/hand_wire.md
|
||||
git diff 0.15.17 HEAD -- docs/hand_wire.md | cat
|
||||
-->
|
||||
|
||||
## 模块清单
|
||||
|
||||
你需要的模块有:(*x*为你设计的键盘的键数)
|
||||
|
||||
* QMK所兼容的主控板(Teensy, Pro-Micro, QMK Proton C 等)
|
||||
* *x* 个键轴 (MX, Matias, Gateron 等)
|
||||
* *x* 个通孔二极管(译注:即普通的直插二极管)
|
||||
* 定位板及卫星轴
|
||||
* 电线
|
||||
* 电烙铁
|
||||
* 松香/焊油
|
||||
* 通风的环境/风扇通风
|
||||
* 剪线钳
|
||||
|
||||
可选地但比较有用的:
|
||||
|
||||
* 剥线钳/一把锋利的剪刀
|
||||
* 镊子及小尖嘴钳
|
||||
* 焊台/一位助手
|
||||
|
||||
## 前期工作
|
||||
|
||||
组装PCB矩阵的方法多种多样,这份指引会描述一些基础信息并给出一些推荐方案。
|
||||
|
||||
既然我们要进行手工飞线搭建,这里就假设你已经有了定位板。如果你想构建完全定制化的配列,有 [ai03 Plate Generator](https://kbplate.ai03.me/) 以及 [Swillkb Plate & Case Builder](http://builder.swillkb.com/) 这样的工具可以助你设计出一个新的。
|
||||
|
||||
首先从安装键轴及卫星轴开始,考虑厚度及材质的影响,可能需要热熔胶来固定。
|
||||
|
||||
## 设计矩阵 :id=planning-the-matrix
|
||||
|
||||
如果你在参考已有的手工搭建指南(比如[自制键盘固件目录](https://github.com/qmk/qmk_firmware/tree/master/keyboards/handwired)下的键盘),可以跳过该步骤,确保是按照文中的矩阵方案连线即可。
|
||||
|
||||
如果你的方案是将每个开关的一个引脚与两边的开关相连(行方向),另一个引脚与上下的开关相连(列方向),并串联一个二极管到一端,最常用的方案是二极管背对着连接到行方向的引脚(列向行)。即让远离二极管黑线一端连接到开关上(电流只能从一个方向通过二极管)。
|
||||
|
||||
可以很容易地设计出正交连接的键盘(如Planck)。
|
||||
(译注:这里的“正交”意思是行列方向连接规整)
|
||||
|
||||

|
||||
[作者:RoastPotatoe "如何手工搭建Planck键盘"](https://blog.roastpotatoes.co/guide/2015/11/04/how-to-handwire-a-planck/) (英文)内的图例
|
||||
|
||||
键盘配列越大,功能越丰富,则矩阵也会更复杂。[Keyboard Firmware Builder](https://kbfirmware.com/) 可以帮助你设计矩阵配列(下图为通过 [Keyboard Layout Editor](https://www.keyboard-layout-editor.com) 导出的全尺寸ISO键盘)。
|
||||
|
||||

|
||||
|
||||
必须时刻留意矩阵的行列数总和不能超出控制器的IO引脚数,因此上图的方案可以使用 Proton C 或 Teensy++ 控制器,但常规 Teensy 或 Pro Micro 不行。
|
||||
|
||||
### 常见微控制器板 :id=common-microcontroller-boards
|
||||
|
||||
| 控制器板 | 控制器方案 | # I/O引脚数 | 引脚图 |
|
||||
| :------------ |:-------------:| ------:| ------ |
|
||||
| Pro Micro* | ATmega32u4 | 20 | [链接](https://learn.sparkfun.com/tutorials/pro-micro--fio-v3-hookup-guide/hardware-overview-pro-micro#Teensy++_2.0) |
|
||||
| Teensy 2.0 | ATmega32u4 | 25 | [链接](https://www.pjrc.com/teensy/pinout.html) |
|
||||
| [QMK Proton C](https://qmk.fm/proton-c/) | STM32F303xC | 36 | [链接 1](https://i.imgur.com/RhtrAlc.png), [2](https://deskthority.net/wiki/QMK_Proton_C) |
|
||||
| Teensy++ 2.0 | AT90USB1286 | 46 | [链接](https://www.pjrc.com/teensy/pinout.html#Teensy_2.0) |
|
||||
|
||||
*Elite C 与 Pro Micro 除将 Micro USB 替换为 USB-C 外其余无差别。
|
||||
|
||||
一些主控板专门为手工接线设计,除可直接连接少量开关外还有额外的引脚,但这些通常会更贵一些,也更难掌控。
|
||||
|
||||
<img src="https://i.imgur.com/QiA3ta6.jpg" alt="实装的 Postage mini 主控板" width="500"/>
|
||||
|
||||
| 控制器板 | 控制器方案 | # I/O引脚数 |
|
||||
| :------------ |:-------------:| ------:|
|
||||
| [Swiss helper](https://www.reddit.com/r/MechanicalKeyboards/comments/8jg5d6/hand_wiring_this_might_help/) | ATmega32u4 | 20 |
|
||||
| [Postage 主控板](https://github.com/LifeIsOnTheWire/Postage-Board/)| ATmega32u4| 25 |
|
||||
| [Postage mini 主控板](https://geekhack.org/index.php?topic=101460.0)| ATmega32u4| 25 |
|
||||
|
||||
## 矩阵布线
|
||||
|
||||
布线方案不是唯一的,要达成的效果是可以正确连接所有的焊点并不会出现预期外的短路。
|
||||
|
||||
公开的材料和技术方案:
|
||||
|
||||
(译注:链接文章及标题恕不翻译)
|
||||
|
||||
| 技术方案 | 示例 | 优点 | 缺点 | 图片
|
||||
| :-----------| :------- | :------ | :--- | :---
|
||||
| 间断开口的线缆 | [Sasha Solomon's Dactyl](https://medium.com/@sachee/building-my-first-keyboard-and-you-can-too-512c0f8a4c5f) 以及 [Cribbit's modern hand wire](https://geekhack.org/index.php?topic=87689.0) | 整洁 | 线缆开口的操作会有些困难 | 
|
||||
| 适宜长度的线缆 | [u/xicolinguada's ortho build](https://www.reddit.com/r/MechanicalKeyboards/comments/c39k4f/my_first_hand_wired_keyboard_its_not_perfect_but/) | 剥线容易 | 较难固定位置 | 
|
||||
| 漆包线 | [fknraiden's custom board](https://geekhack.org/index.php?topic=74223.0) | 可以直接焊接(烧掉绝缘层) | 外观差? | 
|
||||
| 弯折二极管引脚作为行方向连线 | [Matt3o's Brownfox](https://deskthority.net/viewtopic.php?f=7&t=6050) | 焊点更少 | 绝缘性差 | 
|
||||
| 硬线(如铜管) | [u/d_stilgar's invisible hardline](https://www.reddit.com/r/MechanicalKeyboards/comments/8aw5j2/invisible_hardline_keyboard_progress_update_april/) 以及 [u/jonasfasler's first attempt](https://www.reddit.com/r/MechanicalKeyboards/comments/de1jyv/my_first_attempt_at_handwiring_a_keyboard/) | 非常漂亮 | 难度高,没有物理绝缘 | 
|
||||
| 用绝缘胶带(如高温胶带*)隔离开的裸线 | [Matt3o's 65% on his website](https://matt3o.com/hand-wiring-a-custom-keyboard/) | 简单(不用剥线) | 丑拒 | 
|
||||
| 铜箔胶带 | [ManuForm Dactyl](https://github.com/tshort/dactyl-keyboard) | 非常简单 | 只适用于定位板/外壳与开关底部平齐的情况 | 
|
||||
|
||||
(*译注:原文是聚酰亚胺胶带,在中国通常叫高温胶带)
|
||||
|
||||
|
||||
以上方案可以结合使用,在焊接前请准备好各种长度的线缆。
|
||||
|
||||
|
||||
### 分体键盘的注意事项
|
||||
|
||||
如果你想制作的是分体键盘(如Dactyl),每一半边都需要一个控制器以及连通两方的通信用线(如TRRS或硬连接线)。更多资料参见[QMK分体键盘文档](zh-cn/feature_split_keyboard.md)。
|
||||
(译注:TRRS即一种常用的4线耳机线插口,具体信息请查阅维基百科或[这份知乎文章](https://zhuanlan.zhihu.com/p/144233538))
|
||||
|
||||
|
||||
### 焊接
|
||||
|
||||
你可以找到很多焊接指导及技巧,这里列出了最相关及最关键的部分:
|
||||
|
||||
要想焊接的牢固需要确保焊料与焊接两端的金属面充分地接触,一个好办法(也不是必须)是上锡前先(将线缆)在针脚上绕一圈或先拧在一起。
|
||||
|
||||
<img src="https://i.imgur.com/eHJjmnU.jpg" alt="杆上绕圈" width="200"/> <img src="https://i.imgur.com/8nbxmmr.jpg?1" alt="绕环的二极管引脚" width="200"/>
|
||||
|
||||
如果二极管还在包装条上且需要弯折(作为绕圈的起点处或用于连接到邻接处),一个简便的办法是找一个盒子、桌子或尺子的直边上进行弯折。由于弯折统一在二极管一侧,也有助于区分二极管的方向。
|
||||
|
||||
<img src="https://i.imgur.com/oITudbX.jpg" alt="弯折二极管引脚" width="200"/>
|
||||
|
||||
如果你的电烙铁有温控功能,将其设置在 315ºC(600ºF)。
|
||||
|
||||
热起来后,给电烙铁上锡 - 即融化一部分锡料到烙铁头上然后立刻用湿海绵或烙铁头海绵擦掉,这样烙铁头上会有一层光滑明亮的焊料,以防止氧化且有助于焊料的焊接操作。
|
||||
|
||||
接下来进行焊接,先将烙铁头在焊接面上接触一会儿进行加热,然后上焊料焊接两侧。加热焊接面的目的是为了确保焊料可以粘附且不会过早冷却下来。
|
||||
|
||||
不能让焊料/焊点加热过度,热量会通过接触面烧毁原件(融毁开关外壳等)。并且,由于焊锡中有帮助[“浸润”](https://en.m.wikipedia.org/wiki/Wetting)(即上锡)的助焊剂,加热的越久助焊剂蒸发掉的越多,最终导致焊接点虚焊,除了看起来糟糕外,还有导致电路短路的风险。
|
||||
|
||||
#### 焊接二极管
|
||||
|
||||
从左上角的那个开关开始,将二极管放到开关上(用镊子,如果有的话)并纵向放直,有黑线的一端朝向你。让二极管间并联(二极管的阴极不应连接到其它二极管的阳极),二极管的阳极应连接到开关的左引脚上,而弯曲的阴极应朝向右边放置,如图:
|
||||
|
||||

|
||||
|
||||
在放稳二极管后,拿起焊锡,将其与左轴脚同时接触到电烙铁上 - 在松香的帮助下焊锡会很容易地覆盖在二极管及轴脚上。二极管可能会有些位移,此时你可以抓住二极管另外一端弯折过的引脚,小心地放回到位置上 - 但请留意另一端是会迅速变得烫手的。如果二极管容易乱跑,可以使用尖嘴钳之类的东西在焊接时辅助保持稳固。
|
||||
|
||||
松香加热时升起的烟有害,注意保护口鼻,不要熏到眼睛或皮肤。
|
||||
|
||||
焊接到位时,可以将焊点升起的烟吹走以免熏脸,也能帮助焊点快速降温。焊点在冷却后会形成沙哑状(无光泽)的表面,但请注意此时它依旧非常烫,需要几分钟时间的冷却才可以触摸,多吹吹有助于快速冷却。
|
||||
|
||||
在第一个二极管焊接完毕后,第二个二极管需要焊接轴脚以及上一个二极管弯折的那一端,看起来像这样:
|
||||
|
||||

|
||||
|
||||
在焊接完毕一整行后,用剪线钳剪掉二极管上方(绕轴脚后多出的部分),以及这一行最后侧多出来的引脚部分。在每一行焊接完毕后都要记得这一步。
|
||||
|
||||
在你完成了所有的二极管的焊接工作后,最好是逐一测试一下以确保焊接牢固稳定 - 再往后不是不能回头修正,但会越来越困难。
|
||||
|
||||
#### 纵向上的焊接
|
||||
|
||||
这一步你有几个可选项需考虑 - 给横向电缆进行绝缘处理是个好主意(毕竟二极管没有绝缘层),但如果你足够小心,横向电缆裸露着也行 - 但仍旧不建议这么做。如果你用的是单芯线,先将外皮整个褪下来再酌情装回去可能是最好的办法,但会因尺寸及材质原因造成操作困难,你可以将线缆上需要焊接到开关轴的部分裸露出来。
|
||||
|
||||
如果你使用多股线/铜绞线,可能最简单的方案就是用不固定长度的小段电线来纵向连接开关。通过融化掉焊接点的外皮的方式来用一整根线不是不可以,但这里不推荐这样做,这种操作会产生更多的有害烟尘,也会毁掉你的电烙铁。
|
||||
|
||||
在进行焊接操作前,先预弯折好线缆(如果是单芯线),或至少心中已经规划好焊接路线顺序(特别是你要做的设计是错列的时)。实际上焊接顺序不是特别重要,因为我们是通过焊接方案来确定键映射定义的 - 只要确保一行上的所有按键都有独自的列,且从左到右依次排列。
|
||||
|
||||
如果你不做任何的绝缘处理,可以将纵向的线升高一些,焊接在轴脚尖端上 - 如果线缆本身足够稳固,不会短路到连接着二极管的横线线缆上。
|
||||
|
||||
## 连接控制器
|
||||
|
||||
在矩阵焊接完成后,可以将其焊接到微控制器板上了。
|
||||
|
||||
将微控制器放在预期的位置上,同时要考虑到安装及外壳对齐问题。须记得USB槽的位置是可以与微控制器分开的,只需使用一小段公对母线接驳下即可。
|
||||
|
||||
找到微控制器板的引脚定义/文档([链接](#common-microcontroller-boards))并将所有的I/O引脚标出来(留意像teensy这种的控制器,模拟I/O引脚可能是数字I/O引脚的两倍),将线缆连接到这些引脚上。
|
||||
|
||||
----
|
||||
|
||||
### 针对 Teensy 2.0 的特殊说明
|
||||
|
||||
Teensy 上的部分引脚有点特殊,像 D6(片上LED),及一些 UART、SPI、I2C或PWM通道,不过只是在你计划着在键盘上还有其它功能设计时才需避免使用。如果你还不是很确定以后会不会增加什么功能上去,引脚应该还是足够充足到可以剩一部分出来的。
|
||||
|
||||
那些无论在什么控制器上都不应去使用的引脚,有:GND、VCC、AREF以及RST - 其它所有引脚都是可以用且也能在固件中访问的到的。
|
||||
|
||||
----
|
||||
|
||||
|
||||
将电线切割为控制器到各行/列上某一点距离的长度。可以焊到各行的任意位置上,只需要确保是在二极管之后 - 焊接到二极管前面(轴脚侧)的话该行将无法正常使用。
|
||||
|
||||
这里用排线的话会显得非常整洁,你也可以考虑如何排布线缆以连接到各行/列的近处。
|
||||
|
||||
<img src="https://i.imgur.com/z2QlKfB.jpg" alt="排线" width="350"/>
|
||||
|
||||
在往控制器上焊接电线时,请记住各引脚连接的是哪一行/列,在后续制作固件时我们需要用到这些信息来定义矩阵。
|
||||
|
||||
在你往下继续以前,请确保控制器已装配到位 - 切掉线缆再重新焊接非常麻烦!
|
||||
|
||||
|
||||
## 一些基础的固件配置
|
||||
|
||||
至此,在你构建好固件后,键盘就应该能正常工作了。
|
||||
|
||||
通过 [Keyboard Firmware Builder](https://kbfirmware.com/) 网站可以轻松地创建一个简单的固件。通过 [Keyboard Layout Editor](https://www.keyboard-layout-editor.com) 可以自己制作配列数据,之后就可以导入进来并重新构建矩阵信息(如果你没有在先前的 [设计矩阵](#planning-the-matrix) 完成的话)。
|
||||
|
||||
继续完成剩下的步骤,在逐一配置完所有的按键后就可以编译下载固件了。其中 .hex 文件可以用来直接刷写到键盘上,而 .zip 包中的源代码可以用来添加高级功能并通过 [构建第一个固件](zh-cn/newbs_building_firmware?id=build-your-firmware) 中详述的方法进行本地构建。
|
||||
|
||||
Keyboard Firmware Builder提供的源代码是QMK的,但版本是2017年初的。如果要用现今版本的QMK来构建 .zip 中的源代码,需要在打开 .zip 后遵循以下几步:
|
||||
|
||||
1. 解压 `kb` 目录到 `qmk_firmware/keyboards/handwired/`。
|
||||
2. 进入解压的 `kb` 目录,转到 `keymaps/default/` 目录下,打开 `keymap.c`。
|
||||
3. 找到并删除 `action_get_macro` 代码段:
|
||||
```
|
||||
const macro_t *action_get_macro(keyrecord_t *record, uint8_t id, uint8_t opt) {
|
||||
...
|
||||
return MACRO_NONE;
|
||||
}
|
||||
```
|
||||
4. 保存并关闭 `keymap.c`。
|
||||
|
||||
## 刷写固件
|
||||
|
||||
安装 [QMK Toolbox](https://github.com/qmk/qmk_toolbox).
|
||||
|
||||

|
||||
|
||||
在 “Local File” 栏处定位到你新创建的 .hex 文件,在 “MicroController” 中选择你的控制器板(常见型号[这里](#common-microcontroller-boards)有)。
|
||||
|
||||
插上你的键盘后在QMK Toolbox中点击reset(重置)按钮(如果没有重置按钮,短接一下Reset和接地引脚)再点击“Flash”(刷写)按钮。
|
||||
|
||||
|
||||
## 测试固件
|
||||
|
||||
可以用 [QMK配置器的键盘测试器](https://config.qmk.fm/#/test)、[Keyboard Tester](https://www.keyboardtester.com/tester.html) 或 [Keyboard Checker](https://keyboardchecker.com/) 进行测试,也可以打开一个文本编辑器并试着输入 - 你应该能成功输入键映射方案中的所有字符。对每个按键进行测试,并记录下不能正常工作的按键。对这些不能正常工作的按键,这里有一个快速排查指引:
|
||||
|
||||
1. 将键盘翻过来,用一段金属物短接一下轴脚 - 这么做可以排除掉需要更换掉的坏轴的可能性。
|
||||
2. 检查轴脚上的焊点 - 应该是饱满且完整覆盖的。如果你稍加用力就能将其弄下来,那么就是焊接不到位。
|
||||
3. 检查二极管的焊点 - 如果二极管虚焊了,部分行可以使用,但其它的可能就不行了。
|
||||
4. 检查连接到各行的焊点 - 如果这里虚焊了,这些行就无法正常使用。
|
||||
5. 检查 Teensy 两侧的进/出线的焊点 - 两侧的线缆都必须确保已被良好地焊接。
|
||||
6. 检查 `<project_name>.h` 文件中是否有错误或不当的 `KC_NO` - 如果不确定在哪里,用已有的 k*xy* 变量替换一下。
|
||||
7. 检查固件文件确实经过编译且正确刷写到Teensy上了。除非你在终端看到了错误消息,或是刷写时出现了弹框,否则一切应该是正常的。
|
||||
8. 使用万用表实测一下,触发开关时是否成功闭合(按下时可以连通电路)。
|
||||
|
||||
如果你完成了上述所有检查,应当留意有时可能是多种因素共同造成了开关的异常,因此最后将其短路掉来排查问题并没有什么害处。
|
||||
|
||||
## 即将完成
|
||||
|
||||
在确认键盘可以正常使用后,如果你用的是独立的控制器模块(非手工构建用),须将其固定好。办法有很多,比如热熔胶、双面胶带、3D打印的盒子、电工胶带等。
|
||||
|
||||
如果你觉得成就感满满,可以试着增加一些额外的功能,比如 [轴内LED](https://geekhack.org/index.php?topic=94258.0),[轴内RGB](https://www.reddit.com/r/MechanicalKeyboards/comments/5s1l5u/photoskeyboard_science_i_made_a_handwired_rgb/),[RGB背光](https://medium.com/@DavidNZ/hand-wired-custom-keyboard-cdd14429c7b3#.7a1ovebsk) 甚至可以是 [OLED显示屏!](https://www.reddit.com/r/olkb/comments/5zy7og/adding_ssd1306_oled_display_to_your_build/)
|
||||
|
||||
固件的潜力非常大 - 阅览 [docs.qmk.fm](https://docs.qmk.fm) 可以看到全部功能的列表,也能深入了解人们是如何使用那些五花八门的键盘的。随时欢迎到 [OLKB subreddit](https://reddit.com/r/olkb) 或 [QMK Discord](https://discord.gg/Uq7gcHh) 上寻求帮助!
|
||||
|
||||
## 其它指引链接
|
||||
|
||||
- [matt3o 的分步指引 (BrownFox build)](https://deskthority.net/viewtopic.php?f=7&t=6050) 以及他的 [个人站点](https://matt3o.com/hand-wiring-a-custom-keyboard/) 和 [指导视频](https://www.youtube.com/watch?v=LVzpsjFWPP4)
|
||||
- [Cribbit:“现代化的手工搭建指南 - 强大,简洁,友好”](https://geekhack.org/index.php?topic=87689.0)
|
||||
- [Sasha Solomon:“打造我的第一把键盘”](https://medium.com/@sachee/building-my-first-keyboard-and-you-can-too-512c0f8a4c5f)
|
||||
- [RoastPotatoe: “如何手工搭建Planck键盘”](https://blog.roastpotatoes.co/guide/2015/11/04/how-to-handwire-a-planck/)
|
||||
- [Masterzen:“手工搭建键盘记录”](https://www.masterzen.fr/2018/12/16/handwired-keyboard-build-log-part-1/)
|
||||
|
||||
|
||||
# 遗留内容
|
||||
|
||||
以前本页内还有其它内容,现在我们已经将他们单独分离出去了。以下的内容是一些重定向链接,以供那些从老链接地址过来的人能找到自己要找的内容。
|
||||
|
||||
## 序: 键盘矩阵是如何工作的(以及为什么需要二极管) :id=preamble-how-a-keyboard-matrix-works-and-why-we-need-diodes
|
||||
|
||||
* [键盘矩阵是如何工作的](zh-cn/how_a_matrix_works.md)
|
||||
@@ -0,0 +1,90 @@
|
||||
# 在Eclipse中设置QMK开发环境
|
||||
|
||||
<!---
|
||||
original document: 0.15.16:docs/other_eclipse.md
|
||||
git diff 0.15.16 HEAD -- docs/other_eclipse.md | cat
|
||||
-->
|
||||
|
||||
|
||||
[Eclipse][1]是一款广泛用于Java开发的[集成开发环境](https://en.wikipedia.org/wiki/Integrated_development_environment)(IDE),但有着强大的插件体系允许自定义开发其它语言及用途。
|
||||
|
||||
相对于使用普通的文本编辑器,使用形如Eclipse这样的IDE有着诸多好处,例如:
|
||||
* 智能代码补全
|
||||
* 快速代码跳转
|
||||
* 重构工具
|
||||
* 构建自动化(无需使用命令行)
|
||||
* 图形化交互的GIT
|
||||
* 静态代码分析
|
||||
* 以及大量其它工具,如调试器,代码格式化,显示调用链等。
|
||||
|
||||
本文专注于阐述如何将Eclipse配置为AVR软件开发环境,并用于基于QMK代码的开发工作。
|
||||
|
||||
注意,在本文编写时,仅在Ubuntu 16.04环境中进行过验证。
|
||||
|
||||
# 需求
|
||||
## 构建环境
|
||||
在开始之前,你需要确保遵循了新手教程中的[新手指引](zh-cn/newbs_getting_started.md)一节。通常,此时你应该具备了[通过 `qmk complile` 命令](zh-cn/newbs_building_firmware.md#build-your-firmware)构建固件文件的能力。
|
||||
|
||||
## Java
|
||||
Eclipse为Java程序,因此需要安装Java 8或更高版本才能运行。你可以选择JRE或JDK,后者在进行Java开发时需要用到。
|
||||
|
||||
# 安装Eclipse及插件
|
||||
Eclipse有[多种可选安装方式](https://www.eclipse.org/downloads/eclipse-packages/),取决于你的使用目标。目前没有完备的AVR开发栈安装包,所以我们需要从Eclipse CDT(C/C++ 开发工具环境)开始并安装对应的插件。
|
||||
|
||||
## 下载安装Eclipse CDT
|
||||
如果系统中已安装了Eclipse CDT,可以跳过本步骤。同时,为了确保版本支持情况,我们推荐保持其更新至最新版。
|
||||
|
||||
如果你已安装了Eclipse包,通常也可以[在上面再安装CDT插件](https://eclipse.org/cdt/downloads.php)。但是可能更好的方案是重新全新安装一下,以确保环境轻量,以及防止已安装的工具对后续的工程开发工作产生干扰。
|
||||
|
||||
安装很简单:遵循[Eclipse安装5步走](https://eclipse.org/downloads/eclipse-packages/?show_instructions=TRUE),并在第三步选择 **用于C/C++开发者的Eclipse IDE(Eclipse IDE for C/C++ Developers)**。
|
||||
|
||||
此外,也可以选择直接[下载 用于C/C++开发者的Eclipse IDE](https://www.eclipse.org/downloads/eclipse-packages/)([最新版直达链接](https://www.eclipse.org/downloads/packages/eclipse-ide-cc-developers/neonr))并解压至任意目录下(会生成 `eclipse` 目录)。
|
||||
|
||||
## 首次运行
|
||||
在安装完毕后,点击<kbd>运行</kbd>按钮。(如果是手动解压的,请在安装目录下双击 `eclipse` 可执行程序
|
||||
|
||||
在提示你选择工作区目录时,选择一个可用于存储Eclipse元数据及工程的目录。**不要选择 `qmk_firmware` 目录**,这是你的项目目录。可以使用其父目录,或其它(最好是空)目录(默认目标目录如果未作他用亦可使用)。
|
||||
|
||||
启动后,点击右上角的<kbd>工作台(Workbench)</kbd>按钮切换到工作台视图(启动时的欢迎页最下方有个确认框可以在下次启动时不再展示欢迎页)。
|
||||
|
||||
## 安装必要的插件
|
||||
注意:无需在每个插件安装完成时重启Eclipse,全部安装完毕后重启一次即可。
|
||||
|
||||
### [AVR插件](https://avr-eclipse.sourceforge.net/)
|
||||
这是最重要的一个插件,可以帮助Eclipse理解AVR下的C语言代码。参照执行[更新网址使用指引](https://avr-eclipse.sourceforge.net/wiki/index.php/Plugin_Download#Update_Site),并允许那些未签名内容产生的警告。
|
||||
|
||||
### [ANSI Escape in Console(命令行下的ANSI转义符)](https://marketplace.eclipse.org/content/ansi-escape-console)
|
||||
该插件可以允许QMK makefile产生的具有颜色标记的构建输出信息能够正确显示。
|
||||
|
||||
1. 打开<kbd>帮助</kbd> > <kbd>Eclipse插件市场…</kbd>
|
||||
2. 搜索_ANSI Escape in Console_
|
||||
3. 点击插件的<samp>安装</samp>按钮
|
||||
4. 跟随安装指引并再次允许那些未签名的内容产生的警告。
|
||||
|
||||
在插件皆安装完毕后,依照提示重启Eclipse。
|
||||
|
||||
# 配置Eclipse QMK环境
|
||||
## 导入工程
|
||||
1. 点击<kbd>文件</kbd> > <kbd>新建</kbd> > <kbd>现有的Makefile工程代码</kbd>
|
||||
2. 在之后这一页中:
|
||||
* 选择仓库所克隆到的目录位置作为 _现有代码位置_;
|
||||
* (可选地)指定一个不同的工程名,如 _QMK_ 或 _Quantum_ ;
|
||||
* 选择 _AVR-GCC Toolchain_;
|
||||
* 其它选项保留不动,点击<kbd>完成</kbd>
|
||||
|
||||

|
||||
|
||||
3. 工程即完成加载及分析,其下的文件可以方便地在左侧的 _Project Explorer_ 中查看了。
|
||||
|
||||
¹ 导入工程时若自定义名称有时会遇到些问题,如果行不通,保留默认的工程名(即目录名,通常是 `qmk_firmware`)再试一次。
|
||||
|
||||
## 构建你的键盘
|
||||
|
||||
我们将默认构建目标从 `all` 调整到我们期望构建的键盘及键映射组合上,即 `kinesis/kint36:stapelberg`。此时,形如清理、构建等工程级别的操作可以很快地执行完毕,而不至于耗费大量时间且导致Eclipse卡住。
|
||||
|
||||
1. 焦点置于工程下的任一编辑器tab中
|
||||
2. 打开`工程` > `属性`窗口, 选择 `C/C++构建` 菜单项并切至 `Behavior` 标签。
|
||||
3. 将 `Make build target`选项中的全量构建 `all` 改为 `kinesis/kint41:stapelberg`。
|
||||
4. 点击 `工程` > `清理...` 以确认配置正确。
|
||||
|
||||
[1]: https://en.wikipedia.org/wiki/Eclipse_(software)
|
||||
@@ -0,0 +1,122 @@
|
||||
# 在Visual Studio Code中设置QMK开发环境
|
||||
|
||||
<!---
|
||||
original document: 0.15.12:docs/other_vscode.md
|
||||
git diff 0.15.12 HEAD -- docs/other_vscode.md | cat
|
||||
-->
|
||||
|
||||
[Visual Studio Code](https://code.visualstudio.com/) (VS Code) 是一款支援非常多种不同编程语言的开源编辑器。
|
||||
|
||||
相比于使用简陋的文本编辑器,形如VS Code这样的多功能编辑器有诸多优势,比如:
|
||||
* 智能的代码补全
|
||||
* 便捷的代码导航
|
||||
* 重构工具
|
||||
* 自动化构建支持(不再需要命令行操作)
|
||||
* 图形化的GIT界面
|
||||
* 调试器、代码格式化、显示调用层级等多种工具
|
||||
|
||||
本章节旨在阐述如何配置VS Code以在其上进行QMK固件开发。
|
||||
|
||||
这份指引提供了在Windows及Ubuntu 18.04下所有的配置方法。
|
||||
|
||||
# 配置VS Code
|
||||
一开始,你需要首先确认所有的构建工具已经安装配置完成,且QMK Firmware仓库已拷贝至本地。前往参阅[新人指引](zh-cn/newbs_getting_started.md)确保已完成初始配置。
|
||||
|
||||
## Windows
|
||||
|
||||
### 依赖项
|
||||
|
||||
* [Git for Windows](https://git-scm.com/download/win) (该链接会自动提示你保存或运行安装包)
|
||||
|
||||
1. 除 `Git LFS (Large File Support)(大文件支援)` 及 `Check daily for Git for Windows updates(每天检查更新)` 外取消所有可选项。
|
||||
2. 将默认编辑器改为 `Use Visual Studio Code as Git's default editor(将VS Code作为默认编辑器)`
|
||||
3. 选择 `Use Git from Git Bash only(仅在Git Bash中使用Git)`,这是应使用的方案。
|
||||
4. 在 `Choosing HTTPS transport backend(选择HTTPS传输服务)` 选项上,皆可。
|
||||
5. 选择 `Checkout as-is, commit Unix-style line endings(检出不作更改,提交时使用Unix风格换行符)`,QMK仓库使用的是Unix style提交。
|
||||
6. 在额外选项页,保持默认选择即可。
|
||||
|
||||
该软件是VS Code支持Git的所需项目,是有可能不去使用它,但直接用它会省很多事。
|
||||
|
||||
* [Git Credential Manager for Windows(Windows版Git凭据管理器)](https://github.com/Microsoft/Git-Credential-Manager-for-Windows/releases) (可选)
|
||||
|
||||
该软件提供了更好的git 凭据加密存储、多因素身份认证(MFA)及私有访问token生成器。
|
||||
|
||||
这个不是严格必须的,但我们依旧推荐使用。
|
||||
|
||||
|
||||
### 安装VS Code
|
||||
|
||||
1. 到[VS Code](https://code.visualstudio.com/)下载安装包
|
||||
2. 运行安装包
|
||||
|
||||
很简单的操作。然而,仍有一些配置我们需要确保是设置正确的。
|
||||
|
||||
### VS Code设置
|
||||
|
||||
首先来配置IntelliSense,虽不是严格必要的,但能让你后续使用便捷**很多**。首先,在QMK Firmware目录下创建文件 `.vscode/c_cpp_properties.json`,之后的操作可以手动完成,但我已经完成了大部分。
|
||||
|
||||
获取[这份文件](https://gist.github.com/drashna/48e2c49ce877be592a1650f91f8473e8),如果你的MSYS2没有安装在默认路径,或在用WSL/LxSS,你可能需要做一下编辑修改。
|
||||
|
||||
在保存妥当后,如果你有已打开的VS Code,你需要reload一下。
|
||||
|
||||
?> 在 `.vscode` 目录下你应该还能看到 `extensions.json` 和 `settings.json` 文件。
|
||||
|
||||
现在,我们配置MSYS2作为VSCode的集成终端。这么做有很多好处,最主要的是可以通过按住control点击错误消息直接跳转到文件,调试起来会简单得多,另外的好处是,你不用在窗口间切换。
|
||||
|
||||
1. 点击 <kbd><kbd>文件</kbd> > <kbd>首选项 ></kbd> > <kbd>设置</kbd> </kbd>
|
||||
2. 点击上方右侧的 <kbd>{}</kbd> 按钮,打开 `settings.json` 文件。
|
||||
3. 将文件改为:
|
||||
|
||||
```json
|
||||
{
|
||||
"terminal.integrated.profiles.windows": {
|
||||
"QMK_MSYS": {
|
||||
"path": "C:/QMK_MSYS/usr/bin/bash.exe",
|
||||
"env": {
|
||||
"MSYSTEM": "MINGW64",
|
||||
"CHERE_INVOKING": "1"
|
||||
},
|
||||
"args": ["--login"]
|
||||
}
|
||||
},
|
||||
|
||||
"terminal.integrated.cursorStyle": "line"
|
||||
}
|
||||
```
|
||||
|
||||
如果该文件内已经有一些配置项,将上面的内容粘贴在最外层的花括号内,并用一个逗号将新旧内容分隔开。
|
||||
|
||||
?> 如果你的MSYS2安装在不同的目录下,你需要将 `terminal.integrated.shell.windows` 更改为你系统中正确的目录。
|
||||
|
||||
4. 点击Ctrl-<code>`</code> (Grave) 或在 <kbd><kbd>视图</kbd> > <kbd>终端</kbd></kbd> 可以打开终端界面 (`workbench.action.terminal.toggleTerminal` 命令)。如果没有终端它会自动打开一个。
|
||||
|
||||
终端应启动于工程目录中(即 `qmk_firmware` 目录),之后你可以构建键盘了。
|
||||
|
||||
|
||||
## 其它系统
|
||||
|
||||
1. 到[VS Code](https://code.visualstudio.com/)下载安装包
|
||||
2. 运行安装包
|
||||
3. 搞定
|
||||
|
||||
是的,确实是搞定了。安装的时候所有所需的路径配置都会被包含进来,在检查当前工程文件并进行IntelliSense解析上表现也会更好。
|
||||
|
||||
## 插件
|
||||
|
||||
有一些你可能感兴趣的扩展可以安装:<!-- 老外自己也分不清plugin和extension啊-_-||| -->
|
||||
|
||||
* [Git Extension Pack](https://marketplace.visualstudio.com/items?itemName=donjayamanne.git-extension-pack) - 提供了一系列的Git工具可以让你在QMK Firmware中使用Git便捷一些。
|
||||
* [EditorConfig for VS Code](https://marketplace.visualstudio.com/items?itemName=EditorConfig.EditorConfig) - _[可选]_ - 可以让你的代码更符合QMK规范。
|
||||
* [Bracket Pair Colorizer 2](https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer-2) - _[可选]_ - 可以给大括号着色,可以更好地阅读嵌套代码。
|
||||
* [GitHub Markdown Preview](https://marketplace.visualstudio.com/items?itemName=bierner.github-markdown-preview) - _[可选]_ - 使得VS Code下的markdown预览更符合Github的效果。
|
||||
* [VS Live Share Extension Pack](https://marketplace.visualstudio.com/items?itemName=MS-vsliveshare.vsliveshare-pack) - _[可选]_ - 这个扩展允许他人访问你的工作区(或反之)进行协作,在你遇到问题需要他人帮助时挺有用。
|
||||
* [VIM Keymap](https://marketplace.visualstudio.com/items?itemName=GiuseppeCesarano.vim-keymap) - _[可选]_ - 为那些更喜欢VIM风格的按键操作的人所准备。这样的扩展还有挺多。
|
||||
|
||||
安装扩展后需要重启VS Code。
|
||||
|
||||
# 配置VS Code下的QMK
|
||||
1. 点击 <kbd><kbd>文件</kbd> > <kbd>打开目录</kbd></kbd>
|
||||
2. 打开你从Github克隆的QMK固件仓库所在目录。
|
||||
3. 点击 <kbd><kbd>文件</kbd> > <kbd>保存工作区为...</kbd></kbd>
|
||||
|
||||
此时你已完成了在VS Code下编写QMK固件的准备工作。
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "adafruit_ble.h"
|
||||
#include "bluefruit_le.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -16,20 +16,20 @@
|
||||
// These are the pin assignments for the 32u4 boards.
|
||||
// You may define them to something else in your config.h
|
||||
// if yours is wired up differently.
|
||||
#ifndef ADAFRUIT_BLE_RST_PIN
|
||||
# define ADAFRUIT_BLE_RST_PIN D4
|
||||
#ifndef BLUEFRUIT_LE_RST_PIN
|
||||
# define BLUEFRUIT_LE_RST_PIN D4
|
||||
#endif
|
||||
|
||||
#ifndef ADAFRUIT_BLE_CS_PIN
|
||||
# define ADAFRUIT_BLE_CS_PIN B4
|
||||
#ifndef BLUEFRUIT_LE_CS_PIN
|
||||
# define BLUEFRUIT_LE_CS_PIN B4
|
||||
#endif
|
||||
|
||||
#ifndef ADAFRUIT_BLE_IRQ_PIN
|
||||
# define ADAFRUIT_BLE_IRQ_PIN E6
|
||||
#ifndef BLUEFRUIT_LE_IRQ_PIN
|
||||
# define BLUEFRUIT_LE_IRQ_PIN E6
|
||||
#endif
|
||||
|
||||
#ifndef ADAFRUIT_BLE_SCK_DIVISOR
|
||||
# define ADAFRUIT_BLE_SCK_DIVISOR 2 // 4MHz SCK/8MHz CPU, calculated for Feather 32U4 BLE
|
||||
#ifndef BLUEFRUIT_LE_SCK_DIVISOR
|
||||
# define BLUEFRUIT_LE_SCK_DIVISOR 2 // 4MHz SCK/8MHz CPU, calculated for Feather 32U4 BLE
|
||||
#endif
|
||||
|
||||
#define SAMPLE_BATTERY
|
||||
@@ -143,7 +143,7 @@ static bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool ver
|
||||
|
||||
// Send a single SDEP packet
|
||||
static bool sdep_send_pkt(const struct sdep_msg *msg, uint16_t timeout) {
|
||||
spi_start(ADAFRUIT_BLE_CS_PIN, false, 0, ADAFRUIT_BLE_SCK_DIVISOR);
|
||||
spi_start(BLUEFRUIT_LE_CS_PIN, false, 0, BLUEFRUIT_LE_SCK_DIVISOR);
|
||||
uint16_t timerStart = timer_read();
|
||||
bool success = false;
|
||||
bool ready = false;
|
||||
@@ -157,7 +157,7 @@ static bool sdep_send_pkt(const struct sdep_msg *msg, uint16_t timeout) {
|
||||
// Release it and let it initialize
|
||||
spi_stop();
|
||||
wait_us(SdepBackOff);
|
||||
spi_start(ADAFRUIT_BLE_CS_PIN, false, 0, ADAFRUIT_BLE_SCK_DIVISOR);
|
||||
spi_start(BLUEFRUIT_LE_CS_PIN, false, 0, BLUEFRUIT_LE_SCK_DIVISOR);
|
||||
} while (timer_elapsed(timerStart) < timeout);
|
||||
|
||||
if (ready) {
|
||||
@@ -190,7 +190,7 @@ static bool sdep_recv_pkt(struct sdep_msg *msg, uint16_t timeout) {
|
||||
bool ready = false;
|
||||
|
||||
do {
|
||||
ready = readPin(ADAFRUIT_BLE_IRQ_PIN);
|
||||
ready = readPin(BLUEFRUIT_LE_IRQ_PIN);
|
||||
if (ready) {
|
||||
break;
|
||||
}
|
||||
@@ -198,7 +198,7 @@ static bool sdep_recv_pkt(struct sdep_msg *msg, uint16_t timeout) {
|
||||
} while (timer_elapsed(timerStart) < timeout);
|
||||
|
||||
if (ready) {
|
||||
spi_start(ADAFRUIT_BLE_CS_PIN, false, 0, ADAFRUIT_BLE_SCK_DIVISOR);
|
||||
spi_start(BLUEFRUIT_LE_CS_PIN, false, 0, BLUEFRUIT_LE_SCK_DIVISOR);
|
||||
|
||||
do {
|
||||
// Read the command type, waiting for the data to be ready
|
||||
@@ -207,7 +207,7 @@ static bool sdep_recv_pkt(struct sdep_msg *msg, uint16_t timeout) {
|
||||
// Release it and let it initialize
|
||||
spi_stop();
|
||||
wait_us(SdepBackOff);
|
||||
spi_start(ADAFRUIT_BLE_CS_PIN, false, 0, ADAFRUIT_BLE_SCK_DIVISOR);
|
||||
spi_start(BLUEFRUIT_LE_CS_PIN, false, 0, BLUEFRUIT_LE_SCK_DIVISOR);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ static void resp_buf_read_one(bool greedy) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (readPin(ADAFRUIT_BLE_IRQ_PIN)) {
|
||||
if (readPin(BLUEFRUIT_LE_IRQ_PIN)) {
|
||||
struct sdep_msg msg;
|
||||
|
||||
again:
|
||||
@@ -244,7 +244,7 @@ static void resp_buf_read_one(bool greedy) {
|
||||
dprintf("recv latency %dms\n", TIMER_DIFF_16(timer_read(), last_send));
|
||||
}
|
||||
|
||||
if (greedy && resp_buf.peek(last_send) && readPin(ADAFRUIT_BLE_IRQ_PIN)) {
|
||||
if (greedy && resp_buf.peek(last_send) && readPin(BLUEFRUIT_LE_IRQ_PIN)) {
|
||||
goto again;
|
||||
}
|
||||
}
|
||||
@@ -295,16 +295,16 @@ static bool ble_init(void) {
|
||||
state.configured = false;
|
||||
state.is_connected = false;
|
||||
|
||||
setPinInput(ADAFRUIT_BLE_IRQ_PIN);
|
||||
setPinInput(BLUEFRUIT_LE_IRQ_PIN);
|
||||
|
||||
spi_init();
|
||||
|
||||
// Perform a hardware reset
|
||||
setPinOutput(ADAFRUIT_BLE_RST_PIN);
|
||||
writePinHigh(ADAFRUIT_BLE_RST_PIN);
|
||||
writePinLow(ADAFRUIT_BLE_RST_PIN);
|
||||
setPinOutput(BLUEFRUIT_LE_RST_PIN);
|
||||
writePinHigh(BLUEFRUIT_LE_RST_PIN);
|
||||
writePinLow(BLUEFRUIT_LE_RST_PIN);
|
||||
wait_ms(10);
|
||||
writePinHigh(ADAFRUIT_BLE_RST_PIN);
|
||||
writePinHigh(BLUEFRUIT_LE_RST_PIN);
|
||||
|
||||
wait_ms(1000); // Give it a second to initialize
|
||||
|
||||
@@ -424,9 +424,9 @@ bool at_command_P(const char *cmd, char *resp, uint16_t resplen, bool verbose) {
|
||||
return at_command(cmdbuf, resp, resplen, verbose);
|
||||
}
|
||||
|
||||
bool adafruit_ble_is_connected(void) { return state.is_connected; }
|
||||
bool bluefruit_le_is_connected(void) { return state.is_connected; }
|
||||
|
||||
bool adafruit_ble_enable_keyboard(void) {
|
||||
bool bluefruit_le_enable_keyboard(void) {
|
||||
char resbuf[128];
|
||||
|
||||
if (!state.initialized && !ble_init()) {
|
||||
@@ -498,16 +498,16 @@ static void set_connected(bool connected) {
|
||||
}
|
||||
}
|
||||
|
||||
void adafruit_ble_task(void) {
|
||||
void bluefruit_le_task(void) {
|
||||
char resbuf[48];
|
||||
|
||||
if (!state.configured && !adafruit_ble_enable_keyboard()) {
|
||||
if (!state.configured && !bluefruit_le_enable_keyboard()) {
|
||||
return;
|
||||
}
|
||||
resp_buf_read_one(true);
|
||||
send_buf_send_one(SdepShortTimeout);
|
||||
|
||||
if (resp_buf.empty() && (state.event_flags & UsingEvents) && readPin(ADAFRUIT_BLE_IRQ_PIN)) {
|
||||
if (resp_buf.empty() && (state.event_flags & UsingEvents) && readPin(BLUEFRUIT_LE_IRQ_PIN)) {
|
||||
// Must be an event update
|
||||
if (at_command_P(PSTR("AT+EVENTSTATUS"), resbuf, sizeof(resbuf))) {
|
||||
uint32_t mask = strtoul(resbuf, NULL, 16);
|
||||
@@ -609,7 +609,7 @@ static bool process_queue_item(struct queue_item *item, uint16_t timeout) {
|
||||
}
|
||||
}
|
||||
|
||||
void adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys) {
|
||||
void bluefruit_le_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys) {
|
||||
struct queue_item item;
|
||||
bool didWait = false;
|
||||
|
||||
@@ -643,7 +643,7 @@ void adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nk
|
||||
}
|
||||
}
|
||||
|
||||
void adafruit_ble_send_consumer_key(uint16_t usage) {
|
||||
void bluefruit_le_send_consumer_key(uint16_t usage) {
|
||||
struct queue_item item;
|
||||
|
||||
item.queue_type = QTConsumer;
|
||||
@@ -655,7 +655,7 @@ void adafruit_ble_send_consumer_key(uint16_t usage) {
|
||||
}
|
||||
|
||||
#ifdef MOUSE_ENABLE
|
||||
void adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons) {
|
||||
void bluefruit_le_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons) {
|
||||
struct queue_item item;
|
||||
|
||||
item.queue_type = QTMouseMove;
|
||||
@@ -671,9 +671,9 @@ void adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan,
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t adafruit_ble_read_battery_voltage(void) { return state.vbat; }
|
||||
uint32_t bluefruit_le_read_battery_voltage(void) { return state.vbat; }
|
||||
|
||||
bool adafruit_ble_set_mode_leds(bool on) {
|
||||
bool bluefruit_le_set_mode_leds(bool on) {
|
||||
if (!state.configured) {
|
||||
return false;
|
||||
}
|
||||
@@ -689,7 +689,7 @@ bool adafruit_ble_set_mode_leds(bool on) {
|
||||
}
|
||||
|
||||
// https://learn.adafruit.com/adafruit-feather-32u4-bluefruit-le/ble-generic#at-plus-blepowerlevel
|
||||
bool adafruit_ble_set_power_level(int8_t level) {
|
||||
bool bluefruit_le_set_power_level(int8_t level) {
|
||||
char cmd[46];
|
||||
if (!state.configured) {
|
||||
return false;
|
||||
@@ -16,43 +16,43 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* Instruct the module to enable HID keyboard support and reset */
|
||||
extern bool adafruit_ble_enable_keyboard(void);
|
||||
extern bool bluefruit_le_enable_keyboard(void);
|
||||
|
||||
/* Query to see if the BLE module is connected */
|
||||
extern bool adafruit_ble_query_is_connected(void);
|
||||
extern bool bluefruit_le_query_is_connected(void);
|
||||
|
||||
/* Returns true if we believe that the BLE module is connected.
|
||||
* This uses our cached understanding that is maintained by
|
||||
* calling ble_task() periodically. */
|
||||
extern bool adafruit_ble_is_connected(void);
|
||||
extern bool bluefruit_le_is_connected(void);
|
||||
|
||||
/* Call this periodically to process BLE-originated things */
|
||||
extern void adafruit_ble_task(void);
|
||||
extern void bluefruit_le_task(void);
|
||||
|
||||
/* Generates keypress events for a set of keys.
|
||||
* The hid modifier mask specifies the state of the modifier keys for
|
||||
* this set of keys.
|
||||
* Also sends a key release indicator, so that the keys do not remain
|
||||
* held down. */
|
||||
extern void adafruit_ble_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys);
|
||||
extern void bluefruit_le_send_keys(uint8_t hid_modifier_mask, uint8_t *keys, uint8_t nkeys);
|
||||
|
||||
/* Send a consumer usage.
|
||||
* (milliseconds) */
|
||||
extern void adafruit_ble_send_consumer_key(uint16_t usage);
|
||||
extern void bluefruit_le_send_consumer_key(uint16_t usage);
|
||||
|
||||
#ifdef MOUSE_ENABLE
|
||||
/* Send a mouse/wheel movement report.
|
||||
* The parameters are signed and indicate positive or negative direction
|
||||
* change. */
|
||||
extern void adafruit_ble_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons);
|
||||
extern void bluefruit_le_send_mouse_move(int8_t x, int8_t y, int8_t scroll, int8_t pan, uint8_t buttons);
|
||||
#endif
|
||||
|
||||
/* Compute battery voltage by reading an analog pin.
|
||||
* Returns the integer number of millivolts */
|
||||
extern uint32_t adafruit_ble_read_battery_voltage(void);
|
||||
extern uint32_t bluefruit_le_read_battery_voltage(void);
|
||||
|
||||
extern bool adafruit_ble_set_mode_leds(bool on);
|
||||
extern bool adafruit_ble_set_power_level(int8_t level);
|
||||
extern bool bluefruit_le_set_mode_leds(bool on);
|
||||
extern bool bluefruit_le_set_power_level(int8_t level);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
@@ -18,8 +18,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# include "lufa.h"
|
||||
#endif
|
||||
|
||||
#ifdef MODULE_ADAFRUIT_BLE
|
||||
# include "adafruit_ble.h"
|
||||
#ifdef BLUETOOTH_BLUEFRUIT_LE
|
||||
# include "bluefruit_le.h"
|
||||
#endif
|
||||
|
||||
uint8_t desired_output = OUTPUT_DEFAULT;
|
||||
@@ -54,8 +54,8 @@ uint8_t auto_detect_output(void) {
|
||||
return OUTPUT_USB;
|
||||
}
|
||||
|
||||
#ifdef MODULE_ADAFRUIT_BLE
|
||||
if (adafruit_ble_is_connected()) {
|
||||
#ifdef BLUETOOTH_BLUEFRUIT_LE
|
||||
if (bluefruit_le_is_connected()) {
|
||||
return OUTPUT_BLUETOOTH;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/* Copyright 2021
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "report.h"
|
||||
#include "uart.h"
|
||||
|
||||
#ifndef RN42_BAUD_RATE
|
||||
# define RN42_BAUD_RATE 115200
|
||||
#endif
|
||||
|
||||
// https://cdn.sparkfun.com/datasheets/Wireless/Bluetooth/bluetooth_cr_UG-v1.0r.pdf#G7.663734
|
||||
static inline uint16_t rn42_consumer_usage_to_bitmap(uint16_t usage) {
|
||||
switch (usage) {
|
||||
case AC_HOME:
|
||||
return 0x0001;
|
||||
case AL_EMAIL:
|
||||
return 0x0002;
|
||||
case AC_SEARCH:
|
||||
return 0x0004;
|
||||
case AL_KEYBOARD_LAYOUT:
|
||||
return 0x0008;
|
||||
case AUDIO_VOL_UP:
|
||||
return 0x0010;
|
||||
case AUDIO_VOL_DOWN:
|
||||
return 0x0020;
|
||||
case AUDIO_MUTE:
|
||||
return 0x0040;
|
||||
case TRANSPORT_PLAY_PAUSE:
|
||||
return 0x0080;
|
||||
case TRANSPORT_NEXT_TRACK:
|
||||
return 0x0100;
|
||||
case TRANSPORT_PREV_TRACK:
|
||||
return 0x0200;
|
||||
case TRANSPORT_STOP:
|
||||
return 0x0400;
|
||||
case TRANSPORT_EJECT:
|
||||
return 0x0800;
|
||||
case TRANSPORT_FAST_FORWARD:
|
||||
return 0x1000;
|
||||
case TRANSPORT_REWIND:
|
||||
return 0x2000;
|
||||
case TRANSPORT_STOP_EJECT:
|
||||
return 0x4000;
|
||||
case AL_LOCAL_BROWSER:
|
||||
return 0x8000;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void rn42_init(void) { uart_init(RN42_BAUD_RATE); }
|
||||
|
||||
void rn42_send_keyboard(report_keyboard_t *report) {
|
||||
uart_write(0xFD);
|
||||
uart_write(0x09);
|
||||
uart_write(0x01);
|
||||
uart_write(report->mods);
|
||||
uart_write(0x00);
|
||||
for (uint8_t i = 0; i < KEYBOARD_REPORT_KEYS; i++) {
|
||||
uart_write(report->keys[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void rn42_send_mouse(report_mouse_t *report) {
|
||||
uart_write(0xFD);
|
||||
uart_write(0x00);
|
||||
uart_write(0x03);
|
||||
uart_write(report->buttons);
|
||||
uart_write(report->x);
|
||||
uart_write(report->y);
|
||||
uart_write(report->v); // should try sending the wheel v here
|
||||
uart_write(report->h); // should try sending the wheel h here
|
||||
uart_write(0x00);
|
||||
}
|
||||
|
||||
void rn42_send_consumer(uint16_t data) {
|
||||
static uint16_t last_data = 0;
|
||||
if (data == last_data) return;
|
||||
last_data = data;
|
||||
uint16_t bitmap = rn42_consumer_usage_to_bitmap(data);
|
||||
uart_write(0xFD);
|
||||
uart_write(0x03);
|
||||
uart_write(0x03);
|
||||
uart_write(bitmap & 0xFF);
|
||||
uart_write((bitmap >> 8) & 0xFF);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/* Copyright 2021
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "report.h"
|
||||
|
||||
void rn42_init(void);
|
||||
|
||||
void rn42_send_keyboard(report_keyboard_t *report);
|
||||
|
||||
void rn42_send_mouse(report_mouse_t *report);
|
||||
|
||||
void rn42_send_consumer(uint16_t data);
|
||||
+10
-1
@@ -125,7 +125,16 @@ void CKLED2001_init(uint8_t addr) {
|
||||
// Set CURRENT PAGE (Page 4)
|
||||
CKLED2001_write_register(addr, CONFIGURE_CMD_PAGE, CURRENT_TUNE_PAGE);
|
||||
for (int i = 0; i < LED_CURRENT_TUNE_LENGTH; i++) {
|
||||
CKLED2001_write_register(addr, i, 0xFF);
|
||||
switch (i) {
|
||||
case 2:
|
||||
case 5:
|
||||
case 8:
|
||||
case 11:
|
||||
CKLED2001_write_register(addr, i, 0xA0);
|
||||
break;
|
||||
default:
|
||||
CKLED2001_write_register(addr, i, 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
// Enable LEDs ON/OFF
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
/* Copyright 2017 Jason Williams
|
||||
* Copyright 2018 Jack Humbert
|
||||
* Copyright 2018 Yiancar
|
||||
* Copyright 2021 Doni Crosby
|
||||
* Copyright 2021 Leo Deng
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "is31fl3733-simple.h"
|
||||
#include "i2c_master.h"
|
||||
#include "wait.h"
|
||||
|
||||
// This is a 7-bit address, that gets left-shifted and bit 0
|
||||
// set to 0 for write, 1 for read (as per I2C protocol)
|
||||
// The address will vary depending on your wiring:
|
||||
// 00 <-> GND
|
||||
// 01 <-> SCL
|
||||
// 10 <-> SDA
|
||||
// 11 <-> VCC
|
||||
// ADDR1 represents A1:A0 of the 7-bit address.
|
||||
// ADDR2 represents A3:A2 of the 7-bit address.
|
||||
// The result is: 0b101(ADDR2)(ADDR1)
|
||||
#define ISSI_ADDR_DEFAULT 0x50
|
||||
|
||||
#define ISSI_COMMANDREGISTER 0xFD
|
||||
#define ISSI_COMMANDREGISTER_WRITELOCK 0xFE
|
||||
#define ISSI_INTERRUPTMASKREGISTER 0xF0
|
||||
#define ISSI_INTERRUPTSTATUSREGISTER 0xF1
|
||||
|
||||
#define ISSI_PAGE_LEDCONTROL 0x00 // PG0
|
||||
#define ISSI_PAGE_PWM 0x01 // PG1
|
||||
#define ISSI_PAGE_AUTOBREATH 0x02 // PG2
|
||||
#define ISSI_PAGE_FUNCTION 0x03 // PG3
|
||||
|
||||
#define ISSI_REG_CONFIGURATION 0x00 // PG3
|
||||
#define ISSI_REG_GLOBALCURRENT 0x01 // PG3
|
||||
#define ISSI_REG_RESET 0x11 // PG3
|
||||
#define ISSI_REG_SWPULLUP 0x0F // PG3
|
||||
#define ISSI_REG_CSPULLUP 0x10 // PG3
|
||||
|
||||
#ifndef ISSI_TIMEOUT
|
||||
# define ISSI_TIMEOUT 100
|
||||
#endif
|
||||
|
||||
#ifndef ISSI_PERSISTENCE
|
||||
# define ISSI_PERSISTENCE 0
|
||||
#endif
|
||||
|
||||
#ifndef ISSI_PWM_FREQUENCY
|
||||
# define ISSI_PWM_FREQUENCY 0b000 // PFS - IS31FL3733B only
|
||||
#endif
|
||||
|
||||
#ifndef ISSI_SWPULLUP
|
||||
# define ISSI_SWPULLUP PUR_0R
|
||||
#endif
|
||||
|
||||
#ifndef ISSI_CSPULLUP
|
||||
# define ISSI_CSPULLUP PUR_0R
|
||||
#endif
|
||||
|
||||
// Transfer buffer for TWITransmitData()
|
||||
uint8_t g_twi_transfer_buffer[20];
|
||||
|
||||
// These buffers match the IS31FL3733 PWM registers.
|
||||
// The control buffers match the PG0 LED On/Off registers.
|
||||
// Storing them like this is optimal for I2C transfers to the registers.
|
||||
// We could optimize this and take out the unused registers from these
|
||||
// buffers and the transfers in IS31FL3733_write_pwm_buffer() but it's
|
||||
// probably not worth the extra complexity.
|
||||
uint8_t g_pwm_buffer[LED_DRIVER_COUNT][192];
|
||||
bool g_pwm_buffer_update_required[LED_DRIVER_COUNT] = {false};
|
||||
|
||||
/* There's probably a better way to init this... */
|
||||
#if LED_DRIVER_COUNT == 1
|
||||
uint8_t g_led_control_registers[LED_DRIVER_COUNT][24] = {{0}};
|
||||
#elif LED_DRIVER_COUNT == 2
|
||||
uint8_t g_led_control_registers[LED_DRIVER_COUNT][24] = {{0}, {0}};
|
||||
#elif LED_DRIVER_COUNT == 3
|
||||
uint8_t g_led_control_registers[LED_DRIVER_COUNT][24] = {{0}, {0}, {0}};
|
||||
#elif LED_DRIVER_COUNT == 4
|
||||
uint8_t g_led_control_registers[LED_DRIVER_COUNT][24] = {{0}, {0}, {0}, {0}};
|
||||
#endif
|
||||
bool g_led_control_registers_update_required[LED_DRIVER_COUNT] = {false};
|
||||
|
||||
bool IS31FL3733_write_register(uint8_t addr, uint8_t reg, uint8_t data) {
|
||||
// If the transaction fails function returns false.
|
||||
g_twi_transfer_buffer[0] = reg;
|
||||
g_twi_transfer_buffer[1] = data;
|
||||
|
||||
#if ISSI_PERSISTENCE > 0
|
||||
for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) {
|
||||
if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 2, ISSI_TIMEOUT) != 0) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IS31FL3733_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer) {
|
||||
// Assumes PG1 is already selected.
|
||||
// If any of the transactions fails function returns false.
|
||||
// Transmit PWM registers in 12 transfers of 16 bytes.
|
||||
// g_twi_transfer_buffer[] is 20 bytes
|
||||
|
||||
// Iterate over the pwm_buffer contents at 16 byte intervals.
|
||||
for (int i = 0; i < 192; i += 16) {
|
||||
g_twi_transfer_buffer[0] = i;
|
||||
// Copy the data from i to i+15.
|
||||
// Device will auto-increment register for data after the first byte
|
||||
// Thus this sets registers 0x00-0x0F, 0x10-0x1F, etc. in one transfer.
|
||||
for (int j = 0; j < 16; j++) {
|
||||
g_twi_transfer_buffer[1 + j] = pwm_buffer[i + j];
|
||||
}
|
||||
|
||||
#if ISSI_PERSISTENCE > 0
|
||||
for (uint8_t i = 0; i < ISSI_PERSISTENCE; i++) {
|
||||
if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT) != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#else
|
||||
if (i2c_transmit(addr << 1, g_twi_transfer_buffer, 17, ISSI_TIMEOUT) != 0) {
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void IS31FL3733_init(uint8_t addr, uint8_t sync) {
|
||||
// In order to avoid the LEDs being driven with garbage data
|
||||
// in the LED driver's PWM registers, shutdown is enabled last.
|
||||
// Set up the mode and other settings, clear the PWM registers,
|
||||
// then disable software shutdown.
|
||||
// Sync is passed so set it according to the datasheet.
|
||||
|
||||
// Unlock the command register.
|
||||
IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5);
|
||||
|
||||
// Select PG0
|
||||
IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL);
|
||||
// Turn off all LEDs.
|
||||
for (int i = 0x00; i <= 0x17; i++) {
|
||||
IS31FL3733_write_register(addr, i, 0x00);
|
||||
}
|
||||
|
||||
// Unlock the command register.
|
||||
IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5);
|
||||
|
||||
// Select PG1
|
||||
IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM);
|
||||
// Set PWM on all LEDs to 0
|
||||
// No need to setup Breath registers to PWM as that is the default.
|
||||
for (int i = 0x00; i <= 0xBF; i++) {
|
||||
IS31FL3733_write_register(addr, i, 0x00);
|
||||
}
|
||||
|
||||
// Unlock the command register.
|
||||
IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5);
|
||||
|
||||
// Select PG3
|
||||
IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_FUNCTION);
|
||||
// Set de-ghost pull-up resistors (SWx)
|
||||
IS31FL3733_write_register(addr, ISSI_REG_SWPULLUP, ISSI_SWPULLUP);
|
||||
// Set de-ghost pull-down resistors (CSx)
|
||||
IS31FL3733_write_register(addr, ISSI_REG_CSPULLUP, ISSI_CSPULLUP);
|
||||
// Set global current to maximum.
|
||||
IS31FL3733_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF);
|
||||
// Disable software shutdown.
|
||||
IS31FL3733_write_register(addr, ISSI_REG_CONFIGURATION, ((sync & 0b11) << 6) | ((ISSI_PWM_FREQUENCY & 0b111) << 3) | 0x01);
|
||||
|
||||
// Wait 10ms to ensure the device has woken up.
|
||||
wait_ms(10);
|
||||
}
|
||||
|
||||
void IS31FL3733_set_value(int index, uint8_t value) {
|
||||
if (index >= 0 && index < DRIVER_LED_TOTAL) {
|
||||
is31_led led = g_is31_leds[index];
|
||||
|
||||
g_pwm_buffer[led.driver][led.v] = value;
|
||||
g_pwm_buffer_update_required[led.driver] = true;
|
||||
}
|
||||
}
|
||||
|
||||
void IS31FL3733_set_value_all(uint8_t value) {
|
||||
for (int i = 0; i < DRIVER_LED_TOTAL; i++) {
|
||||
IS31FL3733_set_value(i, value);
|
||||
}
|
||||
}
|
||||
|
||||
void IS31FL3733_set_led_control_register(uint8_t index, bool value) {
|
||||
is31_led led = g_is31_leds[index];
|
||||
|
||||
uint8_t control_register = led.v / 8;
|
||||
uint8_t bit_value = led.v % 8;
|
||||
|
||||
if (value) {
|
||||
g_led_control_registers[led.driver][control_register] |= (1 << bit_value);
|
||||
} else {
|
||||
g_led_control_registers[led.driver][control_register] &= ~(1 << bit_value);
|
||||
}
|
||||
|
||||
g_led_control_registers_update_required[led.driver] = true;
|
||||
}
|
||||
|
||||
void IS31FL3733_update_pwm_buffers(uint8_t addr, uint8_t index) {
|
||||
if (g_pwm_buffer_update_required[index]) {
|
||||
// Firstly we need to unlock the command register and select PG1.
|
||||
IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5);
|
||||
IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_PWM);
|
||||
|
||||
// If any of the transactions fail we risk writing dirty PG0,
|
||||
// refresh page 0 just in case.
|
||||
if (!IS31FL3733_write_pwm_buffer(addr, g_pwm_buffer[index])) {
|
||||
g_led_control_registers_update_required[index] = true;
|
||||
}
|
||||
g_pwm_buffer_update_required[index] = false;
|
||||
}
|
||||
}
|
||||
|
||||
void IS31FL3733_update_led_control_registers(uint8_t addr, uint8_t index) {
|
||||
if (g_led_control_registers_update_required[index]) {
|
||||
// Firstly we need to unlock the command register and select PG0
|
||||
IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER_WRITELOCK, 0xC5);
|
||||
IS31FL3733_write_register(addr, ISSI_COMMANDREGISTER, ISSI_PAGE_LEDCONTROL);
|
||||
for (int i = 0; i < 24; i++) {
|
||||
IS31FL3733_write_register(addr, i, g_led_control_registers[index][i]);
|
||||
}
|
||||
g_led_control_registers_update_required[index] = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
/* Copyright 2017 Jason Williams
|
||||
* Copyright 2018 Jack Humbert
|
||||
* Copyright 2018 Yiancar
|
||||
* Copyright 2021 Doni Crosby
|
||||
* Copyright 2021 Leo Deng
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include "progmem.h"
|
||||
|
||||
typedef struct is31_led {
|
||||
uint8_t driver : 2;
|
||||
uint8_t v;
|
||||
} __attribute__((packed)) is31_led;
|
||||
|
||||
extern const is31_led __flash g_is31_leds[DRIVER_LED_TOTAL];
|
||||
|
||||
void IS31FL3733_init(uint8_t addr, uint8_t sync);
|
||||
bool IS31FL3733_write_register(uint8_t addr, uint8_t reg, uint8_t data);
|
||||
bool IS31FL3733_write_pwm_buffer(uint8_t addr, uint8_t *pwm_buffer);
|
||||
|
||||
void IS31FL3733_set_value(int index, uint8_t value);
|
||||
void IS31FL3733_set_value_all(uint8_t value);
|
||||
|
||||
void IS31FL3733_set_led_control_register(uint8_t index, bool value);
|
||||
|
||||
// This should not be called from an interrupt
|
||||
// (eg. from a timer interrupt).
|
||||
// Call this while idle (in between matrix scans).
|
||||
// If the buffer is dirty, it will update the driver with the buffer.
|
||||
void IS31FL3733_update_pwm_buffers(uint8_t addr, uint8_t index);
|
||||
void IS31FL3733_update_led_control_registers(uint8_t addr, uint8_t index);
|
||||
|
||||
#define PUR_0R 0x00 // No PUR resistor
|
||||
#define PUR_05KR 0x02 // 0.5k Ohm resistor in t_NOL
|
||||
#define PUR_3KR 0x03 // 3.0k Ohm resistor on all the time
|
||||
#define PUR_4KR 0x04 // 4.0k Ohm resistor on all the time
|
||||
#define PUR_8KR 0x05 // 8.0k Ohm resistor on all the time
|
||||
#define PUR_16KR 0x06 // 16k Ohm resistor on all the time
|
||||
#define PUR_32KR 0x07 // 32k Ohm resistor in t_NOL
|
||||
|
||||
#define A_1 0x00
|
||||
#define A_2 0x01
|
||||
#define A_3 0x02
|
||||
#define A_4 0x03
|
||||
#define A_5 0x04
|
||||
#define A_6 0x05
|
||||
#define A_7 0x06
|
||||
#define A_8 0x07
|
||||
#define A_9 0x08
|
||||
#define A_10 0x09
|
||||
#define A_11 0x0A
|
||||
#define A_12 0x0B
|
||||
#define A_13 0x0C
|
||||
#define A_14 0x0D
|
||||
#define A_15 0x0E
|
||||
#define A_16 0x0F
|
||||
|
||||
#define B_1 0x10
|
||||
#define B_2 0x11
|
||||
#define B_3 0x12
|
||||
#define B_4 0x13
|
||||
#define B_5 0x14
|
||||
#define B_6 0x15
|
||||
#define B_7 0x16
|
||||
#define B_8 0x17
|
||||
#define B_9 0x18
|
||||
#define B_10 0x19
|
||||
#define B_11 0x1A
|
||||
#define B_12 0x1B
|
||||
#define B_13 0x1C
|
||||
#define B_14 0x1D
|
||||
#define B_15 0x1E
|
||||
#define B_16 0x1F
|
||||
|
||||
#define C_1 0x20
|
||||
#define C_2 0x21
|
||||
#define C_3 0x22
|
||||
#define C_4 0x23
|
||||
#define C_5 0x24
|
||||
#define C_6 0x25
|
||||
#define C_7 0x26
|
||||
#define C_8 0x27
|
||||
#define C_9 0x28
|
||||
#define C_10 0x29
|
||||
#define C_11 0x2A
|
||||
#define C_12 0x2B
|
||||
#define C_13 0x2C
|
||||
#define C_14 0x2D
|
||||
#define C_15 0x2E
|
||||
#define C_16 0x2F
|
||||
|
||||
#define D_1 0x30
|
||||
#define D_2 0x31
|
||||
#define D_3 0x32
|
||||
#define D_4 0x33
|
||||
#define D_5 0x34
|
||||
#define D_6 0x35
|
||||
#define D_7 0x36
|
||||
#define D_8 0x37
|
||||
#define D_9 0x38
|
||||
#define D_10 0x39
|
||||
#define D_11 0x3A
|
||||
#define D_12 0x3B
|
||||
#define D_13 0x3C
|
||||
#define D_14 0x3D
|
||||
#define D_15 0x3E
|
||||
#define D_16 0x3F
|
||||
|
||||
#define E_1 0x40
|
||||
#define E_2 0x41
|
||||
#define E_3 0x42
|
||||
#define E_4 0x43
|
||||
#define E_5 0x44
|
||||
#define E_6 0x45
|
||||
#define E_7 0x46
|
||||
#define E_8 0x47
|
||||
#define E_9 0x48
|
||||
#define E_10 0x49
|
||||
#define E_11 0x4A
|
||||
#define E_12 0x4B
|
||||
#define E_13 0x4C
|
||||
#define E_14 0x4D
|
||||
#define E_15 0x4E
|
||||
#define E_16 0x4F
|
||||
|
||||
#define F_1 0x50
|
||||
#define F_2 0x51
|
||||
#define F_3 0x52
|
||||
#define F_4 0x53
|
||||
#define F_5 0x54
|
||||
#define F_6 0x55
|
||||
#define F_7 0x56
|
||||
#define F_8 0x57
|
||||
#define F_9 0x58
|
||||
#define F_10 0x59
|
||||
#define F_11 0x5A
|
||||
#define F_12 0x5B
|
||||
#define F_13 0x5C
|
||||
#define F_14 0x5D
|
||||
#define F_15 0x5E
|
||||
#define F_16 0x5F
|
||||
|
||||
#define G_1 0x60
|
||||
#define G_2 0x61
|
||||
#define G_3 0x62
|
||||
#define G_4 0x63
|
||||
#define G_5 0x64
|
||||
#define G_6 0x65
|
||||
#define G_7 0x66
|
||||
#define G_8 0x67
|
||||
#define G_9 0x68
|
||||
#define G_10 0x69
|
||||
#define G_11 0x6A
|
||||
#define G_12 0x6B
|
||||
#define G_13 0x6C
|
||||
#define G_14 0x6D
|
||||
#define G_15 0x6E
|
||||
#define G_16 0x6F
|
||||
|
||||
#define H_1 0x70
|
||||
#define H_2 0x71
|
||||
#define H_3 0x72
|
||||
#define H_4 0x73
|
||||
#define H_5 0x74
|
||||
#define H_6 0x75
|
||||
#define H_7 0x76
|
||||
#define H_8 0x77
|
||||
#define H_9 0x78
|
||||
#define H_10 0x79
|
||||
#define H_11 0x7A
|
||||
#define H_12 0x7B
|
||||
#define H_13 0x7C
|
||||
#define H_14 0x7D
|
||||
#define H_15 0x7E
|
||||
#define H_16 0x7F
|
||||
|
||||
#define I_1 0x80
|
||||
#define I_2 0x81
|
||||
#define I_3 0x82
|
||||
#define I_4 0x83
|
||||
#define I_5 0x84
|
||||
#define I_6 0x85
|
||||
#define I_7 0x86
|
||||
#define I_8 0x87
|
||||
#define I_9 0x88
|
||||
#define I_10 0x89
|
||||
#define I_11 0x8A
|
||||
#define I_12 0x8B
|
||||
#define I_13 0x8C
|
||||
#define I_14 0x8D
|
||||
#define I_15 0x8E
|
||||
#define I_16 0x8F
|
||||
|
||||
#define J_1 0x90
|
||||
#define J_2 0x91
|
||||
#define J_3 0x92
|
||||
#define J_4 0x93
|
||||
#define J_5 0x94
|
||||
#define J_6 0x95
|
||||
#define J_7 0x96
|
||||
#define J_8 0x97
|
||||
#define J_9 0x98
|
||||
#define J_10 0x99
|
||||
#define J_11 0x9A
|
||||
#define J_12 0x9B
|
||||
#define J_13 0x9C
|
||||
#define J_14 0x9D
|
||||
#define J_15 0x9E
|
||||
#define J_16 0x9F
|
||||
|
||||
#define K_1 0xA0
|
||||
#define K_2 0xA1
|
||||
#define K_3 0xA2
|
||||
#define K_4 0xA3
|
||||
#define K_5 0xA4
|
||||
#define K_6 0xA5
|
||||
#define K_7 0xA6
|
||||
#define K_8 0xA7
|
||||
#define K_9 0xA8
|
||||
#define K_10 0xA9
|
||||
#define K_11 0xAA
|
||||
#define K_12 0xAB
|
||||
#define K_13 0xAC
|
||||
#define K_14 0xAD
|
||||
#define K_15 0xAE
|
||||
#define K_16 0xAF
|
||||
|
||||
#define L_1 0xB0
|
||||
#define L_2 0xB1
|
||||
#define L_3 0xB2
|
||||
#define L_4 0xB3
|
||||
#define L_5 0xB4
|
||||
#define L_6 0xB5
|
||||
#define L_7 0xB6
|
||||
#define L_8 0xB7
|
||||
#define L_9 0xB8
|
||||
#define L_10 0xB9
|
||||
#define L_11 0xBA
|
||||
#define L_12 0xBB
|
||||
#define L_13 0xBC
|
||||
#define L_14 0xBD
|
||||
#define L_15 0xBE
|
||||
#define L_16 0xBF
|
||||
@@ -135,10 +135,8 @@ void adns9800_init() {
|
||||
wait_us(15);
|
||||
|
||||
// send all bytes of the firmware
|
||||
unsigned char c;
|
||||
for (int i = 0; i < FIRMWARE_LENGTH; i++) {
|
||||
c = (unsigned char)pgm_read_byte(adns9800_firmware_data + i);
|
||||
spi_write(c);
|
||||
for (uint16_t i = 0; i < FIRMWARE_LENGTH; i++) {
|
||||
spi_write(pgm_read_byte(firmware_data + i));
|
||||
wait_us(15);
|
||||
}
|
||||
|
||||
@@ -154,8 +152,8 @@ void adns9800_init() {
|
||||
}
|
||||
|
||||
config_adns9800_t adns9800_get_config(void) {
|
||||
uint8_t config_1 = adns9800_read(REG_Configuration_I);
|
||||
return (config_adns9800_t){(config_1 & 0xFF) * CPI_STEP};
|
||||
uint8_t cpival = adns9800_read(REG_Configuration_I);
|
||||
return (config_adns9800_t){(cpival & 0xFF) * CPI_STEP};
|
||||
}
|
||||
|
||||
void adns9800_set_config(config_adns9800_t config) {
|
||||
@@ -164,8 +162,8 @@ void adns9800_set_config(config_adns9800_t config) {
|
||||
}
|
||||
|
||||
uint16_t adns9800_get_cpi(void) {
|
||||
uint8_t config_1 = adns9800_read(REG_Configuration_I);
|
||||
return (uint16_t){(config_1 & 0xFF) * CPI_STEP};
|
||||
uint8_t cpival = adns9800_read(REG_Configuration_I);
|
||||
return (uint16_t)(cpival & 0xFF) * CPI_STEP;
|
||||
}
|
||||
|
||||
void adns9800_set_cpi(uint16_t cpi) {
|
||||
@@ -184,7 +182,7 @@ static int16_t convertDeltaToInt(uint8_t high, uint8_t low) {
|
||||
}
|
||||
|
||||
report_adns9800_t adns9800_get_report(void) {
|
||||
report_adns9800_t report = {0, 0};
|
||||
report_adns9800_t report = {0};
|
||||
|
||||
adns9800_spi_start();
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
// clang-format off
|
||||
|
||||
const uint8_t adns9800_firmware_data[FIRMWARE_LENGTH] PROGMEM = {
|
||||
const uint8_t firmware_data[FIRMWARE_LENGTH] PROGMEM = {
|
||||
0x03, 0xA6, 0x68, 0x1E, 0x7D, 0x10, 0x7E, 0x7E, 0x5F, 0x1C, 0xB8, 0xF2, 0x47, 0x0C, 0x7B, 0x74,
|
||||
0x4B, 0x14, 0x8B, 0x75, 0x66, 0x51, 0x0B, 0x8C, 0x76, 0x74, 0x4B, 0x14, 0xAA, 0xD6, 0x0F, 0x9C,
|
||||
0xBA, 0xF6, 0x6E, 0x3F, 0xDD, 0x38, 0xD5, 0x02, 0x80, 0x9B, 0x82, 0x6D, 0x58, 0x13, 0xA4, 0xAB,
|
||||
|
||||
@@ -33,8 +33,24 @@
|
||||
|
||||
static uint16_t precision = 128;
|
||||
|
||||
float pimoroni_trackball_get_precision(void) { return ((float)precision / 128); }
|
||||
void pimoroni_trackball_set_precision(float floatprecision) { precision = (floatprecision * 128); }
|
||||
uint16_t pimoroni_trackball_get_cpi(void) { return (precision * 125); }
|
||||
/**
|
||||
* @brief Sets the scaling value for pimoroni trackball
|
||||
*
|
||||
* Sets a scaling value for pimoroni trackball to allow runtime adjustment. This isn't used by the sensor and is an
|
||||
* approximation so the functions are consistent across drivers.
|
||||
*
|
||||
* NOTE: This rounds down to the nearest number divisable by 125 that's a positive integer, values below 125 are clamped to 125.
|
||||
*
|
||||
* @param cpi uint16_t
|
||||
*/
|
||||
void pimoroni_trackball_set_cpi(uint16_t cpi) {
|
||||
if (cpi < 249) {
|
||||
precision = 1;
|
||||
} else {
|
||||
precision = (cpi - (cpi % 125)) / 125;
|
||||
}
|
||||
}
|
||||
|
||||
void pimoroni_trackball_set_rgbw(uint8_t r, uint8_t g, uint8_t b, uint8_t w) {
|
||||
uint8_t data[4] = {r, g, b, w};
|
||||
@@ -60,7 +76,7 @@ i2c_status_t read_pimoroni_trackball(pimoroni_data_t* data) {
|
||||
return status;
|
||||
}
|
||||
|
||||
__attribute__((weak)) void pimironi_trackball_device_init(void) {
|
||||
__attribute__((weak)) void pimoroni_trackball_device_init(void) {
|
||||
i2c_init();
|
||||
pimoroni_trackball_set_rgbw(0x00, 0x00, 0x00, 0x00);
|
||||
}
|
||||
|
||||
@@ -23,9 +23,6 @@
|
||||
#ifndef PIMORONI_TRACKBALL_ADDRESS
|
||||
# define PIMORONI_TRACKBALL_ADDRESS 0x0A
|
||||
#endif
|
||||
#ifndef PIMORONI_TRACKBALL_INTERVAL_MS
|
||||
# define PIMORONI_TRACKBALL_INTERVAL_MS 8
|
||||
#endif
|
||||
#ifndef PIMORONI_TRACKBALL_SCALE
|
||||
# define PIMORONI_TRACKBALL_SCALE 5
|
||||
#endif
|
||||
@@ -52,10 +49,10 @@ typedef struct {
|
||||
uint8_t click;
|
||||
} pimoroni_data_t;
|
||||
|
||||
void pimironi_trackball_device_init(void);
|
||||
void pimoroni_trackball_device_init(void);
|
||||
void pimoroni_trackball_set_rgbw(uint8_t red, uint8_t green, uint8_t blue, uint8_t white);
|
||||
int16_t pimoroni_trackball_get_offsets(uint8_t negative_dir, uint8_t positive_dir, uint8_t scale);
|
||||
void pimoroni_trackball_adapt_values(int8_t* mouse, int16_t* offset);
|
||||
float pimoroni_trackball_get_precision(void);
|
||||
void pimoroni_trackball_set_precision(float precision);
|
||||
uint16_t pimoroni_trackball_get_cpi(void);
|
||||
void pimoroni_trackball_set_cpi(uint16_t cpi);
|
||||
i2c_status_t read_pimoroni_trackball(pimoroni_data_t* data);
|
||||
|
||||
+144
-139
@@ -16,67 +16,71 @@
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "spi_master.h"
|
||||
#include "pmw3360.h"
|
||||
#include "wait.h"
|
||||
#include "debug.h"
|
||||
#include "print.h"
|
||||
#include PMW3360_FIRMWARE_H
|
||||
#include "pmw3360_firmware.h"
|
||||
|
||||
// Registers
|
||||
// clang-format off
|
||||
#define REG_Product_ID 0x00
|
||||
#define REG_Revision_ID 0x01
|
||||
#define REG_Motion 0x02
|
||||
#define REG_Delta_X_L 0x03
|
||||
#define REG_Delta_X_H 0x04
|
||||
#define REG_Delta_Y_L 0x05
|
||||
#define REG_Delta_Y_H 0x06
|
||||
#define REG_SQUAL 0x07
|
||||
#define REG_Raw_Data_Sum 0x08
|
||||
#define REG_Maximum_Raw_data 0x09
|
||||
#define REG_Minimum_Raw_data 0x0A
|
||||
#define REG_Shutter_Lower 0x0B
|
||||
#define REG_Shutter_Upper 0x0C
|
||||
#define REG_Control 0x0D
|
||||
#define REG_Config1 0x0F
|
||||
#define REG_Config2 0x10
|
||||
#define REG_Angle_Tune 0x11
|
||||
#define REG_Frame_Capture 0x12
|
||||
#define REG_SROM_Enable 0x13
|
||||
#define REG_Run_Downshift 0x14
|
||||
#define REG_Rest1_Rate_Lower 0x15
|
||||
#define REG_Rest1_Rate_Upper 0x16
|
||||
#define REG_Rest1_Downshift 0x17
|
||||
#define REG_Rest2_Rate_Lower 0x18
|
||||
#define REG_Rest2_Rate_Upper 0x19
|
||||
#define REG_Rest2_Downshift 0x1A
|
||||
#define REG_Rest3_Rate_Lower 0x1B
|
||||
#define REG_Rest3_Rate_Upper 0x1C
|
||||
#define REG_Observation 0x24
|
||||
#define REG_Data_Out_Lower 0x25
|
||||
#define REG_Data_Out_Upper 0x26
|
||||
#define REG_Raw_Data_Dump 0x29
|
||||
#define REG_SROM_ID 0x2A
|
||||
#define REG_Min_SQ_Run 0x2B
|
||||
#define REG_Raw_Data_Threshold 0x2C
|
||||
#define REG_Config5 0x2F
|
||||
#define REG_Power_Up_Reset 0x3A
|
||||
#define REG_Shutdown 0x3B
|
||||
#define REG_Inverse_Product_ID 0x3F
|
||||
#define REG_LiftCutoff_Tune3 0x41
|
||||
#define REG_Angle_Snap 0x42
|
||||
#define REG_LiftCutoff_Tune1 0x4A
|
||||
#define REG_Motion_Burst 0x50
|
||||
#define REG_LiftCutoff_Tune_Timeout 0x58
|
||||
#define REG_LiftCutoff_Tune_Min_Length 0x5A
|
||||
#define REG_SROM_Load_Burst 0x62
|
||||
#define REG_Lift_Config 0x63
|
||||
#define REG_Raw_Data_Burst 0x64
|
||||
#define REG_LiftCutoff_Tune2 0x65
|
||||
#define REG_Product_ID 0x00
|
||||
#define REG_Revision_ID 0x01
|
||||
#define REG_Motion 0x02
|
||||
#define REG_Delta_X_L 0x03
|
||||
#define REG_Delta_X_H 0x04
|
||||
#define REG_Delta_Y_L 0x05
|
||||
#define REG_Delta_Y_H 0x06
|
||||
#define REG_SQUAL 0x07
|
||||
#define REG_Raw_Data_Sum 0x08
|
||||
#define REG_Maximum_Raw_data 0x09
|
||||
#define REG_Minimum_Raw_data 0x0a
|
||||
#define REG_Shutter_Lower 0x0b
|
||||
#define REG_Shutter_Upper 0x0c
|
||||
#define REG_Control 0x0d
|
||||
#define REG_Config1 0x0f
|
||||
#define REG_Config2 0x10
|
||||
#define REG_Angle_Tune 0x11
|
||||
#define REG_Frame_Capture 0x12
|
||||
#define REG_SROM_Enable 0x13
|
||||
#define REG_Run_Downshift 0x14
|
||||
#define REG_Rest1_Rate_Lower 0x15
|
||||
#define REG_Rest1_Rate_Upper 0x16
|
||||
#define REG_Rest1_Downshift 0x17
|
||||
#define REG_Rest2_Rate_Lower 0x18
|
||||
#define REG_Rest2_Rate_Upper 0x19
|
||||
#define REG_Rest2_Downshift 0x1a
|
||||
#define REG_Rest3_Rate_Lower 0x1b
|
||||
#define REG_Rest3_Rate_Upper 0x1c
|
||||
#define REG_Observation 0x24
|
||||
#define REG_Data_Out_Lower 0x25
|
||||
#define REG_Data_Out_Upper 0x26
|
||||
#define REG_Raw_Data_Dump 0x29
|
||||
#define REG_SROM_ID 0x2a
|
||||
#define REG_Min_SQ_Run 0x2b
|
||||
#define REG_Raw_Data_Threshold 0x2c
|
||||
#define REG_Config5 0x2f
|
||||
#define REG_Power_Up_Reset 0x3a
|
||||
#define REG_Shutdown 0x3b
|
||||
#define REG_Inverse_Product_ID 0x3f
|
||||
#define REG_LiftCutoff_Tune3 0x41
|
||||
#define REG_Angle_Snap 0x42
|
||||
#define REG_LiftCutoff_Tune1 0x4a
|
||||
#define REG_Motion_Burst 0x50
|
||||
#define REG_LiftCutoff_Tune_Timeout 0x58
|
||||
#define REG_LiftCutoff_Tune_Min_Length 0x5a
|
||||
#define REG_SROM_Load_Burst 0x62
|
||||
#define REG_Lift_Config 0x63
|
||||
#define REG_Raw_Data_Burst 0x64
|
||||
#define REG_LiftCutoff_Tune2 0x65
|
||||
|
||||
#define CPI_STEP 100
|
||||
// clang-format on
|
||||
|
||||
// limits to 0--119, resulting in a CPI range of 100 -- 12000 (as only steps of 100 are possible).
|
||||
#ifndef MAX_CPI
|
||||
# define MAX_CPI 0x77 // limits to 0--119, should be max cpi/100
|
||||
# define MAX_CPI 0x77
|
||||
#endif
|
||||
|
||||
bool _inBurst = false;
|
||||
@@ -86,66 +90,50 @@ void print_byte(uint8_t byte) { dprintf("%c%c%c%c%c%c%c%c|", (byte & 0x80 ? '1'
|
||||
#endif
|
||||
#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
|
||||
|
||||
bool spi_start_adv(void) {
|
||||
bool pmw3360_spi_start(void) {
|
||||
bool status = spi_start(PMW3360_CS_PIN, PMW3360_SPI_LSBFIRST, PMW3360_SPI_MODE, PMW3360_SPI_DIVISOR);
|
||||
// tNCS-SCLK, 120ns
|
||||
wait_us(1);
|
||||
return status;
|
||||
}
|
||||
|
||||
void spi_stop_adv(void) {
|
||||
wait_us(1);
|
||||
spi_stop();
|
||||
}
|
||||
spi_status_t pmw3360_write(uint8_t reg_addr, uint8_t data) {
|
||||
pmw3360_spi_start();
|
||||
|
||||
spi_status_t spi_write_adv(uint8_t reg_addr, uint8_t data) {
|
||||
if (reg_addr != REG_Motion_Burst) {
|
||||
_inBurst = false;
|
||||
}
|
||||
|
||||
spi_start_adv();
|
||||
// send address of the register, with MSBit = 1 to indicate it's a write
|
||||
spi_status_t status = spi_write(reg_addr | 0x80);
|
||||
status = spi_write(data);
|
||||
|
||||
// tSCLK-NCS for write operation
|
||||
wait_us(20);
|
||||
|
||||
// tSWW/tSWR (=120us) minus tSCLK-NCS. Could be shortened, but is looks like a safe lower bound
|
||||
wait_us(100);
|
||||
// tSCLK-NCS for write operation is 35us
|
||||
wait_us(35);
|
||||
spi_stop();
|
||||
|
||||
// tSWW/tSWR (=180us) minus tSCLK-NCS. Could be shortened, but is looks like a safe lower bound
|
||||
wait_us(145);
|
||||
return status;
|
||||
}
|
||||
|
||||
uint8_t spi_read_adv(uint8_t reg_addr) {
|
||||
spi_start_adv();
|
||||
uint8_t pmw3360_read(uint8_t reg_addr) {
|
||||
pmw3360_spi_start();
|
||||
// send adress of the register, with MSBit = 0 to indicate it's a read
|
||||
spi_write(reg_addr & 0x7f);
|
||||
|
||||
// tSRAD (=160us)
|
||||
wait_us(160);
|
||||
uint8_t data = spi_read();
|
||||
|
||||
// tSCLK-NCS for read operation is 120ns
|
||||
wait_us(1);
|
||||
spi_stop();
|
||||
|
||||
// tSRW/tSRR (=20us) minus tSCLK-NCS
|
||||
wait_us(19);
|
||||
|
||||
spi_stop();
|
||||
return data;
|
||||
}
|
||||
|
||||
void pmw3360_set_cpi(uint16_t cpi) {
|
||||
uint8_t cpival = constrain((cpi / 100) - 1, 0, MAX_CPI);
|
||||
|
||||
spi_start_adv();
|
||||
spi_write_adv(REG_Config1, cpival);
|
||||
spi_stop();
|
||||
}
|
||||
|
||||
uint16_t pmw3360_get_cpi(void) {
|
||||
uint8_t cpival = spi_read_adv(REG_Config1);
|
||||
return (uint16_t)((cpival + 1) & 0xFF) * 100;
|
||||
}
|
||||
|
||||
bool pmw3360_init(void) {
|
||||
setPinOutput(PMW3360_CS_PIN);
|
||||
|
||||
@@ -153,42 +141,51 @@ bool pmw3360_init(void) {
|
||||
_inBurst = false;
|
||||
|
||||
spi_stop();
|
||||
spi_start_adv();
|
||||
pmw3360_spi_start();
|
||||
spi_stop();
|
||||
|
||||
spi_write_adv(REG_Shutdown, 0xb6); // Shutdown first
|
||||
pmw3360_write(REG_Shutdown, 0xb6); // Shutdown first
|
||||
wait_ms(300);
|
||||
|
||||
spi_start_adv();
|
||||
pmw3360_spi_start();
|
||||
wait_us(40);
|
||||
spi_stop_adv();
|
||||
spi_stop();
|
||||
wait_us(40);
|
||||
|
||||
spi_write_adv(REG_Power_Up_Reset, 0x5a);
|
||||
// power up, need to first drive NCS high then low, see above.
|
||||
pmw3360_write(REG_Power_Up_Reset, 0x5a);
|
||||
wait_ms(50);
|
||||
|
||||
spi_read_adv(REG_Motion);
|
||||
spi_read_adv(REG_Delta_X_L);
|
||||
spi_read_adv(REG_Delta_X_H);
|
||||
spi_read_adv(REG_Delta_Y_L);
|
||||
spi_read_adv(REG_Delta_Y_H);
|
||||
// read registers and discard
|
||||
pmw3360_read(REG_Motion);
|
||||
pmw3360_read(REG_Delta_X_L);
|
||||
pmw3360_read(REG_Delta_X_H);
|
||||
pmw3360_read(REG_Delta_Y_L);
|
||||
pmw3360_read(REG_Delta_Y_H);
|
||||
|
||||
pmw3360_upload_firmware();
|
||||
|
||||
spi_stop_adv();
|
||||
spi_stop();
|
||||
|
||||
wait_ms(10);
|
||||
pmw3360_set_cpi(PMW3360_CPI);
|
||||
|
||||
wait_ms(1);
|
||||
|
||||
spi_write_adv(REG_Config2, 0x00);
|
||||
pmw3360_write(REG_Config2, 0x00);
|
||||
|
||||
spi_write_adv(REG_Angle_Tune, constrain(ROTATIONAL_TRANSFORM_ANGLE, -30, 30));
|
||||
pmw3360_write(REG_Angle_Tune, constrain(ROTATIONAL_TRANSFORM_ANGLE, -127, 127));
|
||||
|
||||
spi_write_adv(REG_Lift_Config, PMW3360_LIFTOFF_DISTANCE);
|
||||
pmw3360_write(REG_Lift_Config, PMW3360_LIFTOFF_DISTANCE);
|
||||
|
||||
bool init_success = pmw3360_check_signature();
|
||||
#ifdef CONSOLE_ENABLE
|
||||
if (init_success) {
|
||||
dprintf("pmw3360 signature verified");
|
||||
} else {
|
||||
dprintf("pmw3360 signature verification failed!");
|
||||
}
|
||||
#endif
|
||||
|
||||
writePinLow(PMW3360_CS_PIN);
|
||||
|
||||
@@ -196,86 +193,94 @@ bool pmw3360_init(void) {
|
||||
}
|
||||
|
||||
void pmw3360_upload_firmware(void) {
|
||||
spi_write_adv(REG_SROM_Enable, 0x1d);
|
||||
// Datasheet claims we need to disable REST mode first, but during startup
|
||||
// it's already disabled and we're not turning it on ...
|
||||
// pmw3360_write(REG_Config2, 0x00); // disable REST mode
|
||||
pmw3360_write(REG_SROM_Enable, 0x1d);
|
||||
|
||||
wait_ms(10);
|
||||
|
||||
spi_write_adv(REG_SROM_Enable, 0x18);
|
||||
pmw3360_write(REG_SROM_Enable, 0x18);
|
||||
|
||||
spi_start_adv();
|
||||
pmw3360_spi_start();
|
||||
spi_write(REG_SROM_Load_Burst | 0x80);
|
||||
wait_us(15);
|
||||
|
||||
unsigned char c;
|
||||
for (int i = 0; i < FIRMWARE_LENGTH; i++) {
|
||||
c = (unsigned char)pgm_read_byte(firmware_data + i);
|
||||
spi_write(c);
|
||||
for (uint16_t i = 0; i < FIRMWARE_LENGTH; i++) {
|
||||
spi_write(pgm_read_byte(firmware_data + i));
|
||||
#ifndef PMW3360_FIRMWARE_UPLOAD_FAST
|
||||
wait_us(15);
|
||||
#endif
|
||||
}
|
||||
wait_us(200);
|
||||
|
||||
spi_read_adv(REG_SROM_ID);
|
||||
|
||||
spi_write_adv(REG_Config2, 0x00);
|
||||
|
||||
spi_stop();
|
||||
wait_ms(10);
|
||||
pmw3360_read(REG_SROM_ID);
|
||||
pmw3360_write(REG_Config2, 0x00);
|
||||
}
|
||||
|
||||
bool pmw3360_check_signature(void) {
|
||||
uint8_t pid = spi_read_adv(REG_Product_ID);
|
||||
uint8_t iv_pid = spi_read_adv(REG_Inverse_Product_ID);
|
||||
uint8_t SROM_ver = spi_read_adv(REG_SROM_ID);
|
||||
uint8_t pid = pmw3360_read(REG_Product_ID);
|
||||
uint8_t iv_pid = pmw3360_read(REG_Inverse_Product_ID);
|
||||
uint8_t SROM_ver = pmw3360_read(REG_SROM_ID);
|
||||
return (pid == firmware_signature[0] && iv_pid == firmware_signature[1] && SROM_ver == firmware_signature[2]); // signature for SROM 0x04
|
||||
}
|
||||
|
||||
uint16_t pmw3360_get_cpi(void) {
|
||||
uint8_t cpival = pmw3360_read(REG_Config1);
|
||||
return (uint16_t)((cpival + 1) & 0xFF) * CPI_STEP;
|
||||
}
|
||||
|
||||
void pmw3360_set_cpi(uint16_t cpi) {
|
||||
uint8_t cpival = constrain((cpi / CPI_STEP) - 1, 0, MAX_CPI);
|
||||
pmw3360_write(REG_Config1, cpival);
|
||||
}
|
||||
|
||||
report_pmw3360_t pmw3360_read_burst(void) {
|
||||
report_pmw3360_t report = {0};
|
||||
|
||||
if (!_inBurst) {
|
||||
#ifdef CONSOLE_ENABLE
|
||||
dprintf("burst on");
|
||||
#endif
|
||||
spi_write_adv(REG_Motion_Burst, 0x00);
|
||||
pmw3360_write(REG_Motion_Burst, 0x00);
|
||||
_inBurst = true;
|
||||
}
|
||||
|
||||
spi_start_adv();
|
||||
pmw3360_spi_start();
|
||||
spi_write(REG_Motion_Burst);
|
||||
wait_us(35); // waits for tSRAD
|
||||
wait_us(35); // waits for tSRAD_MOTBR
|
||||
|
||||
report_pmw3360_t data = {0};
|
||||
report.motion = spi_read();
|
||||
spi_read(); // skip Observation
|
||||
// delta registers
|
||||
report.dx = spi_read();
|
||||
report.mdx = spi_read();
|
||||
report.dy = spi_read();
|
||||
report.mdy = spi_read();
|
||||
|
||||
data.motion = spi_read();
|
||||
spi_write(0x00); // skip Observation
|
||||
data.dx = spi_read();
|
||||
data.mdx = spi_read();
|
||||
data.dy = spi_read();
|
||||
data.mdy = spi_read();
|
||||
if (report.motion & 0b111) { // panic recovery, sometimes burst mode works weird.
|
||||
_inBurst = false;
|
||||
}
|
||||
|
||||
spi_stop();
|
||||
|
||||
#ifdef CONSOLE_ENABLE
|
||||
if (debug_mouse) {
|
||||
print_byte(data.motion);
|
||||
print_byte(data.dx);
|
||||
print_byte(data.mdx);
|
||||
print_byte(data.dy);
|
||||
print_byte(data.mdy);
|
||||
print_byte(report.motion);
|
||||
print_byte(report.dx);
|
||||
print_byte(report.mdx);
|
||||
print_byte(report.dy);
|
||||
print_byte(report.mdy);
|
||||
dprintf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
data.isMotion = (data.motion & 0x80) != 0;
|
||||
data.isOnSurface = (data.motion & 0x08) == 0;
|
||||
data.dx |= (data.mdx << 8);
|
||||
data.dx = data.dx * -1;
|
||||
data.dy |= (data.mdy << 8);
|
||||
data.dy = data.dy * -1;
|
||||
report.isMotion = (report.motion & 0x80) != 0;
|
||||
report.isOnSurface = (report.motion & 0x08) == 0;
|
||||
report.dx |= (report.mdx << 8);
|
||||
report.dx = report.dx * -1;
|
||||
report.dy |= (report.mdy << 8);
|
||||
report.dy = report.dy * -1;
|
||||
|
||||
spi_stop();
|
||||
|
||||
if (data.motion & 0b111) { // panic recovery, sometimes burst mode works weird.
|
||||
_inBurst = false;
|
||||
}
|
||||
|
||||
return data;
|
||||
return report;
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "report.h"
|
||||
#include "spi_master.h"
|
||||
|
||||
#ifndef PMW3360_CPI
|
||||
# define PMW3360_CPI 1600
|
||||
@@ -58,21 +56,6 @@
|
||||
# error "No chip select pin defined -- missing PMW3360_CS_PIN"
|
||||
#endif
|
||||
|
||||
/*
|
||||
The pmw33660 and pmw3389 use the same registers and timing and such.
|
||||
The only differences between the two is the firmware used, and the
|
||||
range for the DPI. So add a semi-secret hack to allow use of the
|
||||
pmw3389's firmware blob. Also, can set the max cpi range too.
|
||||
This should work for the 3390 and 3391 too, in theory.
|
||||
*/
|
||||
#ifndef PMW3360_FIRMWARE_H
|
||||
# define PMW3360_FIRMWARE_H "pmw3360_firmware.h"
|
||||
#endif
|
||||
|
||||
#ifdef CONSOLE_ENABLE
|
||||
void print_byte(uint8_t byte);
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int8_t motion;
|
||||
bool isMotion; // True if a motion is detected.
|
||||
@@ -83,16 +66,10 @@ typedef struct {
|
||||
int8_t mdy;
|
||||
} report_pmw3360_t;
|
||||
|
||||
bool spi_start_adv(void);
|
||||
void spi_stop_adv(void);
|
||||
spi_status_t spi_write_adv(uint8_t reg_addr, uint8_t data);
|
||||
uint8_t spi_read_adv(uint8_t reg_addr);
|
||||
bool pmw3360_init(void);
|
||||
void pmw3360_set_cpi(uint16_t cpi);
|
||||
uint16_t pmw3360_get_cpi(void);
|
||||
void pmw3360_upload_firmware(void);
|
||||
bool pmw3360_check_signature(void);
|
||||
bool pmw3360_init(void);
|
||||
void pmw3360_upload_firmware(void);
|
||||
bool pmw3360_check_signature(void);
|
||||
uint16_t pmw3360_get_cpi(void);
|
||||
void pmw3360_set_cpi(uint16_t cpi);
|
||||
/* Reads and clears the current delta values on the sensor */
|
||||
report_pmw3360_t pmw3360_read_burst(void);
|
||||
|
||||
#define degToRad(angleInDegrees) ((angleInDegrees)*M_PI / 180.0)
|
||||
#define radToDeg(angleInRadians) ((angleInRadians)*180.0 / M_PI)
|
||||
|
||||
@@ -0,0 +1,292 @@
|
||||
/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
|
||||
* Copyright 2019 Sunjun Kim
|
||||
* Copyright 2020 Ploopy Corporation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "spi_master.h"
|
||||
#include "pmw3389.h"
|
||||
#include "wait.h"
|
||||
#include "debug.h"
|
||||
#include "print.h"
|
||||
#include "pmw3389_firmware.h"
|
||||
|
||||
// Registers
|
||||
// clang-format off
|
||||
#define REG_Product_ID 0x00
|
||||
#define REG_Revision_ID 0x01
|
||||
#define REG_Motion 0x02
|
||||
#define REG_Delta_X_L 0x03
|
||||
#define REG_Delta_X_H 0x04
|
||||
#define REG_Delta_Y_L 0x05
|
||||
#define REG_Delta_Y_H 0x06
|
||||
#define REG_SQUAL 0x07
|
||||
#define REG_RawData_Sum 0x08
|
||||
#define REG_Maximum_RawData 0x09
|
||||
#define REG_Minimum_RawData 0x0a
|
||||
#define REG_Shutter_Lower 0x0b
|
||||
#define REG_Shutter_Upper 0x0c
|
||||
#define REG_Ripple_Control 0x0d
|
||||
#define REG_Resolution_L 0x0e
|
||||
#define REG_Resolution_H 0x0f
|
||||
#define REG_Config2 0x10
|
||||
#define REG_Angle_Tune 0x11
|
||||
#define REG_Frame_Capture 0x12
|
||||
#define REG_SROM_Enable 0x13
|
||||
#define REG_Run_Downshift 0x14
|
||||
#define REG_Rest1_Rate_Lower 0x15
|
||||
#define REG_Rest1_Rate_Upper 0x16
|
||||
#define REG_Rest1_Downshift 0x17
|
||||
#define REG_Rest2_Rate_Lower 0x18
|
||||
#define REG_Rest2_Rate_Upper 0x19
|
||||
#define REG_Rest2_Downshift 0x1a
|
||||
#define REG_Rest3_Rate_Lower 0x1b
|
||||
#define REG_Rest3_Rate_Upper 0x1c
|
||||
#define REG_Observation 0x24
|
||||
#define REG_Data_Out_Lower 0x25
|
||||
#define REG_Data_Out_Upper 0x26
|
||||
#define REG_SROM_ID 0x2a
|
||||
#define REG_Min_SQ_Run 0x2b
|
||||
#define REG_RawData_Threshold 0x2c
|
||||
#define REG_Control2 0x2d
|
||||
#define REG_Config5_L 0x2e
|
||||
#define REG_Config5_H 0x2f
|
||||
#define REG_Power_Up_Reset 0X3a
|
||||
#define REG_Shutdown 0x3b
|
||||
#define REG_Inverse_Product_ID 0x3f
|
||||
#define REG_LiftCutoff_Cal3 0x41
|
||||
#define REG_Angle_Snap 0x42
|
||||
#define REG_LiftCutoff_Cal1 0x4a
|
||||
#define REG_Motion_Burst 0x50
|
||||
#define REG_SROM_Load_Burst 0x62
|
||||
#define REG_Lift_Config 0x63
|
||||
#define REG_RawData_Burst 0x64
|
||||
#define REG_LiftCutoff_Cal2 0x65
|
||||
#define REG_LiftCutoff_Cal_Timeout 0x71
|
||||
#define REG_LiftCutoff_Cal_Min_Length 0x72
|
||||
#define REG_PWM_Period_Cnt 0x73
|
||||
#define REG_PWM_Width_Cnt 0x74
|
||||
|
||||
#define CPI_STEP 50
|
||||
// clang-format on
|
||||
|
||||
// limits to 0--319, resulting in a CPI range of 50 -- 16000 (as only steps of 50 are possible).
|
||||
#ifndef MAX_CPI
|
||||
# define MAX_CPI 0x013f
|
||||
#endif
|
||||
|
||||
bool _inBurst = false;
|
||||
|
||||
#ifdef CONSOLE_ENABLE
|
||||
void print_byte(uint8_t byte) { dprintf("%c%c%c%c%c%c%c%c|", (byte & 0x80 ? '1' : '0'), (byte & 0x40 ? '1' : '0'), (byte & 0x20 ? '1' : '0'), (byte & 0x10 ? '1' : '0'), (byte & 0x08 ? '1' : '0'), (byte & 0x04 ? '1' : '0'), (byte & 0x02 ? '1' : '0'), (byte & 0x01 ? '1' : '0')); }
|
||||
#endif
|
||||
#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
|
||||
|
||||
bool pmw3389_spi_start(void) {
|
||||
bool status = spi_start(PMW3389_CS_PIN, PMW3389_SPI_LSBFIRST, PMW3389_SPI_MODE, PMW3389_SPI_DIVISOR);
|
||||
// tNCS-SCLK, 120ns
|
||||
wait_us(1);
|
||||
return status;
|
||||
}
|
||||
|
||||
spi_status_t pmw3389_write(uint8_t reg_addr, uint8_t data) {
|
||||
pmw3389_spi_start();
|
||||
|
||||
if (reg_addr != REG_Motion_Burst) {
|
||||
_inBurst = false;
|
||||
}
|
||||
|
||||
// send address of the register, with MSBit = 1 to indicate it's a write
|
||||
spi_status_t status = spi_write(reg_addr | 0x80);
|
||||
status = spi_write(data);
|
||||
|
||||
// tSCLK-NCS for write operation is 35 us
|
||||
wait_us(35);
|
||||
spi_stop();
|
||||
|
||||
// tSWW/tSWR (=180us) minus tSCLK-NCS. Could be shortened, but is looks like a safe lower bound
|
||||
wait_us(145);
|
||||
return status;
|
||||
}
|
||||
|
||||
uint8_t pmw3389_read(uint8_t reg_addr) {
|
||||
pmw3389_spi_start();
|
||||
// send adress of the register, with MSBit = 0 to indicate it's a read
|
||||
spi_write(reg_addr & 0x7f);
|
||||
// tSRAD (=160us)
|
||||
wait_us(160);
|
||||
uint8_t data = spi_read();
|
||||
|
||||
// tSCLK-NCS, 120ns
|
||||
wait_us(1);
|
||||
spi_stop();
|
||||
|
||||
// tSRW/tSRR (=20us) minus tSCLK-NCS
|
||||
wait_us(19);
|
||||
return data;
|
||||
}
|
||||
|
||||
bool pmw3389_init(void) {
|
||||
setPinOutput(PMW3389_CS_PIN);
|
||||
|
||||
spi_init();
|
||||
_inBurst = false;
|
||||
|
||||
spi_stop();
|
||||
pmw3389_spi_start();
|
||||
spi_stop();
|
||||
|
||||
pmw3389_write(REG_Shutdown, 0xb6); // Shutdown first
|
||||
wait_ms(300);
|
||||
|
||||
pmw3389_spi_start();
|
||||
wait_us(40);
|
||||
spi_stop();
|
||||
wait_us(40);
|
||||
|
||||
// power up, need to first drive NCS high then low, see above.
|
||||
pmw3389_write(REG_Power_Up_Reset, 0x5a);
|
||||
wait_ms(50);
|
||||
|
||||
// read registers and discard
|
||||
pmw3389_read(REG_Motion);
|
||||
pmw3389_read(REG_Delta_X_L);
|
||||
pmw3389_read(REG_Delta_X_H);
|
||||
pmw3389_read(REG_Delta_Y_L);
|
||||
pmw3389_read(REG_Delta_Y_H);
|
||||
|
||||
pmw3389_upload_firmware();
|
||||
|
||||
spi_stop();
|
||||
|
||||
wait_ms(10);
|
||||
pmw3389_set_cpi(PMW3389_CPI);
|
||||
|
||||
wait_ms(1);
|
||||
|
||||
pmw3389_write(REG_Config2, 0x00);
|
||||
|
||||
pmw3389_write(REG_Angle_Tune, constrain(ROTATIONAL_TRANSFORM_ANGLE, -127, 127));
|
||||
|
||||
pmw3389_write(REG_Lift_Config, PMW3389_LIFTOFF_DISTANCE);
|
||||
|
||||
bool init_success = pmw3389_check_signature();
|
||||
#ifdef CONSOLE_ENABLE
|
||||
if (init_success) {
|
||||
dprintf("pmw3389 signature verified");
|
||||
} else {
|
||||
dprintf("pmw3389 signature verification failed!");
|
||||
}
|
||||
#endif
|
||||
|
||||
writePinLow(PMW3389_CS_PIN);
|
||||
|
||||
return init_success;
|
||||
}
|
||||
|
||||
void pmw3389_upload_firmware(void) {
|
||||
// Datasheet claims we need to disable REST mode first, but during startup
|
||||
// it's already disabled and we're not turning it on ...
|
||||
// pmw3389_write(REG_Config2, 0x00); // disable REST mode
|
||||
pmw3389_write(REG_SROM_Enable, 0x1d);
|
||||
|
||||
wait_ms(10);
|
||||
|
||||
pmw3389_write(REG_SROM_Enable, 0x18);
|
||||
|
||||
pmw3389_spi_start();
|
||||
spi_write(REG_SROM_Load_Burst | 0x80);
|
||||
wait_us(15);
|
||||
|
||||
for (uint16_t i = 0; i < FIRMWARE_LENGTH; i++) {
|
||||
spi_write(pgm_read_byte(firmware_data + i));
|
||||
#ifndef PMW3389_FIRMWARE_UPLOAD_FAST
|
||||
wait_us(15);
|
||||
#endif
|
||||
}
|
||||
wait_us(200);
|
||||
|
||||
pmw3389_read(REG_SROM_ID);
|
||||
pmw3389_write(REG_Config2, 0x00);
|
||||
}
|
||||
|
||||
bool pmw3389_check_signature(void) {
|
||||
uint8_t pid = pmw3389_read(REG_Product_ID);
|
||||
uint8_t iv_pid = pmw3389_read(REG_Inverse_Product_ID);
|
||||
uint8_t SROM_ver = pmw3389_read(REG_SROM_ID);
|
||||
return (pid == firmware_signature[0] && iv_pid == firmware_signature[1] && SROM_ver == firmware_signature[2]); // signature for SROM 0x04
|
||||
}
|
||||
|
||||
uint16_t pmw3389_get_cpi(void) {
|
||||
uint16_t cpival = (pmw3389_read(REG_Resolution_H) << 8) | pmw3389_read(REG_Resolution_L);
|
||||
return (uint16_t)((cpival + 1) & 0xffff) * CPI_STEP;
|
||||
}
|
||||
|
||||
void pmw3389_set_cpi(uint16_t cpi) {
|
||||
uint16_t cpival = constrain((cpi / CPI_STEP) - 1, 0, MAX_CPI);
|
||||
// Sets upper byte first for more consistent setting of cpi
|
||||
pmw3389_write(REG_Resolution_H, (cpival >> 8) & 0xff);
|
||||
pmw3389_write(REG_Resolution_L, cpival & 0xff);
|
||||
}
|
||||
|
||||
report_pmw3389_t pmw3389_read_burst(void) {
|
||||
report_pmw3389_t report = {0};
|
||||
|
||||
if (!_inBurst) {
|
||||
#ifdef CONSOLE_ENABLE
|
||||
dprintf("burst on");
|
||||
#endif
|
||||
pmw3389_write(REG_Motion_Burst, 0x00);
|
||||
_inBurst = true;
|
||||
}
|
||||
|
||||
pmw3389_spi_start();
|
||||
spi_write(REG_Motion_Burst);
|
||||
wait_us(35); // waits for tSRAD_MOTBR
|
||||
|
||||
report.motion = spi_read();
|
||||
spi_read(); // skip Observation
|
||||
// delta registers
|
||||
report.dx = spi_read();
|
||||
report.mdx = spi_read();
|
||||
report.dy = spi_read();
|
||||
report.mdy = spi_read();
|
||||
|
||||
if (report.motion & 0b111) { // panic recovery, sometimes burst mode works weird.
|
||||
_inBurst = false;
|
||||
}
|
||||
|
||||
spi_stop();
|
||||
|
||||
#ifdef CONSOLE_ENABLE
|
||||
if (debug_mouse) {
|
||||
print_byte(report.motion);
|
||||
print_byte(report.dx);
|
||||
print_byte(report.mdx);
|
||||
print_byte(report.dy);
|
||||
print_byte(report.mdy);
|
||||
dprintf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
report.isMotion = (report.motion & 0x80) != 0;
|
||||
report.isOnSurface = (report.motion & 0x08) == 0;
|
||||
report.dx |= (report.mdx << 8);
|
||||
report.dx = report.dx * -1;
|
||||
report.dy |= (report.mdy << 8);
|
||||
report.dy = report.dy * -1;
|
||||
|
||||
return report;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/* Copyright 2021 Alabastard (@Alabastard-64)
|
||||
* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
|
||||
* Copyright 2019 Sunjun Kim
|
||||
* Copyright 2020 Ploopy Corporation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef PMW3389_CPI
|
||||
# define PMW3389_CPI 2000
|
||||
#endif
|
||||
|
||||
#ifndef PMW3389_CLOCK_SPEED
|
||||
# define PMW3389_CLOCK_SPEED 2000000
|
||||
#endif
|
||||
|
||||
#ifndef PMW3389_SPI_LSBFIRST
|
||||
# define PMW3389_SPI_LSBFIRST false
|
||||
#endif
|
||||
|
||||
#ifndef PMW3389_SPI_MODE
|
||||
# define PMW3389_SPI_MODE 3
|
||||
#endif
|
||||
|
||||
#ifndef PMW3389_SPI_DIVISOR
|
||||
# ifdef __AVR__
|
||||
# define PMW3389_SPI_DIVISOR (F_CPU / PMW3389_CLOCK_SPEED)
|
||||
# else
|
||||
# define PMW3389_SPI_DIVISOR 64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef PMW3389_LIFTOFF_DISTANCE
|
||||
# define PMW3389_LIFTOFF_DISTANCE 0x02
|
||||
#endif
|
||||
|
||||
#ifndef ROTATIONAL_TRANSFORM_ANGLE
|
||||
# define ROTATIONAL_TRANSFORM_ANGLE 0x00
|
||||
#endif
|
||||
|
||||
#ifndef PMW3389_CS_PIN
|
||||
# error "No chip select pin defined -- missing PMW3389_CS_PIN"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int8_t motion;
|
||||
bool isMotion; // True if a motion is detected.
|
||||
bool isOnSurface; // True when a chip is on a surface
|
||||
int16_t dx; // displacement on x directions. Unit: Count. (CPI * Count = Inch value)
|
||||
int8_t mdx;
|
||||
int16_t dy; // displacement on y directions.
|
||||
int8_t mdy;
|
||||
} report_pmw3389_t;
|
||||
|
||||
bool pmw3389_init(void);
|
||||
void pmw3389_upload_firmware(void);
|
||||
bool pmw3389_check_signature(void);
|
||||
uint16_t pmw3389_get_cpi(void);
|
||||
void pmw3389_set_cpi(uint16_t cpi);
|
||||
/* Reads and clears the current delta values on the sensor */
|
||||
report_pmw3389_t pmw3389_read_burst(void);
|
||||
+282
-278
@@ -18,286 +18,290 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "progmem.h"
|
||||
|
||||
// PID, Inverse PID, SROM version
|
||||
const uint8_t firmware_signature[] PROGMEM = {0x42, 0xBD, 0x04};
|
||||
|
||||
// clang-format off
|
||||
// Firmware Blob foor PMW3389
|
||||
const uint16_t firmware_length = 4094;
|
||||
// clang-format off
|
||||
const uint8_t firmware_data[] PROGMEM = { // SROM 0x04
|
||||
0x01, 0xe8, 0xba, 0x26, 0x0b, 0xb2, 0xbe, 0xfe, 0x7e, 0x5f, 0x3c, 0xdb, 0x15, 0xa8, 0xb3,
|
||||
0xe4, 0x2b, 0xb5, 0xe8, 0x53, 0x07, 0x6d, 0x3b, 0xd1, 0x20, 0xc2, 0x06, 0x6f, 0x3d, 0xd9,
|
||||
0x11, 0xa0, 0xc2, 0xe7, 0x2d, 0xb9, 0xd1, 0x20, 0xa3, 0xa5, 0xc8, 0xf3, 0x64, 0x4a, 0xf7,
|
||||
0x4d, 0x18, 0x93, 0xa4, 0xca, 0xf7, 0x6c, 0x5a, 0x36, 0xee, 0x5e, 0x3e, 0xfe, 0x7e, 0x7e,
|
||||
0x5f, 0x1d, 0x99, 0xb0, 0xc3, 0xe5, 0x29, 0xd3, 0x03, 0x65, 0x48, 0x12, 0x87, 0x6d, 0x58,
|
||||
0x32, 0xe6, 0x2f, 0xdc, 0x3a, 0xf2, 0x4f, 0xfd, 0x59, 0x11, 0x81, 0x61, 0x21, 0xc0, 0x02,
|
||||
0x86, 0x8e, 0x7f, 0x5d, 0x38, 0xf2, 0x47, 0x0c, 0x7b, 0x55, 0x28, 0xb3, 0xe4, 0x4a, 0x16,
|
||||
0xab, 0xbf, 0xdd, 0x38, 0xf2, 0x66, 0x4e, 0xff, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xa5, 0xc8,
|
||||
0x12, 0xa6, 0xaf, 0xdc, 0x3a, 0xd1, 0x41, 0x60, 0x75, 0x58, 0x24, 0x92, 0xd4, 0x72, 0x6c,
|
||||
0xe0, 0x2f, 0xfd, 0x23, 0x8d, 0x1c, 0x5b, 0xb2, 0x97, 0x36, 0x3d, 0x0b, 0xa2, 0x49, 0xb1,
|
||||
0x58, 0xf2, 0x1f, 0xc0, 0xcb, 0xf8, 0x41, 0x4f, 0xcd, 0x1e, 0x6b, 0x39, 0xa7, 0x2b, 0xe9,
|
||||
0x30, 0x16, 0x83, 0xd2, 0x0e, 0x47, 0x8f, 0xe3, 0xb1, 0xdf, 0xa2, 0x15, 0xdb, 0x5d, 0x30,
|
||||
0xc5, 0x1a, 0xab, 0x31, 0x99, 0xf3, 0xfa, 0xb2, 0x86, 0x69, 0xad, 0x7a, 0xe8, 0xa7, 0x18,
|
||||
0x6a, 0xcc, 0xc8, 0x65, 0x23, 0x87, 0xa8, 0x5f, 0xf5, 0x21, 0x59, 0x75, 0x09, 0x71, 0x45,
|
||||
0x55, 0x25, 0x4b, 0xda, 0xa1, 0xc3, 0xf7, 0x41, 0xab, 0x59, 0xd9, 0x74, 0x12, 0x55, 0x5f,
|
||||
0xbc, 0xaf, 0xd9, 0xfd, 0xb0, 0x1e, 0xa3, 0x0f, 0xff, 0xde, 0x11, 0x16, 0x6a, 0xae, 0x0e,
|
||||
0xe1, 0x5d, 0x3c, 0x10, 0x43, 0x9a, 0xa1, 0x0b, 0x24, 0x8f, 0x0d, 0x7f, 0x0b, 0x5e, 0x4c,
|
||||
0x42, 0xa4, 0x84, 0x2c, 0x40, 0xd0, 0x55, 0x39, 0xe6, 0x4b, 0xf8, 0x9b, 0x2f, 0xdc, 0x28,
|
||||
0xff, 0xfa, 0xb5, 0x85, 0x19, 0xe5, 0x28, 0xa1, 0x77, 0xaa, 0x73, 0xf3, 0x03, 0xc7, 0x62,
|
||||
0xa6, 0x91, 0x18, 0xc9, 0xb0, 0xcd, 0x05, 0xdc, 0xca, 0x81, 0x26, 0x1a, 0x47, 0x40, 0xda,
|
||||
0x36, 0x7d, 0x6a, 0x53, 0xc8, 0x5a, 0x77, 0x5d, 0x19, 0xa4, 0x1b, 0x23, 0x83, 0xd0, 0xb2,
|
||||
0xaa, 0x0e, 0xbf, 0x77, 0x4e, 0x3a, 0x3b, 0x59, 0x00, 0x31, 0x0d, 0x02, 0x1b, 0x88, 0x7a,
|
||||
0xd4, 0xbd, 0x9d, 0xcc, 0x58, 0x04, 0x69, 0xf6, 0x3b, 0xca, 0x42, 0xe2, 0xfd, 0xc3, 0x3d,
|
||||
0x39, 0xc5, 0xd0, 0x71, 0xe4, 0xc8, 0xb7, 0x3e, 0x3f, 0xc8, 0xe9, 0xca, 0xc9, 0x3f, 0x04,
|
||||
0x4e, 0x1b, 0x79, 0xca, 0xa5, 0x61, 0xc2, 0xed, 0x1d, 0xa6, 0xda, 0x5a, 0xe9, 0x7f, 0x65,
|
||||
0x8c, 0xbe, 0x12, 0x6e, 0xa4, 0x5b, 0x33, 0x2f, 0x84, 0x28, 0x9c, 0x1c, 0x88, 0x2d, 0xff,
|
||||
0x07, 0xbf, 0xa6, 0xd7, 0x5a, 0x88, 0x86, 0xb0, 0x3f, 0xf6, 0x31, 0x5b, 0x11, 0x6d, 0xf5,
|
||||
0x58, 0xeb, 0x58, 0x02, 0x9e, 0xb5, 0x9a, 0xb1, 0xff, 0x25, 0x9d, 0x8b, 0x4f, 0xb6, 0x0a,
|
||||
0xf9, 0xea, 0x3e, 0x3f, 0x21, 0x09, 0x65, 0x21, 0x22, 0xfe, 0x3d, 0x4e, 0x11, 0x5b, 0x9e,
|
||||
0x5a, 0x59, 0x8b, 0xdd, 0xd8, 0xce, 0xd6, 0xd9, 0x59, 0xd2, 0x1e, 0xfd, 0xef, 0x0d, 0x1b,
|
||||
0xd9, 0x61, 0x7f, 0xd7, 0x2d, 0xad, 0x62, 0x09, 0xe5, 0x22, 0x63, 0xea, 0xc7, 0x31, 0xd9,
|
||||
0xa1, 0x38, 0x80, 0x5c, 0xa7, 0x32, 0x82, 0xec, 0x1b, 0xa2, 0x49, 0x5a, 0x06, 0xd2, 0x7c,
|
||||
0xc9, 0x96, 0x57, 0xbb, 0x17, 0x75, 0xfc, 0x7a, 0x8f, 0x0d, 0x77, 0xb5, 0x7a, 0x8e, 0x3e,
|
||||
0xf4, 0xba, 0x2f, 0x69, 0x13, 0x26, 0xd6, 0xd9, 0x21, 0x60, 0x2f, 0x21, 0x3e, 0x87, 0xee,
|
||||
0xfd, 0x87, 0x16, 0x0d, 0xc8, 0x08, 0x00, 0x25, 0x71, 0xac, 0x2c, 0x03, 0x2a, 0x37, 0x2d,
|
||||
0xb3, 0x34, 0x09, 0x91, 0xe3, 0x06, 0x2c, 0x38, 0x37, 0x95, 0x3b, 0x17, 0x7a, 0xaf, 0xac,
|
||||
0x99, 0x55, 0xab, 0x41, 0x39, 0x5f, 0x8e, 0xa6, 0x43, 0x80, 0x03, 0x88, 0x6f, 0x7d, 0xbd,
|
||||
0x5a, 0xb4, 0x2b, 0x32, 0x23, 0x5a, 0xa9, 0x31, 0x32, 0x39, 0x4c, 0x5b, 0xf4, 0x6b, 0xaf,
|
||||
0x66, 0x6f, 0x3c, 0x8e, 0x2d, 0x82, 0x97, 0x9f, 0x4a, 0x01, 0xdc, 0x99, 0x98, 0x00, 0xec,
|
||||
0x38, 0x7a, 0x79, 0x70, 0xa6, 0x85, 0xd6, 0x21, 0x63, 0x0d, 0x45, 0x9a, 0x2e, 0x5e, 0xa7,
|
||||
0xb1, 0xea, 0x66, 0x6a, 0xbc, 0x62, 0x2d, 0x7b, 0x7d, 0x85, 0xea, 0x95, 0x2f, 0xc0, 0xe8,
|
||||
0x6f, 0x35, 0xa0, 0x3a, 0x02, 0x25, 0xbc, 0xb2, 0x5f, 0x5c, 0x43, 0x96, 0xcc, 0x26, 0xd2,
|
||||
0x16, 0xb4, 0x96, 0x73, 0xd7, 0x13, 0xc7, 0xae, 0x53, 0x15, 0x31, 0x89, 0x68, 0x66, 0x6d,
|
||||
0x2c, 0x92, 0x1f, 0xcc, 0x5b, 0xa7, 0x8f, 0x5d, 0xbb, 0xc9, 0xdb, 0xe8, 0x3b, 0x9d, 0x61,
|
||||
0x74, 0x8b, 0x05, 0xa1, 0x58, 0x52, 0x68, 0xee, 0x3d, 0x39, 0x79, 0xa0, 0x9b, 0xdd, 0xe1,
|
||||
0x55, 0xc9, 0x60, 0xeb, 0xad, 0xb8, 0x5b, 0xc2, 0x5a, 0xb5, 0x2c, 0x18, 0x55, 0xa9, 0x50,
|
||||
0xc3, 0xf6, 0x72, 0x5f, 0xcc, 0xe2, 0xf4, 0x55, 0xb5, 0xd6, 0xb5, 0x4a, 0x99, 0xa5, 0x28,
|
||||
0x74, 0x97, 0x18, 0xe8, 0xc0, 0x84, 0x89, 0x50, 0x03, 0x86, 0x4d, 0x1a, 0xb7, 0x09, 0x90,
|
||||
0xa2, 0x01, 0x04, 0xbb, 0x73, 0x62, 0xcb, 0x97, 0x22, 0x70, 0x5d, 0x52, 0x41, 0x8e, 0xd9,
|
||||
0x90, 0x15, 0xaa, 0xab, 0x0a, 0x31, 0x65, 0xb4, 0xda, 0xd0, 0xee, 0x24, 0xc9, 0x41, 0x91,
|
||||
0x1e, 0xbc, 0x46, 0x70, 0x40, 0x9d, 0xda, 0x0e, 0x2a, 0xe4, 0xb2, 0x4c, 0x9f, 0xf2, 0xfc,
|
||||
0xf3, 0x84, 0x17, 0x44, 0x1e, 0xd7, 0xca, 0x23, 0x1f, 0x3f, 0x5a, 0x22, 0x3d, 0xaf, 0x9b,
|
||||
0x2d, 0xfc, 0x41, 0xad, 0x26, 0xb4, 0x45, 0x67, 0x0b, 0x80, 0x0e, 0xf9, 0x61, 0x37, 0xec,
|
||||
0x3b, 0xf4, 0x4b, 0x14, 0xdf, 0x5a, 0x0c, 0x3a, 0x50, 0x0b, 0x14, 0x0c, 0x72, 0xae, 0xc6,
|
||||
0xc5, 0xec, 0x35, 0x53, 0x2d, 0x59, 0xed, 0x91, 0x74, 0xe2, 0xc4, 0xc8, 0xf2, 0x25, 0x6b,
|
||||
0x97, 0x6f, 0xc9, 0x76, 0xce, 0xa9, 0xb1, 0x99, 0x8f, 0x5a, 0x92, 0x3b, 0xc4, 0x8d, 0x54,
|
||||
0x50, 0x40, 0x72, 0xd6, 0x90, 0x83, 0xfc, 0xe5, 0x49, 0x8b, 0x17, 0xf5, 0xfd, 0x6b, 0x8d,
|
||||
0x32, 0x02, 0xe9, 0x0a, 0xfe, 0xbf, 0x00, 0x6b, 0xa3, 0xad, 0x5f, 0x09, 0x4b, 0x97, 0x2b,
|
||||
0x00, 0x58, 0x65, 0x2e, 0x07, 0x49, 0x0a, 0x3b, 0x6b, 0x2e, 0x50, 0x6c, 0x1d, 0xac, 0xb7,
|
||||
0x6a, 0x26, 0xd8, 0x13, 0xa4, 0xca, 0x16, 0xae, 0xab, 0x93, 0xb9, 0x1c, 0x1c, 0xb4, 0x47,
|
||||
0x6a, 0x38, 0x36, 0x17, 0x27, 0xc9, 0x7f, 0xc7, 0x64, 0xcb, 0x89, 0x58, 0xc5, 0x61, 0xc2,
|
||||
0xc6, 0xea, 0x15, 0x0b, 0x34, 0x0c, 0x5d, 0x61, 0x76, 0x6e, 0x2b, 0x62, 0x40, 0x92, 0xa3,
|
||||
0x6c, 0xef, 0xf4, 0xe4, 0xc3, 0xa1, 0xa8, 0xf5, 0x94, 0x79, 0x0d, 0xd1, 0x3d, 0xcb, 0x3d,
|
||||
0x40, 0xb6, 0xd0, 0xf0, 0x10, 0x54, 0xd8, 0x47, 0x25, 0x51, 0xc5, 0x41, 0x79, 0x00, 0xe5,
|
||||
0xa0, 0x72, 0xde, 0xbb, 0x3b, 0x62, 0x17, 0xf6, 0xbc, 0x5d, 0x00, 0x76, 0x2e, 0xa7, 0x3b,
|
||||
0xb6, 0xf1, 0x98, 0x72, 0x59, 0x2a, 0x73, 0xb0, 0x21, 0xd6, 0x49, 0xe0, 0xc0, 0xd5, 0xeb,
|
||||
0x02, 0x7d, 0x4b, 0x41, 0x28, 0x70, 0x2d, 0xec, 0x2b, 0x71, 0x1f, 0x0b, 0xb9, 0x71, 0x63,
|
||||
0x06, 0xe6, 0xbc, 0x60, 0xbb, 0xf4, 0x9a, 0x62, 0x43, 0x09, 0x18, 0x4e, 0x93, 0x06, 0x4d,
|
||||
0x76, 0xfa, 0x7f, 0xbd, 0x02, 0xe4, 0x50, 0x91, 0x12, 0xe5, 0x86, 0xff, 0x64, 0x1e, 0xaf,
|
||||
0x7e, 0xb3, 0xb2, 0xde, 0x89, 0xc1, 0xa2, 0x6f, 0x40, 0x7b, 0x41, 0x51, 0x63, 0xea, 0x25,
|
||||
0xd1, 0x97, 0x57, 0x92, 0xa8, 0x45, 0xa1, 0xa5, 0x45, 0x21, 0x43, 0x7f, 0x83, 0x15, 0x29,
|
||||
0xd0, 0x30, 0x53, 0x32, 0xb4, 0x5a, 0x17, 0x96, 0xbc, 0xc2, 0x68, 0xa9, 0xb7, 0xaf, 0xac,
|
||||
0xdf, 0xf1, 0xe3, 0x89, 0xba, 0x24, 0x79, 0x54, 0xc6, 0x14, 0x07, 0x1c, 0x1e, 0x0d, 0x3a,
|
||||
0x6b, 0xe5, 0x3d, 0x4e, 0x10, 0x60, 0x96, 0xec, 0x6c, 0xda, 0x47, 0xae, 0x03, 0x25, 0x39,
|
||||
0x1d, 0x74, 0xc8, 0xac, 0x6a, 0xf2, 0x6b, 0x05, 0x2a, 0x9a, 0xe7, 0xe8, 0x92, 0xd6, 0xc2,
|
||||
0x6d, 0xfa, 0xe8, 0xa7, 0x9d, 0x5f, 0x48, 0xc9, 0x75, 0xf1, 0x66, 0x6a, 0xdb, 0x5d, 0x9a,
|
||||
0xcd, 0x27, 0xdd, 0xb9, 0x24, 0x04, 0x9c, 0x18, 0xc2, 0x6d, 0x0c, 0x91, 0x34, 0x48, 0x42,
|
||||
0x6f, 0xe9, 0x59, 0x70, 0xc4, 0x7e, 0x81, 0x0e, 0x32, 0x0a, 0x93, 0x48, 0xb0, 0xc0, 0x15,
|
||||
0x9e, 0x05, 0xac, 0x36, 0x16, 0xcb, 0x59, 0x65, 0xa0, 0x83, 0xdf, 0x3e, 0xda, 0xfb, 0x1d,
|
||||
0x1a, 0xdb, 0x65, 0xec, 0x9a, 0xc6, 0xc3, 0x8e, 0x3c, 0x45, 0xfd, 0xc8, 0xf5, 0x1c, 0x6a,
|
||||
0x67, 0x0d, 0x8f, 0x99, 0x7d, 0x30, 0x21, 0x8c, 0xea, 0x22, 0x87, 0x65, 0xc9, 0xb2, 0x4c,
|
||||
0xe4, 0x1b, 0x46, 0xba, 0x54, 0xbd, 0x7c, 0xca, 0xd5, 0x8f, 0x5b, 0xa5, 0x01, 0x04, 0xd8,
|
||||
0x0a, 0x16, 0xbf, 0xb9, 0x50, 0x2e, 0x37, 0x2f, 0x64, 0xf3, 0x70, 0x11, 0x02, 0x05, 0x31,
|
||||
0x9b, 0xa0, 0xb2, 0x01, 0x5e, 0x4f, 0x19, 0xc9, 0xd4, 0xea, 0xa1, 0x79, 0x54, 0x53, 0xa7,
|
||||
0xde, 0x2f, 0x49, 0xd3, 0xd1, 0x63, 0xb5, 0x03, 0x15, 0x4e, 0xbf, 0x04, 0xb3, 0x26, 0x8b,
|
||||
0x20, 0xb2, 0x45, 0xcf, 0xcd, 0x5b, 0x82, 0x32, 0x88, 0x61, 0xa7, 0xa8, 0xb2, 0xa0, 0x72,
|
||||
0x96, 0xc0, 0xdb, 0x2b, 0xe2, 0x5f, 0xba, 0xe3, 0xf5, 0x8a, 0xde, 0xf1, 0x18, 0x01, 0x16,
|
||||
0x40, 0xd9, 0x86, 0x12, 0x09, 0x18, 0x1b, 0x05, 0x0c, 0xb1, 0xb5, 0x47, 0xe2, 0x43, 0xab,
|
||||
0xfe, 0x92, 0x63, 0x7e, 0x95, 0x2b, 0xf0, 0xaf, 0xe1, 0xf1, 0xc3, 0x4a, 0xff, 0x2b, 0x09,
|
||||
0xbb, 0x4a, 0x0e, 0x9a, 0xc4, 0xd8, 0x64, 0x7d, 0x83, 0xa0, 0x4f, 0x44, 0xdb, 0xc4, 0xa8,
|
||||
0x58, 0xef, 0xfc, 0x9e, 0x77, 0xf9, 0xa6, 0x8f, 0x58, 0x8b, 0x12, 0xf4, 0xe9, 0x81, 0x12,
|
||||
0x47, 0x51, 0x41, 0x83, 0xef, 0xf6, 0x73, 0xbc, 0x8e, 0x0f, 0x4c, 0x8f, 0x4e, 0x69, 0x90,
|
||||
0x77, 0x29, 0x5d, 0x92, 0xb0, 0x6d, 0x06, 0x67, 0x29, 0x60, 0xbd, 0x4b, 0x17, 0xc8, 0x89,
|
||||
0x69, 0x28, 0x29, 0xd6, 0x78, 0xcb, 0x11, 0x4c, 0xba, 0x8b, 0x68, 0xae, 0x7e, 0x9f, 0xef,
|
||||
0x95, 0xda, 0xe2, 0x9e, 0x7f, 0xe9, 0x55, 0xe5, 0xe1, 0xe2, 0xb7, 0xe6, 0x5f, 0xbb, 0x2c,
|
||||
0xa2, 0xe6, 0xee, 0xc7, 0x0a, 0x60, 0xa9, 0xd1, 0x80, 0xdf, 0x7f, 0xd6, 0x97, 0xab, 0x1d,
|
||||
0x22, 0x25, 0xfc, 0x79, 0x23, 0xe0, 0xae, 0xc5, 0xef, 0x16, 0xa4, 0xa1, 0x0f, 0x92, 0xa9,
|
||||
0xc7, 0xe3, 0x3a, 0x55, 0xdf, 0x62, 0x49, 0xd9, 0xf5, 0x84, 0x49, 0xc5, 0x90, 0x34, 0xd3,
|
||||
0xe1, 0xac, 0x99, 0x21, 0xb1, 0x02, 0x76, 0x4a, 0xfa, 0xd4, 0xbb, 0xa4, 0x9c, 0xa2, 0xe2,
|
||||
0xcb, 0x3d, 0x3b, 0x14, 0x75, 0x60, 0xd1, 0x02, 0xb4, 0xa3, 0xb4, 0x72, 0x06, 0xf9, 0x19,
|
||||
0x9c, 0xe2, 0xe4, 0xa7, 0x0f, 0x25, 0x88, 0xc6, 0x86, 0xd6, 0x8c, 0x74, 0x4e, 0x6e, 0xfc,
|
||||
0xa8, 0x48, 0x9e, 0xa7, 0x9d, 0x1a, 0x4b, 0x37, 0x09, 0xc8, 0xb0, 0x10, 0xbe, 0x6f, 0xfe,
|
||||
0xa3, 0xc4, 0x7a, 0xb5, 0x3d, 0xe8, 0x30, 0xf1, 0x0d, 0xa0, 0xb2, 0x44, 0xfc, 0x9b, 0x8c,
|
||||
0xf8, 0x61, 0xed, 0x81, 0xd1, 0x62, 0x11, 0xb4, 0xe1, 0xd5, 0x39, 0x52, 0x89, 0xd3, 0xa8,
|
||||
0x49, 0x31, 0xdf, 0xb6, 0xf9, 0x91, 0xf4, 0x1c, 0x9d, 0x09, 0x95, 0x40, 0x56, 0xe7, 0xe3,
|
||||
0xcd, 0x5c, 0x92, 0xc1, 0x1d, 0x6b, 0xe9, 0x78, 0x6f, 0x8e, 0x94, 0x42, 0x66, 0xa2, 0xaa,
|
||||
0xd3, 0xc8, 0x2e, 0xe3, 0xf6, 0x07, 0x72, 0x0b, 0x6b, 0x1e, 0x7b, 0xb9, 0x7c, 0xe0, 0xa0,
|
||||
0xbc, 0xd9, 0x25, 0xdf, 0x87, 0xa8, 0x5f, 0x9c, 0xcc, 0xf0, 0xdb, 0x42, 0x8e, 0x07, 0x31,
|
||||
0x13, 0x01, 0x66, 0x32, 0xd1, 0xb8, 0xd6, 0xe3, 0x5e, 0x12, 0x76, 0x61, 0xd3, 0x38, 0x89,
|
||||
0xe6, 0x17, 0x6f, 0xa5, 0xf2, 0x71, 0x0e, 0xa5, 0xe2, 0x88, 0x30, 0xbb, 0xbe, 0x8a, 0xea,
|
||||
0xc7, 0x62, 0xc4, 0xcf, 0xb8, 0xcd, 0x33, 0x8d, 0x3d, 0x3e, 0xb5, 0x60, 0x3a, 0x03, 0x92,
|
||||
0xe4, 0x6d, 0x1b, 0xe0, 0xb4, 0x84, 0x08, 0x55, 0x88, 0xa7, 0x3a, 0xb9, 0x3d, 0x43, 0xc3,
|
||||
0xc0, 0xfa, 0x07, 0x6a, 0xca, 0x94, 0xad, 0x99, 0x55, 0xf1, 0xf1, 0xc0, 0x23, 0x87, 0x1d,
|
||||
0x3d, 0x1c, 0xd1, 0x66, 0xa0, 0x57, 0x10, 0x52, 0xa2, 0x7f, 0xbe, 0xf9, 0x88, 0xb6, 0x02,
|
||||
0xbf, 0x08, 0x23, 0xa9, 0x0c, 0x63, 0x17, 0x2a, 0xae, 0xf5, 0xf7, 0xb7, 0x21, 0x83, 0x92,
|
||||
0x31, 0x23, 0x0d, 0x20, 0xc3, 0xc2, 0x05, 0x21, 0x62, 0x8e, 0x45, 0xe8, 0x14, 0xc1, 0xda,
|
||||
0x75, 0xb8, 0xf8, 0x92, 0x01, 0xd0, 0x5d, 0x18, 0x9f, 0x99, 0x11, 0x19, 0xf5, 0x35, 0xe8,
|
||||
0x7f, 0x20, 0x88, 0x8c, 0x05, 0x75, 0xf5, 0xd7, 0x40, 0x17, 0xbb, 0x1e, 0x36, 0x52, 0xd9,
|
||||
0xa4, 0x9c, 0xc2, 0x9d, 0x42, 0x81, 0xd8, 0xc7, 0x8a, 0xe7, 0x4c, 0x81, 0xe0, 0xb7, 0x57,
|
||||
0xed, 0x48, 0x8b, 0xf0, 0x97, 0x15, 0x61, 0xd9, 0x2c, 0x7c, 0x45, 0xaf, 0xc2, 0xcd, 0xfc,
|
||||
0xaa, 0x13, 0xad, 0x59, 0xcc, 0xb2, 0xb2, 0x6e, 0xdd, 0x63, 0x9c, 0x32, 0x0f, 0xec, 0x83,
|
||||
0xbe, 0x78, 0xac, 0x91, 0x44, 0x1a, 0x1f, 0xea, 0xfd, 0x5d, 0x8e, 0xb4, 0xc0, 0x84, 0xd4,
|
||||
0xac, 0xb4, 0x87, 0x5f, 0xac, 0xef, 0xdf, 0xcd, 0x12, 0x56, 0xc8, 0xcd, 0xfe, 0xc5, 0xda,
|
||||
0xd3, 0xc1, 0x69, 0xf3, 0x61, 0x05, 0xea, 0x25, 0xe2, 0x12, 0x05, 0x8f, 0x39, 0x08, 0x08,
|
||||
0x7c, 0x37, 0xb6, 0x7e, 0x5b, 0xd8, 0xb1, 0x0e, 0xf2, 0xdb, 0x4b, 0xf1, 0xad, 0x90, 0x01,
|
||||
0x57, 0xcd, 0xa0, 0xb4, 0x52, 0xe8, 0xf3, 0xd7, 0x8a, 0xbd, 0x4f, 0x9f, 0x21, 0x40, 0x72,
|
||||
0xa4, 0xfc, 0x0b, 0x01, 0x2b, 0x2f, 0xb6, 0x4c, 0x95, 0x2d, 0x35, 0x33, 0x41, 0x6b, 0xa0,
|
||||
0x93, 0xe7, 0x2c, 0xf2, 0xd3, 0x72, 0x8b, 0xf4, 0x4f, 0x15, 0x3c, 0xaf, 0xd6, 0x12, 0xde,
|
||||
0x3f, 0x83, 0x3f, 0xff, 0xf8, 0x7f, 0xf6, 0xcc, 0xa6, 0x7f, 0xc9, 0x9a, 0x6e, 0x1f, 0xc1,
|
||||
0x0c, 0xfb, 0xee, 0x9c, 0xe7, 0xaf, 0xc9, 0x26, 0x54, 0xef, 0xb0, 0x39, 0xef, 0xb2, 0xe9,
|
||||
0x23, 0xc4, 0xef, 0xd1, 0xa1, 0xa4, 0x25, 0x24, 0x6f, 0x8d, 0x6a, 0xe5, 0x8a, 0x32, 0x3a,
|
||||
0xaf, 0xfc, 0xda, 0xce, 0x18, 0x25, 0x42, 0x07, 0x4d, 0x45, 0x8b, 0xdf, 0x85, 0xcf, 0x55,
|
||||
0xb2, 0x24, 0xfe, 0x9c, 0x69, 0x74, 0xa7, 0x6e, 0xa0, 0xce, 0xc0, 0x39, 0xf4, 0x86, 0xc6,
|
||||
0x8d, 0xae, 0xb9, 0x48, 0x64, 0x13, 0x0b, 0x40, 0x81, 0xa2, 0xc9, 0xa8, 0x85, 0x51, 0xee,
|
||||
0x9f, 0xcf, 0xa2, 0x8c, 0x19, 0x52, 0x48, 0xe2, 0xc1, 0xa8, 0x58, 0xb4, 0x10, 0x24, 0x06,
|
||||
0x58, 0x51, 0xfc, 0xb9, 0x12, 0xec, 0xfd, 0x73, 0xb4, 0x6d, 0x84, 0xfa, 0x06, 0x8b, 0x05,
|
||||
0x0b, 0x2d, 0xd6, 0xd6, 0x1f, 0x29, 0x82, 0x9f, 0x19, 0x12, 0x1e, 0xb2, 0x04, 0x8f, 0x7f,
|
||||
0x4d, 0xbd, 0x30, 0x2e, 0xe3, 0xe0, 0x88, 0x29, 0xc5, 0x93, 0xd6, 0x6c, 0x1f, 0x29, 0x45,
|
||||
0x91, 0xa7, 0x58, 0xcd, 0x05, 0x17, 0xd6, 0x6d, 0xb3, 0xca, 0x66, 0xcc, 0x3c, 0x4a, 0x74,
|
||||
0xfd, 0x08, 0x10, 0xa6, 0x99, 0x92, 0x10, 0xd2, 0x85, 0xab, 0x6e, 0x1d, 0x0e, 0x8b, 0x26,
|
||||
0x46, 0xd1, 0x6c, 0x84, 0xc0, 0x26, 0x43, 0x59, 0x68, 0xf0, 0x13, 0x1d, 0xfb, 0xe3, 0xd1,
|
||||
0xd2, 0xb4, 0x71, 0x9e, 0xf2, 0x59, 0x6a, 0x33, 0x29, 0x79, 0xd2, 0xd7, 0x26, 0xf1, 0xae,
|
||||
0x78, 0x9e, 0x1f, 0x0f, 0x3f, 0xe3, 0xe8, 0xd0, 0x27, 0x78, 0x77, 0xf6, 0xac, 0x9c, 0x56,
|
||||
0x39, 0x73, 0x8a, 0x6b, 0x2f, 0x34, 0x78, 0xb1, 0x11, 0xdb, 0xa4, 0x5c, 0x80, 0x01, 0x71,
|
||||
0x6a, 0xc2, 0xd1, 0x2e, 0x5e, 0x76, 0x28, 0x70, 0x93, 0xae, 0x3e, 0x78, 0xb0, 0x1f, 0x0f,
|
||||
0xda, 0xbf, 0xfb, 0x8a, 0x67, 0x65, 0x4f, 0x91, 0xed, 0x49, 0x75, 0x78, 0x62, 0xa2, 0x93,
|
||||
0xb5, 0x70, 0x7f, 0x4d, 0x08, 0x4e, 0x79, 0x61, 0xa8, 0x5f, 0x7f, 0xb4, 0x65, 0x9f, 0x91,
|
||||
0x54, 0x3a, 0xe8, 0x50, 0x33, 0xd3, 0xd5, 0x8a, 0x7c, 0xf3, 0x9e, 0x8b, 0x77, 0x7b, 0xc6,
|
||||
0xc6, 0x0c, 0x45, 0x95, 0x1f, 0xb0, 0xd0, 0x0b, 0x27, 0x4a, 0xfd, 0xc7, 0xf7, 0x0d, 0x5a,
|
||||
0x43, 0xc9, 0x7d, 0x35, 0xb0, 0x7d, 0xc4, 0x9c, 0x57, 0x1e, 0x76, 0x0d, 0xf1, 0x95, 0x30,
|
||||
0x71, 0xcc, 0xb3, 0x66, 0x3b, 0x63, 0xa8, 0x6c, 0xa3, 0x43, 0xa0, 0x24, 0xcc, 0xb7, 0x53,
|
||||
0xfe, 0xfe, 0xbc, 0x6e, 0x60, 0x89, 0xaf, 0x16, 0x21, 0xc8, 0x91, 0x6a, 0x89, 0xce, 0x80,
|
||||
0x2c, 0xf1, 0x59, 0xce, 0xc3, 0x60, 0x61, 0x3b, 0x0b, 0x19, 0xfe, 0x99, 0xac, 0x65, 0x90,
|
||||
0x15, 0x12, 0x05, 0xac, 0x7e, 0xff, 0x98, 0x7b, 0x66, 0x64, 0x0e, 0x4b, 0x5b, 0xaa, 0x8d,
|
||||
0x3b, 0xd2, 0x56, 0xcf, 0x99, 0x39, 0xee, 0x22, 0x81, 0xd0, 0x60, 0x06, 0x66, 0x20, 0x81,
|
||||
0x48, 0x3c, 0x6f, 0x3a, 0x77, 0xba, 0xcb, 0x52, 0xac, 0x79, 0x56, 0xaf, 0xe9, 0x16, 0x17,
|
||||
0x0a, 0xa3, 0x82, 0x08, 0xd5, 0x3c, 0x97, 0xcb, 0x09, 0xff, 0x7f, 0xf9, 0x4f, 0x60, 0x05,
|
||||
0xb9, 0x53, 0x26, 0xaa, 0xb8, 0x50, 0xaa, 0x19, 0x25, 0xae, 0x5f, 0xea, 0x8a, 0xd0, 0x89,
|
||||
0x12, 0x80, 0x43, 0x50, 0x24, 0x12, 0x21, 0x14, 0xcd, 0x77, 0xeb, 0x21, 0xcc, 0x5c, 0x09,
|
||||
0x64, 0xf3, 0xc7, 0xcb, 0xc5, 0x4b, 0xc3, 0xe7, 0xed, 0xe7, 0x86, 0x2c, 0x1d, 0x8e, 0x19,
|
||||
0x52, 0x9b, 0x2a, 0x0c, 0x18, 0x72, 0x0b, 0x1e, 0x1b, 0xb0, 0x0f, 0x42, 0x99, 0x04, 0xae,
|
||||
0xd5, 0xb7, 0x89, 0x1a, 0xb9, 0x4f, 0xd6, 0xaf, 0xf3, 0xc9, 0x93, 0x6f, 0xb0, 0x60, 0x83,
|
||||
0x6e, 0x6b, 0xd1, 0x5f, 0x3f, 0x1a, 0x83, 0x1e, 0x24, 0x00, 0x87, 0xb5, 0x3e, 0xdb, 0xf9,
|
||||
0x4d, 0xa7, 0x16, 0x2e, 0x19, 0x5b, 0x8f, 0x1b, 0x0d, 0x47, 0x72, 0x42, 0xe9, 0x0a, 0x11,
|
||||
0x08, 0x2d, 0x88, 0x1c, 0xbc, 0xc7, 0xb4, 0xbe, 0x29, 0x4d, 0x03, 0x5e, 0xec, 0xdf, 0xf3,
|
||||
0x3d, 0x2f, 0xe8, 0x1d, 0x9a, 0xd2, 0xd1, 0xab, 0x41, 0x3d, 0x87, 0x11, 0x45, 0xb0, 0x0d,
|
||||
0x46, 0xf5, 0xe8, 0x95, 0x62, 0x1c, 0x68, 0xf7, 0xa6, 0x5b, 0x39, 0x4e, 0xbf, 0x47, 0xba,
|
||||
0x5d, 0x7f, 0xb7, 0x6a, 0xf4, 0xba, 0x1d, 0x69, 0xf6, 0xa4, 0xe7, 0xe4, 0x6b, 0x3b, 0x0d,
|
||||
0x23, 0x16, 0x4a, 0xb2, 0x68, 0xf0, 0xb2, 0x0d, 0x09, 0x17, 0x6a, 0x63, 0x8c, 0x83, 0xd3,
|
||||
0xbd, 0x05, 0xc9, 0xf6, 0xf0, 0xa1, 0x31, 0x0b, 0x2c, 0xac, 0x83, 0xac, 0x80, 0x34, 0x32,
|
||||
0xb4, 0xec, 0xd0, 0xbc, 0x54, 0x82, 0x9a, 0xc8, 0xf6, 0xa0, 0x7d, 0xc6, 0x79, 0x73, 0xf4,
|
||||
0x20, 0x99, 0xf3, 0xb4, 0x01, 0xde, 0x91, 0x27, 0xf2, 0xc0, 0xdc, 0x81, 0x00, 0x4e, 0x7e,
|
||||
0x07, 0x99, 0xc8, 0x3a, 0x51, 0xbc, 0x38, 0xd6, 0x8a, 0xa2, 0xde, 0x3b, 0x6a, 0x8c, 0x1a,
|
||||
0x7c, 0x81, 0x0f, 0x3a, 0x1f, 0xe4, 0x05, 0x7b, 0x20, 0x35, 0x6b, 0xa5, 0x6a, 0xa7, 0xe7,
|
||||
0xbc, 0x9c, 0x20, 0xec, 0x00, 0x15, 0xe2, 0x51, 0xaf, 0x77, 0xeb, 0x29, 0x3c, 0x7d, 0x2e,
|
||||
0x00, 0x5c, 0x81, 0x21, 0xfa, 0x35, 0x6f, 0x40, 0xef, 0xfb, 0xd1, 0x3f, 0xcc, 0x9d, 0x55,
|
||||
0x53, 0xfb, 0x5a, 0xa5, 0x56, 0x89, 0x0b, 0x52, 0xeb, 0x57, 0x73, 0x4f, 0x1b, 0x67, 0x24,
|
||||
0xcb, 0xb8, 0x6a, 0x10, 0x69, 0xd6, 0xfb, 0x52, 0x40, 0xff, 0x20, 0xa5, 0xf3, 0x72, 0xe1,
|
||||
0x3d, 0xa4, 0x8c, 0x81, 0x66, 0x16, 0x0d, 0x5d, 0xad, 0xa8, 0x50, 0x25, 0x78, 0x31, 0x77,
|
||||
0x0c, 0x57, 0xe4, 0xe9, 0x15, 0x2d, 0xdb, 0x07, 0x87, 0xc8, 0xb0, 0x43, 0xde, 0xfc, 0xfe,
|
||||
0xa9, 0xeb, 0xf5, 0xb0, 0xd3, 0x7b, 0xe9, 0x1f, 0x6e, 0xca, 0xe4, 0x03, 0x95, 0xc5, 0xd1,
|
||||
0x59, 0x72, 0x63, 0xf0, 0x86, 0x54, 0xe8, 0x16, 0x62, 0x0b, 0x35, 0x29, 0xc2, 0x68, 0xd0,
|
||||
0xd6, 0x3e, 0x90, 0x60, 0x57, 0x1d, 0xc9, 0xed, 0x3f, 0xed, 0xb0, 0x2f, 0x7e, 0x97, 0x02,
|
||||
0x51, 0xec, 0xee, 0x6f, 0x82, 0x74, 0x76, 0x7f, 0xfb, 0xd6, 0xc4, 0xc3, 0xdd, 0xe8, 0xb1,
|
||||
0x60, 0xfc, 0xc6, 0xb9, 0x0d, 0x6a, 0x33, 0x78, 0xc6, 0xc1, 0xbf, 0x86, 0x2c, 0x50, 0xcc,
|
||||
0x9a, 0x70, 0x8e, 0x7b, 0xec, 0xab, 0x95, 0xac, 0x53, 0xa0, 0x4b, 0x07, 0x88, 0xaf, 0x42,
|
||||
0xed, 0x19, 0x8d, 0xf6, 0x32, 0x17, 0x48, 0x47, 0x1d, 0x41, 0x6f, 0xfe, 0x2e, 0xa7, 0x8f,
|
||||
0x4b, 0xa0, 0x51, 0xf3, 0xbf, 0x02, 0x0a, 0x48, 0x58, 0xf7, 0xa1, 0x6d, 0xea, 0xa5, 0x13,
|
||||
0x5a, 0x5b, 0xea, 0x0c, 0x9e, 0x52, 0x4f, 0x9e, 0xb9, 0x71, 0x7f, 0x23, 0x83, 0xda, 0x1b,
|
||||
0x86, 0x9a, 0x41, 0x29, 0xda, 0x70, 0xe7, 0x64, 0xa1, 0x7b, 0xd5, 0x0a, 0x22, 0x0d, 0x5c,
|
||||
0x40, 0xc4, 0x81, 0x07, 0x25, 0x35, 0x4a, 0x1c, 0x10, 0xdb, 0x45, 0x0a, 0xff, 0x36, 0xd4,
|
||||
0xe0, 0xeb, 0x5f, 0x68, 0xd6, 0x67, 0xc6, 0xd0, 0x8b, 0x76, 0x1a, 0x7d, 0x59, 0x42, 0xa1,
|
||||
0xcb, 0x96, 0x4d, 0x84, 0x09, 0x9a, 0x3d, 0xe0, 0x52, 0x85, 0x6e, 0x48, 0x90, 0x85, 0x2a,
|
||||
0x63, 0xb2, 0x69, 0xd2, 0x00, 0x43, 0x31, 0x37, 0xb3, 0x52, 0xaf, 0x62, 0xfa, 0xc1, 0xe0,
|
||||
0x03, 0xfb, 0x62, 0xaa, 0x88, 0xc9, 0xb2, 0x2c, 0xd5, 0xa8, 0xf5, 0xa5, 0x4c, 0x12, 0x59,
|
||||
0x4e, 0x06, 0x5e, 0x9b, 0x15, 0x66, 0x11, 0xb2, 0x27, 0x92, 0xdc, 0x98, 0x59, 0xde, 0xdf,
|
||||
0xfa, 0x9a, 0x32, 0x2e, 0xc0, 0x5d, 0x3c, 0x33, 0x41, 0x6d, 0xaf, 0xb2, 0x25, 0x23, 0x14,
|
||||
0xa5, 0x7b, 0xc7, 0x9b, 0x68, 0xf3, 0xda, 0xeb, 0xe3, 0xa9, 0xe2, 0x6f, 0x0e, 0x1d, 0x1c,
|
||||
0xba, 0x55, 0xb6, 0x34, 0x6a, 0x93, 0x1f, 0x1f, 0xb8, 0x34, 0xc8, 0x84, 0x08, 0xb1, 0x6b,
|
||||
0x6a, 0x28, 0x74, 0x74, 0xe5, 0xeb, 0x75, 0xe9, 0x7c, 0xd8, 0xba, 0xd8, 0x42, 0xa5, 0xee,
|
||||
0x1f, 0x80, 0xd9, 0x96, 0xb2, 0x2e, 0xe7, 0xbf, 0xba, 0xeb, 0xd1, 0x69, 0xbb, 0x8f, 0xfd,
|
||||
0x5a, 0x63, 0x8f, 0x39, 0x7f, 0xdf, 0x1d, 0x37, 0xd2, 0x18, 0x35, 0x9d, 0xb6, 0xcc, 0xe4,
|
||||
0x27, 0x81, 0x89, 0x38, 0x38, 0x68, 0x33, 0xe7, 0x78, 0xd8, 0x76, 0xf5, 0xee, 0xd0, 0x4a,
|
||||
0x07, 0x69, 0x19, 0x7a, 0xad, 0x18, 0xb1, 0x94, 0x61, 0x45, 0x53, 0xa2, 0x48, 0xda, 0x96,
|
||||
0x4a, 0xf9, 0xee, 0x94, 0x2a, 0x1f, 0x6e, 0x18, 0x3c, 0x92, 0x46, 0xd1, 0x1a, 0x28, 0x18,
|
||||
0x32, 0x1f, 0x3a, 0x45, 0xbe, 0x04, 0x35, 0x92, 0xe5, 0xa3, 0xcb, 0xb5, 0x2e, 0x32, 0x43,
|
||||
0xac, 0x65, 0x17, 0x89, 0x99, 0x15, 0x03, 0x9e, 0xb1, 0x23, 0x2f, 0xed, 0x76, 0x4d, 0xd8,
|
||||
0xac, 0x21, 0x40, 0xc4, 0x99, 0x4e, 0x65, 0x71, 0x2c, 0xb3, 0x45, 0xab, 0xfb, 0xe7, 0x72,
|
||||
0x39, 0x56, 0x30, 0x6d, 0xfb, 0x74, 0xeb, 0x99, 0xf3, 0xcd, 0x57, 0x5c, 0x78, 0x75, 0xe9,
|
||||
0x8d, 0xc3, 0xa2, 0xfb, 0x5d, 0xe0, 0x90, 0xc5, 0x55, 0xad, 0x91, 0x53, 0x4e, 0x9e, 0xbd,
|
||||
0x8c, 0x49, 0xa4, 0xa4, 0x69, 0x10, 0x0c, 0xc5, 0x76, 0xe9, 0x25, 0x86, 0x8d, 0x66, 0x23,
|
||||
0xa8, 0xdb, 0x5c, 0xe8, 0xd9, 0x30, 0xe1, 0x15, 0x7b, 0xc0, 0x99, 0x0f, 0x03, 0xec, 0xaa,
|
||||
0x12, 0xef, 0xce, 0xd4, 0xea, 0x55, 0x5c, 0x08, 0x86, 0xf4, 0xf4, 0xb0, 0x83, 0x42, 0x95,
|
||||
0x37, 0xb6, 0x38, 0xe0, 0x2b, 0x54, 0x89, 0xbd, 0x4e, 0x20, 0x9d, 0x3f, 0xc3, 0x4b, 0xb7,
|
||||
0xec, 0xfa, 0x5a, 0x14, 0x03, 0xcb, 0x64, 0xc8, 0x34, 0x4a, 0x4b, 0x6e, 0xf8, 0x6e, 0x56,
|
||||
0xf6, 0xdd, 0x5f, 0xa1, 0x24, 0xe2, 0xd4, 0xd0, 0x82, 0x64, 0x1f, 0x8e, 0x9b, 0xfa, 0xb4,
|
||||
0xcb, 0xdb, 0x0a, 0xe8, 0x15, 0xfc, 0x15, 0xab, 0x4b, 0x18, 0xbf, 0xd4, 0x42, 0x14, 0x48,
|
||||
0x82, 0x85, 0xdd, 0xeb, 0x49, 0x1b, 0x0b, 0x0b, 0x05, 0xe9, 0xb4, 0xa1, 0x33, 0x0a, 0x5d,
|
||||
0x0e, 0x6c, 0x4b, 0xc0, 0xd6, 0x6c, 0x7c, 0xfb, 0x69, 0x0b, 0x53, 0x19, 0xe4, 0xf3, 0x35,
|
||||
0xfc, 0xbe, 0xa1, 0x34, 0x02, 0x09, 0x4f, 0x74, 0x86, 0x92, 0xcd, 0x5d, 0x1a, 0xc1, 0x27,
|
||||
0x0c, 0xf2, 0xc5, 0xcf, 0xdd, 0x23, 0x93, 0x02, 0xbd, 0x41, 0x5e, 0x42, 0xf0, 0xa0, 0x9d,
|
||||
0x0c, 0x72, 0xc8, 0xec, 0x32, 0x0a, 0x8a, 0xfd, 0x3d, 0x5a, 0x41, 0x27, 0x0c, 0x88, 0x59,
|
||||
0xad, 0x94, 0x2e, 0xef, 0x5d, 0x8f, 0xc7, 0xdf, 0x66, 0xe4, 0xdd, 0x56, 0x6c, 0x7b, 0xca,
|
||||
0x55, 0x81, 0xae, 0xae, 0x5c, 0x1b, 0x1a, 0xab, 0xae, 0x99, 0x8d, 0xcc, 0x42, 0x97, 0x59,
|
||||
0xf4, 0x14, 0x3f, 0x75, 0xc6, 0xd1, 0x88, 0xba, 0xaa, 0x84, 0x4a, 0xd0, 0x34, 0x08, 0x3b,
|
||||
0x7d, 0xdb, 0x15, 0x06, 0xb0, 0x5c, 0xbd, 0x40, 0xf5, 0xa8, 0xec, 0xae, 0x36, 0x40, 0xdd,
|
||||
0x90, 0x1c, 0x3e, 0x0d, 0x7e, 0x73, 0xc7, 0xc2, 0xc5, 0x6a, 0xff, 0x52, 0x05, 0x7f, 0xbe,
|
||||
0xd0, 0x92, 0xfd, 0xb3, 0x6f, 0xff, 0x5d, 0xb7, 0x97, 0x64, 0x73, 0x7b, 0xca, 0xd1, 0x98,
|
||||
0x24, 0x6b, 0x0b, 0x01, 0x68, 0xdd, 0x27, 0x85, 0x85, 0xb5, 0x83, 0xc1, 0xe0, 0x50, 0x64,
|
||||
0xc7, 0xaf, 0xf1, 0xc6, 0x4d, 0xb1, 0xef, 0xc9, 0xb4, 0x0a, 0x6d, 0x65, 0xf3, 0x47, 0xcc,
|
||||
0xa3, 0x02, 0x21, 0x0c, 0xbe, 0x22, 0x29, 0x05, 0xcf, 0x5f, 0xe8, 0x94, 0x6c, 0xe5, 0xdc,
|
||||
0xc4, 0xdf, 0xbe, 0x3e, 0xa8, 0xb4, 0x18, 0xb0, 0x99, 0xb8, 0x6f, 0xff, 0x5d, 0xb9, 0xfd,
|
||||
0x3b, 0x5d, 0x16, 0xbf, 0x3e, 0xd8, 0xb3, 0xd8, 0x08, 0x34, 0xf6, 0x47, 0x35, 0x5b, 0x72,
|
||||
0x1a, 0x33, 0xad, 0x52, 0x5d, 0xb8, 0xd0, 0x77, 0xc6, 0xab, 0xba, 0x55, 0x09, 0x5f, 0x02,
|
||||
0xf8, 0xd4, 0x5f, 0x53, 0x06, 0x91, 0xcd, 0x74, 0x42, 0xae, 0x54, 0x91, 0x81, 0x62, 0x13,
|
||||
0x6f, 0xd8, 0xa9, 0x77, 0xc3, 0x6c, 0xcb, 0xf1, 0x29, 0x5a, 0xcc, 0xda, 0x35, 0xbd, 0x52,
|
||||
0x23, 0xbe, 0x59, 0xeb, 0x12, 0x6d, 0xb7, 0x53, 0xee, 0xfc, 0xb4, 0x1b, 0x13, 0x5e, 0xba,
|
||||
0x16, 0x7c, 0xc5, 0xf3, 0xe3, 0x6d, 0x07, 0x78, 0xf5, 0x2b, 0x21, 0x05, 0x88, 0x4c, 0xc0,
|
||||
0xa1, 0xe3, 0x36, 0x10, 0xf8, 0x1b, 0xd8, 0x17, 0xfb, 0x6a, 0x4e, 0xd8, 0xb3, 0x47, 0x2d,
|
||||
0x99, 0xbd, 0xbb, 0x5d, 0x37, 0x7d, 0xba, 0xf1, 0xe1, 0x7c, 0xc0, 0xc5, 0x54, 0x62, 0x7f,
|
||||
0xcf, 0x5a, 0x4a, 0x93, 0xcc, 0xf1, 0x1b, 0x34, 0xc8, 0xa6, 0x05, 0x4c, 0x55, 0x8b, 0x54,
|
||||
0x84, 0xd5, 0x77, 0xeb, 0xc0, 0x6d, 0x3a, 0x29, 0xbd, 0x75, 0x61, 0x09, 0x9a, 0x2c, 0xbb,
|
||||
0xf7, 0x18, 0x79, 0x34, 0x90, 0x24, 0xa5, 0x81, 0x70, 0x87, 0xc5, 0x02, 0x7c, 0xba, 0xd4,
|
||||
0x5e, 0x14, 0x8e, 0xe4, 0xed, 0xa2, 0x61, 0x6a, 0xb9, 0x6e, 0xb5, 0x4a, 0xb9, 0x01, 0x46,
|
||||
0xf4, 0xcf, 0xbc, 0x09, 0x2f, 0x27, 0x4b, 0xbd, 0x86, 0x7a, 0x10, 0xe1, 0xd4, 0xc8, 0xd9,
|
||||
0x20, 0x8d, 0x8a, 0x63, 0x00, 0x63, 0x44, 0xeb, 0x54, 0x0b, 0x75, 0x49, 0x10, 0xa2, 0xa7,
|
||||
0xad, 0xb9, 0xd1, 0x01, 0x80, 0x63, 0x25, 0xc8, 0x12, 0xa6, 0xce, 0x1e, 0xbe, 0xfe, 0x7e,
|
||||
0x5f, 0x3c, 0xdb, 0x34, 0xea, 0x37, 0xec, 0x3b, 0xd5, 0x28, 0xd2, 0x07, 0x8c, 0x9a, 0xb6,
|
||||
0xee, 0x5e, 0x3e, 0xdf, 0x1d, 0x99, 0xb0, 0xe2, 0x46, 0xef, 0x5c, 0x1b, 0xb4, 0xea, 0x56,
|
||||
0x2e, 0xde, 0x1f, 0x9d, 0xb8, 0xd3, 0x24, 0xab, 0xd4, 0x2a, 0xd6, 0x2e, 0xde, 0x1f, 0x9d,
|
||||
0xb8, 0xf2, 0x66, 0x2f, 0xbd, 0xf8, 0x72, 0x66, 0x4e, 0x1e, 0x9f, 0x9d, 0xb8, 0xf2, 0x47,
|
||||
0x0c, 0x9a, 0xb6, 0xee, 0x3f, 0xfc, 0x7a, 0x57, 0x0d, 0x79, 0x70, 0x62, 0x27, 0xad, 0xb9,
|
||||
0xd1, 0x01, 0x61, 0x40, 0x02, 0x67, 0x2d, 0xd8, 0x32, 0xe6, 0x2f, 0xdc, 0x3a, 0xd7, 0x2c,
|
||||
0xbb, 0xf4, 0x4b, 0xf5, 0x49, 0xf1, 0x60, 0x23, 0xc4, 0x0a, 0x77, 0x4d, 0xf9, 0x51, 0x01,
|
||||
0x80, 0x63, 0x25, 0xa9, 0xb1, 0xe0, 0x42, 0xe7, 0x4c, 0x1a, 0x97, 0xac, 0xbb, 0xf4, 0x6a,
|
||||
0x37, 0xcd, 0x18, 0xb2, 0xe6, 0x2f, 0xdc, 0x1b, 0x95, 0xa8, 0xd2, 0x07, 0x6d, 0x58, 0x32,
|
||||
0xe6, 0x4e, 0x1e, 0x9f, 0xbc, 0xfa, 0x57, 0x0d, 0x79, 0x51, 0x20, 0xc2, 0x06, 0x6f, 0x5c,
|
||||
0x1b, 0x95, 0xa8, 0xb3, 0xc5, 0xe9, 0x31, 0xe0, 0x23, 0xc4, 0x0a, 0x77, 0x4d, 0x18, 0x93,
|
||||
0x85, 0x69, 0x31, 0xc1, 0xe1, 0x21, 0xc0, 0xe3, 0x44, 0x0a, 0x77, 0x6c, 0x5a, 0x17, 0x8d,
|
||||
0x98, 0x93, 0xa4, 0xab, 0xd4, 0x2a, 0xb7, 0xec, 0x5a, 0x17, 0xac, 0xbb, 0xf4, 0x4b, 0x14,
|
||||
0xaa, 0xb7, 0xec, 0x3b, 0xd5, 0x28, 0xb3, 0xc5, 0xe9, 0x31, 0xc1, 0x00, 0x82, 0x67, 0x4c,
|
||||
0xfb, 0x55, 0x28, 0xd2, 0x26, 0xaf, 0xbd, 0xd9, 0x11, 0x81, 0x61, 0x21, 0xa1, 0xa1, 0xc0,
|
||||
0x02, 0x86, 0x6f, 0x5c, 0x1b, 0xb4, 0xcb, 0x14, 0x8b, 0x94, 0xaa, 0xd6, 0x2e, 0xbf, 0xdd,
|
||||
0x19, 0xb0, 0xe2, 0x46, 0x0e, 0x7f, 0x7c, 0x5b, 0x15, 0x89, 0x90, 0x83, 0x84, 0x6b, 0x54,
|
||||
0x0b, 0x75, 0x68, 0x52, 0x07, 0x6d, 0x58, 0x32, 0xc7, 0xed, 0x58, 0x32, 0xc7, 0xed, 0x58,
|
||||
0x32, 0xe6, 0x4e, 0xff, 0x7c, 0x7a, 0x76, 0x6e, 0x3f, 0xdd, 0x38, 0xd3, 0x05, 0x88, 0x92,
|
||||
0xa6, 0xaf, 0xdc, 0x1b, 0xb4, 0xcb, 0xf5, 0x68, 0x52, 0x07, 0x8c, 0x7b, 0x55, 0x09, 0x90,
|
||||
0x83, 0x84, 0x6b, 0x54, 0x2a, 0xb7, 0xec, 0x3b, 0xd5, 0x09, 0x90, 0xa2, 0xc6, 0x0e, 0x7f,
|
||||
0x7c, 0x7a, 0x57, 0x0d, 0x98, 0xb2, 0xc7, 0xed, 0x58, 0x32, 0xc7, 0x0c, 0x7b, 0x74, 0x4b,
|
||||
0x14, 0x8b, 0x94, 0xaa, 0xb7, 0xcd, 0x18, 0x93, 0xa4, 0xca, 0x16, 0xae, 0xbf, 0xdd, 0x19,
|
||||
0xb0, 0xe2, 0x46, 0x0e, 0x7f, 0x5d, 0x19, 0x91, 0x81, 0x80, 0x63, 0x44, 0xeb, 0x35, 0xc9,
|
||||
0x10, 0x83, 0x65, 0x48, 0x12, 0xa6, 0xce, 0x1e, 0x9f, 0xbc, 0xdb, 0x15, 0x89, 0x71, 0x60,
|
||||
0x23, 0xc4, 0xeb, 0x54, 0x2a, 0xb7, 0xec, 0x5a, 0x36, 0xcf, 0x81, 0x10, 0xac, 0x74 };
|
||||
#define FIRMWARE_LENGTH 4094
|
||||
|
||||
// Firmware Blob for PMW3389
|
||||
|
||||
// clang-format off
|
||||
const uint8_t firmware_data[FIRMWARE_LENGTH] PROGMEM = {
|
||||
0x01, 0xe8, 0xba, 0x26, 0x0b, 0xb2, 0xbe, 0xfe, 0x7e, 0x5f, 0x3c, 0xdb, 0x15, 0xa8, 0xb3,
|
||||
0xe4, 0x2b, 0xb5, 0xe8, 0x53, 0x07, 0x6d, 0x3b, 0xd1, 0x20, 0xc2, 0x06, 0x6f, 0x3d, 0xd9,
|
||||
0x11, 0xa0, 0xc2, 0xe7, 0x2d, 0xb9, 0xd1, 0x20, 0xa3, 0xa5, 0xc8, 0xf3, 0x64, 0x4a, 0xf7,
|
||||
0x4d, 0x18, 0x93, 0xa4, 0xca, 0xf7, 0x6c, 0x5a, 0x36, 0xee, 0x5e, 0x3e, 0xfe, 0x7e, 0x7e,
|
||||
0x5f, 0x1d, 0x99, 0xb0, 0xc3, 0xe5, 0x29, 0xd3, 0x03, 0x65, 0x48, 0x12, 0x87, 0x6d, 0x58,
|
||||
0x32, 0xe6, 0x2f, 0xdc, 0x3a, 0xf2, 0x4f, 0xfd, 0x59, 0x11, 0x81, 0x61, 0x21, 0xc0, 0x02,
|
||||
0x86, 0x8e, 0x7f, 0x5d, 0x38, 0xf2, 0x47, 0x0c, 0x7b, 0x55, 0x28, 0xb3, 0xe4, 0x4a, 0x16,
|
||||
0xab, 0xbf, 0xdd, 0x38, 0xf2, 0x66, 0x4e, 0xff, 0x5d, 0x19, 0x91, 0xa0, 0xa3, 0xa5, 0xc8,
|
||||
0x12, 0xa6, 0xaf, 0xdc, 0x3a, 0xd1, 0x41, 0x60, 0x75, 0x58, 0x24, 0x92, 0xd4, 0x72, 0x6c,
|
||||
0xe0, 0x2f, 0xfd, 0x23, 0x8d, 0x1c, 0x5b, 0xb2, 0x97, 0x36, 0x3d, 0x0b, 0xa2, 0x49, 0xb1,
|
||||
0x58, 0xf2, 0x1f, 0xc0, 0xcb, 0xf8, 0x41, 0x4f, 0xcd, 0x1e, 0x6b, 0x39, 0xa7, 0x2b, 0xe9,
|
||||
0x30, 0x16, 0x83, 0xd2, 0x0e, 0x47, 0x8f, 0xe3, 0xb1, 0xdf, 0xa2, 0x15, 0xdb, 0x5d, 0x30,
|
||||
0xc5, 0x1a, 0xab, 0x31, 0x99, 0xf3, 0xfa, 0xb2, 0x86, 0x69, 0xad, 0x7a, 0xe8, 0xa7, 0x18,
|
||||
0x6a, 0xcc, 0xc8, 0x65, 0x23, 0x87, 0xa8, 0x5f, 0xf5, 0x21, 0x59, 0x75, 0x09, 0x71, 0x45,
|
||||
0x55, 0x25, 0x4b, 0xda, 0xa1, 0xc3, 0xf7, 0x41, 0xab, 0x59, 0xd9, 0x74, 0x12, 0x55, 0x5f,
|
||||
0xbc, 0xaf, 0xd9, 0xfd, 0xb0, 0x1e, 0xa3, 0x0f, 0xff, 0xde, 0x11, 0x16, 0x6a, 0xae, 0x0e,
|
||||
0xe1, 0x5d, 0x3c, 0x10, 0x43, 0x9a, 0xa1, 0x0b, 0x24, 0x8f, 0x0d, 0x7f, 0x0b, 0x5e, 0x4c,
|
||||
0x42, 0xa4, 0x84, 0x2c, 0x40, 0xd0, 0x55, 0x39, 0xe6, 0x4b, 0xf8, 0x9b, 0x2f, 0xdc, 0x28,
|
||||
0xff, 0xfa, 0xb5, 0x85, 0x19, 0xe5, 0x28, 0xa1, 0x77, 0xaa, 0x73, 0xf3, 0x03, 0xc7, 0x62,
|
||||
0xa6, 0x91, 0x18, 0xc9, 0xb0, 0xcd, 0x05, 0xdc, 0xca, 0x81, 0x26, 0x1a, 0x47, 0x40, 0xda,
|
||||
0x36, 0x7d, 0x6a, 0x53, 0xc8, 0x5a, 0x77, 0x5d, 0x19, 0xa4, 0x1b, 0x23, 0x83, 0xd0, 0xb2,
|
||||
0xaa, 0x0e, 0xbf, 0x77, 0x4e, 0x3a, 0x3b, 0x59, 0x00, 0x31, 0x0d, 0x02, 0x1b, 0x88, 0x7a,
|
||||
0xd4, 0xbd, 0x9d, 0xcc, 0x58, 0x04, 0x69, 0xf6, 0x3b, 0xca, 0x42, 0xe2, 0xfd, 0xc3, 0x3d,
|
||||
0x39, 0xc5, 0xd0, 0x71, 0xe4, 0xc8, 0xb7, 0x3e, 0x3f, 0xc8, 0xe9, 0xca, 0xc9, 0x3f, 0x04,
|
||||
0x4e, 0x1b, 0x79, 0xca, 0xa5, 0x61, 0xc2, 0xed, 0x1d, 0xa6, 0xda, 0x5a, 0xe9, 0x7f, 0x65,
|
||||
0x8c, 0xbe, 0x12, 0x6e, 0xa4, 0x5b, 0x33, 0x2f, 0x84, 0x28, 0x9c, 0x1c, 0x88, 0x2d, 0xff,
|
||||
0x07, 0xbf, 0xa6, 0xd7, 0x5a, 0x88, 0x86, 0xb0, 0x3f, 0xf6, 0x31, 0x5b, 0x11, 0x6d, 0xf5,
|
||||
0x58, 0xeb, 0x58, 0x02, 0x9e, 0xb5, 0x9a, 0xb1, 0xff, 0x25, 0x9d, 0x8b, 0x4f, 0xb6, 0x0a,
|
||||
0xf9, 0xea, 0x3e, 0x3f, 0x21, 0x09, 0x65, 0x21, 0x22, 0xfe, 0x3d, 0x4e, 0x11, 0x5b, 0x9e,
|
||||
0x5a, 0x59, 0x8b, 0xdd, 0xd8, 0xce, 0xd6, 0xd9, 0x59, 0xd2, 0x1e, 0xfd, 0xef, 0x0d, 0x1b,
|
||||
0xd9, 0x61, 0x7f, 0xd7, 0x2d, 0xad, 0x62, 0x09, 0xe5, 0x22, 0x63, 0xea, 0xc7, 0x31, 0xd9,
|
||||
0xa1, 0x38, 0x80, 0x5c, 0xa7, 0x32, 0x82, 0xec, 0x1b, 0xa2, 0x49, 0x5a, 0x06, 0xd2, 0x7c,
|
||||
0xc9, 0x96, 0x57, 0xbb, 0x17, 0x75, 0xfc, 0x7a, 0x8f, 0x0d, 0x77, 0xb5, 0x7a, 0x8e, 0x3e,
|
||||
0xf4, 0xba, 0x2f, 0x69, 0x13, 0x26, 0xd6, 0xd9, 0x21, 0x60, 0x2f, 0x21, 0x3e, 0x87, 0xee,
|
||||
0xfd, 0x87, 0x16, 0x0d, 0xc8, 0x08, 0x00, 0x25, 0x71, 0xac, 0x2c, 0x03, 0x2a, 0x37, 0x2d,
|
||||
0xb3, 0x34, 0x09, 0x91, 0xe3, 0x06, 0x2c, 0x38, 0x37, 0x95, 0x3b, 0x17, 0x7a, 0xaf, 0xac,
|
||||
0x99, 0x55, 0xab, 0x41, 0x39, 0x5f, 0x8e, 0xa6, 0x43, 0x80, 0x03, 0x88, 0x6f, 0x7d, 0xbd,
|
||||
0x5a, 0xb4, 0x2b, 0x32, 0x23, 0x5a, 0xa9, 0x31, 0x32, 0x39, 0x4c, 0x5b, 0xf4, 0x6b, 0xaf,
|
||||
0x66, 0x6f, 0x3c, 0x8e, 0x2d, 0x82, 0x97, 0x9f, 0x4a, 0x01, 0xdc, 0x99, 0x98, 0x00, 0xec,
|
||||
0x38, 0x7a, 0x79, 0x70, 0xa6, 0x85, 0xd6, 0x21, 0x63, 0x0d, 0x45, 0x9a, 0x2e, 0x5e, 0xa7,
|
||||
0xb1, 0xea, 0x66, 0x6a, 0xbc, 0x62, 0x2d, 0x7b, 0x7d, 0x85, 0xea, 0x95, 0x2f, 0xc0, 0xe8,
|
||||
0x6f, 0x35, 0xa0, 0x3a, 0x02, 0x25, 0xbc, 0xb2, 0x5f, 0x5c, 0x43, 0x96, 0xcc, 0x26, 0xd2,
|
||||
0x16, 0xb4, 0x96, 0x73, 0xd7, 0x13, 0xc7, 0xae, 0x53, 0x15, 0x31, 0x89, 0x68, 0x66, 0x6d,
|
||||
0x2c, 0x92, 0x1f, 0xcc, 0x5b, 0xa7, 0x8f, 0x5d, 0xbb, 0xc9, 0xdb, 0xe8, 0x3b, 0x9d, 0x61,
|
||||
0x74, 0x8b, 0x05, 0xa1, 0x58, 0x52, 0x68, 0xee, 0x3d, 0x39, 0x79, 0xa0, 0x9b, 0xdd, 0xe1,
|
||||
0x55, 0xc9, 0x60, 0xeb, 0xad, 0xb8, 0x5b, 0xc2, 0x5a, 0xb5, 0x2c, 0x18, 0x55, 0xa9, 0x50,
|
||||
0xc3, 0xf6, 0x72, 0x5f, 0xcc, 0xe2, 0xf4, 0x55, 0xb5, 0xd6, 0xb5, 0x4a, 0x99, 0xa5, 0x28,
|
||||
0x74, 0x97, 0x18, 0xe8, 0xc0, 0x84, 0x89, 0x50, 0x03, 0x86, 0x4d, 0x1a, 0xb7, 0x09, 0x90,
|
||||
0xa2, 0x01, 0x04, 0xbb, 0x73, 0x62, 0xcb, 0x97, 0x22, 0x70, 0x5d, 0x52, 0x41, 0x8e, 0xd9,
|
||||
0x90, 0x15, 0xaa, 0xab, 0x0a, 0x31, 0x65, 0xb4, 0xda, 0xd0, 0xee, 0x24, 0xc9, 0x41, 0x91,
|
||||
0x1e, 0xbc, 0x46, 0x70, 0x40, 0x9d, 0xda, 0x0e, 0x2a, 0xe4, 0xb2, 0x4c, 0x9f, 0xf2, 0xfc,
|
||||
0xf3, 0x84, 0x17, 0x44, 0x1e, 0xd7, 0xca, 0x23, 0x1f, 0x3f, 0x5a, 0x22, 0x3d, 0xaf, 0x9b,
|
||||
0x2d, 0xfc, 0x41, 0xad, 0x26, 0xb4, 0x45, 0x67, 0x0b, 0x80, 0x0e, 0xf9, 0x61, 0x37, 0xec,
|
||||
0x3b, 0xf4, 0x4b, 0x14, 0xdf, 0x5a, 0x0c, 0x3a, 0x50, 0x0b, 0x14, 0x0c, 0x72, 0xae, 0xc6,
|
||||
0xc5, 0xec, 0x35, 0x53, 0x2d, 0x59, 0xed, 0x91, 0x74, 0xe2, 0xc4, 0xc8, 0xf2, 0x25, 0x6b,
|
||||
0x97, 0x6f, 0xc9, 0x76, 0xce, 0xa9, 0xb1, 0x99, 0x8f, 0x5a, 0x92, 0x3b, 0xc4, 0x8d, 0x54,
|
||||
0x50, 0x40, 0x72, 0xd6, 0x90, 0x83, 0xfc, 0xe5, 0x49, 0x8b, 0x17, 0xf5, 0xfd, 0x6b, 0x8d,
|
||||
0x32, 0x02, 0xe9, 0x0a, 0xfe, 0xbf, 0x00, 0x6b, 0xa3, 0xad, 0x5f, 0x09, 0x4b, 0x97, 0x2b,
|
||||
0x00, 0x58, 0x65, 0x2e, 0x07, 0x49, 0x0a, 0x3b, 0x6b, 0x2e, 0x50, 0x6c, 0x1d, 0xac, 0xb7,
|
||||
0x6a, 0x26, 0xd8, 0x13, 0xa4, 0xca, 0x16, 0xae, 0xab, 0x93, 0xb9, 0x1c, 0x1c, 0xb4, 0x47,
|
||||
0x6a, 0x38, 0x36, 0x17, 0x27, 0xc9, 0x7f, 0xc7, 0x64, 0xcb, 0x89, 0x58, 0xc5, 0x61, 0xc2,
|
||||
0xc6, 0xea, 0x15, 0x0b, 0x34, 0x0c, 0x5d, 0x61, 0x76, 0x6e, 0x2b, 0x62, 0x40, 0x92, 0xa3,
|
||||
0x6c, 0xef, 0xf4, 0xe4, 0xc3, 0xa1, 0xa8, 0xf5, 0x94, 0x79, 0x0d, 0xd1, 0x3d, 0xcb, 0x3d,
|
||||
0x40, 0xb6, 0xd0, 0xf0, 0x10, 0x54, 0xd8, 0x47, 0x25, 0x51, 0xc5, 0x41, 0x79, 0x00, 0xe5,
|
||||
0xa0, 0x72, 0xde, 0xbb, 0x3b, 0x62, 0x17, 0xf6, 0xbc, 0x5d, 0x00, 0x76, 0x2e, 0xa7, 0x3b,
|
||||
0xb6, 0xf1, 0x98, 0x72, 0x59, 0x2a, 0x73, 0xb0, 0x21, 0xd6, 0x49, 0xe0, 0xc0, 0xd5, 0xeb,
|
||||
0x02, 0x7d, 0x4b, 0x41, 0x28, 0x70, 0x2d, 0xec, 0x2b, 0x71, 0x1f, 0x0b, 0xb9, 0x71, 0x63,
|
||||
0x06, 0xe6, 0xbc, 0x60, 0xbb, 0xf4, 0x9a, 0x62, 0x43, 0x09, 0x18, 0x4e, 0x93, 0x06, 0x4d,
|
||||
0x76, 0xfa, 0x7f, 0xbd, 0x02, 0xe4, 0x50, 0x91, 0x12, 0xe5, 0x86, 0xff, 0x64, 0x1e, 0xaf,
|
||||
0x7e, 0xb3, 0xb2, 0xde, 0x89, 0xc1, 0xa2, 0x6f, 0x40, 0x7b, 0x41, 0x51, 0x63, 0xea, 0x25,
|
||||
0xd1, 0x97, 0x57, 0x92, 0xa8, 0x45, 0xa1, 0xa5, 0x45, 0x21, 0x43, 0x7f, 0x83, 0x15, 0x29,
|
||||
0xd0, 0x30, 0x53, 0x32, 0xb4, 0x5a, 0x17, 0x96, 0xbc, 0xc2, 0x68, 0xa9, 0xb7, 0xaf, 0xac,
|
||||
0xdf, 0xf1, 0xe3, 0x89, 0xba, 0x24, 0x79, 0x54, 0xc6, 0x14, 0x07, 0x1c, 0x1e, 0x0d, 0x3a,
|
||||
0x6b, 0xe5, 0x3d, 0x4e, 0x10, 0x60, 0x96, 0xec, 0x6c, 0xda, 0x47, 0xae, 0x03, 0x25, 0x39,
|
||||
0x1d, 0x74, 0xc8, 0xac, 0x6a, 0xf2, 0x6b, 0x05, 0x2a, 0x9a, 0xe7, 0xe8, 0x92, 0xd6, 0xc2,
|
||||
0x6d, 0xfa, 0xe8, 0xa7, 0x9d, 0x5f, 0x48, 0xc9, 0x75, 0xf1, 0x66, 0x6a, 0xdb, 0x5d, 0x9a,
|
||||
0xcd, 0x27, 0xdd, 0xb9, 0x24, 0x04, 0x9c, 0x18, 0xc2, 0x6d, 0x0c, 0x91, 0x34, 0x48, 0x42,
|
||||
0x6f, 0xe9, 0x59, 0x70, 0xc4, 0x7e, 0x81, 0x0e, 0x32, 0x0a, 0x93, 0x48, 0xb0, 0xc0, 0x15,
|
||||
0x9e, 0x05, 0xac, 0x36, 0x16, 0xcb, 0x59, 0x65, 0xa0, 0x83, 0xdf, 0x3e, 0xda, 0xfb, 0x1d,
|
||||
0x1a, 0xdb, 0x65, 0xec, 0x9a, 0xc6, 0xc3, 0x8e, 0x3c, 0x45, 0xfd, 0xc8, 0xf5, 0x1c, 0x6a,
|
||||
0x67, 0x0d, 0x8f, 0x99, 0x7d, 0x30, 0x21, 0x8c, 0xea, 0x22, 0x87, 0x65, 0xc9, 0xb2, 0x4c,
|
||||
0xe4, 0x1b, 0x46, 0xba, 0x54, 0xbd, 0x7c, 0xca, 0xd5, 0x8f, 0x5b, 0xa5, 0x01, 0x04, 0xd8,
|
||||
0x0a, 0x16, 0xbf, 0xb9, 0x50, 0x2e, 0x37, 0x2f, 0x64, 0xf3, 0x70, 0x11, 0x02, 0x05, 0x31,
|
||||
0x9b, 0xa0, 0xb2, 0x01, 0x5e, 0x4f, 0x19, 0xc9, 0xd4, 0xea, 0xa1, 0x79, 0x54, 0x53, 0xa7,
|
||||
0xde, 0x2f, 0x49, 0xd3, 0xd1, 0x63, 0xb5, 0x03, 0x15, 0x4e, 0xbf, 0x04, 0xb3, 0x26, 0x8b,
|
||||
0x20, 0xb2, 0x45, 0xcf, 0xcd, 0x5b, 0x82, 0x32, 0x88, 0x61, 0xa7, 0xa8, 0xb2, 0xa0, 0x72,
|
||||
0x96, 0xc0, 0xdb, 0x2b, 0xe2, 0x5f, 0xba, 0xe3, 0xf5, 0x8a, 0xde, 0xf1, 0x18, 0x01, 0x16,
|
||||
0x40, 0xd9, 0x86, 0x12, 0x09, 0x18, 0x1b, 0x05, 0x0c, 0xb1, 0xb5, 0x47, 0xe2, 0x43, 0xab,
|
||||
0xfe, 0x92, 0x63, 0x7e, 0x95, 0x2b, 0xf0, 0xaf, 0xe1, 0xf1, 0xc3, 0x4a, 0xff, 0x2b, 0x09,
|
||||
0xbb, 0x4a, 0x0e, 0x9a, 0xc4, 0xd8, 0x64, 0x7d, 0x83, 0xa0, 0x4f, 0x44, 0xdb, 0xc4, 0xa8,
|
||||
0x58, 0xef, 0xfc, 0x9e, 0x77, 0xf9, 0xa6, 0x8f, 0x58, 0x8b, 0x12, 0xf4, 0xe9, 0x81, 0x12,
|
||||
0x47, 0x51, 0x41, 0x83, 0xef, 0xf6, 0x73, 0xbc, 0x8e, 0x0f, 0x4c, 0x8f, 0x4e, 0x69, 0x90,
|
||||
0x77, 0x29, 0x5d, 0x92, 0xb0, 0x6d, 0x06, 0x67, 0x29, 0x60, 0xbd, 0x4b, 0x17, 0xc8, 0x89,
|
||||
0x69, 0x28, 0x29, 0xd6, 0x78, 0xcb, 0x11, 0x4c, 0xba, 0x8b, 0x68, 0xae, 0x7e, 0x9f, 0xef,
|
||||
0x95, 0xda, 0xe2, 0x9e, 0x7f, 0xe9, 0x55, 0xe5, 0xe1, 0xe2, 0xb7, 0xe6, 0x5f, 0xbb, 0x2c,
|
||||
0xa2, 0xe6, 0xee, 0xc7, 0x0a, 0x60, 0xa9, 0xd1, 0x80, 0xdf, 0x7f, 0xd6, 0x97, 0xab, 0x1d,
|
||||
0x22, 0x25, 0xfc, 0x79, 0x23, 0xe0, 0xae, 0xc5, 0xef, 0x16, 0xa4, 0xa1, 0x0f, 0x92, 0xa9,
|
||||
0xc7, 0xe3, 0x3a, 0x55, 0xdf, 0x62, 0x49, 0xd9, 0xf5, 0x84, 0x49, 0xc5, 0x90, 0x34, 0xd3,
|
||||
0xe1, 0xac, 0x99, 0x21, 0xb1, 0x02, 0x76, 0x4a, 0xfa, 0xd4, 0xbb, 0xa4, 0x9c, 0xa2, 0xe2,
|
||||
0xcb, 0x3d, 0x3b, 0x14, 0x75, 0x60, 0xd1, 0x02, 0xb4, 0xa3, 0xb4, 0x72, 0x06, 0xf9, 0x19,
|
||||
0x9c, 0xe2, 0xe4, 0xa7, 0x0f, 0x25, 0x88, 0xc6, 0x86, 0xd6, 0x8c, 0x74, 0x4e, 0x6e, 0xfc,
|
||||
0xa8, 0x48, 0x9e, 0xa7, 0x9d, 0x1a, 0x4b, 0x37, 0x09, 0xc8, 0xb0, 0x10, 0xbe, 0x6f, 0xfe,
|
||||
0xa3, 0xc4, 0x7a, 0xb5, 0x3d, 0xe8, 0x30, 0xf1, 0x0d, 0xa0, 0xb2, 0x44, 0xfc, 0x9b, 0x8c,
|
||||
0xf8, 0x61, 0xed, 0x81, 0xd1, 0x62, 0x11, 0xb4, 0xe1, 0xd5, 0x39, 0x52, 0x89, 0xd3, 0xa8,
|
||||
0x49, 0x31, 0xdf, 0xb6, 0xf9, 0x91, 0xf4, 0x1c, 0x9d, 0x09, 0x95, 0x40, 0x56, 0xe7, 0xe3,
|
||||
0xcd, 0x5c, 0x92, 0xc1, 0x1d, 0x6b, 0xe9, 0x78, 0x6f, 0x8e, 0x94, 0x42, 0x66, 0xa2, 0xaa,
|
||||
0xd3, 0xc8, 0x2e, 0xe3, 0xf6, 0x07, 0x72, 0x0b, 0x6b, 0x1e, 0x7b, 0xb9, 0x7c, 0xe0, 0xa0,
|
||||
0xbc, 0xd9, 0x25, 0xdf, 0x87, 0xa8, 0x5f, 0x9c, 0xcc, 0xf0, 0xdb, 0x42, 0x8e, 0x07, 0x31,
|
||||
0x13, 0x01, 0x66, 0x32, 0xd1, 0xb8, 0xd6, 0xe3, 0x5e, 0x12, 0x76, 0x61, 0xd3, 0x38, 0x89,
|
||||
0xe6, 0x17, 0x6f, 0xa5, 0xf2, 0x71, 0x0e, 0xa5, 0xe2, 0x88, 0x30, 0xbb, 0xbe, 0x8a, 0xea,
|
||||
0xc7, 0x62, 0xc4, 0xcf, 0xb8, 0xcd, 0x33, 0x8d, 0x3d, 0x3e, 0xb5, 0x60, 0x3a, 0x03, 0x92,
|
||||
0xe4, 0x6d, 0x1b, 0xe0, 0xb4, 0x84, 0x08, 0x55, 0x88, 0xa7, 0x3a, 0xb9, 0x3d, 0x43, 0xc3,
|
||||
0xc0, 0xfa, 0x07, 0x6a, 0xca, 0x94, 0xad, 0x99, 0x55, 0xf1, 0xf1, 0xc0, 0x23, 0x87, 0x1d,
|
||||
0x3d, 0x1c, 0xd1, 0x66, 0xa0, 0x57, 0x10, 0x52, 0xa2, 0x7f, 0xbe, 0xf9, 0x88, 0xb6, 0x02,
|
||||
0xbf, 0x08, 0x23, 0xa9, 0x0c, 0x63, 0x17, 0x2a, 0xae, 0xf5, 0xf7, 0xb7, 0x21, 0x83, 0x92,
|
||||
0x31, 0x23, 0x0d, 0x20, 0xc3, 0xc2, 0x05, 0x21, 0x62, 0x8e, 0x45, 0xe8, 0x14, 0xc1, 0xda,
|
||||
0x75, 0xb8, 0xf8, 0x92, 0x01, 0xd0, 0x5d, 0x18, 0x9f, 0x99, 0x11, 0x19, 0xf5, 0x35, 0xe8,
|
||||
0x7f, 0x20, 0x88, 0x8c, 0x05, 0x75, 0xf5, 0xd7, 0x40, 0x17, 0xbb, 0x1e, 0x36, 0x52, 0xd9,
|
||||
0xa4, 0x9c, 0xc2, 0x9d, 0x42, 0x81, 0xd8, 0xc7, 0x8a, 0xe7, 0x4c, 0x81, 0xe0, 0xb7, 0x57,
|
||||
0xed, 0x48, 0x8b, 0xf0, 0x97, 0x15, 0x61, 0xd9, 0x2c, 0x7c, 0x45, 0xaf, 0xc2, 0xcd, 0xfc,
|
||||
0xaa, 0x13, 0xad, 0x59, 0xcc, 0xb2, 0xb2, 0x6e, 0xdd, 0x63, 0x9c, 0x32, 0x0f, 0xec, 0x83,
|
||||
0xbe, 0x78, 0xac, 0x91, 0x44, 0x1a, 0x1f, 0xea, 0xfd, 0x5d, 0x8e, 0xb4, 0xc0, 0x84, 0xd4,
|
||||
0xac, 0xb4, 0x87, 0x5f, 0xac, 0xef, 0xdf, 0xcd, 0x12, 0x56, 0xc8, 0xcd, 0xfe, 0xc5, 0xda,
|
||||
0xd3, 0xc1, 0x69, 0xf3, 0x61, 0x05, 0xea, 0x25, 0xe2, 0x12, 0x05, 0x8f, 0x39, 0x08, 0x08,
|
||||
0x7c, 0x37, 0xb6, 0x7e, 0x5b, 0xd8, 0xb1, 0x0e, 0xf2, 0xdb, 0x4b, 0xf1, 0xad, 0x90, 0x01,
|
||||
0x57, 0xcd, 0xa0, 0xb4, 0x52, 0xe8, 0xf3, 0xd7, 0x8a, 0xbd, 0x4f, 0x9f, 0x21, 0x40, 0x72,
|
||||
0xa4, 0xfc, 0x0b, 0x01, 0x2b, 0x2f, 0xb6, 0x4c, 0x95, 0x2d, 0x35, 0x33, 0x41, 0x6b, 0xa0,
|
||||
0x93, 0xe7, 0x2c, 0xf2, 0xd3, 0x72, 0x8b, 0xf4, 0x4f, 0x15, 0x3c, 0xaf, 0xd6, 0x12, 0xde,
|
||||
0x3f, 0x83, 0x3f, 0xff, 0xf8, 0x7f, 0xf6, 0xcc, 0xa6, 0x7f, 0xc9, 0x9a, 0x6e, 0x1f, 0xc1,
|
||||
0x0c, 0xfb, 0xee, 0x9c, 0xe7, 0xaf, 0xc9, 0x26, 0x54, 0xef, 0xb0, 0x39, 0xef, 0xb2, 0xe9,
|
||||
0x23, 0xc4, 0xef, 0xd1, 0xa1, 0xa4, 0x25, 0x24, 0x6f, 0x8d, 0x6a, 0xe5, 0x8a, 0x32, 0x3a,
|
||||
0xaf, 0xfc, 0xda, 0xce, 0x18, 0x25, 0x42, 0x07, 0x4d, 0x45, 0x8b, 0xdf, 0x85, 0xcf, 0x55,
|
||||
0xb2, 0x24, 0xfe, 0x9c, 0x69, 0x74, 0xa7, 0x6e, 0xa0, 0xce, 0xc0, 0x39, 0xf4, 0x86, 0xc6,
|
||||
0x8d, 0xae, 0xb9, 0x48, 0x64, 0x13, 0x0b, 0x40, 0x81, 0xa2, 0xc9, 0xa8, 0x85, 0x51, 0xee,
|
||||
0x9f, 0xcf, 0xa2, 0x8c, 0x19, 0x52, 0x48, 0xe2, 0xc1, 0xa8, 0x58, 0xb4, 0x10, 0x24, 0x06,
|
||||
0x58, 0x51, 0xfc, 0xb9, 0x12, 0xec, 0xfd, 0x73, 0xb4, 0x6d, 0x84, 0xfa, 0x06, 0x8b, 0x05,
|
||||
0x0b, 0x2d, 0xd6, 0xd6, 0x1f, 0x29, 0x82, 0x9f, 0x19, 0x12, 0x1e, 0xb2, 0x04, 0x8f, 0x7f,
|
||||
0x4d, 0xbd, 0x30, 0x2e, 0xe3, 0xe0, 0x88, 0x29, 0xc5, 0x93, 0xd6, 0x6c, 0x1f, 0x29, 0x45,
|
||||
0x91, 0xa7, 0x58, 0xcd, 0x05, 0x17, 0xd6, 0x6d, 0xb3, 0xca, 0x66, 0xcc, 0x3c, 0x4a, 0x74,
|
||||
0xfd, 0x08, 0x10, 0xa6, 0x99, 0x92, 0x10, 0xd2, 0x85, 0xab, 0x6e, 0x1d, 0x0e, 0x8b, 0x26,
|
||||
0x46, 0xd1, 0x6c, 0x84, 0xc0, 0x26, 0x43, 0x59, 0x68, 0xf0, 0x13, 0x1d, 0xfb, 0xe3, 0xd1,
|
||||
0xd2, 0xb4, 0x71, 0x9e, 0xf2, 0x59, 0x6a, 0x33, 0x29, 0x79, 0xd2, 0xd7, 0x26, 0xf1, 0xae,
|
||||
0x78, 0x9e, 0x1f, 0x0f, 0x3f, 0xe3, 0xe8, 0xd0, 0x27, 0x78, 0x77, 0xf6, 0xac, 0x9c, 0x56,
|
||||
0x39, 0x73, 0x8a, 0x6b, 0x2f, 0x34, 0x78, 0xb1, 0x11, 0xdb, 0xa4, 0x5c, 0x80, 0x01, 0x71,
|
||||
0x6a, 0xc2, 0xd1, 0x2e, 0x5e, 0x76, 0x28, 0x70, 0x93, 0xae, 0x3e, 0x78, 0xb0, 0x1f, 0x0f,
|
||||
0xda, 0xbf, 0xfb, 0x8a, 0x67, 0x65, 0x4f, 0x91, 0xed, 0x49, 0x75, 0x78, 0x62, 0xa2, 0x93,
|
||||
0xb5, 0x70, 0x7f, 0x4d, 0x08, 0x4e, 0x79, 0x61, 0xa8, 0x5f, 0x7f, 0xb4, 0x65, 0x9f, 0x91,
|
||||
0x54, 0x3a, 0xe8, 0x50, 0x33, 0xd3, 0xd5, 0x8a, 0x7c, 0xf3, 0x9e, 0x8b, 0x77, 0x7b, 0xc6,
|
||||
0xc6, 0x0c, 0x45, 0x95, 0x1f, 0xb0, 0xd0, 0x0b, 0x27, 0x4a, 0xfd, 0xc7, 0xf7, 0x0d, 0x5a,
|
||||
0x43, 0xc9, 0x7d, 0x35, 0xb0, 0x7d, 0xc4, 0x9c, 0x57, 0x1e, 0x76, 0x0d, 0xf1, 0x95, 0x30,
|
||||
0x71, 0xcc, 0xb3, 0x66, 0x3b, 0x63, 0xa8, 0x6c, 0xa3, 0x43, 0xa0, 0x24, 0xcc, 0xb7, 0x53,
|
||||
0xfe, 0xfe, 0xbc, 0x6e, 0x60, 0x89, 0xaf, 0x16, 0x21, 0xc8, 0x91, 0x6a, 0x89, 0xce, 0x80,
|
||||
0x2c, 0xf1, 0x59, 0xce, 0xc3, 0x60, 0x61, 0x3b, 0x0b, 0x19, 0xfe, 0x99, 0xac, 0x65, 0x90,
|
||||
0x15, 0x12, 0x05, 0xac, 0x7e, 0xff, 0x98, 0x7b, 0x66, 0x64, 0x0e, 0x4b, 0x5b, 0xaa, 0x8d,
|
||||
0x3b, 0xd2, 0x56, 0xcf, 0x99, 0x39, 0xee, 0x22, 0x81, 0xd0, 0x60, 0x06, 0x66, 0x20, 0x81,
|
||||
0x48, 0x3c, 0x6f, 0x3a, 0x77, 0xba, 0xcb, 0x52, 0xac, 0x79, 0x56, 0xaf, 0xe9, 0x16, 0x17,
|
||||
0x0a, 0xa3, 0x82, 0x08, 0xd5, 0x3c, 0x97, 0xcb, 0x09, 0xff, 0x7f, 0xf9, 0x4f, 0x60, 0x05,
|
||||
0xb9, 0x53, 0x26, 0xaa, 0xb8, 0x50, 0xaa, 0x19, 0x25, 0xae, 0x5f, 0xea, 0x8a, 0xd0, 0x89,
|
||||
0x12, 0x80, 0x43, 0x50, 0x24, 0x12, 0x21, 0x14, 0xcd, 0x77, 0xeb, 0x21, 0xcc, 0x5c, 0x09,
|
||||
0x64, 0xf3, 0xc7, 0xcb, 0xc5, 0x4b, 0xc3, 0xe7, 0xed, 0xe7, 0x86, 0x2c, 0x1d, 0x8e, 0x19,
|
||||
0x52, 0x9b, 0x2a, 0x0c, 0x18, 0x72, 0x0b, 0x1e, 0x1b, 0xb0, 0x0f, 0x42, 0x99, 0x04, 0xae,
|
||||
0xd5, 0xb7, 0x89, 0x1a, 0xb9, 0x4f, 0xd6, 0xaf, 0xf3, 0xc9, 0x93, 0x6f, 0xb0, 0x60, 0x83,
|
||||
0x6e, 0x6b, 0xd1, 0x5f, 0x3f, 0x1a, 0x83, 0x1e, 0x24, 0x00, 0x87, 0xb5, 0x3e, 0xdb, 0xf9,
|
||||
0x4d, 0xa7, 0x16, 0x2e, 0x19, 0x5b, 0x8f, 0x1b, 0x0d, 0x47, 0x72, 0x42, 0xe9, 0x0a, 0x11,
|
||||
0x08, 0x2d, 0x88, 0x1c, 0xbc, 0xc7, 0xb4, 0xbe, 0x29, 0x4d, 0x03, 0x5e, 0xec, 0xdf, 0xf3,
|
||||
0x3d, 0x2f, 0xe8, 0x1d, 0x9a, 0xd2, 0xd1, 0xab, 0x41, 0x3d, 0x87, 0x11, 0x45, 0xb0, 0x0d,
|
||||
0x46, 0xf5, 0xe8, 0x95, 0x62, 0x1c, 0x68, 0xf7, 0xa6, 0x5b, 0x39, 0x4e, 0xbf, 0x47, 0xba,
|
||||
0x5d, 0x7f, 0xb7, 0x6a, 0xf4, 0xba, 0x1d, 0x69, 0xf6, 0xa4, 0xe7, 0xe4, 0x6b, 0x3b, 0x0d,
|
||||
0x23, 0x16, 0x4a, 0xb2, 0x68, 0xf0, 0xb2, 0x0d, 0x09, 0x17, 0x6a, 0x63, 0x8c, 0x83, 0xd3,
|
||||
0xbd, 0x05, 0xc9, 0xf6, 0xf0, 0xa1, 0x31, 0x0b, 0x2c, 0xac, 0x83, 0xac, 0x80, 0x34, 0x32,
|
||||
0xb4, 0xec, 0xd0, 0xbc, 0x54, 0x82, 0x9a, 0xc8, 0xf6, 0xa0, 0x7d, 0xc6, 0x79, 0x73, 0xf4,
|
||||
0x20, 0x99, 0xf3, 0xb4, 0x01, 0xde, 0x91, 0x27, 0xf2, 0xc0, 0xdc, 0x81, 0x00, 0x4e, 0x7e,
|
||||
0x07, 0x99, 0xc8, 0x3a, 0x51, 0xbc, 0x38, 0xd6, 0x8a, 0xa2, 0xde, 0x3b, 0x6a, 0x8c, 0x1a,
|
||||
0x7c, 0x81, 0x0f, 0x3a, 0x1f, 0xe4, 0x05, 0x7b, 0x20, 0x35, 0x6b, 0xa5, 0x6a, 0xa7, 0xe7,
|
||||
0xbc, 0x9c, 0x20, 0xec, 0x00, 0x15, 0xe2, 0x51, 0xaf, 0x77, 0xeb, 0x29, 0x3c, 0x7d, 0x2e,
|
||||
0x00, 0x5c, 0x81, 0x21, 0xfa, 0x35, 0x6f, 0x40, 0xef, 0xfb, 0xd1, 0x3f, 0xcc, 0x9d, 0x55,
|
||||
0x53, 0xfb, 0x5a, 0xa5, 0x56, 0x89, 0x0b, 0x52, 0xeb, 0x57, 0x73, 0x4f, 0x1b, 0x67, 0x24,
|
||||
0xcb, 0xb8, 0x6a, 0x10, 0x69, 0xd6, 0xfb, 0x52, 0x40, 0xff, 0x20, 0xa5, 0xf3, 0x72, 0xe1,
|
||||
0x3d, 0xa4, 0x8c, 0x81, 0x66, 0x16, 0x0d, 0x5d, 0xad, 0xa8, 0x50, 0x25, 0x78, 0x31, 0x77,
|
||||
0x0c, 0x57, 0xe4, 0xe9, 0x15, 0x2d, 0xdb, 0x07, 0x87, 0xc8, 0xb0, 0x43, 0xde, 0xfc, 0xfe,
|
||||
0xa9, 0xeb, 0xf5, 0xb0, 0xd3, 0x7b, 0xe9, 0x1f, 0x6e, 0xca, 0xe4, 0x03, 0x95, 0xc5, 0xd1,
|
||||
0x59, 0x72, 0x63, 0xf0, 0x86, 0x54, 0xe8, 0x16, 0x62, 0x0b, 0x35, 0x29, 0xc2, 0x68, 0xd0,
|
||||
0xd6, 0x3e, 0x90, 0x60, 0x57, 0x1d, 0xc9, 0xed, 0x3f, 0xed, 0xb0, 0x2f, 0x7e, 0x97, 0x02,
|
||||
0x51, 0xec, 0xee, 0x6f, 0x82, 0x74, 0x76, 0x7f, 0xfb, 0xd6, 0xc4, 0xc3, 0xdd, 0xe8, 0xb1,
|
||||
0x60, 0xfc, 0xc6, 0xb9, 0x0d, 0x6a, 0x33, 0x78, 0xc6, 0xc1, 0xbf, 0x86, 0x2c, 0x50, 0xcc,
|
||||
0x9a, 0x70, 0x8e, 0x7b, 0xec, 0xab, 0x95, 0xac, 0x53, 0xa0, 0x4b, 0x07, 0x88, 0xaf, 0x42,
|
||||
0xed, 0x19, 0x8d, 0xf6, 0x32, 0x17, 0x48, 0x47, 0x1d, 0x41, 0x6f, 0xfe, 0x2e, 0xa7, 0x8f,
|
||||
0x4b, 0xa0, 0x51, 0xf3, 0xbf, 0x02, 0x0a, 0x48, 0x58, 0xf7, 0xa1, 0x6d, 0xea, 0xa5, 0x13,
|
||||
0x5a, 0x5b, 0xea, 0x0c, 0x9e, 0x52, 0x4f, 0x9e, 0xb9, 0x71, 0x7f, 0x23, 0x83, 0xda, 0x1b,
|
||||
0x86, 0x9a, 0x41, 0x29, 0xda, 0x70, 0xe7, 0x64, 0xa1, 0x7b, 0xd5, 0x0a, 0x22, 0x0d, 0x5c,
|
||||
0x40, 0xc4, 0x81, 0x07, 0x25, 0x35, 0x4a, 0x1c, 0x10, 0xdb, 0x45, 0x0a, 0xff, 0x36, 0xd4,
|
||||
0xe0, 0xeb, 0x5f, 0x68, 0xd6, 0x67, 0xc6, 0xd0, 0x8b, 0x76, 0x1a, 0x7d, 0x59, 0x42, 0xa1,
|
||||
0xcb, 0x96, 0x4d, 0x84, 0x09, 0x9a, 0x3d, 0xe0, 0x52, 0x85, 0x6e, 0x48, 0x90, 0x85, 0x2a,
|
||||
0x63, 0xb2, 0x69, 0xd2, 0x00, 0x43, 0x31, 0x37, 0xb3, 0x52, 0xaf, 0x62, 0xfa, 0xc1, 0xe0,
|
||||
0x03, 0xfb, 0x62, 0xaa, 0x88, 0xc9, 0xb2, 0x2c, 0xd5, 0xa8, 0xf5, 0xa5, 0x4c, 0x12, 0x59,
|
||||
0x4e, 0x06, 0x5e, 0x9b, 0x15, 0x66, 0x11, 0xb2, 0x27, 0x92, 0xdc, 0x98, 0x59, 0xde, 0xdf,
|
||||
0xfa, 0x9a, 0x32, 0x2e, 0xc0, 0x5d, 0x3c, 0x33, 0x41, 0x6d, 0xaf, 0xb2, 0x25, 0x23, 0x14,
|
||||
0xa5, 0x7b, 0xc7, 0x9b, 0x68, 0xf3, 0xda, 0xeb, 0xe3, 0xa9, 0xe2, 0x6f, 0x0e, 0x1d, 0x1c,
|
||||
0xba, 0x55, 0xb6, 0x34, 0x6a, 0x93, 0x1f, 0x1f, 0xb8, 0x34, 0xc8, 0x84, 0x08, 0xb1, 0x6b,
|
||||
0x6a, 0x28, 0x74, 0x74, 0xe5, 0xeb, 0x75, 0xe9, 0x7c, 0xd8, 0xba, 0xd8, 0x42, 0xa5, 0xee,
|
||||
0x1f, 0x80, 0xd9, 0x96, 0xb2, 0x2e, 0xe7, 0xbf, 0xba, 0xeb, 0xd1, 0x69, 0xbb, 0x8f, 0xfd,
|
||||
0x5a, 0x63, 0x8f, 0x39, 0x7f, 0xdf, 0x1d, 0x37, 0xd2, 0x18, 0x35, 0x9d, 0xb6, 0xcc, 0xe4,
|
||||
0x27, 0x81, 0x89, 0x38, 0x38, 0x68, 0x33, 0xe7, 0x78, 0xd8, 0x76, 0xf5, 0xee, 0xd0, 0x4a,
|
||||
0x07, 0x69, 0x19, 0x7a, 0xad, 0x18, 0xb1, 0x94, 0x61, 0x45, 0x53, 0xa2, 0x48, 0xda, 0x96,
|
||||
0x4a, 0xf9, 0xee, 0x94, 0x2a, 0x1f, 0x6e, 0x18, 0x3c, 0x92, 0x46, 0xd1, 0x1a, 0x28, 0x18,
|
||||
0x32, 0x1f, 0x3a, 0x45, 0xbe, 0x04, 0x35, 0x92, 0xe5, 0xa3, 0xcb, 0xb5, 0x2e, 0x32, 0x43,
|
||||
0xac, 0x65, 0x17, 0x89, 0x99, 0x15, 0x03, 0x9e, 0xb1, 0x23, 0x2f, 0xed, 0x76, 0x4d, 0xd8,
|
||||
0xac, 0x21, 0x40, 0xc4, 0x99, 0x4e, 0x65, 0x71, 0x2c, 0xb3, 0x45, 0xab, 0xfb, 0xe7, 0x72,
|
||||
0x39, 0x56, 0x30, 0x6d, 0xfb, 0x74, 0xeb, 0x99, 0xf3, 0xcd, 0x57, 0x5c, 0x78, 0x75, 0xe9,
|
||||
0x8d, 0xc3, 0xa2, 0xfb, 0x5d, 0xe0, 0x90, 0xc5, 0x55, 0xad, 0x91, 0x53, 0x4e, 0x9e, 0xbd,
|
||||
0x8c, 0x49, 0xa4, 0xa4, 0x69, 0x10, 0x0c, 0xc5, 0x76, 0xe9, 0x25, 0x86, 0x8d, 0x66, 0x23,
|
||||
0xa8, 0xdb, 0x5c, 0xe8, 0xd9, 0x30, 0xe1, 0x15, 0x7b, 0xc0, 0x99, 0x0f, 0x03, 0xec, 0xaa,
|
||||
0x12, 0xef, 0xce, 0xd4, 0xea, 0x55, 0x5c, 0x08, 0x86, 0xf4, 0xf4, 0xb0, 0x83, 0x42, 0x95,
|
||||
0x37, 0xb6, 0x38, 0xe0, 0x2b, 0x54, 0x89, 0xbd, 0x4e, 0x20, 0x9d, 0x3f, 0xc3, 0x4b, 0xb7,
|
||||
0xec, 0xfa, 0x5a, 0x14, 0x03, 0xcb, 0x64, 0xc8, 0x34, 0x4a, 0x4b, 0x6e, 0xf8, 0x6e, 0x56,
|
||||
0xf6, 0xdd, 0x5f, 0xa1, 0x24, 0xe2, 0xd4, 0xd0, 0x82, 0x64, 0x1f, 0x8e, 0x9b, 0xfa, 0xb4,
|
||||
0xcb, 0xdb, 0x0a, 0xe8, 0x15, 0xfc, 0x15, 0xab, 0x4b, 0x18, 0xbf, 0xd4, 0x42, 0x14, 0x48,
|
||||
0x82, 0x85, 0xdd, 0xeb, 0x49, 0x1b, 0x0b, 0x0b, 0x05, 0xe9, 0xb4, 0xa1, 0x33, 0x0a, 0x5d,
|
||||
0x0e, 0x6c, 0x4b, 0xc0, 0xd6, 0x6c, 0x7c, 0xfb, 0x69, 0x0b, 0x53, 0x19, 0xe4, 0xf3, 0x35,
|
||||
0xfc, 0xbe, 0xa1, 0x34, 0x02, 0x09, 0x4f, 0x74, 0x86, 0x92, 0xcd, 0x5d, 0x1a, 0xc1, 0x27,
|
||||
0x0c, 0xf2, 0xc5, 0xcf, 0xdd, 0x23, 0x93, 0x02, 0xbd, 0x41, 0x5e, 0x42, 0xf0, 0xa0, 0x9d,
|
||||
0x0c, 0x72, 0xc8, 0xec, 0x32, 0x0a, 0x8a, 0xfd, 0x3d, 0x5a, 0x41, 0x27, 0x0c, 0x88, 0x59,
|
||||
0xad, 0x94, 0x2e, 0xef, 0x5d, 0x8f, 0xc7, 0xdf, 0x66, 0xe4, 0xdd, 0x56, 0x6c, 0x7b, 0xca,
|
||||
0x55, 0x81, 0xae, 0xae, 0x5c, 0x1b, 0x1a, 0xab, 0xae, 0x99, 0x8d, 0xcc, 0x42, 0x97, 0x59,
|
||||
0xf4, 0x14, 0x3f, 0x75, 0xc6, 0xd1, 0x88, 0xba, 0xaa, 0x84, 0x4a, 0xd0, 0x34, 0x08, 0x3b,
|
||||
0x7d, 0xdb, 0x15, 0x06, 0xb0, 0x5c, 0xbd, 0x40, 0xf5, 0xa8, 0xec, 0xae, 0x36, 0x40, 0xdd,
|
||||
0x90, 0x1c, 0x3e, 0x0d, 0x7e, 0x73, 0xc7, 0xc2, 0xc5, 0x6a, 0xff, 0x52, 0x05, 0x7f, 0xbe,
|
||||
0xd0, 0x92, 0xfd, 0xb3, 0x6f, 0xff, 0x5d, 0xb7, 0x97, 0x64, 0x73, 0x7b, 0xca, 0xd1, 0x98,
|
||||
0x24, 0x6b, 0x0b, 0x01, 0x68, 0xdd, 0x27, 0x85, 0x85, 0xb5, 0x83, 0xc1, 0xe0, 0x50, 0x64,
|
||||
0xc7, 0xaf, 0xf1, 0xc6, 0x4d, 0xb1, 0xef, 0xc9, 0xb4, 0x0a, 0x6d, 0x65, 0xf3, 0x47, 0xcc,
|
||||
0xa3, 0x02, 0x21, 0x0c, 0xbe, 0x22, 0x29, 0x05, 0xcf, 0x5f, 0xe8, 0x94, 0x6c, 0xe5, 0xdc,
|
||||
0xc4, 0xdf, 0xbe, 0x3e, 0xa8, 0xb4, 0x18, 0xb0, 0x99, 0xb8, 0x6f, 0xff, 0x5d, 0xb9, 0xfd,
|
||||
0x3b, 0x5d, 0x16, 0xbf, 0x3e, 0xd8, 0xb3, 0xd8, 0x08, 0x34, 0xf6, 0x47, 0x35, 0x5b, 0x72,
|
||||
0x1a, 0x33, 0xad, 0x52, 0x5d, 0xb8, 0xd0, 0x77, 0xc6, 0xab, 0xba, 0x55, 0x09, 0x5f, 0x02,
|
||||
0xf8, 0xd4, 0x5f, 0x53, 0x06, 0x91, 0xcd, 0x74, 0x42, 0xae, 0x54, 0x91, 0x81, 0x62, 0x13,
|
||||
0x6f, 0xd8, 0xa9, 0x77, 0xc3, 0x6c, 0xcb, 0xf1, 0x29, 0x5a, 0xcc, 0xda, 0x35, 0xbd, 0x52,
|
||||
0x23, 0xbe, 0x59, 0xeb, 0x12, 0x6d, 0xb7, 0x53, 0xee, 0xfc, 0xb4, 0x1b, 0x13, 0x5e, 0xba,
|
||||
0x16, 0x7c, 0xc5, 0xf3, 0xe3, 0x6d, 0x07, 0x78, 0xf5, 0x2b, 0x21, 0x05, 0x88, 0x4c, 0xc0,
|
||||
0xa1, 0xe3, 0x36, 0x10, 0xf8, 0x1b, 0xd8, 0x17, 0xfb, 0x6a, 0x4e, 0xd8, 0xb3, 0x47, 0x2d,
|
||||
0x99, 0xbd, 0xbb, 0x5d, 0x37, 0x7d, 0xba, 0xf1, 0xe1, 0x7c, 0xc0, 0xc5, 0x54, 0x62, 0x7f,
|
||||
0xcf, 0x5a, 0x4a, 0x93, 0xcc, 0xf1, 0x1b, 0x34, 0xc8, 0xa6, 0x05, 0x4c, 0x55, 0x8b, 0x54,
|
||||
0x84, 0xd5, 0x77, 0xeb, 0xc0, 0x6d, 0x3a, 0x29, 0xbd, 0x75, 0x61, 0x09, 0x9a, 0x2c, 0xbb,
|
||||
0xf7, 0x18, 0x79, 0x34, 0x90, 0x24, 0xa5, 0x81, 0x70, 0x87, 0xc5, 0x02, 0x7c, 0xba, 0xd4,
|
||||
0x5e, 0x14, 0x8e, 0xe4, 0xed, 0xa2, 0x61, 0x6a, 0xb9, 0x6e, 0xb5, 0x4a, 0xb9, 0x01, 0x46,
|
||||
0xf4, 0xcf, 0xbc, 0x09, 0x2f, 0x27, 0x4b, 0xbd, 0x86, 0x7a, 0x10, 0xe1, 0xd4, 0xc8, 0xd9,
|
||||
0x20, 0x8d, 0x8a, 0x63, 0x00, 0x63, 0x44, 0xeb, 0x54, 0x0b, 0x75, 0x49, 0x10, 0xa2, 0xa7,
|
||||
0xad, 0xb9, 0xd1, 0x01, 0x80, 0x63, 0x25, 0xc8, 0x12, 0xa6, 0xce, 0x1e, 0xbe, 0xfe, 0x7e,
|
||||
0x5f, 0x3c, 0xdb, 0x34, 0xea, 0x37, 0xec, 0x3b, 0xd5, 0x28, 0xd2, 0x07, 0x8c, 0x9a, 0xb6,
|
||||
0xee, 0x5e, 0x3e, 0xdf, 0x1d, 0x99, 0xb0, 0xe2, 0x46, 0xef, 0x5c, 0x1b, 0xb4, 0xea, 0x56,
|
||||
0x2e, 0xde, 0x1f, 0x9d, 0xb8, 0xd3, 0x24, 0xab, 0xd4, 0x2a, 0xd6, 0x2e, 0xde, 0x1f, 0x9d,
|
||||
0xb8, 0xf2, 0x66, 0x2f, 0xbd, 0xf8, 0x72, 0x66, 0x4e, 0x1e, 0x9f, 0x9d, 0xb8, 0xf2, 0x47,
|
||||
0x0c, 0x9a, 0xb6, 0xee, 0x3f, 0xfc, 0x7a, 0x57, 0x0d, 0x79, 0x70, 0x62, 0x27, 0xad, 0xb9,
|
||||
0xd1, 0x01, 0x61, 0x40, 0x02, 0x67, 0x2d, 0xd8, 0x32, 0xe6, 0x2f, 0xdc, 0x3a, 0xd7, 0x2c,
|
||||
0xbb, 0xf4, 0x4b, 0xf5, 0x49, 0xf1, 0x60, 0x23, 0xc4, 0x0a, 0x77, 0x4d, 0xf9, 0x51, 0x01,
|
||||
0x80, 0x63, 0x25, 0xa9, 0xb1, 0xe0, 0x42, 0xe7, 0x4c, 0x1a, 0x97, 0xac, 0xbb, 0xf4, 0x6a,
|
||||
0x37, 0xcd, 0x18, 0xb2, 0xe6, 0x2f, 0xdc, 0x1b, 0x95, 0xa8, 0xd2, 0x07, 0x6d, 0x58, 0x32,
|
||||
0xe6, 0x4e, 0x1e, 0x9f, 0xbc, 0xfa, 0x57, 0x0d, 0x79, 0x51, 0x20, 0xc2, 0x06, 0x6f, 0x5c,
|
||||
0x1b, 0x95, 0xa8, 0xb3, 0xc5, 0xe9, 0x31, 0xe0, 0x23, 0xc4, 0x0a, 0x77, 0x4d, 0x18, 0x93,
|
||||
0x85, 0x69, 0x31, 0xc1, 0xe1, 0x21, 0xc0, 0xe3, 0x44, 0x0a, 0x77, 0x6c, 0x5a, 0x17, 0x8d,
|
||||
0x98, 0x93, 0xa4, 0xab, 0xd4, 0x2a, 0xb7, 0xec, 0x5a, 0x17, 0xac, 0xbb, 0xf4, 0x4b, 0x14,
|
||||
0xaa, 0xb7, 0xec, 0x3b, 0xd5, 0x28, 0xb3, 0xc5, 0xe9, 0x31, 0xc1, 0x00, 0x82, 0x67, 0x4c,
|
||||
0xfb, 0x55, 0x28, 0xd2, 0x26, 0xaf, 0xbd, 0xd9, 0x11, 0x81, 0x61, 0x21, 0xa1, 0xa1, 0xc0,
|
||||
0x02, 0x86, 0x6f, 0x5c, 0x1b, 0xb4, 0xcb, 0x14, 0x8b, 0x94, 0xaa, 0xd6, 0x2e, 0xbf, 0xdd,
|
||||
0x19, 0xb0, 0xe2, 0x46, 0x0e, 0x7f, 0x7c, 0x5b, 0x15, 0x89, 0x90, 0x83, 0x84, 0x6b, 0x54,
|
||||
0x0b, 0x75, 0x68, 0x52, 0x07, 0x6d, 0x58, 0x32, 0xc7, 0xed, 0x58, 0x32, 0xc7, 0xed, 0x58,
|
||||
0x32, 0xe6, 0x4e, 0xff, 0x7c, 0x7a, 0x76, 0x6e, 0x3f, 0xdd, 0x38, 0xd3, 0x05, 0x88, 0x92,
|
||||
0xa6, 0xaf, 0xdc, 0x1b, 0xb4, 0xcb, 0xf5, 0x68, 0x52, 0x07, 0x8c, 0x7b, 0x55, 0x09, 0x90,
|
||||
0x83, 0x84, 0x6b, 0x54, 0x2a, 0xb7, 0xec, 0x3b, 0xd5, 0x09, 0x90, 0xa2, 0xc6, 0x0e, 0x7f,
|
||||
0x7c, 0x7a, 0x57, 0x0d, 0x98, 0xb2, 0xc7, 0xed, 0x58, 0x32, 0xc7, 0x0c, 0x7b, 0x74, 0x4b,
|
||||
0x14, 0x8b, 0x94, 0xaa, 0xb7, 0xcd, 0x18, 0x93, 0xa4, 0xca, 0x16, 0xae, 0xbf, 0xdd, 0x19,
|
||||
0xb0, 0xe2, 0x46, 0x0e, 0x7f, 0x5d, 0x19, 0x91, 0x81, 0x80, 0x63, 0x44, 0xeb, 0x35, 0xc9,
|
||||
0x10, 0x83, 0x65, 0x48, 0x12, 0xa6, 0xce, 0x1e, 0x9f, 0xbc, 0xdb, 0x15, 0x89, 0x71, 0x60,
|
||||
0x23, 0xc4, 0xeb, 0x54, 0x2a, 0xb7, 0xec, 0x5a, 0x36, 0xcf, 0x81, 0x10, 0xac, 0x74
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
|
||||
+1
-18
@@ -26,21 +26,4 @@ void soft_serial_initiator_init(void);
|
||||
// target is interrupt accept side
|
||||
void soft_serial_target_init(void);
|
||||
|
||||
// initiator result
|
||||
#define TRANSACTION_END 0
|
||||
#define TRANSACTION_NO_RESPONSE 0x1
|
||||
#define TRANSACTION_DATA_ERROR 0x2
|
||||
#define TRANSACTION_TYPE_ERROR 0x4
|
||||
int soft_serial_transaction(int sstd_index);
|
||||
|
||||
// target status
|
||||
// *SSTD_t.status has
|
||||
// initiator:
|
||||
// TRANSACTION_END
|
||||
// or TRANSACTION_NO_RESPONSE
|
||||
// or TRANSACTION_DATA_ERROR
|
||||
// target:
|
||||
// TRANSACTION_DATA_ERROR
|
||||
// or TRANSACTION_ACCEPTED
|
||||
#define TRANSACTION_ACCEPTED 0x8
|
||||
int soft_serial_get_and_clean_status(int sstd_index);
|
||||
bool soft_serial_transaction(int sstd_index);
|
||||
|
||||
@@ -20,7 +20,7 @@ BACKLIGHT_ENABLE = no # Enable keyboard backlight functionality
|
||||
RGBLIGHT_ENABLE = no # Enable keyboard RGB underglow
|
||||
AUDIO_ENABLE = no # Audio output
|
||||
BLUETOOTH_ENABLE = yes
|
||||
BLUETOOTH_DRIVER = AdafruitBLE
|
||||
BLUETOOTH_DRIVER = BluefruitLE
|
||||
OLED_ENABLE = yes
|
||||
OLED_DRIVER = SSD1306
|
||||
ENCODER_ENABLE = yes
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
|
||||
Make example for this keyboard (after setting up your build environment):
|
||||
|
||||
make aleth42:default
|
||||
make 25keys/aleth42/rev1:default
|
||||
|
||||
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
|
||||
@@ -0,0 +1 @@
|
||||
DEFAULT_FOLDER = 25keys/aleth42/rev1
|
||||
@@ -49,4 +49,4 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
# define RGBLIGHT_ANIMATIONS
|
||||
#endif
|
||||
|
||||
#define OLED_FONT_H "keyboards/cassette42/common/glcdfont.c"
|
||||
#define OLED_FONT_H "keyboards/25keys/cassette42/common/glcdfont.c"
|
||||
@@ -10,6 +10,6 @@ An audio control pad with 4 switches and 2 rotary encoders.
|
||||
|
||||
Make example for this keyboard (after setting up your build environment):
|
||||
|
||||
make cassette42:default
|
||||
make 25keys/cassette42:default
|
||||
|
||||
See the [build environment setup](https://docs.qmk.fm/#/getting_started_build_tools) and the [make instructions](https://docs.qmk.fm/#/getting_started_make_guide) for more information. Brand new to QMK? Start with our [Complete Newbs Guide](https://docs.qmk.fm/#/newbs).
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user