Compare commits
1698 Commits
nvstore-re
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
542dcd32c7 | ||
|
|
0ef6413cd8 | ||
|
|
97d86c9571 | ||
|
|
edae8c1ee6 | ||
|
|
553405776f | ||
|
|
ad2088d231 | ||
|
|
67a5c6c270 | ||
|
|
eb112eb3a1 | ||
|
|
0d04e5e1f8 | ||
|
|
59eb529a20 | ||
|
|
d5aba396a6 | ||
|
|
6fd256dbdc | ||
|
|
6716fcbacb | ||
|
|
1dddd88525 | ||
|
|
d656f371c7 | ||
|
|
7e92e5162a | ||
|
|
74d34cfcf7 | ||
|
|
64658621bb | ||
|
|
755353f029 | ||
|
|
2981d15933 | ||
|
|
9ff3f5c447 | ||
|
|
f5a1ef32c9 | ||
|
|
841e44335e | ||
|
|
38616234e7 | ||
|
|
8e3bbfdf84 | ||
|
|
f9b65ce968 | ||
|
|
8d71040acf | ||
|
|
5feae87e03 | ||
|
|
0949c0ac86 | ||
|
|
c36eac23d2 | ||
|
|
a24a894cfd | ||
|
|
ca06dfd250 | ||
|
|
3a1ef6fe50 | ||
|
|
883be60fc5 | ||
|
|
393ebf5b43 | ||
|
|
2b5178bd63 | ||
|
|
44e7be3681 | ||
|
|
300323f18d | ||
|
|
c998432fc4 | ||
|
|
9c6cfcbbd7 | ||
|
|
be614dab92 | ||
|
|
02bd428786 | ||
|
|
6869ba87b0 | ||
|
|
d0f834570b | ||
|
|
00afe533ca | ||
|
|
621523c1a8 | ||
|
|
fdf630ab31 | ||
|
|
d2ad7a5923 | ||
|
|
29ef16be63 | ||
|
|
3344975607 | ||
|
|
15191eaaa5 | ||
|
|
717a3f591a | ||
|
|
74790ab80d | ||
|
|
50b1704c60 | ||
|
|
1e9338c550 | ||
|
|
17fc097cbd | ||
|
|
6f6563c2cb | ||
|
|
4904d38bb6 | ||
|
|
1ea83d9b70 | ||
|
|
2410897c86 | ||
|
|
6541812e20 | ||
|
|
2604f4d092 | ||
|
|
c6da2612ef | ||
|
|
538b1a6df8 | ||
|
|
2edf3c72e4 | ||
|
|
5e3f7a9321 | ||
|
|
00beed7b94 | ||
|
|
12e0af3f5c | ||
|
|
01629e1396 | ||
|
|
d893575ecf | ||
|
|
0cc6818728 | ||
|
|
b7bc614323 | ||
|
|
02b5a75675 | ||
|
|
e35f60ed5e | ||
|
|
0b425b8609 | ||
|
|
43ef951d83 | ||
|
|
38553d1ac5 | ||
|
|
9b131b2eff | ||
|
|
c19be4f41e | ||
|
|
e92a8ccde1 | ||
|
|
7d937aca84 | ||
|
|
382eef61d2 | ||
|
|
cfc46b565e | ||
|
|
45542d1d4f | ||
|
|
470fe2843c | ||
|
|
6c247d4852 | ||
|
|
6f366d1603 | ||
|
|
d53c7b2e1b | ||
|
|
598ccda8c0 | ||
|
|
1bbaeef439 | ||
|
|
eb50a0e198 | ||
|
|
08d0a70de2 | ||
|
|
a3d5d6152e | ||
|
|
9f832476eb | ||
|
|
78195d8fb9 | ||
|
|
aecc870c6b | ||
|
|
0c43c802e1 | ||
|
|
4ce43c74c6 | ||
|
|
1176c83e34 | ||
|
|
ef2f35b1fb | ||
|
|
5d7d5d881d | ||
|
|
5047512bae | ||
|
|
9862f53bec | ||
|
|
6a34760943 | ||
|
|
d0576a205f | ||
|
|
dfd52e5c03 | ||
|
|
6fd47d4c16 | ||
|
|
06879c59e0 | ||
|
|
21392bd3df | ||
|
|
e4d2326959 | ||
|
|
72e336628a | ||
|
|
7ca3baae43 | ||
|
|
89d6e226d7 | ||
|
|
f966d47012 | ||
|
|
dbf9482fea | ||
|
|
ecd796b3a5 | ||
|
|
b1fe2cca26 | ||
|
|
5d9ab62595 | ||
|
|
7dbbf29b8d | ||
|
|
722c45df0a | ||
|
|
88e4a5e8ab | ||
|
|
910c096145 | ||
|
|
a3d5485fd2 | ||
|
|
366670b4d5 | ||
|
|
0fffb07e9e | ||
|
|
4e91d2ca3f | ||
|
|
eb467988bb | ||
|
|
9fbf208c3f | ||
|
|
da1d6e28bd | ||
|
|
c1e17d3a26 | ||
|
|
a2f0eb323a | ||
|
|
53c6d33c2f | ||
|
|
a6a66bc367 | ||
|
|
386cbcbb1d | ||
|
|
d5713851ea | ||
|
|
91f96ff870 | ||
|
|
c25af2bfb1 | ||
|
|
b3cd82ed61 | ||
|
|
02ee6a58e2 | ||
|
|
192f2d2dda | ||
|
|
f235a83cf3 | ||
|
|
d34f59697c | ||
|
|
f966d3b079 | ||
|
|
6b7294cea0 | ||
|
|
efa8e1d56a | ||
|
|
946b4e9ae4 | ||
|
|
0d1104dfe0 | ||
|
|
1e371d9297 | ||
|
|
f88b8da729 | ||
|
|
52a090e31b | ||
|
|
cbd1b841b9 | ||
|
|
82fabe75d4 | ||
|
|
bc8b55a059 | ||
|
|
c54b3801ce | ||
|
|
076bb34285 | ||
|
|
48709f3329 | ||
|
|
ef0ba6a556 | ||
|
|
a08550cfd8 | ||
|
|
3e818cbbf6 | ||
|
|
fe0041f99c | ||
|
|
15e571b0d9 | ||
|
|
36521dfef9 | ||
|
|
25249eb68c | ||
|
|
be1328c720 | ||
|
|
8d6ce99cd3 | ||
|
|
fcd848d821 | ||
|
|
203394a709 | ||
|
|
284616d597 | ||
|
|
55c9ee4626 | ||
|
|
47430cb211 | ||
|
|
dd1bea1949 | ||
|
|
2aea18ba53 | ||
|
|
3c4922e3ca | ||
|
|
c6ec10206c | ||
|
|
88a9f4719b | ||
|
|
6a3eec50f1 | ||
|
|
722facf0d9 | ||
|
|
0a9d99429b | ||
|
|
d8c13ddc73 | ||
|
|
d73c1bd8d3 | ||
|
|
5764073837 | ||
|
|
259be18962 | ||
|
|
248e0b568d | ||
|
|
ca00ee0798 | ||
|
|
f3aaf3d5cb | ||
|
|
06fa4f338c | ||
|
|
2d81b7251d | ||
|
|
91f10c2f35 | ||
|
|
52e7c75539 | ||
|
|
a1e7e4c8de | ||
|
|
fce9503d0e | ||
|
|
5fc25566ee | ||
|
|
b88590f8e8 | ||
|
|
765cc2a5a4 | ||
|
|
1a591a70eb | ||
|
|
26680a00f0 | ||
|
|
429b8e645e | ||
|
|
74fd862c9c | ||
|
|
0625aa462c | ||
|
|
faa5ebf11e | ||
|
|
d0c5998e55 | ||
|
|
50d20713a0 | ||
|
|
2445b4d435 | ||
|
|
a8366f55e0 | ||
|
|
41b8167837 | ||
|
|
3461ce336d | ||
|
|
4457576ad4 | ||
|
|
038199a3e2 | ||
|
|
1929067aa1 | ||
|
|
2b115059e8 | ||
|
|
88110bc5c5 | ||
|
|
0a2c0cba12 | ||
|
|
1e9e3ffb9d | ||
|
|
863e0d85ad | ||
|
|
2109ab4ab1 | ||
|
|
e5dce7105b | ||
|
|
0237fd29ba | ||
|
|
3efeb4f1ef | ||
|
|
8b3603b15f | ||
|
|
e8ba25fd04 | ||
|
|
9e762d29a5 | ||
|
|
de043f2250 | ||
|
|
20ce5f2bae | ||
|
|
3353f3d4a4 | ||
|
|
4d2349fef4 | ||
|
|
54dcf2dce8 | ||
|
|
3291faa31e | ||
|
|
bbac20b453 | ||
|
|
98420f8ac3 | ||
|
|
5b26b306b5 | ||
|
|
a3cac15a53 | ||
|
|
c7a19ee50f | ||
|
|
e42c0631d0 | ||
|
|
609af3a257 | ||
|
|
7daa67cc63 | ||
|
|
3f24307dcd | ||
|
|
372954e43a | ||
|
|
391aea0462 | ||
|
|
ee464f4a40 | ||
|
|
54d58d4b43 | ||
|
|
4bd8d12d9d | ||
|
|
8ceb6a4602 | ||
|
|
76cc136a9e | ||
|
|
8d84979ddf | ||
|
|
bb391515a0 | ||
|
|
16c3caee28 | ||
|
|
ab1b656277 | ||
|
|
1a1daf32e3 | ||
|
|
6b1c38fe2f | ||
|
|
43544f4f96 | ||
|
|
d15de0321d | ||
|
|
0420d4b6eb | ||
|
|
00b2f67d55 | ||
|
|
6ab63b9dcf | ||
|
|
d053398a9a | ||
|
|
d9a601e87c | ||
|
|
6abb24443e | ||
|
|
9d54e261ec | ||
|
|
335df666ab | ||
|
|
7c5503d81a | ||
|
|
a4c7f95dc1 | ||
|
|
dbb2a21798 | ||
|
|
f12457cbb5 | ||
|
|
28ba1adce3 | ||
|
|
a62d5fb31e | ||
|
|
b8435fdd79 | ||
|
|
d3caf63265 | ||
|
|
c3a454abd6 | ||
|
|
73bb6b850d | ||
|
|
bc49347a69 | ||
|
|
9a4d3986b7 | ||
|
|
f89061ffbe | ||
|
|
3eb99272b3 | ||
|
|
56e5b98438 | ||
|
|
123caec8d1 | ||
|
|
637624dea9 | ||
|
|
9d5b86e39b | ||
|
|
7bd952973e | ||
|
|
aa4524339b | ||
|
|
5dd034c051 | ||
|
|
f90973af9b | ||
|
|
d71f24959c | ||
|
|
00b05e20b8 | ||
|
|
11da344abf | ||
|
|
89dfe1f6d4 | ||
|
|
81f2830425 | ||
|
|
efb445fbe3 | ||
|
|
0a899727b5 | ||
|
|
6d17350293 | ||
|
|
86d5eb890b | ||
|
|
b3b384b7d6 | ||
|
|
6dbedfaeb5 | ||
|
|
e29e0b65e3 | ||
|
|
2b750c993b | ||
|
|
17a715bfc5 | ||
|
|
15678037d5 | ||
|
|
213fdd3c57 | ||
|
|
406ab5adaa | ||
|
|
416f2efffd | ||
|
|
8aba8fe655 | ||
|
|
68d5a8fc35 | ||
|
|
170b701e94 | ||
|
|
4a0cd36c9c | ||
|
|
6a5311e8f5 | ||
|
|
20a8d14ede | ||
|
|
bab58af710 | ||
|
|
d4c4cc1b69 | ||
|
|
75a9f9f3eb | ||
|
|
e856343c66 | ||
|
|
51bbee9eb1 | ||
|
|
f40d16b76b | ||
|
|
227196da42 | ||
|
|
ea9d183a48 | ||
|
|
32cfd53569 | ||
|
|
49087f6f41 | ||
|
|
6c0ee684dc | ||
|
|
bee2f95e0a | ||
|
|
594e64affc | ||
|
|
6f3cbf20c8 | ||
|
|
7ca83c5929 | ||
|
|
3bf9c13bbb | ||
|
|
063ee4cf4d | ||
|
|
d7b9ed4813 | ||
|
|
10b82e080f | ||
|
|
a1b319347a | ||
|
|
709207f28e | ||
|
|
c680b0461f | ||
|
|
a4fa421a17 | ||
|
|
2f35c0d496 | ||
|
|
315e650344 | ||
|
|
d9be8cb2f1 | ||
|
|
176a7f80cb | ||
|
|
2441e6044e | ||
|
|
f076695120 | ||
|
|
6a3c8ae676 | ||
|
|
28926acd06 | ||
|
|
adcf2c8e22 | ||
|
|
1ae8c51a3c | ||
|
|
36d4df8a49 | ||
|
|
1aed412080 | ||
|
|
bc0f3e2d12 | ||
|
|
cae59ecddd | ||
|
|
9b95d29152 | ||
|
|
d376c4efbf | ||
|
|
e021fc7317 | ||
|
|
ef72dc00ae | ||
|
|
e2fc69661a | ||
|
|
b65f2948d4 | ||
|
|
fbbf0a3413 | ||
|
|
c4b7260686 | ||
|
|
6a63c7bde9 | ||
|
|
efd5a4ff45 | ||
|
|
b866e0912d | ||
|
|
9ba8aeaaad | ||
|
|
3239dc6cd5 | ||
|
|
8a18e413e9 | ||
|
|
78fcfa56a5 | ||
|
|
634bb69873 | ||
|
|
00f8d7a5ca | ||
|
|
0a200d1f1c | ||
|
|
30bc6a1f57 | ||
|
|
f23d7f09bf | ||
|
|
5c5f8902a1 | ||
|
|
6bba62224c | ||
|
|
8837cdcdda | ||
|
|
c4b56d95d0 | ||
|
|
2156844d18 | ||
|
|
b47412bbc1 | ||
|
|
1ca170946f | ||
|
|
0dedaf353d | ||
|
|
6779345665 | ||
|
|
698f84ff97 | ||
|
|
6a5f4843aa | ||
|
|
e851e4382a | ||
|
|
fc21241a49 | ||
|
|
5de2ba364d | ||
|
|
cc62502ab1 | ||
|
|
0815fbcc81 | ||
|
|
a676ef8eb7 | ||
|
|
78e560376c | ||
|
|
7e65cc3e47 | ||
|
|
a954821826 | ||
|
|
828b09dba2 | ||
|
|
2b88a14124 | ||
|
|
8acb15e4ce | ||
|
|
97d8398e8a | ||
|
|
5f87d21811 | ||
|
|
5c8a73ddb0 | ||
|
|
979a4e65e9 | ||
|
|
6e5c68abe5 | ||
|
|
d3634b3448 | ||
|
|
67fa34666d | ||
|
|
39adb2ac41 | ||
|
|
6fd2ef619e | ||
|
|
4f25f6dbf5 | ||
|
|
b4eeeda53a | ||
|
|
f8bc38b558 | ||
|
|
414793053e | ||
|
|
b885976601 | ||
|
|
ec64a9aa38 | ||
|
|
0aa0fc4500 | ||
|
|
3ebde0ea34 | ||
|
|
b6098a94e5 | ||
|
|
e726637319 | ||
|
|
446bea9926 | ||
|
|
9a28d36097 | ||
|
|
a4d7f884c0 | ||
|
|
ce1ce080ab | ||
|
|
e06449f59f | ||
|
|
ffda830f66 | ||
|
|
d23187f187 | ||
|
|
15766b418d | ||
|
|
7450940730 | ||
|
|
d1fd24c9ef | ||
|
|
19ce22e607 | ||
|
|
4476089d0f | ||
|
|
341265c486 | ||
|
|
f3a2f59549 | ||
|
|
4a245ce553 | ||
|
|
de443d5b89 | ||
|
|
ff756f086e | ||
|
|
cd1728b81d | ||
|
|
633120b760 | ||
|
|
3fd8fb9dc1 | ||
|
|
7a27adfcfd | ||
|
|
33faa04652 | ||
|
|
56f0d56a08 | ||
|
|
481d64d2dd | ||
|
|
e3ae6bcbdf | ||
|
|
e150150d11 | ||
|
|
f117423210 | ||
|
|
962bb4b0f2 | ||
|
|
ae9806f702 | ||
|
|
66e4cf130f | ||
|
|
72fef6d5b8 | ||
|
|
bb3073af76 | ||
|
|
b09bb521a8 | ||
|
|
22ff7b1fe9 | ||
|
|
7eb5a7ea03 | ||
|
|
6b9e2ef9b9 | ||
|
|
7c9436d237 | ||
|
|
8bf4731cf5 | ||
|
|
e14fb64904 | ||
|
|
12f62f95bc | ||
|
|
58eec8be8b | ||
|
|
b5a6bf5d18 | ||
|
|
70acd6a602 | ||
|
|
1fe0c58b76 | ||
|
|
18ea47f334 | ||
|
|
96b8d48136 | ||
|
|
4a463da9db | ||
|
|
239d1ebd00 | ||
|
|
77956158ae | ||
|
|
3d4336bab7 | ||
|
|
b2f6e290d1 | ||
|
|
f920020ba0 | ||
|
|
4a234e8452 | ||
|
|
d980c42dad | ||
|
|
37c7119ae4 | ||
|
|
ab55c00065 | ||
|
|
6f93847f8a | ||
|
|
2eb615b358 | ||
|
|
c899f6e7ce | ||
|
|
d0f7a451ef | ||
|
|
14be94e049 | ||
|
|
5fb1839620 | ||
|
|
a2eed31416 | ||
|
|
9203c4f2aa | ||
|
|
3d08b749b3 | ||
|
|
58b5d1071f | ||
|
|
f795f9027f | ||
|
|
2cf006beaa | ||
|
|
0c28987190 | ||
|
|
012433aba4 | ||
|
|
57cdd69c81 | ||
|
|
9e082570aa | ||
|
|
117daaf17f | ||
|
|
359d05dc7b | ||
|
|
77059ffcf1 | ||
|
|
17306e2a38 | ||
|
|
1f1045b401 | ||
|
|
29b860e84e | ||
|
|
0849e538b5 | ||
|
|
44dae36141 | ||
|
|
8a8860d9a0 | ||
|
|
0a185669d0 | ||
|
|
6445fad042 | ||
|
|
0ccd701421 | ||
|
|
7ff8342e01 | ||
|
|
0009028817 | ||
|
|
7e9ce496d8 | ||
|
|
869e317db8 | ||
|
|
6df24f646d | ||
|
|
9d863edcdb | ||
|
|
4c308205a6 | ||
|
|
2641650090 | ||
|
|
84a476d586 | ||
|
|
8b97535a40 | ||
|
|
119fc35c43 | ||
|
|
2feade4f74 | ||
|
|
9761c65614 | ||
|
|
00d8c841f7 | ||
|
|
531ae613c7 | ||
|
|
ac782fdd59 | ||
|
|
d35ccc1ade | ||
|
|
2c52cca4bd | ||
|
|
07e66811f3 | ||
|
|
077d502139 | ||
|
|
4030f6f59f | ||
|
|
15990fa0f6 | ||
|
|
ef01a57626 | ||
|
|
d21515e2cf | ||
|
|
fc5e99c226 | ||
|
|
bc59709966 | ||
|
|
d983549fae | ||
|
|
b6fc24e705 | ||
|
|
fcae022ba8 | ||
|
|
65d202160e | ||
|
|
4fb37d7850 | ||
|
|
5b69ec07fc | ||
|
|
60d254314b | ||
|
|
0f3fe830b9 | ||
|
|
4087f8f25b | ||
|
|
6b770024ce | ||
|
|
bbd8f9b282 | ||
|
|
d81d6ea80c | ||
|
|
8edef87ae5 | ||
|
|
9cc6ce368d | ||
|
|
e037037924 | ||
|
|
5b38dd87a6 | ||
|
|
b55db05aab | ||
|
|
6d4b3d6990 | ||
|
|
c7d216fff3 | ||
|
|
a3f815a74d | ||
|
|
e61493668b | ||
|
|
eb325e5fec | ||
|
|
242641d396 | ||
|
|
a507677dc1 | ||
|
|
262c4ea717 | ||
|
|
a16516b8e1 | ||
|
|
695c3b4b29 | ||
|
|
08bb9783d2 | ||
|
|
4515e688ed | ||
|
|
5694ada611 | ||
|
|
d2636c7621 | ||
|
|
67febe2758 | ||
|
|
7e6be45e2d | ||
|
|
660b4617bd | ||
|
|
afe85a3772 | ||
|
|
6c91bd7328 | ||
|
|
9c7f4c5451 | ||
|
|
4ea455aa20 | ||
|
|
9e38974f7a | ||
|
|
75751b8d2b | ||
|
|
dd66cd8811 | ||
|
|
a640dd5d78 | ||
|
|
14e85304df | ||
|
|
1eec58ece7 | ||
|
|
41cde6be6c | ||
|
|
15536e4c9e | ||
|
|
2feb991d96 | ||
|
|
a2bdfc9a58 | ||
|
|
d3c50521e8 | ||
|
|
2558ed7ac0 | ||
|
|
4f8f1fe593 | ||
|
|
3878897369 | ||
|
|
1a18258b5a | ||
|
|
38c92ef0c1 | ||
|
|
cc7097b4f7 | ||
|
|
9b597592bc | ||
|
|
70d303af78 | ||
|
|
cd6d74d9f3 | ||
|
|
a71f350c78 | ||
|
|
ce1026cb4b | ||
|
|
e039fb8603 | ||
|
|
a0949ecb87 | ||
|
|
a8202972b3 | ||
|
|
85ff2dcf45 | ||
|
|
262df4a257 | ||
|
|
e9d17e5efb | ||
|
|
513a3b8258 | ||
|
|
ac761c23d5 | ||
|
|
de0a679eef | ||
|
|
92a776cfc3 | ||
|
|
f2a3667593 | ||
|
|
6b73eb2fa6 | ||
|
|
66b01c1fd5 | ||
|
|
14ce2ca6e0 | ||
|
|
86fe33137f | ||
|
|
c65280cd42 | ||
|
|
2fb66da58d | ||
|
|
87b5142145 | ||
|
|
6aedb0a73a | ||
|
|
072eb24ed9 | ||
|
|
b443f38d60 | ||
|
|
8957ad3c10 | ||
|
|
d270cf66c6 | ||
|
|
c425fc6bcc | ||
|
|
c9882d7a8a | ||
|
|
85b478346b | ||
|
|
95b13083dc | ||
|
|
5568082f35 | ||
|
|
8f86ed1c0e | ||
|
|
1b54536eff | ||
|
|
d1d104cb7e | ||
|
|
9e1ce7a956 | ||
|
|
f30686f252 | ||
|
|
3dbc9caa73 | ||
|
|
114d1dd675 | ||
|
|
e64a623a4e | ||
|
|
6514275a05 | ||
|
|
7a438fe834 | ||
|
|
81ebecddb6 | ||
|
|
b5f31fb9de | ||
|
|
0cac3b7c41 | ||
|
|
603109d36e | ||
|
|
2772af753c | ||
|
|
de186d5f27 | ||
|
|
741189da06 | ||
|
|
e1b810c8f6 | ||
|
|
5e42fbf2fc | ||
|
|
3ec3095e20 | ||
|
|
2d004bccd5 | ||
|
|
4e52900d10 | ||
|
|
b1704a73b1 | ||
|
|
24b1dc2251 | ||
|
|
2b0fb901b4 | ||
|
|
22e3ec40e7 | ||
|
|
b6381fdbb5 | ||
|
|
8de49876b4 | ||
|
|
837c649168 | ||
|
|
dee80eef3a | ||
|
|
ee2b721c27 | ||
|
|
915f103c8f | ||
|
|
dccf27b40e | ||
|
|
21b93f1f0b | ||
|
|
8a7f0d046c | ||
|
|
602cc622bb | ||
|
|
4579b1eff3 | ||
|
|
fac58c6969 | ||
|
|
7fc656ac53 | ||
|
|
383aafe6f7 | ||
|
|
5fa2f385ef | ||
|
|
58f7c59a6e | ||
|
|
cdeeb7ee63 | ||
|
|
133c18e7c1 | ||
|
|
48c7227c08 | ||
|
|
3edbb4e560 | ||
|
|
592c2e324c | ||
|
|
5fa1b2ade9 | ||
|
|
93b7bcbf2b | ||
|
|
5059f5bdee | ||
|
|
ea619e0596 | ||
|
|
457d3bd8a3 | ||
|
|
a3ef684e91 | ||
|
|
2715d87e37 | ||
|
|
08602b5d9a | ||
|
|
7bbe300e7a | ||
|
|
6ffdee7a84 | ||
|
|
ec27f410ea | ||
|
|
4a1628f9d5 | ||
|
|
74bbcfacfd | ||
|
|
2d85b3299c | ||
|
|
8ade0946c6 | ||
|
|
97c9ad5f9c | ||
|
|
1bc488214a | ||
|
|
1536011f44 | ||
|
|
89c59e4e4c | ||
|
|
f5dc1a1d44 | ||
|
|
9471daab91 | ||
|
|
a1ce940436 | ||
|
|
840c87cf64 | ||
|
|
5eacd63cf5 | ||
|
|
dda27300dd | ||
|
|
817ea30fa1 | ||
|
|
e4f925c7bf | ||
|
|
aaddedd4c6 | ||
|
|
80d1b5317f | ||
|
|
f7a0902c1a | ||
|
|
dfbc3c9031 | ||
|
|
577ea92e1e | ||
|
|
e73765b9fb | ||
|
|
1a72c70290 | ||
|
|
d4c559a302 | ||
|
|
6d31ed05ef | ||
|
|
139009970b | ||
|
|
5296a8aa7a | ||
|
|
9eab533dd9 | ||
|
|
f0457bf4a7 | ||
|
|
deb6e542cd | ||
|
|
5cfc29878e | ||
|
|
a1c11c6e28 | ||
|
|
f95f988078 | ||
|
|
536bc43308 | ||
|
|
22befce4e6 | ||
|
|
fced4a9bd5 | ||
|
|
625b7b8ccc | ||
|
|
fe703aba4e | ||
|
|
44a0f874b5 | ||
|
|
cf4f826c35 | ||
|
|
ec246e292f | ||
|
|
5e37125bd8 | ||
|
|
34ae8b2bb0 | ||
|
|
eaa03f56ed | ||
|
|
f746755110 | ||
|
|
3e4f68e52c | ||
|
|
03427e7bb5 | ||
|
|
e2901f8e28 | ||
|
|
e03d3d4339 | ||
|
|
07bdad7211 | ||
|
|
36a3558fb3 | ||
|
|
cc7f24c75c | ||
|
|
69ed3bc9fc | ||
|
|
40d7adea3c | ||
|
|
13a8e16371 | ||
|
|
599ca53030 | ||
|
|
7f5aeb6143 | ||
|
|
76883a5d72 | ||
|
|
ecbed88127 | ||
|
|
e908083694 | ||
|
|
13365dc258 | ||
|
|
7e1b6dd7b5 | ||
|
|
7cffec944d | ||
|
|
e1a17ac43f | ||
|
|
1abb04f928 | ||
|
|
9f1df84d26 | ||
|
|
180fa944f3 | ||
|
|
604edbd21c | ||
|
|
3a433ce82b | ||
|
|
41931df6df | ||
|
|
d373a863ef | ||
|
|
95d1476a68 | ||
|
|
2dc83743ed | ||
|
|
c7f06670c6 | ||
|
|
d712fe9d81 | ||
|
|
d1ad9f31f7 | ||
|
|
df73778b1e | ||
|
|
81f7af1857 | ||
|
|
947ec35d68 | ||
|
|
d68903b3bd | ||
|
|
8335ccc009 | ||
|
|
de41770853 | ||
|
|
85c1a8cc63 | ||
|
|
a6d87758f0 | ||
|
|
121f500d05 | ||
|
|
2b738fc2fd | ||
|
|
8c0e94715d | ||
|
|
24bfca106a | ||
|
|
03ff4f842e | ||
|
|
9fe6ab13ef | ||
|
|
bc601ae1ec | ||
|
|
34328a0d30 | ||
|
|
90466a502a | ||
|
|
4789bd85d5 | ||
|
|
ccfac53917 | ||
|
|
8fb572bd21 | ||
|
|
c8cabd8948 | ||
|
|
53fe2d4e26 | ||
|
|
80c07f6c1e | ||
|
|
ea4d489253 | ||
|
|
9dea698f1a | ||
|
|
a0bf320e54 | ||
|
|
b13f68a7be | ||
|
|
2b99b94222 | ||
|
|
4e4847da1b | ||
|
|
f686236a16 | ||
|
|
ca819b7dfd | ||
|
|
af3a2712cc | ||
|
|
9169bedc87 | ||
|
|
a4133e1b1d | ||
|
|
28d1b2f44a | ||
|
|
c45a6c33bc | ||
|
|
090993b642 | ||
|
|
c89ad02972 | ||
|
|
cf289d4cb7 | ||
|
|
21174226db | ||
|
|
7c0f225ff6 | ||
|
|
6b65efca11 | ||
|
|
b540d28124 | ||
|
|
950b604a93 | ||
|
|
72c9390093 | ||
|
|
afd19c54cc | ||
|
|
3f11894929 | ||
|
|
71b5ef7f73 | ||
|
|
7db94542bf | ||
|
|
12b2febd7a | ||
|
|
3fbde4a7a3 | ||
|
|
c5eb37d464 | ||
|
|
aa1e837ebe | ||
|
|
f05da2460a | ||
|
|
6a58c27ae5 | ||
|
|
88b152076e | ||
|
|
8ddd600b34 | ||
|
|
14c6365314 | ||
|
|
492b3ef2f3 | ||
|
|
11297b8e8f | ||
|
|
93d27beffc | ||
|
|
34456a44b6 | ||
|
|
f572537d67 | ||
|
|
17a76482a6 | ||
|
|
071ae11d63 | ||
|
|
9a7d4a6312 | ||
|
|
5aca245283 | ||
|
|
6e851b1271 | ||
|
|
77f576c50c | ||
|
|
c028c5ba7b | ||
|
|
327cfa5505 | ||
|
|
f42518148a | ||
|
|
3886fa0019 | ||
|
|
f11a345e87 | ||
|
|
7cf39eac2e | ||
|
|
89b80e584f | ||
|
|
cf03da130c | ||
|
|
df6f827f89 | ||
|
|
5c0ae6f1e5 | ||
|
|
341552f001 | ||
|
|
359978aac8 | ||
|
|
a040fe0097 | ||
|
|
87ff4ea9c3 | ||
|
|
99dbca9d3d | ||
|
|
7d82b43332 | ||
|
|
ecca4c7e6e | ||
|
|
767651e6b6 | ||
|
|
90b8b02724 | ||
|
|
46e908ac0a | ||
|
|
45d6f7c055 | ||
|
|
bb8ba5135c | ||
|
|
fb08b21d83 | ||
|
|
f007f169b7 | ||
|
|
8a32583f57 | ||
|
|
dd7e820013 | ||
|
|
79625e8df4 | ||
|
|
2eb0646e66 | ||
|
|
1431c2a58d | ||
|
|
762819a87e | ||
|
|
7af0589105 | ||
|
|
b134d89ed0 | ||
|
|
b519ea172c | ||
|
|
e7505a28bc | ||
|
|
87eda8619d | ||
|
|
524e40512c | ||
|
|
ab894d174d | ||
|
|
11f31d0466 | ||
|
|
562609af67 | ||
|
|
df881409e3 | ||
|
|
1d8b81d494 | ||
|
|
51b719a7d5 | ||
|
|
aa452f5578 | ||
|
|
16d506fd9f | ||
|
|
698a087c94 | ||
|
|
014953e2fa | ||
|
|
0423cbafc9 | ||
|
|
0a076e04f2 | ||
|
|
24935b7784 | ||
|
|
5ab96643b4 | ||
|
|
f07665c8f3 | ||
|
|
f4590d8596 | ||
|
|
59c7272a82 | ||
|
|
609b824ac9 | ||
|
|
5f0636c4e7 | ||
|
|
6598be34d4 | ||
|
|
9b3673b470 | ||
|
|
5e77e0a02b | ||
|
|
7bdd05e51d | ||
|
|
be7501f3da | ||
|
|
a80f7076d7 | ||
|
|
a839f02e80 | ||
|
|
e15d6697da | ||
|
|
1c455b99ee | ||
|
|
ef97f9e131 | ||
|
|
3f62b4e05e | ||
|
|
efc4ae2fca | ||
|
|
0f5653de62 | ||
|
|
d623514422 | ||
|
|
751cd7707e | ||
|
|
7640410d71 | ||
|
|
a51468118d | ||
|
|
3eee677648 | ||
|
|
2411c7566d | ||
|
|
3c016d2669 | ||
|
|
a3f1f7f5de | ||
|
|
964c8b77ab | ||
|
|
c7bc3e8348 | ||
|
|
10b066f193 | ||
|
|
6c12a124f2 | ||
|
|
3dbeedceda | ||
|
|
f7a94ad18a | ||
|
|
735f161966 | ||
|
|
4faa4303fe | ||
|
|
51eabbcd81 | ||
|
|
e4de80d028 | ||
|
|
17a0b39da8 | ||
|
|
654952842a | ||
|
|
b201cfa664 | ||
|
|
d22df75b7c | ||
|
|
bc6fab8c9f | ||
|
|
e55006f74b | ||
|
|
18864ad67f | ||
|
|
019d09c770 | ||
|
|
0a5ec22ddd | ||
|
|
8bb8e100d3 | ||
|
|
ffa513906a | ||
|
|
de12eb6c4a | ||
|
|
98d8b45dc4 | ||
|
|
e9a770315d | ||
|
|
c966f9a2f3 | ||
|
|
ad8626b1eb | ||
|
|
f19cbfa718 | ||
|
|
7819f0b4d8 | ||
|
|
64a2e5bc91 | ||
|
|
fd54ad7314 | ||
|
|
cae9340a5d | ||
|
|
c9641bcd55 | ||
|
|
d963dab12a | ||
|
|
1e9fcd95c9 | ||
|
|
3e2aec1a03 | ||
|
|
b66fd79d21 | ||
|
|
57b813f39d | ||
|
|
b62073ce77 | ||
|
|
3f37d9c9c1 | ||
|
|
bde879104e | ||
|
|
e7b481d93e | ||
|
|
51af760783 | ||
|
|
104a485302 | ||
|
|
6db13355e7 | ||
|
|
eafae52ba5 | ||
|
|
0c71e02e56 | ||
|
|
7e60cdb198 | ||
|
|
79f77125e1 | ||
|
|
61513f910b | ||
|
|
5228119251 | ||
|
|
2fa29b90cc | ||
|
|
c9ecc2ddf7 | ||
|
|
1468cf0051 | ||
|
|
e71c28ef99 | ||
|
|
c0442a131c | ||
|
|
086c0ec5c7 | ||
|
|
6e40db4975 | ||
|
|
1713f2f9aa | ||
|
|
38531c77ab | ||
|
|
3cf8aff57f | ||
|
|
3d87b9ccab | ||
|
|
2aecce6161 | ||
|
|
adf1b0408c | ||
|
|
7380a8b163 | ||
|
|
1ed6dd76c6 | ||
|
|
3258313300 | ||
|
|
16f3f7e9fd | ||
|
|
6174b97b99 | ||
|
|
df8901ca3a | ||
|
|
697ebc6599 | ||
|
|
2728aa6db0 | ||
|
|
3e7a3a879b | ||
|
|
98f2341a4b | ||
|
|
8fdfdc0f50 | ||
|
|
cfd26f7d18 | ||
|
|
a0b281a035 | ||
|
|
e96fe12663 | ||
|
|
2a865e78f8 | ||
|
|
c640480e6d | ||
|
|
93941f5e1b | ||
|
|
a5bfd9b9b8 | ||
|
|
0eb1b6ac8b | ||
|
|
87b89e54ba | ||
|
|
64c0549844 | ||
|
|
7665c73acc | ||
|
|
b68ef803ce | ||
|
|
4f2f50e32e | ||
|
|
d717fe28e4 | ||
|
|
f728f01857 | ||
|
|
ba3cc9061f | ||
|
|
fb12383641 | ||
|
|
fce952b71c | ||
|
|
2d8e148e95 | ||
|
|
ce560b2bb2 | ||
|
|
5e62325a18 | ||
|
|
65b652a6f4 | ||
|
|
35509356f0 | ||
|
|
9799dd2455 | ||
|
|
33f2bb0d79 | ||
|
|
86db5cd629 | ||
|
|
347862ac5a | ||
|
|
dfcdf4419d | ||
|
|
287d2929c9 | ||
|
|
f2c64f1925 | ||
|
|
a690092acf | ||
|
|
cda6eb261e | ||
|
|
e5aa66fe72 | ||
|
|
7f629160d4 | ||
|
|
0de432be00 | ||
|
|
c0b0ec216a | ||
|
|
0b4efea5b8 | ||
|
|
11c68af70c | ||
|
|
3cf02c33ef | ||
|
|
189781312b | ||
|
|
fd21495b10 | ||
|
|
05738a14ab | ||
|
|
65cbefdc80 | ||
|
|
80ea6ad839 | ||
|
|
c1c6f549cd | ||
|
|
320b46783a | ||
|
|
7af08a4b48 | ||
|
|
3053fb6b38 | ||
|
|
92be45cdad | ||
|
|
31c9d17a78 | ||
|
|
bf05d4779b | ||
|
|
5d3eccdb0f | ||
|
|
b6e543bc2b | ||
|
|
9a8dab92d1 | ||
|
|
729e05af40 | ||
|
|
ce662e5c3a | ||
|
|
b8f69d39ce | ||
|
|
1c8381be73 | ||
|
|
0e7e81e8c0 | ||
|
|
f687b17645 | ||
|
|
4f147b7bbc | ||
|
|
316e4aff8a | ||
|
|
61ad847513 | ||
|
|
5173a4e533 | ||
|
|
527d24a5fd | ||
|
|
71c9417d75 | ||
|
|
746b85abc3 | ||
|
|
259b9b063e | ||
|
|
d41f254bea | ||
|
|
8e43f6f4fc | ||
|
|
c40c78dfdd | ||
|
|
7d45999ace | ||
|
|
7ded800457 | ||
|
|
6560f9a2e9 | ||
|
|
5c9c1b8e3c | ||
|
|
68964f4b75 | ||
|
|
a6f549e867 | ||
|
|
e9e6ec9d22 | ||
|
|
40e39f12be | ||
|
|
1e1fc5ad54 | ||
|
|
833979c77a | ||
|
|
10830dacbc | ||
|
|
85bce938fc | ||
|
|
ddf02b5ea1 | ||
|
|
8e8e103b0a | ||
|
|
444262d856 | ||
|
|
b466aec998 | ||
|
|
c1afdbfbd7 | ||
|
|
cf393afbcb | ||
|
|
8dd42aba14 | ||
|
|
42828ba0a9 | ||
|
|
688ef4da7d | ||
|
|
8c15ff6ae6 | ||
|
|
0a38118f51 | ||
|
|
7579ce796d | ||
|
|
1decdebab9 | ||
|
|
c691adc894 | ||
|
|
c5e984eb72 | ||
|
|
236363eb99 | ||
|
|
77963577b1 | ||
|
|
e32d1ff144 | ||
|
|
085f703ec9 | ||
|
|
7a76942833 | ||
|
|
6c793047f3 | ||
|
|
b197cee5fa | ||
|
|
1e49d9cc81 | ||
|
|
afea316ea0 | ||
|
|
074ad08911 | ||
|
|
aebf66b9aa | ||
|
|
9643d9d72c | ||
|
|
5c0fe5b634 | ||
|
|
f8a084c5e9 | ||
|
|
726180dc36 | ||
|
|
95a1b63b80 | ||
|
|
d1f4c5f1c3 | ||
|
|
952f88936c | ||
|
|
4ad0326ec3 | ||
|
|
d4885cc30a | ||
|
|
8cb010ca04 | ||
|
|
989d084075 | ||
|
|
6b044b18cf | ||
|
|
2ceb53d630 | ||
|
|
94dccba69c | ||
|
|
ad9f213399 | ||
|
|
011e9c4437 | ||
|
|
c965aaf380 | ||
|
|
a312d1e96e | ||
|
|
e85cd6aa3a | ||
|
|
de7e98b3fd | ||
|
|
55cbc8610c | ||
|
|
3dbda0ab5f | ||
|
|
c82d6050b0 | ||
|
|
dc22d2e7ee | ||
|
|
8c70a8b961 | ||
|
|
c225e168bf | ||
|
|
a251f16ae7 | ||
|
|
0bb1504c38 | ||
|
|
e2a1bcbc3e | ||
|
|
3dd2ace221 | ||
|
|
d7846eb049 | ||
|
|
d924f7b4ed | ||
|
|
84d0a7e002 | ||
|
|
ec17c24c9f | ||
|
|
fa93e4cf95 | ||
|
|
4e6881c088 | ||
|
|
9890b0a8b9 | ||
|
|
131c717f0f | ||
|
|
412bd411dc | ||
|
|
e257e225f7 | ||
|
|
3a77095e09 | ||
|
|
1ee50b95c6 | ||
|
|
6dae87a349 | ||
|
|
376ecb60b6 | ||
|
|
36823f55f4 | ||
|
|
c526616e84 | ||
|
|
6aff15bb45 | ||
|
|
909e32c084 | ||
|
|
da106e70ae | ||
|
|
0fd5a43618 | ||
|
|
b121b0de51 | ||
|
|
cfb8ebe66b | ||
|
|
91e536efb4 | ||
|
|
6be0394931 | ||
|
|
6a185aba71 | ||
|
|
c5f52f352a | ||
|
|
0cb05ed5d6 | ||
|
|
51b293d883 | ||
|
|
27447d3c46 | ||
|
|
482926ce8a | ||
|
|
bc8fa0b83c | ||
|
|
4190b3316b | ||
|
|
d208be330b | ||
|
|
41bb8a8267 | ||
|
|
c8f9981c28 | ||
|
|
f357bc3d8b | ||
|
|
e8a4795ff6 | ||
|
|
9e1f61bd67 | ||
|
|
e26b849d20 | ||
|
|
a5a6ba2384 | ||
|
|
fa0ea70500 | ||
|
|
415c9f9dcb | ||
|
|
d0a22014dd | ||
|
|
6538dc9cb6 | ||
|
|
3542a79b5a | ||
|
|
dad8b50b8c | ||
|
|
3f12554d36 | ||
|
|
ad5d25460e | ||
|
|
b3c3d2d21a | ||
|
|
0d6504caac | ||
|
|
79d4307520 | ||
|
|
a51734237a | ||
|
|
a5a88b8d16 | ||
|
|
cce74865d0 | ||
|
|
53088fb169 | ||
|
|
2859d8902b | ||
|
|
3ce1b5dd61 | ||
|
|
eb9f154ee5 | ||
|
|
d27ec0b417 | ||
|
|
726fda5dd3 | ||
|
|
f89aa8204d | ||
|
|
4daf0bbc08 | ||
|
|
bd5e795dba | ||
|
|
18a931ee11 | ||
|
|
5dd3568167 | ||
|
|
aff1a7bc44 | ||
|
|
0c368bab99 | ||
|
|
053adbc5cd | ||
|
|
406079954f | ||
|
|
36acb54012 | ||
|
|
a757483db0 | ||
|
|
d54f57457e | ||
|
|
5b4c81c21b | ||
|
|
f5f7162c4d | ||
|
|
bd05d2f4c0 | ||
|
|
3a04b50051 | ||
|
|
eae64dc18b | ||
|
|
388842988d | ||
|
|
ae87b63524 | ||
|
|
6715c73834 | ||
|
|
cb2268aa1a | ||
|
|
c283381b44 | ||
|
|
b810fbd98f | ||
|
|
b259c01dcf | ||
|
|
b7f4ae5b01 | ||
|
|
f970aa1a9a | ||
|
|
a788c4769d | ||
|
|
927225f4fa | ||
|
|
9d32f971d4 | ||
|
|
e75e4be9ff | ||
|
|
b59046a3bd | ||
|
|
c394053016 | ||
|
|
a4d99f8a28 | ||
|
|
e9af823446 | ||
|
|
26656fec7d | ||
|
|
5e5682b51b | ||
|
|
7cbd85f350 | ||
|
|
2867560199 | ||
|
|
c944aa11b9 | ||
|
|
49b5a434f0 | ||
|
|
b19570043c | ||
|
|
dd42e3f8ca | ||
|
|
bd91f5f83e | ||
|
|
bf4aa1ba4b | ||
|
|
15e86494a3 | ||
|
|
bc686ef1ad | ||
|
|
30480f084a | ||
|
|
2ac2e4ed63 | ||
|
|
4880292eae | ||
|
|
b0957d770f | ||
|
|
89d7cca418 | ||
|
|
0ea48acfd2 | ||
|
|
2d2f8f3d9d | ||
|
|
0c4977af91 | ||
|
|
ebc5830977 | ||
|
|
81d5c1c87b | ||
|
|
ee3ac849ea | ||
|
|
d7ced1e954 | ||
|
|
5525d6ed29 | ||
|
|
3e282a0569 | ||
|
|
58d7630ef3 | ||
|
|
9007bf94ef | ||
|
|
418be24d01 | ||
|
|
76c99abbf4 | ||
|
|
c704a2e01d | ||
|
|
25173d83c6 | ||
|
|
6853c82026 | ||
|
|
3f7d144e99 | ||
|
|
d4d4abfd8e | ||
|
|
65245e28f6 | ||
|
|
b95f29bbaf | ||
|
|
cfaabdbba9 | ||
|
|
4c39d61b3b | ||
|
|
257be0e609 | ||
|
|
f46c349e43 | ||
|
|
54c1a6e06b | ||
|
|
9bbf8943ec | ||
|
|
2c08f6dc68 | ||
|
|
14387d1d71 | ||
|
|
104dd842a3 | ||
|
|
62937ee9e2 | ||
|
|
387f562991 | ||
|
|
b88f63edf0 | ||
|
|
35c2a064e2 | ||
|
|
9efda25855 | ||
|
|
370cf9de26 | ||
|
|
82b9ad0705 | ||
|
|
565ae1dec8 | ||
|
|
d87387e77e | ||
|
|
b1858490f1 | ||
|
|
bf74da8aef | ||
|
|
33c578e90a | ||
|
|
8cb32c6458 | ||
|
|
20ab243d31 | ||
|
|
fad62952d7 | ||
|
|
998827c456 | ||
|
|
1c178d3ebc | ||
|
|
85a90e3516 | ||
|
|
49d302ded9 | ||
|
|
b29187fa93 | ||
|
|
d726a1e13c | ||
|
|
607a78ffe4 | ||
|
|
21e24fb75b | ||
|
|
7de0729543 | ||
|
|
23a7119fad | ||
|
|
846a00137f | ||
|
|
bf4fddca02 | ||
|
|
23f4b0a2bb | ||
|
|
04d29c70dd | ||
|
|
bc9bf3ee61 | ||
|
|
a7c3539bb1 | ||
|
|
ef8e1a63d2 | ||
|
|
6ee936db79 | ||
|
|
6f77347dc3 | ||
|
|
a785422049 | ||
|
|
b161e9a0e1 | ||
|
|
6d978f2a94 | ||
|
|
387502018f | ||
|
|
be73522f53 | ||
|
|
325cff977f | ||
|
|
23e263347e | ||
|
|
932dd8d06d | ||
|
|
bb6318c62c | ||
|
|
f066f60543 | ||
|
|
93c3afacbf | ||
|
|
96544fd819 | ||
|
|
5f41a73938 | ||
|
|
cd8733e5c8 | ||
|
|
248f5f769b | ||
|
|
5559950997 | ||
|
|
633a2d193e | ||
|
|
0755676585 | ||
|
|
86ce1fde06 | ||
|
|
a28cbfab3f | ||
|
|
fff2fc522b | ||
|
|
2ab4dfb9e8 | ||
|
|
0cf0bc0bd7 | ||
|
|
9036ae9475 | ||
|
|
4077e3ed51 | ||
|
|
23f145d8bc | ||
|
|
45855062c2 | ||
|
|
c67c9ad4d5 | ||
|
|
9826e6a174 | ||
|
|
b2afc88b4c | ||
|
|
4678fc3b3e | ||
|
|
db19cb6862 | ||
|
|
c72a7aab5e | ||
|
|
bf4a7d69e4 | ||
|
|
5c37b9d20c | ||
|
|
8b4ac42ec7 | ||
|
|
1bd9a4cdec | ||
|
|
f0872f2dac | ||
|
|
cae4c25810 | ||
|
|
712923547f | ||
|
|
0f62518dde | ||
|
|
f15913d044 | ||
|
|
4efb76821d | ||
|
|
57bf27e78f | ||
|
|
4e1b0f0f69 | ||
|
|
10e9a4f929 | ||
|
|
a63d3bdf40 | ||
|
|
68c0499e21 | ||
|
|
c1a474dc83 | ||
|
|
319c267e34 | ||
|
|
209cdba897 | ||
|
|
78101a7f66 | ||
|
|
b20a1c2419 | ||
|
|
d41d13683f | ||
|
|
ad947e4d49 | ||
|
|
28c3ab5af3 | ||
|
|
60a8df882d | ||
|
|
65caaef1e6 | ||
|
|
7404df4269 | ||
|
|
e996470196 | ||
|
|
32ba53f06f | ||
|
|
e734087706 | ||
|
|
f755947f7e | ||
|
|
17d0e7d345 | ||
|
|
7ac6915202 | ||
|
|
1fc6cd4dc6 | ||
|
|
010156f690 | ||
|
|
34e9006702 | ||
|
|
369e21f430 | ||
|
|
e444b823c2 | ||
|
|
024655be6b | ||
|
|
d31fee5d22 | ||
|
|
90aebe81cc | ||
|
|
fb7cdd7d98 | ||
|
|
fc0ad052dd | ||
|
|
a951c80bf6 | ||
|
|
b7d2cdf6b5 | ||
|
|
b46ad42885 | ||
|
|
f738f277c8 | ||
|
|
6f23c781ae | ||
|
|
a36506d7a0 | ||
|
|
dd0ce1a2ba | ||
|
|
1278024384 | ||
|
|
4e12ba97f7 | ||
|
|
28404489d1 | ||
|
|
d52c0089bd | ||
|
|
5a7ea48438 | ||
|
|
f8a0574b93 | ||
|
|
6fb20e0d62 | ||
|
|
f991f4125e | ||
|
|
55d5490852 | ||
|
|
d289bfc7c2 | ||
|
|
93bf6d9509 | ||
|
|
fe9c2b2490 | ||
|
|
af380d0358 | ||
|
|
d3d176cafe | ||
|
|
21cb0ec248 | ||
|
|
4cbc932967 | ||
|
|
e14e024a4e | ||
|
|
d7e8333aed | ||
|
|
bb98e94183 | ||
|
|
c8d1dc92ac | ||
|
|
7716846541 | ||
|
|
96c9fd3806 | ||
|
|
94f696ca01 | ||
|
|
ebf0b7bec6 | ||
|
|
17d60844e6 | ||
|
|
96173d7500 | ||
|
|
dc216ff081 | ||
|
|
e0afee6b13 | ||
|
|
313fb74dc7 | ||
|
|
f3db5d7822 | ||
|
|
d7b63d072a | ||
|
|
f81bb5cd22 | ||
|
|
155c71de86 | ||
|
|
a0eda9c6aa | ||
|
|
00a56eaa8a | ||
|
|
f5df3f93ac | ||
|
|
8423f6d2d7 | ||
|
|
b3109e2241 | ||
|
|
2b633b99a3 | ||
|
|
cf521d26c7 | ||
|
|
158a6f26e2 | ||
|
|
c4ffe25603 | ||
|
|
e8d593e467 | ||
|
|
f6aec0ec2a | ||
|
|
7cea7ef549 | ||
|
|
84a6a44bbe | ||
|
|
5bfdc4f45a | ||
|
|
5102e55b7e | ||
|
|
46dc0b5b6d | ||
|
|
5cb63b299d | ||
|
|
979c27387e | ||
|
|
f6f977503e | ||
|
|
2b5a99ed59 | ||
|
|
d1c5b907c0 | ||
|
|
58f0adc560 | ||
|
|
697b6e211d | ||
|
|
3977ae2ce0 | ||
|
|
09b9065e10 | ||
|
|
3197ad19e5 | ||
|
|
4359a9735b | ||
|
|
77f63ecd28 | ||
|
|
2f369e1d38 | ||
|
|
9367098259 | ||
|
|
de9072a1b5 | ||
|
|
1ef283ad22 | ||
|
|
858faf2c88 | ||
|
|
9824e59ef9 | ||
|
|
9594efcf03 | ||
|
|
3e5fd573a6 | ||
|
|
79c143b7eb | ||
|
|
af753c38be | ||
|
|
5b826cc9e9 | ||
|
|
b50afff4a1 | ||
|
|
7d5641bae7 | ||
|
|
03500503ab | ||
|
|
0237c94a5f | ||
|
|
a27a985551 | ||
|
|
4a39fc82f1 | ||
|
|
4428efbc3b | ||
|
|
88bd695007 | ||
|
|
84215b1721 | ||
|
|
8ec2c7f88c | ||
|
|
9188c7faf2 | ||
|
|
f8ac8eda89 | ||
|
|
8e689db6d7 | ||
|
|
c602789ac4 | ||
|
|
b91156db9b | ||
|
|
b3fb8a7a15 | ||
|
|
89236042c2 | ||
|
|
27ee8c90d5 | ||
|
|
d330c09e60 | ||
|
|
33cc1f0b2d | ||
|
|
ea5717da6e | ||
|
|
2a906b02fb | ||
|
|
913b7304d6 | ||
|
|
1ad42867bc | ||
|
|
412979f721 | ||
|
|
68c7f0f000 | ||
|
|
2029fe08f1 | ||
|
|
71b46ea44e | ||
|
|
5ff976793e | ||
|
|
522d838ec5 | ||
|
|
c1441a8dab | ||
|
|
a7a1e6e8b0 | ||
|
|
b3bddd33ea | ||
|
|
28ea702901 | ||
|
|
ec62c80ccc | ||
|
|
e9ae9a9922 | ||
|
|
dd5cb223a9 | ||
|
|
d4f13317fc | ||
|
|
2ca125ab07 | ||
|
|
30546d0b5e | ||
|
|
60074be670 | ||
|
|
2e2f7bd7c4 | ||
|
|
8ae490c7b2 | ||
|
|
f85112afa9 | ||
|
|
589d0b9dde | ||
|
|
285c90999e | ||
|
|
cd00c626c7 | ||
|
|
138cbad573 | ||
|
|
801fbb89b5 | ||
|
|
15a4277302 | ||
|
|
b21a684180 | ||
|
|
f8d66cf76e | ||
|
|
205da83357 | ||
|
|
da21039a38 | ||
|
|
559c014bc4 | ||
|
|
6fce68aa76 | ||
|
|
5131631de5 | ||
|
|
01ba495e10 | ||
|
|
4e395eafbb | ||
|
|
3162e8db93 | ||
|
|
ecd57daa56 | ||
|
|
6dccaa5841 | ||
|
|
c8bded4468 | ||
|
|
a1f6743de2 | ||
|
|
32a39e530a | ||
|
|
69882216e9 | ||
|
|
83341c30a0 | ||
|
|
bac6a98a72 | ||
|
|
7a72106197 | ||
|
|
9c569ed87e | ||
|
|
5dcbc9a5d3 | ||
|
|
0d625d516f | ||
|
|
652e9a3d3d | ||
|
|
67d61ac11e | ||
|
|
8541dbd8c6 | ||
|
|
99b8481f4d | ||
|
|
074065b190 | ||
|
|
f63db63e76 | ||
|
|
359c343854 | ||
|
|
a18c05e41a | ||
|
|
87c5da1ba0 | ||
|
|
b8fc6e5227 | ||
|
|
100132d20a | ||
|
|
60cee89061 | ||
|
|
377f16d6e6 | ||
|
|
b0213fe517 | ||
|
|
f791019ad1 | ||
|
|
cb2be2f382 | ||
|
|
89f5cbfb78 | ||
|
|
b16b685bb7 | ||
|
|
73af932419 | ||
|
|
d3833180e8 | ||
|
|
fc226dc578 | ||
|
|
d7c3e23b00 | ||
|
|
da11ed70a4 | ||
|
|
6f2a30e18f | ||
|
|
3ac0b2462f | ||
|
|
2c21320679 | ||
|
|
1d05a87a8c | ||
|
|
74a6d00c42 | ||
|
|
543adf32cf | ||
|
|
5399481a0d | ||
|
|
67fe10b128 | ||
|
|
d6e8404560 | ||
|
|
dae2133d58 | ||
|
|
f1fc2d1ba6 | ||
|
|
283ff13016 | ||
|
|
007a2aafb0 | ||
|
|
035d2d50f3 | ||
|
|
011e25e298 | ||
|
|
ae9fabb001 | ||
|
|
02b004b3cd | ||
|
|
4b7d331bef | ||
|
|
3652388aa5 | ||
|
|
f69157dcd9 | ||
|
|
f3527e1960 | ||
|
|
a2268c6560 | ||
|
|
3cc888d053 | ||
|
|
0acaee5871 | ||
|
|
f4c6c470db | ||
|
|
3aa4bd1eb6 | ||
|
|
f2c5a6fe91 | ||
|
|
9c8827cdab | ||
|
|
4b6247105a | ||
|
|
cafb573a39 | ||
|
|
c37197f91a | ||
|
|
a9dcc52b10 | ||
|
|
940096746f | ||
|
|
ec0254739f | ||
|
|
f3a3191730 | ||
|
|
5ea4029e0a | ||
|
|
2c5305d2f6 | ||
|
|
c32df6489f | ||
|
|
3e3a833332 | ||
|
|
bccabdc5ba | ||
|
|
dd2be687e1 | ||
|
|
3c71a30cbb | ||
|
|
fd8c22bb26 | ||
|
|
d1088b70dd | ||
|
|
9054726d53 | ||
|
|
cc6dfc8068 | ||
|
|
c192c26447 | ||
|
|
ddf2e6a0f3 | ||
|
|
a7041eda93 | ||
|
|
657097029c | ||
|
|
70c189b56a | ||
|
|
b5988ffa0f | ||
|
|
2764c0beef | ||
|
|
11887fd53a | ||
|
|
e47a6ba988 | ||
|
|
14efa6248e | ||
|
|
81f5afc76f | ||
|
|
9cd25bd5ff | ||
|
|
3ecd474137 | ||
|
|
04152d09f5 | ||
|
|
8c706e2a4c | ||
|
|
094a3b5c52 | ||
|
|
f2724daa5b | ||
|
|
3781f7a08d | ||
|
|
394d1c0590 | ||
|
|
63291a1906 | ||
|
|
3e77d1efae | ||
|
|
c8adf9cefa | ||
|
|
05b86b6375 | ||
|
|
eb77c7cbde | ||
|
|
0493aee1ae | ||
|
|
f11e1b7e1a | ||
|
|
7d3c213b7e | ||
|
|
c3e0c1449a | ||
|
|
989984b05e | ||
|
|
ddceab0c5e | ||
|
|
c6e0fd7fa7 | ||
|
|
ce0d82dfbc | ||
|
|
5eba49e20a | ||
|
|
343918bd8a | ||
|
|
a4d33afe60 | ||
|
|
86ef471467 | ||
|
|
ce8c5dacd5 | ||
|
|
1fd6f1a1c3 | ||
|
|
7e622c391d | ||
|
|
cc1bb2306b | ||
|
|
4d1ab35ddf | ||
|
|
2c18f0dbc1 | ||
|
|
11db6004e4 | ||
|
|
0e2be61276 | ||
|
|
8324a1fefa | ||
|
|
a5d9010494 | ||
|
|
0a5e06c569 | ||
|
|
13af836ca1 | ||
|
|
675b815ce0 | ||
|
|
c3f5af6d60 | ||
|
|
d4a9789efc | ||
|
|
a9fb99fbbc | ||
|
|
55e81b75dc | ||
|
|
8620d8fb68 | ||
|
|
7225e445ce | ||
|
|
afd1c8cda1 | ||
|
|
88496cd851 | ||
|
|
1f4c2298aa | ||
|
|
b4ff436b5f | ||
|
|
e912ef64fe | ||
|
|
4d0241e61d | ||
|
|
62cb894484 | ||
|
|
b4d0aadaeb | ||
|
|
6072544004 | ||
|
|
f61b8c9337 | ||
|
|
9a048f250d | ||
|
|
bef465e2c7 | ||
|
|
3eb98562ef | ||
|
|
1407e0cf26 | ||
|
|
69d2b8641b | ||
|
|
b286be7d22 | ||
|
|
7f6a1e0140 | ||
|
|
535e70637f | ||
|
|
0fa2b5ce6d | ||
|
|
eabc237a59 | ||
|
|
f4791be5c3 | ||
|
|
9b6dec06bc | ||
|
|
819a513030 | ||
|
|
a33c1fb733 | ||
|
|
f8a4166c6c | ||
|
|
a2452767cb | ||
|
|
efe1180e1c | ||
|
|
b830201675 | ||
|
|
bda639a23b | ||
|
|
c6502101d4 | ||
|
|
95e6d0371d | ||
|
|
7f6cde45d1 | ||
|
|
04a7d08c1a | ||
|
|
28b909e4fb | ||
|
|
cd57742602 | ||
|
|
338136bd4c | ||
|
|
a7c7496465 | ||
|
|
82cf526f43 | ||
|
|
f02b6aa9de | ||
|
|
a7c1cdf8ff | ||
|
|
9b6b676dd1 | ||
|
|
3ea0711b28 | ||
|
|
b85f9b22a1 | ||
|
|
279da41b1d | ||
|
|
645a172801 | ||
|
|
020cef6706 | ||
|
|
6b0bcf3927 | ||
|
|
125489b4ea | ||
|
|
77828b3d00 | ||
|
|
31b4823281 | ||
|
|
407737df09 | ||
|
|
30a66adb60 | ||
|
|
cf5834653f | ||
|
|
c115e6e816 | ||
|
|
a5e2c1600a | ||
|
|
2f2a56bd12 | ||
|
|
21e84b84ef | ||
|
|
e71d932b30 | ||
|
|
ced5f068b1 | ||
|
|
883c79b14f | ||
|
|
073e8cf98b | ||
|
|
73b84862fb | ||
|
|
d5f5956187 | ||
|
|
1b90f240b1 | ||
|
|
56e26d051e | ||
|
|
dc6625e466 | ||
|
|
080f935a42 | ||
|
|
e797e7d78b | ||
|
|
a65b1fcc09 | ||
|
|
e3014390c4 | ||
|
|
81e8f3dee2 | ||
|
|
55fc81755f | ||
|
|
ec7b54979e | ||
|
|
adb9939df0 | ||
|
|
48be2d9005 | ||
|
|
8a4b4b3d7b | ||
|
|
c9cf5b7db8 | ||
|
|
bb6fea731e | ||
|
|
05a08b6ff8 | ||
|
|
3784e1e007 |
2
.gitignore
vendored
@ -25,4 +25,4 @@ __pycache__/
|
||||
.tags
|
||||
pp
|
||||
|
||||
.idea/
|
||||
.idea/
|
||||
|
||||
6
.gitmodules
vendored
@ -14,3 +14,9 @@
|
||||
[submodule "stm32/mk4-bootloader/hal"]
|
||||
path = stm32/mk4-bootloader/hal
|
||||
url = https://github.com/STMicroelectronics/STM32CubeL4.git
|
||||
[submodule "misc/gpu/external/stm32c0xx_hal_driver"]
|
||||
path = misc/gpu/external/stm32c0xx_hal_driver
|
||||
url = https://github.com/STMicroelectronics/stm32c0xx_hal_driver.git
|
||||
[submodule "misc/gpu/external/cmsis_device_c0"]
|
||||
path = misc/gpu/external/cmsis_device_c0
|
||||
url = https://github.com/STMicroelectronics/cmsis_device_c0.git
|
||||
|
||||
56
README.md
@ -1,4 +1,4 @@
|
||||
# Coldcard Wallet
|
||||
# COLDCARD Hardware Wallet
|
||||
|
||||
Coldcard is an Affordable, Ultra-secure & Verifiable Hardware Wallet for Bitcoin.
|
||||
Get yours at [Coldcard.com](http://coldcard.com)
|
||||
@ -8,7 +8,13 @@ with the latest updates and security alerts.
|
||||
|
||||

|
||||
|
||||

|
||||

|
||||
|
||||
## Quick Links
|
||||
|
||||
- [Latest firmware changes and updates](releases/ChangeLog.md)
|
||||
- [PGP signature file](releases/signatures.txt)
|
||||
- [Firmware binaries](https://coldcard.com/downloads)
|
||||
|
||||
## Reproducible Builds
|
||||
|
||||
@ -18,17 +24,23 @@ has been automated using Docker. Steps are as follows:
|
||||
|
||||
1. Install [Docker](https://www.docker.com) and start it.
|
||||
2. Install [make (GNUMake)](https://www.gnu.org/software/make/) if you don't already have it.
|
||||
3. Checkout the code, and start the process.
|
||||
3. Checkout a specific version of the code, and start the process.
|
||||
|
||||
```shell
|
||||
git clone https://github.com/Coldcard/firmware.git
|
||||
cd firmware/stm32
|
||||
make repro
|
||||
cd firmware
|
||||
# DOWNLOAD https://coldcard.com/downloads
|
||||
# get a copy of binary into ./releases/2026-03-05T2052-v5.5.0-mk-coldcard.dfu
|
||||
git checkout 2026-03-05T2052-v5.5.0
|
||||
cd stm32
|
||||
make -f MK4-Makefile repro
|
||||
```
|
||||
|
||||
4. At the end of the process a clear confirmation message is shown, or the differences.
|
||||
5. Build products can be found `firmware/stm32/built`.
|
||||
6. If you do not trust the results of `make repro` refer to `docs/notes-on-repro.md` which breaks down the process.
|
||||
6. If you do not trust the results of `make repro` refer to `docs/notes-on-repro.md`
|
||||
which breaks down the process.
|
||||
7. Process for Q firmware is the same, but change `MK4-Makefile` in last step to `Q1-Makefile`
|
||||
|
||||
## Long-Lived Branches
|
||||
|
||||
@ -39,13 +51,18 @@ such as Taproot or Miniscript. Our standards for releasing new Edge
|
||||
versions are lower, so we can iterate faster and get these advancements
|
||||
out to other developers.
|
||||
|
||||
Q and Mk series share the same code base. Individual files that are added,
|
||||
or removed, can be see in differences between `shared/manifest_mk4.py`
|
||||
and `shared/manifest_q1.py`. Common files are in `shared/manifest.py`.
|
||||
Firmware built for Mk5, supports the Mk4 without any functional differences.
|
||||
|
||||
|
||||
## Check-out and Setup
|
||||
|
||||
**NOTE** This is the `master` branch and covers the latest hardware (Mk4).
|
||||
**NOTE** This is the `master` branch and covers the latest hardware (Mk and Q).
|
||||
See branch `v4-legacy` for firmware which supports only Mk3/Mk2 and earlier.
|
||||
|
||||
Do a checkout, recursively to get all the submodules:
|
||||
Do a checkout, recursively, to get all the submodules:
|
||||
|
||||
```shell
|
||||
git clone --recursive https://github.com/Coldcard/firmware.git
|
||||
@ -68,7 +85,7 @@ git submodule update --init --recursive
|
||||
```
|
||||
|
||||
Do not use a path with any spaces in it. The Makefiles do not handle
|
||||
that well, and we're not planning to fix it.
|
||||
that well and we're not planning to fix it.
|
||||
|
||||
Keep in mind that python requirements may change between versions,
|
||||
so at the top level, do this command:
|
||||
@ -169,7 +186,16 @@ git clone --recursive https://github.com/Coldcard/firmware.git
|
||||
cd firmware
|
||||
|
||||
# Apply address patch
|
||||
git apply unix/linux_addr.patch
|
||||
# if unix/linux_addr.patch exists use below command
|
||||
# not needed in current revision
|
||||
# git apply unix/linux_addr.patch
|
||||
|
||||
# * below is needed for ubuntu 24.04
|
||||
pushd external/micropython
|
||||
git apply ../../ubuntu24_mpy.patch
|
||||
popd
|
||||
# *
|
||||
|
||||
|
||||
# Create Python virtual environment and activate it
|
||||
python3 -m venv ENV # or virtualenv -p python3 ENV
|
||||
@ -209,8 +235,8 @@ Top-level dirs:
|
||||
|
||||
- shared code between desktop test version and real-deal
|
||||
- expected to be largely in python, and higher-level
|
||||
- new code found only on the Mk4 will be listed in `manifest_mk4.py` code exclusive
|
||||
to earlier hardware is in `manifest_mk3.py`
|
||||
- code exclusive to the Mk4 or Mk5 will be listed in `manifest_mk4.py`, and
|
||||
to the Q will be listed in `manifest_q1.py`
|
||||
|
||||
`unix`
|
||||
|
||||
@ -240,13 +266,14 @@ Top-level dirs:
|
||||
- however, you can inspect what code is on your coldcard and compare to this.
|
||||
|
||||
`stm32/mk4-bootloader`
|
||||
`stm32/q1-bootloader`
|
||||
|
||||
- 128k of factory-set code that you cannot change for Mk4
|
||||
- 128k of factory-set code that you cannot change
|
||||
- however, you can inspect what code is on your coldcard and compare to this.
|
||||
|
||||
`hardware`
|
||||
|
||||
- schematic and bill of materials for the Coldcard
|
||||
- schematic and bill of materials for the Coldcard, all versions.
|
||||
|
||||
`unix/work/...`
|
||||
|
||||
@ -259,3 +286,4 @@ Top-level dirs:
|
||||
## Support
|
||||
|
||||
Found a bug? Email: support@coinkite.com
|
||||
|
||||
|
||||
@ -1 +1 @@
|
||||
../stm32/bootloader/sigheader.py
|
||||
../stm32/sigheader.py
|
||||
@ -208,7 +208,9 @@ def readback(fname):
|
||||
if v & MK_2_OK: d.append('Mk2')
|
||||
if v & MK_3_OK: d.append('Mk3')
|
||||
if v & MK_4_OK: d.append('Mk4')
|
||||
if v & ~(MK_1_OK | MK_2_OK | MK_3_OK | MK_4_OK):
|
||||
if v & MK_5_OK: d.append('Mk5')
|
||||
if v & MK_Q1_OK: d.append('Q1')
|
||||
if v & ~(MK_1_OK | MK_2_OK | MK_3_OK | MK_4_OK | MK_5_OK | MK_Q1_OK):
|
||||
d.append('?other?')
|
||||
v = nv + '+'.join(d)
|
||||
elif fld == 'timestamp':
|
||||
@ -244,7 +246,7 @@ def readback(fname):
|
||||
@click.option('--pubkey-num', '-k', type=int, help='Which key # to use for signing', default=0)
|
||||
@click.option('--high_water', '-h', is_flag=True, help='Mark version as new highwater mark (no downgrades below this version)')
|
||||
@click.option('--verbose', '-v', default=False, is_flag=True, help='Show numbers related to signature')
|
||||
@click.option('--hw-compat', '-m', type=int, metavar='BITMASK', help="Set HW compat field (mk number)")
|
||||
@click.option('--hw-compat', '-m', type=str, metavar='mk', help="Set HW compat field (hw_label value)")
|
||||
@click.option('--backdate', type=int, metavar='DAYS',
|
||||
help='Make downgrade attack test version', default=0)
|
||||
@click.option('--build_dir', '-b', default='l-port/build-COLDCARD')
|
||||
@ -277,9 +279,12 @@ def doit(keydir, outfn=None, build_dir=None, high_water=False,
|
||||
vectors = open(build_dir + '/firmware0.bin', 'rb').read()
|
||||
body = open(build_dir + '/firmware1.bin', 'rb').read()
|
||||
|
||||
if hw_compat == 4:
|
||||
hw_compat = MK_4_OK
|
||||
elif hw_compat in {3, None}:
|
||||
if hw_compat in { 'mk4', '4', 'mk5', '5', 'mk' }:
|
||||
# Mk4 and 5 can run the same firmware, once Mk5 support was added
|
||||
hw_compat = MK_4_OK | MK_5_OK
|
||||
elif hw_compat == 'q1':
|
||||
hw_compat = MK_Q1_OK
|
||||
elif hw_compat in { 'mk3', '3'}:
|
||||
hw_compat = MK_2_OK | MK_3_OK
|
||||
else:
|
||||
assert not "known"
|
||||
@ -316,14 +321,15 @@ def doit(keydir, outfn=None, build_dir=None, high_water=False,
|
||||
pubkey_num=pubkey_num,
|
||||
timestamp=timestamp(backdate) )
|
||||
|
||||
assert FW_MIN_LENGTH <= hdr.firmware_length <= FW_MAX_LENGTH, hdr.firmware_length
|
||||
|
||||
if hw_compat & MK_4_OK:
|
||||
# new value for Mk4: limited only by final binary size, not SPI flash
|
||||
USB_MAX_LEN = 1472 * 1024
|
||||
else:
|
||||
if hw_compat & MK_3_OK:
|
||||
# actual file length limited by size of SPI flash area reserved to txn data/uploads
|
||||
assert FW_MIN_LENGTH <= hdr.firmware_length <= FW_MAX_LENGTH, hdr.firmware_length
|
||||
USB_MAX_LEN = (786432-128)
|
||||
else:
|
||||
# new value for Mk4 and later: limited only by final binary size, not SPI flash
|
||||
assert FW_MIN_LENGTH <= hdr.firmware_length <= FW_MAX_LENGTH_MK4, hdr.firmware_length
|
||||
USB_MAX_LEN = 1472 * 1024
|
||||
|
||||
assert hdr.firmware_length <= USB_MAX_LEN, \
|
||||
"too big for our USB upgrades: %d = %d bytes too big" % (
|
||||
|
||||
@ -3,14 +3,32 @@
|
||||
These docs are meant for you hackers out there... but also for anyone who
|
||||
wants to understand why it's safe to put your moneys into Coldcard.
|
||||
|
||||
- [`security-model.md`](security-model.md) The COLDCARD Mk4/Mk5/Q security model.
|
||||
- [`pin-entry.md`](pin-entry.md) Huge and detailed discussion of PIN codes and the security element that holds the secrets.
|
||||
- [`secure-elements.md`](secure-elements.md) How the dual secure elements work together.
|
||||
- [`dev-access.md`](dev-access.md) How developers can modify Coldcard to extend it.
|
||||
- [`memory-map.md`](memory-map.md) Memory map highlights
|
||||
- [`notes-on-repro.md`](notes-on-repro.md) Detailed breakdown of the reproducible build process.
|
||||
- [`upgrade-recovery.md`](upgrade-recovery.md) Firmware upgrade and recovery process.
|
||||
- [`backup-files.md`](backup-files.md) Some details of our encrypted backup files.
|
||||
- [`temporary-seeds.md`](temporary-seeds.md) Temporary (ephemeral) seeds and the Seed Vault.
|
||||
- [`seed-xor.md`](seed-xor.md) More about _Seed XOR_ feature, including fully worked Seed XOR example, and useful XOR lookup chart.
|
||||
- [`key-teleport.md`](key-teleport.md) Key Teleport: encrypted transfer of seeds and secrets between Q devices.
|
||||
- [`spending-policy.md`](spending-policy.md) Spending policy: autonomous signing with configurable limits.
|
||||
- [`microsd-2fa.md`](microsd-2fa.md) Using a MicroSD card as a second factor for login.
|
||||
- [`web2fa.md`](web2fa.md) Web 2FA authentication.
|
||||
- [`bip85-passwords.md`](bip85-passwords.md) Deriving deterministic passwords via BIP-85.
|
||||
- [`msg-signing.md`](msg-signing.md) COLDCARD message signing.
|
||||
- [`proof-of-reserves-bip-322.md`](proof-of-reserves-bip-322.md) BIP-322 generic signed message format and proof of reserves.
|
||||
- [`generic-wallet-export.md`](generic-wallet-export.md) Generic JSON wallet export file format.
|
||||
- [`bip-21-extensions.md`](bip-21-extensions.md) Coldcard's BIP-21 URI extensions, including multisig ownership address check.
|
||||
- [`nfc-coldcard.md`](nfc-coldcard.md) NFC support on Coldcard Mk4 and Q.
|
||||
- [`nfc-pushtx.md`](nfc-pushtx.md) NFC Push Transaction: broadcast a signed transaction via your phone.
|
||||
- [`usb-batteries.md`](usb-batteries.md) Using USB battery packs with Coldcard.
|
||||
- [`electrum-usage.md`](electrum-usage.md) Importing seed words into Electrum for funds usage (and other tips).
|
||||
- [`bitcoin-core-usage.md`](bitcoin-core-usage.md) How to use with Bitcoin Core.
|
||||
- [`bitcoin-core2of2desc.md`](bitcoin-core2of2desc.md) Airgapped 2-of-2 multisig with Bitcoin Core using descriptors.
|
||||
- [`limitations.md`](limitations.md) Documented limitations, policy choices, and TODO items.
|
||||
- [`paperwallet.pdf`](paperwallet.pdf) Example paper wallet template file.
|
||||
- [`seed-xor.md`](seed-xor.md) More about _Seed XOR_ feature, including fully worked Seed XOR example, and useful XOR lookup chart.
|
||||
- [`menu-tree.txt`](menu-tree.txt) Dump of the menu system. Incomplete, may be out of date.
|
||||
|
||||
|
||||
15
docs/bip-21-extensions.md
Normal file
@ -0,0 +1,15 @@
|
||||
## Multisig Ownership address check: "wallet"
|
||||
|
||||
If the name of the multisig wallet related to an address is provided, address search
|
||||
can be greatly accelerated. Just provide `wallet=name` parameter in a standard
|
||||
[BIP-21](https://github.com/bitcoin/bips/blob/master/bip-0021.mediawiki) URL
|
||||
shown in QR code or NFC record. If omitted, search will continue across
|
||||
all multisig wallets known by COLDCARD.
|
||||
|
||||
### Examples
|
||||
|
||||
```
|
||||
tb1q4d67p7stxml3kdudrgkg5mgaxsrgzcqzjrrj4gg62nxtvnsnvqjsxjkej0?wallet=goldmine
|
||||
|
||||
bitcoin:mtHSVByP9EYZmB26jASDdPVm19gvpecb5R?label=coldcard_purchase&amount=50&wallet=Haystack%20Four
|
||||
```
|
||||
@ -5,13 +5,13 @@ according to [BIP-85 PWD BASE64](https://github.com/bitcoin/bips/blob/master/bip
|
||||
Generated passwords can be sent as keystrokes via USB to the host computer,
|
||||
effectively using Coldcard as specialized password manager.
|
||||
|
||||
In addition to deriving up to 10,000 distinct secure passwords, the Coldcard Mk4
|
||||
In addition to deriving up to 10,000 distinct secure passwords, the Coldcard
|
||||
can also type them into a computer by emulating a USB keyboard, and simulating the
|
||||
keystrokes needed to type the password.
|
||||
|
||||
#### Requirements
|
||||
|
||||
* Coldcard Mk4 with version 5.0.5 or newer
|
||||
* Coldcard Mk4 or Mk5 (firmware 5.0.5 or newer), or any Q
|
||||
* USB-C with data link (won't work with power only cable from Coinkite)
|
||||
|
||||
## Type Passwords over USB
|
||||
@ -32,11 +32,13 @@ to exit. Exiting from "Type Passwords" will cause Coldcard to turn off keyboard
|
||||
1. Go to Advanced/Tools -> Derive Seed B85 -> Passwords
|
||||
2. Choose "Password/Index number" (BIP-85 index) and press OK to generate password.
|
||||
3. Screen shows generated password, path, and entropy from which password was derived
|
||||
4. A few different options are available at this point:
|
||||
1. press 1 to save password backup file on MicroSD card (cleartext!)
|
||||
2. press 2 to send keystrokes (this will first of all enable keyboard emulation, then send keystrokes + enter, and finally disables keyboard emulation)
|
||||
3. press 3 to view password as QR code
|
||||
4. press 4 to send over NFC (only appears when NFC is enabled)
|
||||
4. A few different options are available at this point (on Mk; on Q the NFC and
|
||||
QR buttons are used instead of (3)/(4)):
|
||||
1. press (1) to save password backup file on MicroSD card (cleartext!)
|
||||
2. press (2) to save to Virtual Disk (only when available)
|
||||
3. press (3) to send over NFC (only appears when NFC is enabled)
|
||||
4. press (4) to view password as QR code
|
||||
5. press (6) to send keystrokes over USB (this enables keyboard emulation, sends keystrokes + enter, then disables keyboard emulation)
|
||||
|
||||
## Keyboard language settings
|
||||
|
||||
|
||||
@ -1,44 +0,0 @@
|
||||
# Ephemeral Seeds
|
||||
|
||||
Ephemeral seed is temporary secret mostly stored only in Coldcard volatile
|
||||
memory (RAM). Ephemeral seed can also be stored in `Seed Vault` (5.2.0+).
|
||||
It only survives single boot, meaning after Coldcard
|
||||
restart it is gone. Ephemeral seeds *completely* defeats the design
|
||||
of Coldcard's security model, based on secure elements.
|
||||
|
||||
Make sure you know what you're doing!
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
- go to `Advanced/Tools -> Ephemeral Seed`
|
||||
- if ephemeral seed is already in use, top menu item `[<xfp>]` is visible
|
||||
with fingerprint of ephemeral master secret
|
||||
- an ephemeral seed can be Imported or Generated at random
|
||||
- go to `Advanced/Tools -> Ephemeral Seed`
|
||||
- `Generate Words`:
|
||||
- same options as generating new seed words, dice rolls included
|
||||
- Import words via NFC with `Import via NFC` option
|
||||
- `Import Words`:
|
||||
- same options as importing seed words
|
||||
- `Import XPRV`:
|
||||
- import extended private key
|
||||
- `Tapsigner Backup`
|
||||
- import TAPSIGNER encrypted backup
|
||||
- an ephemeral seed can also be a BIP-85 derived value
|
||||
|
||||
## Trick PIN Notes
|
||||
|
||||
If you intend to use the ephemeral seed feature frequently, you can
|
||||
define a "Trick PIN" which takes you to a "look blank" trick wallet
|
||||
(ie. no seed set appears to be set). Then you may then safely
|
||||
unlock your Coldcard, without revealing the true PIN, and perform
|
||||
all your ephemeral seed work in that state.
|
||||
|
||||
## Purpose
|
||||
|
||||
This feature is intended for those one-off signings, like recovering
|
||||
a lost seed from some other system or importing some seed as an
|
||||
balance check. We do not recommend handing unencrypted seed material
|
||||
on a regular basis!
|
||||
|
||||
@ -5,9 +5,12 @@ wallet systems, but we also have a file format for general purpose
|
||||
exports, which we hope future wallet makers will leverage.
|
||||
|
||||
It contains master XPUB, XFP for that, and derived values for the top hardened
|
||||
position of BIP44, BIP84 and BIP49.
|
||||
position of the single-signature schemes BIP44, BIP49 and BIP84, plus the
|
||||
multisig schemes BIP48 (`bip48_1` = `.../1h` P2SH-P2WSH and `bip48_2` = `.../2h` P2WSH).
|
||||
When the account number is zero, a BIP45 (`m/45h`) multisig section is also included
|
||||
(it is omitted for non-zero accounts, as in the example below).
|
||||
|
||||
The feature can be found here: _Advanced > MicroSD > Export Wallet > Generic JSON_
|
||||
The feature can be found here: _Advanced/Tools > Export Wallet > Generic JSON_
|
||||
|
||||
Please contact us (or better yet, make a pull request), if you need something
|
||||
more in this file.
|
||||
@ -18,32 +21,51 @@ Here is an example, produced by the Simulator for account number 123.
|
||||
|
||||
```javascript
|
||||
{
|
||||
"chain": "XTN",
|
||||
"chain": "BTC",
|
||||
"xfp": "0F056943",
|
||||
"xpub": "tpubD6NzVbkrYhZ4XzL5Dhayo67Gorv1YMS7j8pRUvVMd5odC2LBPLAygka9p7748JtSq82FNGPppFEz5xxZUdasBRCqJqXvUHq6xpnsMcYJzeh",
|
||||
"account": 123,
|
||||
"xpub": "xpub661MyMwAqRbcGC9DmWbtbAmuUjpMYxw4BWE88NSDHB3jSjfUK7KtYJuKa52GbowD3DVLkgsxH9QwPnTx5mjdHykYFEncnmAsNsCTbWzBhA7",
|
||||
"bip44": {
|
||||
"deriv": "m/44'/1'/123'",
|
||||
"first": "n44vs1Rv7T8SANrg2PFGQhzVkhr5Q6jMMD",
|
||||
"name": "p2pkh",
|
||||
"xfp": "B7908B26",
|
||||
"xpub": "tpubDCiHGUNYdRRGoSH22j8YnruUKgguCK1CC2NFQUf9PApeZh8ewAJJWGMUrhggDNK73iCTanWXv1RN5FYemUH8UrVUBjqDb8WF2VoKmDh9UTo"
|
||||
"xfp": "5F898064",
|
||||
"deriv": "m/44h/0h/123h",
|
||||
"xpub": "xpub6DStQXfAgHuLbMpCf86ruVkF4yT9pSLyWsFiqQTWY9osuinq8Dyee4W5jCjMfyku5LNkRB9oFinrY5ufn9XXEn8Vvzc2jnifKMaQCNV7RBZ",
|
||||
"desc": "pkh([0f056943/44h/0h/123h]xpub6DStQXfAgHuLbMpCf86ruVkF4yT9pSLyWsFiqQTWY9osuinq8Dyee4W5jCjMfyku5LNkRB9oFinrY5ufn9XXEn8Vvzc2jnifKMaQCNV7RBZ/<0;1>/*)#4tl8jryn",
|
||||
"first": "1GTNtzG5xX2UhdD5e3Nu7i1WPxFdjxQMJt"
|
||||
},
|
||||
"bip49": {
|
||||
"_pub": "upub5DMRSsh6mNak9KbcVjJ7xAgHJvbE3Nx22CBTier5C35kv8j7g2q58ywxskBe6JCcAE2VH86CE2aL4MifJyKbRw8Gj9ay7SWvUBkp2DJ7y52",
|
||||
"deriv": "m/49'/1'/123'",
|
||||
"first": "2N87V39riUUCd4vmXfDjMWAu9gUCiBji5jB",
|
||||
"name": "p2wpkh-p2sh",
|
||||
"xfp": "CEE1D809",
|
||||
"xpub": "tpubDCDqt7XXvhAdy1MpSze5nMJA9x8DrdRaKALRRPasfxyHpiqWWEAr9cbDBQ9BcX7cB3up98Pk97U2QQ3xrvQsi5dNPmRYYhdcsKY9wwEY87T"
|
||||
"name": "p2sh-p2wpkh",
|
||||
"xfp": "A748B1FC",
|
||||
"deriv": "m/49h/0h/123h",
|
||||
"xpub": "xpub6DDm8WzH5a9qjKkttzqSB3uGofNohU9D3n3UG8WMxkUZzJEMPTYiQRf1dvTFCQR82MjGW4LUMVuTtnW4hF17RpzCqVwhf6Z2fnJPWtjG164",
|
||||
"desc": "sh(wpkh([0f056943/49h/0h/123h]xpub6DDm8WzH5a9qjKkttzqSB3uGofNohU9D3n3UG8WMxkUZzJEMPTYiQRf1dvTFCQR82MjGW4LUMVuTtnW4hF17RpzCqVwhf6Z2fnJPWtjG164/<0;1>/*))#5j7t2n2u",
|
||||
"_pub": "ypub6Y42SBfCEFhKacx1jMd4P8zmydXFe68hxtZh3XQFLkrT3Q3ae7iH2VK9f8QqCK53Rzr5FXw2pAG1n57dQwR8E4fohqe8F1NWwWN2uVRfBry",
|
||||
"first": "3CeBRbJKCpg7BpJME2vM8ZxhCjBnhG4toy"
|
||||
},
|
||||
"bip84": {
|
||||
"_pub": "vpub5Y5a91QvDT45EnXQaKeuvJupVvX8f9BiywDcadSTtaeJ1VgJPPXMitnYsqd9k7GnEqh44FKJ5McJfu6KrihFXhAmvSWgm7BAVVK8Gupu4fL",
|
||||
"deriv": "m/84'/1'/123'",
|
||||
"first": "tb1qc58ys2dphtphg6yuugdf3d0kufmk0tye044g3l",
|
||||
"name": "p2wpkh",
|
||||
"xfp": "78CF94E5",
|
||||
"xpub": "tpubDC7jGaaSE66VDB6VhEDFYQSCAyugXmfnMnrMVyHNzW9wryyTxvha7TmfAHd7GRXrr2TaAn2HXn9T8ep4gyNX1bzGiieqcTUNcu2poyntrET"
|
||||
"xfp": "2C5207AA",
|
||||
"deriv": "m/84h/0h/123h",
|
||||
"xpub": "xpub6CaWStGvcXqSW9BzU2vpCoP7aWjz9VfR5DS2nuYWVvKV2nug2dESg3HdFsaWHeoZaxuAhNcPB3TH2gq8MugS3JX1yGuhB4QbC2BneaYqB16",
|
||||
"desc": "wpkh([0f056943/84h/0h/123h]xpub6CaWStGvcXqSW9BzU2vpCoP7aWjz9VfR5DS2nuYWVvKV2nug2dESg3HdFsaWHeoZaxuAhNcPB3TH2gq8MugS3JX1yGuhB4QbC2BneaYqB16/<0;1>/*)#yk84tprf",
|
||||
"_pub": "zpub6rF34DckutvQCjaE8kW4cya7vT2t2jeQuSUUMhLHFw5F8zY8XwZZvAbuJHVgHU7QQF8nCKoW6NANoG4FoJWTdmtDhxJYLt3ZjUK5RqUSMdF",
|
||||
"first": "bc1qhj6avwmp5lhpgqwm6dgxrf3v5lf67rjm99a8an"
|
||||
},
|
||||
"bip48_1": {
|
||||
"name": "p2sh-p2wsh",
|
||||
"xfp": "845A3542",
|
||||
"deriv": "m/48h/0h/123h/1h",
|
||||
"xpub": "xpub6EkcQSTygvxVnBP2X2fM6HY5D7wv46tWbBc54ADaypuCr47vQh1GPdPAZFdx81ou5Rp4vBnzeJT5MDWDZstzijxkHfrofXRycpt1ASfg1La",
|
||||
"desc": "sh(wsh(sortedmulti(M,[0f056943/48h/0h/123h/1h]xpub6EkcQSTygvxVnBP2X2fM6HY5D7wv46tWbBc54ADaypuCr47vQh1GPdPAZFdx81ou5Rp4vBnzeJT5MDWDZstzijxkHfrofXRycpt1ASfg1La/0/*,...)))",
|
||||
"_pub": "Ypub6kUxqLsLQa4M43jXJ3ux8SyP6t8dD5ZbpZmxkpP1jc7VXLW4RkZ76ouEPAZ1gMgiiXzrYFPfzBC8MfjYaoTxfTm1zUfdeqiTnHDX8raCfeg"
|
||||
},
|
||||
"bip48_2": {
|
||||
"name": "p2wsh",
|
||||
"xfp": "2A01C6B0",
|
||||
"deriv": "m/48h/0h/123h/2h",
|
||||
"xpub": "xpub6EkcQSTygvxVneXmk3ywiS2PFhBdiPxeMxYf6RFxHCHH36NxdcN7DjUpudCppAAxs58CG6DQLjtqZNmyC3MpgVob6wpdeATjpZZ1woX92EF",
|
||||
"desc": "wsh(sortedmulti(M,[0f056943/48h/0h/123h/2h]xpub6EkcQSTygvxVneXmk3ywiS2PFhBdiPxeMxYf6RFxHCHH36NxdcN7DjUpudCppAAxs58CG6DQLjtqZNmyC3MpgVob6wpdeATjpZZ1woX92EF/0/*,...))",
|
||||
"_pub": "Zpub75KE91YFZFbpup5PMS2AxgZCKRWnozdEWTEmaUKGQysSmUaKuL5WYyf2kk5UNQhhupRnddQe9GzST7crvfLoRTHTg6KtDPZiFjxBJobzcUz"
|
||||
}
|
||||
}
|
||||
```
|
||||
@ -51,16 +73,23 @@ Here is an example, produced by the Simulator for account number 123.
|
||||
## Notes
|
||||
|
||||
1. The `first` address is formed by added `/0/0` onto the given derivation, and is assumed
|
||||
to be the first (non-change) receive address for the wallet.
|
||||
to be the first (non-change) receive address for the wallet. It is only present on the
|
||||
single-signature sections (`bip44`, `bip49`, `bip84`); multisig sections omit it.
|
||||
|
||||
1a. Each section includes a `desc` field: a ready-to-import Bitcoin output descriptor
|
||||
(with `#checksum`). Single-sig descriptors use the `<0;1>/*` multipath form. Multisig
|
||||
sections (`bip48_1`, `bip48_2`, and `bip45` when present) emit a `sortedmulti(...)`
|
||||
template with `M` and a trailing `...` as placeholders, to be completed with your
|
||||
threshold and the other co-signers' keys.
|
||||
|
||||
2. The user may specify any value (up to 9999) for the account number, and it's meant to
|
||||
segregate funds into sub-wallets. Don't assume it's zero.
|
||||
|
||||
3. When making your PSBT files to spend these amounts, remember that the XFP of the master
|
||||
(`0F056943` in this example) is is the root of the subkey paths found in the file, and
|
||||
(`0F056943` in this example) is the root of the subkey paths found in the file, and
|
||||
you must include the full derivation path from master. So based on this example,
|
||||
to spend a UTXO on `tb1qc58ys2dphtphg6yuugdf3d0kufmk0tye044g3l`, the input section
|
||||
of your PSBT would need to specify `(m=0F056943)/84'/1'/123'/0/0`.
|
||||
to spend a UTXO on `bc1qhj6avwmp5lhpgqwm6dgxrf3v5lf67rjm99a8an`, the input section
|
||||
of your PSBT would need to specify `(m=0F056943)/84'/0'/123'/0/0`.
|
||||
|
||||
4. The `_pub` value is the [SLIP-132](https://github.com/satoshilabs/slips/blob/master/slip-0132.md) style "ypub/zpub/etc" which some systems might want. It implies
|
||||
a specific address format.
|
||||
|
||||
224
docs/key-teleport.md
Normal file
@ -0,0 +1,224 @@
|
||||
|
||||
# Key Teleport
|
||||
|
||||
Purpose: Send a small quantity of very secret data between two COLDCARD Q systems, with
|
||||
no risk of anything in the middle learning the secret.
|
||||
|
||||
Method: ECDH and AES-256-CTR plus an extra wrapping layer, transmitted over a mixture of
|
||||
NFC, passive websites, and QR/BBQr codes.
|
||||
|
||||
# Protocol Overview
|
||||
|
||||
## Steps
|
||||
|
||||
- Receiver picks an EC keypair, stores it in settings, and publishes the pubkey via a QR/NFC
|
||||
- The pubkey is encrypted by a short 8-digit numeric code, which should be
|
||||
sent by a different channel.
|
||||
- Sender gets QR and numeric code, picks own keypair, and does ECDH to arrive at a
|
||||
shared session key
|
||||
- Sender picks a human-readable secret which is independent of anything else (P key)
|
||||
- The secret data (perhaps a seed phrase, XPRV, secure note, full backup, etc) is
|
||||
AES-256-CTR encrypted with P key, then encrypted + MAC added with session key
|
||||
- Data packet is sent to receiver (via BBQr), who can reconstruct the session key via ECDH
|
||||
- Prompt user for the P key to finish decoding
|
||||
- Decoded secret value is saved to Seed Vault or secure notes as appropriate
|
||||
- Receiver destroys EC keypair used in transfer
|
||||
|
||||
### When used for PSBT Multisig
|
||||
|
||||
- No action required on receiver
|
||||
- Sender uses the pubkey derived from pre-shared XPUB involved in the multisig wallet.
|
||||
- Same steps, but drops immediately into signing process when decoded correctly
|
||||
|
||||
## Notes and Limitations
|
||||
|
||||
- max 4k (after encoding) of data is possible due to HTTP limitations
|
||||
- all transfers are "data typed" and decode only on COLDCARD
|
||||
- Q model is required due to the use of QR codes to ultimately get data into the COLDCARD
|
||||
|
||||
|
||||
# Details
|
||||
|
||||
## Data Type Codes
|
||||
|
||||
The first byte encodes what the package contents (under all the encryption).
|
||||
|
||||
- `s` - 12/18/24 words/raw master/xprv - 17-72 bytes follow, encoded in an internal format
|
||||
- `x` - XPRV mode, full details - 4 bytes (XPRV) + base58 *decoded* binary-XPRV follows
|
||||
- `n` - one or many notes export (JSON array)
|
||||
- `v` - seed vault export (JSON: one secret key but includes name, source of key)
|
||||
- `p` - binary PSBT to be signed, perhaps multisig but not required.
|
||||
- `b` - complete system backup file (text lines, internal format)
|
||||
|
||||
## QR details
|
||||
|
||||
BBQr is always used for the QR's involved in this process, even if
|
||||
they are short enough for a normal QR code. Because the BBQr is
|
||||
being generated by the COLDCARD embedded firmware, it will not be
|
||||
compressed and will always be Base32 encoded.
|
||||
|
||||
New type codes for BBQr are defined for the purposes of this application:
|
||||
|
||||
- `R` contains `(pubkey)` ... begins the process from receiver; compressed pubkey is 33 bytes
|
||||
- `S` contains `(pubkey)(data)` ... data from sender; first 33 bytes are sender's pubkey
|
||||
- `E` for Multisig PSBT: `(randint)(data)` ... randint (4 byte nonce) indicates which
|
||||
derived subkey from pre-shared xpub associated with receiver
|
||||
|
||||
All the data is encrypted with the exception randint. Keep in mind
|
||||
this is a nonce value picked uniquely for each transfer. The
|
||||
receiver's pubkey is only weakly encrypted by the 8-digit numeric
|
||||
password, but is also a nonce effectively.
|
||||
|
||||
### PSBT Key Selection
|
||||
|
||||
When sending PSBT data, a nonce is picked at random by the sender
|
||||
in range: `0..(2^28)`
|
||||
|
||||
This nonce is called `randint`. The receiver's pubkey will be
|
||||
|
||||
.../20250317/(randint)
|
||||
|
||||
where `...` is the derivation used in the multisig wallet for the co-signer who will
|
||||
receive the package. The sender's keypair has the same sub key path assuming all
|
||||
co-signers have same derivation path from root (not required).
|
||||
|
||||
Because both the sender and receiver already have each other's XPUB they can derive
|
||||
the appropriate pubkeys (and privkey for their side) without communicating
|
||||
more than `randint`. The sending COLDCARD will pick a new random value each time.
|
||||
|
||||
When receiving a multisig PSBT encrypted this way, the receiver does not need
|
||||
to do any setup (nor numeric password) and can receive a QR code at any time.
|
||||
This works because the shared multisig wallet is already setup. Receiver will
|
||||
take the nonce value (randint) and seach all pre-defined multisig wallets for
|
||||
any pubkey that can decrypt the package successfully (based on checksum inside
|
||||
first layer of ECDH encryption).
|
||||
|
||||
The next layer of encryption (paranoid password) is unchanged.
|
||||
|
||||
## Encryption Details
|
||||
|
||||
AES-256-CTR is used exclusively. Session key is picked via ECDH with final
|
||||
key value being the SHA256 over 64 bytes of coordinate X (concat) Y.
|
||||
|
||||
While ECDH is enough to assure privacy from men in the middle, we
|
||||
add an additional layer of encryption. We call this the "paranoid key" internally
|
||||
and in the UX it is called "Teleport Password".
|
||||
|
||||
The user sees a random 8-character password, generated as a random 40-bit value, but
|
||||
shown in Base32 (8 chars) for the human to enter. We apply PBKDF2-SHA512 with
|
||||
an iteration count of 5000 to stretch that to 512 bits, of which we use half.
|
||||
The session key is used as the key for the KDF, and the entered value as salt.
|
||||
|
||||
- ECDH arrives at session key
|
||||
- decrypt (AES-256-CTR) the binary body of message
|
||||
- verify checksum:
|
||||
- final 2 bytes should be `== SHA256(decrypted body[0:-2])[-2:]`
|
||||
- if not, corruption, truncation, or wrong keys
|
||||
- if that decryption is correct, then prompt user for the paranoid key (8 chars)
|
||||
- stretch that value using session key and 5000 iterations of PBKDF2-SHA512
|
||||
- use upper 256 bits and run AES-256-CTR again
|
||||
- same checksum of 2 bytes of SHA256 are found inside after decryption
|
||||
|
||||
Encryption adds 4 bytes of overhead because of these MAC values,
|
||||
but should catch truncation and bitrot. There are no other
|
||||
protections against truncation as length data is not transmitted.
|
||||
|
||||
# Receiver Password
|
||||
|
||||
When the teleport process is started, the receiver shares his pubkey
|
||||
as QR. However, we also show an 8-digit numeric password. The
|
||||
purpose of this is force the receiver to share this separately from
|
||||
the pubkey QR on another channel. The code is randomly picked, but
|
||||
only represents about 26 bits of entropy and is stretched with
|
||||
a single round of SHA256 before being used as a AES-256-CTR key
|
||||
to decrypt the pubkey. No checksum verifies correct
|
||||
decryption, so any code is accepted, and will with near-50% odds,
|
||||
decrypt to a valid pubkey.
|
||||
|
||||
When the sender is given the receiver's pubkey via QR code, it
|
||||
prompts for the numeric code and uses it to decrypt the pubkey.
|
||||
Thus a MiTM who injects their pubkey will be detected and blocked.
|
||||
|
||||
The "paranoid key" serves the same role in the other direction but
|
||||
it is Base32 character set, so it will not look similar or be
|
||||
confusing as to its purpose.
|
||||
|
||||
# Web Component
|
||||
|
||||
In order to "teleport" the contents of a QR code over NFC, we will
|
||||
publish a static website directly from an open Github repository.
|
||||
The single-page website contains javascript code which looks at the
|
||||
"hash" part of the incoming URL (`window.location.hash`) and if it
|
||||
meets the requirements, renders a large QR. The QR data must look like
|
||||
a correctly-encoded BBQr with one of the 3 type-codes above (`R` `S` or `E`).
|
||||
Otherwise the website could render any QR, which we don't want to
|
||||
support.
|
||||
|
||||
The page will offer "copy to clipboard" features for the data inside
|
||||
the QR as a URL (ie. same URL as shown) and as an image and of course,
|
||||
the COLDCARD Q can scan from the web browser screen itself.
|
||||
|
||||
When the BBQr data is larger than comfortable for a single QR, the
|
||||
website can split into a multi-frame BBQr. The website can
|
||||
do this without understanding the contents of the BBQr data (all
|
||||
of which is encrypted). Download options will be provided for
|
||||
single-frame QR, animated PNG, and "stacked BBQr" (a single tall
|
||||
PNG with each QR frame stacked).
|
||||
|
||||
On the COLDCARD side, when NFC is tapped, it will offer a long URL
|
||||
to this site with the data to be transferred "after the hash". This
|
||||
is optional since the QR can be shown on the Q itself, and would
|
||||
pass the same data.
|
||||
|
||||
Since the website is running on Github, Coinkite does not have
|
||||
access to IP addresses or other access log details. Because the data for
|
||||
teleport is "after the hash" it is never sent to Github's servers
|
||||
but remains in the browser only. All JS resources referenced by the
|
||||
webpage will have content hashes applied to prevent interference,
|
||||
and the site will be served over SSL.
|
||||
|
||||
Visit [keyteleport.com](https://keyteleport.com/), or an
|
||||
[example small QR](https://keyteleport.com/#B$2R0100VHT2AGUUH7KUZUUSTOWOIWHJX3XM7GA2N4BHQOXDFHXLVHVA7K6ZO)
|
||||
and [view source code](https://github.com/coinkite/keyteleport.com).
|
||||
|
||||
# UX Details
|
||||
|
||||
- When the receive process is started by the user, a pubkey is picked
|
||||
and stored, so that they can come back later (after a power cycle)
|
||||
and make use of the data encoded by the sender. However once a package
|
||||
is decoded successfully, that key is deleted.
|
||||
|
||||
- Sender must start by scanning the QR from a receiver. Then can pick what
|
||||
to send, from secure notes to seeds and so on.
|
||||
|
||||
- For PSBT multisig, user must pick a single co-signer (who hasn't already
|
||||
signed) and the QR is prepared for that receiver. Because we
|
||||
cannot do arbitary combining, it's best if the next signer continues
|
||||
to teleport the updated PSBT to further signers. In other words,
|
||||
a daisy-chain pattern is prefered to a star pattern. The signer
|
||||
who completes the Mth (of N) signature will be able to finalize
|
||||
the transaction, and ideally with PushTx feature, broadcast it.
|
||||
|
||||
# Security Comments
|
||||
|
||||
## Such short passwords?
|
||||
|
||||
We are using 8-character passwords because we want them to be
|
||||
practical to share over non-digital channels such as a voice phone
|
||||
call, or hand-written note.
|
||||
|
||||
It is very important to remind users that the passwords should be sent
|
||||
by a different channel from the QR itself. Best is to call up your
|
||||
other party and say the letters to them directly.
|
||||
|
||||
## Is it safe to save image of QR to cloud?
|
||||
|
||||
Yes, this seems safe. Of course, if you can control it, perhaps not
|
||||
a risk to accept... but the QR is encrypted via ECDH using a key
|
||||
that is forgotten after the transfer, so forward privacy is protected.
|
||||
Also your cloud service (or photo roll, chat app log, etc) will not
|
||||
have the 8-character password which is also required unpack the secrets.
|
||||
|
||||
The QR codes themselves are fully random and do not reveal the
|
||||
identity of your COLDCARD, your on chain funds or anything linked
|
||||
to you.
|
||||
@ -1,12 +1,12 @@
|
||||
# BIP39 Import
|
||||
# BIP-39 Import
|
||||
|
||||
- there must be 12, 18 or 24 words in your mnemonic
|
||||
- we have only the English word list
|
||||
- we support BIP39 passwords during import
|
||||
- we support BIP-39 passwords during import
|
||||
|
||||
# XPRV Import
|
||||
|
||||
- we can import a BIP32 HD-wallet root private key in XPRV format
|
||||
- we can import a BIP-32 HD-wallet root private key in XPRV format
|
||||
- it's assumed to be top-level, and we don't store the parent fingerprint or depth value
|
||||
- SLIP-132 format HD-wallet keys are also supported (xprv/yprv/zprv), but we strip
|
||||
the implied address format
|
||||
@ -14,11 +14,12 @@
|
||||
# PIN Codes
|
||||
|
||||
- 2-2 through 6-6 in size, numeric digits only
|
||||
- pin code 999999-999999 is reserved (means 'clear pin')
|
||||
- pin code 999999-999999 was reserved (meaning 'clear pin'), but now available again
|
||||
|
||||
# Backup Files
|
||||
|
||||
- we don't know what day it is, so meta data on files will not have correct date/time
|
||||
- release date of the firmware version that made the file is used instead of true date
|
||||
- encrypted files produced cannot be changed, and we don't support other tools making them
|
||||
|
||||
# Micro SD
|
||||
@ -32,7 +33,7 @@
|
||||
- with Electrum, we support classic payment addresses (p2pkh), Bech32 Segwit and P2SH/Segwit
|
||||
- however, each wallet must be of a single address type; cannot be mixed (their limitation)
|
||||
- the same Coldcard could be used in each of the three modes (we don't care about address format)
|
||||
- with Bitcoin Core (version 0.17?), we can do PSBT transactions, which support all address types
|
||||
- with Bitcoin Core (version 0.17+), we can do PSBT transactions, which support all address types
|
||||
- we don't support signing coinbase transactions, so don't mine directly into a Coldcard wallet
|
||||
|
||||
# Max Transaction Size
|
||||
@ -41,7 +42,7 @@
|
||||
- we support transactions up to 384k-bytes in size when serialized into PSBT format
|
||||
- we can handle transactions with up to 20 inputs to be signed at one time.
|
||||
- a maximum of 250 outputs per transaction is supported (will attempt more if memory allows)
|
||||
- mk4:
|
||||
- mk4/Q:
|
||||
- we support PSBT files up to 2M bytes in size.
|
||||
- any number of inputs and outputs are supported, limited only by final transaction size (100k)
|
||||
- tested with: 250 inputs, 2000 outputs
|
||||
@ -55,23 +56,36 @@
|
||||
|
||||
- only one signature will be added per input. However, if needed the partly-signed
|
||||
PSBT can be given again, and the "next" leg will be signed.
|
||||
- we do not support PSBT combining or finalizing of transactions involving
|
||||
P2SH signatures (so the combine step must be off-device)
|
||||
- finalizing of multisig transactions involving P2SH signatures:
|
||||
* SD/Vdisk signing exports both signed PSBT and finalized txn ready for broadcast (if txn is complete)
|
||||
* QR/NFC outputs finalized txn ready for broadcast if txn is complete otherwise signed PSBT only
|
||||
* USB signing requires `--finalize` parameter (as for standard single signature wallets)
|
||||
|
||||
- we can sign for P2SH and P2WSH addresses that represent multisig (M of N) but
|
||||
we cannot sign for non-standard scripts because we don't know how to present
|
||||
that to the user for approval.
|
||||
- during USB "show address" for multisig, we limit subkey paths to
|
||||
16 levels deep (including master fingerprint)
|
||||
- max of 15 co-signers due to 520 byte script limitation in consensus layer with classic P2SH
|
||||
- max of 15 co-signers due to 1650 byte `scriptSig` limitation in policy with classic P2SH (same limit applies to segwit even though consensus allows up to 20 co-signers).
|
||||
note: the consensus layer sets an upper bound of 520 bytes for the length of each stack element
|
||||
- (mk3) we have space for up to 8 M-of-3 wallets, or a single M-of-15 wallet. YMMV
|
||||
- only a single multisig wallet can be involved in a PSBT; can't sign inputs from two different
|
||||
multisig wallets at the same time.
|
||||
- we always store xpubs in BIP32 format, although we can read SLIP132 format (Ypub/Zpub/etc)
|
||||
- we always store xpubs in BIP-32 format, although we can read SLIP132 format (Ypub/Zpub/etc)
|
||||
- change outputs (indicated with paths, scripts in output section) must correspond to
|
||||
the active multisig wallet, and cannot be used to describe an unrelated (multisig) wallet.
|
||||
- derivation path for each cosigner must be known and consistent with PSBT
|
||||
- XFP values (fingerprints) MUST be unique for each of the co-signers
|
||||
- multisig wallet `name` can only contain printable ASCII characters `range(32, 127)`
|
||||
|
||||
### BIP-67
|
||||
|
||||
- importing multisig from PSBT can ONLY create `sortedmulti(...)` multisig according to BIP-67, DO NOT use with `multi(...)`
|
||||
- creating airgapped multisig using COLDCARD as coordinator always produces `sortedmulti(...)` multisig according to BIP-67
|
||||
- COLDCARD import/export [format](https://coldcard.com/docs/multisig/#configuration-text-file-for-multisig) only supports `sortedmulti(...)` multisig according to BIP-67. To import multisig wallet with `multi(...)` use descriptor import [format](https://github.com/bitcoin/bips/blob/master/bip-0383.mediawiki)
|
||||
- encrypted COLDCARD backups that contains multisig wallets with `multi(...)` MUST only be restored on firmware versions with `multi(...)` support
|
||||
- all imported `multi(...)` must differ in keys (same as `sortedmulti(...)`). If `wsh(multi(2,A,B))` is already registered, `wsh(multi(2,B,A))` will be rejected upon import as duplicate, even thought they are actually different script/wallet.
|
||||
- just BIP67 difference is also treated as duplicate. If `wsh(multi(2,A,B)` is registered, `wsh(sortedmulti(2,A,B))` will be rejected as duplicate and vice-versa.
|
||||
|
||||
# SIGHASH types
|
||||
|
||||
@ -105,7 +119,7 @@
|
||||
|
||||
We will summarize transaction outputs as "change" back into same wallet, however:
|
||||
|
||||
- PSBT must specify BIP32 path in corresponding output section for us to treat as change
|
||||
- PSBT must specify BIP-32 path in corresponding output section for us to treat as change
|
||||
- for p2sh-wrapped segwit outputs, redeem script must be provided when needed
|
||||
- any incorrect values here are assumed to be fraud attempts, and are highlighted to user
|
||||
- the _redeemScript_ for `p2wsh-p2sh` is optional, but if provided must be
|
||||
@ -126,21 +140,25 @@ We will summarize transaction outputs as "change" back into same wallet, however
|
||||
|
||||
- key derivatation paths must be 12 or less in depth (`MAX_PATH_DEPTH`)
|
||||
|
||||
# Pay-to-Pubkey
|
||||
|
||||
# NFC Feature (Mk4)
|
||||
- although we have some code for "pay to pubkey" (P2PK not P2PKH), it is untested
|
||||
and unused since this style of payment address is obsolete and largely unused today
|
||||
|
||||
# NFC Feature
|
||||
|
||||
- can share up to 8000 bytes of PSBT or signed transaction data.
|
||||
- NFC-V (ISO-15693) radio/modulation is common on mobile phones but very rare on desktops
|
||||
|
||||
# Fast Wipe (Mk4)
|
||||
# Fast Wipe
|
||||
|
||||
- each use of "fast wipe" feature consumes a MCU key slot, of which there are 256.
|
||||
- use _Advanced > Danger Zone > MCU Key Slots_ to view usage
|
||||
|
||||
# Trick Pins (Mk4)
|
||||
# Trick Pins
|
||||
|
||||
- "deltamode" PIN must be same length as true pin, and differ only in final 4 positions.
|
||||
- there are 14 trick "slots", but we avoid slot 10, so 13 available.
|
||||
- there are 14 trick "slots", but on mk4, we avoid slot 10, so 13 available. (Q: 14)
|
||||
- duress wallets consume 2 slots (or 3 slots for legacy duress wallet) which must be contiguous
|
||||
- when restoring trick pins from backup files, "forgotten" pins are not restored,
|
||||
and any trick pin which matches the true PIN of the restored system will be dropped
|
||||
@ -148,9 +166,58 @@ We will summarize transaction outputs as "change" back into same wallet, however
|
||||
is not compatible, the deltamode trick PIN is dropped and not restored
|
||||
- duress wallets are supported when derived from 24- or 12-word seed phrases
|
||||
|
||||
# Debug Serial Port (Mk4)
|
||||
# Debug Serial Port
|
||||
|
||||
- virtual USB serial port disabled completely by default, and even if enabled
|
||||
in Danger Zone, only echos output, and does not accept any input
|
||||
- use hardware serial port for interactive REPL access (3.3v TTL levels)
|
||||
|
||||
# BBQr Scanning (Q)
|
||||
|
||||
- files up to 2MiB in size can be accepted
|
||||
- when 14 or less parts, we display status of each part, if more, just percent complete
|
||||
|
||||
# QR Scanning (Q)
|
||||
|
||||
- if not BBQr (or sent as unicode inside BBQr) we auto detect these data types:
|
||||
- PSBT in Base64 or hex
|
||||
- Wire Transaction in Base64 or hex
|
||||
- XPRV, XPUB, bare payment addresses, BIP-21 invoices
|
||||
- seed words (truncated, or full)
|
||||
- SeedQR (but not Compact SeedQR)
|
||||
- for Base58, Bech32 encoded values, if checksum is wrong then it is shown as text
|
||||
- binary QR codes are not supported
|
||||
- when pasting into a secure note, if the QR's data is > 60 chars long, we assume done
|
||||
|
||||
# Secure Notes & Passwords (Q)
|
||||
|
||||
- when Q picks a password for you (using F1 thru F5), the entropy is 126 bits or more,
|
||||
except F3 which makes an easier to type password of around 48 bits entropy.
|
||||
- Title, Sitename and Username fields are limited to 32 characters in length.
|
||||
- Passwords are limited to 128 characters.
|
||||
- Note text is unlimited, but storing very large notes may affect performance system-wide.
|
||||
- Q Backup files restored onto Mk4 will lose their notes, since notes feature is not supported.
|
||||
|
||||
# Address Ownership
|
||||
|
||||
- only the first 1528 addresses (764 each from internal and external (change/not) paths)
|
||||
are considered
|
||||
- if you have used an sub-account, without ever exploring it in the Address Explorer, nor
|
||||
signing a PSBT with those account numbers, we do not search it.
|
||||
- does not search Seed Vault, you'll need to load each of those and re-search
|
||||
- if you have an XFP collision between multiple wallets in SeedVault (ie. two wallets
|
||||
with same descriptors, but different seeds) you will get false negatives
|
||||
|
||||
# Spending Policy
|
||||
|
||||
- (Cosign mode) only 12 or 24 word seeds (not XPRV) are accepted for "key C"
|
||||
- velocity limit:
|
||||
- based on a max magnitude per txn, and a required minimum block height
|
||||
gap, based on previous `nLockTime` value in last-signed PSBT.
|
||||
- if you sign a transaction, but never broadcast it, you will still have to wait out
|
||||
the velocity policy.
|
||||
- PSBT creator must put in `nLockTime` block heights (most already do to avoid fee sniping)
|
||||
- maximum of 25 whitelisted addresses can be stored
|
||||
- Web2FA: any number of mobile devices can be enrolled, but all will have the same shared secret
|
||||
- any warning from the PSBT, such as huge fees, will cause the transaction to be rejected
|
||||
|
||||
|
||||
@ -38,7 +38,7 @@ directly from python programs.
|
||||
|
||||
| Start | Size | Notes
|
||||
|---------------|-----------|--------------------------
|
||||
| 0x0800 0000 | 128k | Bootloader code, including reset vector. See `stm32/mk4-bootloader`
|
||||
| 0x0800 0000 | 112k | Bootloader code, including reset vector. See `stm32/mk4-bootloader`
|
||||
| 0x0801 c000 | 8k | Sensitive "pairing secrets" for SE1 and SE2
|
||||
| 0x0801 e000 | 8k | MCU keys, consumable; 256 32-bit write-once slots.
|
||||
| 0x0802 0000 | 16k | Interrupt handlers, file header (Micropython and Coldcard code)
|
||||
|
||||
@ -2,24 +2,6 @@
|
||||
Choose PIN Code
|
||||
Advanced/Tools
|
||||
View Identity
|
||||
Ephemeral Seed
|
||||
Generate Words
|
||||
24 Words
|
||||
12 Words
|
||||
24 Word Dice Roll
|
||||
12 Word Dice Roll
|
||||
Import Words
|
||||
24 Words
|
||||
18 Words
|
||||
12 Words
|
||||
Import via NFC
|
||||
Import XPRV
|
||||
Tapsigner Backup
|
||||
Upgrade Firmware
|
||||
Show Version
|
||||
From MicroSD
|
||||
From VirtDisk [IF VIRTDISK ENABLED]
|
||||
Bless Firmware
|
||||
Paper Wallets
|
||||
Perform Selftest
|
||||
Secure Logout
|
||||
@ -29,86 +11,95 @@
|
||||
|
||||
[IF BLANK WALLET]
|
||||
New Seed Words
|
||||
24 Word (default)
|
||||
12 Word
|
||||
24 Word Dice Roll
|
||||
12 Word Dice Roll
|
||||
Import Existing
|
||||
24 Words
|
||||
[SEED WORD MENUS]
|
||||
18 Words
|
||||
[SEED WORD MENUS]
|
||||
12 Words
|
||||
[SEED WORD MENUS]
|
||||
24 Words
|
||||
Advanced
|
||||
12 Word Dice Roll
|
||||
24 Word Dice Roll
|
||||
Import Existing
|
||||
12 Words
|
||||
[SEED WORD ENTRY]
|
||||
18 Words
|
||||
[SEED WORD ENTRY]
|
||||
24 Words
|
||||
[SEED WORD ENTRY]
|
||||
Scan QR Code [IF QR SCANNER]
|
||||
Restore Backup
|
||||
Clone Coldcard
|
||||
Import XPRV
|
||||
Tapsigner Backup
|
||||
Seed XOR
|
||||
Migrate Coldcard
|
||||
Key Teleport (start)
|
||||
Help
|
||||
Advanced/Tools
|
||||
View Identity
|
||||
Ephemeral Seed
|
||||
Temporary Seed
|
||||
Generate Words
|
||||
24 Words
|
||||
12 Words
|
||||
24 Word Dice Roll
|
||||
24 Words
|
||||
12 Word Dice Roll
|
||||
24 Word Dice Roll
|
||||
Import from QR Scan [IF QR SCANNER]
|
||||
Import Words
|
||||
24 Words
|
||||
18 Words
|
||||
12 Words
|
||||
Import via NFC
|
||||
18 Words
|
||||
24 Words
|
||||
Import via NFC [IF NFC ENABLED]
|
||||
Import XPRV
|
||||
Tapsigner Backup
|
||||
Upgrade Firmware
|
||||
Coldcard Backup
|
||||
Restore Seed XOR
|
||||
Upgrade Firmware [IF NOT TMP SEED]
|
||||
Show Version
|
||||
From MicroSD
|
||||
From VirtDisk [IF VIRTDISK ENABLED]
|
||||
Bless Firmware
|
||||
File Management
|
||||
Verify Backup
|
||||
List Files
|
||||
Verify Sig File
|
||||
NFC File Share [IF NFC ENABLED]
|
||||
BBQr File Share [IF QR SCANNER]
|
||||
QR File Share [IF QR SCANNER]
|
||||
Format SD Card
|
||||
Format RAM Disk [IF VIRTDISK ENABLED]
|
||||
Key Teleport (start)
|
||||
Paper Wallets
|
||||
Perform Selftest
|
||||
I Am Developer.
|
||||
Serial REPL
|
||||
Wipe LFS
|
||||
Warm Reset
|
||||
Restore Txt Bkup
|
||||
Restore Bkup
|
||||
Reflash GPU [IF QWERTY KEYBOARD]
|
||||
Secure Logout
|
||||
Settings
|
||||
Login Settings
|
||||
Change Main PIN
|
||||
PIN Options
|
||||
Trick PINs
|
||||
Add New Trick
|
||||
Add If Wrong
|
||||
Delete All
|
||||
Set Nickname
|
||||
Scramble Keypad
|
||||
Scramble Keys
|
||||
Kill Key
|
||||
Login Countdown
|
||||
Disabled
|
||||
5 minutes
|
||||
15 minutes
|
||||
30 minutes
|
||||
4 hours
|
||||
1 hour
|
||||
5 minutes
|
||||
2 hours
|
||||
4 hours
|
||||
8 hours
|
||||
12 hours
|
||||
2 hours
|
||||
3 days
|
||||
48 hours
|
||||
1 week
|
||||
24 hours
|
||||
48 hours
|
||||
3 days
|
||||
1 week
|
||||
28 days later
|
||||
MicroSD 2FA [MAYBE]
|
||||
MicroSD 2FA [IF SECRET AND NOT TMP SEED]
|
||||
Add Card
|
||||
Check Card
|
||||
Remove Card #1
|
||||
Calculator Login [IF QWERTY KEYBOARD]
|
||||
Default Off
|
||||
Calculator Login
|
||||
Test Login Now
|
||||
Hardware On/Off
|
||||
USB Port
|
||||
@ -121,23 +112,11 @@
|
||||
NFC Sharing
|
||||
Default Off
|
||||
Enable NFC
|
||||
Multisig Wallets
|
||||
2/2: core2of2_native
|
||||
"core2of2_native"
|
||||
View Details
|
||||
Delete
|
||||
Coldcard Export
|
||||
Descriptors
|
||||
View Descriptor
|
||||
Export
|
||||
Bitcoin Core
|
||||
Electrum Wallet
|
||||
Import from File
|
||||
Import via NFC
|
||||
Export XPUB
|
||||
Create Airgapped
|
||||
Trust PSBT?
|
||||
Skip Checks?
|
||||
NFC Push Tx
|
||||
coldcard.com
|
||||
mempool.space
|
||||
Custom URL...
|
||||
Disable
|
||||
Display Units
|
||||
BTC
|
||||
mBTC
|
||||
@ -156,21 +135,106 @@
|
||||
4 hours
|
||||
8 hours
|
||||
Never
|
||||
Idle Timeout (on battery) [IF BATTERIES]
|
||||
30 seconds
|
||||
60 seconds
|
||||
2 minutes
|
||||
5 minutes
|
||||
10 minutes
|
||||
15 minutes
|
||||
30 minutes
|
||||
1 hour
|
||||
4 hours
|
||||
Never
|
||||
LCD Brightness (on battery) [IF BATTERIES]
|
||||
25%
|
||||
50%
|
||||
60%
|
||||
70%
|
||||
80%
|
||||
90%
|
||||
95% (default)
|
||||
100%
|
||||
Delete PSBTs
|
||||
Default Keep
|
||||
Delete PSBTs
|
||||
Menu Wrapping
|
||||
Default Off
|
||||
Enable
|
||||
Buried Settings
|
||||
Home Menu XFP [IF SECRET AND NOT TMP SEED]
|
||||
Only Tmp
|
||||
Always Show
|
||||
Menu Wrapping
|
||||
Default
|
||||
Always Wrap
|
||||
[QR key shortcut] [IF QR SCANNER]
|
||||
---
|
||||
|
||||
[NORMAL OPERATION]
|
||||
Ready To Sign
|
||||
Passphrase
|
||||
Passphrase [IF WORD BASED SEED]
|
||||
Restore Saved
|
||||
c*******
|
||||
[3A14F788]
|
||||
Restore
|
||||
Delete
|
||||
Edit Phrase
|
||||
Scan Any QR Code [IF QR SCANNER]
|
||||
Start HSM Mode [IF HSM POLICY]
|
||||
Address Explorer
|
||||
Type Passwords
|
||||
Secure Logout
|
||||
Classic P2PKH
|
||||
↳ mtHSVByP9EYZ⋯Vm19gvpecb5R
|
||||
P2SH-Segwit
|
||||
↳ 2NCAJ5wD4Gvm⋯NphNU8UYoEJv
|
||||
Segwit P2WPKH
|
||||
↳ tb1qupyd58nd⋯vu9jtdyws9n9
|
||||
Applications
|
||||
Samourai
|
||||
Post-mix
|
||||
Pre-mix
|
||||
Wasabi
|
||||
Account Number
|
||||
Custom Path
|
||||
CC-2-of-4
|
||||
Secure Notes & Passwords [IF ENBALED] [MAYBE]
|
||||
1: note0
|
||||
"note0"
|
||||
View Note
|
||||
Edit
|
||||
Delete
|
||||
Export
|
||||
Sign Note Text
|
||||
2: secret-PWD
|
||||
"secret-PWD"
|
||||
↳ satoshi
|
||||
↳ abc.org
|
||||
View Password
|
||||
Send Password [MAYBE]
|
||||
Export
|
||||
Edit Metadata
|
||||
Delete
|
||||
Change Password
|
||||
Sign Note Text
|
||||
New Note
|
||||
New Password
|
||||
Export All
|
||||
Sort By Title
|
||||
Import
|
||||
Type Passwords [MAYBE]
|
||||
Seed Vault [MAYBE]
|
||||
1: [7126EB3C]
|
||||
[7126EB3C]
|
||||
Use This Seed
|
||||
Rename
|
||||
Delete
|
||||
2: [CCEE13B9]
|
||||
[CCEE13B9]
|
||||
Use This Seed
|
||||
Rename
|
||||
Delete
|
||||
3: [03EE9989]
|
||||
[03EE9989]
|
||||
Use This Seed
|
||||
Rename
|
||||
Delete
|
||||
Advanced/Tools
|
||||
Backup
|
||||
Backup System
|
||||
@ -178,11 +242,19 @@
|
||||
Restore Backup
|
||||
Clone Coldcard
|
||||
Export Wallet
|
||||
Sparrow
|
||||
Cove
|
||||
Bitcoin Core
|
||||
Nunchuk
|
||||
Bull Bitcoin
|
||||
Blue Wallet
|
||||
Electrum Wallet
|
||||
Wasabi Wallet
|
||||
Unchained Capital
|
||||
Lily Wallet
|
||||
Fully Noded
|
||||
Unchained
|
||||
Theya
|
||||
Bitcoin Safe
|
||||
Zeus
|
||||
Samourai Postmix
|
||||
Samourai Premix
|
||||
Descriptor
|
||||
@ -190,24 +262,32 @@
|
||||
Export XPUB
|
||||
Segwit (BIP-84)
|
||||
Classic (BIP-44)
|
||||
P2WPKH/P2SH (49)
|
||||
P2WPKH/P2SH (BIP-49)
|
||||
Master XPUB
|
||||
Current XFP
|
||||
Key Expression
|
||||
Dump Summary
|
||||
Upgrade Firmware
|
||||
Upgrade Firmware [IF NOT TMP SEED]
|
||||
Show Version
|
||||
From MicroSD
|
||||
From VirtDisk [IF VIRTDISK ENABLED]
|
||||
Bless Firmware
|
||||
File Management
|
||||
Verify Backup
|
||||
Backup System
|
||||
Export Wallet
|
||||
Sparrow
|
||||
Cove
|
||||
Bitcoin Core
|
||||
Nunchuk
|
||||
Bull Bitcoin
|
||||
Blue Wallet
|
||||
Electrum Wallet
|
||||
Wasabi Wallet
|
||||
Unchained Capital
|
||||
Lily Wallet
|
||||
Fully Noded
|
||||
Unchained
|
||||
Theya
|
||||
Bitcoin Safe
|
||||
Zeus
|
||||
Samourai Postmix
|
||||
Samourai Premix
|
||||
Descriptor
|
||||
@ -215,99 +295,176 @@
|
||||
Export XPUB
|
||||
Segwit (BIP-84)
|
||||
Classic (BIP-44)
|
||||
P2WPKH/P2SH (49)
|
||||
P2WPKH/P2SH (BIP-49)
|
||||
Master XPUB
|
||||
Current XFP
|
||||
Key Expression
|
||||
Dump Summary
|
||||
Sign Text File
|
||||
Clone Coldcard
|
||||
Batch Sign PSBT
|
||||
Teleport Multisig PSBT
|
||||
List Files
|
||||
Verify Sig File
|
||||
NFC File Share [IF NFC ENABLED]
|
||||
BBQr File Share [IF QR SCANNER]
|
||||
QR File Share [IF QR SCANNER]
|
||||
Clone Coldcard
|
||||
Format SD Card
|
||||
Format RAM Disk [IF VIRTDISK ENABLED]
|
||||
Derive Seed B85
|
||||
Secure Notes & Passwords [IF QWERTY KEYBOARD]
|
||||
1: note0
|
||||
"note0"
|
||||
View Note
|
||||
Edit
|
||||
Delete
|
||||
Export
|
||||
Sign Note Text
|
||||
2: secret-PWD
|
||||
"secret-PWD"
|
||||
↳ satoshi
|
||||
↳ abc.org
|
||||
View Password
|
||||
Send Password [MAYBE]
|
||||
Export
|
||||
Edit Metadata
|
||||
Delete
|
||||
Change Password
|
||||
Sign Note Text
|
||||
New Note
|
||||
New Password
|
||||
Export All
|
||||
Sort By Title
|
||||
Import
|
||||
Derive Seeds (BIP-85)
|
||||
View Identity
|
||||
Ephemeral Seed
|
||||
Temporary Seed
|
||||
Generate Words
|
||||
24 Words
|
||||
12 Words
|
||||
24 Word Dice Roll
|
||||
24 Words
|
||||
12 Word Dice Roll
|
||||
24 Word Dice Roll
|
||||
Import from QR Scan [IF QR SCANNER]
|
||||
Import Words
|
||||
24 Words
|
||||
18 Words
|
||||
12 Words
|
||||
Import via NFC
|
||||
18 Words
|
||||
24 Words
|
||||
Import via NFC [IF NFC ENABLED]
|
||||
Import XPRV
|
||||
Tapsigner Backup
|
||||
Coldcard Backup
|
||||
Restore Seed XOR
|
||||
Key Teleport (start)
|
||||
Spending Policy [IF SECRET AND NOT TMP SEED]
|
||||
Single-Signer [IF SECRET AND NOT TMP SEED]
|
||||
Co-Sign Multisig (CCC) [IF NOT TMP SEED]
|
||||
HSM Mode [IF HSM AND SECRET]
|
||||
Default Off
|
||||
Enable
|
||||
User Management [MAYBE]
|
||||
Paper Wallets
|
||||
Enable HSM
|
||||
Default Off
|
||||
Enable
|
||||
User Management
|
||||
(no users yet)
|
||||
WIF Store
|
||||
NFC Tools [IF NFC ENABLED]
|
||||
Sign PSBT
|
||||
Show Address
|
||||
Sign Message
|
||||
Verify Sig File
|
||||
Verify Address
|
||||
File Share
|
||||
Import Multisig
|
||||
Push Transaction [IF PUSHTX ENABLED]
|
||||
Danger Zone
|
||||
Debug Functions
|
||||
Seed Functions
|
||||
View Seed Words
|
||||
Seed XOR
|
||||
Split Existing
|
||||
Split Existing [IF WORD BASED SEED]
|
||||
Restore Seed XOR
|
||||
Destroy Seed
|
||||
Lock Down Seed
|
||||
Destroy Seed [IF SECRET AND NOT TMP SEED]
|
||||
Lock Down Seed [MAYBE]
|
||||
Export SeedQR [IF WORD BASED SEED]
|
||||
I Am Developer.
|
||||
Serial REPL
|
||||
Wipe LFS
|
||||
Warm Reset
|
||||
Restore Txt Bkup
|
||||
Restore Bkup
|
||||
BKPW Override
|
||||
Reflash GPU [IF QWERTY KEYBOARD]
|
||||
Seed Vault [IF SECRET AND NOT TMP SEED]
|
||||
Default Off
|
||||
Enable
|
||||
Perform Selftest
|
||||
Set High-Water
|
||||
Wipe HSM Policy [IF HSM POLICY]
|
||||
Clear OV cache
|
||||
Clear Address cache
|
||||
Sighash Checks
|
||||
Default: Block
|
||||
Warn
|
||||
Testnet Mode
|
||||
Bitcoin
|
||||
Testnet3
|
||||
Testnet4
|
||||
Regtest
|
||||
AE Start Index
|
||||
Default Off
|
||||
Enable
|
||||
B85 Idx Values
|
||||
Default Off
|
||||
Unlimited
|
||||
Settings Space
|
||||
MCU Key Slots
|
||||
Bless Firmware
|
||||
Wipe LFS
|
||||
Nuke Device
|
||||
Settings
|
||||
Login Settings
|
||||
Change Main PIN
|
||||
PIN Options
|
||||
Trick PINs
|
||||
Trick PINs [IF SECRET AND NOT TMP SEED]
|
||||
Trick PINs:
|
||||
↳11-11
|
||||
PIN 11-11
|
||||
↳Bricks CC
|
||||
Hide Trick
|
||||
Delete Trick
|
||||
Change PIN
|
||||
↳333-3334
|
||||
PIN 333-3334
|
||||
↳Duress Wallet
|
||||
Activate Wallet
|
||||
Hide Trick
|
||||
Delete Trick
|
||||
Change PIN
|
||||
↳WRONG PIN
|
||||
After 3 wrong:
|
||||
↳Wipes seed
|
||||
↳Reboots
|
||||
Hide Trick
|
||||
Delete Trick
|
||||
Add New Trick
|
||||
Add If Wrong
|
||||
Delete All
|
||||
Set Nickname
|
||||
Scramble Keypad
|
||||
Scramble Keys
|
||||
Kill Key
|
||||
Login Countdown
|
||||
Disabled
|
||||
5 minutes
|
||||
15 minutes
|
||||
30 minutes
|
||||
4 hours
|
||||
1 hour
|
||||
5 minutes
|
||||
2 hours
|
||||
4 hours
|
||||
8 hours
|
||||
12 hours
|
||||
2 hours
|
||||
3 days
|
||||
48 hours
|
||||
1 week
|
||||
24 hours
|
||||
48 hours
|
||||
3 days
|
||||
1 week
|
||||
28 days later
|
||||
MicroSD 2FA [MAYBE]
|
||||
MicroSD 2FA [IF SECRET AND NOT TMP SEED]
|
||||
Add Card
|
||||
Check Card
|
||||
Remove Card #1
|
||||
Calculator Login [IF QWERTY KEYBOARD]
|
||||
Default Off
|
||||
Calculator Login
|
||||
Test Login Now
|
||||
Hardware On/Off
|
||||
USB Port
|
||||
@ -321,22 +478,30 @@
|
||||
Default Off
|
||||
Enable NFC
|
||||
Multisig Wallets
|
||||
2/2: core2of2_native
|
||||
"core2of2_native"
|
||||
2/4: CC-2-of-4
|
||||
"CC-2-of-4"
|
||||
View Details
|
||||
Delete
|
||||
Coldcard Export
|
||||
Electrum Wallet
|
||||
Descriptors
|
||||
View Descriptor
|
||||
Export
|
||||
Bitcoin Core
|
||||
Electrum Wallet
|
||||
Import from File
|
||||
Import via NFC
|
||||
Import
|
||||
Export XPUB
|
||||
Create Airgapped
|
||||
Trust PSBT?
|
||||
Skip Checks?
|
||||
Full Address View?
|
||||
Partly Censor
|
||||
Show Full
|
||||
Unsorted Multisig?
|
||||
NFC Push Tx
|
||||
coldcard.com
|
||||
mempool.space
|
||||
Custom URL...
|
||||
Disable
|
||||
Display Units
|
||||
BTC
|
||||
mBTC
|
||||
@ -355,23 +520,205 @@
|
||||
4 hours
|
||||
8 hours
|
||||
Never
|
||||
Idle Timeout (on battery) [IF BATTERIES]
|
||||
30 seconds
|
||||
60 seconds
|
||||
2 minutes
|
||||
5 minutes
|
||||
10 minutes
|
||||
15 minutes
|
||||
30 minutes
|
||||
1 hour
|
||||
4 hours
|
||||
Never
|
||||
LCD Brightness (on battery) [IF BATTERIES]
|
||||
25%
|
||||
50%
|
||||
60%
|
||||
70%
|
||||
80%
|
||||
90%
|
||||
95% (default)
|
||||
100%
|
||||
Delete PSBTs
|
||||
Default Keep
|
||||
Delete PSBTs
|
||||
Menu Wrapping
|
||||
Default Off
|
||||
Enable
|
||||
Keyboard EMU
|
||||
Default Off
|
||||
Enable
|
||||
Buried Settings
|
||||
Home Menu XFP [IF SECRET AND NOT TMP SEED]
|
||||
Only Tmp
|
||||
Always Show
|
||||
Menu Wrapping
|
||||
Default
|
||||
Always Wrap
|
||||
Secure Logout
|
||||
[NFC key shortcut] [IF NFC ENABLED]
|
||||
Sign PSBT
|
||||
Show Address
|
||||
Sign Message
|
||||
Verify Sig File
|
||||
Verify Address
|
||||
File Share
|
||||
Import Multisig
|
||||
Push Transaction [IF PUSHTX ENABLED]
|
||||
---
|
||||
|
||||
[FACTORY MODE]
|
||||
Bag Me Now
|
||||
Version: 5.x.x
|
||||
DFU Upgrade
|
||||
Show Version
|
||||
Ship W/O Bag
|
||||
Debug Functions
|
||||
Perform Selftest
|
||||
---
|
||||
|
||||
[SSSP]
|
||||
Ready To Sign
|
||||
Passphrase [IF WORD BASED SEED & SSSP RELATED KEYS ENABLED]
|
||||
Restore Saved
|
||||
c*******
|
||||
[3A14F788]
|
||||
Restore
|
||||
Delete
|
||||
Edit Phrase
|
||||
Scan Any QR Code [IF QR SCANNER]
|
||||
Address Explorer
|
||||
Classic P2PKH
|
||||
↳ mtHSVByP9EYZ⋯Vm19gvpecb5R
|
||||
P2SH-Segwit
|
||||
↳ 2NCAJ5wD4Gvm⋯NphNU8UYoEJv
|
||||
Segwit P2WPKH
|
||||
↳ tb1qupyd58nd⋯vu9jtdyws9n9
|
||||
Applications
|
||||
Samourai
|
||||
Post-mix
|
||||
Pre-mix
|
||||
Wasabi
|
||||
Account Number
|
||||
Custom Path
|
||||
CC-2-of-4
|
||||
Secure Notes & Passwords[IF ENABLED & SSSP ALLOW NOTES]
|
||||
1: note0
|
||||
"note0"
|
||||
View Note
|
||||
Sign Note Text
|
||||
2: secret-PWD
|
||||
"secret-PWD"
|
||||
↳ satoshi
|
||||
↳ abc.org
|
||||
View Password
|
||||
Send Password [MAYBE]
|
||||
Sign Note Text
|
||||
Type Passwords [MAYBE]
|
||||
Seed Vault[IF ENABLED & SSSP RELATED KEYS ENABLED]
|
||||
1: [7126EB3C]
|
||||
[7126EB3C]
|
||||
Use This Seed
|
||||
2: [CCEE13B9]
|
||||
[CCEE13B9]
|
||||
Use This Seed
|
||||
3: [03EE9989]
|
||||
[03EE9989]
|
||||
Use This Seed
|
||||
Advanced/Tools
|
||||
File Management
|
||||
Sign Text File
|
||||
Batch Sign PSBT
|
||||
List Files
|
||||
Export Wallet
|
||||
Sparrow
|
||||
Cove
|
||||
Bitcoin Core
|
||||
Nunchuk
|
||||
Bull Bitcoin
|
||||
Blue Wallet
|
||||
Electrum Wallet
|
||||
Wasabi Wallet
|
||||
Fully Noded
|
||||
Unchained
|
||||
Theya
|
||||
Bitcoin Safe
|
||||
Zeus
|
||||
Samourai Postmix
|
||||
Samourai Premix
|
||||
Descriptor
|
||||
Generic JSON
|
||||
Export XPUB
|
||||
Segwit (BIP-84)
|
||||
Classic (BIP-44)
|
||||
P2WPKH/P2SH (BIP-49)
|
||||
Master XPUB
|
||||
Current XFP
|
||||
Key Expression
|
||||
Dump Summary
|
||||
Verify Sig File
|
||||
NFC File Share [IF NFC ENABLED]
|
||||
BBQr File Share [IF QR SCANNER]
|
||||
QR File Share [IF QR SCANNER]
|
||||
Format SD Card
|
||||
Format RAM Disk [IF VIRTDISK ENABLED]
|
||||
Export Wallet
|
||||
Sparrow
|
||||
Cove
|
||||
Bitcoin Core
|
||||
Nunchuk
|
||||
Bull Bitcoin
|
||||
Blue Wallet
|
||||
Electrum Wallet
|
||||
Wasabi Wallet
|
||||
Fully Noded
|
||||
Unchained
|
||||
Theya
|
||||
Bitcoin Safe
|
||||
Zeus
|
||||
Samourai Postmix
|
||||
Samourai Premix
|
||||
Descriptor
|
||||
Generic JSON
|
||||
Export XPUB
|
||||
Segwit (BIP-84)
|
||||
Classic (BIP-44)
|
||||
P2WPKH/P2SH (BIP-49)
|
||||
Master XPUB
|
||||
Current XFP
|
||||
Key Expression
|
||||
Dump Summary
|
||||
Teleport Multisig PSBT [MAYBE]
|
||||
View Identity
|
||||
Temporary Seed [IF SSSP RELATED KEYS ENABLED]
|
||||
Import from QR Scan [IF QR SCANNER]
|
||||
Import Words
|
||||
12 Words
|
||||
18 Words
|
||||
24 Words
|
||||
Import via NFC [IF NFC ENABLED]
|
||||
Import XPRV
|
||||
Tapsigner Backup
|
||||
Coldcard Backup
|
||||
Restore Seed XOR
|
||||
Paper Wallets
|
||||
WIF Store
|
||||
NFC Tools [IF NFC ENABLED]
|
||||
Sign PSBT
|
||||
Show Address
|
||||
Sign Message
|
||||
Verify Sig File
|
||||
Verify Address
|
||||
File Share
|
||||
Push Transaction [IF PUSHTX ENABLED]
|
||||
Show Firmware Version
|
||||
Destroy Seed [IF SECRET AND NOT TMP SEED]
|
||||
Secure Logout
|
||||
EXIT TEST DRIVE [MAYBE]
|
||||
[NFC key shortcut] [IF NFC ENABLED]
|
||||
Sign PSBT
|
||||
Show Address
|
||||
Sign Message
|
||||
Verify Sig File
|
||||
Verify Address
|
||||
File Share
|
||||
Push Transaction [IF PUSHTX ENABLED]
|
||||
---
|
||||
|
||||
|
||||
@ -29,6 +29,9 @@ tools may or may not hide it from you based on Unix filename
|
||||
conventions. Reformating the card will certainly remove this file,
|
||||
so keep that in mind when managing your "special" cards.
|
||||
|
||||
If using COLDCARD Q and both card slot are populated during login
|
||||
make sure that enrolled card is in top slot (slot A).
|
||||
|
||||
## Menu Settings
|
||||
|
||||
See menu in: `Settings -> Login Settings -> MicroSD 2FA`
|
||||
|
||||
@ -2,15 +2,16 @@
|
||||
|
||||
COLDCARD can sign messages send to it via USB with the help of `ckcc` utility,
|
||||
sign messages provided via specially crafted file on SD card or Vdisk,
|
||||
and Mk4 can also sign messages sent to COLDCARD via NFC.
|
||||
and NFC-equipped models (Mk4, Mk5, and Q) can also sign messages sent to COLDCARD via NFC.
|
||||
The resulting signature can be returned over SD card/Vdisk, NFC, or — on Q — as a QR code.
|
||||
|
||||
Signature format follows [BIP-0137](https://github.com/bitcoin/bips/blob/master/bip-0137.mediawiki) specification.
|
||||
COLDCARD Mk3 and COLDCARD Mk4 up to version `5.1.0` used compressed P2PKH header byte for all script types.
|
||||
From Mk4 `5.1.0` correct header byte is used for corresponding script type.
|
||||
From version `5.1.0` correct header byte is used for corresponding script type.
|
||||
|
||||
### Verification
|
||||
|
||||
From COLDCARD Mk4 version `5.1.0` users can verify signed messages directly on the device.
|
||||
From version `5.1.0` users can verify signed messages directly on the device.
|
||||
If signature file is on SD card or Virtual disk `Advanced/Tools -> File Management -> Verify Sig File`. In case
|
||||
signature file is detached signature of signed export (or any other file), COLDCARD can check if digest of file
|
||||
specified in the message matches contents of file. This requires file signed to be available on SD card or Vdisk.
|
||||
@ -21,7 +22,7 @@ Bitcoin core can only verify P2PKH.
|
||||
|
||||
## Signed Exports
|
||||
|
||||
From Mk4 version `5.1.0` most of SD card and Virtual disk exports are accompanied by detached signature file.
|
||||
From version `5.1.0` most of SD card and Virtual disk exports are accompanied by detached signature file.
|
||||
If exported file name is `addresses.csv` signature file name will be `addresses.sig`.
|
||||
|
||||
### Message construction and signature file format
|
||||
@ -39,29 +40,23 @@ IFOvGVJrm31S0j+F4dVfQ5kbRKWKcmhmXIn/Lw8iIgaCG5QNZswjrN4X673R7jTZo1kvLmiD4hlIrbuL
|
||||
-----END BITCOIN SIGNATURE-----
|
||||
```
|
||||
|
||||
### What is signed
|
||||
### What Is Signed
|
||||
|
||||
1. **Single sig address explorer exports**. Signed by key corresponding to first (0th) address on the exported list.
|
||||
2. **Specific single sig exports**. Signed by key corresponding to external address at index zero of chosen application specific derivation `m/<app_deriv>/0/0`
|
||||
1. **Single sig address explorer exports:** Signed by the key corresponding to the first (0th) address on the exported list.
|
||||
2. **Specific single sig exports:** Signed by the key corresponding to the external address at index zero of chosen application specific derivation `m/<app_deriv>h/<coin_type>'h/<account>h/0/0`.
|
||||
* Bitcoin Core
|
||||
* Electrum Wallet
|
||||
* Wasabi Wallet
|
||||
* Samourai Postmix
|
||||
* Samourai Premix
|
||||
* Descriptor
|
||||
3. **Generic single sig exports**. Signed by key that corresponds to address at derivation `m/44'/<coin_type>'/0'/0/0`
|
||||
Lily Wallet
|
||||
Generic JSON
|
||||
Dump Summary
|
||||
4. **BIP85 derived entropy exports**. Signed by path that corresponds to specific BIP85 application.
|
||||
5. **Paper wallet exports**. Signed by key and address exported as paper wallet itself.
|
||||
|
||||
### What is NOT signed
|
||||
|
||||
Multisig exports and generic multisig xpub exports are not signed. It is not clear at this point
|
||||
whether to sign these exports with some generic single signature key (i.e. `m/44'/<coin_type>'/0'/0/0`)
|
||||
or with our portion (leg) of script. In both cases script type (address format) would not match as multisignature
|
||||
message signing is not standardized.
|
||||
|
||||
1. **Multisig exports**
|
||||
2. **Generic multisig exports**
|
||||
3. **Generic single sig exports:** Signed by key that corresponds to first (0th) external address at derivation `m/44h/<coin_type>h/<account>h/0/0`.
|
||||
* Lily Wallet
|
||||
* Generic JSON
|
||||
* Dump Summary
|
||||
4. **BIP85 derived entropy exports:** Signed by path that corresponds to specific BIP85 application.
|
||||
5. **Paper wallet exports:** Signed by key and address exported as paper wallet itself.
|
||||
6. **Multisig exports:** public keys are encoded as P2PKH address for all multisg signature exports
|
||||
* Multisig wallet descriptor: signed by the key corresponding to the first external address of own enrolled extended key `my_key/0/0`
|
||||
* Generic XPUBs export: signed by the key corresponding to the first external address of own standard P2WSH derivation `m/48h/<coin_type>h/<account>h/2h/0/0`
|
||||
* Multisig address explorer export: Signed by own key at the same derivation as first (0th) row on exported list. `my_key/<change>/<start_index>`
|
||||
@ -1,10 +1,20 @@
|
||||
# NFC and Coldcard Mk4
|
||||
# NFC and Coldcard
|
||||
|
||||
(Applies to Coldcard Mk4 only)
|
||||
(Applies to NFC-equipped models: Mk4, Mk5, and Q)
|
||||
|
||||
## Usage
|
||||
|
||||
Mk4 NFC antenna is centered under number `8` on the keypad. Before using NFC,
|
||||
The NFC antenna location depends on the hardware:
|
||||
|
||||
- **Mk4**: a PCB trace loop, centered under number `8` on the keypad.
|
||||
- **Mk5**: a discrete coil (`L6`) in the **top-right corner** of the device
|
||||
- **Q1**: a flexible "sticker" antenna behind the display. The green LED below the
|
||||
bottom-right of the display (`D12`) lights up while an NFC transfer is active —
|
||||
it is the activity indicator, not the antenna.
|
||||
|
||||

|
||||
|
||||
Before using NFC,
|
||||
it is important to locate the position of NFC antenna on your device and point it
|
||||
correctly towards the Coldcard NFC antenna. Picture below shows an example with iPhone
|
||||
that has NFC antenna located at the top right edge. The NFC smartphone antenna
|
||||
@ -36,7 +46,7 @@ in general. Good interoperability is critical with radio standards.
|
||||
|
||||
## Lower Layers
|
||||
|
||||
The Coldcard Mk4 has an chip that acts as a Type 5 NFC tag. The
|
||||
The Coldcard has a chip that acts as a Type 5 NFC tag. The
|
||||
radio standard is called "NFC-V" or ISO-15693, and operates on a
|
||||
13.56 Mhz carrier wave.
|
||||
|
||||
@ -58,9 +68,13 @@ unless we are actively sharing something. We disable the "energy
|
||||
harvesting" features of the chip, so it will not do anything when
|
||||
the Coldcard is powered-down, regardless of the NFC setting.
|
||||
|
||||
If the above is not enough for you, the antenna can be destroyed
|
||||
by cutting the trace labeled "NFC" inside the hole for the MicroSD
|
||||
card. Use the point of a sharp knife to cut and peel up the trace.
|
||||
If the above is not enough for you, the antenna can be destroyed:
|
||||
|
||||
- **Mk4**: cut the trace labeled "NFC" inside the hole for the MicroSD card,
|
||||
using the point of a sharp knife to cut and peel up the trace.
|
||||
- **Mk5**: has no such trace — its antenna is the discrete coil `L6` in the
|
||||
top-right corner, which would have to be physically removed instead.
|
||||
- **Q1**: cut the trace labeled "NFC DATA" under the batteries.
|
||||
|
||||
The NFC traffic is not encrypted and is subject to eavesdropping.
|
||||
While the NFC feature is active, your Coldcard can be uniquely
|
||||
|
||||
103
docs/nfc-pushtx.md
Normal file
@ -0,0 +1,103 @@
|
||||
# NFC Push Tx
|
||||
|
||||
This feature allows single-tap broadcast of the freshly-signed transaction.
|
||||
|
||||
`PSBT ==[SD|QR|NFC]==> COLDCARD signed TXN ==[NFC tap]==> Phone Browser ==> Server TXN Broadcast`
|
||||
|
||||
Once enabled with a URL, the COLDCARD will show the NFC animation
|
||||
after signing the transaction. When the user taps their phone, the
|
||||
phone will see an NFC tag with URL inside. That URL contains the
|
||||
signed transaction ready to go, and once opening in the mobile
|
||||
browser, that URL will load. The landing page will connect to a
|
||||
Bitcoin node (or similar) and send the transaction on the public
|
||||
Bitcoin network.
|
||||
|
||||
This feature is available on Q and Mk4 and requires NFC to be enabled.
|
||||
See `Settings > NFC Push Tx`.
|
||||
|
||||
See the latest on our feature minisite: [PushTx.org](https://pushtx.org)
|
||||
|
||||
## Protocol Spec
|
||||
|
||||
The COLDCARD needs a URL prefix. To that it appends some values:
|
||||
|
||||
- `t=...`
|
||||
- this is the transaction, in binary encoded with
|
||||
[base64url](https://datatracker.ietf.org/doc/html/rfc4648#section-5)
|
||||
|
||||
- `&c=...`
|
||||
- the rightmost 8 bytes of SHA256 over the transaction. Also `base64url` encoded.
|
||||
|
||||
- `&n=XTN`
|
||||
- if, and only if, the COLDCARD is set for Testnet, this value is appended to
|
||||
indicate that the transaction is for Testnet3 and not MainNet.
|
||||
- when RegTest is enabled, the value will be `XRT`
|
||||
|
||||
We provide a few default URL values to our customers, including one backend we
|
||||
will operate on `coldcard.com`. The URL can also be directly entered by the
|
||||
customer. On the Q, it can be scanned from a QR code.
|
||||
|
||||
For COLDCARD backend, the url used is:
|
||||
|
||||
https://coldcard.com/pushtx#
|
||||
|
||||
The complete URL with a typical transaction might look like this (but longer):
|
||||
|
||||
https://coldcard.com/pushtx#t=AgAAAAMNCxXtp2GVYVhkRXHLMmdZFs4p3kbFK ⋯ ABf&c=uiSVRda-1tw
|
||||
|
||||
We are using hash symbol here so that our server logs do not get
|
||||
contaminated with the arguments. The landing page uses javascript
|
||||
to read the hash part of the URL and decodes from there. If you
|
||||
prefer, your URL can end with `?` and then the arguments will be
|
||||
sent by the phone's browser to your server. Your processing can be
|
||||
entirely done in the backend in this case.
|
||||
|
||||
## Expectations for the Backend
|
||||
|
||||
Your code should decode the transaction and check the SHA-256 hash
|
||||
matches. If it does not match, or if `c` value is missing, assume
|
||||
the URL has been truncated and report that to the user.
|
||||
|
||||
Once decoded, your code should immediately broadcast the transaction.
|
||||
A confirmation step is not required in our opinion. Once it is
|
||||
submitted to Bitcoin Core (or other API), any status response should
|
||||
be decoded and shown to the user so they know it is on it's way.
|
||||
If it was not accepted, please report the error to the user as
|
||||
clearly as possible.
|
||||
|
||||
Next, it would make sense to either link to the TXID on a block
|
||||
explorer to provide further proof that it has been sent and that
|
||||
it is now waiting in the mempool.
|
||||
|
||||
## Backend Implementations
|
||||
|
||||
- Mempool.space's [implementation of this feature](https://github.com/mempool/mempool/pull/5132).
|
||||
|
||||
- A single-file (html and javascript) file is available
|
||||
at [coldcard.com/static/coldcard-pushtx.html](https://coldcard.com/static/coldcard-pushtx.html).
|
||||
You can host this file anywhere your phone can reach, and then use that URL in your
|
||||
COLDCARD settings. It uses your phone's browser to submit directly
|
||||
to `mempool.space` and `blockstream.info` sites (both at same time). It is equivalent
|
||||
to the page hosted at `https://coldcard.com/pushtx#`. Full source code is published here:
|
||||
[github.com/Coldcard/push-tx](https://github.com/Coldcard/push-tx)
|
||||
|
||||
### Notes
|
||||
|
||||
- Complete URL might be as large as 8,000 bytes. Some web servers will not support beyond
|
||||
4k bytes and the NFC implementation of the phone may also have limits.
|
||||
- The service URL provided must end in `?` or `#` or `&`.
|
||||
- `base64url` values from COLDCARD will not have padding (`=` bytes) at end.
|
||||
- POST cannot be used directly because the expect the phone to do a GET on the URL provided.
|
||||
- Honest backends will not log the IP address of incoming transactions, but there is
|
||||
no way to enforce that, and CloudFlare sees all.
|
||||
|
||||
## Example URL
|
||||
|
||||
```
|
||||
https://mempool.space/pushtx#t=AgAAAAOHqK3w3hC6PSC0buthnJA5R9Y88WAlEvm9cifNVUPhIwAAAABqRzBEAiB-M9YprNYoohqHdQHg4wY_qcEMwDmyIQH8prykk8-0KwIgARxcojKrtixicouiUxhk4jQq_MAl11ptIgHDlRjgk5ABIQM4bgMAVDbDSr_9CvLjbg5nxrWnDGI-kVmkfL81GXZtCf____8OaH0RxW7DjZKdIF6rvbHvvyFGCBQ0PTgpx20nA_wbLgAAAABqRzBEAiBwUFigORJDPK8ptnYPAntjV-RUn1jAuzphicQstwVv-QIgEbMC8FWXQ5Jve5DaAqKJsqoj3peK83iub_oOkmbiYg4BIQO5Ehn2t0oUG3hnK4cBnwCwMc33DcdJ8aSMWzRQ_wjZL_____-UG6M-eBeAun-EZp6EbVypvVJ3mXCQrN_fUDn-kwoEnQAAAABqRzBEAiAgFAtVTpQYTKplc9NuV7Ws7ZFYeNO8BCS4ozgWrgd2ogIgGTTcw98xQdcGWeWQhVfVm_vZorBIOYovQPQeK0Lg9t8BIQLPWPioVWvj1z4NMHBCkeirYOUalCa83wbSH0CREnGZvv____8CjM_wCAAAAAAZdqkUIJA8_yqzaj0NzhvYVEIBno5gETGIrIzP8AgAAAAAGXapFEaV7xTyleuEX9OejdlUlsz7RTr0iKwAAAAA&c=hre47vyMC78&n=XTN
|
||||
```
|
||||
|
||||
- this transaction doesn't have valid inputs, and will cause an error
|
||||
- mempool.space will redirect this to a testnet endpoint (because ends with `n=XTN`)
|
||||
|
||||
|
||||
BIN
docs/nfc-tap-locations.png
Normal file
|
After Width: | Height: | Size: 258 KiB |
@ -11,11 +11,17 @@ The entrypoint makefile for repro builds.
|
||||
The `repro` command in `shared.mk` is the first step in the repro build process, which triggers a docker build and run process.
|
||||
|
||||
```makefile
|
||||
repro: submods-match code-committed
|
||||
repro:
|
||||
docker build -t coldcard-build - < dockerfile.build
|
||||
(cd ..; docker run $(DOCK_RUN_ARGS) sh src/stm32/repro-build.sh $(VERSION_STRING) $(MK_NUM))
|
||||
(cd ..; docker run $(DOCK_RUN_ARGS) sh src/stm32/repro-build.sh $(VERSION_STRING) $(HW_MODEL) $(PARENT_MKFILE))
|
||||
```
|
||||
|
||||
`$(HW_MODEL)` is the model string (e.g. `mk4`, `q1`) and `$(PARENT_MKFILE)` is the
|
||||
top-level makefile being used (`MK-Makefile` or `Q1-Makefile`). The `submods-match`
|
||||
and `code-committed` prerequisites ensure the submodules and working tree are clean
|
||||
before a repro build.
|
||||
|
||||
Below are interesting sections from the docker logs that give an idea as to what is going on in build process:
|
||||
|
||||
```stdout
|
||||
@ -61,19 +67,19 @@ Successfully installed signit-1.0
|
||||
|
||||
...
|
||||
|
||||
+ make -f MK4-Makefile setup
|
||||
+ make -f MK-Makefile setup
|
||||
|
||||
...
|
||||
|
||||
+ make -f MK4-Makefile firmware-signed.bin firmware-signed.dfu production.bin dev.dfu firmware.lss firmware.elf
|
||||
+ make -f MK-Makefile firmware-signed.bin firmware-signed.dfu production.bin dev.dfu firmware.lss firmware.elf
|
||||
|
||||
...
|
||||
|
||||
signit sign -b l-port/build-COLDCARD_MK4 -m 4 5.0.7 -o firmware-signed.bin
|
||||
signit sign -b l-port/build-COLDCARD_MK4 -m mk4 5.0.7 -o firmware-signed.bin
|
||||
|
||||
...
|
||||
|
||||
signit sign -m 4 5.0.7 -r firmware-signed.bin -k 1 -o production.bin
|
||||
signit sign -m mk4 5.0.7 -r firmware-signed.bin -k 1 -o production.bin
|
||||
You don't have that key (1), so using key zero instead!
|
||||
...
|
||||
|
||||
@ -96,7 +102,7 @@ production.bin
|
||||
|
||||
...
|
||||
|
||||
+ make -f MK4-Makefile 'PUBLISHED_BIN=/tmp/checkout/firmware/releases/2022-10-05T1724-v5.0.7-mk4-coldcard.dfu' check-repro
|
||||
+ make -f MK-Makefile 'PUBLISHED_BIN=/tmp/checkout/firmware/releases/2022-10-05T1724-v5.0.7-mk4-coldcard.dfu' check-repro
|
||||
|
||||
...
|
||||
|
||||
@ -183,7 +189,7 @@ To summarize `check-repro`:
|
||||
|
||||
- `split` (cli/signit.py: Line 153-175) is run against the release `*.dfu` resulting in a `check-fw.bin` and `check-bootrom.bin`. "This splits the DFU file into the two parts it contains: the main firmware (COLDCARD application) and the boot loader code."
|
||||
|
||||
- `check` (cli/signit.py: Line 176-241) is run against each the release `check-fw.bin` and our built `firmware-signed.bin`.
|
||||
- `check` (cli/signit.py: Line 176-243) is run against each the release `check-fw.bin` and our built `firmware-signed.bin`.
|
||||
|
||||
- a hexdump is taken of each the release `check-fw.bin` and our built `firmware-signed.bin` piped through $TRIM_SIG which removes 64 bytes of signature data and subsitutes it with a common string.
|
||||
|
||||
|
||||
@ -183,12 +183,12 @@ This double-hashed value is what's stored inside the secure element
|
||||
as it travels on the bus. Because of the inclusion of the pairing
|
||||
secret, the hashes generated by each Coldcard will be different.
|
||||
|
||||
With Mark3 hardware, we've added a key-streching step, which starts
|
||||
With Mark3 hardware, we've added a key-stretching step, which starts
|
||||
with the above value, and does HMAC-SHA256 using a secret key known
|
||||
only to the 608a (repeatedly). That value is used directly to check the
|
||||
duress PIN, and if that doesn't match, it is HMAC-SHA256'ed again,
|
||||
using a key that is usage limited. This limits actual PIN login attempts
|
||||
to a set value and is enfoced by the 608a internally.
|
||||
to a set value and is enforced by the 608a internally.
|
||||
|
||||
## Genuine vs. Caution Lights
|
||||
|
||||
@ -281,7 +281,7 @@ Here's what the warning screen looks like:
|
||||
|
||||
### Benefits
|
||||
|
||||
- no warnings, but still trustable thanks to ATECC608A
|
||||
- no warnings, but still trustable thanks to ATECC608
|
||||
- random devs can replace 99% of firmware at Micropython layer (everything but bootloader)
|
||||
- but they need to retain our code for talking to bootloader and secure element,
|
||||
so that PIN can be entered and verified.
|
||||
|
||||
112
docs/proof-of-reserves-bip-322.md
Normal file
@ -0,0 +1,112 @@
|
||||
# BIP-322 Generic Signed Message Format
|
||||
|
||||
BIP-322 specification: <https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki>
|
||||
|
||||
## Proof of Reserves (POR)
|
||||
|
||||
### PoR PSBT
|
||||
|
||||
COLDCARD accepts a specially crafted PSBT file to sign as BIP-322 Proof of Reserves. The PSBT
|
||||
must meet all these requirements:
|
||||
|
||||
* COLDCARD acts as a BIP-322 PSBT signer. It validates the BIP-322 `to_sign`
|
||||
transaction, shows the message from `PSBT_GLOBAL_GENERIC_SIGNED_MESSAGE`, and
|
||||
adds signatures to the PSBT. Finalizing and encoding the final BIP-322
|
||||
signature string is the responsibility of the finalizer.
|
||||
* PSBT MUST include `PSBT_GLOBAL_GENERIC_SIGNED_MESSAGE = 0x09`; the value is
|
||||
the exact message shown to the user and signed by BIP-322.
|
||||
* PSBT requires `PSBT_IN_BIP32_DERIVATION` for each input
|
||||
* P2SH wrapped segwit addresses MUST have proper redeem script in PSBT: `PSBT_IN_REDEEM_SCRIPT`
|
||||
* P2WSH segwit addresses MUST have proper witness script in PSBT: `PSBT_IN_WITNESS_SCRIPT`
|
||||
* PSBT (`to_sign`) MUST have at least one input.
|
||||
* First (0th) input of `to_sign` MUST spend the BIP-322 `to_spend` output.
|
||||
* Input 0 MUST include one of `PSBT_IN_NON_WITNESS_UTXO` or `PSBT_IN_WITNESS_UTXO`.
|
||||
* When input 0 provides `PSBT_IN_WITNESS_UTXO`, COLDCARD reconstructs the
|
||||
expected `to_spend` txid from `PSBT_GLOBAL_GENERIC_SIGNED_MESSAGE` and the
|
||||
witness UTXO scriptPubKey.
|
||||
* When input 0 provides `PSBT_IN_NON_WITNESS_UTXO`, it MUST be the BIP-322
|
||||
`to_spend` transaction as defined in
|
||||
[BIP-322](https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki#full):
|
||||
* 1 input, 1 output
|
||||
* output nValue is 0
|
||||
* input prevout hash is 0
|
||||
* input prevout n is 0xffffffff
|
||||
* input scriptSig is `OP_0 PUSH32 message_hash`
|
||||
* PSBT (`to_sign`) MUST only have one output with null-data `OP_RETURN`
|
||||
* `to_sign` transaction version MUST be 0 or 2.
|
||||
* Optionally inputs can be added to `to_sign` for Proof of Reserve signing.
|
||||
* PSBT MUST be version 0 or 2.
|
||||
* Foreign inputs not allowed in POR PSBT.
|
||||
|
||||
The signatures created by the BIP-322 process will never be suitable
|
||||
for a on-chain Bitcoin transaction that could move funds, because
|
||||
of these restrictions imposed by BIP-322.
|
||||
|
||||
### Output
|
||||
|
||||
COLDCARD always returns a signed PSBT for BIP-322 message signing and Proof of
|
||||
Reserves. It never returns an extracted/finalized transaction for these PSBTs.
|
||||
This is true even when finalization is requested over USB, such as with
|
||||
`ckcc unsigned.psbt --finalize`.
|
||||
|
||||
The signed PSBT is the handoff artifact for the external finalizer/verifier. It
|
||||
keeps the PSBT metadata needed to verify or finalize the BIP-322 signature,
|
||||
including public keys, scripts, partial signatures, and UTXO data. This matters
|
||||
because the address being proven normally commits only to a hash of the public
|
||||
key or script, not the public key or script itself.
|
||||
|
||||
### Proof of Reserves Signing Experience
|
||||
|
||||
After Coldcard recognizes a BIP-322 PSBT it reads the message from
|
||||
`PSBT_GLOBAL_GENERIC_SIGNED_MESSAGE` and shows it to the user for approval.
|
||||
COLDCARD verifies that the message hash matches the input 0 `to_spend`
|
||||
commitment before offering to sign.
|
||||
|
||||
When the PSBT contains only input 0, COLDCARD labels the request as
|
||||
`BIP-322 Message`, because it is message signing and does not prove ownership
|
||||
of any additional reserve UTXOs. In that case it does not show transaction
|
||||
input/output counts. When the PSBT contains additional inputs, COLDCARD labels
|
||||
the request as `Proof of Reserves` and shows the reserve amount.
|
||||
|
||||
If the message contains non-ASCII characters, COLDCARD warns that some
|
||||
characters may not be readable on screen.
|
||||
|
||||
Legacy PoR PSBTs without `PSBT_GLOBAL_GENERIC_SIGNED_MESSAGE` are rejected by
|
||||
this flow.
|
||||
|
||||
Read more [here.](https://gist.github.com/orangesurf/0c1d0a31d3ebe7e48335a34d56788d4c)
|
||||
|
||||
Example screen text for a one-input BIP-322 message signing PSBT:
|
||||
|
||||
```text
|
||||
BIP-322 Message
|
||||
|
||||
Message:
|
||||
This is the signed message
|
||||
|
||||
Challenge Address:
|
||||
bc1qzvjnhf7k70uxv6xvneaqxql7k09dd6nsr5wheq
|
||||
|
||||
Press ENTER to approve and sign message. Press (2) to explore transaction.
|
||||
CANCEL to abort.
|
||||
```
|
||||
|
||||
Example screen text for a Proof of Reserves PSBT:
|
||||
|
||||
```text
|
||||
Proof of Reserves
|
||||
|
||||
Message:
|
||||
POR
|
||||
|
||||
Amount 0.20000000 BTC
|
||||
|
||||
Challenge Address:
|
||||
bc1qzvjnhf7k70uxv6xvneaqxql7k09dd6nsr5wheq
|
||||
|
||||
21 inputs
|
||||
1 output
|
||||
|
||||
Press ENTER to approve and sign proof of reserves. Press (2) to explore transaction.
|
||||
CANCEL to abort.
|
||||
```
|
||||
@ -2,9 +2,9 @@
|
||||
|
||||
## Background
|
||||
|
||||
The Mk4 **COLDCARD<sup>®</sup>** has two secure elements:
|
||||
The **COLDCARD<sup>®</sup>** Mk4 and Q have two secure elements:
|
||||
|
||||
- SE1 (Secure Element 1): Microchip ATECC608B
|
||||
- SE1 (Secure Element 1): Microchip ATECC608
|
||||
- SE2 (Secure Element 2): Maxim DS28C36B
|
||||
|
||||
Because different vendors make them, they do not share bugs and weaknesses.
|
||||
@ -20,15 +20,13 @@ HMAC-SHA256.
|
||||
|
||||
Assume attackers have physical access to a COLDCARD, have opened
|
||||
the case, and can probe the bus connections between the MCU and SE1
|
||||
or SE2. They may even desolder SE1 and SE2 from the board, and put
|
||||
active circuits between them and the MCU — an active MiTM
|
||||
attack. (The Mk4 has improved goop on all three parts and all these
|
||||
critical signals run on internal layers of the PCBA.)
|
||||
or SE2. They may even de-solder SE1 and SE2 from the board, and put
|
||||
active circuits between them and the MCU — an active MiTM attack.
|
||||
|
||||
|
||||
### The Solutions
|
||||
|
||||
Three parties hold secrets in the Mk4: the main MCU (microcontroller)
|
||||
Three parties hold secrets in the COLDCARD: the main MCU (microcontroller)
|
||||
and the two secure elements. Our goal is that **all three** must
|
||||
be fully compromised to access the seed words. Thus, if one part
|
||||
has a vulnerability, the COLDCARD as a whole is still secure.
|
||||
@ -37,7 +35,7 @@ if all three devices are cracked wide open. (This is a last line
|
||||
of defence, a brute-force attack on all PIN combinations will breach
|
||||
it.)
|
||||
|
||||
The Mk4 also supports new Trick PIN codes with side effects such
|
||||
COLDCARD also supports new Trick PIN codes with side effects such
|
||||
as wiping or bricking the COLDCARD, or providing access to a decoy
|
||||
or duress wallet. Ideally, attackers will not detect using a false
|
||||
PIN, even while probing the signals on the board.
|
||||
@ -53,7 +51,7 @@ and the MicroPython code cannot read this area of the chip. Using
|
||||
an internal firewall feature and PCROP (proprietary code readout
|
||||
protection) achieves this result.
|
||||
|
||||
Mk4 also shares a secret between SE2 and the MCU. Just like SE1,
|
||||
COLDCARD also shares a secret between SE2 and the MCU. Just like SE1,
|
||||
this authenticates SE2 to the MCU and encrypts their mutual
|
||||
communications. The Pairing Secret for SE2 is not stored in SE1 and
|
||||
is unique from the other Pairing Secret used for SE1.
|
||||
@ -94,8 +92,8 @@ increases flexibility and resistance to known plain text attacks.
|
||||
| `pin stretch` | slot 2 | HMAC | SE1 | Key stretching for PIN entry and anti-phish words
|
||||
| `firmware` | slot 14 | SHA256d | SE1 | Firmware checksum, controls green/red LEDs
|
||||
| `nonce/chksum` | slot 10 | data | SE1 | AES nonce and GMAC tag, protected by PIN
|
||||
| `SE2 easy key` | page 15 | AES via HMAC | SE2 | Another SE2 part of AES seed key
|
||||
| `SE2 hard key` | page 14 | AES via ECC | SE2 | SE2's part of AES seed key; ECC used to unlock
|
||||
| `SE2 easy key` | page 14 | AES via HMAC | SE2 | Another SE2 part of AES seed key
|
||||
| `SE2 hard key` | page 15 | AES via ECC | SE2 | SE2's part of AES seed key; ECC used to unlock
|
||||
| `tpin key` | `tpin_key` | HMAC(key) | MCU | Key for HMAC used to encrypt trick PINs
|
||||
| `trick PIN slots` | pages 0-12 | HMAC | SE2 | Protect duress wallet seeds and pins (6 spots)
|
||||
| `SE2 trash` | secret B | HMAC | SE2 | Used to destroy values (only SE2 knows the value)
|
||||
@ -195,7 +193,7 @@ user enters against all the slots and works silently to support the
|
||||
Trick features.
|
||||
|
||||
The type of support depends on the type of Trick. Duress wallets
|
||||
require storing 32 bytes of seed words (generated from the true
|
||||
require storing 32 or 64 bytes of seed words (generated from the true
|
||||
seed via BIP-85). Other cases dictate encoding a short numeric code
|
||||
provided to higher layers for implementation. For example, a flag
|
||||
in that code can trigger the boot ROM to wipe the `mcu seed key`.
|
||||
@ -206,7 +204,8 @@ key` being zero makes the seed permanently inaccessible.
|
||||
|
||||
The MCU code may continue speaking to SE1 to complete the fraud,
|
||||
but in general, SE1 will no longer store the duress wallet or Brick
|
||||
Me PINs. Mk4 implements those feature in SE2.
|
||||
Me PINs as in previous generations (Mk1-3). Mk4 and Q implement
|
||||
those feature in SE2.
|
||||
|
||||
|
||||
### Trick PIN Operation
|
||||
@ -268,7 +267,7 @@ inside SE1. This storage is called Spare Secrets. Spare Secrets has
|
||||
3 × 72 bytes of space, protected by the same measures as the
|
||||
seed words.
|
||||
|
||||
Mk4 still supports the Long Secret (416 bytes), but its API is
|
||||
Mk4/Q still supports the Long Secret (416 bytes), but its API is
|
||||
changed. The slow speed of fetching the Long Secret in 32-byte
|
||||
blocks due to the reconstructing the primary AES Seed Key for each
|
||||
call necessitated the change.
|
||||
@ -292,7 +291,7 @@ PINs that continue operation (duress PINs), unlike the average thug.
|
||||
|
||||
## Fast Brick
|
||||
|
||||
On the Mk4, quickly bricking the system is done by rotating the SE1
|
||||
Quickly bricking the system is done by rotating the SE1
|
||||
pairing secret by mixing in a random nonce via the chip's key
|
||||
rotation process. Only a knowledge of the old pairing secret is
|
||||
needed for this change. This is similar the to `brick_me` PIN
|
||||
@ -1,4 +1,4 @@
|
||||
# COLDCARD Mk4 Security Model
|
||||
# COLDCARD Mk4/Mk5/Q Security Model
|
||||
|
||||
## Abstract
|
||||
|
||||
@ -8,11 +8,14 @@ seed words used to generate a deterministic wallet. This secure
|
||||
element is in a limited and read-only state until authorized by PIN entry.
|
||||
|
||||
Clearing the secure element is impossible without first entering
|
||||
the correct PIN. The Mark 4 COLDCARD (Mk4) introduces several new
|
||||
security features, including a second secure element and Trick PINs
|
||||
which can render stored data unrecoverable, or brick the COLDCARD
|
||||
entirely if necessary, without entering the true authorization PIN
|
||||
(True PIN).
|
||||
the correct PIN. The Mk4 COLDCARD introduced several new security
|
||||
features, including a second secure element and Trick PINs which
|
||||
can render stored data unrecoverable, or brick the COLDCARD entirely
|
||||
if necessary, without entering the true authorization PIN (True
|
||||
PIN).
|
||||
|
||||
The COLDCARD Q continues with the same security model introduced
|
||||
in Mk4.
|
||||
|
||||
|
||||
## Introduction
|
||||
@ -22,7 +25,7 @@ the Microchip ATECC508A and later the ATECC608B, to store its
|
||||
secrets. This secure element has 72 bytes of storage protected by
|
||||
a 4- to 12-digit PIN code.
|
||||
|
||||
Mk4 adds a second secure element to the COLDCARD. The ATECC608B is
|
||||
Mk4 adds a second secure element to the COLDCARD. The ATECC608 is
|
||||
still used, now called SE1 (Secure Element 1), along with a new
|
||||
chip, the Maxim DS28C36B, called SE2 (Secure Element 2). The
|
||||
DS28C36B (SE2) has more memory with fifteen 32-byte slots of secure
|
||||
@ -93,9 +96,10 @@ user entered the True PIN. An attacker will only have access to the
|
||||
duress wallet. They won't have access to steal the main stash.
|
||||
|
||||
The private key can be automatically derived using BIP-85 methods,
|
||||
based on account numbers 1001, 1002, or 1003. Because this is BIP-85
|
||||
based and uses a 24-word seed, it behaves exactly like a normal
|
||||
wallet. Defining a passphrase for the wallet is also possible.
|
||||
based on account numbers 1001, 1002, or 1003 for a 24-word duress wallet
|
||||
(or 2001, 2002, 2003 for a 12-word one). Because this is BIP-85
|
||||
based, it behaves exactly like a normal wallet. Defining a passphrase
|
||||
for the wallet is also possible.
|
||||
|
||||
The Mk4 also supports older COLDCARD duress wallets and their UTXOs
|
||||
on the blockchain. There is an option to create compatible wallets
|
||||
@ -187,9 +191,9 @@ customers suggested.
|
||||
|
||||
### Kill Key Feature
|
||||
|
||||
This feature allows the user to execute a Fast Wipe when the
|
||||
anti-phishing words are displayed on the screen. This feature is
|
||||
turned off by default.
|
||||
On the Mk4, this feature allows the user to execute a Fast Wipe
|
||||
when the anti-phishing words are displayed on the screen. This
|
||||
feature is turned off by default.
|
||||
|
||||
The user sets a particular key number to trigger Fast Wipe. If that
|
||||
key is pressed while viewing the anti-phishing words, the seed is
|
||||
@ -200,13 +204,19 @@ It is strongly recommended that the first digit for the second half
|
||||
of the True PIN is **not** used as the Kill Key. Missing a step
|
||||
would unintentionally wipe the seed.
|
||||
|
||||
For the COLDCARD Q, the same feature exists: any letter may be
|
||||
specified but numbers are not supported. This change allows the
|
||||
"kill button" to be active through-out the entire login process.
|
||||
It can be even be pressed while the nickname is shown, and at any
|
||||
point during the PIN entry.
|
||||
|
||||
|
||||
### SPI Serial Flash Removed
|
||||
|
||||
The Mk3 and earlier had a dedicated, external chip to hold settings
|
||||
and the PSBT during operation. Mk4 does not have that chip. The
|
||||
settings now reside inside the main MCU, increasing security.
|
||||
Settings are still AES-encrypted as before.
|
||||
and the PSBT during operation. Mk4 and later, do not have that
|
||||
chip. The settings now reside inside the main MCU, increasing
|
||||
security. Settings are still AES-encrypted as before.
|
||||
|
||||
The separate settings chip could be blanked externally or even
|
||||
removed/replaced. This possibility might enable getting around
|
||||
@ -234,11 +244,11 @@ COLDCARD's case to do so, but the option is there if needed.
|
||||
|
||||
## SD Card Recovery Mode
|
||||
|
||||
Mk4 bootloader is smart enough to be able to read an SD card. You
|
||||
Mk4/Mk5/Q bootloader is smart enough to be able to read an SD card. You
|
||||
will only be able to trigger the SD card loading code, if the
|
||||
COLDCARD was powered down during the upgrade process. At that point,
|
||||
the intended firmware image has been lost because it it held in
|
||||
PSRAM only during the flash writing process. The bootloader knows
|
||||
PSRAM only, during the flash writing process. The bootloader knows
|
||||
main flash (ie. Micropython code) is corrupt because it fails the
|
||||
checksum check (and/or signature check).
|
||||
|
||||
@ -256,6 +266,9 @@ If any other parts of flash---beyond the normal upgradable firmware
|
||||
area---have also been corrupted, this process will not work and the
|
||||
unit will be a brick.
|
||||
|
||||
On the COLDCARD Q, only the top slot (A) is supported for this
|
||||
operation.
|
||||
|
||||
|
||||
## Flash ECC (Error Detection/Correction Codes)
|
||||
|
||||
@ -274,7 +287,7 @@ that it's an attack, such as exposing the bare die to targeted UV-C
|
||||
radiation. If the attacker is able to flip 2 or more bits, then
|
||||
this will effectively brick the COLDCARD once the ECC error is detected.
|
||||
|
||||
Critical flash cells, such as those that prevent both JTAG access,
|
||||
are not a single bit (it's a special bit pattern), and regardless
|
||||
are protected via ECC the same as other flash cells.
|
||||
Critical flash cells, such as those that prevent JTAG access, are
|
||||
not a single bit (it's a special bit pattern), and regardless are
|
||||
protected via ECC the same as other flash cells.
|
||||
|
||||
@ -12,7 +12,7 @@ are not discrete and you could be compelled to produce the passphrase.
|
||||
|
||||
Enter [_Seed XOR_](https://seedxor.com), a plausibly deniable means
|
||||
of storing secrets in two or more parts that look and behave just
|
||||
like the original secret. One 12 or 24-word seed phrase becomes two or more parts
|
||||
like the original secret. One 12-, 18-, or 24-word seed phrase becomes two or more parts
|
||||
that are also BIP-39 compatible seeds phrases. These should be backed up in your
|
||||
preferred method, metal or otherwise. These parts can be individually loaded
|
||||
with honeypot funds as each one has same word length, with the last being
|
||||
@ -22,7 +22,7 @@ This one more solution for your game-theory arsenal.
|
||||
|
||||
- *Q*: I'm lazy, can I do this to my Existing Seed?
|
||||
- *A*: Yes. You can split the words you have already in your Coldcard, making
|
||||
2, 3 or 4 new SEEDPLATES. You could also any number of existing SEEDPLATES
|
||||
2, 3 or 4 new SEEDPLATES. You could also use any number of existing SEEDPLATES
|
||||
you have, and combine them to make a new random wallet that is the XOR of
|
||||
their values. Effectively that makes a new random wallet.
|
||||
|
||||
@ -78,10 +78,12 @@ words right the next day.
|
||||
|
||||
When the parts are made deterministically, we take a double-SHA256 over
|
||||
a fixed string (`Batshitoshi`), your master secret, and the text
|
||||
`1 of 4 parts` which changes for each part.
|
||||
`0 of 4 parts` which changes for each part (the index is 0-based).
|
||||
|
||||
In random mode, we simply pick 32 random bytes (and then double-SHA256
|
||||
them) from the Coldcard's True Random Number Generator (TRNG)..
|
||||
In random mode, we simply pick random bytes (and then double-SHA256
|
||||
them) from the Coldcard's True Random Number Generator (TRNG). The number
|
||||
of bytes matches your secret length: 16, 24, or 32 bytes for a 12-, 18-,
|
||||
or 24-word seed respectively.
|
||||
|
||||
This is done to make all but the one part. The final part is the
|
||||
value needed to get back to your secret, so it's the XOR of the
|
||||
@ -157,6 +159,12 @@ with the others on a SEEDPLATE.
|
||||
- right to A, down to B ... take that number, and go to that column
|
||||
- down to C, that is answer: a ⊕ b ⊕ c
|
||||
|
||||
## Open Standard
|
||||
Seed XOR is an open standard. Other software and hardware wallets are encouraged to
|
||||
implement support. No license or permission is required, including usage of the term
|
||||
"Seed XOR" when referring to implementations of this feature. Such implementations
|
||||
should match the process described in this documentation and be fully interoperable.
|
||||
|
||||
---
|
||||
|
||||
# 24 Words XOR Seed Example Using 3 Parts
|
||||
|
||||
209
docs/spending-policy.md
Normal file
@ -0,0 +1,209 @@
|
||||
# Spending Policy
|
||||
|
||||
This special mode will stop you from signing transactions if they
|
||||
exceed a spending policy you define beforehand. Once enabled, many
|
||||
features of the COLDCARD are disabled or inaccessible.
|
||||
|
||||
You might want to use this feature when traveling with your COLDCARD.
|
||||
|
||||
## Spending Policy: Multisig (formerly CCC)
|
||||
|
||||
We also support a mode where the COLDCARD is a multisig co-signer
|
||||
and only performs its signature when a spending policy is met. The
|
||||
other multisig signers are free to sign or not sign as appropriate.
|
||||
|
||||
Multisig mode is more advanced and requires use of multisig addresses,
|
||||
new UTXO, and cooperating multisig on-chain wallets.
|
||||
|
||||
This document will only discuss the "Single signer" version of
|
||||
Spending Policy. Both modes can be active at the same time, but if
|
||||
a transaction would be signed by Multisig policy, then we assume
|
||||
it's also okay to sign your main key as well.
|
||||
|
||||
# Before You Start
|
||||
|
||||
When a Spending Policy is in effect, there are limitations
|
||||
in effect:
|
||||
|
||||
- Firmware updates are blocked.
|
||||
- There is no way to backup the COLDCARD.
|
||||
- Seed vault and Secure Notes are read-only (and can also be hidden).
|
||||
- Settings menu is inaccessible.
|
||||
- BIP-39 passphrases may be blocked (optional).
|
||||
|
||||
We recommend getting the COLDCARD fully configured and setup
|
||||
for typical transactions before enabling the Spending Policy.
|
||||
|
||||
# Setup Spending Policy
|
||||
|
||||
Visit `Advanced / Tools > Spending Policy` menu and choose
|
||||
"Single-Signer". First some background information is shown,
|
||||
then you are prompted to define the "Bypass PIN". This PIN code
|
||||
is only used when you need to disable the spending policy, but is
|
||||
also the only way to do so once enabled... so don't loose it.
|
||||
|
||||
Once the "Bypass PIN" is confirmed, you will arrive at menu for
|
||||
related settings. Use "Edit Policy..." to change the spending policy
|
||||
and define a Max Magnitude (limit number of BTC per transaction),
|
||||
Velocity (minimum time gaps between signed transactions). You can
|
||||
define a whitelist of up to 25 destination addresses (leave empty
|
||||
for any). Finally you can enroll your phone in 2FA (second factor)
|
||||
so that you must open an Authenticator app on your phone before
|
||||
transactions are signed.
|
||||
|
||||
## Other Security Settings
|
||||
|
||||
In addition to policy itself, there are a number of on/off
|
||||
switches which affect operation of the COLDCARD while the Spending
|
||||
Policy is in effect:
|
||||
|
||||
### Word Check
|
||||
|
||||
If enabled, you will have to enter the first and last seed word
|
||||
after the Bypass PIN as an additional security check.
|
||||
|
||||
### Allow Notes
|
||||
|
||||
On the Q, secure notes and passwords may be visible or hidden
|
||||
using this setting. In either case they are strictly readonly.
|
||||
|
||||
### Related Keys
|
||||
|
||||
BIP-39 passphrase entry, Seed Vault usage will be blocked unless this
|
||||
setting is enabled. Even when enabled, the Seed Vault is always readonly
|
||||
and cannot be changed.
|
||||
|
||||
# Other Menu Items
|
||||
|
||||
## Last Violation
|
||||
|
||||
If you have recently tried and failed to sign a transaction, the
|
||||
reason for the transaction being rejected can be viewed and cleared,
|
||||
using menu item "Last Violation". It is shown only if a Spending
|
||||
Policy violation (attempt) has occurred since the last valid signing.
|
||||
|
||||
This is meant as a debugging tool, and the information stored is
|
||||
terse.
|
||||
|
||||
## Remove Policy
|
||||
|
||||
This will remove your spending policy completely and remove
|
||||
the Bypass PIN. Your COLDCARD will be back to normal.
|
||||
|
||||
## Test Drive
|
||||
|
||||
Experiment with how the COLDCARD will function if the Spending
|
||||
Policy was enabled. You can try to sign transactions that should
|
||||
be rejected and view the menus in the new mode without rebooting.
|
||||
|
||||
Choose "EXIT TEST DRIVE" on top menu to return to the Spending
|
||||
Policy menu. Reboot will also restore normal operation without
|
||||
any special challenges.
|
||||
|
||||
## ACTIVATE
|
||||
|
||||
This step will enable the Spending Policy and return to the
|
||||
main menu with it in effect. When you reboot the COLDCARD,
|
||||
the policy will still be in effect. You must use the
|
||||
Bypass PIN, followed by the normal main PIN, possibly
|
||||
followed by entering the first and last words of your seed
|
||||
phrase, before you can disable and change the policy.
|
||||
|
||||
We recommend test-driving the feature before doing that.
|
||||
|
||||
|
||||
# Tips and Tricks
|
||||
|
||||
## Money Manager Mode
|
||||
|
||||
You could setup a Coldcard for another person, perhaps a family member,
|
||||
and enable web 2FA authentication. There does not need to be any
|
||||
other spending policy limits (velocity could be unlimited).
|
||||
|
||||
Then enroll your own phone with the required 2FA values, and
|
||||
keep both that and the spending policy bypass PIN confidential.
|
||||
|
||||
The holder the the Coldcard will need a 2FA code from your phone
|
||||
when they want to spend. They can call you for the 6-digit code
|
||||
from the 2FA app on your phone. This is not hard to provide over a
|
||||
voice call.
|
||||
|
||||
Because a spending policy is in effect, they will not be able to
|
||||
see the seed words, other private key material, so regardless of
|
||||
any spoofing or phishing, they cannot move funds without your help.
|
||||
|
||||
You should record the bypass PIN, so it can be revealed somehow,
|
||||
should you die. You do not need to share the risks associated with
|
||||
holding a copy of the seed words.
|
||||
|
||||
## Passphrase Considerations
|
||||
|
||||
If you are using the same BIP-39 passphrase for everything, you should
|
||||
probably do a "Lock Down Seed" (Advanced/Tools > Danger Zone > Seed
|
||||
Functions) first. This takes your master seed and BIP-39 passphrase
|
||||
and cooks them together into an XPRV which then is stored as your
|
||||
master secret. (Replacing the master seed phrase.) This process
|
||||
cannot be reversed, so other funds you may have on the same seed
|
||||
words are protected. Once you are operating in XPRV mode, you can
|
||||
define a spending policy, and know that it is restricted to only
|
||||
that wallet.
|
||||
|
||||
When operating in XPRV mode, the "Passphrase" menu item is not shown
|
||||
because BIP-39 passwords cannot be applied to XPRV secrets.
|
||||
|
||||
## Trick PIN Thoughts
|
||||
|
||||
When doing your game theory w.r.t to bypass mode and this feature,
|
||||
remember that you should assume the attacker already has your main
|
||||
PIN. That's how they know they cannot spend all your coin, because
|
||||
they either tried to, or noticed the menus are very limited. They also
|
||||
have all your UTXO locations and total wallet balance (because they
|
||||
can export your xpubs to any wallet and load balance from there).
|
||||
|
||||
Therefore, a trick pin that leads to a duress wallet after giving up
|
||||
the bypass unlock PIN, will not fool them. Best would be to provide
|
||||
a false bypass PIN that is in fact a brick/wipe PIN.
|
||||
|
||||
|
||||
## Lock Out Changes to Policy
|
||||
|
||||
In the Trick Pin menu once Spending Policy has been enabled, you will
|
||||
find the Bypass PIN listed. You could delete or "hide" it. Hiding
|
||||
it is pointless since you cannot get to the trick PIN menu while
|
||||
the policy is in effect. Deleting the PIN however, is useful because
|
||||
it assures changes to spending policy are impossible. To recover
|
||||
the COLDCARD when this move is later regretted, under Advanced,
|
||||
there is "Destroy Seed" option which will clear the seed words and
|
||||
all settings, including the spending policy.
|
||||
|
||||
### Unlock Policy & Wipe
|
||||
|
||||
We've provided a new trick PIN that pretends to be the unlock
|
||||
spending policy pin, so the login sequence is correct... but it
|
||||
will wipe the seed in the process. It will be obvious to your
|
||||
attackers that you've wiped the seed because the main PIN will lead
|
||||
to blank wallet now (no seed loaded).
|
||||
|
||||
### Delta Mode and Spending Policy
|
||||
|
||||
If, from the start, you gave your "delta mode PIN" to the attackers,
|
||||
then when they bypass the policy (after also getting the bypass PIN
|
||||
from you), they will still be in Delta Mode.
|
||||
|
||||
They could attempt unlimited spending, but transactions signed will
|
||||
not be valid. If they try to view the seed words or generally export
|
||||
private key material, they will hit many of the "wipe seed if delta
|
||||
mode" cases.
|
||||
|
||||
## Forgotten Bypass PIN Code
|
||||
|
||||
If you've enabled a spending policy and still remember the main PIN,
|
||||
but cannot disable the feature because you've forgotten the Bypass
|
||||
PIN, your only option is to use `Advanced > Destroy Seed`. After
|
||||
some confirmations, this erases the master seed, all settings, seed
|
||||
vault items, secure notes, and trick pins. It's basically a factory
|
||||
reset except for the main PIN code which is unchanged. Once you've
|
||||
done that, you can enter your seed words from backup (or restore a
|
||||
backup file) and continue to use the COLDCARD again.
|
||||
|
||||
|
||||
122
docs/temporary-seeds.md
Normal file
@ -0,0 +1,122 @@
|
||||
# Temporary Seeds
|
||||
|
||||
|
||||
[_(new in v5.0.7, requires Mk4, Mk5, or Q)_](upgrade.md)
|
||||
|
||||
|
||||
Temporary seed (renamed in `5.2.0` from Ephemeral seed) is a temporary secret completely separate
|
||||
from the master seed, typically held in **COLDCARD<sup>®</sup>** RAM and
|
||||
not persisted between reboots in the Secure Element.
|
||||
Temporary seeds *completely* defeat the design
|
||||
of Coldcard's security model, based on secure elements.
|
||||
Enable the `Seed Vault` feature to store these secrets longer-term.
|
||||
Read more about `Seed Vault` feature below.
|
||||
|
||||
|
||||
!!! warning "Make sure you know what you're doing!"
|
||||
|
||||
This feature is intended for those one-off signings, like recovering
|
||||
a lost seed from some other system or importing some seed as a
|
||||
balance check. We do not recommend handing unencrypted seed material
|
||||
on a regular basis!
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
* if temporary seed is already in use, first home menu option `[<xfp>]` is visible with fingerprint of temporary master secret
|
||||
* go to `Advanced/Tools > Temporary Seed`
|
||||
|
||||
* temporary seed words can be Generated with TRNG
|
||||
- `Advanced/Tools > Temporary Seed > Generate Words`
|
||||
|
||||
* temporary seed words can be imported
|
||||
- `Advanced/Tools > Temporary Seed > Import Words`
|
||||
|
||||
* importing extended private keys
|
||||
- `Advanced/Tools > Temporary Seed > Import XPRV`
|
||||
- `Advanced/Tools > Temporary Seed > Tapsigner Backup`
|
||||
|
||||
* temporary seed can be activated from BIP-85 derived secrets - go to `Advanced/Tools > Derive Seed B85` and pick types of secret. Keep in mind that only word based and xprv based secrets can be used as temporary seed.
|
||||
- `12 words`
|
||||
- `18 words`
|
||||
- `24 words`
|
||||
- `XPRV (BIP-32)`
|
||||
- pick derivation `Index` in next prompt, or just press OK for index 0
|
||||
- Press (0) in next prompt to activate derived secret as a temporary seed
|
||||
|
||||
* temporary seed can be activated from Duress Wallet
|
||||
- go to `Settings -> Login Settings -> Trick Pins`
|
||||
- add new Duress Wallet trick pin and save it
|
||||
- choose newly created trick pin in trick pins menu and use `Activate Wallet` option
|
||||
|
||||
* temporary seed can be obtained from `SeedXOR`
|
||||
- go to `Advanced/Tools -> Danger Zone -> Seed Functions -> SeedXOR`
|
||||
- pick `Restore Seed XOR` option and provide all XOR parts
|
||||
- Press (2) to activate restored seed as temporary seed
|
||||
|
||||
* BIP-39 passphrase is from version `5.2.0` handled internally as temporary seed
|
||||
|
||||
|
||||
Ability to generate and use **Temporary seed** is available on Coldcard when:
|
||||
|
||||
1. no PIN chosen and no secret chosen (newly unpacked Coldcard)
|
||||
2. PIN set up but no secret chosen yet
|
||||
3. with both PIN and secret already picked
|
||||
|
||||
|
||||
# Restore Master
|
||||
|
||||
[_(new in v5.2.0, requires Mk4, Mk5, or Q)_](upgrade.md)
|
||||
|
||||
From version `5.2.0` users no longer need to reboot COLDCARD to return
|
||||
to their "master seed" (one stored in SE2). Once COLDCARD has temporary
|
||||
seed active, first item in home menu is `[xfp]` and is a clone of `Ready To Sign`.
|
||||
Last item in home menu is `Restore Master`.
|
||||
|
||||
`Restore Master` offers two options. First, if user presses OK, COLDCARD wipes temporary seed settings
|
||||
and switches back to master seed and its settings.
|
||||
If user presses (1) temporary seed settings are preserved for later use and COLDCARD only switches
|
||||
back to master seed and its settings.
|
||||
|
||||
If current temporary seed is also saved in Seed Vault, option to wipe settings is not available.
|
||||
Seed Vault entries can only be deleted in Seed Vault menu.
|
||||
|
||||
|
||||
# Seed Vault
|
||||
|
||||
[_(new in v5.2.0, requires Mk4, Mk5, or Q)_](upgrade.md)
|
||||
|
||||
Seed Vault adds the ability to store multiple temporary secrets into encrypted settings for simple
|
||||
recall and later use (AES-256-CTR encrypted with your master seed's key).
|
||||
Users can capture and hold master secret from any temporary seed source, including: TRNG, Dice Rolls,
|
||||
SeedXOR, TAPSIGNER backups, BIP-85 derived values, BIP-39 passphrase wallets.
|
||||
|
||||
## Enable Seed Vault
|
||||
|
||||
Enable this functionality in `Advanced/Tools -> Danger Zone -> Seed Vault -> Enable`.
|
||||
Once seed vault is enabled new menu item is visible in home menu `Seed Vault`.
|
||||
To disable Seed Vault user needs to remove all entries from Seed Vault first.
|
||||
|
||||
|
||||
## Add Seed to Vault
|
||||
|
||||
After `Seed Vault` is enabled, users will see a new prompt, after
|
||||
creation of temporary seed, asking whether to save this temporary
|
||||
seed to Seed Vault. Press (1) to save or any other key to ignore.
|
||||
|
||||
If option to save was chosen, confirmation prompt is shown - `Saved to seed vault.`
|
||||
|
||||
|
||||
## Seed Vault menu
|
||||
|
||||
* if Seed Vault is empty `(none saved yet)` is the first menu item followed by shortcut to `Temporary Seed` menu.
|
||||
* if not empty, saved seeds are listed in menu as `[xfp]`
|
||||
* if current active temporary seed is stored in Seed Vault - it has checkmark next to it
|
||||
* if temporary seed is active - last menu item of Seed Vault menu is `Restore Master`
|
||||
|
||||
## Seed Vault entry submenu
|
||||
|
||||
1. by default `[xfp]` but can be renamed to allow user labeling and leads to additional information about the seed
|
||||
2. `Use This Seed` allows to switch to the saved temporary seed. If it is already active `In Use` is shown instead.
|
||||
3. `Rename` allows to change 1. menu item to something personalized to user (limited to 40 characters)
|
||||
4. `Delete` allows to remove temporary seed from Seed Vault and optionally to completely wipe its settings.
|
||||
@ -1,11 +1,12 @@
|
||||
|
||||
# Firmware Upgrade and Recovery Process
|
||||
|
||||
_This document applies only to the Mk4. Earlier COLDCARDs did not use this approach._
|
||||
_This document applies to the Mk4, Mk5, and Q. Earlier COLDCARDs did not use this approach._
|
||||
|
||||
On the new Mk4 COLDCARD, we have done away with the slow external
|
||||
SPI flash (serial flash) chip entirely. In it's place we use a much
|
||||
faster and huge 64 Mbit PSRAM chip (quad SPI RAM chip: ESP-PSRAM64H).
|
||||
On the COLDCARD, we have done away with the slow external SPI flash
|
||||
(serial flash) chip entirely (used in Mk1-Mk3). In it's place we
|
||||
use a much faster and huge 64 Mbit PSRAM chip (quad SPI RAM chip:
|
||||
ESP-PSRAM64H).
|
||||
|
||||
This chip is volatile and forgets its contents at power down.
|
||||
|
||||
@ -14,7 +15,7 @@ can be a problem during firmware upgrades. This document explains
|
||||
how we've solved the risks of firmware upgrades and possible bricking
|
||||
that can happen with power fails at just the wrong time.
|
||||
|
||||
## Firmware Upgrade Process on Mk4
|
||||
## Firmware Upgrade Process
|
||||
|
||||
Steps:
|
||||
|
||||
@ -26,7 +27,7 @@ Steps:
|
||||
- a checksum is calculated over the new firmware, and the current contents of
|
||||
flash, including the bootloader code, its secrets, unique identity bits
|
||||
(for the main chip). We call this the "world checksum".
|
||||
- before anything else happens, we update the main secure element (608B) with
|
||||
- before anything else happens, we update the main secure element (608C) with
|
||||
the world checksum, and during boot, knowledge of the world checksum is required
|
||||
to light the green genuine light.
|
||||
- the light stays green at this point, and the system could still boot the old firmware
|
||||
@ -79,7 +80,7 @@ to main flash. The PSRAM will forget it's contents, and the COLDCARD
|
||||
no longer has a complete copy of firmware anywhere.
|
||||
|
||||
Most products would be a "brick" at this point, and the docs would
|
||||
warn against power fails during upgrade. However, the Mk4 can read
|
||||
warn against power fails during upgrade. However, the COLCARD can read
|
||||
SD Cards to load replacement firmware. The card does not need to
|
||||
be specially prepared, but we recommend erasing it, formating with
|
||||
FAT32 and then copying just the firmware onto the card.
|
||||
@ -91,7 +92,7 @@ Once a card is inserted, a search is made for a suitable firmware file.
|
||||
All DFU files will be considered, but you must provide the firmware
|
||||
file that you were attempting to upgrade to during the power failure,
|
||||
because the "world checksum" is calculated for each image found on
|
||||
the card. You will not be able to substitue a newer version of firmware.
|
||||
the card. You will not be able to substitute a newer version of firmware.
|
||||
Of course, firmware factory signatures are checked as well.
|
||||
|
||||
|
||||
|
||||
97
docs/web2fa.md
Normal file
@ -0,0 +1,97 @@
|
||||
# Web 2FA Authentication
|
||||
|
||||
How to support [RFC 6238](https://www.rfc-editor.org/rfc/rfc6238)
|
||||
TOTP (Time based One Time Password) 2FA check, on our little embedded
|
||||
device without a real-time clock?
|
||||
|
||||
Solution: Store the pre-shared secret in the COLDCARD, and send that
|
||||
securely to a trusted webserver which knows the time and can do a
|
||||
fancy UX. That webserver accepts the time-based-one-time 2FA numeric
|
||||
code from the user, and if correct, reveals a secret
|
||||
that can be used back on the COLDCARD to authorize an action.
|
||||
|
||||
For the Mk4, the secret is 8 digit numeric code to be entered,
|
||||
for the COLDCARD Q, it is a QR code to be scanned.
|
||||
|
||||
### History / Background
|
||||
|
||||
The HSM feature uses HOTP tokens, which do not require a backend,
|
||||
but are not as robust as time-based tokens.
|
||||
|
||||
Web2FA is available to be enabled as part of a Spending Policy,
|
||||
both in Multisig and Single Signer modes. When enabled, you will be
|
||||
prompted complete 2FA authentication after viewing the details of
|
||||
the transaction to be signed. You will not be able to sign without
|
||||
the correct code.
|
||||
|
||||
## How It Works
|
||||
|
||||
- Web backend has a ECC keypair, with pubkey known to CC firmware releases.
|
||||
- Usual 2fa base32 secret is picked by CC and stored in CC (so that server is stateless)
|
||||
- CC creates URL encrypted to the pubkey of server, containing args:
|
||||
- shared secret for TOTP (same value as held in user's phone)
|
||||
- the response nonce (32 bytes, shown as 64 hex chars, on Q; or 8 digits on Mk4)
|
||||
to be revealed to the user on successful auth
|
||||
- flag if Q model, so can provide a QR to be scanned in that case (rather than digits)
|
||||
- some text label for what's being approved, which is presented to user so they can pick
|
||||
correct 2fa shared secret.
|
||||
- above is all encrypted in transit, and only the server can decrypt
|
||||
- user is sent to that encrypted URL using NFC tap on the COLDCARD
|
||||
- user arrives at server:
|
||||
- shown label [which also indicates the server can be trusted, since only it could decrypt it]
|
||||
- prompt for 6 digits from authenticator app
|
||||
- does [RFC 6238](https://www.rfc-editor.org/rfc/rfc6238) 2FA check using current time
|
||||
- checks using current time and the shared secret provided by CC, fails if wrong.
|
||||
- time based failure: offer retry (they typed too slow / minor clock drift)
|
||||
- can offer to retry, but also do some rate limiting (only one attempt per 30-sec period)
|
||||
- server will store very recent responses so attacker cannot get two codes
|
||||
in any 30sec period (ie. blocks immediate reuse of same URL)
|
||||
- until a valid code is given, user is stuck here
|
||||
- when valid token received:
|
||||
- if Q, show a QR code to be scanned, with the full nonce
|
||||
- for non-Q system, a 8-digit decimal value is given: user has to enter that into the COLDCARD
|
||||
- web site shows instructions about what to do next on product.
|
||||
|
||||
## From COLDCARD PoV
|
||||
|
||||
- makes complex encrypted URL, which contains a nonce it wants, waits for that nonce back (or QR)
|
||||
- it's either the nonce from the URL, or fail
|
||||
- if the right nonce, then we know the server knows the decryption key, and we
|
||||
are trusting it actually verify the 2FA token properly.
|
||||
|
||||
## Encryption - Simple ECDH
|
||||
|
||||
- CC picks a secp256k1 keypair, generates compressed pubkey
|
||||
- multiplies that private key by server's known public key
|
||||
- apply sha256(resulting coordinate) => the session key
|
||||
- apply AES-256-CTR over URL contents (ascii text)
|
||||
- prepend 33 bytes of pubkey, and then base64url encode all of it
|
||||
- full url is: `https://coldcard.com/2fa?{base64 encoded binary}`
|
||||
|
||||
## Trust Issues
|
||||
|
||||
- 2FA enrol happens on the CC, which picks the shared secret and shows QR for mobile
|
||||
app setup. Same TRNG process as picking a seed.
|
||||
- Server knows the shared secret, but only during operation, and we won't store it [sorry,
|
||||
gotta trust us on that, but no help to us to store it].
|
||||
- Only we can run the server, because the private key is company-secret.
|
||||
- MiTM and network snoopers get nothing because HTTPS is used and only your browser
|
||||
can see the nonce, and only after you've given the right digits.
|
||||
- Coinkite server could skip the 2FA checks and just give you the answer
|
||||
you want to type into the COLDCARD. Again, you have to trust us on that.
|
||||
|
||||
## URL Format
|
||||
|
||||
https://coldcard.com/2fa?g={nonce}&ss={shared_secret}&nm={label_text}&q={is_q}
|
||||
|
||||
(the query string is then encrypted to the server's pubkey, so the args above
|
||||
are what is inside the encrypted payload.)
|
||||
|
||||
- `nonce`: text string that is either 8 digits on Mk4, or 64 hex chars on Q
|
||||
- `shared_secret`: 16 chars of Base32-encoded pre-shared secret
|
||||
- `nm`: human readable label for the transaction/purpose
|
||||
- `is_q`: flag indicating use of QR to provide nonce back to user
|
||||
|
||||
Server will accept plaintext arguments as above, but normally everything
|
||||
after the question mark is encrypted.
|
||||
|
||||
2
external/ckcc-protocol
vendored
@ -1 +1 @@
|
||||
Subproject commit 52b5950105af3c40dc2e6ab7c0b3a161667db787
|
||||
Subproject commit 3d1dfa858beb58b8dac37d8c66d7aed2909812f2
|
||||
2
external/libngu
vendored
@ -1 +1 @@
|
||||
Subproject commit 356b9137cf7ddf5de66ec4cdc0a4d757b2e42790
|
||||
Subproject commit 537519a829259622ea6b0334fbafd6cae852852f
|
||||
2
external/micropython
vendored
@ -1 +1 @@
|
||||
Subproject commit abf88c98b6ee9897b6fcc8ffea0276f07447dd48
|
||||
Subproject commit 4107246f8a080807b62c3b4838e71e812ea68b6f
|
||||
2
external/mpy-qr
vendored
@ -1 +1 @@
|
||||
Subproject commit 3ccf19ca142e9059904f0c8e53b6baeccb9c6b79
|
||||
Subproject commit 11347d83f4eb325b10676a4eb8e17deccfe0df44
|
||||
@ -1,15 +1,16 @@
|
||||
# (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
|
||||
all: graphics.py graphics_mk4.py
|
||||
all: graphics_mk4.py graphics_q1.py
|
||||
|
||||
SOURCES = $(filter-out mk4_%, $(wildcard *.txt) $(wildcard *.png))
|
||||
MK4_SOURCES = $(wildcard mk4_*.txt) $(wildcard mk4_*.png)
|
||||
|
||||
graphics.py: Makefile $(SOURCES) build.py
|
||||
./build.py graphics.py $(SOURCES)
|
||||
MK4_SOURCES = $(wildcard mono/*.txt) $(wildcard mono/*.png)
|
||||
Q1_SOURCES = colour/*.???
|
||||
|
||||
graphics_mk4.py: Makefile $(MK4_SOURCES) build.py
|
||||
./build.py graphics_mk4.py $(MK4_SOURCES)
|
||||
|
||||
graphics_q1.py: Makefile $(Q1_SOURCES) compress.py
|
||||
./compress.py graphics_q1.py $(Q1_SOURCES)
|
||||
|
||||
up: all
|
||||
(cd ../shared; make up)
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@ def read_text(fname):
|
||||
def read_img(fn):
|
||||
img = Image.open(fn)
|
||||
w,h = img.size
|
||||
assert 1 <= w < 128, w
|
||||
assert 1 <= w < 128, (w, fn)
|
||||
|
||||
img = img.convert('L')
|
||||
# fix colour issues: assume minority colour is white (1)
|
||||
@ -88,7 +88,7 @@ class Graphics:
|
||||
assert img.mode == '1'
|
||||
#img.show()
|
||||
|
||||
varname = fn.split('.')[0].replace('-', '_')
|
||||
varname = fn.split('/')[-1].split('.')[0].replace('-', '_')
|
||||
|
||||
w,h = img.size
|
||||
raw = img.tobytes()
|
||||
|
||||
BIN
graphics/colour/nfc_0.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
graphics/colour/nfc_1.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
graphics/colour/scan_1.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
graphics/colour/scan_2.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
graphics/colour/scan_3.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
graphics/colour/scan_4.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
graphics/colour/scan_5.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
graphics/colour/splash.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
212
graphics/compress.py
Executable file
@ -0,0 +1,212 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# (c) Copyright 2023 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
#
|
||||
# Read in PNG (or even JPG) and output heavily compressed RGB565 data suited to Q1's LCD panel.
|
||||
#
|
||||
# - also renders status bar icons/indicators
|
||||
#
|
||||
import os, sys, pdb
|
||||
from PIL import Image, ImageOps, ImageFont, ImageDraw
|
||||
import zlib
|
||||
from struct import pack
|
||||
|
||||
WBITS = -10
|
||||
|
||||
FONT_PATH = './fonts/'
|
||||
|
||||
def read_img(fn):
|
||||
img = Image.open(fn)
|
||||
w,h = img.size
|
||||
assert 1 <= w <= 320, f'too wide; {w}'
|
||||
assert 1 <= h <= 240, f'too tall: {h}'
|
||||
|
||||
img = img.convert('RGB')
|
||||
|
||||
# maybe: quantitize to a reasonable num colours, so compression
|
||||
# can work better?
|
||||
|
||||
return img
|
||||
|
||||
def compress(n, wbits=WBITS):
|
||||
# NOTE: neg wbits implies no zlib header, and receiver may need to know it?
|
||||
z = zlib.compressobj(wbits=wbits, level=zlib.Z_BEST_COMPRESSION)
|
||||
rv = z.compress(n)
|
||||
rv += z.flush(zlib.Z_FINISH)
|
||||
return rv
|
||||
|
||||
def crunch(n):
|
||||
# try them all... not finding any difference tho.
|
||||
a = [(wb,compress(n, wb)) for wb in range(-9, -15, -1)]
|
||||
|
||||
a.sort(key=lambda i: (-len(i[1]), -i[0]))
|
||||
|
||||
print("Wbit values:")
|
||||
print('\n'.join("%3d => %d" % (wb,len(d)) for wb,d in a))
|
||||
|
||||
return a[0]
|
||||
|
||||
# LCD Display wants RGB565 values, but big endian, so green gets split weird.
|
||||
def swizzle(r,g,b):
|
||||
# from 0-255 per component => two bytes
|
||||
b = (b >> 3)
|
||||
g = (g >> 3) # should be >> 2 for 6 bits; but looks trash?
|
||||
r = (r >> 3)
|
||||
|
||||
return pack('>H', ((r<<11) | (g<<6) | b))
|
||||
|
||||
# these values tested on real hardware
|
||||
assert swizzle(255, 0, 0) == b'\xf8\x00' # red
|
||||
##assert swizzle(0, 255, 0) == b'\xc0\x0f' # green (6 bits)
|
||||
assert swizzle(0, 255, 0) == b'\x07\xc0' # green (5 bits)
|
||||
assert swizzle(0, 0, 255) == b'\x00\x1f' # blue
|
||||
|
||||
|
||||
def into_bgr565(img):
|
||||
# get the raw bytes needed for this specific display
|
||||
rv = bytearray()
|
||||
for y in range(img.height):
|
||||
for x in range(img.width):
|
||||
px = img.getpixel((x, y))
|
||||
assert len(px) == 3
|
||||
r,g,b = px
|
||||
rv.extend(swizzle(r,g,b))
|
||||
|
||||
return rv
|
||||
|
||||
def make_icons():
|
||||
# return list of (varname, img) for each image
|
||||
|
||||
# - see shared/lcd_display.py TOP_MARGIN for this
|
||||
ICON_SIZE = 14
|
||||
MAX_HEIGHT = 14
|
||||
|
||||
# PROBLEM: this file costs money... altho free version looks okay too
|
||||
try:
|
||||
awesome = ImageFont.truetype(FONT_PATH + 'Font Awesome 6 Sharp-Regular-400.otf', ICON_SIZE)
|
||||
except:
|
||||
raise
|
||||
|
||||
# use a bitmap font for best readability
|
||||
sm_font = ImageFont.load('ter-powerline-x12b.pil')
|
||||
|
||||
targets = [
|
||||
#( 'brand', True, 'Q', dict(col='#ffb000') ),
|
||||
( 'shift', True, 'SHIFT', {} ),
|
||||
( 'symbol', True, 'SYM', {} ),
|
||||
( 'caps', True, 'CAPS', {} ),
|
||||
( 'bip39', True, 'PASSPHRASE', dict(col_1='yellow') ),
|
||||
( 'tmp', True, 'TMP.SEED', dict(col_0='black', col_1='red') ),
|
||||
( 'devmode', True, 'DEV', dict(col='#66E6FF') ),
|
||||
( 'edge', True, 'EDGE', dict(col='#66E6FF') ),
|
||||
( 'bat_0', False, '\uf244', dict(col='red', y=-1, pad=1)),
|
||||
( 'bat_1', False, '\uf243', dict(col='yellow', y=-1, pad=1)),
|
||||
( 'bat_2', False, '\uf242', dict(col='amber', y=-1, pad=1)),
|
||||
( 'bat_3', False, '\uf240', dict(col='amber', y=-1, pad=1)),
|
||||
( 'plugged', False, '\uf1e6', dict(col='amber', x=3, w=16, y=-2)), # to match width of bat_*
|
||||
#( 'locked', False, '\uf023', dict(col='green')),
|
||||
#( 'unlocked', False, '\uf3c1', dict(col='green')), # why tho?
|
||||
]
|
||||
|
||||
targets += [ ( 'ch_'+c, True, c.upper(), dict(col='white') ) for c in
|
||||
'0123456789abcdef']
|
||||
|
||||
samples = Image.new('RGB', (320*3, ICON_SIZE+1))
|
||||
s_x = 5
|
||||
|
||||
for basename, is_text, body, opts in targets:
|
||||
for state in [0, 1]:
|
||||
col = opts.get('col', '#fff' if state else '#444')
|
||||
vn = f'{basename}_{state}'
|
||||
|
||||
if 'col' in opts:
|
||||
if state == 0: continue
|
||||
vn = basename
|
||||
|
||||
if state == 0 and 'col_0' in opts:
|
||||
col = opts['col_0']
|
||||
if state == 1 and 'col_1' in opts:
|
||||
col = opts['col_1']
|
||||
|
||||
img = Image.new('RGB', (100,100))
|
||||
d = ImageDraw.Draw(img)
|
||||
f = sm_font if is_text else awesome
|
||||
|
||||
|
||||
x, y = (0, 1 if is_text else 0)
|
||||
y += opts.get('y', 0)
|
||||
x += opts.get('x', 0)
|
||||
|
||||
tl = (x, y)
|
||||
_,_, w,h = d.textbbox(tl, body, font=f)
|
||||
|
||||
w = opts.get('w', w)
|
||||
|
||||
if h > MAX_HEIGHT:
|
||||
h = MAX_HEIGHT
|
||||
print(f'"{vn}" too tall, cropped')
|
||||
elif opts.get('pad'):
|
||||
h = MAX_HEIGHT
|
||||
|
||||
if col == 'amber':
|
||||
# brand colour
|
||||
col = '#ffb000'
|
||||
|
||||
d.text(tl, body, font=f, fill=col)
|
||||
rv = img.crop( (0, 0, w,h) )
|
||||
|
||||
samples.paste(rv, (s_x, 0))
|
||||
s_x += w + 10
|
||||
|
||||
yield (vn, rv)
|
||||
|
||||
samples = samples.crop( (0,0, s_x, samples.height ))
|
||||
samples.save('icon-samples.png')
|
||||
|
||||
|
||||
|
||||
def doit(outfname, fnames):
|
||||
|
||||
assert outfname.endswith('.py')
|
||||
assert outfname != 'compress.py'
|
||||
assert fnames, "need some files"
|
||||
|
||||
fp = open(outfname, 'wt')
|
||||
|
||||
fp.write("""\
|
||||
# autogenerated; don't edit
|
||||
#
|
||||
# BGR565 pixel data
|
||||
#
|
||||
class Graphics:
|
||||
# (w,h, data)
|
||||
|
||||
""")
|
||||
|
||||
fnames += make_icons()
|
||||
|
||||
for fn in fnames:
|
||||
if isinstance(fn, str):
|
||||
img = read_img(fn)
|
||||
varname = fn.split('/')[-1].split('.')[0].replace('-', '_')
|
||||
else:
|
||||
varname, img = fn
|
||||
|
||||
assert img.mode == 'RGB'
|
||||
|
||||
w,h = img.size
|
||||
raw = into_bgr565(img)
|
||||
comp = compress(raw)
|
||||
#crunch(raw)
|
||||
|
||||
print(" %s = (%d, %d,\n %r\n )\n" % (varname, w, h, comp), file=fp)
|
||||
|
||||
print("done: '%s' (%d x %d) => %d raw => %d compressed bytes" % (
|
||||
varname, w, h, len(raw), len(comp)))
|
||||
|
||||
fp.write("\n# EOF\n")
|
||||
|
||||
if 1:
|
||||
doit(sys.argv[1], sys.argv[2:])
|
||||
|
||||
# EOF
|
||||
@ -1,4 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Generate some data for hsm_ux.py animation
|
||||
#
|
||||
from math import sin, pi
|
||||
from collections import Counter
|
||||
|
||||
|
||||
3
graphics/fonts/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
Font Awesome 6*.otf
|
||||
iosevka-*.ttf
|
||||
!iosevka-heavy.ttf
|
||||
11
graphics/fonts/README.md
Normal file
@ -0,0 +1,11 @@
|
||||
|
||||
# Fonts for Q1
|
||||
|
||||
This directory may contain font files from Font Awesome.
|
||||
|
||||
We cannot re-distribute the OTF files themselves due to their license.
|
||||
|
||||
However, once we render and build the compressed graphics file that we need,
|
||||
the font is not required anymore.
|
||||
|
||||
Iosveka is open and can be re-distributed here.
|
||||
18
graphics/fonts/font-awesome-license.txt
Normal file
@ -0,0 +1,18 @@
|
||||
Font Awesome Pro License
|
||||
------------------------
|
||||
|
||||
Font Awesome Pro is commercial software that requires a paid license. Full
|
||||
Font Awesome Pro license: https://fontawesome.com/license.
|
||||
|
||||
# Commercial License
|
||||
The Font Awesome Pro commercial license allows you to pay for FA Pro once, own
|
||||
it, and use it just about everywhere you'd like.
|
||||
|
||||
# Attribution
|
||||
Attribution is not required by the Font Awesome Pro commercial license.
|
||||
|
||||
# Brand Icons
|
||||
All brand icons are trademarks of their respective owners. The use of these
|
||||
trademarks does not indicate endorsement of the trademark holder by Font
|
||||
Awesome, nor vice versa. **Please do not use brand logos for any purpose except
|
||||
to represent the company, product, or service to which they refer.**
|
||||
BIN
graphics/fonts/iosevka-heavy.ttf
Normal file
@ -1,27 +0,0 @@
|
||||
# autogenerated; don't edit
|
||||
#
|
||||
class Graphics:
|
||||
# (w,h, w_bytes, wbits, data)
|
||||
|
||||
arrow_down = (7, 11, 1, 0, b'\x10\x10\x10\x10\x10\x10\x10\xfe|8\x10')
|
||||
|
||||
arrow_up = (7, 11, 1, 0, b'\x108|\xfe\x10\x10\x10\x10\x10\x10\x10')
|
||||
|
||||
box = (13, 21, 2, 0, b'?\xe0@\x10\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08@\x10?\xe0')
|
||||
|
||||
scroll = (3, 61, 1, 0, b'@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@@\xe0@')
|
||||
|
||||
selected = (15, 12, 2, 0, b'\x00\x00\x00\x00\x00\x06\x00\x0c\x00\x18\x0000`\x18\xc0\r\x80\x07\x00\x02\x00\x00\x00')
|
||||
|
||||
sm_box = (11, 17, 2, 0, b'\xe4\xe0\x80 \x80 \x80 \x00\x00\x00\x00\x80 \x00\x00\x00\x00\x00\x00\x80 \x00\x00\x00\x00\x80 \x80 \x80 \xe4\xe0')
|
||||
|
||||
space = (9, 2, 2, 0, b'\x80\x80\xff\x80')
|
||||
|
||||
spin = (13, 36, 2, 0, b'\x02\x00\x07\x00\x0f\x80\x1f\xc0\x00\x00\x00\x00\x00\x00\xf2x\x80\x08\x80\x08\x80\x08\x00\x00\x00\x00\x80\x08\x00\x00\x00\x00\x00\x00\x80\x08\x00\x00\x00\x00\x00\x00\x80\x08\x00\x00\x00\x00\x80\x08\x80\x08\x80\x08\xf2x\x00\x00\x00\x00\x00\x00\x1f\xc0\x0f\x80\x07\x00\x02\x00\x00\x00')
|
||||
|
||||
wedge = (6, 11, 1, 0, b'\x00\x00\xc0\xe0p8\x1c8p\xe0\xc0')
|
||||
|
||||
xbox = (13, 21, 2, 0, b'?\xe0b0\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88b0?\xe0')
|
||||
|
||||
|
||||
# EOF
|
||||
@ -3,6 +3,12 @@
|
||||
class Graphics:
|
||||
# (w,h, w_bytes, wbits, data)
|
||||
|
||||
arrow_down = (7, 11, 1, 0, b'\x10\x10\x10\x10\x10\x10\x10\xfe|8\x10')
|
||||
|
||||
arrow_up = (7, 11, 1, 0, b'\x108|\xfe\x10\x10\x10\x10\x10\x10\x10')
|
||||
|
||||
box = (13, 21, 2, 0, b'?\xe0@\x10\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08\x80\x08@\x10?\xe0')
|
||||
|
||||
mk4_nfc_1 = (126, 49, 16, 0, b'\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x0e\x00\xe0\x0e\x03\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\xe0\x0e\x00\xe0\x0e\x07\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xe0\x0e\x00\xe0\x0e\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00(D\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00(D\x04\x00\x00\x00xp\x00\xff\xff\xff\xff\xfe0\x00$G\xe4\x00\x00\x00xp\x00\xff\xff\xff\xff\xfe0\x00$G\xe4\x00\x00\x00xp\x00\xe0\x0e\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e?\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xff\xff\xff\xff\xfe\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xff\xff\xff\xff\xfe\x0f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
|
||||
|
||||
mk4_nfc_2 = (118, 49, 15, 0, b'\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x0e\x00\xe0\x03\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\xe0\x0e\x00\xe0\x07\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xe0\x0e\x00\xe0\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x000D\x04\x10\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x000D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00(D\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00(D\x04\x00\x00\x00xp\x00\xff\xff\xff\xff0\x00$G\xe4\x00\x00\x00xp\x00\xff\xff\xff\xff0\x00$G\xe4\x00\x00\x00xp\x00\xe0\x0e\x00\xe00\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe00\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe00\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0?\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xff\xff\xff\xff\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xff\xff\xff\xff\x0f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00')
|
||||
@ -11,5 +17,27 @@ class Graphics:
|
||||
|
||||
mk4_nfc_4 = (102, 49, 13, 0, b'\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xcf\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x03\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x0e\x03\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\xe0\x0e\x07\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xe0\x0e\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00(D\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00(D\x04\x00\x00\x00xp\x00\xff\xff\xb0\x00$G\xe4\x00\x00\x00xp\x00\xff\xff\xb0\x00$G\xe4\x00\x00\x00xp\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e?\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xff\xff\x9f\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xff\xff\x8f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x7f\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00')
|
||||
|
||||
mk5_nfc_1 = (126, 49, 16, 0, b'\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xf0\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x0e\x00\xe0\x0e\x03\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\xe0\x0e\x00\xe0\x0e\x07\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xe0\x0e\x00\xe0\x0e\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00(D\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00(D\x04\x00\x00\x00xp\x00\xff\xff\xff\xff\xfe0\x00$G\xe4\x00\x00\x00xp\x00\xff\xff\xff\xff\xfe0\x00$G\xe4\x00\x00\x00xp\x00\xe0\x0e\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xff\xff\xff\xff\xfe0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0\x0e?\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xff\xff\xff\xff\xfe\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xff\xff\xff\xff\xfe\x0f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
|
||||
|
||||
mk5_nfc_2 = (118, 49, 15, 0, b'\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xf0\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xe0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x0e\x00\xe0\x03\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\xe0\x0e\x00\xe0\x07\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xe0\x0e\x00\xe0\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x000D\x04\x10\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x000D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00(D\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00(D\x04\x00\x00\x00xp\x00\xff\xff\xff\xff0\x00$G\xe4\x00\x00\x00xp\x00\xff\xff\xff\xff0\x00$G\xe4\x00\x00\x00xp\x00\xe0\x0e\x00\xe00\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe00\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x00\xe00\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xff\xff\xff\xff0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe00\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00\xe0?\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xff\xff\xff\xff\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xff\xff\xff\xff\x0f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00\x00')
|
||||
|
||||
mk5_nfc_3 = (110, 49, 14, 0, b'\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xf0\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x0e\x00\x03\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\xe0\x0e\x00\x07\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xe0\x0e\x00\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\xe0\x0e\x000\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x000\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x000\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x000\x000D\x04\x10\x00\x00\x7f\xf0\x00\xe0\x0e\x000\x000D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00(D\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00(D\x04\x00\x00\x00xp\x00\xff\xff\xff0\x00$G\xe4\x00\x00\x00xp\x00\xff\xff\xff0\x00$G\xe4\x00\x00\x00xp\x00\xe0\x0e\x000\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x000\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e\x000\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x000\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xff\xff\xff0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xe0\x0e\x000\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x000\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x000\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e\x00?\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xff\xff\xff\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xff\xff\xff\x0f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x7f\xff\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00\x00')
|
||||
|
||||
mk5_nfc_4 = (102, 49, 13, 0, b'\x00\x7f\xff\xff\xff\xfc\x00\x00\x00\x00\x00\x00\x00\x00\xf0\xf0\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x00\x00\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\xfe\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xe0\x0e\x03\xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\xe0\x0e\x07\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xe0\x0e\x1f\xff\xff\xff\xff\xff\xff\xff\xff\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e0\x00 G\xe3\xe0\x00\x00\x7f\xf0\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xe0\x0e0\x000D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00(D\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00(D\x04\x00\x00\x00xp\x00\xff\xff\xb0\x00$G\xe4\x00\x00\x00xp\x00\xff\xff\xb0\x00$G\xe4\x00\x00\x00xp\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e0\x00"D\x04\x00\x00\x00xp\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00 \xc4\x04\x00\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x04\x10\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xff\xff\xb0\x00 D\x03\xe0\x00\x00\x7f\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e0\x00\x00\x00\x00\x00\x00\x00\x7f\xf0\x00\xe0\x0e?\xff\xff\xff\xff\xff\xff\xff\xff\xe0\x00\xff\xff\x9f\xff\xff\xff\xff\xff\xff\xff\xff\xc0\x00\xff\xff\x8f\xff\xff\xff\xff\xff\xff\xff\xff\x00\x00\x7f\xff\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00?\xff\xff\xff\xf8\x00\x00\x00\x00\x00\x00\x00')
|
||||
|
||||
scroll = (3, 61, 1, 0, b'@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@\x00\x00@@\xe0@')
|
||||
|
||||
selected = (9, 12, 2, 0, b'\x00\x00\x00\x00\x00\x80\x01\x80\x01\x00\x03\x00\x82\x00\xc6\x00d\x00<\x00\x18\x00\x00\x00')
|
||||
|
||||
sm_box = (11, 17, 2, 0, b'\xe4\xe0\x80 \x80 \x80 \x00\x00\x00\x00\x80 \x00\x00\x00\x00\x00\x00\x80 \x00\x00\x00\x00\x80 \x80 \x80 \xe4\xe0')
|
||||
|
||||
space = (9, 2, 2, 0, b'\x80\x80\xff\x80')
|
||||
|
||||
spin = (13, 36, 2, 0, b'\x02\x00\x07\x00\x0f\x80\x1f\xc0\x00\x00\x00\x00\x00\x00\xf2x\x80\x08\x80\x08\x80\x08\x00\x00\x00\x00\x80\x08\x00\x00\x00\x00\x00\x00\x80\x08\x00\x00\x00\x00\x00\x00\x80\x08\x00\x00\x00\x00\x80\x08\x80\x08\x80\x08\xf2x\x00\x00\x00\x00\x00\x00\x1f\xc0\x0f\x80\x07\x00\x02\x00\x00\x00')
|
||||
|
||||
wedge = (6, 11, 1, 0, b'\x00\x00\xc0\xe0p8\x1c8p\xe0\xc0')
|
||||
|
||||
xbox = (13, 21, 2, 0, b'?\xe0b0\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88\xa2(\x88\x88b0?\xe0')
|
||||
|
||||
|
||||
# EOF
|
||||
|
||||
173
graphics/graphics_q1.py
Normal file
BIN
graphics/icon-samples.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
49
graphics/mono/mk5_nfc_1.txt
Normal file
@ -0,0 +1,49 @@
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxx xxxx xxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxx xxx xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxx xxx xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxx xxx xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxx xxx xxx xxx yy yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||
xxx xxx xxx xxx yy n n ffffff ccccc yyyyyyyyyyy
|
||||
xxx xxx xxx xxx yy n n ffffff ccccc yyyyyyyyyyy
|
||||
xxx xxx xxx xxx yy nn n f c c yyyyyyyyyyy
|
||||
xxx xxx xxx xxx yy nn n f c c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n n f c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n n f c yyyy yyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n n ffffff c yyyy yyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n n ffffff c yyyy yyy
|
||||
xxx xxx xxx xxx yy n n n f c yyyy yyy
|
||||
xxx xxx xxx xxx yy n n n f c yyyy yyy
|
||||
xxx xxx xxx xxx yy n nn f c yyyyyyyyyyy
|
||||
xxx xxx xxx xxx yy n nn f c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n f c c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n f c c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n f ccccc yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n f ccccc yyyyyyyyyyy
|
||||
xxx xxx xxx xxx yy yyyyyyyyyyy
|
||||
xxx xxx xxx xxx yy yyyyyyyyyyy
|
||||
xxx xxx xxx xxx yy yyyyyyyyyyy
|
||||
xxx xxx xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
49
graphics/mono/mk5_nfc_2.txt
Normal file
@ -0,0 +1,49 @@
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxx xxxx xxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxx xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxx xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxx xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxx xxx xxx yy yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||
xxx xxx xxx yy n n ffffff ccccc yyyyyyyyyyy
|
||||
xxx xxx xxx yy n n ffffff ccccc yyyyyyyyyyy
|
||||
xxx xxx xxx yy nn n f c c yyyyyyyyyyy
|
||||
xxx xxx xxx yy nn n f c c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n n f c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n n f c yyyy yyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n n ffffff c yyyy yyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n n ffffff c yyyy yyy
|
||||
xxx xxx xxx yy n n n f c yyyy yyy
|
||||
xxx xxx xxx yy n n n f c yyyy yyy
|
||||
xxx xxx xxx yy n nn f c yyyyyyyyyyy
|
||||
xxx xxx xxx yy n nn f c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n f c c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n f c c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n f ccccc yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yy n n f ccccc yyyyyyyyyyy
|
||||
xxx xxx xxx yy yyyyyyyyyyy
|
||||
xxx xxx xxx yy yyyyyyyyyyy
|
||||
xxx xxx xxx yy yyyyyyyyyyy
|
||||
xxx xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
49
graphics/mono/mk5_nfc_3.txt
Normal file
@ -0,0 +1,49 @@
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxx xxxx xxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxx xxx yy yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||
xxx xxx yy n n ffffff ccccc yyyyyyyyyyy
|
||||
xxx xxx yy n n ffffff ccccc yyyyyyyyyyy
|
||||
xxx xxx yy nn n f c c yyyyyyyyyyy
|
||||
xxx xxx yy nn n f c c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxx yy n n n f c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxx yy n n n f c yyyy yyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxx yy n n n ffffff c yyyy yyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxx yy n n n ffffff c yyyy yyy
|
||||
xxx xxx yy n n n f c yyyy yyy
|
||||
xxx xxx yy n n n f c yyyy yyy
|
||||
xxx xxx yy n nn f c yyyyyyyyyyy
|
||||
xxx xxx yy n nn f c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxx yy n n f c c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxx yy n n f c c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxx yy n n f ccccc yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxx yy n n f ccccc yyyyyyyyyyy
|
||||
xxx xxx yy yyyyyyyyyyy
|
||||
xxx xxx yy yyyyyyyyyyy
|
||||
xxx xxx yy yyyyyyyyyyy
|
||||
xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
49
graphics/mono/mk5_nfc_4.txt
Normal file
@ -0,0 +1,49 @@
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxx xxxx xxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxx xxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxx
|
||||
xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxx xxx yy yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxx yy yyyyyyyyyyy
|
||||
xxx xxx yy n n ffffff ccccc yyyyyyyyyyy
|
||||
xxx xxx yy n n ffffff ccccc yyyyyyyyyyy
|
||||
xxx xxx yy nn n f c c yyyyyyyyyyy
|
||||
xxx xxx yy nn n f c c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxx yy n n n f c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxx yy n n n f c yyyy yyy
|
||||
xxxxxxxxxxxxxxxxx yy n n n ffffff c yyyy yyy
|
||||
xxxxxxxxxxxxxxxxx yy n n n ffffff c yyyy yyy
|
||||
xxx xxx yy n n n f c yyyy yyy
|
||||
xxx xxx yy n n n f c yyyy yyy
|
||||
xxx xxx yy n nn f c yyyyyyyyyyy
|
||||
xxx xxx yy n nn f c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxx yy n n f c c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxx yy n n f c c yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxx yy n n f ccccc yyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxx yy n n f ccccc yyyyyyyyyyy
|
||||
xxx xxx yy yyyyyyyyyyy
|
||||
xxx xxx yy yyyyyyyyyyy
|
||||
xxx xxx yy yyyyyyyyyyy
|
||||
xxx xxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxx yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
|
||||
xxxxxxxxxxxxxxxxx
|
||||
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
12
graphics/mono/selected.txt
Normal file
@ -0,0 +1,12 @@
|
||||
|
||||
|
||||
X
|
||||
XX
|
||||
X
|
||||
XX
|
||||
X X
|
||||
XX XX
|
||||
XX X
|
||||
XXXX
|
||||
XX
|
||||
|
||||
@ -1,12 +0,0 @@
|
||||
|
||||
|
||||
xx
|
||||
xx
|
||||
xx
|
||||
xx
|
||||
xx xx
|
||||
xx xx
|
||||
xx xx
|
||||
xxx
|
||||
x
|
||||
|
||||
17913
graphics/ter-powerline-x12b.bdf
Normal file
BIN
graphics/ter-powerline-x12b.pbm
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
graphics/ter-powerline-x12b.pil
Normal file
@ -1,4 +1,3 @@
|
||||
|
||||
# Coldcard Hardware Details
|
||||
|
||||
This directory contains enough information for you to be able to
|
||||
@ -6,9 +5,20 @@ build your own Coldcard from off-the-shelf parts.
|
||||
We are sharing this information for the benefit of security
|
||||
researchers who wish to analyse the Coldcard more completely.
|
||||
|
||||
|
||||
# Schematic
|
||||
|
||||

|
||||
|
||||
`schematic-q1d.png`
|
||||
|
||||
This is the Q rev D schematic.
|
||||
|
||||

|
||||
|
||||
`schematic-mark5f.png`
|
||||
|
||||
This is the Mark4 rev F schematic.
|
||||
|
||||

|
||||
|
||||
`schematic-mark4d.png`
|
||||
@ -24,11 +34,13 @@ This is the Mark3 rev B schematic.
|
||||
|
||||
# BOM - Bill of Materials
|
||||
|
||||
`bom-mark3b.xlsx`
|
||||
The parts used in the Coldcard are detailed in these spreadsheets.
|
||||
Most of them could be bought on Digikey, but some are direct from suppliers.
|
||||
|
||||
The parts used in the Coldcard are detailed in this spreadsheet file.
|
||||
All of them could be bought on Digikey, and where we know
|
||||
it, we've included the Digikey SKU.
|
||||
- BOM for Q rev D: `bom-q1d.xlsx`
|
||||
- BOM for Mk5 rev F: `bom-mark5f.xlsx`
|
||||
- BOM for Mk4 rev D: `bom-mark4d.xlsx`
|
||||
- BOM for Mk3 rev B: `bom-mark3b.xlsx`
|
||||
|
||||
Not included are these minor bits:
|
||||
|
||||
@ -36,14 +48,10 @@ Not included are these minor bits:
|
||||
- the secure bag (with barcode serial number)
|
||||
- pin-recovery card
|
||||
|
||||
`bom-mark4d.xlsx`
|
||||
|
||||
- Same for Mk4 rev D.
|
||||
|
||||
# Important
|
||||
|
||||
- No promises that these files are 100% current because we do make quality improvements.
|
||||
- No promises that these files are 100% current because we constantly make quality improvements.
|
||||
- Copyright of these files, and all design elements of the Coldcard remain with Coinkite Inc.
|
||||
- This information is for research and testing purposes only—no warranties.
|
||||
- **Coinkite does not grant license of this information for comercial use.**
|
||||
- **Coinkite does NOT grant license of this information for comercial use.**
|
||||
|
||||
|
||||
BIN
hardware/bom-mark5f.xlsx
Normal file
BIN
hardware/bom-q1d.xlsx
Normal file
BIN
hardware/schematic-mark5f.png
Normal file
|
After Width: | Height: | Size: 428 KiB |
BIN
hardware/schematic-q1d.png
Normal file
|
After Width: | Height: | Size: 796 KiB |
@ -1,26 +1,28 @@
|
||||
diff --git a/mpy-cross/Makefile b/mpy-cross/Makefile
|
||||
index 971f2f81a..b175c4dc7 100644
|
||||
index 971f2f81a..0c25a11e0 100644
|
||||
--- a/mpy-cross/Makefile
|
||||
+++ b/mpy-cross/Makefile
|
||||
@@ -17,7 +17,7 @@ INC += -I$(BUILD)
|
||||
@@ -17,7 +17,8 @@ INC += -I$(BUILD)
|
||||
INC += -I$(TOP)
|
||||
|
||||
# compiler settings
|
||||
-CWARN = -Wall -Werror
|
||||
+CWARN = -Wall -Werror -Wno-error=unused-but-set-variable -Wno-error=array-bounds
|
||||
+CWARN += -Wno-error=unknown-warning-option
|
||||
CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith
|
||||
CFLAGS = $(INC) $(CWARN) -std=gnu99 $(CFLAGS_MOD) $(COPT) $(CFLAGS_EXTRA)
|
||||
CFLAGS += -fdata-sections -ffunction-sections -fno-asynchronous-unwind-tables
|
||||
diff --git a/ports/unix/Makefile b/ports/unix/Makefile
|
||||
index 6a936a242..6b4900561 100644
|
||||
index 6a936a242..43e6bf02a 100644
|
||||
--- a/ports/unix/Makefile
|
||||
+++ b/ports/unix/Makefile
|
||||
@@ -38,7 +38,7 @@ INC += -I$(TOP)
|
||||
@@ -38,7 +38,8 @@ INC += -I$(TOP)
|
||||
INC += -I$(BUILD)
|
||||
|
||||
# compiler settings
|
||||
-CWARN = -Wall -Werror
|
||||
+CWARN = -Wall -Werror -Wno-error=unused-but-set-variable -Wno-error=array-bounds
|
||||
+CWARN += -Wno-error=unknown-warning-option -Wno-error=deprecated-non-prototype -Wno-error=bitwise-instead-of-logical
|
||||
CWARN += -Wextra -Wno-unused-parameter -Wpointer-arith -Wdouble-promotion -Wfloat-conversion
|
||||
CFLAGS += $(INC) $(CWARN) -std=gnu99 -DUNIX $(CFLAGS_MOD) $(COPT) -I$(VARIANT_DIR) $(CFLAGS_EXTRA)
|
||||
|
||||
|
||||
@ -74,4 +74,9 @@ special_chars = dict(small=[
|
||||
x x x x x
|
||||
'''),
|
||||
|
||||
# thin space
|
||||
('\u2009', dict(y=0, w=5), '''\
|
||||
|
||||
'''),
|
||||
|
||||
])
|
||||
|
||||
10
misc/gpu/.gitignore
vendored
Normal file
@ -0,0 +1,10 @@
|
||||
|
||||
# build products, see Makefile:
|
||||
gpu.lss
|
||||
gpu.sym
|
||||
gpu.bin.tmp
|
||||
|
||||
checksums.txt
|
||||
version-full.txt
|
||||
version.txt
|
||||
|
||||
184
misc/gpu/Makefile
Normal file
@ -0,0 +1,184 @@
|
||||
# (c) Copyright 2023 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
#
|
||||
# Makefile for Q1's GPU co-processor.
|
||||
#
|
||||
# Targets:
|
||||
# all - make everything, look for dafu.elf inparticular
|
||||
# clean - delete intermediates
|
||||
# clobber - delete all build products
|
||||
#
|
||||
|
||||
# Toolchain
|
||||
TOOLCHAIN = arm-none-eabi-
|
||||
CC = $(TOOLCHAIN)gcc
|
||||
OBJDUMP = $(TOOLCHAIN)objdump
|
||||
OBJCOPY = $(TOOLCHAIN)objcopy
|
||||
NM = $(TOOLCHAIN)nm
|
||||
SIZE = $(TOOLCHAIN)size
|
||||
|
||||
# Basename of all targets
|
||||
TARGET_NAME = gpu
|
||||
|
||||
# Source files, listed here as the object files they will become.
|
||||
OBJS += startup.o
|
||||
OBJS += main.o lcd.o version.o interrupts.o
|
||||
OBJS += stm32c0xx_ll_gpio.o stm32c0xx_ll_spi.o stm32c0xx_ll_i2c.o stm32c0xx_ll_utils.o
|
||||
|
||||
# Have to have copies of these because the DMA and interrupt stuff
|
||||
# needs to be commented-out.
|
||||
#OBJS += stm32l4xx_hal_gpio.o stm32l4xx_hal_spi.o
|
||||
#OBJS += stm32l4xx_hal_rcc.o stm32l4xx_hal_rcc_ex.o
|
||||
|
||||
# Where we will end up in the memory map (at start of flash)
|
||||
GPU_FLASH_BASE = 0x08000000
|
||||
GPU_FLASH_SIZE = 0x4000
|
||||
GPU_FLASH_LAST = 0x08004000
|
||||
|
||||
# Use all of 6k of SRAM...
|
||||
GPU_SRAM_BASE = 0x20000000
|
||||
GPU_SRAM_SIZE = 0x00001800
|
||||
|
||||
# Compiler flags.
|
||||
CFLAGS = -I. -Wall --std=gnu99 -Os -g3 \
|
||||
-mthumb -mfpu=fpv4-sp-d16 -mfloat-abi=soft -mtune=cortex-m0 \
|
||||
-ffunction-sections -fdata-sections \
|
||||
-mcpu=cortex-m0 -DMCU_SERIES_C0 -DSTM32C011xx \
|
||||
-DUSE_FULL_LL_DRIVER
|
||||
#-DUSE_HAL_DRIVER
|
||||
|
||||
# Pass in the locations of stuff
|
||||
CFLAGS += -D GPU_FLASH_BASE=$(GPU_FLASH_BASE) -D GPU_FLASH_SIZE=$(GPU_FLASH_SIZE)
|
||||
CFLAGS += -D GPU_SRAM_BASE=$(GPU_SRAM_BASE) -D GPU_SRAM_SIZE=$(GPU_SRAM_SIZE)
|
||||
|
||||
# Header file search path
|
||||
INC_PATHS = external/cmsis_device_c0/Include \
|
||||
external/stm32c0xx_hal_driver/Inc \
|
||||
../../external/micropython/lib/cmsis/inc
|
||||
|
||||
CFLAGS += $(foreach INC,$(INC_PATHS),-I$(INC))
|
||||
|
||||
# Specialized linker-script here. Not the standard one!
|
||||
#
|
||||
LINKER_SCRIPT = link-script.ld
|
||||
LDFLAGS += -Wl,-T$(LINKER_SCRIPT)
|
||||
|
||||
LDFLAGS += -flto -Wl,--gc-sections --specs=nano.specs
|
||||
LDFLAGS += -Wl,--defsym,GPU_FLASH_BASE=$(GPU_FLASH_BASE)
|
||||
LDFLAGS += -Wl,--defsym,GPU_FLASH_SIZE=$(GPU_FLASH_SIZE)
|
||||
LDFLAGS += -Wl,--defsym,GPU_SRAM_BASE=$(GPU_SRAM_BASE)
|
||||
LDFLAGS += -Wl,--defsym,GPU_SRAM_SIZE=$(GPU_SRAM_SIZE)
|
||||
LDFLAGS += -Wl,-Map=$(TARGET_NAME).map
|
||||
|
||||
ASFLAGS += -Wa,--defsym,GPU_FLASH_BASE=$(GPU_FLASH_BASE) -Wa,--defsym,GPU_FLASH_SIZE=$(GPU_FLASH_SIZE)
|
||||
ASFLAGS += -Wa,--defsym,GPU_SRAM_BASE=$(GPU_SRAM_BASE) -Wa,--defsym,GPU_SRAM_SIZE=$(GPU_SRAM_SIZE)
|
||||
|
||||
|
||||
TARGET_ELF = $(TARGET_NAME).elf
|
||||
TARGETS = $(TARGET_NAME).lss $(TARGET_NAME).bin $(TARGET_NAME).sym gpu_binary.py
|
||||
|
||||
all: $(TARGETS)
|
||||
|
||||
# recompile on any Makefile change, because with a small project like this...
|
||||
$(OBJS): Makefile
|
||||
$(TARGETS): $(TARGET_ELF) Makefile
|
||||
|
||||
# link step
|
||||
$(TARGET_ELF): $(OBJS) $(LINKER_SCRIPT) Makefile
|
||||
$(CC) $(CFLAGS) -o $(TARGET_ELF) $(LDFLAGS) $(OBJS)
|
||||
$(SIZE) -Ax $@
|
||||
|
||||
# detailed listing, very handy
|
||||
%.lss: $(TARGET_ELF)
|
||||
$(OBJDUMP) -h -S $< > $@
|
||||
|
||||
# symbol dump, meh
|
||||
%.sym: $(TARGET_ELF)
|
||||
$(NM) -n $< > $@
|
||||
|
||||
# raw binary, forced to right size, pad w/ 0xff
|
||||
%.bin: $(TARGET_ELF)
|
||||
$(OBJCOPY) -O binary --gap-fill 0xff $< $@
|
||||
|
||||
# assumes openocd running from current directory
|
||||
up:
|
||||
echo 'flash write_image $(TARGET_ELF)' | nc localhost 4444
|
||||
|
||||
# make a 'release' build
|
||||
release: code-committed clean all capture
|
||||
release: CFLAGS += -DRELEASE=1 -Werror
|
||||
|
||||
.PHONY: code-committed
|
||||
code-committed:
|
||||
@echo ""
|
||||
@echo "Are all changes commited already?"
|
||||
git diff --stat --exit-code .
|
||||
@echo '... yes'
|
||||
|
||||
# these files are what we capture and store for each release.
|
||||
DELIVERABLES = $(TARGET_NAME).bin $(TARGET_NAME).lss gpu_binary.py
|
||||
|
||||
# package the binary into a mpy file to be frozen/included into main micro code
|
||||
gpu_binary.py: version.txt $(TARGET_NAME).bin repackage.py
|
||||
./repackage.py `cat version.txt` $(TARGET_NAME).bin > $@
|
||||
wc -c $(TARGET_NAME).bin
|
||||
|
||||
checksums.txt: $(DELIVERABLES)
|
||||
shasum -a 256 $(DELIVERABLES) > $@
|
||||
|
||||
lcd.o: barcode.h
|
||||
barcode.h: make_barcode.py Makefile
|
||||
python3 make_barcode.py
|
||||
|
||||
# Track released versions
|
||||
.PHONY: capture
|
||||
capture: version.txt version-full.txt $(DELIVERABLES) checksums.txt
|
||||
V=`cat version.txt` && cat checksums.txt > releases/$$V.txt && cat version-full.txt >> releases/$$V.txt && mkdir -p releases/$$V; cp $(DELIVERABLES) releases/$$V
|
||||
@echo
|
||||
@echo " Version: " `cat version.txt`
|
||||
@echo
|
||||
V=`cat version.txt` && git tag -am "Q1 GPU version $$V" "q1-gpu-"$$V
|
||||
git add -f releases/*/gpu.* releases/*.txt releases/*/*.py
|
||||
|
||||
# Pull out the version string from binary object (already linked in) and
|
||||
# construct a text file (version.txt) with those contents
|
||||
version.txt version-full.txt: version.o Makefile
|
||||
$(OBJCOPY) -O binary -j .rodata.version_string version.o version-tmp.txt
|
||||
cat version-tmp.txt | sed -e 's/ .*//' | sed -e 's/ .*//' > version.txt
|
||||
cat version-tmp.txt | tr '\0' '\n' > version-full.txt
|
||||
@echo
|
||||
@echo "Version string: " `cat version-full.txt`
|
||||
@echo
|
||||
$(RM) version-tmp.txt
|
||||
|
||||
# nice version numbers.
|
||||
BUILD_TIME = $(shell date '+%Y%m%d.%H%M%S')
|
||||
BRANCH = $(shell git rev-parse --abbrev-ref HEAD)
|
||||
SHA_VERSION = $(shell git rev-parse --short HEAD)
|
||||
GIT_HASH = "$(BRANCH)@$(SHA_VERSION)"
|
||||
version.o: CFLAGS += -DBUILD_TIME='"$(BUILD_TIME)"' -DGIT_HASH='$(GIT_HASH)'
|
||||
version.o main.o: Makefile version.h
|
||||
|
||||
clean:
|
||||
$(RM) $(OBJS)
|
||||
|
||||
clobber: clean
|
||||
$(RM) $(TARGETS)
|
||||
|
||||
# In another window:
|
||||
#
|
||||
# openocd-stm -s /usr/local/Cellar/open-ocd/0.12.0/share/openocd/scripts -f openocd-gpu.cfg
|
||||
#
|
||||
# Can do:
|
||||
# - "load" which writes the flash (medium speed, lots of output on st-util)
|
||||
# - "cont" starts/continues system
|
||||
# - "br main" sets breakpoints
|
||||
# - "mon reset" to reset micro
|
||||
# - and so on
|
||||
#
|
||||
debug:
|
||||
arm-none-eabi-gdb $(TARGET_ELF) -x gogo.gdb
|
||||
|
||||
tags:
|
||||
ctags -f .tags *.[ch] -R $(INC_PATHS)
|
||||
|
||||
# EOF
|
||||
97
misc/gpu/README.md
Normal file
@ -0,0 +1,97 @@
|
||||
# GPU on Q1
|
||||
|
||||
The name is a joke. It's not a GPU, just a very simple and cheap micro that can
|
||||
animate a progress bar. And that's all we want it to do.
|
||||
|
||||
It is field upgradable, but we will remove that and start locking it down in
|
||||
production once it's features are stable.
|
||||
|
||||
|
||||
## Hardware
|
||||
|
||||
It's a STM32C011F4:
|
||||
|
||||
- 16k bytes of Flash
|
||||
- 6k bytes of RAM
|
||||
- 4-48Mhz
|
||||
- 18 GPIO
|
||||
- 20 pins
|
||||
- a newer part, so some challenges there
|
||||
|
||||
Of the two TagConnect spots, the GPU is the inboard one; other is for main micro.
|
||||
|
||||
## OpenOCD
|
||||
|
||||
Version 0.12.0 of OpenOCD, the latest release as of this writing, does not yet support this chip.
|
||||
|
||||
You'll need to compile from ST Micro's fork of OpenOCD. In particular we need
|
||||
this diff:
|
||||
<https://github.com/STMicroelectronics/OpenOCD/commit/21c81a2b2edf5402afbba8c22feaeda6f626554e>
|
||||
|
||||
I am using brew's install of normal 0.12.0 for config files, and
|
||||
a compiled version named `openocd-stm`, so my command line is:
|
||||
|
||||
openocd-stm -s /usr/local/Cellar/open-ocd/0.12.0/share/openocd/scripts -f openocd-gpu.cfg
|
||||
|
||||
Useful commands:
|
||||
|
||||
flash erase_sector 0 0 last
|
||||
|
||||
Set EMPTY bit, so goes into BL:
|
||||
|
||||
> mdw 0x40022000
|
||||
0x40022000: 00040600
|
||||
> mmw 0x40022000 0x10000 0
|
||||
> mdw 0x40022000
|
||||
0x40022000: 00050600
|
||||
|
||||
|
||||
|
||||
## In-Circuit Programming
|
||||
|
||||
- AN4221 describes the protocol used to load the flash
|
||||
- timing is sensitive, but more important is where the i2c start/stops fall:
|
||||
|
||||
## First Time Boot
|
||||
|
||||
- on a fresh device, there is an `EMPTY` bit set on power-up (only) if flash looks empty
|
||||
- this causes bootmode to happen, regardless of subsequent flash contents, resets, and `BOOT0` line
|
||||
- so must clear bit 16 of `FLASH_ACR` after loading image: @ `0x40022000`
|
||||
- also, main micro has control over `BOOT0` (PE2) which stop main flash from running too
|
||||
- and the reset line on E6
|
||||
- we use this flag to get into boot mode from working code
|
||||
|
||||
## Getting BOOT0 to work
|
||||
|
||||
- default config in flash bit (option bytes) is to
|
||||
- see `FLASH_OPTR` bit: `nBOOT_SEL` (bit 24) needs to be zero, default is one
|
||||
- `NRST_MODE` should be 0b01 (input only) not default (0b11 = bidirectional)
|
||||
- register `FLASH_OPTR` at 0x40022020 => found as 0xfffffeaa
|
||||
- loads from 0x1FFF7800 at power up
|
||||
- TODO XXX still need this!
|
||||
|
||||
## AN4221 / Bootloader Bugs
|
||||
|
||||
- command 0x00 - 'get' ... returns 19 bytes, but says v1.1 of protocol; clearly v1.2
|
||||
- command 0x02 - 'getid' ... returns 1 byte, but math wrong on length part of response
|
||||
- command 0x01 - 'getversion' ... return 1 byte, and doesn't include length prefix byte
|
||||
- memory read only works from flash, some parts of SRAM... not IO registers
|
||||
- undocumented need for N-1 as length in read/write commands
|
||||
- flash writes need to be 256-aligned, or else they do nothing and don't fail
|
||||
|
||||
## Resource Sharing
|
||||
|
||||
- SPI bus to the display is shared by the GPU and main micro.
|
||||
- Main micro configures its pins as pull-up, open-drain outputs (there is no input except TEAR).
|
||||
- GPU does the same, but no pull-ups (so open drain).
|
||||
- Later turns out we need push-pull I/O to get the SPI speeds involved (rise times too slow
|
||||
with built-in resistors)
|
||||
|
||||
## Other References
|
||||
|
||||
- Ideas, not code: <https://github.com/rogerclarkmelbourne/Arduino_STM32/blob/341cd894516f747f14108de5da593dad99900ae0/tools/macosx/src/stm32flash_serial/src/stm32.c>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
8
misc/gpu/barcode.h
Normal file
@ -0,0 +1,8 @@
|
||||
// autogen file, see make_barcode.py
|
||||
|
||||
// in python: b'\x00\x00\x00\x00\x00\x00\x00?\x1c\x0e\x00\x1f\x8e\x00\xe0\x0f\xf8\xff\x8f\xc7\xe3\xfe?\xe3\xf1\xf8\xff\xf1\xf8\x03\xfe8\xfc\x00\x00\x00\x00\x00\x00\x00'
|
||||
static const uint8_t test_barcode[40] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x1c, 0x0e, 0x00, 0x1f, 0x8e, 0x00, 0xe0, 0x0f, 0xf8, 0xff, 0x8f, 0xc7, 0xe3, 0xfe, 0x3f, 0xe3, 0xf1, 0xf8, 0xff, 0xf1, 0xf8, 0x03, 0xfe, 0x38, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
// EOF
|
||||
62
misc/gpu/basics.h
Normal file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
*/
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
extern void fatal_error(const char *) __attribute__((noreturn));
|
||||
|
||||
// I don't like the ususal assert macro, so here is my replacement,
|
||||
// and BTW: "assert()" is actually a macro, so it should
|
||||
// always be capitalized.
|
||||
//
|
||||
#undef assert
|
||||
#undef ASSERT
|
||||
|
||||
// this does have an impact, but probably doesn't matter.
|
||||
#define __unlikely(x) __builtin_expect((x),0)
|
||||
|
||||
#define ASSERT(x) do { if(__unlikely(!(x))) { fatal_error("assert");} } while(0)
|
||||
|
||||
// Use anywhere. Will just crash on production, but useful in dev.
|
||||
#ifndef RELEASE
|
||||
#define BREAKPOINT asm("BKPT #0")
|
||||
#else
|
||||
#define BREAKPOINT #error
|
||||
#endif
|
||||
|
||||
// An assertion that we will be checked at *compile* time. Useful GCC feature.
|
||||
#define STATIC_ASSERT(cond) _Static_assert(cond, #cond)
|
||||
|
||||
// Similarly: for those times when you want to write ASSERT(False),
|
||||
// use this instead to provide a msg and abort. Altho the msg isn't
|
||||
// in the binary, it's still helpful when looking at source via debugger.
|
||||
//
|
||||
// CAUTION: some security checks end up here, so we want to always crash
|
||||
// in those cases.
|
||||
//
|
||||
#define INCONSISTENT(x) fatal_error("incon")
|
||||
|
||||
// Wait for an interrupt which will never happen (ie. die)
|
||||
#define LOCKUP_FOREVER() while(1) { __WFI(); }
|
||||
|
||||
// Like "sizeof()" but works on arrays, and returns the "numberof" elements.
|
||||
//
|
||||
#define numberof(x) (sizeof(x)/sizeof((x)[0]))
|
||||
|
||||
// This is an old favourite with dangerous programers...
|
||||
//
|
||||
#ifndef offsetof
|
||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
||||
#endif
|
||||
|
||||
#define msizeof(TYPE, MEMBER) sizeof(((TYPE *)0)->MEMBER)
|
||||
|
||||
// Handy macros.
|
||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||
#define CLAMP(x,mn,mx) (((x)>(mx))?(mx):( ((x)<(mn)) ? (mn) : (x)))
|
||||
#define SGN(x) (((x)<0)?-1:(((x)>0)?1:0))
|
||||
#define ABS(x) (((x)<0)?-(x):(x))
|
||||
|
||||
1
misc/gpu/external/cmsis_device_c0
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 7e32bf9d8117ee4c8f6a1d138b814fc24bf4c906
|
||||
1
misc/gpu/external/stm32c0xx_hal_driver
vendored
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 4c5e3e45a8478a33decb1f45d663f485f89c459b
|
||||
22
misc/gpu/gogo.gdb
Normal file
@ -0,0 +1,22 @@
|
||||
add-symbol-file gpu.elf 0x08000000
|
||||
|
||||
# hex for all numbers
|
||||
set output-radix 16
|
||||
|
||||
# kill X repeats N times, which interfere w/ cut-n-paste into python of dumps
|
||||
set print repeats 128
|
||||
|
||||
# Use ST-Link (st-utils)
|
||||
#target extended-remote :4242
|
||||
|
||||
# Connect to the OpenOCD gdb server (needs to be already running & connected)
|
||||
target extended-remote :3333
|
||||
|
||||
define reset
|
||||
mon reset init
|
||||
end
|
||||
|
||||
define wipe_chip
|
||||
mon flash erase_sector 0 0 last
|
||||
mon reset halt
|
||||
end
|
||||
118
misc/gpu/gpu_binary.py
Normal file
@ -0,0 +1,118 @@
|
||||
# (c) Copyright 2023 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
#
|
||||
# Binary for Q1 GPU co-processor
|
||||
#
|
||||
# see misc/gpu for source
|
||||
#
|
||||
VERSION = '1.3.3'
|
||||
|
||||
LENGTH = const(3536) # bytes (after decompression)
|
||||
|
||||
# len(BINARY) = 2618
|
||||
BINARY = (b"x\x9c\x8dW\x7fl\x13\xd7\x1d\xff\xbe\xbbsb;\x8188\xd08?\xcf~\t\x04\x9c\x10'"
|
||||
b'GZ\ne\x1c>j\x12\x1f\xa4\x14J\x051\xdd\x9c\x1f\x853\xa1\xeb\xad\xe9*k\xfdc.'
|
||||
b'\xa8]\xc76\xdabZ\xc0\x866\x90\xfeB\xedF\x16\xc9\x9b\xd6\x11\x95\xb5\xdb\xaa'
|
||||
b'\xb5j\xeb#\xad\xc6\x08ZS\xe8duSWSM\xb5\x81\xc6\xb7\xef\x99P9\x12\x9af\xeb'
|
||||
b'\xeb\xf7\xfd\xf5\xbe\xdf\xcf}\xef\xbd\xef{\x86J\xe0-\x04\xcc\xab,`^\x8d\x04'
|
||||
b"\xff\xe3\xb3\xa6\xc0.!\x7f'\xd2\x16r]g\x8c7\xa3\xff\xc7v#\xe6\xcd\xfc"
|
||||
b'o\xa6/\xc4dK\x14\xad\xa7ap\x17k&\x19\xdcL\x92\xeb\x84)x\x93P\xaa\xda\xc6\xd1'
|
||||
b'\x917|\xfe8\x07\xcc\x9clK\x80\x9bM\xb2]\xd7=l\xe3g|\x86\xad\x14}\x0c{i'
|
||||
b'\xe7\xe3>H\x1f\xbc\x02Nv\xca*\x07\xb6J\x1b\xb96K\xa7U\xf6V\xc6\xbc_OX\xfc'
|
||||
b'\xcc\x14P{\x90k/\x96c\xde+\x13\x90\xfe\xd3\x95\\\n*\xf3\xf1\xf3d\x9e'
|
||||
b'\xa1\xb5Hh\x81t\x824\xfet\xb4\xc2\x85\xf1^\x85\xf4\xb9\xe92y\xb8\xa1g'
|
||||
b'\x90Y\xb4D\xea\xe9\x0f\x0c~fr\x8b$J\xe2\xab)s\x92\x87\xc8B&\xca'
|
||||
b"\x1d\x82\xf4\x85k@\xbf&<0'\x99\xe7\xd8g\xb9CEQH\x9f\xbd\xf6r\x9fe4="
|
||||
b'\x0e6F\xb4%\x98\x06^vv\xf5<\xf0\xe4\xa8U\xec\xb9\xbfg\x10\x9c\xae|'
|
||||
b'\xbcR\x17\x15!\x8a\x99\xe2\x90>1}\x86\x92\xe8\x9b+\xb9(9i\x12\x16t'
|
||||
b'\x16E\x99\x83\x90\xfe\xd5\xb5\x1a\xc4B\x10\xcb\x81\xe9y\xb2}=\x13'
|
||||
b'}\x97\xf2\x80\x1e\x98\xa3m:B\xfb\x948g\x97\xfa\x83\x97\x949~\xbbx\t'
|
||||
b'\xc7\xd2\xfcH\x95\x12\x1c)\x8e\xd6\xfch\x1e\xb5\xe5\xb1\xe8\x1f\xea:'
|
||||
b'p\xb0\xd1\xce\xd9\x00\xee\x01\x91du]\xff1\x92\x9eA\x9a\xd6#\x94\xf5\x07\x98'
|
||||
b'r\xa5D\xb2\x07\xd5uXk\x9e\x11\xcd4\x93\xe8_?\xe0?\x1erxm\xc9OC%R\xc4y\xa9w'
|
||||
b'$\xd4\xc5\x94\x88\x0e\xe8\xac{lM\xb9\nn\xaam\xef*Q\r\xb2\x87\x8f\x87Ht\x9b\\'
|
||||
b"\x1f\xde&\xd7\x86y\xea\xf0\xb6'/\x86\xec\xd2\xa5^\x12\x07w\xb3vO\xb7\xa0"
|
||||
b"\xf6\xb7nK\x96\x9d\xebm\xbd?\xd9\xd7*'\xefm\xadHn\x947\xfa\xab\x82"
|
||||
b'f\xea\x9d\xa2\xca]]%\x88\xf9|\xea\xe1\xd6\xef&\xfd\xf2#\xadBRm\xfd'
|
||||
b'\xb7\xe6\xf7w\xa8\xe81\x05-\xdb\xb5\xce\xce\xb5re\x10\xd2e\xd3\xc4\xe3Q\t'
|
||||
b'=\x81\xf1Gz\xc1\xc5\xd1r8\xea#\xfc\x0e\xdfHH\xf0n\xd0`1I\xde*\xd7\xab\xb0'
|
||||
b'\x84$;\xe4ZU_\x04\x8d\xcc\xc2\xd3>\xa1sY\x17\x1b\xb6*\xe4\x05h]\xafA\x0bI'
|
||||
b'\xb2\xaa5\x98\x19\x87\x96\xa5Z;\xe2(\xa2\x82:\x91\x82\x96E\x9a'
|
||||
b"\x9e\xf9\xa1\xde*7\xf9\xedA\x96\xfe'\xc5\xb6\xd4iM\xfef\xb9<|D\xbd;\xfc7\xd5"
|
||||
b'\xe4<\x10\xeeQ\xab\xc2\xfb\xa4*\xf5\xf7\xe8_\xa6\x11W\x83\xec\x08[Q\xbeO'
|
||||
b'\x1dCM\x91\xc6:y\xd9\xf0(\x07\xc6\xf5Uj\x81\\\x8b\xf1-\xf4\x83T\xff'
|
||||
b'\xae\xc91h-N\x16\xb7\xbcr\xce\xde\xbd\xabfh\xcb\xc7c\x0c\x1cO\xd5\x03'
|
||||
b'\x81\xe7S;}\xaf\xf4\x9dJ\xbd\x12\xba\xcd{*\t\xeeLr~\x98\xac|\xa9'
|
||||
b'\x8f\xb4\x93c\x93c#)\xe3\xdd-\xc55\xdb\x82\xd4\x80\xb4\x0c\xc9\x83\xb4\r\xf7'
|
||||
b'\x84\xae\xe7\xf4F\xe4\x0f"\xbf\x11\xe9^\xa4;P\xee\xc31\xe2\xaa\x92\xe7\x99b'
|
||||
b'\xc1\x88\xcb!o\x02\x87\x828\x91?\x8b\\\xb9\xf7\x9bd\x8fR\xd1U.\xa2L'
|
||||
b'\xacRO\xb0J\x99\x97\x976\x11\xc3+\xa6\x94uY\xc5bg\x0c\xb9}R,\xb8\xdcuD'
|
||||
b'1\x83M,\xf7^\xd5b\x8a\x05m\xb1\xa0E\xb6\xf8{\x82&\xd7\xe1`\x15\xae'
|
||||
b'\x1e\xf8\x02w\xac\xb1\xe6"\xb8\xb4\xdeAJ#=\xa5\xeb\xb6)\x98\xfa\x04\xc1W'
|
||||
b'\xcaC\t\xc7\xee\xca\xce\xe1\x06"9\x06\x1es\x92\x85U\xbb\xbbL\x8cH\x0e\x90'
|
||||
b'\xd8y\xdckV\xe9|\xff\xe4`\t\xee\x10\x88\xeb\x99\xf6\x1c\xa4Og\xf5\xcc\xd6'
|
||||
b'\\\xa9\x7fN\x97])\x11\xedA=\xf3\xeb\x1c\xc5\xf7|U\xe3\x1bi\xc8\xed\xfd'
|
||||
b':\t\xe9\x17\xaf\x18\xdc\xe5\xa4\x9e\x19\xc9]I\x19\xf9\x89\xcd\xd8\xe9'
|
||||
b'\x88\x03\xeb2Lm.\xb3s\xd2dK\xc4z\x8f\xf4\xc5\xfa\xce\xd0\x00\xa9\x01\xb3'
|
||||
b'\xff\x19\xc5!\x1e\xf7^K\xda\x86\x90\xf3~\xa3\x19~\x93\xa6X\xafyE\xac7\xdfs<D'
|
||||
b'\x1c\xa6\x9e\x04\xcen0\xf4G{q\xae\x0b\xa8e\xfd&r\xd8[|aD\xb1\x17\xcc\xf2\x8c'
|
||||
b"\xbf\xa4\xcc\x17\x9f\xc5x\xefo'B\xe3\xd0\x17)c\xfePb.\xd4\x02Y\xb1w,VI^?0V"
|
||||
b'm\xa5jP\xb5[\x97\xf0#\xeaE\x15\x9fEw\x02\xc7\xeb\x99\xf7t\xb2jll\x8b\xe3\x97'
|
||||
b'c\xf3\xac.\xd5\xcd/\xb1\x9ePw\xa8\xff@\x8f\xe1\x19\x8f7\xf4f\xfc=\xa2'
|
||||
b'\x0f\x8d\x0fSu6&\xfa\xc1\xd8\xa7"4\x94\xf8\x03d\x18q\xcd~\x1au\xfcY\xa5V<'
|
||||
b'\x86\xb8\x16\x0c\xdd\xe0\xca\x87\xc8\xb2\xcf\xf3\xf8\xd4D\rp\xaf\xd5=Ia>\xe8'
|
||||
b'\x99Wu\x1e\xda@\x91\xf4\xcc\xfb\xba:nK\xec\x1b\xad\x99\xe9\x8a'
|
||||
b'\x1b\xae\x9d\xa1\xd5\x0cD\xf7\xd0\x00\x90\xe8\x14\x9d\x04&\x1a\xc1J\x84'
|
||||
b'|ql\xaaFgz\xf9\xaaH]\x8a]\xa2AB9\x7fy\x18\xbb\x89j\x1d\xbdQGc-\xa6\x13\x8f'
|
||||
b'\x8fV\x00\x1bu6\xddv\xc1\xb2\xb8\xe3\x82\xa5Q\x91^\xf7\xcd\xe9\xd8 \x95\xd1'
|
||||
b'\xc50o\x91]\xfcsmY\xdb\xc5"\xf8h\xa7\x8f=\xdaWwp\r\xef\x1f\xf0V\x88\xf5'
|
||||
b'\xfe\x17+\x19w\xbd\xb6\x02<@V\xc2A=\xf3\xa2\xbe\x18\x085\xe4\x866['
|
||||
b'\x87\xa1\x89\xeb\x15\x94\xb8\x16\xa3\xc6\x90\x0e\xceHi\x07Yn\xc8?'
|
||||
b'\xd7M\xd8\x97\x89\xdb\x94d\xddW\xb4\x05\x94s\xc1\xc1\xa2)\x16;\x93I3\xcb'
|
||||
b'+\x00\xa2\x0b\xa8\x07\xfe\x99\x02\xc4\x01\xd17\xealmfO\x85p1u\xc6\xc7'
|
||||
b'\xbe\x80\x1d2\x08\x90I\xd4\xca\x9b\x9cp\xea\xd8\xda\xef\xfb\xc0U\xd4'
|
||||
b'P\xd5\xa9\xb7\xd9\x81\x8a\xf7y\x07\xd7Tn\x08xY1\xe0\xd8\x02\xa4}h\xf3'
|
||||
b'>\xefW\x9a\x89\x0e\xbb\xfe\xe5\x04>\xe0\xdd\x84U\x9d\xce\x99\x1al'
|
||||
b'\x1b\x86y\xb7\x12\x81G\x83e\xf4G\n\xb9\xe3HU\x17\xfc\xa0R\xcf|\x98\x83'
|
||||
b'\xe6\xb4\xf6\xa8b\xf1\x13\xc1.r\x1f\xdb\\d\xe5&\xaf]"\xc2\xb8\xcf\x8d\xbd'
|
||||
b'i\xeb\xb4\xae\xdf\xc0 b\r\xcb\x00"\xd9D\x85l \xd9\xed\x8b\xf0.\x00g'
|
||||
b'\x11\x94\xcb\x81\xed\xacX\x0b\x83\x88&\xe0\xb5GDs\x85F\xda\x9a\x16\xdb\xb4a'
|
||||
b'W\x98\x0e/4P\xbc\x91\x0b7\xfe\x06\x9cF\rW\xe9\x99h\x0eZ\xb2\xda\xb8'
|
||||
b'/;\xee\x01\xa6\xfd\xef\xa9\x08\xe6\xd9\x8d\xbdBMD\xe8p\xe3\x13\xa3_\x98&'
|
||||
b'I)\xbe\xfb\xd7z\x8d\xb7\xdf}\x95]XD\x99\x86\x90\xaf\t\xeb\xc3<G\xf0\x94\nd+'
|
||||
b')DoYI\xa2@\r=\xf3\x1c\x17e\xa3\xc6J\xe8\xce:\xbb\x850\xf5r\xb8\x1fO\xea'
|
||||
b'BxD\x12T!<YL>\xd63\x01\xfd\xa10,\xa9K:64+\xd0l\xd3\x84\xf0\xe5p\xa0x'
|
||||
b'\xb2l4\xacg\xbe\xcc\x11\x97\x10\xdeV\xfc\x97\xb2}\x12\xe7<\x00?\x93\xec8'
|
||||
b'\xd3\xe6\xef\xaf1*\xc3\x7f[\x19wp\xb8\xa1b\xe6\x84$W\xeb\xe8g\xa6\x90'
|
||||
b'\x0f\x0fv\xcc\\\x9e\x8d\xd0I2\xd2W4\xaa\xe2\xba3\xd6\xdcr\xa4z\xacY'
|
||||
b'.\x95K\xa9\xeb\x8co:\xf1\x93\xd1\x12\x85y\xa6\xdeE\x9c$j\x02r8`\x06w\x9d\xf6'
|
||||
b'\xb4\xc8\x0b\xd0\xc4`7\xf9\xdd\x95\xb7\xc7\xd8(\x13gc\x01\x05O'
|
||||
b'\xe6\xf8\x84\xb8@\xe3\xe2d%q\x9b\xcf\r*$F\x8eD%&vV\xf1#\xbe\xc1 \xf0'
|
||||
b'\xc5\xb8\xb6j\xf0\xed\x94\x8a\xbcDV\x04\xcc\x7fM\x11\xca\xc6\xc8\xd1\xa8Hb5'
|
||||
b'b\x95\x17\xb4\x89\xa9\x1df\x1e\x04\xa8w\xb5*\xe0V\x0br\xed5r\xb9\x02\x10'
|
||||
b'\x13y8$\x19\x1e\xe0\xdeY`\x1fB;\x173\xec\\\xfc\x16\x89\xacl\r\x12w\xc39&'
|
||||
b'\xceC\\\xa9w\x99\xa2\x02\x9c\xc2\x88[\nf\xf4\xdc$\xe2\xfa\x02'
|
||||
b'\xbb\x1f\xed\xa6|\xc4[\xa4SA#Ru\xe8z\xa4/1\xd2w\n<;n\x12\xa9\xa3\xc0'
|
||||
b'\xde\xf8m$\x03\xdb\x97A\xc6\xfd=m\xe6)\xa7\x88S\x04\x87h\xce\xd7\xe3\xf1'
|
||||
b'T\xa1\xb4\x7f\x964<K:9K\xfa\xed,\xe9\xcc,\tOG\x8d\x89?-\x06B\\\xb4'
|
||||
b'\x03\xb1|\x92-nj\xbb0\x93}\x17\xb8k\x0bpj\xd9\xb7\xc7\xca\\q\xc4YO\x0fI'
|
||||
b'\xb0t\x01\xa2<,\xf2\xf4\xba\xf5\xad\xacQ\xe1x\xbe\x1e\xad}l\x9c\x080+'
|
||||
b'\xd3\xb9\x14\xe1\x07\xc0#rX\xfdG\xcc\x9f\xa4\x16Z\x07\xac\x1e\xa0'
|
||||
b'\x98\xe7A\xccS]\x90\xe7\xd8\xec<\xcd\x15\x9a\xa7 \xcf\xfe\x82<\x0f\xf6\xbd;'
|
||||
b'+\xc7y\xcc\xf1\x08\xf0b\x11\xe6\x180\x7f\x8awRVa@M\x10>P\xd4\xfcQ\xb7R'
|
||||
b'\xa2t\x86\x04\xe9\x03e\xbe"HsC\xa5\xbb\x04i\x7f\x88\x95P\x13\x82RA\xb2uS\xa9'
|
||||
b'Ct\xe3\xedm\xb3\xf2\x0benw\x93$\x88\x95R\x84n\x0cV\x93c^\xeel\x84\xdf\xac'
|
||||
b'\x88\x84\x956\x07#\x14\xf889\xeae4yW|\xcc\xde;\x11b\xf1\xd65\x81g\x84\x08'
|
||||
b'\xba~-}\xfdJH\\\xac\xe2ID%6\xf8\x1e\xc6\xabf8\xc5-Ulh\x16)jd\xc5\xbe\x9e'
|
||||
b'\xede\x959\xa1*\x89\t\xeeU\xf6\x85\xa8\xb8\x17\xc7%\xd2\xa4u\x92\xa9\x92\xf6'
|
||||
b'\x04\xa1\x85KF\xe8\x1e\x9cg\x97\xf6\x06\x19\xc5,W\x89%\x8a\xe1-)~\xf4'
|
||||
b'\xb6K\x12\xee\x19\x0f\xeeO}\xea\xc6=\xf4C\xbd\xc6Ih5w\xd8K&\xa0\xd4v{\xb5'
|
||||
b'5\xcfY\xcd\xb7W[\xf2\x9c\x85\xbb\x9d9a\xdb.V\x1a\xf7S\x8ee\x18\x82'
|
||||
b"\x9f\x1b\xff+X\xd8S\x19\xc5]\xa6\xaes\xa8D\xc0\xf3\x9f\xbe\x85'0,\xb9"
|
||||
b'\xa6m\xad\xc3\x1b\td\x13g|\xd9\xd3\xe6\xd3\xcf\xfb\xd4u\x85|\xdbRa\xa9'
|
||||
b'\x00w\xc9\xe0\xed\x1d\xe0\xfb\x1f\x18X\x9dgz\x1f\xda9\xb4\xfaF\xe8\xd55s'
|
||||
b'\xa1~?L\x95e\xf5\xa7\xde\xb9\x94[}\xe9rV\xbf\x9ces\xcb\xbf\x99q'
|
||||
b'\xc8\xc7\xe0\x1f\x0e=p\xff\xaavO\xfb2O[\xfb\xadK\xdb<\xc2\xad\xed\xed'
|
||||
b'\xfc\xce\xd0\xc3\xab\xee\x16=\xfd;<}\xfd\x1e~\xed\x9d\xf7\xaej\xbb>\xe7s'
|
||||
b'\x00\xf3\x1f\x90\xfe\x0bJ`i=')
|
||||
|
||||
# EOF
|
||||
107
misc/gpu/interrupts.c
Normal file
@ -0,0 +1,107 @@
|
||||
// from https://github.com/STMicroelectronics/STM32CubeC0/blob/main/Projects/STM32C0116-DK/Templates_LL/Src/stm32c0xx_it.c
|
||||
/* USER CODE BEGIN Header */
|
||||
/**
|
||||
******************************************************************************
|
||||
* @file stm32c0xx_it.c
|
||||
* @brief Interrupt Service Routines.
|
||||
******************************************************************************
|
||||
* @attention
|
||||
*
|
||||
* Copyright (c) 2022 STMicroelectronics.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This software is licensed under terms that can be found in the LICENSE file
|
||||
* in the root directory of this software component.
|
||||
* If no LICENSE file comes with this software, it is provided AS-IS.
|
||||
*
|
||||
******************************************************************************
|
||||
*/
|
||||
/* USER CODE END Header */
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "main.h"
|
||||
#include "interrupts.h"
|
||||
|
||||
/******************************************************************************/
|
||||
/* Cortex Processor Interruption and Exception Handlers */
|
||||
/******************************************************************************/
|
||||
/**
|
||||
* @brief This function handles Non maskable interrupt.
|
||||
*/
|
||||
void NMI_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN NonMaskableInt_IRQn 0 */
|
||||
|
||||
/* USER CODE END NonMaskableInt_IRQn 0 */
|
||||
/* USER CODE BEGIN NonMaskableInt_IRQn 1 */
|
||||
while (1)
|
||||
{
|
||||
}
|
||||
/* USER CODE END NonMaskableInt_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Hard fault interrupt.
|
||||
*/
|
||||
void HardFault_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN HardFault_IRQn 0 */
|
||||
|
||||
/* USER CODE END HardFault_IRQn 0 */
|
||||
while (1)
|
||||
{
|
||||
/* USER CODE BEGIN W1_HardFault_IRQn 0 */
|
||||
/* USER CODE END W1_HardFault_IRQn 0 */
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles System service call via SWI instruction.
|
||||
*/
|
||||
void SVC_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN SVC_IRQn 0 */
|
||||
|
||||
/* USER CODE END SVC_IRQn 0 */
|
||||
/* USER CODE BEGIN SVC_IRQn 1 */
|
||||
|
||||
/* USER CODE END SVC_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles Pendable request for system service.
|
||||
*/
|
||||
void PendSV_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN PendSV_IRQn 0 */
|
||||
|
||||
/* USER CODE END PendSV_IRQn 0 */
|
||||
/* USER CODE BEGIN PendSV_IRQn 1 */
|
||||
|
||||
/* USER CODE END PendSV_IRQn 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief This function handles System tick timer.
|
||||
*/
|
||||
void SysTick_Handler(void)
|
||||
{
|
||||
/* USER CODE BEGIN SysTick_IRQn 0 */
|
||||
|
||||
/* USER CODE END SysTick_IRQn 0 */
|
||||
|
||||
/* USER CODE BEGIN SysTick_IRQn 1 */
|
||||
|
||||
/* USER CODE END SysTick_IRQn 1 */
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/* STM32C0xx Peripheral Interrupt Handlers */
|
||||
/* Add here the Interrupt Handlers for the used peripherals. */
|
||||
/* For the available peripheral interrupt handler names, */
|
||||
/* please refer to the startup file (startup_stm32c0xx.s). */
|
||||
/******************************************************************************/
|
||||
|
||||
/* USER CODE BEGIN 1 */
|
||||
|
||||
/* USER CODE END 1 */
|
||||
9
misc/gpu/interrupts.h
Normal file
@ -0,0 +1,9 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
void NMI_Handler(void);
|
||||
void HardFault_Handler(void);
|
||||
void SVC_Handler(void);
|
||||
void PendSV_Handler(void);
|
||||
void SysTick_Handler(void);
|
||||
|
||||
450
misc/gpu/lcd.c
Normal file
@ -0,0 +1,450 @@
|
||||
/*
|
||||
* (c) Copyright 2023 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
*
|
||||
* Control the LCD.
|
||||
*
|
||||
* - see <external/stm32c0xx_hal_driver/Inc/stm32c0xx_ll_spi.h> for the API of the SPI
|
||||
*
|
||||
*/
|
||||
#include "main.h"
|
||||
#include "lcd.h"
|
||||
#include <string.h>
|
||||
#include "stm32c0xx_hal_gpio_ex.h"
|
||||
#include "barcode.h"
|
||||
|
||||
lcd_state_t lcd_state;
|
||||
|
||||
const int LCD_WIDTH = 320;
|
||||
const int LCD_HEIGHT = 240;
|
||||
const int NUM_PIXELS = (LCD_WIDTH*LCD_HEIGHT);
|
||||
|
||||
// doing RGB565, but swab16
|
||||
const uint16_t COL_BLACK = 0;
|
||||
const uint16_t COL_WHITE = ~0;
|
||||
const uint16_t COL_RED = 0x00f8; //SWAP16(0xf800);
|
||||
const uint16_t COL_FOREGROUND = 0x60fd; //SWAB16(0xfd60); // brand orange
|
||||
|
||||
// progress bar specs
|
||||
const uint16_t PROG_HEIGHT = 5;
|
||||
const uint16_t PROG_Y = LCD_HEIGHT - PROG_HEIGHT;
|
||||
|
||||
static const int NUM_PHASES = 16;
|
||||
|
||||
#if 0
|
||||
// memset2()
|
||||
//
|
||||
static inline void
|
||||
memset2(uint16_t *dest, uint16_t value, uint16_t byte_len)
|
||||
{
|
||||
for(; byte_len; byte_len-=2, dest++) {
|
||||
*dest = value;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void wait_vsync(void) {
|
||||
// PA5 is TEAR input: a positive pulse every 60Hz that
|
||||
// corresponds to vertical blanking time
|
||||
uint32_t timeout = 1000000;
|
||||
for(; timeout; timeout--) {
|
||||
if(LL_GPIO_IsInputPinSet(GPIOA, PIN_TEAR)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
//puts("TEAR timeout");
|
||||
}
|
||||
#endif
|
||||
|
||||
// write_byte()
|
||||
//
|
||||
static inline void
|
||||
write_byte(uint8_t b)
|
||||
{
|
||||
while(LL_SPI_GetTxFIFOLevel(SPI1) == LL_SPI_TX_FIFO_FULL) {
|
||||
// wait for space
|
||||
}
|
||||
|
||||
LL_SPI_TransmitData8(SPI1, b);
|
||||
|
||||
while(LL_SPI_GetTxFIFOLevel(SPI1) != LL_SPI_TX_FIFO_EMPTY) {
|
||||
// wait for FIFO to drain completely
|
||||
}
|
||||
}
|
||||
|
||||
// write_bytes()
|
||||
//
|
||||
static inline void
|
||||
write_bytes(int len, const uint8_t *buf)
|
||||
{
|
||||
for(int n=0; n<len; n++, buf++) {
|
||||
while(LL_SPI_GetTxFIFOLevel(SPI1) == LL_SPI_TX_FIFO_FULL) {
|
||||
// wait for space
|
||||
}
|
||||
|
||||
LL_SPI_TransmitData8(SPI1, *buf);
|
||||
}
|
||||
|
||||
while(LL_SPI_GetTxFIFOLevel(SPI1) != LL_SPI_TX_FIFO_EMPTY) {
|
||||
// wait for FIFO to drain completely
|
||||
}
|
||||
}
|
||||
|
||||
// write_uint16()
|
||||
//
|
||||
static inline void
|
||||
write_uint16(int count, uint16_t val)
|
||||
{
|
||||
uint8_t a = val & 0xff;
|
||||
uint8_t b = val >> 8;
|
||||
|
||||
for(int n=0; n<count; n++) {
|
||||
while(LL_SPI_GetTxFIFOLevel(SPI1) == LL_SPI_TX_FIFO_FULL) {
|
||||
// wait for space
|
||||
}
|
||||
LL_SPI_TransmitData8(SPI1, a);
|
||||
|
||||
while(LL_SPI_GetTxFIFOLevel(SPI1) == LL_SPI_TX_FIFO_FULL) {
|
||||
// wait for space
|
||||
}
|
||||
LL_SPI_TransmitData8(SPI1, b);
|
||||
}
|
||||
|
||||
while(LL_SPI_GetTxFIFOLevel(SPI1) != LL_SPI_TX_FIFO_EMPTY) {
|
||||
// wait for FIFO to drain completely
|
||||
}
|
||||
}
|
||||
|
||||
// lcd_write_cmd()
|
||||
//
|
||||
static void
|
||||
lcd_write_cmd(uint8_t cmd)
|
||||
{
|
||||
LL_GPIO_SetOutputPin(GPIOA, PIN_CS);
|
||||
LL_GPIO_ResetOutputPin(GPIOA, PIN_DATA_CMD);
|
||||
LL_GPIO_ResetOutputPin(GPIOA, PIN_CS);
|
||||
|
||||
write_byte(cmd);
|
||||
|
||||
LL_GPIO_SetOutputPin(GPIOA, PIN_CS);
|
||||
LL_GPIO_SetOutputPin(GPIOA, PIN_DATA_CMD);
|
||||
}
|
||||
|
||||
|
||||
// lcd_write_data()
|
||||
//
|
||||
void
|
||||
lcd_write_data(int len, const uint8_t *pixels)
|
||||
{
|
||||
LL_GPIO_SetOutputPin(GPIOA, PIN_CS);
|
||||
LL_GPIO_SetOutputPin(GPIOA, PIN_DATA_CMD);
|
||||
LL_GPIO_ResetOutputPin(GPIOA, PIN_CS);
|
||||
|
||||
write_bytes(len, pixels);
|
||||
|
||||
LL_GPIO_SetOutputPin(GPIOA, PIN_CS);
|
||||
}
|
||||
|
||||
// lcd_write_constant()
|
||||
//
|
||||
void
|
||||
lcd_write_constant(int len, const uint16_t pixel)
|
||||
{
|
||||
LL_GPIO_SetOutputPin(GPIOA, PIN_CS);
|
||||
LL_GPIO_SetOutputPin(GPIOA, PIN_DATA_CMD);
|
||||
LL_GPIO_ResetOutputPin(GPIOA, PIN_CS);
|
||||
|
||||
write_uint16(len, pixel);
|
||||
|
||||
LL_GPIO_SetOutputPin(GPIOA, PIN_CS);
|
||||
}
|
||||
|
||||
// lcd_write_cmd4()
|
||||
//
|
||||
static void
|
||||
lcd_write_cmd4(uint8_t cmd, uint16_t a, uint16_t b)
|
||||
{
|
||||
uint8_t d[4] = { (a>>8), a&0xff, (b>>8), b&0xff };
|
||||
|
||||
lcd_write_cmd(cmd);
|
||||
lcd_write_data(4, d);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// lcd_write_data1()
|
||||
//
|
||||
static void
|
||||
lcd_write_data1(uint8_t data)
|
||||
{
|
||||
lcd_write_data(1, &data);
|
||||
}
|
||||
#endif
|
||||
|
||||
// lcd_spi_setup()
|
||||
//
|
||||
// Just setup SPI, do not reset display, etc.
|
||||
//
|
||||
void
|
||||
lcd_setup(void)
|
||||
{
|
||||
LL_SPI_InitTypeDef init = { 0 };
|
||||
|
||||
// see SPI_InitTypeDef
|
||||
init.TransferDirection = LL_SPI_HALF_DUPLEX_TX;
|
||||
init.Mode = LL_SPI_MODE_MASTER;
|
||||
init.DataWidth = LL_SPI_DATAWIDTH_8BIT;
|
||||
init.ClockPolarity = LL_SPI_POLARITY_LOW;
|
||||
init.ClockPhase = LL_SPI_PHASE_1EDGE;
|
||||
init.NSS = LL_SPI_NSS_SOFT;
|
||||
init.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV2; // measured: 6 Mhz
|
||||
init.BitOrder = LL_SPI_MSB_FIRST;
|
||||
init.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;
|
||||
|
||||
LL_SPI_Init(SPI1, &init);
|
||||
LL_SPI_Enable(SPI1);
|
||||
|
||||
// usually want the busy bar
|
||||
lcd_state.activity_bar = true;
|
||||
|
||||
#if 0
|
||||
// debug values
|
||||
lcd_state.cursor_x = 9;
|
||||
lcd_state.cursor_y = 2;
|
||||
lcd_state.outline_cursor = true;
|
||||
#endif
|
||||
#if 0
|
||||
lcd_state.dbl_wide = true;
|
||||
lcd_state.cursor_x = 16;
|
||||
lcd_state.cursor_y = 4;
|
||||
lcd_state.solid_cursor = true;
|
||||
//lcd_state.outline_cursor = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
// take_control()
|
||||
//
|
||||
// Make the shared SPI bus ours. All push-pull, because we need the speed.
|
||||
// - force PIN_G_CTRL low while we are in control, so CPU knows we are actively
|
||||
// speaking to the LCD
|
||||
//
|
||||
static void
|
||||
take_control(void)
|
||||
{
|
||||
LL_GPIO_SetOutputPin(GPIOA, PIN_GPU_BUSY);
|
||||
|
||||
LL_GPIO_InitTypeDef init = {0};
|
||||
|
||||
init.Pin = SPI_PINS;
|
||||
init.Mode = LL_GPIO_MODE_ALTERNATE;
|
||||
init.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
init.Pull = LL_GPIO_PULL_NO;
|
||||
init.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
|
||||
init.Alternate = GPIO_AF0_SPI1;
|
||||
|
||||
LL_GPIO_Init(GPIOA, &init);
|
||||
|
||||
init.Pin = SPI_CTRL_PINS;
|
||||
init.Mode = LL_GPIO_MODE_OUTPUT;
|
||||
init.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
|
||||
init.Pull = LL_GPIO_PULL_NO;
|
||||
init.OutputType = LL_GPIO_OUTPUT_PUSHPULL;
|
||||
init.Alternate = 0;
|
||||
|
||||
LL_GPIO_Init(GPIOA, &init);
|
||||
}
|
||||
|
||||
// release_control()
|
||||
//
|
||||
// Go back to being a listener only on SPI.
|
||||
//
|
||||
static void
|
||||
release_control(void)
|
||||
{
|
||||
// make all inputs again
|
||||
LL_GPIO_InitTypeDef init = {0};
|
||||
|
||||
init.Pin = SPI_PINS | SPI_CTRL_PINS;
|
||||
init.Mode = LL_GPIO_MODE_INPUT;
|
||||
init.Speed = LL_GPIO_SPEED_FREQ_LOW;
|
||||
init.Pull = LL_GPIO_PULL_NO;
|
||||
|
||||
LL_GPIO_Init(GPIOA, &init);
|
||||
|
||||
LL_GPIO_ResetOutputPin(GPIOA, PIN_GPU_BUSY);
|
||||
}
|
||||
|
||||
// send_window()
|
||||
//
|
||||
static void
|
||||
send_window(int x, int y, int w, int h, const void *data)
|
||||
{
|
||||
// write inclusive range
|
||||
// note, MADCTL MV/MX/MY setting causes row vs. col swap here
|
||||
lcd_write_cmd4(0x2a, x, x+w-1); // CASET - Column address set range (x)
|
||||
lcd_write_cmd4(0x2b, y, y+h-1); // RASET - Row address set range (y)
|
||||
lcd_write_cmd(0x2c); // RAMWR - memory write
|
||||
|
||||
if(data) {
|
||||
// follow with data write of 2*w*h bytes
|
||||
lcd_write_data(2*w*h, (uint8_t *)data);
|
||||
}
|
||||
}
|
||||
|
||||
// send_solid()
|
||||
//
|
||||
static void
|
||||
send_solid(int x, int y, int w, int h, uint16_t pixel)
|
||||
{
|
||||
send_window(x, y, w, h, NULL);
|
||||
|
||||
lcd_write_constant(w*h, pixel);
|
||||
}
|
||||
|
||||
// cursor_draw()
|
||||
//
|
||||
void
|
||||
cursor_draw(int char_x, int char_y, uint8_t ctype, bool phase)
|
||||
{
|
||||
// see shared/lcd.py and shared/font_iosevka.py
|
||||
const int LEFT_MARGIN = 7;
|
||||
const int TOP_MARGIN = 15;
|
||||
const int CHARS_W = 34;
|
||||
const int CHARS_H = 10;
|
||||
const int CELL_W = 9;
|
||||
const int CELL_H = 22;
|
||||
|
||||
// no error reporting.. but dont die either
|
||||
if(char_x >= CHARS_W) return;
|
||||
if(char_y >= CHARS_H) return;
|
||||
|
||||
bool dbl_wide = ctype & 0x10;
|
||||
ctype &= 0xf;
|
||||
|
||||
// top left corner, just on edge of character cell
|
||||
int x = LEFT_MARGIN + (char_x * CELL_W);
|
||||
int y = TOP_MARGIN + (char_y * CELL_H);
|
||||
int cell_w = CELL_W + (dbl_wide?CELL_W:0);
|
||||
|
||||
uint16_t colour = phase ? COL_BLACK : COL_FOREGROUND;
|
||||
|
||||
if(ctype == CURSOR_OUTLINE) {
|
||||
// horz
|
||||
send_solid(x,y, cell_w, 1, colour);
|
||||
send_solid(x,y+CELL_H-1, cell_w, 1, colour);
|
||||
|
||||
// vert
|
||||
send_solid(x, y+1, 1, CELL_H-2, colour);
|
||||
send_solid(x+cell_w-1, y+1, 1, CELL_H-2, colour);
|
||||
}
|
||||
|
||||
if(ctype == CURSOR_SOLID) {
|
||||
if(!phase) {
|
||||
// solid fill -- draw first time
|
||||
send_solid(x,y, cell_w, CELL_H, COL_FOREGROUND);
|
||||
} else {
|
||||
// box shape, blank interior pixels
|
||||
send_solid(x+1,y+1, cell_w-2, CELL_H-2, COL_BLACK);
|
||||
}
|
||||
}
|
||||
|
||||
if(ctype == CURSOR_MENU) {
|
||||
// half-block
|
||||
send_solid(x,y, 4, CELL_H, colour);
|
||||
}
|
||||
}
|
||||
|
||||
// lcd_fill_solid()
|
||||
//
|
||||
void
|
||||
lcd_fill_solid(uint16_t pattern)
|
||||
{
|
||||
// whole screen
|
||||
send_window(0, 0, LCD_WIDTH, LCD_HEIGHT, NULL);
|
||||
lcd_write_constant(LCD_WIDTH*LCD_HEIGHT, pattern);
|
||||
}
|
||||
|
||||
// lcd_draw_progress()
|
||||
//
|
||||
void
|
||||
lcd_draw_progress(void)
|
||||
{
|
||||
static int phase = 0;
|
||||
|
||||
uint16_t row[LCD_WIDTH + NUM_PHASES + 1];
|
||||
|
||||
for(int i=0; i<numberof(row); i++) {
|
||||
row[i] = ((i % 8) < 2) ? COL_BLACK : COL_FOREGROUND;
|
||||
}
|
||||
|
||||
send_window(0, PROG_Y, LCD_WIDTH, PROG_Y-LCD_HEIGHT, NULL);
|
||||
|
||||
for(int y=0; y<PROG_HEIGHT; y++) {
|
||||
lcd_write_data(LCD_WIDTH*2, (uint8_t *)(&row[NUM_PHASES - phase - 1]));
|
||||
}
|
||||
|
||||
phase = (phase + 1) % NUM_PHASES;
|
||||
}
|
||||
|
||||
// lcd_animate()
|
||||
//
|
||||
// Called at LCD frame rate, when we have control over LCD.
|
||||
//
|
||||
void
|
||||
lcd_animate(void)
|
||||
{
|
||||
take_control();
|
||||
|
||||
if(lcd_state.test_pattern) {
|
||||
lcd_test_pattern();
|
||||
lcd_state.test_pattern = false;
|
||||
}
|
||||
|
||||
if(lcd_state.activity_bar) {
|
||||
lcd_draw_progress();
|
||||
}
|
||||
|
||||
if(lcd_state.cursor_type != NO_CURSOR) {
|
||||
static int cur_phase;
|
||||
|
||||
if(cur_phase == 0) {
|
||||
cursor_draw(lcd_state.cursor_x, lcd_state.cursor_y,
|
||||
lcd_state.cursor_type, lcd_state.cur_flash);
|
||||
|
||||
lcd_state.cur_flash = !lcd_state.cur_flash;
|
||||
}
|
||||
|
||||
cur_phase = (cur_phase+1) % 32;
|
||||
}
|
||||
|
||||
release_control();
|
||||
}
|
||||
|
||||
// lcd_test_pattern()
|
||||
//
|
||||
void
|
||||
lcd_test_pattern(void)
|
||||
{
|
||||
// NOTE: this is very limited so it cannot be abused to show arbitrary things
|
||||
// - take packed pixels in (blk/white)
|
||||
// - draw them centered w/ red side border
|
||||
// - repeat same pattern bunch of times.
|
||||
// - used for a linear barcode in selftest process
|
||||
// - important: this cannot render a QR code, nor misleading text.
|
||||
// - LATER: let's just make fully static instead.
|
||||
|
||||
STATIC_ASSERT(sizeof(test_barcode) == LCD_WIDTH/8);
|
||||
|
||||
uint16_t row[LCD_WIDTH];
|
||||
for(int i=0, x=0; i<sizeof(test_barcode); i++) {
|
||||
for(uint8_t m=0x80; m; m >>= 1) {
|
||||
row[x++] = (test_barcode[i] & m) ? COL_BLACK : COL_WHITE;
|
||||
}
|
||||
}
|
||||
|
||||
const int y = 40, h = 120;
|
||||
send_window(0, y, LCD_WIDTH, h, NULL);
|
||||
|
||||
for(int i=0; i<h; i++) {
|
||||
lcd_write_data(sizeof(row), (uint8_t *)&row);
|
||||
}
|
||||
}
|
||||
|
||||
// EOF
|
||||
30
misc/gpu/lcd.h
Normal file
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
static const uint8_t NO_CURSOR = 0;
|
||||
static const uint8_t CURSOR_SOLID = 0x01;
|
||||
static const uint8_t CURSOR_OUTLINE = 0x02;
|
||||
static const uint8_t CURSOR_MENU = 0x03;
|
||||
static const uint8_t CURSOR_DW_OUTLINE = 0x11;
|
||||
static const uint8_t CURSOR_DW_SOLID = 0x12;
|
||||
|
||||
|
||||
typedef struct {
|
||||
bool activity_bar:1;
|
||||
bool test_pattern:1; // self clearing
|
||||
|
||||
bool cur_flash:1; // clear when changing pos/type/enable
|
||||
uint8_t cursor_type;
|
||||
|
||||
uint8_t cursor_x, cursor_y;
|
||||
} lcd_state_t;
|
||||
|
||||
extern lcd_state_t lcd_state;
|
||||
|
||||
void lcd_setup(void);
|
||||
void lcd_animate(void);
|
||||
void lcd_test_pattern(void);
|
||||
|
||||
// EOF
|
||||
213
misc/gpu/link-script.ld
Normal file
@ -0,0 +1,213 @@
|
||||
/**
|
||||
*
|
||||
* a specialized linker script:
|
||||
* - limits itself to just part of the device
|
||||
* - assumes only a small amount of ram is available.
|
||||
* - reference: <https://sourceware.org/binutils/docs/ld/>
|
||||
* - spaces actually matter in expressions in this file
|
||||
*
|
||||
*/
|
||||
|
||||
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
|
||||
OUTPUT_ARCH(arm)
|
||||
SEARCH_DIR(.)
|
||||
|
||||
/* Memory Spaces Definitions */
|
||||
MEMORY
|
||||
{
|
||||
FLASH (rx) : ORIGIN = GPU_FLASH_BASE, LENGTH = GPU_FLASH_SIZE
|
||||
RAM (rwx) : ORIGIN = GPU_SRAM_BASE, LENGTH = GPU_SRAM_SIZE
|
||||
}
|
||||
|
||||
/* from /Applications/ARM/share/gcc-arm-none-eabi/samples/ldscripts/gcc.ld */
|
||||
|
||||
/* Linker script to place sections and symbol values. Should be used together
|
||||
* with other linker script that defines memory regions FLASH and RAM.
|
||||
* It references following symbols, which must be defined in code:
|
||||
* Reset_Handler : Entry of reset handler
|
||||
*
|
||||
* It defines following symbols, which code can use without definition:
|
||||
* __exidx_start
|
||||
* __exidx_end
|
||||
* __copy_table_start__
|
||||
* __copy_table_end__
|
||||
* __zero_table_start__
|
||||
* __zero_table_end__
|
||||
* __etext
|
||||
* __data_start__
|
||||
* __preinit_array_start
|
||||
* __preinit_array_end
|
||||
* __init_array_start
|
||||
* __init_array_end
|
||||
* __fini_array_start
|
||||
* __fini_array_end
|
||||
* __data_end__
|
||||
* __bss_start__
|
||||
* __bss_end__
|
||||
* __end__
|
||||
* end
|
||||
* __HeapLimit
|
||||
* __StackLimit
|
||||
* __StackTop
|
||||
* __stack
|
||||
*/
|
||||
ENTRY(Reset_Handler)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
.text :
|
||||
{
|
||||
KEEP(*(.isr_vector))
|
||||
*(.text*)
|
||||
|
||||
KEEP(*(.init))
|
||||
KEEP(*(.fini))
|
||||
|
||||
/* .ctors */
|
||||
*crtbegin.o(.ctors)
|
||||
*crtbegin?.o(.ctors)
|
||||
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
|
||||
*(SORT(.ctors.*))
|
||||
*(.ctors)
|
||||
|
||||
/* .dtors */
|
||||
*crtbegin.o(.dtors)
|
||||
*crtbegin?.o(.dtors)
|
||||
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors)
|
||||
*(SORT(.dtors.*))
|
||||
*(.dtors)
|
||||
|
||||
*(.rodata*)
|
||||
|
||||
KEEP(*(.eh_frame*))
|
||||
} > FLASH
|
||||
|
||||
.ARM.extab :
|
||||
{
|
||||
*(.ARM.extab* .gnu.linkonce.armextab.*)
|
||||
} > FLASH
|
||||
|
||||
__exidx_start = .;
|
||||
.ARM.exidx :
|
||||
{
|
||||
*(.ARM.exidx* .gnu.linkonce.armexidx.*)
|
||||
} > FLASH
|
||||
__exidx_end = .;
|
||||
|
||||
/* To copy multiple ROM to RAM sections,
|
||||
* uncomment .copy.table section and,
|
||||
* define __STARTUP_COPY_MULTIPLE in startup_ARMCMx.S */
|
||||
/*
|
||||
.copy.table :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__copy_table_start__ = .;
|
||||
LONG (__etext)
|
||||
LONG (__data_start__)
|
||||
LONG (__data_end__ - __data_start__)
|
||||
LONG (__etext2)
|
||||
LONG (__data2_start__)
|
||||
LONG (__data2_end__ - __data2_start__)
|
||||
__copy_table_end__ = .;
|
||||
} > FLASH
|
||||
*/
|
||||
|
||||
/* To clear multiple BSS sections,
|
||||
* uncomment .zero.table section and,
|
||||
* define __STARTUP_CLEAR_BSS_MULTIPLE in startup_ARMCMx.S */
|
||||
/*
|
||||
.zero.table :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__zero_table_start__ = .;
|
||||
LONG (__bss_start__)
|
||||
LONG (__bss_end__ - __bss_start__)
|
||||
LONG (__bss2_start__)
|
||||
LONG (__bss2_end__ - __bss2_start__)
|
||||
__zero_table_end__ = .;
|
||||
} > FLASH
|
||||
*/
|
||||
|
||||
/* Location counter can end up 2byte aligned with narrow Thumb code but
|
||||
__etext is assumed by startup code to be the LMA of a section in RAM
|
||||
which must be 4byte aligned */
|
||||
__etext = ALIGN (4);
|
||||
|
||||
.data : AT (__etext)
|
||||
{
|
||||
__data_start__ = .;
|
||||
*(vtable)
|
||||
*(.data*)
|
||||
|
||||
. = ALIGN(4);
|
||||
/* preinit data */
|
||||
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||
KEEP(*(.preinit_array))
|
||||
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||
|
||||
. = ALIGN(4);
|
||||
/* init data */
|
||||
PROVIDE_HIDDEN (__init_array_start = .);
|
||||
KEEP(*(SORT(.init_array.*)))
|
||||
KEEP(*(.init_array))
|
||||
PROVIDE_HIDDEN (__init_array_end = .);
|
||||
|
||||
|
||||
. = ALIGN(4);
|
||||
/* finit data */
|
||||
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||
KEEP(*(SORT(.fini_array.*)))
|
||||
KEEP(*(.fini_array))
|
||||
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||
|
||||
KEEP(*(.jcr*))
|
||||
. = ALIGN(4);
|
||||
/* All data end */
|
||||
__data_end__ = .;
|
||||
|
||||
} > RAM
|
||||
|
||||
.bss :
|
||||
{
|
||||
. = ALIGN(4);
|
||||
__bss_start__ = .;
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
. = ALIGN(4);
|
||||
__bss_end__ = .;
|
||||
} > RAM
|
||||
|
||||
.heap (COPY):
|
||||
{
|
||||
__end__ = .;
|
||||
PROVIDE(end = .);
|
||||
*(.heap*)
|
||||
__HeapLimit = .;
|
||||
} > RAM
|
||||
|
||||
/* .stack_dummy section doesn't contains any symbols. It is only
|
||||
* used for linker to calculate size of stack sections, and assign
|
||||
* values to stack symbols later */
|
||||
.stack_dummy (COPY):
|
||||
{
|
||||
*(.stack*)
|
||||
} > RAM
|
||||
|
||||
/* Set stack top to end of RAM, and stack limit move down by
|
||||
* size of stack_dummy section */
|
||||
__StackTop = ORIGIN(RAM) + LENGTH(RAM);
|
||||
__StackLimit = __StackTop - SIZEOF(.stack_dummy);
|
||||
PROVIDE(__stack = __StackTop);
|
||||
|
||||
/* Check if data + heap + stack exceeds RAM limit */
|
||||
ASSERT(__StackLimit >= __HeapLimit, "region RAM overflowed with stack")
|
||||
|
||||
/* my values for startup.S code inhirited */
|
||||
PROVIDE(_estack = __StackTop);
|
||||
PROVIDE(_sidata = __init_array_start); /* start address for the init values of the .data section. */
|
||||
PROVIDE(_sdata = __data_start__); /* start address for the .data section. */
|
||||
PROVIDE(_edata = __data_end__); /* end address for the .data section. */
|
||||
PROVIDE(_sbss = __bss_start__); /* start address for the .bss section. */
|
||||
PROVIDE(_ebss = __bss_end__); /* end address for the .bss section. */
|
||||
|
||||
}
|
||||
322
misc/gpu/main.c
Normal file
@ -0,0 +1,322 @@
|
||||
/*
|
||||
* (c) Copyright 2023 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
*/
|
||||
#include "main.h"
|
||||
#include "lcd.h"
|
||||
#include "version.h"
|
||||
#include <string.h>
|
||||
|
||||
// LL/CMSIS internal vars
|
||||
uint32_t SystemCoreClock = 12000000UL;
|
||||
|
||||
#define MY_I2C_ADDR 0x65
|
||||
|
||||
// gpio_setup()
|
||||
//
|
||||
void
|
||||
gpio_setup(void)
|
||||
{
|
||||
LL_GPIO_InitTypeDef init = {0};
|
||||
|
||||
// see external/stm32c0xx_hal_driver/Inc/stm32c0xx_ll_gpio.h
|
||||
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOA);
|
||||
|
||||
//LL_GPIO_SetOutputPin(GPIOA, LL_GPIO_PIN_3);
|
||||
|
||||
// Setup input pins -- which is all!
|
||||
// - make SPI stuff input at this point as well.
|
||||
init.Pin = INPUT_PINS | SPI_PINS | SPI_CTRL_PINS;
|
||||
init.Mode = LL_GPIO_MODE_INPUT;
|
||||
init.Speed = LL_GPIO_SPEED_FREQ_HIGH;
|
||||
init.Pull = LL_GPIO_PULL_NO;
|
||||
|
||||
LL_GPIO_Init(GPIOA, &init);
|
||||
|
||||
// one output PIN: tells CPU we are controlling the bus
|
||||
init.Pin = OUTPUT_PINS;
|
||||
init.Mode = LL_GPIO_MODE_OUTPUT;
|
||||
init.Speed = LL_GPIO_SPEED_FREQ_HIGH;
|
||||
init.Pull = LL_GPIO_PULL_NO;
|
||||
LL_GPIO_Init(GPIOA, &init);
|
||||
|
||||
// clear output signal
|
||||
LL_GPIO_ResetOutputPin(GPIOA, PIN_GPU_BUSY);
|
||||
}
|
||||
|
||||
// i2c_setup()
|
||||
//
|
||||
void
|
||||
i2c_setup(void)
|
||||
{
|
||||
// useful <https://github.com/STMicroelectronics/STM32CubeG0/blob/ae31d181b3244190d7d5bc0d91e66a82ce4270ce/Projects/NUCLEO-G031K8/Examples_LL/I2C/I2C_TwoBoards_MasterRx_SlaveTx_IT_Init/Src/main.c#L205>
|
||||
|
||||
LL_RCC_SetI2CClockSource(LL_RCC_I2C1_CLKSOURCE_PCLK1);
|
||||
LL_IOP_GRP1_EnableClock(LL_IOP_GRP1_PERIPH_GPIOB);
|
||||
|
||||
{
|
||||
// setup pins PB6/7
|
||||
LL_GPIO_InitTypeDef init = {0};
|
||||
|
||||
init.Pin = I2C_PINS;
|
||||
init.Mode = LL_GPIO_MODE_ALTERNATE;
|
||||
init.Speed = LL_GPIO_SPEED_FREQ_LOW;
|
||||
init.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
|
||||
init.Pull = LL_GPIO_PULL_NO;
|
||||
init.Alternate = LL_GPIO_AF_6;
|
||||
|
||||
LL_GPIO_Init(GPIOB, &init);
|
||||
}
|
||||
|
||||
{
|
||||
LL_I2C_InitTypeDef init = {0};
|
||||
|
||||
init.PeripheralMode = LL_I2C_MODE_I2C;
|
||||
|
||||
// from MXCube w/ FastMode @ 12Mhz main micro
|
||||
init.Timing = 0x00100413;
|
||||
|
||||
init.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;
|
||||
init.DigitalFilter = 0x0; // disabled
|
||||
init.OwnAddress1 = MY_I2C_ADDR << 1;
|
||||
init.TypeAcknowledge = LL_I2C_ACK;
|
||||
init.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;
|
||||
|
||||
LL_I2C_Init(I2C1, &init);
|
||||
|
||||
LL_I2C_EnableAutoEndMode(I2C1);
|
||||
LL_I2C_SetOwnAddress2(I2C1, 0, LL_I2C_OWNADDRESS2_NOMASK);
|
||||
LL_I2C_DisableOwnAddress2(I2C1);
|
||||
LL_I2C_DisableGeneralCall(I2C1);
|
||||
LL_I2C_EnableClockStretching(I2C1);
|
||||
}
|
||||
}
|
||||
|
||||
// enter_bootloader()
|
||||
//
|
||||
void
|
||||
enter_bootloader(void)
|
||||
{
|
||||
// Force entry into bootloader on next reset
|
||||
SET_BIT(FLASH->ACR, FLASH_ACR_PROGEMPTY);
|
||||
}
|
||||
|
||||
// i2c_poll()
|
||||
//
|
||||
void
|
||||
i2c_poll(void)
|
||||
{
|
||||
static uint8_t cmd, respLen, argLen;
|
||||
static uint8_t args[8];
|
||||
static const char *resp;
|
||||
static bool isRead;
|
||||
|
||||
// do we have work from I2C port?
|
||||
if(I2C1->ISR & I2C_ISR_ADDR) {
|
||||
// we are selected; note DIR and ADDR
|
||||
I2C1->ICR |= I2C_ICR_ADDRCF;
|
||||
|
||||
isRead = !!(I2C1->ISR & I2C_ISR_DIR);
|
||||
|
||||
// reset our state
|
||||
if(!isRead) {
|
||||
cmd = 0;
|
||||
argLen = 0;
|
||||
} else {
|
||||
// during write to us, allow any length, but we might ignore stuff
|
||||
CLEAR_BIT(I2C1->CR1, I2C_CR1_SBC); // start bit control BROKEN?
|
||||
}
|
||||
}
|
||||
|
||||
if(I2C1->ISR & I2C_ISR_STOPF) {
|
||||
// master is done sending us bytes
|
||||
I2C1->ICR |= I2C_ICR_STOPCF;
|
||||
|
||||
// Implement the command logic after STOP of the sending request
|
||||
// - sending strings as zero-terminated
|
||||
// - for other responses, master will need to know true length of response
|
||||
if(!isRead) {
|
||||
respLen = 0;
|
||||
switch(cmd) {
|
||||
case 'V': // full version
|
||||
if(argLen != 0) goto bad_args;
|
||||
resp = version_string;
|
||||
respLen = strlen(version_string)+1;
|
||||
break;
|
||||
|
||||
case 'v': // short version
|
||||
if(argLen != 0) goto bad_args;
|
||||
resp = RELEASE_VERSION;
|
||||
respLen = strlen(RELEASE_VERSION)+1;
|
||||
break;
|
||||
|
||||
case 'p': // ping
|
||||
resp = (const char *)args;
|
||||
respLen = argLen;
|
||||
break;
|
||||
|
||||
case 'b': // enter bootloader (follow w/ hard reset)
|
||||
if(argLen != 0) goto bad_args;
|
||||
enter_bootloader();
|
||||
resp = "OK";
|
||||
respLen = 3;
|
||||
break;
|
||||
|
||||
case 'c': // enable cursor: args=x,y,ctype
|
||||
if(argLen != 3) goto bad_args;
|
||||
lcd_state.activity_bar = false;
|
||||
lcd_state.cursor_x = args[0];
|
||||
lcd_state.cursor_y = args[1];
|
||||
lcd_state.cursor_type = args[2];
|
||||
lcd_state.cur_flash = false;
|
||||
break;
|
||||
|
||||
case 'a': // disable cursor (implied: enable activity bar)
|
||||
if(argLen != 0) goto bad_args;
|
||||
lcd_state.activity_bar = true;
|
||||
lcd_state.cursor_type = NO_CURSOR;
|
||||
break;
|
||||
|
||||
case 't': // test feature: draw a single test pattern
|
||||
if(argLen != 0) goto bad_args;
|
||||
lcd_state.test_pattern = true;
|
||||
lcd_state.activity_bar = false;
|
||||
lcd_state.cursor_type = NO_CURSOR;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
default:
|
||||
resp = "Bad cmd?";
|
||||
respLen = strlen(resp);
|
||||
break;
|
||||
|
||||
bad_args:
|
||||
resp = "Bad args?";
|
||||
respLen = strlen(resp);
|
||||
break;
|
||||
}
|
||||
|
||||
// critical: flush old data
|
||||
SET_BIT(I2C1->ISR, I2C_ISR_TXE);
|
||||
|
||||
// prepare for N byte response (respLen)
|
||||
//BROKEN//SET_BIT(I2C1->CR1, I2C_CR1_SBC); // start bit control
|
||||
//BROKEN//MODIFY_REG(I2C1->CR2, I2C_CR2_NBYTES_Msk, (respLen << I2C_CR2_NBYTES_Pos));
|
||||
//BROKEN//SET_BIT(I2C1->CR2, I2C_CR2_RELOAD);
|
||||
}
|
||||
}
|
||||
|
||||
while(I2C1->ISR & I2C_ISR_RXNE) {
|
||||
// master sent us a byte
|
||||
uint8_t rx = I2C1->RXDR;
|
||||
|
||||
if(cmd == 0) {
|
||||
cmd = rx;
|
||||
} else {
|
||||
if(argLen < sizeof(args)) {
|
||||
args[argLen++] = rx;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while(isRead && (I2C1->ISR & I2C_ISR_TXIS)) {
|
||||
// master wants to read a byte from us
|
||||
if(respLen) {
|
||||
// keep sending response
|
||||
I2C1->TXDR = *resp;
|
||||
resp++;
|
||||
respLen--;
|
||||
} else {
|
||||
// send NACK -- Doesn't work...
|
||||
//BROKEN//SET_BIT(I2C1->CR2, I2C_CR2_NACK);
|
||||
//BROKEN//SET_BIT(I2C1->ISR, I2C_ISR_TXE);
|
||||
|
||||
// workaround: give it something
|
||||
I2C1->TXDR = 0xff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clock_setup()
|
||||
//
|
||||
// Called from startup.S, before C runtime setup
|
||||
//
|
||||
void
|
||||
clock_setup(void)
|
||||
{
|
||||
// Vector Table Relocation in Internal FLASH (see interrupts.c)
|
||||
SCB->VTOR = FLASH_BASE;
|
||||
|
||||
// HSI configuration and activation
|
||||
LL_RCC_HSI_Enable();
|
||||
while(LL_RCC_HSI_IsReady() != 1)
|
||||
;
|
||||
|
||||
LL_RCC_HSI_SetCalibTrimming(64);
|
||||
LL_RCC_SetHSIDiv(LL_RCC_HSI_DIV_4);
|
||||
LL_RCC_SetAHBPrescaler(LL_RCC_HCLK_DIV_1);
|
||||
|
||||
// Sysclk activation on the HSI
|
||||
LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_HSI);
|
||||
while(LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_HSI)
|
||||
;
|
||||
|
||||
// Set APB1 prescaler
|
||||
LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
|
||||
|
||||
// WAS:
|
||||
// LL_Init1msTick(12000000);
|
||||
// LL_SetSystemCoreClock(12000000);
|
||||
// but, this saves 296-324 bytes because it avoids a division that pulls in a math helper
|
||||
//SysTick->LOAD = (uint32_t)((12000000 / 1000) - 1UL); // set reload register
|
||||
SysTick->LOAD = 11999;
|
||||
SysTick->VAL = 0; // Load the SysTick Counter Value
|
||||
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
|
||||
SysTick_CTRL_ENABLE_Msk; // Enable the Systick Timer
|
||||
}
|
||||
|
||||
// mainloop()
|
||||
//
|
||||
// TODO: add naked attr and debug why that kills the code, or waste stack space forever
|
||||
//
|
||||
void __attribute__((noreturn))
|
||||
mainloop(void)
|
||||
{
|
||||
// Reset & enable of all peripherals we are using.
|
||||
LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG | LL_APB2_GRP1_PERIPH_SPI1);
|
||||
LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR | LL_APB1_GRP1_PERIPH_I2C1);
|
||||
|
||||
// Our setup code.
|
||||
gpio_setup();
|
||||
lcd_setup();
|
||||
i2c_setup();
|
||||
|
||||
// If we started ok, flash isn't empty and we don't need to force
|
||||
// entry into bootloader anymore.
|
||||
CLEAR_BIT(FLASH->ACR, FLASH_ACR_PROGEMPTY);
|
||||
|
||||
while(1) {
|
||||
i2c_poll();
|
||||
|
||||
// G_CTRL must be low, and TEAR high, and if so we can write to LCD.
|
||||
if(!LL_GPIO_IsInputPinSet(GPIOA, PIN_G_CTRL)
|
||||
&& LL_GPIO_IsInputPinSet(GPIOA, PIN_TEAR)
|
||||
) {
|
||||
lcd_animate();
|
||||
|
||||
// wait until start of next frame before looking again
|
||||
while(LL_GPIO_IsInputPinSet(GPIOA, PIN_TEAR)) {
|
||||
i2c_poll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// fatal_error()
|
||||
//
|
||||
void __attribute__((noreturn))
|
||||
fatal_error(const char *msg)
|
||||
{
|
||||
while(1) ;
|
||||
}
|
||||
|
||||
// EOF
|
||||
38
misc/gpu/main.h
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* (c) Copyright 2018 by Coinkite Inc. This file is covered by license found in COPYING-CC.
|
||||
*/
|
||||
#pragma once
|
||||
#include "basics.h"
|
||||
|
||||
// note: USE_FULL_LL_DRIVER is defined in Makefile for all files.
|
||||
|
||||
#include "stm32c0xx.h"
|
||||
#include "stm32c0xx_ll_bus.h"
|
||||
#include "stm32c0xx_ll_gpio.h"
|
||||
#include "stm32c0xx_ll_spi.h"
|
||||
#include "stm32c0xx_ll_i2c.h"
|
||||
#include "stm32c0xx_ll_rcc.h"
|
||||
#include "stm32c0xx_ll_utils.h"
|
||||
|
||||
// Pins in use: be careful, most are also controlled by main micro
|
||||
|
||||
// Port A
|
||||
#define PIN_G_CTRL LL_GPIO_PIN_0
|
||||
#define PIN_SCLK LL_GPIO_PIN_1
|
||||
#define PIN_MOSI LL_GPIO_PIN_2
|
||||
#define PIN_DATA_CMD LL_GPIO_PIN_3
|
||||
#define PIN_CS LL_GPIO_PIN_4
|
||||
#define PIN_TEAR LL_GPIO_PIN_5
|
||||
#define PIN_GPU_BUSY LL_GPIO_PIN_14 // G_SWCLK_B0 pin to CPU
|
||||
|
||||
#define INPUT_PINS (PIN_TEAR | PIN_G_CTRL)
|
||||
#define OUTPUT_PINS (PIN_GPU_BUSY)
|
||||
#define SPI_PINS (PIN_MOSI | PIN_SCLK)
|
||||
#define SPI_CTRL_PINS (PIN_DATA_CMD | PIN_CS)
|
||||
|
||||
// Port B
|
||||
#define PIN_SCL LL_GPIO_PIN_6
|
||||
#define PIN_SDA LL_GPIO_PIN_7
|
||||
#define I2C_PINS PIN_SCL | PIN_SDA
|
||||
|
||||
// EOF
|
||||
93
misc/gpu/make_barcode.py
Normal file
@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env python3
|
||||
#
|
||||
# Render a little barcode we need for selftest process.
|
||||
#
|
||||
# - packed bytes
|
||||
#
|
||||
import barcode
|
||||
from io import BytesIO
|
||||
from barcode import Code128
|
||||
from barcode.writer import ImageWriter
|
||||
|
||||
|
||||
class Packer(barcode.writer.BaseWriter):
|
||||
# api in <../../ENV/lib/python3.10/site-packages/barcode/writer.py>
|
||||
def __init__(self):
|
||||
super().__init__(initialize=self.do_init,
|
||||
paint_module=self.paint, paint_text=self.do_text, finish=self.do_fin)
|
||||
|
||||
def do_init(self, code):
|
||||
# the answer I want is given to init function: binary for black/white sections
|
||||
assert len(code) == 1, 'not a list?'
|
||||
code = code[0]
|
||||
|
||||
if len(code) % 2:
|
||||
code += '0'
|
||||
while (len(code) % 8) != 0:
|
||||
code = f'0{code}0'
|
||||
|
||||
#code = code.replace('0', '00').replace('1', '11') # double it up
|
||||
code = code.replace('0', '000').replace('1', '111') # 3X
|
||||
#code = code.replace('0', '0000').replace('1', '1111') # 4X
|
||||
|
||||
# pad to 320 pixels (div 8) (centered)
|
||||
while len(code) < 320:
|
||||
code = f'0000{code}0000'
|
||||
|
||||
# convert to bytes
|
||||
self.result = int(code, 2).to_bytes(len(code)//8, 'big')
|
||||
|
||||
def do_text(self, *unused):
|
||||
pass
|
||||
|
||||
def paint(self, xpos, ypos, width, color):
|
||||
#print(f'paint: pos={xpos},{ypos} w={width} c={color}')
|
||||
pass
|
||||
|
||||
def do_fin(self):
|
||||
return self.result
|
||||
|
||||
def doit(ofile='barcode.h'):
|
||||
|
||||
# contents of barcode
|
||||
if 0:
|
||||
# works, but overkill and reads better if simpler
|
||||
version = None
|
||||
with open('version.h') as fd:
|
||||
for ln in fd:
|
||||
if 'RELEASE_VERSION' in ln:
|
||||
version = eval(ln.split()[-1])
|
||||
break
|
||||
assert version
|
||||
msg = f'GPU={version}'
|
||||
|
||||
msg = f'GPU'
|
||||
bc = Code128(msg, writer=Packer())
|
||||
rv = bc.render()
|
||||
|
||||
#bc2 = Code128(msg, writer=ImageWriter())
|
||||
#bc2.write('check.png')
|
||||
|
||||
#print(f'Result: {rv.hex()} len={len(rv)}')
|
||||
|
||||
assert len(rv) * 8 <= 320, 'too wide to fit on screen'
|
||||
assert len(rv) == 40, 'expected 320 pixels'
|
||||
|
||||
enc = rv.hex(' ', 1).replace(' ', ', 0x')
|
||||
|
||||
with open(ofile, 'wt') as fd:
|
||||
fd.write(f'''// autogen file, see make_barcode.py
|
||||
|
||||
// in python: {repr(rv)}
|
||||
static const uint8_t test_barcode[{len(rv)}] = {{
|
||||
0x{enc}
|
||||
}};
|
||||
|
||||
// EOF''')
|
||||
|
||||
print(f"Updated: {ofile}")
|
||||
|
||||
if __name__ == '__main__':
|
||||
doit()
|
||||
|
||||
# EOF
|
||||
64
misc/gpu/openocd-gpu.cfg
Normal file
@ -0,0 +1,64 @@
|
||||
# This script configures OpenOCD for use with an ST-Link V2 programmer/debugger
|
||||
# and an STM32L4S5 target microcontroller.
|
||||
#
|
||||
# To flash your firmware:
|
||||
#
|
||||
# $ openocd -f openocd_stm32l4x6.cfg \
|
||||
# -c "stm_flash build-BOARD/firmware0.bin 0x08000000 build-BOARD/firmware1.bin 0x08004000"
|
||||
#
|
||||
# For a gdb server on port 3333:
|
||||
#
|
||||
# $ openocd -f openocd_stm32l4x6.cfg
|
||||
|
||||
|
||||
source [find interface/stlink.cfg]
|
||||
transport select hla_swd
|
||||
#source [find target/stm32c011.cfg]
|
||||
source stm32c0x.cfg
|
||||
|
||||
# from <http://www.openstm32.org/forumthread7123>
|
||||
#reset_config srst_only
|
||||
reset_config none separate
|
||||
|
||||
init
|
||||
|
||||
proc stm_flash { BIN0 ADDR0 BIN1 ADDR1 } {
|
||||
reset halt
|
||||
sleep 100
|
||||
wait_halt 2
|
||||
flash write_image erase $BIN0 $ADDR0
|
||||
sleep 100
|
||||
verify_image $BIN0 $ADDR0
|
||||
sleep 100
|
||||
flash write_image erase $BIN1 $ADDR1
|
||||
sleep 100
|
||||
verify_image $BIN1 $ADDR1
|
||||
sleep 100
|
||||
reset run
|
||||
shutdown
|
||||
}
|
||||
|
||||
proc stm_erase {} {
|
||||
reset halt
|
||||
sleep 100
|
||||
stm32l4x mass_erase 0
|
||||
sleep 100
|
||||
shutdown
|
||||
}
|
||||
|
||||
proc dfu {} {
|
||||
# reset and get it started; doesn't work from "reset halt" nor "reset init"
|
||||
reset run
|
||||
halt
|
||||
|
||||
# SYSCFG->MEMRMP setup for system flash @ 0x0
|
||||
# do __HAL_SYSCFG_REMAPMEMORY_SYSTEMFLASH()
|
||||
mww 0x40010000 0x1
|
||||
|
||||
# do "mdw 0x0 2" to learn these two values
|
||||
reg msp 0x20003560
|
||||
reg pc 0x1fff51db
|
||||
|
||||
resume
|
||||
sleep 500
|
||||
}
|
||||