forked from mirrors/qmk_firmware
Compare commits
557 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c586cfda48 | ||
|
|
c39a902867 | ||
|
|
2202efaf0c | ||
|
|
536511a32a | ||
|
|
8de0427fec | ||
|
|
0e81d63b64 | ||
|
|
de10784799 | ||
|
|
f1671ec720 | ||
|
|
b9c7d4c48d | ||
|
|
d681eac0ad | ||
|
|
5a0e47db5e | ||
|
|
bfed88dba2 | ||
|
|
4ca99af8f5 | ||
|
|
5f32690cba | ||
|
|
5c90732622 | ||
|
|
6081a8091d | ||
|
|
7f0581cd35 | ||
|
|
d510e80b89 | ||
|
|
4efe6330c4 | ||
|
|
493d422406 | ||
|
|
a6d70de96a | ||
|
|
9a31bbb3fa | ||
|
|
05f30f0787 | ||
|
|
ab45e3b993 | ||
|
|
62e3f8b885 | ||
|
|
1db5272154 | ||
|
|
ee17ffadea | ||
|
|
adfa36fee4 | ||
|
|
55f16167e4 | ||
|
|
fa44f2b21e | ||
|
|
00c8e24c6a | ||
|
|
12eb6444c6 | ||
|
|
6992efb229 | ||
|
|
a7893f207d | ||
|
|
d0c095eec2 | ||
|
|
32512bbf10 | ||
|
|
d458df7698 | ||
|
|
819231afe1 | ||
|
|
7a10c3370f | ||
|
|
1bf95d60e4 | ||
|
|
1cdde7ba6a | ||
|
|
59c7b15b4d | ||
|
|
e8b14a52de | ||
|
|
7aea67980b | ||
|
|
c3f1ba7dd1 | ||
|
|
eabbc04213 | ||
|
|
627e35b7ac | ||
|
|
0e4f953976 | ||
|
|
c10d0fc785 | ||
|
|
11cfc8a0b6 | ||
|
|
4be736c192 | ||
|
|
42eff8c372 | ||
|
|
32cc8a7f43 | ||
|
|
a444ccd27c | ||
|
|
a304a9b51e | ||
|
|
4779539543 | ||
|
|
931c7539d2 | ||
|
|
4f7be48758 | ||
|
|
747b33cb81 | ||
|
|
96c92d208f | ||
|
|
6025df79b3 | ||
|
|
a1fb1405e4 | ||
|
|
37cd5ad810 | ||
|
|
859c1a6fc9 | ||
|
|
4e5cc3c2ba | ||
|
|
54be228882 | ||
|
|
28f9def219 | ||
|
|
06e93a8f5c | ||
|
|
05f6838f37 | ||
|
|
e50b1d33f3 | ||
|
|
92c3e6305b | ||
|
|
de545b8e21 | ||
|
|
4d443d921b | ||
|
|
9fa14655df | ||
|
|
847cca541c | ||
|
|
580bcff4f6 | ||
|
|
f5e16f94d5 | ||
|
|
9cdccb12d1 | ||
|
|
c8ce87e044 | ||
|
|
66983f090c | ||
|
|
abdca8847d | ||
|
|
1f93485aef | ||
|
|
c84f68d4c8 | ||
|
|
303992da70 | ||
|
|
82f806b1ab | ||
|
|
f5333e9136 | ||
|
|
38cd3684e1 | ||
|
|
ba4ba66b2f | ||
|
|
ce2dbe17b5 | ||
|
|
09b0d3e0ed | ||
|
|
c79818e703 | ||
|
|
0ececbcdb7 | ||
|
|
64d2097a27 | ||
|
|
3c6765b21c | ||
|
|
f54a55dcfe | ||
|
|
16c91e0cf2 | ||
|
|
15c09335e9 | ||
|
|
807620fa3c | ||
|
|
7501523e1f | ||
|
|
be56817743 | ||
|
|
d547c0bea7 | ||
|
|
2d7de91888 | ||
|
|
8ee42cd6c4 | ||
|
|
67f9777b8f | ||
|
|
2f73e65837 | ||
|
|
1862ac5454 | ||
|
|
da4689d6b5 | ||
|
|
300dab7962 | ||
|
|
2efad277ee | ||
|
|
3c58f98929 | ||
|
|
82685fc2ac | ||
|
|
928be32c83 | ||
|
|
9b04e9be04 | ||
|
|
acc11f4941 | ||
|
|
633df1f365 | ||
|
|
99e9e1b8e7 | ||
|
|
ce2ac433d9 | ||
|
|
4ef0c8230c | ||
|
|
2cdaa639ee | ||
|
|
f7510ca202 | ||
|
|
6eac98286a | ||
|
|
dc70ba612a | ||
|
|
2a0d490eb3 | ||
|
|
d98f309429 | ||
|
|
09e4001bba | ||
|
|
4b108f7689 | ||
|
|
acf114315e | ||
|
|
b21a52c824 | ||
|
|
2468be889b | ||
|
|
2a3cd98fc6 | ||
|
|
bc385435a7 | ||
|
|
320219d5d8 | ||
|
|
38c8fc9baf | ||
|
|
63154631ab | ||
|
|
0052b03ee0 | ||
|
|
4f4e72e44c | ||
|
|
98312417b5 | ||
|
|
068d5688d8 | ||
|
|
2271b28386 | ||
|
|
590c2342fc | ||
|
|
f80bb4a517 | ||
|
|
b99ccd4f06 | ||
|
|
1dfe2bb49a | ||
|
|
34fec2c07d | ||
|
|
5a126e1a74 | ||
|
|
a991d65e87 | ||
|
|
018fad6b95 | ||
|
|
019bfc4159 | ||
|
|
8a1ca7f6b8 | ||
|
|
dfff040433 | ||
|
|
f9724dfa67 | ||
|
|
e68de95214 | ||
|
|
27dd4dc91e | ||
|
|
5bc81d3a63 | ||
|
|
5db705d054 | ||
|
|
904ec0ce78 | ||
|
|
7a090bb3df | ||
|
|
9d6a94cfb5 | ||
|
|
257fc042df | ||
|
|
36c2575658 | ||
|
|
6bb2ed68a8 | ||
|
|
26954bbc28 | ||
|
|
82f0263e41 | ||
|
|
2a3dd95229 | ||
|
|
ffb34fc082 | ||
|
|
45ffe42f1a | ||
|
|
bbd6ea977c | ||
|
|
a768ec265d | ||
|
|
2714c70bd7 | ||
|
|
b78a7e42b1 | ||
|
|
9a41a303cc | ||
|
|
85cdde1541 | ||
|
|
7c3b6c4bc4 | ||
|
|
61df87ae2c | ||
|
|
52e9ed75e8 | ||
|
|
2bb0550707 | ||
|
|
51b7828540 | ||
|
|
61a5059fc5 | ||
|
|
6663dd7288 | ||
|
|
3f5dc47296 | ||
|
|
57021d6358 | ||
|
|
61ce15f202 | ||
|
|
5925ea3478 | ||
|
|
c8f969a3ce | ||
|
|
5e750cf039 | ||
|
|
2dab029bcf | ||
|
|
7a73f9a6b3 | ||
|
|
5e347f42a6 | ||
|
|
5389f088b1 | ||
|
|
2e567150ea | ||
|
|
16b837b35b | ||
|
|
0348071810 | ||
|
|
35d78aa8a4 | ||
|
|
0bee7cbebe | ||
|
|
a5eeee4ded | ||
|
|
a15e44cfb3 | ||
|
|
2106acc24a | ||
|
|
39e1e27ea9 | ||
|
|
561c5e1d7a | ||
|
|
13b2b93fb0 | ||
|
|
30f2556ae9 | ||
|
|
06310e81e9 | ||
|
|
345e19f691 | ||
|
|
81d317aa87 | ||
|
|
b0c3d61c17 | ||
|
|
e724801d33 | ||
|
|
643f6367a1 | ||
|
|
8224f62806 | ||
|
|
cca5d35321 | ||
|
|
d9bb189e25 | ||
|
|
8f086faf8a | ||
|
|
0d30565bb7 | ||
|
|
744af003be | ||
|
|
29a2bac469 | ||
|
|
0e5d67145a | ||
|
|
5cad58dfa9 | ||
|
|
75bc9e6496 | ||
|
|
d37db0c50c | ||
|
|
8fa7b62011 | ||
|
|
e68205db1b | ||
|
|
9a157a3a99 | ||
|
|
b7fee11e34 | ||
|
|
63474e2c17 | ||
|
|
168a631720 | ||
|
|
7d89dfe2dc | ||
|
|
d87d537b50 | ||
|
|
6154c184a8 | ||
|
|
665feccca1 | ||
|
|
e8c46fab96 | ||
|
|
1c43410e26 | ||
|
|
03909b8a3f | ||
|
|
a3119385a4 | ||
|
|
2d5047a79c | ||
|
|
c5215d4a06 | ||
|
|
4ba5102a50 | ||
|
|
c8a78b1f04 | ||
|
|
f2d4424bb7 | ||
|
|
fb40abe2f2 | ||
|
|
ce29cb0f10 | ||
|
|
fbf3cbcd5c | ||
|
|
4d243e94fa | ||
|
|
71f9a07b0f | ||
|
|
6a0814bb04 | ||
|
|
4b7c01c84b | ||
|
|
3ed4a7086e | ||
|
|
8744d57578 | ||
|
|
43e33ba232 | ||
|
|
5f11d7b554 | ||
|
|
2011aec06f | ||
|
|
ba1f184267 | ||
|
|
bb1edf6676 | ||
|
|
a41c5d8023 | ||
|
|
4804b73540 | ||
|
|
6c7d549e31 | ||
|
|
40d295abf6 | ||
|
|
efd41fe9df | ||
|
|
18a1cbce75 | ||
|
|
f346c8400c | ||
|
|
36de989e6f | ||
|
|
9b8ae05796 | ||
|
|
b56edb5f11 | ||
|
|
b9a6126518 | ||
|
|
1b9491f8f3 | ||
|
|
ea14a93718 | ||
|
|
ac5e6b6a3b | ||
|
|
5108d53169 | ||
|
|
97dfdcb2bd | ||
|
|
11299b337b | ||
|
|
d694488e2e | ||
|
|
25033d5d9e | ||
|
|
f083eb1a37 | ||
|
|
1cffe5b6ce | ||
|
|
61eca0c972 | ||
|
|
7c64a2bcaa | ||
|
|
7de801ed9a | ||
|
|
81b7d6f67f | ||
|
|
3871c717da | ||
|
|
60ab61386e | ||
|
|
0c74892e90 | ||
|
|
326d3ffad8 | ||
|
|
5ac71ef27a | ||
|
|
1bf67b808d | ||
|
|
2aa4f7cf61 | ||
|
|
d9e311ad30 | ||
|
|
783d1cd458 | ||
|
|
c1d9f9911c | ||
|
|
7e926f5c93 | ||
|
|
e25879e836 | ||
|
|
414a387f22 | ||
|
|
d66b5db1d6 | ||
|
|
84d9996b6d | ||
|
|
5a727dbc6d | ||
|
|
a6faf3bc9e | ||
|
|
0365f640af | ||
|
|
fcc14b8838 | ||
|
|
4e35697e1a | ||
|
|
ec6875af56 | ||
|
|
bf44fc81bd | ||
|
|
feea704da7 | ||
|
|
5f16a4ec62 | ||
|
|
0c84dd6bdc | ||
|
|
fd883890af | ||
|
|
3059d7883c | ||
|
|
90ad47b1f2 | ||
|
|
07f6fba6de | ||
|
|
4a3e0ef9ab | ||
|
|
f996a4c5b7 | ||
|
|
56ecc86482 | ||
|
|
6285a1c0d3 | ||
|
|
627f9321a8 | ||
|
|
882eadd94d | ||
|
|
7a5f76d40a | ||
|
|
4aca94d247 | ||
|
|
7a8a4b1938 | ||
|
|
3b14383f48 | ||
|
|
5699763d4c | ||
|
|
5c5610074a | ||
|
|
ac333016eb | ||
|
|
fa0aea2a5a | ||
|
|
a80943579c | ||
|
|
65832c0fc3 | ||
|
|
ef633cf461 | ||
|
|
b8e8a20ca6 | ||
|
|
3ecb0a80af | ||
|
|
7e41eb0277 | ||
|
|
871eeae4ea | ||
|
|
9c2505676c | ||
|
|
c7d8adfeaa | ||
|
|
f03aec28fb | ||
|
|
5d711c89c3 | ||
|
|
c3ef70b9a6 | ||
|
|
ca0a9d243c | ||
|
|
8b78fac451 | ||
|
|
8c4a5f9ba2 | ||
|
|
08721b4125 | ||
|
|
ee26d3e77f | ||
|
|
5d1bc92c64 | ||
|
|
a80461e264 | ||
|
|
0112938140 | ||
|
|
2af2c5e109 | ||
|
|
a7179b188d | ||
|
|
48721b20fc | ||
|
|
59e28b8958 | ||
|
|
9dc7b9d40c | ||
|
|
0856b36139 | ||
|
|
c725f6f768 | ||
|
|
c679decb2b | ||
|
|
2f11509465 | ||
|
|
6b21f8369e | ||
|
|
69f0fc5868 | ||
|
|
6f1eca9c7b | ||
|
|
f8a56cd638 | ||
|
|
05074cbdf0 | ||
|
|
096db8c8ca | ||
|
|
6fce400ef5 | ||
|
|
a949d32072 | ||
|
|
3842b15cf1 | ||
|
|
5d8b6847c7 | ||
|
|
f2f88bcfcc | ||
|
|
a9af4c928e | ||
|
|
fd44341cbf | ||
|
|
92c0b29be9 | ||
|
|
f439fe6055 | ||
|
|
e3cad4045a | ||
|
|
0eab24be26 | ||
|
|
93e657fa99 | ||
|
|
578a3e3505 | ||
|
|
5846b40f74 | ||
|
|
9f1c4f304d | ||
|
|
3def7b98d4 | ||
|
|
b67ae67687 | ||
|
|
d6c39490df | ||
|
|
a61e549a31 | ||
|
|
dfb23456b1 | ||
|
|
03630db506 | ||
|
|
5936e05a33 | ||
|
|
2f2d3e9c7b | ||
|
|
a98f69850f | ||
|
|
e5a15f404d | ||
|
|
77d960cce3 | ||
|
|
d717396708 | ||
|
|
d206c1791e | ||
|
|
4f124574f1 | ||
|
|
fb05b491e7 | ||
|
|
34e244cecf | ||
|
|
1204cbb7ea | ||
|
|
dcdc7290e5 | ||
|
|
f7eb7926e8 | ||
|
|
0151f4c307 | ||
|
|
1f61fb33b4 | ||
|
|
2daad28ab1 | ||
|
|
54383674db | ||
|
|
33b62b6867 | ||
|
|
01ecf332ff | ||
|
|
0d013a21e1 | ||
|
|
01bc974365 | ||
|
|
60cbb25148 | ||
|
|
99614bd89a | ||
|
|
e30cd0fa16 | ||
|
|
c43e89bb4a | ||
|
|
3c9f27e1c9 | ||
|
|
3b9e186019 | ||
|
|
0e60b3a620 | ||
|
|
7060cb7b26 | ||
|
|
2239527871 | ||
|
|
32792826a8 | ||
|
|
25b5c2c538 | ||
|
|
d3858585ac | ||
|
|
a0f857b7a2 | ||
|
|
2f9145c6ea | ||
|
|
b02f178c06 | ||
|
|
9aa9155e88 | ||
|
|
eac0f6d4c9 | ||
|
|
2e27eb318e | ||
|
|
8ea9f13c67 | ||
|
|
b450ffc5c6 | ||
|
|
267864e42c | ||
|
|
86bfd8195c | ||
|
|
608404f874 | ||
|
|
be42c5fb98 | ||
|
|
2d7a2dfad0 | ||
|
|
65fcf951d3 | ||
|
|
d116cf5e9a | ||
|
|
2b23ca876d | ||
|
|
503b40e748 | ||
|
|
52c1517766 | ||
|
|
1a400d8644 | ||
|
|
4c39bad2e6 | ||
|
|
a6eeb930ae | ||
|
|
3370e2b74d | ||
|
|
589e756e98 | ||
|
|
2fb24c0298 | ||
|
|
93ee789387 | ||
|
|
6a81cb44f2 | ||
|
|
2703ecc9e9 | ||
|
|
62eaec52e0 | ||
|
|
36d60769f8 | ||
|
|
2bddffeaec | ||
|
|
4e3db51e92 | ||
|
|
c725b6bf89 | ||
|
|
d6eff188e9 | ||
|
|
7f8886a1b7 | ||
|
|
0da6562c4d | ||
|
|
cfcd647b2e | ||
|
|
17ec1650fd | ||
|
|
7b3ee1db8c | ||
|
|
fe680a8568 | ||
|
|
6d67e9df4b | ||
|
|
e44604c256 | ||
|
|
00872ea7e7 | ||
|
|
c251d88934 | ||
|
|
4610a6bf49 | ||
|
|
999b91fbd9 | ||
|
|
9e35a1f617 | ||
|
|
4e8b864258 | ||
|
|
e312fa44e2 | ||
|
|
0b1bed1d41 | ||
|
|
ef80a1dd67 | ||
|
|
050fa9062f | ||
|
|
fa9ecc431d | ||
|
|
cac5f96275 | ||
|
|
fa8fb60279 | ||
|
|
589bdedc47 | ||
|
|
6e10a80174 | ||
|
|
c40af06871 | ||
|
|
81d2218cee | ||
|
|
85d84938cf | ||
|
|
adf4c27db2 | ||
|
|
4cde5c243b | ||
|
|
87e1ff218d | ||
|
|
2f4c7697a9 | ||
|
|
84d3575fdb | ||
|
|
1706da9054 | ||
|
|
b17324498e | ||
|
|
0c82aafb8a | ||
|
|
577e9d89fa | ||
|
|
d21ee22cc5 | ||
|
|
5ba04d1204 | ||
|
|
10345adaa5 | ||
|
|
0d64038b73 | ||
|
|
d288121f21 | ||
|
|
191c180644 | ||
|
|
90765aaefd | ||
|
|
0d991b8873 | ||
|
|
1a7a6f313e | ||
|
|
af6435d44d | ||
|
|
5887bf7158 | ||
|
|
80034a847f | ||
|
|
568924c76c | ||
|
|
0fd08da806 | ||
|
|
d05a1deb7c | ||
|
|
6b838785b7 | ||
|
|
97fc4f1b6a | ||
|
|
738cec9bd5 | ||
|
|
ef8a30250b | ||
|
|
ed15a579a7 | ||
|
|
c84d058c8b | ||
|
|
e5e2cd94be | ||
|
|
474b4083ae | ||
|
|
c5f26b0e9a | ||
|
|
d2abfaeacd | ||
|
|
0ab51ee29d | ||
|
|
84944df6a6 | ||
|
|
728f7308af | ||
|
|
0e2009c669 | ||
|
|
8a6fd0dc7e | ||
|
|
1e1f387be7 | ||
|
|
1085500e89 | ||
|
|
6df5fce073 | ||
|
|
5141d6eeb1 | ||
|
|
fe08bbc4a0 | ||
|
|
da1c562ddf | ||
|
|
36109a887a | ||
|
|
b74509d4ae | ||
|
|
9d226b92a8 | ||
|
|
11836128fc | ||
|
|
6f82647e8d | ||
|
|
85b3b98570 | ||
|
|
e89478eb0f | ||
|
|
6221c86186 | ||
|
|
d6402fe9fb | ||
|
|
08c556b78b | ||
|
|
af84772a5f | ||
|
|
b1a3f806f5 | ||
|
|
bb324e5b3e | ||
|
|
267f392237 | ||
|
|
b94baa8bc3 | ||
|
|
86e93d7654 | ||
|
|
344b8410f7 | ||
|
|
8bb2c66c88 | ||
|
|
73bd3dff8c | ||
|
|
af02baae78 | ||
|
|
f9e97fd3c3 | ||
|
|
38839a9105 | ||
|
|
6fdce80822 | ||
|
|
bbab8eb993 | ||
|
|
ecce9900c9 | ||
|
|
d44a950c10 | ||
|
|
8545473307 | ||
|
|
9e2fe4eff6 | ||
|
|
e869d089b7 | ||
|
|
f663f84413 | ||
|
|
044486500c | ||
|
|
a099579aa0 | ||
|
|
67e80780bb | ||
|
|
6e4e50d5aa | ||
|
|
2de70e6f2d | ||
|
|
31fb141528 | ||
|
|
6b640db4bb | ||
|
|
e4be4d282c | ||
|
|
9a2943d221 | ||
|
|
f03fe5b917 | ||
|
|
6123698270 | ||
|
|
a765f730b1 | ||
|
|
3ce029c7fd | ||
|
|
87c3a53716 | ||
|
|
103c08cc75 |
3
.github/dependabot.yml
vendored
3
.github/dependabot.yml
vendored
@@ -2,5 +2,8 @@ version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
labels: CI
|
||||
reviewers:
|
||||
- "qmk/collaborators"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
|
||||
2
.github/workflows/docs.yml
vendored
2
.github/workflows/docs.yml
vendored
@@ -34,7 +34,7 @@ jobs:
|
||||
qmk --verbose generate-docs
|
||||
|
||||
- name: Deploy
|
||||
uses: JamesIves/github-pages-deploy-action@v4.3.4
|
||||
uses: JamesIves/github-pages-deploy-action@v4.4.0
|
||||
with:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
BASE_BRANCH: master
|
||||
|
||||
19
.gitignore
vendored
19
.gitignore
vendored
@@ -5,6 +5,10 @@
|
||||
.DS_Store
|
||||
._*
|
||||
|
||||
# Merge files
|
||||
*.orig
|
||||
*.rej
|
||||
|
||||
# Build artifacts
|
||||
.clang_complete
|
||||
.build/
|
||||
@@ -27,16 +31,11 @@ quantum/version.h
|
||||
*.uf2
|
||||
|
||||
# Old-style QMK Makefiles
|
||||
/keyboards/*/Makefile
|
||||
/keyboards/*/*/Makefile
|
||||
/keyboards/*/*/*/Makefile
|
||||
/keyboards/*/*/*/*/Makefile
|
||||
/keyboards/*/*/*/*/*/Makefile
|
||||
/keyboards/*/keymaps/Makefile
|
||||
/keyboards/*/*/keymaps/Makefile
|
||||
/keyboards/*/*/*/keymaps/Makefile
|
||||
/keyboards/*/*/*/*/keymaps/Makefile
|
||||
/keyboards/*/*/*/*/*/keymaps/Makefile
|
||||
/keyboards/**/Makefile
|
||||
|
||||
# kbfirmware....
|
||||
/keyboards/**/kb.h
|
||||
/keyboards/**/kb.c
|
||||
|
||||
# Eclipse/PyCharm/Other IDE Settings
|
||||
*.iml
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -18,3 +18,6 @@
|
||||
[submodule "lib/printf"]
|
||||
path = lib/printf
|
||||
url = https://github.com/qmk/printf
|
||||
[submodule "lib/pico-sdk"]
|
||||
path = lib/pico-sdk
|
||||
url = https://github.com/qmk/pico-sdk.git
|
||||
|
||||
1
Makefile
1
Makefile
@@ -401,6 +401,7 @@ ifndef SKIP_GIT
|
||||
if [ ! -e lib/lufa ]; then git submodule sync lib/lufa && git submodule update --depth 50 --init lib/lufa; fi
|
||||
if [ ! -e lib/vusb ]; then git submodule sync lib/vusb && git submodule update --depth 50 --init lib/vusb; fi
|
||||
if [ ! -e lib/printf ]; then git submodule sync lib/printf && git submodule update --depth 50 --init lib/printf; fi
|
||||
if [ ! -e lib/pico-sdk ]; then git submodule sync lib/pico-sdk && git submodule update --depth 50 --init lib/pico-sdk; fi
|
||||
git submodule status --recursive 2>/dev/null | \
|
||||
while IFS= read -r x; do \
|
||||
case "$$x" in \
|
||||
|
||||
@@ -105,8 +105,8 @@ ifeq ($(strip $(BOOTLOADER)), halfkay)
|
||||
ifeq ($(strip $(MCU)), at90usb1286)
|
||||
BOOTLOADER_SIZE = 1024
|
||||
endif
|
||||
# Teensy LC, 3.x
|
||||
ifneq (,$(filter $(MCU_ORIG), MKL26Z64 MK20DX128 MK20DX256 MK66FX1M0))
|
||||
# Teensy LC, 3.0, 3.1/2, 3.5, 3.6
|
||||
ifneq (,$(filter $(MCU_ORIG), MKL26Z64 MK20DX128 MK20DX256 MK64FX512 MK66FX1M0))
|
||||
FIRMWARE_FORMAT = hex
|
||||
endif
|
||||
endif
|
||||
@@ -200,6 +200,10 @@ ifeq ($(strip $(BOOTLOADER)), tinyuf2)
|
||||
OPT_DEFS += -DBOOTLOADER_TINYUF2
|
||||
BOOTLOADER_TYPE = tinyuf2
|
||||
endif
|
||||
ifeq ($(strip $(BOOTLOADER)), rp2040)
|
||||
OPT_DEFS += -DBOOTLOADER_RP2040
|
||||
BOOTLOADER_TYPE = rp2040
|
||||
endif
|
||||
ifeq ($(strip $(BOOTLOADER)), halfkay)
|
||||
OPT_DEFS += -DBOOTLOADER_HALFKAY
|
||||
BOOTLOADER_TYPE = halfkay
|
||||
|
||||
@@ -13,6 +13,14 @@ endif
|
||||
include paths.mk
|
||||
include $(BUILDDEFS_PATH)/message.mk
|
||||
|
||||
# Helper to add defines with a 'QMK_' prefix
|
||||
define add_qmk_prefix_defs
|
||||
ifdef $1
|
||||
# Need to cater for 'STM32L4xx+'
|
||||
OPT_DEFS += -DQMK_$(2)="$($1)" -DQMK_$(2)_$(shell echo $($1) | sed -e 's@+@Plus@g' -e 's@[^a-zA-Z0-9]@_@g' | tr '[:lower:]' '[:upper:]')
|
||||
endif
|
||||
endef
|
||||
|
||||
# Set the qmk cli to use
|
||||
QMK_BIN ?= qmk
|
||||
|
||||
@@ -390,10 +398,18 @@ ifneq ("$(KEYMAP_H)","")
|
||||
CONFIG_H += $(KEYMAP_H)
|
||||
endif
|
||||
|
||||
OPT_DEFS += -DKEYMAP_C=\"$(KEYMAP_C)\"
|
||||
|
||||
# If a keymap or userspace places their keymap array in another file instead, allow for it to be included
|
||||
# !!NOTE!! -- For this to work, the source file cannot be part of $(SRC), so users should not add it via `SRC += <file>`
|
||||
ifneq ($(strip $(INTROSPECTION_KEYMAP_C)),)
|
||||
OPT_DEFS += -DINTROSPECTION_KEYMAP_C=\"$(strip $(INTROSPECTION_KEYMAP_C))\"
|
||||
endif
|
||||
|
||||
# project specific files
|
||||
SRC += \
|
||||
$(KEYBOARD_SRC) \
|
||||
$(KEYMAP_C) \
|
||||
$(QUANTUM_DIR)/keymap_introspection.c \
|
||||
$(QUANTUM_SRC) \
|
||||
$(QUANTUM_DIR)/main.c \
|
||||
|
||||
@@ -436,6 +452,14 @@ else
|
||||
include $(TMK_PATH)/protocol/$(PLATFORM_KEY).mk
|
||||
endif
|
||||
|
||||
# Setup definitions based on the selected MCU
|
||||
$(eval $(call add_qmk_prefix_defs,MCU_ORIG,MCU))
|
||||
$(eval $(call add_qmk_prefix_defs,MCU_ARCH,MCU_ARCH))
|
||||
$(eval $(call add_qmk_prefix_defs,MCU_PORT_NAME,MCU_PORT_NAME))
|
||||
$(eval $(call add_qmk_prefix_defs,MCU_FAMILY,MCU_FAMILY))
|
||||
$(eval $(call add_qmk_prefix_defs,MCU_SERIES,MCU_SERIES))
|
||||
$(eval $(call add_qmk_prefix_defs,BOARD,BOARD))
|
||||
|
||||
# TODO: remove this bodge?
|
||||
PROJECT_DEFS := $(OPT_DEFS)
|
||||
PROJECT_INC := $(VPATH) $(EXTRAINCDIRS) $(KEYBOARD_PATHS)
|
||||
@@ -469,6 +493,19 @@ check-size: build
|
||||
check-md5: build
|
||||
objs-size: build
|
||||
|
||||
ifeq ($(strip $(TOP_SYMBOLS)),yes)
|
||||
all: top-symbols
|
||||
check-size: top-symbols
|
||||
top-symbols: build
|
||||
echo "###########################################"
|
||||
echo "# Highest flash usage:"
|
||||
$(NM) -Crtd --size-sort $(BUILD_DIR)/$(TARGET).elf | grep -i ' [t] ' | head -n10 | sed -e 's#^0000000# #g' -e 's#^000000# #g' -e 's#^00000# #g' -e 's#^0000# #g' -e 's#^000# #g' -e 's#^00# #g' -e 's#^0# #g'
|
||||
echo "###########################################"
|
||||
echo "# Highest RAM usage:"
|
||||
$(NM) -Crtd --size-sort $(BUILD_DIR)/$(TARGET).elf | grep -i ' [dbv] ' | head -n10 | sed -e 's#^0000000# #g' -e 's#^000000# #g' -e 's#^00000# #g' -e 's#^0000# #g' -e 's#^000# #g' -e 's#^00# #g' -e 's#^0# #g'
|
||||
echo "###########################################"
|
||||
endif
|
||||
|
||||
include $(BUILDDEFS_PATH)/show_options.mk
|
||||
include $(BUILDDEFS_PATH)/common_rules.mk
|
||||
|
||||
|
||||
@@ -38,11 +38,11 @@ CREATE_MAP := no
|
||||
VPATH += \
|
||||
$(LIB_PATH)/googletest \
|
||||
$(LIB_PATH)/googlemock \
|
||||
$(LIB_PATH)/printf
|
||||
$(COMMON_VPATH) \
|
||||
$(TEST_PATH)
|
||||
|
||||
all: elf
|
||||
|
||||
VPATH += $(COMMON_VPATH)
|
||||
PLATFORM:=TEST
|
||||
PLATFORM_KEY:=test
|
||||
BOOTLOADER_TYPE:=none
|
||||
@@ -63,6 +63,8 @@ include $(TMK_PATH)/protocol.mk
|
||||
include $(QUANTUM_PATH)/debounce/tests/rules.mk
|
||||
include $(QUANTUM_PATH)/encoder/tests/rules.mk
|
||||
include $(QUANTUM_PATH)/sequencer/tests/rules.mk
|
||||
include $(QUANTUM_PATH)/wear_leveling/tests/rules.mk
|
||||
include $(QUANTUM_PATH)/logging/print.mk
|
||||
include $(PLATFORM_PATH)/test/rules.mk
|
||||
ifneq ($(filter $(FULL_TESTS),$(TEST)),)
|
||||
include $(BUILDDEFS_PATH)/build_full_test.mk
|
||||
@@ -70,7 +72,6 @@ endif
|
||||
|
||||
$(TEST)_SRC += \
|
||||
tests/test_common/main.c \
|
||||
$(LIB_PATH)/printf/printf.c \
|
||||
$(QUANTUM_PATH)/logging/print.c
|
||||
|
||||
$(TEST_OBJ)/$(TEST)_SRC := $($(TEST)_SRC)
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
|
||||
QUANTUM_SRC += \
|
||||
$(QUANTUM_DIR)/quantum.c \
|
||||
$(QUANTUM_DIR)/send_string.c \
|
||||
$(QUANTUM_DIR)/bitwise.c \
|
||||
$(QUANTUM_DIR)/led.c \
|
||||
$(QUANTUM_DIR)/action.c \
|
||||
@@ -92,10 +91,29 @@ ifeq ($(MUSIC_ENABLE), yes)
|
||||
SRC += $(QUANTUM_DIR)/process_keycode/process_music.c
|
||||
endif
|
||||
|
||||
VALID_STENO_PROTOCOL_TYPES := geminipr txbolt all
|
||||
STENO_PROTOCOL ?= all
|
||||
ifeq ($(strip $(STENO_ENABLE)), yes)
|
||||
OPT_DEFS += -DSTENO_ENABLE
|
||||
VIRTSER_ENABLE ?= yes
|
||||
SRC += $(QUANTUM_DIR)/process_keycode/process_steno.c
|
||||
ifeq ($(filter $(STENO_PROTOCOL),$(VALID_STENO_PROTOCOL_TYPES)),)
|
||||
$(call CATASTROPHIC_ERROR,Invalid STENO_PROTOCOL,STENO_PROTOCOL="$(STENO_PROTOCOL)" is not a valid stenography protocol)
|
||||
else
|
||||
OPT_DEFS += -DSTENO_ENABLE
|
||||
VIRTSER_ENABLE ?= yes
|
||||
|
||||
ifeq ($(strip $(STENO_PROTOCOL)), geminipr)
|
||||
OPT_DEFS += -DSTENO_ENABLE_GEMINI
|
||||
endif
|
||||
ifeq ($(strip $(STENO_PROTOCOL)), txbolt)
|
||||
OPT_DEFS += -DSTENO_ENABLE_BOLT
|
||||
endif
|
||||
ifeq ($(strip $(STENO_PROTOCOL)), all)
|
||||
OPT_DEFS += -DSTENO_ENABLE_ALL
|
||||
OPT_DEFS += -DSTENO_ENABLE_GEMINI
|
||||
OPT_DEFS += -DSTENO_ENABLE_BOLT
|
||||
endif
|
||||
|
||||
SRC += $(QUANTUM_DIR)/process_keycode/process_steno.c
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(VIRTSER_ENABLE)), yes)
|
||||
@@ -108,15 +126,16 @@ 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 pmw3389 pimoroni_trackball custom
|
||||
VALID_POINTING_DEVICE_DRIVER_TYPES := adns5050 adns9800 analog_joystick cirque_pinnacle_i2c cirque_pinnacle_spi paw3204 pmw3360 pmw3389 pimoroni_trackball custom
|
||||
ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes)
|
||||
ifeq ($(filter $(POINTING_DEVICE_DRIVER),$(VALID_POINTING_DEVICE_DRIVER_TYPES)),)
|
||||
$(call CATASTROPHIC_ERROR,Invalid POINTING_DEVICE_DRIVER,POINTING_DEVICE_DRIVER="$(POINTING_DEVICE_DRIVER)" is not a valid pointing device type)
|
||||
else
|
||||
OPT_DEFS += -DPOINTING_DEVICE_ENABLE
|
||||
MOUSE_ENABLE := yes
|
||||
SRC += $(QUANTUM_DIR)/pointing_device.c
|
||||
SRC += $(QUANTUM_DIR)/pointing_device_drivers.c
|
||||
VPATH += $(QUANTUM_DIR)/pointing_device
|
||||
SRC += $(QUANTUM_DIR)/pointing_device/pointing_device.c
|
||||
SRC += $(QUANTUM_DIR)/pointing_device/pointing_device_drivers.c
|
||||
ifneq ($(strip $(POINTING_DEVICE_DRIVER)), custom)
|
||||
SRC += drivers/sensors/$(strip $(POINTING_DEVICE_DRIVER)).c
|
||||
OPT_DEFS += -DPOINTING_DEVICE_DRIVER_$(strip $(shell echo $(POINTING_DEVICE_DRIVER) | tr '[:lower:]' '[:upper:]'))
|
||||
@@ -131,19 +150,21 @@ ifeq ($(strip $(POINTING_DEVICE_ENABLE)), yes)
|
||||
else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), cirque_pinnacle_i2c)
|
||||
OPT_DEFS += -DSTM32_I2C -DHAL_USE_I2C=TRUE
|
||||
SRC += drivers/sensors/cirque_pinnacle.c
|
||||
SRC += drivers/sensors/cirque_pinnacle_gestures.c
|
||||
SRC += $(QUANTUM_DIR)/pointing_device/pointing_device_gestures.c
|
||||
QUANTUM_LIB_SRC += i2c_master.c
|
||||
else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), cirque_pinnacle_spi)
|
||||
OPT_DEFS += -DSTM32_SPI -DHAL_USE_SPI=TRUE
|
||||
SRC += drivers/sensors/cirque_pinnacle.c
|
||||
SRC += drivers/sensors/cirque_pinnacle_gestures.c
|
||||
SRC += $(QUANTUM_DIR)/pointing_device/pointing_device_gestures.c
|
||||
QUANTUM_LIB_SRC += spi_master.c
|
||||
else ifeq ($(strip $(POINTING_DEVICE_DRIVER)), pimoroni_trackball)
|
||||
OPT_DEFS += -DSTM32_SPI -DHAL_USE_I2C=TRUE
|
||||
QUANTUM_LIB_SRC += i2c_master.c
|
||||
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)
|
||||
else ifneq ($(filter $(strip $(POINTING_DEVICE_DRIVER)),pmw3360 pmw3389),)
|
||||
OPT_DEFS += -DSTM32_SPI -DHAL_USE_SPI=TRUE
|
||||
SRC += drivers/sensors/pmw33xx_common.c
|
||||
QUANTUM_LIB_SRC += spi_master.c
|
||||
endif
|
||||
endif
|
||||
@@ -154,33 +175,36 @@ ifeq ($(strip $(QUANTUM_PAINTER_ENABLE)), yes)
|
||||
include $(QUANTUM_DIR)/painter/rules.mk
|
||||
endif
|
||||
|
||||
VALID_EEPROM_DRIVER_TYPES := vendor custom transient i2c spi
|
||||
VALID_EEPROM_DRIVER_TYPES := vendor custom transient i2c spi wear_leveling
|
||||
EEPROM_DRIVER ?= vendor
|
||||
ifeq ($(filter $(EEPROM_DRIVER),$(VALID_EEPROM_DRIVER_TYPES)),)
|
||||
$(call CATASTROPHIC_ERROR,Invalid EEPROM_DRIVER,EEPROM_DRIVER="$(EEPROM_DRIVER)" is not a valid EEPROM driver)
|
||||
else
|
||||
OPT_DEFS += -DEEPROM_ENABLE
|
||||
COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/eeprom
|
||||
COMMON_VPATH += $(DRIVER_PATH)/eeprom
|
||||
COMMON_VPATH += $(PLATFORM_COMMON_DIR)
|
||||
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)), wear_leveling)
|
||||
# Wear-leveling EEPROM implementation
|
||||
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_WEAR_LEVELING
|
||||
SRC += eeprom_driver.c eeprom_wear_leveling.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
|
||||
@@ -191,17 +215,18 @@ else
|
||||
ifneq ($(filter STM32F3xx_% STM32F1xx_% %_STM32F401xC %_STM32F401xE %_STM32F405xG %_STM32F411xE %_STM32F072xB %_STM32F042x6 %_GD32VF103xB %_GD32VF103x8, $(MCU_SERIES)_$(MCU_LDSCRIPT)),)
|
||||
# Emulated EEPROM
|
||||
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_STM32_FLASH_EMULATED
|
||||
COMMON_VPATH += $(DRIVER_PATH)/eeprom
|
||||
SRC += eeprom_driver.c
|
||||
SRC += $(PLATFORM_COMMON_DIR)/eeprom_stm32.c
|
||||
SRC += $(PLATFORM_COMMON_DIR)/flash_stm32.c
|
||||
COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/flash
|
||||
COMMON_VPATH += $(DRIVER_PATH)/flash
|
||||
SRC += eeprom_driver.c eeprom_stm32.c flash_stm32.c
|
||||
else ifneq ($(filter $(MCU_SERIES),STM32L0xx STM32L1xx),)
|
||||
# True EEPROM on STM32L0xx, L1xx
|
||||
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_STM32_L0_L1
|
||||
COMMON_VPATH += $(DRIVER_PATH)/eeprom
|
||||
COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/eeprom
|
||||
SRC += eeprom_driver.c
|
||||
SRC += eeprom_stm32_L0_L1.c
|
||||
SRC += eeprom_driver.c eeprom_stm32_L0_L1.c
|
||||
else ifneq ($(filter $(MCU_SERIES),RP2040),)
|
||||
# Wear-leveling EEPROM implementation, backed by RP2040 flash
|
||||
OPT_DEFS += -DEEPROM_DRIVER -DEEPROM_WEAR_LEVELING
|
||||
SRC += eeprom_driver.c eeprom_wear_leveling.c
|
||||
WEAR_LEVELING_DRIVER = rp2040_flash
|
||||
else ifneq ($(filter $(MCU_SERIES),KL2x K20x),)
|
||||
# Teensy EEPROM implementations
|
||||
OPT_DEFS += -DEEPROM_TEENSY
|
||||
@@ -209,32 +234,64 @@ else
|
||||
else
|
||||
# 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
|
||||
OPT_DEFS += -DEEPROM_SAMD
|
||||
SRC += $(PLATFORM_COMMON_DIR)/eeprom_samd.c
|
||||
SRC += eeprom_samd.c
|
||||
else ifeq ($(PLATFORM),TEST)
|
||||
# Test harness "EEPROM"
|
||||
OPT_DEFS += -DEEPROM_TEST_HARNESS
|
||||
SRC += $(PLATFORM_COMMON_DIR)/eeprom.c
|
||||
SRC += eeprom.c
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
VALID_WEAR_LEVELING_DRIVER_TYPES := custom embedded_flash spi_flash rp2040_flash legacy
|
||||
WEAR_LEVELING_DRIVER ?= none
|
||||
ifneq ($(strip $(WEAR_LEVELING_DRIVER)),none)
|
||||
ifeq ($(filter $(WEAR_LEVELING_DRIVER),$(VALID_WEAR_LEVELING_DRIVER_TYPES)),)
|
||||
$(call CATASTROPHIC_ERROR,Invalid WEAR_LEVELING_DRIVER,WEAR_LEVELING_DRIVER="$(WEAR_LEVELING_DRIVER)" is not a valid wear leveling driver)
|
||||
else
|
||||
FNV_ENABLE := yes
|
||||
OPT_DEFS += -DWEAR_LEVELING_ENABLE
|
||||
OPT_DEFS += -DWEAR_LEVELING_$(strip $(shell echo $(WEAR_LEVELING_DRIVER) | tr '[:lower:]' '[:upper:]'))
|
||||
COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/wear_leveling
|
||||
COMMON_VPATH += $(DRIVER_PATH)/wear_leveling
|
||||
COMMON_VPATH += $(QUANTUM_DIR)/wear_leveling
|
||||
SRC += wear_leveling.c
|
||||
ifeq ($(strip $(WEAR_LEVELING_DRIVER)), embedded_flash)
|
||||
OPT_DEFS += -DHAL_USE_EFL
|
||||
SRC += wear_leveling_efl.c
|
||||
POST_CONFIG_H += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/wear_leveling/wear_leveling_efl_config.h
|
||||
else ifeq ($(strip $(WEAR_LEVELING_DRIVER)), spi_flash)
|
||||
FLASH_DRIVER := spi
|
||||
SRC += wear_leveling_flash_spi.c
|
||||
POST_CONFIG_H += $(DRIVER_PATH)/wear_leveling/wear_leveling_flash_spi_config.h
|
||||
else ifeq ($(strip $(WEAR_LEVELING_DRIVER)), rp2040_flash)
|
||||
SRC += wear_leveling_rp2040_flash.c
|
||||
POST_CONFIG_H += $(DRIVER_PATH)/wear_leveling/wear_leveling_rp2040_flash_config.h
|
||||
else ifeq ($(strip $(WEAR_LEVELING_DRIVER)), legacy)
|
||||
COMMON_VPATH += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/flash
|
||||
SRC += flash_stm32.c wear_leveling_legacy.c
|
||||
POST_CONFIG_H += $(PLATFORM_PATH)/$(PLATFORM_KEY)/$(DRIVER_DIR)/wear_leveling/wear_leveling_legacy_config.h
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
VALID_FLASH_DRIVER_TYPES := spi
|
||||
FLASH_DRIVER ?= no
|
||||
ifneq ($(strip $(FLASH_DRIVER)), no)
|
||||
FLASH_DRIVER ?= none
|
||||
ifneq ($(strip $(FLASH_DRIVER)), none)
|
||||
ifeq ($(filter $(FLASH_DRIVER),$(VALID_FLASH_DRIVER_TYPES)),)
|
||||
$(error FLASH_DRIVER="$(FLASH_DRIVER)" is not a valid FLASH driver)
|
||||
$(call CATASTROPHIC_ERROR,Invalid FLASH_DRIVER,FLASH_DRIVER="$(FLASH_DRIVER)" is not a valid flash driver)
|
||||
else
|
||||
OPT_DEFS += -DFLASH_ENABLE
|
||||
ifeq ($(strip $(FLASH_DRIVER)), spi)
|
||||
ifeq ($(strip $(FLASH_DRIVER)),spi)
|
||||
OPT_DEFS += -DFLASH_DRIVER -DFLASH_SPI
|
||||
COMMON_VPATH += $(DRIVER_PATH)/flash
|
||||
SRC += flash_spi.c
|
||||
QUANTUM_LIB_SRC += spi_master.c
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
@@ -500,7 +557,7 @@ ifeq ($(strip $(BACKLIGHT_ENABLE)), yes)
|
||||
endif
|
||||
endif
|
||||
|
||||
VALID_WS2812_DRIVER_TYPES := bitbang pwm spi i2c
|
||||
VALID_WS2812_DRIVER_TYPES := bitbang pwm spi i2c vendor
|
||||
|
||||
WS2812_DRIVER ?= bitbang
|
||||
ifeq ($(strip $(WS2812_DRIVER_REQUIRED)), yes)
|
||||
@@ -542,12 +599,6 @@ ifeq ($(strip $(LED_TABLES)), yes)
|
||||
SRC += $(QUANTUM_DIR)/led_tables.c
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(TERMINAL_ENABLE)), yes)
|
||||
SRC += $(QUANTUM_DIR)/process_keycode/process_terminal.c
|
||||
OPT_DEFS += -DTERMINAL_ENABLE
|
||||
OPT_DEFS += -DUSER_PRINT
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(VIA_ENABLE)), yes)
|
||||
DYNAMIC_KEYMAP_ENABLE := yes
|
||||
RAW_ENABLE := yes
|
||||
@@ -595,6 +646,14 @@ ifneq ($(strip $(DEBOUNCE_TYPE)), custom)
|
||||
QUANTUM_SRC += $(QUANTUM_DIR)/debounce/$(strip $(DEBOUNCE_TYPE)).c
|
||||
endif
|
||||
|
||||
|
||||
VALID_SERIAL_DRIVER_TYPES := bitbang usart vendor
|
||||
|
||||
SERIAL_DRIVER ?= bitbang
|
||||
ifeq ($(filter $(SERIAL_DRIVER),$(VALID_SERIAL_DRIVER_TYPES)),)
|
||||
$(call CATASTROPHIC_ERROR,Invalid SERIAL_DRIVER,SERIAL_DRIVER="$(SERIAL_DRIVER)" is not a valid SERIAL driver)
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
|
||||
POST_CONFIG_H += $(QUANTUM_DIR)/split_common/post_config.h
|
||||
OPT_DEFS += -DSPLIT_KEYBOARD
|
||||
@@ -619,11 +678,11 @@ ifeq ($(strip $(SPLIT_KEYBOARD)), yes)
|
||||
endif
|
||||
endif
|
||||
|
||||
SERIAL_DRIVER ?= bitbang
|
||||
OPT_DEFS += -DSERIAL_DRIVER_$(strip $(shell echo $(SERIAL_DRIVER) | tr '[:lower:]' '[:upper:]'))
|
||||
ifeq ($(strip $(SERIAL_DRIVER)), bitbang)
|
||||
QUANTUM_LIB_SRC += serial.c
|
||||
else
|
||||
QUANTUM_LIB_SRC += serial_protocol.c
|
||||
QUANTUM_LIB_SRC += serial_$(strip $(SERIAL_DRIVER)).c
|
||||
endif
|
||||
endif
|
||||
@@ -635,6 +694,12 @@ ifeq ($(strip $(CRC_ENABLE)), yes)
|
||||
SRC += crc.c
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(FNV_ENABLE)), yes)
|
||||
OPT_DEFS += -DFNV_ENABLE
|
||||
VPATH += $(LIB_PATH)/fnv
|
||||
SRC += qmk_fnv_type_validation.c hash_32a.c hash_64a.c
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(HAPTIC_ENABLE)),yes)
|
||||
COMMON_VPATH += $(DRIVER_PATH)/haptic
|
||||
|
||||
@@ -711,6 +776,13 @@ ifeq ($(strip $(MAGIC_ENABLE)), yes)
|
||||
OPT_DEFS += -DMAGIC_KEYCODE_ENABLE
|
||||
endif
|
||||
|
||||
SEND_STRING_ENABLE ?= yes
|
||||
ifeq ($(strip $(SEND_STRING_ENABLE)), yes)
|
||||
OPT_DEFS += -DSEND_STRING_ENABLE
|
||||
COMMON_VPATH += $(QUANTUM_DIR)/send_string
|
||||
SRC += $(QUANTUM_DIR)/send_string/send_string.c
|
||||
endif
|
||||
|
||||
ifeq ($(strip $(AUTO_SHIFT_ENABLE)), yes)
|
||||
SRC += $(QUANTUM_DIR)/process_keycode/process_auto_shift.c
|
||||
OPT_DEFS += -DAUTO_SHIFT_ENABLE
|
||||
|
||||
@@ -1,19 +1,5 @@
|
||||
# Hey Emacs, this is a -*- makefile -*-
|
||||
#----------------------------------------------------------------------------
|
||||
# WinAVR Makefile Template written by Eric B. Weddington, Jg Wunsch, et al.
|
||||
#
|
||||
# Released to the Public Domain
|
||||
#
|
||||
# Additional material for this makefile was written by:
|
||||
# Peter Fleury
|
||||
# Tim Henigan
|
||||
# Colin O'Flynn
|
||||
# Reiner Patommel
|
||||
# Markus Pfaff
|
||||
# Sander Pool
|
||||
# Frederik Rouleau
|
||||
# Carlos Lamas
|
||||
#
|
||||
|
||||
# Enable vpath seraching for source files only
|
||||
# Without this, output files, could be read from the wrong .build directories
|
||||
@@ -38,36 +24,15 @@ NO_LTO_OBJ := $(filter %.a,$(OBJ))
|
||||
|
||||
MASTER_OUTPUT := $(firstword $(OUTPUTS))
|
||||
|
||||
|
||||
|
||||
# Output format. (can be srec, ihex, binary)
|
||||
FORMAT = ihex
|
||||
|
||||
# Optimization level, can be [0, 1, 2, 3, s].
|
||||
# 0 = turn off optimization. s = optimize for size.
|
||||
# (Note: 3 is not always the best optimization level. See avr-libc FAQ.)
|
||||
OPT ?= s
|
||||
|
||||
# Compiler flag to set the C Standard level.
|
||||
# c89 = "ANSI" C
|
||||
# gnu89 = c89 plus GCC extensions
|
||||
# c99 = ISO C99 standard (not yet fully implemented)
|
||||
# gnu99 = c99 plus GCC extensions
|
||||
CSTANDARD = -std=gnu99
|
||||
|
||||
|
||||
# Place -D or -U options here for C sources
|
||||
#CDEFS +=
|
||||
|
||||
|
||||
# Place -D or -U options here for ASM sources
|
||||
#ADEFS +=
|
||||
|
||||
|
||||
# Place -D or -U options here for C++ sources
|
||||
#CXXDEFS += -D__STDC_LIMIT_MACROS
|
||||
#CXXDEFS += -D__STDC_CONSTANT_MACROS
|
||||
#CXXDEFS +=
|
||||
# Compiler flag to set the C and C++ language standard level
|
||||
CSTANDARD = -std=gnu11
|
||||
CXXSTANDARD = -std=gnu++14
|
||||
|
||||
# Speed up recompilations by opt-in usage of ccache
|
||||
USE_CCACHE ?= no
|
||||
@@ -75,12 +40,8 @@ ifneq ($(USE_CCACHE),no)
|
||||
CC_PREFIX ?= ccache
|
||||
endif
|
||||
|
||||
#---------------- Compiler Options C ----------------
|
||||
# -g*: generate debugging information
|
||||
# -O*: optimization level
|
||||
# -f...: tuning, see GCC manual and avr-libc documentation
|
||||
# -Wall...: warning level
|
||||
# -Wa,...: tell GCC to pass this to the assembler.
|
||||
#---------------- C Compiler Options ----------------
|
||||
|
||||
ifeq ($(strip $(LTO_ENABLE)), yes)
|
||||
ifeq ($(PLATFORM),ARM_ATSAM)
|
||||
$(info Enabling LTO on arm_atsam-targeting boards is known to have a high likelihood of failure.)
|
||||
@@ -111,23 +72,14 @@ CFLAGS += -Wstrict-prototypes
|
||||
ifneq ($(strip $(ALLOW_WARNINGS)), yes)
|
||||
CFLAGS += -Werror
|
||||
endif
|
||||
#CFLAGS += -mshort-calls
|
||||
#CFLAGS += -fno-unit-at-a-time
|
||||
#CFLAGS += -Wundef
|
||||
#CFLAGS += -Wunreachable-code
|
||||
#CFLAGS += -Wsign-compare
|
||||
CFLAGS += $(CSTANDARD)
|
||||
|
||||
# This fixes lots of keyboards linking errors but SHOULDN'T BE A FINAL SOLUTION
|
||||
# Fixing of multiple variable definitions must be made.
|
||||
CFLAGS += -fcommon
|
||||
|
||||
#---------------- Compiler Options C++ ----------------
|
||||
# -g*: generate debugging information
|
||||
# -O*: optimization level
|
||||
# -f...: tuning, see GCC manual and avr-libc documentation
|
||||
# -Wall...: warning level
|
||||
# -Wa,...: tell GCC to pass this to the assembler.
|
||||
#---------------- C++ Compiler Options ----------------
|
||||
|
||||
ifeq ($(strip $(DEBUG_ENABLE)),yes)
|
||||
CXXFLAGS += -g$(DEBUG)
|
||||
endif
|
||||
@@ -141,57 +93,17 @@ CXXFLAGS += -Wundef
|
||||
ifneq ($(strip $(ALLOW_WARNINGS)), yes)
|
||||
CXXFLAGS += -Werror
|
||||
endif
|
||||
#CXXFLAGS += -mshort-calls
|
||||
#CXXFLAGS += -fno-unit-at-a-time
|
||||
#CXXFLAGS += -Wstrict-prototypes
|
||||
#CXXFLAGS += -Wunreachable-code
|
||||
#CXXFLAGS += -Wsign-compare
|
||||
#CXXFLAGS += $(CSTANDARD)
|
||||
|
||||
#---------------- Assembler Options ----------------
|
||||
|
||||
ASFLAGS += $(ADEFS)
|
||||
ifeq ($(VERBOSE_AS_CMD),yes)
|
||||
ASFLAGS += -v
|
||||
endif
|
||||
|
||||
#---------------- Library Options ----------------
|
||||
# Minimalistic printf version
|
||||
PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min
|
||||
|
||||
# Floating point printf version (requires MATH_LIB = -lm below)
|
||||
PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt
|
||||
|
||||
# If this is left blank, then it will use the Standard printf version.
|
||||
PRINTF_LIB =
|
||||
#PRINTF_LIB = $(PRINTF_LIB_MIN)
|
||||
#PRINTF_LIB = $(PRINTF_LIB_FLOAT)
|
||||
|
||||
|
||||
# Minimalistic scanf version
|
||||
SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min
|
||||
|
||||
# Floating point + %[ scanf version (requires MATH_LIB = -lm below)
|
||||
SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt
|
||||
|
||||
# If this is left blank, then it will use the Standard scanf version.
|
||||
SCANF_LIB =
|
||||
#SCANF_LIB = $(SCANF_LIB_MIN)
|
||||
#SCANF_LIB = $(SCANF_LIB_FLOAT)
|
||||
|
||||
|
||||
MATH_LIB = -lm
|
||||
CREATE_MAP ?= yes
|
||||
|
||||
|
||||
#---------------- Linker Options ----------------
|
||||
# -Wl,...: tell GCC to pass this to linker.
|
||||
# -Map: create map file
|
||||
# --cref: add cross reference to map file
|
||||
#
|
||||
# Comennt out "--relax" option to avoid a error such:
|
||||
# (.vectors+0x30): relocation truncated to fit: R_AVR_13_PCREL against symbol `__vector_12'
|
||||
#
|
||||
|
||||
CREATE_MAP ?= yes
|
||||
ifeq ($(CREATE_MAP),yes)
|
||||
LDFLAGS += -Wl,-Map=$(BUILD_DIR)/$(TARGET).map,--cref
|
||||
endif
|
||||
@@ -201,20 +113,11 @@ endif
|
||||
#LDFLAGS += -Wl,--relax
|
||||
LDFLAGS += $(EXTMEMOPTS)
|
||||
LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS))
|
||||
LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB)
|
||||
#LDFLAGS += -T linker_script.x
|
||||
LDFLAGS += -lm
|
||||
# You can give EXTRALDFLAGS at 'make' command line.
|
||||
LDFLAGS += $(EXTRALDFLAGS)
|
||||
|
||||
#---------------- Assembler Listings ----------------
|
||||
# -Wa,...: tell GCC to pass this to the assembler.
|
||||
# -adhlns: create listing
|
||||
# -gstabs: have the assembler create line number information; note that
|
||||
# for use in COFF files, additional information about filenames
|
||||
# and function names needs to be present in the assembler source
|
||||
# files -- see avr-libc docs [FIXME: not yet described there]
|
||||
# -listing-cont-lines: Sets the maximum number of continuation lines of hex
|
||||
# dump that will be displayed for a given single line of source input.
|
||||
|
||||
ADHLNS_ENABLE ?= no
|
||||
ifeq ($(ADHLNS_ENABLE),yes)
|
||||
|
||||
@@ -87,6 +87,33 @@ ifneq ($(findstring MK20DX256, $(MCU)),)
|
||||
BOARD ?= PJRC_TEENSY_3_1
|
||||
endif
|
||||
|
||||
ifneq ($(findstring MK64FX512, $(MCU)),)
|
||||
# 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 = KINETIS
|
||||
MCU_SERIES = K60x
|
||||
|
||||
# Linker script to use
|
||||
# - it should exist either in <chibios>/os/common/ports/ARMCMx/compilers/GCC/ld/
|
||||
# or <keyboard_dir>/ld/
|
||||
MCU_LDSCRIPT ?= MK64FX512
|
||||
|
||||
# Startup code to use
|
||||
# - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
|
||||
MCU_STARTUP ?= k60x
|
||||
|
||||
# Board: it should exist either in <chibios>/os/hal/boards/,
|
||||
# <keyboard_dir>/boards/, or drivers/boards/
|
||||
BOARD ?= PJRC_TEENSY_3_5
|
||||
endif
|
||||
|
||||
ifneq ($(findstring MK66FX1M0, $(MCU)),)
|
||||
# Cortex version
|
||||
MCU = cortex-m4
|
||||
@@ -116,6 +143,41 @@ ifneq ($(findstring MK66FX1M0, $(MCU)),)
|
||||
BOARD ?= PJRC_TEENSY_3_6
|
||||
endif
|
||||
|
||||
ifneq ($(findstring RP2040, $(MCU)),)
|
||||
# Cortex version
|
||||
MCU = cortex-m0plus
|
||||
|
||||
# ARM version, CORTEX-M0/M1 are 6, CORTEX-M3/M4/M7 are 7
|
||||
CHIBIOS_PORT = ARMv6-M-RP2
|
||||
|
||||
## chip/board settings
|
||||
# - the next two should match the directories in
|
||||
# <chibios[-contrib]>/os/hal/ports/$(MCU_PORT_NAME)/$(MCU_SERIES)
|
||||
# OR
|
||||
# <chibios[-contrib]>/os/hal/ports/$(MCU_FAMILY)/$(MCU_SERIES)
|
||||
MCU_FAMILY = RP
|
||||
MCU_SERIES = RP2040
|
||||
|
||||
# Linker script to use
|
||||
# - it should exist either in <chibios>/os/common/ports/ARMCMx/compilers/GCC/ld/
|
||||
# or <keyboard_dir>/ld/
|
||||
STARTUPLD_CONTRIB = $(CHIBIOS_CONTRIB)/os/common/startup/ARMCMx/compilers/GCC/ld
|
||||
MCU_LDSCRIPT ?= RP2040_FLASH_TIMECRIT
|
||||
LDFLAGS += -L $(STARTUPLD_CONTRIB)
|
||||
|
||||
# Startup code to use
|
||||
# - it should exist in <chibios>/os/common/startup/ARMCMx/compilers/GCC/mk/
|
||||
MCU_STARTUP ?= rp2040
|
||||
|
||||
# Board: it should exist either in <chibios>/os/hal/boards/,
|
||||
# <keyboard_dir>/boards/, or drivers/boards/
|
||||
BOARD ?= GENERIC_PROMICRO_RP2040
|
||||
|
||||
# Default UF2 Bootloader settings
|
||||
UF2_FAMILY ?= RP2040
|
||||
FIRMWARE_FORMAT ?= uf2
|
||||
endif
|
||||
|
||||
ifneq ($(findstring STM32F042, $(MCU)),)
|
||||
# Cortex version
|
||||
MCU = cortex-m0
|
||||
|
||||
@@ -5,7 +5,6 @@ BUILD_OPTION_NAMES = \
|
||||
CONSOLE_ENABLE \
|
||||
COMMAND_ENABLE \
|
||||
NKRO_ENABLE \
|
||||
TERMINAL_ENABLE \
|
||||
CUSTOM_MATRIX \
|
||||
DEBOUNCE_TYPE \
|
||||
SPLIT_KEYBOARD \
|
||||
@@ -46,6 +45,7 @@ OTHER_OPTION_NAMES = \
|
||||
LEADER_ENABLE \
|
||||
PRINTING_ENABLE \
|
||||
STENO_ENABLE \
|
||||
STENO_PROTOCOL \
|
||||
TAP_DANCE_ENABLE \
|
||||
VIRTSER_ENABLE \
|
||||
OLED_ENABLE \
|
||||
|
||||
@@ -4,6 +4,7 @@ FULL_TESTS := $(notdir $(TEST_LIST))
|
||||
include $(QUANTUM_PATH)/debounce/tests/testlist.mk
|
||||
include $(QUANTUM_PATH)/encoder/tests/testlist.mk
|
||||
include $(QUANTUM_PATH)/sequencer/tests/testlist.mk
|
||||
include $(QUANTUM_PATH)/wear_leveling/tests/testlist.mk
|
||||
include $(PLATFORM_PATH)/test/testlist.mk
|
||||
|
||||
define VALIDATE_TEST_LIST
|
||||
|
||||
@@ -16,6 +16,24 @@
|
||||
"board": "QMK_PROTON_C",
|
||||
"pin_compatible": "promicro"
|
||||
},
|
||||
"kb2040": {
|
||||
"processor": "RP2040",
|
||||
"bootloader": "rp2040",
|
||||
"board": "QMK_PM2040",
|
||||
"pin_compatible": "promicro"
|
||||
},
|
||||
"promicro_rp2040": {
|
||||
"processor": "RP2040",
|
||||
"bootloader": "rp2040",
|
||||
"board": "QMK_PM2040",
|
||||
"pin_compatible": "promicro"
|
||||
},
|
||||
"blok": {
|
||||
"processor": "RP2040",
|
||||
"bootloader": "rp2040",
|
||||
"board": "QMK_PM2040",
|
||||
"pin_compatible": "promicro"
|
||||
},
|
||||
"bluepill": {
|
||||
"processor": "STM32F103",
|
||||
"bootloader": "stm32duino",
|
||||
@@ -32,4 +50,4 @@
|
||||
"board": "BLACKPILL_STM32_F411"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
"AUDIO_VOICES": {"info_key": "audio.voices", "value_type": "bool"},
|
||||
"BACKLIGHT_BREATHING": {"info_key": "backlight.breathing", "value_type": "bool"},
|
||||
"BREATHING_PERIOD": {"info_key": "backlight.breathing_period", "value_type": "int"},
|
||||
"BACKLIGHT_ON_STATE": {"info_key": "backlight.on_state", "value_type": "int"},
|
||||
"BACKLIGHT_PIN": {"info_key": "backlight.pin"},
|
||||
"BOTH_SHIFTS_TURNS_ON_CAPS_WORD": {"info_key": "caps_word.both_shifts_turns_on", "value_type": "bool"},
|
||||
"CAPS_WORD_IDLE_TIMEOUT": {"info_key": "caps_word.idle_timeout", "value_type": "int"},
|
||||
@@ -35,6 +36,9 @@
|
||||
"LED_CAPS_LOCK_PIN": {"info_key": "indicators.caps_lock"},
|
||||
"LED_NUM_LOCK_PIN": {"info_key": "indicators.num_lock"},
|
||||
"LED_SCROLL_LOCK_PIN": {"info_key": "indicators.scroll_lock"},
|
||||
"LED_COMPOSE_PIN": {"info_key": "indicators.compose"},
|
||||
"LED_KANA_PIN": {"info_key": "indicators.kana"},
|
||||
"LED_PIN_ON_STATE": {"info_key": "indicators.on_state", "value_type": "int"},
|
||||
"MANUFACTURER": {"info_key": "manufacturer"},
|
||||
"MATRIX_HAS_GHOST": {"info_key": "matrix_pins.ghost", "value_type": "bool"},
|
||||
"MATRIX_IO_DELAY": {"info_key": "matrix_pins.io_delay", "value_type": "int"},
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
"BOOTLOADER": {"info_key": "bootloader", "warn_duplicate": false},
|
||||
"BLUETOOTH": {"info_key": "bluetooth.driver"},
|
||||
"CAPS_WORD_ENABLE": {"info_key": "caps_word.enabled", "value_type": "bool"},
|
||||
"ENCODER_ENABLE": {"info_key": "encoder.enabled", "value_type": "bool"},
|
||||
"FIRMWARE_FORMAT": {"info_key": "build.firmware_format"},
|
||||
"KEYBOARD_SHARED_EP": {"info_key": "usb.shared_endpoint.keyboard", "value_type": "bool"},
|
||||
"MOUSE_SHARED_EP": {"info_key": "usb.shared_endpoint.mouse", "value_type": "bool"},
|
||||
@@ -27,6 +28,8 @@
|
||||
"SPLIT_KEYBOARD": {"info_key": "split.enabled", "value_type": "bool"},
|
||||
"SPLIT_TRANSPORT": {"info_key": "split.transport.protocol", "to_c": false},
|
||||
"WAIT_FOR_USB": {"info_key": "usb.wait_for", "value_type": "bool"},
|
||||
"STENO_ENABLE": {"info_key": "stenography.enabled", "value_type": "bool"},
|
||||
"STENO_PROTOCOL": {"info_key": "stenography.protocol"},
|
||||
|
||||
# Items we want flagged in lint
|
||||
"CTPC": {"info_key": "_deprecated.ctpc", "deprecated": true},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema#",
|
||||
"$id": "qmk.definitions.v1",
|
||||
"title": "Common definitions used across QMK's jsonschemas.",
|
||||
"type": "object",
|
||||
@@ -65,8 +65,7 @@
|
||||
]
|
||||
},
|
||||
"key_unit": {
|
||||
"type": "number",
|
||||
"min": 0.25
|
||||
"type": "number"
|
||||
},
|
||||
"keyboard": {
|
||||
"oneOf": [
|
||||
@@ -103,8 +102,11 @@
|
||||
"pattern": "^LINE_PIN\\d{1,2}$"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"multipleOf": 1
|
||||
"type": "string",
|
||||
"pattern": "^GP\\d{1,2}$"
|
||||
},
|
||||
{
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
@@ -115,14 +117,12 @@
|
||||
"type": "number"
|
||||
},
|
||||
"signed_int": {
|
||||
"type": "number",
|
||||
"multipleOf": 1
|
||||
"type": "integer"
|
||||
},
|
||||
"signed_int_8": {
|
||||
"type": "number",
|
||||
"min": -127,
|
||||
"max": 127,
|
||||
"multipleOf": 1
|
||||
"type": "integer",
|
||||
"minimum": -127,
|
||||
"maximum": 127
|
||||
},
|
||||
"string_array": {
|
||||
"type": "array",
|
||||
@@ -138,17 +138,20 @@
|
||||
},
|
||||
"unsigned_decimal": {
|
||||
"type": "number",
|
||||
"min": 0
|
||||
"minimum": 0
|
||||
},
|
||||
"unsigned_int": {
|
||||
"type": "number",
|
||||
"min": 0,
|
||||
"multipleOf": 1
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
},
|
||||
"unsigned_int_8": {
|
||||
"type": "number",
|
||||
"min": 0,
|
||||
"max": 255,
|
||||
"multipleOf": 1
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 255
|
||||
},
|
||||
"bit": {
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,27 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema#",
|
||||
"$id": "qmk.keyboard.v1",
|
||||
"title": "Keyboard Information",
|
||||
"definitions": {
|
||||
"encoder_config": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"rotary": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["pin_a", "pin_b"],
|
||||
"properties": {
|
||||
"pin_a": {"$ref": "qmk.definitions.v1#/mcu_pin"},
|
||||
"pin_b": {"$ref": "qmk.definitions.v1#/mcu_pin"},
|
||||
"resolution": {"$ref": "qmk.definitions.v1#/unsigned_int"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"keyboard_name": {"$ref": "qmk.definitions.v1#/text_identifier"},
|
||||
@@ -14,7 +34,7 @@
|
||||
},
|
||||
"development_board": {
|
||||
"type": "string",
|
||||
"enum": ["promicro", "elite_c", "proton_c", "bluepill", "blackpill_f401", "blackpill_f411"]
|
||||
"enum": ["promicro", "elite_c", "proton_c", "kb2040", "promicro_rp2040", "blok", "bluepill", "blackpill_f401", "blackpill_f411"]
|
||||
},
|
||||
"pin_compatible": {
|
||||
"type": "string",
|
||||
@@ -22,7 +42,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", "STM32L432", "STM32L433", "STM32L442", "STM32L443", "GD32VF103", "WB32F3G71", "WB32FQ95", "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", "MK64FX512", "MK66FX1M0", "RP2040", "STM32F042", "STM32F072", "STM32F103", "STM32F303", "STM32F401", "STM32F405", "STM32F407", "STM32F411", "STM32F446", "STM32G431", "STM32G474", "STM32L412", "STM32L422", "STM32L432", "STM32L433", "STM32L442", "STM32L443", "GD32VF103", "WB32F3G71", "WB32FQ95", "atmega16u2", "atmega32u2", "atmega16u4", "atmega32u4", "at90usb162", "at90usb646", "at90usb647", "at90usb1286", "at90usb1287", "atmega32a", "atmega328p", "atmega328", "attiny85", "unknown"]
|
||||
},
|
||||
"audio": {
|
||||
"type": "object",
|
||||
@@ -40,12 +60,12 @@
|
||||
"breathing": {"type": "boolean"},
|
||||
"breathing_period": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
|
||||
"levels": {
|
||||
"type": "number",
|
||||
"min": 1,
|
||||
"max": 31,
|
||||
"multipleOf": 1
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 31
|
||||
},
|
||||
"pin": {"$ref": "qmk.definitions.v1#/mcu_pin"}
|
||||
"pin": {"$ref": "qmk.definitions.v1#/mcu_pin"},
|
||||
"on_state": {"$ref": "qmk.definitions.v1#/bit"}
|
||||
}
|
||||
},
|
||||
"bluetooth": {
|
||||
@@ -66,7 +86,7 @@
|
||||
},
|
||||
"bootloader": {
|
||||
"type": "string",
|
||||
"enum": ["atmel-dfu", "bootloadhid", "bootloadHID", "custom", "caterina", "halfkay", "kiibohd", "lufa-dfu", "lufa-ms", "md-boot", "qmk-dfu", "qmk-hid", "stm32-dfu", "stm32duino", "gd32v-dfu", "wb32-dfu", "unknown", "usbasploader", "USBasp", "tinyuf2"],
|
||||
"enum": ["atmel-dfu", "bootloadhid", "bootloadHID", "custom", "caterina", "halfkay", "kiibohd", "lufa-dfu", "lufa-ms", "md-boot", "qmk-dfu", "qmk-hid", "stm32-dfu", "stm32duino", "gd32v-dfu", "wb32-dfu", "unknown", "usbasploader", "USBasp", "tinyuf2", "rp2040"],
|
||||
},
|
||||
"bootloader_instructions": {
|
||||
"type": "string",
|
||||
@@ -113,13 +133,22 @@
|
||||
"type": "array",
|
||||
"items": {"$ref": "qmk.definitions.v1#/filename"}
|
||||
},
|
||||
"encoder": {
|
||||
"$ref": "#/definitions/encoder_config",
|
||||
"properties": {
|
||||
"enabled": {"type": "boolean"}
|
||||
}
|
||||
},
|
||||
"features": {"$ref": "qmk.definitions.v1#/boolean_array"},
|
||||
"indicators": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"caps_lock": {"$ref": "qmk.definitions.v1#/mcu_pin"},
|
||||
"num_lock": {"$ref": "qmk.definitions.v1#/mcu_pin"},
|
||||
"scroll_lock": {"$ref": "qmk.definitions.v1#/mcu_pin"}
|
||||
"scroll_lock": {"$ref": "qmk.definitions.v1#/mcu_pin"},
|
||||
"compose": {"$ref": "qmk.definitions.v1#/mcu_pin"},
|
||||
"kana": {"$ref": "qmk.definitions.v1#/mcu_pin"},
|
||||
"on_state": {"$ref": "qmk.definitions.v1#/bit"}
|
||||
}
|
||||
},
|
||||
"layout_aliases": {
|
||||
@@ -154,12 +183,11 @@
|
||||
"minItems": 2,
|
||||
"maxItems": 2,
|
||||
"items": {
|
||||
"type": "number",
|
||||
"min": 0,
|
||||
"multipleOf": 1
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"r": {"$ref": "qmk.definitions.v1#/unsigned_decimal"},
|
||||
"r": {"$ref": "qmk.definitions.v1#/signed_decimal"},
|
||||
"rx": {"$ref": "qmk.definitions.v1#/unsigned_decimal"},
|
||||
"ry": {"$ref": "qmk.definitions.v1#/unsigned_decimal"},
|
||||
"h": {"$ref": "qmk.definitions.v1#/key_unit"},
|
||||
@@ -230,14 +258,13 @@
|
||||
"minItems": 2,
|
||||
"maxItems": 2,
|
||||
"items": {
|
||||
"type": "number",
|
||||
"min": 0,
|
||||
"multipleOf": 1
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"x": {"$ref": "qmk.definitions.v1#/key_unit"},
|
||||
"y": {"$ref": "qmk.definitions.v1#/key_unit"},
|
||||
"flags": {"$ref": "qmk.definitions.v1#/unsigned_decimal"}
|
||||
"flags": {"$ref": "qmk.definitions.v1#/unsigned_int_8"}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -258,14 +285,13 @@
|
||||
"minItems": 2,
|
||||
"maxItems": 2,
|
||||
"items": {
|
||||
"type": "number",
|
||||
"min": 0,
|
||||
"multipleOf": 1
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"x": {"$ref": "qmk.definitions.v1#/key_unit"},
|
||||
"y": {"$ref": "qmk.definitions.v1#/key_unit"},
|
||||
"flags": {"$ref": "qmk.definitions.v1#/unsigned_decimal"}
|
||||
"flags": {"$ref": "qmk.definitions.v1#/unsigned_int_8"}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -290,10 +316,9 @@
|
||||
"blink": {"type": "boolean"},
|
||||
"enabled": {"type": "boolean"},
|
||||
"max": {
|
||||
"type": "number",
|
||||
"min": 1,
|
||||
"max": 32,
|
||||
"multipleOf": 1
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 32
|
||||
},
|
||||
"override_rgb": {"type": "boolean"}
|
||||
}
|
||||
@@ -307,8 +332,8 @@
|
||||
"split": {"type": "boolean"},
|
||||
"split_count": {
|
||||
"type": "array",
|
||||
"minLength": 2,
|
||||
"maxLength": 2,
|
||||
"minItems": 2,
|
||||
"maxItems": 2,
|
||||
"items": {"$ref": "qmk.definitions.v1#/unsigned_int"}
|
||||
}
|
||||
}
|
||||
@@ -322,21 +347,31 @@
|
||||
"idle_timeout": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||
"unlock_sequence": {
|
||||
"type": "array",
|
||||
"minLength": 1,
|
||||
"maxLength": 5,
|
||||
"minItems": 1,
|
||||
"maxItems": 5,
|
||||
"items": {
|
||||
"type": "array",
|
||||
"minItems": 2,
|
||||
"maxItems": 2,
|
||||
"items": {
|
||||
"type": "number",
|
||||
"min": 0,
|
||||
"multipleOf": 1
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"stenography": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"enabled": {"type": "boolean"},
|
||||
"protocol": {
|
||||
"type": "string",
|
||||
"enum": ["all", "geminipr", "txbolt"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"split": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
@@ -365,16 +400,24 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"encoder": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"right": {
|
||||
"$ref": "#/definitions/encoder_config"
|
||||
}
|
||||
}
|
||||
},
|
||||
"main": {
|
||||
"type": "string",
|
||||
"enum": ["eeprom", "left", "matrix_grid", "pin", "right"]
|
||||
},
|
||||
"soft_serial_pin": {"$ref": "qmk.definitions.v1#/mcu_pin"},
|
||||
"soft_serial_speed": {
|
||||
"type": "number",
|
||||
"min": 0,
|
||||
"max": 5,
|
||||
"multipleOf": 1
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"maximum": 5
|
||||
},
|
||||
"transport": {
|
||||
"type": "object",
|
||||
@@ -428,7 +471,7 @@
|
||||
"force_nkro": {"type": "boolean"},
|
||||
"pid": {"$ref": "qmk.definitions.v1#/hex_number_4d"},
|
||||
"vid": {"$ref": "qmk.definitions.v1#/hex_number_4d"},
|
||||
"max_power": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
|
||||
"max_power": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||
"no_startup_check": {"type": "boolean"},
|
||||
"polling_interval": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
|
||||
"shared_endpoint": {
|
||||
@@ -439,7 +482,7 @@
|
||||
"mouse": {"type": "boolean"}
|
||||
}
|
||||
},
|
||||
"suspend_wakeup_delay": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
|
||||
"suspend_wakeup_delay": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||
"wait_for": {"type": "boolean"},
|
||||
}
|
||||
},
|
||||
@@ -448,8 +491,8 @@
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"keys_per_scan": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
|
||||
"tap_keycode_delay": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
|
||||
"tap_capslock_delay": {"$ref": "qmk.definitions.v1#/unsigned_int_8"},
|
||||
"tap_keycode_delay": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||
"tap_capslock_delay": {"$ref": "qmk.definitions.v1#/unsigned_int"},
|
||||
}
|
||||
},
|
||||
"qmk_lufa_bootloader": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema#",
|
||||
"$id": "qmk.keymap.v1",
|
||||
"title": "Keymap Information",
|
||||
"type": "object",
|
||||
@@ -50,8 +50,7 @@
|
||||
},
|
||||
"config": {"$ref": "qmk.keyboard.v1"},
|
||||
"notes": {
|
||||
"type": "string",
|
||||
"description": "asdf"
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
|
||||
@@ -84,11 +84,12 @@
|
||||
* [One Shot Keys](one_shot_keys.md)
|
||||
* [Pointing Device](feature_pointing_device.md)
|
||||
* [Raw HID](feature_rawhid.md)
|
||||
* [Secure](feature_secure.md)
|
||||
* [Send String](feature_send_string.md)
|
||||
* [Sequencer](feature_sequencer.md)
|
||||
* [Swap Hands](feature_swap_hands.md)
|
||||
* [Tap Dance](feature_tap_dance.md)
|
||||
* [Tap-Hold Configuration](tap_hold.md)
|
||||
* [Terminal](feature_terminal.md)
|
||||
* [Unicode](feature_unicode.md)
|
||||
* [Userspace](feature_userspace.md)
|
||||
* [WPM Calculation](feature_wpm.md)
|
||||
@@ -107,6 +108,7 @@
|
||||
* [Audio](feature_audio.md)
|
||||
* [Bluetooth](feature_bluetooth.md)
|
||||
* [Bootmagic Lite](feature_bootmagic.md)
|
||||
* [Converters](feature_converters.md)
|
||||
* [Custom Matrix](custom_matrix.md)
|
||||
* [Digitizer](feature_digitizer.md)
|
||||
* [DIP Switch](feature_dip_switch.md)
|
||||
@@ -115,7 +117,6 @@
|
||||
* [Joystick](feature_joystick.md)
|
||||
* [LED Indicators](feature_led_indicators.md)
|
||||
* [MIDI](feature_midi.md)
|
||||
* [Proton C Conversion](proton_c_conversion.md)
|
||||
* [PS/2 Mouse](feature_ps2_mouse.md)
|
||||
* [Split Keyboard](feature_split_keyboard.md)
|
||||
* [Stenography](feature_stenography.md)
|
||||
@@ -147,6 +148,7 @@
|
||||
* [SPI Driver](spi_driver.md)
|
||||
* [WS2812 Driver](ws2812_driver.md)
|
||||
* [EEPROM Driver](eeprom_driver.md)
|
||||
* [Flash Driver](flash_driver.md)
|
||||
* ['serial' Driver](serial_driver.md)
|
||||
* [UART Driver](uart_driver.md)
|
||||
* [GPIO Controls](gpio_control.md)
|
||||
@@ -165,6 +167,8 @@
|
||||
* Arm/ChibiOS
|
||||
* [Selecting an MCU](platformdev_selecting_arm_mcu.md)
|
||||
* [Early initialization](platformdev_chibios_earlyinit.md)
|
||||
* [Raspberry Pi RP2040](platformdev_rp2040.md)
|
||||
* [Proton C](platformdev_proton_c.md)
|
||||
|
||||
* QMK Reference
|
||||
* [Contributing to QMK](contributing.md)
|
||||
|
||||
@@ -352,6 +352,73 @@ $ qmk via2json -kb ai03/polaris -o polaris_keymap.json polaris_via_backup.json
|
||||
Ψ Wrote keymap to /home/you/qmk_firmware/polaris_keymap.json
|
||||
```
|
||||
|
||||
## `qmk import-keyboard`
|
||||
|
||||
This command imports a data-driven `info.json` keyboard into the repo.
|
||||
|
||||
**Usage**:
|
||||
|
||||
```
|
||||
usage: qmk import-keyboard [-h] filename
|
||||
```
|
||||
|
||||
**Example:**
|
||||
|
||||
```
|
||||
$ qmk import-keyboard ~/Downloads/forever60.json
|
||||
Ψ Importing forever60.json.
|
||||
|
||||
Ψ Imported a new keyboard named forever60.
|
||||
Ψ To start working on things, `cd` into keyboards/forever60,
|
||||
Ψ or open the directory in your preferred text editor.
|
||||
Ψ And build with qmk compile -kb forever60 -km default.
|
||||
```
|
||||
|
||||
## `qmk import-keymap`
|
||||
|
||||
This command imports a data-driven `keymap.json` keymap into the repo.
|
||||
|
||||
**Usage**:
|
||||
|
||||
```
|
||||
usage: qmk import-keymap [-h] filename
|
||||
```
|
||||
|
||||
**Example:**
|
||||
|
||||
```
|
||||
qmk import-keymap ~/Downloads/asdf2.json
|
||||
Ψ Importing asdf2.json.
|
||||
|
||||
Ψ Imported a new keymap named asdf2.
|
||||
Ψ To start working on things, `cd` into keyboards/takashicompany/dogtag/keymaps/asdf2,
|
||||
Ψ or open the directory in your preferred text editor.
|
||||
Ψ And build with qmk compile -kb takashicompany/dogtag -km asdf2.
|
||||
```
|
||||
|
||||
## `qmk import-kbfirmware`
|
||||
|
||||
This command creates a new keyboard based on a [Keyboard Firmware Builder](https://kbfirmware.com/) export.
|
||||
|
||||
**Usage**:
|
||||
|
||||
```
|
||||
usage: qmk import-kbfirmware [-h] filename
|
||||
```
|
||||
|
||||
**Example:**
|
||||
|
||||
```
|
||||
$ qmk import-kbfirmware ~/Downloads/gh62.json
|
||||
Ψ Importing gh62.json.
|
||||
|
||||
⚠ Support here is basic - Consider using 'qmk new-keyboard' instead
|
||||
Ψ Imported a new keyboard named gh62.
|
||||
Ψ To start working on things, `cd` into keyboards/gh62,
|
||||
Ψ or open the directory in your preferred text editor.
|
||||
Ψ And build with qmk compile -kb gh62 -km default.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Developer Commands
|
||||
@@ -527,3 +594,4 @@ This command converts a TTF font to an intermediate format for editing, before c
|
||||
## `qmk painter-convert-font-image`
|
||||
|
||||
This command converts an intermediate font image to the QFF File Format. See the [Quantum Painter](quantum_painter.md?id=quantum-painter-cli) documentation for more information on this command.
|
||||
|
||||
|
||||
@@ -14,6 +14,10 @@ Add this to the end of your `.profile` or `.bashrc`:
|
||||
|
||||
If you put `qmk_firmware` into another location you will need to adjust this path.
|
||||
|
||||
Zsh users will need to load `bashcompinit`. The following can be added to `~/.zshrc` file:
|
||||
|
||||
autoload -Uz bashcompinit && bashcompinit
|
||||
|
||||
### System Wide Symlink
|
||||
|
||||
If you want the tab completion available to all users of the system you can add a symlink to the `qmk_tab_complete.sh` script:
|
||||
|
||||
@@ -62,9 +62,17 @@ You can also use any ARM chip with USB that [ChibiOS](https://www.chibios.org) s
|
||||
* [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
|
||||
* [MK64FX512](https://www.nxp.com/products/processors-and-microcontrollers/arm-microcontrollers/general-purpose-mcus/k-series-cortex-m4/k6x-ethernet/kinetis-k64-120-mhz-256-kb-sram-microcontrollers-mcus-based-on-arm-cortex-m4-core:K64_120)
|
||||
* PJRC Teensy 3.5
|
||||
* [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
|
||||
|
||||
### Raspberry Pi
|
||||
|
||||
* [RP2040](https://www.raspberrypi.com/documentation/microcontrollers/rp2040.html)
|
||||
|
||||
For a detailed overview about the RP2040 support by QMK see the [dedicated RP2040 page](platformdev_rp2040.md).
|
||||
|
||||
## 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). However, it is not recommended to design a board with this microcontroller as the support is quite specialized to Massdrop hardware.
|
||||
|
||||
@@ -107,8 +107,10 @@ This is a C header file that is one of the first things included, and will persi
|
||||
* sets the maximum power (in mA) over USB for the device (default: 500)
|
||||
* `#define USB_POLLING_INTERVAL_MS 10`
|
||||
* sets the USB polling rate in milliseconds for the keyboard, mouse, and shared (NKRO/media keys) interfaces
|
||||
* `#define USB_SUSPEND_WAKEUP_DELAY 200`
|
||||
* set the number of milliseconde to pause after sending a wakeup packet
|
||||
* `#define USB_SUSPEND_WAKEUP_DELAY 0`
|
||||
* sets the number of milliseconds to pause after sending a wakeup packet.
|
||||
Disabled by default, you might want to set this to 200 (or higher) if the
|
||||
keyboard does not wake up properly after suspending.
|
||||
* `#define F_SCL 100000L`
|
||||
* sets the I2C clock rate speed for keyboards using I2C. The default is `400000L`, except for keyboards using `split_common`, where the default is `100000L`.
|
||||
|
||||
@@ -141,7 +143,7 @@ If you define these options you will enable the associated feature, which may in
|
||||
## Behaviors That Can Be Configured
|
||||
|
||||
* `#define TAPPING_TERM 200`
|
||||
* how long before a tap becomes a hold, if set above 500, a key tapped during the tapping term will turn it into a hold too
|
||||
* how long before a key press becomes a hold
|
||||
* `#define TAPPING_TERM_PER_KEY`
|
||||
* enables handling for per key `TAPPING_TERM` settings
|
||||
* `#define RETRO_TAPPING`
|
||||
@@ -174,6 +176,8 @@ If you define these options you will enable the associated feature, which may in
|
||||
* sets the timer for leader key chords to run on each key press rather than overall
|
||||
* `#define LEADER_KEY_STRICT_KEY_PROCESSING`
|
||||
* Disables keycode filtering for Mod-Tap and Layer-Tap keycodes. Eg, if you enable this, you would need to specify `MT(MOD_CTL, KC_A)` if you want to use `KC_A`.
|
||||
* `#define MOUSE_EXTENDED_REPORT`
|
||||
* Enables support for extended reports (-32767 to 32767, instead of -127 to 127), which may allow for smoother reporting, and prevent maxing out of the reports. Applies to both Pointing Device and Mousekeys.
|
||||
* `#define ONESHOT_TIMEOUT 300`
|
||||
* how long before oneshot times out
|
||||
* `#define ONESHOT_TAP_TOGGLE 2`
|
||||
|
||||
@@ -81,17 +81,17 @@ void matrix_init(void) {
|
||||
}
|
||||
|
||||
uint8_t matrix_scan(void) {
|
||||
bool matrix_has_changed = false;
|
||||
bool changed = false;
|
||||
|
||||
// TODO: add matrix scanning routine here
|
||||
|
||||
// Unless hardware debouncing - use the configured debounce routine
|
||||
debounce(raw_matrix, matrix, MATRIX_ROWS, changed);
|
||||
changed = debounce(raw_matrix, matrix, MATRIX_ROWS, changed);
|
||||
|
||||
// This *must* be called for correct keyboard behavior
|
||||
matrix_scan_quantum();
|
||||
|
||||
return matrix_has_changed;
|
||||
return changed;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -2,12 +2,15 @@
|
||||
|
||||
The EEPROM driver can be swapped out depending on the needs of the keyboard, or whether extra hardware is present.
|
||||
|
||||
Selecting the EEPROM driver is done in your keyboard's `rules.mk`:
|
||||
|
||||
Driver | Description
|
||||
-----------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
`EEPROM_DRIVER = vendor` (default) | Uses the on-chip driver provided by the chip manufacturer. For AVR, this is provided by avr-libc. This is supported on ARM for a subset of chips -- STM32F3xx, STM32F1xx, and STM32F072xB will be emulated by writing to flash. STM32L0xx and STM32L1xx will use the onboard dedicated true EEPROM. Other chips will generally act as "transient" below.
|
||||
`EEPROM_DRIVER = i2c` | Supports writing to I2C-based 24xx EEPROM chips. See the driver section below.
|
||||
`EEPROM_DRIVER = spi` | Supports writing to SPI-based 25xx EEPROM chips. See the driver section below.
|
||||
`EEPROM_DRIVER = transient` | Fake EEPROM driver -- supports reading/writing to RAM, and will be discarded when power is lost.
|
||||
`EEPROM_DRIVER = wear_leveling` | Frontend driver for the wear_leveling system, allowing for EEPROM emulation on top of flash -- both in-MCU and external SPI NOR flash.
|
||||
|
||||
## Vendor Driver Configuration :id=vendor-eeprom-driver-configuration
|
||||
|
||||
@@ -43,8 +46,9 @@ Module | Equivalent `#define` | Source
|
||||
-----------------|---------------------------------|------------------------------------------
|
||||
CAT24C512 EEPROM | `#define EEPROM_I2C_CAT24C512` | <https://www.sparkfun.com/products/14764>
|
||||
RM24C512C EEPROM | `#define EEPROM_I2C_RM24C512C` | <https://www.sparkfun.com/products/14764>
|
||||
24LC64 EEPROM | `#define EEPROM_I2C_24LC64` | <https://www.microchip.com/wwwproducts/en/24LC64>
|
||||
24LC128 EEPROM | `#define EEPROM_I2C_24LC128` | <https://www.microchip.com/wwwproducts/en/24LC128>
|
||||
24LC32A EEPROM | `#define EEPROM_I2C_24LC32A` | <https://www.microchip.com/en-us/product/24LC32A>
|
||||
24LC64 EEPROM | `#define EEPROM_I2C_24LC64` | <https://www.microchip.com/en-us/product/24LC64>
|
||||
24LC128 EEPROM | `#define EEPROM_I2C_24LC128` | <https://www.microchip.com/en-us/product/24LC128>
|
||||
24LC256 EEPROM | `#define EEPROM_I2C_24LC256` | <https://www.sparkfun.com/products/525>
|
||||
MB85RC256V FRAM | `#define EEPROM_I2C_MB85RC256V` | <https://www.adafruit.com/product/1895>
|
||||
|
||||
@@ -54,13 +58,13 @@ MB85RC256V FRAM | `#define EEPROM_I2C_MB85RC256V` | <https://www.adafruit.com/p
|
||||
|
||||
Currently QMK supports 25xx-series chips over SPI. As such, requires a working spi_master driver configuration. You can override the driver configuration via your config.h:
|
||||
|
||||
`config.h` override | Description | Default Value
|
||||
-----------------------------------------------|--------------------------------------------------------------------------------------|--------------
|
||||
`#define EXTERNAL_EEPROM_SPI_SLAVE_SELECT_PIN` | SPI Slave select pin in order to inform that the EEPROM is currently being addressed | _none_
|
||||
`#define EXTERNAL_EEPROM_SPI_CLOCK_DIVISOR` | Clock divisor used to divide the peripheral clock to derive the SPI frequency | `64`
|
||||
`#define EXTERNAL_EEPROM_BYTE_COUNT` | Total size of the EEPROM in bytes | 8192
|
||||
`#define EXTERNAL_EEPROM_PAGE_SIZE` | Page size of the EEPROM in bytes, as specified in the datasheet | 32
|
||||
`#define EXTERNAL_EEPROM_ADDRESS_SIZE` | The number of bytes to transmit for the memory location within the EEPROM | 2
|
||||
`config.h` override | Default Value | Description
|
||||
-----------------------------------------------|---------------|-------------------------------------------------------------------------------------
|
||||
`#define EXTERNAL_EEPROM_SPI_SLAVE_SELECT_PIN` | _none_ | SPI Slave select pin in order to inform that the EEPROM is currently being addressed
|
||||
`#define EXTERNAL_EEPROM_SPI_CLOCK_DIVISOR` | `64` | Clock divisor used to divide the peripheral clock to derive the SPI frequency
|
||||
`#define EXTERNAL_EEPROM_BYTE_COUNT` | `8192` | Total size of the EEPROM in bytes
|
||||
`#define EXTERNAL_EEPROM_PAGE_SIZE` | `32` | Page size of the EEPROM in bytes, as specified in the datasheet
|
||||
`#define EXTERNAL_EEPROM_ADDRESS_SIZE` | `2` | The number of bytes to transmit for the memory location within the EEPROM
|
||||
|
||||
!> There's no way to determine if there is an SPI EEPROM actually responding. Generally, this will result in reads of nothing but zero.
|
||||
|
||||
@@ -73,3 +77,84 @@ The only configurable item for the transient EEPROM driver is its size:
|
||||
`#define TRANSIENT_EEPROM_SIZE` | Total size of the EEPROM storage in bytes | 64
|
||||
|
||||
Default values and extended descriptions can be found in `drivers/eeprom/eeprom_transient.h`.
|
||||
|
||||
## Wear-leveling Driver Configuration :id=wear_leveling-eeprom-driver-configuration
|
||||
|
||||
The wear-leveling driver uses an algorithm to minimise the number of erase cycles on the underlying MCU flash memory.
|
||||
|
||||
There is no specific configuration for this driver, but the wear-leveling system used by this driver may need configuration. See the [wear-leveling configuration](#wear_leveling-configuration) section for more information.
|
||||
|
||||
# Wear-leveling Configuration :id=wear_leveling-configuration
|
||||
|
||||
The wear-leveling driver has a few possible _backing stores_ that may be used by adding to your keyboard's `rules.mk` file:
|
||||
|
||||
Driver | Description
|
||||
----------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
`WEAR_LEVELING_DRIVER = embedded_flash` | This driver is used for emulating EEPROM by writing to embedded flash on the MCU.
|
||||
`WEAR_LEVELING_DRIVER = spi_flash` | This driver is used to address external SPI NOR Flash peripherals.
|
||||
`WEAR_LEVELING_DRIVER = rp2040_flash` | This driver is used to write to the same storage the RP2040 executes code from.
|
||||
`WEAR_LEVELING_DRIVER = legacy` | This driver is the "legacy" emulated EEPROM provided in historical revisions of QMK. Currently used for STM32F0xx and STM32F4x1, but slated for deprecation and removal once `embedded_flash` support for those MCU families is complete.
|
||||
|
||||
!> All wear-leveling drivers require an amount of RAM equivalent to the selected logical EEPROM size. Increasing the size to 32kB of EEPROM requires 32kB of RAM, which a significant number of MCUs simply do not have.
|
||||
|
||||
## Wear-leveling Embedded Flash Driver Configuration :id=wear_leveling-efl-driver-configuration
|
||||
|
||||
This driver performs writes to the embedded flash storage embedded in the MCU. In most circumstances, the last few of sectors of flash are used in order to minimise the likelihood of collision with program code.
|
||||
|
||||
Configurable options in your keyboard's `config.h`:
|
||||
|
||||
`config.h` override | Default | Description
|
||||
-----------------------------------------|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||
`#define WEAR_LEVELING_EFL_FIRST_SECTOR` | _unset_ | The first sector on the MCU to use. By default this is not defined and calculated at runtime based on the MCU. However, different flash sizes on MCUs may require custom configuration.
|
||||
`#define WEAR_LEVELING_EFL_FLASH_SIZE` | _unset_ | Allows overriding the flash size available for use for wear-leveling. Under normal circumstances this is automatically calculated and should not need to be overridden. Specifying a size larger than the amount actually available in flash will usually prevent the MCU from booting.
|
||||
`#define WEAR_LEVELING_LOGICAL_SIZE` | `1024` | Number of bytes "exposed" to the rest of QMK and denotes the size of the usable EEPROM.
|
||||
`#define WEAR_LEVELING_BACKING_SIZE` | `2048` | Number of bytes used by the wear-leveling algorithm for its underlying storage, and needs to be a multiple of the logical size.
|
||||
`#define BACKING_STORE_WRITE_SIZE` | _automatic_ | The byte width of the underlying write used on the MCU, and is usually automatically determined from the selected MCU family. If an error occurs in the auto-detection, you'll need to consult the MCU's datasheet and determine this value, specifying it directly.
|
||||
|
||||
!> If your MCU does not boot after swapping to the EFL wear-leveling driver, it's likely that the flash size is incorrectly detected, usually as an MCU with larger flash and may require overriding.
|
||||
|
||||
## Wear-leveling SPI Flash Driver Configuration :id=wear_leveling-flash_spi-driver-configuration
|
||||
|
||||
This driver performs writes to an external SPI NOR Flash peripheral. It also requires a working configuration for the SPI NOR Flash peripheral -- see the [flash driver](flash_driver.md) documentation for more information.
|
||||
|
||||
Configurable options in your keyboard's `config.h`:
|
||||
|
||||
`config.h` override | Default | Description
|
||||
----------------------------------------------------|--------------------------------|--------------------------------------------------------------------------------------------------------------------------------
|
||||
`#define WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_COUNT` | `1` | Number of blocks in the external flash used by the wear-leveling algorithm.
|
||||
`#define WEAR_LEVELING_EXTERNAL_FLASH_BLOCK_OFFSET` | `0` | The index first block in the external flash used by the wear-leveling algorithm.
|
||||
`#define WEAR_LEVELING_LOGICAL_SIZE` | `((block_count*block_size)/2)` | Number of bytes "exposed" to the rest of QMK and denotes the size of the usable EEPROM. Result must be <= 64kB.
|
||||
`#define WEAR_LEVELING_BACKING_SIZE` | `(block_count*block_size)` | Number of bytes used by the wear-leveling algorithm for its underlying storage, and needs to be a multiple of the logical size.
|
||||
`#define BACKING_STORE_WRITE_SIZE` | `8` | The write width used whenever a write is performed on the external flash peripheral.
|
||||
|
||||
!> There is currently a limit of 64kB for the EEPROM subsystem within QMK, so using a larger flash is not going to be beneficial as the logical size cannot be increased beyond 65536. The backing size may be increased to a larger value, but erase timing may suffer as a result.
|
||||
|
||||
## Wear-leveling RP2040 Driver Configuration :id=wear_leveling-rp2040-driver-configuration
|
||||
|
||||
This driver performs writes to the same underlying storage that the RP2040 executes its code.
|
||||
|
||||
Configurable options in your keyboard's `config.h`:
|
||||
|
||||
`config.h` override | Default | Description
|
||||
------------------------------------------|----------------------------|--------------------------------------------------------------------------------------------------------------------------------
|
||||
`#define WEAR_LEVELING_RP2040_FLASH_SIZE` | `PICO_FLASH_SIZE_BYTES` | Number of bytes of flash on the board.
|
||||
`#define WEAR_LEVELING_RP2040_FLASH_BASE` | `(flash_size-sector_size)` | The byte-wise location that the backing storage should be located.
|
||||
`#define WEAR_LEVELING_LOGICAL_SIZE` | `4096` | Number of bytes "exposed" to the rest of QMK and denotes the size of the usable EEPROM.
|
||||
`#define WEAR_LEVELING_BACKING_SIZE` | `8192` | Number of bytes used by the wear-leveling algorithm for its underlying storage, and needs to be a multiple of the logical size as well as the sector size.
|
||||
`#define BACKING_STORE_WRITE_SIZE` | `2` | The write width used whenever a write is performed on the external flash peripheral.
|
||||
|
||||
## Wear-leveling Legacy EEPROM Emulation Driver Configuration :id=wear_leveling-legacy-driver-configuration
|
||||
|
||||
This driver performs writes to the embedded flash storage embedded in the MCU much like the normal Embedded Flash Driver, and is only for use with STM32F0xx and STM32F4x1 devices. This flash implementation is still currently provided as the EFL driver is currently non-functional for the previously mentioned families.
|
||||
|
||||
By default, `1024` bytes of emulated EEPROM is provided:
|
||||
|
||||
MCU | EEPROM Provided | Flash Used
|
||||
----------|-----------------|--------------
|
||||
STM32F042 | `1024` bytes | `2048` bytes
|
||||
STM32F070 | `1024` bytes | `2048` bytes
|
||||
STM32F072 | `1024` bytes | `2048` bytes
|
||||
STM32F401 | `1024` bytes | `16384` bytes
|
||||
STM32F411 | `1024` bytes | `16384` bytes
|
||||
|
||||
Under normal circumstances configuration of this driver requires intimate knowledge of the MCU's flash structure -- reconfiguration is at your own risk and will require referring to the code.
|
||||
|
||||
98
docs/feature_converters.md
Normal file
98
docs/feature_converters.md
Normal file
@@ -0,0 +1,98 @@
|
||||
# Converters
|
||||
|
||||
Since many drop-in replacement controllers now exist, we've done our best to make them easy to use in existing designs.
|
||||
|
||||
This page documents the handy automated process for converting keyboards.
|
||||
|
||||
### Supported Converters
|
||||
|
||||
Currently the following converters are available:
|
||||
|
||||
| From | To |
|
||||
|------------|-------------------|
|
||||
| `promicro` | `proton_c` |
|
||||
| `promicro` | `kb2040` |
|
||||
| `promicro` | `promicro_rp2040` |
|
||||
| `promicro` | `blok` |
|
||||
|
||||
See below for more in depth information on each converter.
|
||||
|
||||
## Overview
|
||||
|
||||
Each converter category is broken down by its declared `pin compatibility`.
|
||||
This ensures that only valid combinations are attempted.
|
||||
|
||||
You can generate the firmware by appending `-e CONVERT_TO=<target>` to your compile/flash command. For example:
|
||||
|
||||
```sh
|
||||
qmk flash -c -kb keebio/bdn9/rev1 -km default -e CONVERT_TO=proton_c
|
||||
```
|
||||
|
||||
You can also add the same `CONVERT_TO=<target>` to your keymap's `rules.mk`, which will accomplish the same thing.
|
||||
|
||||
?> If you get errors about `PORTB/DDRB`, etc not being defined, you'll need to convert the keyboard's code to use the [GPIO Controls](gpio_control.md) that will work for both ARM and AVR. This shouldn't affect the AVR builds at all.
|
||||
|
||||
### Conditional Configuration
|
||||
|
||||
Once a converter is enabled, it exposes the `CONVERT_TO_<target_uppercase>` flag that you can use in your code with `#ifdef`s, For example:
|
||||
|
||||
```c
|
||||
#ifdef CONVERT_TO_PROTON_C
|
||||
// Proton C code
|
||||
#else
|
||||
// Pro Micro code
|
||||
#endif
|
||||
```
|
||||
|
||||
## Pro Micro
|
||||
|
||||
If a board currently supported in QMK uses a [Pro Micro](https://www.sparkfun.com/products/12640) (or compatible board), the supported alternative controllers are:
|
||||
|
||||
| Device | Target |
|
||||
|------------------------------------------------------------------------|-------------------|
|
||||
| [Proton C](https://qmk.fm/proton-c/) | `proton_c` |
|
||||
| [Adafruit KB2040](https://learn.adafruit.com/adafruit-kb2040) | `kb2040` |
|
||||
| [SparkFun Pro Micro - RP2040](https://www.sparkfun.com/products/18288) | `promicro_rp2040` |
|
||||
| [Blok](https://boardsource.xyz/store/628b95b494dfa308a6581622) | `blok` |
|
||||
|
||||
Converter summary:
|
||||
|
||||
| Target | Argument | `rules.mk` | Condition |
|
||||
|-------------------|---------------------------------|------------------------------|-------------------------------------|
|
||||
| `proton_c` | `-e CONVERT_TO=proton_c` | `CONVERT_TO=proton_c` | `#ifdef CONVERT_TO_PROTON_C` |
|
||||
| `kb2040` | `-e CONVERT_TO=kb2040` | `CONVERT_TO=kb2040` | `#ifdef CONVERT_TO_KB2040` |
|
||||
| `promicro_rp2040` | `-e CONVERT_TO=promicro_rp2040` | `CONVERT_TO=promicro_rp2040` | `#ifdef CONVERT_TO_PROMICRO_RP2040` |
|
||||
| `blok` | `-e CONVERT_TO=blok` | `CONVERT_TO=blok` | `#ifdef CONVERT_TO_BLOK` |
|
||||
|
||||
### Proton C :id=proton_c
|
||||
|
||||
The Proton C only has one on-board LED (C13), and by default, the TXLED (D5) is mapped to it. If you want the RXLED (B0) mapped to it instead, add this line to your `config.h`:
|
||||
|
||||
```c
|
||||
#define CONVERT_TO_PROTON_C_RXLED
|
||||
```
|
||||
|
||||
The following defaults are based on what has been implemented for STM32 boards.
|
||||
|
||||
| Feature | Notes |
|
||||
|----------------------------------------------|------------------------------------------------------------------------------------------------------------------|
|
||||
| [Audio](feature_audio.md) | Enabled |
|
||||
| [RGB Lighting](feature_rgblight.md) | Disabled |
|
||||
| [Backlight](feature_backlight.md) | Forces [task driven PWM](feature_backlight.md#software-pwm-driver) until ARM can provide automatic configuration |
|
||||
| USB Host (e.g. USB-USB converter) | Not supported (USB host code is AVR specific and is not currently supported on ARM) |
|
||||
| [Split keyboards](feature_split_keyboard.md) | Partial - heavily dependent on enabled features |
|
||||
|
||||
### Adafruit KB2040 :id=kb2040
|
||||
|
||||
The following defaults are based on what has been implemented for [RP2040](platformdev_rp2040.md) boards.
|
||||
|
||||
| Feature | Notes |
|
||||
|----------------------------------------------|------------------------------------------------------------------------------------------------------------------|
|
||||
| [RGB Lighting](feature_rgblight.md) | Enabled via `PIO` vendor driver |
|
||||
| [Backlight](feature_backlight.md) | Forces [task driven PWM](feature_backlight.md#software-pwm-driver) until ARM can provide automatic configuration |
|
||||
| USB Host (e.g. USB-USB converter) | Not supported (USB host code is AVR specific and is not currently supported on ARM) |
|
||||
| [Split keyboards](feature_split_keyboard.md) | Partial via `PIO` vendor driver - heavily dependent on enabled features |
|
||||
|
||||
### SparkFun Pro Micro - RP2040 and Blok :id=promicro_rp2040
|
||||
|
||||
Currently identical to [Adafruit KB2040](#kb2040).
|
||||
@@ -35,6 +35,7 @@ There are a number of options added that should allow some additional degree of
|
||||
|`DYNAMIC_MACRO_SIZE` |128 |Sets the amount of memory that Dynamic Macros can use. This is a limited resource, dependent on the controller. |
|
||||
|`DYNAMIC_MACRO_USER_CALL` |*Not defined* |Defining this falls back to using the user `keymap.c` file to trigger the macro behavior. |
|
||||
|`DYNAMIC_MACRO_NO_NESTING` |*Not Defined* |Defining this disables the ability to call a macro from another macro (nested macros). |
|
||||
|`DYNAMIC_MACRO_DELAY` |*Not Defined* |Sets the waiting time (ms unit) when sending each key. |
|
||||
|
||||
|
||||
If the LEDs start blinking during the recording with each keypress, it means there is no more space for the macro in the macro buffer. To fit the macro in, either make the other macro shorter (they share the same buffer) or increase the buffer size by adding the `DYNAMIC_MACRO_SIZE` define in your `config.h` (default value: 128; please read the comments for it in the header).
|
||||
|
||||
@@ -106,6 +106,8 @@ Only basic keycodes (prefixed by `KC_`) are supported. Do not include the `KC_`
|
||||
|
||||
### `SEND_STRING()` & `process_record_user`
|
||||
|
||||
See also: [Send String](feature_send_string.md)
|
||||
|
||||
Sometimes you want a key to type out words or phrases. For the most common situations, we've provided `SEND_STRING()`, which will type out a string (i.e. a sequence of characters) for you. All ASCII characters that are easily translatable to a keycode are supported (e.g. `qmk 123\n\t`).
|
||||
|
||||
Here is an example `keymap.c` for a two-key keyboard:
|
||||
|
||||
@@ -87,9 +87,9 @@ This is an extension of the accelerated mode. The kinetic mode uses a quadratic
|
||||
|`MK_KINETIC_SPEED` |undefined|Enable kinetic mode |
|
||||
|`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_MOVE_DELTA` |16 |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_BASE_SPEED` |5000 |Maximum cursor speed at which acceleration stops |
|
||||
|`MOUSEKEY_DECELERATED_SPEED` |400 |Decelerated cursor speed |
|
||||
|`MOUSEKEY_ACCELERATED_SPEED` |3000 |Accelerated cursor speed |
|
||||
|`MOUSEKEY_WHEEL_INITIAL_MOVEMENTS` |16 |Initial number of movements of the mouse wheel |
|
||||
@@ -100,7 +100,7 @@ This is an extension of the accelerated mode. The kinetic mode uses a quadratic
|
||||
Tips:
|
||||
|
||||
* The smoothness of the cursor movement depends on the `MOUSEKEY_INTERVAL` setting. The shorter the interval is set the smoother the movement will be. Setting the value too low makes the cursor unresponsive. Lower settings are possible if the micro processor is fast enough. For example: At an interval of `8` milliseconds, `125` movements per second will be initiated. With a base speed of `1000` each movement will move the cursor by `8` pixels.
|
||||
* Mouse wheel movements are implemented differently from cursor movements. While it's okay for the cursor to move multiple pixels at once for the mouse wheel this would lead to jerky movements. Instead, the mouse wheel operates at step size `1`. Setting mouse wheel speed is done by adjusting the number of wheel movements per second.
|
||||
* Mouse wheel movements are implemented differently from cursor movements. While it's okay for the cursor to move multiple pixels at once for the mouse wheel this would lead to jerky movements. Instead, the mouse wheel operates at step size `2`. Setting mouse wheel speed is done by adjusting the number of wheel movements per second.
|
||||
|
||||
### Constant mode
|
||||
|
||||
|
||||
@@ -22,11 +22,11 @@ POINTING_DEVICE_DRIVER = adns5050
|
||||
|
||||
The ADNS 5050 sensor uses a serial type protocol for communication, and requires an additional light source.
|
||||
|
||||
| Setting | Description |
|
||||
|--------------------|---------------------------------------------------------------------|
|
||||
|`ADNS5050_SCLK_PIN` | (Required) The pin connected to the clock pin of the sensor. |
|
||||
|`ADNS5050_SDIO_PIN` | (Required) The pin connected to the data pin of the sensor. |
|
||||
|`ADNS5050_CS_PIN` | (Required) The pin connected to the cable select pin of the sensor. |
|
||||
| Setting | Description |
|
||||
| ------------------- | ------------------------------------------------------------------- |
|
||||
| `ADNS5050_SCLK_PIN` | (Required) The pin connected to the clock pin of the sensor. |
|
||||
| `ADNS5050_SDIO_PIN` | (Required) The pin connected to the data pin of the sensor. |
|
||||
| `ADNS5050_CS_PIN` | (Required) The pin connected to the cable select pin of the sensor. |
|
||||
|
||||
The CPI range is 125-1375, in increments of 125. Defaults to 500 CPI.
|
||||
|
||||
@@ -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.
|
||||
@@ -61,17 +61,16 @@ POINTING_DEVICE_DRIVER = analog_joystick
|
||||
|
||||
The Analog Joystick is an analog (ADC) driven sensor. There are a variety of joysticks that you can use for this.
|
||||
|
||||
| Setting | Description | Default |
|
||||
|----------------------------------|----------------------------------------------------------------------------|---------------|
|
||||
|`ANALOG_JOYSTICK_X_AXIS_PIN` | (Required) The pin used for the vertical/X axis. | _not defined_ |
|
||||
|`ANALOG_JOYSTICK_Y_AXIS_PIN` | (Required) The pin used for the horizontal/Y axis. | _not defined_ |
|
||||
|`ANALOG_JOYSTICK_AXIS_MIN` | (Optional) Sets the lower range to be considered movement. | `0` |
|
||||
|`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 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_ |
|
||||
|
||||
| Setting | Description | Default |
|
||||
| --------------------------------- | -------------------------------------------------------------------------- | ------------- |
|
||||
| `ANALOG_JOYSTICK_X_AXIS_PIN` | (Required) The pin used for the vertical/X axis. | _not defined_ |
|
||||
| `ANALOG_JOYSTICK_Y_AXIS_PIN` | (Required) The pin used for the horizontal/Y axis. | _not defined_ |
|
||||
| `ANALOG_JOYSTICK_AXIS_MIN` | (Optional) Sets the lower range to be considered movement. | `0` |
|
||||
| `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 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_ |
|
||||
|
||||
### Cirque Trackpad
|
||||
|
||||
@@ -90,29 +89,70 @@ POINTING_DEVICE_DRIVER = cirque_pinnacle_spi
|
||||
|
||||
This supports the Cirque Pinnacle 1CA027 Touch Controller, which is used in the TM040040, TM035035 and the TM023023 trackpads. These are I2C or SPI compatible, and both configurations are supported.
|
||||
|
||||
| Setting | Description | Default |
|
||||
|---------------------------------|---------------------------------------------------------------------------------|-----------------------|
|
||||
|`CIRQUE_PINNACLE_X_LOWER` | (Optional) The minimum reachable X value on the sensor. | `127` |
|
||||
|`CIRQUE_PINNACLE_X_UPPER` | (Optional) The maximum reachable X value on the sensor. | `1919` |
|
||||
|`CIRQUE_PINNACLE_Y_LOWER` | (Optional) The minimum reachable Y value on the sensor. | `63` |
|
||||
|`CIRQUE_PINNACLE_Y_UPPER` | (Optional) The maximum reachable Y value on the sensor. | `1471` |
|
||||
|`CIRQUE_PINNACLE_TAPPING_TERM` | (Optional) Length of time that a touch can be to be considered a tap. | `TAPPING_TERM`/`200` |
|
||||
|`CIRQUE_PINNACLE_TOUCH_DEBOUNCE` | (Optional) Length of time that a touch can be to be considered a tap. | `TAPPING_TERM`/`200` |
|
||||
| Setting | Description | Default |
|
||||
| -------------------------------- | ---------------------------------------------------------- | ------------------ |
|
||||
| `CIRQUE_PINNACLE_X_LOWER` | (Optional) The minimum reachable X value on the sensor. | `127` |
|
||||
| `CIRQUE_PINNACLE_X_UPPER` | (Optional) The maximum reachable X value on the sensor. | `1919` |
|
||||
| `CIRQUE_PINNACLE_Y_LOWER` | (Optional) The minimum reachable Y value on the sensor. | `63` |
|
||||
| `CIRQUE_PINNACLE_Y_UPPER` | (Optional) The maximum reachable Y value on the sensor. | `1471` |
|
||||
| `CIRQUE_PINNACLE_DIAMETER_MM` | (Optional) Diameter of the trackpad sensor in millimeters. | `40` |
|
||||
| `CIRQUE_PINNACLE_ATTENUATION` | (Optional) Sets the attenuation of the sensor data. | `ADC_ATTENUATE_4X` |
|
||||
| `CIRQUE_PINNACLE_CURVED_OVERLAY` | (Optional) Applies settings tuned for curved overlay. | _not defined_ |
|
||||
|
||||
| I2C Setting | Description | Default |
|
||||
|--------------------------|---------------------------------------------------------------------------------|---------|
|
||||
|`CIRQUE_PINNACLE_ADDR` | (Required) Sets the I2C Address for the Cirque Trackpad | `0x2A` |
|
||||
|`CIRQUE_PINNACLE_TIMEOUT` | (Optional) The timeout for i2c communication with the trackpad in milliseconds. | `20` |
|
||||
**`CIRQUE_PINNACLE_ATTENUATION`** is a measure of how much data is suppressed in regards to sensitivity. The higher the attenuation, the less sensitive the touchpad will be.
|
||||
|
||||
| SPI Setting | Description | Default |
|
||||
|-------------------------------|------------------------------------------------------------------------|---------------|
|
||||
|`CIRQUE_PINNACLE_CLOCK_SPEED` | (Optional) Sets the clock speed that the sensor runs at. | `1000000` |
|
||||
|`CIRQUE_PINNACLE_SPI_LSBFIRST` | (Optional) Sets the Least/Most Significant Byte First setting for SPI. | `false` |
|
||||
|`CIRQUE_PINNACLE_SPI_MODE` | (Optional) Sets the SPI Mode for the sensor. | `1` |
|
||||
|`CIRQUE_PINNACLE_SPI_DIVISOR` | (Optional) Sets the SPI Divisor used for SPI communication. | _varies_ |
|
||||
|`CIRQUE_PINNACLE_SPI_CS_PIN` | (Required) Sets the Cable Select pin connected to the sensor. | _not defined_ |
|
||||
Default attenuation is set to 4X, although if you are using a thicker overlay (such as the curved overlay) you will want a lower attenuation such as 2X. The possible values are:
|
||||
* `ADC_ATTENUATE_4X`: Least sensitive
|
||||
* `ADC_ATTENUATE_3X`
|
||||
* `ADC_ATTENUATE_2X`
|
||||
* `ADC_ATTENUATE_1X`: Most sensitive
|
||||
|
||||
| I2C Setting | Description | Default |
|
||||
| ------------------------- | ------------------------------------------------------------------------------- | ------- |
|
||||
| `CIRQUE_PINNACLE_ADDR` | (Required) Sets the I2C Address for the Cirque Trackpad | `0x2A` |
|
||||
| `CIRQUE_PINNACLE_TIMEOUT` | (Optional) The timeout for i2c communication with the trackpad in milliseconds. | `20` |
|
||||
|
||||
| SPI Setting | Description | Default |
|
||||
| ------------------------------ | ---------------------------------------------------------------------- | ------------- |
|
||||
| `CIRQUE_PINNACLE_CLOCK_SPEED` | (Optional) Sets the clock speed that the sensor runs at. | `1000000` |
|
||||
| `CIRQUE_PINNACLE_SPI_LSBFIRST` | (Optional) Sets the Least/Most Significant Byte First setting for SPI. | `false` |
|
||||
| `CIRQUE_PINNACLE_SPI_MODE` | (Optional) Sets the SPI Mode for the sensor. | `1` |
|
||||
| `CIRQUE_PINNACLE_SPI_DIVISOR` | (Optional) Sets the SPI Divisor used for SPI communication. | _varies_ |
|
||||
| `CIRQUE_PINNACLE_SPI_CS_PIN` | (Required) Sets the Cable Select pin connected to the sensor. | _not defined_ |
|
||||
|
||||
Default Scaling is 1024. Actual CPI depends on trackpad diameter.
|
||||
|
||||
Also see the `POINTING_DEVICE_TASK_THROTTLE_MS`, which defaults to 10ms when using Cirque Pinnacle, which matches the internal update rate of the position registers (in standard configuration). Advanced configuration for pen/stylus usage might require lower values.
|
||||
|
||||
#### Cirque Trackpad gestures
|
||||
|
||||
| Gesture Setting | Description | Default |
|
||||
| ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------- |
|
||||
| `POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE` | (Optional) Enable inertial cursor. Cursor continues moving after a flick gesture and slows down by kinetic friction | _not defined_ |
|
||||
| `CIRQUE_PINNACLE_CIRCULAR_SCROLL_ENABLE` | (Optional) Enable circular scroll. Touch originating in outer ring can trigger scroll by moving along the perimeter. Near side triggers vertical scroll and far side triggers horizontal scroll. | _not defined_ |
|
||||
| `CIRQUE_PINNACLE_TAP_ENABLE` | (Optional) Enable tap to click. This currently only works on the master side. | _not defined_ |
|
||||
| `CIRQUE_PINNACLE_TAPPING_TERM` | (Optional) Length of time that a touch can be to be considered a tap. | `TAPPING_TERM`/`200` |
|
||||
| `CIRQUE_PINNACLE_TOUCH_DEBOUNCE` | (Optional) Length of time that a touch can be to be considered a tap. | `TAPPING_TERM`/`200` |
|
||||
|
||||
**`POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE`** is not specific to Cirque trackpad; any pointing device with a lift/contact status can integrate this gesture into its driver. e.g. PMW3360 can use Lift_Stat from Motion register. Note that `POINTING_DEVICE_MOTION_PIN` cannot be used with this feature; continuous polling of `pointing_device_get_report()` is needed to generate glide reports.
|
||||
|
||||
### PAW 3204 Sensor
|
||||
|
||||
To use the paw 3204 sensor, add this to your `rules.mk`
|
||||
|
||||
```make
|
||||
POINTING_DEVICE_DRIVER = paw3204
|
||||
```
|
||||
|
||||
The paw 3204 sensor uses a serial type protocol for communication, and requires an additional light source.
|
||||
|
||||
| Setting | Description |
|
||||
|--------------------|---------------------------------------------------------------------|
|
||||
|`PAW3204_SCLK_PIN` | (Required) The pin connected to the clock pin of the sensor. |
|
||||
|`PAW3204_SDIO_PIN` | (Required) The pin connected to the data pin of the sensor. |
|
||||
|
||||
The CPI range is 400-1600, with supported values of (400, 500, 600, 800, 1000, 1200 and 1600). Defaults to 1000 CPI.
|
||||
|
||||
Default Scaling/CPI is 1024.
|
||||
|
||||
### Pimoroni Trackball
|
||||
|
||||
@@ -124,62 +164,69 @@ POINTING_DEVICE_DRIVER = pimoroni_trackball
|
||||
|
||||
The Pimoroni Trackball module is a I2C based breakout board with an RGB enable trackball.
|
||||
|
||||
| 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 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` |
|
||||
| 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 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` |
|
||||
|
||||
### PMW 3360 Sensor
|
||||
### PMW 3360 and PMW 3389 Sensor
|
||||
|
||||
This drivers supports multiple sensors _per_ controller, so 2 can be attached at the same side for split keyboards (or unsplit keyboards).
|
||||
To use the PMW 3360 sensor, add this to your `rules.mk`
|
||||
This drivers supports both the PMW 3360 and PMW 3389 sensor as well as multiple sensors of the same type _per_ controller, so 2 can be attached at the same side for split keyboards (or unsplit keyboards).
|
||||
|
||||
To use the **PMW 3360** sensor, add this to your `rules.mk`
|
||||
|
||||
```make
|
||||
POINTING_DEVICE_DRIVER = pmw3360
|
||||
```
|
||||
|
||||
The PMW 3360 is an SPI driven optical sensor, that uses a built in IR LED for surface tracking.
|
||||
|
||||
| Setting | Description | Default |
|
||||
|-----------------------------|--------------------------------------------------------------------------------------------|---------------|
|
||||
|`PMW3360_CS_PIN` | (Required) Sets the Cable Select pin connected to the sensor. | _not defined_ |
|
||||
|`PMW3360_CS_PINS` | (Alternative) Sets the Cable Select pins connected to multiple sensors. | _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.
|
||||
|
||||
To use multiple sensors, instead of setting `PMW3360_CS_PIN` you need to set `PMW3360_CS_PINS` and also handle and merge the read from this sensor in user code.
|
||||
To use the **PMW 3389** sensor, add this to your `rules.mk`
|
||||
|
||||
```make
|
||||
POINTING_DEVICE_DRIVER = pmw3389
|
||||
```
|
||||
|
||||
The CPI range is 50-16000, in increments of 50. Defaults to 2000 CPI.
|
||||
|
||||
Both PMW 3360 and PMW 3389 are SPI driven optical sensors, that use a built in IR LED for surface tracking.
|
||||
|
||||
| Setting | Description | Default |
|
||||
| ---------------------------- | ------------------------------------------------------------------------------------------- | ------------- |
|
||||
| `PMW33XX_CS_PIN` | (Required) Sets the Cable Select pin connected to the sensor. | _not defined_ |
|
||||
| `PMW33XX_CS_PINS` | (Alternative) Sets the Cable Select pins connected to multiple sensors. | _not defined_ |
|
||||
| `PMW33XX_CPI` | (Optional) Sets counts per inch sensitivity of the sensor. | _varies_ |
|
||||
| `PMW33XX_CLOCK_SPEED` | (Optional) Sets the clock speed that the sensor runs at. | `2000000` |
|
||||
| `PMW33XX_SPI_DIVISOR` | (Optional) Sets the SPI Divisor used for SPI communication. | _varies_ |
|
||||
| `PMW33XX_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` |
|
||||
|
||||
To use multiple sensors, instead of setting `PMW33XX_CS_PIN` you need to set `PMW33XX_CS_PINS` and also handle and merge the read from this sensor in user code.
|
||||
Note that different (per sensor) values of CPI, speed liftoff, rotational angle or flipping of X/Y is not currently supported.
|
||||
|
||||
```c
|
||||
// in config.h:
|
||||
#define PMW3360_CS_PINS { B5, B6 }
|
||||
|
||||
#define PMW33XX_CS_PINS { B5, B6 }
|
||||
// in keyboard.c:
|
||||
#ifdef POINTING_DEVICE_ENABLE
|
||||
void pointing_device_init_kb(void) {
|
||||
pmw3360_init(1); // index 1 is the second device.
|
||||
pointing_device_set_cpi(800); // applies to both sensors
|
||||
pmw33xx_init(1); // index 1 is the second device.
|
||||
pmw33xx_set_cpi(0, 800); // applies to first sensor
|
||||
pmw33xx_set_cpi(1, 800); // applies to second sensor
|
||||
pointing_device_init_user();
|
||||
}
|
||||
|
||||
// Contains report from sensor #0 already, need to merge in from sensor #1
|
||||
report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
|
||||
report_pmw3360_t data = pmw3360_read_burst(1);
|
||||
if (data.isOnSurface && data.isMotion) {
|
||||
pmw33xx_report_t report = pmw33xx_read_burst(1);
|
||||
if (!report.motion.b.is_lifted && report.motion.b.is_motion) {
|
||||
// From quantum/pointing_device_drivers.c
|
||||
#define constrain_hid(amt) ((amt) < -127 ? -127 : ((amt) > 127 ? 127 : (amt)))
|
||||
mouse_report.x = constrain_hid(mouse_report.x + data.dx);
|
||||
mouse_report.y = constrain_hid(mouse_report.y + data.dy);
|
||||
mouse_report.x = constrain_hid(mouse_report.x + report.delta_x);
|
||||
mouse_report.y = constrain_hid(mouse_report.y + report.delta_y);
|
||||
}
|
||||
return pointing_device_task_user(mouse_report);
|
||||
}
|
||||
@@ -187,30 +234,6 @@ report_mouse_t pointing_device_task_kb(report_mouse_t mouse_report) {
|
||||
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
If you have a sensor type that isn't supported above, a custom option is available by adding the following to your `rules.mk`
|
||||
@@ -232,15 +255,15 @@ 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_ |
|
||||
|`POINTING_DEVICE_TASK_THROTTLE_MS` | (Optional) Limits the frequency that the sensor is polled for motion. | _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.
|
||||
|
||||
@@ -249,24 +272,25 @@ void pointing_device_driver_set_cpi(uint16_t cpi) {}
|
||||
|
||||
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_ |
|
||||
| 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_ |
|
||||
| `MOUSE_EXTENDED_REPORT` | (Optional) Enables support for extended mouse reports. (-32767 to 32767, instead of just -127 to 127) |
|
||||
|
||||
!> 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
|
||||
|
||||
| Function | Description |
|
||||
|-----------------------------------|----------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| Function | Description |
|
||||
| ---------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
|
||||
| `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. |
|
||||
@@ -274,11 +298,11 @@ The following configuration options are only available when using `SPLIT_POINTIN
|
||||
| `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. |
|
||||
| `pointing_device_get_report(void)` | Returns the current mouse report (as a `mouse_report_t` data structure). |
|
||||
| `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. |
|
||||
| `pointing_device_get_report(void)` | Returns the current mouse report (as a `mouse_report_t` data structure). |
|
||||
| `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(new_report, old_report)` | 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. |
|
||||
| `pointing_device_adjust_by_defines(mouse_report)` | Applies rotations and invert configurations to a raw mouse report. |
|
||||
|
||||
|
||||
## Split Keyboard Callbacks and Functions
|
||||
@@ -286,7 +310,7 @@ The following configuration options are only available when using `SPLIT_POINTIN
|
||||
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) |
|
||||
|
||||
@@ -86,6 +86,7 @@ You can use between 1 and 4 IS31FL3733 IC's. Do not specify `DRIVER_ADDR_<N>` de
|
||||
| `ISSI_TIMEOUT` | (Optional) How long to wait for i2c messages, in milliseconds | 100 |
|
||||
| `ISSI_PERSISTENCE` | (Optional) Retry failed messages this many times | 0 |
|
||||
| `ISSI_PWM_FREQUENCY` | (Optional) PWM Frequency Setting - IS31FL3733B only | 0 |
|
||||
| `ISSI_GLOBALCURRENT` | (Optional) Configuration for the Global Current Register | 0xFF |
|
||||
| `ISSI_SWPULLUP` | (Optional) Set the value of the SWx lines on-chip de-ghosting resistors | PUR_0R (Disabled) |
|
||||
| `ISSI_CSPULLUP` | (Optional) Set the value of the CSx lines on-chip de-ghosting resistors | PUR_0R (Disabled) |
|
||||
| `DRIVER_COUNT` | (Required) How many RGB driver IC's are present | |
|
||||
@@ -172,6 +173,7 @@ Configure the hardware via your `config.h`:
|
||||
| `ISSI_TIMEOUT` | (Optional) How long to wait for i2c messages, in milliseconds | 100 |
|
||||
| `ISSI_PERSISTENCE` | (Optional) Retry failed messages this many times | 0 |
|
||||
| `ISSI_PWM_FREQUENCY` | (Optional) PWM Frequency Setting - IS31FL3737B only | 0 |
|
||||
| `ISSI_GLOBALCURRENT` | (Optional) Configuration for the Global Current Register | 0xFF |
|
||||
| `ISSI_SWPULLUP` | (Optional) Set the value of the SWx lines on-chip de-ghosting resistors | PUR_0R (Disabled) |
|
||||
| `ISSI_CSPULLUP` | (Optional) Set the value of the CSx lines on-chip de-ghosting resistors | PUR_0R (Disabled) |
|
||||
| `DRIVER_COUNT` | (Required) How many RGB driver IC's are present | |
|
||||
@@ -409,6 +411,7 @@ You can use up to 2 AW20216 IC's. Do not specify `DRIVER_<N>_xxx` defines for IC
|
||||
| `DRIVER_LED_TOTAL` | (Required) How many RGB lights are present across all drivers | |
|
||||
| `AW_SCALING_MAX` | (Optional) LED current scaling value (0-255, higher values mean LED is brighter at full PWM) | 150 |
|
||||
| `AW_GLOBAL_CURRENT_MAX` | (Optional) Driver global current limit (0-255, higher values means the driver may consume more power) | 150 |
|
||||
| `AW_SPI_MODE` | (Optional) Mode for SPI communication (0-3, defines polarity and phase of the clock) | 3 |
|
||||
| `AW_SPI_DIVISOR` | (Optional) Clock divisor for SPI communication (powers of 2, smaller numbers means faster communication, should not be less than 4) | 4 |
|
||||
|
||||
Here is an example using 2 drivers.
|
||||
@@ -665,11 +668,36 @@ In order to change the delay of temperature decrease define `RGB_MATRIX_TYPING_H
|
||||
#define RGB_MATRIX_TYPING_HEATMAP_DECREASE_DELAY_MS 50
|
||||
```
|
||||
|
||||
Heatmap effect may not light up the correct adjacent LEDs for certain key matrix layout such as split keyboards. The following define will limit the effect to pressed keys only:
|
||||
As heatmap uses the physical position of the leds set in the g_led_config, you may need to tweak the following options to get the best effect for your keyboard. Note the size of this grid is `224x64`.
|
||||
|
||||
Limit the distance the effect spreads to surrounding keys.
|
||||
|
||||
```c
|
||||
#define RGB_MATRIX_TYPING_HEATMAP_SPREAD 40
|
||||
```
|
||||
|
||||
Limit how hot surrounding keys get from each press.
|
||||
|
||||
```c
|
||||
#define RGB_MATRIX_TYPING_HEATMAP_AREA_LIMIT 16
|
||||
```
|
||||
|
||||
Remove the spread effect entirely.
|
||||
|
||||
```c
|
||||
#define RGB_MATRIX_TYPING_HEATMAP_SLIM
|
||||
```
|
||||
|
||||
### RGB Matrix Effect Solid Reactive :id=rgb-matrix-effect-solid-reactive
|
||||
|
||||
Solid reactive effects will pulse RGB light on key presses with user configurable hues. To enable gradient mode that will automatically change reactive color, add the following define:
|
||||
|
||||
```c
|
||||
#define RGB_MATRIX_SOLID_REACTIVE_GRADIENT_MODE
|
||||
```
|
||||
|
||||
Gradient mode will loop through the color wheel hues over time and its duration can be controlled with the effect speed keycodes (`RGB_SPI`/`RGB_SPD`).
|
||||
|
||||
## Custom RGB Matrix Effects :id=custom-rgb-matrix-effects
|
||||
|
||||
By setting `RGB_MATRIX_CUSTOM_USER = yes` in `rules.mk`, new effects can be defined directly from your keymap or userspace, without having to edit any QMK core files. To declare new effects, create a `rgb_matrix_user.inc` file in the user keymap directory or userspace folder.
|
||||
@@ -777,6 +805,7 @@ These are defined in [`color.h`](https://github.com/qmk/qmk_firmware/blob/master
|
||||
#define RGB_MATRIX_DISABLE_KEYCODES // disables control of rgb matrix by keycodes (must use code functions to control the feature)
|
||||
#define RGB_MATRIX_SPLIT { X, Y } // (Optional) For split keyboards, the number of LEDs connected on each half. X = left, Y = Right.
|
||||
// If RGB_MATRIX_KEYPRESSES or RGB_MATRIX_KEYRELEASES is enabled, you also will want to enable SPLIT_TRANSPORT_MIRROR
|
||||
#define RGB_TRIGGER_ON_KEYDOWN // Triggers RGB keypress events on key down. This makes RGB control feel more responsive. This may cause RGB to not function properly on some boards
|
||||
```
|
||||
|
||||
## EEPROM storage :id=eeprom-storage
|
||||
|
||||
54
docs/feature_secure.md
Normal file
54
docs/feature_secure.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Secure
|
||||
|
||||
The secure feature aims to prevent unwanted interaction without user intervention.
|
||||
|
||||
?> Secure does **not** currently implement encryption/decryption/etc and should not be a replacement where a strong hardware/software based solution is required.
|
||||
|
||||
### Unlock sequence
|
||||
|
||||
To unlock, the user must perform a set of actions. This can optionally be configured to be multiple keys.
|
||||
|
||||
* While unlocking all keyboard input is ignored
|
||||
* Incorrect attempts will revert back to the previously locked state
|
||||
|
||||
### Automatic Locking
|
||||
|
||||
Once unlocked, the keyboard will revert back to a locked state after the configured timeout.
|
||||
The timeout can be refreshed by using the `secure_activity_event` function, for example from one of the various [hooks](custom_quantum_functions.md).
|
||||
|
||||
## Usage
|
||||
|
||||
Add the following to your `rules.mk`:
|
||||
|
||||
```make
|
||||
SECURE_ENABLE = yes
|
||||
```
|
||||
|
||||
## Keycodes
|
||||
|
||||
| Key | Description |
|
||||
|------------------|--------------------------------------------------------------------------------|
|
||||
| `SECURE_LOCK` | Revert back to a locked state |
|
||||
| `SECURE_UNLOCK` | Forces unlock without performing a unlock sequence |
|
||||
| `SECURE_TOGGLE` | Toggle directly between locked and unlock without performing a unlock sequence |
|
||||
| `SECURE_REQUEST` | Request that user perform the unlock sequence |
|
||||
|
||||
## Configuration
|
||||
|
||||
| Define | Default | Description |
|
||||
|-------------------------|----------------|---------------------------------------------------------------------------------|
|
||||
|`SECURE_UNLOCK_TIMEOUT` | `5000` | Timeout for the user to perform the configured unlock sequence - `0` to disable |
|
||||
|`SECURE_IDLE_TIMEOUT` | `60000` | Timeout while unlocked before returning to locked - `0` to disable |
|
||||
|`SECURE_UNLOCK_SEQUENCE` | `{ { 0, 0 } }` | Array of matrix locations describing a sequential sequence of keypresses |
|
||||
|
||||
## Functions
|
||||
|
||||
| Function | Description |
|
||||
|---------------------------|----------------------------------------------------------------------------|
|
||||
| `secure_is_locked()` | Check if the device is currently locked |
|
||||
| `secure_is_unlocking()` | Check if an unlock sequence is currently in progress |
|
||||
| `secure_is_unlocked()` | Check if the device is currently unlocked |
|
||||
| `secure_lock()` | Lock down the device |
|
||||
| `secure_unlock()` | Force unlock the device - bypasses user unlock sequence |
|
||||
| `secure_request_unlock()` | Begin listening for an unlock sequence |
|
||||
| `secure_activity_event()` | Flag that user activity has happened and the device should remain unlocked |
|
||||
224
docs/feature_send_string.md
Normal file
224
docs/feature_send_string.md
Normal file
@@ -0,0 +1,224 @@
|
||||
# Send String
|
||||
|
||||
The Send String API is part of QMK's macro system. It allows for sequences of keystrokes to be sent automatically.
|
||||
|
||||
The full ASCII character set is supported, along with all of the keycodes in the Basic Keycode range (as these are the only ones that will actually be sent to the host).
|
||||
|
||||
?> Unicode characters are **not** supported with this API -- see the [Unicode](feature_unicode.md) feature instead.
|
||||
|
||||
## Usage
|
||||
|
||||
Send String is enabled by default, so there is usually no need for any special setup. However, if it is disabled, add the following to your `rules.mk`:
|
||||
|
||||
```make
|
||||
SEND_STRING_ENABLE = yes
|
||||
```
|
||||
|
||||
## Basic Configuration
|
||||
|
||||
Add the following to your `config.h`:
|
||||
|
||||
|Define |Default |Description |
|
||||
|-----------------|----------------|------------------------------------------------------------------------------------------------------------|
|
||||
|`SENDSTRING_BELL`|*Not defined* |If the [Audio](feature_audio.md) feature is enabled, the `\a` character (ASCII `BEL`) will beep the speaker.|
|
||||
|`BELL_SOUND` |`TERMINAL_SOUND`|The song to play when the `\a` character is encountered. By default, this is an eighth note of C5. |
|
||||
|
||||
## Keycodes
|
||||
|
||||
The Send String functions accept C string literals, but specific keycodes can be injected with the below macros. All of the keycodes in the [Basic Keycode range](keycodes_basic.md) are supported (as these are the only ones that will actually be sent to the host), but with an `X_` prefix instead of `KC_`.
|
||||
|
||||
|Macro |Description |
|
||||
|--------------|-------------------------------------------------------------------|
|
||||
|`SS_TAP(x)` |Send a keydown, then keyup, event for the given Send String keycode|
|
||||
|`SS_DOWN(x)` |Send a keydown event for the given Send String keycode |
|
||||
|`SS_UP(x)` |Send a keyup event for the given Send String keycode |
|
||||
|`SS_DELAY(ms)`|Wait for `ms` milliseconds |
|
||||
|
||||
The following characters are also mapped to their respective keycodes for convenience:
|
||||
|
||||
|Character|Hex |ASCII|Keycode |
|
||||
|---------|------|-----|--------------|
|
||||
|`\b` |`\x08`|`BS` |`KC_BACKSPACE`|
|
||||
|`\e` |`\x09`|`ESC`|`KC_ESCAPE` |
|
||||
|`\n` |`\x0A`|`LF` |`KC_ENTER` |
|
||||
|`\t` |`\x1B`|`TAB`|`KC_TAB` |
|
||||
| |`\x7F`|`DEL`|`KC_DELETE` |
|
||||
|
||||
### Language Support
|
||||
|
||||
By default, Send String assumes your OS keyboard layout is set to US ANSI. If you are using a different keyboard layout, you can [override the lookup tables used to convert ASCII characters to keystrokes](reference_keymap_extras.md#sendstring-support).
|
||||
|
||||
## Examples
|
||||
|
||||
### Hello World
|
||||
|
||||
A simple custom keycode which types out "Hello, world!" and the Enter key when pressed.
|
||||
|
||||
Add the following to your `keymap.c`:
|
||||
|
||||
```c
|
||||
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||
switch (keycode) {
|
||||
case SS_HELLO:
|
||||
if (record->event.pressed) {
|
||||
SEND_STRING("Hello, world!\n");
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
||||
### Keycode Injection
|
||||
|
||||
This example types out opening and closing curly braces, then taps the left arrow key to move the cursor between the two.
|
||||
|
||||
```c
|
||||
SEND_STRING("{}" SS_TAP(X_LEFT));
|
||||
```
|
||||
|
||||
This example types Ctrl+A, then Ctrl+C, without releasing Ctrl.
|
||||
|
||||
```c
|
||||
SEND_STRING(SS_LCTL("ac"));
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### `void send_string(const char *string)`
|
||||
|
||||
Type out a string of ASCII characters.
|
||||
|
||||
This function simply calls `send_string_with_delay(string, 0)`.
|
||||
|
||||
#### Arguments
|
||||
|
||||
- `const char *string`
|
||||
The string to type out.
|
||||
|
||||
---
|
||||
|
||||
### `void send_string_with_delay(const char *string, uint8_t interval)`
|
||||
|
||||
Type out a string of ASCII characters, with a delay between each character.
|
||||
|
||||
#### Arguments
|
||||
|
||||
- `const char *string`
|
||||
The string to type out.
|
||||
- `uint8_t interval`
|
||||
The amount of time, in milliseconds, to wait before typing the next character.
|
||||
|
||||
---
|
||||
|
||||
### `void send_string_P(const char *string)`
|
||||
|
||||
Type out a PROGMEM string of ASCII characters.
|
||||
|
||||
On ARM devices, this function is simply an alias for `send_string_with_delay(string, 0)`.
|
||||
|
||||
#### Arguments
|
||||
|
||||
- `const char *string`
|
||||
The string to type out.
|
||||
|
||||
---
|
||||
|
||||
### `void send_string_with_delay_P(const char *string, uint8_t interval)`
|
||||
|
||||
Type out a PROGMEM string of ASCII characters, with a delay between each character.
|
||||
|
||||
On ARM devices, this function is simply an alias for `send_string_with_delay(string, interval)`.
|
||||
|
||||
#### Arguments
|
||||
|
||||
- `const char *string`
|
||||
The string to type out.
|
||||
- `uint8_t interval`
|
||||
The amount of time, in milliseconds, to wait before typing the next character.
|
||||
|
||||
---
|
||||
|
||||
### `void send_char(char ascii_code)`
|
||||
|
||||
Type out an ASCII character.
|
||||
|
||||
#### Arguments
|
||||
|
||||
- `char ascii_code`
|
||||
The character to type.
|
||||
|
||||
---
|
||||
|
||||
### `void send_dword(uint32_t number)`
|
||||
|
||||
Type out an eight digit (unsigned 32-bit) hexadecimal value.
|
||||
|
||||
The format is `[0-9a-f]{8}`, eg. `00000000` through `ffffffff`.
|
||||
|
||||
#### Arguments
|
||||
|
||||
- `uint32_t number`
|
||||
The value to type, from 0 to 4,294,967,295.
|
||||
|
||||
---
|
||||
|
||||
### `void send_word(uint16_t number)`
|
||||
|
||||
Type out a four digit (unsigned 16-bit) hexadecimal value.
|
||||
|
||||
The format is `[0-9a-f]{4}`, eg. `0000` through `ffff`.
|
||||
|
||||
#### Arguments
|
||||
|
||||
- `uint16_t number`
|
||||
The value to type, from 0 to 65,535.
|
||||
|
||||
---
|
||||
|
||||
### `void send_byte(uint8_t number)`
|
||||
|
||||
Type out a two digit (8-bit) hexadecimal value.
|
||||
|
||||
The format is `[0-9a-f]{2}`, eg. `00` through `ff`.
|
||||
|
||||
#### Arguments
|
||||
|
||||
- `uint8_t number`
|
||||
The value to type, from 0 to 255.
|
||||
|
||||
---
|
||||
|
||||
### `void send_nibble(uint8_t number)`
|
||||
|
||||
Type out a single hexadecimal digit.
|
||||
|
||||
The format is `[0-9a-f]{1}`, eg. `0` through `f`.
|
||||
|
||||
#### Arguments
|
||||
|
||||
- `uint8_t number`
|
||||
The value to type, from 0 to 15.
|
||||
|
||||
---
|
||||
|
||||
### `void tap_random_base64(void)`
|
||||
|
||||
Type a pseudorandom character from the set `A-Z`, `a-z`, `0-9`, `+` and `/`.
|
||||
|
||||
---
|
||||
|
||||
### `SEND_STRING(string)`
|
||||
|
||||
Shortcut macro for `send_string_with_delay_P(PSTR(string), 0)`.
|
||||
|
||||
On ARM devices, this define evaluates to `send_string_with_delay(string, 0)`.
|
||||
|
||||
---
|
||||
|
||||
### `SEND_STRING_DELAY(string, interval)`
|
||||
|
||||
Shortcut macro for `send_string_with_delay_P(PSTR(string), interval)`.
|
||||
|
||||
On ARM devices, this define evaluates to `send_string_with_delay(string, interval)`.
|
||||
@@ -143,6 +143,9 @@ Next, you will have to flash the EEPROM files once for the correct hand to the c
|
||||
* ARM controllers with a DFU compatible bootloader (e.g. Proton-C):
|
||||
* `:dfu-util-split-left`
|
||||
* `:dfu-util-split-right`
|
||||
* ARM controllers with a UF2 compatible bootloader:
|
||||
* `:uf2-split-left`
|
||||
* `:uf2-split-right`
|
||||
|
||||
Example:
|
||||
|
||||
@@ -367,7 +370,7 @@ There are some settings that you may need to configure, based on how the hardwar
|
||||
#define MATRIX_COL_PINS_RIGHT { <col pins> }
|
||||
```
|
||||
|
||||
This allows you to specify a different set of pins for the matrix on the right side. This is useful if you have a board with differently-shaped halves that requires a different configuration (such as Keebio's Quefrency).
|
||||
This allows you to specify a different set of pins for the matrix on the right side. This is useful if you have a board with differently-shaped halves that requires a different configuration (such as Keebio's Quefrency). The number of pins in the right and left matrices must be the same, if you have a board with a different number of rows or columns on one side, pad out the extra spaces with `NO_PIN` and make sure you add the unused rows or columns to your matrix.
|
||||
|
||||
```c
|
||||
#define DIRECT_PINS_RIGHT { { F1, F0, B0, C7 }, { F4, F5, F6, F7 } }
|
||||
|
||||
@@ -8,46 +8,107 @@ The [Open Steno Project](https://www.openstenoproject.org/) has built an open-so
|
||||
|
||||
Plover can work with any standard QWERTY keyboard, although it is more efficient if the keyboard supports NKRO (n-key rollover) to allow Plover to see all the pressed keys at once. An example keymap for Plover can be found in `planck/keymaps/default`. Switching to the `PLOVER` layer adjusts the position of the keyboard to support the number bar.
|
||||
|
||||
To use Plover with QMK just enable NKRO and optionally adjust your layout if you have anything other than a standard layout. You may also want to purchase some steno-friendly keycaps to make it easier to hit multiple keys.
|
||||
To enable NKRO, add `NKRO_ENABLE = yes` in your `rules.mk` and make sure to press `NK_ON` to turn it on because `NKRO_ENABLE = yes` merely adds the possibility of switching to NKRO mode but it doesn't automatically switch to it. If you want to automatically switch, add `#define FORCE_NKRO` in your `config.h`.
|
||||
|
||||
You may also need to adjust your layout, either in QMK or in Plover, if you have anything other than a standard layout. You may also want to purchase some steno-friendly keycaps to make it easier to hit multiple keys.
|
||||
|
||||
## Plover with Steno Protocol :id=plover-with-steno-protocol
|
||||
|
||||
Plover also understands the language of several steno machines. QMK can speak a couple of these languages, TX Bolt and GeminiPR. An example layout can be found in `planck/keymaps/steno`.
|
||||
Plover also understands the language of several steno machines. QMK can speak a couple of these languages: TX Bolt and GeminiPR. An example layout can be found in `planck/keymaps/steno`.
|
||||
|
||||
When QMK speaks to Plover over a steno protocol Plover will not use the keyboard as input. This means that you can switch back and forth between a standard keyboard and your steno keyboard, or even switch layers from Plover to standard and back without needing to activate/deactivate Plover.
|
||||
When QMK speaks to Plover over a steno protocol, Plover will not use the keyboard as input. This means that you can switch back and forth between a standard keyboard and your steno keyboard, or even switch layers from Plover to standard and back without needing to activate/deactivate Plover.
|
||||
|
||||
In this mode Plover expects to speak with a steno machine over a serial port so QMK will present itself to the operating system as a virtual serial port in addition to a keyboard. By default QMK will speak the TX Bolt protocol but can be switched to GeminiPR; the last protocol used is stored in non-volatile memory so QMK will use the same protocol on restart.
|
||||
In this mode, Plover expects to speak with a steno machine over a serial port so QMK will present itself to the operating system as a virtual serial port in addition to a keyboard.
|
||||
|
||||
> Note: Due to hardware limitations you may not be able to run both a virtual serial port and mouse emulation at the same time.
|
||||
> Note: Due to hardware limitations, you might not be able to run both a virtual serial port and mouse emulation at the same time.
|
||||
|
||||
!> Serial stenography protocols are not supported on [V-USB keyboards](compatible_microcontrollers#atmel-avr).
|
||||
|
||||
To enable stenography protocols, add the following lines to your `rules.mk`:
|
||||
```mk
|
||||
STENO_ENABLE = yes
|
||||
```
|
||||
|
||||
### TX Bolt :id=tx-bolt
|
||||
|
||||
TX Bolt communicates the status of 24 keys over a very simple protocol in variable-sized (1-5 byte) packets.
|
||||
TX Bolt communicates the status of 24 keys over a simple protocol in variable-sized (1–4 bytes) packets.
|
||||
|
||||
To select TX Bolt, add the following lines to your `rules.mk`:
|
||||
```mk
|
||||
STENO_ENABLE = yes
|
||||
STENO_PROTOCOL = txbolt
|
||||
```
|
||||
|
||||
Each byte of the packet represents a different group of steno keys. Determining the group of a certain byte of the packet is done by checking the first two bits, the remaining bits are set if the corresponding steno key was pressed for the stroke. The last set of keys (as indicated by leading `11`) needs to keep track of less keys than there are bits so one of the bits is constantly 0.
|
||||
|
||||
The start of a new packet can be detected by comparing the group “ID” (the two MSBs) of the current byte to that of the previously received byte. If the group “ID” of the current byte is smaller or equal to that of the previous byte, it means that the current byte is the beginning of a new packet.
|
||||
|
||||
The format of TX Bolt packets is shown below.
|
||||
```
|
||||
00HWPKTS 01UE*OAR 10GLBPRF 110#ZDST
|
||||
```
|
||||
|
||||
Examples of steno strokes and the associated packet:
|
||||
- `EUBG` = `01110000 10101000`
|
||||
- `WAZ` = `00010000 01000010 11001000`
|
||||
- `PHAPBGS` = `00101000 01000010 10101100 11000010`
|
||||
|
||||
### GeminiPR :id=geminipr
|
||||
|
||||
GeminiPR encodes 42 keys into a 6-byte packet. While TX Bolt contains everything that is necessary for standard stenography, GeminiPR opens up many more options, including supporting non-English theories.
|
||||
GeminiPR encodes 42 keys into a 6-byte packet. While TX Bolt contains everything that is necessary for standard stenography, GeminiPR opens up many more options, including differentiating between top and bottom `S-`, and supporting non-English theories.
|
||||
|
||||
To select GeminiPR, add the following lines to your `rules.mk`:
|
||||
```mk
|
||||
STENO_ENABLE = yes
|
||||
STENO_PROTOCOL = geminipr
|
||||
```
|
||||
|
||||
All packets in the GeminiPR protocol consist of exactly six bytes, used as bit-arrays for different groups of keys. The beginning of a packet is indicated by setting the most significant bit (MSB) to 1 while setting the MSB of the remaining five bytes to 0.
|
||||
|
||||
The format of GeminiPR packets is shown below.
|
||||
```
|
||||
1 Fn #1 #2 #3 #4 #5 #6
|
||||
0 S1- S2- T- K- P- W- H-
|
||||
0 R- A- O- *1 *2 res1 res2
|
||||
0 pwr *3 *4 -E -U -F -R
|
||||
0 -P -B -L -G -T -S -D
|
||||
0 #7 #8 #9 #A #B #C -Z
|
||||
```
|
||||
|
||||
Examples of steno strokes and the associated packet:
|
||||
- `EUBG` = `10000000 00000000 00000000 00001100 00101000 00000000`
|
||||
- `WAZ` = `10000000 00000010 00100000 00000000 00000000 00000001`
|
||||
- `PHAPBGS` = `10000000 00000101 00100000 00000000 01101010 00000000`
|
||||
|
||||
### Switching protocols on the fly :id=switching-protocols-on-the-fly
|
||||
|
||||
If you wish to switch the serial protocol used to transfer the steno chords without having to recompile your keyboard firmware every time, you can press the `QK_STENO_BOLT` and `QK_STENO_GEMINI` keycodes in order to switch protocols on the fly.
|
||||
|
||||
To enable these special keycodes, add the following lines to your `rules.mk`:
|
||||
```mk
|
||||
STENO_ENABLE = yes
|
||||
STENO_PROTOCOL = all
|
||||
```
|
||||
|
||||
If you want to switch protocols programatically, as part of a custom macro for example, don't use `tap_code(QK_STENO_*)`, as `tap_code` only supports [basic keycodes](keycodes_basic). Instead, you should use `steno_set_mode(STENO_MODE_*)`, whose valid arguments are `STENO_MODE_BOLT` and `STENO_MODE_GEMINI`.
|
||||
|
||||
The default protocol is Gemini PR but the last protocol used is stored in non-volatile memory so QMK will remember your choice between reboots of your keyboard — assuming that your keyboard features (emulated) EEPROM.
|
||||
|
||||
Naturally, this option takes the most amount of firmware space as it needs to compile the code for all the available stenography protocols. In most cases, compiling a single stenography protocol is sufficient.
|
||||
|
||||
The default value for `STENO_PROTOCOL` is `all`.
|
||||
|
||||
## Configuring QMK for Steno :id=configuring-qmk-for-steno
|
||||
|
||||
Firstly, enable steno in your keymap's Makefile. You may also need disable mousekeys, extra keys, or another USB endpoint to prevent conflicts. The builtin USB stack for some processors only supports a certain number of USB endpoints and the virtual serial port needed for steno fills 3 of them.
|
||||
After enabling stenography and optionally selecting a protocol, you may also need disable mouse keys, extra keys, or another USB endpoint to prevent conflicts. The builtin USB stack for some processors only supports a certain number of USB endpoints and the virtual serial port needed for steno fills 3 of them.
|
||||
|
||||
```make
|
||||
STENO_ENABLE = yes
|
||||
MOUSEKEY_ENABLE = no
|
||||
```
|
||||
!> If you had *explicitly* set `VIRSTER_ENABLE = no`, none of the serial stenography protocols (GeminiPR, TX Bolt) will work properly. You are expected to either set it to `yes`, remove the line from your `rules.mk` or send the steno chords yourself in an alternative way using the [provided interceptable hooks](#interfacing-with-the-code).
|
||||
|
||||
In your keymap create a new layer for Plover. You will need to include `keymap_steno.h`. See `planck/keymaps/steno/keymap.c` for an example. Remember to create a key to switch to the layer as well as a key for exiting the layer. If you would like to switch modes on the fly you can use the keycodes `QK_STENO_BOLT` and `QK_STENO_GEMINI`. If you only want to use one of the protocols you may set it up in your initialization function:
|
||||
In your keymap, create a new layer for Plover, that you can fill in with the [steno keycodes](#keycode-reference) (you will need to include `keymap_steno.h`, see `planck/keymaps/steno/keymap.c` for an example). Remember to create a key to switch to the layer as well as a key for exiting the layer.
|
||||
|
||||
```c
|
||||
void eeconfig_init_user() {
|
||||
steno_set_mode(STENO_MODE_GEMINI); // or STENO_MODE_BOLT
|
||||
}
|
||||
```
|
||||
Once you have your keyboard flashed, launch Plover. Click the 'Configure...' button. In the 'Machine' tab, select the Stenotype Machine that corresponds to your desired protocol. Click the 'Configure...' button on this tab and enter the serial port or click 'Scan'. Baud rate is fine at 9600 (although you should be able to set as high as 115200 with no issues). Use the default settings for everything else (Data Bits: 8, Stop Bits: 1, Parity: N, no flow control).
|
||||
|
||||
Once you have your keyboard flashed launch Plover. Click the 'Configure...' button. In the 'Machine' tab select the Stenotype Machine that corresponds to your desired protocol. Click the 'Configure...' button on this tab and enter the serial port or click 'Scan'. Baud rate is fine at 9600 (although you should be able to set as high as 115200 with no issues). Use the default settings for everything else (Data Bits: 8, Stop Bits: 1, Parity: N, no flow control).
|
||||
|
||||
On the display tab click 'Open stroke display'. With Plover disabled you should be able to hit keys on your keyboard and see them show up in the stroke display window. Use this to make sure you have set up your keymap correctly. You are now ready to steno!
|
||||
To test your keymap, you can chord keys on your keyboard and either look at the output of the 'paper tape' (Tools > Paper Tape) or that of the 'layout display' (Tools > Layout Display). If your strokes correctly show up, you are now ready to steno!
|
||||
|
||||
## Learning Stenography :id=learning-stenography
|
||||
|
||||
@@ -60,7 +121,7 @@ On the display tab click 'Open stroke display'. With Plover disabled you should
|
||||
The steno code has three interceptable hooks. If you define these functions, they will be called at certain points in processing; if they return true, processing continues, otherwise it's assumed you handled things.
|
||||
|
||||
```c
|
||||
bool send_steno_chord_user(steno_mode_t mode, uint8_t chord[6]);
|
||||
bool send_steno_chord_user(steno_mode_t mode, uint8_t chord[MAX_STROKE_SIZE]);
|
||||
```
|
||||
|
||||
This function is called when a chord is about to be sent. Mode will be one of `STENO_MODE_BOLT` or `STENO_MODE_GEMINI`. This represents the actual chord that would be sent via whichever protocol. You can modify the chord provided to alter what gets sent. Remember to return true if you want the regular sending process to happen.
|
||||
@@ -72,15 +133,23 @@ bool process_steno_user(uint16_t keycode, keyrecord_t *record) { return true; }
|
||||
This function is called when a keypress has come in, before it is processed. The keycode should be one of `QK_STENO_BOLT`, `QK_STENO_GEMINI`, or one of the `STN_*` key values.
|
||||
|
||||
```c
|
||||
bool postprocess_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[6], int8_t pressed);
|
||||
bool postprocess_steno_user(uint16_t keycode, keyrecord_t *record, steno_mode_t mode, uint8_t chord[MAX_STROKE_SIZE], int8_t n_pressed_keys);
|
||||
```
|
||||
|
||||
This function is called after a key has been processed, but before any decision about whether or not to send a chord. If `IS_PRESSED(record->event)` is false, and `pressed` is 0 or 1, the chord will be sent shortly, but has not yet been sent. This is where to put hooks for things like, say, live displays of steno chords or keys.
|
||||
This function is called after a key has been processed, but before any decision about whether or not to send a chord. This is where to put hooks for things like, say, live displays of steno chords or keys.
|
||||
|
||||
If `IS_PRESSED(record->event)` is false, and `n_pressed_keys` is 0 or 1, the chord will be sent shortly, but has not yet been sent. This relieves you of the need of keeping track of where a packet ends and another begins.
|
||||
|
||||
The `chord` argument contains the packet of the current chord as specified by the protocol in use. This is *NOT* simply a list of chorded steno keys of the form `[STN_E, STN_U, STN_BR, STN_GR]`. Refer to the appropriate protocol section of this document to learn more about the format of the packets in your steno protocol/mode of choice.
|
||||
|
||||
The `n_pressed_keys` argument is the number of physical keys actually being held down.
|
||||
This is not always equal to the number of bits set to 1 (aka the [Hamming weight](https://en.wikipedia.org/wiki/Hamming_weight)) in `chord` because it is possible to simultaneously press down four keys, then release three of those four keys and then press yet another key while the fourth finger is still holding down its key.
|
||||
At the end of this scenario given as an example, `chord` would have five bits set to 1 but
|
||||
`n_pressed_keys` would be set to 2 because there are only two keys currently being pressed down.
|
||||
|
||||
## Keycode Reference :id=keycode-reference
|
||||
|
||||
As defined in `keymap_steno.h`.
|
||||
You must include `keymap_steno.h` to your `keymap.c` with `#include "keymap_steno.h"` before you can use these keycodes
|
||||
|
||||
> Note: TX Bolt does not support the full set of keys. The TX Bolt implementation in QMK will map the GeminiPR keys to the nearest TX Bolt key so that one key map will work for both.
|
||||
|
||||
@@ -124,10 +193,10 @@ As defined in `keymap_steno.h`.
|
||||
|`STN_SR`|`STN_SR`| `-S`|
|
||||
|`STN_DR`|`STN_DR`| `-D`|
|
||||
|`STN_ZR`|`STN_ZR`| `-Z`|
|
||||
|`STN_FN`|| (GeminiPR only)|
|
||||
|`STN_RES1`||(GeminiPR only)|
|
||||
|`STN_RES2`||(GeminiPR only)|
|
||||
|`STN_PWR`||(GeminiPR only)|
|
||||
|`STN_FN`|| (Function)|
|
||||
|`STN_RES1`||(Reset 1)|
|
||||
|`STN_RES2`||(Reset 2)|
|
||||
|`STN_PWR`||(Power)|
|
||||
|
||||
If you do not want to hit two keys with one finger combined keycodes can be used. These are also defined in `keymap_steno.h`, and causes both keys to be reported as pressed or released. To use these keycodes define `STENO_COMBINEDMAP` in your `config.h` file.
|
||||
|
||||
|
||||
@@ -14,55 +14,48 @@ Optionally, you might want to set a custom `TAPPING_TERM` time by adding somethi
|
||||
|
||||
```c
|
||||
#define TAPPING_TERM 175
|
||||
#define TAPPING_TERM_PER_KEY
|
||||
```
|
||||
|
||||
The `TAPPING_TERM` time is the maximum time allowed between taps of your Tap Dance key, and is measured in milliseconds. For example, if you used the above `#define` statement and set up a Tap Dance key that sends `Space` on single-tap and `Enter` on double-tap, then this key will send `ENT` only if you tap this key twice in less than 175ms. If you tap the key, wait more than 175ms, and tap the key again you'll end up sending `SPC SPC` instead.
|
||||
The `TAPPING_TERM` time is the maximum time allowed between taps of your Tap Dance key, and is measured in milliseconds. For example, if you used the above `#define` statement and set up a Tap Dance key that sends `Space` on single-tap and `Enter` on double-tap, then this key will send `ENT` only if you tap this key twice in less than 175ms. If you tap the key, wait more than 175ms, and tap the key again you'll end up sending `SPC SPC` instead. The `TAPPING_TERM_PER_KEY` definition is only needed if you control the tapping term through a [custom `get_tapping_term` function](tap_hold.md#tapping_term), which may be needed because `TAPPING_TERM` affects not just tap-dance keys.
|
||||
|
||||
Next, you will want to define some tap-dance keys, which is easiest to do with the `TD()` macro, that takes a number which will later be used as an index into the `tap_dance_actions` array.
|
||||
Next, you will want to define some tap-dance keys, which is easiest to do with the `TD()` macro. That macro takes a number which will later be used as an index into the `tap_dance_actions` array and turns it into a tap-dance keycode.
|
||||
|
||||
After this, you'll want to use the `tap_dance_actions` array to specify what actions shall be taken when a tap-dance key is in action. Currently, there are five possible options:
|
||||
|
||||
* `ACTION_TAP_DANCE_DOUBLE(kc1, kc2)`: Sends the `kc1` keycode when tapped once, `kc2` otherwise. When the key is held, the appropriate keycode is registered: `kc1` when pressed and held, `kc2` when tapped once, then pressed and held.
|
||||
* `ACTION_TAP_DANCE_LAYER_MOVE(kc, layer)`: Sends the `kc` keycode when tapped once, or moves to `layer`. (this functions like the `TO` layer keycode).
|
||||
* This is the same as `ACTION_TAP_DANCE_DUAL_ROLE`, but renamed to something that is clearer about its functionality. Both names will work.
|
||||
* `ACTION_TAP_DANCE_LAYER_TOGGLE(kc, layer)`: Sends the `kc` keycode when tapped once, or toggles the state of `layer`. (this functions like the `TG` layer keycode).
|
||||
* `ACTION_TAP_DANCE_FN(fn)`: Calls the specified function - defined in the user keymap - with the final tap count of the tap dance action.
|
||||
* `ACTION_TAP_DANCE_FN_ADVANCED(on_each_tap_fn, on_dance_finished_fn, on_dance_reset_fn)`: Calls the first specified function - defined in the user keymap - on every tap, the second function when the dance action finishes (like the previous option), and the last function when the tap dance action resets.
|
||||
* ~~`ACTION_TAP_DANCE_FN_ADVANCED_TIME(on_each_tap_fn, on_dance_finished_fn, on_dance_reset_fn, tap_specific_tapping_term)`~~: This functions identically to the `ACTION_TAP_DANCE_FN_ADVANCED` function, but uses a custom tapping term for it, instead of the predefined `TAPPING_TERM`.
|
||||
* This is deprecated in favor of the Per Key Tapping Term functionality, as outlined [here](tap_hold.md#tapping-term). You'd want to check for the specific `TD()` macro that you want to use (such as `TD(TD_ESC_CAPS)`) instead of using this specific Tap Dance function.
|
||||
|
||||
|
||||
The first option is enough for a lot of cases, that just want dual roles. For example, `ACTION_TAP_DANCE_DOUBLE(KC_SPC, KC_ENT)` will result in `Space` being sent on single-tap, `Enter` otherwise.
|
||||
|
||||
!> Keep in mind that only [basic keycodes](keycodes_basic.md) are supported here. Custom keycodes are not supported.
|
||||
|
||||
Similar to the first option, the second option is good for simple layer-switching cases.
|
||||
Similar to the first option, the second and third option are good for simple layer-switching cases.
|
||||
|
||||
For more complicated cases, use the third or fourth options (examples of each are listed below).
|
||||
|
||||
Finally, the fifth option is particularly useful if your non-Tap-Dance keys start behaving weirdly after adding the code for your Tap Dance keys. The likely problem is that you changed the `TAPPING_TERM` time to make your Tap Dance keys easier for you to use, and that this has changed the way your other keys handle interrupts.
|
||||
For more complicated cases, like blink the LEDs, fiddle with the backlighting, and so on, use the fourth or fifth option. Examples of each are listed below.
|
||||
|
||||
## Implementation Details :id=implementation
|
||||
|
||||
Well, that's the bulk of it! You should now be able to work through the examples below, and to develop your own Tap Dance functionality. But if you want a deeper understanding of what's going on behind the scenes, then read on for the explanation of how it all works!
|
||||
|
||||
The main entry point is `process_tap_dance()`, called from `process_record_quantum()`, which is run for every keypress, and our handler gets to run early. This function checks whether the key pressed is a tap-dance key. If it is not, and a tap-dance was in action, we handle that first, and enqueue the newly pressed key. If it is a tap-dance key, then we check if it is the same as the already active one (if there's one active, that is). If it is not, we fire off the old one first, then register the new one. If it was the same, we increment the counter and reset the timer.
|
||||
Let's go over the three functions mentioned in `ACTION_TAP_DANCE_FN_ADVANCED` in a little more detail. They all receive the same too arguments: a pointer to a structure that holds all dance related state information, and a pointer to a use case specific state variable. The three functions differ in when they are called. The first, `on_each_tap_fn()`, is called every time the tap dance key is *pressed*. Before it is called, the counter is incremented and the timer is reset. The second function, `on_dance_finished_fn()`, is called when the tap dance is interrupted or ends because `TAPPING_TERM` milliseconds have passed since the last tap. When the `finished` field of the dance state structure is set to `true`, the `on_dance_finished_fn()` is skipped. After `on_dance_finished_fn()` was called or would have been called, but no sooner than when the tap dance key is *released*, `on_dance_reset_fn()` is called. It is possible to end a tap dance immediately, skipping `on_dance_finished_fn()`, but not `on_dance_reset_fn`, by calling `reset_tap_dance(state)`.
|
||||
|
||||
To accomplish this logic, the tap dance mechanics use three entry points. The main entry point is `process_tap_dance()`, called from `process_record_quantum()` *after* `process_record_kb()` and `process_record_user()`. This function is responsible for calling `on_each_tap_fn()` and `on_dance_reset_fn()`. In order to handle interruptions of a tap dance, another entry point, `preprocess_tap_dance()` is run right at the beginning of `process_record_quantum()`. This function checks whether the key pressed is a tap-dance key. If it is not, and a tap-dance was in action, we handle that first, and enqueue the newly pressed key. If it is a tap-dance key, then we check if it is the same as the already active one (if there's one active, that is). If it is not, we fire off the old one first, then register the new one. Finally, `tap_dance_task()` periodically checks whether `TAPPING_TERM` has passed since the last key press and finishes a tap dance if that is the case.
|
||||
|
||||
This means that you have `TAPPING_TERM` time to tap the key again; you do not have to input all the taps within a single `TAPPING_TERM` timeframe. This allows for longer tap counts, with minimal impact on responsiveness.
|
||||
|
||||
Our next stop is `tap_dance_task()`. This handles the timeout of tap-dance keys.
|
||||
|
||||
For the sake of flexibility, tap-dance actions can be either a pair of keycodes, or a user function. The latter allows one to handle higher tap counts, or do extra things, like blink the LEDs, fiddle with the backlighting, and so on. This is accomplished by using an union, and some clever macros.
|
||||
|
||||
## Examples :id=examples
|
||||
|
||||
### Simple Example :id=simple-example
|
||||
### Simple Example: Send `ESC` on Single Tap, `CAPS_LOCK` on Double Tap :id=simple-example
|
||||
|
||||
Here's a simple example for a single definition:
|
||||
|
||||
1. In your `rules.mk`, add `TAP_DANCE_ENABLE = yes`
|
||||
2. In your `config.h` (which you can copy from `qmk_firmware/keyboards/planck/config.h` to your keymap directory), add `#define TAPPING_TERM 200`
|
||||
3. In your `keymap.c` file, define the variables and definitions, then add to your keymap:
|
||||
2. In your `keymap.c` file, define the variables and definitions, then add to your keymap:
|
||||
|
||||
```c
|
||||
// Tap Dance declarations
|
||||
@@ -92,40 +85,15 @@ All the enums used in the examples are declared like this:
|
||||
```c
|
||||
// Enums defined for all examples:
|
||||
enum {
|
||||
CT_SE,
|
||||
CT_CLN,
|
||||
TD_ESC_CAPS,
|
||||
CT_EGG,
|
||||
CT_FLSH,
|
||||
X_TAP_DANCE
|
||||
CT_CLN,
|
||||
X_CTL,
|
||||
};
|
||||
```
|
||||
|
||||
#### Example 1: Send `:` on Single Tap, `;` on Double Tap :id=example-1
|
||||
|
||||
```c
|
||||
void dance_cln_finished(qk_tap_dance_state_t *state, void *user_data) {
|
||||
if (state->count == 1) {
|
||||
register_code16(KC_COLN);
|
||||
} else {
|
||||
register_code(KC_SCLN);
|
||||
}
|
||||
}
|
||||
|
||||
void dance_cln_reset(qk_tap_dance_state_t *state, void *user_data) {
|
||||
if (state->count == 1) {
|
||||
unregister_code16(KC_COLN);
|
||||
} else {
|
||||
unregister_code(KC_SCLN);
|
||||
}
|
||||
}
|
||||
|
||||
// All tap dance functions would go here. Only showing this one.
|
||||
qk_tap_dance_action_t tap_dance_actions[] = {
|
||||
[CT_CLN] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, dance_cln_finished, dance_cln_reset),
|
||||
};
|
||||
```
|
||||
|
||||
#### Example 2: Send "Safety Dance!" After 100 Taps :id=example-2
|
||||
#### Example 1: Send "Safety Dance!" After 100 Taps :id=example-1
|
||||
|
||||
```c
|
||||
void dance_egg(qk_tap_dance_state_t *state, void *user_data) {
|
||||
@@ -140,7 +108,7 @@ qk_tap_dance_action_t tap_dance_actions[] = {
|
||||
};
|
||||
```
|
||||
|
||||
#### Example 3: Turn LED Lights On Then Off, One at a Time :id=example-3
|
||||
#### Example 2: Turn LED Lights On Then Off, One at a Time :id=example-2
|
||||
|
||||
```c
|
||||
// On each tap, light up one LED, from right to left
|
||||
@@ -181,15 +149,74 @@ void dance_flsh_reset(qk_tap_dance_state_t *state, void *user_data) {
|
||||
ergodox_right_led_3_off();
|
||||
}
|
||||
|
||||
// All tap dances now put together. Example 3 is "CT_FLASH"
|
||||
// All tap dances now put together. Example 2 is "CT_FLSH"
|
||||
qk_tap_dance_action_t tap_dance_actions[] = {
|
||||
[CT_SE] = ACTION_TAP_DANCE_DOUBLE(KC_SPC, KC_ENT),
|
||||
[CT_CLN] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, dance_cln_finished, dance_cln_reset),
|
||||
[TD_ESC_CAPS] = ACTION_TAP_DANCE_DOUBLE(KC_ESC, KC_CAPS),
|
||||
[CT_EGG] = ACTION_TAP_DANCE_FN(dance_egg),
|
||||
[CT_FLSH] = ACTION_TAP_DANCE_FN_ADVANCED(dance_flsh_each, dance_flsh_finished, dance_flsh_reset)
|
||||
};
|
||||
```
|
||||
|
||||
#### Example 3: Send `:` on Tap, `;` on Hold :id=example-3
|
||||
|
||||
With a little effort, powerful tap-hold configurations can be implemented as tap dances. To emit taps as early as possible, we need to act on releases of the tap dance key. There is no callback for this in the tap dance framework, so we use `process_record_user()`.
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
uint16_t tap;
|
||||
uint16_t hold;
|
||||
uint16_t held;
|
||||
} tap_dance_tap_hold_t;
|
||||
|
||||
bool process_record_user(uint16_t keycode, keyrecord_t *record) {
|
||||
qk_tap_dance_action_t *action;
|
||||
|
||||
switch (keycode) {
|
||||
case TD(CT_CLN): // list all tap dance keycodes with tap-hold configurations
|
||||
action = &tap_dance_actions[TD_INDEX(keycode)];
|
||||
if (!record->event.pressed && action->state.count && !action->state.finished) {
|
||||
tap_dance_tap_hold_t *tap_hold = (tap_dance_tap_hold_t *)action->user_data;
|
||||
tap_code16(tap_hold->tap);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void tap_dance_tap_hold_finished(qk_tap_dance_state_t *state, void *user_data) {
|
||||
tap_dance_tap_hold_t *tap_hold = (tap_dance_tap_hold_t *)user_data;
|
||||
|
||||
if (state->pressed) {
|
||||
if (state->count == 1
|
||||
#ifndef PERMISSIVE_HOLD
|
||||
&& !state->interrupted
|
||||
#endif
|
||||
) {
|
||||
register_code16(tap_hold->hold);
|
||||
tap_hold->held = tap_hold->hold;
|
||||
} else {
|
||||
register_code16(tap_hold->tap);
|
||||
tap_hold->held = tap_hold->tap;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void tap_dance_tap_hold_reset(qk_tap_dance_state_t *state, void *user_data) {
|
||||
tap_dance_tap_hold_t *tap_hold = (tap_dance_tap_hold_t *)user_data;
|
||||
|
||||
if (tap_hold->held) {
|
||||
unregister_code16(tap_hold->held);
|
||||
tap_hold->held = 0;
|
||||
}
|
||||
}
|
||||
|
||||
#define ACTION_TAP_DANCE_TAP_HOLD(tap, hold) \
|
||||
{ .fn = {NULL, tap_dance_tap_hold_finished, tap_dance_tap_hold_reset}, .user_data = (void *)&((tap_dance_tap_hold_t){tap, hold, 0}), }
|
||||
|
||||
qk_tap_dance_action_t tap_dance_actions[] = {
|
||||
[CT_CLN] = ACTION_TAP_DANCE_TAP_HOLD(KC_COLN, KC_SCLN),
|
||||
};
|
||||
```
|
||||
|
||||
#### Example 4: 'Quad Function Tap-Dance' :id=example-4
|
||||
|
||||
By [DanielGGordon](https://github.com/danielggordon)
|
||||
@@ -329,7 +356,7 @@ And then simply use `TD(X_CTL)` anywhere in your keymap.
|
||||
|
||||
If you want to implement this in your userspace, then you may want to check out how [DanielGGordon](https://github.com/qmk/qmk_firmware/tree/master/users/gordon) has implemented this in their userspace.
|
||||
|
||||
> In this configuration "hold" takes place **after** tap dance timeout (see `ACTION_TAP_DANCE_FN_ADVANCED_TIME`). To achieve instant hold, remove `state->interrupted` checks in conditions. As a result you may use comfortable longer tapping periods to have more time for taps and not to wait too long for holds (try starting with doubled `TAPPING_TERM`).
|
||||
> In this configuration "hold" takes place **after** tap dance timeout. To achieve instant hold, remove `state->interrupted` checks in conditions. As a result you may use comfortable longer tapping periods to have more time for taps and not to wait too long for holds (try starting with doubled `TAPPING_TERM`).
|
||||
|
||||
#### Example 5: Using tap dance for advanced mod-tap and layer-tap keys :id=example-5
|
||||
|
||||
@@ -511,8 +538,18 @@ void ql_reset(qk_tap_dance_state_t *state, void *user_data) {
|
||||
|
||||
// Associate our tap dance key with its functionality
|
||||
qk_tap_dance_action_t tap_dance_actions[] = {
|
||||
[QUOT_LAYR] = ACTION_TAP_DANCE_FN_ADVANCED_TIME(NULL, ql_finished, ql_reset, 275)
|
||||
[QUOT_LAYR] = ACTION_TAP_DANCE_FN_ADVANCED(NULL, ql_finished, ql_reset)
|
||||
};
|
||||
|
||||
// Set a long-ish tapping term for tap-dance keys
|
||||
uint16_t get_tapping_term(uint16_t keycode, keyrecord_t *record) {
|
||||
switch (keycode) {
|
||||
case QK_TAP_DANCE ... QK_TAP_DANCE_MAX:
|
||||
return 275;
|
||||
default:
|
||||
return TAPPING_TERM;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The above code is similar to that used in previous examples. The one point to note is that we need to be able to check which layers are active at any time so we can toggle them if needed. To do this we use the `layer_state_is(layer)` function which returns `true` if the given `layer` is active.
|
||||
@@ -521,6 +558,6 @@ The use of `cur_dance()` and `ql_tap_state` mirrors the above examples.
|
||||
|
||||
The `case: TD_SINGLE_TAP` in `ql_finished` is similar to the above examples. The `TD_SINGLE_HOLD` case works in conjunction with `ql_reset()` to switch to `_MY_LAYER` while the tap dance key is held, and to switch away from `_MY_LAYER` when the key is released. This mirrors the use of `MO(_MY_LAYER)`. The `TD_DOUBLE_TAP` case works by checking whether `_MY_LAYER` is the active layer, and toggling it on or off accordingly. This mirrors the use of `TG(_MY_LAYER)`.
|
||||
|
||||
`tap_dance_actions[]` works similar to the above examples. Note that I used `ACTION_TAP_DANCE_FN_ADVANCED_TIME()` instead of `ACTION_TAP_DANCE_FN_ADVANCED()`. This is because I like my `TAPPING_TERM` to be short (\~175ms) for my non-tap-dance keys but find that this is too quick for me to reliably complete tap dance actions - thus the increased time of 275ms here.
|
||||
`tap_dance_actions[]` works similar to the above examples. Note that, additionally, I set a longer tapping term for the tap dance keys. This is because I like my `TAPPING_TERM` to be short (\~175ms) for my non-tap-dance keys but find that this is too quick for me to reliably complete tap dance actions - thus the increased time of 275ms here. In order for the per-key tapping terms to take effect, `TAPPING_TERM_PER_KEY` must be defined in your `config.h`.
|
||||
|
||||
Finally, to get this tap dance key working, be sure to include `TD(QUOT_LAYR)` in your `keymaps[]`.
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
# Terminal
|
||||
|
||||
> This feature is currently *huge*, and should probably only be put on boards with a lot of memory, or for fun.
|
||||
|
||||
The terminal feature is a command-line-like interface designed to communicate through a text editor with keystrokes. It's beneficial to turn off auto-indent features in your editor.
|
||||
|
||||
To enable, stick this in your `rules.mk` or `Makefile`:
|
||||
|
||||
TERMINAL_ENABLE = yes
|
||||
|
||||
And use the `TERM_ON` and `TERM_OFF` keycodes to turn it on or off.
|
||||
|
||||
When enabled, a `> ` prompt will appear, where you'll be able to type, backspace (a bell will ding if you reach the beginning and audio is enabled), and hit enter to send the command. Arrow keys are currently disabled so it doesn't get confused. Moving your cursor around with the mouse is discouraged.
|
||||
|
||||
`#define TERMINAL_HELP` enables some other output helpers that aren't really needed with this page.
|
||||
|
||||
Pressing "up" and "down" will allow you to cycle through the past 5 commands entered.
|
||||
|
||||
## Future Ideas
|
||||
|
||||
* Keyboard/user-extensible commands
|
||||
* Smaller footprint
|
||||
* Arrow key support
|
||||
* Command history - Done
|
||||
* SD card support
|
||||
* LCD support for buffer display
|
||||
* Keycode -> name string LUT
|
||||
* Layer status
|
||||
* *Analog/digital port read/write*
|
||||
* RGB mode stuff
|
||||
* Macro definitions
|
||||
* EEPROM read/write
|
||||
* Audio control
|
||||
|
||||
## Current Commands
|
||||
|
||||
### `about`
|
||||
|
||||
Prints out the current version of QMK with a build date:
|
||||
|
||||
```
|
||||
> about
|
||||
QMK Firmware
|
||||
v0.5.115-7-g80ed73-dirty
|
||||
Built: 2017-08-29-20:24:44
|
||||
```
|
||||
|
||||
|
||||
### `print-buffer`
|
||||
|
||||
Outputs the last 5 commands entered
|
||||
|
||||
```
|
||||
> print-buffer
|
||||
0. print-buffer
|
||||
1. help
|
||||
2. about
|
||||
3. keymap 0
|
||||
4. help
|
||||
5. flush-buffer
|
||||
```
|
||||
|
||||
### `flush-buffer`
|
||||
|
||||
Clears command buffer
|
||||
```
|
||||
> flush-buffer
|
||||
Buffer cleared!
|
||||
```
|
||||
|
||||
|
||||
### `help`
|
||||
|
||||
|
||||
Prints out the available commands:
|
||||
|
||||
```
|
||||
> help
|
||||
commands available:
|
||||
about help keycode keymap exit print-buffer flush-buffer
|
||||
```
|
||||
|
||||
### `keycode <layer> <row> <col>`
|
||||
|
||||
Prints out the keycode value of a certain layer, row, and column:
|
||||
|
||||
```
|
||||
> keycode 0 1 0
|
||||
0x29 (41)
|
||||
```
|
||||
|
||||
### `keymap <layer>`
|
||||
|
||||
Prints out the entire keymap for a certain layer
|
||||
|
||||
```
|
||||
> keymap 0
|
||||
0x002b, 0x0014, 0x001a, 0x0008, 0x0015, 0x0017, 0x001c, 0x0018, 0x000c, 0x0012, 0x0013, 0x002a,
|
||||
0x0029, 0x0004, 0x0016, 0x0007, 0x0009, 0x000a, 0x000b, 0x000d, 0x000e, 0x000f, 0x0033, 0x0034,
|
||||
0x00e1, 0x001d, 0x001b, 0x0006, 0x0019, 0x0005, 0x0011, 0x0010, 0x0036, 0x0037, 0x0038, 0x0028,
|
||||
0x5cd6, 0x00e0, 0x00e2, 0x00e3, 0x5cd4, 0x002c, 0x002c, 0x5cd5, 0x0050, 0x0051, 0x0052, 0x004f,
|
||||
>
|
||||
```
|
||||
|
||||
### `exit`
|
||||
|
||||
Exits the terminal - same as `TERM_OFF`.
|
||||
@@ -358,3 +358,46 @@ CLI Flashing sequence:
|
||||
2. Wait for the OS to detect the device
|
||||
3. Flash via QMK CLI eg. `qmk flash --keyboard handwired/onekey/blackpill_f411_tinyuf2 --keymap default`
|
||||
4. Wait for the keyboard to become available
|
||||
|
||||
### `make` Targets
|
||||
|
||||
* `:uf2-split-left` and `:uf2-split-right`: Flashes the firmware but also sets the handedness setting in EEPROM by generating a side specific firmware.
|
||||
|
||||
## Raspberry Pi RP2040 UF2
|
||||
|
||||
The `rules.mk` setting for this bootloader is `rp2040`, and can be specified at the keymap or user level.
|
||||
|
||||
To ensure compatibility with the rp2040 bootloader, make sure this block is present in your `rules.mk`:
|
||||
|
||||
```make
|
||||
# Bootloader selection
|
||||
BOOTLOADER = rp2040
|
||||
```
|
||||
|
||||
Compatible flashers:
|
||||
|
||||
* Any application able to copy a file from one place to another, such as _macOS Finder_ or _Windows Explorer_.
|
||||
|
||||
Flashing sequence:
|
||||
|
||||
1. Enter the bootloader using any of the following methods:
|
||||
* Tap the `QK_BOOTLOADER` keycode
|
||||
* Hold the `BOOTSEL` button on the PCB while plugin in the usb cable.
|
||||
* Double-tap the `RESET` button on the PCB<sup>1</sup>.
|
||||
2. Wait for the OS to detect the device
|
||||
3. Copy the .uf2 file to the new USB disk
|
||||
4. Wait for the keyboard to become available
|
||||
|
||||
or
|
||||
|
||||
CLI Flashing sequence:
|
||||
|
||||
1. Enter the bootloader using any of the following methods:
|
||||
* Tap the `QK_BOOTLOADER` keycode
|
||||
* Hold the `BOOTSEL` button on the PCB while plugin in the usb cable.
|
||||
* Double-tap the `RESET` button on the PCB<sup>1</sup>.
|
||||
2. Wait for the OS to detect the device
|
||||
3. Flash via QMK CLI eg. `qmk flash --keyboard handwired/onekey/rpi_pico --keymap default`
|
||||
4. Wait for the keyboard to become available
|
||||
|
||||
<sup>1</sup>: This works only if QMK was compiled with `RP2040_BOOTLOADER_DOUBLE_TAP_RESET` defined.
|
||||
|
||||
@@ -85,7 +85,6 @@
|
||||
* [スワップハンド](ja/feature_swap_hands.md)
|
||||
* [タップダンス](ja/feature_tap_dance.md)
|
||||
* [タップホールド設定](ja/tap_hold.md)
|
||||
* [ターミナル](ja/feature_terminal.md)
|
||||
* [ユニコード](ja/feature_unicode.md)
|
||||
* [ユーザスペース](ja/feature_userspace.md)
|
||||
* [WPM 計算](ja/feature_wpm.md)
|
||||
|
||||
@@ -108,7 +108,7 @@ QMK での全ての利用可能な設定にはデフォルトがあります。
|
||||
* デバイスの USB 経由の最大電力(mA) を設定します (デフォルト: 500)
|
||||
* `#define USB_POLLING_INTERVAL_MS 10`
|
||||
* キーボード、マウス および 共有 (NKRO/メディアキー) インタフェースのための USB ポーリングレートをミリ秒で設定します
|
||||
* `#define USB_SUSPEND_WAKEUP_DELAY 200`
|
||||
* `#define USB_SUSPEND_WAKEUP_DELAY 0`
|
||||
* ウェイクアップパケットを送信した後で一時停止するミリ秒を設定します
|
||||
* `#define F_SCL 100000L`
|
||||
* I2C を使用するキーボードのための I2C クロックレート速度を設定します。デフォルトは `400000L` ですが、`split_common` を使っているキーボードは別でデフォルトは `100000L` です。
|
||||
@@ -144,7 +144,7 @@ QMK での全ての利用可能な設定にはデフォルトがあります。
|
||||
## 設定可能な挙動 :id=behaviors-that-can-be-configured
|
||||
|
||||
* `#define TAPPING_TERM 200`
|
||||
* タップがホールドになるまでの時間。500以上に設定された場合、タップ期間中にタップされたキーもホールドになります。(訳注: PERMISSIVE_HOLDも参照)
|
||||
* タップがホールドになるまでの時間。
|
||||
* `#define TAPPING_TERM_PER_KEY`
|
||||
* キーごとの `TAPPING_TERM` 設定の処理を有効にします
|
||||
* `#define RETRO_TAPPING`
|
||||
|
||||
@@ -87,17 +87,17 @@ void matrix_init(void) {
|
||||
}
|
||||
|
||||
uint8_t matrix_scan(void) {
|
||||
bool matrix_has_changed = false;
|
||||
bool changed = false;
|
||||
|
||||
// TODO: ここにマトリックススキャンルーチンを追加します
|
||||
|
||||
// ハードウェアによるデバウンスがない場合 - 設定されているデバウンスルーチンを使用します
|
||||
debounce(raw_matrix, matrix, MATRIX_ROWS, changed);
|
||||
changed = debounce(raw_matrix, matrix, MATRIX_ROWS, changed);
|
||||
|
||||
// 正しいキーボード動作のためにこれを呼び出す*必要があります*
|
||||
matrix_scan_quantum();
|
||||
|
||||
return matrix_has_changed;
|
||||
return changed;
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ QMK はその場で作られた一時的なマクロをサポートします。
|
||||
| `DYNAMIC_MACRO_SIZE` | 128 | 動的マクロが使用できるメモリ量を設定します。これは限られたリソースであり、コントローラに依存します。 |
|
||||
| `DYNAMIC_MACRO_USER_CALL` | *定義なし* | これを定義すると、ユーザの `keymap.c` ファイルを使ってマクロが起動されます。 |
|
||||
| `DYNAMIC_MACRO_NO_NESTING` | *定義なし* | これを定義すると、別のマクロからマクロを呼び出す(入れ子になったマクロ)機能を無効にします。 |
|
||||
| `DYNAMIC_MACRO_DELAY` | *定義なし* | 各キーを送信する時の待ち時間(ms単位)を設定します。 |
|
||||
|
||||
|
||||
記録中にキーを押すたびに LED が点滅し始めた場合は、マクロバッファにマクロを入れるスペースがもう無いことを意味します。マクロを入れるには、他のマクロ(それらは同じバッファを共有します)を短くするか、`config.h` に `DYNAMIC_MACRO_SIZE` 定義を追加することでバッファを増やします(デフォルト値: 128; ヘッダ内のコメントを読んでください)。
|
||||
|
||||
@@ -28,7 +28,6 @@
|
||||
|
||||
* `ACTION_TAP_DANCE_DOUBLE(kc1, kc2)`: 1回タップすると `kc1` キーコードを送信し、2回タップすると `kc2` キーコードを送信します。キーを押し続けているときは、適切なキーコードが登録されます: キーを押し続けた場合は `kc1`、一度タップしてから続けてもう一度キーを押してそのまま押し続けたときは、 `kc2` が登録されます。
|
||||
* `ACTION_TAP_DANCE_LAYER_MOVE(kc, layer)`: 1回タップすると `kc` キーコードが送信され、2回タップすると `layer` レイヤーに移動します(これは `TO` レイヤーキーコードのように機能します)。
|
||||
* この機能は `ACTION_TAP_DANCE_DUAL_ROLE` と同じですが、機能が明確になるように関数名を変更しました。どちらの関数名でも実行できます。
|
||||
* `ACTION_TAP_DANCE_LAYER_TOGGLE(kc, layer)`: 1回タップすると `kc` キーコードが送信され、2回タップすると `layer` の状態をトグルします(これは `TG` レイヤーキーコードのように機能します)。
|
||||
* `ACTION_TAP_DANCE_FN(fn)`: ユーザーキーマップに定義した指定の関数が呼び出されます。タップダンス実行の回数分タップすると、最後の時点で呼び出されます。
|
||||
* `ACTION_TAP_DANCE_FN_ADVANCED(on_each_tap_fn, on_dance_finished_fn, on_dance_reset_fn)`: タップする度にユーザーキーマップに定義した最初の関数が呼び出されます。タップダンスの実行が終わった時点で2番目の関数が呼び出され、タップダンスの実行をリセットするときに最後の関数が呼び出されます。
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
# ターミナル
|
||||
|
||||
<!---
|
||||
original document: 0.8.147:docs/feature_terminal.md
|
||||
git diff 0.8.147 HEAD -- docs/feature_terminal.md | cat
|
||||
-->
|
||||
|
||||
> この機能は現在のところ*巨大*であり、おそらく大量のメモリを搭載したキーボード、または楽しみのためにのみ配置する必要があります。
|
||||
|
||||
ターミナル機能はテキストエディタを介してキーストロークで通信するように設計されたコマンドラインのようなインタフェースです。エディタで自動インデント機能をオフにすることは有益です。
|
||||
|
||||
有効にするには、以下を `rules.mk` または `Makefile` に貼り付けます:
|
||||
|
||||
TERMINAL_ENABLE = yes
|
||||
|
||||
そして、オンまたはオフにするために、`TERM_ON` および `TERM_OFF` キーコードを使います。
|
||||
|
||||
有効な場合、`> ` プロンプトが現れ、ここでコマンドやバックスペース(オーディオが有効な場合は、先頭に到達するとベルが鳴ります)を入力することができ、エンターを入力するとコマンドを送信します。矢印キーは現在のところ無効なため、混乱することはありません。マウスでカーソルを移動することはお勧めしません。
|
||||
|
||||
`#define TERMINAL_HELP` は、このページでは実際には必要のない他の出力ヘルパーを有効にします。
|
||||
|
||||
"上矢印" および "下矢印" により、過去に入力した5つのコマンドを順に切り替えることができます。
|
||||
|
||||
## 今後のアイデア
|
||||
|
||||
* キーボード/ユーザ拡張可能なコマンド
|
||||
* より小さなフットプリント
|
||||
* 矢印キーのサポート
|
||||
* コマンド履歴 - 完了
|
||||
* SD カードのサポート
|
||||
* バッファディスプレイのための LCD サポート
|
||||
* キーコード -> 名称の対応表
|
||||
* レイヤー状態
|
||||
* *アナログ/デジタル ポートの読み込み/書き込み*
|
||||
* RGB モード関連機能
|
||||
* マクロ定義
|
||||
* EEPROM の読み込み/書き込み
|
||||
* オーディオ制御
|
||||
|
||||
## 現在のコマンド
|
||||
|
||||
### `about`
|
||||
|
||||
現在の QMK のバージョンとビルドした日の出力:
|
||||
|
||||
```
|
||||
> about
|
||||
QMK Firmware
|
||||
v0.5.115-7-g80ed73-dirty
|
||||
Built: 2017-08-29-20:24:44
|
||||
```
|
||||
|
||||
|
||||
### `print-buffer`
|
||||
|
||||
最後に入力した5つのコマンドの出力
|
||||
|
||||
```
|
||||
> print-buffer
|
||||
0. print-buffer
|
||||
1. help
|
||||
2. about
|
||||
3. keymap 0
|
||||
4. help
|
||||
5. flush-buffer
|
||||
```
|
||||
|
||||
### `flush-buffer`
|
||||
|
||||
コマンドバッファをクリア
|
||||
```
|
||||
> flush-buffer
|
||||
Buffer cleared!
|
||||
```
|
||||
|
||||
|
||||
### `help`
|
||||
|
||||
|
||||
利用可能なコマンドの出力:
|
||||
|
||||
```
|
||||
> help
|
||||
commands available:
|
||||
about help keycode keymap exit print-buffer flush-buffer
|
||||
```
|
||||
|
||||
### `keycode <layer> <row> <col>`
|
||||
|
||||
特定のレイヤー、行および列のキーコード値の出力:
|
||||
|
||||
```
|
||||
> keycode 0 1 0
|
||||
0x29 (41)
|
||||
```
|
||||
|
||||
### `keymap <layer>`
|
||||
|
||||
特定のレイヤーの全てのキーマップの出力
|
||||
|
||||
```
|
||||
> keymap 0
|
||||
0x002b, 0x0014, 0x001a, 0x0008, 0x0015, 0x0017, 0x001c, 0x0018, 0x000c, 0x0012, 0x0013, 0x002a,
|
||||
0x0029, 0x0004, 0x0016, 0x0007, 0x0009, 0x000a, 0x000b, 0x000d, 0x000e, 0x000f, 0x0033, 0x0034,
|
||||
0x00e1, 0x001d, 0x001b, 0x0006, 0x0019, 0x0005, 0x0011, 0x0010, 0x0036, 0x0037, 0x0038, 0x0028,
|
||||
0x5cd6, 0x00e0, 0x00e2, 0x00e3, 0x5cd4, 0x002c, 0x002c, 0x5cd5, 0x0050, 0x0051, 0x0052, 0x004f,
|
||||
>
|
||||
```
|
||||
|
||||
### `exit`
|
||||
|
||||
ターミナルの終了 - `TERM_OFF` と同じ。
|
||||
@@ -161,7 +161,6 @@ const uint16_t PROGMEM keymaps[][MATRIX_ROWS][MATRIX_COLS] = {
|
||||
* [`bool process_combo(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_combo.c#L115)
|
||||
* [`bool process_printer(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_printer.c#L77)
|
||||
* [`bool process_auto_shift(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_auto_shift.c#L94)
|
||||
* [`bool process_terminal(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_terminal.c#L264)
|
||||
* [Quantum 固有のキーコードを識別して処理する](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/quantum.c#L291)
|
||||
|
||||
この一連のイベントの中の任意のステップで (`process_record_kb()` のような)関数は `false` を返して、以降の処理を停止することができます。
|
||||
|
||||
@@ -337,6 +337,9 @@ 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_SWAP_ESCAPE_CAPSLOCK` |`EC_SWAP`|Swap Caps Lock and Escape |
|
||||
|`MAGIC_UNSWAP_ESCAPE_CAPSLOCK` |`EC_NORM`|Unswap Caps Lock and Escape |
|
||||
|`MAGIC_TOGGLE_ESCAPE_CAPSLOCK` |`EC_TOGG`|Toggle Caps Lock and Escape 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 |
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
|`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_SWAP_ESCAPE_CAPSLOCK` |`EC_SWAP`|Swap Caps Lock and Escape |
|
||||
|`MAGIC_UNSWAP_ESCAPE_CAPSLOCK` |`EC_NORM`|Unswap Caps Lock and Escape |
|
||||
|`MAGIC_TOGGLE_ESCAPE_CAPSLOCK` |`EC_TOGG`|Toggle Caps Lock and Escape 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 |
|
||||
|
||||
@@ -108,6 +108,8 @@ However, this does rely on the bootloader being set by the keyboard. If this inf
|
||||
|
||||
In this case, you'll have to fall back on specifying the bootloader. See the [Flashing Firmware](flashing.md) Guide for more details.
|
||||
|
||||
!> If your bootloader is not detected by `qmk flash`, try running `qmk doctor` for suggestions on how to fix common problems.
|
||||
|
||||
## Test It Out!
|
||||
|
||||
Congrats! Your custom firmware has been programmed to your keyboard and you're ready to test it out!
|
||||
|
||||
@@ -27,30 +27,24 @@ QMK maintains a Bundle of MSYS2, the CLI and all necessary dependencies. It also
|
||||
|
||||
You will need to install [QMK MSYS](https://msys.qmk.fm/). The latest release is available [here](https://github.com/qmk/qmk_distro_msys/releases/latest).
|
||||
|
||||
Alternatively, if you'd like to manually install MSYS2, the following section will walk you through the process.
|
||||
|
||||
<details>
|
||||
<summary>Manual Install</summary>
|
||||
<summary>Advanced Users</summary>
|
||||
|
||||
?> Ignore the following steps if you use `QMK MSYS`.
|
||||
!> <b style="font-size:150%">This process is not recommended for new users.</b>
|
||||
|
||||
If you'd like to manually install MSYS2, the following sections will walk you through the process.
|
||||
|
||||
#### Prerequisites
|
||||
|
||||
You will need to install MSYS2, Git and Python. Follow the installation instructions on https://www.msys2.org.
|
||||
|
||||
Once MSYS2 is installed, close any open MSYS terminals and open a new MinGW 64-bit terminal.
|
||||
You will need to install [MSYS2](https://www.msys2.org). Once installed, close any open MSYS terminals (purple icon) and open a new MinGW 64-bit terminal (blue icon) from the Start Menu.
|
||||
|
||||
!> **NOTE:** The MinGW 64-bit terminal is *not* the same as the MSYS terminal that opens when installation is completed. Your prompt should say "MINGW64" in purple text, rather than "MSYS". See [this page](https://www.msys2.org/wiki/MSYS2-introduction/#subsystems) for more information on the differences.
|
||||
|
||||
Then run the following command:
|
||||
|
||||
pacman --needed --noconfirm --disable-download-timeout -S git mingw-w64-x86_64-toolchain mingw-w64-x86_64-python3-pip mingw-w64-x86_64-python-pillow
|
||||
|
||||
#### Installation
|
||||
|
||||
Install the QMK CLI by running:
|
||||
|
||||
python3 -m pip install qmk
|
||||
pacman --needed --noconfirm --disable-download-timeout -S git mingw-w64-x86_64-python-qmk
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ As such, if you wish to override this API consider limiting use to writing to lo
|
||||
| `#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` |
|
||||
| `#define STM32_BOOTLOADER_DUAL_BANK_DELAY` | Relevant for dual-bank STM32 MCUs, an arbitrary measurement of time to delay before resetting the MCU. Increasing number increases the delay. | `100000` |
|
||||
| `#define STM32_BOOTLOADER_DUAL_BANK_DELAY` | Relevant for dual-bank STM32 MCUs, an arbitrary measurement of time to delay before resetting the MCU. Increasing number increases the delay. | `100` |
|
||||
|
||||
Kinetis MCUs have no configurable options.
|
||||
|
||||
|
||||
77
docs/platformdev_proton_c.md
Normal file
77
docs/platformdev_proton_c.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# Proton C
|
||||
|
||||
The Proton C is an Arm STM32F303xC based drop-in replacement for the Pro Micro.
|
||||
|
||||
<img src="https://i.imgur.com/GdsN1Rdh.jpg" alt="Proton C" />
|
||||
|
||||
#### Features
|
||||
|
||||
* Through-hole mounted USB-C Port
|
||||
* 32-bit 72MHz Cortex-M4 processor (STM32F303CCT6)
|
||||
* I2C, SPI, PWM, DMA, DAC, USART, I2S
|
||||
* 23x 3.3V I/O Ports
|
||||
* 1x 5V output for WS2812 LED chains
|
||||
* 256kB flash
|
||||
* 40kB RAM
|
||||
* AST1109MLTRQ speaker footprint
|
||||
* Reset button
|
||||
|
||||
## Warnings
|
||||
|
||||
Some of the PCBs compatible with Pro Micro have VCC (3.3V) and RAW (5V) pins connected (shorted) on the pcb. Using the Proton C will short 5V power from USB and regulated 3.3V which is connected directly to the MCU. Shorting those pins may damage the MCU on the Proton C.
|
||||
|
||||
So far, it appears that this is only an issue on the Gherkin PCBs, but other PCBs may be affected in this way.
|
||||
|
||||
In this case, you may want to not hook up the RAW pin at all.
|
||||
|
||||
## Manual Conversion
|
||||
|
||||
To use the Proton C natively, without having to specify `CONVERT_TO=proton_c`, you need to change the `MCU` line in `rules.mk`:
|
||||
|
||||
```
|
||||
MCU = STM32F303
|
||||
BOARD = QMK_PROTON_C
|
||||
```
|
||||
|
||||
Remove these variables if they exist:
|
||||
|
||||
* `BOOTLOADER`
|
||||
* `EXTRA_FLAGS`
|
||||
|
||||
Finally convert all pin assignments in `config.h` to the stm32 equivalents.
|
||||
|
||||
| Pro Micro Left | Proton C Left | | Proton C Right | Pro Micro Right |
|
||||
|-----------|----------|-|----------|-----------|
|
||||
| `D3` | `A9` | | 5v | RAW (5v) |
|
||||
| `D2` | `A10` | | GND | GND |
|
||||
| GND | GND | | FLASH | RESET |
|
||||
| GND | GND | | 3.3v | VCC <sup>1</sup> |
|
||||
| `D1` | `B7` | | `A2` | `F4` |
|
||||
| `D0` | `B6` | | `A1` | `F5` |
|
||||
| `D4` | `B5` | | `A0` | `F6` |
|
||||
| `C6` | `B4` | | `B8` | `F7` |
|
||||
| `D7` | `B3` | | `B13` | `B1` |
|
||||
| `E6` | `B2` | | `B14` | `B3` |
|
||||
| `B4` | `B1` | | `B15` | `B2` |
|
||||
| `B5` | `B0` | | `B9` | `B6` |
|
||||
| `B0` (RX LED) | `C13` <sup>2</sup> | | `C13` <sup>2</sup> | `D5` (TX LED) |
|
||||
|
||||
You can also make use of several new pins on the extended portion of the Proton C:
|
||||
|
||||
| Left | | Right |
|
||||
|------|-|-------|
|
||||
| `A4`<sup>3</sup> | | `B10` |
|
||||
| `A5`<sup>4</sup> | | `B11` |
|
||||
| `A6` | | `B12` |
|
||||
| `A7` | | `A14`<sup>5</sup> (SWCLK) |
|
||||
| `A8` | | `A13`<sup>5</sup> (SWDIO) |
|
||||
| `A15` | | RESET<sup>6</sup> |
|
||||
|
||||
Notes:
|
||||
|
||||
1. On a Pro Micro VCC can be 3.3v or 5v.
|
||||
2. A Proton C only has one onboard LED, not two like a Pro Micro. The Pro Micro has an RX LED on `D5` and a TX LED on `B0`.
|
||||
3. `A4` is shared with the speaker.
|
||||
4. `A5` is shared with the speaker.
|
||||
5. `A13` and `A14` are used for hardware debugging (SWD). You can also use them for GPIO, but should use them last.
|
||||
6. Short RESET to 3.3v (pull high) to reboot the MCU. This does not enter bootloader mode like a Pro Micro, it only resets the MCU.
|
||||
125
docs/platformdev_rp2040.md
Normal file
125
docs/platformdev_rp2040.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# Raspberry Pi RP2040
|
||||
|
||||
The following table shows the current driver status for peripherals on RP2040 MCUs:
|
||||
|
||||
| System | Support |
|
||||
| ---------------------------------------------------------------- | ---------------------------------------------- |
|
||||
| [ADC driver](adc_driver.md) | Support planned (no ETA) |
|
||||
| [Audio](audio_driver.md) | Support planned (no ETA) |
|
||||
| [I2C driver](i2c_driver.md) | :heavy_check_mark: |
|
||||
| [SPI driver](spi_driver.md) | :heavy_check_mark: |
|
||||
| [WS2812 driver](ws2812_driver.md) | :heavy_check_mark: using `PIO` driver |
|
||||
| [External EEPROMs](eeprom_driver.md) | :heavy_check_mark: using `I2C` or `SPI` driver |
|
||||
| [EEPROM emulation](eeprom_driver.md#wear_leveling-configuration) | :heavy_check_mark: |
|
||||
| [serial driver](serial_driver.md) | :heavy_check_mark: using `SIO` or `PIO` driver |
|
||||
| [UART driver](uart_driver.md) | Support planned (no ETA) |
|
||||
|
||||
## GPIO
|
||||
|
||||
<img alt="Raspberry Pi Pico pinout" src="https://i.imgur.com/nLaiYDE.jpg" width="48%"/>
|
||||
<img alt="Sparkfun RP2040 Pro Micro pinout" src="https://i.imgur.com/1TPAhrs.jpg" width="48%"/>
|
||||
|
||||
!> The GPIO pins of the RP2040 are not 5V tolerant!
|
||||
|
||||
### Pin nomenclature
|
||||
|
||||
To address individual pins on the RP2040, QMK uses the `GPx` abbreviation -- where the `x` stands for the GPIO number of the pin. This number can likely be found on the official pinout diagram of your board. Note that these GPIO numbers match the RP2040 MCU datasheet, and don't necessarily match the number you see printed on the board. For instance the Raspberry Pi Pico uses numbers from 1 to 40 for their pins, but these are not identical to the RP2040's GPIO numbers. So if you want to use the pin 11 of the Pico for your keyboard, you would refer to it as `GP8` in the config files.
|
||||
|
||||
### Alternate functions
|
||||
|
||||
The RP2040 features flexible GPIO function multiplexing, this means that every pin can be connected to nearly all the internal peripherals like I2C, SPI, UART or PWM. This allows for flexible PCB designs that are much less restricted in the selection of GPIO pins. To find out which pin can use which peripheral refer to the official [Raspberry PI RP2040 datasheet](https://datasheets.raspberrypi.com/rp2040/rp2040-datasheet.pdf#page=14) section 1.4.3 GPIO functions.
|
||||
|
||||
## Selecting hardware peripherals and drivers
|
||||
|
||||
QMK RP2040 support builds upon ChibiOS and thus follows their convention for activating drivers and associated hardware peripherals. These tables only give a quick overview which values have to be used, please refer to the ChibiOS specific sections on the driver pages.
|
||||
|
||||
### I2C Driver
|
||||
|
||||
| RP2040 Peripheral | `mcuconf.h` values | `I2C_DRIVER` |
|
||||
| ----------------- | ------------------ | ------------ |
|
||||
| `I2C0` | `RP_I2C_USE_I2C0` | `I2CD1` |
|
||||
| `I2C1` | `RP_I2C_USE_I2C1` | `I2CD2` |
|
||||
|
||||
To configure the I2C driver please read the [ChibiOS/ARM](i2c_driver.md#arm-configuration) section.
|
||||
|
||||
### SPI Driver
|
||||
|
||||
| RP2040 Peripheral | `mcuconf.h` values | `SPI_DRIVER` |
|
||||
| ----------------- | ------------------ | ------------ |
|
||||
| `SPI0` | `RP_SPI_USE_SPI0` | `SPID0` |
|
||||
| `SPI1` | `RP_SPI_USE_SPI1` | `SPID1` |
|
||||
|
||||
To configure the SPI driver please read the [ChibiOS/ARM](spi_driver.md#chibiosarm-configuration) section.
|
||||
|
||||
## Double-tap reset boot-loader entry :id=double-tap
|
||||
|
||||
The double-tap reset mechanism is an alternate way in QMK to enter the embedded mass storage UF2 boot-loader of the RP2040. It enables bootloader entry by a fast double-tap of the reset pin on start up, which is similar to the behavior of AVR Pro Micros. This feature activated by default for the Pro Micro RP2040 board, but has to be configured for other boards. To activate it, add the following options to your keyboards `config.h` file:
|
||||
|
||||
```c
|
||||
#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET // Activates the double-tap behavior
|
||||
#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_TIMEOUT 200U // Timeout window in ms in which the double tap can occur.
|
||||
#define RP2040_BOOTLOADER_DOUBLE_TAP_RESET_LED_MASK 0U // Specify a optional status led which blinks when entering the bootloader
|
||||
```
|
||||
|
||||
## Pre-defined RP2040 boards
|
||||
|
||||
QMK defines two boards that you can choose from to base your RP2040 powered keyboard upon. These boards provide pre-configured default pins and drivers.
|
||||
|
||||
### Generic Pro Micro RP2040
|
||||
|
||||
This is the default board that is chosen, unless any other RP2040 board is selected in your keyboards `rules.mk` file. It assumes a pin layout for the I2C, SPI and Serial drivers which is identical to the Sparkfun Pro Micro RP2040, however all values can be overwritten by defining them in your keyboards `config.h` file. The [double-tap](#double-tap) reset to enter boot-loader behavior is activated by default.
|
||||
|
||||
|
||||
| Driver configuration define | Value |
|
||||
| -------------------------------------------------------------------------- | ------------------------------------ |
|
||||
| **I2C driver** | |
|
||||
| `I2C_DRIVER` | `I2CD2` |
|
||||
| `I2C1_SDA_PIN` | `GP2` |
|
||||
| `I2C1_SCL_PIN` | `GP3` |
|
||||
| **SPI driver** | |
|
||||
| `SPI_DRIVER` | `SPID0` |
|
||||
| `SPI_SCK_PIN` | `GP18` |
|
||||
| `SPI_MISO_PIN` | `GP20` |
|
||||
| `SPI_MOSI_PIN` | `GP19` |
|
||||
| **Serial driver** | |
|
||||
| `SERIAL_USART_DRIVER` ([SIO Driver](serial_driver.md#the-sio-driver) only) | `SIOD0` |
|
||||
| `SOFT_SERIAL_PIN` | undefined, use `SERIAL_USART_TX_PIN` |
|
||||
| `SERIAL_USART_TX_PIN` | `GP0` |
|
||||
| `SERIAL_USART_RX_PIN` | `GP1` |
|
||||
|
||||
?> The pin-outs of Adafruit's KB2040 and Boardsource's Blok both deviate from the Sparkfun Pro Micro RP2040. Lookup the pin-out of these boards and adjust your keyboards pin definition accordingly if you want to use these boards.
|
||||
|
||||
### Generic RP2040 board
|
||||
|
||||
This board can be chosen as a base for RP2040 keyboards which configure all necessary pins and drivers themselves and do not wish to leverage the configuration matching the Generic Pro Micro RP2040 board. Thus it doesn't provide any pre-configured pins or drivers. To select this board add the following line to your keyboards `rules.mk` file.
|
||||
|
||||
```make
|
||||
BOARD = GENERIC_RP_RP2040
|
||||
```
|
||||
|
||||
## Split keyboard support
|
||||
|
||||
Split keyboards are fully supported using the [serial driver](serial_driver.md) in both full-duplex and half-duplex configurations. Two driver subsystems are supported by the RP2040, the hardware UART based `SIO` and the Programmable IO based `PIO` driver.
|
||||
|
||||
| Feature | [SIO Driver](serial_driver.md#the-sio-driver) | [PIO Driver](serial_driver.md#the-pio-driver) |
|
||||
| ----------------------------- | --------------------------------------------- | --------------------------------------------- |
|
||||
| Half-Duplex operation | | :heavy_check_mark: |
|
||||
| Full-Duplex operation | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| `TX` and `RX` pin swapping | | :heavy_check_mark: |
|
||||
| Any GPIO as `TX` and `RX` pin | Only UART capable pins | :heavy_check_mark: |
|
||||
| Simple configuration | | :heavy_check_mark: |
|
||||
|
||||
The `PIO` driver is much more flexible then the `SIO` driver, the only "downside" is the usage of `PIO` resources which in turn are not available for advanced user programs. Under normal circumstances, this resource allocation will be a non-issue.
|
||||
|
||||
## RP2040 second stage bootloader selection
|
||||
|
||||
As the RP2040 does not have any internal flash memory it depends on an external SPI flash memory chip to store and execute instructions from. To successfully interact with a wide variety of these chips a second stage bootloader that is compatible with the chosen external flash memory has to be supplied with each firmware image. By default an `W25Q080` compatible bootloader is assumed, but others can be chosen by adding one of the defines listed in the table below to your keyboards `config.h` file.
|
||||
|
||||
| Compatible with flash chip | Selection |
|
||||
| :------------------------- | ---------------------------------- |
|
||||
| W25Q080 | Selected by default |
|
||||
| AT25SF128A | `#define RP2040_FLASH_AT25SF128A` |
|
||||
| GD25Q64CS | `#define RP2040_FLASH_GD25Q64CS` |
|
||||
| W25X10CL | `#define RP2040_FLASH_W25X10CL` |
|
||||
| IS25LP080 | `#define RP2040_FLASH_IS25LP080` |
|
||||
| Generic 03H flash | `#define RP2040_FLASH_GENERIC_03H` |
|
||||
@@ -79,6 +79,9 @@ https://github.com/qmk/qmk_firmware/pulls?q=is%3Apr+is%3Aclosed+label%3Akeyboard
|
||||
- `matrix_init_board()` etc. migrated to `keyboard_pre_init_kb()`, see: [keyboard_pre_init*](custom_quantum_functions.md?id=keyboard_pre_init_-function-documentation)
|
||||
- prefer `CUSTOM_MATRIX = lite` if custom matrix used, allows for standard debounce, see [custom matrix 'lite'](custom_matrix.md?id=lite)
|
||||
- prefer LED indicator [Configuration Options](feature_led_indicators.md?id=configuration-options) to custom `led_update_*()` implementations where possible
|
||||
- Encoder support should not be hacked into the keymap here -- no `tap_code(dynamic_keymap_get_keycode())` or `action_exec()` hacks. The [Encoder Map](feature_encoders.md?id=encoder-map) feature already supports the dynamic keymap feature (what power's VIA's "live keymap updates" capability).
|
||||
- If support is absolutely necessary, it should be implemented exclusively at the keymap level, with none of the implementation bleeding into the keyboard level (no empty rows/columns, no encoder specific layouts, etc.), as those configurations can be redefined at the keymap level. Keymaps can then choose to use the `action_exec` hack. <!-- because people will complain, give them a way to implement it, in the meanwhile. To be removed. -->
|
||||
- [Request for official proper VIA support](https://github.com/the-via/app/issues/26)
|
||||
- `<keyboard>.h`
|
||||
- `#include "quantum.h"` appears at the top
|
||||
- `LAYOUT` macros should use standard definitions if applicable
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
# Converting a board to use the Proton C
|
||||
|
||||
Since the Proton C is a drop-in replacement for a Pro Micro we've made it easy to use. This page documents a handy automated process for converting keyboards, as well as documenting the manual process if you'd like to make use of Proton C features that aren't available on Pro Micros.
|
||||
|
||||
## Automatic Conversion
|
||||
|
||||
If a board currently supported in QMK uses a Pro Micro (or compatible board) and you want to use the Proton C, you can generate the firmware by appending `CONVERT_TO_PROTON_C=yes` (or `CTPC=yes`) to your make argument, like this:
|
||||
|
||||
make 40percentclub/mf68:default CTPC=yes
|
||||
|
||||
You can add the same argument to your keymap's `rules.mk`, which will accomplish the same thing.
|
||||
|
||||
This exposes the `CONVERT_TO_PROTON_C` flag that you can use in your code with `#ifdef`s, like this:
|
||||
|
||||
```c
|
||||
#ifdef CONVERT_TO_PROTON_C
|
||||
// Proton C code
|
||||
#else
|
||||
// Pro Micro code
|
||||
#endif
|
||||
```
|
||||
|
||||
If you get errors about `PORTB/DDRB`, etc not being defined, so you'll need to convert the keyboard's code to use the [GPIO Controls](gpio_control.md) that will work for both ARM and AVR. This shouldn't affect the AVR builds at all.
|
||||
|
||||
The Proton C only has one on-board LED (C13), and by default, the TXLED (D5) is mapped to it. If you want the RXLED (B0) mapped to it instead, add this like to your `config.h`:
|
||||
|
||||
#define CONVERT_TO_PROTON_C_RXLED
|
||||
|
||||
## Feature Conversion
|
||||
|
||||
These are defaults based on what has been implemented for ARM boards.
|
||||
|
||||
| Feature | Notes |
|
||||
|-------------------------------------|------------------------------------------------------------------------------------------------------------------|
|
||||
| [Audio](feature_audio.md) | Enabled |
|
||||
| [RGB Lighting](feature_rgblight.md) | Disabled |
|
||||
| [Backlight](feature_backlight.md) | Forces [task driven PWM](feature_backlight.md#software-pwm-driver) until ARM can provide automatic configuration |
|
||||
| USB Host (e.g. USB-USB converter) | Not supported (USB host code is AVR specific and is not currently supported on ARM) |
|
||||
| [Split keyboards](feature_split_keyboard.md) | Partial - heavily dependent on enabled features |
|
||||
|
||||
## Manual Conversion
|
||||
|
||||
To use the Proton C natively, without having to specify `CTPC=yes`, you need to change the `MCU` line in `rules.mk`:
|
||||
|
||||
```
|
||||
MCU = STM32F303
|
||||
BOARD = QMK_PROTON_C
|
||||
```
|
||||
|
||||
Remove these variables if they exist:
|
||||
|
||||
* `BOOTLOADER`
|
||||
* `EXTRA_FLAGS`
|
||||
|
||||
Finally convert all pin assignments in `config.h` to the stm32 equivalents.
|
||||
|
||||
| Pro Micro Left | Proton C Left | | Proton C Right | Pro Micro Right |
|
||||
|-----------|----------|-|----------|-----------|
|
||||
| `D3` | `A9` | | 5v | RAW (5v) |
|
||||
| `D2` | `A10` | | GND | GND |
|
||||
| GND | GND | | FLASH | RESET |
|
||||
| GND | GND | | 3.3v | VCC <sup>1</sup> |
|
||||
| `D1` | `B7` | | `A2` | `F4` |
|
||||
| `D0` | `B6` | | `A1` | `F5` |
|
||||
| `D4` | `B5` | | `A0` | `F6` |
|
||||
| `C6` | `B4` | | `B8` | `F7` |
|
||||
| `D7` | `B3` | | `B13` | `B1` |
|
||||
| `E6` | `B2` | | `B14` | `B3` |
|
||||
| `B4` | `B1` | | `B15` | `B2` |
|
||||
| `B5` | `B0` | | `B9` | `B6` |
|
||||
| `B0` (RX LED) | `C13` <sup>2</sup> | | `C13` <sup>2</sup> | `D5` (TX LED) |
|
||||
|
||||
You can also make use of several new pins on the extended portion of the Proton C:
|
||||
|
||||
| Left | | Right |
|
||||
|------|-|-------|
|
||||
| `A4`<sup>3</sup> | | `B10` |
|
||||
| `A5`<sup>4</sup> | | `B11` |
|
||||
| `A6` | | `B12` |
|
||||
| `A7` | | `A14`<sup>5</sup> (SWCLK) |
|
||||
| `A8` | | `A13`<sup>5</sup> (SWDIO) |
|
||||
| `A15` | | RESET<sup>6</sup> |
|
||||
|
||||
Notes:
|
||||
|
||||
1. On a Pro Micro VCC can be 3.3v or 5v.
|
||||
2. A Proton C only has one onboard LED, not two like a Pro Micro. The Pro Micro has an RX LED on `D5` and a TX LED on `B0`.
|
||||
3. `A4` is shared with the speaker.
|
||||
4. `A5` is shared with the speaker.
|
||||
5. `A13` and `A14` are used for hardware debugging (SWD). You can also use them for GPIO, but should use them last.
|
||||
6. Short RESET to 3.3v (pull high) to reboot the MCU. This does not enter bootloader mode like a Pro Micro, it only resets the MCU.
|
||||
@@ -24,6 +24,7 @@ Hardware supported:
|
||||
| GC9A01 | RGB LCD (circular) | 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = gc9a01_spi` |
|
||||
| ILI9163 | RGB LCD | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = ili9163_spi` |
|
||||
| ILI9341 | RGB LCD | 240x320 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = ili9341_spi` |
|
||||
| ILI9488 | RGB LCD | 320x480 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = ili9488_spi` |
|
||||
| SSD1351 | RGB OLED | 128x128 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = ssd1351_spi` |
|
||||
| ST7789 | RGB LCD | 240x320, 240x240 | SPI + D/C + RST | `QUANTUM_PAINTER_DRIVERS = st7789_spi` |
|
||||
|
||||
@@ -654,6 +655,30 @@ The maximum number of displays can be configured by changing the following in yo
|
||||
#define ILI9341_NUM_DEVICES 3
|
||||
```
|
||||
|
||||
### ILI9488 :id=qp-driver-ili9488
|
||||
|
||||
Enabling support for the ILI9488 in Quantum Painter is done by adding the following to `rules.mk`:
|
||||
|
||||
```make
|
||||
QUANTUM_PAINTER_ENABLE = yes
|
||||
QUANTUM_PAINTER_DRIVERS = ili9488_spi
|
||||
```
|
||||
|
||||
Creating a ILI9488 device in firmware can then be done with the following API:
|
||||
|
||||
```c
|
||||
painter_device_t qp_ili9488_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
|
||||
```
|
||||
|
||||
The device handle returned from the `qp_ili9488_make_spi_device` function can be used to perform all other drawing operations.
|
||||
|
||||
The maximum number of displays can be configured by changing the following in your `config.h` (default is 1):
|
||||
|
||||
```c
|
||||
// 3 displays:
|
||||
#define ILI9488_NUM_DEVICES 3
|
||||
```
|
||||
|
||||
### SSD1351 :id=qp-driver-ssd1351
|
||||
|
||||
Enabling support for the SSD1351 in Quantum Painter is done by adding the following to `rules.mk`:
|
||||
|
||||
@@ -108,7 +108,58 @@ Example:
|
||||
}
|
||||
```
|
||||
|
||||
### RGB Lighting
|
||||
## Non-RGB LED Lighting
|
||||
|
||||
This section controls basic 2-pin LEDs, which typically pass through keyswitches and are soldered into the PCB, or are placed in PCB sockets.
|
||||
### Backlight
|
||||
|
||||
* `breathing`
|
||||
* Enable backlight breathing, if supported
|
||||
* `breathing_period`
|
||||
* The length of one backlight “breath” in seconds
|
||||
* `levels`
|
||||
* The number of brightness levels (maximum 31, excluding off)
|
||||
* `pin`
|
||||
* The pin that controls the backlight LED(s)
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"backlight": {
|
||||
"breathing": true,
|
||||
"breathing_period": 5,
|
||||
"levels": 15,
|
||||
"pin": "B7"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### LED Indicators
|
||||
|
||||
Used for indicating Num Lock, Caps Lock, and Scroll Lock. May be soldered in-switch or in a dedicated area.
|
||||
|
||||
* `num_lock`
|
||||
* The pin that controls the `Num Lock` LED
|
||||
* `caps_lock`
|
||||
* The pin that controls the `Caps Lock` LED
|
||||
* `scroll_lock`
|
||||
* The pin that controls the `Scroll Lock` LED
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"indicators": {
|
||||
"num_lock": "B6",
|
||||
"caps_lock": "D2",
|
||||
"scroll_lock": "A3"
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## RGB Lighting
|
||||
|
||||
This section controls the legacy WS2812 support in QMK. This should not be confused with the RGB Matrix feature, which can be used to control both WS2812 and ISSI RGB LEDs.
|
||||
|
||||
@@ -152,7 +203,7 @@ Example:
|
||||
}
|
||||
```
|
||||
|
||||
#### RGBLight Animations
|
||||
### RGBLight Animations
|
||||
|
||||
The following animations can be enabled:
|
||||
|
||||
@@ -187,3 +238,61 @@ Example:
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
### Encoders
|
||||
|
||||
This section controls the basic [rotary encoder](feature_encoders.md) support.
|
||||
|
||||
The following items can be set. Not every value is required.
|
||||
|
||||
* `pin_a`
|
||||
* __Required__. A pad definition
|
||||
* `pin_b`
|
||||
* __Required__. B pad definition
|
||||
* `resolution`
|
||||
* How many pulses the encoder registers between each detent
|
||||
|
||||
Examples:
|
||||
|
||||
```json
|
||||
{
|
||||
"encoder": {
|
||||
"rotary": [
|
||||
{ "pin_a": "B5", "pin_b": "A2" }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
{
|
||||
"encoder": {
|
||||
"rotary": [
|
||||
{ "pin_a": "B5", "pin_b": "A2", "resolution": 4 }
|
||||
{ "pin_a": "B6", "pin_b": "A3", "resolution": 2 }
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Secure
|
||||
|
||||
The following options can be configured:
|
||||
|
||||
|Key |Description |
|
||||
|------------------|---------------------------------------------------------------------------------|
|
||||
|`unlock_sequence` | Timeout for the user to perform the configured unlock sequence - `0` to disable |
|
||||
|`unlock_timeout` | Timeout while unlocked before returning to locked - `0` to disable |
|
||||
|`idle_timeout` | Array of matrix locations describing a sequential sequence of keypresses |
|
||||
|
||||
Example:
|
||||
|
||||
```json
|
||||
{
|
||||
"secure": {
|
||||
"unlock_sequence": [ [0,0], [0,1] ],
|
||||
"unlock_timeout": 5000,
|
||||
"idle_timeout": 60000
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -1,129 +1,301 @@
|
||||
# 'serial' Driver
|
||||
This driver powers the [Split Keyboard](feature_split_keyboard.md) feature.
|
||||
|
||||
The serial driver powers the [Split Keyboard](feature_split_keyboard.md) feature. Several implementations are available, depending on the platform of your split keyboard. Note that none of the drivers support split keyboards with more then two halves.
|
||||
|
||||
| Driver | AVR | ARM | Connection between halves |
|
||||
| --------------------------------------- | ------------------ | ------------------ | --------------------------------------------------------------------------------------------- |
|
||||
| [Bitbang](#bitbang) | :heavy_check_mark: | :heavy_check_mark: | Single wire communication. One wire is used for reception and transmission. |
|
||||
| [USART Half-duplex](#usart-half-duplex) | | :heavy_check_mark: | Efficient single wire communication. One wire is used for reception and transmission. |
|
||||
| [USART Full-duplex](#usart-full-duplex) | | :heavy_check_mark: | Efficient two wire communication. Two distinct wires are used for reception and transmission. |
|
||||
|
||||
?> Serial in this context should be read as **sending information one bit at a time**, rather than implementing UART/USART/RS485/RS232 standards.
|
||||
|
||||
Drivers in this category have the following characteristics:
|
||||
* bit bang and USART Half-duplex provide data and signaling over a single conductor
|
||||
* USART Full-duplex provide data and signaling over two conductors
|
||||
* They are all limited to single master and single slave communication scheme
|
||||
<hr>
|
||||
|
||||
## Supported Driver Types
|
||||
## Bitbang
|
||||
|
||||
| | AVR | ARM |
|
||||
| ----------------- | ------------------ | ------------------ |
|
||||
| bit bang | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| USART Half-duplex | | :heavy_check_mark: |
|
||||
| USART Full-duplex | | :heavy_check_mark: |
|
||||
This is the Default driver, the absence of configuration assumes this driver. It works by [bit banging](https://en.wikipedia.org/wiki/Bit_banging) a GPIO pin using the CPU. It is therefore not as efficient as a dedicated hardware peripheral, which the Half-duplex and Full-duplex drivers use.
|
||||
|
||||
## Driver configuration
|
||||
!> On ARM platforms the bitbang driver causes connection issues when using it together with the bitbang WS2812 driver. Choosing alternate drivers for both serial and WS2812 (instead of bitbang) is strongly recommended.
|
||||
|
||||
### Bitbang
|
||||
Default driver, the absence of configuration assumes this driver. To configure it, add this to your rules.mk:
|
||||
### Pin configuration
|
||||
|
||||
```
|
||||
LEFT RIGHT
|
||||
+-------+ SERIAL +-------+
|
||||
| SSP |-----------------| SSP |
|
||||
| | VDD | |
|
||||
| |-----------------| |
|
||||
| | GND | |
|
||||
| |-----------------| |
|
||||
+-------+ +-------+
|
||||
```
|
||||
|
||||
One GPIO pin is needed for the bitbang driver, as only one wire is used for receiving and transmitting data. This pin is referred to as the `SOFT_SERIAL_PIN` (SSP) in the configuration. A simple TRS or USB cable provides enough conductors for this driver to work.
|
||||
|
||||
### Setup
|
||||
|
||||
To use the bitbang driver follow these steps to activate it.
|
||||
|
||||
1. Change the `SERIAL_DRIVER` to `bitbang` in your keyboards `rules.mk` file:
|
||||
|
||||
```make
|
||||
SERIAL_DRIVER = bitbang
|
||||
```
|
||||
|
||||
Configure the driver via your config.h:
|
||||
2. Configure the GPIO pin of your keyboard via the `config.h` file:
|
||||
|
||||
```c
|
||||
#define SOFT_SERIAL_PIN D0 // or D1, D2, D3, E6
|
||||
#define SELECT_SOFT_SERIAL_SPEED 1 // or 0, 2, 3, 4, 5
|
||||
// 0: about 189kbps (Experimental only)
|
||||
// 1: about 137kbps (default)
|
||||
// 2: about 75kbps
|
||||
// 3: about 39kbps
|
||||
// 4: about 26kbps
|
||||
// 5: about 20kbps
|
||||
```
|
||||
|
||||
#### ARM
|
||||
3. On ARM platforms you must turn on ChibiOS `PAL_USE_CALLBACKS` feature:
|
||||
|
||||
!> The bitbang driver causes connection issues with bitbang WS2812 driver
|
||||
* In `halconf.h` add the line `#define PAL_USE_CALLBACKS TRUE`.
|
||||
|
||||
Along with the generic options above, you must also turn on the `PAL_USE_CALLBACKS` feature in your halconf.h.
|
||||
<hr>
|
||||
|
||||
### USART Half-duplex
|
||||
Targeting STM32 boards where communication is offloaded to a USART hardware device. The advantage over bitbang is that this provides fast and accurate timings. `SERIAL_PIN_TX` for this driver is the configured USART TX pin. As this Pin is configured in open-drain mode an **external pull-up resistor is needed to keep the line high** (resistor values of 1.5k to 8.2k are known to work). To configure it, add this to your rules.mk:
|
||||
## USART Half-duplex
|
||||
|
||||
Targeting ARM boards based on ChibiOS, where communication is offloaded to a USART hardware device that supports Half-duplex operation. The advantages over bitbanging are fast, accurate timings and reduced CPU usage. Therefore it is advised to choose this driver or the Full-duplex driver whenever possible.
|
||||
|
||||
### Pin configuration
|
||||
|
||||
```
|
||||
LEFT RIGHT
|
||||
+-------+ | | +-------+
|
||||
| | R R | |
|
||||
| | | SERIAL | | |
|
||||
| TX |-----------------| TX |
|
||||
| | VDD | |
|
||||
| |-----------------| |
|
||||
| | GND | |
|
||||
| |-----------------| |
|
||||
+-------+ +-------+
|
||||
```
|
||||
|
||||
Only one GPIO pin is needed for the Half-duplex driver, as only one wire is used for receiving and transmitting data. This pin is referred to as the `SERIAL_USART_TX_PIN` in the configuration. Take care that the pin you chose can act as the TX pin of the USART peripheral. A simple TRS or USB cable provides enough conductors for this driver to work. As the split connection is configured to work in open-drain mode, an **external pull-up resistor is needed to keep the line high**. Resistor values of 1.5kΩ to 8.2kΩ are known to work.
|
||||
|
||||
### Setup
|
||||
|
||||
To use the Half-duplex driver follow these steps to activate it. If you target the Raspberry Pi RP2040 PIO implementation skip step 1.
|
||||
|
||||
1. Change the `SERIAL_DRIVER` to `usart` in your keyboards `rules.mk` file:
|
||||
|
||||
```make
|
||||
SERIAL_DRIVER = usart
|
||||
```
|
||||
|
||||
Configure the hardware via your config.h:
|
||||
2. (RP2040 PIO only!) Change the `SERIAL_DRIVER` to `vendor` in your keyboards `rules.mk` file:
|
||||
|
||||
```make
|
||||
SERIAL_DRIVER = vendor
|
||||
```
|
||||
|
||||
3. Configure the hardware of your keyboard via the `config.h` file:
|
||||
|
||||
```c
|
||||
#define SOFT_SERIAL_PIN B6 // USART TX pin
|
||||
//#define USART1_REMAP // Remap USART TX and RX pins on STM32F103 MCUs, see table below.
|
||||
#define SELECT_SOFT_SERIAL_SPEED 1 // or 0, 2, 3, 4, 5
|
||||
// 0: about 460800 baud
|
||||
// 1: about 230400 baud (default)
|
||||
// 2: about 115200 baud
|
||||
// 3: about 57600 baud
|
||||
// 4: about 38400 baud
|
||||
// 5: about 19200 baud
|
||||
#define SERIAL_USART_DRIVER SD1 // USART driver of TX pin. default: SD1
|
||||
#define SERIAL_USART_TX_PAL_MODE 7 // Pin "alternate function", see the respective datasheet for the appropriate values for your MCU. default: 7
|
||||
#define SERIAL_USART_TIMEOUT 20 // USART driver timeout. default 20
|
||||
#define SERIAL_USART_TX_PIN B6 // The GPIO pin that is used split communication.
|
||||
```
|
||||
|
||||
You must also enable the ChibiOS `SERIAL` feature:
|
||||
* In your board's halconf.h: `#define HAL_USE_SERIAL TRUE`
|
||||
* In your board's mcuconf.h: `#define STM32_SERIAL_USE_USARTn TRUE` (where 'n' matches the peripheral number of your selected USART on the MCU)
|
||||
For STM32 MCUs several GPIO configuration options can be changed as well. See the section ["Alternate Functions for selected STM32 MCUs"](alternate-functions-for-selected-stm32-mcus).
|
||||
|
||||
Do note that the configuration required is for the `SERIAL` peripheral, not the `UART` peripheral.
|
||||
```c
|
||||
#define USART1_REMAP // Remap USART TX and RX pins on STM32F103 MCUs, see table below.
|
||||
#define SERIAL_USART_TX_PAL_MODE 7 // Pin "alternate function", see the respective datasheet for the appropriate values for your MCU. default: 7
|
||||
```
|
||||
|
||||
### USART Full-duplex
|
||||
Targeting STM32 boards where communication is offloaded to a USART hardware device. The advantage over bitbang is that this provides fast and accurate timings. USART Full-Duplex requires two conductors **without** pull-up resistors instead of one conductor with a pull-up resistor unlike the Half-duplex driver. Due to its internal design it is more efficent, which can result in even faster transmission speeds.
|
||||
1. Decide either for `SERIAL`, `SIO` or `PIO` subsystem, see the section ["Choosing a driver subsystem"](#choosing-a-driver-subsystem).
|
||||
|
||||
#### Pin configuration
|
||||
<hr>
|
||||
|
||||
`SERIAL_USART_TX_PIN` is the USART `TX` pin, `SERIAL_USART_RX_PIN` is the USART `RX` pin. No external pull-up resistors are needed as the `TX` pin operates in push-pull mode. To use this driver the usart peripherals `TX` and `RX` pins must be configured with the correct Alternate-functions. If you are using a Proton-C everything is already setup, same is true for STM32F103 MCUs. For MCUs which are using a modern flexible GPIO configuration you have to specify these by setting `SERIAL_USART_TX_PAL_MODE` and `SERIAL_USART_RX_PAL_MODE`. Refeer to the corresponding datasheets of your MCU or find those settings in the table below.
|
||||
## USART Full-duplex
|
||||
|
||||
#### Connecting the halves and Pin Swap
|
||||
Please note that `TX` of the master half has to be connected with the `RX` pin of the slave half and `RX` of the master half has to be connected with the `TX` pin of the slave half! Usually this pin swap has to be done outside of the MCU e.g. with cables or on the pcb. Some MCUs like the STM32F303 used on the Proton-C allow this pin swap directly inside the MCU, this feature can be enabled using `#define SERIAL_USART_PIN_SWAP` in your config.h.
|
||||
Targeting ARM boards based on ChibiOS where communication is offloaded to an USART hardware device. The advantages over bitbanging are fast, accurate timings and reduced CPU usage. Therefore it is advised to choose this driver or the Full-duplex driver whenever possible. Due to its internal design it is slightly more efficient then the Half-duplex driver, but it should be primarily chosen if Half-duplex operation is not supported by the USART peripheral.
|
||||
|
||||
#### Setup
|
||||
To use the driver, add this to your rules.mk:
|
||||
### Pin configuration
|
||||
|
||||
```
|
||||
LEFT RIGHT
|
||||
+-------+ +-------+
|
||||
| | SERIAL | |
|
||||
| TX |-----------------| RX |
|
||||
| | SERIAL | |
|
||||
| RX |-----------------| TX |
|
||||
| | VDD | |
|
||||
| |-----------------| |
|
||||
| | GND | |
|
||||
| |-----------------| |
|
||||
+-------+ +-------+
|
||||
```
|
||||
|
||||
Two GPIO pins are needed for the Full-duplex driver, as two distinct wires are used for receiving and transmitting data. The pin transmitting data is the `TX` pin and refereed to as the `SERIAL_USART_TX_PIN`, the pin receiving data is the `RX` pin and refereed to as the `SERIAL_USART_RX_PIN` in this configuration. Please note that `TX` pin of the master half has to be connected with the `RX` pin of the slave half and the `RX` pin of the master half has to be connected with the `TX` pin of the slave half! Usually this pin swap has to be done outside of the MCU e.g. with cables or on the PCB. Some MCUs like the STM32F303 used on the Proton-C allow this pin swap directly inside the MCU. A simple TRRS or USB cable provides enough conductors for this driver to work.
|
||||
|
||||
To use this driver the usart peripherals `TX` and `RX` pins must be configured with the correct Alternate-functions. If you are using a Proton-C everything is already setup, same is true for STM32F103 MCUs. For MCUs which are using a modern flexible GPIO configuration you have to specify these by setting `SERIAL_USART_TX_PAL_MODE` and `SERIAL_USART_RX_PAL_MODE`. Refer to the corresponding datasheets of your MCU or find those settings in the section ["Alternate Functions for selected STM32 MCUs"](#alternate-functions-for-selected-stm32-mcus).
|
||||
|
||||
### Setup
|
||||
|
||||
To use the Full-duplex driver follow these steps to activate it. If you target the Raspberry Pi RP2040 PIO implementation skip step 1.
|
||||
|
||||
1. Change the `SERIAL_DRIVER` to `usart` in your keyboards `rules.mk` file:
|
||||
|
||||
```make
|
||||
SERIAL_DRIVER = usart
|
||||
```
|
||||
|
||||
Next configure the hardware via your config.h:
|
||||
2. (RP2040 PIO only!) Change the `SERIAL_DRIVER` to `vendor` in your keyboards `rules.mk` file:
|
||||
|
||||
```make
|
||||
SERIAL_DRIVER = vendor
|
||||
```
|
||||
|
||||
3. Configure the hardware of your keyboard via the `config.h` file:
|
||||
|
||||
```c
|
||||
#define SERIAL_USART_FULL_DUPLEX // Enable full duplex operation mode.
|
||||
#define SERIAL_USART_TX_PIN B6 // USART TX pin
|
||||
#define SERIAL_USART_RX_PIN B7 // USART RX pin
|
||||
//#define USART1_REMAP // Remap USART TX and RX pins on STM32F103 MCUs, see table below.
|
||||
//#define SERIAL_USART_PIN_SWAP // Swap TX and RX pins if keyboard is master halve.
|
||||
// Check if this feature is necessary with your keyboard design and available on the mcu.
|
||||
#define SELECT_SOFT_SERIAL_SPEED 1 // or 0, 2, 3, 4, 5
|
||||
// 0: 460800 baud
|
||||
// 1: 230400 baud (default)
|
||||
// 2: 115200 baud
|
||||
// 3: 57600 baud
|
||||
// 4: 38400 baud
|
||||
// 5: 19200 baud
|
||||
#define SERIAL_USART_DRIVER SD1 // USART driver of TX and RX pin. default: SD1
|
||||
```
|
||||
|
||||
For STM32 MCUs several GPIO configuration options, including the ability for `TX` to `RX` pin swapping, can be changed as well. See the section ["Alternate Functions for selected STM32 MCUs"](alternate-functions-for-selected-stm32-mcus).
|
||||
|
||||
```c
|
||||
#define SERIAL_USART_PIN_SWAP // Swap TX and RX pins if keyboard is master halve. (Only available on some MCUs)
|
||||
#define USART1_REMAP // Remap USART TX and RX pins on STM32F103 MCUs, see table below.
|
||||
#define SERIAL_USART_TX_PAL_MODE 7 // Pin "alternate function", see the respective datasheet for the appropriate values for your MCU. default: 7
|
||||
#define SERIAL_USART_RX_PAL_MODE 7 // Pin "alternate function", see the respective datasheet for the appropriate values for your MCU. default: 7
|
||||
```
|
||||
|
||||
1. Decide either for `SERIAL`, `SIO` or `PIO` subsystem, see the section ["Choosing a driver subsystem"](#choosing-a-driver-subsystem).
|
||||
|
||||
<hr>
|
||||
|
||||
## Choosing a driver subsystem
|
||||
|
||||
### The `SERIAL` driver
|
||||
|
||||
The `SERIAL` Subsystem is supported for the majority of ChibiOS MCUs and should be used whenever supported. Follow these steps in order to activate it:
|
||||
|
||||
1. In your keyboards `halconf.h` add:
|
||||
|
||||
```c
|
||||
#define HAL_USE_SERIAL TRUE
|
||||
```
|
||||
|
||||
2. In your keyboards `mcuconf.h`: activate the USART peripheral that is used on your MCU. The shown example is for an STM32 MCU, so this will not work on MCUs by other manufacturers. You can find the correct names in the `mcuconf.h` files of your MCU that ship with ChibiOS.
|
||||
|
||||
Just below `#include_next <mcuconf.h>` add:
|
||||
|
||||
```c
|
||||
#include_next <mcuconf.h>
|
||||
|
||||
#undef STM32_SERIAL_USE_USARTn
|
||||
#define STM32_SERIAL_USE_USARTn TRUE
|
||||
```
|
||||
|
||||
Where 'n' matches the peripheral number of your selected USART on the MCU.
|
||||
|
||||
3. In you keyboards `config.h`: override the default USART `SERIAL` driver if you use a USART peripheral that does not belong to the default selected `SD1` driver. For instance, if you selected `STM32_SERIAL_USE_USART3` the matching driver would be `SD3`.
|
||||
|
||||
```c
|
||||
#define SERIAL_USART_DRIVER SD3
|
||||
```
|
||||
|
||||
### The `SIO` driver
|
||||
|
||||
The `SIO` Subsystem was added to ChibiOS with the 21.11 release and is only supported on selected MCUs. It should only be chosen when the `SERIAL` subsystem is not supported by your MCU.
|
||||
|
||||
Follow these steps in order to activate it:
|
||||
|
||||
1. In your keyboards `halconf.h` add:
|
||||
|
||||
```c
|
||||
#define HAL_USE_SIO TRUE
|
||||
```
|
||||
|
||||
2. In your keyboards `mcuconf.h:` activate the USART peripheral that is used on your MCU. The shown example is for an STM32 MCU, so this will not work on MCUs by other manufacturers. You can find the correct names in the `mcuconf.h` files of your MCU that ship with ChibiOS.
|
||||
|
||||
Just below `#include_next <mcuconf.h>` add:
|
||||
|
||||
```c
|
||||
#include_next <mcuconf.h>
|
||||
|
||||
#undef STM32_SIO_USE_USARTn
|
||||
#define STM32_SIO_USE_USARTn TRUE
|
||||
```
|
||||
|
||||
Where 'n' matches the peripheral number of your selected USART on the MCU.
|
||||
|
||||
3. In you keyboards `config.h`: override the default USART `SIO` driver if you use a USART peripheral that does not belong to the default selected `SIOD1` driver. For instance, if you selected `STM32_SERIAL_USE_USART3` the matching driver would be `SIOD3`.
|
||||
|
||||
```c
|
||||
#define SERIAL_USART_DRIVER SIOD3
|
||||
```
|
||||
|
||||
### The `PIO` driver
|
||||
|
||||
The `PIO` subsystem is a Raspberry Pi RP2040 specific implementation, using the integrated PIO peripheral and is therefore only available on this MCU. Because of the flexible nature of the PIO peripherals, **any** GPIO pin can be used as a `TX` or `RX` pin. Half-duplex and Full-duplex operation is fully supported. The Half-duplex operation mode uses the built-in pull-ups and GPIO manipulation on the RP2040 to drive the line high by default. An external pull-up is therefore not necessary.
|
||||
|
||||
Configure the hardware via your config.h:
|
||||
```c
|
||||
#define SERIAL_PIO_USE_PIO1 // Force the usage of PIO1 peripheral, by default the Serial implementation uses the PIO0 peripheral
|
||||
```
|
||||
|
||||
The Serial PIO program uses 2 state machines, 13 instructions and the complete interrupt handler of the PIO peripheral it is running on.
|
||||
|
||||
<hr>
|
||||
|
||||
## Advanced Configuration
|
||||
|
||||
There are several advanced configuration options that can be defined in your keyboards `config.h` file:
|
||||
|
||||
### Baudrate
|
||||
|
||||
If you're having issues or need a higher baudrate with serial communication, you can change the baudrate which in turn controls the communication speed for serial. You want to lower the baudrate if you experience failed transactions.
|
||||
|
||||
```c
|
||||
#define SELECT_SOFT_SERIAL_SPEED {#}
|
||||
```
|
||||
|
||||
| Speed | Bitbang | Half-duplex and Full-duplex |
|
||||
| ----- | -------------------------- | --------------------------- |
|
||||
| `0` | 189000 baud (experimental) | 460800 baud |
|
||||
| `1` | 137000 baud (default) | 230400 baud (default) |
|
||||
| `2` | 75000 baud | 115200 baud |
|
||||
| `3` | 39000 baud | 57600 baud |
|
||||
| `4` | 26000 baud | 38400 baud |
|
||||
| `5` | 20000 baud | 19200 baud |
|
||||
|
||||
Alternatively you can specify the baudrate directly by defining `SERIAL_USART_SPEED`.
|
||||
|
||||
### Timeout
|
||||
|
||||
This is the default time window in milliseconds in which a successful communication has to complete. Usually you don't want to change this value. But you can do so anyways by defining an alternate one in your keyboards `config.h` file:
|
||||
|
||||
```c
|
||||
#define SERIAL_USART_TIMEOUT 20 // USART driver timeout. default 20
|
||||
```
|
||||
|
||||
You must also enable the ChibiOS `SERIAL` feature:
|
||||
* In your board's halconf.h: `#define HAL_USE_SERIAL TRUE`
|
||||
* In your board's mcuconf.h: `#define STM32_SERIAL_USE_USARTn TRUE` (where 'n' matches the peripheral number of your selected USART on the MCU)
|
||||
<hr>
|
||||
|
||||
Do note that the configuration required is for the `SERIAL` peripheral, not the `UART` peripheral.
|
||||
## Troubleshooting
|
||||
|
||||
#### Pins for USART Peripherals with Alternate Functions for selected STM32 MCUs
|
||||
If you're having issues withe serial communication, you can enable debug messages that will give you insights which part of the communication failed. The enable these messages add to your keyboards `config.h` file:
|
||||
|
||||
##### STM32F303 / Proton-C [Datasheet](https://www.st.com/resource/en/datasheet/stm32f303cc.pdf)
|
||||
```c
|
||||
#define SERIAL_DEBUG
|
||||
```
|
||||
|
||||
?> The messages will be printed out to the `CONSOLE` output. For additional information, refer to [Debugging/Troubleshooting QMK](faq_debug.md).
|
||||
|
||||
## Alternate Functions for selected STM32 MCUs
|
||||
|
||||
Pins for USART Peripherals with
|
||||
|
||||
### STM32F303 / Proton-C [Datasheet](https://www.st.com/resource/en/datasheet/stm32f303cc.pdf)
|
||||
|
||||
Pin Swap available: :heavy_check_mark:
|
||||
|
||||
| Pin | Function | Mode |
|
||||
| Pin | Function | Mode |
|
||||
| ---------- | -------- | ---- |
|
||||
| **USART1** | | |
|
||||
| PA9 | TX | AF7 |
|
||||
@@ -151,11 +323,11 @@ Pin Swap available: :heavy_check_mark:
|
||||
| PD8 | TX | AF7 |
|
||||
| PD9 | RX | AF7 |
|
||||
|
||||
##### STM32F072 [Datasheet](https://www.st.com/resource/en/datasheet/stm32f072c8.pdf)
|
||||
### STM32F072 [Datasheet](https://www.st.com/resource/en/datasheet/stm32f072c8.pdf)
|
||||
|
||||
Pin Swap available: :heavy_check_mark:
|
||||
|
||||
| Pin | Function | Mode |
|
||||
| Pin | Function | Mode |
|
||||
| ------ | -------- | ---- |
|
||||
| USART1 | | |
|
||||
| PA9 | TX | AF1 |
|
||||
@@ -180,7 +352,7 @@ Pin Swap available: :heavy_check_mark:
|
||||
| PA0 | TX | AF4 |
|
||||
| PA1 | RX | AF4 |
|
||||
|
||||
##### STM32F103 Medium Density (C8-CB) [Datasheet](https://www.st.com/resource/en/datasheet/stm32f103c8.pdf)
|
||||
### STM32F103 Medium Density (C8-CB) [Datasheet](https://www.st.com/resource/en/datasheet/stm32f103c8.pdf)
|
||||
|
||||
Pin Swap available: N/A
|
||||
|
||||
@@ -190,7 +362,7 @@ Pin remapping:
|
||||
|
||||
The pins of USART Peripherals use default Pins that can be remapped to use other pins using the AFIO registers. Default pins are marked **bold**. Add the appropriate defines to your config.h file.
|
||||
|
||||
| Pin | Function | Mode | USART_REMAP |
|
||||
| Pin | Function | Mode | USART_REMAP |
|
||||
| ---------- | -------- | ---- | ------------------- |
|
||||
| **USART1** | | | |
|
||||
| **PA9** | TX | AFPP | |
|
||||
|
||||
@@ -155,7 +155,6 @@ The `process_record()` function itself is deceptively simple, but hidden within
|
||||
* [`bool process_printer(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_printer.c#L77)
|
||||
* [`bool process_auto_shift(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_auto_shift.c#L94)
|
||||
* `bool process_dynamic_tapping_term(uint16_t keycode, keyrecord_t *record)`
|
||||
* [`bool process_terminal(uint16_t keycode, keyrecord_t *record)`](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/process_keycode/process_terminal.c#L264)
|
||||
* [Identify and process Quantum-specific keycodes](https://github.com/qmk/qmk_firmware/blob/e1203a222bb12ab9733916164a000ef3ac48da93/quantum/quantum.c#L291)
|
||||
|
||||
At any step during this chain of events a function (such as `process_record_kb()`) can `return false` to halt all further processing.
|
||||
|
||||
@@ -11,11 +11,12 @@ These LEDs are called "addressable" because instead of using a wire per color, e
|
||||
## Supported Driver Types
|
||||
|
||||
| | AVR | ARM |
|
||||
|----------|--------------------|--------------------|
|
||||
| -------- | ------------------ | ------------------ |
|
||||
| bit bang | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| I2C | :heavy_check_mark: | |
|
||||
| SPI | | :heavy_check_mark: |
|
||||
| PWM | | :heavy_check_mark: |
|
||||
| PIO | | :heavy_check_mark: |
|
||||
|
||||
## Driver configuration
|
||||
|
||||
@@ -33,11 +34,11 @@ The default setting is 280 µs, which should work for most cases, but this can b
|
||||
Some variants of the WS2812 may have their color components in a different physical or logical order. For example, the WS2812B-2020 has physically swapped red and green LEDs, which causes the wrong color to be displayed, because the default order of the bytes sent over the wire is defined as GRB.
|
||||
In this case, you can change the byte order by defining `WS2812_BYTE_ORDER` as one of the following values:
|
||||
|
||||
|Byte order |Known devices |
|
||||
|---------------------------------|-----------------------------|
|
||||
|`WS2812_BYTE_ORDER_GRB` (default)|Most WS2812's, SK6812, SK6805|
|
||||
|`WS2812_BYTE_ORDER_RGB` |WS2812B-2020 |
|
||||
|`WS2812_BYTE_ORDER_BGR` |TM1812 |
|
||||
| Byte order | Known devices |
|
||||
| --------------------------------- | ----------------------------- |
|
||||
| `WS2812_BYTE_ORDER_GRB` (default) | Most WS2812's, SK6812, SK6805 |
|
||||
| `WS2812_BYTE_ORDER_RGB` | WS2812B-2020 |
|
||||
| `WS2812_BYTE_ORDER_BGR` | TM1812 |
|
||||
|
||||
|
||||
### Bitbang
|
||||
@@ -54,13 +55,13 @@ WS2812_DRIVER = bitbang
|
||||
The WS2812 LED communication topology depends on a serialized timed window. Different versions of the addressable LEDs have differing requirements for the timing parameters, for instance, of the SK6812.
|
||||
You can tune these parameters through the definition of the following macros:
|
||||
|
||||
| Macro |Default | AVR | ARM |
|
||||
|---------------------|--------------------------------------------|--------------------|--------------------|
|
||||
|`WS2812_TIMING` |`1250` | :heavy_check_mark: | :heavy_check_mark: |
|
||||
|`WS2812_T0H` |`350` | :heavy_check_mark: | :heavy_check_mark: |
|
||||
|`WS2812_T0L` |`WS2812_TIMING - WS2812_T0H` | | :heavy_check_mark: |
|
||||
|`WS2812_T1H` |`900` | :heavy_check_mark: | :heavy_check_mark: |
|
||||
|`WS2812_T1L` |`WS2812_TIMING - WS2812_T1H` | | :heavy_check_mark: |
|
||||
| Macro | Default | AVR | ARM |
|
||||
| --------------- | ---------------------------- | ------------------ | ------------------ |
|
||||
| `WS2812_TIMING` | `1250` | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| `WS2812_T0H` | `350` | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| `WS2812_T0L` | `WS2812_TIMING - WS2812_T0H` | | :heavy_check_mark: |
|
||||
| `WS2812_T1H` | `900` | :heavy_check_mark: | :heavy_check_mark: |
|
||||
| `WS2812_T1L` | `WS2812_TIMING - WS2812_T1H` | | :heavy_check_mark: |
|
||||
|
||||
### I2C
|
||||
Targeting boards where WS2812 support is offloaded to a 2nd MCU. Currently the driver is limited to AVR given the known consumers are ps2avrGB/BMC. To configure it, add this to your rules.mk:
|
||||
@@ -107,16 +108,16 @@ To adjust the baudrate at which the SPI peripheral is configured, users will nee
|
||||
|
||||
Only divisors of 2, 4, 8, 16, 32, 64, 128 and 256 are supported by hardware.
|
||||
|
||||
|Define |Default|Description |
|
||||
|--------------------|-------|-------------------------------------|
|
||||
|`WS2812_SPI_DIVISOR`|`16` |SPI source clock peripheral divisor |
|
||||
| Define | Default | Description |
|
||||
| -------------------- | ------- | ----------------------------------- |
|
||||
| `WS2812_SPI_DIVISOR` | `16` | SPI source clock peripheral divisor |
|
||||
|
||||
#### Testing Notes
|
||||
|
||||
While not an exhaustive list, the following table provides the scenarios that have been partially validated:
|
||||
|
||||
| | SPI1 | SPI2 | SPI3 |
|
||||
|------|---------------------------------------------|-----------------------------------------|-----------------------|
|
||||
| ---- | ------------------------------------------- | --------------------------------------- | --------------------- |
|
||||
| f072 | ? | B15 :heavy_check_mark: (needs SCK: B13) | N/A |
|
||||
| f103 | A7 :heavy_check_mark: | B15 :heavy_check_mark: | N/A |
|
||||
| f303 | A7 :heavy_check_mark: B5 :heavy_check_mark: | B15 :heavy_check_mark: | B5 :heavy_check_mark: |
|
||||
@@ -150,15 +151,32 @@ You must also turn on the PWM feature in your halconf.h and mcuconf.h
|
||||
|
||||
While not an exhaustive list, the following table provides the scenarios that have been partially validated:
|
||||
|
||||
| | Status |
|
||||
|-|-|
|
||||
| f072 | ? |
|
||||
| f103 | :heavy_check_mark: |
|
||||
| f303 | :heavy_check_mark: |
|
||||
| | Status |
|
||||
| --------- | ------------------ |
|
||||
| f072 | ? |
|
||||
| f103 | :heavy_check_mark: |
|
||||
| f303 | :heavy_check_mark: |
|
||||
| f401/f411 | :heavy_check_mark: |
|
||||
|
||||
*Other supported ChibiOS boards and/or pins may function, it will be highly chip and configuration dependent.*
|
||||
|
||||
### PIO
|
||||
|
||||
Targeting Raspberry Pi RP2040 boards only where WS2812 support is offloaded to an dedicated PIO implementation. This offloads processing of the WS2812 protocol from the MCU to a dedicated PIO program using DMA transfers.
|
||||
|
||||
To configure it, add this to your rules.mk:
|
||||
|
||||
```make
|
||||
WS2812_DRIVER = vendor
|
||||
```
|
||||
|
||||
Configure the hardware via your config.h:
|
||||
```c
|
||||
#define WS2812_PIO_USE_PIO1 // Force the usage of PIO1 peripheral, by default the WS2812 implementation uses the PIO0 peripheral
|
||||
```
|
||||
|
||||
The WS2812 PIO programm uses 1 state machine, 4 instructions and does not use any interrupt handlers.
|
||||
|
||||
### Push Pull and Open Drain Configuration
|
||||
The default configuration is a push pull on the defined pin.
|
||||
This can be configured for bitbang, PWM and SPI.
|
||||
|
||||
@@ -91,7 +91,6 @@
|
||||
* [换手](zh-cn/feature_swap_hands.md)
|
||||
* [一键多用](zh-cn/feature_tap_dance.md)
|
||||
* [点按配置](zh-cn/tap_hold.md)
|
||||
* [终端](zh-cn/feature_terminal.md)
|
||||
* [Unicode](zh-cn/feature_unicode.md)
|
||||
* [用户空间](zh-cn/feature_userspace.md)
|
||||
* [WPM计算](zh-cn/feature_wpm.md)
|
||||
|
||||
@@ -240,7 +240,7 @@ void suspend_wakeup_init_user(void) {
|
||||
|
||||
```c
|
||||
layer_state_t layer_state_set_user(layer_state_t state) {
|
||||
switch (biton32(state)) {
|
||||
switch (get_highest_layer(state)) {
|
||||
case _RAISE:
|
||||
rgblight_setrgb (0x00, 0x00, 0xFF);
|
||||
break;
|
||||
@@ -267,7 +267,7 @@ layer_state_t layer_state_set_user(layer_state_t state) {
|
||||
|
||||
### `layer_state_set_*` 函数文档
|
||||
|
||||
* 键盘/各子版本:`uint32_t layer_state_set_kb(uint32_t state)`
|
||||
* 键盘/各子版本:`layer_state_t layer_state_set_kb(layer_state_t state)`
|
||||
* 布局: `layer_state_t layer_state_set_user(layer_state_t state)`
|
||||
|
||||
|
||||
@@ -325,7 +325,7 @@ void keyboard_post_init_user(void) {
|
||||
|
||||
```c
|
||||
layer_state_t layer_state_set_user(layer_state_t state) {
|
||||
switch (biton32(state)) {
|
||||
switch (get_highest_layer(state)) {
|
||||
case _RAISE:
|
||||
if (user_config.rgb_layer_change) { rgblight_sethsv_noeeprom_magenta(); rgblight_mode_noeeprom(1); }
|
||||
break;
|
||||
@@ -474,4 +474,3 @@ cancel_deferred_exec(my_token);
|
||||
```c
|
||||
#define MAX_DEFERRED_EXECUTORS 16
|
||||
```
|
||||
|
||||
|
||||
@@ -54,6 +54,11 @@
|
||||
# define EXTERNAL_EEPROM_PAGE_SIZE 32
|
||||
# define EXTERNAL_EEPROM_ADDRESS_SIZE 2
|
||||
# define EXTERNAL_EEPROM_WRITE_TIME 5
|
||||
#elif defined(EEPROM_I2C_24LC32A)
|
||||
# define EXTERNAL_EEPROM_BYTE_COUNT 4096
|
||||
# define EXTERNAL_EEPROM_PAGE_SIZE 32
|
||||
# define EXTERNAL_EEPROM_ADDRESS_SIZE 2
|
||||
# define EXTERNAL_EEPROM_WRITE_TIME 5
|
||||
#elif defined(EEPROM_I2C_MB85RC256V)
|
||||
# define EXTERNAL_EEPROM_BYTE_COUNT 32768
|
||||
# define EXTERNAL_EEPROM_PAGE_SIZE 128
|
||||
|
||||
@@ -58,14 +58,20 @@ static bool spi_eeprom_start(void) {
|
||||
|
||||
static spi_status_t spi_eeprom_wait_while_busy(int timeout) {
|
||||
uint32_t deadline = timer_read32() + timeout;
|
||||
spi_status_t response;
|
||||
do {
|
||||
spi_status_t response = SR_WIP;
|
||||
while (response & SR_WIP) {
|
||||
if (!spi_eeprom_start()) {
|
||||
return SPI_STATUS_ERROR;
|
||||
}
|
||||
|
||||
spi_write(CMD_RDSR);
|
||||
response = spi_read();
|
||||
spi_stop();
|
||||
|
||||
if (timer_read32() >= deadline) {
|
||||
return SPI_STATUS_TIMEOUT;
|
||||
}
|
||||
} while (response & SR_WIP);
|
||||
}
|
||||
return SPI_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -105,27 +111,21 @@ void eeprom_driver_erase(void) {
|
||||
void eeprom_read_block(void *buf, const void *addr, size_t len) {
|
||||
//-------------------------------------------------
|
||||
// Wait for the write-in-progress bit to be cleared
|
||||
bool res = spi_eeprom_start();
|
||||
if (!res) {
|
||||
dprint("failed to start SPI for WIP check\n");
|
||||
memset(buf, 0, len);
|
||||
return;
|
||||
}
|
||||
|
||||
spi_status_t response = spi_eeprom_wait_while_busy(EXTERNAL_EEPROM_SPI_TIMEOUT);
|
||||
spi_stop();
|
||||
if (response == SPI_STATUS_TIMEOUT) {
|
||||
dprint("SPI timeout for WIP check\n");
|
||||
if (response != SPI_STATUS_SUCCESS) {
|
||||
spi_stop();
|
||||
memset(buf, 0, len);
|
||||
dprint("SPI timeout for WIP check\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// Perform read
|
||||
res = spi_eeprom_start();
|
||||
bool res = spi_eeprom_start();
|
||||
if (!res) {
|
||||
dprint("failed to start SPI for read\n");
|
||||
spi_stop();
|
||||
memset(buf, 0, len);
|
||||
dprint("failed to start SPI for read\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -158,15 +158,9 @@ void eeprom_write_block(const void *buf, void *addr, size_t len) {
|
||||
|
||||
//-------------------------------------------------
|
||||
// Wait for the write-in-progress bit to be cleared
|
||||
res = spi_eeprom_start();
|
||||
if (!res) {
|
||||
dprint("failed to start SPI for WIP check\n");
|
||||
return;
|
||||
}
|
||||
|
||||
spi_status_t response = spi_eeprom_wait_while_busy(EXTERNAL_EEPROM_SPI_TIMEOUT);
|
||||
spi_stop();
|
||||
if (response == SPI_STATUS_TIMEOUT) {
|
||||
if (response != SPI_STATUS_SUCCESS) {
|
||||
spi_stop();
|
||||
dprint("SPI timeout for WIP check\n");
|
||||
return;
|
||||
}
|
||||
@@ -175,6 +169,7 @@ void eeprom_write_block(const void *buf, void *addr, size_t len) {
|
||||
// Enable writes
|
||||
res = spi_eeprom_start();
|
||||
if (!res) {
|
||||
spi_stop();
|
||||
dprint("failed to start SPI for write-enable\n");
|
||||
return;
|
||||
}
|
||||
@@ -186,6 +181,7 @@ void eeprom_write_block(const void *buf, void *addr, size_t len) {
|
||||
// Perform the write
|
||||
res = spi_eeprom_start();
|
||||
if (!res) {
|
||||
spi_stop();
|
||||
dprint("failed to start SPI for write\n");
|
||||
return;
|
||||
}
|
||||
|
||||
23
drivers/eeprom/eeprom_wear_leveling.c
Normal file
23
drivers/eeprom/eeprom_wear_leveling.c
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright 2022 Nick Brassel (@tzarc)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "eeprom_driver.h"
|
||||
#include "wear_leveling.h"
|
||||
|
||||
void eeprom_driver_init(void) {
|
||||
wear_leveling_init();
|
||||
}
|
||||
|
||||
void eeprom_driver_erase(void) {
|
||||
wear_leveling_erase();
|
||||
}
|
||||
|
||||
void eeprom_read_block(void *buf, const void *addr, size_t len) {
|
||||
wear_leveling_read((uint32_t)addr, buf, len);
|
||||
}
|
||||
|
||||
void eeprom_write_block(const void *buf, void *addr, size_t len) {
|
||||
wear_leveling_write((uint32_t)addr, buf, len);
|
||||
}
|
||||
166
drivers/gpio/pca9505.c
Normal file
166
drivers/gpio/pca9505.c
Normal file
@@ -0,0 +1,166 @@
|
||||
// Copyright 2022 nirim000
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "i2c_master.h"
|
||||
#include "pca9505.h"
|
||||
|
||||
#include "debug.h"
|
||||
|
||||
#define SLAVE_TO_ADDR(n) (n << 1)
|
||||
#define TIMEOUT 100
|
||||
|
||||
enum {
|
||||
CMD_INPUT_0 = 0,
|
||||
CMD_INPUT_1,
|
||||
CMD_INPUT_2,
|
||||
CMD_INPUT_3,
|
||||
CMD_INPUT_4,
|
||||
CMD_OUTPUT_0 = 8,
|
||||
CMD_OUTPUT_1,
|
||||
CMD_OUTPUT_2,
|
||||
CMD_OUTPUT_3,
|
||||
CMD_OUTPUT_4,
|
||||
CMD_INVERSION_0 = 16,
|
||||
CMD_INVERSION_1,
|
||||
CMD_INVERSION_2,
|
||||
CMD_INVERSION_3,
|
||||
CMD_INVERSION_4,
|
||||
CMD_CONFIG_0 = 24,
|
||||
CMD_CONFIG_1,
|
||||
CMD_CONFIG_2,
|
||||
CMD_CONFIG_3,
|
||||
CMD_CONFIG_4,
|
||||
};
|
||||
|
||||
void pca9505_init(uint8_t slave_addr) {
|
||||
static uint8_t s_init = 0;
|
||||
if (!s_init) {
|
||||
i2c_init();
|
||||
|
||||
s_init = 1;
|
||||
}
|
||||
|
||||
// TODO: could check device connected
|
||||
// i2c_start(SLAVE_TO_ADDR(slave) | I2C_WRITE);
|
||||
// i2c_stop();
|
||||
}
|
||||
|
||||
bool pca9505_set_config(uint8_t slave_addr, pca9505_port_t port, uint8_t conf) {
|
||||
uint8_t addr = SLAVE_TO_ADDR(slave_addr);
|
||||
uint8_t cmd = 0;
|
||||
switch (port) {
|
||||
case 0:
|
||||
cmd = CMD_CONFIG_0;
|
||||
break;
|
||||
case 1:
|
||||
cmd = CMD_CONFIG_1;
|
||||
break;
|
||||
case 2:
|
||||
cmd = CMD_CONFIG_2;
|
||||
break;
|
||||
case 3:
|
||||
cmd = CMD_CONFIG_3;
|
||||
break;
|
||||
case 4:
|
||||
cmd = CMD_CONFIG_4;
|
||||
break;
|
||||
}
|
||||
|
||||
i2c_status_t ret = i2c_writeReg(addr, cmd, &conf, sizeof(conf), TIMEOUT);
|
||||
if (ret != I2C_STATUS_SUCCESS) {
|
||||
print("pca9505_set_config::FAILED\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pca9505_set_polarity(uint8_t slave_addr, pca9505_port_t port, uint8_t conf) {
|
||||
uint8_t addr = SLAVE_TO_ADDR(slave_addr);
|
||||
uint8_t cmd = 0;
|
||||
switch (port) {
|
||||
case 0:
|
||||
cmd = CMD_INVERSION_0;
|
||||
break;
|
||||
case 1:
|
||||
cmd = CMD_INVERSION_1;
|
||||
break;
|
||||
case 2:
|
||||
cmd = CMD_INVERSION_2;
|
||||
break;
|
||||
case 3:
|
||||
cmd = CMD_INVERSION_3;
|
||||
break;
|
||||
case 4:
|
||||
cmd = CMD_INVERSION_4;
|
||||
break;
|
||||
}
|
||||
|
||||
i2c_status_t ret = i2c_writeReg(addr, cmd, &conf, sizeof(conf), TIMEOUT);
|
||||
if (ret != I2C_STATUS_SUCCESS) {
|
||||
print("pca9505_set_polarity::FAILED\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pca9505_set_output(uint8_t slave_addr, pca9505_port_t port, uint8_t conf) {
|
||||
uint8_t addr = SLAVE_TO_ADDR(slave_addr);
|
||||
uint8_t cmd = 0;
|
||||
switch (port) {
|
||||
case 0:
|
||||
cmd = CMD_OUTPUT_0;
|
||||
break;
|
||||
case 1:
|
||||
cmd = CMD_OUTPUT_1;
|
||||
break;
|
||||
case 2:
|
||||
cmd = CMD_OUTPUT_2;
|
||||
break;
|
||||
case 3:
|
||||
cmd = CMD_OUTPUT_3;
|
||||
break;
|
||||
case 4:
|
||||
cmd = CMD_OUTPUT_4;
|
||||
break;
|
||||
}
|
||||
|
||||
i2c_status_t ret = i2c_writeReg(addr, cmd, &conf, sizeof(conf), TIMEOUT);
|
||||
if (ret != I2C_STATUS_SUCCESS) {
|
||||
print("pca9505_set_output::FAILED\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool pca9505_readPins(uint8_t slave_addr, pca9505_port_t port, uint8_t* out) {
|
||||
uint8_t addr = SLAVE_TO_ADDR(slave_addr);
|
||||
uint8_t cmd = 0;
|
||||
switch (port) {
|
||||
case 0:
|
||||
cmd = CMD_INPUT_0;
|
||||
break;
|
||||
case 1:
|
||||
cmd = CMD_INPUT_1;
|
||||
break;
|
||||
case 2:
|
||||
cmd = CMD_INPUT_2;
|
||||
break;
|
||||
case 3:
|
||||
cmd = CMD_INPUT_3;
|
||||
break;
|
||||
case 4:
|
||||
cmd = CMD_INPUT_4;
|
||||
break;
|
||||
}
|
||||
|
||||
i2c_status_t ret = i2c_readReg(addr, cmd, out, sizeof(uint8_t), TIMEOUT);
|
||||
if (ret != I2C_STATUS_SUCCESS) {
|
||||
print("pca9505_readPins::FAILED\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
67
drivers/gpio/pca9505.h
Normal file
67
drivers/gpio/pca9505.h
Normal file
@@ -0,0 +1,67 @@
|
||||
// Copyright 2022 nirim000
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* Port ID
|
||||
*/
|
||||
typedef enum {
|
||||
PCA9505_PORT0,
|
||||
PCA9505_PORT1,
|
||||
PCA9505_PORT2,
|
||||
PCA9505_PORT3,
|
||||
PCA9505_PORT4,
|
||||
} pca9505_port_t;
|
||||
|
||||
/**
|
||||
* Helpers for set_config
|
||||
*/
|
||||
enum {
|
||||
ALL_NORMAL = 0,
|
||||
ALL_INVERTED = 0xFF,
|
||||
};
|
||||
|
||||
/**
|
||||
* Helpers for set_config
|
||||
*/
|
||||
enum {
|
||||
ALL_OUTPUT = 0,
|
||||
ALL_INPUT = 0xFF,
|
||||
};
|
||||
|
||||
/**
|
||||
* Helpers for set_output
|
||||
*/
|
||||
enum {
|
||||
ALL_LOW = 0,
|
||||
ALL_HIGH = 0xFF,
|
||||
};
|
||||
|
||||
/**
|
||||
* Init expander and any other dependent drivers
|
||||
*/
|
||||
void pca9505_init(uint8_t slave_addr);
|
||||
|
||||
/**
|
||||
* Configure input/output to a given port
|
||||
*/
|
||||
bool pca9505_set_config(uint8_t slave_addr, pca9505_port_t port, uint8_t conf);
|
||||
|
||||
/**
|
||||
* Configure polarity to a given port
|
||||
*/
|
||||
bool pca9505_set_polarity(uint8_t slave_addr, pca9505_port_t port, uint8_t conf);
|
||||
|
||||
/**
|
||||
* Write high/low to a given port
|
||||
*/
|
||||
bool pca9505_set_output(uint8_t slave_addr, pca9505_port_t port, uint8_t conf);
|
||||
|
||||
/**
|
||||
* Read state of a given port
|
||||
*/
|
||||
bool pca9505_readPins(uint8_t slave_addr, pca9505_port_t port, uint8_t* ret);
|
||||
@@ -53,6 +53,10 @@
|
||||
# define AW_GLOBAL_CURRENT_MAX 150
|
||||
#endif
|
||||
|
||||
#ifndef AW_SPI_MODE
|
||||
# define AW_SPI_MODE 0
|
||||
#endif
|
||||
|
||||
#ifndef AW_SPI_DIVISOR
|
||||
# define AW_SPI_DIVISOR 4
|
||||
#endif
|
||||
@@ -63,7 +67,7 @@ bool g_pwm_buffer_update_required[DRIVER_COUNT] = {false};
|
||||
bool AW20216_write(pin_t cs_pin, uint8_t page, uint8_t reg, uint8_t* data, uint8_t len) {
|
||||
static uint8_t s_spi_transfer_buffer[2] = {0};
|
||||
|
||||
if (!spi_start(cs_pin, false, 3, AW_SPI_DIVISOR)) {
|
||||
if (!spi_start(cs_pin, false, AW_SPI_MODE, AW_SPI_DIVISOR)) {
|
||||
spi_stop();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -70,6 +70,10 @@
|
||||
# define ISSI_CSPULLUP PUR_0R
|
||||
#endif
|
||||
|
||||
#ifndef ISSI_GLOBALCURRENT
|
||||
# define ISSI_GLOBALCURRENT 0xFF
|
||||
#endif
|
||||
|
||||
// Transfer buffer for TWITransmitData()
|
||||
uint8_t g_twi_transfer_buffer[20];
|
||||
|
||||
@@ -182,7 +186,7 @@ void IS31FL3733_init(uint8_t addr, uint8_t sync) {
|
||||
// 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);
|
||||
IS31FL3733_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT);
|
||||
// Disable software shutdown.
|
||||
IS31FL3733_write_register(addr, ISSI_REG_CONFIGURATION, ((sync & 0b11) << 6) | ((ISSI_PWM_FREQUENCY & 0b111) << 3) | 0x01);
|
||||
|
||||
|
||||
@@ -69,6 +69,10 @@
|
||||
# define ISSI_CSPULLUP PUR_0R
|
||||
#endif
|
||||
|
||||
#ifndef ISSI_GLOBALCURRENT
|
||||
# define ISSI_GLOBALCURRENT 0xFF
|
||||
#endif
|
||||
|
||||
// Transfer buffer for TWITransmitData()
|
||||
uint8_t g_twi_transfer_buffer[20];
|
||||
|
||||
@@ -172,7 +176,7 @@ void IS31FL3733_init(uint8_t addr, uint8_t sync) {
|
||||
// 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);
|
||||
IS31FL3733_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT);
|
||||
// Disable software shutdown.
|
||||
IS31FL3733_write_register(addr, ISSI_REG_CONFIGURATION, ((sync & 0b11) << 6) | ((ISSI_PWM_FREQUENCY & 0b111) << 3) | 0x01);
|
||||
|
||||
|
||||
@@ -63,6 +63,10 @@
|
||||
# define ISSI_CSPULLUP PUR_0R
|
||||
#endif
|
||||
|
||||
#ifndef ISSI_GLOBALCURRENT
|
||||
# define ISSI_GLOBALCURRENT 0xFF
|
||||
#endif
|
||||
|
||||
// Transfer buffer for TWITransmitData()
|
||||
uint8_t g_twi_transfer_buffer[20];
|
||||
|
||||
@@ -154,7 +158,7 @@ void IS31FL3736_init(uint8_t addr) {
|
||||
// Set de-ghost pull-down resistors (CSx)
|
||||
IS31FL3736_write_register(addr, ISSI_REG_CSPULLUP, ISSI_CSPULLUP);
|
||||
// Set global current to maximum.
|
||||
IS31FL3736_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF);
|
||||
IS31FL3736_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT);
|
||||
// Disable software shutdown.
|
||||
IS31FL3736_write_register(addr, ISSI_REG_CONFIGURATION, 0x01);
|
||||
|
||||
|
||||
@@ -69,6 +69,10 @@
|
||||
# define ISSI_CSPULLUP PUR_0R
|
||||
#endif
|
||||
|
||||
#ifndef ISSI_GLOBALCURRENT
|
||||
# define ISSI_GLOBALCURRENT 0xFF
|
||||
#endif
|
||||
|
||||
// Transfer buffer for TWITransmitData()
|
||||
uint8_t g_twi_transfer_buffer[20];
|
||||
|
||||
@@ -161,7 +165,7 @@ void IS31FL3737_init(uint8_t addr) {
|
||||
// Set de-ghost pull-down resistors (CSx)
|
||||
IS31FL3737_write_register(addr, ISSI_REG_CSPULLUP, ISSI_CSPULLUP);
|
||||
// Set global current to maximum.
|
||||
IS31FL3737_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF);
|
||||
IS31FL3737_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT);
|
||||
// Disable software shutdown.
|
||||
IS31FL3737_write_register(addr, ISSI_REG_CONFIGURATION, ((ISSI_PWM_FREQUENCY & 0b111) << 3) | 0x01);
|
||||
|
||||
|
||||
@@ -69,6 +69,10 @@
|
||||
# define ISSI_CSPULLUP PUR_32KR
|
||||
#endif
|
||||
|
||||
#ifndef ISSI_GLOBALCURRENT
|
||||
# define ISSI_GLOBALCURRENT 0xFF
|
||||
#endif
|
||||
|
||||
#define ISSI_MAX_LEDS 351
|
||||
|
||||
// Transfer buffer for TWITransmitData()
|
||||
@@ -163,7 +167,7 @@ void IS31FL3741_init(uint8_t addr) {
|
||||
IS31FL3741_write_register(addr, ISSI_REG_CONFIGURATION, 0x01);
|
||||
|
||||
// Set Golbal Current Control Register
|
||||
IS31FL3741_write_register(addr, ISSI_REG_GLOBALCURRENT, 0xFF);
|
||||
IS31FL3741_write_register(addr, ISSI_REG_GLOBALCURRENT, ISSI_GLOBALCURRENT);
|
||||
// Set Pull up & Down for SWx CSy
|
||||
IS31FL3741_write_register(addr, ISSI_REG_PULLDOWNUP, ((ISSI_CSPULLUP << 4) | ISSI_SWPULLUP));
|
||||
|
||||
|
||||
@@ -102,12 +102,11 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t gc9a01_driver_vtable = {
|
||||
.flush = qp_tft_panel_flush,
|
||||
.pixdata = qp_tft_panel_pixdata,
|
||||
.viewport = qp_tft_panel_viewport,
|
||||
.palette_convert = qp_tft_panel_palette_convert,
|
||||
.append_pixels = qp_tft_panel_append_pixels,
|
||||
.palette_convert = qp_tft_panel_palette_convert_rgb565_swapped,
|
||||
.append_pixels = qp_tft_panel_append_pixels_rgb565,
|
||||
},
|
||||
.rgb888_to_native16bit = qp_rgb888_to_rgb565_swapped,
|
||||
.num_window_bytes = 2,
|
||||
.swap_window_coords = false,
|
||||
.num_window_bytes = 2,
|
||||
.swap_window_coords = false,
|
||||
.opcodes =
|
||||
{
|
||||
.display_on = GC9A01_CMD_DISPLAY_ON,
|
||||
|
||||
@@ -67,12 +67,11 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t ili9163_driver_vtable =
|
||||
.flush = qp_tft_panel_flush,
|
||||
.pixdata = qp_tft_panel_pixdata,
|
||||
.viewport = qp_tft_panel_viewport,
|
||||
.palette_convert = qp_tft_panel_palette_convert,
|
||||
.append_pixels = qp_tft_panel_append_pixels,
|
||||
.palette_convert = qp_tft_panel_palette_convert_rgb565_swapped,
|
||||
.append_pixels = qp_tft_panel_append_pixels_rgb565,
|
||||
},
|
||||
.rgb888_to_native16bit = qp_rgb888_to_rgb565_swapped,
|
||||
.num_window_bytes = 2,
|
||||
.swap_window_coords = false,
|
||||
.num_window_bytes = 2,
|
||||
.swap_window_coords = false,
|
||||
.opcodes =
|
||||
{
|
||||
.display_on = ILI9XXX_CMD_DISPLAY_ON,
|
||||
|
||||
@@ -74,12 +74,11 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t ili9341_driver_vtable =
|
||||
.flush = qp_tft_panel_flush,
|
||||
.pixdata = qp_tft_panel_pixdata,
|
||||
.viewport = qp_tft_panel_viewport,
|
||||
.palette_convert = qp_tft_panel_palette_convert,
|
||||
.append_pixels = qp_tft_panel_append_pixels,
|
||||
.palette_convert = qp_tft_panel_palette_convert_rgb565_swapped,
|
||||
.append_pixels = qp_tft_panel_append_pixels_rgb565,
|
||||
},
|
||||
.rgb888_to_native16bit = qp_rgb888_to_rgb565_swapped,
|
||||
.num_window_bytes = 2,
|
||||
.swap_window_coords = false,
|
||||
.num_window_bytes = 2,
|
||||
.swap_window_coords = false,
|
||||
.opcodes =
|
||||
{
|
||||
.display_on = ILI9XXX_CMD_DISPLAY_ON,
|
||||
|
||||
120
drivers/painter/ili9xxx/qp_ili9488.c
Normal file
120
drivers/painter/ili9xxx/qp_ili9488.c
Normal file
@@ -0,0 +1,120 @@
|
||||
// Copyright 2021 Nick Brassel (@tzarc)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "qp_internal.h"
|
||||
#include "qp_comms.h"
|
||||
#include "qp_ili9488.h"
|
||||
#include "qp_ili9xxx_opcodes.h"
|
||||
#include "qp_tft_panel.h"
|
||||
|
||||
#ifdef QUANTUM_PAINTER_ILI9488_SPI_ENABLE
|
||||
# include <qp_comms_spi.h>
|
||||
#endif // QUANTUM_PAINTER_ILI9488_SPI_ENABLE
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Common
|
||||
|
||||
// Driver storage
|
||||
tft_panel_dc_reset_painter_device_t ili9488_drivers[ILI9488_NUM_DEVICES] = {0};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Initialization
|
||||
|
||||
bool qp_ili9488_init(painter_device_t device, painter_rotation_t rotation) {
|
||||
// clang-format off
|
||||
const uint8_t ili9488_init_sequence[] = {
|
||||
// Command, Delay, N, Data[N]
|
||||
ILI9XXX_CMD_RESET, 120, 0,
|
||||
ILI9XXX_SET_PGAMMA, 0, 15, 0x00, 0x03, 0x09, 0x08, 0x16, 0x0A, 0x3F, 0x78, 0x4C, 0x09, 0x0A, 0x08, 0x16, 0x1A, 0x0F,
|
||||
ILI9XXX_SET_NGAMMA, 0, 15, 0x00, 0x16, 0x19, 0x03, 0x0F, 0x05, 0x32, 0x45, 0x46, 0x04, 0x0E, 0x0D, 0x35, 0x37, 0x0F,
|
||||
ILI9XXX_SET_POWER_CTL_1, 0, 2, 0x17, 0x15,
|
||||
ILI9XXX_SET_POWER_CTL_2, 0, 1, 0x41,
|
||||
ILI9XXX_SET_VCOM_CTL_1, 0, 3, 0x00, 0x12, 0x80,
|
||||
ILI9XXX_SET_PIX_FMT, 0, 1, 0x66,
|
||||
ILI9XXX_SET_RGB_IF_SIG_CTL, 0, 1, 0x80,
|
||||
ILI9XXX_SET_FRAME_CTL_NORMAL, 0, 1, 0xA0,
|
||||
ILI9XXX_SET_INVERSION_CTL, 0, 1, 0x02,
|
||||
ILI9XXX_SET_FUNCTION_CTL, 0, 2, 0x02, 0x02,
|
||||
ILI9XXX_SET_IMAGE_FUNCTION, 0, 1, 0x00,
|
||||
ILI9XXX_SET_PUMP_RATIO_CTL, 0, 4, 0xA9, 0x51, 0x2C, 0x82,
|
||||
ILI9XXX_CMD_SLEEP_OFF, 5, 0,
|
||||
ILI9XXX_CMD_DISPLAY_ON, 20, 0
|
||||
};
|
||||
// clang-format on
|
||||
qp_comms_bulk_command_sequence(device, ili9488_init_sequence, sizeof(ili9488_init_sequence));
|
||||
|
||||
// Configure the rotation (i.e. the ordering and direction of memory writes in GRAM)
|
||||
const uint8_t madctl[] = {
|
||||
[QP_ROTATION_0] = ILI9XXX_MADCTL_BGR | ILI9XXX_MADCTL_MY,
|
||||
[QP_ROTATION_90] = ILI9XXX_MADCTL_BGR | ILI9XXX_MADCTL_MX | ILI9XXX_MADCTL_MV | ILI9XXX_MADCTL_MY,
|
||||
[QP_ROTATION_180] = ILI9XXX_MADCTL_BGR | ILI9XXX_MADCTL_MX,
|
||||
[QP_ROTATION_270] = ILI9XXX_MADCTL_BGR | ILI9XXX_MADCTL_MV,
|
||||
};
|
||||
qp_comms_command_databyte(device, ILI9XXX_SET_MEM_ACS_CTL, madctl[rotation]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Driver vtable
|
||||
|
||||
const struct tft_panel_dc_reset_painter_driver_vtable_t ili9488_driver_vtable = {
|
||||
.base =
|
||||
{
|
||||
.init = qp_ili9488_init,
|
||||
.power = qp_tft_panel_power,
|
||||
.clear = qp_tft_panel_clear,
|
||||
.flush = qp_tft_panel_flush,
|
||||
.pixdata = qp_tft_panel_pixdata,
|
||||
.viewport = qp_tft_panel_viewport,
|
||||
.palette_convert = qp_tft_panel_palette_convert_rgb888,
|
||||
.append_pixels = qp_tft_panel_append_pixels_rgb888,
|
||||
},
|
||||
.num_window_bytes = 2,
|
||||
.swap_window_coords = false,
|
||||
.opcodes =
|
||||
{
|
||||
.display_on = ILI9XXX_CMD_DISPLAY_ON,
|
||||
.display_off = ILI9XXX_CMD_DISPLAY_OFF,
|
||||
.set_column_address = ILI9XXX_SET_COL_ADDR,
|
||||
.set_row_address = ILI9XXX_SET_PAGE_ADDR,
|
||||
.enable_writes = ILI9XXX_SET_MEM,
|
||||
},
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// SPI
|
||||
|
||||
#ifdef QUANTUM_PAINTER_ILI9488_SPI_ENABLE
|
||||
|
||||
// Factory function for creating a handle to the ILI9488 device
|
||||
painter_device_t qp_ili9488_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode) {
|
||||
for (uint32_t i = 0; i < ILI9488_NUM_DEVICES; ++i) {
|
||||
tft_panel_dc_reset_painter_device_t *driver = &ili9488_drivers[i];
|
||||
if (!driver->base.driver_vtable) {
|
||||
driver->base.driver_vtable = (const struct painter_driver_vtable_t *)&ili9488_driver_vtable;
|
||||
driver->base.comms_vtable = (const struct painter_comms_vtable_t *)&spi_comms_with_dc_vtable;
|
||||
driver->base.native_bits_per_pixel = 24; // RGB888
|
||||
driver->base.panel_width = panel_width;
|
||||
driver->base.panel_height = panel_height;
|
||||
driver->base.rotation = QP_ROTATION_0;
|
||||
driver->base.offset_x = 0;
|
||||
driver->base.offset_y = 0;
|
||||
|
||||
// SPI and other pin configuration
|
||||
driver->base.comms_config = &driver->spi_dc_reset_config;
|
||||
driver->spi_dc_reset_config.spi_config.chip_select_pin = chip_select_pin;
|
||||
driver->spi_dc_reset_config.spi_config.divisor = spi_divisor;
|
||||
driver->spi_dc_reset_config.spi_config.lsb_first = false;
|
||||
driver->spi_dc_reset_config.spi_config.mode = spi_mode;
|
||||
driver->spi_dc_reset_config.dc_pin = dc_pin;
|
||||
driver->spi_dc_reset_config.reset_pin = reset_pin;
|
||||
return (painter_device_t)driver;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif // QUANTUM_PAINTER_ILI9488_SPI_ENABLE
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
37
drivers/painter/ili9xxx/qp_ili9488.h
Normal file
37
drivers/painter/ili9xxx/qp_ili9488.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright 2021 Nick Brassel (@tzarc)
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "gpio.h"
|
||||
#include "qp_internal.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Quantum Painter ILI9488 configurables (add to your keyboard's config.h)
|
||||
|
||||
#ifndef ILI9488_NUM_DEVICES
|
||||
/**
|
||||
* @def This controls the maximum number of ILI9488 devices that Quantum Painter can communicate with at any one time.
|
||||
* Increasing this number allows for multiple displays to be used.
|
||||
*/
|
||||
# define ILI9488_NUM_DEVICES 1
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Quantum Painter ILI9488 device factories
|
||||
|
||||
#ifdef QUANTUM_PAINTER_ILI9488_SPI_ENABLE
|
||||
/**
|
||||
* Factory method for an ILI9488 SPI LCD device.
|
||||
*
|
||||
* @param panel_width[in] the width of the display panel
|
||||
* @param panel_height[in] the height of the display panel
|
||||
* @param chip_select_pin[in] the GPIO pin used for SPI chip select
|
||||
* @param dc_pin[in] the GPIO pin used for D/C control
|
||||
* @param reset_pin[in] the GPIO pin used for RST
|
||||
* @param spi_divisor[in] the SPI divisor to use when communicating with the display
|
||||
* @param spi_mode[in] the SPI mode to use when communicating with the display
|
||||
* @return the device handle used with all drawing routines in Quantum Painter
|
||||
*/
|
||||
painter_device_t qp_ili9488_make_spi_device(uint16_t panel_width, uint16_t panel_height, pin_t chip_select_pin, pin_t dc_pin, pin_t reset_pin, uint16_t spi_divisor, int spi_mode);
|
||||
#endif // QUANTUM_PAINTER_ILI9488_SPI_ENABLE
|
||||
@@ -85,6 +85,7 @@
|
||||
#define ILI9XXX_SET_NGAMMA 0xE1 // Set negative gamma
|
||||
#define ILI9XXX_SET_DGAMMA_CTL_1 0xE2 // Set digital gamma ctl 1
|
||||
#define ILI9XXX_SET_DGAMMA_CTL_2 0xE3 // Set digital gamma ctl 2
|
||||
#define ILI9XXX_SET_IMAGE_FUNCTION 0xE9 // Set image function
|
||||
#define ILI9XXX_ENABLE_3_GAMMA 0xF2 // Enable 3 gamma
|
||||
#define ILI9XXX_SET_IF_CTL 0xF6 // Set interface control
|
||||
#define ILI9XXX_SET_PUMP_RATIO_CTL 0xF7 // Set pump ratio control
|
||||
|
||||
@@ -71,12 +71,11 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t ssd1351_driver_vtable =
|
||||
.flush = qp_tft_panel_flush,
|
||||
.pixdata = qp_tft_panel_pixdata,
|
||||
.viewport = qp_tft_panel_viewport,
|
||||
.palette_convert = qp_tft_panel_palette_convert,
|
||||
.append_pixels = qp_tft_panel_append_pixels,
|
||||
.palette_convert = qp_tft_panel_palette_convert_rgb565_swapped,
|
||||
.append_pixels = qp_tft_panel_append_pixels_rgb565,
|
||||
},
|
||||
.rgb888_to_native16bit = qp_rgb888_to_rgb565_swapped,
|
||||
.num_window_bytes = 1,
|
||||
.swap_window_coords = true,
|
||||
.num_window_bytes = 1,
|
||||
.swap_window_coords = true,
|
||||
.opcodes =
|
||||
{
|
||||
.display_on = SSD1351_DISPLAYON,
|
||||
|
||||
@@ -90,12 +90,11 @@ const struct tft_panel_dc_reset_painter_driver_vtable_t st7789_driver_vtable = {
|
||||
.flush = qp_tft_panel_flush,
|
||||
.pixdata = qp_tft_panel_pixdata,
|
||||
.viewport = qp_tft_panel_viewport,
|
||||
.palette_convert = qp_tft_panel_palette_convert,
|
||||
.append_pixels = qp_tft_panel_append_pixels,
|
||||
.palette_convert = qp_tft_panel_palette_convert_rgb565_swapped,
|
||||
.append_pixels = qp_tft_panel_append_pixels_rgb565,
|
||||
},
|
||||
.rgb888_to_native16bit = qp_rgb888_to_rgb565_swapped,
|
||||
.num_window_bytes = 2,
|
||||
.swap_window_coords = false,
|
||||
.num_window_bytes = 2,
|
||||
.swap_window_coords = false,
|
||||
.opcodes =
|
||||
{
|
||||
.display_on = ST77XX_CMD_DISPLAY_ON,
|
||||
|
||||
@@ -9,29 +9,6 @@
|
||||
|
||||
#define BYTE_SWAP(x) (((((uint16_t)(x)) >> 8) & 0x00FF) | ((((uint16_t)(x)) << 8) & 0xFF00))
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Native pixel format conversion
|
||||
|
||||
uint16_t qp_rgb888_to_rgb565(uint8_t r, uint8_t g, uint8_t b) {
|
||||
uint16_t rgb565 = (((uint16_t)r) >> 3) << 11 | (((uint16_t)g) >> 2) << 5 | (((uint16_t)b) >> 3);
|
||||
return rgb565;
|
||||
}
|
||||
|
||||
uint16_t qp_rgb888_to_rgb565_swapped(uint8_t r, uint8_t g, uint8_t b) {
|
||||
uint16_t rgb565 = (((uint16_t)r) >> 3) << 11 | (((uint16_t)g) >> 2) << 5 | (((uint16_t)b) >> 3);
|
||||
return BYTE_SWAP(rgb565);
|
||||
}
|
||||
|
||||
uint16_t qp_rgb888_to_bgr565(uint8_t r, uint8_t g, uint8_t b) {
|
||||
uint16_t bgr565 = (((uint16_t)b) >> 3) << 11 | (((uint16_t)g) >> 2) << 5 | (((uint16_t)r) >> 3);
|
||||
return bgr565;
|
||||
}
|
||||
|
||||
uint16_t qp_rgb888_to_bgr565_swapped(uint8_t r, uint8_t g, uint8_t b) {
|
||||
uint16_t bgr565 = (((uint16_t)b) >> 3) << 11 | (((uint16_t)g) >> 2) << 5 | (((uint16_t)r) >> 3);
|
||||
return BYTE_SWAP(bgr565);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Quantum Painter API implementations
|
||||
|
||||
@@ -105,26 +82,49 @@ bool qp_tft_panel_viewport(painter_device_t device, uint16_t left, uint16_t top,
|
||||
|
||||
// Stream pixel data to the current write position in GRAM
|
||||
bool qp_tft_panel_pixdata(painter_device_t device, const void *pixel_data, uint32_t native_pixel_count) {
|
||||
qp_comms_send(device, pixel_data, native_pixel_count * sizeof(uint16_t));
|
||||
struct painter_driver_t *driver = (struct painter_driver_t *)device;
|
||||
qp_comms_send(device, pixel_data, native_pixel_count * driver->native_bits_per_pixel / 8);
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Convert supplied palette entries into their native equivalents
|
||||
bool qp_tft_panel_palette_convert(painter_device_t device, int16_t palette_size, qp_pixel_t *palette) {
|
||||
struct painter_driver_t * driver = (struct painter_driver_t *)device;
|
||||
struct tft_panel_dc_reset_painter_driver_vtable_t *vtable = (struct tft_panel_dc_reset_painter_driver_vtable_t *)driver->driver_vtable;
|
||||
|
||||
bool qp_tft_panel_palette_convert_rgb565_swapped(painter_device_t device, int16_t palette_size, qp_pixel_t *palette) {
|
||||
for (int16_t i = 0; i < palette_size; ++i) {
|
||||
RGB rgb = hsv_to_rgb_nocie((HSV){palette[i].hsv888.h, palette[i].hsv888.s, palette[i].hsv888.v});
|
||||
palette[i].rgb565 = vtable->rgb888_to_native16bit(rgb.r, rgb.g, rgb.b);
|
||||
RGB rgb = hsv_to_rgb_nocie((HSV){palette[i].hsv888.h, palette[i].hsv888.s, palette[i].hsv888.v});
|
||||
uint16_t rgb565 = (((uint16_t)rgb.r) >> 3) << 11 | (((uint16_t)rgb.g) >> 2) << 5 | (((uint16_t)rgb.b) >> 3);
|
||||
palette[i].rgb565 = BYTE_SWAP(rgb565);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qp_tft_panel_palette_convert_rgb888(painter_device_t device, int16_t palette_size, qp_pixel_t *palette) {
|
||||
for (int16_t i = 0; i < palette_size; ++i) {
|
||||
RGB rgb = hsv_to_rgb_nocie((HSV){palette[i].hsv888.h, palette[i].hsv888.s, palette[i].hsv888.v});
|
||||
palette[i].rgb888.r = rgb.r;
|
||||
palette[i].rgb888.g = rgb.g;
|
||||
palette[i].rgb888.b = rgb.b;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Append pixels to the target location, keyed by the pixel index
|
||||
bool qp_tft_panel_append_pixels(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices) {
|
||||
|
||||
bool qp_tft_panel_append_pixels_rgb565(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices) {
|
||||
uint16_t *buf = (uint16_t *)target_buffer;
|
||||
for (uint32_t i = 0; i < pixel_count; ++i) {
|
||||
buf[pixel_offset + i] = palette[palette_indices[i]].rgb565;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool qp_tft_panel_append_pixels_rgb888(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices) {
|
||||
for (uint32_t i = 0; i < pixel_count; ++i) {
|
||||
target_buffer[(pixel_offset + i) * 3 + 0] = palette[palette_indices[i]].rgb888.r;
|
||||
target_buffer[(pixel_offset + i) * 3 + 1] = palette[palette_indices[i]].rgb888.g;
|
||||
target_buffer[(pixel_offset + i) * 3 + 2] = palette[palette_indices[i]].rgb888.b;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -11,15 +11,10 @@
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Common TFT panel implementation using D/C, and RST pins.
|
||||
|
||||
typedef uint16_t (*rgb888_to_native_uint16_t)(uint8_t r, uint8_t g, uint8_t b);
|
||||
|
||||
// Driver vtable with extras
|
||||
struct tft_panel_dc_reset_painter_driver_vtable_t {
|
||||
struct painter_driver_vtable_t base; // must be first, so it can be cast to/from the painter_driver_vtable_t* type
|
||||
|
||||
// Conversion function for palette entries
|
||||
rgb888_to_native_uint16_t rgb888_to_native16bit;
|
||||
|
||||
// Number of bytes for transmitting x/y coordinates
|
||||
uint8_t num_window_bytes;
|
||||
|
||||
@@ -58,10 +53,9 @@ bool qp_tft_panel_clear(painter_device_t device);
|
||||
bool qp_tft_panel_flush(painter_device_t device);
|
||||
bool qp_tft_panel_viewport(painter_device_t device, uint16_t left, uint16_t top, uint16_t right, uint16_t bottom);
|
||||
bool qp_tft_panel_pixdata(painter_device_t device, const void *pixel_data, uint32_t native_pixel_count);
|
||||
bool qp_tft_panel_palette_convert(painter_device_t device, int16_t palette_size, qp_pixel_t *palette);
|
||||
bool qp_tft_panel_append_pixels(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices);
|
||||
|
||||
uint16_t qp_rgb888_to_rgb565(uint8_t r, uint8_t g, uint8_t b);
|
||||
uint16_t qp_rgb888_to_rgb565_swapped(uint8_t r, uint8_t g, uint8_t b);
|
||||
uint16_t qp_rgb888_to_bgr565(uint8_t r, uint8_t g, uint8_t b);
|
||||
uint16_t qp_rgb888_to_bgr565_swapped(uint8_t r, uint8_t g, uint8_t b);
|
||||
bool qp_tft_panel_palette_convert_rgb565_swapped(painter_device_t device, int16_t palette_size, qp_pixel_t *palette);
|
||||
bool qp_tft_panel_palette_convert_rgb888(painter_device_t device, int16_t palette_size, qp_pixel_t *palette);
|
||||
|
||||
bool qp_tft_panel_append_pixels_rgb565(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices);
|
||||
bool qp_tft_panel_append_pixels_rgb888(painter_device_t device, uint8_t *target_buffer, qp_pixel_t *palette, uint32_t pixel_offset, uint32_t pixel_count, uint8_t *palette_indices);
|
||||
|
||||
@@ -89,6 +89,7 @@ uint8_t ps2_host_send(uint8_t data);
|
||||
uint8_t ps2_host_recv_response(void);
|
||||
uint8_t ps2_host_recv(void);
|
||||
void ps2_host_set_led(uint8_t usb_led);
|
||||
bool pbuf_has_data(void);
|
||||
|
||||
/*--------------------------------------------------------------------
|
||||
* static functions
|
||||
|
||||
@@ -66,8 +66,8 @@ uint8_t ps2_error = PS2_ERR_NONE;
|
||||
|
||||
static inline uint8_t pbuf_dequeue(void);
|
||||
static inline void pbuf_enqueue(uint8_t data);
|
||||
static inline bool pbuf_has_data(void);
|
||||
static inline void pbuf_clear(void);
|
||||
bool pbuf_has_data(void);
|
||||
|
||||
#if defined(PROTOCOL_CHIBIOS)
|
||||
void ps2_interrupt_service_routine(void);
|
||||
@@ -309,7 +309,7 @@ static inline uint8_t pbuf_dequeue(void) {
|
||||
|
||||
return val;
|
||||
}
|
||||
static inline bool pbuf_has_data(void) {
|
||||
bool pbuf_has_data(void) {
|
||||
#if defined(__AVR__)
|
||||
uint8_t sreg = SREG;
|
||||
cli();
|
||||
|
||||
@@ -53,6 +53,7 @@ void ps2_mouse_init(void) {
|
||||
ps2_mouse_set_remote_mode();
|
||||
#else
|
||||
ps2_mouse_enable_data_reporting();
|
||||
ps2_mouse_set_stream_mode();
|
||||
#endif
|
||||
|
||||
#ifdef PS2_MOUSE_ENABLE_SCROLLING
|
||||
@@ -75,19 +76,33 @@ void ps2_mouse_task(void) {
|
||||
extern int tp_buttons;
|
||||
|
||||
/* receives packet from mouse */
|
||||
#ifdef PS2_MOUSE_USE_REMOTE_MODE
|
||||
uint8_t rcv;
|
||||
rcv = ps2_host_send(PS2_MOUSE_READ_DATA);
|
||||
if (rcv == PS2_ACK) {
|
||||
mouse_report.buttons = ps2_host_recv_response() | tp_buttons;
|
||||
mouse_report.x = ps2_host_recv_response() * PS2_MOUSE_X_MULTIPLIER;
|
||||
mouse_report.y = ps2_host_recv_response() * PS2_MOUSE_Y_MULTIPLIER;
|
||||
#ifdef PS2_MOUSE_ENABLE_SCROLLING
|
||||
# ifdef PS2_MOUSE_ENABLE_SCROLLING
|
||||
mouse_report.v = -(ps2_host_recv_response() & PS2_MOUSE_SCROLL_MASK) * PS2_MOUSE_V_MULTIPLIER;
|
||||
#endif
|
||||
# endif
|
||||
} else {
|
||||
if (debug_mouse) print("ps2_mouse: fail to get mouse packet\n");
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (pbuf_has_data()) {
|
||||
mouse_report.buttons = ps2_host_recv_response() | tp_buttons;
|
||||
mouse_report.x = ps2_host_recv_response() * PS2_MOUSE_X_MULTIPLIER;
|
||||
mouse_report.y = ps2_host_recv_response() * PS2_MOUSE_Y_MULTIPLIER;
|
||||
# ifdef PS2_MOUSE_ENABLE_SCROLLING
|
||||
mouse_report.v = -(ps2_host_recv_response() & PS2_MOUSE_SCROLL_MASK) * PS2_MOUSE_V_MULTIPLIER;
|
||||
# endif
|
||||
} else {
|
||||
if (debug_mouse) print("ps2_mouse: fail to get mouse packet\n");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* if mouse moves or buttons state changes */
|
||||
if (mouse_report.x || mouse_report.y || mouse_report.v || ((mouse_report.buttons ^ buttons_prev) & PS2_MOUSE_BTN_MASK)) {
|
||||
|
||||
@@ -1,52 +1,24 @@
|
||||
// Copyright (c) 2018 Cirque Corp. Restrictions apply. See: www.cirque.com/sw-license
|
||||
// based on https://github.com/cirque-corp/Cirque_Pinnacle_1CA027/tree/master/Circular_Trackpad
|
||||
// with modifications and changes for QMK
|
||||
// refer to documentation: Gen2 and Gen3 (Pinnacle ASIC) at https://www.cirque.com/documentation
|
||||
|
||||
#include "cirque_pinnacle.h"
|
||||
#include "print.h"
|
||||
#include "debug.h"
|
||||
#include "wait.h"
|
||||
#include "timer.h"
|
||||
|
||||
// Registers for RAP
|
||||
// clang-format off
|
||||
#define FIRMWARE_ID 0x00
|
||||
#define FIRMWARE_VERSION_C 0x01
|
||||
#define STATUS_1 0x02
|
||||
#define SYSCONFIG_1 0x03
|
||||
#define FEEDCONFIG_1 0x04
|
||||
#define FEEDCONFIG_2 0x05
|
||||
#define CALIBRATION_CONFIG_1 0x07
|
||||
#define PS2_AU_CONTROL 0x08
|
||||
#define SAMPLE_RATE 0x09
|
||||
#define Z_IDLE_COUNT 0x0A
|
||||
#define Z_SCALER 0x0B
|
||||
#define SLEEP_INTERVAL 0x0C
|
||||
#define SLEEP_TIMER 0x0D
|
||||
#define PACKET_BYTE_0 0x12
|
||||
#define PACKET_BYTE_1 0x13
|
||||
#define PACKET_BYTE_2 0x14
|
||||
#define PACKET_BYTE_3 0x15
|
||||
#define PACKET_BYTE_4 0x16
|
||||
#define PACKET_BYTE_5 0x17
|
||||
|
||||
#define ERA_VALUE 0x1B
|
||||
#define ERA_HIGH_BYTE 0x1C
|
||||
#define ERA_LOW_BYTE 0x1D
|
||||
#define ERA_CONTROL 0x1E
|
||||
|
||||
// ADC-attenuation settings (held in BIT_7 and BIT_6)
|
||||
// 1X = most sensitive, 4X = least sensitive
|
||||
#define ADC_ATTENUATE_1X 0x00
|
||||
#define ADC_ATTENUATE_2X 0x40
|
||||
#define ADC_ATTENUATE_3X 0x80
|
||||
#define ADC_ATTENUATE_4X 0xC0
|
||||
|
||||
// Register config values for this demo
|
||||
#define SYSCONFIG_1_VALUE 0x00
|
||||
#define FEEDCONFIG_1_VALUE 0x03 // 0x03 for absolute mode 0x01 for relative mode
|
||||
#define FEEDCONFIG_2_VALUE 0x1C // 0x1F for normal functionality 0x1E for intellimouse disabled
|
||||
#define Z_IDLE_COUNT_VALUE 0x05
|
||||
// clang-format on
|
||||
#ifndef CIRQUE_PINNACLE_ATTENUATION
|
||||
# ifdef CIRQUE_PINNACLE_CURVED_OVERLAY
|
||||
# define CIRQUE_PINNACLE_ATTENUATION EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_2X
|
||||
# else
|
||||
# define CIRQUE_PINNACLE_ATTENUATION EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_4X
|
||||
# endif
|
||||
#endif
|
||||
|
||||
bool touchpad_init;
|
||||
uint16_t scale_data = 1024;
|
||||
uint16_t scale_data = CIRQUE_PINNACLE_DEFAULT_SCALE;
|
||||
|
||||
void cirque_pinnacle_clear_flags(void);
|
||||
void cirque_pinnacle_enable_feed(bool feedEnable);
|
||||
@@ -103,45 +75,45 @@ void cirque_pinnacle_scale_data(pinnacle_data_t* coordinates, uint16_t xResoluti
|
||||
|
||||
// Clears Status1 register flags (SW_CC and SW_DR)
|
||||
void cirque_pinnacle_clear_flags() {
|
||||
RAP_Write(STATUS_1, 0x00);
|
||||
RAP_Write(HOSTREG__STATUS1, HOSTREG__STATUS1_DEFVAL & ~(HOSTREG__STATUS1__COMMAND_COMPLETE | HOSTREG__STATUS1__DATA_READY));
|
||||
wait_us(50);
|
||||
}
|
||||
|
||||
// Enables/Disables the feed
|
||||
void cirque_pinnacle_enable_feed(bool feedEnable) {
|
||||
uint8_t temp;
|
||||
|
||||
RAP_ReadBytes(FEEDCONFIG_1, &temp, 1); // Store contents of FeedConfig1 register
|
||||
uint8_t feedconfig1;
|
||||
RAP_ReadBytes(HOSTREG__FEEDCONFIG1, &feedconfig1, 1);
|
||||
|
||||
if (feedEnable) {
|
||||
temp |= 0x01; // Set Feed Enable bit
|
||||
RAP_Write(0x04, temp);
|
||||
feedconfig1 |= HOSTREG__FEEDCONFIG1__FEED_ENABLE;
|
||||
} else {
|
||||
temp &= ~0x01; // Clear Feed Enable bit
|
||||
RAP_Write(0x04, temp);
|
||||
feedconfig1 &= ~HOSTREG__FEEDCONFIG1__FEED_ENABLE;
|
||||
}
|
||||
RAP_Write(HOSTREG__FEEDCONFIG1, feedconfig1);
|
||||
}
|
||||
|
||||
/* ERA (Extended Register Access) Functions */
|
||||
// Reads <count> bytes from an extended register at <address> (16-bit address),
|
||||
// stores values in <*data>
|
||||
void ERA_ReadBytes(uint16_t address, uint8_t* data, uint16_t count) {
|
||||
uint8_t ERAControlValue = 0xFF;
|
||||
uint8_t ERAControlValue = 0xFF;
|
||||
uint16_t timeout_timer;
|
||||
|
||||
cirque_pinnacle_enable_feed(false); // Disable feed
|
||||
|
||||
RAP_Write(ERA_HIGH_BYTE, (uint8_t)(address >> 8)); // Send upper byte of ERA address
|
||||
RAP_Write(ERA_LOW_BYTE, (uint8_t)(address & 0x00FF)); // Send lower byte of ERA address
|
||||
RAP_Write(HOSTREG__EXT_REG_AXS_ADDR_HIGH, (uint8_t)(address >> 8)); // Send upper byte of ERA address
|
||||
RAP_Write(HOSTREG__EXT_REG_AXS_ADDR_LOW, (uint8_t)(address & 0x00FF)); // Send lower byte of ERA address
|
||||
|
||||
for (uint16_t i = 0; i < count; i++) {
|
||||
RAP_Write(ERA_CONTROL, 0x05); // Signal ERA-read (auto-increment) to Pinnacle
|
||||
RAP_Write(HOSTREG__EXT_REG_AXS_CTRL, HOSTREG__EREG_AXS__INC_ADDR_READ | HOSTREG__EREG_AXS__READ); // Signal ERA-read (auto-increment) to Pinnacle
|
||||
|
||||
// Wait for status register 0x1E to clear
|
||||
timeout_timer = timer_read();
|
||||
do {
|
||||
RAP_ReadBytes(ERA_CONTROL, &ERAControlValue, 1);
|
||||
} while (ERAControlValue != 0x00);
|
||||
RAP_ReadBytes(HOSTREG__EXT_REG_AXS_CTRL, &ERAControlValue, 1);
|
||||
} while ((ERAControlValue != 0x00) && (timer_elapsed(timeout_timer) <= CIRQUE_PINNACLE_TIMEOUT));
|
||||
|
||||
RAP_ReadBytes(ERA_VALUE, data + i, 1);
|
||||
RAP_ReadBytes(HOSTREG__EXT_REG_AXS_VALUE, data + i, 1);
|
||||
|
||||
cirque_pinnacle_clear_flags();
|
||||
}
|
||||
@@ -149,49 +121,83 @@ void ERA_ReadBytes(uint16_t address, uint8_t* data, uint16_t count) {
|
||||
|
||||
// Writes a byte, <data>, to an extended register at <address> (16-bit address)
|
||||
void ERA_WriteByte(uint16_t address, uint8_t data) {
|
||||
uint8_t ERAControlValue = 0xFF;
|
||||
uint8_t ERAControlValue = 0xFF;
|
||||
uint16_t timeout_timer;
|
||||
|
||||
cirque_pinnacle_enable_feed(false); // Disable feed
|
||||
|
||||
RAP_Write(ERA_VALUE, data); // Send data byte to be written
|
||||
RAP_Write(HOSTREG__EXT_REG_AXS_VALUE, data); // Send data byte to be written
|
||||
|
||||
RAP_Write(ERA_HIGH_BYTE, (uint8_t)(address >> 8)); // Upper byte of ERA address
|
||||
RAP_Write(ERA_LOW_BYTE, (uint8_t)(address & 0x00FF)); // Lower byte of ERA address
|
||||
RAP_Write(HOSTREG__EXT_REG_AXS_ADDR_HIGH, (uint8_t)(address >> 8)); // Upper byte of ERA address
|
||||
RAP_Write(HOSTREG__EXT_REG_AXS_ADDR_LOW, (uint8_t)(address & 0x00FF)); // Lower byte of ERA address
|
||||
|
||||
RAP_Write(ERA_CONTROL, 0x02); // Signal an ERA-write to Pinnacle
|
||||
RAP_Write(HOSTREG__EXT_REG_AXS_CTRL, HOSTREG__EREG_AXS__WRITE); // Signal an ERA-write to Pinnacle
|
||||
|
||||
// Wait for status register 0x1E to clear
|
||||
timeout_timer = timer_read();
|
||||
do {
|
||||
RAP_ReadBytes(ERA_CONTROL, &ERAControlValue, 1);
|
||||
} while (ERAControlValue != 0x00);
|
||||
RAP_ReadBytes(HOSTREG__EXT_REG_AXS_CTRL, &ERAControlValue, 1);
|
||||
} while ((ERAControlValue != 0x00) && (timer_elapsed(timeout_timer) <= CIRQUE_PINNACLE_TIMEOUT));
|
||||
|
||||
cirque_pinnacle_clear_flags();
|
||||
}
|
||||
|
||||
void cirque_pinnacle_set_adc_attenuation(uint8_t adcGain) {
|
||||
uint8_t temp = 0x00;
|
||||
uint8_t adcconfig = 0x00;
|
||||
|
||||
ERA_ReadBytes(0x0187, &temp, 1);
|
||||
temp &= 0x3F; // clear top two bits
|
||||
temp |= adcGain;
|
||||
ERA_WriteByte(0x0187, temp);
|
||||
ERA_ReadBytes(0x0187, &temp, 1);
|
||||
ERA_ReadBytes(EXTREG__TRACK_ADCCONFIG, &adcconfig, 1);
|
||||
adcconfig &= EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_MASK;
|
||||
adcconfig |= adcGain;
|
||||
ERA_WriteByte(EXTREG__TRACK_ADCCONFIG, adcconfig);
|
||||
ERA_ReadBytes(EXTREG__TRACK_ADCCONFIG, &adcconfig, 1);
|
||||
}
|
||||
|
||||
// Changes thresholds to improve detection of fingers
|
||||
// Not needed for flat overlay?
|
||||
void cirque_pinnacle_tune_edge_sensitivity(void) {
|
||||
uint8_t temp = 0x00;
|
||||
uint8_t widezmin = 0x00;
|
||||
|
||||
ERA_ReadBytes(0x0149, &temp, 1);
|
||||
ERA_WriteByte(0x0149, 0x04);
|
||||
ERA_ReadBytes(0x0149, &temp, 1);
|
||||
ERA_ReadBytes(EXTREG__XAXIS_WIDEZMIN, &widezmin, 1);
|
||||
ERA_WriteByte(EXTREG__XAXIS_WIDEZMIN, 0x04); // magic number from Cirque sample code
|
||||
ERA_ReadBytes(EXTREG__XAXIS_WIDEZMIN, &widezmin, 1);
|
||||
|
||||
ERA_ReadBytes(0x0168, &temp, 1);
|
||||
ERA_WriteByte(0x0168, 0x03);
|
||||
ERA_ReadBytes(0x0168, &temp, 1);
|
||||
ERA_ReadBytes(EXTREG__YAXIS_WIDEZMIN, &widezmin, 1);
|
||||
ERA_WriteByte(EXTREG__YAXIS_WIDEZMIN, 0x03); // magic number from Cirque sample code
|
||||
ERA_ReadBytes(EXTREG__YAXIS_WIDEZMIN, &widezmin, 1);
|
||||
}
|
||||
|
||||
/* Pinnacle-based TM040040 Functions */
|
||||
// Perform calibration
|
||||
void cirque_pinnacle_calibrate(void) {
|
||||
uint8_t calconfig;
|
||||
uint16_t timeout_timer;
|
||||
|
||||
RAP_ReadBytes(HOSTREG__CALCONFIG1, &calconfig, 1);
|
||||
calconfig |= HOSTREG__CALCONFIG1__CALIBRATE;
|
||||
RAP_Write(HOSTREG__CALCONFIG1, calconfig);
|
||||
|
||||
// Calibration takes ~100ms according to GT-AN-090624, doubling the timeout just to be safe
|
||||
timeout_timer = timer_read();
|
||||
do {
|
||||
RAP_ReadBytes(HOSTREG__CALCONFIG1, &calconfig, 1);
|
||||
} while ((calconfig & HOSTREG__CALCONFIG1__CALIBRATE) && (timer_elapsed(timeout_timer) <= 200));
|
||||
|
||||
cirque_pinnacle_clear_flags();
|
||||
}
|
||||
|
||||
// Enable/disable cursor smoothing, smoothing is enabled by default
|
||||
void cirque_pinnacle_cursor_smoothing(bool enable) {
|
||||
uint8_t feedconfig3;
|
||||
|
||||
RAP_ReadBytes(HOSTREG__FEEDCONFIG3, &feedconfig3, 1);
|
||||
if (enable) {
|
||||
feedconfig3 &= ~HOSTREG__FEEDCONFIG3__DISABLE_CROSS_RATE_SMOOTHING;
|
||||
} else {
|
||||
feedconfig3 |= HOSTREG__FEEDCONFIG3__DISABLE_CROSS_RATE_SMOOTHING;
|
||||
}
|
||||
RAP_Write(HOSTREG__FEEDCONFIG3, feedconfig3);
|
||||
}
|
||||
|
||||
/* Pinnacle-based TM040040/TM035035/TM023023 Functions */
|
||||
void cirque_pinnacle_init(void) {
|
||||
#if defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi)
|
||||
spi_init();
|
||||
@@ -200,39 +206,71 @@ void cirque_pinnacle_init(void) {
|
||||
#endif
|
||||
|
||||
touchpad_init = true;
|
||||
|
||||
// Host clears SW_CC flag
|
||||
cirque_pinnacle_clear_flags();
|
||||
|
||||
// Host configures bits of registers 0x03 and 0x05
|
||||
RAP_Write(SYSCONFIG_1, SYSCONFIG_1_VALUE);
|
||||
RAP_Write(FEEDCONFIG_2, FEEDCONFIG_2_VALUE);
|
||||
// send a RESET command now, in case QMK had a soft-reset without a power cycle
|
||||
RAP_Write(HOSTREG__SYSCONFIG1, HOSTREG__SYSCONFIG1__RESET);
|
||||
wait_ms(30); // Pinnacle needs 10-15ms to boot, so wait long enough before configuring
|
||||
RAP_Write(HOSTREG__SYSCONFIG1, HOSTREG__SYSCONFIG1_DEFVAL);
|
||||
wait_us(50);
|
||||
|
||||
// Host enables preferred output mode (absolute)
|
||||
RAP_Write(FEEDCONFIG_1, FEEDCONFIG_1_VALUE);
|
||||
// FeedConfig2 (Feature flags for Relative Mode Only)
|
||||
RAP_Write(HOSTREG__FEEDCONFIG2, HOSTREG__FEEDCONFIG2_DEFVAL);
|
||||
|
||||
// Host sets z-idle packet count to 5 (default is 30)
|
||||
RAP_Write(Z_IDLE_COUNT, Z_IDLE_COUNT_VALUE);
|
||||
// FeedConfig1 (Data Output Flags)
|
||||
RAP_Write(HOSTREG__FEEDCONFIG1, CIRQUE_PINNACLE_POSITION_MODE ? HOSTREG__FEEDCONFIG1__DATA_TYPE__REL0_ABS1 : HOSTREG__FEEDCONFIG1_DEFVAL);
|
||||
|
||||
cirque_pinnacle_set_adc_attenuation(0xFF);
|
||||
// Host sets z-idle packet count to 5 (default is 0x1E/30)
|
||||
RAP_Write(HOSTREG__ZIDLE, 5);
|
||||
|
||||
cirque_pinnacle_set_adc_attenuation(CIRQUE_PINNACLE_ATTENUATION);
|
||||
#ifdef CIRQUE_PINNACLE_CURVED_OVERLAY
|
||||
cirque_pinnacle_tune_edge_sensitivity();
|
||||
#endif
|
||||
// Force a calibration after setting ADC attenuation
|
||||
cirque_pinnacle_calibrate();
|
||||
|
||||
cirque_pinnacle_enable_feed(true);
|
||||
}
|
||||
|
||||
// Reads XYZ data from Pinnacle registers 0x14 through 0x17
|
||||
// Stores result in pinnacle_data_t struct with xValue, yValue, and zValue members
|
||||
pinnacle_data_t cirque_pinnacle_read_data(void) {
|
||||
uint8_t data[6] = {0};
|
||||
pinnacle_data_t result = {0};
|
||||
RAP_ReadBytes(PACKET_BYTE_0, data, 6);
|
||||
uint8_t data_ready = 0;
|
||||
uint8_t data[6] = {0};
|
||||
pinnacle_data_t result = {0};
|
||||
|
||||
// Check if there is valid data available
|
||||
RAP_ReadBytes(HOSTREG__STATUS1, &data_ready, 1);
|
||||
if ((data_ready & HOSTREG__STATUS1__DATA_READY) == 0) {
|
||||
// no data available yet
|
||||
result.valid = false; // be explicit
|
||||
return result;
|
||||
}
|
||||
|
||||
// Read all data bytes
|
||||
RAP_ReadBytes(HOSTREG__PACKETBYTE_0, data, 6);
|
||||
|
||||
// Get ready for the next data sample
|
||||
cirque_pinnacle_clear_flags();
|
||||
|
||||
result.buttonFlags = data[0] & 0x3F;
|
||||
result.xValue = data[2] | ((data[4] & 0x0F) << 8);
|
||||
result.yValue = data[3] | ((data[4] & 0xF0) << 4);
|
||||
result.zValue = data[5] & 0x3F;
|
||||
|
||||
result.touchDown = (result.xValue != 0 || result.yValue != 0);
|
||||
#if CIRQUE_PINNACLE_POSITION_MODE
|
||||
// Decode data for absolute mode
|
||||
// Register 0x13 is unused in this mode (palm detection area)
|
||||
result.buttonFlags = data[0] & 0x3F; // bit0 to bit5 are switch 0-5, only hardware button presses (from input pin on the Pinnacle chip)
|
||||
result.xValue = data[2] | ((data[4] & 0x0F) << 8); // merge high and low bits for X
|
||||
result.yValue = data[3] | ((data[4] & 0xF0) << 4); // merge high and low bits for Y
|
||||
result.zValue = data[5] & 0x3F; // Z is only lower 6 bits, upper 2 bits are reserved/unused
|
||||
result.touchDown = (result.xValue != 0 || result.yValue != 0); // (0,0) is a "magic coordinate" to indicate "finger touched down"
|
||||
#else
|
||||
// Decode data for relative mode
|
||||
// Registers 0x16 and 0x17 are unused in this mode
|
||||
result.buttons = data[0] & 0x07; // bit0 = primary button, bit1 = secondary button, bit2 = auxilary button, if Taps enabled then also software-recognized taps are reported
|
||||
result.xDelta = data[1];
|
||||
result.yDelta = data[2];
|
||||
result.wheelCount = data[3];
|
||||
#endif
|
||||
|
||||
result.valid = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -2,26 +2,23 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "cirque_pinnacle_regdefs.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
// Convenient way to store and access measurements
|
||||
typedef struct {
|
||||
uint16_t xValue;
|
||||
uint16_t yValue;
|
||||
uint16_t zValue;
|
||||
uint8_t buttonFlags;
|
||||
bool touchDown;
|
||||
} pinnacle_data_t;
|
||||
|
||||
void cirque_pinnacle_init(void);
|
||||
pinnacle_data_t cirque_pinnacle_read_data(void);
|
||||
void cirque_pinnacle_scale_data(pinnacle_data_t* coordinates, uint16_t xResolution, uint16_t yResolution);
|
||||
uint16_t cirque_pinnacle_get_scale(void);
|
||||
void cirque_pinnacle_set_scale(uint16_t scale);
|
||||
|
||||
#ifndef CIRQUE_PINNACLE_TIMEOUT
|
||||
# define CIRQUE_PINNACLE_TIMEOUT 20
|
||||
# define CIRQUE_PINNACLE_TIMEOUT 20 // I2C timeout in milliseconds
|
||||
#endif
|
||||
|
||||
#define CIRQUE_PINNACLE_ABSOLUTE_MODE 1
|
||||
#define CIRQUE_PINNACLE_RELATIVE_MODE 0
|
||||
#ifndef CIRQUE_PINNACLE_POSITION_MODE
|
||||
# define CIRQUE_PINNACLE_POSITION_MODE CIRQUE_PINNACLE_ABSOLUTE_MODE
|
||||
#endif
|
||||
|
||||
#define CIRQUE_PINNACLE_DEFAULT_SCALE 1024
|
||||
#ifndef CIRQUE_PINNACLE_DIAMETER_MM
|
||||
# define CIRQUE_PINNACLE_DIAMETER_MM 40
|
||||
#endif
|
||||
|
||||
// Coordinate scaling values
|
||||
@@ -43,12 +40,14 @@ void cirque_pinnacle_set_scale(uint16_t scale);
|
||||
#ifndef CIRQUE_PINNACLE_Y_RANGE
|
||||
# define CIRQUE_PINNACLE_Y_RANGE (CIRQUE_PINNACLE_Y_UPPER - CIRQUE_PINNACLE_Y_LOWER)
|
||||
#endif
|
||||
|
||||
#if !defined(POINTING_DEVICE_TASK_THROTTLE_MS)
|
||||
# define POINTING_DEVICE_TASK_THROTTLE_MS 10 // Cirque Pinnacle in normal operation produces data every 10ms. Advanced configuration for pen/stylus usage might require lower values.
|
||||
#endif
|
||||
#if defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_i2c)
|
||||
# include "i2c_master.h"
|
||||
// Cirque's 7-bit I2C Slave Address
|
||||
# ifndef CIRQUE_PINNACLE_ADDR
|
||||
# define CIRQUE_PINNACLE_ADDR 0x2A
|
||||
# define CIRQUE_PINNACLE_ADDR I2C_ADDRESS_DEFAULT
|
||||
# endif
|
||||
#elif defined(POINTING_DEVICE_DRIVER_cirque_pinnacle_spi)
|
||||
# include "spi_master.h"
|
||||
@@ -72,3 +71,32 @@ void cirque_pinnacle_set_scale(uint16_t scale);
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#define DIVIDE_UNSIGNED_ROUND(numerator, denominator) (((numerator) + ((denominator) / 2)) / (denominator))
|
||||
#define CIRQUE_PINNACLE_INCH_TO_PX(inch) (DIVIDE_UNSIGNED_ROUND((inch) * (uint32_t)CIRQUE_PINNACLE_DIAMETER_MM * 10, 254))
|
||||
#define CIRQUE_PINNACLE_PX_TO_INCH(px) (DIVIDE_UNSIGNED_ROUND((px) * (uint32_t)254, CIRQUE_PINNACLE_DIAMETER_MM * 10))
|
||||
|
||||
// Convenient way to store and access measurements
|
||||
typedef struct {
|
||||
bool valid; // true if valid data was read, false if no data was ready
|
||||
#if CIRQUE_PINNACLE_POSITION_MODE
|
||||
uint16_t xValue;
|
||||
uint16_t yValue;
|
||||
uint16_t zValue;
|
||||
uint8_t buttonFlags;
|
||||
bool touchDown;
|
||||
#else
|
||||
uint8_t xDelta;
|
||||
uint8_t yDelta;
|
||||
uint8_t wheelCount;
|
||||
uint8_t buttons;
|
||||
#endif
|
||||
} pinnacle_data_t;
|
||||
|
||||
void cirque_pinnacle_init(void);
|
||||
void cirque_pinnacle_calibrate(void);
|
||||
void cirque_pinnacle_cursor_smoothing(bool enable);
|
||||
pinnacle_data_t cirque_pinnacle_read_data(void);
|
||||
void cirque_pinnacle_scale_data(pinnacle_data_t* coordinates, uint16_t xResolution, uint16_t yResolution);
|
||||
uint16_t cirque_pinnacle_get_scale(void);
|
||||
void cirque_pinnacle_set_scale(uint16_t scale);
|
||||
|
||||
227
drivers/sensors/cirque_pinnacle_gestures.c
Normal file
227
drivers/sensors/cirque_pinnacle_gestures.c
Normal file
@@ -0,0 +1,227 @@
|
||||
/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
|
||||
* Copyright 2022 Daniel Kao <daniel.m.kao@gmail.com>
|
||||
*
|
||||
* 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 <stdlib.h>
|
||||
#include <lib/lib8tion/lib8tion.h>
|
||||
#include "cirque_pinnacle_gestures.h"
|
||||
#include "pointing_device.h"
|
||||
#include "timer.h"
|
||||
#include "wait.h"
|
||||
|
||||
#if defined(CIRQUE_PINNACLE_TAP_ENABLE) || defined(CIRQUE_PINNACLE_CIRCULAR_SCROLL_ENABLE)
|
||||
static cirque_pinnacle_features_t features = {.tap_enable = true, .circular_scroll_enable = true};
|
||||
#endif
|
||||
|
||||
#ifdef CIRQUE_PINNACLE_TAP_ENABLE
|
||||
static trackpad_tap_context_t tap;
|
||||
|
||||
static report_mouse_t trackpad_tap(report_mouse_t mouse_report, pinnacle_data_t touchData) {
|
||||
if (touchData.touchDown != tap.touchDown) {
|
||||
tap.touchDown = touchData.touchDown;
|
||||
if (!touchData.zValue) {
|
||||
if (timer_elapsed(tap.timer) < CIRQUE_PINNACLE_TAPPING_TERM && tap.timer != 0) {
|
||||
mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, true, POINTING_DEVICE_BUTTON1);
|
||||
pointing_device_set_report(mouse_report);
|
||||
pointing_device_send();
|
||||
# if TAP_CODE_DELAY > 0
|
||||
wait_ms(TAP_CODE_DELAY);
|
||||
# endif
|
||||
mouse_report.buttons = pointing_device_handle_buttons(mouse_report.buttons, false, POINTING_DEVICE_BUTTON1);
|
||||
pointing_device_set_report(mouse_report);
|
||||
pointing_device_send();
|
||||
}
|
||||
}
|
||||
tap.timer = timer_read();
|
||||
}
|
||||
if (timer_elapsed(tap.timer) > (CIRQUE_PINNACLE_TOUCH_DEBOUNCE)) {
|
||||
tap.timer = 0;
|
||||
}
|
||||
|
||||
return mouse_report;
|
||||
}
|
||||
|
||||
void cirque_pinnacle_enable_tap(bool enable) {
|
||||
features.tap_enable = enable;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CIRQUE_PINNACLE_CIRCULAR_SCROLL_ENABLE
|
||||
/* To set a trackpad exclusively as scroll wheel: outer_ring_pct = 100, trigger_px = 0, trigger_ang = 0 */
|
||||
static circular_scroll_context_t scroll = {.config = {.outer_ring_pct = 33,
|
||||
.trigger_px = 16,
|
||||
.trigger_ang = 9102, /* 50 degrees */
|
||||
.wheel_clicks = 18}};
|
||||
|
||||
static inline uint16_t atan2_16(int32_t dy, int32_t dx) {
|
||||
if (dy == 0) {
|
||||
if (dx >= 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return 32768;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t abs_y = dy > 0 ? dy : -dy;
|
||||
int16_t a;
|
||||
|
||||
if (dx >= 0) {
|
||||
a = 8192 - (8192 * (dx - abs_y) / (dx + abs_y));
|
||||
} else {
|
||||
a = 24576 - (8192 * (dx + abs_y) / (abs_y - dx));
|
||||
}
|
||||
|
||||
if (dy < 0) {
|
||||
return -a; // negate if in quad III or IV
|
||||
}
|
||||
return a;
|
||||
}
|
||||
|
||||
static circular_scroll_t circular_scroll(pinnacle_data_t touchData) {
|
||||
circular_scroll_t report = {0, 0, false};
|
||||
int8_t x, y, wheel_clicks;
|
||||
uint8_t center = 256 / 2, mag;
|
||||
int16_t ang, dot, det, opposite_side, adjacent_side;
|
||||
uint16_t scale = cirque_pinnacle_get_scale();
|
||||
|
||||
if (touchData.zValue) {
|
||||
/*
|
||||
* Place origin at center of trackpad, treat coordinates as vectors.
|
||||
* Scale to fixed int8_t size; angles are independent of resolution.
|
||||
*/
|
||||
if (scale) {
|
||||
x = (int8_t)((int32_t)touchData.xValue * 256 / scale - center);
|
||||
y = (int8_t)((int32_t)touchData.yValue * 256 / scale - center);
|
||||
} else {
|
||||
x = 0;
|
||||
y = 0;
|
||||
}
|
||||
|
||||
/* Check if first touch */
|
||||
if (!scroll.z) {
|
||||
report.suppress_touch = false;
|
||||
/* Check if touch falls within outer ring */
|
||||
mag = sqrt16(x * x + y * y);
|
||||
if (mag * 100 / center >= 100 - scroll.config.outer_ring_pct) {
|
||||
scroll.state = SCROLL_DETECTING;
|
||||
scroll.x = x;
|
||||
scroll.y = y;
|
||||
scroll.mag = mag;
|
||||
/*
|
||||
* Decide scroll axis:
|
||||
* Vertical if started from righ half
|
||||
* Horizontal if started from left half
|
||||
* Flipped for left-handed
|
||||
*/
|
||||
# if defined(POINTING_DEVICE_ROTATION_90)
|
||||
scroll.axis = y < 0;
|
||||
# elif defined(POINTING_DEVICE_ROTATION_180)
|
||||
scroll.axis = x > 0;
|
||||
# elif defined(POINTING_DEVICE_ROTATION_270)
|
||||
scroll.axis = y > 0;
|
||||
# else
|
||||
scroll.axis = x < 0;
|
||||
# endif
|
||||
}
|
||||
} else if (scroll.state == SCROLL_DETECTING) {
|
||||
report.suppress_touch = true;
|
||||
/* Already detecting scroll, check movement from touchdown location */
|
||||
mag = sqrt16((x - scroll.x) * (x - scroll.x) + (y - scroll.y) * (y - scroll.y));
|
||||
if (mag >= scroll.config.trigger_px) {
|
||||
/*
|
||||
* Find angle of movement.
|
||||
* 0 degrees here means movement towards center of circle
|
||||
*/
|
||||
dot = scroll.x * x + scroll.y * y;
|
||||
det = scroll.x * y - scroll.y * x;
|
||||
opposite_side = abs(det); /* Based on scalar rejection */
|
||||
adjacent_side = abs(scroll.mag * scroll.mag - abs(dot)); /* Based on scalar projection */
|
||||
ang = (int16_t)atan2_16(opposite_side, adjacent_side);
|
||||
if (ang < scroll.config.trigger_ang) {
|
||||
/* Not a scroll, release coordinates */
|
||||
report.suppress_touch = false;
|
||||
scroll.state = NOT_SCROLL;
|
||||
} else {
|
||||
/* Scroll detected */
|
||||
scroll.state = SCROLL_VALID;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (scroll.state == SCROLL_VALID) {
|
||||
report.suppress_touch = true;
|
||||
dot = scroll.x * x + scroll.y * y;
|
||||
det = scroll.x * y - scroll.y * x;
|
||||
ang = (int16_t)atan2_16(det, dot);
|
||||
wheel_clicks = ((int32_t)ang * scroll.config.wheel_clicks) / 65536;
|
||||
if (wheel_clicks >= 1 || wheel_clicks <= -1) {
|
||||
if (scroll.config.left_handed) {
|
||||
if (scroll.axis == 0) {
|
||||
report.h = -wheel_clicks;
|
||||
} else {
|
||||
report.v = wheel_clicks;
|
||||
}
|
||||
} else {
|
||||
if (scroll.axis == 0) {
|
||||
report.v = -wheel_clicks;
|
||||
} else {
|
||||
report.h = wheel_clicks;
|
||||
}
|
||||
}
|
||||
scroll.x = x;
|
||||
scroll.y = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
scroll.z = touchData.zValue;
|
||||
if (!scroll.z) scroll.state = SCROLL_UNINITIALIZED;
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
void cirque_pinnacle_enable_circular_scroll(bool enable) {
|
||||
features.circular_scroll_enable = enable;
|
||||
}
|
||||
|
||||
void cirque_pinnacle_configure_circular_scroll(uint8_t outer_ring_pct, uint8_t trigger_px, uint16_t trigger_ang, uint8_t wheel_clicks, bool left_handed) {
|
||||
scroll.config.outer_ring_pct = outer_ring_pct;
|
||||
scroll.config.trigger_px = trigger_px;
|
||||
scroll.config.trigger_ang = trigger_ang;
|
||||
scroll.config.wheel_clicks = wheel_clicks;
|
||||
scroll.config.left_handed = left_handed;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool cirque_pinnacle_gestures(report_mouse_t* mouse_report, pinnacle_data_t touchData) {
|
||||
bool suppress_mouse_update = false;
|
||||
|
||||
#ifdef CIRQUE_PINNACLE_CIRCULAR_SCROLL_ENABLE
|
||||
circular_scroll_t scroll_report;
|
||||
if (features.circular_scroll_enable) {
|
||||
scroll_report = circular_scroll(touchData);
|
||||
mouse_report->v = scroll_report.v;
|
||||
mouse_report->h = scroll_report.h;
|
||||
suppress_mouse_update = scroll_report.suppress_touch;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CIRQUE_PINNACLE_TAP_ENABLE
|
||||
if (features.tap_enable) {
|
||||
*mouse_report = trackpad_tap(*mouse_report, touchData);
|
||||
}
|
||||
#endif
|
||||
|
||||
return suppress_mouse_update;
|
||||
}
|
||||
107
drivers/sensors/cirque_pinnacle_gestures.h
Normal file
107
drivers/sensors/cirque_pinnacle_gestures.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
|
||||
* Copyright 2022 Daniel Kao <daniel.m.kao@gmail.com>
|
||||
*
|
||||
* 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 "cirque_pinnacle.h"
|
||||
#include "report.h"
|
||||
|
||||
typedef struct {
|
||||
bool tap_enable;
|
||||
bool circular_scroll_enable;
|
||||
} cirque_pinnacle_features_t;
|
||||
|
||||
#ifdef CIRQUE_PINNACLE_TAP_ENABLE
|
||||
# ifndef CIRQUE_PINNACLE_TAPPING_TERM
|
||||
# include "action.h"
|
||||
# include "action_tapping.h"
|
||||
# define CIRQUE_PINNACLE_TAPPING_TERM GET_TAPPING_TERM(KC_BTN1, &(keyrecord_t){})
|
||||
# endif
|
||||
# ifndef CIRQUE_PINNACLE_TOUCH_DEBOUNCE
|
||||
# define CIRQUE_PINNACLE_TOUCH_DEBOUNCE (CIRQUE_PINNACLE_TAPPING_TERM * 8)
|
||||
# endif
|
||||
|
||||
typedef struct {
|
||||
uint16_t timer;
|
||||
bool touchDown;
|
||||
} trackpad_tap_context_t;
|
||||
|
||||
/* Enable/disable tap gesture */
|
||||
void cirque_pinnacle_enable_tap(bool enable);
|
||||
#endif
|
||||
|
||||
#ifdef CIRQUE_PINNACLE_CIRCULAR_SCROLL_ENABLE
|
||||
typedef enum {
|
||||
SCROLL_UNINITIALIZED,
|
||||
SCROLL_DETECTING,
|
||||
SCROLL_VALID,
|
||||
NOT_SCROLL,
|
||||
} circular_scroll_status_t;
|
||||
|
||||
typedef struct {
|
||||
int8_t v;
|
||||
int8_t h;
|
||||
bool suppress_touch;
|
||||
} circular_scroll_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t outer_ring_pct; /* Width of outer ring, given as a percentage of the radius */
|
||||
uint8_t trigger_px; /* Amount of movement before triggering scroll validation, in pixels 0~127 */
|
||||
uint16_t trigger_ang; /* Angle required to validate scroll, in radians where pi = 32768 */
|
||||
uint8_t wheel_clicks; /* How many clicks to report in a circle */
|
||||
bool left_handed; /* Whether scrolling should be flipped for left handed use */
|
||||
} circular_scroll_config_t;
|
||||
|
||||
typedef struct {
|
||||
circular_scroll_config_t config;
|
||||
circular_scroll_status_t state;
|
||||
uint8_t mag;
|
||||
int8_t x;
|
||||
int8_t y;
|
||||
uint16_t z;
|
||||
bool axis;
|
||||
} circular_scroll_context_t;
|
||||
|
||||
/* Enable/disable circular scroll gesture */
|
||||
void cirque_pinnacle_enable_circular_scroll(bool enable);
|
||||
|
||||
/*
|
||||
* Configure circular scroll gesture.
|
||||
* Trackpad can be configured to act exclusively as a scroll wheel with outer_ring_pct = 0, trigger_px = 0, trigger_ang = 0.
|
||||
* @param outer_ring_pct Width of outer ring from which to begin scroll validation, given as a percentage of the radius.
|
||||
* @param trigger_px Amount of movement before triggering scroll validation. Expressed in pixels, trackpad coordinates are scaled to radius of 128 pixels for circular scroll.
|
||||
* @param triger_ang Angle required to validate scroll, angle smaller than this will invalidate scroll. In radians where pi = 32768, 0 means movement towards center of trackpad, 16384 means movement perpendicular to center.
|
||||
* @param wheel_clicks Number of scroll wheel clicks to report in a full rotation.
|
||||
* @param left_handed Whether scrolling should be flipped for left-handed use.
|
||||
*/
|
||||
void cirque_pinnacle_configure_circular_scroll(uint8_t outer_ring_pct, uint8_t trigger_px, uint16_t trigger_ang, uint8_t wheel_clicks, bool left_handed);
|
||||
#endif
|
||||
|
||||
#ifdef POINTING_DEVICE_GESTURES_CURSOR_GLIDE_ENABLE
|
||||
/* Implementation in pointing_device_drivers.c */
|
||||
|
||||
/* Enable/disable inertial cursor */
|
||||
void cirque_pinnacle_enable_cursor_glide(bool enable);
|
||||
|
||||
/*
|
||||
* Configure inertial cursor.
|
||||
* @param trigger_px Movement required to trigger cursor glide, set this to non-zero if you have some amount of hover.
|
||||
*/
|
||||
void cirque_pinnacle_configure_cursor_glide(float trigger_px);
|
||||
#endif
|
||||
|
||||
/* Process available gestures */
|
||||
bool cirque_pinnacle_gestures(report_mouse_t* mouse_report, pinnacle_data_t touchData);
|
||||
@@ -19,7 +19,7 @@ void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count) {
|
||||
i2c_writeReg(CIRQUE_PINNACLE_ADDR << 1, cmdByte, NULL, 0, CIRQUE_PINNACLE_TIMEOUT);
|
||||
if (i2c_readReg(CIRQUE_PINNACLE_ADDR << 1, cmdByte, data, count, CIRQUE_PINNACLE_TIMEOUT) != I2C_STATUS_SUCCESS) {
|
||||
#ifdef CONSOLE_ENABLE
|
||||
dprintf("error right touchpad\n");
|
||||
dprintf("error cirque_pinnacle i2c_readReg\n");
|
||||
#endif
|
||||
touchpad_init = false;
|
||||
}
|
||||
@@ -34,7 +34,7 @@ void RAP_Write(uint8_t address, uint8_t data) {
|
||||
if (touchpad_init) {
|
||||
if (i2c_writeReg(CIRQUE_PINNACLE_ADDR << 1, cmdByte, &data, sizeof(data), CIRQUE_PINNACLE_TIMEOUT) != I2C_STATUS_SUCCESS) {
|
||||
#ifdef CONSOLE_ENABLE
|
||||
dprintf("error right touchpad\n");
|
||||
dprintf("error cirque_pinnacle i2c_writeReg\n");
|
||||
#endif
|
||||
touchpad_init = false;
|
||||
}
|
||||
|
||||
405
drivers/sensors/cirque_pinnacle_regdefs.h
Normal file
405
drivers/sensors/cirque_pinnacle_regdefs.h
Normal file
@@ -0,0 +1,405 @@
|
||||
// Copyright (c) 2018 Cirque Corp. Restrictions apply. See: www.cirque.com/sw-license
|
||||
// based on https://github.com/cirque-corp/Cirque_Pinnacle_1CA027/tree/master/Additional_Examples
|
||||
// with modifications and changes for QMK
|
||||
// refer to documentation: Gen2 and Gen3 (Pinnacle ASIC) at https://www.cirque.com/gen2gen3-asic-details
|
||||
|
||||
#pragma once
|
||||
|
||||
// clang-format off
|
||||
|
||||
#define HostReg__0 (0x00)
|
||||
#define HostReg__1 (0x01)
|
||||
#define HostReg__2 (0x02)
|
||||
#define HostReg__3 (0x03)
|
||||
#define HostReg__4 (0x04)
|
||||
#define HostReg__5 (0x05)
|
||||
#define HostReg__6 (0x06)
|
||||
#define HostReg__7 (0x07)
|
||||
#define HostReg__8 (0x08)
|
||||
#define HostReg__9 (0x09)
|
||||
#define HostReg__10 (0x0A)
|
||||
#define HostReg__11 (0x0B)
|
||||
#define HostReg__12 (0x0C)
|
||||
#define HostReg__13 (0x0D)
|
||||
#define HostReg__14 (0x0E)
|
||||
#define HostReg__15 (0x0F)
|
||||
#define HostReg__16 (0x10)
|
||||
#define HostReg__17 (0x11)
|
||||
#define HostReg__18 (0x12)
|
||||
#define HostReg__19 (0x13)
|
||||
#define HostReg__20 (0x14)
|
||||
#define HostReg__21 (0x15)
|
||||
#define HostReg__22 (0x16)
|
||||
#define HostReg__23 (0x17)
|
||||
#define HostReg__24 (0x18)
|
||||
#define HostReg__25 (0x19)
|
||||
#define HostReg__26 (0x1A)
|
||||
#define HostReg__27 (0x1B)
|
||||
#define HostReg__28 (0x1C)
|
||||
#define HostReg__29 (0x1D)
|
||||
#define HostReg__30 (0x1E)
|
||||
#define HostReg__31 (0x1F)
|
||||
|
||||
// ---------------- Register Assignments -------------------------------------
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Chip ID / Version
|
||||
\*--------------------------------------------------------------------------*/
|
||||
// Chip ID Register
|
||||
#define HOSTREG__CHIPID HostReg__0
|
||||
|
||||
// Chip Version Register
|
||||
#define HOSTREG__VERSION HostReg__1
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Status Register
|
||||
\*--------------------------------------------------------------------------*/
|
||||
// Status 1 Register -- MUST BE HOSTREG__2
|
||||
#define HOSTREG__STATUS1 HostReg__2
|
||||
# define HOSTREG__STATUS1__DATA_READY 0x04
|
||||
# define HOSTREG__STATUS1__COMMAND_COMPLETE 0x08
|
||||
#define HOSTREG__STATUS1_DEFVAL 0x00
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
System Config Register
|
||||
\*--------------------------------------------------------------------------*/
|
||||
#define HOSTREG__SYSCONFIG1 HostReg__3
|
||||
# define HOSTREG__SYSCONFIG1__RESET 0x01
|
||||
# define HOSTREG__SYSCONFIG1__STANDBY 0x02
|
||||
# define HOSTREG__SYSCONFIG1__AUTO_SLEEP 0x04
|
||||
# define HOSTREG__SYSCONFIG1__TRACK_DISABLE 0x08
|
||||
# define HOSTREG__SYSCONFIG1__ANYMEAS_ENABLE 0x10
|
||||
# define HOSTREG__SYSCONFIG1__GPIO_CTRL_ENABLE 0x20
|
||||
# define HOSTREG__SYSCONFIG1__WAKEUP_TOGGLE 0x40
|
||||
# define HOSTREG__SYSCONFIG1__FORCE_WAKEUP 0x80
|
||||
#define HOSTREG__SYSCONFIG1_DEFVAL 0x00
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Feed Config Registers
|
||||
\*--------------------------------------------------------------------------*/
|
||||
// Feed Config Register1
|
||||
#define HOSTREG__FEEDCONFIG1 HostReg__4
|
||||
# define HOSTREG__FEEDCONFIG1__FEED_ENABLE 0x01
|
||||
# define HOSTREG__FEEDCONFIG1__DATA_TYPE__REL0_ABS1 0x02
|
||||
# define HOSTREG__FEEDCONFIG1__FILTER_DISABLE 0x04
|
||||
# define HOSTREG__FEEDCONFIG1__X_AXIS_DISABLE 0x08
|
||||
# define HOSTREG__FEEDCONFIG1__Y_AXIS_DISABLE 0x10
|
||||
# define HOSTREG__FEEDCONFIG1__AXIS_FOR_Z__Y0_X1 0x20
|
||||
# define HOSTREG__FEEDCONFIG1__X_DATA_INVERT 0x40
|
||||
# define HOSTREG__FEEDCONFIG1__Y_DATA_INVERT 0x80
|
||||
#define HOSTREG__FEEDCONFIG1_DEFVAL 0x00
|
||||
|
||||
// Feed Config Register2
|
||||
#define HOSTREG__FEEDCONFIG2 HostReg__5
|
||||
# define HOSTREG__FEEDCONFIG2__INTELLIMOUSE_MODE 0x01
|
||||
# define HOSTREG__FEEDCONFIG2__ALL_TAP_DISABLE 0x02
|
||||
# define HOSTREG__FEEDCONFIG2__SECONDARY_TAP_DISABLE 0x04
|
||||
# define HOSTREG__FEEDCONFIG2__SCROLL_DISABLE 0x08
|
||||
# define HOSTREG__FEEDCONFIG2__GLIDE_EXTEND_DISABLE 0x10
|
||||
# define HOSTREG__FEEDCONFIG2__PALM_BEFORE_Z_ENABLE 0x20
|
||||
# define HOSTREG__FEEDCONFIG2__BUTNS_46_SCROLL_5_MIDDLE 0x40
|
||||
# define HOSTREG__FEEDCONFIG2__SWAP_XY_RELATIVE 0x80
|
||||
#define HOSTREG__FEEDCONFIG2_DEFVAL 0x00
|
||||
|
||||
// Feed Config Register3
|
||||
#define HOSTREG__FEEDCONFIG3 HostReg__6
|
||||
# define HOSTREG__FEEDCONFIG3__BTNS_456_TO_123_IN_REL 0x01
|
||||
# define HOSTREG__FEEDCONFIG3__DISABLE_CROSS_RATE_SMOOTHING 0x02
|
||||
# define HOSTREG__FEEDCONFIG3__DISABLE_PALM_NERD_MEAS 0x04
|
||||
# define HOSTREG__FEEDCONFIG3__DISABLE_NOISE_AVOIDANCE 0x08
|
||||
# define HOSTREG__FEEDCONFIG3__DISABLE_WRAP_LOCKOUT 0x10
|
||||
# define HOSTREG__FEEDCONFIG3__DISABLE_DYNAMIC_EMI_ADJUST 0x20
|
||||
# define HOSTREG__FEEDCONFIG3__DISABLE_HW_EMI_DETECT 0x40
|
||||
# define HOSTREG__FEEDCONFIG3__DISABLE_SW_EMI_DETECT 0x80
|
||||
#define HOSTREG__FEEDCONFIG3_DEFVAL 0x00
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Calibration Config
|
||||
\*--------------------------------------------------------------------------*/
|
||||
#define HOSTREG__CALCONFIG1 HostReg__7
|
||||
# define HOSTREG__CALCONFIG1__CALIBRATE 0x01
|
||||
# define HOSTREG__CALCONFIG1__BACKGROUND_COMP_ENABLE 0x02
|
||||
# define HOSTREG__CALCONFIG1__NERD_COMP_ENABLE 0x04
|
||||
# define HOSTREG__CALCONFIG1__TRACK_ERROR_COMP_ENABLE 0x08
|
||||
# define HOSTREG__CALCONFIG1__TAP_COMP_ENABLE 0x10
|
||||
# define HOSTREG__CALCONFIG1__PALM_ERROR_COMP_ENABLE 0x20
|
||||
# define HOSTREG__CALCONFIG1__CALIBRATION_MATRIX_DISABLE 0x40
|
||||
# define HOSTREG__CALCONFIG1__FORCE_PRECALIBRATION_NOISE_CHECK 0x80
|
||||
#define HOSTREG__CALCONFIG1_DEFVAL (HOSTREG__CALCONFIG1__BACKGROUND_COMP_ENABLE | HOSTREG__CALCONFIG1__NERD_COMP_ENABLE | HOSTREG__CALCONFIG1__TRACK_ERROR_COMP_ENABLE | HOSTREG__CALCONFIG1__TAP_COMP_ENABLE | HOSTREG__CALCONFIG1__PALM_ERROR_COMP_ENABLE)
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
PS2 Aux Control Register
|
||||
\*--------------------------------------------------------------------------*/
|
||||
#define HOSTREG__PS2AUX_CTRL HostReg__8
|
||||
# define HOSTREG__PS2AUX_CTRL__CMD_PASSTHRU_ENABLE 0x01
|
||||
# define HOSTREG__PS2AUX_CTRL__SP_EXTENDED_MODE 0x02
|
||||
# define HOSTREG__PS2AUX_CTRL__GS_DISABLE 0x04
|
||||
# define HOSTREG__PS2AUX_CTRL__SP_DISABLE 0x08
|
||||
# define HOSTREG__PS2AUX_CTRL__GS_COORDINATE_DISABLE 0x10
|
||||
# define HOSTREG__PS2AUX_CTRL__SP_COORDINATE_DISABLE 0x20
|
||||
# define HOSTREG__PS2AUX_CTRL__DISABLE_AA00_DETECT 0x40
|
||||
# define HOSTREG__PS2AUX_CTRL__AUX_PRESENT 0x80
|
||||
#define HOSTREG__PR2AUX_CTRL_DEFVAL 0x00
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Sample Rate Value
|
||||
\*--------------------------------------------------------------------------*/
|
||||
#define HOSTREG__SAMPLERATE HostReg__9
|
||||
# define HOSTREG__SAMPLERATE__10_SPS 0x0A
|
||||
# define HOSTREG__SAMPLERATE__20_SPS 0x14
|
||||
# define HOSTREG__SAMPLERATE__40_SPS 0x28
|
||||
# define HOSTREG__SAMPLERATE__60_SPS 0x3C
|
||||
# define HOSTREG__SAMPLERATE__80_SPS 0x50
|
||||
# define HOSTREG__SAMPLERATE__100_SPS 0x64
|
||||
# define HOSTREG__SAMPLERATE__200_SPS 0xC8 // 200sps not supported
|
||||
// only for ps2 compatibility
|
||||
// rate set to 100sps
|
||||
#define HOSTREG__SAMPLERATE_DEFVAL HOSTREG__SAMPLERATE__100_SPS
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Z Idle Value
|
||||
\*--------------------------------------------------------------------------*/
|
||||
#define HOSTREG__ZIDLE HostReg__10
|
||||
#define HOSTREG__ZIDLE_DEFVAL 30 // 0x1E
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Z Scaler Value
|
||||
\*--------------------------------------------------------------------------*/
|
||||
#define HOSTREG__ZSCALER HostReg__11
|
||||
#define HOSTREG__ZSCALER_DEFVAL 8 // 0x08
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Sleep Interval Value
|
||||
\*--------------------------------------------------------------------------*/
|
||||
#define HOSTREG__SLEEP_INTERVAL HostReg__12
|
||||
#define HOSTREG__SLEEP_INTERVAL_DEFVAL 73 // 0x49
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Sleep Delay Value
|
||||
\*--------------------------------------------------------------------------*/
|
||||
#define HOSTREG__SLEEP_DELAY HostReg__13
|
||||
#define HOSTREG__SLEEP_DELAY_DEFVAL 39 // 0x27
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Dynamic EMI Bad Channel Count Thresholds
|
||||
\*--------------------------------------------------------------------------*/
|
||||
#define HOSTREG__DYNAMIC_EMI_ADJUST_THRESHOLD HostReg__14
|
||||
#define HOSTREG__DYNAMIC_EMI_ADJUST_THRESHOLD_DEFVAL 66 // 0x42
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Packet Registers
|
||||
\*--------------------------------------------------------------------------*/
|
||||
#define HOSTREG__PACKETBYTE_0 HostReg__18
|
||||
#define HOSTREG__PACKETBYTE_1 HostReg__19
|
||||
#define HOSTREG__PACKETBYTE_2 HostReg__20
|
||||
#define HOSTREG__PACKETBYTE_3 HostReg__21
|
||||
#define HOSTREG__PACKETBYTE_4 HostReg__22
|
||||
#define HOSTREG__PACKETBYTE_5 HostReg__23
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Port A GPIO Control
|
||||
\*--------------------------------------------------------------------------*/
|
||||
#define HOSTREG__PORTA_GPIO_CTRL HostReg__24
|
||||
#define HOSTREG__PORTA_GPIO_CTRL_DEFVAL 0xFF
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Port A GPIO Data
|
||||
\*--------------------------------------------------------------------------*/
|
||||
#define HOSTREG__PORTA_GPIO_DATA HostReg__25
|
||||
#define HOSTREG__PORTA_GPIO_DATA_DEFVAL 0x00
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Port B GPIO Control And Data
|
||||
\*--------------------------------------------------------------------------*/
|
||||
|
||||
#define HOSTREG__PORTB_GPIO_CTRL_DATA HostReg__26
|
||||
# define HOSTREG__PORTB_GPIO_DATA__PB0 0x01
|
||||
# define HOSTREG__PORTB_GPIO_DATA__PB1 0x02
|
||||
# define HOSTREG__PORTB_GPIO_DATA__PB2 0x04
|
||||
# define HOSTREG__PORTB_GPIO_CTRL__PB0 0x08
|
||||
# define HOSTREG__PORTB_GPIO_CTRL__PB1 0x10
|
||||
# define HOSTREG__PORTB_GPIO_CTRL__PB2 0x20
|
||||
# define HOSTREG__PORTB_GPIO_RSVD_0 0x40
|
||||
# define HOSTREG__PORTB_GPIO_READ1_WRITE0 0x80
|
||||
#define HOSTREG__PORTB_GPIO_CTRL_DATA_DEFVAL (HOSTREG__PORTB_GPIO_CTRL__PB0 | HOSTREG__PORTB_GPIO_CTRL__PB1 | HOSTREG__PORTB_GPIO_CTRL__PB2)
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Extended Register Access
|
||||
\*--------------------------------------------------------------------------*/
|
||||
#define HOSTREG__EXT_REG_AXS_VALUE HostReg__27
|
||||
|
||||
#define HOSTREG__EXT_REG_AXS_ADDR_HIGH HostReg__28
|
||||
#define HOSTREG__EXT_REG_AXS_ADDR_LOW HostReg__29
|
||||
|
||||
#define HOSTREG__EXT_REG_AXS_CTRL HostReg__30
|
||||
# define HOSTREG__EREG_AXS__READ 0x01
|
||||
# define HOSTREG__EREG_AXS__WRITE 0x02
|
||||
# define HOSTREG__EREG_AXS__INC_ADDR_READ 0x04
|
||||
# define HOSTREG__EREG_AXS__INC_ADDR_WRITE 0x08
|
||||
# define HOSTREG__EREG_AXS__RSVD_3 0x10
|
||||
# define HOSTREG__EREG_AXS__RSVD_2 0x20
|
||||
# define HOSTREG__EREG_AXS__RSVD_1 0x40
|
||||
# define HOSTREG__EREG_AXS__RSVD_0 0x80
|
||||
|
||||
#define HOSTREG__EXT_REG_AXS_VALUE_DEFVAL 0x00
|
||||
#define HOSTREG__EXT_REG_AXS_ADDR_HIGH_DEFVAL 0x00
|
||||
#define HOSTREG__EXT_REG_AXS_ADDR_LOW_DEFVAL 0x00
|
||||
#define HOSTREG__EXT_REG_AXS_CTRL_DEFVAL 0x00
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Product ID
|
||||
\*--------------------------------------------------------------------------*/
|
||||
#define HOSTREG__PRODUCT_ID HostReg__31
|
||||
|
||||
|
||||
|
||||
//Some useful values
|
||||
#define I2C_ADDRESS_DEFAULT 0x2A
|
||||
#define FIRMWARE_ID 0x07
|
||||
#define FIRMWARE_VERSION 0x9D
|
||||
|
||||
//Anymeas config options
|
||||
//First setting is HostReg 5. This sets toggle frequency (EF) and gain.
|
||||
//Gain is upper two bits (0xC0), frequency is lower 6 bits (0x3F)
|
||||
#define AnyMeas_AccumBits_ElecFreq HostReg__5
|
||||
# define ADCCNFG_ELEC_FREQ 0x3F /* Bit 4, 3, 2, 1, 0 */
|
||||
# define ADCCNFG_EF_0 0x02 // 500,000Hz
|
||||
# define ADCCNFG_EF_1 0x03 // 444,444Hz
|
||||
# define ADCCNFG_EF_2 0x04 // 400,000Hz
|
||||
# define ADCCNFG_EF_3 0x05 // 363,636Hz
|
||||
# define ADCCNFG_EF_4 0x06 // 333,333Hz
|
||||
# define ADCCNFG_EF_5 0x07 // 307,692Hz
|
||||
# define ADCCNFG_EF_6 0x09 // 267,000Hz
|
||||
# define ADCCNFG_EF_7 0x0B // 235,000Hz
|
||||
# define ADCCNFG_ACCUMBITSSELECT 0xC0 /* Bit 7, 6 */
|
||||
# define ADCCNFG_ACCBITS_17_14_0 0x00 //This is about 2x gain
|
||||
# define ADCCNFG_ACCBITS_17_15_1 0x40 //This is about 1.6x gain
|
||||
# define ADCCNFG_ACCBITS_17_2__80 0x80 //This is about 1.3x gain
|
||||
# define ADCCNFG_ACCBITS_17_2__C0 0xC0 //This is lowest gain
|
||||
//Note, all frequencies above are based on default 500ns aperture. If aperture is shorter the frequencies will be faster and if aperture is longer the frequencies will be slower.
|
||||
|
||||
//Next is HostReg 6. This sets the sample length. There are four possible settings to bit length. All other settings are not normally used and should be a 0.
|
||||
#define AnyMeas_BitLength HostReg__6
|
||||
# define ADCCTRL_BIT_LENGTH 0x03 /* Bit 1, 0 */
|
||||
# define ADCCTRL_SAMPLES_32 0x00 //Note: this does not work.
|
||||
# define ADCCTRL_SAMPLES_128 0x01
|
||||
# define ADCCTRL_SAMPLES_256 0x02
|
||||
# define ADCCTRL_SAMPLES_512 0x03
|
||||
# define ADCCTRL_ENABLE 0x20 /* Bit 5 */
|
||||
# define ADCCTRL_INT_FLAG 0x40 /* Bit 6 */
|
||||
# define ADCCTRL_START_BUSY 0x80 /* Bit 7 */
|
||||
//The smaller the sample length the faster the measurement but the lower the SNR. For high SNR requirements 512 sample length is recommended. Alternatively, multiple 128 or 256 length measurements could be averaged.
|
||||
|
||||
//Next is HostReg 7. This sets the sense mux. Pinnacle has 2 sense lines, Sense N and Sense P1. There is also a Sense P2 but it is not bonded out, it is only internal.
|
||||
//Signal on Sense N will be inverted from signal on Sense P1. Other than sign inversion, signal strength should be the same.
|
||||
#define AnyMeas_ADC_MuxControl HostReg__7
|
||||
# define ADCMUXCTRL_SENSEP1GATE 0x01 //Enables Sense P1. Can be combined with Sense N input or exclusivly Sense P1 alone.
|
||||
# define ADCMUXCTRL_SENSEP2GATE 0x02 //Not used.
|
||||
# define ADCMUXCTRL_SENSENGATE 0x04 //Enables Sense N. Can be combined with Sense P inputs or exclusivly Sense N alone.
|
||||
# define ADCMUXCTRL_REF0GATE 0x08 //This enables the RefCap0. This is a capacitor inside the chip that is roughly 0.25pF. It is also controlled with the toggle and polarity bits so those bits must be set properly as well in order to use it.
|
||||
# define ADCMUXCTRL_REF1GATE 0x10 //This enables the RefCap1. This is a capacitor inside the chip that is roughly 0.5pF. It is also controlled with the toggle and polarity bits so those bits must be set properly as well in order to use it.
|
||||
# define ADCMUXCTRL_OSCMEASEN 0x80 //this is a test mode for measuring the internal oscillator. It is for IC test only.
|
||||
|
||||
//Next is HostReg 8. This contains various ADC config settings that are not likely to be used.
|
||||
#define AnyMeas_ADC_Config2 HostReg__8
|
||||
# define ADCCNFG2_ADC_CLK_SELECT 0x01 /* Bit 0 */ //If 0 use the standard 8Mhz clock. If 1 use a divide by 2, 4Mhz clock. Only used if extra slow toggle frequencies are required.
|
||||
# define ADCCNFG2_EMI_FLAG 0x02 /* Bit 1 */ //EMI flag threshold only used with internal FW. Not valid in anymeas mode.
|
||||
# define ADCCNFG2_EMI_FLAG_THRESHOLD_0 0x04 /* Bit 2 */ //EMI flag threshold only used with internal FW. Not valid in anymeas mode.
|
||||
# define ADCCNFG2_EMI_FLAG_THRESHOLD_1 0x08 /* Bit 3 */ //EMI flag threshold only used with internal FW. Not valid in anymeas mode.
|
||||
# define ADCCNFG2_DSX2_EXTEND 0x10 /* Bit 4 */ //extend one signal on the receive. Could also be helpful in situations where sensor cap is extremely high.
|
||||
# define ADCCNFG2_ETOGGLE_DELAY 0x20 /* Bit 5 */ //delay a bit before toggling electrodes. Could be helpful in situations where sensor cap is extremely high.
|
||||
|
||||
//Next is HostReg 9. This sets the aperture length. Bottom 4 bits set the aperture width
|
||||
#define AnyMeas_ADC_AWidth HostReg__9
|
||||
# define ADCAWIDTH_AWIDTHMASK 0x0F
|
||||
# define ADCAWIDTH_APERTURE_OPEN 0x00 //does not work
|
||||
# define ADCAWIDTH_APERTURE_125NS 0x01 //does not work
|
||||
# define ADCAWIDTH_APERTURE_250NS 0x02
|
||||
# define ADCAWIDTH_APERTURE_375NS 0x03
|
||||
# define ADCAWIDTH_APERTURE_500NS 0x04
|
||||
# define ADCAWIDTH_APERTURE_625NS 0x05
|
||||
# define ADCAWIDTH_APERTURE_750NS 0x06
|
||||
# define ADCAWIDTH_APERTURE_875NS 0x07
|
||||
# define ADCAWIDTH_APERTURE_1000NS 0x08
|
||||
# define ADCAWIDTH_APERTURE_1125NS 0x09
|
||||
# define ADCAWIDTH_APERTURE_1250NS 0x0A
|
||||
# define ADCAWIDTH_APERTURE_1375NS 0x0B
|
||||
# define ADCAWIDTH_APERTURE_1500NS 0x0C
|
||||
# define ADCAWIDTH_APERTURE_1625NS 0x0D
|
||||
# define ADCAWIDTH_APERTURE_1750NS 0x0E
|
||||
# define ADCAWIDTH_APERTURE_1875NS 0x0F
|
||||
# define ADCAWIDTH_AWIDTHPLUSHALF 0x10
|
||||
# define ADCAWIDTH_AOPEN 0x20
|
||||
# define ADCAWIDTH_W2WAIT 0x40
|
||||
|
||||
//next two registers give the high and low bytes to the 16 bit address where Pinnacle will pull the measurement data. Normally these addresses are within the base 32 registers.
|
||||
#define AnyMeas_pADCMeasInfoStart_High_Byte HostReg__10
|
||||
#define AnyMeas_pADCMeasInfoStart_Low_Byte HostReg__11
|
||||
|
||||
//Next is the measurement index, this sets the measurement state machine to the start and should be a 0 at start.
|
||||
#define AnyMeas_MeasIndex HostReg__12
|
||||
# define ANYMEASSTATE_RESET_START 0x00
|
||||
# define ANYMEASSTATE_START_MEASUREMENT 0x01
|
||||
# define ANYMEASSTATE_WAIT_FOR_MEASUREMENT_AND_HOST 0x02
|
||||
|
||||
//next is the state itself of the measurement, should always be 0.
|
||||
#define AnyMeas_State HostReg__13
|
||||
|
||||
//next is the number of measurements. Use 0x80 to repeat the single measurement or repeat a number of measurements.
|
||||
//0x40 will turn the ADC off after measurements. This will result in longer startup time for a subsequent measurement, but lower idle power draw.
|
||||
#define AnyMeas_Control_NumMeas HostReg__14
|
||||
# define ANYMEAS_CONTROL__NUM_MEAS_MASK 0x3F
|
||||
# define ANYMEAS_CONTROL__ADC_POST_MEAS_PWR 0x40
|
||||
# define ANYMEAS_CONTROL__REPEAT 0x80
|
||||
|
||||
//These are not used
|
||||
#define AnyMeas_pADCMeasInfo_High_Byte HostReg__15
|
||||
#define AnyMeas_pADCMeasInfo_Low_Byte HostReg__16
|
||||
|
||||
//16 bit result of measurement will be found in these two registers.
|
||||
#define AnyMeas_Result_High_Byte HostReg__17
|
||||
#define AnyMeas_Result_Low_Byte HostReg__18
|
||||
|
||||
// ---------------- Extended Register Assignments ----------------------------
|
||||
/*--------------------------------------------------------------------------*\
|
||||
ADC Mux Control
|
||||
\*--------------------------------------------------------------------------*/
|
||||
#define EXTREG__ADCMUX_CTRL 0x00EB
|
||||
# define EXTREG__ADCMUX_CTRL__SNSP_ENABLE 0x01
|
||||
# define EXTREG__ADCMUX_CTRL__SNSN_ENABLE 0x04
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Timer Reload Registers
|
||||
\*--------------------------------------------------------------------------*/
|
||||
#define EXTREG__PACKET_TIMER_RELOAD 0x019F
|
||||
#define EXTREG__TRACK_TIMER_RELOAD 0x019E
|
||||
// These two registers should have matching content.
|
||||
# define EXTREG__TIMER_RELOAD__300_SPS 0x06
|
||||
# define EXTREG__TIMER_RELOAD__200_SPS 0x09
|
||||
# define EXTREG__TIMER_RELOAD__100_SPS 0x13
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Track ADC Config
|
||||
\*--------------------------------------------------------------------------*/
|
||||
#define EXTREG__TRACK_ADCCONFIG 0x0187
|
||||
// ADC-attenuation settings (held in BIT_7 and BIT_6)
|
||||
// 1X = most sensitive, 4X = least sensitive
|
||||
# define EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_MASK 0x3F
|
||||
# define EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_1X 0x00
|
||||
# define EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_2X 0x40
|
||||
# define EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_3X 0x80
|
||||
# define EXTREG__TRACK_ADCCONFIG__ADC_ATTENUATE_4X 0xC0
|
||||
#define EXTREG__TRACK_ADCCONFIG_DEFVAL 0x4E
|
||||
|
||||
|
||||
/*--------------------------------------------------------------------------*\
|
||||
Tune Edge Sensitivity
|
||||
\*--------------------------------------------------------------------------*/
|
||||
// These registers are not detailed in any publically available documentation
|
||||
// Names inferred from debug prints in https://github.com/cirque-corp/Cirque_Pinnacle_1CA027/blob/master/Circular_Trackpad
|
||||
#define EXTREG__XAXIS_WIDEZMIN 0x0149
|
||||
#define EXTREG__YAXIS_WIDEZMIN 0x0168
|
||||
#define EXTREG__XAXIS_WIDEZMIN_DEFVAL 0x06
|
||||
#define EXTREG__YAXIS_WIDEZMIN_DEFVAL 0x05
|
||||
|
||||
// clang-format on
|
||||
@@ -25,7 +25,7 @@ void RAP_ReadBytes(uint8_t address, uint8_t* data, uint8_t count) {
|
||||
}
|
||||
} else {
|
||||
#ifdef CONSOLE_ENABLE
|
||||
dprintf("error right touchpad\n");
|
||||
dprintf("error cirque_pinnacle spi_start read\n");
|
||||
#endif
|
||||
touchpad_init = false;
|
||||
}
|
||||
@@ -43,7 +43,7 @@ void RAP_Write(uint8_t address, uint8_t data) {
|
||||
spi_write(data);
|
||||
} else {
|
||||
#ifdef CONSOLE_ENABLE
|
||||
dprintf("error right touchpad\n");
|
||||
dprintf("error cirque_pinnacle spi_start write\n");
|
||||
#endif
|
||||
touchpad_init = false;
|
||||
}
|
||||
|
||||
172
drivers/sensors/paw3204.c
Normal file
172
drivers/sensors/paw3204.c
Normal file
@@ -0,0 +1,172 @@
|
||||
/* Copyright 2021 Gompa (@Gompa)
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
// https://github.com/shinoaliceKabocha/choco60_track/tree/master/keymaps/default
|
||||
|
||||
#include "paw3204.h"
|
||||
#include "wait.h"
|
||||
#include "debug.h"
|
||||
#include "gpio.h"
|
||||
|
||||
#define REG_PID1 0x00
|
||||
#define REG_PID2 0x01
|
||||
#define REG_STAT 0x02
|
||||
#define REG_X 0x03
|
||||
#define REG_Y 0x04
|
||||
|
||||
#define REG_SETUP 0x06
|
||||
#define REG_IMGQUAL 0x07
|
||||
#define REG_IMGREC 0x0E
|
||||
#define REG_IMGTRASH 0x0D
|
||||
|
||||
#define constrain(amt, low, high) ((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)))
|
||||
|
||||
// CPI values
|
||||
enum cpi_values {
|
||||
CPI400, // 0b000
|
||||
CPI500, // 0b001
|
||||
CPI600, // 0b010
|
||||
CPI800, // 0b011
|
||||
CPI1000, // 0b100
|
||||
CPI1200, // 0b101
|
||||
CPI1600, // 0b110
|
||||
};
|
||||
|
||||
uint8_t paw3204_serial_read(void);
|
||||
void paw3204_serial_write(uint8_t reg_addr);
|
||||
uint8_t paw3204_read_reg(uint8_t reg_addr);
|
||||
void paw3204_write_reg(uint8_t reg_addr, uint8_t data);
|
||||
|
||||
void paw3204_init(void) {
|
||||
setPinOutput(PAW3204_SCLK_PIN); // setclockpin to output
|
||||
setPinInputHigh(PAW3204_SDIO_PIN); // set datapin input high
|
||||
|
||||
paw3204_write_reg(REG_SETUP, 0x86); // reset sensor and set 1600cpi
|
||||
wait_us(5);
|
||||
|
||||
paw3204_read_reg(0x00); // read id
|
||||
paw3204_read_reg(0x01); // read id2
|
||||
// PAW3204_write_reg(REG_SETUP,0x06); // dont reset sensor and set cpi 1600
|
||||
paw3204_write_reg(REG_IMGTRASH, 0x32); // write image trashhold
|
||||
}
|
||||
|
||||
uint8_t paw3204_serial_read(void) {
|
||||
setPinInput(PAW3204_SDIO_PIN);
|
||||
uint8_t byte = 0;
|
||||
|
||||
for (uint8_t i = 0; i < 8; ++i) {
|
||||
writePinLow(PAW3204_SCLK_PIN);
|
||||
wait_us(1);
|
||||
|
||||
byte = (byte << 1) | readPin(PAW3204_SDIO_PIN);
|
||||
|
||||
writePinHigh(PAW3204_SCLK_PIN);
|
||||
wait_us(1);
|
||||
}
|
||||
|
||||
return byte;
|
||||
}
|
||||
|
||||
void paw3204_serial_write(uint8_t data) {
|
||||
writePinLow(PAW3204_SDIO_PIN);
|
||||
setPinOutput(PAW3204_SDIO_PIN);
|
||||
|
||||
for (int8_t b = 7; b >= 0; b--) {
|
||||
writePinLow(PAW3204_SCLK_PIN);
|
||||
if (data & (1 << b)) {
|
||||
writePinHigh(PAW3204_SDIO_PIN);
|
||||
} else {
|
||||
writePinLow(PAW3204_SDIO_PIN);
|
||||
}
|
||||
writePinHigh(PAW3204_SCLK_PIN);
|
||||
}
|
||||
|
||||
wait_us(4);
|
||||
}
|
||||
|
||||
report_paw3204_t paw3204_read(void) {
|
||||
report_paw3204_t data = {0};
|
||||
|
||||
data.isMotion = paw3204_read_reg(REG_STAT) & (1 << 7); // check for motion only (bit 7 in field)
|
||||
data.x = (int8_t)paw3204_read_reg(REG_X);
|
||||
data.y = (int8_t)paw3204_read_reg(REG_Y);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
void paw3204_write_reg(uint8_t reg_addr, uint8_t data) {
|
||||
paw3204_serial_write(0b10000000 | reg_addr);
|
||||
paw3204_serial_write(data);
|
||||
}
|
||||
|
||||
uint8_t paw3204_read_reg(uint8_t reg_addr) {
|
||||
paw3204_serial_write(reg_addr);
|
||||
wait_us(5);
|
||||
return paw3204_serial_read();
|
||||
}
|
||||
|
||||
void paw3204_set_cpi(uint16_t cpi) {
|
||||
uint8_t cpival = CPI1000;
|
||||
if (cpi <= 450) {
|
||||
cpival = CPI400;
|
||||
} else if (cpi <= 550) {
|
||||
cpival = CPI500;
|
||||
} else if (cpi <= 700) {
|
||||
cpival = CPI600;
|
||||
} else if (cpi <= 900) {
|
||||
cpival = CPI800;
|
||||
} else if (cpi <= 1100) {
|
||||
cpival = CPI1000;
|
||||
} else if (cpi <= 1400) {
|
||||
cpival = CPI1200;
|
||||
} else if (cpi > 1400) {
|
||||
cpival = CPI1600;
|
||||
}
|
||||
paw3204_write_reg(REG_SETUP, cpival);
|
||||
}
|
||||
|
||||
uint16_t paw3204_get_cpi(void) {
|
||||
uint16_t cpival = 1000;
|
||||
|
||||
switch (paw3204_read_reg(REG_SETUP) & 0b111) {
|
||||
case CPI400:
|
||||
cpival = 400;
|
||||
break;
|
||||
case CPI500:
|
||||
cpival = 500;
|
||||
break;
|
||||
case CPI600:
|
||||
cpival = 600;
|
||||
break;
|
||||
case CPI800:
|
||||
cpival = 800;
|
||||
break;
|
||||
case CPI1000:
|
||||
cpival = 1000;
|
||||
break;
|
||||
case CPI1200:
|
||||
cpival = 1200;
|
||||
break;
|
||||
case CPI1600:
|
||||
cpival = 1600;
|
||||
break;
|
||||
}
|
||||
return cpival;
|
||||
}
|
||||
|
||||
uint8_t read_pid_paw3204(void) {
|
||||
return paw3204_read_reg(REG_PID1);
|
||||
}
|
||||
68
drivers/sensors/paw3204.h
Normal file
68
drivers/sensors/paw3204.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* Copyright 2021 Gompa (@Gompa)
|
||||
*
|
||||
* 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>
|
||||
|
||||
#ifndef PAW3204_SCLK_PIN
|
||||
# error "No clock pin defined -- missing PAW3204_SCLK_PIN"
|
||||
#endif
|
||||
#ifndef PAW3204_SDIO_PIN
|
||||
# error "No data pin defined -- missing PAW3204_SDIO_PIN"
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
bool isMotion;
|
||||
} report_paw3204_t;
|
||||
|
||||
/**
|
||||
* @brief Initializes the sensor so it is in a working state and ready to
|
||||
* be polled for data.
|
||||
*
|
||||
* @return true Initialization was a success
|
||||
* @return false Initialization failed, do not proceed operation
|
||||
*/
|
||||
void paw3204_init(void);
|
||||
|
||||
/**
|
||||
* @brief Reads and clears the current delta, and motion register values on the
|
||||
* given sensor.
|
||||
*
|
||||
* @return pmw33xx_report_t Current values of the sensor, if errors occurred all
|
||||
* fields are set to zero
|
||||
*/
|
||||
|
||||
report_paw3204_t paw3204_read(void);
|
||||
/**
|
||||
* @brief Sets the given CPI value the sensor. CPI is often refereed to
|
||||
* as the sensors sensitivity. Values outside of the allowed range are
|
||||
* constrained into legal values.
|
||||
*
|
||||
* @param cpi CPI value to set
|
||||
*/
|
||||
void paw3204_set_cpi(uint16_t cpi);
|
||||
|
||||
/**
|
||||
* @brief Gets the currently set CPI value from the sensor. CPI is often
|
||||
* refereed to as the sensors sensitivity.
|
||||
*
|
||||
* @return uint16_t Current CPI value of the sensor
|
||||
*/
|
||||
uint16_t paw3204_get_cpi(void);
|
||||
@@ -95,16 +95,3 @@ int16_t pimoroni_trackball_get_offsets(uint8_t negative_dir, uint8_t positive_di
|
||||
uint16_t magnitude = (scale * offset * offset * precision) >> 7;
|
||||
return isnegative ? -(int16_t)(magnitude) : (int16_t)(magnitude);
|
||||
}
|
||||
|
||||
void pimoroni_trackball_adapt_values(int8_t* mouse, int16_t* offset) {
|
||||
if (*offset > 127) {
|
||||
*mouse = 127;
|
||||
*offset -= 127;
|
||||
} else if (*offset < -127) {
|
||||
*mouse = -127;
|
||||
*offset += 127;
|
||||
} else {
|
||||
*mouse = *offset;
|
||||
*offset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,6 @@ typedef struct {
|
||||
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);
|
||||
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);
|
||||
|
||||
@@ -1,291 +1,294 @@
|
||||
/* Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
|
||||
* Copyright 2019 Sunjun Kim
|
||||
* Copyright 2020 Ploopy Corporation
|
||||
* Copyright 2022 Ulrich Spörlein
|
||||
*
|
||||
* 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/>.
|
||||
*/
|
||||
// Copyright 2022 Stefan Kerkmann (KarlK90)
|
||||
// Copyright 2022 Ulrich Spörlein (@uqs)
|
||||
// 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
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "spi_master.h"
|
||||
#include "pmw3360.h"
|
||||
#include "wait.h"
|
||||
#include "debug.h"
|
||||
#include "print.h"
|
||||
#include "pmw3360_firmware.h"
|
||||
#include "pmw33xx_common.h"
|
||||
#include "progmem.h"
|
||||
|
||||
// Registers
|
||||
extern const size_t pmw33xx_number_of_sensors;
|
||||
|
||||
uint16_t pmw33xx_get_cpi(uint8_t sensor) {
|
||||
if (sensor >= pmw33xx_number_of_sensors) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint8_t cpival = pmw33xx_read(sensor, REG_Config1);
|
||||
return (uint16_t)((cpival + 1) & 0xFF) * PMW33XX_CPI_STEP;
|
||||
}
|
||||
|
||||
void pmw33xx_set_cpi(uint8_t sensor, uint16_t cpi) {
|
||||
if (sensor >= pmw33xx_number_of_sensors) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t cpival = CONSTRAIN((cpi / PMW33XX_CPI_STEP) - 1, 0, (PMW33XX_CPI_MAX / PMW33XX_CPI_STEP) - 1U);
|
||||
pmw33xx_write(sensor, REG_Config1, cpival);
|
||||
}
|
||||
|
||||
// PID, Inverse PID, SROM version
|
||||
const uint8_t pmw33xx_firmware_signature[3] PROGMEM = {0x42, 0xBD, 0x04};
|
||||
|
||||
// Firmware Blob for PMW3360
|
||||
// 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 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
|
||||
#endif
|
||||
|
||||
static const pin_t pins[] = PMW3360_CS_PINS;
|
||||
#define NUMBER_OF_SENSORS (sizeof(pins) / sizeof(pin_t))
|
||||
|
||||
// per-sensor driver state
|
||||
static bool _inBurst[NUMBER_OF_SENSORS] = {0};
|
||||
|
||||
#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 pmw3360_spi_start(int8_t index) {
|
||||
bool status = spi_start(pins[index], PMW3360_SPI_LSBFIRST, PMW3360_SPI_MODE, PMW3360_SPI_DIVISOR);
|
||||
// tNCS-SCLK, 120ns
|
||||
wait_us(1);
|
||||
return status;
|
||||
}
|
||||
|
||||
spi_status_t pmw3360_write(int8_t index, uint8_t reg_addr, uint8_t data) {
|
||||
pmw3360_spi_start(index);
|
||||
|
||||
if (reg_addr != REG_Motion_Burst) {
|
||||
_inBurst[index] = 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 35us
|
||||
wait_us(35);
|
||||
spi_stop();
|
||||
|
||||
// tSWW/tSWR (=180us) minus tSCLK-NCS. Could be shortened, but it looks like a safe lower bound
|
||||
wait_us(145);
|
||||
return status;
|
||||
}
|
||||
|
||||
uint8_t pmw3360_read(int8_t index, uint8_t reg_addr) {
|
||||
pmw3360_spi_start(index);
|
||||
// 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);
|
||||
return data;
|
||||
}
|
||||
|
||||
bool pmw3360_check_signature(int8_t index) {
|
||||
uint8_t pid = pmw3360_read(index, REG_Product_ID);
|
||||
uint8_t iv_pid = pmw3360_read(index, REG_Inverse_Product_ID);
|
||||
uint8_t SROM_ver = pmw3360_read(index, REG_SROM_ID);
|
||||
return (pid == firmware_signature[0] && iv_pid == firmware_signature[1] && SROM_ver == firmware_signature[2]); // signature for SROM 0x04
|
||||
}
|
||||
|
||||
void pmw3360_upload_firmware(int8_t index) {
|
||||
// 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(index, REG_Config2, 0x00); // disable REST mode
|
||||
pmw3360_write(index, REG_SROM_Enable, 0x1d);
|
||||
|
||||
wait_ms(10);
|
||||
|
||||
pmw3360_write(index, REG_SROM_Enable, 0x18);
|
||||
|
||||
pmw3360_spi_start(index);
|
||||
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 PMW3360_FIRMWARE_UPLOAD_FAST
|
||||
wait_us(15);
|
||||
#endif
|
||||
}
|
||||
wait_us(200);
|
||||
|
||||
pmw3360_read(index, REG_SROM_ID);
|
||||
pmw3360_write(index, REG_Config2, 0x00);
|
||||
}
|
||||
|
||||
bool pmw3360_init(int8_t index) {
|
||||
if (index >= NUMBER_OF_SENSORS) {
|
||||
return false;
|
||||
}
|
||||
spi_init();
|
||||
|
||||
// power up, need to first drive NCS high then low.
|
||||
// the datasheet does not say for how long, 40us works well in practice.
|
||||
pmw3360_spi_start(index);
|
||||
wait_us(40);
|
||||
spi_stop();
|
||||
wait_us(40);
|
||||
pmw3360_write(index, REG_Power_Up_Reset, 0x5a);
|
||||
wait_ms(50);
|
||||
|
||||
// read registers and discard
|
||||
pmw3360_read(index, REG_Motion);
|
||||
pmw3360_read(index, REG_Delta_X_L);
|
||||
pmw3360_read(index, REG_Delta_X_H);
|
||||
pmw3360_read(index, REG_Delta_Y_L);
|
||||
pmw3360_read(index, REG_Delta_Y_H);
|
||||
|
||||
pmw3360_upload_firmware(index);
|
||||
|
||||
spi_stop();
|
||||
|
||||
wait_ms(10);
|
||||
pmw3360_set_cpi(PMW3360_CPI);
|
||||
|
||||
wait_ms(1);
|
||||
|
||||
pmw3360_write(index, REG_Config2, 0x00);
|
||||
|
||||
pmw3360_write(index, REG_Angle_Tune, constrain(ROTATIONAL_TRANSFORM_ANGLE, -127, 127));
|
||||
|
||||
pmw3360_write(index, REG_Lift_Config, PMW3360_LIFTOFF_DISTANCE);
|
||||
|
||||
bool init_success = pmw3360_check_signature(index);
|
||||
#ifdef CONSOLE_ENABLE
|
||||
if (init_success) {
|
||||
dprintf("pmw3360 signature verified");
|
||||
} else {
|
||||
dprintf("pmw3360 signature verification failed!");
|
||||
}
|
||||
#endif
|
||||
|
||||
return init_success;
|
||||
}
|
||||
|
||||
// Only support reading the value from sensor #0, no one is using this anyway.
|
||||
uint16_t pmw3360_get_cpi(void) {
|
||||
uint8_t cpival = pmw3360_read(0, REG_Config1);
|
||||
return (uint16_t)((cpival + 1) & 0xFF) * CPI_STEP;
|
||||
}
|
||||
|
||||
// Write same CPI to all sensors.
|
||||
void pmw3360_set_cpi(uint16_t cpi) {
|
||||
uint8_t cpival = constrain((cpi / CPI_STEP) - 1, 0, MAX_CPI);
|
||||
for (size_t i = 0; i < NUMBER_OF_SENSORS; i++) {
|
||||
pmw3360_write(i, REG_Config1, cpival);
|
||||
}
|
||||
}
|
||||
|
||||
report_pmw3360_t pmw3360_read_burst(int8_t index) {
|
||||
report_pmw3360_t report = {0};
|
||||
if (index >= NUMBER_OF_SENSORS) {
|
||||
return report;
|
||||
}
|
||||
|
||||
if (!_inBurst[index]) {
|
||||
#ifdef CONSOLE_ENABLE
|
||||
dprintf("burst on for index %d", index);
|
||||
#endif
|
||||
pmw3360_write(index, REG_Motion_Burst, 0x00);
|
||||
_inBurst[index] = true;
|
||||
}
|
||||
|
||||
pmw3360_spi_start(index);
|
||||
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[index] = 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;
|
||||
}
|
||||
const uint8_t pmw33xx_firmware_data[PMW33XX_FIRMWARE_LENGTH] PROGMEM = {
|
||||
0x01, 0x04, 0x8E, 0x96, 0x6E, 0x77, 0x3E, 0xFE, 0x7E, 0x5F, 0x1D, 0xB8, 0xF2, 0x66, 0x4E, 0xFF,
|
||||
0x5D, 0x19, 0xB0, 0xC2, 0x04, 0x69, 0x54, 0x2A, 0xD6, 0x2E, 0xBF, 0xDD, 0x19, 0xB0, 0xC3, 0xE5,
|
||||
0x29, 0xB1, 0xE0, 0x23, 0xA5, 0xA9, 0xB1, 0xC1, 0x00, 0x82, 0x67, 0x4C, 0x1A, 0x97, 0x8D, 0x79,
|
||||
0x51, 0x20, 0xC7, 0x06, 0x8E, 0x7C, 0x7C, 0x7A, 0x76, 0x4F, 0xFD, 0x59, 0x30, 0xE2, 0x46, 0x0E,
|
||||
0x9E, 0xBE, 0xDF, 0x1D, 0x99, 0x91, 0xA0, 0xA5, 0xA1, 0xA9, 0xD0, 0x22, 0xC6, 0xEF, 0x5C, 0x1B,
|
||||
0x95, 0x89, 0x90, 0xA2, 0xA7, 0xCC, 0xFB, 0x55, 0x28, 0xB3, 0xE4, 0x4A, 0xF7, 0x6C, 0x3B, 0xF4,
|
||||
0x6A, 0x56, 0x2E, 0xDE, 0x1F, 0x9D, 0xB8, 0xD3, 0x05, 0x88, 0x92, 0xA6, 0xCE, 0x1E, 0xBE, 0xDF,
|
||||
0x1D, 0x99, 0xB0, 0xE2, 0x46, 0xEF, 0x5C, 0x07, 0x11, 0x5D, 0x98, 0x0B, 0x9D, 0x94, 0x97, 0xEE,
|
||||
0x4E, 0x45, 0x33, 0x6B, 0x44, 0xC7, 0x29, 0x56, 0x27, 0x30, 0xC6, 0xA7, 0xD5, 0xF2, 0x56, 0xDF,
|
||||
0xB4, 0x38, 0x62, 0xCB, 0xA0, 0xB6, 0xE3, 0x0F, 0x84, 0x06, 0x24, 0x05, 0x65, 0x6F, 0x76, 0x89,
|
||||
0xB5, 0x77, 0x41, 0x27, 0x82, 0x66, 0x65, 0x82, 0xCC, 0xD5, 0xE6, 0x20, 0xD5, 0x27, 0x17, 0xC5,
|
||||
0xF8, 0x03, 0x23, 0x7C, 0x5F, 0x64, 0xA5, 0x1D, 0xC1, 0xD6, 0x36, 0xCB, 0x4C, 0xD4, 0xDB, 0x66,
|
||||
0xD7, 0x8B, 0xB1, 0x99, 0x7E, 0x6F, 0x4C, 0x36, 0x40, 0x06, 0xD6, 0xEB, 0xD7, 0xA2, 0xE4, 0xF4,
|
||||
0x95, 0x51, 0x5A, 0x54, 0x96, 0xD5, 0x53, 0x44, 0xD7, 0x8C, 0xE0, 0xB9, 0x40, 0x68, 0xD2, 0x18,
|
||||
0xE9, 0xDD, 0x9A, 0x23, 0x92, 0x48, 0xEE, 0x7F, 0x43, 0xAF, 0xEA, 0x77, 0x38, 0x84, 0x8C, 0x0A,
|
||||
0x72, 0xAF, 0x69, 0xF8, 0xDD, 0xF1, 0x24, 0x83, 0xA3, 0xF8, 0x4A, 0xBF, 0xF5, 0x94, 0x13, 0xDB,
|
||||
0xBB, 0xD8, 0xB4, 0xB3, 0xA0, 0xFB, 0x45, 0x50, 0x60, 0x30, 0x59, 0x12, 0x31, 0x71, 0xA2, 0xD3,
|
||||
0x13, 0xE7, 0xFA, 0xE7, 0xCE, 0x0F, 0x63, 0x15, 0x0B, 0x6B, 0x94, 0xBB, 0x37, 0x83, 0x26, 0x05,
|
||||
0x9D, 0xFB, 0x46, 0x92, 0xFC, 0x0A, 0x15, 0xD1, 0x0D, 0x73, 0x92, 0xD6, 0x8C, 0x1B, 0x8C, 0xB8,
|
||||
0x55, 0x8A, 0xCE, 0xBD, 0xFE, 0x8E, 0xFC, 0xED, 0x09, 0x12, 0x83, 0x91, 0x82, 0x51, 0x31, 0x23,
|
||||
0xFB, 0xB4, 0x0C, 0x76, 0xAD, 0x7C, 0xD9, 0xB4, 0x4B, 0xB2, 0x67, 0x14, 0x09, 0x9C, 0x7F, 0x0C,
|
||||
0x18, 0xBA, 0x3B, 0xD6, 0x8E, 0x14, 0x2A, 0xE4, 0x1B, 0x52, 0x9F, 0x2B, 0x7D, 0xE1, 0xFB, 0x6A,
|
||||
0x33, 0x02, 0xFA, 0xAC, 0x5A, 0xF2, 0x3E, 0x88, 0x7E, 0xAE, 0xD1, 0xF3, 0x78, 0xE8, 0x05, 0xD1,
|
||||
0xE3, 0xDC, 0x21, 0xF6, 0xE1, 0x9A, 0xBD, 0x17, 0x0E, 0xD9, 0x46, 0x9B, 0x88, 0x03, 0xEA, 0xF6,
|
||||
0x66, 0xBE, 0x0E, 0x1B, 0x50, 0x49, 0x96, 0x40, 0x97, 0xF1, 0xF1, 0xE4, 0x80, 0xA6, 0x6E, 0xE8,
|
||||
0x77, 0x34, 0xBF, 0x29, 0x40, 0x44, 0xC2, 0xFF, 0x4E, 0x98, 0xD3, 0x9C, 0xA3, 0x32, 0x2B, 0x76,
|
||||
0x51, 0x04, 0x09, 0xE7, 0xA9, 0xD1, 0xA6, 0x32, 0xB1, 0x23, 0x53, 0xE2, 0x47, 0xAB, 0xD6, 0xF5,
|
||||
0x69, 0x5C, 0x3E, 0x5F, 0xFA, 0xAE, 0x45, 0x20, 0xE5, 0xD2, 0x44, 0xFF, 0x39, 0x32, 0x6D, 0xFD,
|
||||
0x27, 0x57, 0x5C, 0xFD, 0xF0, 0xDE, 0xC1, 0xB5, 0x99, 0xE5, 0xF5, 0x1C, 0x77, 0x01, 0x75, 0xC5,
|
||||
0x6D, 0x58, 0x92, 0xF2, 0xB2, 0x47, 0x00, 0x01, 0x26, 0x96, 0x7A, 0x30, 0xFF, 0xB7, 0xF0, 0xEF,
|
||||
0x77, 0xC1, 0x8A, 0x5D, 0xDC, 0xC0, 0xD1, 0x29, 0x30, 0x1E, 0x77, 0x38, 0x7A, 0x94, 0xF1, 0xB8,
|
||||
0x7A, 0x7E, 0xEF, 0xA4, 0xD1, 0xAC, 0x31, 0x4A, 0xF2, 0x5D, 0x64, 0x3D, 0xB2, 0xE2, 0xF0, 0x08,
|
||||
0x99, 0xFC, 0x70, 0xEE, 0x24, 0xA7, 0x7E, 0xEE, 0x1E, 0x20, 0x69, 0x7D, 0x44, 0xBF, 0x87, 0x42,
|
||||
0xDF, 0x88, 0x3B, 0x0C, 0xDA, 0x42, 0xC9, 0x04, 0xF9, 0x45, 0x50, 0xFC, 0x83, 0x8F, 0x11, 0x6A,
|
||||
0x72, 0xBC, 0x99, 0x95, 0xF0, 0xAC, 0x3D, 0xA7, 0x3B, 0xCD, 0x1C, 0xE2, 0x88, 0x79, 0x37, 0x11,
|
||||
0x5F, 0x39, 0x89, 0x95, 0x0A, 0x16, 0x84, 0x7A, 0xF6, 0x8A, 0xA4, 0x28, 0xE4, 0xED, 0x83, 0x80,
|
||||
0x3B, 0xB1, 0x23, 0xA5, 0x03, 0x10, 0xF4, 0x66, 0xEA, 0xBB, 0x0C, 0x0F, 0xC5, 0xEC, 0x6C, 0x69,
|
||||
0xC5, 0xD3, 0x24, 0xAB, 0xD4, 0x2A, 0xB7, 0x99, 0x88, 0x76, 0x08, 0xA0, 0xA8, 0x95, 0x7C, 0xD8,
|
||||
0x38, 0x6D, 0xCD, 0x59, 0x02, 0x51, 0x4B, 0xF1, 0xB5, 0x2B, 0x50, 0xE3, 0xB6, 0xBD, 0xD0, 0x72,
|
||||
0xCF, 0x9E, 0xFD, 0x6E, 0xBB, 0x44, 0xC8, 0x24, 0x8A, 0x77, 0x18, 0x8A, 0x13, 0x06, 0xEF, 0x97,
|
||||
0x7D, 0xFA, 0x81, 0xF0, 0x31, 0xE6, 0xFA, 0x77, 0xED, 0x31, 0x06, 0x31, 0x5B, 0x54, 0x8A, 0x9F,
|
||||
0x30, 0x68, 0xDB, 0xE2, 0x40, 0xF8, 0x4E, 0x73, 0xFA, 0xAB, 0x74, 0x8B, 0x10, 0x58, 0x13, 0xDC,
|
||||
0xD2, 0xE6, 0x78, 0xD1, 0x32, 0x2E, 0x8A, 0x9F, 0x2C, 0x58, 0x06, 0x48, 0x27, 0xC5, 0xA9, 0x5E,
|
||||
0x81, 0x47, 0x89, 0x46, 0x21, 0x91, 0x03, 0x70, 0xA4, 0x3E, 0x88, 0x9C, 0xDA, 0x33, 0x0A, 0xCE,
|
||||
0xBC, 0x8B, 0x8E, 0xCF, 0x9F, 0xD3, 0x71, 0x80, 0x43, 0xCF, 0x6B, 0xA9, 0x51, 0x83, 0x76, 0x30,
|
||||
0x82, 0xC5, 0x6A, 0x85, 0x39, 0x11, 0x50, 0x1A, 0x82, 0xDC, 0x1E, 0x1C, 0xD5, 0x7D, 0xA9, 0x71,
|
||||
0x99, 0x33, 0x47, 0x19, 0x97, 0xB3, 0x5A, 0xB1, 0xDF, 0xED, 0xA4, 0xF2, 0xE6, 0x26, 0x84, 0xA2,
|
||||
0x28, 0x9A, 0x9E, 0xDF, 0xA6, 0x6A, 0xF4, 0xD6, 0xFC, 0x2E, 0x5B, 0x9D, 0x1A, 0x2A, 0x27, 0x68,
|
||||
0xFB, 0xC1, 0x83, 0x21, 0x4B, 0x90, 0xE0, 0x36, 0xDD, 0x5B, 0x31, 0x42, 0x55, 0xA0, 0x13, 0xF7,
|
||||
0xD0, 0x89, 0x53, 0x71, 0x99, 0x57, 0x09, 0x29, 0xC5, 0xF3, 0x21, 0xF8, 0x37, 0x2F, 0x40, 0xF3,
|
||||
0xD4, 0xAF, 0x16, 0x08, 0x36, 0x02, 0xFC, 0x77, 0xC5, 0x8B, 0x04, 0x90, 0x56, 0xB9, 0xC9, 0x67,
|
||||
0x9A, 0x99, 0xE8, 0x00, 0xD3, 0x86, 0xFF, 0x97, 0x2D, 0x08, 0xE9, 0xB7, 0xB3, 0x91, 0xBC, 0xDF,
|
||||
0x45, 0xC6, 0xED, 0x0F, 0x8C, 0x4C, 0x1E, 0xE6, 0x5B, 0x6E, 0x38, 0x30, 0xE4, 0xAA, 0xE3, 0x95,
|
||||
0xDE, 0xB9, 0xE4, 0x9A, 0xF5, 0xB2, 0x55, 0x9A, 0x87, 0x9B, 0xF6, 0x6A, 0xB2, 0xF2, 0x77, 0x9A,
|
||||
0x31, 0xF4, 0x7A, 0x31, 0xD1, 0x1D, 0x04, 0xC0, 0x7C, 0x32, 0xA2, 0x9E, 0x9A, 0xF5, 0x62, 0xF8,
|
||||
0x27, 0x8D, 0xBF, 0x51, 0xFF, 0xD3, 0xDF, 0x64, 0x37, 0x3F, 0x2A, 0x6F, 0x76, 0x3A, 0x7D, 0x77,
|
||||
0x06, 0x9E, 0x77, 0x7F, 0x5E, 0xEB, 0x32, 0x51, 0xF9, 0x16, 0x66, 0x9A, 0x09, 0xF3, 0xB0, 0x08,
|
||||
0xA4, 0x70, 0x96, 0x46, 0x30, 0xFF, 0xDA, 0x4F, 0xE9, 0x1B, 0xED, 0x8D, 0xF8, 0x74, 0x1F, 0x31,
|
||||
0x92, 0xB3, 0x73, 0x17, 0x36, 0xDB, 0x91, 0x30, 0xD6, 0x88, 0x55, 0x6B, 0x34, 0x77, 0x87, 0x7A,
|
||||
0xE7, 0xEE, 0x06, 0xC6, 0x1C, 0x8C, 0x19, 0x0C, 0x48, 0x46, 0x23, 0x5E, 0x9C, 0x07, 0x5C, 0xBF,
|
||||
0xB4, 0x7E, 0xD6, 0x4F, 0x74, 0x9C, 0xE2, 0xC5, 0x50, 0x8B, 0xC5, 0x8B, 0x15, 0x90, 0x60, 0x62,
|
||||
0x57, 0x29, 0xD0, 0x13, 0x43, 0xA1, 0x80, 0x88, 0x91, 0x00, 0x44, 0xC7, 0x4D, 0x19, 0x86, 0xCC,
|
||||
0x2F, 0x2A, 0x75, 0x5A, 0xFC, 0xEB, 0x97, 0x2A, 0x70, 0xE3, 0x78, 0xD8, 0x91, 0xB0, 0x4F, 0x99,
|
||||
0x07, 0xA3, 0x95, 0xEA, 0x24, 0x21, 0xD5, 0xDE, 0x51, 0x20, 0x93, 0x27, 0x0A, 0x30, 0x73, 0xA8,
|
||||
0xFF, 0x8A, 0x97, 0xE9, 0xA7, 0x6A, 0x8E, 0x0D, 0xE8, 0xF0, 0xDF, 0xEC, 0xEA, 0xB4, 0x6C, 0x1D,
|
||||
0x39, 0x2A, 0x62, 0x2D, 0x3D, 0x5A, 0x8B, 0x65, 0xF8, 0x90, 0x05, 0x2E, 0x7E, 0x91, 0x2C, 0x78,
|
||||
0xEF, 0x8E, 0x7A, 0xC1, 0x2F, 0xAC, 0x78, 0xEE, 0xAF, 0x28, 0x45, 0x06, 0x4C, 0x26, 0xAF, 0x3B,
|
||||
0xA2, 0xDB, 0xA3, 0x93, 0x06, 0xB5, 0x3C, 0xA5, 0xD8, 0xEE, 0x8F, 0xAF, 0x25, 0xCC, 0x3F, 0x85,
|
||||
0x68, 0x48, 0xA9, 0x62, 0xCC, 0x97, 0x8F, 0x7F, 0x2A, 0xEA, 0xE0, 0x15, 0x0A, 0xAD, 0x62, 0x07,
|
||||
0xBD, 0x45, 0xF8, 0x41, 0xD8, 0x36, 0xCB, 0x4C, 0xDB, 0x6E, 0xE6, 0x3A, 0xE7, 0xDA, 0x15, 0xE9,
|
||||
0x29, 0x1E, 0x12, 0x10, 0xA0, 0x14, 0x2C, 0x0E, 0x3D, 0xF4, 0xBF, 0x39, 0x41, 0x92, 0x75, 0x0B,
|
||||
0x25, 0x7B, 0xA3, 0xCE, 0x39, 0x9C, 0x15, 0x64, 0xC8, 0xFA, 0x3D, 0xEF, 0x73, 0x27, 0xFE, 0x26,
|
||||
0x2E, 0xCE, 0xDA, 0x6E, 0xFD, 0x71, 0x8E, 0xDD, 0xFE, 0x76, 0xEE, 0xDC, 0x12, 0x5C, 0x02, 0xC5,
|
||||
0x3A, 0x4E, 0x4E, 0x4F, 0xBF, 0xCA, 0x40, 0x15, 0xC7, 0x6E, 0x8D, 0x41, 0xF1, 0x10, 0xE0, 0x4F,
|
||||
0x7E, 0x97, 0x7F, 0x1C, 0xAE, 0x47, 0x8E, 0x6B, 0xB1, 0x25, 0x31, 0xB0, 0x73, 0xC7, 0x1B, 0x97,
|
||||
0x79, 0xF9, 0x80, 0xD3, 0x66, 0x22, 0x30, 0x07, 0x74, 0x1E, 0xE4, 0xD0, 0x80, 0x21, 0xD6, 0xEE,
|
||||
0x6B, 0x6C, 0x4F, 0xBF, 0xF5, 0xB7, 0xD9, 0x09, 0x87, 0x2F, 0xA9, 0x14, 0xBE, 0x27, 0xD9, 0x72,
|
||||
0x50, 0x01, 0xD4, 0x13, 0x73, 0xA6, 0xA7, 0x51, 0x02, 0x75, 0x25, 0xE1, 0xB3, 0x45, 0x34, 0x7D,
|
||||
0xA8, 0x8E, 0xEB, 0xF3, 0x16, 0x49, 0xCB, 0x4F, 0x8C, 0xA1, 0xB9, 0x36, 0x85, 0x39, 0x75, 0x5D,
|
||||
0x08, 0x00, 0xAE, 0xEB, 0xF6, 0xEA, 0xD7, 0x13, 0x3A, 0x21, 0x5A, 0x5F, 0x30, 0x84, 0x52, 0x26,
|
||||
0x95, 0xC9, 0x14, 0xF2, 0x57, 0x55, 0x6B, 0xB1, 0x10, 0xC2, 0xE1, 0xBD, 0x3B, 0x51, 0xC0, 0xB7,
|
||||
0x55, 0x4C, 0x71, 0x12, 0x26, 0xC7, 0x0D, 0xF9, 0x51, 0xA4, 0x38, 0x02, 0x05, 0x7F, 0xB8, 0xF1,
|
||||
0x72, 0x4B, 0xBF, 0x71, 0x89, 0x14, 0xF3, 0x77, 0x38, 0xD9, 0x71, 0x24, 0xF3, 0x00, 0x11, 0xA1,
|
||||
0xD8, 0xD4, 0x69, 0x27, 0x08, 0x37, 0x35, 0xC9, 0x11, 0x9D, 0x90, 0x1C, 0x0E, 0xE7, 0x1C, 0xFF,
|
||||
0x2D, 0x1E, 0xE8, 0x92, 0xE1, 0x18, 0x10, 0x95, 0x7C, 0xE0, 0x80, 0xF4, 0x96, 0x43, 0x21, 0xF9,
|
||||
0x75, 0x21, 0x64, 0x38, 0xDD, 0x9F, 0x1E, 0x95, 0x16, 0xDA, 0x56, 0x1D, 0x4F, 0x9A, 0x53, 0xB2,
|
||||
0xE2, 0xE4, 0x18, 0xCB, 0x6B, 0x1A, 0x65, 0xEB, 0x56, 0xC6, 0x3B, 0xE5, 0xFE, 0xD8, 0x26, 0x3F,
|
||||
0x3A, 0x84, 0x59, 0x72, 0x66, 0xA2, 0xF3, 0x75, 0xFF, 0xFB, 0x60, 0xB3, 0x22, 0xAD, 0x3F, 0x2D,
|
||||
0x6B, 0xF9, 0xEB, 0xEA, 0x05, 0x7C, 0xD8, 0x8F, 0x6D, 0x2C, 0x98, 0x9E, 0x2B, 0x93, 0xF1, 0x5E,
|
||||
0x46, 0xF0, 0x87, 0x49, 0x29, 0x73, 0x68, 0xD7, 0x7F, 0xF9, 0xF0, 0xE5, 0x7D, 0xDB, 0x1D, 0x75,
|
||||
0x19, 0xF3, 0xC4, 0x58, 0x9B, 0x17, 0x88, 0xA8, 0x92, 0xE0, 0xBE, 0xBD, 0x8B, 0x1D, 0x8D, 0x9F,
|
||||
0x56, 0x76, 0xAD, 0xAF, 0x29, 0xE2, 0xD9, 0xD5, 0x52, 0xF6, 0xB5, 0x56, 0x35, 0x57, 0x3A, 0xC8,
|
||||
0xE1, 0x56, 0x43, 0x19, 0x94, 0xD3, 0x04, 0x9B, 0x6D, 0x35, 0xD8, 0x0B, 0x5F, 0x4D, 0x19, 0x8E,
|
||||
0xEC, 0xFA, 0x64, 0x91, 0x0A, 0x72, 0x20, 0x2B, 0xBC, 0x1A, 0x4A, 0xFE, 0x8B, 0xFD, 0xBB, 0xED,
|
||||
0x1B, 0x23, 0xEA, 0xAD, 0x72, 0x82, 0xA1, 0x29, 0x99, 0x71, 0xBD, 0xF0, 0x95, 0xC1, 0x03, 0xDD,
|
||||
0x7B, 0xC2, 0xB2, 0x3C, 0x28, 0x54, 0xD3, 0x68, 0xA4, 0x72, 0xC8, 0x66, 0x96, 0xE0, 0xD1, 0xD8,
|
||||
0x7F, 0xF8, 0xD1, 0x26, 0x2B, 0xF7, 0xAD, 0xBA, 0x55, 0xCA, 0x15, 0xB9, 0x32, 0xC3, 0xE5, 0x88,
|
||||
0x97, 0x8E, 0x5C, 0xFB, 0x92, 0x25, 0x8B, 0xBF, 0xA2, 0x45, 0x55, 0x7A, 0xA7, 0x6F, 0x8B, 0x57,
|
||||
0x5B, 0xCF, 0x0E, 0xCB, 0x1D, 0xFB, 0x20, 0x82, 0x77, 0xA8, 0x8C, 0xCC, 0x16, 0xCE, 0x1D, 0xFA,
|
||||
0xDE, 0xCC, 0x0B, 0x62, 0xFE, 0xCC, 0xE1, 0xB7, 0xF0, 0xC3, 0x81, 0x64, 0x73, 0x40, 0xA0, 0xC2,
|
||||
0x4D, 0x89, 0x11, 0x75, 0x33, 0x55, 0x33, 0x8D, 0xE8, 0x4A, 0xFD, 0xEA, 0x6E, 0x30, 0x0B, 0xD7,
|
||||
0x31, 0x2C, 0xDE, 0x47, 0xE3, 0xBF, 0xF8, 0x55, 0x42, 0xE2, 0x7F, 0x59, 0xE5, 0x17, 0xEF, 0x99,
|
||||
0x34, 0x69, 0x91, 0xB1, 0x23, 0x8E, 0x20, 0x87, 0x2D, 0xA8, 0xFE, 0xD5, 0x8A, 0xF3, 0x84, 0x3A,
|
||||
0xF0, 0x37, 0xE4, 0x09, 0x00, 0x54, 0xEE, 0x67, 0x49, 0x93, 0xE4, 0x81, 0x70, 0xE3, 0x90, 0x4D,
|
||||
0xEF, 0xFE, 0x41, 0xB7, 0x99, 0x7B, 0xC1, 0x83, 0xBA, 0x62, 0x12, 0x6F, 0x7D, 0xDE, 0x6B, 0xAF,
|
||||
0xDA, 0x16, 0xF9, 0x55, 0x51, 0xEE, 0xA6, 0x0C, 0x2B, 0x02, 0xA3, 0xFD, 0x8D, 0xFB, 0x30, 0x17,
|
||||
0xE4, 0x6F, 0xDF, 0x36, 0x71, 0xC4, 0xCA, 0x87, 0x25, 0x48, 0xB0, 0x47, 0xEC, 0xEA, 0xB4, 0xBF,
|
||||
0xA5, 0x4D, 0x9B, 0x9F, 0x02, 0x93, 0xC4, 0xE3, 0xE4, 0xE8, 0x42, 0x2D, 0x68, 0x81, 0x15, 0x0A,
|
||||
0xEB, 0x84, 0x5B, 0xD6, 0xA8, 0x74, 0xFB, 0x7D, 0x1D, 0xCB, 0x2C, 0xDA, 0x46, 0x2A, 0x76, 0x62,
|
||||
0xCE, 0xBC, 0x5C, 0x9E, 0x8B, 0xE7, 0xCF, 0xBE, 0x78, 0xF5, 0x7C, 0xEB, 0xB3, 0x3A, 0x9C, 0xAA,
|
||||
0x6F, 0xCC, 0x72, 0xD1, 0x59, 0xF2, 0x11, 0x23, 0xD6, 0x3F, 0x48, 0xD1, 0xB7, 0xCE, 0xB0, 0xBF,
|
||||
0xCB, 0xEA, 0x80, 0xDE, 0x57, 0xD4, 0x5E, 0x97, 0x2F, 0x75, 0xD1, 0x50, 0x8E, 0x80, 0x2C, 0x66,
|
||||
0x79, 0xBF, 0x72, 0x4B, 0xBD, 0x8A, 0x81, 0x6C, 0xD3, 0xE1, 0x01, 0xDC, 0xD2, 0x15, 0x26, 0xC5,
|
||||
0x36, 0xDA, 0x2C, 0x1A, 0xC0, 0x27, 0x94, 0xED, 0xB7, 0x9B, 0x85, 0x0B, 0x5E, 0x80, 0x97, 0xC5,
|
||||
0xEC, 0x4F, 0xEC, 0x88, 0x5D, 0x50, 0x07, 0x35, 0x47, 0xDC, 0x0B, 0x3B, 0x3D, 0xDD, 0x60, 0xAF,
|
||||
0xA8, 0x5D, 0x81, 0x38, 0x24, 0x25, 0x5D, 0x5C, 0x15, 0xD1, 0xDE, 0xB3, 0xAB, 0xEC, 0x05, 0x69,
|
||||
0xEF, 0x83, 0xED, 0x57, 0x54, 0xB8, 0x64, 0x64, 0x11, 0x16, 0x32, 0x69, 0xDA, 0x9F, 0x2D, 0x7F,
|
||||
0x36, 0xBB, 0x44, 0x5A, 0x34, 0xE8, 0x7F, 0xBF, 0x03, 0xEB, 0x00, 0x7F, 0x59, 0x68, 0x22, 0x79,
|
||||
0xCF, 0x73, 0x6C, 0x2C, 0x29, 0xA7, 0xA1, 0x5F, 0x38, 0xA1, 0x1D, 0xF0, 0x20, 0x53, 0xE0, 0x1A,
|
||||
0x63, 0x14, 0x58, 0x71, 0x10, 0xAA, 0x08, 0x0C, 0x3E, 0x16, 0x1A, 0x60, 0x22, 0x82, 0x7F, 0xBA,
|
||||
0xA4, 0x43, 0xA0, 0xD0, 0xAC, 0x1B, 0xD5, 0x6B, 0x64, 0xB5, 0x14, 0x93, 0x31, 0x9E, 0x53, 0x50,
|
||||
0xD0, 0x57, 0x66, 0xEE, 0x5A, 0x4F, 0xFB, 0x03, 0x2A, 0x69, 0x58, 0x76, 0xF1, 0x83, 0xF7, 0x4E,
|
||||
0xBA, 0x8C, 0x42, 0x06, 0x60, 0x5D, 0x6D, 0xCE, 0x60, 0x88, 0xAE, 0xA4, 0xC3, 0xF1, 0x03, 0xA5,
|
||||
0x4B, 0x98, 0xA1, 0xFF, 0x67, 0xE1, 0xAC, 0xA2, 0xB8, 0x62, 0xD7, 0x6F, 0xA0, 0x31, 0xB4, 0xD2,
|
||||
0x77, 0xAF, 0x21, 0x10, 0x06, 0xC6, 0x9A, 0xFF, 0x1D, 0x09, 0x17, 0x0E, 0x5F, 0xF1, 0xAA, 0x54,
|
||||
0x34, 0x4B, 0x45, 0x8A, 0x87, 0x63, 0xA6, 0xDC, 0xF9, 0x24, 0x30, 0x67, 0xC6, 0xB2, 0xD6, 0x61,
|
||||
0x33, 0x69, 0xEE, 0x50, 0x61, 0x57, 0x28, 0xE7, 0x7E, 0xEE, 0xEC, 0x3A, 0x5A, 0x73, 0x4E, 0xA8,
|
||||
0x8D, 0xE4, 0x18, 0xEA, 0xEC, 0x41, 0x64, 0xC8, 0xE2, 0xE8, 0x66, 0xB6, 0x2D, 0xB6, 0xFB, 0x6A,
|
||||
0x6C, 0x16, 0xB3, 0xDD, 0x46, 0x43, 0xB9, 0x73, 0x00, 0x6A, 0x71, 0xED, 0x4E, 0x9D, 0x25, 0x1A,
|
||||
0xC3, 0x3C, 0x4A, 0x95, 0x15, 0x99, 0x35, 0x81, 0x14, 0x02, 0xD6, 0x98, 0x9B, 0xEC, 0xD8, 0x23,
|
||||
0x3B, 0x84, 0x29, 0xAF, 0x0C, 0x99, 0x83, 0xA6, 0x9A, 0x34, 0x4F, 0xFA, 0xE8, 0xD0, 0x3C, 0x4B,
|
||||
0xD0, 0xFB, 0xB6, 0x68, 0xB8, 0x9E, 0x8F, 0xCD, 0xF7, 0x60, 0x2D, 0x7A, 0x22, 0xE5, 0x7D, 0xAB,
|
||||
0x65, 0x1B, 0x95, 0xA7, 0xA8, 0x7F, 0xB6, 0x77, 0x47, 0x7B, 0x5F, 0x8B, 0x12, 0x72, 0xD0, 0xD4,
|
||||
0x91, 0xEF, 0xDE, 0x19, 0x50, 0x3C, 0xA7, 0x8B, 0xC4, 0xA9, 0xB3, 0x23, 0xCB, 0x76, 0xE6, 0x81,
|
||||
0xF0, 0xC1, 0x04, 0x8F, 0xA3, 0xB8, 0x54, 0x5B, 0x97, 0xAC, 0x19, 0xFF, 0x3F, 0x55, 0x27, 0x2F,
|
||||
0xE0, 0x1D, 0x42, 0x9B, 0x57, 0xFC, 0x4B, 0x4E, 0x0F, 0xCE, 0x98, 0xA9, 0x43, 0x57, 0x03, 0xBD,
|
||||
0xE7, 0xC8, 0x94, 0xDF, 0x6E, 0x36, 0x73, 0x32, 0xB4, 0xEF, 0x2E, 0x85, 0x7A, 0x6E, 0xFC, 0x6C,
|
||||
0x18, 0x82, 0x75, 0x35, 0x90, 0x07, 0xF3, 0xE4, 0x9F, 0x3E, 0xDC, 0x68, 0xF3, 0xB5, 0xF3, 0x19,
|
||||
0x80, 0x92, 0x06, 0x99, 0xA2, 0xE8, 0x6F, 0xFF, 0x2E, 0x7F, 0xAE, 0x42, 0xA4, 0x5F, 0xFB, 0xD4,
|
||||
0x0E, 0x81, 0x2B, 0xC3, 0x04, 0xFF, 0x2B, 0xB3, 0x74, 0x4E, 0x36, 0x5B, 0x9C, 0x15, 0x00, 0xC6,
|
||||
0x47, 0x2B, 0xE8, 0x8B, 0x3D, 0xF1, 0x9C, 0x03, 0x9A, 0x58, 0x7F, 0x9B, 0x9C, 0xBF, 0x85, 0x49,
|
||||
0x79, 0x35, 0x2E, 0x56, 0x7B, 0x41, 0x14, 0x39, 0x47, 0x83, 0x26, 0xAA, 0x07, 0x89, 0x98, 0x11,
|
||||
0x1B, 0x86, 0xE7, 0x73, 0x7A, 0xD8, 0x7D, 0x78, 0x61, 0x53, 0xE9, 0x79, 0xF5, 0x36, 0x8D, 0x44,
|
||||
0x92, 0x84, 0xF9, 0x13, 0x50, 0x58, 0x3B, 0xA4, 0x6A, 0x36, 0x65, 0x49, 0x8E, 0x3C, 0x0E, 0xF1,
|
||||
0x6F, 0xD2, 0x84, 0xC4, 0x7E, 0x8E, 0x3F, 0x39, 0xAE, 0x7C, 0x84, 0xF1, 0x63, 0x37, 0x8E, 0x3C,
|
||||
0xCC, 0x3E, 0x44, 0x81, 0x45, 0xF1, 0x4B, 0xB9, 0xED, 0x6B, 0x36, 0x5D, 0xBB, 0x20, 0x60, 0x1A,
|
||||
0x0F, 0xA3, 0xAA, 0x55, 0x77, 0x3A, 0xA9, 0xAE, 0x37, 0x4D, 0xBA, 0xB8, 0x86, 0x6B, 0xBC, 0x08,
|
||||
0x50, 0xF6, 0xCC, 0xA4, 0xBD, 0x1D, 0x40, 0x72, 0xA5, 0x86, 0xFA, 0xE2, 0x10, 0xAE, 0x3D, 0x58,
|
||||
0x4B, 0x97, 0xF3, 0x43, 0x74, 0xA9, 0x9E, 0xEB, 0x21, 0xB7, 0x01, 0xA4, 0x86, 0x93, 0x97, 0xEE,
|
||||
0x2F, 0x4F, 0x3B, 0x86, 0xA1, 0x41, 0x6F, 0x41, 0x26, 0x90, 0x78, 0x5C, 0x7F, 0x30, 0x38, 0x4B,
|
||||
0x3F, 0xAA, 0xEC, 0xED, 0x5C, 0x6F, 0x0E, 0xAD, 0x43, 0x87, 0xFD, 0x93, 0x35, 0xE6, 0x01, 0xEF,
|
||||
0x41, 0x26, 0x90, 0x99, 0x9E, 0xFB, 0x19, 0x5B, 0xAD, 0xD2, 0x91, 0x8A, 0xE0, 0x46, 0xAF, 0x65,
|
||||
0xFA, 0x4F, 0x84, 0xC1, 0xA1, 0x2D, 0xCF, 0x45, 0x8B, 0xD3, 0x85, 0x50, 0x55, 0x7C, 0xF9, 0x67,
|
||||
0x88, 0xD4, 0x4E, 0xE9, 0xD7, 0x6B, 0x61, 0x54, 0xA1, 0xA4, 0xA6, 0xA2, 0xC2, 0xBF, 0x30, 0x9C,
|
||||
0x40, 0x9F, 0x5F, 0xD7, 0x69, 0x2B, 0x24, 0x82, 0x5E, 0xD9, 0xD6, 0xA7, 0x12, 0x54, 0x1A, 0xF7,
|
||||
0x55, 0x9F, 0x76, 0x50, 0xA9, 0x95, 0x84, 0xE6, 0x6B, 0x6D, 0xB5, 0x96, 0x54, 0xD6, 0xCD, 0xB3,
|
||||
0xA1, 0x9B, 0x46, 0xA7, 0x94, 0x4D, 0xC4, 0x94, 0xB4, 0x98, 0xE3, 0xE1, 0xE2, 0x34, 0xD5, 0x33,
|
||||
0x16, 0x07, 0x54, 0xCD, 0xB7, 0x77, 0x53, 0xDB, 0x4F, 0x4D, 0x46, 0x9D, 0xE9, 0xD4, 0x9C, 0x8A,
|
||||
0x36, 0xB6, 0xB8, 0x38, 0x26, 0x6C, 0x0E, 0xFF, 0x9C, 0x1B, 0x43, 0x8B, 0x80, 0xCC, 0xB9, 0x3D,
|
||||
0xDA, 0xC7, 0xF1, 0x8A, 0xF2, 0x6D, 0xB8, 0xD7, 0x74, 0x2F, 0x7E, 0x1E, 0xB7, 0xD3, 0x4A, 0xB4,
|
||||
0xAC, 0xFC, 0x79, 0x48, 0x6C, 0xBC, 0x96, 0xB6, 0x94, 0x46, 0x57, 0x2D, 0xB0, 0xA3, 0xFC, 0x1E,
|
||||
0xB9, 0x52, 0x60, 0x85, 0x2D, 0x41, 0xD0, 0x43, 0x01, 0x1E, 0x1C, 0xD5, 0x7D, 0xFC, 0xF3, 0x96,
|
||||
0x0D, 0xC7, 0xCB, 0x2A, 0x29, 0x9A, 0x93, 0xDD, 0x88, 0x2D, 0x37, 0x5D, 0xAA, 0xFB, 0x49, 0x68,
|
||||
0xA0, 0x9C, 0x50, 0x86, 0x7F, 0x68, 0x56, 0x57, 0xF9, 0x79, 0x18, 0x39, 0xD4, 0xE0, 0x01, 0x84,
|
||||
0x33, 0x61, 0xCA, 0xA5, 0xD2, 0xD6, 0xE4, 0xC9, 0x8A, 0x4A, 0x23, 0x44, 0x4E, 0xBC, 0xF0, 0xDC,
|
||||
0x24, 0xA1, 0xA0, 0xC4, 0xE2, 0x07, 0x3C, 0x10, 0xC4, 0xB5, 0x25, 0x4B, 0x65, 0x63, 0xF4, 0x80,
|
||||
0xE7, 0xCF, 0x61, 0xB1, 0x71, 0x82, 0x21, 0x87, 0x2C, 0xF5, 0x91, 0x00, 0x32, 0x0C, 0xEC, 0xA9,
|
||||
0xB5, 0x9A, 0x74, 0x85, 0xE3, 0x36, 0x8F, 0x76, 0x4F, 0x9C, 0x6D, 0xCE, 0xBC, 0xAD, 0x0A, 0x4B,
|
||||
0xED, 0x76, 0x04, 0xCB, 0xC3, 0xB9, 0x33, 0x9E, 0x01, 0x93, 0x96, 0x69, 0x7D, 0xC5, 0xA2, 0x45,
|
||||
0x79, 0x9B, 0x04, 0x5C, 0x84, 0x09, 0xED, 0x88, 0x43, 0xC7, 0xAB, 0x93, 0x14, 0x26, 0xA1, 0x40,
|
||||
0xB5, 0xCE, 0x4E, 0xBF, 0x2A, 0x42, 0x85, 0x3E, 0x2C, 0x3B, 0x54, 0xE8, 0x12, 0x1F, 0x0E, 0x97,
|
||||
0x59, 0xB2, 0x27, 0x89, 0xFA, 0xF2, 0xDF, 0x8E, 0x68, 0x59, 0xDC, 0x06, 0xBC, 0xB6, 0x85, 0x0D,
|
||||
0x06, 0x22, 0xEC, 0xB1, 0xCB, 0xE5, 0x04, 0xE6, 0x3D, 0xB3, 0xB0, 0x41, 0x73, 0x08, 0x3F, 0x3C,
|
||||
0x58, 0x86, 0x63, 0xEB, 0x50, 0xEE, 0x1D, 0x2C, 0x37, 0x74, 0xA9, 0xD3, 0x18, 0xA3, 0x47, 0x6E,
|
||||
0x93, 0x54, 0xAD, 0x0A, 0x5D, 0xB8, 0x2A, 0x55, 0x5D, 0x78, 0xF6, 0xEE, 0xBE, 0x8E, 0x3C, 0x76,
|
||||
0x69, 0xB9, 0x40, 0xC2, 0x34, 0xEC, 0x2A, 0xB9, 0xED, 0x7E, 0x20, 0xE4, 0x8D, 0x00, 0x38, 0xC7,
|
||||
0xE6, 0x8F, 0x44, 0xA8, 0x86, 0xCE, 0xEB, 0x2A, 0xE9, 0x90, 0xF1, 0x4C, 0xDF, 0x32, 0xFB, 0x73,
|
||||
0x1B, 0x6D, 0x92, 0x1E, 0x95, 0xFE, 0xB4, 0xDB, 0x65, 0xDF, 0x4D, 0x23, 0x54, 0x89, 0x48, 0xBF,
|
||||
0x4A, 0x2E, 0x70, 0xD6, 0xD7, 0x62, 0xB4, 0x33, 0x29, 0xB1, 0x3A, 0x33, 0x4C, 0x23, 0x6D, 0xA6,
|
||||
0x76, 0xA5, 0x21, 0x63, 0x48, 0xE6, 0x90, 0x5D, 0xED, 0x90, 0x95, 0x0B, 0x7A, 0x84, 0xBE, 0xB8,
|
||||
0x0D, 0x5E, 0x63, 0x0C, 0x62, 0x26, 0x4C, 0x14, 0x5A, 0xB3, 0xAC, 0x23, 0xA4, 0x74, 0xA7, 0x6F,
|
||||
0x33, 0x30, 0x05, 0x60, 0x01, 0x42, 0xA0, 0x28, 0xB7, 0xEE, 0x19, 0x38, 0xF1, 0x64, 0x80, 0x82,
|
||||
0x43, 0xE1, 0x41, 0x27, 0x1F, 0x1F, 0x90, 0x54, 0x7A, 0xD5, 0x23, 0x2E, 0xD1, 0x3D, 0xCB, 0x28,
|
||||
0xBA, 0x58, 0x7F, 0xDC, 0x7C, 0x91, 0x24, 0xE9, 0x28, 0x51, 0x83, 0x6E, 0xC5, 0x56, 0x21, 0x42,
|
||||
0xED, 0xA0, 0x56, 0x22, 0xA1, 0x40, 0x80, 0x6B, 0xA8, 0xF7, 0x94, 0xCA, 0x13, 0x6B, 0x0C, 0x39,
|
||||
0xD9, 0xFD, 0xE9, 0xF3, 0x6F, 0xA6, 0x9E, 0xFC, 0x70, 0x8A, 0xB3, 0xBC, 0x59, 0x3C, 0x1E, 0x1D,
|
||||
0x6C, 0xF9, 0x7C, 0xAF, 0xF9, 0x88, 0x71, 0x95, 0xEB, 0x57, 0x00, 0xBD, 0x9F, 0x8C, 0x4F, 0xE1,
|
||||
0x24, 0x83, 0xC5, 0x22, 0xEA, 0xFD, 0xD3, 0x0C, 0xE2, 0x17, 0x18, 0x7C, 0x6A, 0x4C, 0xDE, 0x77,
|
||||
0xB4, 0x53, 0x9B, 0x4C, 0x81, 0xCD, 0x23, 0x60, 0xAA, 0x0E, 0x25, 0x73, 0x9C, 0x02, 0x79, 0x32,
|
||||
0x30, 0xDF, 0x74, 0xDF, 0x75, 0x19, 0xF4, 0xA5, 0x14, 0x5C, 0xF7, 0x7A, 0xA8, 0xA5, 0x91, 0x84,
|
||||
0x7C, 0x60, 0x03, 0x06, 0x3B, 0xCD, 0x50, 0xB6, 0x27, 0x9C, 0xFE, 0xB1, 0xDD, 0xCC, 0xD3, 0xB0,
|
||||
0x59, 0x24, 0xB2, 0xCA, 0xE2, 0x1C, 0x81, 0x22, 0x9D, 0x07, 0x8F, 0x8E, 0xB9, 0xBE, 0x4E, 0xFA,
|
||||
0xFC, 0x39, 0x65, 0xBA, 0xBF, 0x9D, 0x12, 0x37, 0x5E, 0x97, 0x7E, 0xF3, 0x89, 0xF5, 0x5D, 0xF5,
|
||||
0xE3, 0x09, 0x8C, 0x62, 0xB5, 0x20, 0x9D, 0x0C, 0x53, 0x8A, 0x68, 0x1B, 0xD2, 0x8F, 0x75, 0x17,
|
||||
0x5D, 0xD4, 0xE5, 0xDA, 0x75, 0x62, 0x19, 0x14, 0x6A, 0x26, 0x2D, 0xEB, 0xF8, 0xAF, 0x37, 0xF0,
|
||||
0x6C, 0xA4, 0x55, 0xB1, 0xBC, 0xE2, 0x33, 0xC0, 0x9A, 0xCA, 0xB0, 0x11, 0x49, 0x4F, 0x68, 0x9B,
|
||||
0x3B, 0x6B, 0x3C, 0xCC, 0x13, 0xF6, 0xC7, 0x85, 0x61, 0x68, 0x42, 0xAE, 0xBB, 0xDD, 0xCD, 0x45,
|
||||
0x16, 0x29, 0x1D, 0xEA, 0xDB, 0xC8, 0x03, 0x94, 0x3C, 0xEE, 0x4F, 0x82, 0x11, 0xC3, 0xEC, 0x28,
|
||||
0xBD, 0x97, 0x05, 0x99, 0xDE, 0xD7, 0xBB, 0x5E, 0x22, 0x1F, 0xD4, 0xEB, 0x64, 0xD9, 0x92, 0xD9,
|
||||
0x85, 0xB7, 0x6A, 0x05, 0x6A, 0xE4, 0x24, 0x41, 0xF1, 0xCD, 0xF0, 0xD8, 0x3F, 0xF8, 0x9E, 0x0E,
|
||||
0xCD, 0x0B, 0x7A, 0x70, 0x6B, 0x5A, 0x75, 0x0A, 0x6A, 0x33, 0x88, 0xEC, 0x17, 0x75, 0x08, 0x70,
|
||||
0x10, 0x2F, 0x24, 0xCF, 0xC4, 0xE9, 0x42, 0x00, 0x61, 0x94, 0xCA, 0x1F, 0x3A, 0x76, 0x06, 0xFA,
|
||||
0xD2, 0x48, 0x81, 0xF0, 0x77, 0x60, 0x03, 0x45, 0xD9, 0x61, 0xF4, 0xA4, 0x6F, 0x3D, 0xD9, 0x30,
|
||||
0xC3, 0x04, 0x6B, 0x54, 0x2A, 0xB7, 0xEC, 0x3B, 0xF4, 0x4B, 0xF5, 0x68, 0x52, 0x26, 0xCE, 0xFF,
|
||||
0x5D, 0x19, 0x91, 0xA0, 0xA3, 0xA5, 0xA9, 0xB1, 0xE0, 0x23, 0xC4, 0x0A, 0x77, 0x4D, 0xF9, 0x51,
|
||||
0x20, 0xA3, 0xA5, 0xA9, 0xB1, 0xC1, 0x00, 0x82, 0x86, 0x8E, 0x7F, 0x5D, 0x19, 0x91, 0xA0, 0xA3,
|
||||
0xC4, 0xEB, 0x54, 0x0B, 0x75, 0x68, 0x52, 0x07, 0x8C, 0x9A, 0x97, 0x8D, 0x79, 0x70, 0x62, 0x46,
|
||||
0xEF, 0x5C, 0x1B, 0x95, 0x89, 0x71, 0x41, 0xE1, 0x21, 0xA1, 0xA1, 0xA1, 0xC0, 0x02, 0x67, 0x4C,
|
||||
0x1A, 0xB6, 0xCF, 0xFD, 0x78, 0x53, 0x24, 0xAB, 0xB5, 0xC9, 0xF1, 0x60, 0x23, 0xA5, 0xC8, 0x12,
|
||||
0x87, 0x6D, 0x58, 0x13, 0x85, 0x88, 0x92, 0x87, 0x6D, 0x58, 0x32, 0xC7, 0x0C, 0x9A, 0x97, 0xAC,
|
||||
0xDA, 0x36, 0xEE, 0x5E, 0x3E, 0xDF, 0x1D, 0xB8, 0xF2, 0x66, 0x2F, 0xBD, 0xF8, 0x72, 0x47, 0xED,
|
||||
0x58, 0x13, 0x85, 0x88, 0x92, 0x87, 0x8C, 0x7B, 0x55, 0x09, 0x90, 0xA2, 0xC6, 0xEF, 0x3D, 0xF8,
|
||||
0x53, 0x24, 0xAB, 0xD4, 0x2A, 0xB7, 0xEC, 0x5A, 0x36, 0xEE, 0x5E, 0x3E, 0xDF, 0x3C, 0xFA, 0x76,
|
||||
0x4F, 0xFD, 0x59, 0x30, 0xE2, 0x46, 0xEF, 0x3D, 0xF8, 0x53, 0x05, 0x69, 0x31, 0xC1, 0x00, 0x82,
|
||||
0x86, 0x8E, 0x7F, 0x5D, 0x19, 0xB0, 0xE2, 0x27, 0xCC, 0xFB, 0x74, 0x4B, 0x14, 0x8B, 0x94, 0x8B,
|
||||
0x75, 0x68, 0x33, 0xC5, 0x08, 0x92, 0x87, 0x8C, 0x9A, 0xB6, 0xCF, 0x1C, 0xBA, 0xD7, 0x0D, 0x98,
|
||||
0xB2, 0xE6, 0x2F, 0xDC, 0x1B, 0x95, 0x89, 0x71, 0x60, 0x23, 0xC4, 0x0A, 0x96, 0x8F, 0x9C, 0xBA,
|
||||
0xF6, 0x6E, 0x3F, 0xFC, 0x5B, 0x15, 0xA8, 0xD2, 0x26, 0xAF, 0xBD, 0xF8, 0x72, 0x66, 0x2F, 0xDC,
|
||||
0x1B, 0xB4, 0xCB, 0x14, 0x8B, 0x94, 0xAA, 0xB7, 0xCD, 0xF9, 0x51, 0x01, 0x80, 0x82, 0x86, 0x6F,
|
||||
0x3D, 0xD9, 0x30, 0xE2, 0x27, 0xCC, 0xFB, 0x74, 0x4B, 0x14, 0xAA, 0xB7, 0xCD, 0xF9, 0x70, 0x43,
|
||||
0x04, 0x6B, 0x35, 0xC9, 0xF1, 0x60, 0x23, 0xA5, 0xC8, 0xF3, 0x45, 0x08, 0x92, 0x87, 0x6D, 0x58,
|
||||
0x32, 0xE6, 0x2F, 0xBD, 0xF8, 0x72, 0x66, 0x4E, 0x1E, 0xBE, 0xFE, 0x7E, 0x7E, 0x7E, 0x5F, 0x1D,
|
||||
0x99, 0x91, 0xA0, 0xA3, 0xC4, 0x0A, 0x77, 0x4D, 0x18, 0x93, 0xA4, 0xAB, 0xD4, 0x0B, 0x75, 0x49,
|
||||
0x10, 0xA2, 0xC6, 0xEF, 0x3D, 0xF8, 0x53, 0x24, 0xAB, 0xB5, 0xE8, 0x33, 0xE4, 0x4A, 0x16, 0xAE,
|
||||
0xDE, 0x1F, 0xBC, 0xDB, 0x15, 0xA8, 0xB3, 0xC5, 0x08, 0x73, 0x45, 0xE9, 0x31, 0xC1, 0xE1, 0x21,
|
||||
0xA1, 0xA1, 0xA1, 0xC0, 0x02, 0x86, 0x6F, 0x5C, 0x3A, 0xD7, 0x0D, 0x98, 0x93, 0xA4, 0xCA, 0x16,
|
||||
0xAE, 0xDE, 0x1F, 0x9D, 0x99, 0xB0, 0xE2, 0x46, 0xEF, 0x3D, 0xF8, 0x72, 0x47, 0x0C, 0x9A, 0xB6,
|
||||
0xCF, 0xFD, 0x59, 0x11, 0xA0, 0xA3, 0xA5, 0xC8, 0xF3, 0x45, 0x08, 0x92, 0x87, 0x6D, 0x39, 0xF0,
|
||||
0x43, 0x04, 0x8A, 0x96, 0xAE, 0xDE, 0x3E, 0xDF, 0x1D, 0x99, 0x91, 0xA0, 0xC2, 0x06, 0x6F, 0x3D,
|
||||
0xF8, 0x72, 0x47, 0x0C, 0x9A, 0x97, 0x8D, 0x98, 0x93, 0x85, 0x88, 0x73, 0x45, 0xE9, 0x31, 0xE0,
|
||||
0x23, 0xA5, 0xA9, 0xD0, 0x03, 0x84, 0x8A, 0x96, 0xAE, 0xDE, 0x1F, 0xBC, 0xDB, 0x15, 0xA8, 0xD2,
|
||||
0x26, 0xCE, 0xFF, 0x5D, 0x19, 0x91, 0x81, 0x80, 0x82, 0x67, 0x2D, 0xD8, 0x13, 0xA4, 0xAB, 0xD4,
|
||||
0x0B, 0x94, 0xAA, 0xB7, 0xCD, 0xF9, 0x51, 0x20, 0xA3, 0xA5, 0xC8, 0xF3, 0x45, 0xE9, 0x50, 0x22,
|
||||
0xC6, 0xEF, 0x5C, 0x3A, 0xD7, 0x0D, 0x98, 0x93, 0x85, 0x88, 0x73, 0x64, 0x4A, 0xF7, 0x4D, 0xF9,
|
||||
0x51, 0x20, 0xA3, 0xC4, 0x0A, 0x96, 0xAE, 0xDE, 0x3E, 0xFE, 0x7E, 0x7E, 0x7E, 0x5F, 0x3C, 0xFA,
|
||||
0x76, 0x4F, 0xFD, 0x78, 0x72, 0x66, 0x2F, 0xBD, 0xD9, 0x30, 0xC3, 0xE5, 0x48, 0x12, 0x87, 0x8C,
|
||||
0x7B, 0x55, 0x28, 0xD2, 0x07, 0x8C, 0x9A, 0x97, 0xAC, 0xDA, 0x17, 0x8D, 0x79, 0x51, 0x20, 0xA3,
|
||||
0xC4, 0xEB, 0x54, 0x0B, 0x94, 0x8B, 0x94, 0xAA, 0xD6, 0x2E, 0xBF, 0xFC, 0x5B, 0x15, 0xA8, 0xD2,
|
||||
0x26, 0xAF, 0xDC, 0x1B, 0xB4, 0xEA, 0x37, 0xEC, 0x3B, 0xF4, 0x6A, 0x37, 0xCD, 0x18, 0x93, 0x85,
|
||||
0x69, 0x31, 0xC1, 0xE1, 0x40, 0xE3, 0x25, 0xC8, 0x12, 0x87, 0x8C, 0x9A, 0xB6, 0xCF, 0xFD, 0x59,
|
||||
0x11, 0xA0, 0xC2, 0x06, 0x8E, 0x7F, 0x5D, 0x38, 0xF2, 0x47, 0x0C, 0x7B, 0x74, 0x6A, 0x37, 0xEC,
|
||||
0x5A, 0x36, 0xEE, 0x3F, 0xFC, 0x7A, 0x76, 0x4F, 0x1C, 0x9B, 0x95, 0x89, 0x71, 0x41, 0x00, 0x63,
|
||||
0x44, 0xEB, 0x54, 0x2A, 0xD6, 0x0F, 0x9C, 0xBA, 0xD7, 0x0D, 0x98, 0x93, 0x85, 0x69, 0x31, 0xC1,
|
||||
0x00, 0x82, 0x86, 0x8E, 0x9E, 0xBE, 0xDF, 0x3C, 0xFA, 0x57, 0x2C, 0xDA, 0x36, 0xEE, 0x3F, 0xFC,
|
||||
0x5B, 0x15, 0x89, 0x71, 0x41, 0x00, 0x82, 0x86, 0x8E, 0x7F, 0x5D, 0x38, 0xF2, 0x47, 0xED, 0x58,
|
||||
0x13, 0xA4, 0xCA, 0xF7, 0x4D, 0xF9, 0x51, 0x01, 0x80, 0x63, 0x44, 0xEB, 0x54, 0x2A, 0xD6, 0x2E,
|
||||
0xBF, 0xDD, 0x19, 0x91, 0xA0, 0xA3, 0xA5, 0xA9, 0xB1, 0xE0, 0x42, 0x06, 0x8E, 0x7F, 0x5D, 0x19,
|
||||
0x91, 0xA0, 0xA3, 0xC4, 0x0A, 0x96, 0x8F, 0x7D, 0x78, 0x72, 0x47, 0x0C, 0x7B, 0x74, 0x6A, 0x56,
|
||||
0x2E, 0xDE, 0x1F, 0xBC, 0xFA, 0x57, 0x0D, 0x79, 0x51, 0x01, 0x61, 0x21, 0xA1, 0xC0, 0xE3, 0x25,
|
||||
0xA9, 0xB1, 0xC1, 0xE1, 0x40, 0x02, 0x67, 0x4C, 0x1A, 0x97, 0x8D, 0x98, 0x93, 0xA4, 0xAB, 0xD4,
|
||||
0x2A, 0xD6, 0x0F, 0x9C, 0x9B, 0xB4, 0xCB, 0x14, 0xAA, 0xB7, 0xCD, 0xF9, 0x51, 0x20, 0xA3, 0xC4,
|
||||
0xEB, 0x35, 0xC9, 0xF1, 0x60, 0x42, 0x06, 0x8E, 0x7F, 0x7C, 0x7A, 0x76, 0x6E, 0x3F, 0xFC, 0x7A,
|
||||
0x76, 0x6E, 0x5E, 0x3E, 0xFE, 0x7E, 0x5F, 0x3C, 0xDB, 0x15, 0x89, 0x71, 0x41, 0xE1, 0x21, 0xC0,
|
||||
0xE3, 0x44, 0xEB, 0x54, 0x2A, 0xB7, 0xCD, 0xF9, 0x70, 0x62, 0x27, 0xAD, 0xD8, 0x32, 0xC7, 0x0C,
|
||||
0x7B, 0x74, 0x4B, 0x14, 0xAA, 0xB7, 0xEC, 0x3B, 0xD5, 0x28, 0xD2, 0x07, 0x6D, 0x39, 0xD1, 0x20,
|
||||
0xC2, 0xE7, 0x4C, 0x1A, 0x97, 0x8D, 0x98, 0xB2, 0xC7, 0x0C, 0x59, 0x28, 0xF3, 0x9B
|
||||
};
|
||||
|
||||
@@ -1,79 +1,73 @@
|
||||
/* 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/>.
|
||||
*/
|
||||
// Copyright 2022 Stefan Kerkmann (KarlK90)
|
||||
// Copyright 2022 Ulrich Spörlein (@uqs)
|
||||
// Copyright 2020 Christopher Courtney, aka Drashna Jael're (@drashna) <drashna@live.com>
|
||||
// Copyright 2019 Sunjun Kim
|
||||
// Copyright 2020 Ploopy Corporation
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef PMW3360_CPI
|
||||
# define PMW3360_CPI 1600
|
||||
#if !defined(PMW33XX_CPI)
|
||||
# define PMW33XX_CPI 1600U
|
||||
#endif
|
||||
|
||||
#ifndef PMW3360_CLOCK_SPEED
|
||||
# define PMW3360_CLOCK_SPEED 2000000
|
||||
#endif
|
||||
#define PMW33XX_CPI_STEP 100
|
||||
#define PMW33XX_CPI_MIN 100
|
||||
#define PMW33XX_CPI_MAX 12000
|
||||
|
||||
#ifndef PMW3360_SPI_LSBFIRST
|
||||
# define PMW3360_SPI_LSBFIRST false
|
||||
#endif
|
||||
#define PMW33XX_FIRMWARE_LENGTH 4094
|
||||
|
||||
#ifndef PMW3360_SPI_MODE
|
||||
# define PMW3360_SPI_MODE 3
|
||||
#endif
|
||||
|
||||
#ifndef PMW3360_SPI_DIVISOR
|
||||
# ifdef __AVR__
|
||||
# define PMW3360_SPI_DIVISOR (F_CPU / PMW3360_CLOCK_SPEED)
|
||||
# else
|
||||
# define PMW3360_SPI_DIVISOR 64
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifndef PMW3360_LIFTOFF_DISTANCE
|
||||
# define PMW3360_LIFTOFF_DISTANCE 0x02
|
||||
#endif
|
||||
|
||||
#ifndef ROTATIONAL_TRANSFORM_ANGLE
|
||||
# define ROTATIONAL_TRANSFORM_ANGLE 0x00
|
||||
#endif
|
||||
|
||||
// Support single and plural spellings
|
||||
#ifndef PMW3360_CS_PINS
|
||||
# ifndef PMW3360_CS_PIN
|
||||
# error "No chip select pin defined -- missing PMW3360_CS_PIN or PMW3360_CS_PINS"
|
||||
# else
|
||||
# define PMW3360_CS_PINS \
|
||||
{ PMW3360_CS_PIN }
|
||||
# endif
|
||||
#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_pmw3360_t;
|
||||
|
||||
bool pmw3360_init(int8_t index);
|
||||
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(int8_t index);
|
||||
// PMW3360 register addresses
|
||||
// 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
|
||||
// clang-format on
|
||||
|
||||
@@ -1,288 +0,0 @@
|
||||
/* 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 "progmem.h"
|
||||
|
||||
// PID, Inverse PID, SROM version
|
||||
const uint8_t firmware_signature[] PROGMEM = {0x42, 0xBD, 0x04};
|
||||
|
||||
#define FIRMWARE_LENGTH 4094
|
||||
|
||||
// Firmware Blob foor PMW3360
|
||||
|
||||
// clang-format off
|
||||
const uint8_t firmware_data[FIRMWARE_LENGTH] PROGMEM = {
|
||||
0x01, 0x04, 0x8E, 0x96, 0x6E, 0x77, 0x3E, 0xFE, 0x7E, 0x5F, 0x1D, 0xB8, 0xF2, 0x66, 0x4E, 0xFF,
|
||||
0x5D, 0x19, 0xB0, 0xC2, 0x04, 0x69, 0x54, 0x2A, 0xD6, 0x2E, 0xBF, 0xDD, 0x19, 0xB0, 0xC3, 0xE5,
|
||||
0x29, 0xB1, 0xE0, 0x23, 0xA5, 0xA9, 0xB1, 0xC1, 0x00, 0x82, 0x67, 0x4C, 0x1A, 0x97, 0x8D, 0x79,
|
||||
0x51, 0x20, 0xC7, 0x06, 0x8E, 0x7C, 0x7C, 0x7A, 0x76, 0x4F, 0xFD, 0x59, 0x30, 0xE2, 0x46, 0x0E,
|
||||
0x9E, 0xBE, 0xDF, 0x1D, 0x99, 0x91, 0xA0, 0xA5, 0xA1, 0xA9, 0xD0, 0x22, 0xC6, 0xEF, 0x5C, 0x1B,
|
||||
0x95, 0x89, 0x90, 0xA2, 0xA7, 0xCC, 0xFB, 0x55, 0x28, 0xB3, 0xE4, 0x4A, 0xF7, 0x6C, 0x3B, 0xF4,
|
||||
0x6A, 0x56, 0x2E, 0xDE, 0x1F, 0x9D, 0xB8, 0xD3, 0x05, 0x88, 0x92, 0xA6, 0xCE, 0x1E, 0xBE, 0xDF,
|
||||
0x1D, 0x99, 0xB0, 0xE2, 0x46, 0xEF, 0x5C, 0x07, 0x11, 0x5D, 0x98, 0x0B, 0x9D, 0x94, 0x97, 0xEE,
|
||||
0x4E, 0x45, 0x33, 0x6B, 0x44, 0xC7, 0x29, 0x56, 0x27, 0x30, 0xC6, 0xA7, 0xD5, 0xF2, 0x56, 0xDF,
|
||||
0xB4, 0x38, 0x62, 0xCB, 0xA0, 0xB6, 0xE3, 0x0F, 0x84, 0x06, 0x24, 0x05, 0x65, 0x6F, 0x76, 0x89,
|
||||
0xB5, 0x77, 0x41, 0x27, 0x82, 0x66, 0x65, 0x82, 0xCC, 0xD5, 0xE6, 0x20, 0xD5, 0x27, 0x17, 0xC5,
|
||||
0xF8, 0x03, 0x23, 0x7C, 0x5F, 0x64, 0xA5, 0x1D, 0xC1, 0xD6, 0x36, 0xCB, 0x4C, 0xD4, 0xDB, 0x66,
|
||||
0xD7, 0x8B, 0xB1, 0x99, 0x7E, 0x6F, 0x4C, 0x36, 0x40, 0x06, 0xD6, 0xEB, 0xD7, 0xA2, 0xE4, 0xF4,
|
||||
0x95, 0x51, 0x5A, 0x54, 0x96, 0xD5, 0x53, 0x44, 0xD7, 0x8C, 0xE0, 0xB9, 0x40, 0x68, 0xD2, 0x18,
|
||||
0xE9, 0xDD, 0x9A, 0x23, 0x92, 0x48, 0xEE, 0x7F, 0x43, 0xAF, 0xEA, 0x77, 0x38, 0x84, 0x8C, 0x0A,
|
||||
0x72, 0xAF, 0x69, 0xF8, 0xDD, 0xF1, 0x24, 0x83, 0xA3, 0xF8, 0x4A, 0xBF, 0xF5, 0x94, 0x13, 0xDB,
|
||||
0xBB, 0xD8, 0xB4, 0xB3, 0xA0, 0xFB, 0x45, 0x50, 0x60, 0x30, 0x59, 0x12, 0x31, 0x71, 0xA2, 0xD3,
|
||||
0x13, 0xE7, 0xFA, 0xE7, 0xCE, 0x0F, 0x63, 0x15, 0x0B, 0x6B, 0x94, 0xBB, 0x37, 0x83, 0x26, 0x05,
|
||||
0x9D, 0xFB, 0x46, 0x92, 0xFC, 0x0A, 0x15, 0xD1, 0x0D, 0x73, 0x92, 0xD6, 0x8C, 0x1B, 0x8C, 0xB8,
|
||||
0x55, 0x8A, 0xCE, 0xBD, 0xFE, 0x8E, 0xFC, 0xED, 0x09, 0x12, 0x83, 0x91, 0x82, 0x51, 0x31, 0x23,
|
||||
0xFB, 0xB4, 0x0C, 0x76, 0xAD, 0x7C, 0xD9, 0xB4, 0x4B, 0xB2, 0x67, 0x14, 0x09, 0x9C, 0x7F, 0x0C,
|
||||
0x18, 0xBA, 0x3B, 0xD6, 0x8E, 0x14, 0x2A, 0xE4, 0x1B, 0x52, 0x9F, 0x2B, 0x7D, 0xE1, 0xFB, 0x6A,
|
||||
0x33, 0x02, 0xFA, 0xAC, 0x5A, 0xF2, 0x3E, 0x88, 0x7E, 0xAE, 0xD1, 0xF3, 0x78, 0xE8, 0x05, 0xD1,
|
||||
0xE3, 0xDC, 0x21, 0xF6, 0xE1, 0x9A, 0xBD, 0x17, 0x0E, 0xD9, 0x46, 0x9B, 0x88, 0x03, 0xEA, 0xF6,
|
||||
0x66, 0xBE, 0x0E, 0x1B, 0x50, 0x49, 0x96, 0x40, 0x97, 0xF1, 0xF1, 0xE4, 0x80, 0xA6, 0x6E, 0xE8,
|
||||
0x77, 0x34, 0xBF, 0x29, 0x40, 0x44, 0xC2, 0xFF, 0x4E, 0x98, 0xD3, 0x9C, 0xA3, 0x32, 0x2B, 0x76,
|
||||
0x51, 0x04, 0x09, 0xE7, 0xA9, 0xD1, 0xA6, 0x32, 0xB1, 0x23, 0x53, 0xE2, 0x47, 0xAB, 0xD6, 0xF5,
|
||||
0x69, 0x5C, 0x3E, 0x5F, 0xFA, 0xAE, 0x45, 0x20, 0xE5, 0xD2, 0x44, 0xFF, 0x39, 0x32, 0x6D, 0xFD,
|
||||
0x27, 0x57, 0x5C, 0xFD, 0xF0, 0xDE, 0xC1, 0xB5, 0x99, 0xE5, 0xF5, 0x1C, 0x77, 0x01, 0x75, 0xC5,
|
||||
0x6D, 0x58, 0x92, 0xF2, 0xB2, 0x47, 0x00, 0x01, 0x26, 0x96, 0x7A, 0x30, 0xFF, 0xB7, 0xF0, 0xEF,
|
||||
0x77, 0xC1, 0x8A, 0x5D, 0xDC, 0xC0, 0xD1, 0x29, 0x30, 0x1E, 0x77, 0x38, 0x7A, 0x94, 0xF1, 0xB8,
|
||||
0x7A, 0x7E, 0xEF, 0xA4, 0xD1, 0xAC, 0x31, 0x4A, 0xF2, 0x5D, 0x64, 0x3D, 0xB2, 0xE2, 0xF0, 0x08,
|
||||
0x99, 0xFC, 0x70, 0xEE, 0x24, 0xA7, 0x7E, 0xEE, 0x1E, 0x20, 0x69, 0x7D, 0x44, 0xBF, 0x87, 0x42,
|
||||
0xDF, 0x88, 0x3B, 0x0C, 0xDA, 0x42, 0xC9, 0x04, 0xF9, 0x45, 0x50, 0xFC, 0x83, 0x8F, 0x11, 0x6A,
|
||||
0x72, 0xBC, 0x99, 0x95, 0xF0, 0xAC, 0x3D, 0xA7, 0x3B, 0xCD, 0x1C, 0xE2, 0x88, 0x79, 0x37, 0x11,
|
||||
0x5F, 0x39, 0x89, 0x95, 0x0A, 0x16, 0x84, 0x7A, 0xF6, 0x8A, 0xA4, 0x28, 0xE4, 0xED, 0x83, 0x80,
|
||||
0x3B, 0xB1, 0x23, 0xA5, 0x03, 0x10, 0xF4, 0x66, 0xEA, 0xBB, 0x0C, 0x0F, 0xC5, 0xEC, 0x6C, 0x69,
|
||||
0xC5, 0xD3, 0x24, 0xAB, 0xD4, 0x2A, 0xB7, 0x99, 0x88, 0x76, 0x08, 0xA0, 0xA8, 0x95, 0x7C, 0xD8,
|
||||
0x38, 0x6D, 0xCD, 0x59, 0x02, 0x51, 0x4B, 0xF1, 0xB5, 0x2B, 0x50, 0xE3, 0xB6, 0xBD, 0xD0, 0x72,
|
||||
0xCF, 0x9E, 0xFD, 0x6E, 0xBB, 0x44, 0xC8, 0x24, 0x8A, 0x77, 0x18, 0x8A, 0x13, 0x06, 0xEF, 0x97,
|
||||
0x7D, 0xFA, 0x81, 0xF0, 0x31, 0xE6, 0xFA, 0x77, 0xED, 0x31, 0x06, 0x31, 0x5B, 0x54, 0x8A, 0x9F,
|
||||
0x30, 0x68, 0xDB, 0xE2, 0x40, 0xF8, 0x4E, 0x73, 0xFA, 0xAB, 0x74, 0x8B, 0x10, 0x58, 0x13, 0xDC,
|
||||
0xD2, 0xE6, 0x78, 0xD1, 0x32, 0x2E, 0x8A, 0x9F, 0x2C, 0x58, 0x06, 0x48, 0x27, 0xC5, 0xA9, 0x5E,
|
||||
0x81, 0x47, 0x89, 0x46, 0x21, 0x91, 0x03, 0x70, 0xA4, 0x3E, 0x88, 0x9C, 0xDA, 0x33, 0x0A, 0xCE,
|
||||
0xBC, 0x8B, 0x8E, 0xCF, 0x9F, 0xD3, 0x71, 0x80, 0x43, 0xCF, 0x6B, 0xA9, 0x51, 0x83, 0x76, 0x30,
|
||||
0x82, 0xC5, 0x6A, 0x85, 0x39, 0x11, 0x50, 0x1A, 0x82, 0xDC, 0x1E, 0x1C, 0xD5, 0x7D, 0xA9, 0x71,
|
||||
0x99, 0x33, 0x47, 0x19, 0x97, 0xB3, 0x5A, 0xB1, 0xDF, 0xED, 0xA4, 0xF2, 0xE6, 0x26, 0x84, 0xA2,
|
||||
0x28, 0x9A, 0x9E, 0xDF, 0xA6, 0x6A, 0xF4, 0xD6, 0xFC, 0x2E, 0x5B, 0x9D, 0x1A, 0x2A, 0x27, 0x68,
|
||||
0xFB, 0xC1, 0x83, 0x21, 0x4B, 0x90, 0xE0, 0x36, 0xDD, 0x5B, 0x31, 0x42, 0x55, 0xA0, 0x13, 0xF7,
|
||||
0xD0, 0x89, 0x53, 0x71, 0x99, 0x57, 0x09, 0x29, 0xC5, 0xF3, 0x21, 0xF8, 0x37, 0x2F, 0x40, 0xF3,
|
||||
0xD4, 0xAF, 0x16, 0x08, 0x36, 0x02, 0xFC, 0x77, 0xC5, 0x8B, 0x04, 0x90, 0x56, 0xB9, 0xC9, 0x67,
|
||||
0x9A, 0x99, 0xE8, 0x00, 0xD3, 0x86, 0xFF, 0x97, 0x2D, 0x08, 0xE9, 0xB7, 0xB3, 0x91, 0xBC, 0xDF,
|
||||
0x45, 0xC6, 0xED, 0x0F, 0x8C, 0x4C, 0x1E, 0xE6, 0x5B, 0x6E, 0x38, 0x30, 0xE4, 0xAA, 0xE3, 0x95,
|
||||
0xDE, 0xB9, 0xE4, 0x9A, 0xF5, 0xB2, 0x55, 0x9A, 0x87, 0x9B, 0xF6, 0x6A, 0xB2, 0xF2, 0x77, 0x9A,
|
||||
0x31, 0xF4, 0x7A, 0x31, 0xD1, 0x1D, 0x04, 0xC0, 0x7C, 0x32, 0xA2, 0x9E, 0x9A, 0xF5, 0x62, 0xF8,
|
||||
0x27, 0x8D, 0xBF, 0x51, 0xFF, 0xD3, 0xDF, 0x64, 0x37, 0x3F, 0x2A, 0x6F, 0x76, 0x3A, 0x7D, 0x77,
|
||||
0x06, 0x9E, 0x77, 0x7F, 0x5E, 0xEB, 0x32, 0x51, 0xF9, 0x16, 0x66, 0x9A, 0x09, 0xF3, 0xB0, 0x08,
|
||||
0xA4, 0x70, 0x96, 0x46, 0x30, 0xFF, 0xDA, 0x4F, 0xE9, 0x1B, 0xED, 0x8D, 0xF8, 0x74, 0x1F, 0x31,
|
||||
0x92, 0xB3, 0x73, 0x17, 0x36, 0xDB, 0x91, 0x30, 0xD6, 0x88, 0x55, 0x6B, 0x34, 0x77, 0x87, 0x7A,
|
||||
0xE7, 0xEE, 0x06, 0xC6, 0x1C, 0x8C, 0x19, 0x0C, 0x48, 0x46, 0x23, 0x5E, 0x9C, 0x07, 0x5C, 0xBF,
|
||||
0xB4, 0x7E, 0xD6, 0x4F, 0x74, 0x9C, 0xE2, 0xC5, 0x50, 0x8B, 0xC5, 0x8B, 0x15, 0x90, 0x60, 0x62,
|
||||
0x57, 0x29, 0xD0, 0x13, 0x43, 0xA1, 0x80, 0x88, 0x91, 0x00, 0x44, 0xC7, 0x4D, 0x19, 0x86, 0xCC,
|
||||
0x2F, 0x2A, 0x75, 0x5A, 0xFC, 0xEB, 0x97, 0x2A, 0x70, 0xE3, 0x78, 0xD8, 0x91, 0xB0, 0x4F, 0x99,
|
||||
0x07, 0xA3, 0x95, 0xEA, 0x24, 0x21, 0xD5, 0xDE, 0x51, 0x20, 0x93, 0x27, 0x0A, 0x30, 0x73, 0xA8,
|
||||
0xFF, 0x8A, 0x97, 0xE9, 0xA7, 0x6A, 0x8E, 0x0D, 0xE8, 0xF0, 0xDF, 0xEC, 0xEA, 0xB4, 0x6C, 0x1D,
|
||||
0x39, 0x2A, 0x62, 0x2D, 0x3D, 0x5A, 0x8B, 0x65, 0xF8, 0x90, 0x05, 0x2E, 0x7E, 0x91, 0x2C, 0x78,
|
||||
0xEF, 0x8E, 0x7A, 0xC1, 0x2F, 0xAC, 0x78, 0xEE, 0xAF, 0x28, 0x45, 0x06, 0x4C, 0x26, 0xAF, 0x3B,
|
||||
0xA2, 0xDB, 0xA3, 0x93, 0x06, 0xB5, 0x3C, 0xA5, 0xD8, 0xEE, 0x8F, 0xAF, 0x25, 0xCC, 0x3F, 0x85,
|
||||
0x68, 0x48, 0xA9, 0x62, 0xCC, 0x97, 0x8F, 0x7F, 0x2A, 0xEA, 0xE0, 0x15, 0x0A, 0xAD, 0x62, 0x07,
|
||||
0xBD, 0x45, 0xF8, 0x41, 0xD8, 0x36, 0xCB, 0x4C, 0xDB, 0x6E, 0xE6, 0x3A, 0xE7, 0xDA, 0x15, 0xE9,
|
||||
0x29, 0x1E, 0x12, 0x10, 0xA0, 0x14, 0x2C, 0x0E, 0x3D, 0xF4, 0xBF, 0x39, 0x41, 0x92, 0x75, 0x0B,
|
||||
0x25, 0x7B, 0xA3, 0xCE, 0x39, 0x9C, 0x15, 0x64, 0xC8, 0xFA, 0x3D, 0xEF, 0x73, 0x27, 0xFE, 0x26,
|
||||
0x2E, 0xCE, 0xDA, 0x6E, 0xFD, 0x71, 0x8E, 0xDD, 0xFE, 0x76, 0xEE, 0xDC, 0x12, 0x5C, 0x02, 0xC5,
|
||||
0x3A, 0x4E, 0x4E, 0x4F, 0xBF, 0xCA, 0x40, 0x15, 0xC7, 0x6E, 0x8D, 0x41, 0xF1, 0x10, 0xE0, 0x4F,
|
||||
0x7E, 0x97, 0x7F, 0x1C, 0xAE, 0x47, 0x8E, 0x6B, 0xB1, 0x25, 0x31, 0xB0, 0x73, 0xC7, 0x1B, 0x97,
|
||||
0x79, 0xF9, 0x80, 0xD3, 0x66, 0x22, 0x30, 0x07, 0x74, 0x1E, 0xE4, 0xD0, 0x80, 0x21, 0xD6, 0xEE,
|
||||
0x6B, 0x6C, 0x4F, 0xBF, 0xF5, 0xB7, 0xD9, 0x09, 0x87, 0x2F, 0xA9, 0x14, 0xBE, 0x27, 0xD9, 0x72,
|
||||
0x50, 0x01, 0xD4, 0x13, 0x73, 0xA6, 0xA7, 0x51, 0x02, 0x75, 0x25, 0xE1, 0xB3, 0x45, 0x34, 0x7D,
|
||||
0xA8, 0x8E, 0xEB, 0xF3, 0x16, 0x49, 0xCB, 0x4F, 0x8C, 0xA1, 0xB9, 0x36, 0x85, 0x39, 0x75, 0x5D,
|
||||
0x08, 0x00, 0xAE, 0xEB, 0xF6, 0xEA, 0xD7, 0x13, 0x3A, 0x21, 0x5A, 0x5F, 0x30, 0x84, 0x52, 0x26,
|
||||
0x95, 0xC9, 0x14, 0xF2, 0x57, 0x55, 0x6B, 0xB1, 0x10, 0xC2, 0xE1, 0xBD, 0x3B, 0x51, 0xC0, 0xB7,
|
||||
0x55, 0x4C, 0x71, 0x12, 0x26, 0xC7, 0x0D, 0xF9, 0x51, 0xA4, 0x38, 0x02, 0x05, 0x7F, 0xB8, 0xF1,
|
||||
0x72, 0x4B, 0xBF, 0x71, 0x89, 0x14, 0xF3, 0x77, 0x38, 0xD9, 0x71, 0x24, 0xF3, 0x00, 0x11, 0xA1,
|
||||
0xD8, 0xD4, 0x69, 0x27, 0x08, 0x37, 0x35, 0xC9, 0x11, 0x9D, 0x90, 0x1C, 0x0E, 0xE7, 0x1C, 0xFF,
|
||||
0x2D, 0x1E, 0xE8, 0x92, 0xE1, 0x18, 0x10, 0x95, 0x7C, 0xE0, 0x80, 0xF4, 0x96, 0x43, 0x21, 0xF9,
|
||||
0x75, 0x21, 0x64, 0x38, 0xDD, 0x9F, 0x1E, 0x95, 0x16, 0xDA, 0x56, 0x1D, 0x4F, 0x9A, 0x53, 0xB2,
|
||||
0xE2, 0xE4, 0x18, 0xCB, 0x6B, 0x1A, 0x65, 0xEB, 0x56, 0xC6, 0x3B, 0xE5, 0xFE, 0xD8, 0x26, 0x3F,
|
||||
0x3A, 0x84, 0x59, 0x72, 0x66, 0xA2, 0xF3, 0x75, 0xFF, 0xFB, 0x60, 0xB3, 0x22, 0xAD, 0x3F, 0x2D,
|
||||
0x6B, 0xF9, 0xEB, 0xEA, 0x05, 0x7C, 0xD8, 0x8F, 0x6D, 0x2C, 0x98, 0x9E, 0x2B, 0x93, 0xF1, 0x5E,
|
||||
0x46, 0xF0, 0x87, 0x49, 0x29, 0x73, 0x68, 0xD7, 0x7F, 0xF9, 0xF0, 0xE5, 0x7D, 0xDB, 0x1D, 0x75,
|
||||
0x19, 0xF3, 0xC4, 0x58, 0x9B, 0x17, 0x88, 0xA8, 0x92, 0xE0, 0xBE, 0xBD, 0x8B, 0x1D, 0x8D, 0x9F,
|
||||
0x56, 0x76, 0xAD, 0xAF, 0x29, 0xE2, 0xD9, 0xD5, 0x52, 0xF6, 0xB5, 0x56, 0x35, 0x57, 0x3A, 0xC8,
|
||||
0xE1, 0x56, 0x43, 0x19, 0x94, 0xD3, 0x04, 0x9B, 0x6D, 0x35, 0xD8, 0x0B, 0x5F, 0x4D, 0x19, 0x8E,
|
||||
0xEC, 0xFA, 0x64, 0x91, 0x0A, 0x72, 0x20, 0x2B, 0xBC, 0x1A, 0x4A, 0xFE, 0x8B, 0xFD, 0xBB, 0xED,
|
||||
0x1B, 0x23, 0xEA, 0xAD, 0x72, 0x82, 0xA1, 0x29, 0x99, 0x71, 0xBD, 0xF0, 0x95, 0xC1, 0x03, 0xDD,
|
||||
0x7B, 0xC2, 0xB2, 0x3C, 0x28, 0x54, 0xD3, 0x68, 0xA4, 0x72, 0xC8, 0x66, 0x96, 0xE0, 0xD1, 0xD8,
|
||||
0x7F, 0xF8, 0xD1, 0x26, 0x2B, 0xF7, 0xAD, 0xBA, 0x55, 0xCA, 0x15, 0xB9, 0x32, 0xC3, 0xE5, 0x88,
|
||||
0x97, 0x8E, 0x5C, 0xFB, 0x92, 0x25, 0x8B, 0xBF, 0xA2, 0x45, 0x55, 0x7A, 0xA7, 0x6F, 0x8B, 0x57,
|
||||
0x5B, 0xCF, 0x0E, 0xCB, 0x1D, 0xFB, 0x20, 0x82, 0x77, 0xA8, 0x8C, 0xCC, 0x16, 0xCE, 0x1D, 0xFA,
|
||||
0xDE, 0xCC, 0x0B, 0x62, 0xFE, 0xCC, 0xE1, 0xB7, 0xF0, 0xC3, 0x81, 0x64, 0x73, 0x40, 0xA0, 0xC2,
|
||||
0x4D, 0x89, 0x11, 0x75, 0x33, 0x55, 0x33, 0x8D, 0xE8, 0x4A, 0xFD, 0xEA, 0x6E, 0x30, 0x0B, 0xD7,
|
||||
0x31, 0x2C, 0xDE, 0x47, 0xE3, 0xBF, 0xF8, 0x55, 0x42, 0xE2, 0x7F, 0x59, 0xE5, 0x17, 0xEF, 0x99,
|
||||
0x34, 0x69, 0x91, 0xB1, 0x23, 0x8E, 0x20, 0x87, 0x2D, 0xA8, 0xFE, 0xD5, 0x8A, 0xF3, 0x84, 0x3A,
|
||||
0xF0, 0x37, 0xE4, 0x09, 0x00, 0x54, 0xEE, 0x67, 0x49, 0x93, 0xE4, 0x81, 0x70, 0xE3, 0x90, 0x4D,
|
||||
0xEF, 0xFE, 0x41, 0xB7, 0x99, 0x7B, 0xC1, 0x83, 0xBA, 0x62, 0x12, 0x6F, 0x7D, 0xDE, 0x6B, 0xAF,
|
||||
0xDA, 0x16, 0xF9, 0x55, 0x51, 0xEE, 0xA6, 0x0C, 0x2B, 0x02, 0xA3, 0xFD, 0x8D, 0xFB, 0x30, 0x17,
|
||||
0xE4, 0x6F, 0xDF, 0x36, 0x71, 0xC4, 0xCA, 0x87, 0x25, 0x48, 0xB0, 0x47, 0xEC, 0xEA, 0xB4, 0xBF,
|
||||
0xA5, 0x4D, 0x9B, 0x9F, 0x02, 0x93, 0xC4, 0xE3, 0xE4, 0xE8, 0x42, 0x2D, 0x68, 0x81, 0x15, 0x0A,
|
||||
0xEB, 0x84, 0x5B, 0xD6, 0xA8, 0x74, 0xFB, 0x7D, 0x1D, 0xCB, 0x2C, 0xDA, 0x46, 0x2A, 0x76, 0x62,
|
||||
0xCE, 0xBC, 0x5C, 0x9E, 0x8B, 0xE7, 0xCF, 0xBE, 0x78, 0xF5, 0x7C, 0xEB, 0xB3, 0x3A, 0x9C, 0xAA,
|
||||
0x6F, 0xCC, 0x72, 0xD1, 0x59, 0xF2, 0x11, 0x23, 0xD6, 0x3F, 0x48, 0xD1, 0xB7, 0xCE, 0xB0, 0xBF,
|
||||
0xCB, 0xEA, 0x80, 0xDE, 0x57, 0xD4, 0x5E, 0x97, 0x2F, 0x75, 0xD1, 0x50, 0x8E, 0x80, 0x2C, 0x66,
|
||||
0x79, 0xBF, 0x72, 0x4B, 0xBD, 0x8A, 0x81, 0x6C, 0xD3, 0xE1, 0x01, 0xDC, 0xD2, 0x15, 0x26, 0xC5,
|
||||
0x36, 0xDA, 0x2C, 0x1A, 0xC0, 0x27, 0x94, 0xED, 0xB7, 0x9B, 0x85, 0x0B, 0x5E, 0x80, 0x97, 0xC5,
|
||||
0xEC, 0x4F, 0xEC, 0x88, 0x5D, 0x50, 0x07, 0x35, 0x47, 0xDC, 0x0B, 0x3B, 0x3D, 0xDD, 0x60, 0xAF,
|
||||
0xA8, 0x5D, 0x81, 0x38, 0x24, 0x25, 0x5D, 0x5C, 0x15, 0xD1, 0xDE, 0xB3, 0xAB, 0xEC, 0x05, 0x69,
|
||||
0xEF, 0x83, 0xED, 0x57, 0x54, 0xB8, 0x64, 0x64, 0x11, 0x16, 0x32, 0x69, 0xDA, 0x9F, 0x2D, 0x7F,
|
||||
0x36, 0xBB, 0x44, 0x5A, 0x34, 0xE8, 0x7F, 0xBF, 0x03, 0xEB, 0x00, 0x7F, 0x59, 0x68, 0x22, 0x79,
|
||||
0xCF, 0x73, 0x6C, 0x2C, 0x29, 0xA7, 0xA1, 0x5F, 0x38, 0xA1, 0x1D, 0xF0, 0x20, 0x53, 0xE0, 0x1A,
|
||||
0x63, 0x14, 0x58, 0x71, 0x10, 0xAA, 0x08, 0x0C, 0x3E, 0x16, 0x1A, 0x60, 0x22, 0x82, 0x7F, 0xBA,
|
||||
0xA4, 0x43, 0xA0, 0xD0, 0xAC, 0x1B, 0xD5, 0x6B, 0x64, 0xB5, 0x14, 0x93, 0x31, 0x9E, 0x53, 0x50,
|
||||
0xD0, 0x57, 0x66, 0xEE, 0x5A, 0x4F, 0xFB, 0x03, 0x2A, 0x69, 0x58, 0x76, 0xF1, 0x83, 0xF7, 0x4E,
|
||||
0xBA, 0x8C, 0x42, 0x06, 0x60, 0x5D, 0x6D, 0xCE, 0x60, 0x88, 0xAE, 0xA4, 0xC3, 0xF1, 0x03, 0xA5,
|
||||
0x4B, 0x98, 0xA1, 0xFF, 0x67, 0xE1, 0xAC, 0xA2, 0xB8, 0x62, 0xD7, 0x6F, 0xA0, 0x31, 0xB4, 0xD2,
|
||||
0x77, 0xAF, 0x21, 0x10, 0x06, 0xC6, 0x9A, 0xFF, 0x1D, 0x09, 0x17, 0x0E, 0x5F, 0xF1, 0xAA, 0x54,
|
||||
0x34, 0x4B, 0x45, 0x8A, 0x87, 0x63, 0xA6, 0xDC, 0xF9, 0x24, 0x30, 0x67, 0xC6, 0xB2, 0xD6, 0x61,
|
||||
0x33, 0x69, 0xEE, 0x50, 0x61, 0x57, 0x28, 0xE7, 0x7E, 0xEE, 0xEC, 0x3A, 0x5A, 0x73, 0x4E, 0xA8,
|
||||
0x8D, 0xE4, 0x18, 0xEA, 0xEC, 0x41, 0x64, 0xC8, 0xE2, 0xE8, 0x66, 0xB6, 0x2D, 0xB6, 0xFB, 0x6A,
|
||||
0x6C, 0x16, 0xB3, 0xDD, 0x46, 0x43, 0xB9, 0x73, 0x00, 0x6A, 0x71, 0xED, 0x4E, 0x9D, 0x25, 0x1A,
|
||||
0xC3, 0x3C, 0x4A, 0x95, 0x15, 0x99, 0x35, 0x81, 0x14, 0x02, 0xD6, 0x98, 0x9B, 0xEC, 0xD8, 0x23,
|
||||
0x3B, 0x84, 0x29, 0xAF, 0x0C, 0x99, 0x83, 0xA6, 0x9A, 0x34, 0x4F, 0xFA, 0xE8, 0xD0, 0x3C, 0x4B,
|
||||
0xD0, 0xFB, 0xB6, 0x68, 0xB8, 0x9E, 0x8F, 0xCD, 0xF7, 0x60, 0x2D, 0x7A, 0x22, 0xE5, 0x7D, 0xAB,
|
||||
0x65, 0x1B, 0x95, 0xA7, 0xA8, 0x7F, 0xB6, 0x77, 0x47, 0x7B, 0x5F, 0x8B, 0x12, 0x72, 0xD0, 0xD4,
|
||||
0x91, 0xEF, 0xDE, 0x19, 0x50, 0x3C, 0xA7, 0x8B, 0xC4, 0xA9, 0xB3, 0x23, 0xCB, 0x76, 0xE6, 0x81,
|
||||
0xF0, 0xC1, 0x04, 0x8F, 0xA3, 0xB8, 0x54, 0x5B, 0x97, 0xAC, 0x19, 0xFF, 0x3F, 0x55, 0x27, 0x2F,
|
||||
0xE0, 0x1D, 0x42, 0x9B, 0x57, 0xFC, 0x4B, 0x4E, 0x0F, 0xCE, 0x98, 0xA9, 0x43, 0x57, 0x03, 0xBD,
|
||||
0xE7, 0xC8, 0x94, 0xDF, 0x6E, 0x36, 0x73, 0x32, 0xB4, 0xEF, 0x2E, 0x85, 0x7A, 0x6E, 0xFC, 0x6C,
|
||||
0x18, 0x82, 0x75, 0x35, 0x90, 0x07, 0xF3, 0xE4, 0x9F, 0x3E, 0xDC, 0x68, 0xF3, 0xB5, 0xF3, 0x19,
|
||||
0x80, 0x92, 0x06, 0x99, 0xA2, 0xE8, 0x6F, 0xFF, 0x2E, 0x7F, 0xAE, 0x42, 0xA4, 0x5F, 0xFB, 0xD4,
|
||||
0x0E, 0x81, 0x2B, 0xC3, 0x04, 0xFF, 0x2B, 0xB3, 0x74, 0x4E, 0x36, 0x5B, 0x9C, 0x15, 0x00, 0xC6,
|
||||
0x47, 0x2B, 0xE8, 0x8B, 0x3D, 0xF1, 0x9C, 0x03, 0x9A, 0x58, 0x7F, 0x9B, 0x9C, 0xBF, 0x85, 0x49,
|
||||
0x79, 0x35, 0x2E, 0x56, 0x7B, 0x41, 0x14, 0x39, 0x47, 0x83, 0x26, 0xAA, 0x07, 0x89, 0x98, 0x11,
|
||||
0x1B, 0x86, 0xE7, 0x73, 0x7A, 0xD8, 0x7D, 0x78, 0x61, 0x53, 0xE9, 0x79, 0xF5, 0x36, 0x8D, 0x44,
|
||||
0x92, 0x84, 0xF9, 0x13, 0x50, 0x58, 0x3B, 0xA4, 0x6A, 0x36, 0x65, 0x49, 0x8E, 0x3C, 0x0E, 0xF1,
|
||||
0x6F, 0xD2, 0x84, 0xC4, 0x7E, 0x8E, 0x3F, 0x39, 0xAE, 0x7C, 0x84, 0xF1, 0x63, 0x37, 0x8E, 0x3C,
|
||||
0xCC, 0x3E, 0x44, 0x81, 0x45, 0xF1, 0x4B, 0xB9, 0xED, 0x6B, 0x36, 0x5D, 0xBB, 0x20, 0x60, 0x1A,
|
||||
0x0F, 0xA3, 0xAA, 0x55, 0x77, 0x3A, 0xA9, 0xAE, 0x37, 0x4D, 0xBA, 0xB8, 0x86, 0x6B, 0xBC, 0x08,
|
||||
0x50, 0xF6, 0xCC, 0xA4, 0xBD, 0x1D, 0x40, 0x72, 0xA5, 0x86, 0xFA, 0xE2, 0x10, 0xAE, 0x3D, 0x58,
|
||||
0x4B, 0x97, 0xF3, 0x43, 0x74, 0xA9, 0x9E, 0xEB, 0x21, 0xB7, 0x01, 0xA4, 0x86, 0x93, 0x97, 0xEE,
|
||||
0x2F, 0x4F, 0x3B, 0x86, 0xA1, 0x41, 0x6F, 0x41, 0x26, 0x90, 0x78, 0x5C, 0x7F, 0x30, 0x38, 0x4B,
|
||||
0x3F, 0xAA, 0xEC, 0xED, 0x5C, 0x6F, 0x0E, 0xAD, 0x43, 0x87, 0xFD, 0x93, 0x35, 0xE6, 0x01, 0xEF,
|
||||
0x41, 0x26, 0x90, 0x99, 0x9E, 0xFB, 0x19, 0x5B, 0xAD, 0xD2, 0x91, 0x8A, 0xE0, 0x46, 0xAF, 0x65,
|
||||
0xFA, 0x4F, 0x84, 0xC1, 0xA1, 0x2D, 0xCF, 0x45, 0x8B, 0xD3, 0x85, 0x50, 0x55, 0x7C, 0xF9, 0x67,
|
||||
0x88, 0xD4, 0x4E, 0xE9, 0xD7, 0x6B, 0x61, 0x54, 0xA1, 0xA4, 0xA6, 0xA2, 0xC2, 0xBF, 0x30, 0x9C,
|
||||
0x40, 0x9F, 0x5F, 0xD7, 0x69, 0x2B, 0x24, 0x82, 0x5E, 0xD9, 0xD6, 0xA7, 0x12, 0x54, 0x1A, 0xF7,
|
||||
0x55, 0x9F, 0x76, 0x50, 0xA9, 0x95, 0x84, 0xE6, 0x6B, 0x6D, 0xB5, 0x96, 0x54, 0xD6, 0xCD, 0xB3,
|
||||
0xA1, 0x9B, 0x46, 0xA7, 0x94, 0x4D, 0xC4, 0x94, 0xB4, 0x98, 0xE3, 0xE1, 0xE2, 0x34, 0xD5, 0x33,
|
||||
0x16, 0x07, 0x54, 0xCD, 0xB7, 0x77, 0x53, 0xDB, 0x4F, 0x4D, 0x46, 0x9D, 0xE9, 0xD4, 0x9C, 0x8A,
|
||||
0x36, 0xB6, 0xB8, 0x38, 0x26, 0x6C, 0x0E, 0xFF, 0x9C, 0x1B, 0x43, 0x8B, 0x80, 0xCC, 0xB9, 0x3D,
|
||||
0xDA, 0xC7, 0xF1, 0x8A, 0xF2, 0x6D, 0xB8, 0xD7, 0x74, 0x2F, 0x7E, 0x1E, 0xB7, 0xD3, 0x4A, 0xB4,
|
||||
0xAC, 0xFC, 0x79, 0x48, 0x6C, 0xBC, 0x96, 0xB6, 0x94, 0x46, 0x57, 0x2D, 0xB0, 0xA3, 0xFC, 0x1E,
|
||||
0xB9, 0x52, 0x60, 0x85, 0x2D, 0x41, 0xD0, 0x43, 0x01, 0x1E, 0x1C, 0xD5, 0x7D, 0xFC, 0xF3, 0x96,
|
||||
0x0D, 0xC7, 0xCB, 0x2A, 0x29, 0x9A, 0x93, 0xDD, 0x88, 0x2D, 0x37, 0x5D, 0xAA, 0xFB, 0x49, 0x68,
|
||||
0xA0, 0x9C, 0x50, 0x86, 0x7F, 0x68, 0x56, 0x57, 0xF9, 0x79, 0x18, 0x39, 0xD4, 0xE0, 0x01, 0x84,
|
||||
0x33, 0x61, 0xCA, 0xA5, 0xD2, 0xD6, 0xE4, 0xC9, 0x8A, 0x4A, 0x23, 0x44, 0x4E, 0xBC, 0xF0, 0xDC,
|
||||
0x24, 0xA1, 0xA0, 0xC4, 0xE2, 0x07, 0x3C, 0x10, 0xC4, 0xB5, 0x25, 0x4B, 0x65, 0x63, 0xF4, 0x80,
|
||||
0xE7, 0xCF, 0x61, 0xB1, 0x71, 0x82, 0x21, 0x87, 0x2C, 0xF5, 0x91, 0x00, 0x32, 0x0C, 0xEC, 0xA9,
|
||||
0xB5, 0x9A, 0x74, 0x85, 0xE3, 0x36, 0x8F, 0x76, 0x4F, 0x9C, 0x6D, 0xCE, 0xBC, 0xAD, 0x0A, 0x4B,
|
||||
0xED, 0x76, 0x04, 0xCB, 0xC3, 0xB9, 0x33, 0x9E, 0x01, 0x93, 0x96, 0x69, 0x7D, 0xC5, 0xA2, 0x45,
|
||||
0x79, 0x9B, 0x04, 0x5C, 0x84, 0x09, 0xED, 0x88, 0x43, 0xC7, 0xAB, 0x93, 0x14, 0x26, 0xA1, 0x40,
|
||||
0xB5, 0xCE, 0x4E, 0xBF, 0x2A, 0x42, 0x85, 0x3E, 0x2C, 0x3B, 0x54, 0xE8, 0x12, 0x1F, 0x0E, 0x97,
|
||||
0x59, 0xB2, 0x27, 0x89, 0xFA, 0xF2, 0xDF, 0x8E, 0x68, 0x59, 0xDC, 0x06, 0xBC, 0xB6, 0x85, 0x0D,
|
||||
0x06, 0x22, 0xEC, 0xB1, 0xCB, 0xE5, 0x04, 0xE6, 0x3D, 0xB3, 0xB0, 0x41, 0x73, 0x08, 0x3F, 0x3C,
|
||||
0x58, 0x86, 0x63, 0xEB, 0x50, 0xEE, 0x1D, 0x2C, 0x37, 0x74, 0xA9, 0xD3, 0x18, 0xA3, 0x47, 0x6E,
|
||||
0x93, 0x54, 0xAD, 0x0A, 0x5D, 0xB8, 0x2A, 0x55, 0x5D, 0x78, 0xF6, 0xEE, 0xBE, 0x8E, 0x3C, 0x76,
|
||||
0x69, 0xB9, 0x40, 0xC2, 0x34, 0xEC, 0x2A, 0xB9, 0xED, 0x7E, 0x20, 0xE4, 0x8D, 0x00, 0x38, 0xC7,
|
||||
0xE6, 0x8F, 0x44, 0xA8, 0x86, 0xCE, 0xEB, 0x2A, 0xE9, 0x90, 0xF1, 0x4C, 0xDF, 0x32, 0xFB, 0x73,
|
||||
0x1B, 0x6D, 0x92, 0x1E, 0x95, 0xFE, 0xB4, 0xDB, 0x65, 0xDF, 0x4D, 0x23, 0x54, 0x89, 0x48, 0xBF,
|
||||
0x4A, 0x2E, 0x70, 0xD6, 0xD7, 0x62, 0xB4, 0x33, 0x29, 0xB1, 0x3A, 0x33, 0x4C, 0x23, 0x6D, 0xA6,
|
||||
0x76, 0xA5, 0x21, 0x63, 0x48, 0xE6, 0x90, 0x5D, 0xED, 0x90, 0x95, 0x0B, 0x7A, 0x84, 0xBE, 0xB8,
|
||||
0x0D, 0x5E, 0x63, 0x0C, 0x62, 0x26, 0x4C, 0x14, 0x5A, 0xB3, 0xAC, 0x23, 0xA4, 0x74, 0xA7, 0x6F,
|
||||
0x33, 0x30, 0x05, 0x60, 0x01, 0x42, 0xA0, 0x28, 0xB7, 0xEE, 0x19, 0x38, 0xF1, 0x64, 0x80, 0x82,
|
||||
0x43, 0xE1, 0x41, 0x27, 0x1F, 0x1F, 0x90, 0x54, 0x7A, 0xD5, 0x23, 0x2E, 0xD1, 0x3D, 0xCB, 0x28,
|
||||
0xBA, 0x58, 0x7F, 0xDC, 0x7C, 0x91, 0x24, 0xE9, 0x28, 0x51, 0x83, 0x6E, 0xC5, 0x56, 0x21, 0x42,
|
||||
0xED, 0xA0, 0x56, 0x22, 0xA1, 0x40, 0x80, 0x6B, 0xA8, 0xF7, 0x94, 0xCA, 0x13, 0x6B, 0x0C, 0x39,
|
||||
0xD9, 0xFD, 0xE9, 0xF3, 0x6F, 0xA6, 0x9E, 0xFC, 0x70, 0x8A, 0xB3, 0xBC, 0x59, 0x3C, 0x1E, 0x1D,
|
||||
0x6C, 0xF9, 0x7C, 0xAF, 0xF9, 0x88, 0x71, 0x95, 0xEB, 0x57, 0x00, 0xBD, 0x9F, 0x8C, 0x4F, 0xE1,
|
||||
0x24, 0x83, 0xC5, 0x22, 0xEA, 0xFD, 0xD3, 0x0C, 0xE2, 0x17, 0x18, 0x7C, 0x6A, 0x4C, 0xDE, 0x77,
|
||||
0xB4, 0x53, 0x9B, 0x4C, 0x81, 0xCD, 0x23, 0x60, 0xAA, 0x0E, 0x25, 0x73, 0x9C, 0x02, 0x79, 0x32,
|
||||
0x30, 0xDF, 0x74, 0xDF, 0x75, 0x19, 0xF4, 0xA5, 0x14, 0x5C, 0xF7, 0x7A, 0xA8, 0xA5, 0x91, 0x84,
|
||||
0x7C, 0x60, 0x03, 0x06, 0x3B, 0xCD, 0x50, 0xB6, 0x27, 0x9C, 0xFE, 0xB1, 0xDD, 0xCC, 0xD3, 0xB0,
|
||||
0x59, 0x24, 0xB2, 0xCA, 0xE2, 0x1C, 0x81, 0x22, 0x9D, 0x07, 0x8F, 0x8E, 0xB9, 0xBE, 0x4E, 0xFA,
|
||||
0xFC, 0x39, 0x65, 0xBA, 0xBF, 0x9D, 0x12, 0x37, 0x5E, 0x97, 0x7E, 0xF3, 0x89, 0xF5, 0x5D, 0xF5,
|
||||
0xE3, 0x09, 0x8C, 0x62, 0xB5, 0x20, 0x9D, 0x0C, 0x53, 0x8A, 0x68, 0x1B, 0xD2, 0x8F, 0x75, 0x17,
|
||||
0x5D, 0xD4, 0xE5, 0xDA, 0x75, 0x62, 0x19, 0x14, 0x6A, 0x26, 0x2D, 0xEB, 0xF8, 0xAF, 0x37, 0xF0,
|
||||
0x6C, 0xA4, 0x55, 0xB1, 0xBC, 0xE2, 0x33, 0xC0, 0x9A, 0xCA, 0xB0, 0x11, 0x49, 0x4F, 0x68, 0x9B,
|
||||
0x3B, 0x6B, 0x3C, 0xCC, 0x13, 0xF6, 0xC7, 0x85, 0x61, 0x68, 0x42, 0xAE, 0xBB, 0xDD, 0xCD, 0x45,
|
||||
0x16, 0x29, 0x1D, 0xEA, 0xDB, 0xC8, 0x03, 0x94, 0x3C, 0xEE, 0x4F, 0x82, 0x11, 0xC3, 0xEC, 0x28,
|
||||
0xBD, 0x97, 0x05, 0x99, 0xDE, 0xD7, 0xBB, 0x5E, 0x22, 0x1F, 0xD4, 0xEB, 0x64, 0xD9, 0x92, 0xD9,
|
||||
0x85, 0xB7, 0x6A, 0x05, 0x6A, 0xE4, 0x24, 0x41, 0xF1, 0xCD, 0xF0, 0xD8, 0x3F, 0xF8, 0x9E, 0x0E,
|
||||
0xCD, 0x0B, 0x7A, 0x70, 0x6B, 0x5A, 0x75, 0x0A, 0x6A, 0x33, 0x88, 0xEC, 0x17, 0x75, 0x08, 0x70,
|
||||
0x10, 0x2F, 0x24, 0xCF, 0xC4, 0xE9, 0x42, 0x00, 0x61, 0x94, 0xCA, 0x1F, 0x3A, 0x76, 0x06, 0xFA,
|
||||
0xD2, 0x48, 0x81, 0xF0, 0x77, 0x60, 0x03, 0x45, 0xD9, 0x61, 0xF4, 0xA4, 0x6F, 0x3D, 0xD9, 0x30,
|
||||
0xC3, 0x04, 0x6B, 0x54, 0x2A, 0xB7, 0xEC, 0x3B, 0xF4, 0x4B, 0xF5, 0x68, 0x52, 0x26, 0xCE, 0xFF,
|
||||
0x5D, 0x19, 0x91, 0xA0, 0xA3, 0xA5, 0xA9, 0xB1, 0xE0, 0x23, 0xC4, 0x0A, 0x77, 0x4D, 0xF9, 0x51,
|
||||
0x20, 0xA3, 0xA5, 0xA9, 0xB1, 0xC1, 0x00, 0x82, 0x86, 0x8E, 0x7F, 0x5D, 0x19, 0x91, 0xA0, 0xA3,
|
||||
0xC4, 0xEB, 0x54, 0x0B, 0x75, 0x68, 0x52, 0x07, 0x8C, 0x9A, 0x97, 0x8D, 0x79, 0x70, 0x62, 0x46,
|
||||
0xEF, 0x5C, 0x1B, 0x95, 0x89, 0x71, 0x41, 0xE1, 0x21, 0xA1, 0xA1, 0xA1, 0xC0, 0x02, 0x67, 0x4C,
|
||||
0x1A, 0xB6, 0xCF, 0xFD, 0x78, 0x53, 0x24, 0xAB, 0xB5, 0xC9, 0xF1, 0x60, 0x23, 0xA5, 0xC8, 0x12,
|
||||
0x87, 0x6D, 0x58, 0x13, 0x85, 0x88, 0x92, 0x87, 0x6D, 0x58, 0x32, 0xC7, 0x0C, 0x9A, 0x97, 0xAC,
|
||||
0xDA, 0x36, 0xEE, 0x5E, 0x3E, 0xDF, 0x1D, 0xB8, 0xF2, 0x66, 0x2F, 0xBD, 0xF8, 0x72, 0x47, 0xED,
|
||||
0x58, 0x13, 0x85, 0x88, 0x92, 0x87, 0x8C, 0x7B, 0x55, 0x09, 0x90, 0xA2, 0xC6, 0xEF, 0x3D, 0xF8,
|
||||
0x53, 0x24, 0xAB, 0xD4, 0x2A, 0xB7, 0xEC, 0x5A, 0x36, 0xEE, 0x5E, 0x3E, 0xDF, 0x3C, 0xFA, 0x76,
|
||||
0x4F, 0xFD, 0x59, 0x30, 0xE2, 0x46, 0xEF, 0x3D, 0xF8, 0x53, 0x05, 0x69, 0x31, 0xC1, 0x00, 0x82,
|
||||
0x86, 0x8E, 0x7F, 0x5D, 0x19, 0xB0, 0xE2, 0x27, 0xCC, 0xFB, 0x74, 0x4B, 0x14, 0x8B, 0x94, 0x8B,
|
||||
0x75, 0x68, 0x33, 0xC5, 0x08, 0x92, 0x87, 0x8C, 0x9A, 0xB6, 0xCF, 0x1C, 0xBA, 0xD7, 0x0D, 0x98,
|
||||
0xB2, 0xE6, 0x2F, 0xDC, 0x1B, 0x95, 0x89, 0x71, 0x60, 0x23, 0xC4, 0x0A, 0x96, 0x8F, 0x9C, 0xBA,
|
||||
0xF6, 0x6E, 0x3F, 0xFC, 0x5B, 0x15, 0xA8, 0xD2, 0x26, 0xAF, 0xBD, 0xF8, 0x72, 0x66, 0x2F, 0xDC,
|
||||
0x1B, 0xB4, 0xCB, 0x14, 0x8B, 0x94, 0xAA, 0xB7, 0xCD, 0xF9, 0x51, 0x01, 0x80, 0x82, 0x86, 0x6F,
|
||||
0x3D, 0xD9, 0x30, 0xE2, 0x27, 0xCC, 0xFB, 0x74, 0x4B, 0x14, 0xAA, 0xB7, 0xCD, 0xF9, 0x70, 0x43,
|
||||
0x04, 0x6B, 0x35, 0xC9, 0xF1, 0x60, 0x23, 0xA5, 0xC8, 0xF3, 0x45, 0x08, 0x92, 0x87, 0x6D, 0x58,
|
||||
0x32, 0xE6, 0x2F, 0xBD, 0xF8, 0x72, 0x66, 0x4E, 0x1E, 0xBE, 0xFE, 0x7E, 0x7E, 0x7E, 0x5F, 0x1D,
|
||||
0x99, 0x91, 0xA0, 0xA3, 0xC4, 0x0A, 0x77, 0x4D, 0x18, 0x93, 0xA4, 0xAB, 0xD4, 0x0B, 0x75, 0x49,
|
||||
0x10, 0xA2, 0xC6, 0xEF, 0x3D, 0xF8, 0x53, 0x24, 0xAB, 0xB5, 0xE8, 0x33, 0xE4, 0x4A, 0x16, 0xAE,
|
||||
0xDE, 0x1F, 0xBC, 0xDB, 0x15, 0xA8, 0xB3, 0xC5, 0x08, 0x73, 0x45, 0xE9, 0x31, 0xC1, 0xE1, 0x21,
|
||||
0xA1, 0xA1, 0xA1, 0xC0, 0x02, 0x86, 0x6F, 0x5C, 0x3A, 0xD7, 0x0D, 0x98, 0x93, 0xA4, 0xCA, 0x16,
|
||||
0xAE, 0xDE, 0x1F, 0x9D, 0x99, 0xB0, 0xE2, 0x46, 0xEF, 0x3D, 0xF8, 0x72, 0x47, 0x0C, 0x9A, 0xB6,
|
||||
0xCF, 0xFD, 0x59, 0x11, 0xA0, 0xA3, 0xA5, 0xC8, 0xF3, 0x45, 0x08, 0x92, 0x87, 0x6D, 0x39, 0xF0,
|
||||
0x43, 0x04, 0x8A, 0x96, 0xAE, 0xDE, 0x3E, 0xDF, 0x1D, 0x99, 0x91, 0xA0, 0xC2, 0x06, 0x6F, 0x3D,
|
||||
0xF8, 0x72, 0x47, 0x0C, 0x9A, 0x97, 0x8D, 0x98, 0x93, 0x85, 0x88, 0x73, 0x45, 0xE9, 0x31, 0xE0,
|
||||
0x23, 0xA5, 0xA9, 0xD0, 0x03, 0x84, 0x8A, 0x96, 0xAE, 0xDE, 0x1F, 0xBC, 0xDB, 0x15, 0xA8, 0xD2,
|
||||
0x26, 0xCE, 0xFF, 0x5D, 0x19, 0x91, 0x81, 0x80, 0x82, 0x67, 0x2D, 0xD8, 0x13, 0xA4, 0xAB, 0xD4,
|
||||
0x0B, 0x94, 0xAA, 0xB7, 0xCD, 0xF9, 0x51, 0x20, 0xA3, 0xA5, 0xC8, 0xF3, 0x45, 0xE9, 0x50, 0x22,
|
||||
0xC6, 0xEF, 0x5C, 0x3A, 0xD7, 0x0D, 0x98, 0x93, 0x85, 0x88, 0x73, 0x64, 0x4A, 0xF7, 0x4D, 0xF9,
|
||||
0x51, 0x20, 0xA3, 0xC4, 0x0A, 0x96, 0xAE, 0xDE, 0x3E, 0xFE, 0x7E, 0x7E, 0x7E, 0x5F, 0x3C, 0xFA,
|
||||
0x76, 0x4F, 0xFD, 0x78, 0x72, 0x66, 0x2F, 0xBD, 0xD9, 0x30, 0xC3, 0xE5, 0x48, 0x12, 0x87, 0x8C,
|
||||
0x7B, 0x55, 0x28, 0xD2, 0x07, 0x8C, 0x9A, 0x97, 0xAC, 0xDA, 0x17, 0x8D, 0x79, 0x51, 0x20, 0xA3,
|
||||
0xC4, 0xEB, 0x54, 0x0B, 0x94, 0x8B, 0x94, 0xAA, 0xD6, 0x2E, 0xBF, 0xFC, 0x5B, 0x15, 0xA8, 0xD2,
|
||||
0x26, 0xAF, 0xDC, 0x1B, 0xB4, 0xEA, 0x37, 0xEC, 0x3B, 0xF4, 0x6A, 0x37, 0xCD, 0x18, 0x93, 0x85,
|
||||
0x69, 0x31, 0xC1, 0xE1, 0x40, 0xE3, 0x25, 0xC8, 0x12, 0x87, 0x8C, 0x9A, 0xB6, 0xCF, 0xFD, 0x59,
|
||||
0x11, 0xA0, 0xC2, 0x06, 0x8E, 0x7F, 0x5D, 0x38, 0xF2, 0x47, 0x0C, 0x7B, 0x74, 0x6A, 0x37, 0xEC,
|
||||
0x5A, 0x36, 0xEE, 0x3F, 0xFC, 0x7A, 0x76, 0x4F, 0x1C, 0x9B, 0x95, 0x89, 0x71, 0x41, 0x00, 0x63,
|
||||
0x44, 0xEB, 0x54, 0x2A, 0xD6, 0x0F, 0x9C, 0xBA, 0xD7, 0x0D, 0x98, 0x93, 0x85, 0x69, 0x31, 0xC1,
|
||||
0x00, 0x82, 0x86, 0x8E, 0x9E, 0xBE, 0xDF, 0x3C, 0xFA, 0x57, 0x2C, 0xDA, 0x36, 0xEE, 0x3F, 0xFC,
|
||||
0x5B, 0x15, 0x89, 0x71, 0x41, 0x00, 0x82, 0x86, 0x8E, 0x7F, 0x5D, 0x38, 0xF2, 0x47, 0xED, 0x58,
|
||||
0x13, 0xA4, 0xCA, 0xF7, 0x4D, 0xF9, 0x51, 0x01, 0x80, 0x63, 0x44, 0xEB, 0x54, 0x2A, 0xD6, 0x2E,
|
||||
0xBF, 0xDD, 0x19, 0x91, 0xA0, 0xA3, 0xA5, 0xA9, 0xB1, 0xE0, 0x42, 0x06, 0x8E, 0x7F, 0x5D, 0x19,
|
||||
0x91, 0xA0, 0xA3, 0xC4, 0x0A, 0x96, 0x8F, 0x7D, 0x78, 0x72, 0x47, 0x0C, 0x7B, 0x74, 0x6A, 0x56,
|
||||
0x2E, 0xDE, 0x1F, 0xBC, 0xFA, 0x57, 0x0D, 0x79, 0x51, 0x01, 0x61, 0x21, 0xA1, 0xC0, 0xE3, 0x25,
|
||||
0xA9, 0xB1, 0xC1, 0xE1, 0x40, 0x02, 0x67, 0x4C, 0x1A, 0x97, 0x8D, 0x98, 0x93, 0xA4, 0xAB, 0xD4,
|
||||
0x2A, 0xD6, 0x0F, 0x9C, 0x9B, 0xB4, 0xCB, 0x14, 0xAA, 0xB7, 0xCD, 0xF9, 0x51, 0x20, 0xA3, 0xC4,
|
||||
0xEB, 0x35, 0xC9, 0xF1, 0x60, 0x42, 0x06, 0x8E, 0x7F, 0x7C, 0x7A, 0x76, 0x6E, 0x3F, 0xFC, 0x7A,
|
||||
0x76, 0x6E, 0x5E, 0x3E, 0xFE, 0x7E, 0x5F, 0x3C, 0xDB, 0x15, 0x89, 0x71, 0x41, 0xE1, 0x21, 0xC0,
|
||||
0xE3, 0x44, 0xEB, 0x54, 0x2A, 0xB7, 0xCD, 0xF9, 0x70, 0x62, 0x27, 0xAD, 0xD8, 0x32, 0xC7, 0x0C,
|
||||
0x7B, 0x74, 0x4B, 0x14, 0xAA, 0xB7, 0xEC, 0x3B, 0xD5, 0x28, 0xD2, 0x07, 0x6D, 0x39, 0xD1, 0x20,
|
||||
0xC2, 0xE7, 0x4C, 0x1A, 0x97, 0x8D, 0x98, 0xB2, 0xC7, 0x0C, 0x59, 0x28, 0xF3, 0x9B
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user