Compare commits
1264 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
775fb76cb8 | ||
|
|
af1374cb18 | ||
|
|
f07079bb7d | ||
|
|
e7a23550ce | ||
|
|
0beb2d4ae8 | ||
|
|
e5efb8b764 | ||
|
|
4de3ea94a9 | ||
|
|
68f1da5f94 | ||
|
|
948e9bfd22 | ||
|
|
73bd6a0891 | ||
|
|
ecd662640f | ||
|
|
0f211d1aa5 | ||
|
|
f3df355663 | ||
|
|
7dcfe4d483 | ||
|
|
3df1392a1b | ||
|
|
9043412c5f | ||
|
|
7c51742522 | ||
|
|
08353deb88 | ||
|
|
d5e844b2bd | ||
|
|
de7f1a7e83 | ||
|
|
19b14898ea | ||
|
|
304e9ce2d1 | ||
|
|
2bc00bef57 | ||
|
|
47c2cd2b0b | ||
|
|
59614a99c8 | ||
|
|
227d71ed18 | ||
|
|
5e74bbbbb2 | ||
|
|
8d58a9207f | ||
|
|
bc5b2c24ff | ||
|
|
40b9d5b07e | ||
|
|
07ea22d877 | ||
|
|
253e946dcb | ||
|
|
60d28d6c92 | ||
|
|
e8bd9daa82 | ||
|
|
9747990c16 | ||
|
|
299f8e28f2 | ||
|
|
6e48cffd62 | ||
|
|
123ae0ff8b | ||
|
|
0420446529 | ||
|
|
88c717d420 | ||
|
|
9ac7892bd6 | ||
|
|
407bdc93f4 | ||
|
|
91f8872a63 | ||
|
|
d938633048 | ||
|
|
073094fe0e | ||
|
|
2a46bcfc0f | ||
|
|
e05dd50d62 | ||
|
|
54885d79e0 | ||
|
|
cc96a13bed | ||
|
|
e24489b69d | ||
|
|
ecf2b2e39f | ||
|
|
49397a7f3d | ||
|
|
aabbba67ce | ||
|
|
50b9ea99bd | ||
|
|
beece2ec9d | ||
|
|
1a8735700f | ||
|
|
cc1af990b4 | ||
|
|
0ec1dc6724 | ||
|
|
15d1c6813a | ||
|
|
cdf0a65d0f | ||
|
|
e60858c327 | ||
|
|
bebd1dff50 | ||
|
|
14145e4469 | ||
|
|
d9d556bcd0 | ||
|
|
5bd1a3a0f6 | ||
|
|
5bfc35caf5 | ||
|
|
8e1e709ab1 | ||
| 46a58fb4b5 | |||
|
|
8deb6b9724 | ||
| 6236d1f7c5 | |||
|
|
91ce323a68 | ||
|
|
2f82bfd22a | ||
|
|
1689c75ef1 | ||
| bd5492b6e4 | |||
| eef8dd138c | |||
|
|
935eb64a8e | ||
|
|
e3ee60f6eb | ||
|
|
31786cdc24 | ||
|
|
3d17a56ecf | ||
|
|
3cb5c315f3 | ||
|
|
c65cbded84 | ||
|
|
0148b1469c | ||
|
|
96a4059f09 | ||
|
|
c3d15931a4 | ||
|
|
22dfda2c1c | ||
|
|
cab65de189 | ||
|
|
c79e543c41 | ||
|
|
3c556e6729 | ||
|
|
9c680bd65f | ||
|
|
5e2fbf324b | ||
|
|
fb82f16704 | ||
|
|
79568a3e63 | ||
|
|
b506c010f7 | ||
|
|
8c3170596f | ||
|
|
acf81f426c | ||
|
|
a426fbf51d | ||
|
|
e133147192 | ||
|
|
84826935a9 | ||
|
|
9480c2a55d | ||
|
|
b3d0ccc7e3 | ||
|
|
5a34395f46 | ||
|
|
e20c973bf5 | ||
|
|
452ef17174 | ||
|
|
4785c16243 | ||
|
|
2506b8e1d1 | ||
|
|
7bfe25b8aa | ||
|
|
2348051026 | ||
|
|
b4001bfb0e | ||
|
|
0655b7d5b6 | ||
|
|
83b8d122d7 | ||
|
|
8caa590f5c | ||
|
|
ec528d34f8 | ||
|
|
5296241949 | ||
|
|
d84ff02f03 | ||
|
|
cc2581afd6 | ||
|
|
bb682bbb33 | ||
|
|
809beffc8b | ||
|
|
fa22c6c627 | ||
|
|
0788a42477 | ||
|
|
d732ac82ba | ||
|
|
5fb5e16be8 | ||
|
|
45c0b3a1b4 | ||
|
|
7961d2943d | ||
|
|
4d03edc7d5 | ||
|
|
d5a6888cac | ||
|
|
a13d236afd | ||
|
|
2f99b0ae2f | ||
|
|
681a4c5482 | ||
|
|
eecbcdf59a | ||
|
|
f1b965f704 | ||
|
|
66af359578 | ||
|
|
d65b030644 | ||
|
|
33b126836f | ||
|
|
def00bac66 | ||
|
|
06e3ef9556 | ||
|
|
dc0dc50e36 | ||
|
|
21a767e7e4 | ||
|
|
a02e188fc7 | ||
|
|
e56a295e34 | ||
|
|
5b4dff9a77 | ||
|
|
abc07ef4e5 | ||
|
|
0061d3f97f | ||
|
|
48bc91af36 | ||
|
|
1725e2109f | ||
|
|
f2d30abb1c | ||
|
|
f2fc68f55e | ||
|
|
34e02aaeb5 | ||
|
|
6024e9a7e8 | ||
|
|
633faa18ac | ||
|
|
90d4841be7 | ||
|
|
e16c459598 | ||
|
|
33b0fd57a0 | ||
|
|
7add6250e0 | ||
|
|
4068601b01 | ||
|
|
9cea4708c8 | ||
| 1a41be1eb0 | |||
|
|
996c3bfab9 | ||
|
|
322a1af6da | ||
|
|
e25d382732 | ||
|
|
bda12cd7e7 | ||
|
|
ca30518510 | ||
|
|
17aab7e373 | ||
|
|
083d86d251 | ||
|
|
7a0adfebd1 | ||
|
|
db4b167aaa | ||
|
|
5a428647d4 | ||
|
|
6c8d62fdb8 | ||
|
|
64156c42b1 | ||
|
|
f5c4136b94 | ||
|
|
c4b6521849 | ||
|
|
593b3bece4 | ||
|
|
5ef8a5a5cc | ||
|
|
b0e7ad3de2 | ||
|
|
0d26c5eded | ||
|
|
5b135fabc4 | ||
|
|
3aa8df5ab7 | ||
|
|
9c217b13df | ||
|
|
d96c0e6818 | ||
|
|
599c226b8c | ||
|
|
e7419fbdf9 | ||
|
|
060b15fa27 | ||
|
|
4e9a6de09e | ||
|
|
4aee8beeea | ||
|
|
fdd7557156 | ||
|
|
49f83c4310 | ||
|
|
edba2faa34 | ||
|
|
c97c61dce5 | ||
|
|
a314a8c3d7 | ||
|
|
58c0d95114 | ||
|
|
2324d52023 | ||
|
|
b9dadbbdc2 | ||
|
|
6eead5b0df | ||
|
|
5f77e12984 | ||
|
|
2f55223b70 | ||
|
|
67bf5a734a | ||
|
|
ec6bb7e924 | ||
|
|
059bd590d7 | ||
|
|
9d17f42a35 | ||
|
|
1f1fa11216 | ||
|
|
690293e7e1 | ||
|
|
500fcf2513 | ||
|
|
a2164a5b10 | ||
|
|
25501953df | ||
|
|
f6973fc64d | ||
|
|
f49d058477 | ||
|
|
777eacdfc3 | ||
|
|
39ad2aeced | ||
|
|
a9fd579ce9 | ||
|
|
a6ab6e1f95 | ||
|
|
b2ec6ecb09 | ||
|
|
f18fa88565 | ||
|
|
07b7d9748b | ||
|
|
66c1f78f7d | ||
|
|
f6940cc04e | ||
|
|
5830cd8e7d | ||
|
|
2063a2d23d | ||
|
|
4504d72972 | ||
|
|
5db8063756 | ||
|
|
5fbda35282 | ||
|
|
163b209d6c | ||
|
|
ccdc76c279 | ||
|
|
e88d2d0469 | ||
|
|
a0b3876de4 | ||
|
|
5f6e4aff5c | ||
|
|
4d1d1d2304 | ||
|
|
1f291482cd | ||
|
|
d26a358055 | ||
|
|
aaaa99d969 | ||
|
|
12130eb767 | ||
|
|
f5c85fa958 | ||
|
|
ee9649a032 | ||
|
|
4098ba29af | ||
|
|
76811d3c66 | ||
|
|
20c69bdfbd | ||
|
|
a9b390296f | ||
|
|
8f7ddb6dc3 | ||
|
|
3e24400beb | ||
|
|
be2174bdb6 | ||
|
|
70b273544e | ||
|
|
e0ff046f37 | ||
|
|
5e07682d11 | ||
|
|
902f709f6f | ||
|
|
bf33170691 | ||
|
|
50cb17497b | ||
|
|
48c4c20251 | ||
|
|
6a5f98c7ef | ||
|
|
bc7adf42c2 | ||
|
|
94c9932417 | ||
|
|
cde5fe3de5 | ||
|
|
226a318897 | ||
|
|
729163d0cc | ||
|
|
42a0c88174 | ||
|
|
7a9c4271d1 | ||
|
|
ca623a9643 | ||
|
|
057896899c | ||
|
|
9f65f25992 | ||
|
|
0c78fbd6c1 | ||
|
|
2cac51ee4b | ||
|
|
404f188e25 | ||
|
|
84828f0461 | ||
|
|
b2428763d6 | ||
|
|
99a907b0d7 | ||
|
|
9cb9226744 | ||
|
|
f4bffc6ec6 | ||
|
|
94af6f8aca | ||
|
|
45e5ca16da | ||
|
|
b8408961b3 | ||
|
|
ba1face5f1 | ||
|
|
33694a1fcc | ||
|
|
815e17b35a | ||
|
|
32f031112f | ||
|
|
f45db86cc2 | ||
|
|
16d9609ac9 | ||
|
|
2a73651a8c | ||
|
|
bd64b97a20 | ||
|
|
525408e181 | ||
|
|
e022d47e80 | ||
|
|
28b0edac21 | ||
|
|
4bd7d99c96 | ||
|
|
06572e365b | ||
|
|
e86f8f5002 | ||
|
|
4f4e638aee | ||
|
|
34f386a21b | ||
|
|
dd1c9095e8 | ||
|
|
8140c354c7 | ||
|
|
5c4eb022c1 | ||
|
|
6e5b3897b7 | ||
|
|
f3b8c58157 | ||
|
|
6d115cdcec | ||
|
|
9f66e834d4 | ||
|
|
096990123d | ||
|
|
ea2de469a2 | ||
|
|
80196d570b | ||
|
|
1f71135a2b | ||
|
|
c4e713247e | ||
|
|
bd902a93f5 | ||
|
|
372fef06e1 | ||
|
|
41ce4b2f8b | ||
|
|
e8a2654296 | ||
|
|
a584d10321 | ||
|
|
5cdd58dfb8 | ||
|
|
96a2e925cf | ||
|
|
8cb8807573 | ||
|
|
2cde8bd789 | ||
|
|
99b32b8436 | ||
|
|
91240567ce | ||
|
|
247e48fa85 | ||
|
|
268d0aa1c5 | ||
|
|
553f7604ea | ||
|
|
1357e4a37b | ||
|
|
fdc361aff9 | ||
|
|
7df8c35e81 | ||
|
|
2297d61d92 | ||
|
|
6d601250d6 | ||
|
|
c99614c1f5 | ||
|
|
352d363463 | ||
|
|
1775fedf44 | ||
|
|
4ab0ba6133 | ||
|
|
eb0badd817 | ||
|
|
f272995536 | ||
|
|
db13d3c1f8 | ||
|
|
f8c1ec100f | ||
|
|
1fd66bf9c2 | ||
|
|
151c52c1a0 | ||
|
|
bde21e5ae1 | ||
|
|
c104c6717c | ||
|
|
b0ffd89dbb | ||
|
|
0f05ad1cc2 | ||
|
|
0ec12aa49f | ||
|
|
f997a9c3bd | ||
|
|
9039089067 | ||
|
|
8bc8c824d3 | ||
|
|
f08ba6bd42 | ||
|
|
1ef61d725b | ||
|
|
b42083f20a | ||
|
|
f820dc134a | ||
|
|
f6d13d2b70 | ||
|
|
f786583986 | ||
|
|
5f6fb75505 | ||
|
|
962dedad21 | ||
|
|
ce45c65568 | ||
|
|
6d6433f256 | ||
|
|
bf385490d3 | ||
|
|
919a754ef8 | ||
|
|
0a2b616c8a | ||
|
|
56bd539528 | ||
|
|
3839f07afe | ||
|
|
2043623ce6 | ||
|
|
a3dba8be5d | ||
|
|
1f9350dc2a | ||
|
|
361b4e0862 | ||
|
|
fa2bfdc2ba | ||
|
|
679be8520f | ||
|
|
01e9dc99f2 | ||
|
|
ec5e62e533 | ||
|
|
367200a2c8 | ||
|
|
11814823ed | ||
|
|
e6c7ee7813 | ||
|
|
dc856dbb1c | ||
|
|
c4b1ab81c1 | ||
|
|
f33df254f1 | ||
|
|
83a6aaca1c | ||
|
|
182af71492 | ||
|
|
d4cdb3ea69 | ||
|
|
016bf80e3b | ||
|
|
d850de15fa | ||
|
|
819a73ba5a | ||
|
|
8d4ef5ef8c | ||
|
|
8673da2505 | ||
|
|
fa58b6987a | ||
|
|
0b4afab56c | ||
|
|
597251d6b5 | ||
|
|
56e5559357 | ||
|
|
0b4394468b | ||
|
|
315bfdace1 | ||
|
|
783bee5c49 | ||
|
|
a439028087 | ||
|
|
a49bcd4a95 | ||
|
|
6279b60179 | ||
|
|
a8e6634776 | ||
|
|
bd8eb9bca2 | ||
|
|
d53d0033fe | ||
|
|
d554df7670 | ||
|
|
3aaa132e2e | ||
|
|
c2812e187b | ||
|
|
683b62eda7 | ||
|
|
ebbedb3e26 | ||
|
|
72148ffefc | ||
|
|
074b952314 | ||
|
|
11dfb2c913 | ||
|
|
55ea2b515c | ||
|
|
6c22ea3be1 | ||
|
|
1be28b55e4 | ||
|
|
48a52e61ce | ||
|
|
f737be3320 | ||
|
|
2a256f9c25 | ||
|
|
c62215663f | ||
|
|
fd6941479d | ||
|
|
175cbcdcdf | ||
|
|
71edeb8d1a | ||
|
|
c90248dc10 | ||
|
|
a8d1067125 | ||
|
|
22139df33c | ||
|
|
9c94bab290 | ||
|
|
ea8874037c | ||
|
|
77209a12cc | ||
|
|
c670f66140 | ||
|
|
a09ce0d8d0 | ||
|
|
795968a8e0 | ||
|
|
01ab02d02a | ||
|
|
7e73e0b5b4 | ||
|
|
91c007eb8f | ||
|
|
b29f6b922f | ||
|
|
40e52f84b8 | ||
|
|
972b7f53be | ||
|
|
fc894fba0e | ||
|
|
929ee98a6c | ||
|
|
88ccf0c256 | ||
|
|
874b41f549 | ||
|
|
fcd47fe170 | ||
|
|
842ec245ac | ||
|
|
a41618fa87 | ||
|
|
c095fce5b2 | ||
|
|
6715e5e6b7 | ||
|
|
12702717e3 | ||
|
|
9c66d9737b | ||
|
|
7f5756c464 | ||
|
|
1a30113f0d | ||
|
|
f1170e9d54 | ||
|
|
1bf41bcc60 | ||
|
|
7180ca3b0c | ||
|
|
c64a4a58d7 | ||
|
|
02c272b091 | ||
|
|
2a74250a51 | ||
|
|
adb23c1cac | ||
|
|
a99a572bda | ||
|
|
7ce7dde06a | ||
|
|
fef8d2c384 | ||
|
|
916c31d934 | ||
|
|
403c147fa3 | ||
|
|
915e093564 | ||
|
|
32e74d024e | ||
|
|
326697bbe1 | ||
|
|
afbba68549 | ||
|
|
042555206b | ||
|
|
24f6302612 | ||
|
|
15eb459df9 | ||
|
|
3160fde679 | ||
|
|
1160d7cd7c | ||
|
|
2aa85e3263 | ||
|
|
c4f36170d4 | ||
|
|
3068cd0af0 | ||
|
|
fa390f48af | ||
|
|
0c7454b6f7 | ||
|
|
500f197c02 | ||
|
|
2bf249ffe1 | ||
|
|
81070a0b3f | ||
|
|
d45a11f9e7 | ||
|
|
c3a3526aad | ||
|
|
280fc43731 | ||
|
|
762535faf9 | ||
|
|
0e4fd0587b | ||
|
|
d2461a14ad | ||
|
|
a1902b5f41 | ||
|
|
c2d60774af | ||
|
|
269c579846 | ||
|
|
91183ca22f | ||
|
|
971c235e8d | ||
|
|
abd3547711 | ||
|
|
9181ec055d | ||
|
|
58089b1f44 | ||
|
|
4f62e0a4ba | ||
|
|
dbab62c214 | ||
|
|
6a878cdee8 | ||
|
|
cebdb6c917 | ||
|
|
39a2bbd788 | ||
|
|
199314a463 | ||
|
|
1020023eab | ||
|
|
a475c444c5 | ||
|
|
633ac316b4 | ||
|
|
4625d2c8ab | ||
|
|
db7ba160ae | ||
|
|
ea936f00e1 | ||
|
|
8ac616e8db | ||
|
|
3ce902183e | ||
|
|
c34e602937 | ||
|
|
28e25293a9 | ||
|
|
319d36531e | ||
|
|
5bea328967 | ||
|
|
f5f7267f44 | ||
|
|
a4ad8ae0fd | ||
|
|
44abc19d46 | ||
|
|
2e93f1c9c8 | ||
|
|
ae6847cf78 | ||
|
|
d42f0ab4b0 | ||
|
|
10ddaee94d | ||
|
|
5678bb9904 | ||
|
|
5ecef160d4 | ||
|
|
52d50da56f | ||
|
|
47111a6eba | ||
|
|
f6a5ef0f85 | ||
|
|
7868ddee42 | ||
|
|
6a0cc90a4d | ||
|
|
21d212a2ff | ||
|
|
bd6b20dedd | ||
|
|
3cc68f82a2 | ||
|
|
4f945780e7 | ||
|
|
f08ef117b5 | ||
|
|
41b0686aec | ||
|
|
9178ed580e | ||
|
|
60e93f3e20 | ||
|
|
7e8fcc5afa | ||
|
|
39238a505d | ||
|
|
f60b7831c8 | ||
|
|
c48cdeeea0 | ||
|
|
0be7c98dff | ||
|
|
0ed1f3dce1 | ||
|
|
f5e8e5b325 | ||
|
|
1f3d5011b2 | ||
|
|
3950b94474 | ||
|
|
99b4aac48b | ||
|
|
2bd64b566c | ||
|
|
3c93d14b33 | ||
|
|
5639edefee | ||
|
|
585c31ef39 | ||
|
|
a385a4c1e5 | ||
|
|
ef257c32b4 | ||
|
|
88cd4b5288 | ||
|
|
ca7ec56f0d | ||
|
|
74b1156d5e | ||
|
|
6ac7ee1a9d | ||
|
|
0b56452c35 | ||
|
|
b9c66ca0fd | ||
|
|
faf06a3b70 | ||
|
|
d0ac7f06b1 | ||
|
|
e9daaa3589 | ||
|
|
1393811525 | ||
|
|
2b640669a7 | ||
|
|
9d0f0a8d7a | ||
|
|
21d2fb4afa | ||
|
|
ade74986ee | ||
|
|
73722b5c87 | ||
|
|
456b474a48 | ||
|
|
f11cc4db69 | ||
|
|
8c2901da13 | ||
|
|
ca4637d14d | ||
|
|
313caf406e | ||
|
|
25052fedd6 | ||
|
|
678cd2c4b9 | ||
|
|
1231317c9c | ||
|
|
cd76f030cb | ||
|
|
36839cb190 | ||
|
|
23e68973c0 | ||
|
|
70af32eead | ||
|
|
3cc5ac14ff | ||
|
|
4fd8e41db1 | ||
|
|
5fd4736d8f | ||
|
|
67a07edccc | ||
|
|
1dc0872818 | ||
|
|
ead0728a57 | ||
|
|
14eb8d3906 | ||
|
|
4c90b295b2 | ||
|
|
43aa0427ea | ||
|
|
cc5d1779a3 | ||
|
|
0f437e4db2 | ||
|
|
3778fbb833 | ||
|
|
4b6f3d05e1 | ||
|
|
9e89dda900 | ||
|
|
91e69e2a1a | ||
|
|
21d1a285dc | ||
|
|
0e579792d1 | ||
|
|
20cabe824f | ||
|
|
0847d3dbb0 | ||
|
|
fa7c287f07 | ||
|
|
9b3032cd58 | ||
|
|
50646b9e70 | ||
|
|
3d6a1c7b41 | ||
|
|
5b76b0668b | ||
|
|
d18f8dce2f | ||
|
|
c64cdc14b6 | ||
|
|
cc800713bd | ||
|
|
c6a0d6ecfe | ||
|
|
c6426ae461 | ||
|
|
7b04a033b3 | ||
|
|
8e4008bf12 | ||
|
|
7eb176c0b4 | ||
|
|
3f475ac68c | ||
|
|
5204dab99b | ||
|
|
273fb84dc5 | ||
|
|
fe3af4d98b | ||
|
|
9aade5bb24 | ||
|
|
3c408dab7c | ||
|
|
2888f4d03d | ||
|
|
f57b5bc762 | ||
|
|
35a4d57360 | ||
|
|
579e366bcf | ||
|
|
db4f79448d | ||
|
|
45bbcca207 | ||
|
|
8e961a5667 | ||
|
|
64ad69c247 | ||
|
|
4def2f219c | ||
|
|
b2b4b2d71d | ||
|
|
e93bd14ef5 | ||
|
|
652f9f9eda | ||
|
|
cac9eb0cd7 | ||
|
|
3b4fb295ea | ||
|
|
a1ae61b5b1 | ||
|
|
355abd8c57 | ||
|
|
b57ac66815 | ||
|
|
a851a928d2 | ||
|
|
16c2e8e454 | ||
|
|
ae908c8e9b | ||
|
|
723c81470a | ||
|
|
a7905fba3e | ||
|
|
6e52b72523 | ||
|
|
ef4ec4185a | ||
|
|
3dee0a276b | ||
|
|
e95248a787 | ||
|
|
414ff23141 | ||
|
|
2c0ce6f416 | ||
|
|
89fe754a9f | ||
|
|
01ee673dc2 | ||
|
|
5a949443a5 | ||
|
|
a916695155 | ||
|
|
611547ee97 | ||
|
|
ff9f228e1b | ||
|
|
f33dfd2313 | ||
|
|
7ef00c8761 | ||
|
|
437d03583a | ||
|
|
0322a6871c | ||
|
|
4f643d27d9 | ||
|
|
3dcb4bbf8b | ||
|
|
59981aed7f | ||
|
|
07781e9cf5 | ||
|
|
c276a36c9b | ||
|
|
ff0d794c50 | ||
|
|
369c878711 | ||
|
|
5bf570c27d | ||
|
|
0963611fc7 | ||
|
|
00644db9b1 | ||
|
|
f8ba72aa15 | ||
|
|
371b2c87b1 | ||
|
|
387655606e | ||
|
|
e1b881a688 | ||
|
|
869ea4c16b | ||
|
|
71238ccd74 | ||
|
|
1dfd9ebac7 | ||
|
|
3dbe5cf930 | ||
|
|
8e8fea4b7d | ||
|
|
ebe5bfbc07 | ||
|
|
d67930eeef | ||
|
|
084d5b0b87 | ||
|
|
8dc44b5e0d | ||
|
|
7851dc8cb7 | ||
|
|
75c553c391 | ||
|
|
6bff270402 | ||
|
|
72f1e53106 | ||
|
|
e6c7b97b5e | ||
|
|
54f9d3c414 | ||
|
|
9e272733cf | ||
|
|
51afd3440f | ||
|
|
f67bc43584 | ||
|
|
79e1af7bde | ||
|
|
173c44417c | ||
|
|
7aa1c08d17 | ||
|
|
0be1d9c3ea | ||
|
|
305e194993 | ||
|
|
719ab019a4 | ||
|
|
e9df18f910 | ||
|
|
06a1fdac50 | ||
|
|
7308ef4117 | ||
|
|
67c1db9957 | ||
|
|
f5a621935d | ||
|
|
354edb30d3 | ||
|
|
96113fe848 | ||
|
|
fd1596b6c9 | ||
|
|
9760efbca3 | ||
|
|
d92c1025ba | ||
|
|
de55db12f1 | ||
|
|
264b9efb36 | ||
|
|
9fd5cdf1ba | ||
|
|
1b33cbe591 | ||
|
|
a97d5eab22 | ||
|
|
83e790851f | ||
|
|
11ac5ed33e | ||
|
|
b7912f182b | ||
|
|
6db0ac8471 | ||
|
|
060aa52c89 | ||
|
|
ba413bb7ad | ||
|
|
97e787e48a | ||
|
|
b473139758 | ||
|
|
7afcec8edc | ||
|
|
d1a3009447 | ||
|
|
651d596246 | ||
|
|
75bab41e39 | ||
|
|
36e0b4a908 | ||
|
|
974301eaaf | ||
|
|
2acc161ad2 | ||
|
|
7322bad830 | ||
|
|
6afd3260ef | ||
|
|
76e7cca821 | ||
|
|
84206eb237 | ||
|
|
5e576c1a08 | ||
|
|
fc180041aa | ||
|
|
1bfd07c19a | ||
|
|
5dafbf57e9 | ||
|
|
09db2e6c37 | ||
|
|
b6cb2e7edc | ||
|
|
bedcbf57c6 | ||
|
|
7df080ee92 | ||
|
|
b400897ca2 | ||
|
|
7573500e59 | ||
|
|
8a1e03739a | ||
|
|
a1af9698ac | ||
|
|
af01c3cc77 | ||
|
|
4c8bdc2bfc | ||
|
|
c58f94a9ba | ||
|
|
ecaa2bd778 | ||
|
|
d619bf0bc1 | ||
|
|
9a241b0e43 | ||
|
|
e3f2f87e2d | ||
|
|
a8238cb0d4 | ||
|
|
f212720484 | ||
|
|
1328f78099 | ||
|
|
4c234310fd | ||
|
|
f7ee4a868a | ||
|
|
ae386d4308 | ||
|
|
ff9f5d3809 | ||
|
|
ce17a6200b | ||
|
|
8289bbd27b | ||
|
|
aeb41f3e70 | ||
|
|
cefea28539 | ||
|
|
da26016edf | ||
|
|
6bef238772 | ||
|
|
02465b48b3 | ||
|
|
94abf9d19f | ||
|
|
7a4244180b | ||
|
|
6fe6c474f7 | ||
|
|
be34ed1385 | ||
|
|
444bb24464 | ||
|
|
0e6ca28316 | ||
|
|
d718b143d2 | ||
|
|
1e2f1a19ff | ||
|
|
1228251bc3 | ||
|
|
a781ec2fdd | ||
|
|
6a30e4b7a4 | ||
|
|
08d37de94e | ||
|
|
b8906e0a83 | ||
|
|
89947f0300 | ||
|
|
729360379f | ||
|
|
c69c568f49 | ||
|
|
0a58e91523 | ||
|
|
5ef04daf44 | ||
|
|
c9ae04c784 | ||
|
|
47b18ea84a | ||
|
|
dd45bb1694 | ||
|
|
e105c539ad | ||
|
|
4af69f34a2 | ||
|
|
16f5ae7abe | ||
|
|
d184274324 | ||
|
|
4cc8e6d6db | ||
|
|
fecbac2e25 | ||
|
|
e2e65fd53b | ||
|
|
f22ed52b75 | ||
|
|
03dbd6af65 | ||
|
|
fca7fb5e0f | ||
|
|
80d6e2f0ec | ||
|
|
d35e938c36 | ||
|
|
4e16a700c6 | ||
|
|
d717b58001 | ||
|
|
861da4c361 | ||
|
|
f9321b034f | ||
|
|
65dd19a158 | ||
|
|
be60060941 | ||
|
|
39ac1d6bfb | ||
|
|
d94ca66e3e | ||
|
|
e47e3c73c2 | ||
|
|
f11c22d984 | ||
|
|
bd4a2d232f | ||
|
|
158cf3c7b3 | ||
|
|
a7cf5cd1ca | ||
|
|
4e6e1d6024 | ||
|
|
0133ecc887 | ||
|
|
913dfad1ad | ||
|
|
2062f94adc | ||
|
|
f9db547cf3 | ||
|
|
2782dd1716 | ||
|
|
852219caf5 | ||
|
|
07fbed06c6 | ||
|
|
ea5f8241e3 | ||
|
|
895ffced8e | ||
|
|
40855c90fb | ||
|
|
6570c4856b | ||
|
|
008c4d62ef | ||
|
|
63dfd9ab6b | ||
|
|
9b28fc3e17 | ||
|
|
6bbaf64daf | ||
|
|
44eeebbc6f | ||
|
|
ec7631096b | ||
|
|
07a1484d72 | ||
|
|
9503620525 | ||
|
|
e05a3b8ad0 | ||
|
|
9d0b9bef67 | ||
|
|
0446b732fa | ||
|
|
c3da4ada61 | ||
|
|
4fdcc6e5ac | ||
|
|
b82336c8d9 | ||
|
|
075958883f | ||
|
|
fe632cde4b | ||
|
|
10090b60a9 | ||
|
|
a6bdb27178 | ||
|
|
62ed93f12a | ||
|
|
e89ce78c79 | ||
|
|
98c4b921b8 | ||
|
|
86765cebb2 | ||
|
|
25ceb08f93 | ||
|
|
205983e206 | ||
|
|
1e7098c1cb | ||
|
|
68ecdfc023 | ||
|
|
a9356ceca5 | ||
|
|
69ab736cf8 | ||
|
|
3e758dcebb | ||
|
|
b249811e28 | ||
|
|
7f216f35ab | ||
|
|
029471ecca | ||
|
|
4cc6c36c37 | ||
|
|
0cd5b0ac47 | ||
|
|
939c83127e | ||
|
|
3768aa7e1f | ||
|
|
7a85c3917f | ||
|
|
cd0e83843f | ||
|
|
78ce055165 | ||
|
|
d9478801ed | ||
|
|
77fe24f798 | ||
|
|
4e77ee02e8 | ||
|
|
91b4bdb58f | ||
|
|
d6628972c5 | ||
|
|
b0d0e292c9 | ||
|
|
e2b04e7405 | ||
|
|
f79b0867b6 | ||
|
|
db337a9b36 | ||
|
|
1303ef55b2 | ||
|
|
85d39cf242 | ||
|
|
2d777accc6 | ||
|
|
3f36f7fab1 | ||
|
|
1812b829dc | ||
|
|
36d5cebde6 | ||
|
|
34d311fd81 | ||
|
|
59bd3b5144 | ||
|
|
805d20d199 | ||
|
|
166f63f955 | ||
|
|
d2beb2da19 | ||
|
|
7ef44d9878 | ||
|
|
408813c387 | ||
|
|
4d2f64a12b | ||
|
|
9997461e3a | ||
|
|
4699522299 | ||
|
|
a582ca7b95 | ||
|
|
024ae9bb42 | ||
|
|
38bcf4f956 | ||
|
|
486caf42a0 | ||
|
|
92f2ca9108 | ||
|
|
bde4da2b7e | ||
|
|
b4b1c39049 | ||
|
|
b233cb6e7f | ||
|
|
95d1bfb760 | ||
|
|
064dd4794f | ||
|
|
257db5ac7d | ||
|
|
9ff31b91f4 | ||
|
|
0edba2ee2a | ||
|
|
c501306c4f | ||
|
|
8aad2ca3d2 | ||
|
|
de215a6e1b | ||
|
|
0b390d7dc4 | ||
|
|
a3f5fee6a5 | ||
|
|
a3f4d89bc4 | ||
|
|
2044d2e51c | ||
|
|
f9e3278863 | ||
|
|
0d15723444 | ||
|
|
6e0d6a27ec | ||
|
|
a2465f5fb7 | ||
|
|
88e98f17b6 | ||
|
|
b4db1ad54a | ||
|
|
7be472932b | ||
|
|
d019f31ef1 | ||
|
|
e2afeaef27 | ||
|
|
2b6ab6c19d | ||
|
|
0ef026cfa4 | ||
|
|
5787b4c02b | ||
|
|
e947895119 | ||
|
|
bb91d978b1 | ||
|
|
da86a8942b | ||
|
|
71be07e69f | ||
|
|
be18c76c99 | ||
|
|
af2671d8eb | ||
|
|
11cb82b058 | ||
|
|
ab6a2aaadb | ||
|
|
a358f892d3 | ||
|
|
cabb06d495 | ||
|
|
005cba3acd | ||
|
|
bb029cc287 | ||
|
|
8fd56ada8b | ||
|
|
5ab19e9a9f | ||
|
|
82abc76e0c | ||
|
|
6e0175bd8e | ||
|
|
e6e87fd307 | ||
|
|
1f5139d209 | ||
|
|
2397d034e3 | ||
|
|
c889a3c1f0 | ||
|
|
cfc05dab2c | ||
|
|
4a174106cc | ||
|
|
f04c8536c8 | ||
|
|
a97dc38e87 | ||
|
|
042c6af887 | ||
|
|
0e18f0986a | ||
|
|
40f4fdf246 | ||
|
|
67b3c8fc25 | ||
|
|
b88ad3d143 | ||
|
|
be9e25785c | ||
|
|
824070b899 | ||
|
|
c3a580ee89 | ||
|
|
53cecae109 | ||
|
|
61742c9357 | ||
|
|
fee036604c | ||
|
|
988940b25e | ||
|
|
abf2c586c7 | ||
|
|
c025c4a1f8 | ||
|
|
fb05d96979 | ||
|
|
8eb030ed89 | ||
|
|
5be405308e | ||
|
|
af0c1c87f5 | ||
|
|
cfaae84813 | ||
|
|
da8ab1e9dd | ||
|
|
baf65f510f | ||
|
|
13f68fbc64 | ||
|
|
3071b3f2dd | ||
|
|
de069cf8c9 | ||
|
|
8cf8923a18 | ||
|
|
d954510c9d | ||
|
|
8966a9b094 | ||
|
|
3d9611d020 | ||
|
|
78b7f26076 | ||
|
|
7233c39166 | ||
|
|
0ee072671b | ||
|
|
1130007761 | ||
|
|
a0060d9c3a | ||
|
|
66eb0613b0 | ||
|
|
af8f544913 | ||
|
|
803184c164 | ||
|
|
857f91771f | ||
|
|
592418d9f3 | ||
|
|
0a23dfeb42 | ||
|
|
4a94677ee5 | ||
|
|
3414b73172 | ||
|
|
3bcbb24603 | ||
|
|
26752f6f90 | ||
|
|
8999ec2c7a | ||
|
|
778cf4cb9e | ||
|
|
b6a9e756e4 | ||
|
|
285c964c98 | ||
|
|
1d6f66f834 | ||
|
|
3fb8cbf39f | ||
|
|
c352105176 | ||
|
|
c4623f4297 | ||
|
|
1c85a1ca52 | ||
|
|
fdf30febea | ||
|
|
7d5e7f5dda | ||
|
|
e3a1debc65 | ||
|
|
578d3d2a76 | ||
|
|
e3053f69f8 | ||
|
|
04ec75e515 | ||
|
|
420d669a4b | ||
|
|
9e3f6ade61 | ||
|
|
0aa0f973aa | ||
|
|
8fc9c19af9 | ||
|
|
10b869ef30 | ||
|
|
c863dad73e | ||
|
|
24583494c6 | ||
|
|
4ede3ff8a4 | ||
|
|
a58154b52b | ||
|
|
9e659b003c | ||
|
|
7d30e6da61 | ||
|
|
a9b24827e2 | ||
|
|
fc55e1e778 | ||
|
|
0188ccf696 | ||
|
|
65d50e4d8b | ||
|
|
3ce961f84d | ||
|
|
eaf5e049eb | ||
|
|
e4153b03bc | ||
|
|
a3a5abac23 | ||
|
|
8054015bff | ||
|
|
646d56046f | ||
|
|
7b296a4dc9 | ||
|
|
61ac01c31b | ||
|
|
79a2128704 | ||
|
|
0c9359cddd | ||
|
|
dbf855e1aa | ||
|
|
0afd6ae54f | ||
|
|
07500e89db | ||
|
|
3adc1c5321 | ||
|
|
55394a7dcd | ||
|
|
230758b1ee | ||
|
|
d7e02c6f34 | ||
|
|
c32ad45724 | ||
|
|
541e23d663 | ||
|
|
65fe176795 | ||
|
|
cfc91804c8 | ||
|
|
88d213a30b | ||
|
|
189b796499 | ||
|
|
af7f430227 | ||
|
|
797abb5a7f | ||
|
|
ffff21a936 | ||
|
|
781fb3ab48 | ||
|
|
bda630e419 | ||
|
|
9afdc48ddd | ||
|
|
3ee031abc9 | ||
|
|
d1f9bce083 | ||
|
|
670957487a | ||
|
|
1c0133704e | ||
|
|
5927d4ee2b | ||
|
|
5dee051a7a | ||
|
|
561110231d | ||
|
|
eff908385e | ||
|
|
784a6ed5ad | ||
|
|
da2d08a27b | ||
|
|
061b38f0b8 | ||
|
|
9971bda9cb | ||
|
|
6cb2bf7009 | ||
|
|
50befc42c3 | ||
|
|
53043830e7 | ||
|
|
8deb47f2c3 | ||
|
|
01093482e7 | ||
|
|
da215aecd4 | ||
|
|
be21c31eab | ||
|
|
6457cb7dd0 | ||
|
|
e444a7329c | ||
|
|
28d7818c2b | ||
|
|
6561310d25 | ||
|
|
f8e8a7b72e | ||
|
|
5a0d67f1ac | ||
|
|
03626e615b | ||
|
|
bac6dae0ad | ||
|
|
5c186d8467 | ||
|
|
25b34913c6 | ||
|
|
8dabe44693 | ||
|
|
8a7977fcb3 | ||
|
|
d689165a39 | ||
|
|
f2fd654b84 | ||
|
|
1b61a86618 | ||
|
|
44cd697b29 | ||
|
|
d562b00c37 | ||
|
|
ba92377eba | ||
|
|
acbe190a20 | ||
|
|
4cd65d1512 | ||
|
|
bbae702e9f | ||
|
|
c4046602f0 | ||
|
|
baf925fefd | ||
|
|
ec00479640 | ||
|
|
66e4866091 | ||
|
|
5b47a61209 | ||
|
|
b0365cd9ad | ||
|
|
36bb604d38 | ||
|
|
d8835df9ab | ||
|
|
d24c8442c4 | ||
|
|
4a955b2a28 | ||
|
|
4f27ec44eb | ||
|
|
843630c3c7 | ||
|
|
00c0bc1e6e | ||
|
|
5980993774 | ||
|
|
72c875183a | ||
|
|
97f9afac0a | ||
|
|
a7035ab61e | ||
|
|
ea4c0999d0 | ||
|
|
d51fa99b70 | ||
|
|
2c97bffc54 | ||
|
|
626b62c413 | ||
|
|
25b9ca821e | ||
|
|
d5ddf4cd7f | ||
|
|
d43dcbcf8c | ||
|
|
1fdc0ab7c1 | ||
|
|
9408b7e2c4 | ||
|
|
12f3505eea | ||
|
|
464ee85884 | ||
|
|
87d745d5dc | ||
|
|
576f8941d6 | ||
|
|
039cbcf2cf | ||
|
|
f91c4b3b9d | ||
|
|
83b9486985 | ||
|
|
dc54eeb8d0 | ||
|
|
3a2a7f8cf1 | ||
|
|
52a22e5185 | ||
|
|
cae8c70e51 | ||
|
|
513bd81810 | ||
|
|
891f653ead | ||
|
|
5b270aab61 | ||
|
|
6591da9acf | ||
|
|
c80c08d32c | ||
|
|
ce7d337c5c | ||
|
|
dc1198bd9c | ||
|
|
f46d7cc84f | ||
|
|
5ee764390e | ||
|
|
894a82f54f | ||
|
|
5cc9835303 | ||
|
|
48877984b7 | ||
|
|
a58f49018a | ||
|
|
7120a1508c | ||
|
|
a808f4ae6a | ||
|
|
4d1f5baa7e | ||
|
|
f106035100 | ||
|
|
21f49d032b | ||
|
|
341307cb8d | ||
|
|
85990ff51d | ||
|
|
238a6c83db | ||
|
|
77f03a44b6 | ||
|
|
29756de336 | ||
|
|
1afbbaba63 | ||
|
|
52b3120448 | ||
|
|
b7d76bd51d | ||
|
|
c0411eefeb | ||
|
|
3d821f73a4 | ||
|
|
1726f56a27 | ||
|
|
a305b30d90 | ||
|
|
9bed59858b | ||
|
|
cf63040c5a | ||
|
|
e8ec79290b | ||
|
|
0c22150fdb | ||
|
|
423476dc87 | ||
|
|
bfa3819b0d | ||
|
|
adf1c88c27 | ||
|
|
ad905ae992 | ||
|
|
608a5da480 | ||
|
|
3df3f0741a | ||
|
|
3585c58688 | ||
|
|
a8121f31d4 | ||
|
|
38c005c208 | ||
|
|
cd91d3ef0f | ||
|
|
02e8577f45 | ||
|
|
8451bc21ec | ||
|
|
28fe90e504 | ||
|
|
2c29314578 | ||
|
|
e196db9645 | ||
|
|
733aca5ac3 | ||
|
|
177a2d03a1 | ||
|
|
fec3ea882d | ||
|
|
580970cd72 | ||
|
|
c13bb1ec2b | ||
|
|
c777dd1657 | ||
|
|
cb9931f3e8 | ||
|
|
6b6254e84a | ||
|
|
61c6305aa8 | ||
|
|
b43056cd73 | ||
|
|
e4c144829c | ||
|
|
05356da2c5 | ||
|
|
47a4d9f803 | ||
|
|
e4185ce4ce | ||
|
|
c539742e13 | ||
|
|
ebd2289971 | ||
|
|
d67329a2b8 | ||
|
|
3a9703fc20 | ||
|
|
856b105ab9 | ||
|
|
03e740a511 | ||
|
|
e628c8e211 | ||
|
|
7eca6c609f | ||
|
|
f299120798 | ||
|
|
aac8146f00 | ||
|
|
35c974d4c0 | ||
|
|
27476815ab | ||
|
|
b02b9c4be8 | ||
|
|
6afcf5881d | ||
|
|
30704a7c5e | ||
|
|
08b6748d79 | ||
|
|
bedfbda372 | ||
|
|
9fbf6ab35d | ||
|
|
793496da98 | ||
|
|
81cbf8357d | ||
|
|
55a260e4e8 | ||
|
|
5c71564844 | ||
|
|
bf4f0454e1 | ||
|
|
33b9e915d9 | ||
|
|
77712f5904 | ||
|
|
c02388dfbe | ||
|
|
56dae62b8e | ||
|
|
53b52a975a | ||
|
|
f87ccacdb1 | ||
|
|
d2a2fcb89d | ||
|
|
c65c4bfb4e | ||
|
|
6431b8157b | ||
|
|
7d1e83b416 | ||
|
|
fd685aac82 | ||
|
|
79539d7d8d | ||
|
|
457e763466 | ||
|
|
0da71844fd | ||
|
|
1fd0b0404d | ||
|
|
d0f3e89954 | ||
|
|
9c95c4d7ab | ||
|
|
7e0eefe802 | ||
|
|
5d7ff8e628 | ||
|
|
83163797c6 | ||
|
|
6393eac4f8 | ||
|
|
376e4770f3 | ||
|
|
c91b0ae605 | ||
|
|
b14c49ad5d | ||
|
|
88485e56f5 | ||
|
|
e339e4f51c | ||
|
|
a6307afadd | ||
|
|
436bf0fe41 | ||
|
|
e72975af68 | ||
|
|
099b7034d4 | ||
|
|
5173d2668e | ||
|
|
ab02801d76 | ||
|
|
e0d33e2536 | ||
|
|
657464f134 | ||
|
|
799e3a03f5 | ||
|
|
6d11ec6e70 | ||
|
|
860b43b342 | ||
|
|
35260c1f0f | ||
|
|
a1c9dfe84d | ||
|
|
8016a932f3 | ||
|
|
fd4f7bbf0b | ||
|
|
77eae66cb1 | ||
|
|
eb6750d7d4 | ||
|
|
83a32f1ba3 | ||
|
|
10a44c83f1 | ||
|
|
a55fac8c82 | ||
|
|
052331168e | ||
|
|
4509e6cf38 | ||
|
|
69876c7d03 | ||
|
|
a6bd1c55ac | ||
|
|
0d593252e6 | ||
|
|
a1dc348ec7 | ||
|
|
a0dac52e0e | ||
|
|
010039578f | ||
|
|
f8a2f38fe7 | ||
|
|
39d1a286a8 | ||
|
|
7dc0aa16ec | ||
|
|
b504feaa50 | ||
|
|
fa982c8dd0 | ||
|
|
f1f62264fe | ||
|
|
1de1d04fb4 | ||
|
|
af8b548e29 | ||
|
|
0550fe75b2 | ||
|
|
ef6024911a | ||
|
|
78c021aadf | ||
|
|
fdcfe549cb | ||
|
|
a64339b195 | ||
|
|
9725155f25 | ||
|
|
cdc2831103 | ||
|
|
d3c5039c2f | ||
|
|
13f4be33bc | ||
|
|
6cf90add8c | ||
|
|
2723a6e71d | ||
|
|
4a8ac3d902 | ||
|
|
9c17986ae6 | ||
|
|
93c30e0233 | ||
|
|
f327e09e3e | ||
|
|
c2cf09acbf | ||
|
|
72a644f77d | ||
|
|
a259eb7396 | ||
|
|
7f8f0cc137 | ||
|
|
d776ec2f56 | ||
|
|
8ae69a3463 | ||
|
|
763846aee8 | ||
|
|
2da190f5b4 | ||
|
|
9b2f40c06a |
1288 changed files with 321385 additions and 5020 deletions
42
.github/workflows/build-libpico.yml
vendored
Normal file
42
.github/workflows/build-libpico.yml
vendored
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
# Run whenever it is manually triggered, a pull request or a push is done that modifes the libpico configuration
|
||||||
|
|
||||||
|
name: libpico Builder
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- tools/libpico/**
|
||||||
|
workflow_dispatch:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- tools/libpico/**
|
||||||
|
jobs:
|
||||||
|
build-libpico:
|
||||||
|
name: Build libpico precompiled libraries
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: false
|
||||||
|
- name: Get submodules for pico-sdk
|
||||||
|
run: cd pico-sdk && git submodule update --init --recursive
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install cmake make build-essential wget
|
||||||
|
# Automatically get correct toolchain
|
||||||
|
cd tools && python3 get.py && cd ..
|
||||||
|
# add to PATH
|
||||||
|
echo "$GITHUB_WORKSPACE/system/riscv32-unknown-elf/bin" >> "$GITHUB_PATH"
|
||||||
|
echo "$GITHUB_WORKSPACE/system/arm-none-eabi/bin" >> "$GITHUB_PATH"
|
||||||
|
- name: Build libpico
|
||||||
|
run: |
|
||||||
|
cd tools/libpico
|
||||||
|
./make-libpico.sh
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: libpico
|
||||||
|
path: |
|
||||||
|
tools/libpico/build-rp2040/*.a
|
||||||
|
tools/libpico/build-rp2350/*.a
|
||||||
|
tools/libpico/build-rp2350-riscv/*.a
|
||||||
341
.github/workflows/pull-request.yml
vendored
Normal file
341
.github/workflows/pull-request.yml
vendored
Normal file
|
|
@ -0,0 +1,341 @@
|
||||||
|
# Run whenever a PR is generated or updated.
|
||||||
|
|
||||||
|
|
||||||
|
name: Arduino-Pico CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
# Consistent style, spelling
|
||||||
|
astyle:
|
||||||
|
name: Spelling, Style, Boards, Package, PIO
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: false
|
||||||
|
- name: Run codespell
|
||||||
|
uses: codespell-project/actions-codespell@v2
|
||||||
|
with:
|
||||||
|
skip: ./ArduinoCore-API,./libraries/ESP8266SdFat,./libraries/Adafruit_TinyUSB_Arduino,./libraries/LittleFS/lib,./tools/pyserial,./pico-sdk,./.github,./docs/i2s.rst,./cores/rp2040/api,./libraries/FreeRTOS,./tools/libbearssl/bearssl,./include,./libraries/WiFi/examples/BearSSL_Server,./ota/uzlib,./libraries/http-parser/lib,./libraries/WebServer/examples/HelloServerBearSSL/HelloServerBearSSL.ino,./libraries/HTTPUpdateServer/examples/SecureBearSSLUpdater/SecureBearSSLUpdater.ino,./.git,./libraries/FatFS/lib/fatfs,./libraries/FatFS/src/diskio.h,./libraries/FatFS/src/ff.cpp,./libraries/FatFS/src/ffconf.h,./libraries/FatFS/src/ffsystem.cpp,./libraries/FatFS/src/ff.h,./libraries/lwIP_WINC1500/src/driver,./libraries/lwIP_WINC1500/src/common,./libraries/lwIP_WINC1500/src/bus_wrapper,./libraries/lwIP_WINC1500/src/spi_flash,./libraries/WiFi/examples/BearSSL_Validation/certs.h
|
||||||
|
ignore_words_list: ser,dout,shiftIn,acount,froms
|
||||||
|
- name: Check boards.txt was not edited after makeboards.py
|
||||||
|
run: |
|
||||||
|
./tools/makeboards.py
|
||||||
|
# If anything changed, GIT should return an error and fail the test
|
||||||
|
git diff --exit-code
|
||||||
|
- name: Run astyle on all code/examples
|
||||||
|
run: |
|
||||||
|
sudo apt update
|
||||||
|
sudo apt install astyle
|
||||||
|
./tests/restyle.sh
|
||||||
|
# If anything changed, GIT should return an error and fail the test
|
||||||
|
git diff --exit-code
|
||||||
|
- name: Check compiled PIO files
|
||||||
|
run: |
|
||||||
|
(cd ./tools && ./get.py)
|
||||||
|
./tools/makepio.py
|
||||||
|
# If anything changed, GIT should return an error and fail the test
|
||||||
|
git diff -w --exit-code
|
||||||
|
- name: Check package references
|
||||||
|
run: |
|
||||||
|
./tests/ci/pkgrefs_test.sh
|
||||||
|
|
||||||
|
# Build all examples on linux (core and Arduino IDE)
|
||||||
|
build-linux:
|
||||||
|
name: Build ${{ matrix.chunk }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
chunk: [0, 1, 2, 3, 4, 5]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.x'
|
||||||
|
- name: Cache Linux toolchain
|
||||||
|
id: cache-linux
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ./tools/dist
|
||||||
|
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||||
|
- name: Build Sketches
|
||||||
|
env:
|
||||||
|
BUILD_PARITY: custom
|
||||||
|
mod: 6
|
||||||
|
rem: ${{ matrix.chunk }}
|
||||||
|
run: |
|
||||||
|
cd pico-sdk
|
||||||
|
git submodule update --init
|
||||||
|
cd ..
|
||||||
|
bash ./tests/build.sh
|
||||||
|
|
||||||
|
# Build all rp2350 examples on linux (core and Arduino IDE)
|
||||||
|
build-rp2350-linux:
|
||||||
|
name: Build RP2350 ${{ matrix.chunk }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
chunk: [0, 1, 2, 3, 4, 5]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.x'
|
||||||
|
- name: Cache Linux toolchain
|
||||||
|
id: cache-linux
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ./tools/dist
|
||||||
|
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||||
|
- name: Build Sketches
|
||||||
|
env:
|
||||||
|
BUILD_PARITY: custom
|
||||||
|
mod: 6
|
||||||
|
rem: ${{ matrix.chunk }}
|
||||||
|
run: |
|
||||||
|
cd pico-sdk
|
||||||
|
git submodule update --init
|
||||||
|
cd ..
|
||||||
|
bash ./tests/build-rp2350.sh
|
||||||
|
|
||||||
|
# Build all rp2350-riscv examples on linux (core and Arduino IDE)
|
||||||
|
build-rp2350-riscv-linux:
|
||||||
|
name: Build RP2350-RISCV ${{ matrix.chunk }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
chunk: [0, 1, 2, 3, 4, 5]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.x'
|
||||||
|
- name: Cache Linux toolchain
|
||||||
|
id: cache-linux
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ./tools/dist
|
||||||
|
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||||
|
- name: Build Sketches
|
||||||
|
env:
|
||||||
|
BUILD_PARITY: custom
|
||||||
|
mod: 6
|
||||||
|
rem: ${{ matrix.chunk }}
|
||||||
|
run: |
|
||||||
|
cd pico-sdk
|
||||||
|
git submodule update --init
|
||||||
|
cd ..
|
||||||
|
bash ./tests/build-rp2350-riscv.sh
|
||||||
|
|
||||||
|
# Build TinyUSB examples, requires custom build command line
|
||||||
|
build-tinyusb:
|
||||||
|
name: Build TinyUSB Examples
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.x'
|
||||||
|
- name: Cache Linux toolchain
|
||||||
|
id: cache-linux
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ./tools/dist
|
||||||
|
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||||
|
- name: Build Sketches
|
||||||
|
env:
|
||||||
|
BUILD_PARITY: custom
|
||||||
|
run: |
|
||||||
|
cd pico-sdk
|
||||||
|
git submodule update --init
|
||||||
|
cd ..
|
||||||
|
bash ./tests/build-tinyusb.sh
|
||||||
|
|
||||||
|
# Single build under Windows to ensure the Win toolchain is good.
|
||||||
|
build-windows:
|
||||||
|
name: Windows
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.x'
|
||||||
|
- name: Cache Windows toolchain
|
||||||
|
id: cache-windows
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ./tools/dist
|
||||||
|
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||||
|
- name: Build Sketch
|
||||||
|
env:
|
||||||
|
WINDOWS: 1
|
||||||
|
BUILD_PARITY: custom
|
||||||
|
mod: 500
|
||||||
|
rem: 1
|
||||||
|
run: |
|
||||||
|
# Windows has python3 already installed, but it's called "python".
|
||||||
|
# Copy python.exe to the proper name so scripts "just work".
|
||||||
|
try { Get-Command python3 } catch { copy (get-command python).source (get-command python).source.Replace("python.exe", "python3.exe") }
|
||||||
|
cd pico-sdk
|
||||||
|
git submodule update --init
|
||||||
|
cd ..
|
||||||
|
bash ./tests/build.sh
|
||||||
|
|
||||||
|
|
||||||
|
# Single build under macOS to ensure the Mac toolchain is good.
|
||||||
|
build-mac:
|
||||||
|
name: Mac
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [macOS-13, macOS-14]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.x'
|
||||||
|
- name: Cache Mac toolchain
|
||||||
|
id: cache-mac
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ./tools/dist
|
||||||
|
key: ${{ runner.os }}-${{ hashFiles('package/package_pico_index.template.json', 'tests/common.sh') }}
|
||||||
|
- name: Build Sketch
|
||||||
|
env:
|
||||||
|
MACOSX: 1
|
||||||
|
BUILD_PARITY: custom
|
||||||
|
mod: 500
|
||||||
|
rem: 1
|
||||||
|
run: |
|
||||||
|
brew update
|
||||||
|
brew install bash
|
||||||
|
/usr/bin/env bash --version
|
||||||
|
uname -a
|
||||||
|
cd pico-sdk
|
||||||
|
git submodule update --init
|
||||||
|
cd ..
|
||||||
|
/usr/bin/env bash ./tests/build.sh
|
||||||
|
./system/picotool/picotool version
|
||||||
|
otool -L ./system/picotool/picotool
|
||||||
|
|
||||||
|
# Build a few examples with PlatformIO to test if integration works
|
||||||
|
build-platformio:
|
||||||
|
name: Build PlatformIO Examples
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: 'true'
|
||||||
|
- name: Initialize needed submodules
|
||||||
|
run: |
|
||||||
|
cd pico-sdk
|
||||||
|
git submodule update --init
|
||||||
|
cd ../libraries/Adafruit_TinyUSB_Arduino
|
||||||
|
git submodule update --init
|
||||||
|
cd ../..
|
||||||
|
- name: Cache pip
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ~/.cache/pip
|
||||||
|
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-pip-
|
||||||
|
- name: Cache PlatformIO
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ~/.platformio
|
||||||
|
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.x'
|
||||||
|
- name: Install PlatformIO
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install --upgrade platformio
|
||||||
|
rm -rf ~/.platformio/platforms/raspberrypi*
|
||||||
|
pio pkg install --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git
|
||||||
|
pio pkg install --global --tool symlink://.
|
||||||
|
cp -f /home/runner/work/arduino-pico/arduino-pico/tools/json/*.json /home/runner/.platformio/platforms/raspberrypi/boards/.
|
||||||
|
- name: Build Multicore Example
|
||||||
|
run: pio ci -v --board=rpipico --board=rpipico2 --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Multicore/Multicore.ino
|
||||||
|
- name: Build Multicore Example (RISC-V)
|
||||||
|
run: pio ci -v --board=rpipico2 -O "board_build.mcu = rp2350-riscv" -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Multicore/Multicore.ino
|
||||||
|
- name: Build Fade Example
|
||||||
|
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Fade/Fade.ino
|
||||||
|
- name: Build TinyUSB Example
|
||||||
|
run: pio ci --board=rpipico --board=adafruit_feather -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" -O "build_flags=-DUSE_TINYUSB" libraries/Adafruit_TinyUSB_Arduino/examples/CDC/cdc_multi/cdc_multi.ino
|
||||||
|
- name: Build WiFi Example
|
||||||
|
run: pio ci --board=rpipicow -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/WiFi/examples/ScanNetworks/ScanNetworks.ino
|
||||||
|
- name: Build Signed OTA Example
|
||||||
|
run: pio ci --board=rpipicow -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/ArduinoOTA/examples/SignedOTA/SignedOTA.ino
|
||||||
|
- name: Build Bluetooth Example
|
||||||
|
run: pio ci --board=rpipicow -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" -O "build_flags=-DPIO_FRAMEWORK_ARDUINO_ENABLE_BLUETOOTH" libraries/MouseBLE/examples/BLECircle/BLECircle.ino
|
||||||
|
|
||||||
|
# Build every variant using PIO for simplicity
|
||||||
|
build-variants:
|
||||||
|
name: Build Every Variant ${{ matrix.chunk }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
chunk: [0, 1]
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: 'true'
|
||||||
|
- name: Initialize needed submodules
|
||||||
|
run: |
|
||||||
|
cd pico-sdk
|
||||||
|
git submodule update --init
|
||||||
|
cd ../libraries/Adafruit_TinyUSB_Arduino
|
||||||
|
git submodule update --init
|
||||||
|
cd ../..
|
||||||
|
- name: Cache pip
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ~/.cache/pip
|
||||||
|
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-pip-
|
||||||
|
- name: Cache PlatformIO
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ~/.platformio
|
||||||
|
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.x'
|
||||||
|
- name: Install PlatformIO
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install --upgrade platformio
|
||||||
|
rm -rf ~/.platformio/platforms/raspberrypi*
|
||||||
|
pio pkg install --global --platform https://github.com/maxgerhardt/platform-raspberrypi.git
|
||||||
|
pio pkg install --global --tool symlink://.
|
||||||
|
cp -f /home/runner/work/arduino-pico/arduino-pico/tools/json/*.json /home/runner/.platformio/platforms/raspberrypi/boards/.
|
||||||
|
- name: Build Every Variant
|
||||||
|
run: |
|
||||||
|
cnt=0
|
||||||
|
for b in $(cut -f1 -d. /home/runner/work/arduino-pico/arduino-pico/boards.txt | sed 's/#.*//' | sed 's/^menu$//' | sort -u); do
|
||||||
|
cnt=$((cnt + 1))
|
||||||
|
rem=$((cnt % 2))
|
||||||
|
if [ $rem == ${{ matrix.chunk }} ]; then
|
||||||
|
pio ci --board=$b -O "platform_packages=framework-arduinopico@symlink:///home/runner/work/arduino-pico/arduino-pico" libraries/rp2040/examples/Bootsel/Bootsel.ino
|
||||||
|
fi
|
||||||
|
done
|
||||||
46
.github/workflows/release-to-publish.yml
vendored
Normal file
46
.github/workflows/release-to-publish.yml
vendored
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
name: Arduino-Pico Release Publisher
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
package:
|
||||||
|
name: Update master JSON file
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- name: Cache pip
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
path: ~/.cache/pip
|
||||||
|
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-pip-
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.x'
|
||||||
|
# - name: Cache PlatformIO
|
||||||
|
# uses: actions/cache@v4
|
||||||
|
# with:
|
||||||
|
# path: ~/.platformio
|
||||||
|
# key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
||||||
|
# - name: Install PlatformIO
|
||||||
|
# run: |
|
||||||
|
# python -m pip install --upgrade pip
|
||||||
|
# pip install --upgrade platformio
|
||||||
|
- name: Deploy updated JSON
|
||||||
|
env:
|
||||||
|
BUILD_TYPE: package
|
||||||
|
CI_GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
PLATFORMIO_AUTH_TOKEN: ${{ secrets.PLATFORMIO_AUTH_TOKEN }}
|
||||||
|
run: |
|
||||||
|
pip3 install PyGithub
|
||||||
|
TAG=$(git describe --exact-match --tags)
|
||||||
|
curl -L -o package_rp2040_index.json "$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/package_rp2040_index.json"
|
||||||
|
./package/update_release.py --token ${CI_GITHUB_API_KEY} --repo "$GITHUB_REPOSITORY" --tag global package_rp2040_index.json
|
||||||
|
# Upload to Platform.IO
|
||||||
|
# curl -LO $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/releases/download/$TAG/rp2040-$TAG.zip
|
||||||
|
# pio package publish rp2040-$TAG.zip --non-interactive
|
||||||
41
.github/workflows/tag-to-draft-release.yml
vendored
Normal file
41
.github/workflows/tag-to-draft-release.yml
vendored
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Whenever a tag of the form #.xxxx is pushed against master, generate a
|
||||||
|
# draft release and upload the ZIP and JSON file to it. Maintainers then
|
||||||
|
# will manually add the changelist and publish it.
|
||||||
|
|
||||||
|
name: Arduino-Pico Draft Release
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
# Run for tags of the x.x.x* form (i.e. 3.0.0, 3.0.0-beta, etc.).
|
||||||
|
- '[0-9]+.[0-9]+.[0-9]+*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
package:
|
||||||
|
name: Package
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
fetch-depth: 0
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.x'
|
||||||
|
- name: Build package JSON
|
||||||
|
env:
|
||||||
|
BUILD_TYPE: package
|
||||||
|
CI_GITHUB_API_KEY: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
(cd pico-sdk && git submodule update --init)
|
||||||
|
(cd ./package && bash ./build_boards_manager_package.sh)
|
||||||
|
pip3 install PyGithub
|
||||||
|
# Create a draft release and upload the ZIP and JSON files.
|
||||||
|
# This draft is not visible to normal users and needs to be
|
||||||
|
# updated manually with release notes and published from the
|
||||||
|
# GitHub web interface.
|
||||||
|
json=$(find ./package/versions -name package_rp2040_index.json)
|
||||||
|
log=$(find ./package/versions -name package_rp2040_index.log)
|
||||||
|
zip=$(find ./package/versions -name rp2040*zip)
|
||||||
|
tag=$(find ./package/versions -name package_rp2040_index.tag -exec cat \{\} \;)
|
||||||
|
python3 ./package/upload_release.py --repo "$GITHUB_REPOSITORY" --token "$CI_GITHUB_API_KEY" --tag "$tag" --name "Release $tag" --msg "@$log" "$zip" "$json"
|
||||||
11
.gitignore
vendored
11
.gitignore
vendored
|
|
@ -1,5 +1,12 @@
|
||||||
|
|
||||||
.DS_Store
|
.DS_Store
|
||||||
system
|
system
|
||||||
tools/dist
|
tools/dist
|
||||||
cores/rp2040/api
|
docs/_build
|
||||||
|
ota/build
|
||||||
|
ota/build-rp2350
|
||||||
|
ota/build-rp2350-riscv
|
||||||
|
tools/libpico/boot
|
||||||
|
tools/libpico/build-rp2040
|
||||||
|
tools/libpico/build-rp2350
|
||||||
|
tools/libpico/build-rp2350-riscv
|
||||||
|
platform.local.txt
|
||||||
|
|
|
||||||
41
.gitmodules
vendored
41
.gitmodules
vendored
|
|
@ -10,9 +10,42 @@
|
||||||
[submodule "libraries/LittleFS/lib/littlefs"]
|
[submodule "libraries/LittleFS/lib/littlefs"]
|
||||||
path = libraries/LittleFS/lib/littlefs
|
path = libraries/LittleFS/lib/littlefs
|
||||||
url = https://github.com/littlefs-project/littlefs.git
|
url = https://github.com/littlefs-project/littlefs.git
|
||||||
|
[submodule "libraries/Keyboard"]
|
||||||
|
path = libraries/HID_Keyboard
|
||||||
|
url = https://github.com/earlephilhower/Keyboard.git
|
||||||
|
[submodule "libraries/Mouse"]
|
||||||
|
path = libraries/HID_Mouse
|
||||||
|
url = https://github.com/earlephilhower/Mouse.git
|
||||||
|
[submodule "libraries/Joystick"]
|
||||||
|
path = libraries/HID_Joystick
|
||||||
|
url = https://github.com/earlephilhower/Joystick.git
|
||||||
|
[submodule "libraries/Adafruit_TinyUSB_Arduino"]
|
||||||
|
path = libraries/Adafruit_TinyUSB_Arduino
|
||||||
|
url = https://github.com/adafruit/Adafruit_TinyUSB_Arduino.git
|
||||||
|
[submodule "libraries/FreeRTOS/lib/FreeRTOS-Kernel"]
|
||||||
|
path = libraries/FreeRTOS/lib/FreeRTOS-Kernel
|
||||||
|
url = https://github.com/earlephilhower/FreeRTOS-Kernel.git
|
||||||
|
[submodule "tools/libbearssl/bearssl"]
|
||||||
|
path = tools/libbearssl/bearssl
|
||||||
|
url = https://github.com/earlephilhower/bearssl-esp8266.git
|
||||||
|
[submodule "ota/uzlib"]
|
||||||
|
path = ota/uzlib
|
||||||
|
url = https://github.com/pfalcon/uzlib.git
|
||||||
|
[submodule "libraries/http_parser/lib/http-parser"]
|
||||||
|
path = libraries/http-parser/lib/http-parser
|
||||||
|
url = https://github.com/nodejs/http-parser.git
|
||||||
|
[submodule "libraries/FatFS/lib/SPIFTL"]
|
||||||
|
path = libraries/FatFS/lib/SPIFTL
|
||||||
|
url = https://github.com/earlephilhower/SPIFTL.git
|
||||||
|
[submodule "libraries/AsyncUDP"]
|
||||||
|
path = libraries/AsyncUDP
|
||||||
|
url = https://github.com/earlephilhower/AsyncUDP.git
|
||||||
|
[submodule "cores/rp2040/tlsf"]
|
||||||
|
path = lib/tlsf
|
||||||
|
url = https://github.com/earlephilhower/tlsf.git
|
||||||
|
[submodule "libraries/ESPHost"]
|
||||||
|
path = libraries/ESPHost
|
||||||
|
url = https://github.com/Networking-for-Arduino/ESPHost.git
|
||||||
[submodule "libraries/SdFat"]
|
[submodule "libraries/SdFat"]
|
||||||
path = libraries/SdFat
|
path = libraries/SdFat
|
||||||
url = https://github.com/earlephilhower/ESP8266SdFat.git
|
url = https://github.com/greiman/SdFat.git
|
||||||
[submodule "pico-extras"]
|
|
||||||
path = pico-extras
|
|
||||||
url = https://github.com/raspberrypi/pico-extras.git
|
|
||||||
|
|
|
||||||
41
.readthedocs.yaml
Normal file
41
.readthedocs.yaml
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
# Read the Docs configuration file for Sphinx projects
|
||||||
|
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||||
|
|
||||||
|
# Required
|
||||||
|
version: 2
|
||||||
|
|
||||||
|
# Set the OS, Python version and other tools you might need
|
||||||
|
|
||||||
|
build:
|
||||||
|
os: ubuntu-22.04
|
||||||
|
tools:
|
||||||
|
python: "3.12"
|
||||||
|
jobs:
|
||||||
|
post_create_environment:
|
||||||
|
- python -m pip install sphinx_rtd_theme
|
||||||
|
# You can also specify other tool versions:
|
||||||
|
# nodejs: "20"
|
||||||
|
# rust: "1.70"
|
||||||
|
# golang: "1.20"
|
||||||
|
|
||||||
|
|
||||||
|
# Build documentation in the "docs/" directory with Sphinx
|
||||||
|
|
||||||
|
sphinx:
|
||||||
|
configuration: docs/conf.py
|
||||||
|
# You can configure Sphinx to use a different builder, for instance use the dirhtml builder for simpler URLs
|
||||||
|
# builder: "dirhtml"
|
||||||
|
# Fail on all warnings to avoid broken references
|
||||||
|
# fail_on_warning: true
|
||||||
|
|
||||||
|
# Optionally build your docs in additional formats such as PDF and ePub
|
||||||
|
formats:
|
||||||
|
- pdf
|
||||||
|
# - epub
|
||||||
|
|
||||||
|
# Optional but recommended, declare the Python requirements required
|
||||||
|
# to build your documentation
|
||||||
|
# See https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html
|
||||||
|
# python:
|
||||||
|
# install:
|
||||||
|
# - requirements: docs/requirements.txt
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 9da53735171f7cccbe781c66d9ee1068d94d6ec8
|
Subproject commit 82928635c893189343cf8eb78569f0c4136fded0
|
||||||
264
README.md
264
README.md
|
|
@ -1,25 +1,191 @@
|
||||||
# Arduino-Pico [](https://gitter.im/arduino-pico/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
# Arduino-Pico
|
||||||
|
[](https://github.com/earlephilhower/arduino-pico/releases)
|
||||||
|
[](https://gitter.im/arduino-pico/community)
|
||||||
|
|
||||||
Raspberry Pi Pico Arduino core, for all RP2040 boards
|
Raspberry Pi Pico Arduino core, for all RP2040 and RP2350 boards
|
||||||
|
|
||||||
This is a port of the RP2040 (Raspberry Pi Pico processor) to the Arduino ecosystem.
|
This is a port of Arduino to the RP2040 (Raspberry Pi Pico processor) and RP2350 (Raspberry Pi Pico 2 processor). It uses the bare Raspberry Pi Pico SDK and a custom GCC 14.2/Newlib 4.3 toolchain and supports ARM and RISC-V cores.
|
||||||
|
|
||||||
It uses a custom toolset with GCC 10.2 and Newlib 4.0.0, not depending on system-installed prerequisites. https://github.com/earlephilhower/pico-quick-toolchain
|
# Documentation
|
||||||
|
See https://arduino-pico.readthedocs.io/en/latest/ along with the examples for more detailed usage information.
|
||||||
|
|
||||||
There is automated discovery of boards in bootloader mode, so they show up in the IDE, and the upload command works using the Microsoft UF2 tool (included).
|
# Contributing
|
||||||
|
Read the [Contributing Guide](https://github.com/earlephilhower/arduino-pico/blob/master/docs/contrib.rst) for more information on submitting pull requests and porting libraries or sketches to this core.
|
||||||
|
|
||||||
# Detailed Documentation
|
# Supported Boards
|
||||||
Refer to the examples and https://arduino-pico.readthedocs.io/en/latest/ for more detailed usage information.
|
* Raspberry Pi Pico
|
||||||
|
* Raspberry Pi Pico W
|
||||||
|
* Raspberry Pi Pico 2
|
||||||
|
* Raspberry Pi Pico 2W
|
||||||
|
* 0xCB Helios
|
||||||
|
* Adafruit Feather RP2040
|
||||||
|
* Adafruit Feather RP2040 SCORPIO
|
||||||
|
* Adafruit Floppsy RP2040
|
||||||
|
* Adafruit ItsyBitsy RP2040
|
||||||
|
* Adafruit KB2040
|
||||||
|
* Adafruit Macropad RP2040
|
||||||
|
* Adafruit Metro RP2040
|
||||||
|
* Adafruit Metro RP2350
|
||||||
|
* Adafruit QTPy RP2040
|
||||||
|
* Adafruit STEMMA Friend RP2040
|
||||||
|
* Adafruit Trinkey RP2040 QT
|
||||||
|
* Amken Bunny
|
||||||
|
* Amken Revelop
|
||||||
|
* Amken Revelop Plus
|
||||||
|
* Amken Revelop eS
|
||||||
|
* Architeuthis Flux Jumperless
|
||||||
|
* Architeuthis Flux Jumperless V5
|
||||||
|
* Arduino Nano RP2040 Connect
|
||||||
|
* ArtronShop RP2 Nano
|
||||||
|
* Breadstick Raspberry
|
||||||
|
* BridgeTek IDM2040-7A
|
||||||
|
* BridgeTek IDM2040-43A
|
||||||
|
* Cytron IRIV IO Controller
|
||||||
|
* Cytron Maker Pi RP2040
|
||||||
|
* Cytron Maker Nano RP2040
|
||||||
|
* Cytron Maker Uno RP2040
|
||||||
|
* Cytron Motion 2350 Pro
|
||||||
|
* Datanoise PicoADK v1
|
||||||
|
* Datanoise PicoADK v2 (RP2350)
|
||||||
|
* Degz Suibo RP2040
|
||||||
|
* DeRuiLab FlyBoard2040 Core
|
||||||
|
* DFRobot Beetle RP2040
|
||||||
|
* ElectronicCats Hunter Cat NFC
|
||||||
|
* EVN Alpha
|
||||||
|
* ExtremeElectronics RC2040
|
||||||
|
* GroundStudio Marble Pico
|
||||||
|
* Invector Labs Challenger RP2040 WiFi
|
||||||
|
* Invector Labs Challenger RP2040 WiFi/BLE
|
||||||
|
* Invector Labs Challenger RP2040 WiFi6/BLE
|
||||||
|
* Invector Labs Challenger NB RP2040 WiFi
|
||||||
|
* Invector Labs Challenger RP2040 LTE
|
||||||
|
* Invector Labs Challenger RP2040 LoRa
|
||||||
|
* Invector Labs Challenger RP2040 SubGHz
|
||||||
|
* Invector Labs Challenger RP2040 SD/RTC
|
||||||
|
* Invector Labs Challenger RP2040 UWB
|
||||||
|
* Invector Labs Challenger RP2350 BConnect
|
||||||
|
* Invector Labs Challenger RP2350 WiFi/BLE
|
||||||
|
* Invector Labs RPICO32
|
||||||
|
* Melopero Cookie RP2040
|
||||||
|
* Melopero Shake RP2040
|
||||||
|
* METE HOCA Akana R1
|
||||||
|
* Makerbase MKSTHR36
|
||||||
|
* Makerbase MKSTHR42
|
||||||
|
* MyMakers RP2040
|
||||||
|
* Neko Systems BL2040 Mini
|
||||||
|
* Newsan Archi
|
||||||
|
* nullbits Bit-C PRO
|
||||||
|
* Olimex Pico2XL
|
||||||
|
* Olimex Pico2XXL
|
||||||
|
* Olimex RP2040-Pico30
|
||||||
|
* Pimoroni PGA2040
|
||||||
|
* Pimoroni Pico Plus 2
|
||||||
|
* Pimoroni Pico Plus 2W
|
||||||
|
* Pimoroni Plasma2040
|
||||||
|
* Pimoroni Plasma2350
|
||||||
|
* Pimoroni Servo2040
|
||||||
|
* Pimoroni Tiny2040
|
||||||
|
* Pimoroni Tiny2350
|
||||||
|
* Pintronix PinMax
|
||||||
|
* RAKwireless RAK11300
|
||||||
|
* Redscorp RP2040-Eins
|
||||||
|
* Redscorp RP2040-ProMini
|
||||||
|
* Sea-Picro
|
||||||
|
* Seeed Indicator RP2040
|
||||||
|
* Seeed XIAO RP2040
|
||||||
|
* Seeed XIAO RP2350
|
||||||
|
* Silicognition RP2040-Shim
|
||||||
|
* Solder Party RP2040 Stamp
|
||||||
|
* Solder Party RP2350 Stamp
|
||||||
|
* Solder Party RP2350 Stamp XL
|
||||||
|
* SparkFun IoT RedBoard RP2350
|
||||||
|
* SparkFun MicroMod RP2040
|
||||||
|
* SparkFun ProMicro RP2040
|
||||||
|
* SparkFun ProMicro RP2350
|
||||||
|
* SparkFun Thing Plus RP2040
|
||||||
|
* SparkFun Thing Plus RP2350
|
||||||
|
* SparkFun XRP Controller
|
||||||
|
* uPesy RP2040 DevKit
|
||||||
|
* VCC-GND YD-RP2040
|
||||||
|
* Viyalab Mizu RP2040
|
||||||
|
* Waveshare RP2040 Zero
|
||||||
|
* Waveshare RP2040 One
|
||||||
|
* Waveshare RP2040 Plus
|
||||||
|
* Waveshare RP2040 LCD 0.96
|
||||||
|
* Waveshare RP2040 LCD 1.28
|
||||||
|
* Waveshare RP2040 Matrix
|
||||||
|
* Waveshare RP2040 PiZero
|
||||||
|
* WIZnet W5100S-EVB-Pico
|
||||||
|
* WIZnet W5100S-EVB-Pico2
|
||||||
|
* WIZnet W5500-EVB-Pico
|
||||||
|
* WIZnet W5500-EVB-Pico2
|
||||||
|
* WIZnet W55RP20-EVB-Pico
|
||||||
|
* WIZnet WizFi360-EVB-Pico
|
||||||
|
* Generic RP2040 (configurable flash, I/O pins)
|
||||||
|
* Generic RP2350 (configurable flash, I/O pins)
|
||||||
|
|
||||||
|
# Features
|
||||||
|
* Adafruit TinyUSB Arduino (USB mouse, keyboard, flash drive, generic HID, CDC Serial, MIDI, WebUSB, others)
|
||||||
|
* Bluetooth on the PicoW (Classic and BLE) with Keyboard, Mouse, Joystick, and Virtual Serial
|
||||||
|
* Bluetooth Classic and BLE HID master mode (connect to BT keyboard, mouse, or joystick)
|
||||||
|
* Generic Arduino USB Serial, Keyboard, Joystick, and Mouse emulation
|
||||||
|
* WiFi (Pico W, ESP32-based ESPHost, Atmel WINC1500)
|
||||||
|
* Ethernet (Wired WizNet W6100, WizNet W5500, WizNet W5100, ENC28J60)
|
||||||
|
* HTTP client and server (WebServer)
|
||||||
|
* SSL/TLS/HTTPS
|
||||||
|
* Over-the-Air (OTA) upgrades
|
||||||
|
* Filesystems (LittleFS and SD/SDFS)
|
||||||
|
* Multicore support (setup1() and loop1())
|
||||||
|
* FreeRTOS SMP support
|
||||||
|
* Overclocking and underclocking from the menus
|
||||||
|
* digitalWrite/Read, shiftIn/Out, tone, analogWrite(PWM)/Read, temperature
|
||||||
|
* Analog stereo audio in using DMA and the built-in ADC
|
||||||
|
* Analog stereo audio out using PWM hardware
|
||||||
|
* Bluetooth A2DP audio source (output) and sink (input) on the PicoW
|
||||||
|
* USB drive mode for data loggers (SingleFileDrive, FatFSUSB)
|
||||||
|
* Peripherals: SPI master/slave, Wire(I2C) master/slave, dual UART, emulated EEPROM, I2S audio input/output, Servo
|
||||||
|
* printf (i.e. debug) output over USB serial
|
||||||
|
* Transparent use of PSRAM globals and heap (RP2350 only)
|
||||||
|
* ARM or RISC-V (Hazard3) support for the RP2350
|
||||||
|
* Semihosted serial and file system access
|
||||||
|
* GPROF profiling support
|
||||||
|
|
||||||
|
The RP2040 PIO state machines (SMs) are used to generate jitter-free:
|
||||||
|
* Servos
|
||||||
|
* Tones
|
||||||
|
* I2S Input
|
||||||
|
* I2S Output
|
||||||
|
* Software UARTs (Serial ports)
|
||||||
|
* Software SPIs
|
||||||
|
|
||||||
# Installing via Arduino Boards Manager
|
# Installing via Arduino Boards Manager
|
||||||
**Windows Users**: Please do not use the Windows Store version of the actual Arduino application
|
## Windows-specific Notes
|
||||||
|
Please do not use the Windows Store version of the actual Arduino application
|
||||||
because it has issues detecting attached Pico boards. Use the "Windows ZIP" or plain "Windows"
|
because it has issues detecting attached Pico boards. Use the "Windows ZIP" or plain "Windows"
|
||||||
executable (EXE) download direct from https://arduino.cc. and allow it to install any device
|
executable (EXE) download direct from https://arduino.cc. and allow it to install any device
|
||||||
drivers it suggests. Otherwise the Pico board may not be detected. Also, if trying out the
|
drivers it suggests. Otherwise the Pico board may not be detected. Also, if trying out the
|
||||||
2.0 beta Arduino please install the release 1.8 version beforehand to ensure needed device drivers
|
2.0 beta Arduino please install the release 1.8 version beforehand to ensure needed device drivers
|
||||||
are present. (See #20 for more details.)
|
are present. (See #20 for more details.)
|
||||||
|
|
||||||
|
## Linux-specific Notes
|
||||||
|
Installing Arduino using flatpak (often used by "App Stores" in various Linux
|
||||||
|
distributions) will mean it has restricted access to the host. This might cause uploads to fail
|
||||||
|
with error messages such as the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
Scanning for RP2040 devices
|
||||||
|
...
|
||||||
|
No drive to deploy.
|
||||||
|
```
|
||||||
|
|
||||||
|
If you encounter this, you will need to either install Arduino in a different manner, or override
|
||||||
|
the flatpak sandboxing feature using the following command, then restarting Arduino.
|
||||||
|
|
||||||
|
```
|
||||||
|
flatpak override --user --filesystem=host:ro cc.arduino.IDE2
|
||||||
|
```
|
||||||
|
|
||||||
|
## Installation
|
||||||
Open up the Arduino IDE and go to File->Preferences.
|
Open up the Arduino IDE and go to File->Preferences.
|
||||||
|
|
||||||
In the dialog that pops up, enter the following URL in the "Additional Boards Manager URLs" field:
|
In the dialog that pops up, enter the following URL in the "Additional Boards Manager URLs" field:
|
||||||
|
|
@ -37,6 +203,12 @@ Type "pico" in the search box and select "Add":
|
||||||

|

|
||||||
|
|
||||||
# Installing via GIT
|
# Installing via GIT
|
||||||
|
|
||||||
|
**Windows Users:** Before installing via `git` on Windows, please read and follow the directions in
|
||||||
|
[this link](https://arduino-pico.readthedocs.io/en/latest/platformio.html#important-steps-for-windows-users-before-installing).
|
||||||
|
If Win32 long paths are not enabled, and `git` not configured to use them then there
|
||||||
|
may be errors when attempting to clone the submodules.
|
||||||
|
|
||||||
To install via GIT (for latest and greatest versions):
|
To install via GIT (for latest and greatest versions):
|
||||||
````
|
````
|
||||||
mkdir -p ~/Arduino/hardware/pico
|
mkdir -p ~/Arduino/hardware/pico
|
||||||
|
|
@ -45,17 +217,10 @@ cd ~/Arduino/hardware/pico/rp2040
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
cd pico-sdk
|
cd pico-sdk
|
||||||
git submodule update --init
|
git submodule update --init
|
||||||
cd ../pico-extras
|
|
||||||
git submodule update --init
|
|
||||||
cd ../tools
|
cd ../tools
|
||||||
python3 ./get.py
|
python3 ./get.py
|
||||||
`````
|
`````
|
||||||
|
|
||||||
# Installing both Arduino and CMake
|
|
||||||
Tom's Hardware presented a very nice writeup on installing `arduino-pico` on both Windows and Linux, available at https://www.tomshardware.com/how-to/program-raspberry-pi-pico-with-arduino-ide
|
|
||||||
|
|
||||||
If you follow Les' step-by-step you will also have a fully functional `CMake`-based environment to build Pico apps on if you outgrow the Arduino ecosystem.
|
|
||||||
|
|
||||||
# Uploading Sketches
|
# Uploading Sketches
|
||||||
To upload your first sketch, you will need to hold the BOOTSEL button down while plugging in the Pico to your computer.
|
To upload your first sketch, you will need to hold the BOOTSEL button down while plugging in the Pico to your computer.
|
||||||
Then hit the upload button and the sketch should be transferred and start to run.
|
Then hit the upload button and the sketch should be transferred and start to run.
|
||||||
|
|
@ -76,68 +241,51 @@ To install, follow the directions in
|
||||||
* https://github.com/earlephilhower/arduino-pico-littlefs-plugin/blob/master/README.md
|
* https://github.com/earlephilhower/arduino-pico-littlefs-plugin/blob/master/README.md
|
||||||
|
|
||||||
For detailed usage information, please check the ESP8266 repo documentation (ignore SPIFFS related notes) available at
|
For detailed usage information, please check the ESP8266 repo documentation (ignore SPIFFS related notes) available at
|
||||||
* https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html
|
* https://arduino-pico.readthedocs.io/en/latest/fs.html
|
||||||
|
|
||||||
# Uploading Sketches with Picoprobe
|
# Uploading Sketches with Picoprobe/Debugprobe
|
||||||
If you have built a Raspberry Pi Picoprobe, you can use OpenOCD to handle your sketch uploads and for debugging with GDB.
|
If you have built a Raspberry Pi Picoprobe, you can use OpenOCD to handle your sketch uploads and for debugging with GDB.
|
||||||
|
|
||||||
Under Windows a local admin user should be able to access the Picoprobe port automatically, but under Linux `udev` must be told about the device and to allow normal users access.
|
Under Windows a local admin user should be able to access the Picoprobe port automatically, but under Linux `udev` must be told about the device and to allow normal users access.
|
||||||
|
|
||||||
To set up user-level access to Picoprobes on Ubuntu (and other OSes which use `udev`):
|
To set up user-level access to Picoprobes on Ubuntu (and other OSes which use `udev`):
|
||||||
````
|
````
|
||||||
echo 'SUBSYSTEMS=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0004", GROUP="users", MODE="0666"' | sudo tee -a /etc/udev/rules.d/98-PicoProbe.rules
|
echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="0004", MODE="660", GROUP-"plugdev"' | sudo tee -a /etc/udev/rules.d/98-PicoProbe.rules
|
||||||
|
echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000a", MODE="660", GROUP="plugdev"' | sudo tee -a /etc/udev/rules.d/98-PicoProbe.rules
|
||||||
|
echo 'SUBSYSTEM=="usb", ATTRS{idVendor}=="2e8a", ATTRS{idProduct}=="000f", MODE="660", GROUP="plugdev"' | sudo tee -a /etc/udev/rules.d/98-PicoProbe.rules
|
||||||
sudo udevadm control --reload
|
sudo udevadm control --reload
|
||||||
|
sudo udevadm trigger -w -s usb
|
||||||
````
|
````
|
||||||
|
|
||||||
The first line creates a file with the USB vendor and ID of the Picoprobe and tells UDEV to give users full access to it. The second causes `udev` to load this new rule. Note that you will need to unplug and re-plug in your device the first time you create this file, to allow udev to make the device node properly.
|
The first line creates a device file in `/dev` matching the USB vendor and product ID of the Picoprobe, and it enables global read+write permissions. The second line causes `udev` to load this new rule. The third line requests the kernel generate "device change" events that will cause our new `udev` rule to run.
|
||||||
|
|
||||||
|
If for some reason the device file does not appear, manually unplug and re-plug the USB connection and check again. The output from `dmesg` can reveal useful diagnostics if the device file remains absent.
|
||||||
|
|
||||||
Once Picoprobe permissions are set up properly, then select the board "Raspberry Pi Pico (Picoprobe)" in the Tools menu and upload as normal.
|
Once Picoprobe permissions are set up properly, then select the board "Raspberry Pi Pico (Picoprobe)" in the Tools menu and upload as normal.
|
||||||
|
|
||||||
# Debugging with Picoprobe, OpenOCD, and GDB
|
# Debugging with Picoprobe, OpenOCD, and GDB
|
||||||
The installed tools include a version of OpenOCD (in the pqt-openocd directory) and GDB (in the pqt-gcc directory). These may be used to run GDB in an interactive window as documented in the Pico Getting Started manuals from the Raspberry Pi Foundation.
|
The installed tools include a version of OpenOCD (in the pqt-openocd directory) and GDB (in the pqt-gcc directory). These may be used to run GDB in an interactive window as documented in the Pico Getting Started manuals from the Raspberry Pi Foundation. Use the command line `./system/openocd/bin/openocd -f ./lib/rp2040/picoprobe_cmsis_dap.tcl` or `./system/openocd/bin/openocd -f ./lib/rp2350/picoprobe_cmsis_dap.tcl` from the `git` installation directory.
|
||||||
|
|
||||||
# Status of Port
|
|
||||||
Relatively stable and very functional, but bug reports and PRs always accepted.
|
|
||||||
* digitalWrite/Read
|
|
||||||
* shiftIn/Out
|
|
||||||
* SPI master
|
|
||||||
* analogWrite/PWM
|
|
||||||
* tone/noTone
|
|
||||||
* Wire/I2C Master and Slave
|
|
||||||
* EEPROM
|
|
||||||
* USB Serial(ACM) w/automatic reboot-to-UF2 upload)
|
|
||||||
* Hardware UART
|
|
||||||
* Servo, glitchless
|
|
||||||
* Overclocking and underclocking from the menus
|
|
||||||
* analogRead and Pico chip temperature
|
|
||||||
* Filesystems (LittleFS and SD/SDFS)
|
|
||||||
* I2S audio output
|
|
||||||
* printf (i.e. debug) output over USB serial
|
|
||||||
|
|
||||||
The RP2040 PIO state machines (SMs) are used to generate jitter-free:
|
|
||||||
* Servos
|
|
||||||
* Tones
|
|
||||||
* I2S Output
|
|
||||||
|
|
||||||
# Tutorials from Across the Web
|
|
||||||
Here are some links to coverage and additional tutorials for using `arduino-pico`
|
|
||||||
* The File:: class is taken from the ESP8266. See https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html
|
|
||||||
* Arduino Support for the Pi Pico available! And how fast is the Pico? - https://youtu.be/-XHh17cuH5E
|
|
||||||
* Pre-release Adafruit QT Py RP2040 - https://www.youtube.com/watch?v=sfC1msqXX0I
|
|
||||||
* Adafruit Feather RP2040 running LCD + TMP117 - https://www.youtube.com/watch?v=fKDeqZiIwHg
|
|
||||||
* Demonstration of Servos and I2C in Korean - https://cafe.naver.com/arduinoshield/1201
|
|
||||||
|
|
||||||
# Contributing
|
|
||||||
If you want to contribute or have bugfixes, drop me a note at <earlephilhower@yahoo.com> or open an issue/PR here.
|
|
||||||
|
|
||||||
# Licensing and Credits
|
# Licensing and Credits
|
||||||
* The [Arduino IDE and ArduinoCore-API](https://arduino.cc) are developed and maintained by the Arduino team. The IDE is licensed under GPL.
|
* The [Arduino IDE and ArduinoCore-API](https://arduino.cc) are developed and maintained by the Arduino team. The IDE is licensed under GPL.
|
||||||
* The [RP2040 GCC-based toolchain](https://github.com/earlephilhower/pico-quick-toolchain) is licensed under under the GPL.
|
* The [RP2040 GCC-based toolchain](https://github.com/earlephilhower/pico-quick-toolchain) is licensed under under the GPL.
|
||||||
* The [Pico-SDK](https://github.com/raspberrypi/pico-sdk) and [Pico-Extras](https://github.com/raspberrypi/pico-extras) are by Raspberry Pi (Trading) Ltd and licensed under the BSD 3-Clause license.
|
* The [Pico-SDK](https://github.com/raspberrypi/pico-sdk) is by Raspberry Pi (Trading) Ltd and licensed under the BSD 3-Clause license.
|
||||||
* [Arduino-Pico](https://github.com/earlephilhower/arduino-pico) core files are licenses under the LGPL.
|
* [Arduino-Pico](https://github.com/earlephilhower/arduino-pico) core files are licensed under the LGPL.
|
||||||
* [LittleFS](https://github.com/ARMmbed/littlefs) library written by ARM Limited and released under the [BSD 3-clause license](https://github.com/ARMmbed/littlefs/blob/master/LICENSE.md).
|
* [LittleFS](https://github.com/ARMmbed/littlefs) library written by ARM Limited and released under the [BSD 3-clause license](https://github.com/ARMmbed/littlefs/blob/master/LICENSE.md).
|
||||||
* [UF2CONV.PY](https://github.com/microsoft/uf2) is by Microsoft Corporatio and licensed under the MIT license.
|
* [UF2CONV.PY](https://github.com/microsoft/uf2) is by Microsoft Corporation and licensed under the MIT license.
|
||||||
* Some filesystem code taken from the [ESP8266 Arduino Core](https://github.com/esp8266/Arduino) and licensed under the LGPL.
|
* Networking and filesystem code taken from the [ESP8266 Arduino Core](https://github.com/esp8266/Arduino) and licensed under the LGPL.
|
||||||
|
* DHCP server for AP host mode from the [Micropython Project](https://micropython.org), distributed under the MIT License.
|
||||||
|
* [FreeRTOS](https://freertos.org) is copyright Amazon.com, Inc. or its affiliates, and distributed under the MIT license.
|
||||||
|
* [lwIP](https://savannah.nongnu.org/projects/lwip/) is (c) the Swedish Institute of Computer Science and licenced under the BSD license.
|
||||||
|
* [BearSSL](https://bearssl.org) library written by Thomas Pornin, is distributed under the [MIT License](https://bearssl.org/#legal-details).
|
||||||
|
* [UZLib](https://github.com/pfalcon/uzlib) is copyright (c) 2003 Joergen Ibsen and distributed under the zlib license.
|
||||||
|
* [LEAmDNS](https://github.com/LaborEtArs/ESP8266mDNS) is copyright multiple authors and distributed under the MIT license.
|
||||||
|
* [http-parser](https://github.com/nodejs/http-parser) is copyright Joyent, Inc. and other Node contributors.
|
||||||
|
* WebServer code modified from the [ESP32 WebServer](https://github.com/espressif/arduino-esp32/tree/master/libraries/WebServer) and is copyright (c) 2015 Ivan Grokhotkov and others.
|
||||||
|
* [Xoshiro-cpp](https://github.com/Reputeless/Xoshiro-cpp) is copyright (c) 2020 Ryo Suzuki and distributed under the MIT license.
|
||||||
|
* [FatFS low-level filesystem](http://elm-chan.org/fsw/ff/) code is Copyright (C) 2024, ChaN, all rights reserved.
|
||||||
|
* [TLSF memory manager for PSRAM from Espressif fork](https://github.com/espressif/tlsf) of [original](https://github.com/mattconte/tlsf) by Matthew Conte is copyright Matthew Conte and licensed under the MIT license.
|
||||||
|
* [ESPHost library](https://github.com/Networking-for-Arduino/ESPHost) is LGPL licensed by its maintainers.
|
||||||
|
|
||||||
-Earle F. Philhower, III
|
-Earle F. Philhower, III
|
||||||
earlephilhower@yahoo.com
|
earlephilhower@yahoo.com
|
||||||
|
|
|
||||||
315
assembly/crt0.S
315
assembly/crt0.S
|
|
@ -1,315 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "hardware/regs/m0plus.h"
|
|
||||||
#include "hardware/platform_defs.h"
|
|
||||||
#include "hardware/regs/addressmap.h"
|
|
||||||
#include "hardware/regs/sio.h"
|
|
||||||
#include "pico/binary_info/defs.h"
|
|
||||||
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#ifndef COLLAPSE_IRQS
|
|
||||||
#define COLLAPSE_IRQS
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
.syntax unified
|
|
||||||
.cpu cortex-m0plus
|
|
||||||
.thumb
|
|
||||||
|
|
||||||
.section .vectors, "ax"
|
|
||||||
.align 2
|
|
||||||
|
|
||||||
.global __vectors
|
|
||||||
__vectors:
|
|
||||||
.word __StackTop
|
|
||||||
.word _reset_handler
|
|
||||||
.word isr_nmi
|
|
||||||
.word isr_hardfault
|
|
||||||
.word isr_invalid // Reserved, should never fire
|
|
||||||
.word isr_invalid // Reserved, should never fire
|
|
||||||
.word isr_invalid // Reserved, should never fire
|
|
||||||
.word isr_invalid // Reserved, should never fire
|
|
||||||
.word isr_invalid // Reserved, should never fire
|
|
||||||
.word isr_invalid // Reserved, should never fire
|
|
||||||
.word isr_invalid // Reserved, should never fire
|
|
||||||
.word isr_svcall
|
|
||||||
.word isr_invalid // Reserved, should never fire
|
|
||||||
.word isr_invalid // Reserved, should never fire
|
|
||||||
.word isr_pendsv
|
|
||||||
.word isr_systick
|
|
||||||
.word isr_irq0
|
|
||||||
.word isr_irq1
|
|
||||||
.word isr_irq2
|
|
||||||
.word isr_irq3
|
|
||||||
.word isr_irq4
|
|
||||||
.word isr_irq5
|
|
||||||
.word isr_irq6
|
|
||||||
.word isr_irq7
|
|
||||||
.word isr_irq8
|
|
||||||
.word isr_irq9
|
|
||||||
.word isr_irq10
|
|
||||||
.word isr_irq11
|
|
||||||
.word isr_irq12
|
|
||||||
.word isr_irq13
|
|
||||||
.word isr_irq14
|
|
||||||
.word isr_irq15
|
|
||||||
.word isr_irq16
|
|
||||||
.word isr_irq17
|
|
||||||
.word isr_irq18
|
|
||||||
.word isr_irq19
|
|
||||||
.word isr_irq20
|
|
||||||
.word isr_irq21
|
|
||||||
.word isr_irq22
|
|
||||||
.word isr_irq23
|
|
||||||
.word isr_irq24
|
|
||||||
.word isr_irq25
|
|
||||||
.word isr_irq26
|
|
||||||
.word isr_irq27
|
|
||||||
.word isr_irq28
|
|
||||||
.word isr_irq29
|
|
||||||
.word isr_irq30
|
|
||||||
.word isr_irq31
|
|
||||||
|
|
||||||
// Declare a weak symbol for each ISR.
|
|
||||||
// By default, they will fall through to the undefined IRQ handler below (breakpoint),
|
|
||||||
// but can be overridden by C functions with correct name.
|
|
||||||
|
|
||||||
.macro decl_isr_bkpt name
|
|
||||||
.weak \name
|
|
||||||
.type \name,%function
|
|
||||||
.thumb_func
|
|
||||||
\name:
|
|
||||||
bkpt #0
|
|
||||||
.endm
|
|
||||||
|
|
||||||
// these are separated out for clarity
|
|
||||||
decl_isr_bkpt isr_invalid
|
|
||||||
decl_isr_bkpt isr_nmi
|
|
||||||
decl_isr_bkpt isr_hardfault
|
|
||||||
decl_isr_bkpt isr_svcall
|
|
||||||
decl_isr_bkpt isr_pendsv
|
|
||||||
decl_isr_bkpt isr_systick
|
|
||||||
|
|
||||||
.macro decl_isr name
|
|
||||||
.weak \name
|
|
||||||
.type \name,%function
|
|
||||||
.thumb_func
|
|
||||||
\name:
|
|
||||||
.endm
|
|
||||||
|
|
||||||
decl_isr isr_irq0
|
|
||||||
decl_isr isr_irq1
|
|
||||||
decl_isr isr_irq2
|
|
||||||
decl_isr isr_irq3
|
|
||||||
decl_isr isr_irq4
|
|
||||||
decl_isr isr_irq5
|
|
||||||
decl_isr isr_irq6
|
|
||||||
decl_isr isr_irq7
|
|
||||||
decl_isr isr_irq8
|
|
||||||
decl_isr isr_irq9
|
|
||||||
decl_isr isr_irq10
|
|
||||||
decl_isr isr_irq11
|
|
||||||
decl_isr isr_irq12
|
|
||||||
decl_isr isr_irq13
|
|
||||||
decl_isr isr_irq14
|
|
||||||
decl_isr isr_irq15
|
|
||||||
decl_isr isr_irq16
|
|
||||||
decl_isr isr_irq17
|
|
||||||
decl_isr isr_irq18
|
|
||||||
decl_isr isr_irq19
|
|
||||||
decl_isr isr_irq20
|
|
||||||
decl_isr isr_irq21
|
|
||||||
decl_isr isr_irq22
|
|
||||||
decl_isr isr_irq23
|
|
||||||
decl_isr isr_irq24
|
|
||||||
decl_isr isr_irq25
|
|
||||||
decl_isr isr_irq26
|
|
||||||
decl_isr isr_irq27
|
|
||||||
decl_isr isr_irq28
|
|
||||||
decl_isr isr_irq29
|
|
||||||
decl_isr isr_irq30
|
|
||||||
decl_isr isr_irq31
|
|
||||||
|
|
||||||
// All unhandled USER IRQs fall through to here
|
|
||||||
.global __unhandled_user_irq
|
|
||||||
.thumb_func
|
|
||||||
__unhandled_user_irq:
|
|
||||||
bl __get_current_exception
|
|
||||||
subs r0, #16
|
|
||||||
.global unhandled_user_irq_num_in_r0
|
|
||||||
unhandled_user_irq_num_in_r0:
|
|
||||||
bkpt #0
|
|
||||||
|
|
||||||
.section .reset, "ax"
|
|
||||||
|
|
||||||
// This is the beginning of the image, which is entered from stage2 or bootrom USB MSD watchdog reboot
|
|
||||||
|
|
||||||
// note if we are NO_FLASH then start: below is currently identical anyway, so save 4 bytes
|
|
||||||
#if !PICO_NO_FLASH
|
|
||||||
// We simply install our own vector table and redirect through it
|
|
||||||
ldr r0, =__vectors
|
|
||||||
b __vector_entry
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// ELF entry point generally called when we load an ELF via debugger
|
|
||||||
.type _entry_point,%function
|
|
||||||
.thumb_func
|
|
||||||
.global _entry_point
|
|
||||||
_entry_point:
|
|
||||||
|
|
||||||
#if PICO_NO_FLASH
|
|
||||||
// non flash
|
|
||||||
ldr r0, =__vectors
|
|
||||||
#else
|
|
||||||
// todo clear watchdog?
|
|
||||||
// When using flash, we install and use the ROM vector table to go thru regular bootrom/stage2 flash sequence
|
|
||||||
movs r0, #0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
__vector_entry:
|
|
||||||
ldr r1, =(PPB_BASE + M0PLUS_CPUID_OFFSET)
|
|
||||||
str r0, [r1, #8]
|
|
||||||
ldmia r0!, {r1, r2}
|
|
||||||
msr msp, r1
|
|
||||||
bx r2
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Reset handler:
|
|
||||||
// - initialises .data
|
|
||||||
// - clears .bss
|
|
||||||
// - calls runtime_init
|
|
||||||
// - calls main
|
|
||||||
// - calls exit (which should eventually hang the processor via _exit)
|
|
||||||
|
|
||||||
.type _reset_handler,%function
|
|
||||||
.thumb_func
|
|
||||||
_reset_handler:
|
|
||||||
// Hang all cores except core 0
|
|
||||||
ldr r0, =(SIO_BASE + SIO_CPUID_OFFSET)
|
|
||||||
ldr r0, [r0]
|
|
||||||
cmp r0, #0
|
|
||||||
bne wait_for_vector
|
|
||||||
|
|
||||||
adr r4, data_cpy_table
|
|
||||||
|
|
||||||
// assume there is at least one entry
|
|
||||||
1:
|
|
||||||
ldmia r4!, {r1-r3}
|
|
||||||
cmp r1, #0
|
|
||||||
beq 2f
|
|
||||||
bl data_cpy
|
|
||||||
b 1b
|
|
||||||
2:
|
|
||||||
|
|
||||||
// Zero out the BSS
|
|
||||||
ldr r1, =__bss_start__
|
|
||||||
ldr r2, =__bss_end__
|
|
||||||
movs r0, #0
|
|
||||||
b bss_fill_test
|
|
||||||
bss_fill_loop:
|
|
||||||
stm r1!, {r0}
|
|
||||||
bss_fill_test:
|
|
||||||
cmp r1, r2
|
|
||||||
bne bss_fill_loop
|
|
||||||
|
|
||||||
platform_entry: // symbol for stack traces
|
|
||||||
// Use 32-bit jumps, in case these symbols are moved out of branch range
|
|
||||||
// (e.g. if main is in SRAM and crt0 in flash)
|
|
||||||
ldr r1, =runtime_init
|
|
||||||
blx r1
|
|
||||||
ldr r1, =main
|
|
||||||
blx r1
|
|
||||||
ldr r1, =exit
|
|
||||||
blx r1
|
|
||||||
// exit should not return. If it does, hang the core.
|
|
||||||
// (fall thru into our hang _exit impl
|
|
||||||
.weak _exit
|
|
||||||
.type _exit,%function
|
|
||||||
.thumb_func
|
|
||||||
_exit:
|
|
||||||
1: // separate label because _exit can be moved out of branch range
|
|
||||||
bkpt #0
|
|
||||||
b 1b
|
|
||||||
|
|
||||||
data_cpy_loop:
|
|
||||||
ldm r1!, {r0}
|
|
||||||
stm r2!, {r0}
|
|
||||||
data_cpy:
|
|
||||||
cmp r2, r3
|
|
||||||
blo data_cpy_loop
|
|
||||||
bx lr
|
|
||||||
|
|
||||||
#if !PICO_NO_BINARY_INFO
|
|
||||||
binary_info_header:
|
|
||||||
.word BINARY_INFO_MARKER_START
|
|
||||||
.word __binary_info_start
|
|
||||||
.word __binary_info_end
|
|
||||||
.word data_cpy_table // we may need to decode pointers that are in RAM at runtime.
|
|
||||||
.word BINARY_INFO_MARKER_END
|
|
||||||
#endif
|
|
||||||
|
|
||||||
.align 2
|
|
||||||
data_cpy_table:
|
|
||||||
#if PICO_COPY_TO_RAM
|
|
||||||
.word __ram_text_source__
|
|
||||||
.word __ram_text_start__
|
|
||||||
.word __ram_text_end__
|
|
||||||
#endif
|
|
||||||
.word __etext
|
|
||||||
.word __data_start__
|
|
||||||
.word __data_end__
|
|
||||||
|
|
||||||
.word __scratch_x_source__
|
|
||||||
.word __scratch_x_start__
|
|
||||||
.word __scratch_x_end__
|
|
||||||
|
|
||||||
.word __scratch_y_source__
|
|
||||||
.word __scratch_y_start__
|
|
||||||
.word __scratch_y_end__
|
|
||||||
|
|
||||||
.word 0 // null terminator
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Provide safe defaults for _exit and runtime_init
|
|
||||||
// Full implementations usually provided by platform.c
|
|
||||||
|
|
||||||
.weak runtime_init
|
|
||||||
.type runtime_init,%function
|
|
||||||
.thumb_func
|
|
||||||
runtime_init:
|
|
||||||
bx lr
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// In case core 1's VTOR has already been moved into flash, we need to handle
|
|
||||||
// core 1 reset. However, we do so by just jumping back into bootrom version of
|
|
||||||
// wait_for_vector
|
|
||||||
|
|
||||||
wait_for_vector:
|
|
||||||
ldr r0, = 'W' | ('V' << 8)
|
|
||||||
bl rom_func_lookup
|
|
||||||
bx r0
|
|
||||||
|
|
||||||
.global __get_current_exception
|
|
||||||
.thumb_func
|
|
||||||
__get_current_exception:
|
|
||||||
mrs r0, ipsr
|
|
||||||
uxtb r0, r0
|
|
||||||
bx lr
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
|
||||||
// Stack/heap dummies to set size
|
|
||||||
|
|
||||||
.section .stack
|
|
||||||
// align to allow for memory protection (although this alignment is pretty much ignored by linker script)
|
|
||||||
.align 5
|
|
||||||
.equ StackSize, PICO_STACK_SIZE
|
|
||||||
.space StackSize
|
|
||||||
|
|
||||||
.section .heap
|
|
||||||
.align 2
|
|
||||||
.equ HeapSize, PICO_HEAP_SIZE
|
|
||||||
.space HeapSize
|
|
||||||
37222
boards.txt
37222
boards.txt
File diff suppressed because it is too large
Load diff
23
boot2/rp2040/boot2_W25Q32JVxQ_4_padded_checksum.S
Normal file
23
boot2/rp2040/boot2_W25Q32JVxQ_4_padded_checksum.S
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Padded and checksummed version of: generated\Winbond\W25Q32JVxQ\boot2.bin
|
||||||
|
|
||||||
|
.cpu cortex-m0plus
|
||||||
|
.thumb
|
||||||
|
|
||||||
|
.section .boot2, "ax"
|
||||||
|
|
||||||
|
.byte 0xf7, 0xb5, 0x73, 0x46, 0x21, 0x22, 0x02, 0x25, 0x01, 0x93, 0x29, 0x4b, 0xc0, 0x24, 0x5a, 0x60
|
||||||
|
.byte 0x9a, 0x68, 0x01, 0x26, 0xaa, 0x43, 0xda, 0x60, 0x9a, 0x60, 0x1a, 0x61, 0x5a, 0x61, 0x00, 0x23
|
||||||
|
.byte 0x64, 0x05, 0xa3, 0x60, 0x04, 0x33, 0x63, 0x61, 0x22, 0x4b, 0x28, 0x00, 0x1e, 0x60, 0xe0, 0x23
|
||||||
|
.byte 0xdb, 0x02, 0x23, 0x60, 0x35, 0x23, 0xa6, 0x60, 0x23, 0x66, 0x23, 0x66, 0x00, 0xf0, 0x4a, 0xf8
|
||||||
|
.byte 0xc0, 0xb2, 0xa8, 0x42, 0x12, 0xd0, 0x06, 0x23, 0x30, 0x00, 0x23, 0x66, 0x00, 0xf0, 0x42, 0xf8
|
||||||
|
.byte 0x31, 0x23, 0x28, 0x00, 0x23, 0x66, 0x25, 0x66, 0x00, 0xf0, 0x3c, 0xf8, 0x03, 0x35, 0x25, 0x66
|
||||||
|
.byte 0x02, 0x20, 0x25, 0x66, 0x00, 0xf0, 0x36, 0xf8, 0x30, 0x42, 0xf8, 0xd1, 0x00, 0x25, 0x12, 0x4b
|
||||||
|
.byte 0xa5, 0x60, 0x12, 0x4f, 0x23, 0x60, 0x12, 0x4b, 0x65, 0x60, 0x01, 0x26, 0x3b, 0x60, 0xeb, 0x23
|
||||||
|
.byte 0xa6, 0x60, 0x23, 0x66, 0x4b, 0x3b, 0x23, 0x66, 0x02, 0x20, 0x00, 0xf0, 0x23, 0xf8, 0x0d, 0x4b
|
||||||
|
.byte 0xa5, 0x60, 0x3b, 0x60, 0xa6, 0x60, 0x01, 0x9b, 0xab, 0x42, 0x08, 0xd1, 0x0a, 0x4b, 0x0b, 0x4a
|
||||||
|
.byte 0x13, 0x60, 0x1b, 0x68, 0x83, 0xf3, 0x08, 0x88, 0x09, 0x4b, 0x1b, 0x68, 0x18, 0x47, 0xf7, 0xbd
|
||||||
|
.byte 0x00, 0x00, 0x02, 0x40, 0xf0, 0x00, 0x00, 0x18, 0x00, 0x03, 0x5f, 0x00, 0xf4, 0x00, 0x00, 0x18
|
||||||
|
.byte 0x21, 0x22, 0x00, 0x00, 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0
|
||||||
|
.byte 0x04, 0x01, 0x00, 0x10, 0xc0, 0x23, 0x02, 0x00, 0x04, 0x21, 0x5b, 0x05, 0x98, 0x6a, 0x08, 0x42
|
||||||
|
.byte 0xfc, 0xd0, 0x01, 0x21, 0x98, 0x6a, 0x08, 0x42, 0xfc, 0xd1, 0x18, 0x6e, 0x01, 0x2a, 0x00, 0xd0
|
||||||
|
.byte 0x18, 0x6e, 0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x2d, 0x68, 0xca
|
||||||
23
boot2/rp2040/boot2_w25q128jvxq_4_padded_checksum.S
Normal file
23
boot2/rp2040/boot2_w25q128jvxq_4_padded_checksum.S
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Padded and checksummed version of: generated\Winbond\W25Q128JVxQ\boot2.bin by @maxgerhardt
|
||||||
|
|
||||||
|
.cpu cortex-m0plus
|
||||||
|
.thumb
|
||||||
|
|
||||||
|
.section .boot2, "ax"
|
||||||
|
|
||||||
|
.byte 0xf7, 0xb5, 0x73, 0x46, 0x21, 0x22, 0x02, 0x26, 0x01, 0x93, 0x29, 0x4b, 0xc0, 0x24, 0x5a, 0x60
|
||||||
|
.byte 0x9a, 0x68, 0x00, 0x27, 0xb2, 0x43, 0xda, 0x60, 0x9a, 0x60, 0x1a, 0x61, 0x5a, 0x61, 0x04, 0x23
|
||||||
|
.byte 0x01, 0x25, 0x64, 0x05, 0xa7, 0x60, 0x63, 0x61, 0x22, 0x4b, 0x30, 0x00, 0x1d, 0x60, 0xe0, 0x23
|
||||||
|
.byte 0xdb, 0x02, 0x23, 0x60, 0x35, 0x23, 0xa5, 0x60, 0x23, 0x66, 0x23, 0x66, 0x00, 0xf0, 0x4a, 0xf8
|
||||||
|
.byte 0xc0, 0xb2, 0xb0, 0x42, 0x12, 0xd0, 0x06, 0x23, 0x28, 0x00, 0x23, 0x66, 0x00, 0xf0, 0x42, 0xf8
|
||||||
|
.byte 0x25, 0x66, 0x03, 0x20, 0x27, 0x66, 0x26, 0x66, 0x00, 0xf0, 0x3c, 0xf8, 0x03, 0x36, 0x26, 0x66
|
||||||
|
.byte 0x02, 0x20, 0x26, 0x66, 0x00, 0xf0, 0x36, 0xf8, 0x28, 0x42, 0xf8, 0xd1, 0x00, 0x25, 0x12, 0x4b
|
||||||
|
.byte 0xa5, 0x60, 0x12, 0x4f, 0x23, 0x60, 0x12, 0x4b, 0x65, 0x60, 0x01, 0x26, 0x3b, 0x60, 0xeb, 0x23
|
||||||
|
.byte 0xa6, 0x60, 0x23, 0x66, 0x4b, 0x3b, 0x23, 0x66, 0x02, 0x20, 0x00, 0xf0, 0x23, 0xf8, 0x0d, 0x4b
|
||||||
|
.byte 0xa5, 0x60, 0x3b, 0x60, 0xa6, 0x60, 0x01, 0x9b, 0xab, 0x42, 0x08, 0xd1, 0x0a, 0x4b, 0x0b, 0x4a
|
||||||
|
.byte 0x13, 0x60, 0x1b, 0x68, 0x83, 0xf3, 0x08, 0x88, 0x09, 0x4b, 0x1b, 0x68, 0x18, 0x47, 0xf7, 0xbd
|
||||||
|
.byte 0x00, 0x00, 0x02, 0x40, 0xf0, 0x00, 0x00, 0x18, 0x00, 0x03, 0x5f, 0x00, 0xf4, 0x00, 0x00, 0x18
|
||||||
|
.byte 0x21, 0x22, 0x00, 0x00, 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0
|
||||||
|
.byte 0x04, 0x01, 0x00, 0x10, 0xc0, 0x22, 0x03, 0x00, 0x04, 0x21, 0x52, 0x05, 0x90, 0x6a, 0x08, 0x42
|
||||||
|
.byte 0xfc, 0xd0, 0x01, 0x21, 0x90, 0x6a, 0x08, 0x42, 0xfc, 0xd1, 0x01, 0x3b, 0xdb, 0xb2, 0x10, 0x6e
|
||||||
|
.byte 0x00, 0x2b, 0xfa, 0xd1, 0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xa0, 0xf0, 0x2f
|
||||||
23
boot2/rp2040/boot2_w25q16jvxq_4_padded_checksum.S
Normal file
23
boot2/rp2040/boot2_w25q16jvxq_4_padded_checksum.S
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Padded and checksummed version of: generated\Winbond\W25Q16JVxQ\boot2.bin
|
||||||
|
|
||||||
|
.cpu cortex-m0plus
|
||||||
|
.thumb
|
||||||
|
|
||||||
|
.section .boot2, "ax"
|
||||||
|
|
||||||
|
.byte 0xf7, 0xb5, 0x73, 0x46, 0x21, 0x22, 0x02, 0x26, 0x01, 0x93, 0x29, 0x4b, 0xc0, 0x24, 0x5a, 0x60
|
||||||
|
.byte 0x9a, 0x68, 0x00, 0x27, 0xb2, 0x43, 0xda, 0x60, 0x9a, 0x60, 0x1a, 0x61, 0x5a, 0x61, 0x04, 0x23
|
||||||
|
.byte 0x01, 0x25, 0x64, 0x05, 0xa7, 0x60, 0x63, 0x61, 0x22, 0x4b, 0x30, 0x00, 0x1d, 0x60, 0xe0, 0x23
|
||||||
|
.byte 0xdb, 0x02, 0x23, 0x60, 0x35, 0x23, 0xa5, 0x60, 0x23, 0x66, 0x23, 0x66, 0x00, 0xf0, 0x4a, 0xf8
|
||||||
|
.byte 0xc0, 0xb2, 0xb0, 0x42, 0x12, 0xd0, 0x06, 0x23, 0x28, 0x00, 0x23, 0x66, 0x00, 0xf0, 0x42, 0xf8
|
||||||
|
.byte 0x25, 0x66, 0x03, 0x20, 0x27, 0x66, 0x26, 0x66, 0x00, 0xf0, 0x3c, 0xf8, 0x03, 0x36, 0x26, 0x66
|
||||||
|
.byte 0x02, 0x20, 0x26, 0x66, 0x00, 0xf0, 0x36, 0xf8, 0x28, 0x42, 0xf8, 0xd1, 0x00, 0x25, 0x12, 0x4b
|
||||||
|
.byte 0xa5, 0x60, 0x12, 0x4f, 0x23, 0x60, 0x12, 0x4b, 0x65, 0x60, 0x01, 0x26, 0x3b, 0x60, 0xeb, 0x23
|
||||||
|
.byte 0xa6, 0x60, 0x23, 0x66, 0x4b, 0x3b, 0x23, 0x66, 0x02, 0x20, 0x00, 0xf0, 0x23, 0xf8, 0x0d, 0x4b
|
||||||
|
.byte 0xa5, 0x60, 0x3b, 0x60, 0xa6, 0x60, 0x01, 0x9b, 0xab, 0x42, 0x08, 0xd1, 0x0a, 0x4b, 0x0b, 0x4a
|
||||||
|
.byte 0x13, 0x60, 0x1b, 0x68, 0x83, 0xf3, 0x08, 0x88, 0x09, 0x4b, 0x1b, 0x68, 0x18, 0x47, 0xf7, 0xbd
|
||||||
|
.byte 0x00, 0x00, 0x02, 0x40, 0xf0, 0x00, 0x00, 0x18, 0x00, 0x03, 0x5f, 0x00, 0xf4, 0x00, 0x00, 0x18
|
||||||
|
.byte 0x21, 0x22, 0x00, 0x00, 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0
|
||||||
|
.byte 0x04, 0x01, 0x00, 0x10, 0xc0, 0x22, 0x03, 0x00, 0x04, 0x21, 0x52, 0x05, 0x90, 0x6a, 0x08, 0x42
|
||||||
|
.byte 0xfc, 0xd0, 0x01, 0x21, 0x90, 0x6a, 0x08, 0x42, 0xfc, 0xd1, 0x01, 0x3b, 0xdb, 0xb2, 0x10, 0x6e
|
||||||
|
.byte 0x00, 0x2b, 0xfa, 0xd1, 0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xa0, 0xf0, 0x2f
|
||||||
23
boot2/rp2040/boot2_w25q64jv_4_padded_checksum.S
Normal file
23
boot2/rp2040/boot2_w25q64jv_4_padded_checksum.S
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
// Padded and checksummed version of: boot2_w25q64jv.4.bin
|
||||||
|
|
||||||
|
.cpu cortex-m0plus
|
||||||
|
.thumb
|
||||||
|
|
||||||
|
.section .boot2, "ax"
|
||||||
|
|
||||||
|
.byte 0xf7, 0xb5, 0x73, 0x46, 0x21, 0x22, 0x02, 0x25, 0x01, 0x93, 0x29, 0x4b, 0xc0, 0x24, 0x5a, 0x60
|
||||||
|
.byte 0x9a, 0x68, 0x01, 0x26, 0xaa, 0x43, 0xda, 0x60, 0x9a, 0x60, 0x1a, 0x61, 0x5a, 0x61, 0x00, 0x23
|
||||||
|
.byte 0x64, 0x05, 0xa3, 0x60, 0x04, 0x33, 0x63, 0x61, 0x22, 0x4b, 0x28, 0x00, 0x1e, 0x60, 0xe0, 0x23
|
||||||
|
.byte 0xdb, 0x02, 0x23, 0x60, 0x35, 0x23, 0xa6, 0x60, 0x23, 0x66, 0x23, 0x66, 0x00, 0xf0, 0x4a, 0xf8
|
||||||
|
.byte 0xc0, 0xb2, 0xa8, 0x42, 0x12, 0xd0, 0x06, 0x23, 0x30, 0x00, 0x23, 0x66, 0x00, 0xf0, 0x42, 0xf8
|
||||||
|
.byte 0x31, 0x23, 0x28, 0x00, 0x23, 0x66, 0x25, 0x66, 0x00, 0xf0, 0x3c, 0xf8, 0x03, 0x35, 0x25, 0x66
|
||||||
|
.byte 0x02, 0x20, 0x25, 0x66, 0x00, 0xf0, 0x36, 0xf8, 0x30, 0x42, 0xf8, 0xd1, 0x00, 0x25, 0x12, 0x4b
|
||||||
|
.byte 0xa5, 0x60, 0x12, 0x4f, 0x23, 0x60, 0x12, 0x4b, 0x65, 0x60, 0x01, 0x26, 0x3b, 0x60, 0xeb, 0x23
|
||||||
|
.byte 0xa6, 0x60, 0x23, 0x66, 0x4b, 0x3b, 0x23, 0x66, 0x02, 0x20, 0x00, 0xf0, 0x23, 0xf8, 0x0d, 0x4b
|
||||||
|
.byte 0xa5, 0x60, 0x3b, 0x60, 0xa6, 0x60, 0x01, 0x9b, 0xab, 0x42, 0x08, 0xd1, 0x0a, 0x4b, 0x0b, 0x4a
|
||||||
|
.byte 0x13, 0x60, 0x1b, 0x68, 0x83, 0xf3, 0x08, 0x88, 0x09, 0x4b, 0x1b, 0x68, 0x18, 0x47, 0xf7, 0xbd
|
||||||
|
.byte 0x00, 0x00, 0x02, 0x40, 0xf0, 0x00, 0x00, 0x18, 0x00, 0x03, 0x5f, 0x00, 0xf4, 0x00, 0x00, 0x18
|
||||||
|
.byte 0x21, 0x22, 0x00, 0x00, 0x22, 0x20, 0x00, 0xa0, 0x00, 0x01, 0x00, 0x10, 0x08, 0xed, 0x00, 0xe0
|
||||||
|
.byte 0x04, 0x01, 0x00, 0x10, 0xc0, 0x23, 0x02, 0x00, 0x04, 0x21, 0x5b, 0x05, 0x98, 0x6a, 0x08, 0x42
|
||||||
|
.byte 0xfc, 0xd0, 0x01, 0x21, 0x98, 0x6a, 0x08, 0x42, 0xfc, 0xd1, 0x18, 0x6e, 0x01, 0x2a, 0x00, 0xd0
|
||||||
|
.byte 0x18, 0x6e, 0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x2d, 0x68, 0xca
|
||||||
4
boot2/rp2350-riscv/none.S
Normal file
4
boot2/rp2350-riscv/none.S
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
.section .boot2, "ax"
|
||||||
|
|
||||||
|
.global __boot2_entry_point
|
||||||
|
__boot2_entry_point:
|
||||||
4
boot2/rp2350/none.S
Normal file
4
boot2/rp2350/none.S
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
.section .boot2, "ax"
|
||||||
|
|
||||||
|
.global __boot2_entry_point
|
||||||
|
__boot2_entry_point:
|
||||||
|
|
@ -1,107 +1,178 @@
|
||||||
/*
|
/*
|
||||||
* Arduino header for the Raspberry Pi Pico RP2040
|
Arduino header for the Raspberry Pi Pico RP2040
|
||||||
*
|
|
||||||
* Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef Arduino_h
|
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
#define Arduino_h
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "stdlib_noniso.h" // Wacky deprecated AVR compatibility functions
|
||||||
|
#include "RP2040Version.h"
|
||||||
#include "api/ArduinoAPI.h"
|
#include "api/ArduinoAPI.h"
|
||||||
|
#include "api/itoa.h" // ARM toolchain doesn't provide itoa etc, provide them
|
||||||
|
#include <pico.h>
|
||||||
|
#undef PICO_RP2350A // Set in the RP2350 SDK boards file, overridden in the variant pins_arduino.h
|
||||||
#include <pins_arduino.h>
|
#include <pins_arduino.h>
|
||||||
|
#include <hardware/gpio.h> // Required for the port*Register macros
|
||||||
// Required for the port*Register macros
|
|
||||||
#include "hardware/gpio.h"
|
|
||||||
|
|
||||||
#include "debug_internal.h"
|
#include "debug_internal.h"
|
||||||
|
|
||||||
|
// Chip sanity checking. SDK uses interesting way of separating 2350A from 2350B, see https://github.com/raspberrypi/pico-sdk/issues/2364
|
||||||
|
#if (!defined(PICO_RP2040) && !defined(PICO_RP2350)) || defined(PICO_RP2040) && defined(PICO_RP2350)
|
||||||
|
#error Invalid core definition. Either PICO_RP2040 or PICO_RP2350 must be defined.
|
||||||
|
#endif
|
||||||
|
#if defined(PICO_RP2350) && !defined(PICO_RP2350A)
|
||||||
|
#error Invalid RP2350 definition. Need to set PICO_RP2350A=0/1 for A/B variant
|
||||||
|
#endif
|
||||||
|
#if defined(PICO_RP2350B)
|
||||||
|
#error Do not define PICO_RP2350B. Use PICO_RP2350A=0 to indicate RP2350B. See the SDK for more details
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Try and make the best of the old Arduino abs() macro. When in C++, use
|
||||||
|
// the sane std::abs() call, but for C code use their macro since stdlib abs()
|
||||||
|
// is int but their macro "works" for everything (with potential side effects)
|
||||||
|
#ifdef abs
|
||||||
|
#undef abs
|
||||||
|
#endif // abs
|
||||||
|
#if defined(__cplusplus) && !defined(__riscv)
|
||||||
|
using std::abs;
|
||||||
|
using std::round;
|
||||||
|
#else
|
||||||
|
#define abs(x) ({ __typeof__(x) _x = (x); _x >= 0 ? _x : -_x; })
|
||||||
|
#define round(x) ({ __typeof__(x) _x = (x); _x >= 0 ? (long)(_x + 0.5) : (long)(_x - 0.5); })
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C"{
|
extern "C" {
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
||||||
// Disable/reenable all interrupts. Safely handles nested disables
|
// For compatibility to many platforms and libraries
|
||||||
|
#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L )
|
||||||
|
#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() )
|
||||||
|
#define microsecondsToClockCycles(a) ( (a) * clockCyclesPerMicrosecond() )
|
||||||
|
|
||||||
|
// Disable/re-enable all interrupts. Safely handles nested disables
|
||||||
void interrupts();
|
void interrupts();
|
||||||
void noInterrupts();
|
void noInterrupts();
|
||||||
|
|
||||||
// GPIO change/value interrupts
|
// Only implemented on some RP2350 boards, not the OG Pico 2
|
||||||
void attachInterrupt(pin_size_t pin, voidFuncPtr callback, PinStatus mode);
|
#ifdef RP2350_PSRAM_CS
|
||||||
void detachInterrupt(pin_size_t pin);
|
void *pmalloc(size_t size);
|
||||||
|
void *pcalloc(size_t count, size_t size);
|
||||||
|
#else
|
||||||
|
[[deprecated("This chip does not have PSRAM, pmalloc will always fail")]] void *pmalloc(size_t size);
|
||||||
|
[[deprecated("This chip does not have PSRAM, pcalloc will always fail")]] void *pcalloc(size_t count, size_t size);
|
||||||
|
#endif
|
||||||
|
|
||||||
// AVR compatibilty macros...naughty and accesses the HW directly
|
// AVR compatibility macros...naughty and accesses the HW directly
|
||||||
#define digitalPinToPort(pin) (0)
|
#define digitalPinToPort(pin) (0)
|
||||||
#define digitalPinToBitMask(pin) (1UL << (pin))
|
#define digitalPinToBitMask(pin) (1UL << (pin))
|
||||||
#define digitalPinToTimer(pin) (0)
|
#define digitalPinToTimer(pin) (0)
|
||||||
#define digitalPinToInterrupt(pin) (pin)
|
#define digitalPinToInterrupt(pin) (pin)
|
||||||
#define NOT_AN_INTERRUPT (-1)
|
#define NOT_AN_INTERRUPT (-1)
|
||||||
#define portOutputRegister(port) ((volatile uint32_t*) sio_hw->gpio_out)
|
#define portOutputRegister(port) ((volatile uint32_t *)&(sio_hw->gpio_out))
|
||||||
#define portInputRegister(port) ((volatile uint32_t*) sio_hw->gpio_in)
|
#define portInputRegister(port) ((volatile uint32_t *)&(sio_hw->gpio_in))
|
||||||
#define portModeRegister(port) ((volatile uint32_t*) sio_hw->gpio_oe)
|
#define portModeRegister(port) ((volatile uint32_t *)&(sio_hw->gpio_oe))
|
||||||
|
#define digitalWriteFast(pin, val) (val ? sio_hw->gpio_set = (1 << pin) : sio_hw->gpio_clr = (1 << pin))
|
||||||
|
#define digitalReadFast(pin) ((1 << pin) & sio_hw->gpio_in)
|
||||||
|
#define sei() interrupts()
|
||||||
|
#define cli() noInterrupts()
|
||||||
|
|
||||||
// IO config
|
// ADC RP2040-specific calls
|
||||||
void pinMode(pin_size_t pinNumber, PinMode pinMode);
|
void analogReadResolution(int bits);
|
||||||
|
#ifdef __cplusplus
|
||||||
|
float analogReadTemp(float vref = 3.3); // Returns core temp in Centigrade
|
||||||
|
#endif
|
||||||
|
|
||||||
// SIO (GPIO)
|
// PWM RP2040-specific calls
|
||||||
void digitalWrite(pin_size_t pinNumber, PinStatus status);
|
|
||||||
PinStatus digitalRead(pin_size_t pinNumber);
|
|
||||||
|
|
||||||
// ADC
|
|
||||||
int analogRead(pin_size_t pinNumber);
|
|
||||||
float analogReadTemp(); // Returns core temp in Centigrade
|
|
||||||
|
|
||||||
// PWM
|
|
||||||
void analogWrite(pin_size_t pinNumber, int value);
|
|
||||||
void analogWriteFreq(uint32_t freq);
|
void analogWriteFreq(uint32_t freq);
|
||||||
void analogWriteRange(uint32_t range);
|
void analogWriteRange(uint32_t range);
|
||||||
void analogWriteResolution(int res);
|
void analogWriteResolution(int res);
|
||||||
|
|
||||||
// Timing
|
|
||||||
void delay(unsigned long);
|
|
||||||
void delayMicroseconds(unsigned int us);
|
|
||||||
unsigned long millis();
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// FreeRTOS potential calls
|
||||||
|
extern bool __isFreeRTOS;
|
||||||
|
|
||||||
// Ancient AVR defines
|
// Ancient AVR defines
|
||||||
#define HAVE_HWSERIAL0
|
#define HAVE_HWSERIAL0
|
||||||
#define HAVE_HWSERIAL1
|
#define HAVE_HWSERIAL1
|
||||||
#define HAVE_HWSERIAL2
|
#define HAVE_HWSERIAL2
|
||||||
|
|
||||||
|
// PSTR/etc.
|
||||||
|
#ifndef FPSTR
|
||||||
|
#define FPSTR (const char *)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PGM_VOID_P
|
||||||
|
#define PGM_VOID_P const void *
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
|
// emptyString is an ESP-ism, a constant string with ""
|
||||||
|
extern const String emptyString;
|
||||||
|
|
||||||
|
#ifdef USE_TINYUSB
|
||||||
|
// Needed for declaring Serial
|
||||||
|
#include "Adafruit_USBD_CDC.h"
|
||||||
|
#else
|
||||||
#include "SerialUSB.h"
|
#include "SerialUSB.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "SerialUART.h"
|
#include "SerialUART.h"
|
||||||
#include "RP2040.h"
|
#include "SerialSemi.h"
|
||||||
|
#include "RP2040Support.h"
|
||||||
|
#include "SerialPIO.h"
|
||||||
#include "Bootsel.h"
|
#include "Bootsel.h"
|
||||||
|
|
||||||
// Template which will evaluate at *compile time* to a single 32b number
|
// Template which will evaluate at *compile time* to a single 32b number
|
||||||
// with the specified bits set.
|
// with the specified bits set.
|
||||||
template <size_t N>
|
template <size_t N>
|
||||||
constexpr uint32_t __bitset(const int (&a)[N], size_t i = 0U) {
|
constexpr uint64_t __bitset(const int (&a)[N], size_t i = 0U) {
|
||||||
return i < N ? (1L << a[i]) | __bitset(a, i+1) : 0;
|
return i < N ? (1LL << a[i]) | __bitset(a, i + 1) : 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Warn users trying to use Pico SDK's STDIO implementation
|
||||||
|
#include <pico/stdio.h> // Ensure it won't be re-included elsewhere
|
||||||
|
#undef stdio_uart_init
|
||||||
|
#define stdio_uart_init(...) static_assert(0, "stdio_uart_init is not supported or needed. Either use Serial.printf() or set the debug port in the IDE to Serial/1/2 and use printf(). See https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1540354673 and https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1546783109")
|
||||||
|
#undef stdio_init_all
|
||||||
|
#define stdio_init_all(...) static_assert(0, "stdio_init_all is not supported or needed. Either use Serial.printf() or set the debug port in the IDE to Serial/1/2 and use printf(). See https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1540354673 and https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1546783109")
|
||||||
|
#undef stdio_usb_init
|
||||||
|
#define stdio_usb_init(...) static_assert(0, "stdio_usb_init is not supported or needed. Either use Serial.printf() or set the debug port in the IDE to Serial/1/2 and use printf(). See https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1540354673 and https://github.com/earlephilhower/arduino-pico/issues/1433#issuecomment-1546783109")
|
||||||
|
|
||||||
// ARM toolchain doesn't provide itoa etc, provide them
|
// PSRAM decorator
|
||||||
#include "api/itoa.h"
|
#define PSRAM __attribute__((section("\".psram\"")))
|
||||||
|
|
||||||
#endif // Arduino_h
|
// General GPIO/ADC layout info
|
||||||
|
#if defined(PICO_RP2350) && !PICO_RP2350A
|
||||||
|
#define __GPIOCNT 48
|
||||||
|
#define __FIRSTANALOGGPIO 40
|
||||||
|
#else
|
||||||
|
#define __GPIOCNT 30
|
||||||
|
#define __FIRSTANALOGGPIO 26
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
using namespace arduino;
|
||||||
|
#endif
|
||||||
|
|
|
||||||
21
cores/rp2040/AudioOutputBase.h
Normal file
21
cores/rp2040/AudioOutputBase.h
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
// Abstract class for audio output devices to allow easy swapping between output devices
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Print.h>
|
||||||
|
|
||||||
|
class AudioOutputBase : public Print {
|
||||||
|
public:
|
||||||
|
virtual ~AudioOutputBase() { }
|
||||||
|
virtual bool setBuffers(size_t buffers, size_t bufferWords, int32_t silenceSample = 0) = 0;
|
||||||
|
virtual bool setBitsPerSample(int bps) = 0;
|
||||||
|
virtual bool setFrequency(int freq) = 0;
|
||||||
|
virtual bool setStereo(bool stereo = true) = 0;
|
||||||
|
virtual bool begin() = 0;
|
||||||
|
virtual bool end() = 0;
|
||||||
|
virtual bool getUnderflow() = 0;
|
||||||
|
virtual void onTransmit(void(*)(void *), void *) = 0;
|
||||||
|
// From Print
|
||||||
|
virtual size_t write(const uint8_t *buffer, size_t size) = 0;
|
||||||
|
virtual int availableForWrite() = 0;
|
||||||
|
};
|
||||||
87
cores/rp2040/BluetoothDebug.cpp
Normal file
87
cores/rp2040/BluetoothDebug.cpp
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
/*
|
||||||
|
Enable BTStack debugging to a Print-able object
|
||||||
|
|
||||||
|
Copyright (c) 2023 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(ENABLE_CLASSIC) || defined(ENABLE_BLE)
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <btstack.h>
|
||||||
|
#include <hci_dump.h>
|
||||||
|
|
||||||
|
static Print *_print;
|
||||||
|
|
||||||
|
static void _log_packet(uint8_t packet_type, uint8_t in, uint8_t *packet, uint16_t len) {
|
||||||
|
if (!_print) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_print->printf("[BT @%lu] ", millis());
|
||||||
|
|
||||||
|
switch (packet_type) {
|
||||||
|
case HCI_COMMAND_DATA_PACKET:
|
||||||
|
_print->printf("CMD => ");
|
||||||
|
break;
|
||||||
|
case HCI_EVENT_PACKET:
|
||||||
|
_print->printf("EVT <= ");
|
||||||
|
break;
|
||||||
|
case HCI_ACL_DATA_PACKET:
|
||||||
|
_print->printf("ACL %s ", in ? "<=" : "=>");
|
||||||
|
break;
|
||||||
|
case HCI_SCO_DATA_PACKET:
|
||||||
|
_print->printf("SCO %s ", in ? "<=" : "=>");
|
||||||
|
break;
|
||||||
|
case HCI_ISO_DATA_PACKET:
|
||||||
|
_print->printf("ISO %s ", in ? "<=" : "=>");
|
||||||
|
break;
|
||||||
|
case LOG_MESSAGE_PACKET:
|
||||||
|
_print->printf("LOG -- %s\n", (char*) packet);
|
||||||
|
return;
|
||||||
|
default:
|
||||||
|
_print->printf("UNK(%x) %s ", packet_type, in ? "<=" : "=>");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < len; i++) {
|
||||||
|
_print->printf("%02X ", packet[i]);
|
||||||
|
}
|
||||||
|
_print->printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _log_message(int log_level, const char * format, va_list argptr) {
|
||||||
|
(void)log_level;
|
||||||
|
char log_message_buffer[HCI_DUMP_MAX_MESSAGE_LEN];
|
||||||
|
if (!_print) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vsnprintf(log_message_buffer, sizeof(log_message_buffer), format, argptr);
|
||||||
|
_print->printf("[BT @%lu] LOG -- %s\n", millis(), log_message_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const hci_dump_t hci_dump_instance = {
|
||||||
|
NULL,
|
||||||
|
_log_packet,
|
||||||
|
_log_message
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void __EnableBluetoothDebug(Print &print) {
|
||||||
|
_print = &print;
|
||||||
|
hci_dump_init(&hci_dump_instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,14 +1,14 @@
|
||||||
/**
|
/**
|
||||||
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-3-Clause
|
SPDX-License-Identifier: BSD-3-Clause
|
||||||
*/
|
*/
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "pico/stdlib.h"
|
#include <pico/stdlib.h>
|
||||||
#include "hardware/gpio.h"
|
#include <hardware/gpio.h>
|
||||||
#include "hardware/sync.h"
|
#include <hardware/sync.h>
|
||||||
#include "hardware/structs/ioqspi.h"
|
#include <hardware/structs/ioqspi.h>
|
||||||
#include "hardware/structs/sio.h"
|
#include <hardware/structs/sio.h>
|
||||||
|
|
||||||
// This example blinks the Pico LED when the BOOTSEL button is pressed.
|
// This example blinks the Pico LED when the BOOTSEL button is pressed.
|
||||||
//
|
//
|
||||||
|
|
@ -26,7 +26,10 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() {
|
||||||
|
|
||||||
// Must disable interrupts, as interrupt handlers may be in flash, and we
|
// Must disable interrupts, as interrupt handlers may be in flash, and we
|
||||||
// are about to temporarily disable flash access!
|
// are about to temporarily disable flash access!
|
||||||
uint32_t flags = save_and_disable_interrupts();
|
if (!__isFreeRTOS) {
|
||||||
|
noInterrupts();
|
||||||
|
}
|
||||||
|
rp2040.idleOtherCore();
|
||||||
|
|
||||||
// Set chip select to Hi-Z
|
// Set chip select to Hi-Z
|
||||||
hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl,
|
hw_write_masked(&ioqspi_hw->io[CS_PIN_INDEX].ctrl,
|
||||||
|
|
@ -38,7 +41,12 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() {
|
||||||
|
|
||||||
// The HI GPIO registers in SIO can observe and control the 6 QSPI pins.
|
// The HI GPIO registers in SIO can observe and control the 6 QSPI pins.
|
||||||
// Note the button pulls the pin *low* when pressed.
|
// Note the button pulls the pin *low* when pressed.
|
||||||
bool button_state = !(sio_hw->gpio_hi_in & (1u << CS_PIN_INDEX));
|
#if PICO_RP2040
|
||||||
|
#define CS_BIT (1u << 1)
|
||||||
|
#else
|
||||||
|
#define CS_BIT SIO_GPIO_HI_IN_QSPI_CSN_BITS
|
||||||
|
#endif
|
||||||
|
bool button_state = !(sio_hw->gpio_hi_in & CS_BIT);
|
||||||
|
|
||||||
// Need to restore the state of chip select, else we are going to have a
|
// Need to restore the state of chip select, else we are going to have a
|
||||||
// bad time when we return to code in flash!
|
// bad time when we return to code in flash!
|
||||||
|
|
@ -46,7 +54,10 @@ static bool __no_inline_not_in_flash_func(get_bootsel_button)() {
|
||||||
GPIO_OVERRIDE_NORMAL << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
|
GPIO_OVERRIDE_NORMAL << IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_LSB,
|
||||||
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
IO_QSPI_GPIO_QSPI_SS_CTRL_OEOVER_BITS);
|
||||||
|
|
||||||
restore_interrupts(flags);
|
rp2040.resumeOtherCore();
|
||||||
|
if (!__isFreeRTOS) {
|
||||||
|
interrupts();
|
||||||
|
}
|
||||||
|
|
||||||
return button_state;
|
return button_state;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,40 @@
|
||||||
/*
|
/*
|
||||||
* Simple BOOTSEL reader object
|
Simple BOOTSEL reader object
|
||||||
*
|
|
||||||
* Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Wrapper class for polling the BOOTSEL button
|
||||||
|
*/
|
||||||
class __Bootsel {
|
class __Bootsel {
|
||||||
public:
|
public:
|
||||||
__Bootsel() { }
|
__Bootsel() { }
|
||||||
|
/**
|
||||||
|
@brief Get state of the BOOTSEL pin
|
||||||
|
|
||||||
|
@returns True if BOOTSEL pushed
|
||||||
|
*/
|
||||||
operator bool();
|
operator bool();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief BOOTSEL accessor instance
|
||||||
|
*/
|
||||||
extern __Bootsel BOOTSEL;
|
extern __Bootsel BOOTSEL;
|
||||||
|
|
|
||||||
72
cores/rp2040/CoreMutex.cpp
Normal file
72
cores/rp2040/CoreMutex.cpp
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
CoreMutex for the Raspberry Pi Pico RP2040
|
||||||
|
|
||||||
|
Implements a deadlock-safe multicore mutex for sharing things like the
|
||||||
|
USB or UARTs.
|
||||||
|
|
||||||
|
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
#include "CoreMutex.h"
|
||||||
|
|
||||||
|
CoreMutex::CoreMutex(mutex_t *mutex, uint8_t option) {
|
||||||
|
_mutex = mutex;
|
||||||
|
_acquired = false;
|
||||||
|
_option = option;
|
||||||
|
_pxHigherPriorityTaskWoken = 0; // pdFALSE
|
||||||
|
if (__isFreeRTOS) {
|
||||||
|
auto m = __get_freertos_mutex_for_ptr(mutex);
|
||||||
|
|
||||||
|
if (__freertos_check_if_in_isr()) {
|
||||||
|
if (!__freertos_mutex_take_from_isr(m, &_pxHigherPriorityTaskWoken)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// At this point we have the mutex in ISR
|
||||||
|
} else {
|
||||||
|
// Grab the mutex normally, possibly waking other tasks to get it
|
||||||
|
__freertos_mutex_take(m);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uint32_t owner;
|
||||||
|
if (!mutex_try_enter(_mutex, &owner)) {
|
||||||
|
if (owner == get_core_num()) { // Deadlock!
|
||||||
|
if (_option & DebugEnable) {
|
||||||
|
DEBUGCORE("CoreMutex - Deadlock detected!\n");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mutex_enter_blocking(_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_acquired = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
CoreMutex::~CoreMutex() {
|
||||||
|
if (_acquired) {
|
||||||
|
if (__isFreeRTOS) {
|
||||||
|
auto m = __get_freertos_mutex_for_ptr(_mutex);
|
||||||
|
if (__freertos_check_if_in_isr()) {
|
||||||
|
__freertos_mutex_give_from_isr(m, &_pxHigherPriorityTaskWoken);
|
||||||
|
} else {
|
||||||
|
__freertos_mutex_give(m);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mutex_exit(_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,51 +1,39 @@
|
||||||
/*
|
/*
|
||||||
* CoreMutex for the Raspberry Pi Pico RP2040
|
CoreMutex for the Raspberry Pi Pico RP2040
|
||||||
*
|
|
||||||
* Implements a deadlock-safe multicore mutex for sharing things like the
|
Implements a deadlock-safe multicore mutex for sharing things like the
|
||||||
* USB or UARTs.
|
USB or UARTs.
|
||||||
*
|
|
||||||
* Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "pico/mutex.h"
|
#include <pico/mutex.h>
|
||||||
|
#include "_freertos.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
DebugEnable = 1
|
||||||
|
};
|
||||||
|
|
||||||
class CoreMutex {
|
class CoreMutex {
|
||||||
public:
|
public:
|
||||||
CoreMutex(mutex_t *mutex) {
|
CoreMutex(mutex_t *mutex, uint8_t option = DebugEnable);
|
||||||
uint32_t owner;
|
~CoreMutex();
|
||||||
_mutex = mutex;
|
|
||||||
_acquired = false;
|
|
||||||
if (!mutex_try_enter(_mutex, &owner)) {
|
|
||||||
if (owner == get_core_num()) { // Deadlock!
|
|
||||||
DEBUGCORE("CoreMutex - Deadlock detected!\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mutex_enter_blocking(_mutex);
|
|
||||||
}
|
|
||||||
_acquired = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
~CoreMutex() {
|
|
||||||
if (_acquired) {
|
|
||||||
mutex_exit(_mutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
operator bool() {
|
operator bool() {
|
||||||
return _acquired;
|
return _acquired;
|
||||||
|
|
@ -54,4 +42,6 @@ public:
|
||||||
private:
|
private:
|
||||||
mutex_t *_mutex;
|
mutex_t *_mutex;
|
||||||
bool _acquired;
|
bool _acquired;
|
||||||
|
uint8_t _option;
|
||||||
|
BaseType_t _pxHigherPriorityTaskWoken;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,22 @@
|
||||||
/*
|
/*
|
||||||
FS.cpp - file system wrapper
|
FS.cpp - file system wrapper
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "FS.h"
|
#include "FS.h"
|
||||||
#include "FSImpl.h"
|
#include "FSImpl.h"
|
||||||
|
|
@ -26,37 +26,42 @@ using namespace fs;
|
||||||
static bool sflags(const char* mode, OpenMode& om, AccessMode& am);
|
static bool sflags(const char* mode, OpenMode& om, AccessMode& am);
|
||||||
|
|
||||||
size_t File::write(uint8_t c) {
|
size_t File::write(uint8_t c) {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->write(&c, 1);
|
return _p->write(&c, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t File::write(const uint8_t *buf, size_t size) {
|
size_t File::write(const uint8_t *buf, size_t size) {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->write(buf, size);
|
return _p->write(buf, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int File::available() {
|
int File::available() {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->size() - _p->position();
|
return _p->size() - _p->position();
|
||||||
}
|
}
|
||||||
|
|
||||||
int File::availableForWrite() {
|
int File::availableForWrite() {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->availableForWrite();
|
return _p->availableForWrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int File::read() {
|
int File::read() {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
uint8_t result;
|
uint8_t result;
|
||||||
if (_p->read(&result, 1) != 1) {
|
if (_p->read(&result, 1) != 1) {
|
||||||
|
|
@ -67,15 +72,17 @@ int File::read() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int File::read(uint8_t* buf, size_t size) {
|
int File::read(uint8_t* buf, size_t size) {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->read(buf, size);
|
return _p->read(buf, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int File::peek() {
|
int File::peek() {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
size_t curPos = _p->position();
|
size_t curPos = _p->position();
|
||||||
int result = read();
|
int result = read();
|
||||||
|
|
@ -84,29 +91,33 @@ int File::peek() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void File::flush() {
|
void File::flush() {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_p->flush();
|
_p->flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool File::seek(uint32_t pos, SeekMode mode) {
|
bool File::seek(uint32_t pos, SeekMode mode) {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->seek(pos, mode);
|
return _p->seek(pos, mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t File::position() const {
|
size_t File::position() const {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->position();
|
return _p->position();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t File::size() const {
|
size_t File::size() const {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->size();
|
return _p->size();
|
||||||
}
|
}
|
||||||
|
|
@ -123,36 +134,41 @@ File::operator bool() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool File::truncate(uint32_t size) {
|
bool File::truncate(uint32_t size) {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->truncate(size);
|
return _p->truncate(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* File::name() const {
|
const char* File::name() const {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->name();
|
return _p->name();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* File::fullName() const {
|
const char* File::fullName() const {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->fullName();
|
return _p->fullName();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool File::isFile() const {
|
bool File::isFile() const {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->isFile();
|
return _p->isFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool File::isDirectory() const {
|
bool File::isDirectory() const {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->isDirectory();
|
return _p->isDirectory();
|
||||||
}
|
}
|
||||||
|
|
@ -162,7 +178,7 @@ void File::rewindDirectory() {
|
||||||
_fakeDir = std::make_shared<Dir>(_baseFS->openDir(fullName()));
|
_fakeDir = std::make_shared<Dir>(_baseFS->openDir(fullName()));
|
||||||
} else {
|
} else {
|
||||||
_fakeDir->rewind();
|
_fakeDir->rewind();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
File File::openNextFile() {
|
File File::openNextFile() {
|
||||||
|
|
@ -173,42 +189,57 @@ File File::openNextFile() {
|
||||||
return _fakeDir->openFile("r");
|
return _fakeDir->openFile("r");
|
||||||
}
|
}
|
||||||
|
|
||||||
String File::readString()
|
String File::readString() {
|
||||||
{
|
|
||||||
String ret;
|
String ret;
|
||||||
ret.reserve(size() - position());
|
ret.reserve(size() - position());
|
||||||
char temp[256+1];
|
uint8_t temp[256];
|
||||||
int countRead = readBytes(temp, sizeof(temp)-1);
|
int countRead;
|
||||||
while (countRead > 0)
|
do {
|
||||||
{
|
countRead = read(temp, sizeof(temp));
|
||||||
temp[countRead] = 0;
|
ret.concat(temp, countRead);
|
||||||
ret += temp;
|
} while (countRead > 0);
|
||||||
countRead = readBytes(temp, sizeof(temp)-1);
|
|
||||||
}
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t File::getLastWrite() {
|
time_t File::getLastWrite() {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->getLastWrite();
|
return _p->getLastWrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t File::getCreationTime() {
|
time_t File::getCreationTime() {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return _p->getCreationTime();
|
return _p->getCreationTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
void File::setTimeCallback(time_t (*cb)(void)) {
|
void File::setTimeCallback(time_t (*cb)(void)) {
|
||||||
if (!_p)
|
if (!_p) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
_p->setTimeCallback(cb);
|
_p->setTimeCallback(cb);
|
||||||
_timeCallback = cb;
|
_timeCallback = cb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool File::stat(FSStat *st) {
|
||||||
|
if (!_p) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
size_t pos = position();
|
||||||
|
seek(0, SeekEnd);
|
||||||
|
st->size = position() - pos;
|
||||||
|
seek(pos, SeekSet);
|
||||||
|
st->blocksize = 0; // Not set here
|
||||||
|
st->ctime = getCreationTime();
|
||||||
|
st->atime = getLastWrite();
|
||||||
|
st->isDir = isDirectory();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
File Dir::openFile(const char* mode) {
|
File Dir::openFile(const char* mode) {
|
||||||
if (!_impl) {
|
if (!_impl) {
|
||||||
return File();
|
return File();
|
||||||
|
|
@ -235,14 +266,16 @@ String Dir::fileName() {
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t Dir::fileTime() {
|
time_t Dir::fileTime() {
|
||||||
if (!_impl)
|
if (!_impl) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
return _impl->fileTime();
|
return _impl->fileTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t Dir::fileCreationTime() {
|
time_t Dir::fileCreationTime() {
|
||||||
if (!_impl)
|
if (!_impl) {
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
return _impl->fileCreationTime();
|
return _impl->fileCreationTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -255,15 +288,17 @@ size_t Dir::fileSize() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Dir::isFile() const {
|
bool Dir::isFile() const {
|
||||||
if (!_impl)
|
if (!_impl) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return _impl->isFile();
|
return _impl->isFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Dir::isDirectory() const {
|
bool Dir::isDirectory() const {
|
||||||
if (!_impl)
|
if (!_impl) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return _impl->isDirectory();
|
return _impl->isDirectory();
|
||||||
}
|
}
|
||||||
|
|
@ -285,8 +320,9 @@ bool Dir::rewind() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Dir::setTimeCallback(time_t (*cb)(void)) {
|
void Dir::setTimeCallback(time_t (*cb)(void)) {
|
||||||
if (!_impl)
|
if (!_impl) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
_impl->setTimeCallback(cb);
|
_impl->setTimeCallback(cb);
|
||||||
_timeCallback = cb;
|
_timeCallback = cb;
|
||||||
}
|
}
|
||||||
|
|
@ -307,7 +343,7 @@ bool FS::begin() {
|
||||||
}
|
}
|
||||||
_impl->setTimeCallback(_timeCallback);
|
_impl->setTimeCallback(_timeCallback);
|
||||||
bool ret = _impl->begin();
|
bool ret = _impl->begin();
|
||||||
DEBUGV("%s\n", ret? "": "#error: FS could not start");
|
DEBUGV("%s\n", ret ? "" : "#error: FS could not start");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -338,20 +374,13 @@ bool FS::format() {
|
||||||
return _impl->format();
|
return _impl->format();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FS::info(FSInfo& info){
|
bool FS::info(FSInfo& info) {
|
||||||
if (!_impl) {
|
if (!_impl) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return _impl->info(info);
|
return _impl->info(info);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FS::info64(FSInfo64& info){
|
|
||||||
if (!_impl) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return _impl->info64(info);
|
|
||||||
}
|
|
||||||
|
|
||||||
File FS::open(const String& path, const char* mode) {
|
File FS::open(const String& path, const char* mode) {
|
||||||
return open(path.c_str(), mode);
|
return open(path.c_str(), mode);
|
||||||
}
|
}
|
||||||
|
|
@ -441,6 +470,17 @@ bool FS::rename(const String& pathFrom, const String& pathTo) {
|
||||||
return rename(pathFrom.c_str(), pathTo.c_str());
|
return rename(pathFrom.c_str(), pathTo.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FS::stat(const char *path, FSStat *st) {
|
||||||
|
if (!_impl) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return _impl->stat(path, st);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FS::stat(const String& path, FSStat *st) {
|
||||||
|
return stat(path.c_str(), st);
|
||||||
|
}
|
||||||
|
|
||||||
time_t FS::getCreationTime() {
|
time_t FS::getCreationTime() {
|
||||||
if (!_impl) {
|
if (!_impl) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
@ -449,8 +489,9 @@ time_t FS::getCreationTime() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void FS::setTimeCallback(time_t (*cb)(void)) {
|
void FS::setTimeCallback(time_t (*cb)(void)) {
|
||||||
if (!_impl)
|
if (!_impl) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
_impl->setTimeCallback(cb);
|
_impl->setTimeCallback(cb);
|
||||||
_timeCallback = cb;
|
_timeCallback = cb;
|
||||||
}
|
}
|
||||||
|
|
@ -458,29 +499,29 @@ void FS::setTimeCallback(time_t (*cb)(void)) {
|
||||||
|
|
||||||
static bool sflags(const char* mode, OpenMode& om, AccessMode& am) {
|
static bool sflags(const char* mode, OpenMode& om, AccessMode& am) {
|
||||||
switch (mode[0]) {
|
switch (mode[0]) {
|
||||||
case 'r':
|
case 'r':
|
||||||
am = AM_READ;
|
am = AM_READ;
|
||||||
om = OM_DEFAULT;
|
om = OM_DEFAULT;
|
||||||
break;
|
break;
|
||||||
case 'w':
|
case 'w':
|
||||||
am = AM_WRITE;
|
am = AM_WRITE;
|
||||||
om = (OpenMode) (OM_CREATE | OM_TRUNCATE);
|
om = (OpenMode)(OM_CREATE | OM_TRUNCATE);
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
am = AM_WRITE;
|
am = AM_WRITE;
|
||||||
om = (OpenMode) (OM_CREATE | OM_APPEND);
|
om = (OpenMode)(OM_CREATE | OM_APPEND);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
switch(mode[1]) {
|
switch (mode[1]) {
|
||||||
case '+':
|
case '+':
|
||||||
am = (AccessMode) (AM_WRITE | AM_READ);
|
am = (AccessMode)(AM_WRITE | AM_READ);
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -489,7 +530,7 @@ static bool sflags(const char* mode, OpenMode& om, AccessMode& am) {
|
||||||
#if defined(FS_FREESTANDING_FUNCTIONS)
|
#if defined(FS_FREESTANDING_FUNCTIONS)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
TODO: move these functions to public API:
|
TODO: move these functions to public API:
|
||||||
*/
|
*/
|
||||||
File open(const char* path, const char* mode);
|
File open(const char* path, const char* mode);
|
||||||
File open(String& path, const char* mode);
|
File open(String& path, const char* mode);
|
||||||
|
|
@ -545,8 +586,9 @@ File open(const char* path, const char* mode) {
|
||||||
size_t offset = entry->path.length();
|
size_t offset = entry->path.length();
|
||||||
if (strstr(path, entry->path.c_str())) {
|
if (strstr(path, entry->path.c_str())) {
|
||||||
File result = entry->fs->open(path + offset);
|
File result = entry->fs->open(path + offset);
|
||||||
if (result)
|
if (result) {
|
||||||
return result;
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,25 +1,24 @@
|
||||||
/*
|
/*
|
||||||
FS.h - file system wrapper
|
FS.h - file system wrapper
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef FS_H
|
#pragma once
|
||||||
#define FS_H
|
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
@ -49,10 +48,19 @@ enum SeekMode {
|
||||||
SeekEnd = 2
|
SeekEnd = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
class File : public Stream
|
struct FSStat {
|
||||||
{
|
size_t size;
|
||||||
|
size_t blocksize;
|
||||||
|
time_t ctime;
|
||||||
|
time_t atime;
|
||||||
|
bool isDir;
|
||||||
|
};
|
||||||
|
|
||||||
|
class File : public Stream {
|
||||||
public:
|
public:
|
||||||
File(FileImplPtr p = FileImplPtr(), FS *baseFS = nullptr) : _p(p), _fakeDir(nullptr), _baseFS(baseFS) { }
|
File(FileImplPtr p = FileImplPtr(), FS *baseFS = nullptr) : _p(p), _fakeDir(nullptr), _baseFS(baseFS) {
|
||||||
|
_startMillis = millis(); /* workaround -O3 spurious warning #768 */
|
||||||
|
}
|
||||||
|
|
||||||
// Print methods:
|
// Print methods:
|
||||||
size_t write(uint8_t) override;
|
size_t write(uint8_t) override;
|
||||||
|
|
@ -74,7 +82,9 @@ public:
|
||||||
}
|
}
|
||||||
size_t position() const;
|
size_t position() const;
|
||||||
size_t size() const;
|
size_t size() const;
|
||||||
virtual ssize_t streamRemaining() { return (ssize_t)size() - (ssize_t)position(); }
|
virtual ssize_t streamRemaining() {
|
||||||
|
return (ssize_t)size() - (ssize_t)position();
|
||||||
|
}
|
||||||
void close();
|
void close();
|
||||||
operator bool() const;
|
operator bool() const;
|
||||||
const char* name() const;
|
const char* name() const;
|
||||||
|
|
@ -86,26 +96,25 @@ public:
|
||||||
|
|
||||||
// Arduino "class SD" methods for compatibility
|
// Arduino "class SD" methods for compatibility
|
||||||
//TODO use stream::send / check read(buf,size) result
|
//TODO use stream::send / check read(buf,size) result
|
||||||
template<typename T> size_t write(T &src){
|
template<typename T> size_t write(T &src) {
|
||||||
uint8_t obuf[256];
|
uint8_t obuf[256];
|
||||||
size_t doneLen = 0;
|
size_t doneLen = 0;
|
||||||
size_t sentLen;
|
size_t sentLen;
|
||||||
int i;
|
|
||||||
|
|
||||||
while (src.available() > sizeof(obuf)){
|
while ((size_t)src.available() > sizeof(obuf)) {
|
||||||
src.read(obuf, sizeof(obuf));
|
src.read(obuf, sizeof(obuf));
|
||||||
sentLen = write(obuf, sizeof(obuf));
|
sentLen = write(obuf, sizeof(obuf));
|
||||||
doneLen = doneLen + sentLen;
|
doneLen = doneLen + sentLen;
|
||||||
if(sentLen != sizeof(obuf)){
|
if (sentLen != sizeof(obuf)) {
|
||||||
return doneLen;
|
return doneLen;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
size_t leftLen = src.available();
|
size_t leftLen = src.available();
|
||||||
src.read(obuf, leftLen);
|
src.read(obuf, leftLen);
|
||||||
sentLen = write(obuf, leftLen);
|
sentLen = write(obuf, leftLen);
|
||||||
doneLen = doneLen + sentLen;
|
doneLen = doneLen + sentLen;
|
||||||
return doneLen;
|
return doneLen;
|
||||||
}
|
}
|
||||||
using Print::write;
|
using Print::write;
|
||||||
|
|
||||||
|
|
@ -118,6 +127,8 @@ public:
|
||||||
time_t getCreationTime();
|
time_t getCreationTime();
|
||||||
void setTimeCallback(time_t (*cb)(void));
|
void setTimeCallback(time_t (*cb)(void));
|
||||||
|
|
||||||
|
bool stat(FSStat *st);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
FileImplPtr _p;
|
FileImplPtr _p;
|
||||||
time_t (*_timeCallback)(void) = nullptr;
|
time_t (*_timeCallback)(void) = nullptr;
|
||||||
|
|
@ -151,18 +162,8 @@ protected:
|
||||||
time_t (*_timeCallback)(void) = nullptr;
|
time_t (*_timeCallback)(void) = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Backwards compatible, <4GB filesystem usage
|
|
||||||
struct FSInfo {
|
|
||||||
size_t totalBytes;
|
|
||||||
size_t usedBytes;
|
|
||||||
size_t blockSize;
|
|
||||||
size_t pageSize;
|
|
||||||
size_t maxOpenFiles;
|
|
||||||
size_t maxPathLength;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Support > 4GB filesystems (SD, etc.)
|
// Support > 4GB filesystems (SD, etc.)
|
||||||
struct FSInfo64 {
|
struct FSInfo {
|
||||||
uint64_t totalBytes;
|
uint64_t totalBytes;
|
||||||
uint64_t usedBytes;
|
uint64_t usedBytes;
|
||||||
size_t blockSize;
|
size_t blockSize;
|
||||||
|
|
@ -171,9 +172,7 @@ struct FSInfo64 {
|
||||||
size_t maxPathLength;
|
size_t maxPathLength;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FSConfig {
|
||||||
class FSConfig
|
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
static constexpr uint32_t FSId = 0x00000000;
|
static constexpr uint32_t FSId = 0x00000000;
|
||||||
|
|
||||||
|
|
@ -188,20 +187,11 @@ public:
|
||||||
bool _autoFormat;
|
bool _autoFormat;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SPIFFSConfig : public FSConfig
|
class FS {
|
||||||
{
|
|
||||||
public:
|
public:
|
||||||
static constexpr uint32_t FSId = 0x53504946;
|
FS(FSImplPtr impl) : _impl(impl) {
|
||||||
SPIFFSConfig(bool autoFormat = true) : FSConfig(FSId, autoFormat) { }
|
_timeCallback = _defaultTimeCB;
|
||||||
|
}
|
||||||
// Inherit _type and _autoFormat
|
|
||||||
// nothing yet, enableTime TBD when SPIFFS has metadate
|
|
||||||
};
|
|
||||||
|
|
||||||
class FS
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FS(FSImplPtr impl) : _impl(impl) { _timeCallback = _defaultTimeCB; }
|
|
||||||
|
|
||||||
bool setConfig(const FSConfig &cfg);
|
bool setConfig(const FSConfig &cfg);
|
||||||
|
|
||||||
|
|
@ -210,7 +200,6 @@ public:
|
||||||
|
|
||||||
bool format();
|
bool format();
|
||||||
bool info(FSInfo& info);
|
bool info(FSInfo& info);
|
||||||
bool info64(FSInfo64& info);
|
|
||||||
|
|
||||||
File open(const char* path, const char* mode);
|
File open(const char* path, const char* mode);
|
||||||
File open(const String& path, const char* mode);
|
File open(const String& path, const char* mode);
|
||||||
|
|
@ -233,6 +222,9 @@ public:
|
||||||
bool rmdir(const char* path);
|
bool rmdir(const char* path);
|
||||||
bool rmdir(const String& path);
|
bool rmdir(const String& path);
|
||||||
|
|
||||||
|
bool stat(const char *path, FSStat *st);
|
||||||
|
bool stat(const String& path, FSStat *st);
|
||||||
|
|
||||||
// Low-level FS routines, not needed by most applications
|
// Low-level FS routines, not needed by most applications
|
||||||
bool gc();
|
bool gc();
|
||||||
bool check();
|
bool check();
|
||||||
|
|
@ -244,18 +236,22 @@ public:
|
||||||
friend class ::SDClass; // More of a frenemy, but SD needs internal implementation to get private FAT bits
|
friend class ::SDClass; // More of a frenemy, but SD needs internal implementation to get private FAT bits
|
||||||
protected:
|
protected:
|
||||||
FSImplPtr _impl;
|
FSImplPtr _impl;
|
||||||
FSImplPtr getImpl() { return _impl; }
|
FSImplPtr getImpl() {
|
||||||
|
return _impl;
|
||||||
|
}
|
||||||
time_t (*_timeCallback)(void) = nullptr;
|
time_t (*_timeCallback)(void) = nullptr;
|
||||||
static time_t _defaultTimeCB(void) { return time(NULL); }
|
static time_t _defaultTimeCB(void) {
|
||||||
|
return time(nullptr);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fs
|
} // namespace fs
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
void close_all_fs(void);
|
void close_all_fs(void);
|
||||||
void littlefs_request_end(void);
|
void littlefs_request_end(void);
|
||||||
void spiffs_request_end(void);
|
void spiffs_request_end(void);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef FS_NO_GLOBALS
|
#ifndef FS_NO_GLOBALS
|
||||||
|
|
@ -268,11 +264,4 @@ using fs::SeekCur;
|
||||||
using fs::SeekEnd;
|
using fs::SeekEnd;
|
||||||
using fs::FSInfo;
|
using fs::FSInfo;
|
||||||
using fs::FSConfig;
|
using fs::FSConfig;
|
||||||
using fs::SPIFFSConfig;
|
|
||||||
#endif //FS_NO_GLOBALS
|
#endif //FS_NO_GLOBALS
|
||||||
|
|
||||||
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SPIFFS)
|
|
||||||
extern fs::FS SPIFFS __attribute__((deprecated("SPIFFS has been deprecated. Please consider moving to LittleFS or other filesystems.")));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif //FS_H
|
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,24 @@
|
||||||
/*
|
/*
|
||||||
FSImpl.h - base file system interface
|
FSImpl.h - base file system interface
|
||||||
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||||
This file is part of the esp8266 core for Arduino environment.
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
#ifndef FSIMPL_H
|
|
||||||
#define FSIMPL_H
|
#pragma once
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
@ -35,7 +35,9 @@ public:
|
||||||
virtual bool seek(uint32_t pos, SeekMode mode) = 0;
|
virtual bool seek(uint32_t pos, SeekMode mode) = 0;
|
||||||
virtual size_t position() const = 0;
|
virtual size_t position() const = 0;
|
||||||
virtual size_t size() const = 0;
|
virtual size_t size() const = 0;
|
||||||
virtual int availableForWrite() { return 0; }
|
virtual int availableForWrite() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
virtual bool truncate(uint32_t size) = 0;
|
virtual bool truncate(uint32_t size) = 0;
|
||||||
virtual void close() = 0;
|
virtual void close() = 0;
|
||||||
virtual const char* name() const = 0;
|
virtual const char* name() const = 0;
|
||||||
|
|
@ -46,14 +48,20 @@ public:
|
||||||
// Filesystems *may* support a timestamp per-file, so allow the user to override with
|
// Filesystems *may* support a timestamp per-file, so allow the user to override with
|
||||||
// their own callback for *this specific* file (as opposed to the FSImpl call of the
|
// their own callback for *this specific* file (as opposed to the FSImpl call of the
|
||||||
// same name. The default implementation simply returns time(null)
|
// same name. The default implementation simply returns time(null)
|
||||||
virtual void setTimeCallback(time_t (*cb)(void)) { _timeCallback = cb; }
|
virtual void setTimeCallback(time_t (*cb)(void)) {
|
||||||
|
_timeCallback = cb;
|
||||||
|
}
|
||||||
|
|
||||||
// Return the last written time for a file. Undefined when called on a writable file
|
// Return the last written time for a file. Undefined when called on a writable file
|
||||||
// as the FS is allowed to return either the time of the last write() operation or the
|
// as the FS is allowed to return either the time of the last write() operation or the
|
||||||
// time present in the filesystem metadata (often the last time the file was closed)
|
// time present in the filesystem metadata (often the last time the file was closed)
|
||||||
virtual time_t getLastWrite() { return 0; } // Default is to not support timestamps
|
virtual time_t getLastWrite() {
|
||||||
|
return 0; // Default is to not support timestamps
|
||||||
|
}
|
||||||
// Same for creation time.
|
// Same for creation time.
|
||||||
virtual time_t getCreationTime() { return 0; } // Default is to not support timestamps
|
virtual time_t getCreationTime() {
|
||||||
|
return 0; // Default is to not support timestamps
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
time_t (*_timeCallback)(void) = nullptr;
|
time_t (*_timeCallback)(void) = nullptr;
|
||||||
|
|
@ -81,8 +89,12 @@ public:
|
||||||
// Return the last written time for a file. Undefined when called on a writable file
|
// Return the last written time for a file. Undefined when called on a writable file
|
||||||
// as the FS is allowed to return either the time of the last write() operation or the
|
// as the FS is allowed to return either the time of the last write() operation or the
|
||||||
// time present in the filesystem metadata (often the last time the file was closed)
|
// time present in the filesystem metadata (often the last time the file was closed)
|
||||||
virtual time_t fileTime() { return 0; } // By default, FS doesn't report file times
|
virtual time_t fileTime() {
|
||||||
virtual time_t fileCreationTime() { return 0; } // By default, FS doesn't report file times
|
return 0; // By default, FS doesn't report file times
|
||||||
|
}
|
||||||
|
virtual time_t fileCreationTime() {
|
||||||
|
return 0; // By default, FS doesn't report file times
|
||||||
|
}
|
||||||
virtual bool isFile() const = 0;
|
virtual bool isFile() const = 0;
|
||||||
virtual bool isDirectory() const = 0;
|
virtual bool isDirectory() const = 0;
|
||||||
virtual bool next() = 0;
|
virtual bool next() = 0;
|
||||||
|
|
@ -91,7 +103,9 @@ public:
|
||||||
// Filesystems *may* support a timestamp per-file, so allow the user to override with
|
// Filesystems *may* support a timestamp per-file, so allow the user to override with
|
||||||
// their own callback for *this specific* file (as opposed to the FSImpl call of the
|
// their own callback for *this specific* file (as opposed to the FSImpl call of the
|
||||||
// same name. The default implementation simply returns time(null)
|
// same name. The default implementation simply returns time(null)
|
||||||
virtual void setTimeCallback(time_t (*cb)(void)) { _timeCallback = cb; }
|
virtual void setTimeCallback(time_t (*cb)(void)) {
|
||||||
|
_timeCallback = cb;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
time_t (*_timeCallback)(void) = nullptr;
|
time_t (*_timeCallback)(void) = nullptr;
|
||||||
|
|
@ -99,13 +113,12 @@ protected:
|
||||||
|
|
||||||
class FSImpl {
|
class FSImpl {
|
||||||
public:
|
public:
|
||||||
virtual ~FSImpl () { }
|
virtual ~FSImpl() { }
|
||||||
virtual bool setConfig(const FSConfig &cfg) = 0;
|
virtual bool setConfig(const FSConfig &cfg) = 0;
|
||||||
virtual bool begin() = 0;
|
virtual bool begin() = 0;
|
||||||
virtual void end() = 0;
|
virtual void end() = 0;
|
||||||
virtual bool format() = 0;
|
virtual bool format() = 0;
|
||||||
virtual bool info(FSInfo& info) = 0;
|
virtual bool info(FSInfo& info) = 0;
|
||||||
virtual bool info64(FSInfo64& info) = 0;
|
|
||||||
virtual FileImplPtr open(const char* path, OpenMode openMode, AccessMode accessMode) = 0;
|
virtual FileImplPtr open(const char* path, OpenMode openMode, AccessMode accessMode) = 0;
|
||||||
virtual bool exists(const char* path) = 0;
|
virtual bool exists(const char* path) = 0;
|
||||||
virtual DirImplPtr openDir(const char* path) = 0;
|
virtual DirImplPtr openDir(const char* path) = 0;
|
||||||
|
|
@ -113,19 +126,26 @@ public:
|
||||||
virtual bool remove(const char* path) = 0;
|
virtual bool remove(const char* path) = 0;
|
||||||
virtual bool mkdir(const char* path) = 0;
|
virtual bool mkdir(const char* path) = 0;
|
||||||
virtual bool rmdir(const char* path) = 0;
|
virtual bool rmdir(const char* path) = 0;
|
||||||
virtual bool gc() { return true; } // May not be implemented in all file systems.
|
virtual bool stat(const char *path, FSStat *st) = 0;
|
||||||
virtual bool check() { return true; } // May not be implemented in all file systems.
|
virtual bool gc() {
|
||||||
virtual time_t getCreationTime() { return 0; } // May not be implemented in all file systems.
|
return true; // May not be implemented in all file systems.
|
||||||
|
}
|
||||||
|
virtual bool check() {
|
||||||
|
return true; // May not be implemented in all file systems.
|
||||||
|
}
|
||||||
|
virtual time_t getCreationTime() {
|
||||||
|
return 0; // May not be implemented in all file systems.
|
||||||
|
}
|
||||||
|
|
||||||
// Filesystems *may* support a timestamp per-file, so allow the user to override with
|
// Filesystems *may* support a timestamp per-file, so allow the user to override with
|
||||||
// their own callback for all files on this FS. The default implementation simply
|
// their own callback for all files on this FS. The default implementation simply
|
||||||
// returns the present time as reported by time(null)
|
// returns the present time as reported by time(null)
|
||||||
virtual void setTimeCallback(time_t (*cb)(void)) { _timeCallback = cb; }
|
virtual void setTimeCallback(time_t (*cb)(void)) {
|
||||||
|
_timeCallback = cb;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
time_t (*_timeCallback)(void) = nullptr;
|
time_t (*_timeCallback)(void) = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fs
|
} // namespace fs
|
||||||
|
|
||||||
#endif //FSIMPL_H
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1,2 @@
|
||||||
#include "api/IPAddress.h"
|
#include "api/IPAddress.h"
|
||||||
|
using arduino::IPAddress;
|
||||||
|
|
|
||||||
127
cores/rp2040/PIOProgram.cpp
Normal file
127
cores/rp2040/PIOProgram.cpp
Normal file
|
|
@ -0,0 +1,127 @@
|
||||||
|
/*
|
||||||
|
RP2040 PIO utility class
|
||||||
|
|
||||||
|
Copyright (c) 2023 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "PIOProgram.h"
|
||||||
|
#include <map>
|
||||||
|
#include <hardware/claim.h>
|
||||||
|
|
||||||
|
#if defined(PICO_RP2350)
|
||||||
|
#define PIOS pio0, pio1, pio2
|
||||||
|
#define PIOCNT 3
|
||||||
|
#elif defined(PICO_RP2040)
|
||||||
|
#define PIOS pio0, pio1
|
||||||
|
#define PIOCNT 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static std::map<const pio_program_t *, int> __pioMap[PIOCNT];
|
||||||
|
static bool __pioAllocated[PIOCNT];
|
||||||
|
auto_init_mutex(_pioMutex);
|
||||||
|
|
||||||
|
PIOProgram::PIOProgram(const pio_program_t *pgm) {
|
||||||
|
_pgm = pgm;
|
||||||
|
_pio = nullptr;
|
||||||
|
_sm = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We leave the INSN loaded in INSN RAM
|
||||||
|
PIOProgram::~PIOProgram() {
|
||||||
|
if (_pio) {
|
||||||
|
pio_sm_unclaim(_pio, _sm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Possibly load into a PIO and allocate a SM
|
||||||
|
bool PIOProgram::prepare(PIO *pio, int *sm, int *offset, int start, int cnt) {
|
||||||
|
CoreMutex m(&_pioMutex);
|
||||||
|
PIO pi[PIOCNT] = { PIOS };
|
||||||
|
|
||||||
|
uint gpioBaseNeeded = ((start + cnt) >= 32) ? 16 : 0;
|
||||||
|
DEBUGV("PIOProgram %p: Searching for base=%d, pins %d-%d\n", _pgm, gpioBaseNeeded, start, start + cnt - 1);
|
||||||
|
|
||||||
|
// If it's already loaded into PIO IRAM, try and allocate in that specific PIO
|
||||||
|
for (int o = 0; o < PIOCNT; o++) {
|
||||||
|
auto p = __pioMap[o].find(_pgm);
|
||||||
|
if ((p != __pioMap[o].end()) && (pio_get_gpio_base(pio_get_instance(o)) == gpioBaseNeeded)) {
|
||||||
|
int idx = pio_claim_unused_sm(pi[o], false);
|
||||||
|
if (idx >= 0) {
|
||||||
|
DEBUGV("PIOProgram %p: Reusing IMEM ON PIO %p(base=%d) for pins %d-%d\n", _pgm, pi[o], pio_get_gpio_base(pio_get_instance(o)), start, start + cnt - 1);
|
||||||
|
_pio = pi[o];
|
||||||
|
_sm = idx;
|
||||||
|
*pio = pi[o];
|
||||||
|
*sm = idx;
|
||||||
|
*offset = p->second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not in any PIO IRAM, so try and add
|
||||||
|
for (int o = 0; o < PIOCNT; o++) {
|
||||||
|
if (__pioAllocated[o] && (pio_get_gpio_base(pio_get_instance(o)) == gpioBaseNeeded)) {
|
||||||
|
DEBUGV("PIOProgram: Checking PIO %p\n", pi[o]);
|
||||||
|
if (pio_can_add_program(pi[o], _pgm)) {
|
||||||
|
int idx = pio_claim_unused_sm(pi[o], false);
|
||||||
|
if (idx >= 0) {
|
||||||
|
DEBUGV("PIOProgram %p: Adding IMEM ON PIO %p(base=%d) for pins %d-%d\n", _pgm, pi[o], pio_get_gpio_base(pio_get_instance(o)), start, start + cnt - 1);
|
||||||
|
int off = pio_add_program(pi[o], _pgm);
|
||||||
|
__pioMap[o].insert({_pgm, off});
|
||||||
|
_pio = pi[o];
|
||||||
|
_sm = idx;
|
||||||
|
*pio = pi[o];
|
||||||
|
*sm = idx;
|
||||||
|
*offset = off;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
DEBUGV("PIOProgram: can't claim unused SM\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DEBUGV("PIOProgram: can't add program\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
DEBUGV("PIOProgram: Skipping PIO %p, wrong allocated/needhi\n", pi[o]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// No existing PIOs can meet, is there an unallocated one we can allocate?
|
||||||
|
PIO p;
|
||||||
|
uint idx;
|
||||||
|
uint off;
|
||||||
|
auto rc = pio_claim_free_sm_and_add_program_for_gpio_range(_pgm, &p, &idx, &off, start, cnt, true);
|
||||||
|
if (rc) {
|
||||||
|
int o = 0;
|
||||||
|
while (p != pi[o]) {
|
||||||
|
o++;
|
||||||
|
}
|
||||||
|
assert(!__pioAllocated[o]);
|
||||||
|
__pioAllocated[o] = true;
|
||||||
|
DEBUGV("PIOProgram %p: Allocating new PIO %p(base=%d) for pins %d-%d\n", _pgm, pi[o], pio_get_gpio_base(pio_get_instance(o)), start, start + cnt - 1);
|
||||||
|
__pioMap[o].insert({_pgm, off});
|
||||||
|
_pio = pi[o];
|
||||||
|
_sm = idx;
|
||||||
|
*pio = pi[o];
|
||||||
|
*sm = idx;
|
||||||
|
*offset = off;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nope, no room either for SMs or INSNs
|
||||||
|
return false;
|
||||||
|
}
|
||||||
37
cores/rp2040/PIOProgram.h
Normal file
37
cores/rp2040/PIOProgram.h
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
RP2040 PIO utility class
|
||||||
|
|
||||||
|
Copyright (c) 2023 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hardware/pio.h>
|
||||||
|
|
||||||
|
// Wrapper class for PIO programs, abstracting common operations out
|
||||||
|
class PIOProgram {
|
||||||
|
public:
|
||||||
|
PIOProgram(const pio_program_t *pgm);
|
||||||
|
~PIOProgram();
|
||||||
|
// Possibly load into a PIO and allocate a SM
|
||||||
|
bool prepare(PIO *pio, int *sm, int *offset, int gpio_start = 0, int gpio_cnt = 1);
|
||||||
|
|
||||||
|
private:
|
||||||
|
const pio_program_t *_pgm;
|
||||||
|
PIO _pio;
|
||||||
|
int _sm;
|
||||||
|
};
|
||||||
290
cores/rp2040/PolledTimeout.h
Normal file
290
cores/rp2040/PolledTimeout.h
Normal file
|
|
@ -0,0 +1,290 @@
|
||||||
|
/*
|
||||||
|
PolledTimeout.h - Encapsulation of a polled Timeout
|
||||||
|
|
||||||
|
Copyright (c) 2018 Daniel Salazar. All rights reserved.
|
||||||
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <limits> // std::numeric_limits
|
||||||
|
#include <type_traits> // std::is_unsigned
|
||||||
|
|
||||||
|
#define IRAM_ATTR
|
||||||
|
|
||||||
|
namespace esp8266 {
|
||||||
|
|
||||||
|
|
||||||
|
namespace polledTimeout {
|
||||||
|
|
||||||
|
namespace YieldPolicy {
|
||||||
|
|
||||||
|
struct DoNothing {
|
||||||
|
static void execute() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct YieldOrSkip {
|
||||||
|
static void execute() {} //{esp_yield();}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <unsigned long delayMs>
|
||||||
|
struct YieldAndDelayMs {
|
||||||
|
static void execute() {
|
||||||
|
delay(delayMs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} //YieldPolicy
|
||||||
|
|
||||||
|
namespace TimePolicy {
|
||||||
|
|
||||||
|
struct TimeSourceMillis {
|
||||||
|
// time policy in milli-seconds based on millis()
|
||||||
|
|
||||||
|
using timeType = decltype(millis());
|
||||||
|
static timeType time() {
|
||||||
|
return millis();
|
||||||
|
}
|
||||||
|
static constexpr timeType ticksPerSecond = 1000;
|
||||||
|
static constexpr timeType ticksPerSecondMax = 1000;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct TimeSourceCycles {
|
||||||
|
// time policy based on esp_get_cycle_count()
|
||||||
|
// this particular time measurement is intended to be called very often
|
||||||
|
// (every loop, every yield)
|
||||||
|
|
||||||
|
using timeType = decltype(rp2040.getCycleCount());
|
||||||
|
static timeType time() {
|
||||||
|
return rp2040.getCycleCount();
|
||||||
|
}
|
||||||
|
static constexpr timeType ticksPerSecond = F_CPU;
|
||||||
|
static constexpr timeType ticksPerSecondMax = F_CPU;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename TimeSourceType, unsigned long long second_th>
|
||||||
|
// "second_th" units of timeType for one second
|
||||||
|
struct TimeUnit {
|
||||||
|
using timeType = typename TimeSourceType::timeType;
|
||||||
|
|
||||||
|
#if __GNUC__ < 5
|
||||||
|
// gcc-4.8 cannot compile the constexpr-only version of this function
|
||||||
|
// using #defines instead luckily works
|
||||||
|
static constexpr timeType computeRangeCompensation() {
|
||||||
|
#define number_of_secondTh_in_one_tick ((1.0 * second_th) / ticksPerSecond)
|
||||||
|
#define fractional (number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick)
|
||||||
|
|
||||||
|
return ({
|
||||||
|
fractional == 0 ?
|
||||||
|
1 : // no need for compensation
|
||||||
|
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
|
||||||
|
});
|
||||||
|
|
||||||
|
#undef number_of_secondTh_in_one_tick
|
||||||
|
#undef fractional
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
static constexpr timeType computeRangeCompensation() {
|
||||||
|
return ({
|
||||||
|
constexpr double number_of_secondTh_in_one_tick = (1.0 * second_th) / ticksPerSecond;
|
||||||
|
constexpr double fractional = number_of_secondTh_in_one_tick - (long)number_of_secondTh_in_one_tick;
|
||||||
|
fractional == 0 ?
|
||||||
|
1 : // no need for compensation
|
||||||
|
(number_of_secondTh_in_one_tick / fractional) + 0.5; // scalar multiplier allowing exact division
|
||||||
|
});
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static constexpr timeType ticksPerSecond = TimeSourceType::ticksPerSecond;
|
||||||
|
static constexpr timeType ticksPerSecondMax = TimeSourceType::ticksPerSecondMax;
|
||||||
|
static constexpr timeType rangeCompensate = computeRangeCompensation();
|
||||||
|
static constexpr timeType user2UnitMultiplierMax = (ticksPerSecondMax * rangeCompensate) / second_th;
|
||||||
|
static constexpr timeType user2UnitMultiplier = (ticksPerSecond * rangeCompensate) / second_th;
|
||||||
|
static constexpr timeType user2UnitDivider = rangeCompensate;
|
||||||
|
// std::numeric_limits<timeType>::max() is reserved
|
||||||
|
static constexpr timeType timeMax = (std::numeric_limits<timeType>::max() - 1) / user2UnitMultiplierMax;
|
||||||
|
|
||||||
|
static timeType toTimeTypeUnit(const timeType userUnit) {
|
||||||
|
return (userUnit * user2UnitMultiplier) / user2UnitDivider;
|
||||||
|
}
|
||||||
|
static timeType toUserUnit(const timeType internalUnit) {
|
||||||
|
return (internalUnit * user2UnitDivider) / user2UnitMultiplier;
|
||||||
|
}
|
||||||
|
static timeType time() {
|
||||||
|
return TimeSourceType::time();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
using TimeMillis = TimeUnit < TimeSourceMillis, 1'000 >;
|
||||||
|
using TimeFastMillis = TimeUnit < TimeSourceCycles, 1'000 >;
|
||||||
|
using TimeFastMicros = TimeUnit < TimeSourceCycles, 1'000'000 >;
|
||||||
|
using TimeFastNanos = TimeUnit < TimeSourceCycles, 1'000'000'000 >;
|
||||||
|
|
||||||
|
} //TimePolicy
|
||||||
|
|
||||||
|
template <bool PeriodicT, typename YieldPolicyT = YieldPolicy::DoNothing, typename TimePolicyT = TimePolicy::TimeMillis>
|
||||||
|
class timeoutTemplate {
|
||||||
|
public:
|
||||||
|
using timeType = typename TimePolicyT::timeType;
|
||||||
|
static_assert(std::is_unsigned<timeType>::value == true, "timeType must be unsigned");
|
||||||
|
|
||||||
|
static constexpr timeType alwaysExpired = 0;
|
||||||
|
static constexpr timeType neverExpires = std::numeric_limits<timeType>::max();
|
||||||
|
static constexpr timeType rangeCompensate = TimePolicyT::rangeCompensate; //debug
|
||||||
|
|
||||||
|
timeoutTemplate(const timeType userTimeout) {
|
||||||
|
reset(userTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
IRAM_ATTR // fast
|
||||||
|
bool expired() {
|
||||||
|
YieldPolicyT::execute(); //in case of DoNothing: gets optimized away
|
||||||
|
if (PeriodicT) { //in case of false: gets optimized away
|
||||||
|
return expiredRetrigger();
|
||||||
|
}
|
||||||
|
return expiredOneShot();
|
||||||
|
}
|
||||||
|
|
||||||
|
IRAM_ATTR // fast
|
||||||
|
operator bool() {
|
||||||
|
return expired();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canExpire() const {
|
||||||
|
return !_neverExpires;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool canWait() const {
|
||||||
|
return _timeout != alwaysExpired;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resets, will trigger after this new timeout.
|
||||||
|
IRAM_ATTR // called from ISR
|
||||||
|
void reset(const timeType newUserTimeout) {
|
||||||
|
reset();
|
||||||
|
_timeout = TimePolicyT::toTimeTypeUnit(newUserTimeout);
|
||||||
|
_neverExpires = (newUserTimeout < 0) || (newUserTimeout > timeMax());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resets, will trigger after the timeout previously set.
|
||||||
|
IRAM_ATTR // called from ISR
|
||||||
|
void reset() {
|
||||||
|
_start = TimePolicyT::time();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resets to just expired so that on next poll the check will immediately trigger for the user,
|
||||||
|
// also change timeout (after next immediate trigger).
|
||||||
|
IRAM_ATTR // called from ISR
|
||||||
|
void resetAndSetExpired(const timeType newUserTimeout) {
|
||||||
|
reset(newUserTimeout);
|
||||||
|
_start -= _timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Resets to just expired so that on next poll the check will immediately trigger for the user.
|
||||||
|
IRAM_ATTR // called from ISR
|
||||||
|
void resetAndSetExpired() {
|
||||||
|
reset();
|
||||||
|
_start -= _timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetToNeverExpires() {
|
||||||
|
_timeout = alwaysExpired + 1; // because canWait() has precedence
|
||||||
|
_neverExpires = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeType getTimeout() const {
|
||||||
|
return TimePolicyT::toUserUnit(_timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr timeType timeMax() {
|
||||||
|
return TimePolicyT::timeMax;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
IRAM_ATTR // fast
|
||||||
|
bool checkExpired(const timeType internalUnit) const {
|
||||||
|
// canWait() is not checked here
|
||||||
|
// returns "can expire" and "time expired"
|
||||||
|
return (!_neverExpires) && ((internalUnit - _start) >= _timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
IRAM_ATTR // fast
|
||||||
|
bool expiredRetrigger() {
|
||||||
|
if (!canWait()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
timeType current = TimePolicyT::time();
|
||||||
|
if (checkExpired(current)) {
|
||||||
|
unsigned long n = (current - _start) / _timeout; //how many _timeouts periods have elapsed, will usually be 1 (current - _start >= _timeout)
|
||||||
|
_start += n * _timeout;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
IRAM_ATTR // fast
|
||||||
|
bool expiredOneShot() const {
|
||||||
|
// returns "always expired" or "has expired"
|
||||||
|
return !canWait() || checkExpired(TimePolicyT::time());
|
||||||
|
}
|
||||||
|
|
||||||
|
timeType _timeout;
|
||||||
|
timeType _start;
|
||||||
|
bool _neverExpires;
|
||||||
|
};
|
||||||
|
|
||||||
|
// legacy type names, deprecated (unit is milliseconds)
|
||||||
|
|
||||||
|
using oneShot = polledTimeout::timeoutTemplate<false> /*__attribute__((deprecated("use oneShotMs")))*/;
|
||||||
|
using periodic = polledTimeout::timeoutTemplate<true> /*__attribute__((deprecated("use periodicMs")))*/;
|
||||||
|
|
||||||
|
// standard versions (based on millis())
|
||||||
|
// timeMax() is 49.7 days ((2^32)-2 ms)
|
||||||
|
|
||||||
|
using oneShotMs = polledTimeout::timeoutTemplate<false>;
|
||||||
|
using periodicMs = polledTimeout::timeoutTemplate<true>;
|
||||||
|
|
||||||
|
// Time policy based on esp_get_cycle_count(), and intended to be called very often:
|
||||||
|
// "Fast" versions sacrifices time range for improved precision and reduced execution time (by 86%)
|
||||||
|
// (cpu cycles for ::expired(): 372 (millis()) vs 52 (esp_get_cycle_count()))
|
||||||
|
// timeMax() values:
|
||||||
|
// Ms: max is 26843 ms (26.8 s)
|
||||||
|
// Us: max is 26843545 us (26.8 s)
|
||||||
|
// Ns: max is 1073741823 ns ( 1.07 s)
|
||||||
|
// (time policy based on esp_get_cycle_count() is intended to be called very often)
|
||||||
|
|
||||||
|
using oneShotFastMs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastMillis>;
|
||||||
|
using periodicFastMs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastMillis>;
|
||||||
|
using oneShotFastUs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastMicros>;
|
||||||
|
using periodicFastUs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastMicros>;
|
||||||
|
using oneShotFastNs = polledTimeout::timeoutTemplate<false, YieldPolicy::DoNothing, TimePolicy::TimeFastNanos>;
|
||||||
|
using periodicFastNs = polledTimeout::timeoutTemplate<true, YieldPolicy::DoNothing, TimePolicy::TimeFastNanos>;
|
||||||
|
|
||||||
|
} //polledTimeout
|
||||||
|
|
||||||
|
|
||||||
|
/* A 1-shot timeout that auto-yields when in CONT can be built as follows:
|
||||||
|
using oneShotYieldMs = esp8266::polledTimeout::timeoutTemplate<false, esp8266::polledTimeout::YieldPolicy::YieldOrSkip>;
|
||||||
|
|
||||||
|
Other policies can be implemented by the user, e.g.: simple yield that panics in SYS, and the polledTimeout types built as needed as shown above, without modifying this file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
}//esp8266
|
||||||
1
cores/rp2040/Printable.h
Normal file
1
cores/rp2040/Printable.h
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
#include "api/Printable.h"
|
||||||
|
|
@ -1,180 +0,0 @@
|
||||||
/*
|
|
||||||
* RP2040 utility class
|
|
||||||
*
|
|
||||||
* Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <hardware/clocks.h>
|
|
||||||
#include <hardware/irq.h>
|
|
||||||
#include <hardware/pio.h>
|
|
||||||
#include <pico/multicore.h>
|
|
||||||
#include <pico/util/queue.h>
|
|
||||||
|
|
||||||
class _MFIFO {
|
|
||||||
public:
|
|
||||||
_MFIFO() { /* noop */ };
|
|
||||||
~_MFIFO() { /* noop */ };
|
|
||||||
|
|
||||||
void begin(int cores) {
|
|
||||||
constexpr int FIFOCNT = 8;
|
|
||||||
if (cores == 1) {
|
|
||||||
_multicore = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
mutex_init(&_idleMutex);
|
|
||||||
queue_init(&_queue[0], sizeof(uint32_t), FIFOCNT);
|
|
||||||
queue_init(&_queue[1], sizeof(uint32_t), FIFOCNT);
|
|
||||||
_multicore = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void registerCore() {
|
|
||||||
multicore_fifo_clear_irq();
|
|
||||||
irq_set_exclusive_handler(SIO_IRQ_PROC0 + get_core_num(), _irq);
|
|
||||||
irq_set_enabled(SIO_IRQ_PROC0 + get_core_num(), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void push(uint32_t val) {
|
|
||||||
while (!push_nb(val)) { /* noop */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
bool push_nb(uint32_t val) {
|
|
||||||
// Push to the other FIFO
|
|
||||||
return queue_try_add(&_queue[get_core_num()^1], &val);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t pop() {
|
|
||||||
uint32_t ret;
|
|
||||||
while (!pop_nb(&ret)) { /* noop */ }
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool pop_nb(uint32_t *val) {
|
|
||||||
// Pop from my own FIFO
|
|
||||||
return queue_try_remove(&_queue[get_core_num()], val);
|
|
||||||
}
|
|
||||||
|
|
||||||
int available() {
|
|
||||||
return queue_get_level(&_queue[get_core_num()]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void idleOtherCore() {
|
|
||||||
if (!_multicore) return;
|
|
||||||
mutex_enter_blocking(&_idleMutex);
|
|
||||||
_otherIdled = false;
|
|
||||||
multicore_fifo_push_blocking(_GOTOSLEEP);
|
|
||||||
while (!_otherIdled) { /* noop */ }
|
|
||||||
}
|
|
||||||
|
|
||||||
void resumeOtherCore() {
|
|
||||||
if (!_multicore) return;
|
|
||||||
mutex_exit(&_idleMutex);
|
|
||||||
_otherIdled = false;
|
|
||||||
// Other core will exit busy-loop and return to operation
|
|
||||||
// once otherIdled == false.
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void __no_inline_not_in_flash_func(_irq)() {
|
|
||||||
multicore_fifo_clear_irq();
|
|
||||||
noInterrupts(); // We need total control, can't run anything
|
|
||||||
while (multicore_fifo_rvalid()) {
|
|
||||||
if (_GOTOSLEEP == multicore_fifo_pop_blocking()) {
|
|
||||||
_otherIdled = true;
|
|
||||||
while (_otherIdled) { /* noop */ }
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
interrupts();
|
|
||||||
}
|
|
||||||
bool _multicore = false;
|
|
||||||
|
|
||||||
mutex_t _idleMutex;
|
|
||||||
static volatile bool _otherIdled;
|
|
||||||
queue_t _queue[2];
|
|
||||||
|
|
||||||
static constexpr int _GOTOSLEEP = 0x66666666;
|
|
||||||
};
|
|
||||||
|
|
||||||
class RP2040 {
|
|
||||||
public:
|
|
||||||
// Convert from microseconds to PIO clock cycles
|
|
||||||
static int usToPIOCycles(int us) {
|
|
||||||
// Parenthesis needed to guarantee order of operations to avoid 32bit overflow
|
|
||||||
return (us * ( clock_get_hz(clk_sys) / 1000000 ));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get current clock frequency
|
|
||||||
static int f_cpu() {
|
|
||||||
return clock_get_hz(clk_sys);
|
|
||||||
}
|
|
||||||
|
|
||||||
void idleOtherCore() { fifo.idleOtherCore(); }
|
|
||||||
void resumeOtherCore() { fifo.resumeOtherCore(); }
|
|
||||||
|
|
||||||
// Multicore comms FIFO
|
|
||||||
_MFIFO fifo;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern RP2040 rp2040;
|
|
||||||
|
|
||||||
// Wrapper class for PIO programs, abstracting common operations out
|
|
||||||
// TODO - Make dualcore safe
|
|
||||||
// TODO - Add unload/destructor
|
|
||||||
class PIOProgram {
|
|
||||||
public:
|
|
||||||
PIOProgram(const pio_program_t *pgm) { _pgm = pgm; }
|
|
||||||
|
|
||||||
// Possibly load into a PIO and allocate a SM
|
|
||||||
bool prepare(PIO *pio, int *sm, int *offset) {
|
|
||||||
// Is there an open slot to run in, first?
|
|
||||||
if (!_findFreeSM(pio, sm)) return false;
|
|
||||||
// Is it loaded on that PIO?
|
|
||||||
if (_offset[pio_get_index(*pio)] < 0) {
|
|
||||||
// Nope, need to load it
|
|
||||||
if (!pio_can_add_program(*pio, _pgm)) return false;
|
|
||||||
_offset[pio_get_index(*pio)] = pio_add_program(*pio, _pgm);
|
|
||||||
}
|
|
||||||
// Here it's guaranteed loaded, return values
|
|
||||||
// PIO and SM already set
|
|
||||||
*offset = _offset[pio_get_index(*pio)];
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Find an unused PIO state machine to grab, returns false when none available
|
|
||||||
static bool _findFreeSM(PIO *pio, int *sm) {
|
|
||||||
int idx = pio_claim_unused_sm(pio0, false);
|
|
||||||
if (idx >= 0) {
|
|
||||||
*pio = pio0;
|
|
||||||
*sm = idx;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
idx = pio_claim_unused_sm(pio1, false);
|
|
||||||
if (idx >= 0) {
|
|
||||||
*pio = pio1;
|
|
||||||
*sm = idx;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
int _offset[2] = { -1, -1 };
|
|
||||||
const pio_program_t *_pgm;
|
|
||||||
};
|
|
||||||
|
|
||||||
53
cores/rp2040/RP2040Support.cpp
Normal file
53
cores/rp2040/RP2040Support.cpp
Normal file
|
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
RP2040 utility class
|
||||||
|
|
||||||
|
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <pico/runtime.h>
|
||||||
|
|
||||||
|
#ifdef PICO_RP2040
|
||||||
|
|
||||||
|
#include <hardware/structs/psm.h>
|
||||||
|
|
||||||
|
extern "C" void boot_double_tap_check();
|
||||||
|
|
||||||
|
// The following check will never actually execute, but it will cause the boot reset
|
||||||
|
// checker to be linked in as part of the constructors.
|
||||||
|
|
||||||
|
void RP2040::enableDoubleResetBootloader() {
|
||||||
|
if (psm_hw->done == 0) {
|
||||||
|
boot_double_tap_check();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __PROFILE
|
||||||
|
Stream *__profileFile;
|
||||||
|
int __writeProfileCB(const void *data, int len) {
|
||||||
|
return __profileFile->write((const char *)data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __PROFILE
|
||||||
|
extern "C" void runtime_init_setup_profiling();
|
||||||
|
#define PICO_RUNTIME_INIT_PROFILING "11011" // Towards the end, after PSRAM
|
||||||
|
PICO_RUNTIME_INIT_FUNC_RUNTIME(runtime_init_setup_profiling, PICO_RUNTIME_INIT_PROFILING);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
679
cores/rp2040/RP2040Support.h
Normal file
679
cores/rp2040/RP2040Support.h
Normal file
|
|
@ -0,0 +1,679 @@
|
||||||
|
/*
|
||||||
|
RP2040 utility class
|
||||||
|
|
||||||
|
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <hardware/clocks.h>
|
||||||
|
#include <hardware/irq.h>
|
||||||
|
#include <hardware/pio.h>
|
||||||
|
#include <pico/unique_id.h>
|
||||||
|
#ifdef PICO_RP2350
|
||||||
|
#include <hardware/regs/powman.h>
|
||||||
|
#else
|
||||||
|
#include <hardware/regs/vreg_and_chip_reset.h>
|
||||||
|
#endif
|
||||||
|
#include <hardware/exception.h>
|
||||||
|
#include <hardware/watchdog.h>
|
||||||
|
#include <hardware/structs/rosc.h>
|
||||||
|
#include <hardware/structs/systick.h>
|
||||||
|
#include <pico/multicore.h>
|
||||||
|
#include <hardware/dma.h>
|
||||||
|
#include <pico/rand.h>
|
||||||
|
#include <pico/util/queue.h>
|
||||||
|
#include <pico/bootrom.h>
|
||||||
|
#include "CoreMutex.h"
|
||||||
|
#include "PIOProgram.h"
|
||||||
|
#include "ccount.pio.h"
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#include "_freertos.h"
|
||||||
|
|
||||||
|
extern "C" volatile bool __otherCoreIdled;
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#ifdef __PROFILE
|
||||||
|
typedef int (*profileWriteCB)(const void *data, int len);
|
||||||
|
extern void _writeProfile(profileWriteCB writeCB);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MFIFO {
|
||||||
|
public:
|
||||||
|
_MFIFO() { /* noop */ };
|
||||||
|
~_MFIFO() { /* noop */ };
|
||||||
|
|
||||||
|
void begin(int cores) {
|
||||||
|
constexpr int FIFOCNT = 8;
|
||||||
|
if (cores == 1) {
|
||||||
|
_multicore = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mutex_init(&_idleMutex);
|
||||||
|
queue_init(&_queue[0], sizeof(uint32_t), FIFOCNT);
|
||||||
|
queue_init(&_queue[1], sizeof(uint32_t), FIFOCNT);
|
||||||
|
_multicore = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void registerCore() {
|
||||||
|
if (!__isFreeRTOS) {
|
||||||
|
multicore_fifo_clear_irq();
|
||||||
|
#ifdef PICO_RP2350
|
||||||
|
irq_set_exclusive_handler(SIO_IRQ_FIFO, _irq);
|
||||||
|
irq_set_enabled(SIO_IRQ_FIFO, true);
|
||||||
|
#else
|
||||||
|
irq_set_exclusive_handler(SIO_IRQ_PROC0 + get_core_num(), _irq);
|
||||||
|
irq_set_enabled(SIO_IRQ_PROC0 + get_core_num(), true);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
// FreeRTOS port.c will handle the IRQ hooking
|
||||||
|
}
|
||||||
|
|
||||||
|
void push(uint32_t val) {
|
||||||
|
while (!push_nb(val)) { /* noop */ }
|
||||||
|
}
|
||||||
|
|
||||||
|
bool push_nb(uint32_t val) {
|
||||||
|
// Push to the other FIFO
|
||||||
|
return queue_try_add(&_queue[get_core_num() ^ 1], &val);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t pop() {
|
||||||
|
uint32_t ret;
|
||||||
|
while (!pop_nb(&ret)) { /* noop */ }
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool pop_nb(uint32_t *val) {
|
||||||
|
// Pop from my own FIFO
|
||||||
|
return queue_try_remove(&_queue[get_core_num()], val);
|
||||||
|
}
|
||||||
|
|
||||||
|
int available() {
|
||||||
|
return queue_get_level(&_queue[get_core_num()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void idleOtherCore() {
|
||||||
|
if (!_multicore) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (__isFreeRTOS) {
|
||||||
|
__freertos_idle_other_core();
|
||||||
|
} else {
|
||||||
|
mutex_enter_blocking(&_idleMutex);
|
||||||
|
__otherCoreIdled = false;
|
||||||
|
multicore_fifo_push_blocking(_GOTOSLEEP);
|
||||||
|
while (!__otherCoreIdled) { /* noop */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void resumeOtherCore() {
|
||||||
|
if (!_multicore) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mutex_exit(&_idleMutex);
|
||||||
|
__otherCoreIdled = false;
|
||||||
|
if (__isFreeRTOS) {
|
||||||
|
__freertos_resume_other_core();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Other core will exit busy-loop and return to operation
|
||||||
|
// once __otherCoreIdled == false.
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() {
|
||||||
|
uint32_t val;
|
||||||
|
|
||||||
|
while (queue_try_remove(&_queue[0], &val)) {
|
||||||
|
tight_loop_contents();
|
||||||
|
}
|
||||||
|
|
||||||
|
while (queue_try_remove(&_queue[1], &val)) {
|
||||||
|
tight_loop_contents();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void __no_inline_not_in_flash_func(_irq)() {
|
||||||
|
if (!__isFreeRTOS) {
|
||||||
|
multicore_fifo_clear_irq();
|
||||||
|
noInterrupts(); // We need total control, can't run anything
|
||||||
|
while (multicore_fifo_rvalid()) {
|
||||||
|
if (_GOTOSLEEP == multicore_fifo_pop_blocking()) {
|
||||||
|
__otherCoreIdled = true;
|
||||||
|
while (__otherCoreIdled) { /* noop */ }
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
interrupts();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool _multicore = false;
|
||||||
|
mutex_t _idleMutex;
|
||||||
|
queue_t _queue[2];
|
||||||
|
static constexpr uint32_t _GOTOSLEEP = 0xC0DED02E;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class RP2040;
|
||||||
|
extern RP2040 rp2040;
|
||||||
|
extern "C" void main1();
|
||||||
|
extern "C" char __StackLimit;
|
||||||
|
extern "C" char __bss_end__;
|
||||||
|
extern "C" void setup1() __attribute__((weak));
|
||||||
|
extern "C" void loop1() __attribute__((weak));
|
||||||
|
extern "C" bool core1_separate_stack;
|
||||||
|
extern "C" uint32_t* core1_separate_stack_address;
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief RP2040/RP2350 helper function for HW-specific features
|
||||||
|
*/
|
||||||
|
class RP2040 {
|
||||||
|
public:
|
||||||
|
RP2040() { /* noop */ }
|
||||||
|
~RP2040() { /* noop */ }
|
||||||
|
|
||||||
|
void begin(int cpuid) {
|
||||||
|
_epoch[cpuid] = 0;
|
||||||
|
#if !defined(__riscv) && !defined(__PROFILE)
|
||||||
|
if (!__isFreeRTOS) {
|
||||||
|
// Enable SYSTICK exception
|
||||||
|
exception_set_exclusive_handler(SYSTICK_EXCEPTION, _SystickHandler);
|
||||||
|
systick_hw->csr = 0x7;
|
||||||
|
systick_hw->rvr = 0x00FFFFFF;
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
// Only start 1 instance of the PIO SM
|
||||||
|
if (cpuid == 0) {
|
||||||
|
int off = 0;
|
||||||
|
_ccountPgm = new PIOProgram(&ccount_program);
|
||||||
|
_ccountPgm->prepare(&_pio, &_sm, &off);
|
||||||
|
ccount_program_init(_pio, _sm, off);
|
||||||
|
pio_sm_set_enabled(_pio, _sm, true);
|
||||||
|
}
|
||||||
|
#if !defined(__riscv) && !defined(__PROFILE)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Convert from microseconds to PIO clock cycles
|
||||||
|
|
||||||
|
@returns the PIO cycles for a given microsecond delay
|
||||||
|
*/
|
||||||
|
static int usToPIOCycles(int us) {
|
||||||
|
// Parenthesis needed to guarantee order of operations to avoid 32bit overflow
|
||||||
|
return (us * (clock_get_hz(clk_sys) / 1'000'000));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Gets the active CPU speed (may differ from F_CPU
|
||||||
|
|
||||||
|
@returns CPU frequency in Hz
|
||||||
|
*/
|
||||||
|
static int f_cpu() {
|
||||||
|
return clock_get_hz(clk_sys);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Get the core ID that is currently executing this code
|
||||||
|
|
||||||
|
@returns 0 for Core 0, 1 for Core 1
|
||||||
|
*/
|
||||||
|
static int cpuid() {
|
||||||
|
return sio_hw->cpuid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief CPU cycle counter epoch (24-bit cycle). For internal use
|
||||||
|
*/
|
||||||
|
volatile uint64_t _epoch[2] = {};
|
||||||
|
/**
|
||||||
|
@brief Get the count of CPU clock cycles since power on.
|
||||||
|
|
||||||
|
@details
|
||||||
|
The 32-bit count will overflow every 4 billion cycles, so consider using ``getCycleCount64`` for
|
||||||
|
longer measurements
|
||||||
|
|
||||||
|
@returns CPU clock cycles since power up
|
||||||
|
*/
|
||||||
|
inline uint32_t getCycleCount() {
|
||||||
|
#if !defined(__riscv) && !defined(__PROFILE)
|
||||||
|
// Get CPU cycle count. Needs to do magic to extend 24b HW to something longer
|
||||||
|
if (!__isFreeRTOS) {
|
||||||
|
uint32_t epoch;
|
||||||
|
uint32_t ctr;
|
||||||
|
do {
|
||||||
|
epoch = (uint32_t)_epoch[sio_hw->cpuid];
|
||||||
|
ctr = systick_hw->cvr;
|
||||||
|
} while (epoch != (uint32_t)_epoch[sio_hw->cpuid]);
|
||||||
|
return epoch + (1 << 24) - ctr; /* CTR counts down from 1<<24-1 */
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
return ccount_read(_pio, _sm);
|
||||||
|
#if !defined(__riscv) && !defined(__PROFILE)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
@brief Get the count of CPU clock cycles since power on as a 64-bit quantrity
|
||||||
|
|
||||||
|
@returns CPU clock cycles since power up
|
||||||
|
*/
|
||||||
|
inline uint64_t getCycleCount64() {
|
||||||
|
#if !defined(__riscv) && !defined(__PROFILE)
|
||||||
|
if (!__isFreeRTOS) {
|
||||||
|
uint64_t epoch;
|
||||||
|
uint64_t ctr;
|
||||||
|
do {
|
||||||
|
epoch = _epoch[sio_hw->cpuid];
|
||||||
|
ctr = systick_hw->cvr;
|
||||||
|
} while (epoch != _epoch[sio_hw->cpuid]);
|
||||||
|
return epoch + (1LL << 24) - ctr;
|
||||||
|
} else {
|
||||||
|
#endif
|
||||||
|
return ccount_read(_pio, _sm);
|
||||||
|
#if !defined(__riscv) && !defined(__PROFILE)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Gets total unused heap (dynamic memory)
|
||||||
|
|
||||||
|
@details
|
||||||
|
Note that the allocations of the size of the total free heap may fail due to fragmentation.
|
||||||
|
For example, ``getFreeHeap`` can report 100KB available, but an allocation of 90KB may fail
|
||||||
|
because there may not be a contiguous 90KB space available
|
||||||
|
|
||||||
|
@returns Free heap in bytes
|
||||||
|
*/
|
||||||
|
inline int getFreeHeap() {
|
||||||
|
return getTotalHeap() - getUsedHeap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Gets total used heap (dynamic memory)
|
||||||
|
|
||||||
|
@returns Used heap in bytes
|
||||||
|
*/
|
||||||
|
inline int getUsedHeap() {
|
||||||
|
struct mallinfo m = mallinfo();
|
||||||
|
return m.uordblks;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Gets total heap (dynamic memory) compiled into the program
|
||||||
|
|
||||||
|
@returns Total heap size in bytes
|
||||||
|
*/
|
||||||
|
inline int getTotalHeap() {
|
||||||
|
return &__StackLimit - &__bss_end__;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief On the RP2350, returns the amount of heap (dynamic memory) available in PSRAM
|
||||||
|
|
||||||
|
@returns Total free heap in PSRAM, or 0 if no PSRAM present
|
||||||
|
*/
|
||||||
|
inline int getFreePSRAMHeap() {
|
||||||
|
return getTotalPSRAMHeap() - getUsedPSRAMHeap();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief On the RP2350, returns the total amount of PSRAM heap (dynamic memory) used
|
||||||
|
|
||||||
|
@returns Bytes used in PSRAM, or 0 if no PSRAM present
|
||||||
|
*/
|
||||||
|
inline int getUsedPSRAMHeap() {
|
||||||
|
#if defined(RP2350_PSRAM_CS)
|
||||||
|
extern size_t __psram_total_used();
|
||||||
|
return __psram_total_used();
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief On the RP2350, gets total heap (dynamic memory) compiled into the program
|
||||||
|
|
||||||
|
@returns Total PSRAM heap size in bytes, or 0 if no PSRAM present
|
||||||
|
*/
|
||||||
|
inline int getTotalPSRAMHeap() {
|
||||||
|
#if defined(RP2350_PSRAM_CS)
|
||||||
|
extern size_t __psram_total_space();
|
||||||
|
return __psram_total_space();
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Gets the current stack pointer in a ARM/RISC-V safe manner
|
||||||
|
|
||||||
|
@returns Current SP
|
||||||
|
*/
|
||||||
|
inline uint32_t getStackPointer() {
|
||||||
|
uint32_t *sp;
|
||||||
|
#if defined(__riscv)
|
||||||
|
asm volatile("mv %0, sp" : "=r"(sp));
|
||||||
|
#else
|
||||||
|
asm volatile("mov %0, sp" : "=r"(sp));
|
||||||
|
#endif
|
||||||
|
return (uint32_t)sp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Calculates approximately how much stack space is still available for the running core. Handles multiprocessing and separate stacks.
|
||||||
|
|
||||||
|
@details
|
||||||
|
Not valid in FreeRTOS. Use the FreeRTOS internal functions to access this information.
|
||||||
|
|
||||||
|
@returns Approximation of the amount of stack available for use on the specific core
|
||||||
|
*/
|
||||||
|
inline int getFreeStack() {
|
||||||
|
const unsigned int sp = getStackPointer();
|
||||||
|
uint32_t ref = 0x20040000;
|
||||||
|
if (setup1 || loop1) {
|
||||||
|
if (core1_separate_stack) {
|
||||||
|
ref = cpuid() ? (unsigned int)core1_separate_stack_address : 0x20040000;
|
||||||
|
} else {
|
||||||
|
ref = cpuid() ? 0x20040000 : 0x20041000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sp - ref;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief On the RP2350, gets the size of attached PSRAM
|
||||||
|
|
||||||
|
@returns PSRAM size in bytes, or 0 if no PSRAM present
|
||||||
|
*/
|
||||||
|
inline size_t getPSRAMSize() {
|
||||||
|
#if defined(RP2350_PSRAM_CS)
|
||||||
|
extern size_t __psram_size;
|
||||||
|
return __psram_size;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Freezes the other core in a flash-write-safe state. Not generally needed by applications
|
||||||
|
|
||||||
|
@details
|
||||||
|
When the external flash chip is erasing or writing, the Pico cannot fetch instructions from it.
|
||||||
|
In this case both the core doing the writing and the other core (if active) need to run from a
|
||||||
|
routine that's contained in RAM. This call forces the other core into a tight, RAM-based loop
|
||||||
|
safe for this operation. When flash erase/write is completed, ``resumeOtherCore`` to return
|
||||||
|
it to operation.
|
||||||
|
|
||||||
|
Be sure to disable any interrupts or task switches before calling to avoid deadlocks.
|
||||||
|
|
||||||
|
If the second core is not started, this is a no-op.
|
||||||
|
*/
|
||||||
|
void idleOtherCore() {
|
||||||
|
fifo.idleOtherCore();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Resumes normal operation of the other core
|
||||||
|
*/
|
||||||
|
void resumeOtherCore() {
|
||||||
|
fifo.resumeOtherCore();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Hard resets the 2nd core (CORE1).
|
||||||
|
|
||||||
|
@details
|
||||||
|
Because core1 will restart with the heap and global variables not in the same state as
|
||||||
|
power-on, this call may not work as desired and a full CPU reset may be necessary in
|
||||||
|
certain cases.
|
||||||
|
*/
|
||||||
|
void restartCore1() {
|
||||||
|
multicore_reset_core1();
|
||||||
|
fifo.clear();
|
||||||
|
multicore_launch_core1(main1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Warm-reboots the chip in normal mode
|
||||||
|
*/
|
||||||
|
void reboot() {
|
||||||
|
watchdog_reboot(0, 0, 10);
|
||||||
|
while (1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Warm-reboots the chip in normal mode
|
||||||
|
*/
|
||||||
|
inline void restart() {
|
||||||
|
reboot();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Warm-reboots the chip into the USB bootloader mode
|
||||||
|
*/
|
||||||
|
inline void rebootToBootloader() {
|
||||||
|
reset_usb_boot(0, 0);
|
||||||
|
while (1) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PICO_RP2040
|
||||||
|
static void enableDoubleResetBootloader();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Starts the hardware watchdog timer. The CPU will reset if the watchdog is not fed every delay_ms
|
||||||
|
|
||||||
|
@param [in] delay_ms Milliseconds without a wdt_reset before rebooting
|
||||||
|
*/
|
||||||
|
void wdt_begin(uint32_t delay_ms) {
|
||||||
|
watchdog_enable(delay_ms, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Feeds the watchdog timer, resetting it for another delay_ms countdown
|
||||||
|
*/
|
||||||
|
void wdt_reset() {
|
||||||
|
watchdog_update();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Best-effort reasons for chip reset
|
||||||
|
*/
|
||||||
|
enum resetReason_t {UNKNOWN_RESET, PWRON_RESET, RUN_PIN_RESET, SOFT_RESET, WDT_RESET, DEBUG_RESET, GLITCH_RESET, BROWNOUT_RESET};
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Attempts to determine the reason for the last chip reset. May not always be able to determine accurately
|
||||||
|
|
||||||
|
@returns Reason for reset
|
||||||
|
*/
|
||||||
|
resetReason_t getResetReason(void) {
|
||||||
|
io_rw_32 *WD_reason_reg = (io_rw_32 *)(WATCHDOG_BASE + WATCHDOG_REASON_OFFSET);
|
||||||
|
|
||||||
|
if (watchdog_caused_reboot() && watchdog_enable_caused_reboot()) { // watchdog timer
|
||||||
|
return WDT_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*WD_reason_reg & WATCHDOG_REASON_TIMER_BITS) { // soft reset() or reboot()
|
||||||
|
return SOFT_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef PICO_RP2350
|
||||||
|
// **** RP2350 is untested ****
|
||||||
|
io_rw_32 *rrp = (io_rw_32 *)(POWMAN_BASE + POWMAN_CHIP_RESET_OFFSET);
|
||||||
|
|
||||||
|
if (*rrp & POWMAN_CHIP_RESET_HAD_POR_BITS) { // POR: power-on reset (brownout is separately detected on RP2350)
|
||||||
|
return PWRON_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*rrp & POWMAN_CHIP_RESET_HAD_RUN_LOW_BITS) { // RUN pin
|
||||||
|
return RUN_PIN_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((*rrp & POWMAN_CHIP_RESET_HAD_DP_RESET_REQ_BITS) || (*rrp & POWMAN_CHIP_RESET_HAD_RESCUE_BITS) || (*rrp & POWMAN_CHIP_RESET_HAD_HZD_SYS_RESET_REQ_BITS)) { // DEBUG port
|
||||||
|
return DEBUG_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*rrp & POWMAN_CHIP_RESET_HAD_GLITCH_DETECT_BITS) { // power supply glitch
|
||||||
|
return GLITCH_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*rrp & POWMAN_CHIP_RESET_HAD_BOR_BITS) { // power supply brownout reset
|
||||||
|
return BROWNOUT_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
io_rw_32 *rrp = (io_rw_32 *)(VREG_AND_CHIP_RESET_BASE + VREG_AND_CHIP_RESET_CHIP_RESET_OFFSET);
|
||||||
|
|
||||||
|
if (*rrp & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_POR_BITS) { // POR: power-on reset or brown-out detection
|
||||||
|
return PWRON_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*rrp & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_RUN_BITS) { // RUN pin
|
||||||
|
return RUN_PIN_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*rrp & VREG_AND_CHIP_RESET_CHIP_RESET_HAD_PSM_RESTART_BITS) { // DEBUG port
|
||||||
|
return DEBUG_RESET; // **** untested **** debug reset may just cause a rebootToBootloader()
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return UNKNOWN_RESET;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Get unique ID string for the running board
|
||||||
|
@returns String with the unique board ID as determined by the SDK
|
||||||
|
*/
|
||||||
|
const char *getChipID() {
|
||||||
|
static char id[2 * PICO_UNIQUE_BOARD_ID_SIZE_BYTES + 1] = { 0 };
|
||||||
|
if (!id[0]) {
|
||||||
|
pico_get_unique_board_id_string(id, sizeof(id));
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma GCC push_options
|
||||||
|
#pragma GCC optimize ("Os")
|
||||||
|
/**
|
||||||
|
@brief Perform a memcpy using a DMA engine for speed
|
||||||
|
|
||||||
|
@details
|
||||||
|
Uses the DMA to copy to and from RAM. Only works on 4-byte aligned, 4-byte multiple length
|
||||||
|
sources and destination (i.e. word-aligned, word-length). Falls back to normal memcpy otherwise.
|
||||||
|
|
||||||
|
@param [out] dest Memcpy destination, 4-byte aligned
|
||||||
|
@param [in] src Memcpy source, 4-byte aligned
|
||||||
|
@param [in] n Count in bytes to transfer (should be a multiple of 4 bytes)
|
||||||
|
*/
|
||||||
|
void *memcpyDMA(void *dest, const void *src, size_t n) {
|
||||||
|
// Allocate a DMA channel on 1st call, reuse it every call after
|
||||||
|
if (memcpyDMAChannel < 1) {
|
||||||
|
memcpyDMAChannel = dma_claim_unused_channel(true);
|
||||||
|
dma_channel_config c = dma_channel_get_default_config(memcpyDMAChannel);
|
||||||
|
channel_config_set_transfer_data_size(&c, DMA_SIZE_32);
|
||||||
|
channel_config_set_read_increment(&c, true);
|
||||||
|
channel_config_set_write_increment(&c, true);
|
||||||
|
channel_config_set_irq_quiet(&c, true);
|
||||||
|
dma_channel_set_config(memcpyDMAChannel, &c, false);
|
||||||
|
}
|
||||||
|
// If there's any misalignment or too small, use regular memcpy which can handle it
|
||||||
|
if ((n < 64) || (((uint32_t)dest) | ((uint32_t)src) | n) & 3) {
|
||||||
|
return memcpy(dest, src, n);
|
||||||
|
}
|
||||||
|
|
||||||
|
int words = n / 4;
|
||||||
|
dma_channel_set_read_addr(memcpyDMAChannel, src, false);
|
||||||
|
dma_channel_set_write_addr(memcpyDMAChannel, dest, false);
|
||||||
|
dma_channel_set_trans_count(memcpyDMAChannel, words, false);
|
||||||
|
dma_channel_start(memcpyDMAChannel);
|
||||||
|
while (dma_channel_is_busy(memcpyDMAChannel)) {
|
||||||
|
/* busy wait dma */
|
||||||
|
}
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
#pragma GCC pop_options
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Multicore communications FIFO
|
||||||
|
*/
|
||||||
|
_MFIFO fifo;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Return a 32-bit from the hardware random number generator
|
||||||
|
|
||||||
|
@returns Random value using appropriate hardware (RP2350 has true RNG, RP2040 has a less true RNG method)
|
||||||
|
*/
|
||||||
|
uint32_t hwrand32() {
|
||||||
|
return get_rand_32();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Determines if code is running on a Pico or a PicoW
|
||||||
|
|
||||||
|
@details
|
||||||
|
Code compiled for the RP2040 PicoW can run on the RP2040 Pico. This call lets an application
|
||||||
|
identify if the current device is really a Pico or PicoW and handle appropriately. For
|
||||||
|
the RP2350, this runtime detection is not available and the call returns whether it was
|
||||||
|
compiled for the CYW43 WiFi driver
|
||||||
|
|
||||||
|
@returns True if running on a PicoW board with CYW43 WiFi chip.
|
||||||
|
*/
|
||||||
|
bool isPicoW() {
|
||||||
|
#if !defined(PICO_CYW43_SUPPORTED)
|
||||||
|
return false;
|
||||||
|
#else
|
||||||
|
extern bool __isPicoW;
|
||||||
|
return __isPicoW;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __PROFILE
|
||||||
|
void writeProfiling(Stream *f) {
|
||||||
|
extern Stream *__profileFile;
|
||||||
|
extern int __writeProfileCB(const void *data, int len);
|
||||||
|
__profileFile = f;
|
||||||
|
_writeProfile(__writeProfileCB);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t getProfileMemoryUsage() {
|
||||||
|
extern int __profileMemSize;
|
||||||
|
return (size_t) __profileMemSize;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void __no_inline_not_in_flash_func(_SystickHandler)() {
|
||||||
|
rp2040._epoch[sio_hw->cpuid] += 1LL << 24;
|
||||||
|
}
|
||||||
|
PIO _pio;
|
||||||
|
int _sm;
|
||||||
|
PIOProgram *_ccountPgm;
|
||||||
|
int memcpyDMAChannel = -1;
|
||||||
|
};
|
||||||
620
cores/rp2040/RP2040USB.cpp
Normal file
620
cores/rp2040/RP2040USB.cpp
Normal file
|
|
@ -0,0 +1,620 @@
|
||||||
|
/*
|
||||||
|
Shared USB for the Raspberry Pi Pico RP2040
|
||||||
|
Allows for multiple endpoints to share the USB controller
|
||||||
|
|
||||||
|
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(USE_TINYUSB) && !defined(NO_USB)
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "CoreMutex.h"
|
||||||
|
#include "RP2040USB.h"
|
||||||
|
|
||||||
|
#include <tusb.h>
|
||||||
|
#include <class/hid/hid_device.h>
|
||||||
|
#include <class/audio/audio.h>
|
||||||
|
#include <pico/time.h>
|
||||||
|
#include <hardware/irq.h>
|
||||||
|
#include <pico/mutex.h>
|
||||||
|
#include <pico/unique_id.h>
|
||||||
|
#include <pico/usb_reset_interface.h>
|
||||||
|
#include <hardware/watchdog.h>
|
||||||
|
#include <pico/bootrom.h>
|
||||||
|
#include "sdkoverride/tusb_gamepad16.h"
|
||||||
|
#include <device/usbd_pvt.h>
|
||||||
|
|
||||||
|
// Big, global USB mutex, shared with all USB devices to make sure we don't
|
||||||
|
// have multiple cores updating the TUSB state in parallel
|
||||||
|
mutex_t __usb_mutex;
|
||||||
|
|
||||||
|
// USB processing will be a periodic timer task
|
||||||
|
#define USB_TASK_INTERVAL 1000
|
||||||
|
static int __usb_task_irq;
|
||||||
|
|
||||||
|
#ifndef USBD_VID
|
||||||
|
#define USBD_VID (0x2E8A) // Raspberry Pi
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef USBD_PID
|
||||||
|
#define USBD_PID (0x000a) // Raspberry Pi Pico SDK CDC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
|
||||||
|
|
||||||
|
#define USBD_ITF_CDC (0) // needs 2 interfaces
|
||||||
|
#define USBD_ITF_MAX (2)
|
||||||
|
|
||||||
|
#define USBD_CDC_EP_CMD (0x81)
|
||||||
|
#define USBD_CDC_EP_OUT (0x02)
|
||||||
|
#define USBD_CDC_EP_IN (0x82)
|
||||||
|
#define USBD_CDC_CMD_MAX_SIZE (8)
|
||||||
|
#define USBD_CDC_IN_OUT_MAX_SIZE (64)
|
||||||
|
|
||||||
|
#define USBD_STR_0 (0x00)
|
||||||
|
#define USBD_STR_MANUF (0x01)
|
||||||
|
#define USBD_STR_PRODUCT (0x02)
|
||||||
|
#define USBD_STR_SERIAL (0x03)
|
||||||
|
#define USBD_STR_CDC (0x04)
|
||||||
|
#define USBD_STR_RPI_RESET (0x05)
|
||||||
|
|
||||||
|
#define EPNUM_HID 0x83
|
||||||
|
|
||||||
|
#define USBD_MSC_EPOUT 0x03
|
||||||
|
#define USBD_MSC_EPIN 0x84
|
||||||
|
#define USBD_MSC_EPSIZE 64
|
||||||
|
|
||||||
|
#define TUD_RPI_RESET_DESCRIPTOR(_itfnum, _stridx) \
|
||||||
|
/* Interface */\
|
||||||
|
9, TUSB_DESC_INTERFACE, _itfnum, 0, 0, TUSB_CLASS_VENDOR_SPECIFIC, RESET_INTERFACE_SUBCLASS, RESET_INTERFACE_PROTOCOL, _stridx,
|
||||||
|
|
||||||
|
|
||||||
|
int usb_hid_poll_interval __attribute__((weak)) = 10;
|
||||||
|
|
||||||
|
const uint8_t *tud_descriptor_device_cb(void) {
|
||||||
|
static tusb_desc_device_t usbd_desc_device = {
|
||||||
|
.bLength = sizeof(tusb_desc_device_t),
|
||||||
|
.bDescriptorType = TUSB_DESC_DEVICE,
|
||||||
|
.bcdUSB = 0x0200,
|
||||||
|
.bDeviceClass = TUSB_CLASS_CDC,
|
||||||
|
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
||||||
|
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
||||||
|
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
||||||
|
.idVendor = USBD_VID,
|
||||||
|
.idProduct = USBD_PID,
|
||||||
|
.bcdDevice = 0x0100,
|
||||||
|
.iManufacturer = USBD_STR_MANUF,
|
||||||
|
.iProduct = USBD_STR_PRODUCT,
|
||||||
|
.iSerialNumber = USBD_STR_SERIAL,
|
||||||
|
.bNumConfigurations = 1
|
||||||
|
};
|
||||||
|
if (__USBInstallSerial && !__USBInstallKeyboard && !__USBInstallMouse && !__USBInstallAbsoluteMouse && !__USBInstallJoystick && !__USBInstallMassStorage) {
|
||||||
|
// Can use as-is, this is the default USB case
|
||||||
|
return (const uint8_t *)&usbd_desc_device;
|
||||||
|
}
|
||||||
|
// Need a multi-endpoint config which will require changing the PID to help Windows not barf
|
||||||
|
if (__USBInstallKeyboard) {
|
||||||
|
usbd_desc_device.idProduct |= 0x8000;
|
||||||
|
}
|
||||||
|
if (__USBInstallMouse || __USBInstallAbsoluteMouse) {
|
||||||
|
usbd_desc_device.idProduct |= 0x4000;
|
||||||
|
}
|
||||||
|
if (__USBInstallJoystick) {
|
||||||
|
usbd_desc_device.idProduct |= 0x0100;
|
||||||
|
}
|
||||||
|
if (__USBInstallMassStorage) {
|
||||||
|
usbd_desc_device.idProduct ^= 0x2000;
|
||||||
|
}
|
||||||
|
// Set the device class to 0 to indicate multiple device classes
|
||||||
|
usbd_desc_device.bDeviceClass = 0;
|
||||||
|
usbd_desc_device.bDeviceSubClass = 0;
|
||||||
|
usbd_desc_device.bDeviceProtocol = 0;
|
||||||
|
return (const uint8_t *)&usbd_desc_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __USBGetKeyboardReportID() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __USBGetMouseReportID() {
|
||||||
|
return __USBInstallKeyboard ? 3 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int __USBGetJoystickReportID() {
|
||||||
|
int i = 1;
|
||||||
|
if (__USBInstallKeyboard) {
|
||||||
|
i += 2;
|
||||||
|
}
|
||||||
|
if (__USBInstallMouse || __USBInstallAbsoluteMouse) {
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __hid_report_len = 0;
|
||||||
|
static uint8_t *__hid_report = nullptr;
|
||||||
|
|
||||||
|
static uint8_t *GetDescHIDReport(int *len) {
|
||||||
|
if (len) {
|
||||||
|
*len = __hid_report_len;
|
||||||
|
}
|
||||||
|
return __hid_report;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __SetupDescHIDReport() {
|
||||||
|
//allocate memory for the HID report descriptors. We don't use them, but need the size here.
|
||||||
|
uint8_t desc_hid_report_mouse[] = { TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(1)) };
|
||||||
|
uint8_t desc_hid_report_absmouse[] = { TUD_HID_REPORT_DESC_ABSMOUSE(HID_REPORT_ID(1)) };
|
||||||
|
uint8_t desc_hid_report_joystick[] = { TUD_HID_REPORT_DESC_GAMEPAD16(HID_REPORT_ID(1)) };
|
||||||
|
uint8_t desc_hid_report_keyboard[] = { TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(1)), TUD_HID_REPORT_DESC_CONSUMER(HID_REPORT_ID(2)) };
|
||||||
|
int size = 0;
|
||||||
|
|
||||||
|
//accumulate the size of all used HID report descriptors
|
||||||
|
if (__USBInstallKeyboard) {
|
||||||
|
size += sizeof(desc_hid_report_keyboard);
|
||||||
|
}
|
||||||
|
if (__USBInstallMouse) {
|
||||||
|
size += sizeof(desc_hid_report_mouse);
|
||||||
|
} else if (__USBInstallAbsoluteMouse) {
|
||||||
|
size += sizeof(desc_hid_report_absmouse);
|
||||||
|
}
|
||||||
|
if (__USBInstallJoystick) {
|
||||||
|
size += sizeof(desc_hid_report_joystick);
|
||||||
|
}
|
||||||
|
|
||||||
|
//no HID used at all
|
||||||
|
if (size == 0) {
|
||||||
|
__hid_report = nullptr;
|
||||||
|
__hid_report_len = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//allocate the "real" HID report descriptor
|
||||||
|
__hid_report = (uint8_t *)malloc(size);
|
||||||
|
if (__hid_report) {
|
||||||
|
__hid_report_len = size;
|
||||||
|
|
||||||
|
//now copy the descriptors
|
||||||
|
|
||||||
|
//1.) keyboard descriptor, if requested
|
||||||
|
if (__USBInstallKeyboard) {
|
||||||
|
memcpy(__hid_report, desc_hid_report_keyboard, sizeof(desc_hid_report_keyboard));
|
||||||
|
}
|
||||||
|
|
||||||
|
//2.) mouse descriptor, if necessary. Additional offset & new array is necessary if there is a keyboard.
|
||||||
|
if (__USBInstallMouse) {
|
||||||
|
//determine if we need an offset (USB keyboard is installed)
|
||||||
|
if (__USBInstallKeyboard) {
|
||||||
|
uint8_t desc_local[] = { TUD_HID_REPORT_DESC_MOUSE(HID_REPORT_ID(3)) };
|
||||||
|
memcpy(__hid_report + sizeof(desc_hid_report_keyboard), desc_local, sizeof(desc_local));
|
||||||
|
} else {
|
||||||
|
memcpy(__hid_report, desc_hid_report_mouse, sizeof(desc_hid_report_mouse));
|
||||||
|
}
|
||||||
|
} else if (__USBInstallAbsoluteMouse) {
|
||||||
|
//determine if we need an offset (USB keyboard is installed)
|
||||||
|
if (__USBInstallKeyboard) {
|
||||||
|
uint8_t desc_local[] = { TUD_HID_REPORT_DESC_ABSMOUSE(HID_REPORT_ID(3)) };
|
||||||
|
memcpy(__hid_report + sizeof(desc_hid_report_keyboard), desc_local, sizeof(desc_local));
|
||||||
|
} else {
|
||||||
|
memcpy(__hid_report, desc_hid_report_absmouse, sizeof(desc_hid_report_absmouse));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//3.) joystick descriptor. 2 additional checks are necessary for mouse and/or keyboard
|
||||||
|
if (__USBInstallJoystick) {
|
||||||
|
uint8_t reportid = 1;
|
||||||
|
int offset = 0;
|
||||||
|
if (__USBInstallKeyboard) {
|
||||||
|
reportid += 2;
|
||||||
|
offset += sizeof(desc_hid_report_keyboard);
|
||||||
|
}
|
||||||
|
if (__USBInstallMouse) {
|
||||||
|
reportid++;
|
||||||
|
offset += sizeof(desc_hid_report_mouse);
|
||||||
|
} else if (__USBInstallAbsoluteMouse) {
|
||||||
|
reportid++;
|
||||||
|
offset += sizeof(desc_hid_report_absmouse);
|
||||||
|
}
|
||||||
|
uint8_t desc_local[] = { TUD_HID_REPORT_DESC_GAMEPAD16(HID_REPORT_ID(reportid)) };
|
||||||
|
memcpy(__hid_report + offset, desc_local, sizeof(desc_local));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when received GET HID REPORT DESCRIPTOR
|
||||||
|
// Application return pointer to descriptor
|
||||||
|
// Descriptor contents must exist long enough for transfer to complete
|
||||||
|
uint8_t const * tud_hid_descriptor_report_cb(uint8_t instance) {
|
||||||
|
(void) instance;
|
||||||
|
return GetDescHIDReport(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t *usbd_desc_cfg = nullptr;
|
||||||
|
const uint8_t *tud_descriptor_configuration_cb(uint8_t index) {
|
||||||
|
(void)index;
|
||||||
|
return usbd_desc_cfg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __SetupUSBDescriptor() {
|
||||||
|
if (!usbd_desc_cfg) {
|
||||||
|
bool hasHID = __USBInstallKeyboard || __USBInstallMouse || __USBInstallAbsoluteMouse || __USBInstallJoystick;
|
||||||
|
|
||||||
|
uint8_t interface_count = (__USBInstallSerial ? 2 : 0) + (hasHID ? 1 : 0) + (__USBInstallMassStorage ? 1 : 0);
|
||||||
|
|
||||||
|
uint8_t cdc_desc[TUD_CDC_DESC_LEN] = {
|
||||||
|
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
|
||||||
|
TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD, USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, USBD_CDC_EP_IN, USBD_CDC_IN_OUT_MAX_SIZE)
|
||||||
|
};
|
||||||
|
|
||||||
|
int hid_report_len;
|
||||||
|
GetDescHIDReport(&hid_report_len);
|
||||||
|
uint8_t hid_itf = __USBInstallSerial ? 2 : 0;
|
||||||
|
uint8_t hid_desc[TUD_HID_DESC_LEN] = {
|
||||||
|
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
|
||||||
|
TUD_HID_DESCRIPTOR(hid_itf, 0, HID_ITF_PROTOCOL_NONE, hid_report_len, EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, (uint8_t)usb_hid_poll_interval)
|
||||||
|
};
|
||||||
|
|
||||||
|
uint8_t msd_itf = interface_count - 1;
|
||||||
|
uint8_t msd_desc[TUD_MSC_DESC_LEN] = {
|
||||||
|
TUD_MSC_DESCRIPTOR(msd_itf, 0, USBD_MSC_EPOUT, USBD_MSC_EPIN, USBD_MSC_EPSIZE)
|
||||||
|
};
|
||||||
|
|
||||||
|
int usbd_desc_len = TUD_CONFIG_DESC_LEN + (__USBInstallSerial ? sizeof(cdc_desc) : 0) + (hasHID ? sizeof(hid_desc) : 0) + (__USBInstallMassStorage ? sizeof(msd_desc) : 0);
|
||||||
|
|
||||||
|
#ifdef ENABLE_PICOTOOL_USB
|
||||||
|
uint8_t picotool_itf = interface_count++;
|
||||||
|
uint8_t picotool_desc[] = {
|
||||||
|
TUD_RPI_RESET_DESCRIPTOR(picotool_itf, USBD_STR_RPI_RESET)
|
||||||
|
};
|
||||||
|
usbd_desc_len += sizeof(picotool_desc);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uint8_t tud_cfg_desc[TUD_CONFIG_DESC_LEN] = {
|
||||||
|
// Config number, interface count, string index, total length, attribute, power in mA
|
||||||
|
TUD_CONFIG_DESCRIPTOR(1, interface_count, USBD_STR_0, usbd_desc_len, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Combine to one descriptor
|
||||||
|
usbd_desc_cfg = (uint8_t *)malloc(usbd_desc_len);
|
||||||
|
if (usbd_desc_cfg) {
|
||||||
|
bzero(usbd_desc_cfg, usbd_desc_len);
|
||||||
|
uint8_t *ptr = usbd_desc_cfg;
|
||||||
|
memcpy(ptr, tud_cfg_desc, sizeof(tud_cfg_desc));
|
||||||
|
ptr += sizeof(tud_cfg_desc);
|
||||||
|
if (__USBInstallSerial) {
|
||||||
|
memcpy(ptr, cdc_desc, sizeof(cdc_desc));
|
||||||
|
ptr += sizeof(cdc_desc);
|
||||||
|
}
|
||||||
|
if (hasHID) {
|
||||||
|
memcpy(ptr, hid_desc, sizeof(hid_desc));
|
||||||
|
ptr += sizeof(hid_desc);
|
||||||
|
}
|
||||||
|
if (__USBInstallMassStorage) {
|
||||||
|
memcpy(ptr, msd_desc, sizeof(msd_desc));
|
||||||
|
ptr += sizeof(msd_desc);
|
||||||
|
}
|
||||||
|
#ifdef ENABLE_PICOTOOL_USB
|
||||||
|
memcpy(ptr, picotool_desc, sizeof(picotool_desc));
|
||||||
|
ptr += sizeof(picotool_desc);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
||||||
|
(void) langid;
|
||||||
|
#define DESC_STR_MAX (32)
|
||||||
|
static uint16_t desc_str[DESC_STR_MAX];
|
||||||
|
|
||||||
|
static char idString[PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2 + 1];
|
||||||
|
|
||||||
|
static const char *const usbd_desc_str[] = {
|
||||||
|
[USBD_STR_0] = "",
|
||||||
|
[USBD_STR_MANUF] = USB_MANUFACTURER,
|
||||||
|
[USBD_STR_PRODUCT] = USB_PRODUCT,
|
||||||
|
[USBD_STR_SERIAL] = idString,
|
||||||
|
[USBD_STR_CDC] = "Board CDC",
|
||||||
|
#ifdef ENABLE_PICOTOOL_USB
|
||||||
|
[USBD_STR_RPI_RESET] = "Reset",
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!idString[0]) {
|
||||||
|
pico_get_unique_board_id_string(idString, sizeof(idString));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t len;
|
||||||
|
if (index == 0) {
|
||||||
|
desc_str[1] = 0x0409; // supported language is English
|
||||||
|
len = 1;
|
||||||
|
} else {
|
||||||
|
if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const char *str = usbd_desc_str[index];
|
||||||
|
for (len = 0; len < DESC_STR_MAX - 1 && str[len]; ++len) {
|
||||||
|
desc_str[1 + len] = str[len];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// first byte is length (including header), second byte is string type
|
||||||
|
desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * len + 2);
|
||||||
|
|
||||||
|
return desc_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void usb_irq() {
|
||||||
|
// if the mutex is already owned, then we are in user code
|
||||||
|
// in this file which will do a tud_task itself, so we'll just do nothing
|
||||||
|
// until the next tick; we won't starve
|
||||||
|
if (mutex_try_enter(&__usb_mutex, nullptr)) {
|
||||||
|
tud_task();
|
||||||
|
mutex_exit(&__usb_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) {
|
||||||
|
irq_set_pending(__usb_task_irq);
|
||||||
|
return USB_TASK_INTERVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void __USBStart() __attribute__((weak));
|
||||||
|
|
||||||
|
void __USBStart() {
|
||||||
|
if (tusb_inited()) {
|
||||||
|
// Already called
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
__SetupDescHIDReport();
|
||||||
|
__SetupUSBDescriptor();
|
||||||
|
|
||||||
|
mutex_init(&__usb_mutex);
|
||||||
|
|
||||||
|
tusb_init();
|
||||||
|
|
||||||
|
__usb_task_irq = user_irq_claim_unused(true);
|
||||||
|
irq_set_exclusive_handler(__usb_task_irq, usb_irq);
|
||||||
|
irq_set_enabled(__usb_task_irq, true);
|
||||||
|
|
||||||
|
add_alarm_in_us(USB_TASK_INTERVAL, timer_task, nullptr, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool __USBHIDReady() {
|
||||||
|
uint32_t start = millis();
|
||||||
|
const uint32_t timeout = 500;
|
||||||
|
|
||||||
|
while (((millis() - start) < timeout) && tud_ready() && !tud_hid_ready()) {
|
||||||
|
tud_task();
|
||||||
|
delayMicroseconds(1);
|
||||||
|
}
|
||||||
|
return tud_hid_ready();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Invoked when received GET_REPORT control request
|
||||||
|
// Application must fill buffer report's content and return its length.
|
||||||
|
// Return zero will cause the stack to STALL request
|
||||||
|
extern "C" uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) __attribute__((weak));
|
||||||
|
extern "C" uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) {
|
||||||
|
// TODO not implemented
|
||||||
|
(void) instance;
|
||||||
|
(void) report_id;
|
||||||
|
(void) report_type;
|
||||||
|
(void) buffer;
|
||||||
|
(void) reqlen;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invoked when received SET_REPORT control request or
|
||||||
|
// received data on OUT endpoint ( Report ID = 0, Type = 0 )
|
||||||
|
extern "C" void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) __attribute__((weak));
|
||||||
|
extern "C" void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) {
|
||||||
|
// TODO set LED based on CAPLOCK, NUMLOCK etc...
|
||||||
|
(void) instance;
|
||||||
|
(void) report_id;
|
||||||
|
(void) report_type;
|
||||||
|
(void) buffer;
|
||||||
|
(void) bufsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) __attribute__((weak));
|
||||||
|
extern "C" int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) {
|
||||||
|
(void) lun;
|
||||||
|
(void) lba;
|
||||||
|
(void) offset;
|
||||||
|
(void) buffer;
|
||||||
|
(void) bufsize;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" bool tud_msc_test_unit_ready_cb(uint8_t lun) __attribute__((weak));
|
||||||
|
extern "C" bool tud_msc_test_unit_ready_cb(uint8_t lun) {
|
||||||
|
(void) lun;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) __attribute__((weak));
|
||||||
|
extern "C" int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
|
||||||
|
(void) lun;
|
||||||
|
(void) lba;
|
||||||
|
(void) offset;
|
||||||
|
(void) buffer;
|
||||||
|
(void) bufsize;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) __attribute__((weak));
|
||||||
|
extern "C" int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) {
|
||||||
|
(void) lun;
|
||||||
|
(void) scsi_cmd;
|
||||||
|
(void) buffer;
|
||||||
|
(void) bufsize;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) __attribute__((weak));
|
||||||
|
extern "C" void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) {
|
||||||
|
(void) lun;
|
||||||
|
*block_count = 0;
|
||||||
|
*block_size = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) __attribute__((weak));
|
||||||
|
extern "C" void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {
|
||||||
|
(void) lun;
|
||||||
|
vendor_id[0] = 0;
|
||||||
|
product_id[0] = 0;
|
||||||
|
product_rev[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef ENABLE_PICOTOOL_USB
|
||||||
|
|
||||||
|
static uint8_t _picotool_itf_num;
|
||||||
|
|
||||||
|
static void resetd_init() {
|
||||||
|
}
|
||||||
|
|
||||||
|
static void resetd_reset(uint8_t rhport) {
|
||||||
|
(void) rhport;
|
||||||
|
_picotool_itf_num = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t resetd_open(uint8_t rhport,
|
||||||
|
tusb_desc_interface_t const *itf_desc, uint16_t max_len) {
|
||||||
|
(void) rhport;
|
||||||
|
TU_VERIFY(TUSB_CLASS_VENDOR_SPECIFIC == itf_desc->bInterfaceClass &&
|
||||||
|
RESET_INTERFACE_SUBCLASS == itf_desc->bInterfaceSubClass &&
|
||||||
|
RESET_INTERFACE_PROTOCOL == itf_desc->bInterfaceProtocol, 0);
|
||||||
|
|
||||||
|
uint16_t const drv_len = sizeof(tusb_desc_interface_t);
|
||||||
|
TU_VERIFY(max_len >= drv_len, 0);
|
||||||
|
|
||||||
|
_picotool_itf_num = itf_desc->bInterfaceNumber;
|
||||||
|
return drv_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Support for parameterized reset via vendor interface control request
|
||||||
|
static bool resetd_control_xfer_cb(uint8_t rhport, uint8_t stage,
|
||||||
|
tusb_control_request_t const *request) {
|
||||||
|
(void) rhport;
|
||||||
|
// nothing to do with DATA & ACK stage
|
||||||
|
if (stage != CONTROL_STAGE_SETUP) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->wIndex == _picotool_itf_num) {
|
||||||
|
if (request->bRequest == RESET_REQUEST_BOOTSEL) {
|
||||||
|
reset_usb_boot(0, (request->wValue & 0x7f));
|
||||||
|
// does not return, otherwise we'd return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (request->bRequest == RESET_REQUEST_FLASH) {
|
||||||
|
watchdog_reboot(0, 0, 100);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool resetd_xfer_cb(uint8_t rhport, uint8_t ep_addr,
|
||||||
|
xfer_result_t result, uint32_t xferred_bytes) {
|
||||||
|
(void) rhport;
|
||||||
|
(void) ep_addr;
|
||||||
|
(void) result;
|
||||||
|
(void) xferred_bytes;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static usbd_class_driver_t const _resetd_driver = {
|
||||||
|
#if CFG_TUSB_DEBUG >= 2
|
||||||
|
.name = "RESET",
|
||||||
|
#endif
|
||||||
|
.init = resetd_init,
|
||||||
|
.reset = resetd_reset,
|
||||||
|
.open = resetd_open,
|
||||||
|
.control_xfer_cb = resetd_control_xfer_cb,
|
||||||
|
.xfer_cb = resetd_xfer_cb,
|
||||||
|
.sof = NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
// Implement callback to add our custom driver
|
||||||
|
usbd_class_driver_t const *usbd_app_driver_get_cb(uint8_t *driver_count) {
|
||||||
|
*driver_count = 1;
|
||||||
|
return &_resetd_driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined NO_USB
|
||||||
|
|
||||||
|
#warning "NO_USB selected. No output to Serial will occur!"
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
|
||||||
|
void SerialUSB::begin(unsigned long baud) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialUSB::end() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int SerialUSB::peek() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SerialUSB::read() {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SerialUSB::available() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SerialUSB::availableForWrite() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialUSB::flush() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SerialUSB::write(uint8_t c) {
|
||||||
|
(void) c;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SerialUSB::write(const uint8_t *buf, size_t length) {
|
||||||
|
(void) buf;
|
||||||
|
(void) length;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
SerialUSB::operator bool() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SerialUSB Serial;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
50
cores/rp2040/RP2040USB.h
Normal file
50
cores/rp2040/RP2040USB.h
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
Shared USB for the Raspberry Pi Pico RP2040
|
||||||
|
Allows for multiple endpoints to share the USB controller
|
||||||
|
|
||||||
|
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <pico/mutex.h>
|
||||||
|
|
||||||
|
// Weak function definitions for each type of endpoint
|
||||||
|
extern void __USBInstallSerial() __attribute__((weak));
|
||||||
|
|
||||||
|
extern void __USBInstallKeyboard() __attribute__((weak));
|
||||||
|
|
||||||
|
extern void __USBInstallJoystick() __attribute__((weak));
|
||||||
|
|
||||||
|
// One or the other allowed, not both
|
||||||
|
extern void __USBInstallMouse() __attribute__((weak));
|
||||||
|
extern void __USBInstallAbsoluteMouse() __attribute__((weak));
|
||||||
|
|
||||||
|
extern void __USBInstallMassStorage() __attribute__((weak));
|
||||||
|
|
||||||
|
// Big, global USB mutex, shared with all USB devices to make sure we don't
|
||||||
|
// have multiple cores updating the TUSB state in parallel
|
||||||
|
extern mutex_t __usb_mutex;
|
||||||
|
|
||||||
|
// HID report ID inquiry (report ID will vary depending on the number/type of other HID)
|
||||||
|
int __USBGetKeyboardReportID();
|
||||||
|
int __USBGetMouseReportID();
|
||||||
|
int __USBGetJoystickReportID();
|
||||||
|
|
||||||
|
// Called by main() to init the USB HW/SW.
|
||||||
|
void __USBStart();
|
||||||
|
|
||||||
|
// Helper class for HID report sending with wait and timeout
|
||||||
|
bool __USBHIDReady();
|
||||||
5
cores/rp2040/RP2040Version.h
Normal file
5
cores/rp2040/RP2040Version.h
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
#pragma once
|
||||||
|
#define ARDUINO_PICO_MAJOR 4
|
||||||
|
#define ARDUINO_PICO_MINOR 5
|
||||||
|
#define ARDUINO_PICO_REVISION 4
|
||||||
|
#define ARDUINO_PICO_VERSION_STR "4.5.4"
|
||||||
297
cores/rp2040/SemiFS.h
Normal file
297
cores/rp2040/SemiFS.h
Normal file
|
|
@ -0,0 +1,297 @@
|
||||||
|
/*
|
||||||
|
SemiFS.h - File system wrapper for Semihosting ARM
|
||||||
|
Copyright (c) 2024 Earle F. Philhower, III. All rights reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Semihosting.h"
|
||||||
|
#include "FS.h"
|
||||||
|
#include "FSImpl.h"
|
||||||
|
|
||||||
|
using namespace fs;
|
||||||
|
|
||||||
|
namespace semifs {
|
||||||
|
|
||||||
|
class SemiFSFileImpl;
|
||||||
|
class SemiFSConfig : public FSConfig {
|
||||||
|
public:
|
||||||
|
static constexpr uint32_t FSId = 0x53454d49;
|
||||||
|
SemiFSConfig() : FSConfig(FSId, false) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
class SemiFSFileImpl : public FileImpl {
|
||||||
|
public:
|
||||||
|
SemiFSFileImpl(int fd, const char *name, bool writable)
|
||||||
|
: _fd(fd), _opened(true), _writable(writable) {
|
||||||
|
_name = std::shared_ptr<char>(new char[strlen(name) + 1], std::default_delete<char[]>());
|
||||||
|
strcpy(_name.get(), name);
|
||||||
|
}
|
||||||
|
|
||||||
|
~SemiFSFileImpl() override {
|
||||||
|
flush();
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
|
||||||
|
int availableForWrite() override {
|
||||||
|
return 1; // TODO - not implemented? _opened ? _fd->availableSpaceForWrite() : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t write(const uint8_t *buf, size_t size) override {
|
||||||
|
if (_opened) {
|
||||||
|
uint32_t a[3];
|
||||||
|
a[0] = _fd;
|
||||||
|
a[1] = (uint32_t)buf;
|
||||||
|
a[2] = size;
|
||||||
|
return 0 == Semihost(SEMIHOST_SYS_WRITE, a) ? size : -1;
|
||||||
|
}
|
||||||
|
return -1; // some kind of error
|
||||||
|
}
|
||||||
|
|
||||||
|
int read(uint8_t* buf, size_t size) override {
|
||||||
|
if (_opened) {
|
||||||
|
uint32_t a[3];
|
||||||
|
a[0] = _fd;
|
||||||
|
a[1] = (uint32_t)buf;
|
||||||
|
a[2] = size;
|
||||||
|
int ret = Semihost(SEMIHOST_SYS_READ, a);
|
||||||
|
if (ret == 0) {
|
||||||
|
return size;
|
||||||
|
} else if (ret == (int)size) {
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush() override {
|
||||||
|
/* noop */
|
||||||
|
}
|
||||||
|
|
||||||
|
bool seek(uint32_t pos, SeekMode mode) override {
|
||||||
|
if (!_opened || (mode != SeekSet)) {
|
||||||
|
// No seek cur/end in semihost
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint32_t a[2];
|
||||||
|
a[0] = _fd;
|
||||||
|
a[1] = pos;
|
||||||
|
return !Semihost(SEMIHOST_SYS_SEEK, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t position() const override {
|
||||||
|
return 0; // Not available semihost
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const override {
|
||||||
|
if (!_opened) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
uint32_t a;
|
||||||
|
a = _fd;
|
||||||
|
int ret = Semihost(SEMIHOST_SYS_FLEN, &a);
|
||||||
|
if (ret < 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool truncate(uint32_t size) override {
|
||||||
|
return false; // Not allowed
|
||||||
|
}
|
||||||
|
|
||||||
|
void close() override {
|
||||||
|
if (_opened) {
|
||||||
|
uint32_t a = _fd;
|
||||||
|
Semihost(SEMIHOST_SYS_CLOSE, &a);
|
||||||
|
_opened = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* name() const override {
|
||||||
|
if (!_opened) {
|
||||||
|
DEBUGV("SemiFSFileImpl::name: file not opened\n");
|
||||||
|
return nullptr;
|
||||||
|
} else {
|
||||||
|
const char *p = _name.get();
|
||||||
|
const char *slash = strrchr(p, '/');
|
||||||
|
// For names w/o any path elements, return directly
|
||||||
|
// If there are slashes, return name after the last slash
|
||||||
|
// (note that strrchr will return the address of the slash,
|
||||||
|
// so need to increment to ckip it)
|
||||||
|
return (slash && slash[1]) ? slash + 1 : p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* fullName() const override {
|
||||||
|
return _opened ? _name.get() : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isFile() const override {
|
||||||
|
return _opened; // Could look at ISTTY but that's not the sense here. Just differentiating between dirs and files
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isDirectory() const override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t getLastWrite() override {
|
||||||
|
return getCreationTime(); // TODO - FatFS doesn't seem to report both filetimes
|
||||||
|
}
|
||||||
|
|
||||||
|
time_t getCreationTime() override {
|
||||||
|
time_t ftime = 0;
|
||||||
|
return ftime;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int _fd;
|
||||||
|
std::shared_ptr<char> _name;
|
||||||
|
bool _opened;
|
||||||
|
bool _writable;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class SemiFSImpl : public FSImpl {
|
||||||
|
public:
|
||||||
|
SemiFSImpl() {
|
||||||
|
/* noop */
|
||||||
|
}
|
||||||
|
|
||||||
|
FileImplPtr open(const char* path, OpenMode openMode, AccessMode accessMode) override {
|
||||||
|
if (!path || !path[0]) {
|
||||||
|
DEBUGV("SemiFSImpl::open() called with invalid filename\n");
|
||||||
|
return FileImplPtr();
|
||||||
|
}
|
||||||
|
// Mode conversion https://developer.arm.com/documentation/dui0471/m/what-is-semihosting-/sys-open--0x01-?lang=en
|
||||||
|
int mode = 1; // "rb"
|
||||||
|
if (accessMode == AM_READ) {
|
||||||
|
mode = 1; // "rb"
|
||||||
|
} else if (accessMode == AM_WRITE) {
|
||||||
|
if (openMode & OM_APPEND) {
|
||||||
|
mode = 9; // "ab";
|
||||||
|
} else {
|
||||||
|
mode = 5; // "wb";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (openMode & OM_TRUNCATE) {
|
||||||
|
mode = 7; // "w+b";
|
||||||
|
} else if (openMode & OM_APPEND) {
|
||||||
|
mode = 3; // "r+b"
|
||||||
|
} else {
|
||||||
|
mode = 11; // "a+b";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
uint32_t a[3];
|
||||||
|
a[0] = (uint32_t)path;
|
||||||
|
a[1] = mode;
|
||||||
|
a[2] = strlen(path);
|
||||||
|
int handle = Semihost(SEMIHOST_SYS_OPEN, a);
|
||||||
|
if (handle < 0) {
|
||||||
|
return FileImplPtr();
|
||||||
|
}
|
||||||
|
return std::make_shared<SemiFSFileImpl>(handle, path, (accessMode & AM_WRITE) ? true : false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool exists(const char* path) override {
|
||||||
|
File f = open(path, OM_DEFAULT, AM_READ);
|
||||||
|
return f ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DirImplPtr openDir(const char* path) override {
|
||||||
|
// No directories
|
||||||
|
return DirImplPtr();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rename(const char* pathFrom, const char* pathTo) override {
|
||||||
|
uint32_t a[4];
|
||||||
|
a[0] = (uint32_t)pathFrom;
|
||||||
|
a[1] = strlen(pathFrom);
|
||||||
|
a[2] = (uint32_t)pathTo;
|
||||||
|
a[3] = strlen(pathTo);
|
||||||
|
return !Semihost(SEMIHOST_SYS_RENAME, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool info(FSInfo& info) override {
|
||||||
|
// Not available
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool remove(const char* path) override {
|
||||||
|
uint32_t a[2];
|
||||||
|
a[0] = (uint32_t)path;
|
||||||
|
a[1] = strlen(path);
|
||||||
|
return !Semihost(SEMIHOST_SYS_REMOVE, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool mkdir(const char* path) override {
|
||||||
|
// No mkdir
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rmdir(const char* path) override {
|
||||||
|
// No rmdir
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool stat(const char *path, FSStat *st) override {
|
||||||
|
if (!path || !path[0]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
uint32_t a[3];
|
||||||
|
a[0] = (uint32_t)path;
|
||||||
|
a[1] = 0; // READ
|
||||||
|
a[2] = strlen(path);
|
||||||
|
int fn = Semihost(SEMIHOST_SYS_OPEN, a);
|
||||||
|
if (fn < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bzero(st, sizeof(*st));
|
||||||
|
a[0] = fn;
|
||||||
|
st->size = Semihost(SEMIHOST_SYS_FLEN, a);
|
||||||
|
a[0] = fn;
|
||||||
|
Semihost(SEMIHOST_SYS_CLOSE, a);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setConfig(const FSConfig &cfg) override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool begin() override {
|
||||||
|
/* noop */
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void end() override {
|
||||||
|
/* noop */
|
||||||
|
}
|
||||||
|
|
||||||
|
bool format() override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}; // namespace sdfs
|
||||||
|
|
||||||
|
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SEMIFS)
|
||||||
|
extern FS SemiFS;
|
||||||
|
using semifs::SemiFSConfig;
|
||||||
|
#endif
|
||||||
6
cores/rp2040/Semihosting.cpp
Normal file
6
cores/rp2040/Semihosting.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
#include "Semihosting.h"
|
||||||
|
#include "SerialSemi.h"
|
||||||
|
#include "SemiFS.h"
|
||||||
|
|
||||||
|
SerialSemiClass SerialSemi;
|
||||||
|
FS SemiFS = FS(FSImplPtr(new semifs::SemiFSImpl()));
|
||||||
113
cores/rp2040/Semihosting.h
Normal file
113
cores/rp2040/Semihosting.h
Normal file
|
|
@ -0,0 +1,113 @@
|
||||||
|
/*
|
||||||
|
Semihosting.h - Semihosting for Serial and FS access via GDB
|
||||||
|
Copyright (c) 2024 Earle F. Philhower, III. All rights reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Be sure to only use this library with GDB and to enable the ARM semihosting support
|
||||||
|
// (gdb) monitor arm semihosting enable
|
||||||
|
|
||||||
|
// Input/output will be handled by OpenOCD
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Semihosting host API opcodes, from https://developer.arm.com/documentation/dui0471/g/Semihosting/Semihosting-operations?lang=en
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
SEMIHOST_SYS_CLOSE = 0x02,
|
||||||
|
SEMIHOST_SYS_CLOCK = 0x10,
|
||||||
|
SEMIHOST_SYS_ELAPSED = 0x30,
|
||||||
|
SEMIHOST_SYS_ERRNO = 0x13,
|
||||||
|
SEMIHOST_SYS_FLEN = 0x0C,
|
||||||
|
SEMIHOST_SYS_GET_CMDLINE = 0x15,
|
||||||
|
SEMIHOST_SYS_HEAPINFO = 0x16,
|
||||||
|
SEMIHOST_SYS_ISERROR = 0x08,
|
||||||
|
SEMIHOST_SYS_ISTTY = 0x09,
|
||||||
|
SEMIHOST_SYS_OPEN = 0x01,
|
||||||
|
SEMIHOST_SYS_READ = 0x06,
|
||||||
|
SEMIHOST_SYS_READC = 0x07,
|
||||||
|
SEMIHOST_SYS_REMOVE = 0x0E,
|
||||||
|
SEMIHOST_SYS_RENAME = 0x0F,
|
||||||
|
SEMIHOST_SYS_SEEK = 0x0A,
|
||||||
|
SEMIHOST_SYS_SYSTEM = 0x12,
|
||||||
|
SEMIHOST_SYS_TICKFREQ = 0x31,
|
||||||
|
SEMIHOST_SYS_TIME = 0x11,
|
||||||
|
SEMIHOST_SYS_TMPNAM = 0x0D,
|
||||||
|
SEMIHOST_SYS_WRITE = 0x05,
|
||||||
|
SEMIHOST_SYS_WRITEC = 0x03,
|
||||||
|
SEMIHOST_SYS_WRITE0 = 0x04
|
||||||
|
} SEMIHOST_OPCODES;
|
||||||
|
|
||||||
|
#ifdef __arm__
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Execute a semihosted request, from https://github.com/ErichStyger/mcuoneclipse/blob/master/Examples/MCUXpresso/FRDM-K22F/FRDM-K22F_Semihosting/source/McuSemihost.c
|
||||||
|
|
||||||
|
@param [in] reason Opcode to execute
|
||||||
|
@param [in] arg Any arguments for the opcode
|
||||||
|
@returns Result of operation
|
||||||
|
*/
|
||||||
|
static inline int __attribute__((always_inline)) Semihost(int reason, void *arg) {
|
||||||
|
int value;
|
||||||
|
__asm volatile(
|
||||||
|
"mov r0, %[rsn] \n" /* place semihost operation code into R0 */
|
||||||
|
"mov r1, %[arg] \n" /* R1 points to the argument array */
|
||||||
|
"bkpt 0xAB \n" /* call debugger */
|
||||||
|
"mov %[val], r0 \n" /* debugger has stored result code in R0 */
|
||||||
|
|
||||||
|
: [val] "=r"(value) /* outputs */
|
||||||
|
: [rsn] "r"(reason), [arg] "r"(arg) /* inputs */
|
||||||
|
: "r0", "r1", "r2", "r3", "ip", "lr", "memory", "cc" /* clobber */
|
||||||
|
);
|
||||||
|
return value; /* return result code, stored in R0 */
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Execute a semihosted request, from https://groups.google.com/a/groups.riscv.org/g/sw-dev/c/n-5VQ9PHZ4w/m/KbzH5t9MBgAJ
|
||||||
|
|
||||||
|
@param [in] reason Opcode to execute
|
||||||
|
@param [in] argPack Any arguments for the opcode
|
||||||
|
@returns Result of operation
|
||||||
|
*/
|
||||||
|
static inline int __attribute__((always_inline)) Semihost(int reason, void *argPack) {
|
||||||
|
register int value asm("a0") = reason;
|
||||||
|
register void *ptr asm("a1") = argPack;
|
||||||
|
asm volatile(
|
||||||
|
// Force 16-byte alignment to make sure that the 3 instructions fall
|
||||||
|
// within the same virtual page.
|
||||||
|
" .balign 16 \n"
|
||||||
|
" .option push \n"
|
||||||
|
// Force non-compressed RISC-V instructions
|
||||||
|
" .option norvc \n"
|
||||||
|
// semihosting e-break sequence
|
||||||
|
" slli x0, x0, 0x1f \n" // # Entry NOP
|
||||||
|
" ebreak \n" // # Break to debugger
|
||||||
|
" srai x0, x0, 0x7 \n" // # NOP encoding the semihosting call number 7
|
||||||
|
" .option pop \n"
|
||||||
|
/*mark (value) as an output operand*/
|
||||||
|
: "=r"(value) /* Outputs */
|
||||||
|
// The semihosting call number is passed in a0, and the argument in a1.
|
||||||
|
: "0"(value), "r"(ptr) /* Inputs */
|
||||||
|
// The "memory" clobber makes GCC assume that any memory may be arbitrarily read or written by the asm block,
|
||||||
|
// so will prevent the compiler from reordering loads or stores across it, or from caching memory values in registers across it.
|
||||||
|
// The "memory" clobber also prevents the compiler from removing the asm block as dead code.
|
||||||
|
: "memory" /* Clobbers */
|
||||||
|
);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
394
cores/rp2040/SerialPIO.cpp
Normal file
394
cores/rp2040/SerialPIO.cpp
Normal file
|
|
@ -0,0 +1,394 @@
|
||||||
|
/*
|
||||||
|
Serial-over-PIO for the Raspberry Pi Pico RP2040
|
||||||
|
|
||||||
|
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SerialPIO.h"
|
||||||
|
#include "CoreMutex.h"
|
||||||
|
#include <hardware/gpio.h>
|
||||||
|
#include <map>
|
||||||
|
#include "pio_uart.pio.h"
|
||||||
|
|
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
// -- Generates a unique program for differing bit lengths
|
||||||
|
static std::map<int, PIOProgram*> _txMap;
|
||||||
|
static std::map<int, PIOProgram*> _rxMap;
|
||||||
|
|
||||||
|
// Duplicate a program and replace the first insn with a "set x, repl"
|
||||||
|
static pio_program_t *pio_make_uart_prog(int repl, const pio_program_t *pg) {
|
||||||
|
pio_program_t *p = new pio_program_t;
|
||||||
|
memcpy(p, pg, sizeof(*p));
|
||||||
|
p->length = pg->length;
|
||||||
|
p->origin = pg->origin;
|
||||||
|
uint16_t *insn = (uint16_t *)malloc(p->length * 2);
|
||||||
|
if (!insn) {
|
||||||
|
delete p;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
memcpy(insn, pg->instructions, p->length * 2);
|
||||||
|
insn[0] = pio_encode_set(pio_x, repl);
|
||||||
|
p->instructions = insn;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PIOProgram *_getTxProgram(int bits) {
|
||||||
|
auto f = _txMap.find(bits);
|
||||||
|
if (f == _txMap.end()) {
|
||||||
|
pio_program_t * p = pio_make_uart_prog(bits, &pio_tx_program);
|
||||||
|
_txMap.insert({bits, new PIOProgram(p)});
|
||||||
|
f = _txMap.find(bits);
|
||||||
|
}
|
||||||
|
return f->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PIOProgram *_getRxProgram(int bits) {
|
||||||
|
auto f = _rxMap.find(bits);
|
||||||
|
if (f == _rxMap.end()) {
|
||||||
|
pio_program_t * p = pio_make_uart_prog(bits, &pio_rx_program);
|
||||||
|
_rxMap.insert({bits, new PIOProgram(p)});
|
||||||
|
f = _rxMap.find(bits);
|
||||||
|
}
|
||||||
|
return f->second;
|
||||||
|
}
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
static int __not_in_flash_func(_parity)(int data) {
|
||||||
|
data ^= data >> 4;
|
||||||
|
data &= 0xf;
|
||||||
|
return (0x6996 >> data) & 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We need to cache generated SerialPIOs so we can add data to them from
|
||||||
|
// the shared handler
|
||||||
|
static SerialPIO *_pioSP[3][4];
|
||||||
|
static void __not_in_flash_func(_fifoIRQ)() {
|
||||||
|
for (int p = 0; p < 3; p++) {
|
||||||
|
for (int sm = 0; sm < 4; sm++) {
|
||||||
|
SerialPIO *s = _pioSP[p][sm];
|
||||||
|
if (s) {
|
||||||
|
s->_handleIRQ();
|
||||||
|
pio_interrupt_clear((p == 0) ? pio0 : pio1, sm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void __not_in_flash_func(SerialPIO::_handleIRQ)() {
|
||||||
|
if (_rx == NOPIN) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (!pio_sm_is_rx_fifo_empty(_rxPIO, _rxSM)) {
|
||||||
|
uint32_t decode = _rxPIO->rxf[_rxSM];
|
||||||
|
uint32_t val = decode >> (32 - _rxBits - 1);
|
||||||
|
if (_parity == UART_PARITY_EVEN) {
|
||||||
|
int p = ::_parity(val);
|
||||||
|
int r = (val & (1 << _bits)) ? 1 : 0;
|
||||||
|
if (p != r) {
|
||||||
|
// TODO - parity error
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (_parity == UART_PARITY_ODD) {
|
||||||
|
int p = ::_parity(val);
|
||||||
|
int r = (val & (1 << _bits)) ? 1 : 0;
|
||||||
|
if (p == r) {
|
||||||
|
// TODO - parity error
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto next_writer = _writer + 1;
|
||||||
|
if (next_writer == _fifoSize) {
|
||||||
|
next_writer = 0;
|
||||||
|
}
|
||||||
|
if (next_writer != _reader) {
|
||||||
|
_queue[_writer] = val & ((1 << _bits) - 1);
|
||||||
|
asm volatile("" ::: "memory"); // Ensure the queue is written before the written count advances
|
||||||
|
_writer = next_writer;
|
||||||
|
} else {
|
||||||
|
_overflow = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SerialPIO::SerialPIO(pin_size_t tx, pin_size_t rx, size_t fifoSize) {
|
||||||
|
_tx = tx;
|
||||||
|
_rx = rx;
|
||||||
|
_fifoSize = fifoSize + 1; // Always one unused entry
|
||||||
|
_queue = new uint8_t[_fifoSize];
|
||||||
|
mutex_init(&_mutex);
|
||||||
|
_invertTX = false;
|
||||||
|
_invertRX = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SerialPIO::~SerialPIO() {
|
||||||
|
end();
|
||||||
|
delete[] _queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int pio_irq_0(PIO p) {
|
||||||
|
switch (pio_get_index(p)) {
|
||||||
|
case 0:
|
||||||
|
return PIO0_IRQ_0;
|
||||||
|
case 1:
|
||||||
|
return PIO1_IRQ_0;
|
||||||
|
#if defined(PICO_RP2350)
|
||||||
|
case 2:
|
||||||
|
return PIO2_IRQ_0;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialPIO::begin(unsigned long baud, uint16_t config) {
|
||||||
|
_overflow = false;
|
||||||
|
_baud = baud;
|
||||||
|
switch (config & SERIAL_PARITY_MASK) {
|
||||||
|
case SERIAL_PARITY_EVEN:
|
||||||
|
_parity = UART_PARITY_EVEN;
|
||||||
|
break;
|
||||||
|
case SERIAL_PARITY_ODD:
|
||||||
|
_parity = UART_PARITY_ODD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_parity = UART_PARITY_NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (config & SERIAL_STOP_BIT_MASK) {
|
||||||
|
case SERIAL_STOP_BIT_1:
|
||||||
|
_stop = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_stop = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (config & SERIAL_DATA_MASK) {
|
||||||
|
case SERIAL_DATA_5:
|
||||||
|
_bits = 5;
|
||||||
|
break;
|
||||||
|
case SERIAL_DATA_6:
|
||||||
|
_bits = 6;
|
||||||
|
break;
|
||||||
|
case SERIAL_DATA_7:
|
||||||
|
_bits = 7;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
_bits = 8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((_tx == NOPIN) && (_rx == NOPIN)) {
|
||||||
|
DEBUGCORE("ERROR: No pins specified for SerialPIO\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_tx != NOPIN) {
|
||||||
|
_txBits = _bits + _stop + (_parity != UART_PARITY_NONE ? 1 : 0) + 1/*start bit*/;
|
||||||
|
_txPgm = _getTxProgram(_txBits);
|
||||||
|
int off;
|
||||||
|
if (!_txPgm->prepare(&_txPIO, &_txSM, &off, _tx, 1)) {
|
||||||
|
DEBUGCORE("ERROR: Unable to allocate PIO TX UART, out of PIO resources\n");
|
||||||
|
// ERROR, no free slots
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
digitalWrite(_tx, HIGH);
|
||||||
|
pinMode(_tx, OUTPUT);
|
||||||
|
|
||||||
|
pio_tx_program_init(_txPIO, _txSM, off, _tx);
|
||||||
|
pio_sm_clear_fifos(_txPIO, _txSM); // Remove any existing data
|
||||||
|
|
||||||
|
// Put the divider into ISR w/o using up program space
|
||||||
|
pio_sm_put_blocking(_txPIO, _txSM, clock_get_hz(clk_sys) / _baud - 2);
|
||||||
|
pio_sm_exec(_txPIO, _txSM, pio_encode_pull(false, false));
|
||||||
|
pio_sm_exec(_txPIO, _txSM, pio_encode_mov(pio_isr, pio_osr));
|
||||||
|
|
||||||
|
// Start running!
|
||||||
|
gpio_set_outover(_tx, _invertTX);
|
||||||
|
pio_sm_set_enabled(_txPIO, _txSM, true);
|
||||||
|
}
|
||||||
|
if (_rx != NOPIN) {
|
||||||
|
_writer = 0;
|
||||||
|
_reader = 0;
|
||||||
|
|
||||||
|
_rxBits = _bits + (_parity != UART_PARITY_NONE ? 1 : 0);
|
||||||
|
_rxPgm = _getRxProgram(_rxBits);
|
||||||
|
int off;
|
||||||
|
if (!_rxPgm->prepare(&_rxPIO, &_rxSM, &off, _rx, 1)) {
|
||||||
|
DEBUGCORE("ERROR: Unable to allocate PIO RX UART, out of PIO resources\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Stash away the created RX port for the IRQ handler
|
||||||
|
_pioSP[pio_get_index(_rxPIO)][_rxSM] = this;
|
||||||
|
|
||||||
|
pinMode(_rx, INPUT);
|
||||||
|
pio_rx_program_init(_rxPIO, _rxSM, off, _rx);
|
||||||
|
pio_sm_clear_fifos(_rxPIO, _rxSM); // Remove any existing data
|
||||||
|
|
||||||
|
// Put phase divider into OSR w/o using add'l program memory
|
||||||
|
pio_sm_put_blocking(_rxPIO, _rxSM, clock_get_hz(clk_sys) / (_baud * 2) - 3);
|
||||||
|
pio_sm_exec(_rxPIO, _rxSM, pio_encode_pull(false, false));
|
||||||
|
|
||||||
|
// Join the TX FIFO to the RX one now that we don't need it
|
||||||
|
_rxPIO->sm[_rxSM].shiftctrl |= 0x80000000;
|
||||||
|
|
||||||
|
// Enable interrupts on rxfifo
|
||||||
|
switch (_rxSM) {
|
||||||
|
case 0: pio_set_irq0_source_enabled(_rxPIO, pis_sm0_rx_fifo_not_empty, true); break;
|
||||||
|
case 1: pio_set_irq0_source_enabled(_rxPIO, pis_sm1_rx_fifo_not_empty, true); break;
|
||||||
|
case 2: pio_set_irq0_source_enabled(_rxPIO, pis_sm2_rx_fifo_not_empty, true); break;
|
||||||
|
case 3: pio_set_irq0_source_enabled(_rxPIO, pis_sm3_rx_fifo_not_empty, true); break;
|
||||||
|
}
|
||||||
|
auto irqno = pio_irq_0(_rxPIO);
|
||||||
|
irq_set_exclusive_handler(irqno, _fifoIRQ);
|
||||||
|
irq_set_enabled(irqno, true);
|
||||||
|
|
||||||
|
gpio_set_inover(_rx, _invertRX);
|
||||||
|
pio_sm_set_enabled(_rxPIO, _rxSM, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
_running = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialPIO::end() {
|
||||||
|
if (!_running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (_tx != NOPIN) {
|
||||||
|
pio_sm_set_enabled(_txPIO, _txSM, false);
|
||||||
|
pio_sm_unclaim(_txPIO, _txSM);
|
||||||
|
gpio_set_outover(_tx, 0);
|
||||||
|
}
|
||||||
|
if (_rx != NOPIN) {
|
||||||
|
pio_sm_set_enabled(_rxPIO, _rxSM, false);
|
||||||
|
pio_sm_unclaim(_rxPIO, _rxSM);
|
||||||
|
_pioSP[pio_get_index(_rxPIO)][_rxSM] = nullptr;
|
||||||
|
// If no more active, disable the IRQ
|
||||||
|
auto pioNum = pio_get_index(_rxPIO);
|
||||||
|
bool used = false;
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
used = used || !!_pioSP[pioNum][i];
|
||||||
|
}
|
||||||
|
if (!used) {
|
||||||
|
auto irqno = pio_irq_0(_rxPIO);
|
||||||
|
irq_set_enabled(irqno, false);
|
||||||
|
}
|
||||||
|
gpio_set_inover(_rx, 0);
|
||||||
|
}
|
||||||
|
_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SerialPIO::peek() {
|
||||||
|
CoreMutex m(&_mutex);
|
||||||
|
if (!_running || !m || (_rx == NOPIN)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
// If there's something in the FIFO now, just peek at it
|
||||||
|
if (_writer != _reader) {
|
||||||
|
return _queue[_reader];
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SerialPIO::read() {
|
||||||
|
CoreMutex m(&_mutex);
|
||||||
|
if (!_running || !m || (_rx == NOPIN)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (_writer != _reader) {
|
||||||
|
auto ret = _queue[_reader];
|
||||||
|
asm volatile("" ::: "memory"); // Ensure the value is read before advancing
|
||||||
|
auto next_reader = (_reader + 1) % _fifoSize;
|
||||||
|
asm volatile("" ::: "memory"); // Ensure the reader value is only written once, correctly
|
||||||
|
_reader = next_reader;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SerialPIO::overflow() {
|
||||||
|
CoreMutex m(&_mutex);
|
||||||
|
if (!_running || !m || (_rx == NOPIN)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hold = _overflow;
|
||||||
|
_overflow = false;
|
||||||
|
return hold;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SerialPIO::available() {
|
||||||
|
CoreMutex m(&_mutex);
|
||||||
|
if (!_running || !m || (_rx == NOPIN)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (_writer - _reader) % _fifoSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SerialPIO::availableForWrite() {
|
||||||
|
CoreMutex m(&_mutex);
|
||||||
|
if (!_running || !m || (_tx == NOPIN)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 8 - pio_sm_get_tx_fifo_level(_txPIO, _txSM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialPIO::flush() {
|
||||||
|
CoreMutex m(&_mutex);
|
||||||
|
if (!_running || !m || (_tx == NOPIN)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (!pio_sm_is_tx_fifo_empty(_txPIO, _txSM)) {
|
||||||
|
delay(1); // Wait for all FIFO to be read
|
||||||
|
}
|
||||||
|
// Could have 1 byte being transmitted, so wait for bit times
|
||||||
|
delay((1000 * (_txBits + 1)) / _baud);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SerialPIO::write(uint8_t c) {
|
||||||
|
CoreMutex m(&_mutex);
|
||||||
|
if (!_running || !m || (_tx == NOPIN)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t val = c;
|
||||||
|
if (_parity == UART_PARITY_NONE) {
|
||||||
|
val |= 7 << _bits; // Set 2 stop bits, the HW will only transmit the required number
|
||||||
|
} else if (_parity == UART_PARITY_EVEN) {
|
||||||
|
val |= ::_parity(c) << _bits;
|
||||||
|
val |= 7 << (_bits + 1);
|
||||||
|
} else {
|
||||||
|
val |= (1 ^ ::_parity(c)) << _bits;
|
||||||
|
val |= 7 << (_bits + 1);
|
||||||
|
}
|
||||||
|
val <<= 1; // Start bit = low
|
||||||
|
|
||||||
|
pio_sm_put_blocking(_txPIO, _txSM, val);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
SerialPIO::operator bool() {
|
||||||
|
return _running;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ARDUINO_NANO_RP2040_CONNECT
|
||||||
|
// NINA updates
|
||||||
|
SerialPIO Serial3(SERIAL3_TX, SERIAL3_RX);
|
||||||
|
#endif
|
||||||
106
cores/rp2040/SerialPIO.h
Normal file
106
cores/rp2040/SerialPIO.h
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
Serial-over-PIO for the Raspberry Pi Pico RP2040
|
||||||
|
|
||||||
|
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include "api/HardwareSerial.h"
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <queue>
|
||||||
|
#include <hardware/uart.h>
|
||||||
|
#include "CoreMutex.h"
|
||||||
|
|
||||||
|
extern "C" typedef struct uart_inst uart_inst_t;
|
||||||
|
|
||||||
|
class SerialPIO : public arduino::HardwareSerial {
|
||||||
|
public:
|
||||||
|
static const pin_size_t NOPIN = 0xff; // Use in constructor to disable RX or TX unit
|
||||||
|
SerialPIO(pin_size_t tx, pin_size_t rx, size_t fifoSize = 32);
|
||||||
|
~SerialPIO();
|
||||||
|
|
||||||
|
void begin(unsigned long baud = 115200) override {
|
||||||
|
begin(baud, SERIAL_8N1);
|
||||||
|
};
|
||||||
|
void begin(unsigned long baud, uint16_t config) override;
|
||||||
|
void end() override;
|
||||||
|
|
||||||
|
void setInverted(bool invTx = true, bool invRx = true) {
|
||||||
|
setInvertTX(invTx);
|
||||||
|
setInvertRX(invRx);
|
||||||
|
}
|
||||||
|
bool setInvertTX(bool invert = true) {
|
||||||
|
if (!_running) {
|
||||||
|
_invertTX = invert;
|
||||||
|
}
|
||||||
|
return !_running;
|
||||||
|
}
|
||||||
|
bool setInvertRX(bool invert = true) {
|
||||||
|
if (!_running) {
|
||||||
|
_invertRX = invert;
|
||||||
|
}
|
||||||
|
return !_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int peek() override;
|
||||||
|
virtual int read() override;
|
||||||
|
virtual int available() override;
|
||||||
|
virtual int availableForWrite() override;
|
||||||
|
virtual void flush() override;
|
||||||
|
virtual size_t write(uint8_t c) override;
|
||||||
|
bool overflow();
|
||||||
|
using Print::write;
|
||||||
|
operator bool() override;
|
||||||
|
|
||||||
|
// Not to be called by users, only from the IRQ handler. In public so that the C-language IRQ callback can access it
|
||||||
|
void _handleIRQ();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool _running = false;
|
||||||
|
pin_size_t _tx, _rx;
|
||||||
|
int _baud;
|
||||||
|
int _bits;
|
||||||
|
uart_parity_t _parity;
|
||||||
|
int _stop;
|
||||||
|
bool _overflow;
|
||||||
|
mutex_t _mutex;
|
||||||
|
bool _invertTX;
|
||||||
|
bool _invertRX;
|
||||||
|
|
||||||
|
PIOProgram *_txPgm;
|
||||||
|
PIO _txPIO;
|
||||||
|
int _txSM;
|
||||||
|
int _txBits;
|
||||||
|
|
||||||
|
PIOProgram *_rxPgm;
|
||||||
|
PIO _rxPIO;
|
||||||
|
int _rxSM;
|
||||||
|
int _rxBits;
|
||||||
|
|
||||||
|
// Lockless, IRQ-handled circular queue
|
||||||
|
size_t _fifoSize;
|
||||||
|
uint32_t _writer;
|
||||||
|
uint32_t _reader;
|
||||||
|
uint8_t *_queue;
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef ARDUINO_NANO_RP2040_CONNECT
|
||||||
|
// NINA updates
|
||||||
|
extern SerialPIO Serial3;
|
||||||
|
#endif
|
||||||
98
cores/rp2040/SerialSemi.h
Normal file
98
cores/rp2040/SerialSemi.h
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
SerialSemi.h - Serial port over Semihosting for ARM
|
||||||
|
Copyright (c) 2024 Earle F. Philhower, III. All rights reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Semihosting.h"
|
||||||
|
|
||||||
|
#include "Arduino.h"
|
||||||
|
#include "api/HardwareSerial.h"
|
||||||
|
|
||||||
|
class SerialSemiClass : public arduino::HardwareSerial {
|
||||||
|
public:
|
||||||
|
SerialSemiClass() {
|
||||||
|
/* noop */
|
||||||
|
}
|
||||||
|
|
||||||
|
~SerialSemiClass() {
|
||||||
|
/* noop */
|
||||||
|
}
|
||||||
|
|
||||||
|
void begin(unsigned long baudIgnored = 115200) override {
|
||||||
|
(void)baudIgnored;
|
||||||
|
}
|
||||||
|
|
||||||
|
void begin(unsigned long baudIgnored, uint16_t configIgnored) override {
|
||||||
|
(void)baudIgnored;
|
||||||
|
(void)configIgnored;
|
||||||
|
}
|
||||||
|
|
||||||
|
void end() override {
|
||||||
|
/* noop */
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int peek() override {
|
||||||
|
// Can't really peek on SH, so fake it best we can
|
||||||
|
if (!_peeked) {
|
||||||
|
_peekedChar = read();
|
||||||
|
_peeked = true;
|
||||||
|
}
|
||||||
|
return _peekedChar;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int read() override {
|
||||||
|
if (_peeked) {
|
||||||
|
_peeked = false;
|
||||||
|
return _peekedChar;
|
||||||
|
}
|
||||||
|
return Semihost(SEMIHOST_SYS_READC, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int available() override {
|
||||||
|
// Can't really tell with SH, so always true. Buyer beware
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int availableForWrite() override {
|
||||||
|
// Can't really tell with SH, so always true. Buyer beware
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void flush() override {
|
||||||
|
/* noop */
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t write(uint8_t c) override {
|
||||||
|
int32_t param = c;
|
||||||
|
Semihost(SEMIHOST_SYS_WRITEC, ¶m);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
using Print::write;
|
||||||
|
|
||||||
|
operator bool() override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _peeked = false;
|
||||||
|
uint8_t _peekedChar;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern SerialSemiClass SerialSemi;
|
||||||
|
|
@ -1,22 +1,22 @@
|
||||||
/*
|
/*
|
||||||
* Serial-over-UART for the Raspberry Pi Pico RP2040
|
Serial-over-UART for the Raspberry Pi Pico RP2040
|
||||||
*
|
|
||||||
* Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "SerialUART.h"
|
#include "SerialUART.h"
|
||||||
#include "CoreMutex.h"
|
#include "CoreMutex.h"
|
||||||
|
|
@ -31,76 +31,321 @@
|
||||||
extern void serialEvent1() __attribute__((weak));
|
extern void serialEvent1() __attribute__((weak));
|
||||||
extern void serialEvent2() __attribute__((weak));
|
extern void serialEvent2() __attribute__((weak));
|
||||||
|
|
||||||
bool SerialUART::setRX(pin_size_t rx) {
|
bool SerialUART::setRX(pin_size_t pin) {
|
||||||
constexpr uint32_t valid[2] = { __bitset({1, 13, 17, 29}) /* UART0 */,
|
#if defined(PICO_RP2350) && !PICO_RP2350A // RP2350B
|
||||||
__bitset({5, 9, 21, 25}) /* UART1 */};
|
constexpr uint64_t valid[2] = { __bitset({1, 3, 13, 15, 17, 19, 29, 31, 33, 35, 45, 47}) /* UART0 */,
|
||||||
if (_running) {
|
__bitset({5, 7, 9, 11, 21, 23, 25, 27, 37, 39, 41, 43}) /* UART1 */
|
||||||
DEBUGCORE("ERROR: SerialUART setRX while running\n");
|
};
|
||||||
return false;
|
#elif defined(PICO_RP2350)
|
||||||
} else if ((1 << rx) & valid[uart_get_index(_uart)]) {
|
constexpr uint64_t valid[2] = { __bitset({1, 3, 13, 15, 17, 19, 29}) /* UART0 */,
|
||||||
_rx = rx;
|
__bitset({5, 7, 9, 11, 21, 23, 25, 27}) /* UART1 */
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
constexpr uint64_t valid[2] = { __bitset({1, 13, 17, 29}) /* UART0 */,
|
||||||
|
__bitset({5, 9, 21, 25}) /* UART1 */
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if ((!_running) && ((1LL << pin) & valid[uart_get_index(_uart)])) {
|
||||||
|
_rx = pin;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
DEBUGCORE("ERROR: SerialUART setRX illegal pin (%d)\n", rx);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_rx == pin) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_running) {
|
||||||
|
panic("FATAL: Attempting to set Serial%d.RX while running", uart_get_index(_uart) + 1);
|
||||||
|
} else {
|
||||||
|
panic("FATAL: Attempting to set Serial%d.RX to illegal pin %d", uart_get_index(_uart) + 1, pin);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SerialUART::setTX(pin_size_t tx) {
|
bool SerialUART::setTX(pin_size_t pin) {
|
||||||
constexpr uint32_t valid[2] = { __bitset({0, 12, 16, 28}) /* UART0 */,
|
#if defined(PICO_RP2350) && !PICO_RP2350A // RP2350B
|
||||||
__bitset({4, 8, 20, 24}) /* UART1 */};
|
constexpr uint64_t valid[2] = { __bitset({0, 2, 12, 14, 16, 18, 28, 30, 32, 34, 44, 46}) /* UART0 */,
|
||||||
if (_running) {
|
__bitset({4, 6, 8, 10, 20, 22, 24, 26, 36, 38, 40, 42}) /* UART1 */
|
||||||
DEBUGCORE("ERROR: SerialUART setTX while running\n");
|
};
|
||||||
return false;
|
#elif defined(PICO_RP2350)
|
||||||
} else if ((1 << tx) & valid[uart_get_index(_uart)]) {
|
constexpr uint64_t valid[2] = { __bitset({0, 2, 12, 14, 16, 18, 28}) /* UART0 */,
|
||||||
_tx = tx;
|
__bitset({4, 6, 8, 10, 20, 22, 24, 26}) /* UART1 */
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
constexpr uint64_t valid[2] = { __bitset({0, 12, 16, 28}) /* UART0 */,
|
||||||
|
__bitset({4, 8, 20, 24}) /* UART1 */
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
if ((!_running) && ((1LL << pin) & valid[uart_get_index(_uart)])) {
|
||||||
|
_tx = pin;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
|
||||||
DEBUGCORE("ERROR: SerialUART setTX illegal pin (%d)\n", tx);
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_tx == pin) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_running) {
|
||||||
|
panic("FATAL: Attempting to set Serial%d.TX while running", uart_get_index(_uart) + 1);
|
||||||
|
} else {
|
||||||
|
panic("FATAL: Attempting to set Serial%d.TX to illegal pin %d", uart_get_index(_uart) + 1, pin);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialUART::SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx) {
|
bool SerialUART::setRTS(pin_size_t pin) {
|
||||||
|
#if defined(PICO_RP2350) && !PICO_RP2350A // RP2350B
|
||||||
|
constexpr uint64_t valid[2] = { __bitset({3, 15, 19, 31, 35, 47}) /* UART0 */,
|
||||||
|
__bitset({7, 11, 23, 27, 39, 43}) /* UART1 */
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
constexpr uint64_t valid[2] = { __bitset({3, 15, 19}) /* UART0 */,
|
||||||
|
__bitset({7, 11, 23, 27}) /* UART1 */
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
if ((!_running) && ((pin == UART_PIN_NOT_DEFINED) || ((1LL << pin) & valid[uart_get_index(_uart)]))) {
|
||||||
|
_rts = pin;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_rts == pin) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_running) {
|
||||||
|
panic("FATAL: Attempting to set Serial%d.RTS while running", uart_get_index(_uart) + 1);
|
||||||
|
} else {
|
||||||
|
panic("FATAL: Attempting to set Serial%d.RTS to illegal pin %d", uart_get_index(_uart) + 1, pin);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SerialUART::setCTS(pin_size_t pin) {
|
||||||
|
#if defined(PICO_RP2350) && !PICO_RP2350A // RP2350B
|
||||||
|
constexpr uint64_t valid[2] = { __bitset({2, 14, 18, 30, 34, 46}) /* UART0 */,
|
||||||
|
__bitset({6, 10, 22, 26, 38, 42}) /* UART1 */
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
constexpr uint64_t valid[2] = { __bitset({2, 14, 18}) /* UART0 */,
|
||||||
|
__bitset({6, 10, 22, 26}) /* UART1 */
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
if ((!_running) && ((pin == UART_PIN_NOT_DEFINED) || ((1LL << pin) & valid[uart_get_index(_uart)]))) {
|
||||||
|
_cts = pin;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_cts == pin) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_running) {
|
||||||
|
panic("FATAL: Attempting to set Serial%d.CTS while running", uart_get_index(_uart) + 1);
|
||||||
|
} else {
|
||||||
|
panic("FATAL: Attempting to set Serial%d.CTS to illegal pin %d", uart_get_index(_uart) + 1, pin);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool SerialUART::setPollingMode(bool mode) {
|
||||||
|
if (_running) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_polling = mode;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SerialUART::setFIFOSize(size_t size) {
|
||||||
|
if (!size || _running) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_fifoSize = size + 1; // Always 1 unused entry
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
SerialUART::SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx, pin_size_t rts, pin_size_t cts) {
|
||||||
_uart = uart;
|
_uart = uart;
|
||||||
_tx = tx;
|
_tx = tx;
|
||||||
_rx = rx;
|
_rx = rx;
|
||||||
|
_rts = rts;
|
||||||
|
_cts = cts;
|
||||||
mutex_init(&_mutex);
|
mutex_init(&_mutex);
|
||||||
|
mutex_init(&_fifoMutex);
|
||||||
|
_invertTX = false;
|
||||||
|
_invertRX = false;
|
||||||
|
_invertControl = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void _uart0IRQ();
|
||||||
|
static void _uart1IRQ();
|
||||||
|
|
||||||
|
// Does the selected TX/RX need UART_AUX function (rp2350)
|
||||||
|
static gpio_function_t __gpioFunction(int pin) {
|
||||||
|
switch (pin) {
|
||||||
|
#if defined(PICO_RP2350) && !PICO_RP2350A
|
||||||
|
case 2:
|
||||||
|
case 3:
|
||||||
|
case 6:
|
||||||
|
case 7:
|
||||||
|
case 10:
|
||||||
|
case 11:
|
||||||
|
case 14:
|
||||||
|
case 15:
|
||||||
|
case 18:
|
||||||
|
case 19:
|
||||||
|
case 22:
|
||||||
|
case 23:
|
||||||
|
case 26:
|
||||||
|
case 27:
|
||||||
|
case 30:
|
||||||
|
case 31:
|
||||||
|
case 34:
|
||||||
|
case 35:
|
||||||
|
case 38:
|
||||||
|
case 39:
|
||||||
|
case 42:
|
||||||
|
case 43:
|
||||||
|
case 46:
|
||||||
|
case 47:
|
||||||
|
return GPIO_FUNC_UART_AUX;
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
return GPIO_FUNC_UART;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialUART::begin(unsigned long baud, uint16_t config) {
|
void SerialUART::begin(unsigned long baud, uint16_t config) {
|
||||||
|
if (_running) {
|
||||||
|
end();
|
||||||
|
}
|
||||||
|
_overflow = false;
|
||||||
|
_queue = new uint8_t[_fifoSize];
|
||||||
_baud = baud;
|
_baud = baud;
|
||||||
|
|
||||||
|
_fcnTx = gpio_get_function(_tx);
|
||||||
|
_fcnRx = gpio_get_function(_rx);
|
||||||
|
gpio_set_function(_tx, __gpioFunction(_tx));
|
||||||
|
gpio_set_outover(_tx, _invertTX ? 1 : 0);
|
||||||
|
gpio_set_function(_rx, __gpioFunction(_rx));
|
||||||
|
gpio_set_inover(_rx, _invertRX ? 1 : 0);
|
||||||
|
if (_rts != UART_PIN_NOT_DEFINED) {
|
||||||
|
_fcnRts = gpio_get_function(_rts);
|
||||||
|
gpio_set_function(_rts, GPIO_FUNC_UART);
|
||||||
|
gpio_set_outover(_rts, _invertControl ? 1 : 0);
|
||||||
|
}
|
||||||
|
if (_cts != UART_PIN_NOT_DEFINED) {
|
||||||
|
_fcnCts = gpio_get_function(_cts);
|
||||||
|
gpio_set_function(_cts, GPIO_FUNC_UART);
|
||||||
|
gpio_set_inover(_cts, _invertControl ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
uart_init(_uart, baud);
|
uart_init(_uart, baud);
|
||||||
int bits, stop;
|
int bits, stop;
|
||||||
uart_parity_t parity;
|
uart_parity_t parity;
|
||||||
switch (config & SERIAL_PARITY_MASK) {
|
switch (config & SERIAL_PARITY_MASK) {
|
||||||
case SERIAL_PARITY_EVEN: parity = UART_PARITY_EVEN; break;
|
case SERIAL_PARITY_EVEN:
|
||||||
case SERIAL_PARITY_ODD: parity = UART_PARITY_ODD; break;
|
parity = UART_PARITY_EVEN;
|
||||||
default: parity = UART_PARITY_NONE; break;
|
break;
|
||||||
|
case SERIAL_PARITY_ODD:
|
||||||
|
parity = UART_PARITY_ODD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
parity = UART_PARITY_NONE;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
switch ( config & SERIAL_STOP_BIT_MASK) {
|
switch (config & SERIAL_STOP_BIT_MASK) {
|
||||||
case SERIAL_STOP_BIT_1: stop = 1; break;
|
case SERIAL_STOP_BIT_1:
|
||||||
default: stop = 2; break;
|
stop = 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
stop = 2;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
switch (config & SERIAL_DATA_MASK) {
|
switch (config & SERIAL_DATA_MASK) {
|
||||||
case SERIAL_DATA_5: bits = 5; break;
|
case SERIAL_DATA_5:
|
||||||
case SERIAL_DATA_6: bits = 6; break;
|
bits = 5;
|
||||||
case SERIAL_DATA_7: bits = 7; break;
|
break;
|
||||||
default: bits = 8; break;
|
case SERIAL_DATA_6:
|
||||||
|
bits = 6;
|
||||||
|
break;
|
||||||
|
case SERIAL_DATA_7:
|
||||||
|
bits = 7;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
bits = 8;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
uart_set_format(_uart, bits, stop, parity);
|
uart_set_format(_uart, bits, stop, parity);
|
||||||
gpio_set_function(_tx, GPIO_FUNC_UART);
|
uart_set_hw_flow(_uart, _cts != UART_PIN_NOT_DEFINED, _rts != UART_PIN_NOT_DEFINED);
|
||||||
gpio_set_function(_rx, GPIO_FUNC_UART);
|
_writer = 0;
|
||||||
|
_reader = 0;
|
||||||
|
|
||||||
|
if (!_polling) {
|
||||||
|
if (_uart == uart0) {
|
||||||
|
irq_set_exclusive_handler(UART0_IRQ, _uart0IRQ);
|
||||||
|
irq_set_enabled(UART0_IRQ, true);
|
||||||
|
} else {
|
||||||
|
irq_set_exclusive_handler(UART1_IRQ, _uart1IRQ);
|
||||||
|
irq_set_enabled(UART1_IRQ, true);
|
||||||
|
}
|
||||||
|
// Set the IRQ enables and FIFO level to minimum
|
||||||
|
uart_set_irq_enables(_uart, true, false);
|
||||||
|
} else {
|
||||||
|
// Polling mode has no IRQs used
|
||||||
|
}
|
||||||
|
_break = false;
|
||||||
_running = true;
|
_running = true;
|
||||||
_peek = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialUART::end() {
|
void SerialUART::end() {
|
||||||
if (!_running) {
|
if (!_running) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uart_deinit(_uart);
|
|
||||||
_running = false;
|
_running = false;
|
||||||
|
if (!_polling) {
|
||||||
|
if (_uart == uart0) {
|
||||||
|
irq_set_enabled(UART0_IRQ, false);
|
||||||
|
} else {
|
||||||
|
irq_set_enabled(UART1_IRQ, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paranoia - ensure nobody else is using anything here at the same time
|
||||||
|
mutex_enter_blocking(&_mutex);
|
||||||
|
mutex_enter_blocking(&_fifoMutex);
|
||||||
|
uart_deinit(_uart);
|
||||||
|
delete[] _queue;
|
||||||
|
// Reset the mutexes once all is off/cleaned up
|
||||||
|
mutex_exit(&_fifoMutex);
|
||||||
|
mutex_exit(&_mutex);
|
||||||
|
|
||||||
|
// Restore pin functions
|
||||||
|
gpio_set_function(_tx, _fcnTx);
|
||||||
|
gpio_set_outover(_tx, 0);
|
||||||
|
gpio_set_function(_rx, _fcnRx);
|
||||||
|
gpio_set_inover(_rx, 0);
|
||||||
|
if (_rts != UART_PIN_NOT_DEFINED) {
|
||||||
|
gpio_set_function(_rts, _fcnRts);
|
||||||
|
gpio_set_outover(_rts, 0);
|
||||||
|
}
|
||||||
|
if (_cts != UART_PIN_NOT_DEFINED) {
|
||||||
|
gpio_set_function(_cts, _fcnCts);
|
||||||
|
gpio_set_inover(_cts, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SerialUART::_pumpFIFO() {
|
||||||
|
// Use the _fifoMutex to guard against the other core potentially
|
||||||
|
// running the IRQ (since we can't disable their IRQ handler).
|
||||||
|
// We guard against this core by disabling the IRQ handler and
|
||||||
|
// re-enabling if it was previously enabled at the end.
|
||||||
|
auto irqno = (_uart == uart0) ? UART0_IRQ : UART1_IRQ;
|
||||||
|
bool enabled = irq_is_enabled(irqno);
|
||||||
|
irq_set_enabled(irqno, false);
|
||||||
|
mutex_enter_blocking(&_fifoMutex);
|
||||||
|
_handleIRQ(false);
|
||||||
|
mutex_exit(&_fifoMutex);
|
||||||
|
irq_set_enabled(irqno, enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
int SerialUART::peek() {
|
int SerialUART::peek() {
|
||||||
|
|
@ -108,11 +353,15 @@ int SerialUART::peek() {
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (_peek >= 0) {
|
if (_polling) {
|
||||||
return _peek;
|
_handleIRQ(false);
|
||||||
|
} else {
|
||||||
|
_pumpFIFO();
|
||||||
}
|
}
|
||||||
_peek = uart_getc(_uart);
|
if (_writer != _reader) {
|
||||||
return _peek;
|
return _queue[_reader];
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SerialUART::read() {
|
int SerialUART::read() {
|
||||||
|
|
@ -120,12 +369,39 @@ int SerialUART::read() {
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (_peek >= 0) {
|
if (_polling) {
|
||||||
int ret = _peek;
|
_handleIRQ(false);
|
||||||
_peek = -1;
|
} else {
|
||||||
|
_pumpFIFO();
|
||||||
|
}
|
||||||
|
if (_writer != _reader) {
|
||||||
|
auto ret = _queue[_reader];
|
||||||
|
asm volatile("" ::: "memory"); // Ensure the value is read before advancing
|
||||||
|
auto next_reader = (_reader + 1) % _fifoSize;
|
||||||
|
asm volatile("" ::: "memory"); // Ensure the reader value is only written once, correctly
|
||||||
|
_reader = next_reader;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
return uart_getc(_uart);
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SerialUART::overflow() {
|
||||||
|
if (!_running) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_polling) {
|
||||||
|
_handleIRQ(false);
|
||||||
|
} else {
|
||||||
|
_pumpFIFO();
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_enter_blocking(&_fifoMutex);
|
||||||
|
bool ovf = _overflow;
|
||||||
|
_overflow = false;
|
||||||
|
mutex_exit(&_fifoMutex);
|
||||||
|
|
||||||
|
return ovf;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SerialUART::available() {
|
int SerialUART::available() {
|
||||||
|
|
@ -133,7 +409,12 @@ int SerialUART::available() {
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return (uart_is_readable(_uart)) ? 1 : 0;
|
if (_polling) {
|
||||||
|
_handleIRQ(false);
|
||||||
|
} else {
|
||||||
|
_pumpFIFO();
|
||||||
|
}
|
||||||
|
return (_fifoSize + _writer - _reader) % _fifoSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SerialUART::availableForWrite() {
|
int SerialUART::availableForWrite() {
|
||||||
|
|
@ -141,6 +422,9 @@ int SerialUART::availableForWrite() {
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (_polling) {
|
||||||
|
_handleIRQ(false);
|
||||||
|
}
|
||||||
return (uart_is_writable(_uart)) ? 1 : 0;
|
return (uart_is_writable(_uart)) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -149,7 +433,10 @@ void SerialUART::flush() {
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
uart_default_tx_wait_blocking();
|
if (_polling) {
|
||||||
|
_handleIRQ(false);
|
||||||
|
}
|
||||||
|
uart_tx_wait_blocking(_uart);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t SerialUART::write(uint8_t c) {
|
size_t SerialUART::write(uint8_t c) {
|
||||||
|
|
@ -157,6 +444,9 @@ size_t SerialUART::write(uint8_t c) {
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (_polling) {
|
||||||
|
_handleIRQ(false);
|
||||||
|
}
|
||||||
uart_putc_raw(_uart, c);
|
uart_putc_raw(_uart, c);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -166,6 +456,9 @@ size_t SerialUART::write(const uint8_t *p, size_t len) {
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if (_polling) {
|
||||||
|
_handleIRQ(false);
|
||||||
|
}
|
||||||
size_t cnt = len;
|
size_t cnt = len;
|
||||||
while (cnt) {
|
while (cnt) {
|
||||||
uart_putc_raw(_uart, *p);
|
uart_putc_raw(_uart, *p);
|
||||||
|
|
@ -179,17 +472,110 @@ SerialUART::operator bool() {
|
||||||
return _running;
|
return _running;
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialUART Serial1(uart0, PIN_SERIAL1_TX, PIN_SERIAL1_RX);
|
bool SerialUART::getBreakReceived() {
|
||||||
SerialUART Serial2(uart1, PIN_SERIAL2_TX, PIN_SERIAL2_RX);
|
if (!_running) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_polling) {
|
||||||
|
_handleIRQ(false);
|
||||||
|
} else {
|
||||||
|
_pumpFIFO();
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_enter_blocking(&_fifoMutex);
|
||||||
|
bool break_received = _break;
|
||||||
|
_break = false;
|
||||||
|
mutex_exit(&_fifoMutex);
|
||||||
|
|
||||||
|
return break_received;
|
||||||
|
}
|
||||||
|
|
||||||
void arduino::serialEvent1Run(void) {
|
void arduino::serialEvent1Run(void) {
|
||||||
if (serialEvent1 && Serial1.available()) {
|
if (serialEvent1 && Serial1.available()) {
|
||||||
serialEvent1();
|
serialEvent1();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void arduino::serialEvent2Run(void) {
|
void arduino::serialEvent2Run(void) {
|
||||||
if (serialEvent2 && Serial2.available()) {
|
if (serialEvent2 && Serial2.available()) {
|
||||||
serialEvent2();
|
serialEvent2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IRQ handler, called when FIFO > 1/8 full or when it had held unread data for >32 bit times
|
||||||
|
void __not_in_flash_func(SerialUART::_handleIRQ)(bool inIRQ) {
|
||||||
|
if (inIRQ) {
|
||||||
|
uint32_t owner;
|
||||||
|
if (!mutex_try_enter(&_fifoMutex, &owner)) {
|
||||||
|
// Main app on the other core has the mutex so it is
|
||||||
|
// in the process of pulling data out of the HW FIFO
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ICR is write-to-clear
|
||||||
|
uart_get_hw(_uart)->icr = UART_UARTICR_RTIC_BITS | UART_UARTICR_RXIC_BITS;
|
||||||
|
while (uart_is_readable(_uart)) {
|
||||||
|
uint32_t raw = uart_get_hw(_uart)->dr;
|
||||||
|
if (raw & 0x400) {
|
||||||
|
// break!
|
||||||
|
_break = true;
|
||||||
|
continue;
|
||||||
|
} else if (raw & 0x300) {
|
||||||
|
// Framing, Parity Error. Ignore this bad char
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
uint8_t val = raw & 0xff;
|
||||||
|
auto next_writer = _writer + 1;
|
||||||
|
if (next_writer == _fifoSize) {
|
||||||
|
next_writer = 0;
|
||||||
|
}
|
||||||
|
if (next_writer != _reader) {
|
||||||
|
_queue[_writer] = val;
|
||||||
|
asm volatile("" ::: "memory"); // Ensure the queue is written before the written count advances
|
||||||
|
// Avoid using division or mod because the HW divider could be in use
|
||||||
|
_writer = next_writer;
|
||||||
|
} else {
|
||||||
|
_overflow = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (inIRQ) {
|
||||||
|
mutex_exit(&_fifoMutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef __SERIAL1_DEVICE
|
||||||
|
#define __SERIAL1_DEVICE uart0
|
||||||
|
#endif
|
||||||
|
#ifndef __SERIAL2_DEVICE
|
||||||
|
#define __SERIAL2_DEVICE uart1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PIN_SERIAL1_RTS)
|
||||||
|
SerialUART Serial1(__SERIAL1_DEVICE, PIN_SERIAL1_TX, PIN_SERIAL1_RX, PIN_SERIAL1_RTS, PIN_SERIAL1_CTS);
|
||||||
|
#else
|
||||||
|
SerialUART Serial1(__SERIAL1_DEVICE, PIN_SERIAL1_TX, PIN_SERIAL1_RX);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(PIN_SERIAL2_RTS)
|
||||||
|
SerialUART Serial2(__SERIAL2_DEVICE, PIN_SERIAL2_TX, PIN_SERIAL2_RX, PIN_SERIAL2_RTS, PIN_SERIAL2_CTS);
|
||||||
|
#else
|
||||||
|
SerialUART Serial2(__SERIAL2_DEVICE, PIN_SERIAL2_TX, PIN_SERIAL2_RX);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
static void __not_in_flash_func(_uart0IRQ)() {
|
||||||
|
if (__SERIAL1_DEVICE == uart0) {
|
||||||
|
Serial1._handleIRQ();
|
||||||
|
} else {
|
||||||
|
Serial2._handleIRQ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __not_in_flash_func(_uart1IRQ)() {
|
||||||
|
if (__SERIAL2_DEVICE == uart1) {
|
||||||
|
Serial2._handleIRQ();
|
||||||
|
} else {
|
||||||
|
Serial1._handleIRQ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,42 +1,74 @@
|
||||||
/*
|
/*
|
||||||
* Serial-over-UART for the Raspberry Pi Pico RP2040
|
Serial-over-UART for the Raspberry Pi Pico RP2040
|
||||||
*
|
|
||||||
* Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "api/HardwareSerial.h"
|
#include "api/HardwareSerial.h"
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <queue>
|
||||||
#include "CoreMutex.h"
|
#include "CoreMutex.h"
|
||||||
|
|
||||||
extern "C" typedef struct uart_inst uart_inst_t;
|
extern "C" typedef struct uart_inst uart_inst_t;
|
||||||
|
|
||||||
class SerialUART : public HardwareSerial {
|
#define UART_PIN_NOT_DEFINED (255u)
|
||||||
|
class SerialUART : public arduino::HardwareSerial {
|
||||||
public:
|
public:
|
||||||
SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx);
|
SerialUART(uart_inst_t *uart, pin_size_t tx, pin_size_t rx, pin_size_t rts = UART_PIN_NOT_DEFINED, pin_size_t cts = UART_PIN_NOT_DEFINED);
|
||||||
|
|
||||||
// Select the pinout. Call before .begin()
|
// Select the pinout. Call before .begin()
|
||||||
bool setRX(pin_size_t pin);
|
bool setRX(pin_size_t pin);
|
||||||
bool setTX(pin_size_t pin);
|
bool setTX(pin_size_t pin);
|
||||||
bool setPinout(pin_size_t tx, pin_size_t rx) { bool ret = setRX(rx); ret &= setTX(tx); return ret; }
|
bool setRTS(pin_size_t pin);
|
||||||
|
bool setCTS(pin_size_t pin);
|
||||||
|
bool setPinout(pin_size_t tx, pin_size_t rx) {
|
||||||
|
bool ret = setRX(rx);
|
||||||
|
ret &= setTX(tx);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
void begin(unsigned long baud = 115200) override { begin(baud, SERIAL_8N1); };
|
bool setInvertTX(bool invert = true) {
|
||||||
|
if (!_running) {
|
||||||
|
_invertTX = invert;
|
||||||
|
}
|
||||||
|
return !_running;
|
||||||
|
}
|
||||||
|
bool setInvertRX(bool invert = true) {
|
||||||
|
if (!_running) {
|
||||||
|
_invertRX = invert;
|
||||||
|
}
|
||||||
|
return !_running;
|
||||||
|
}
|
||||||
|
bool setInvertControl(bool invert = true) {
|
||||||
|
if (!_running) {
|
||||||
|
_invertControl = invert;
|
||||||
|
}
|
||||||
|
return !_running;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool setFIFOSize(size_t size);
|
||||||
|
bool setPollingMode(bool mode = true);
|
||||||
|
|
||||||
|
void begin(unsigned long baud = 115200) override {
|
||||||
|
begin(baud, SERIAL_8N1);
|
||||||
|
};
|
||||||
void begin(unsigned long baud, uint16_t config) override;
|
void begin(unsigned long baud, uint16_t config) override;
|
||||||
void end() override;
|
void end() override;
|
||||||
|
|
||||||
|
|
@ -48,21 +80,47 @@ public:
|
||||||
virtual size_t write(uint8_t c) override;
|
virtual size_t write(uint8_t c) override;
|
||||||
virtual size_t write(const uint8_t *p, size_t len) override;
|
virtual size_t write(const uint8_t *p, size_t len) override;
|
||||||
using Print::write;
|
using Print::write;
|
||||||
|
bool overflow();
|
||||||
operator bool() override;
|
operator bool() override;
|
||||||
|
|
||||||
|
// ESP8266 compat
|
||||||
|
void setDebugOutput(bool unused) {
|
||||||
|
(void) unused;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not to be called by users, only from the IRQ handler. In public so that the C-language IQR callback can access it
|
||||||
|
void _handleIRQ(bool inIRQ = true);
|
||||||
|
|
||||||
|
// Allows the user to sleep until a break is received (self-clears the flag
|
||||||
|
// on read)
|
||||||
|
bool getBreakReceived();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _running = false;
|
bool _running = false;
|
||||||
uart_inst_t *_uart;
|
uart_inst_t *_uart;
|
||||||
pin_size_t _tx, _rx;
|
pin_size_t _tx, _rx;
|
||||||
|
pin_size_t _rts, _cts;
|
||||||
|
gpio_function_t _fcnTx, _fcnRx, _fcnRts, _fcnCts;
|
||||||
int _baud;
|
int _baud;
|
||||||
int _peek;
|
|
||||||
mutex_t _mutex;
|
mutex_t _mutex;
|
||||||
|
bool _polling = false;
|
||||||
|
bool _overflow;
|
||||||
|
bool _break;
|
||||||
|
bool _invertTX, _invertRX, _invertControl;
|
||||||
|
|
||||||
|
// Lockless, IRQ-handled circular queue
|
||||||
|
uint32_t _writer;
|
||||||
|
uint32_t _reader;
|
||||||
|
size_t _fifoSize = 32;
|
||||||
|
uint8_t *_queue;
|
||||||
|
mutex_t _fifoMutex; // Only needed when non-IRQ updates _writer
|
||||||
|
void _pumpFIFO(); // User space FIFO transfer
|
||||||
};
|
};
|
||||||
|
|
||||||
extern SerialUART Serial1; // HW UART 0
|
extern SerialUART Serial1; // HW UART 0
|
||||||
extern SerialUART Serial2; // HW UART 1
|
extern SerialUART Serial2; // HW UART 1
|
||||||
|
|
||||||
namespace arduino {
|
namespace arduino {
|
||||||
extern void serialEvent1Run(void) __attribute__((weak));
|
extern void serialEvent1Run(void) __attribute__((weak));
|
||||||
extern void serialEvent2Run(void) __attribute__((weak));
|
extern void serialEvent2Run(void) __attribute__((weak));
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,36 +1,44 @@
|
||||||
/*
|
/*
|
||||||
* Serial-Over-USB for the Raspberry Pi Pico RP2040
|
Serial-Over-USB for the Raspberry Pi Pico RP2040
|
||||||
* Implements an ACM which will reboot into UF2 mode on a 1200bps DTR toggle.
|
Implements an ACM which will reboot into UF2 mode on a 1200bps DTR toggle.
|
||||||
* Much of this was modified from the Raspberry Pi Pico SDK stdio_usb.c file.
|
Much of this was modified from the Raspberry Pi Pico SDK stdio_usb.c file.
|
||||||
*
|
|
||||||
* Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#if !defined(USE_TINYUSB) && !defined(NO_USB)
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "CoreMutex.h"
|
#include "CoreMutex.h"
|
||||||
|
|
||||||
#include "tusb.h"
|
#include <tusb.h>
|
||||||
#include "pico/time.h"
|
#include <pico/time.h>
|
||||||
#include "pico/binary_info.h"
|
#include <pico/binary_info.h>
|
||||||
#include "pico/bootrom.h"
|
#include <pico/bootrom.h>
|
||||||
#include "hardware/irq.h"
|
#include <hardware/irq.h>
|
||||||
#include "pico/mutex.h"
|
#include <pico/mutex.h>
|
||||||
#include "hardware/watchdog.h"
|
#include <hardware/watchdog.h>
|
||||||
#include "pico/unique_id.h"
|
#include <pico/unique_id.h>
|
||||||
|
#include <hardware/resets.h>
|
||||||
|
|
||||||
|
#ifndef DISABLE_USB_SERIAL
|
||||||
|
// Ensure we are installed in the USB chain
|
||||||
|
void __USBInstallSerial() { /* noop */ }
|
||||||
|
#endif
|
||||||
|
|
||||||
// SerialEvent functions are weak, so when the user doesn't define them,
|
// SerialEvent functions are weak, so when the user doesn't define them,
|
||||||
// the linker just sets their address to 0 (which is checked below).
|
// the linker just sets their address to 0 (which is checked below).
|
||||||
|
|
@ -39,121 +47,8 @@
|
||||||
// HardwareSerial instance if the user doesn't also refer to it.
|
// HardwareSerial instance if the user doesn't also refer to it.
|
||||||
extern void serialEvent() __attribute__((weak));
|
extern void serialEvent() __attribute__((weak));
|
||||||
|
|
||||||
#define PICO_STDIO_USB_TASK_INTERVAL_US 1000
|
|
||||||
#define PICO_STDIO_USB_LOW_PRIORITY_IRQ 31
|
|
||||||
|
|
||||||
#define USBD_VID (0x2E8A) // Raspberry Pi
|
extern mutex_t __usb_mutex;
|
||||||
|
|
||||||
#ifdef SERIALUSB_PID
|
|
||||||
#define USBD_PID (SERIALUSB_PID)
|
|
||||||
#else
|
|
||||||
#define USBD_PID (0x000a) // Raspberry Pi Pico SDK CDC
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define USBD_DESC_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN)
|
|
||||||
#define USBD_MAX_POWER_MA (250)
|
|
||||||
|
|
||||||
#define USBD_ITF_CDC (0) // needs 2 interfaces
|
|
||||||
#define USBD_ITF_MAX (2)
|
|
||||||
|
|
||||||
#define USBD_CDC_EP_CMD (0x81)
|
|
||||||
#define USBD_CDC_EP_OUT (0x02)
|
|
||||||
#define USBD_CDC_EP_IN (0x82)
|
|
||||||
#define USBD_CDC_CMD_MAX_SIZE (8)
|
|
||||||
#define USBD_CDC_IN_OUT_MAX_SIZE (64)
|
|
||||||
|
|
||||||
#define USBD_STR_0 (0x00)
|
|
||||||
#define USBD_STR_MANUF (0x01)
|
|
||||||
#define USBD_STR_PRODUCT (0x02)
|
|
||||||
#define USBD_STR_SERIAL (0x03)
|
|
||||||
#define USBD_STR_CDC (0x04)
|
|
||||||
|
|
||||||
// Note: descriptors returned from callbacks must exist long enough for transfer to complete
|
|
||||||
|
|
||||||
static const tusb_desc_device_t usbd_desc_device = {
|
|
||||||
.bLength = sizeof(tusb_desc_device_t),
|
|
||||||
.bDescriptorType = TUSB_DESC_DEVICE,
|
|
||||||
.bcdUSB = 0x0200,
|
|
||||||
.bDeviceClass = TUSB_CLASS_CDC,
|
|
||||||
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
|
|
||||||
.bDeviceProtocol = MISC_PROTOCOL_IAD,
|
|
||||||
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
|
|
||||||
.idVendor = USBD_VID,
|
|
||||||
.idProduct = USBD_PID,
|
|
||||||
.bcdDevice = 0x0100,
|
|
||||||
.iManufacturer = USBD_STR_MANUF,
|
|
||||||
.iProduct = USBD_STR_PRODUCT,
|
|
||||||
.iSerialNumber = USBD_STR_SERIAL,
|
|
||||||
.bNumConfigurations = 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
static const uint8_t usbd_desc_cfg[USBD_DESC_LEN] = {
|
|
||||||
TUD_CONFIG_DESCRIPTOR(1, USBD_ITF_MAX, USBD_STR_0, USBD_DESC_LEN,
|
|
||||||
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, USBD_MAX_POWER_MA),
|
|
||||||
|
|
||||||
TUD_CDC_DESCRIPTOR(USBD_ITF_CDC, USBD_STR_CDC, USBD_CDC_EP_CMD,
|
|
||||||
USBD_CDC_CMD_MAX_SIZE, USBD_CDC_EP_OUT, USBD_CDC_EP_IN, USBD_CDC_IN_OUT_MAX_SIZE),
|
|
||||||
};
|
|
||||||
|
|
||||||
static char _idString[PICO_UNIQUE_BOARD_ID_SIZE_BYTES * 2 + 1];
|
|
||||||
|
|
||||||
static const char *const usbd_desc_str[] = {
|
|
||||||
[USBD_STR_0] = "",
|
|
||||||
[USBD_STR_MANUF] = "Raspberry Pi",
|
|
||||||
[USBD_STR_PRODUCT] = "PicoArduino",
|
|
||||||
[USBD_STR_SERIAL] = _idString,
|
|
||||||
[USBD_STR_CDC] = "Board CDC",
|
|
||||||
};
|
|
||||||
|
|
||||||
const uint8_t *tud_descriptor_device_cb(void) {
|
|
||||||
return (const uint8_t *)&usbd_desc_device;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t *tud_descriptor_configuration_cb(uint8_t index) {
|
|
||||||
(void)index;
|
|
||||||
return usbd_desc_cfg;
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint16_t *tud_descriptor_string_cb(uint8_t index, uint16_t langid) {
|
|
||||||
#define DESC_STR_MAX (20)
|
|
||||||
static uint16_t desc_str[DESC_STR_MAX];
|
|
||||||
|
|
||||||
uint8_t len;
|
|
||||||
if (index == 0) {
|
|
||||||
desc_str[1] = 0x0409; // supported language is English
|
|
||||||
len = 1;
|
|
||||||
} else {
|
|
||||||
if (index >= sizeof(usbd_desc_str) / sizeof(usbd_desc_str[0])) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
const char *str = usbd_desc_str[index];
|
|
||||||
for (len = 0; len < DESC_STR_MAX - 1 && str[len]; ++len) {
|
|
||||||
desc_str[1 + len] = str[len];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// first byte is length (including header), second byte is string type
|
|
||||||
desc_str[0] = (TUSB_DESC_STRING << 8) | (2 * len + 2);
|
|
||||||
|
|
||||||
return desc_str;
|
|
||||||
}
|
|
||||||
|
|
||||||
static mutex_t usb_mutex;
|
|
||||||
|
|
||||||
static void low_priority_worker_irq() {
|
|
||||||
// if the mutex is already owned, then we are in user code
|
|
||||||
// in this file which will do a tud_task itself, so we'll just do nothing
|
|
||||||
// until the next tick; we won't starve
|
|
||||||
if (mutex_try_enter(&usb_mutex, NULL)) {
|
|
||||||
tud_task();
|
|
||||||
mutex_exit(&usb_mutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int64_t timer_task(__unused alarm_id_t id, __unused void *user_data) {
|
|
||||||
irq_set_pending(PICO_STDIO_USB_LOW_PRIORITY_IRQ);
|
|
||||||
return PICO_STDIO_USB_TASK_INTERVAL_US;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SerialUSB::begin(unsigned long baud) {
|
void SerialUSB::begin(unsigned long baud) {
|
||||||
(void) baud; //ignored
|
(void) baud; //ignored
|
||||||
|
|
@ -162,24 +57,6 @@ void SerialUSB::begin(unsigned long baud) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get ID string into human readable serial number
|
|
||||||
pico_unique_board_id_t id;
|
|
||||||
pico_get_unique_board_id(&id);
|
|
||||||
_idString[0] = 0;
|
|
||||||
for (auto i = 0; i < PICO_UNIQUE_BOARD_ID_SIZE_BYTES; i++) {
|
|
||||||
char hx[3];
|
|
||||||
sprintf(hx, "%02X", id.id[i]);
|
|
||||||
strcat(_idString, hx);
|
|
||||||
}
|
|
||||||
|
|
||||||
tusb_init();
|
|
||||||
|
|
||||||
irq_set_exclusive_handler(PICO_STDIO_USB_LOW_PRIORITY_IRQ, low_priority_worker_irq);
|
|
||||||
irq_set_enabled(PICO_STDIO_USB_LOW_PRIORITY_IRQ, true);
|
|
||||||
|
|
||||||
mutex_init(&usb_mutex);
|
|
||||||
add_alarm_in_us(PICO_STDIO_USB_TASK_INTERVAL_US, timer_task, NULL, true);
|
|
||||||
|
|
||||||
_running = true;
|
_running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -188,52 +65,57 @@ void SerialUSB::end() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int SerialUSB::peek() {
|
int SerialUSB::peek() {
|
||||||
CoreMutex m(&usb_mutex);
|
CoreMutex m(&__usb_mutex, false);
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t c;
|
uint8_t c;
|
||||||
return tud_cdc_peek(0, &c) ? (int) c : -1;
|
tud_task();
|
||||||
|
return tud_cdc_peek(&c) ? (int) c : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SerialUSB::read() {
|
int SerialUSB::read() {
|
||||||
CoreMutex m(&usb_mutex);
|
CoreMutex m(&__usb_mutex, false);
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tud_cdc_connected() && tud_cdc_available()) {
|
tud_task();
|
||||||
|
if (tud_cdc_available()) {
|
||||||
return tud_cdc_read_char();
|
return tud_cdc_read_char();
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int SerialUSB::available() {
|
int SerialUSB::available() {
|
||||||
CoreMutex m(&usb_mutex);
|
CoreMutex m(&__usb_mutex, false);
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tud_task();
|
||||||
return tud_cdc_available();
|
return tud_cdc_available();
|
||||||
}
|
}
|
||||||
|
|
||||||
int SerialUSB::availableForWrite() {
|
int SerialUSB::availableForWrite() {
|
||||||
CoreMutex m(&usb_mutex);
|
CoreMutex m(&__usb_mutex, false);
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tud_task();
|
||||||
return tud_cdc_write_available();
|
return tud_cdc_write_available();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SerialUSB::flush() {
|
void SerialUSB::flush() {
|
||||||
CoreMutex m(&usb_mutex);
|
CoreMutex m(&__usb_mutex, false);
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
tud_cdc_write_flush();
|
tud_cdc_write_flush();
|
||||||
|
tud_task();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t SerialUSB::write(uint8_t c) {
|
size_t SerialUSB::write(uint8_t c) {
|
||||||
|
|
@ -241,29 +123,32 @@ size_t SerialUSB::write(uint8_t c) {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t SerialUSB::write(const uint8_t *buf, size_t length) {
|
size_t SerialUSB::write(const uint8_t *buf, size_t length) {
|
||||||
CoreMutex m(&usb_mutex);
|
CoreMutex m(&__usb_mutex, false);
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t last_avail_time;
|
static uint64_t last_avail_time;
|
||||||
int i = 0;
|
int written = 0;
|
||||||
if (tud_cdc_connected()) {
|
if (tud_cdc_connected() || _ignoreFlowControl) {
|
||||||
for (int i = 0; i < length;) {
|
for (size_t i = 0; i < length;) {
|
||||||
int n = length - i;
|
int n = length - i;
|
||||||
int avail = tud_cdc_write_available();
|
int avail = tud_cdc_write_available();
|
||||||
if (n > avail) n = avail;
|
if (n > avail) {
|
||||||
|
n = avail;
|
||||||
|
}
|
||||||
if (n) {
|
if (n) {
|
||||||
int n2 = tud_cdc_write(buf + i, n);
|
int n2 = tud_cdc_write(buf + i, n);
|
||||||
tud_task();
|
tud_task();
|
||||||
tud_cdc_write_flush();
|
tud_cdc_write_flush();
|
||||||
i += n2;
|
i += n2;
|
||||||
|
written += n2;
|
||||||
last_avail_time = time_us_64();
|
last_avail_time = time_us_64();
|
||||||
} else {
|
} else {
|
||||||
tud_task();
|
tud_task();
|
||||||
tud_cdc_write_flush();
|
tud_cdc_write_flush();
|
||||||
if (!tud_cdc_connected() ||
|
if (!tud_cdc_connected() ||
|
||||||
(!tud_cdc_write_available() && time_us_64() > last_avail_time + 1000000 /* 1 second */)) {
|
(!tud_cdc_write_available() && time_us_64() > last_avail_time + 1'000'000 /* 1 second */)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -272,11 +157,12 @@ size_t SerialUSB::write(const uint8_t *buf, size_t length) {
|
||||||
// reset our timeout
|
// reset our timeout
|
||||||
last_avail_time = 0;
|
last_avail_time = 0;
|
||||||
}
|
}
|
||||||
return i;
|
tud_task();
|
||||||
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialUSB::operator bool() {
|
SerialUSB::operator bool() {
|
||||||
CoreMutex m(&usb_mutex);
|
CoreMutex m(&__usb_mutex, false);
|
||||||
if (!_running || !m) {
|
if (!_running || !m) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -285,33 +171,59 @@ SerialUSB::operator bool() {
|
||||||
return tud_cdc_connected();
|
return tud_cdc_connected();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SerialUSB::ignoreFlowControl(bool ignore) {
|
||||||
|
_ignoreFlowControl = ignore;
|
||||||
|
}
|
||||||
|
|
||||||
static bool _dtr = false;
|
static bool _dtr = false;
|
||||||
static bool _rts = false;
|
static bool _rts = false;
|
||||||
static int _bps = 115200;
|
static int _bps = 115200;
|
||||||
|
static bool _rebooting = false;
|
||||||
static void CheckSerialReset() {
|
static void CheckSerialReset() {
|
||||||
if ((_bps == 1200) && (!_dtr)) {
|
if (!_rebooting && (_bps == 1200) && (!_dtr)) {
|
||||||
reset_usb_boot(0,0);
|
if (__isFreeRTOS) {
|
||||||
while (1); // WDT will fire here
|
__freertos_idle_other_core();
|
||||||
|
}
|
||||||
|
_rebooting = true;
|
||||||
|
// Disable NVIC IRQ, so that we don't get bothered anymore
|
||||||
|
irq_set_enabled(USBCTRL_IRQ, false);
|
||||||
|
// Reset the whole USB hardware block
|
||||||
|
reset_block(RESETS_RESET_USBCTRL_BITS);
|
||||||
|
unreset_block(RESETS_RESET_USBCTRL_BITS);
|
||||||
|
// Delay a bit, so the PC can figure out that we have disconnected.
|
||||||
|
busy_wait_ms(3);
|
||||||
|
reset_usb_boot(0, 0);
|
||||||
|
while (1); // WDT will fire here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SerialUSB::dtr() {
|
||||||
|
return _dtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SerialUSB::rts() {
|
||||||
|
return _rts;
|
||||||
|
}
|
||||||
|
|
||||||
extern "C" void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) {
|
extern "C" void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts) {
|
||||||
|
(void) itf;
|
||||||
_dtr = dtr ? true : false;
|
_dtr = dtr ? true : false;
|
||||||
_rts = rts ? true : false;
|
_rts = rts ? true : false;
|
||||||
CheckSerialReset();
|
CheckSerialReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding) {
|
extern "C" void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_line_coding) {
|
||||||
|
(void) itf;
|
||||||
_bps = p_line_coding->bit_rate;
|
_bps = p_line_coding->bit_rate;
|
||||||
CheckSerialReset();
|
CheckSerialReset();
|
||||||
}
|
}
|
||||||
|
|
||||||
SerialUSB Serial;
|
SerialUSB Serial;
|
||||||
|
|
||||||
void arduino::serialEventRun(void)
|
void arduino::serialEventRun(void) {
|
||||||
{
|
|
||||||
if (serialEvent && Serial.available()) {
|
if (serialEvent && Serial.available()) {
|
||||||
serialEvent();
|
serialEvent();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -1,35 +1,37 @@
|
||||||
/*
|
/*
|
||||||
* Serial-over-USB for the Raspberry Pi Pico RP2040
|
Serial-over-USB for the Raspberry Pi Pico RP2040
|
||||||
*
|
|
||||||
* Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
|
||||||
* License as published by the Free Software Foundation; either
|
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
* Lesser General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef __SERIALUSB_H__
|
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
#define __SERIALUSB_H__
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "api/HardwareSerial.h"
|
#include "api/HardwareSerial.h"
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
|
||||||
class SerialUSB : public HardwareSerial {
|
class SerialUSB : public arduino::HardwareSerial {
|
||||||
public:
|
public:
|
||||||
SerialUSB() { }
|
SerialUSB() { }
|
||||||
void begin(unsigned long baud = 115200) override;
|
void begin(unsigned long baud = 115200) override;
|
||||||
void begin(unsigned long baud, uint16_t config) override { begin(baud); };
|
void begin(unsigned long baud, uint16_t config) override {
|
||||||
|
(void) config;
|
||||||
|
begin(baud);
|
||||||
|
};
|
||||||
void end() override;
|
void end() override;
|
||||||
|
|
||||||
virtual int peek() override;
|
virtual int peek() override;
|
||||||
|
|
@ -41,15 +43,23 @@ public:
|
||||||
virtual size_t write(const uint8_t *p, size_t len) override;
|
virtual size_t write(const uint8_t *p, size_t len) override;
|
||||||
using Print::write;
|
using Print::write;
|
||||||
operator bool() override;
|
operator bool() override;
|
||||||
|
bool dtr();
|
||||||
|
bool rts();
|
||||||
|
|
||||||
|
void ignoreFlowControl(bool ignore = true);
|
||||||
|
|
||||||
|
// ESP8266 compat
|
||||||
|
void setDebugOutput(bool unused) {
|
||||||
|
(void) unused;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool _running = false;
|
bool _running = false;
|
||||||
|
bool _ignoreFlowControl = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern SerialUSB Serial;
|
extern SerialUSB Serial;
|
||||||
|
|
||||||
namespace arduino {
|
namespace arduino {
|
||||||
extern void serialEventRun(void) __attribute__((weak));
|
extern void serialEventRun(void) __attribute__((weak));
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
||||||
81
cores/rp2040/SoftwareSerial.h
Normal file
81
cores/rp2040/SoftwareSerial.h
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*
|
||||||
|
SoftwareSerial wrapper for SerialPIO
|
||||||
|
|
||||||
|
Copyright (c) 2022 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "SerialPIO.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Implements a UART port using PIO for input and output
|
||||||
|
*/
|
||||||
|
class SoftwareSerial : public SerialPIO {
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
@brief Constructs a PIO-based UART
|
||||||
|
|
||||||
|
@param [in] rx GPIO for RX pin or -1 for transmit-only
|
||||||
|
@param [in] tx GPIO for TX pin or -1 for receive-only
|
||||||
|
@param [in] invert True to invert the receive and transmit lines
|
||||||
|
*/
|
||||||
|
SoftwareSerial(pin_size_t rx, pin_size_t tx, bool invert = false) : SerialPIO(tx, rx) {
|
||||||
|
_invert = invert;
|
||||||
|
}
|
||||||
|
|
||||||
|
~SoftwareSerial() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Starts the PIO UART
|
||||||
|
|
||||||
|
@param [in] baud Serial bit rate
|
||||||
|
*/
|
||||||
|
virtual void begin(unsigned long baud = 115200) override {
|
||||||
|
begin(baud, SERIAL_8N1);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief Starts the PIO UART
|
||||||
|
|
||||||
|
@param [in] baud Serial bit rate
|
||||||
|
@param [in] config Start/Stop/Len configuration (i.e. SERIAL_8N1 or SERIAL_7E2)
|
||||||
|
*/
|
||||||
|
void begin(unsigned long baud, uint16_t config) override {
|
||||||
|
setInvertTX(_invert);
|
||||||
|
setInvertRX(_invert);
|
||||||
|
SerialPIO::begin(baud, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief No-op on this core
|
||||||
|
*/
|
||||||
|
void listen() { /* noop */ }
|
||||||
|
|
||||||
|
/**
|
||||||
|
@brief No-op on this core
|
||||||
|
|
||||||
|
@returns True always
|
||||||
|
*/
|
||||||
|
bool isListening() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _invert;
|
||||||
|
};
|
||||||
108
cores/rp2040/StackThunk.cpp
Normal file
108
cores/rp2040/StackThunk.cpp
Normal file
|
|
@ -0,0 +1,108 @@
|
||||||
|
/*
|
||||||
|
StackThunk - Implements a simple 2nd stack for BSSL and others
|
||||||
|
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "StackThunk.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
uint32_t *stack_thunk_ptr = nullptr;
|
||||||
|
uint32_t *stack_thunk_top = nullptr;
|
||||||
|
uint32_t *stack_thunk_save = nullptr; /* Saved A1 while in BearSSL */
|
||||||
|
uint32_t stack_thunk_refcnt = 0;
|
||||||
|
|
||||||
|
/* Largest stack usage seen in the wild at 6120 */
|
||||||
|
#define _stackSize (6400/4)
|
||||||
|
#define _stackPaint 0xdeadbeef
|
||||||
|
|
||||||
|
/* Add a reference, and allocate the stack if necessary */
|
||||||
|
void stack_thunk_add_ref() {
|
||||||
|
stack_thunk_refcnt++;
|
||||||
|
if (stack_thunk_refcnt == 1) {
|
||||||
|
// The stack must be in DRAM, or an Soft WDT will follow. Not sure why,
|
||||||
|
// maybe too much time is consumed with the non32-bit exception handler.
|
||||||
|
// Also, interrupt handling on an IRAM stack would be very slow.
|
||||||
|
// Strings on the stack would be very slow to access as well.
|
||||||
|
stack_thunk_ptr = (uint32_t *)malloc(_stackSize * sizeof(uint32_t));
|
||||||
|
if (!stack_thunk_ptr) {
|
||||||
|
// This is a fatal error, stop the sketch
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
stack_thunk_top = stack_thunk_ptr + _stackSize - 1;
|
||||||
|
stack_thunk_save = nullptr;
|
||||||
|
stack_thunk_repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Drop a reference, and free stack if no more in use */
|
||||||
|
void stack_thunk_del_ref() {
|
||||||
|
if (stack_thunk_refcnt == 0) {
|
||||||
|
/* Error! */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stack_thunk_refcnt--;
|
||||||
|
if (!stack_thunk_refcnt) {
|
||||||
|
free(stack_thunk_ptr);
|
||||||
|
stack_thunk_ptr = nullptr;
|
||||||
|
stack_thunk_top = nullptr;
|
||||||
|
stack_thunk_save = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void stack_thunk_repaint() {
|
||||||
|
for (int i = 0; i < _stackSize; i++) {
|
||||||
|
stack_thunk_ptr[i] = _stackPaint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Simple accessor functions used by postmortem */
|
||||||
|
uint32_t stack_thunk_get_refcnt() {
|
||||||
|
return stack_thunk_refcnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t stack_thunk_get_stack_top() {
|
||||||
|
return (uint32_t)stack_thunk_top;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t stack_thunk_get_stack_bot() {
|
||||||
|
return (uint32_t)stack_thunk_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t stack_thunk_get_cont_sp() {
|
||||||
|
return (uint32_t)stack_thunk_save;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the number of bytes ever used since the stack was created */
|
||||||
|
uint32_t stack_thunk_get_max_usage() {
|
||||||
|
uint32_t cnt = 0;
|
||||||
|
|
||||||
|
/* No stack == no usage by definition! */
|
||||||
|
if (!stack_thunk_ptr) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (cnt = 0; (cnt < _stackSize) && (stack_thunk_ptr[cnt] == _stackPaint); cnt++) {
|
||||||
|
/* Noop, all work done in for() */
|
||||||
|
}
|
||||||
|
return 4 * (_stackSize - cnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
77
cores/rp2040/StackThunk.h
Normal file
77
cores/rp2040/StackThunk.h
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
StackThunk - Implements a simple 2nd stack for BSSL and others
|
||||||
|
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern void stack_thunk_add_ref();
|
||||||
|
extern void stack_thunk_del_ref();
|
||||||
|
extern void stack_thunk_repaint();
|
||||||
|
|
||||||
|
extern uint32_t stack_thunk_get_refcnt();
|
||||||
|
extern uint32_t stack_thunk_get_stack_top();
|
||||||
|
extern uint32_t stack_thunk_get_stack_bot();
|
||||||
|
extern uint32_t stack_thunk_get_cont_sp();
|
||||||
|
extern uint32_t stack_thunk_get_max_usage();
|
||||||
|
extern void stack_thunk_dump_stack();
|
||||||
|
extern void stack_thunk_fatal_overflow();
|
||||||
|
|
||||||
|
// Globals required for thunking operation
|
||||||
|
extern uint32_t *stack_thunk_ptr;
|
||||||
|
extern uint32_t *stack_thunk_top;
|
||||||
|
extern uint32_t *stack_thunk_save;
|
||||||
|
extern uint32_t stack_thunk_refcnt;
|
||||||
|
|
||||||
|
#define make_stack_thunk_void(fcnToThunk, proto, params) \
|
||||||
|
extern "C" void thunk_##fcnToThunk proto { \
|
||||||
|
register uint32_t* sp asm("sp"); \
|
||||||
|
stack_thunk_save = sp; \
|
||||||
|
sp = stack_thunk_top; \
|
||||||
|
fcnToThunk params; \
|
||||||
|
sp = stack_thunk_save; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define make_stack_thunk_unsigned_char_ptr(fcnToThunk, proto, params) \
|
||||||
|
extern "C" unsigned char * thunk_##fcnToThunk proto { \
|
||||||
|
register uint32_t* sp asm("sp"); \
|
||||||
|
stack_thunk_save = sp; \
|
||||||
|
sp = stack_thunk_top; \
|
||||||
|
auto x = fcnToThunk params; \
|
||||||
|
sp = stack_thunk_save; \
|
||||||
|
return x; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define make_stack_thunk_bool(fcnToThunk, proto, params) \
|
||||||
|
extern "C" bool thunk_##fcnToThunk proto { \
|
||||||
|
register uint32_t* sp asm("sp"); \
|
||||||
|
stack_thunk_save = sp; \
|
||||||
|
sp = stack_thunk_top; \
|
||||||
|
auto x = fcnToThunk params; \
|
||||||
|
sp = stack_thunk_save; \
|
||||||
|
return x; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
@ -1 +1 @@
|
||||||
#include "api/String.h"
|
#include "api/Stream.h"
|
||||||
|
|
|
||||||
247
cores/rp2040/StreamString.h
Normal file
247
cores/rp2040/StreamString.h
Normal file
|
|
@ -0,0 +1,247 @@
|
||||||
|
/**
|
||||||
|
StreamString.h
|
||||||
|
|
||||||
|
Copyright (c) 2020 D. Gauchard. All rights reserved.
|
||||||
|
This file is part of the esp8266 core for Arduino environment.
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __STREAMSTRING_H
|
||||||
|
#define __STREAMSTRING_H
|
||||||
|
|
||||||
|
#include <limits>
|
||||||
|
#include <algorithm>
|
||||||
|
#include "Stream.h"
|
||||||
|
#include "api/String.h"
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////
|
||||||
|
// S2Stream points to a String and makes it a Stream
|
||||||
|
// (it is also the helper for StreamString)
|
||||||
|
|
||||||
|
class S2Stream: public Stream {
|
||||||
|
public:
|
||||||
|
S2Stream(String& string, int peekPointer = -1) : string(&string), peekPointer(peekPointer) { }
|
||||||
|
|
||||||
|
S2Stream(String* string, int peekPointer = -1) : string(string), peekPointer(peekPointer) { }
|
||||||
|
|
||||||
|
virtual int available() override {
|
||||||
|
return string->length();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int availableForWrite() override {
|
||||||
|
return std::numeric_limits<int16_t>::max();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int read() override {
|
||||||
|
if (peekPointer < 0) {
|
||||||
|
// consume chars
|
||||||
|
if (string->length()) {
|
||||||
|
char c = string->charAt(0);
|
||||||
|
string->remove(0, 1);
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
} else if (peekPointer < (int)string->length()) {
|
||||||
|
// return pointed and move pointer
|
||||||
|
return string->charAt(peekPointer++);
|
||||||
|
}
|
||||||
|
|
||||||
|
// everything is read
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t write(uint8_t data) override {
|
||||||
|
return string->concat((char)data);
|
||||||
|
}
|
||||||
|
|
||||||
|
// virtual int read(uint8_t* buffer, size_t len) override
|
||||||
|
// {
|
||||||
|
// if (peekPointer < 0)
|
||||||
|
// {
|
||||||
|
// // string will be consumed
|
||||||
|
// size_t l = std::min(len, (size_t)string->length());
|
||||||
|
// memcpy(buffer, string->c_str(), l);
|
||||||
|
// string->remove(0, l);
|
||||||
|
// return l;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (peekPointer >= (int)string->length())
|
||||||
|
// {
|
||||||
|
// return 0;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// // only the pointer is moved
|
||||||
|
// size_t l = std::min(len, (size_t)(string->length() - peekPointer));
|
||||||
|
// memcpy(buffer, string->c_str() + peekPointer, l);
|
||||||
|
// peekPointer += l;
|
||||||
|
// return l;
|
||||||
|
// }
|
||||||
|
|
||||||
|
virtual size_t write(const uint8_t* buffer, size_t len) override {
|
||||||
|
return string->concat((const char*)buffer, len) ? len : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual int peek() override {
|
||||||
|
if (peekPointer < 0) {
|
||||||
|
if (string->length()) {
|
||||||
|
return string->charAt(0);
|
||||||
|
}
|
||||||
|
} else if (peekPointer < (int)string->length()) {
|
||||||
|
return string->charAt(peekPointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void flush() override {
|
||||||
|
// nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
virtual bool inputCanTimeout() override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool outputCanTimeout() override {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//// Stream's peekBufferAPI
|
||||||
|
|
||||||
|
virtual bool hasPeekBufferAPI() const override {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t peekAvailable() {
|
||||||
|
if (peekPointer < 0) {
|
||||||
|
return string->length();
|
||||||
|
}
|
||||||
|
return string->length() - peekPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual const char* peekBuffer() override {
|
||||||
|
if (peekPointer < 0) {
|
||||||
|
return string->c_str();
|
||||||
|
}
|
||||||
|
if (peekPointer < (int)string->length()) {
|
||||||
|
return string->c_str() + peekPointer;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void peekConsume(size_t consume) override {
|
||||||
|
if (peekPointer < 0) {
|
||||||
|
// string is really consumed
|
||||||
|
string->remove(0, consume);
|
||||||
|
} else {
|
||||||
|
// only the pointer is moved
|
||||||
|
peekPointer = std::min((size_t)string->length(), peekPointer + consume);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual ssize_t streamRemaining() override {
|
||||||
|
return peekPointer < 0 ? string->length() : string->length() - peekPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calling setConsume() will consume bytes as the stream is read
|
||||||
|
// (enabled by default)
|
||||||
|
void setConsume() {
|
||||||
|
peekPointer = -1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
// Reading this stream will mark the string as read without consuming
|
||||||
|
// (not enabled by default)
|
||||||
|
// Calling resetPointer() resets the read state and allows rereading.
|
||||||
|
void resetPointer(int pointer = 0) {
|
||||||
|
peekPointer = pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
String* string;
|
||||||
|
int peekPointer; // -1:String is consumed / >=0:resettable pointer
|
||||||
|
};
|
||||||
|
|
||||||
|
// StreamString is a S2Stream holding the String
|
||||||
|
|
||||||
|
class StreamString: public String, public S2Stream {
|
||||||
|
protected:
|
||||||
|
void resetpp() {
|
||||||
|
if (peekPointer > 0) {
|
||||||
|
peekPointer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
StreamString(StreamString&& bro) : String(bro), S2Stream(this) { }
|
||||||
|
StreamString(const StreamString& bro) : String(bro), S2Stream(this) { }
|
||||||
|
|
||||||
|
// duplicate String constructors and operator=:
|
||||||
|
|
||||||
|
StreamString(const char* text = nullptr) : String(text), S2Stream(this) { }
|
||||||
|
StreamString(const String& string) : String(string), S2Stream(this) { }
|
||||||
|
StreamString(const __FlashStringHelper* str) : String(str), S2Stream(this) { }
|
||||||
|
StreamString(String&& string) : String(string), S2Stream(this) { }
|
||||||
|
|
||||||
|
explicit StreamString(char c) : String(c), S2Stream(this) { }
|
||||||
|
explicit StreamString(unsigned char c, unsigned char base = 10) :
|
||||||
|
String(c, base), S2Stream(this) {
|
||||||
|
}
|
||||||
|
explicit StreamString(int i, unsigned char base = 10) : String(i, base), S2Stream(this) { }
|
||||||
|
explicit StreamString(unsigned int i, unsigned char base = 10) : String(i, base), S2Stream(this) {
|
||||||
|
}
|
||||||
|
explicit StreamString(long l, unsigned char base = 10) : String(l, base), S2Stream(this) { }
|
||||||
|
explicit StreamString(unsigned long l, unsigned char base = 10) :
|
||||||
|
String(l, base), S2Stream(this) {
|
||||||
|
}
|
||||||
|
explicit StreamString(float f, unsigned char decimalPlaces = 2) :
|
||||||
|
String(f, decimalPlaces), S2Stream(this) {
|
||||||
|
}
|
||||||
|
explicit StreamString(double d, unsigned char decimalPlaces = 2) :
|
||||||
|
String(d, decimalPlaces), S2Stream(this) {
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamString& operator=(const StreamString& rhs) {
|
||||||
|
String::operator=(rhs);
|
||||||
|
resetpp();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamString& operator=(const String& rhs) {
|
||||||
|
String::operator=(rhs);
|
||||||
|
resetpp();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamString& operator=(const char* cstr) {
|
||||||
|
String::operator=(cstr);
|
||||||
|
resetpp();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamString& operator=(const __FlashStringHelper* str) {
|
||||||
|
String::operator=(str);
|
||||||
|
resetpp();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
StreamString& operator=(String&& rval) {
|
||||||
|
String::operator=(rval);
|
||||||
|
resetpp();
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __STREAMSTRING_H
|
||||||
474
cores/rp2040/TZ.h
Normal file
474
cores/rp2040/TZ.h
Normal file
|
|
@ -0,0 +1,474 @@
|
||||||
|
|
||||||
|
// autogenerated from https://raw.githubusercontent.com/nayarsystems/posix_tz_db/master/zones.csv
|
||||||
|
// by script <rp2040 arduino core>/tools/tzupdate.sh
|
||||||
|
// Sat 20 Jan 2024 08:54:45 PM UTC
|
||||||
|
//
|
||||||
|
// This database is autogenerated from IANA timezone database
|
||||||
|
// https://raw.githubusercontent.com/nayarsystems/posix_tz_db/master/zones.csv
|
||||||
|
// (using https://www.iana.org/time-zones)
|
||||||
|
// and can be updated on demand in this repository
|
||||||
|
// or by yourself using the above script
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define TZ_Africa_Abidjan ("GMT0")
|
||||||
|
#define TZ_Africa_Accra ("GMT0")
|
||||||
|
#define TZ_Africa_Addis_Ababa ("EAT-3")
|
||||||
|
#define TZ_Africa_Algiers ("CET-1")
|
||||||
|
#define TZ_Africa_Asmara ("EAT-3")
|
||||||
|
#define TZ_Africa_Bamako ("GMT0")
|
||||||
|
#define TZ_Africa_Bangui ("WAT-1")
|
||||||
|
#define TZ_Africa_Banjul ("GMT0")
|
||||||
|
#define TZ_Africa_Bissau ("GMT0")
|
||||||
|
#define TZ_Africa_Blantyre ("CAT-2")
|
||||||
|
#define TZ_Africa_Brazzaville ("WAT-1")
|
||||||
|
#define TZ_Africa_Bujumbura ("CAT-2")
|
||||||
|
#define TZ_Africa_Cairo ("EET-2EEST,M4.5.5/0,M10.5.4/24")
|
||||||
|
#define TZ_Africa_Casablanca ("<+01>-1")
|
||||||
|
#define TZ_Africa_Ceuta ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Africa_Conakry ("GMT0")
|
||||||
|
#define TZ_Africa_Dakar ("GMT0")
|
||||||
|
#define TZ_Africa_Dar_es_Salaam ("EAT-3")
|
||||||
|
#define TZ_Africa_Djibouti ("EAT-3")
|
||||||
|
#define TZ_Africa_Douala ("WAT-1")
|
||||||
|
#define TZ_Africa_El_Aaiun ("<+01>-1")
|
||||||
|
#define TZ_Africa_Freetown ("GMT0")
|
||||||
|
#define TZ_Africa_Gaborone ("CAT-2")
|
||||||
|
#define TZ_Africa_Harare ("CAT-2")
|
||||||
|
#define TZ_Africa_Johannesburg ("SAST-2")
|
||||||
|
#define TZ_Africa_Juba ("CAT-2")
|
||||||
|
#define TZ_Africa_Kampala ("EAT-3")
|
||||||
|
#define TZ_Africa_Khartoum ("CAT-2")
|
||||||
|
#define TZ_Africa_Kigali ("CAT-2")
|
||||||
|
#define TZ_Africa_Kinshasa ("WAT-1")
|
||||||
|
#define TZ_Africa_Lagos ("WAT-1")
|
||||||
|
#define TZ_Africa_Libreville ("WAT-1")
|
||||||
|
#define TZ_Africa_Lome ("GMT0")
|
||||||
|
#define TZ_Africa_Luanda ("WAT-1")
|
||||||
|
#define TZ_Africa_Lubumbashi ("CAT-2")
|
||||||
|
#define TZ_Africa_Lusaka ("CAT-2")
|
||||||
|
#define TZ_Africa_Malabo ("WAT-1")
|
||||||
|
#define TZ_Africa_Maputo ("CAT-2")
|
||||||
|
#define TZ_Africa_Maseru ("SAST-2")
|
||||||
|
#define TZ_Africa_Mbabane ("SAST-2")
|
||||||
|
#define TZ_Africa_Mogadishu ("EAT-3")
|
||||||
|
#define TZ_Africa_Monrovia ("GMT0")
|
||||||
|
#define TZ_Africa_Nairobi ("EAT-3")
|
||||||
|
#define TZ_Africa_Ndjamena ("WAT-1")
|
||||||
|
#define TZ_Africa_Niamey ("WAT-1")
|
||||||
|
#define TZ_Africa_Nouakchott ("GMT0")
|
||||||
|
#define TZ_Africa_Ouagadougou ("GMT0")
|
||||||
|
#define TZ_Africa_PortomNovo ("WAT-1")
|
||||||
|
#define TZ_Africa_Sao_Tome ("GMT0")
|
||||||
|
#define TZ_Africa_Tripoli ("EET-2")
|
||||||
|
#define TZ_Africa_Tunis ("CET-1")
|
||||||
|
#define TZ_Africa_Windhoek ("CAT-2")
|
||||||
|
#define TZ_America_Adak ("HST10HDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Anchorage ("AKST9AKDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Anguilla ("AST4")
|
||||||
|
#define TZ_America_Antigua ("AST4")
|
||||||
|
#define TZ_America_Araguaina ("<-03>3")
|
||||||
|
#define TZ_America_Argentina_Buenos_Aires ("<-03>3")
|
||||||
|
#define TZ_America_Argentina_Catamarca ("<-03>3")
|
||||||
|
#define TZ_America_Argentina_Cordoba ("<-03>3")
|
||||||
|
#define TZ_America_Argentina_Jujuy ("<-03>3")
|
||||||
|
#define TZ_America_Argentina_La_Rioja ("<-03>3")
|
||||||
|
#define TZ_America_Argentina_Mendoza ("<-03>3")
|
||||||
|
#define TZ_America_Argentina_Rio_Gallegos ("<-03>3")
|
||||||
|
#define TZ_America_Argentina_Salta ("<-03>3")
|
||||||
|
#define TZ_America_Argentina_San_Juan ("<-03>3")
|
||||||
|
#define TZ_America_Argentina_San_Luis ("<-03>3")
|
||||||
|
#define TZ_America_Argentina_Tucuman ("<-03>3")
|
||||||
|
#define TZ_America_Argentina_Ushuaia ("<-03>3")
|
||||||
|
#define TZ_America_Aruba ("AST4")
|
||||||
|
#define TZ_America_Asuncion ("<-04>4<-03>,M10.1.0/0,M3.4.0/0")
|
||||||
|
#define TZ_America_Atikokan ("EST5")
|
||||||
|
#define TZ_America_Bahia ("<-03>3")
|
||||||
|
#define TZ_America_Bahia_Banderas ("CST6")
|
||||||
|
#define TZ_America_Barbados ("AST4")
|
||||||
|
#define TZ_America_Belem ("<-03>3")
|
||||||
|
#define TZ_America_Belize ("CST6")
|
||||||
|
#define TZ_America_BlancmSablon ("AST4")
|
||||||
|
#define TZ_America_Boa_Vista ("<-04>4")
|
||||||
|
#define TZ_America_Bogota ("<-05>5")
|
||||||
|
#define TZ_America_Boise ("MST7MDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Cambridge_Bay ("MST7MDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Campo_Grande ("<-04>4")
|
||||||
|
#define TZ_America_Cancun ("EST5")
|
||||||
|
#define TZ_America_Caracas ("<-04>4")
|
||||||
|
#define TZ_America_Cayenne ("<-03>3")
|
||||||
|
#define TZ_America_Cayman ("EST5")
|
||||||
|
#define TZ_America_Chicago ("CST6CDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Chihuahua ("CST6")
|
||||||
|
#define TZ_America_Costa_Rica ("CST6")
|
||||||
|
#define TZ_America_Creston ("MST7")
|
||||||
|
#define TZ_America_Cuiaba ("<-04>4")
|
||||||
|
#define TZ_America_Curacao ("AST4")
|
||||||
|
#define TZ_America_Danmarkshavn ("GMT0")
|
||||||
|
#define TZ_America_Dawson ("MST7")
|
||||||
|
#define TZ_America_Dawson_Creek ("MST7")
|
||||||
|
#define TZ_America_Denver ("MST7MDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Detroit ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Dominica ("AST4")
|
||||||
|
#define TZ_America_Edmonton ("MST7MDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Eirunepe ("<-05>5")
|
||||||
|
#define TZ_America_El_Salvador ("CST6")
|
||||||
|
#define TZ_America_Fortaleza ("<-03>3")
|
||||||
|
#define TZ_America_Fort_Nelson ("MST7")
|
||||||
|
#define TZ_America_Glace_Bay ("AST4ADT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Godthab ("<-02>2<-01>,M3.5.0/-1,M10.5.0/0")
|
||||||
|
#define TZ_America_Goose_Bay ("AST4ADT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Grand_Turk ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Grenada ("AST4")
|
||||||
|
#define TZ_America_Guadeloupe ("AST4")
|
||||||
|
#define TZ_America_Guatemala ("CST6")
|
||||||
|
#define TZ_America_Guayaquil ("<-05>5")
|
||||||
|
#define TZ_America_Guyana ("<-04>4")
|
||||||
|
#define TZ_America_Halifax ("AST4ADT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Havana ("CST5CDT,M3.2.0/0,M11.1.0/1")
|
||||||
|
#define TZ_America_Hermosillo ("MST7")
|
||||||
|
#define TZ_America_Indiana_Indianapolis ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Indiana_Knox ("CST6CDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Indiana_Marengo ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Indiana_Petersburg ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Indiana_Tell_City ("CST6CDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Indiana_Vevay ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Indiana_Vincennes ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Indiana_Winamac ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Inuvik ("MST7MDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Iqaluit ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Jamaica ("EST5")
|
||||||
|
#define TZ_America_Juneau ("AKST9AKDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Kentucky_Louisville ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Kentucky_Monticello ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Kralendijk ("AST4")
|
||||||
|
#define TZ_America_La_Paz ("<-04>4")
|
||||||
|
#define TZ_America_Lima ("<-05>5")
|
||||||
|
#define TZ_America_Los_Angeles ("PST8PDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Lower_Princes ("AST4")
|
||||||
|
#define TZ_America_Maceio ("<-03>3")
|
||||||
|
#define TZ_America_Managua ("CST6")
|
||||||
|
#define TZ_America_Manaus ("<-04>4")
|
||||||
|
#define TZ_America_Marigot ("AST4")
|
||||||
|
#define TZ_America_Martinique ("AST4")
|
||||||
|
#define TZ_America_Matamoros ("CST6CDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Mazatlan ("MST7")
|
||||||
|
#define TZ_America_Menominee ("CST6CDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Merida ("CST6")
|
||||||
|
#define TZ_America_Metlakatla ("AKST9AKDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Mexico_City ("CST6")
|
||||||
|
#define TZ_America_Miquelon ("<-03>3<-02>,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Moncton ("AST4ADT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Monterrey ("CST6")
|
||||||
|
#define TZ_America_Montevideo ("<-03>3")
|
||||||
|
#define TZ_America_Montreal ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Montserrat ("AST4")
|
||||||
|
#define TZ_America_Nassau ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_New_York ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Nipigon ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Nome ("AKST9AKDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Noronha ("<-02>2")
|
||||||
|
#define TZ_America_North_Dakota_Beulah ("CST6CDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_North_Dakota_Center ("CST6CDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_North_Dakota_New_Salem ("CST6CDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Nuuk ("<-02>2<-01>,M3.5.0/-1,M10.5.0/0")
|
||||||
|
#define TZ_America_Ojinaga ("CST6CDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Panama ("EST5")
|
||||||
|
#define TZ_America_Pangnirtung ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Paramaribo ("<-03>3")
|
||||||
|
#define TZ_America_Phoenix ("MST7")
|
||||||
|
#define TZ_America_PortmaumPrince ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Port_of_Spain ("AST4")
|
||||||
|
#define TZ_America_Porto_Velho ("<-04>4")
|
||||||
|
#define TZ_America_Puerto_Rico ("AST4")
|
||||||
|
#define TZ_America_Punta_Arenas ("<-03>3")
|
||||||
|
#define TZ_America_Rainy_River ("CST6CDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Rankin_Inlet ("CST6CDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Recife ("<-03>3")
|
||||||
|
#define TZ_America_Regina ("CST6")
|
||||||
|
#define TZ_America_Resolute ("CST6CDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Rio_Branco ("<-05>5")
|
||||||
|
#define TZ_America_Santarem ("<-03>3")
|
||||||
|
#define TZ_America_Santiago ("<-04>4<-03>,M9.1.6/24,M4.1.6/24")
|
||||||
|
#define TZ_America_Santo_Domingo ("AST4")
|
||||||
|
#define TZ_America_Sao_Paulo ("<-03>3")
|
||||||
|
#define TZ_America_Scoresbysund ("<-01>1<+00>,M3.5.0/0,M10.5.0/1")
|
||||||
|
#define TZ_America_Sitka ("AKST9AKDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_St_Barthelemy ("AST4")
|
||||||
|
#define TZ_America_St_Johns ("NST3:30NDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_St_Kitts ("AST4")
|
||||||
|
#define TZ_America_St_Lucia ("AST4")
|
||||||
|
#define TZ_America_St_Thomas ("AST4")
|
||||||
|
#define TZ_America_St_Vincent ("AST4")
|
||||||
|
#define TZ_America_Swift_Current ("CST6")
|
||||||
|
#define TZ_America_Tegucigalpa ("CST6")
|
||||||
|
#define TZ_America_Thule ("AST4ADT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Thunder_Bay ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Tijuana ("PST8PDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Toronto ("EST5EDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Tortola ("AST4")
|
||||||
|
#define TZ_America_Vancouver ("PST8PDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Whitehorse ("MST7")
|
||||||
|
#define TZ_America_Winnipeg ("CST6CDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Yakutat ("AKST9AKDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_America_Yellowknife ("MST7MDT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_Antarctica_Casey ("<+11>-11")
|
||||||
|
#define TZ_Antarctica_Davis ("<+07>-7")
|
||||||
|
#define TZ_Antarctica_DumontDUrville ("<+10>-10")
|
||||||
|
#define TZ_Antarctica_Macquarie ("AEST-10AEDT,M10.1.0,M4.1.0/3")
|
||||||
|
#define TZ_Antarctica_Mawson ("<+05>-5")
|
||||||
|
#define TZ_Antarctica_McMurdo ("NZST-12NZDT,M9.5.0,M4.1.0/3")
|
||||||
|
#define TZ_Antarctica_Palmer ("<-03>3")
|
||||||
|
#define TZ_Antarctica_Rothera ("<-03>3")
|
||||||
|
#define TZ_Antarctica_Syowa ("<+03>-3")
|
||||||
|
#define TZ_Antarctica_Troll ("<+00>0<+02>-2,M3.5.0/1,M10.5.0/3")
|
||||||
|
#define TZ_Antarctica_Vostok ("<+06>-6")
|
||||||
|
#define TZ_Arctic_Longyearbyen ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Asia_Aden ("<+03>-3")
|
||||||
|
#define TZ_Asia_Almaty ("<+06>-6")
|
||||||
|
#define TZ_Asia_Amman ("<+03>-3")
|
||||||
|
#define TZ_Asia_Anadyr ("<+12>-12")
|
||||||
|
#define TZ_Asia_Aqtau ("<+05>-5")
|
||||||
|
#define TZ_Asia_Aqtobe ("<+05>-5")
|
||||||
|
#define TZ_Asia_Ashgabat ("<+05>-5")
|
||||||
|
#define TZ_Asia_Atyrau ("<+05>-5")
|
||||||
|
#define TZ_Asia_Baghdad ("<+03>-3")
|
||||||
|
#define TZ_Asia_Bahrain ("<+03>-3")
|
||||||
|
#define TZ_Asia_Baku ("<+04>-4")
|
||||||
|
#define TZ_Asia_Bangkok ("<+07>-7")
|
||||||
|
#define TZ_Asia_Barnaul ("<+07>-7")
|
||||||
|
#define TZ_Asia_Beirut ("EET-2EEST,M3.5.0/0,M10.5.0/0")
|
||||||
|
#define TZ_Asia_Bishkek ("<+06>-6")
|
||||||
|
#define TZ_Asia_Brunei ("<+08>-8")
|
||||||
|
#define TZ_Asia_Chita ("<+09>-9")
|
||||||
|
#define TZ_Asia_Choibalsan ("<+08>-8")
|
||||||
|
#define TZ_Asia_Colombo ("<+0530>-5:30")
|
||||||
|
#define TZ_Asia_Damascus ("<+03>-3")
|
||||||
|
#define TZ_Asia_Dhaka ("<+06>-6")
|
||||||
|
#define TZ_Asia_Dili ("<+09>-9")
|
||||||
|
#define TZ_Asia_Dubai ("<+04>-4")
|
||||||
|
#define TZ_Asia_Dushanbe ("<+05>-5")
|
||||||
|
#define TZ_Asia_Famagusta ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||||
|
#define TZ_Asia_Gaza ("EET-2EEST,M3.4.4/50,M10.4.4/50")
|
||||||
|
#define TZ_Asia_Hebron ("EET-2EEST,M3.4.4/50,M10.4.4/50")
|
||||||
|
#define TZ_Asia_Ho_Chi_Minh ("<+07>-7")
|
||||||
|
#define TZ_Asia_Hong_Kong ("HKT-8")
|
||||||
|
#define TZ_Asia_Hovd ("<+07>-7")
|
||||||
|
#define TZ_Asia_Irkutsk ("<+08>-8")
|
||||||
|
#define TZ_Asia_Jakarta ("WIB-7")
|
||||||
|
#define TZ_Asia_Jayapura ("WIT-9")
|
||||||
|
#define TZ_Asia_Jerusalem ("IST-2IDT,M3.4.4/26,M10.5.0")
|
||||||
|
#define TZ_Asia_Kabul ("<+0430>-4:30")
|
||||||
|
#define TZ_Asia_Kamchatka ("<+12>-12")
|
||||||
|
#define TZ_Asia_Karachi ("PKT-5")
|
||||||
|
#define TZ_Asia_Kathmandu ("<+0545>-5:45")
|
||||||
|
#define TZ_Asia_Khandyga ("<+09>-9")
|
||||||
|
#define TZ_Asia_Kolkata ("IST-5:30")
|
||||||
|
#define TZ_Asia_Krasnoyarsk ("<+07>-7")
|
||||||
|
#define TZ_Asia_Kuala_Lumpur ("<+08>-8")
|
||||||
|
#define TZ_Asia_Kuching ("<+08>-8")
|
||||||
|
#define TZ_Asia_Kuwait ("<+03>-3")
|
||||||
|
#define TZ_Asia_Macau ("CST-8")
|
||||||
|
#define TZ_Asia_Magadan ("<+11>-11")
|
||||||
|
#define TZ_Asia_Makassar ("WITA-8")
|
||||||
|
#define TZ_Asia_Manila ("PST-8")
|
||||||
|
#define TZ_Asia_Muscat ("<+04>-4")
|
||||||
|
#define TZ_Asia_Nicosia ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||||
|
#define TZ_Asia_Novokuznetsk ("<+07>-7")
|
||||||
|
#define TZ_Asia_Novosibirsk ("<+07>-7")
|
||||||
|
#define TZ_Asia_Omsk ("<+06>-6")
|
||||||
|
#define TZ_Asia_Oral ("<+05>-5")
|
||||||
|
#define TZ_Asia_Phnom_Penh ("<+07>-7")
|
||||||
|
#define TZ_Asia_Pontianak ("WIB-7")
|
||||||
|
#define TZ_Asia_Pyongyang ("KST-9")
|
||||||
|
#define TZ_Asia_Qatar ("<+03>-3")
|
||||||
|
#define TZ_Asia_Qyzylorda ("<+05>-5")
|
||||||
|
#define TZ_Asia_Riyadh ("<+03>-3")
|
||||||
|
#define TZ_Asia_Sakhalin ("<+11>-11")
|
||||||
|
#define TZ_Asia_Samarkand ("<+05>-5")
|
||||||
|
#define TZ_Asia_Seoul ("KST-9")
|
||||||
|
#define TZ_Asia_Shanghai ("CST-8")
|
||||||
|
#define TZ_Asia_Singapore ("<+08>-8")
|
||||||
|
#define TZ_Asia_Srednekolymsk ("<+11>-11")
|
||||||
|
#define TZ_Asia_Taipei ("CST-8")
|
||||||
|
#define TZ_Asia_Tashkent ("<+05>-5")
|
||||||
|
#define TZ_Asia_Tbilisi ("<+04>-4")
|
||||||
|
#define TZ_Asia_Tehran ("<+0330>-3:30")
|
||||||
|
#define TZ_Asia_Thimphu ("<+06>-6")
|
||||||
|
#define TZ_Asia_Tokyo ("JST-9")
|
||||||
|
#define TZ_Asia_Tomsk ("<+07>-7")
|
||||||
|
#define TZ_Asia_Ulaanbaatar ("<+08>-8")
|
||||||
|
#define TZ_Asia_Urumqi ("<+06>-6")
|
||||||
|
#define TZ_Asia_UstmNera ("<+10>-10")
|
||||||
|
#define TZ_Asia_Vientiane ("<+07>-7")
|
||||||
|
#define TZ_Asia_Vladivostok ("<+10>-10")
|
||||||
|
#define TZ_Asia_Yakutsk ("<+09>-9")
|
||||||
|
#define TZ_Asia_Yangon ("<+0630>-6:30")
|
||||||
|
#define TZ_Asia_Yekaterinburg ("<+05>-5")
|
||||||
|
#define TZ_Asia_Yerevan ("<+04>-4")
|
||||||
|
#define TZ_Atlantic_Azores ("<-01>1<+00>,M3.5.0/0,M10.5.0/1")
|
||||||
|
#define TZ_Atlantic_Bermuda ("AST4ADT,M3.2.0,M11.1.0")
|
||||||
|
#define TZ_Atlantic_Canary ("WET0WEST,M3.5.0/1,M10.5.0")
|
||||||
|
#define TZ_Atlantic_Cape_Verde ("<-01>1")
|
||||||
|
#define TZ_Atlantic_Faroe ("WET0WEST,M3.5.0/1,M10.5.0")
|
||||||
|
#define TZ_Atlantic_Madeira ("WET0WEST,M3.5.0/1,M10.5.0")
|
||||||
|
#define TZ_Atlantic_Reykjavik ("GMT0")
|
||||||
|
#define TZ_Atlantic_South_Georgia ("<-02>2")
|
||||||
|
#define TZ_Atlantic_Stanley ("<-03>3")
|
||||||
|
#define TZ_Atlantic_St_Helena ("GMT0")
|
||||||
|
#define TZ_Australia_Adelaide ("ACST-9:30ACDT,M10.1.0,M4.1.0/3")
|
||||||
|
#define TZ_Australia_Brisbane ("AEST-10")
|
||||||
|
#define TZ_Australia_Broken_Hill ("ACST-9:30ACDT,M10.1.0,M4.1.0/3")
|
||||||
|
#define TZ_Australia_Currie ("AEST-10AEDT,M10.1.0,M4.1.0/3")
|
||||||
|
#define TZ_Australia_Darwin ("ACST-9:30")
|
||||||
|
#define TZ_Australia_Eucla ("<+0845>-8:45")
|
||||||
|
#define TZ_Australia_Hobart ("AEST-10AEDT,M10.1.0,M4.1.0/3")
|
||||||
|
#define TZ_Australia_Lindeman ("AEST-10")
|
||||||
|
#define TZ_Australia_Lord_Howe ("<+1030>-10:30<+11>-11,M10.1.0,M4.1.0")
|
||||||
|
#define TZ_Australia_Melbourne ("AEST-10AEDT,M10.1.0,M4.1.0/3")
|
||||||
|
#define TZ_Australia_Perth ("AWST-8")
|
||||||
|
#define TZ_Australia_Sydney ("AEST-10AEDT,M10.1.0,M4.1.0/3")
|
||||||
|
#define TZ_Europe_Amsterdam ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Andorra ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Astrakhan ("<+04>-4")
|
||||||
|
#define TZ_Europe_Athens ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||||
|
#define TZ_Europe_Belgrade ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Berlin ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Bratislava ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Brussels ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Bucharest ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||||
|
#define TZ_Europe_Budapest ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Busingen ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Chisinau ("EET-2EEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Copenhagen ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Dublin ("IST-1GMT0,M10.5.0,M3.5.0/1")
|
||||||
|
#define TZ_Europe_Gibraltar ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Guernsey ("GMT0BST,M3.5.0/1,M10.5.0")
|
||||||
|
#define TZ_Europe_Helsinki ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||||
|
#define TZ_Europe_Isle_of_Man ("GMT0BST,M3.5.0/1,M10.5.0")
|
||||||
|
#define TZ_Europe_Istanbul ("<+03>-3")
|
||||||
|
#define TZ_Europe_Jersey ("GMT0BST,M3.5.0/1,M10.5.0")
|
||||||
|
#define TZ_Europe_Kaliningrad ("EET-2")
|
||||||
|
#define TZ_Europe_Kiev ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||||
|
#define TZ_Europe_Kirov ("MSK-3")
|
||||||
|
#define TZ_Europe_Lisbon ("WET0WEST,M3.5.0/1,M10.5.0")
|
||||||
|
#define TZ_Europe_Ljubljana ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_London ("GMT0BST,M3.5.0/1,M10.5.0")
|
||||||
|
#define TZ_Europe_Luxembourg ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Madrid ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Malta ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Mariehamn ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||||
|
#define TZ_Europe_Minsk ("<+03>-3")
|
||||||
|
#define TZ_Europe_Monaco ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Moscow ("MSK-3")
|
||||||
|
#define TZ_Europe_Oslo ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Paris ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Podgorica ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Prague ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Riga ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||||
|
#define TZ_Europe_Rome ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Samara ("<+04>-4")
|
||||||
|
#define TZ_Europe_San_Marino ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Sarajevo ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Saratov ("<+04>-4")
|
||||||
|
#define TZ_Europe_Simferopol ("MSK-3")
|
||||||
|
#define TZ_Europe_Skopje ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Sofia ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||||
|
#define TZ_Europe_Stockholm ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Tallinn ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||||
|
#define TZ_Europe_Tirane ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Ulyanovsk ("<+04>-4")
|
||||||
|
#define TZ_Europe_Uzhgorod ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||||
|
#define TZ_Europe_Vaduz ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Vatican ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Vienna ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Vilnius ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||||
|
#define TZ_Europe_Volgograd ("MSK-3")
|
||||||
|
#define TZ_Europe_Warsaw ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Zagreb ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Europe_Zaporozhye ("EET-2EEST,M3.5.0/3,M10.5.0/4")
|
||||||
|
#define TZ_Europe_Zurich ("CET-1CEST,M3.5.0,M10.5.0/3")
|
||||||
|
#define TZ_Indian_Antananarivo ("EAT-3")
|
||||||
|
#define TZ_Indian_Chagos ("<+06>-6")
|
||||||
|
#define TZ_Indian_Christmas ("<+07>-7")
|
||||||
|
#define TZ_Indian_Cocos ("<+0630>-6:30")
|
||||||
|
#define TZ_Indian_Comoro ("EAT-3")
|
||||||
|
#define TZ_Indian_Kerguelen ("<+05>-5")
|
||||||
|
#define TZ_Indian_Mahe ("<+04>-4")
|
||||||
|
#define TZ_Indian_Maldives ("<+05>-5")
|
||||||
|
#define TZ_Indian_Mauritius ("<+04>-4")
|
||||||
|
#define TZ_Indian_Mayotte ("EAT-3")
|
||||||
|
#define TZ_Indian_Reunion ("<+04>-4")
|
||||||
|
#define TZ_Pacific_Apia ("<+13>-13")
|
||||||
|
#define TZ_Pacific_Auckland ("NZST-12NZDT,M9.5.0,M4.1.0/3")
|
||||||
|
#define TZ_Pacific_Bougainville ("<+11>-11")
|
||||||
|
#define TZ_Pacific_Chatham ("<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45")
|
||||||
|
#define TZ_Pacific_Chuuk ("<+10>-10")
|
||||||
|
#define TZ_Pacific_Easter ("<-06>6<-05>,M9.1.6/22,M4.1.6/22")
|
||||||
|
#define TZ_Pacific_Efate ("<+11>-11")
|
||||||
|
#define TZ_Pacific_Enderbury ("<+13>-13")
|
||||||
|
#define TZ_Pacific_Fakaofo ("<+13>-13")
|
||||||
|
#define TZ_Pacific_Fiji ("<+12>-12")
|
||||||
|
#define TZ_Pacific_Funafuti ("<+12>-12")
|
||||||
|
#define TZ_Pacific_Galapagos ("<-06>6")
|
||||||
|
#define TZ_Pacific_Gambier ("<-09>9")
|
||||||
|
#define TZ_Pacific_Guadalcanal ("<+11>-11")
|
||||||
|
#define TZ_Pacific_Guam ("ChST-10")
|
||||||
|
#define TZ_Pacific_Honolulu ("HST10")
|
||||||
|
#define TZ_Pacific_Kiritimati ("<+14>-14")
|
||||||
|
#define TZ_Pacific_Kosrae ("<+11>-11")
|
||||||
|
#define TZ_Pacific_Kwajalein ("<+12>-12")
|
||||||
|
#define TZ_Pacific_Majuro ("<+12>-12")
|
||||||
|
#define TZ_Pacific_Marquesas ("<-0930>9:30")
|
||||||
|
#define TZ_Pacific_Midway ("SST11")
|
||||||
|
#define TZ_Pacific_Nauru ("<+12>-12")
|
||||||
|
#define TZ_Pacific_Niue ("<-11>11")
|
||||||
|
#define TZ_Pacific_Norfolk ("<+11>-11<+12>,M10.1.0,M4.1.0/3")
|
||||||
|
#define TZ_Pacific_Noumea ("<+11>-11")
|
||||||
|
#define TZ_Pacific_Pago_Pago ("SST11")
|
||||||
|
#define TZ_Pacific_Palau ("<+09>-9")
|
||||||
|
#define TZ_Pacific_Pitcairn ("<-08>8")
|
||||||
|
#define TZ_Pacific_Pohnpei ("<+11>-11")
|
||||||
|
#define TZ_Pacific_Port_Moresby ("<+10>-10")
|
||||||
|
#define TZ_Pacific_Rarotonga ("<-10>10")
|
||||||
|
#define TZ_Pacific_Saipan ("ChST-10")
|
||||||
|
#define TZ_Pacific_Tahiti ("<-10>10")
|
||||||
|
#define TZ_Pacific_Tarawa ("<+12>-12")
|
||||||
|
#define TZ_Pacific_Tongatapu ("<+13>-13")
|
||||||
|
#define TZ_Pacific_Wake ("<+12>-12")
|
||||||
|
#define TZ_Pacific_Wallis ("<+12>-12")
|
||||||
|
#define TZ_Etc_GMT ("GMT0")
|
||||||
|
#define TZ_Etc_GMTm0 ("GMT0")
|
||||||
|
#define TZ_Etc_GMTm1 ("<+01>-1")
|
||||||
|
#define TZ_Etc_GMTm2 ("<+02>-2")
|
||||||
|
#define TZ_Etc_GMTm3 ("<+03>-3")
|
||||||
|
#define TZ_Etc_GMTm4 ("<+04>-4")
|
||||||
|
#define TZ_Etc_GMTm5 ("<+05>-5")
|
||||||
|
#define TZ_Etc_GMTm6 ("<+06>-6")
|
||||||
|
#define TZ_Etc_GMTm7 ("<+07>-7")
|
||||||
|
#define TZ_Etc_GMTm8 ("<+08>-8")
|
||||||
|
#define TZ_Etc_GMTm9 ("<+09>-9")
|
||||||
|
#define TZ_Etc_GMTm10 ("<+10>-10")
|
||||||
|
#define TZ_Etc_GMTm11 ("<+11>-11")
|
||||||
|
#define TZ_Etc_GMTm12 ("<+12>-12")
|
||||||
|
#define TZ_Etc_GMTm13 ("<+13>-13")
|
||||||
|
#define TZ_Etc_GMTm14 ("<+14>-14")
|
||||||
|
#define TZ_Etc_GMT0 ("GMT0")
|
||||||
|
#define TZ_Etc_GMTp0 ("GMT0")
|
||||||
|
#define TZ_Etc_GMTp1 ("<-01>1")
|
||||||
|
#define TZ_Etc_GMTp2 ("<-02>2")
|
||||||
|
#define TZ_Etc_GMTp3 ("<-03>3")
|
||||||
|
#define TZ_Etc_GMTp4 ("<-04>4")
|
||||||
|
#define TZ_Etc_GMTp5 ("<-05>5")
|
||||||
|
#define TZ_Etc_GMTp6 ("<-06>6")
|
||||||
|
#define TZ_Etc_GMTp7 ("<-07>7")
|
||||||
|
#define TZ_Etc_GMTp8 ("<-08>8")
|
||||||
|
#define TZ_Etc_GMTp9 ("<-09>9")
|
||||||
|
#define TZ_Etc_GMTp10 ("<-10>10")
|
||||||
|
#define TZ_Etc_GMTp11 ("<-11>11")
|
||||||
|
#define TZ_Etc_GMTp12 ("<-12>12")
|
||||||
|
#define TZ_Etc_UCT ("UTC0")
|
||||||
|
#define TZ_Etc_UTC ("UTC0")
|
||||||
|
#define TZ_Etc_Greenwich ("GMT0")
|
||||||
|
#define TZ_Etc_Universal ("UTC0")
|
||||||
|
#define TZ_Etc_Zulu ("UTC0")
|
||||||
|
|
@ -1,22 +1,22 @@
|
||||||
/*
|
/*
|
||||||
* Tone for the Raspberry Pi Pico RP2040
|
Tone for the Raspberry Pi Pico RP2040
|
||||||
*
|
|
||||||
* Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
Copyright (c) 2021 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
*
|
|
||||||
* This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
* version 2.1 of the License, or (at your option) any later version.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
*
|
|
||||||
* This library is distributed in the hope that it will be useful,
|
This library is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
* License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include "CoreMutex.h"
|
#include "CoreMutex.h"
|
||||||
|
|
@ -28,18 +28,35 @@ typedef struct {
|
||||||
pin_size_t pin;
|
pin_size_t pin;
|
||||||
PIO pio;
|
PIO pio;
|
||||||
int sm;
|
int sm;
|
||||||
|
int off;
|
||||||
|
alarm_id_t alarm;
|
||||||
} Tone;
|
} Tone;
|
||||||
|
|
||||||
// Keep std::map safe for multicore use
|
// Keep std::map safe for multicore use
|
||||||
auto_init_mutex(_toneMutex);
|
auto_init_mutex(_toneMutex);
|
||||||
|
|
||||||
|
#include "tone2.pio.h"
|
||||||
#include "tone.pio.h"
|
static PIOProgram _tone2Pgm(&tone2_program);
|
||||||
static PIOProgram _tonePgm(&tone_program);
|
|
||||||
static std::map<pin_size_t, Tone *> _toneMap;
|
static std::map<pin_size_t, Tone *> _toneMap;
|
||||||
|
|
||||||
|
static inline bool pio_sm_get_enabled(PIO pio, uint sm) {
|
||||||
|
check_pio_param(pio);
|
||||||
|
check_sm_param(sm);
|
||||||
|
return (pio->ctrl & ~(1u << sm)) & (1 << sm);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t _stopTonePIO(alarm_id_t id, void *user_data) {
|
||||||
|
(void) id;
|
||||||
|
Tone *tone = (Tone *)user_data;
|
||||||
|
tone->alarm = 0;
|
||||||
|
digitalWrite(tone->pin, LOW);
|
||||||
|
pinMode(tone->pin, OUTPUT);
|
||||||
|
pio_sm_set_enabled(tone->pio, tone->sm, false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
||||||
if ((pin < 0) || (pin > 29)) {
|
if (pin >= __GPIOCNT) {
|
||||||
DEBUGCORE("ERROR: Illegal pin in tone (%d)\n", pin);
|
DEBUGCORE("ERROR: Illegal pin in tone (%d)\n", pin);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -50,51 +67,69 @@ void tone(uint8_t pin, unsigned int frequency, unsigned long duration) {
|
||||||
|
|
||||||
// Ensure only 1 core can start or stop at a time
|
// Ensure only 1 core can start or stop at a time
|
||||||
CoreMutex m(&_toneMutex);
|
CoreMutex m(&_toneMutex);
|
||||||
if (!m) return; // Weird deadlock case
|
if (!m) {
|
||||||
|
return; // Weird deadlock case
|
||||||
int us = 1000000 / frequency / 2;
|
|
||||||
if (us < 5) {
|
|
||||||
us = 5;
|
|
||||||
}
|
}
|
||||||
// Even phases run forever, odd phases end after count...so ensure its odd
|
|
||||||
int phases = duration ? (duration * 1000 / us) | 1 : 2;
|
unsigned int delay = (RP2040::f_cpu() + frequency) / (frequency * 2) - 3; // rounded
|
||||||
auto entry = _toneMap.find(pin);
|
auto entry = _toneMap.find(pin);
|
||||||
if (entry != _toneMap.end()) {
|
Tone *newTone;
|
||||||
noTone(pin);
|
if (entry == _toneMap.end()) {
|
||||||
|
newTone = new Tone();
|
||||||
|
newTone->pin = pin;
|
||||||
|
pinMode(pin, OUTPUT);
|
||||||
|
if (!_tone2Pgm.prepare(&newTone->pio, &newTone->sm, &newTone->off, pin, 1)) {
|
||||||
|
DEBUGCORE("ERROR: tone unable to start, out of PIO resources\n");
|
||||||
|
// ERROR, no free slots
|
||||||
|
delete newTone;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
newTone->alarm = 0;
|
||||||
|
} else {
|
||||||
|
newTone = entry->second;
|
||||||
|
if (newTone->alarm) {
|
||||||
|
cancel_alarm(newTone->alarm);
|
||||||
|
newTone->alarm = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (!pio_sm_get_enabled(newTone->pio, newTone->sm)) {
|
||||||
auto newTone = new Tone();
|
tone2_program_init(newTone->pio, newTone->sm, newTone->off, pin);
|
||||||
newTone->pin = pin;
|
|
||||||
pinMode(pin, OUTPUT);
|
|
||||||
int off;
|
|
||||||
if (!_tonePgm.prepare(&newTone->pio, &newTone->sm, &off)) {
|
|
||||||
DEBUGCORE("ERROR: tone unable to start, out of PIO resources\n");
|
|
||||||
// ERROR, no free slots
|
|
||||||
delete newTone;
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
tone_program_init(newTone->pio, newTone->sm, off, pin);
|
pio_sm_clear_fifos(newTone->pio, newTone->sm); // Remove any old updates that haven't yet taken effect
|
||||||
pio_sm_set_enabled(newTone->pio, newTone->sm, false);
|
pio_sm_put_blocking(newTone->pio, newTone->sm, delay);
|
||||||
pio_sm_put_blocking(newTone->pio, newTone->sm, RP2040::usToPIOCycles(us));
|
|
||||||
pio_sm_exec(newTone->pio, newTone->sm, pio_encode_pull(false, false));
|
pio_sm_exec(newTone->pio, newTone->sm, pio_encode_pull(false, false));
|
||||||
pio_sm_exec(newTone->pio, newTone->sm, pio_encode_out(pio_isr, 32));
|
pio_sm_exec(newTone->pio, newTone->sm, pio_encode_mov(pio_x, pio_osr));
|
||||||
pio_sm_set_enabled(newTone->pio, newTone->sm, true);
|
pio_sm_set_enabled(newTone->pio, newTone->sm, true);
|
||||||
pio_sm_put_blocking(newTone->pio, newTone->sm, phases);
|
|
||||||
|
|
||||||
_toneMap.insert({pin, newTone});
|
_toneMap.insert({pin, newTone});
|
||||||
|
|
||||||
|
if (duration) {
|
||||||
|
auto ret = add_alarm_in_ms(duration, _stopTonePIO, (void *)newTone, true);
|
||||||
|
if (ret > 0) {
|
||||||
|
newTone->alarm = ret;
|
||||||
|
} else {
|
||||||
|
DEBUGCORE("ERROR: Unable to allocate timer for tone(%d, %d, %lu)\n",
|
||||||
|
pin, frequency, duration);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void noTone(uint8_t pin) {
|
void noTone(uint8_t pin) {
|
||||||
CoreMutex m(&_toneMutex);
|
CoreMutex m(&_toneMutex);
|
||||||
|
|
||||||
if ((pin < 0) || (pin > 29) || !m) {
|
if ((pin > __GPIOCNT) || !m) {
|
||||||
DEBUGCORE("ERROR: Illegal pin in tone (%d)\n", pin);
|
DEBUGCORE("ERROR: Illegal pin in tone (%d)\n", pin);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto entry = _toneMap.find(pin);
|
auto entry = _toneMap.find(pin);
|
||||||
if (entry != _toneMap.end()) {
|
if (entry != _toneMap.end()) {
|
||||||
|
if (entry->second->alarm) {
|
||||||
|
cancel_alarm(entry->second->alarm);
|
||||||
|
entry->second->alarm = 0;
|
||||||
|
}
|
||||||
pio_sm_set_enabled(entry->second->pio, entry->second->sm, false);
|
pio_sm_set_enabled(entry->second->pio, entry->second->sm, false);
|
||||||
pio_sm_unclaim(entry->second->pio, entry->second->sm);
|
pio_sm_unclaim(entry->second->pio, entry->second->sm);
|
||||||
|
delete entry->second;
|
||||||
_toneMap.erase(entry);
|
_toneMap.erase(entry);
|
||||||
pinMode(pin, OUTPUT);
|
pinMode(pin, OUTPUT);
|
||||||
digitalWrite(pin, LOW);
|
digitalWrite(pin, LOW);
|
||||||
|
|
|
||||||
|
|
@ -1,44 +1,44 @@
|
||||||
/*
|
/*
|
||||||
Copyright (c) 2014 Arduino. All right reserved.
|
Copyright (c) 2014 Arduino. All right reserved.
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
This library is free software; you can redistribute it and/or
|
||||||
modify it under the terms of the GNU Lesser General Public
|
modify it under the terms of the GNU Lesser General Public
|
||||||
License as published by the Free Software Foundation; either
|
License as published by the Free Software Foundation; either
|
||||||
version 2.1 of the License, or (at your option) any later version.
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
This library is distributed in the hope that it will be useful,
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
See the GNU Lesser General Public License for more details.
|
See the GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser General Public
|
You should have received a copy of the GNU Lesser General Public
|
||||||
License along with this library; if not, write to the Free Software
|
License along with this library; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "stdlib.h"
|
#include <stdlib.h>
|
||||||
#include "stdint.h"
|
#include <stdint.h>
|
||||||
|
|
||||||
void randomSeed( uint32_t dwSeed ) {
|
void randomSeed(uint32_t dwSeed) {
|
||||||
if ( dwSeed != 0 ) {
|
if (dwSeed != 0) {
|
||||||
srand( dwSeed ) ;
|
srand(dwSeed) ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
long random( long howbig ) {
|
long random(long howbig) {
|
||||||
if ( howbig == 0 ) {
|
if (howbig == 0) {
|
||||||
return 0 ;
|
return 0 ;
|
||||||
}
|
}
|
||||||
|
|
||||||
return rand() % howbig;
|
return rand() % howbig;
|
||||||
}
|
}
|
||||||
|
|
||||||
long random( long howsmall, long howbig ) {
|
long random(long howsmall, long howbig) {
|
||||||
if (howsmall >= howbig) {
|
if (howsmall >= howbig) {
|
||||||
return howsmall;
|
return howsmall;
|
||||||
}
|
}
|
||||||
|
|
||||||
long diff = howbig - howsmall;
|
long diff = howbig - howsmall;
|
||||||
|
|
||||||
return random(diff) + howsmall;
|
return random(diff) + howsmall;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
1
cores/rp2040/WString.h
Normal file
1
cores/rp2040/WString.h
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
#include "api/String.h"
|
||||||
62
cores/rp2040/_freertos.cpp
Normal file
62
cores/rp2040/_freertos.cpp
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
_freertos.cpp - Internal core definitions for FreeRTOS
|
||||||
|
|
||||||
|
Copyright (c) 2022 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "_freertos.h"
|
||||||
|
#include <pico/mutex.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "Arduino.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
mutex_t *src;
|
||||||
|
SemaphoreHandle_t dst;
|
||||||
|
} FMMap;
|
||||||
|
|
||||||
|
static FMMap *_map = nullptr;
|
||||||
|
SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive) {
|
||||||
|
if (!_map) {
|
||||||
|
_map = (FMMap *)calloc(16, sizeof(FMMap));
|
||||||
|
}
|
||||||
|
// Pre-existing map
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
if (m == _map[i].src) {
|
||||||
|
return _map[i].dst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++) {
|
||||||
|
if (_map[i].src == nullptr) {
|
||||||
|
// Make a new mutex
|
||||||
|
SemaphoreHandle_t fm;
|
||||||
|
if (recursive) {
|
||||||
|
fm = _freertos_recursive_mutex_create();
|
||||||
|
} else {
|
||||||
|
fm = __freertos_mutex_create();
|
||||||
|
}
|
||||||
|
if (fm == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
_map[i].src = m;
|
||||||
|
_map[i].dst = fm;
|
||||||
|
return fm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr; // Need to make space for more mutex maps!
|
||||||
|
}
|
||||||
65
cores/rp2040/_freertos.h
Normal file
65
cores/rp2040/_freertos.h
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
_freertos.h - Internal core definitions for FreeRTOS
|
||||||
|
|
||||||
|
Copyright (c) 2022 Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||||
|
|
||||||
|
This library is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 2.1 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
This library is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with this library; if not, write to the Free Software
|
||||||
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <pico/mutex.h>
|
||||||
|
|
||||||
|
// Cannot include refs to FreeRTOS's actual semaphore calls because they
|
||||||
|
// are implemented as macros, so we have a wrapper in our variant hook
|
||||||
|
// to handle it.
|
||||||
|
|
||||||
|
extern bool __isFreeRTOS;
|
||||||
|
|
||||||
|
// FreeRTOS has been set up
|
||||||
|
extern volatile bool __freeRTOSinitted;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif // __cplusplus
|
||||||
|
struct QueueDefinition; /* Using old naming convention so as not to break kernel aware debuggers. */
|
||||||
|
typedef struct QueueDefinition * QueueHandle_t;
|
||||||
|
typedef QueueHandle_t SemaphoreHandle_t;
|
||||||
|
typedef int32_t BaseType_t;
|
||||||
|
|
||||||
|
extern bool __freertos_check_if_in_isr() __attribute__((weak));
|
||||||
|
|
||||||
|
extern SemaphoreHandle_t __freertos_mutex_create() __attribute__((weak));
|
||||||
|
extern SemaphoreHandle_t _freertos_recursive_mutex_create() __attribute__((weak));
|
||||||
|
|
||||||
|
extern void __freertos_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||||
|
|
||||||
|
extern int __freertos_mutex_take_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __attribute__((weak));
|
||||||
|
extern int __freertos_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||||
|
extern void __freertos_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||||
|
extern void __freertos_mutex_give_from_isr(SemaphoreHandle_t mtx, BaseType_t* pxHigherPriorityTaskWoken) __attribute__((weak));
|
||||||
|
|
||||||
|
extern void __freertos_recursive_mutex_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||||
|
extern int __freertos_recursive_mutex_try_take(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||||
|
extern void __freertos_recursive_mutex_give(SemaphoreHandle_t mtx) __attribute__((weak));
|
||||||
|
|
||||||
|
extern void __freertos_idle_other_core() __attribute__((weak));
|
||||||
|
extern void __freertos_resume_other_core() __attribute__((weak));
|
||||||
|
|
||||||
|
extern void __freertos_task_exit_critical() __attribute__((weak));
|
||||||
|
extern void __freertos_task_enter_critical() __attribute__((weak));
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
extern SemaphoreHandle_t __get_freertos_mutex_for_ptr(mutex_t *m, bool recursive = false);
|
||||||
|
#endif // __cplusplus
|
||||||
7
cores/rp2040/_needsbt.h
Normal file
7
cores/rp2040/_needsbt.h
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
// Simple helper header to ensure pico libs support ?BT
|
||||||
|
|
||||||
|
#ifndef ENABLE_CLASSIC
|
||||||
|
#define ENABLE_CLASSIC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static_assert(ENABLE_CLASSIC, "This library needs Bluetooth enabled. Use the 'Tools->IP/Bluetooth Stack' menu in the IDE to enable it.");
|
||||||
1478
cores/rp2040/_xoshiro.h
Normal file
1478
cores/rp2040/_xoshiro.h
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -1 +0,0 @@
|
||||||
../../ArduinoCore-API/api/
|
|
||||||
2
cores/rp2040/api/ArduinoAPI.h
Normal file
2
cores/rp2040/api/ArduinoAPI.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/ArduinoAPI.h"
|
||||||
2
cores/rp2040/api/Binary.h
Normal file
2
cores/rp2040/api/Binary.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/Binary.h"
|
||||||
2
cores/rp2040/api/Client.h
Normal file
2
cores/rp2040/api/Client.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/Client.h"
|
||||||
1
cores/rp2040/api/Common.cpp
Normal file
1
cores/rp2040/api/Common.cpp
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
#include "../../../ArduinoCore-API/api/Common.cpp"
|
||||||
2
cores/rp2040/api/Common.h
Normal file
2
cores/rp2040/api/Common.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/Common.h"
|
||||||
2
cores/rp2040/api/Compat.h
Normal file
2
cores/rp2040/api/Compat.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/Compat.h"
|
||||||
2
cores/rp2040/api/HardwareI2C.h
Normal file
2
cores/rp2040/api/HardwareI2C.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/HardwareI2C.h"
|
||||||
2
cores/rp2040/api/HardwareSPI.h
Normal file
2
cores/rp2040/api/HardwareSPI.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/HardwareSPI.h"
|
||||||
2
cores/rp2040/api/HardwareSerial.h
Normal file
2
cores/rp2040/api/HardwareSerial.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/HardwareSerial.h"
|
||||||
1
cores/rp2040/api/IPAddress.cpp
Normal file
1
cores/rp2040/api/IPAddress.cpp
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
#include "../../../ArduinoCore-API/api/IPAddress.cpp"
|
||||||
2
cores/rp2040/api/IPAddress.h
Normal file
2
cores/rp2040/api/IPAddress.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/IPAddress.h"
|
||||||
2
cores/rp2040/api/Interrupts.h
Normal file
2
cores/rp2040/api/Interrupts.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/Interrupts.h"
|
||||||
1
cores/rp2040/api/PluggableUSB.cpp
Normal file
1
cores/rp2040/api/PluggableUSB.cpp
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
#include "../../../ArduinoCore-API/api/PluggableUSB.cpp"
|
||||||
2
cores/rp2040/api/PluggableUSB.h
Normal file
2
cores/rp2040/api/PluggableUSB.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/PluggableUSB.h"
|
||||||
1
cores/rp2040/api/Print.cpp
Normal file
1
cores/rp2040/api/Print.cpp
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
#include "../../../ArduinoCore-API/api/Print.cpp"
|
||||||
2
cores/rp2040/api/Print.h
Normal file
2
cores/rp2040/api/Print.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/Print.h"
|
||||||
2
cores/rp2040/api/Printable.h
Normal file
2
cores/rp2040/api/Printable.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/Printable.h"
|
||||||
1
cores/rp2040/api/RingBuffer.h
Normal file
1
cores/rp2040/api/RingBuffer.h
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
#include "../../../ArduinoCore-API/api/RingBuffer.h"
|
||||||
2
cores/rp2040/api/Server.h
Normal file
2
cores/rp2040/api/Server.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/Server.h"
|
||||||
1
cores/rp2040/api/Stream.cpp
Normal file
1
cores/rp2040/api/Stream.cpp
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
#include "../../../ArduinoCore-API/api/Stream.cpp"
|
||||||
2
cores/rp2040/api/Stream.h
Normal file
2
cores/rp2040/api/Stream.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/Stream.h"
|
||||||
1
cores/rp2040/api/String.cpp
Normal file
1
cores/rp2040/api/String.cpp
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
#include "../../../ArduinoCore-API/api/String.cpp"
|
||||||
2
cores/rp2040/api/String.h
Normal file
2
cores/rp2040/api/String.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/String.h"
|
||||||
2
cores/rp2040/api/USBAPI.h
Normal file
2
cores/rp2040/api/USBAPI.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/USBAPI.h"
|
||||||
2
cores/rp2040/api/Udp.h
Normal file
2
cores/rp2040/api/Udp.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/Udp.h"
|
||||||
2
cores/rp2040/api/WCharacter.h
Normal file
2
cores/rp2040/api/WCharacter.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../ArduinoCore-API/api/WCharacter.h"
|
||||||
1
cores/rp2040/api/deprecated-avr-comp/avr/dtostrf.c.impl
Normal file
1
cores/rp2040/api/deprecated-avr-comp/avr/dtostrf.c.impl
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
#include "../../../../../ArduinoCore-API/api/deprecated-avr-comp/avr/dtostrf.c.impl"
|
||||||
2
cores/rp2040/api/deprecated-avr-comp/avr/dtostrf.h
Normal file
2
cores/rp2040/api/deprecated-avr-comp/avr/dtostrf.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../../../ArduinoCore-API/api/deprecated-avr-comp/avr/dtostrf.h"
|
||||||
2
cores/rp2040/api/deprecated-avr-comp/avr/interrupt.h
Normal file
2
cores/rp2040/api/deprecated-avr-comp/avr/interrupt.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../../../ArduinoCore-API/api/deprecated-avr-comp/avr/interrupt.h"
|
||||||
2
cores/rp2040/api/deprecated-avr-comp/avr/pgmspace.h
Normal file
2
cores/rp2040/api/deprecated-avr-comp/avr/pgmspace.h
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
#pragma once
|
||||||
|
#include "../../../../../ArduinoCore-API/api/deprecated-avr-comp/avr/pgmspace.h"
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue