mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-07-02 02:51:42 +00:00
Compare commits
580 Commits
v2024.1.1-
...
v2025.0.0-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a7173dbd3c | ||
|
|
2ff7033edf | ||
|
|
ca92ef89d3 | ||
|
|
b8c2571638 | ||
|
|
d2b1aa1869 | ||
|
|
76a3a60712 | ||
|
|
f5df6f88c8 | ||
|
|
7f5970b27a | ||
|
|
25865759f4 | ||
|
|
e2893fc1a3 | ||
|
|
b6bd798f9e | ||
|
|
66c0abb732 | ||
|
|
e884221a8d | ||
|
|
3a0ee5c9a7 | ||
|
|
bb8480c690 | ||
|
|
d3aa7f85dd | ||
|
|
3d6b710293 | ||
|
|
ae6954c78f | ||
|
|
a087544933 | ||
|
|
b9935c9885 | ||
|
|
3617a95260 | ||
|
|
b0cc84a9c7 | ||
|
|
e2dcbd016d | ||
|
|
72ae751b9a | ||
|
|
27cbbfe2ab | ||
|
|
65c6306047 | ||
|
|
a0efc9ca31 | ||
|
|
917b5dde66 | ||
|
|
300595da9e | ||
|
|
0606da64c9 | ||
|
|
1c884b2260 | ||
|
|
5b94421b5a | ||
|
|
ad18fa62ee | ||
|
|
5221069bcc | ||
|
|
df4694c9df | ||
|
|
b99d9c1710 | ||
|
|
d6b66bfa55 | ||
|
|
8def7b2222 | ||
|
|
afaf7e2c3f | ||
|
|
5f8c842223 | ||
|
|
bdc42532ed | ||
|
|
21e970f2cd | ||
|
|
38ee6476f2 | ||
|
|
a97904ed1f | ||
|
|
1828fdaaa4 | ||
|
|
7751f6d1d2 | ||
|
|
7c8a36f3eb | ||
|
|
ae8e4289b9 | ||
|
|
c1fc86033a | ||
|
|
9782abbcb1 | ||
|
|
0ad4cd69d0 | ||
|
|
76685fe7e8 | ||
|
|
3b8d8a367b | ||
|
|
a6ac4228c3 | ||
|
|
98fcbdb44e | ||
|
|
958387ddd3 | ||
|
|
a2f2502f70 | ||
|
|
fbfef85f45 | ||
|
|
cdbd64c3df | ||
|
|
eb3635e622 | ||
|
|
9ef6d13b27 | ||
|
|
e2545231b8 | ||
|
|
4252a36668 | ||
|
|
f1e072fc98 | ||
|
|
221d568bd9 | ||
|
|
c62396ce4e | ||
|
|
f42bc45ee8 | ||
|
|
8c107e4b75 | ||
|
|
652c721895 | ||
|
|
7e00f2d3eb | ||
|
|
5c5e5af0c6 | ||
|
|
237ebfd0f2 | ||
|
|
dc0e9712e6 | ||
|
|
d05c7c125b | ||
|
|
294c9946ae | ||
|
|
6220c6be4d | ||
|
|
72a6d22d9a | ||
|
|
8834cb1de4 | ||
|
|
ae655a3a71 | ||
|
|
65f4505e3c | ||
|
|
badd090538 | ||
|
|
2fd8dae503 | ||
|
|
27efd37c52 | ||
|
|
0c822b45ab | ||
|
|
58751338ec | ||
|
|
0b5aec82ff | ||
|
|
820f68dc08 | ||
|
|
8c420fa4c1 | ||
|
|
ab315e24c8 | ||
|
|
0f45fe9486 | ||
|
|
7fc17811fa | ||
|
|
7fbbecb5b7 | ||
|
|
b0d3bf4ddf | ||
|
|
40b35f0d51 | ||
|
|
637647b941 | ||
|
|
0a967e0e62 | ||
|
|
4ce8f3f935 | ||
|
|
178fe99f12 | ||
|
|
305a0657e2 | ||
|
|
fb3e0e1ecb | ||
|
|
2e828ae053 | ||
|
|
d3af27be94 | ||
|
|
4cb2edbb98 | ||
|
|
d88c71ffdc | ||
|
|
6c9dcc157e | ||
|
|
dc00a13d83 | ||
|
|
bdc7344df1 | ||
|
|
a6dd95eb9e | ||
|
|
2563ff9f18 | ||
|
|
f77d01c085 | ||
|
|
408980462f | ||
|
|
2e71e85b8d | ||
|
|
6a73ca8c08 | ||
|
|
9ed2f66914 | ||
|
|
d3060d8eba | ||
|
|
27babe5584 | ||
|
|
7596aeda10 | ||
|
|
c76b358290 | ||
|
|
bad56bcbe8 | ||
|
|
e172aa66f7 | ||
|
|
9c7120e6bf | ||
|
|
0afc35f336 | ||
|
|
ae4bcefefc | ||
|
|
513d1a0a15 | ||
|
|
a85e7693de | ||
|
|
5359112b15 | ||
|
|
7601b7250a | ||
|
|
a9cfd0d0f9 | ||
|
|
c71db8ea9c | ||
|
|
70417f64da | ||
|
|
f5e08652f8 | ||
|
|
eec99eb653 | ||
|
|
9cae707065 | ||
|
|
0f8aa8aedf | ||
|
|
ac32f921f6 | ||
|
|
67fe11f9cd | ||
|
|
1ec089c7f9 | ||
|
|
1727c74b80 | ||
|
|
890185acee | ||
|
|
fd363fdf5a | ||
|
|
1e4a647918 | ||
|
|
39d33bfca6 | ||
|
|
5edc652c05 | ||
|
|
d9eb3691d8 | ||
|
|
a42ffb8fa4 | ||
|
|
d4e6a068ac | ||
|
|
cdfa2ece6f | ||
|
|
962bf7ff10 | ||
|
|
2cd3935aa8 | ||
|
|
427b7dcc11 | ||
|
|
e73050a8fa | ||
|
|
3e6c0d0b71 | ||
|
|
dc4c63568a | ||
|
|
b620b6a4dd | ||
|
|
d7dfa63ae9 | ||
|
|
e89c8c1008 | ||
|
|
abfe2488ff | ||
|
|
3e5187ff32 | ||
|
|
7bc0380694 | ||
|
|
98d2f45fa9 | ||
|
|
d14dfed828 | ||
|
|
f26adc556d | ||
|
|
3c14d87006 | ||
|
|
77536e68f0 | ||
|
|
c88be31ec2 | ||
|
|
74f648689e | ||
|
|
2def62a1ef | ||
|
|
3a5d24ab1d | ||
|
|
02c78bc9b6 | ||
|
|
998340296d | ||
|
|
d26e6d9ecc | ||
|
|
fbb3669546 | ||
|
|
c46847b32a | ||
|
|
33f12f0e31 | ||
|
|
25ad6eafd5 | ||
|
|
84a55d13f3 | ||
|
|
4a548935d3 | ||
|
|
85ea5f8497 | ||
|
|
c32e7db8e3 | ||
|
|
2392c9f278 | ||
|
|
0dbdbb2aac | ||
|
|
b38540e1af | ||
|
|
ff929d4a5f | ||
|
|
b2113d3a9a | ||
|
|
5370f249a1 | ||
|
|
74057543aa | ||
|
|
b4674bacb9 | ||
|
|
fd4424eb89 | ||
|
|
c10f7d91b7 | ||
|
|
0b13459469 | ||
|
|
a1af2357e8 | ||
|
|
3116f790ea | ||
|
|
0e013dc021 | ||
|
|
f74f6f1d42 | ||
|
|
11c60df3e0 | ||
|
|
3d9152a461 | ||
|
|
fbd239d15e | ||
|
|
7cd4a75323 | ||
|
|
973bb55e66 | ||
|
|
7bd8c44570 | ||
|
|
38c128fe6a | ||
|
|
18e57f7872 | ||
|
|
ccb4cbed63 | ||
|
|
c19ee8b0fe | ||
|
|
e64c20346d | ||
|
|
f1a1ffd7fc | ||
|
|
c27ddf5ef9 | ||
|
|
8b669330eb | ||
|
|
ca6e307ea5 | ||
|
|
607682b687 | ||
|
|
4b94a64b06 | ||
|
|
63d9e945b8 | ||
|
|
0ad6b3acb3 | ||
|
|
02aed35c6e | ||
|
|
a8a352ed8c | ||
|
|
0cdab55e5b | ||
|
|
ba15844c28 | ||
|
|
6afff99640 | ||
|
|
d4d0545dc1 | ||
|
|
9ed0631ec9 | ||
|
|
fb947fe998 | ||
|
|
6b6a55b72e | ||
|
|
1e168f363e | ||
|
|
da3abade83 | ||
|
|
62cba9a4d3 | ||
|
|
3207795d0d | ||
|
|
e506e09a06 | ||
|
|
163f7ee704 | ||
|
|
e9c744c456 | ||
|
|
300419c151 | ||
|
|
1db3936965 | ||
|
|
4f9d73783b | ||
|
|
3b2a2381b6 | ||
|
|
6cc7e52de7 | ||
|
|
d4533a8900 | ||
|
|
90bb6cfffa | ||
|
|
cb094e4ff6 | ||
|
|
60c6ed9812 | ||
|
|
ee15cc172a | ||
|
|
1016e95242 | ||
|
|
19f1903959 | ||
|
|
53ebb6679e | ||
|
|
177132fa2a | ||
|
|
bbb230491a | ||
|
|
84ef71ace0 | ||
|
|
68736d802d | ||
|
|
d895a0c09f | ||
|
|
64a9d413bf | ||
|
|
a70e83ae2e | ||
|
|
47652d7a3c | ||
|
|
be78552db7 | ||
|
|
3acae550d6 | ||
|
|
9d55941ce5 | ||
|
|
51d92c7027 | ||
|
|
9206b47d67 | ||
|
|
6fc16264ce | ||
|
|
ad18f35477 | ||
|
|
0c6bd846bc | ||
|
|
19c1556472 | ||
|
|
3928ed5647 | ||
|
|
e408f3ad27 | ||
|
|
7957f4a625 | ||
|
|
1241dfdf68 | ||
|
|
4d109309c9 | ||
|
|
7560d18e09 | ||
|
|
f518e143d0 | ||
|
|
6fab87fa4c | ||
|
|
42c41785ac | ||
|
|
1a7eeb6282 | ||
|
|
98c0827236 | ||
|
|
57aa8ca0dd | ||
|
|
789af2ad26 | ||
|
|
9a5366bb83 | ||
|
|
77c09b9ce2 | ||
|
|
9ec27c1202 | ||
|
|
d653408873 | ||
|
|
24a24c9051 | ||
|
|
0e5eb3f35c | ||
|
|
4b15c73f64 | ||
|
|
a274e297cd | ||
|
|
d198605562 | ||
|
|
dfaad7ca22 | ||
|
|
2df82ec957 | ||
|
|
3661f485af | ||
|
|
7f9389f101 | ||
|
|
ca35bcd827 | ||
|
|
9227d09960 | ||
|
|
370126db38 | ||
|
|
1330235918 | ||
|
|
d392570659 | ||
|
|
a2d45dbca4 | ||
|
|
30965b20cf | ||
|
|
5bc942f532 | ||
|
|
97828bd325 | ||
|
|
6da21c4943 | ||
|
|
ecf1755e3e | ||
|
|
154d920e67 | ||
|
|
d2ee423749 | ||
|
|
7e3678b0a4 | ||
|
|
4a55d830e4 | ||
|
|
420020c0d5 | ||
|
|
077c8f4092 | ||
|
|
84e3a22baa | ||
|
|
b482321c0d | ||
|
|
d181e353a0 | ||
|
|
2386e44f3a | ||
|
|
fa5b604f16 | ||
|
|
67e8306819 | ||
|
|
1981b8debd | ||
|
|
ba9c21cf38 | ||
|
|
211c2a375c | ||
|
|
75b2fa1cc3 | ||
|
|
84b089b209 | ||
|
|
ce550705d7 | ||
|
|
3989617bde | ||
|
|
f1836e1321 | ||
|
|
d05f179a9a | ||
|
|
b1b03bed85 | ||
|
|
fa63fbf446 | ||
|
|
4809f3d0fc | ||
|
|
dd90965362 | ||
|
|
8659372d08 | ||
|
|
a2e4d0b15d | ||
|
|
0a46a3a618 | ||
|
|
7c26bc70ab | ||
|
|
f94e3d81b9 | ||
|
|
6bed82a18e | ||
|
|
4595f84719 | ||
|
|
707cb06105 | ||
|
|
3e40b9e5da | ||
|
|
106518c3f8 | ||
|
|
19cb2a8eb4 | ||
|
|
13f4460e00 | ||
|
|
4210f5635d | ||
|
|
0f060afb55 | ||
|
|
f29a7d2e50 | ||
|
|
6e58db398d | ||
|
|
4ac0720385 | ||
|
|
44db3e0ac0 | ||
|
|
73c7d87db7 | ||
|
|
25636b712f | ||
|
|
01fb98baaa | ||
|
|
5c424248c4 | ||
|
|
c486972c55 | ||
|
|
783acb9b72 | ||
|
|
99ab836894 | ||
|
|
ad0859a8c9 | ||
|
|
5579219716 | ||
|
|
98f06911c7 | ||
|
|
e1d49b975c | ||
|
|
8a0bf2b7a4 | ||
|
|
91d8837c11 | ||
|
|
e7c9f27683 | ||
|
|
8aca706217 | ||
|
|
7d3e4ddba9 | ||
|
|
ec3cb3dcba | ||
|
|
495585b25d | ||
|
|
f9aabc5ab2 | ||
|
|
c16946c0ec | ||
|
|
b7f4eb2811 | ||
|
|
f419a62b38 | ||
|
|
938bf45fd9 | ||
|
|
c34debe012 | ||
|
|
07183765de | ||
|
|
af46034b7f | ||
|
|
636ef58d94 | ||
|
|
cc631d2a69 | ||
|
|
09f76b32c2 | ||
|
|
47c5fd8620 | ||
|
|
24a76be694 | ||
|
|
9333951736 | ||
|
|
6a2d3c30a6 | ||
|
|
e07de37e64 | ||
|
|
141241d2d6 | ||
|
|
f2c2bab7dc | ||
|
|
5659038443 | ||
|
|
8aeee03626 | ||
|
|
55508706ff | ||
|
|
ab78b930e9 | ||
|
|
795d4be9fd | ||
|
|
7aa9ad44b8 | ||
|
|
92c81d0791 | ||
|
|
1ce617be07 | ||
|
|
2441b57156 | ||
|
|
21d1972d7a | ||
|
|
c29e8c66cf | ||
|
|
ab309e34ef | ||
|
|
22a322c9f3 | ||
|
|
1dba26c937 | ||
|
|
ef1cb3f41e | ||
|
|
aeb1a4aa33 | ||
|
|
c1178d5add | ||
|
|
4e4a468d4d | ||
|
|
d1793f077d | ||
|
|
43fb6e9f87 | ||
|
|
bcef6c5398 | ||
|
|
4059e0cd9f | ||
|
|
0b2cfb3abc | ||
|
|
df5e439b0c | ||
|
|
0ff7478968 | ||
|
|
6f23d32fe1 | ||
|
|
35a1c52788 | ||
|
|
e4e2bafdb1 | ||
|
|
3d201c71f7 | ||
|
|
f02984159f | ||
|
|
a004c9e05f | ||
|
|
0b4c6a1546 | ||
|
|
ab15dae887 | ||
|
|
9599c1f56f | ||
|
|
f87c64af8a | ||
|
|
8798700cec | ||
|
|
85c9ae6eff | ||
|
|
7c8b7a97ad | ||
|
|
d9b504bc84 | ||
|
|
906b810136 | ||
|
|
56e5b404d1 | ||
|
|
8723ee5c39 | ||
|
|
192a28af47 | ||
|
|
d40bdd70ba | ||
|
|
7bfadf32e5 | ||
|
|
a770110438 | ||
|
|
54a55b8b53 | ||
|
|
7d4e515a6b | ||
|
|
5200316c14 | ||
|
|
ddf79a25d4 | ||
|
|
a71adef316 | ||
|
|
39a0bf4b98 | ||
|
|
f5fc101fda | ||
|
|
38bf024c96 | ||
|
|
9d11544c18 | ||
|
|
28deba20f5 | ||
|
|
c2971c0bb3 | ||
|
|
41cfc961e4 | ||
|
|
14c3ade155 | ||
|
|
90757b9e90 | ||
|
|
2676b77873 | ||
|
|
d32c10487c | ||
|
|
9bc5fcf886 | ||
|
|
d431abba3b | ||
|
|
2bb1409b82 | ||
|
|
66172ab288 | ||
|
|
e8f8c0ceb0 | ||
|
|
890992a849 | ||
|
|
a583ca01e1 | ||
|
|
ca272de400 | ||
|
|
76ae090570 | ||
|
|
5172ab8fd0 | ||
|
|
96914143ba | ||
|
|
464e6121ef | ||
|
|
5dad46cd45 | ||
|
|
54ab65a63a | ||
|
|
7ed900ae3a | ||
|
|
74b85b76a9 | ||
|
|
30816111db | ||
|
|
5cc923de33 | ||
|
|
1144115da0 | ||
|
|
ac7d726ac3 | ||
|
|
e09be72ee0 | ||
|
|
0f9ebe92d9 | ||
|
|
9fa28eb07a | ||
|
|
ca684ac207 | ||
|
|
51eecef2bd | ||
|
|
4fcf0b25a1 | ||
|
|
9b8011aa67 | ||
|
|
e00a0e84c1 | ||
|
|
23dd591394 | ||
|
|
b0719942f0 | ||
|
|
7bc89c4322 | ||
|
|
841ea682d1 | ||
|
|
a74db52dae | ||
|
|
a7eb422662 | ||
|
|
544b231d4d | ||
|
|
31cd015970 | ||
|
|
9280054eab | ||
|
|
2aba97c610 | ||
|
|
c80b2d2017 | ||
|
|
3c0652c18a | ||
|
|
95716eb0cb | ||
|
|
423fd75fa8 | ||
|
|
dfdea9c992 | ||
|
|
ca81ced409 | ||
|
|
437cc91af5 | ||
|
|
25b7dca46b | ||
|
|
bb05e20247 | ||
|
|
35744a036e | ||
|
|
80d7ad58ea | ||
|
|
f8d983b154 | ||
|
|
4a44210ee3 | ||
|
|
bdc8620d55 | ||
|
|
0ca1e9b5f9 | ||
|
|
cc30824409 | ||
|
|
b1fad062f7 | ||
|
|
ead9ae5a69 | ||
|
|
cfbff32185 | ||
|
|
7d90d0bcc3 | ||
|
|
7755e45aac | ||
|
|
3985c031da | ||
|
|
7a87fe4b60 | ||
|
|
09f3ed6a5f | ||
|
|
79dd795bc0 | ||
|
|
e117274a67 | ||
|
|
a8b80ca256 | ||
|
|
b3a9c3e96b | ||
|
|
0f8129677b | ||
|
|
d105f9e3e9 | ||
|
|
c5f2f6a0fb | ||
|
|
c1a57e422a | ||
|
|
78ebc6e9ec | ||
|
|
9ada181866 | ||
|
|
95fa5ec72f | ||
|
|
b6f2d3cc14 | ||
|
|
cc2cbeb04c | ||
|
|
fa6b171e1c | ||
|
|
d504639bbe | ||
|
|
3a1194be40 | ||
|
|
70392cbbcb | ||
|
|
17c1bd5a83 | ||
|
|
e69a9efeba | ||
|
|
14dcd0d26f | ||
|
|
ec1d261984 | ||
|
|
63dbf5c614 | ||
|
|
b2e7be9250 | ||
|
|
201a42a3cd | ||
|
|
04a781b4d7 | ||
|
|
87a8a1ced4 | ||
|
|
f1a82828fe | ||
|
|
2a04e12c6f | ||
|
|
33e0089afb | ||
|
|
d06fa633d5 | ||
|
|
049732afb8 | ||
|
|
87f7c19f90 | ||
|
|
6b53ef47cf | ||
|
|
8a3a268ae6 | ||
|
|
1c35d42cd0 | ||
|
|
ddc8db6c26 | ||
|
|
c6aff2c431 | ||
|
|
a9c5b18a39 | ||
|
|
9540b6922d | ||
|
|
83a7d33c47 | ||
|
|
a4a8ad9c75 | ||
|
|
9eecf2a456 | ||
|
|
9536a311cb | ||
|
|
8d5e6737fc | ||
|
|
07e13d60a2 | ||
|
|
1713386869 | ||
|
|
35472f5fc9 | ||
|
|
ed168b522c | ||
|
|
3e7ba2cc6f | ||
|
|
80c47da237 | ||
|
|
abe1cec90c | ||
|
|
cdf981abba | ||
|
|
04dcd80adb | ||
|
|
49920234ac | ||
|
|
366b715942 | ||
|
|
3ba501f947 | ||
|
|
ec569a58ef | ||
|
|
b91317fd36 | ||
|
|
2ab4fcbc24 | ||
|
|
98c14f1692 | ||
|
|
60bcdeded9 | ||
|
|
c87f8fd538 | ||
|
|
ad80eb3a0b | ||
|
|
c7d6ad5a0b | ||
|
|
8a8e220792 | ||
|
|
cfc6a47f76 | ||
|
|
8efa586ace | ||
|
|
23ea188e60 | ||
|
|
928e87b4f4 | ||
|
|
63ef585d4b | ||
|
|
b03a7668f9 | ||
|
|
3f08bcde54 | ||
|
|
196d963dc4 | ||
|
|
f4cbcbc984 | ||
|
|
ec0f7fefb0 | ||
|
|
3d618bdbfd | ||
|
|
1fa7445667 | ||
|
|
269b9647da | ||
|
|
bee32f080e | ||
|
|
25dad5a531 | ||
|
|
4a93581f1a |
@@ -28,6 +28,11 @@ AlignConsecutiveMacros:
|
||||
AcrossComments: false
|
||||
AlignCompound: false
|
||||
PadOperators: false
|
||||
AlignConsecutiveShortCaseStatements:
|
||||
Enabled: false
|
||||
AcrossEmptyLines: false
|
||||
AcrossComments: false
|
||||
AlignCaseColons: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments:
|
||||
@@ -141,10 +146,13 @@ IntegerLiteralSeparator:
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
KeepEmptyLinesAtEOF: false
|
||||
LambdaBodyIndentation: Signature
|
||||
LineEnding: DeriveLF
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
Macros:
|
||||
- 'HAL_ENUM(name)=enum name'
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Never
|
||||
@@ -199,6 +207,7 @@ RawStringFormats:
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: true
|
||||
RemoveBracesLLVM: false
|
||||
RemoveParentheses: Leave
|
||||
RemoveSemicolon: false
|
||||
RequiresClausePosition: OwnLine
|
||||
RequiresExpressionIndentation: OuterScope
|
||||
@@ -216,6 +225,7 @@ SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeJsonColon: false
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeParensOptions:
|
||||
AfterControlStatements: true
|
||||
@@ -230,23 +240,28 @@ SpaceBeforeParensOptions:
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceBeforeSquareBrackets: false
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: Never
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInParens: Never
|
||||
SpacesInParensOptions:
|
||||
InCStyleCasts: false
|
||||
InConditionalStatements: false
|
||||
InEmptyParentheses: false
|
||||
Other: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: c++20
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
VerilogBreakBetweenInstancePorts: true
|
||||
WhitespaceSensitiveMacros:
|
||||
- BOOST_PP_STRINGIZE
|
||||
- CF_SWIFT_NAME
|
||||
|
||||
@@ -49,7 +49,6 @@ Checks:
|
||||
google-build-namespaces,
|
||||
google-explicit-constructor,
|
||||
google-global-names-in-headers,
|
||||
google-readability-avoid-underscore-in-googletest-name,
|
||||
google-readability-casting,
|
||||
google-runtime-operator,
|
||||
misc-definitions-in-headers,
|
||||
|
||||
6
.gersemirc
Normal file
6
.gersemirc
Normal file
@@ -0,0 +1,6 @@
|
||||
color: false
|
||||
definitions: [cmake/modules]
|
||||
line_length: 100
|
||||
list_expansion: favour-inlining
|
||||
quiet: false
|
||||
unsafe: false
|
||||
7
.gitattributes
vendored
7
.gitattributes
vendored
@@ -1,5 +1,12 @@
|
||||
*.cpp text eol=lf
|
||||
*.gradle text eol=lf
|
||||
*.h text eol=lf
|
||||
*.inc text eol=lf
|
||||
*.java text eol=lf
|
||||
*.jinja text eol=lf
|
||||
*.json text eol=lf
|
||||
*.md text eol=lf
|
||||
*.xml text eol=lf
|
||||
|
||||
# Generated files
|
||||
*/src/generated/** linguist-generated
|
||||
|
||||
65
.github/workflows/cmake.yml
vendored
65
.github/workflows/cmake.yml
vendored
@@ -16,11 +16,11 @@ jobs:
|
||||
name: Linux
|
||||
container: wpilib/roborio-cross-ubuntu:2024-22.04
|
||||
flags: "-DCMAKE_BUILD_TYPE=Release -DWITH_EXAMPLES=ON"
|
||||
- os: macOS-12
|
||||
- os: macOS-14
|
||||
name: macOS
|
||||
container: ""
|
||||
env: "PATH=\"/usr/local/opt/protobuf@3/bin:$PATH\""
|
||||
flags: "-DCMAKE_BUILD_TYPE=Release -DWITH_JAVA=OFF -DWITH_EXAMPLES=ON -DCMAKE_LIBRARY_PATH=/usr/local/opt/protobuf@3/lib -DProtobuf_INCLUDE_DIR=/usr/local/opt/protobuf@3/include -DProtobuf_PROTOC_EXECUTABLE=/usr/local/opt/protobuf@3/bin/protoc"
|
||||
env: "PATH=\"/opt/homebrew/opt/protobuf@3/bin:$PATH\""
|
||||
flags: "-DCMAKE_BUILD_TYPE=Release -DWITH_JAVA=OFF -DWITH_EXAMPLES=ON -DCMAKE_LIBRARY_PATH=/opt/homebrew/opt/protobuf@3/lib -DProtobuf_INCLUDE_DIR=/opt/homebrew/opt/protobuf@3/include -DProtobuf_PROTOC_EXECUTABLE=/opt/homebrew/opt/protobuf@3/bin/protoc"
|
||||
|
||||
name: "Build - ${{ matrix.name }}"
|
||||
runs-on: ${{ matrix.os }}
|
||||
@@ -28,29 +28,16 @@ jobs:
|
||||
steps:
|
||||
- name: Install dependencies (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: sudo apt-get update && sudo apt-get install -y libopencv-dev libopencv4.5-java python-is-python3 libprotobuf-dev protobuf-compiler ninja-build
|
||||
run: sudo apt-get update && sudo apt-get install -y libopencv-dev libopencv4.5-java libprotobuf-dev protobuf-compiler ninja-build
|
||||
|
||||
- name: Install QuickBuffers (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: wget https://github.com/HebiRobotics/QuickBuffers/releases/download/1.3.2/protoc-gen-quickbuf_1.3.2_amd64.deb && sudo apt install ./protoc-gen-quickbuf_1.3.2_amd64.deb
|
||||
|
||||
- name: Install opencv (macOS)
|
||||
- name: Install dependencies (macOS)
|
||||
run: brew install opencv protobuf@3 ninja
|
||||
if: runner.os == 'macOS'
|
||||
|
||||
- name: Set up Python 3.8 (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: 3.8
|
||||
|
||||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@v0.0.3
|
||||
uses: mozilla-actions/sccache-action@v0.0.5
|
||||
|
||||
- name: Install jinja
|
||||
run: python -m pip install jinja2
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: configure
|
||||
run: cmake -S . -B build -G "Ninja" -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache ${{ matrix.flags }}
|
||||
@@ -71,45 +58,27 @@ jobs:
|
||||
name: "Build - Windows"
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- uses: ilammy/msvc-dev-cmd@v1
|
||||
- uses: ilammy/msvc-dev-cmd@v1.13.0
|
||||
|
||||
- name: Install CMake
|
||||
uses: lukka/get-cmake@v3.27.6
|
||||
|
||||
- name: Run vcpkg
|
||||
uses: lukka/run-vcpkg@v11.1
|
||||
with:
|
||||
vcpkgDirectory: ${{ runner.workspace }}/vcpkg
|
||||
vcpkgGitCommitId: 78b61582c9e093fda56a01ebb654be15a0033897 # HEAD on 2023-08-6
|
||||
uses: lukka/get-cmake@v3.29.3
|
||||
|
||||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@v0.0.3
|
||||
uses: mozilla-actions/sccache-action@v0.0.5
|
||||
|
||||
- name: Install jinja
|
||||
run: python -m pip install jinja2
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- name: Run vcpkg
|
||||
uses: lukka/run-vcpkg@v11.5
|
||||
with:
|
||||
vcpkgDirectory: ${{ runner.workspace }}/vcpkg
|
||||
vcpkgGitCommitId: 37c3e63a1306562f7f59c4c3c8892ddd50fdf992 # HEAD on 2024-02-24
|
||||
|
||||
- name: configure
|
||||
run: cmake -S . -B build -G "Ninja" -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DCMAKE_BUILD_TYPE=Release -DWITH_JAVA=OFF -DWITH_EXAMPLES=ON -DUSE_SYSTEM_FMTLIB=ON -DUSE_SYSTEM_LIBUV=ON -DUSE_SYSTEM_EIGEN=ON -DCMAKE_TOOLCHAIN_FILE=${{ runner.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_INSTALL_OPTIONS=--clean-after-build -DVCPKG_TARGET_TRIPLET=x64-windows-release -DVCPKG_HOST_TRIPLET=x64-windows-release
|
||||
run: cmake -S . -B build -G "Ninja" -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DCMAKE_BUILD_TYPE=Release -DWITH_JAVA=OFF -DWITH_EXAMPLES=ON -DUSE_SYSTEM_FMTLIB=ON -DUSE_SYSTEM_LIBUV=ON -DUSE_SYSTEM_EIGEN=OFF -DCMAKE_TOOLCHAIN_FILE=${{ runner.workspace }}/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_INSTALL_OPTIONS=--clean-after-build -DVCPKG_TARGET_TRIPLET=x64-windows-release -DVCPKG_HOST_TRIPLET=x64-windows-release
|
||||
env:
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
|
||||
# Build wpiutil at full speed, wpimath depends on wpiutil
|
||||
- name: build wpiutil
|
||||
working-directory: build
|
||||
run: cmake --build . --parallel $(nproc) --target wpiutil/all
|
||||
env:
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
|
||||
# Build wpimath slow to prevent OOM
|
||||
- name: build wpimath
|
||||
working-directory: build
|
||||
run: cmake --build . --parallel 1 --target wpimath/all
|
||||
env:
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
|
||||
# Build everything else fast
|
||||
- name: build
|
||||
working-directory: build
|
||||
run: cmake --build . --parallel $(nproc)
|
||||
|
||||
26
.github/workflows/command-robotpy-pr.yml
vendored
Normal file
26
.github/workflows/command-robotpy-pr.yml
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
name: Comment on PR for robotpy
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
paths:
|
||||
- 'wpilibNewCommands/**'
|
||||
|
||||
jobs:
|
||||
comment:
|
||||
permissions:
|
||||
pull-requests: write
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Comment on PR
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: 'This PR modifies commands. Please open a corresponding PR in [Python Commands](https://github.com/robotpy/robotpy-commands-v2/) and include a link to this PR.'
|
||||
})
|
||||
22
.github/workflows/comment-command.yml
vendored
22
.github/workflows/comment-command.yml
vendored
@@ -9,22 +9,22 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: React Rocket
|
||||
uses: actions/github-script@v4
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const {owner, repo} = context.issue
|
||||
github.reactions.createForIssueComment({
|
||||
github.rest.reactions.createForIssueComment({
|
||||
owner,
|
||||
repo,
|
||||
comment_id: context.payload.comment.id,
|
||||
content: "rocket",
|
||||
});
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.COMMENT_COMMAND_PAT_TOKEN }}
|
||||
- name: Fetch all history and metadata
|
||||
run: |
|
||||
git fetch --prune --unshallow
|
||||
git checkout -b pr
|
||||
git branch -f main origin/main
|
||||
- name: Checkout PR
|
||||
@@ -33,17 +33,17 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: "${{ secrets.COMMENT_COMMAND_PAT_TOKEN }}"
|
||||
NUMBER: ${{ github.event.issue.number }}
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v2
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.8
|
||||
python-version: '3.10'
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 11
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
- name: Install wpiformat
|
||||
run: pip3 install wpiformat
|
||||
run: pip3 install wpiformat==2024.34
|
||||
- name: Run wpiformat
|
||||
run: wpiformat
|
||||
- name: Run spotlessApply
|
||||
|
||||
14
.github/workflows/documentation.yml
vendored
14
.github/workflows/documentation.yml
vendored
@@ -16,14 +16,14 @@ jobs:
|
||||
if: github.repository_owner == 'wpilibsuite' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
concurrency: ci-docs-publish
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-java@v3
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 13
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
- name: Set environment variables (Development)
|
||||
run: |
|
||||
echo "BRANCH=development" >> $GITHUB_ENV
|
||||
@@ -41,11 +41,11 @@ jobs:
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew docs:generateJavaDocs docs:doxygen -PbuildServer ${{ env.EXTRA_GRADLE_ARGS }}
|
||||
- name: Install SSH Client 🔑
|
||||
uses: webfactory/ssh-agent@v0.8.0
|
||||
uses: webfactory/ssh-agent@v0.9.0
|
||||
with:
|
||||
ssh-private-key: ${{ secrets.GH_DEPLOY_KEY }}
|
||||
- name: Deploy 🚀
|
||||
uses: JamesIves/github-pages-deploy-action@v4.4.1
|
||||
uses: JamesIves/github-pages-deploy-action@v4.6.1
|
||||
with:
|
||||
ssh-key: true
|
||||
repository-name: wpilibsuite/wpilibsuite.github.io
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
single-commit: true
|
||||
folder: docs/build/docs
|
||||
- name: Trigger Workflow
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.DISPATCH_PAT_TOKEN }}
|
||||
script: |
|
||||
|
||||
42
.github/workflows/fix_compile_commands.py
vendored
Executable file
42
.github/workflows/fix_compile_commands.py
vendored
Executable file
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import json
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Fix compile_commands.json generated by Gradle"
|
||||
)
|
||||
parser.add_argument("filename", help="compile_commands.json location")
|
||||
cmd_args = parser.parse_args()
|
||||
|
||||
# Read JSON
|
||||
with open(cmd_args.filename) as f:
|
||||
data = json.load(f)
|
||||
|
||||
for obj in data:
|
||||
out_args = []
|
||||
|
||||
# Filter out -isystem flags that cause false positives
|
||||
iter_args = iter(obj["arguments"])
|
||||
for arg in iter_args:
|
||||
if arg == "-isystem":
|
||||
next_arg = next(iter_args)
|
||||
|
||||
# /usr/lib/gcc/x86_64-pc-linux-gnu/13.2.1/include/xmmintrin.h:54:1:
|
||||
# error: conflicting types for '_mm_prefetch' [clang-diagnostic-error]
|
||||
if not next_arg.startswith("/usr/lib/gcc/"):
|
||||
out_args += ["-isystem", next_arg]
|
||||
else:
|
||||
out_args.append(arg)
|
||||
|
||||
obj["arguments"] = out_args
|
||||
|
||||
# Write JSON
|
||||
with open(cmd_args.filename, "w") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -10,5 +10,5 @@ jobs:
|
||||
name: "Validation"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: gradle/wrapper-validation-action@v1
|
||||
- uses: actions/checkout@v4
|
||||
- uses: gradle/actions/wrapper-validation@v3
|
||||
|
||||
91
.github/workflows/gradle.yml
vendored
91
.github/workflows/gradle.yml
vendored
@@ -37,7 +37,7 @@ jobs:
|
||||
large-packages: false
|
||||
docker-images: false
|
||||
swap-storage: false
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set release environment variable
|
||||
@@ -54,14 +54,14 @@ jobs:
|
||||
ARTIFACTORY_PUBLISH_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
|
||||
- name: Check free disk space
|
||||
run: df .
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact-name }}
|
||||
path: build/allOutputs
|
||||
|
||||
build-host:
|
||||
env:
|
||||
MACOSX_DEPLOYMENT_TARGET: 11
|
||||
MACOSX_DEPLOYMENT_TARGET: 13
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -70,55 +70,49 @@ jobs:
|
||||
artifact-name: Win64Debug
|
||||
architecture: x64
|
||||
task: "build"
|
||||
build-options: "-PciDebugOnly --max-workers 1"
|
||||
build-options: "-PciDebugOnly"
|
||||
outputs: "build/allOutputs"
|
||||
build-dir: "c:\\work"
|
||||
- os: windows-2022
|
||||
artifact-name: Win64Release
|
||||
architecture: x64
|
||||
build-options: "-PciReleaseOnly --max-workers 1"
|
||||
build-options: "-PciReleaseOnly"
|
||||
task: "copyAllOutputs"
|
||||
outputs: "build/allOutputs"
|
||||
build-dir: "c:\\work"
|
||||
- os: windows-2022
|
||||
artifact-name: WinArm64Debug
|
||||
architecture: x64
|
||||
task: "build"
|
||||
build-options: "-PciDebugOnly -Pbuildwinarm64 -Ponlywindowsarm64 --max-workers 1"
|
||||
build-options: "-PciDebugOnly -Pbuildwinarm64 -Ponlywindowsarm64"
|
||||
outputs: "build/allOutputs"
|
||||
build-dir: "c:\\work"
|
||||
- os: windows-2022
|
||||
artifact-name: WinArm64Release
|
||||
architecture: x64
|
||||
build-options: "-PciReleaseOnly -Pbuildwinarm64 -Ponlywindowsarm64 --max-workers 1"
|
||||
build-options: "-PciReleaseOnly -Pbuildwinarm64 -Ponlywindowsarm64"
|
||||
task: "copyAllOutputs"
|
||||
outputs: "build/allOutputs"
|
||||
build-dir: "c:\\work"
|
||||
- os: macOS-12
|
||||
- os: macOS-14
|
||||
artifact-name: macOS
|
||||
architecture: x64
|
||||
architecture: aarch64
|
||||
task: "build"
|
||||
outputs: "build/allOutputs"
|
||||
build-dir: "."
|
||||
- os: windows-2022
|
||||
artifact-name: Win32
|
||||
architecture: x86
|
||||
task: ":ntcoreffi:build"
|
||||
outputs: "ntcoreffi/build/outputs"
|
||||
build-dir: "c:\\work"
|
||||
name: "Build - ${{ matrix.artifact-name }}"
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-java@v3
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
architecture: ${{ matrix.architecture }}
|
||||
- name: Import Developer ID Certificate
|
||||
uses: wpilibsuite/import-signing-certificate@v1
|
||||
uses: wpilibsuite/import-signing-certificate@v2
|
||||
with:
|
||||
certificate-data: ${{ secrets.APPLE_CERTIFICATE_DATA }}
|
||||
certificate-passphrase: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
@@ -138,43 +132,38 @@ jobs:
|
||||
- name: Set Java Heap Size
|
||||
run: sed -i 's/-Xmx2g/-Xmx1g/g' gradle.properties
|
||||
if: matrix.artifact-name == 'Win32'
|
||||
- name: Configure build directory (Windows)
|
||||
run: xcopy . ${{ matrix.build-dir }} /i /s /e /h /q
|
||||
if: matrix.os == 'windows-2022'
|
||||
- name: Check disk free space (Windows)
|
||||
run: wmic logicaldisk get caption, freespace
|
||||
if: matrix.os == 'windows-2022'
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew ${{ matrix.task }} --build-cache -PbuildServer -PskipJavaFormat ${{ matrix.build-options }} ${{ env.EXTRA_GRADLE_ARGS }}
|
||||
working-directory: ${{ matrix.build-dir }}
|
||||
env:
|
||||
ARTIFACTORY_PUBLISH_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
|
||||
ARTIFACTORY_PUBLISH_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
|
||||
- name: Sign Libraries with Developer ID
|
||||
run: ./gradlew copyAllOutputs --build-cache -PbuildServer -PskipJavaFormat -PdeveloperID=${{ secrets.APPLE_DEVELOPER_ID }} ${{ matrix.build-options }} ${{ env.EXTRA_GRADLE_ARGS }}
|
||||
working-directory: ${{ matrix.build-dir }}
|
||||
if: |
|
||||
matrix.artifact-name == 'macOS' && (github.repository_owner == 'wpilibsuite' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')))
|
||||
- name: Check disk free space (Windows)
|
||||
run: wmic logicaldisk get caption, freespace
|
||||
if: matrix.os == 'windows-2022'
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{ matrix.artifact-name }}
|
||||
path: ${{ matrix.build-dir }}/${{ matrix.outputs }}
|
||||
path: ${{ matrix.outputs }}
|
||||
|
||||
build-documentation:
|
||||
name: "Build - Documentation"
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-java@v3
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 13
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
- name: Set release environment variable
|
||||
run: echo "EXTRA_GRADLE_ARGS=-PreleaseMode" >> $GITHUB_ENV
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
@@ -183,7 +172,7 @@ jobs:
|
||||
env:
|
||||
ARTIFACTORY_PUBLISH_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
|
||||
ARTIFACTORY_PUBLISH_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Documentation
|
||||
path: docs/build/outputs
|
||||
@@ -193,13 +182,26 @@ jobs:
|
||||
needs: [build-docker, build-host, build-documentation]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Free Disk Space
|
||||
if: |
|
||||
github.repository_owner == 'wpilibsuite' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
with:
|
||||
tool-cache: false
|
||||
android: true
|
||||
dotnet: true
|
||||
haskell: true
|
||||
large-packages: false
|
||||
docker-images: false
|
||||
swap-storage: false
|
||||
- uses: actions/checkout@v4
|
||||
if: |
|
||||
github.repository_owner == 'wpilibsuite' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
with:
|
||||
repository: wpilibsuite/build-tools
|
||||
- uses: actions/download-artifact@v3
|
||||
- uses: actions/download-artifact@v4
|
||||
if: |
|
||||
github.repository_owner == 'wpilibsuite' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
@@ -217,13 +219,13 @@ jobs:
|
||||
run: |
|
||||
cat combiner/products/build/allOutputs/version.txt
|
||||
test -s combiner/products/build/allOutputs/version.txt
|
||||
- uses: actions/setup-java@v3
|
||||
- uses: actions/setup-java@v4
|
||||
if: |
|
||||
github.repository_owner == 'wpilibsuite' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 11
|
||||
distribution: 'temurin'
|
||||
java-version: 17
|
||||
- name: Combine (Main)
|
||||
if: |
|
||||
github.repository_owner == 'wpilibsuite' &&
|
||||
@@ -242,10 +244,25 @@ jobs:
|
||||
RUN_AZURE_ARTIFACTORY_RELEASE: "TRUE"
|
||||
ARTIFACTORY_PUBLISH_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
|
||||
ARTIFACTORY_PUBLISH_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: |
|
||||
github.repository_owner == 'wpilibsuite' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
with:
|
||||
name: Maven
|
||||
path: ~/releases
|
||||
|
||||
dispatch:
|
||||
name: dispatch
|
||||
needs: [combine]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: peter-evans/repository-dispatch@v3
|
||||
if: |
|
||||
github.repository_owner == 'wpilibsuite' &&
|
||||
startsWith(github.ref, 'refs/tags/v')
|
||||
with:
|
||||
token: ${{ secrets.TOOL_REPO_ACCESS_TOKEN }}
|
||||
repository: wpilibsuite/smartdashboard
|
||||
event-type: tag
|
||||
client-payload: '{"package_name": "allwpilib", "package_version": "${{ github.ref_name }}"}'
|
||||
|
||||
55
.github/workflows/lint-format.yml
vendored
55
.github/workflows/lint-format.yml
vendored
@@ -15,19 +15,19 @@ jobs:
|
||||
name: "wpiformat"
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Fetch all history and metadata
|
||||
run: |
|
||||
git config --global --add safe.directory /__w/allwpilib/allwpilib
|
||||
git fetch --prune --unshallow
|
||||
git checkout -b pr
|
||||
git branch -f main origin/main
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v4
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.8
|
||||
python-version: '3.10'
|
||||
- name: Install wpiformat
|
||||
run: pip3 install wpiformat
|
||||
run: pip3 install wpiformat==2024.34
|
||||
- name: Run
|
||||
run: wpiformat
|
||||
- name: Check output
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
- name: Generate diff
|
||||
run: git diff HEAD > wpiformat-fixes.patch
|
||||
if: ${{ failure() }}
|
||||
- uses: actions/upload-artifact@v3
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: wpiformat fixes
|
||||
path: wpiformat-fixes.patch
|
||||
@@ -51,37 +51,44 @@ jobs:
|
||||
tidy:
|
||||
name: "clang-tidy"
|
||||
runs-on: ubuntu-22.04
|
||||
container: wpilib/roborio-cross-ubuntu:2023-22.04
|
||||
container: wpilib/roborio-cross-ubuntu:2024-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Fetch all history and metadata
|
||||
run: |
|
||||
git config --global --add safe.directory /__w/allwpilib/allwpilib
|
||||
git fetch --prune --unshallow
|
||||
git checkout -b pr
|
||||
git branch -f main origin/main
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v4
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.8
|
||||
python-version: '3.10'
|
||||
- name: Install wpiformat
|
||||
run: pip3 install wpiformat
|
||||
run: pip3 install wpiformat==2024.34
|
||||
- name: Create compile_commands.json
|
||||
run: ./gradlew generateCompileCommands -Ptoolchain-optional-roboRio
|
||||
run: |
|
||||
./gradlew generateCompileCommands -Ptoolchain-optional-roboRio
|
||||
./.github/workflows/fix_compile_commands.py build/TargetedCompileCommands/linuxx86-64release/compile_commands.json
|
||||
./.github/workflows/fix_compile_commands.py build/TargetedCompileCommands/linuxx86-64debug/compile_commands.json
|
||||
- name: List changed files
|
||||
run: wpiformat -list-changed-files
|
||||
- name: Run clang-tidy
|
||||
run: wpiformat -no-format -tidy-changed -compile-commands=build/compile_commands/linuxx86-64 -vv
|
||||
- name: Run clang-tidy release
|
||||
run: wpiformat -no-format -tidy-changed -compile-commands=build/TargetedCompileCommands/linuxx86-64release -vv
|
||||
- name: Run clang-tidy debug
|
||||
run: wpiformat -no-format -tidy-changed -compile-commands=build/TargetedCompileCommands/linuxx86-64debug -vv
|
||||
javaformat:
|
||||
name: "Java format"
|
||||
runs-on: ubuntu-22.04
|
||||
container: wpilib/ubuntu-base:22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Fetch all history and metadata
|
||||
run: |
|
||||
git config --global --add safe.directory /__w/allwpilib/allwpilib
|
||||
git fetch --prune --unshallow
|
||||
git checkout -b pr
|
||||
git branch -f main origin/main
|
||||
- name: Run Java format
|
||||
@@ -95,12 +102,12 @@ jobs:
|
||||
name: "Documentation"
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-java@v3
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'zulu'
|
||||
java-version: 13
|
||||
distribution: 'temurin'
|
||||
java-version: 21
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew docs:zipDocs -PbuildServer -PdocWarningsAsErrors ${{ env.EXTRA_GRADLE_ARGS }}
|
||||
|
||||
50
.github/workflows/pregenerate.yml
vendored
Normal file
50
.github/workflows/pregenerate.yml
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
name: Check Pregenerated Files
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches-ignore:
|
||||
- main
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
update:
|
||||
name: "Update"
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up Python 3.9
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.9
|
||||
- name: Install jinja
|
||||
run: python -m pip install jinja2
|
||||
- name: Install protobuf dependencies
|
||||
run: sudo apt-get update && sudo apt-get install -y protobuf-compiler && wget https://github.com/HebiRobotics/QuickBuffers/releases/download/1.3.3/protoc-gen-quickbuf-1.3.3-linux-x86_64.exe && chmod +x protoc-gen-quickbuf-1.3.3-linux-x86_64.exe
|
||||
- name: Run hal
|
||||
run: ./hal/generate_usage_reporting.py
|
||||
- name: Run ntcore
|
||||
run: ./ntcore/generate_topics.py
|
||||
- name: Run wpimath
|
||||
run: ./wpimath/generate_numbers.py && ./wpimath/generate_quickbuf.py --quickbuf_plugin=protoc-gen-quickbuf-1.3.3-linux-x86_64.exe
|
||||
- name: Run HIDs
|
||||
run: ./wpilibj/generate_hids.py && ./wpilibc/generate_hids.py && ./wpilibNewCommands/generate_hids.py
|
||||
- name: Run PWM Controllers
|
||||
run: ./wpilibj/generate_pwm_motor_controllers.py && ./wpilibc/generate_pwm_motor_controllers.py
|
||||
- name: Add untracked files to index so they count as changes
|
||||
run: git add -A
|
||||
- name: Check output
|
||||
run: git --no-pager diff --exit-code HEAD
|
||||
- name: Generate diff
|
||||
run: git diff HEAD > pregenerated-files-fixes.patch
|
||||
if: ${{ failure() }}
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: pregenerated-files-fixes
|
||||
path: pregenerated-files-fixes.patch
|
||||
if: ${{ failure() }}
|
||||
15
.github/workflows/sanitizers.yml
vendored
15
.github/workflows/sanitizers.yml
vendored
@@ -29,22 +29,15 @@ jobs:
|
||||
container: wpilib/roborio-cross-ubuntu:2024-22.04
|
||||
steps:
|
||||
- name: Install Dependencies
|
||||
run: sudo apt-get update && sudo apt-get install -y libopencv-dev libopencv4.5-java python-is-python3 clang-14 libprotobuf-dev protobuf-compiler ninja-build
|
||||
|
||||
- name: Install QuickBuffers
|
||||
if: runner.os == 'Linux'
|
||||
run: wget https://github.com/HebiRobotics/QuickBuffers/releases/download/1.3.2/protoc-gen-quickbuf_1.3.2_amd64.deb && sudo apt install ./protoc-gen-quickbuf_1.3.2_amd64.deb
|
||||
run: sudo apt-get update && sudo apt-get install -y libopencv-dev libopencv4.5-java clang-14 libprotobuf-dev protobuf-compiler ninja-build
|
||||
|
||||
- name: Run sccache-cache
|
||||
uses: mozilla-actions/sccache-action@v0.0.3
|
||||
uses: mozilla-actions/sccache-action@v0.0.5
|
||||
|
||||
- name: Install jinja
|
||||
run: python -m pip install jinja2
|
||||
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: configure
|
||||
run: mkdir build && cd build && cmake -G Ninja -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DCMAKE_C_COMPILER:FILEPATH=/usr/bin/clang-14 -DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/clang++-14 ${{ matrix.cmake-flags }} ..
|
||||
run: mkdir build && cd build && cmake -G Ninja -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache -DCMAKE_C_COMPILER:FILEPATH=/usr/bin/clang-14 -DCMAKE_CXX_COMPILER:FILEPATH=/usr/bin/clang++-14 -DWITH_JAVA=OFF ${{ matrix.cmake-flags }} ..
|
||||
env:
|
||||
SCCACHE_GHA_ENABLED: "true"
|
||||
|
||||
|
||||
144
.github/workflows/tools.yml
vendored
Normal file
144
.github/workflows/tools.yml
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
name: Tools
|
||||
|
||||
on: [pull_request, push]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
YEAR: 2024
|
||||
|
||||
jobs:
|
||||
build-artifacts:
|
||||
name: "Build - WPILib"
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
DISPLAY: ':10'
|
||||
steps:
|
||||
- name: Free Disk Space
|
||||
uses: jlumbroso/free-disk-space@main
|
||||
with:
|
||||
tool-cache: false
|
||||
android: true
|
||||
dotnet: true
|
||||
haskell: true
|
||||
large-packages: false
|
||||
docker-images: false
|
||||
swap-storage: false
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Build WPILib with Gradle
|
||||
uses: addnab/docker-run-action@v3
|
||||
with:
|
||||
image: wpilib/roborio-cross-ubuntu:2024-22.04
|
||||
options: -v ${{ github.workspace }}:/work -w /work -e GITHUB_REF -e CI -e DISPLAY
|
||||
run: df . && rm -f semicolon_delimited_script && ./gradlew :wpilibc:publish :wpilibj:publish :wpilibNewCommands:publish :hal:publish :cameraserver:publish :ntcore:publish :cscore:publish :wpimath:publish :wpinet:publish :wpiutil:publish :apriltag:publish :wpiunits:publish :simulation:halsim_gui:publish :simulation:halsim_ds_socket:publish -x test -x Javadoc -x doxygen --build-cache && cp -r /root/releases/maven/development /work
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: MavenArtifacts
|
||||
path: |
|
||||
development
|
||||
retention-days: 1
|
||||
|
||||
Robotbuilder:
|
||||
name: "Build - RobotBuilder"
|
||||
needs: [build-artifacts]
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
DISPLAY: ':10'
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: wpilibsuite/robotbuilder
|
||||
fetch-depth: 0
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: MavenArtifacts
|
||||
- name: Patch RobotBuilder to use local development
|
||||
run: cd src/main/resources/export && echo "wpi.maven.useLocal = false" >> java/build.gradle && echo "wpi.maven.useFrcMavenLocalDevelopment = true" >> java/build.gradle && echo "wpi.versions.wpilibVersion = '$YEAR.424242.+'" >> java/build.gradle && echo "wpi.versions.wpimathVersion = '$YEAR.424242.+'" >> java/build.gradle && echo "wpi.maven.useLocal = false" >> cpp/build.gradle && echo "wpi.maven.useFrcMavenLocalDevelopment = true" >> cpp/build.gradle && echo "wpi.versions.wpilibVersion = '$YEAR.424242.+'" >> cpp/build.gradle && echo "wpi.versions.wpimathVersion = '$YEAR.424242.+'" >> cpp/build.gradle
|
||||
- name: Install and run xvfb
|
||||
run: sudo apt-get update && sudo apt-get install -y xvfb && Xvfb $DISPLAY &
|
||||
- name: Move artifacts
|
||||
run: mkdir -p ~/releases/maven/development && cp -r edu ~/releases/maven/development
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: 'temurin'
|
||||
- name: Build RobotBuilder with Gradle
|
||||
run: ./gradlew build test --tests 'robotbuilder.exporters.*' -x htmlSanityCheck -PbuildServer -PreleaseMode ; cat build/test-results/test/TEST-robotbuilder.exporters.*.xml ;
|
||||
- name: Summarize RobotBuilder Test Results
|
||||
uses: EnricoMi/publish-unit-test-result-action@v2
|
||||
if: always()
|
||||
with:
|
||||
files: |
|
||||
build/test-results/test/TEST*.xml
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: TestResults
|
||||
path: |
|
||||
build/reports/
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: RobotBuilder Build
|
||||
path: |
|
||||
build/libs/
|
||||
retention-days: 7
|
||||
|
||||
Shuffleboard:
|
||||
name: "Build - Shuffleboard"
|
||||
needs: [build-artifacts]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: wpilibsuite/shuffleboard
|
||||
fetch-depth: 0
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: MavenArtifacts
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: 'temurin'
|
||||
- name: Move artifacts
|
||||
run: mkdir -p ~/releases/maven/development && cp -r edu ~/releases/maven/development
|
||||
- name: Install dependencies
|
||||
run: sudo apt-get install -y libgtk2.0-0
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build -x Javadoc
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: Shuffleboard Build
|
||||
path: |
|
||||
build/allOutputs/
|
||||
retention-days: 7
|
||||
|
||||
PathWeaver:
|
||||
name: "Build - PathWeaver"
|
||||
needs: [build-artifacts]
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: wpilibsuite/PathWeaver
|
||||
fetch-depth: 0
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: MavenArtifacts
|
||||
- uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: 17
|
||||
distribution: 'temurin'
|
||||
- name: Move artifacts
|
||||
run: mkdir -p ~/releases/maven/development && cp -r edu ~/releases/maven/development
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: PathWeaver Build
|
||||
path: |
|
||||
build/allOutputs/
|
||||
retention-days: 7
|
||||
11
.github/workflows/upstream-utils.yml
vendored
11
.github/workflows/upstream-utils.yml
vendored
@@ -15,14 +15,15 @@ jobs:
|
||||
name: "Update"
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Fetch all history and metadata
|
||||
run: |
|
||||
git fetch --prune --unshallow
|
||||
git checkout -b pr
|
||||
git branch -f main origin/main
|
||||
- name: Set up Python 3.9
|
||||
uses: actions/setup-python@v4
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: 3.9
|
||||
- name: Configure committer identity
|
||||
@@ -69,6 +70,10 @@ jobs:
|
||||
run: |
|
||||
cd upstream_utils
|
||||
./update_protobuf.py
|
||||
- name: Run update_sleipnir.py
|
||||
run: |
|
||||
cd upstream_utils
|
||||
./update_sleipnir.py
|
||||
- name: Add untracked files to index so they count as changes
|
||||
run: git add -A
|
||||
- name: Check output
|
||||
|
||||
@@ -10,6 +10,7 @@ cppSrcFileInclude {
|
||||
}
|
||||
|
||||
modifiableFileExclude {
|
||||
cmake/toolchains/
|
||||
\.patch$
|
||||
gradlew
|
||||
}
|
||||
@@ -19,6 +20,7 @@ generatedFileExclude {
|
||||
simulation/gz_msgs/src/include/simulation/gz_msgs/msgs\.h$
|
||||
fieldImages/src/main/native/resources/
|
||||
apriltag/src/test/resources/
|
||||
wpilibc/src/generated/
|
||||
}
|
||||
|
||||
repoRootNameOverride {
|
||||
|
||||
319
CMakeLists.txt
319
CMakeLists.txt
@@ -1,12 +1,15 @@
|
||||
# Disable in-source builds to prevent source tree corruption.
|
||||
if(" ${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL " ${CMAKE_CURRENT_BINARY_DIR}")
|
||||
message(FATAL_ERROR "
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"
|
||||
FATAL: In-source builds are not allowed.
|
||||
You should create a separate directory for build files.
|
||||
")
|
||||
"
|
||||
)
|
||||
endif()
|
||||
|
||||
if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
|
||||
if("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
|
||||
set(CMAKE_SYSTEM_VERSION 10.0.18362.0 CACHE STRING INTERNAL FORCE)
|
||||
set(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION 10.0.18362.0 CACHE STRING INTERNAL FORCE)
|
||||
endif()
|
||||
@@ -16,7 +19,7 @@ project(allwpilib)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
|
||||
|
||||
# Make timestamps of extracted files from FetchContent the time of extraction
|
||||
if (POLICY CMP0135)
|
||||
if(POLICY CMP0135)
|
||||
cmake_policy(SET CMP0135 NEW)
|
||||
endif()
|
||||
|
||||
@@ -24,7 +27,7 @@ message(STATUS "Platform version: ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}")
|
||||
|
||||
set(WPILIB_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
INCLUDE(CPack)
|
||||
include(CPack)
|
||||
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
@@ -35,31 +38,33 @@ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${WPILIB_BINARY_DIR}/bin)
|
||||
set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${WPILIB_BINARY_DIR}/jar)
|
||||
|
||||
# use, i.e. don't skip the full RPATH for the build tree
|
||||
SET(CMAKE_SKIP_BUILD_RPATH FALSE)
|
||||
set(CMAKE_SKIP_BUILD_RPATH FALSE)
|
||||
|
||||
# when building, don't use the install RPATH already
|
||||
# (but later on when installing)
|
||||
SET(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
|
||||
set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
|
||||
|
||||
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
|
||||
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
|
||||
|
||||
# add the automatically determined parts of the RPATH
|
||||
# which point to directories outside the build tree to the install RPATH
|
||||
SET(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
|
||||
# the RPATH to be used when installing, but only if it's not a system directory
|
||||
LIST(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir)
|
||||
IF("${isSystemDir}" STREQUAL "-1")
|
||||
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
|
||||
ENDIF("${isSystemDir}" STREQUAL "-1")
|
||||
list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/lib" isSystemDir)
|
||||
if("${isSystemDir}" STREQUAL "-1")
|
||||
set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
|
||||
endif()
|
||||
|
||||
# Options for building certain parts of the repo. Everything is built by default.
|
||||
option(BUILD_SHARED_LIBS "Build with shared libs (needed for JNI)" ON)
|
||||
option(WITH_JAVA "Include java and JNI in the build" ON)
|
||||
option(WITH_JAVA "Include Java and JNI in the build" ON)
|
||||
option(WITH_JAVA_SOURCE "Build Java source jars" ${WITH_JAVA})
|
||||
option(WITH_CSCORE "Build cscore (needs OpenCV)" ON)
|
||||
option(WITH_NTCORE "Build ntcore" ON)
|
||||
option(WITH_WPIMATH "Build wpimath" ON)
|
||||
option(WITH_WPILIB "Build hal, wpilibc/j, and myRobot (needs OpenCV)" ON)
|
||||
option(WITH_WPIUNITS "Build wpiunits" ON)
|
||||
option(WITH_WPILIB "Build hal, wpilibc/j, and developerRobot (needs OpenCV)" ON)
|
||||
option(WITH_EXAMPLES "Build examples" OFF)
|
||||
option(WITH_TESTS "Build unit tests (requires internet connection)" ON)
|
||||
option(WITH_GUI "Build GUI items" ON)
|
||||
@@ -74,135 +79,157 @@ option(USE_SYSTEM_FMTLIB "Use system fmtlib" OFF)
|
||||
option(USE_SYSTEM_LIBUV "Use system libuv" OFF)
|
||||
option(USE_SYSTEM_EIGEN "Use system eigen" OFF)
|
||||
|
||||
# Options for installation.
|
||||
option(WITH_FLAT_INSTALL "Use a flat install directory" OFF)
|
||||
|
||||
# Options for location of OpenCV Java.
|
||||
set(OPENCV_JAVA_INSTALL_DIR "" CACHE PATH "Location to search for the OpenCV jar file")
|
||||
|
||||
# Options for compilation flags.
|
||||
option(NO_WERROR "Disable -Werror flag during compilation" OFF)
|
||||
|
||||
# Set default build type to release with debug info (i.e. release mode optimizations
|
||||
# are performed, but debug info still exists).
|
||||
if (NOT CMAKE_BUILD_TYPE)
|
||||
set (CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "" FORCE)
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
if (WITH_JAVA AND NOT BUILD_SHARED_LIBS)
|
||||
message(FATAL_ERROR "
|
||||
if(WITH_JAVA AND NOT BUILD_SHARED_LIBS)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"
|
||||
FATAL: Cannot build static libs with Java enabled.
|
||||
Static libs requires both BUILD_SHARED_LIBS=OFF and
|
||||
WITH_JAVA=OFF
|
||||
")
|
||||
"
|
||||
)
|
||||
endif()
|
||||
|
||||
if (WITH_SIMULATION_MODULES AND NOT BUILD_SHARED_LIBS)
|
||||
message(FATAL_ERROR "
|
||||
if(WITH_SIMULATION_MODULES AND NOT BUILD_SHARED_LIBS)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"
|
||||
FATAL: Cannot build static libs with simulation modules enabled.
|
||||
Static libs requires both BUILD_SHARED_LIBS=OFF and
|
||||
WITH_SIMULATION_MODULES=OFF
|
||||
")
|
||||
"
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT WITH_JAVA OR NOT WITH_CSCORE)
|
||||
if(NOT WITH_JAVA OR NOT WITH_CSCORE)
|
||||
if(NOT "${OPENCV_JAVA_INSTALL_DIR}" STREQUAL "")
|
||||
message(WARNING "
|
||||
message(
|
||||
WARNING
|
||||
"
|
||||
WARNING: OpenCV Java dir set but java is not enabled!
|
||||
It will be ignored.
|
||||
")
|
||||
"
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT WITH_WPILIB AND WITH_SIMULATION_MODULES)
|
||||
message(FATAL_ERROR "
|
||||
if(NOT WITH_WPILIB AND WITH_SIMULATION_MODULES)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"
|
||||
FATAL: Cannot build simulation modules with wpilib disabled.
|
||||
Enable wpilib by setting WITH_WPILIB=ON
|
||||
")
|
||||
"
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT WITH_NTCORE AND WITH_CSCORE)
|
||||
message(FATAL_ERROR "
|
||||
if(NOT WITH_NTCORE AND WITH_CSCORE)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"
|
||||
FATAL: Cannot build cameraserver without ntcore.
|
||||
Enable ntcore by setting WITH_NTCORE=ON
|
||||
")
|
||||
"
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT WITH_NTCORE AND WITH_GUI)
|
||||
message(FATAL_ERROR "
|
||||
if(NOT WITH_NTCORE AND WITH_GUI)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"
|
||||
FATAL: Cannot build GUI modules without ntcore.
|
||||
Enable ntcore by setting WITH_NTCORE=ON
|
||||
")
|
||||
"
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT WITH_NTCORE AND WITH_SIMULATION_MODULES)
|
||||
message(FATAL_ERROR "
|
||||
if(NOT WITH_NTCORE AND WITH_SIMULATION_MODULES)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"
|
||||
FATAL: Cannot build simulation modules without ntcore.
|
||||
Enable ntcore by setting WITH_NTCORE=ON
|
||||
")
|
||||
"
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT WITH_NTCORE AND WITH_WPILIB)
|
||||
message(FATAL_ERROR "
|
||||
if(NOT WITH_NTCORE AND WITH_WPILIB)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"
|
||||
FATAL: Cannot build wpilib without ntcore.
|
||||
Enable ntcore by setting WITH_NTCORE=ON
|
||||
")
|
||||
"
|
||||
)
|
||||
endif()
|
||||
|
||||
if (NOT WITH_WPIMATH AND WITH_WPILIB)
|
||||
message(FATAL_ERROR "
|
||||
if(NOT WITH_WPIMATH AND WITH_WPILIB)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"
|
||||
FATAL: Cannot build wpilib without wpimath.
|
||||
Enable wpimath by setting WITH_WPIMATH=ON
|
||||
")
|
||||
"
|
||||
)
|
||||
endif()
|
||||
|
||||
set( wpilib_dest "")
|
||||
set( include_dest include )
|
||||
set( java_lib_dest java )
|
||||
set( jni_lib_dest jni )
|
||||
|
||||
if (WITH_FLAT_INSTALL)
|
||||
set (wpilib_config_dir ${wpilib_dest})
|
||||
else()
|
||||
set (wpilib_config_dir share/wpilib)
|
||||
if(NOT WITH_WPIUNITS AND WITH_WPIMATH AND WITH_JAVA)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"
|
||||
FATAL: Cannot build Java wpimath without wpiunits.
|
||||
Enable wpiunits by setting WITH_WPIUNITS=ON or disable the Java build by setting WITH_JAVA=OFF
|
||||
"
|
||||
)
|
||||
endif()
|
||||
|
||||
if (USE_SYSTEM_LIBUV)
|
||||
set (LIBUV_SYSTEM_REPLACE "
|
||||
set(include_dest include)
|
||||
set(java_lib_dest java)
|
||||
set(jni_lib_dest jni)
|
||||
if(WITH_JAVA)
|
||||
set(CMAKE_JAVA_COMPILE_FLAGS "-encoding" "UTF8" "-Xlint:unchecked")
|
||||
endif()
|
||||
|
||||
if(USE_SYSTEM_LIBUV)
|
||||
set(LIBUV_SYSTEM_REPLACE
|
||||
"
|
||||
find_dependency(libuv CONFIG)
|
||||
")
|
||||
"
|
||||
)
|
||||
endif()
|
||||
|
||||
if (USE_SYSTEM_EIGEN)
|
||||
set (EIGEN_SYSTEM_REPLACE "find_package(Eigen3 CONFIG)")
|
||||
if(USE_SYSTEM_EIGEN)
|
||||
set(EIGEN_SYSTEM_REPLACE "find_package(Eigen3 CONFIG)")
|
||||
endif()
|
||||
|
||||
find_package(LIBSSH 0.7.1)
|
||||
|
||||
find_package(Protobuf REQUIRED)
|
||||
find_program(Quickbuf_EXECUTABLE
|
||||
NAMES protoc-gen-quickbuf
|
||||
DOC "The Quickbuf protoc plugin"
|
||||
)
|
||||
|
||||
if (WITH_FLAT_INSTALL)
|
||||
set(WPIUTIL_DEP_REPLACE "include($\{SELF_DIR\}/wpiutil-config.cmake)")
|
||||
set(WPINET_DEP_REPLACE "include($\{SELF_DIR\}/wpinet-config.cmake)")
|
||||
set(NTCORE_DEP_REPLACE "include($\{SELF_DIR\}/ntcore-config.cmake)")
|
||||
set(CSCORE_DEP_REPLACE_IMPL "include(\${SELF_DIR}/cscore-config.cmake)")
|
||||
set(CAMERASERVER_DEP_REPLACE_IMPL "include(\${SELF_DIR}/cameraserver-config.cmake)")
|
||||
set(HAL_DEP_REPLACE_IMPL "include(\${SELF_DIR}/hal-config.cmake)")
|
||||
set(WPIMATH_DEP_REPLACE "include($\{SELF_DIR\}/wpimath-config.cmake)")
|
||||
set(WPILIBC_DEP_REPLACE_IMPL "include(\${SELF_DIR}/wpilibc-config.cmake)")
|
||||
set(WPILIBNEWCOMMANDS_DEP_REPLACE "include(\${SELF_DIR}/wpilibNewcommands-config.cmake)")
|
||||
else()
|
||||
set(WPIUTIL_DEP_REPLACE "find_dependency(wpiutil)")
|
||||
set(WPINET_DEP_REPLACE "find_dependency(wpinet)")
|
||||
set(NTCORE_DEP_REPLACE "find_dependency(ntcore)")
|
||||
set(CSCORE_DEP_REPLACE_IMPL "find_dependency(cscore)")
|
||||
set(APRILTAG_DEP_REPLACE "find_dependency(apriltag)")
|
||||
set(CAMERASERVER_DEP_REPLACE_IMPL "find_dependency(cameraserver)")
|
||||
set(CSCORE_DEP_REPLACE_IMPL "find_dependency(cscore)")
|
||||
set(HAL_DEP_REPLACE_IMPL "find_dependency(hal)")
|
||||
set(WPIMATH_DEP_REPLACE "find_dependency(wpimath)")
|
||||
set(NTCORE_DEP_REPLACE "find_dependency(ntcore)")
|
||||
set(WPILIBC_DEP_REPLACE_IMPL "find_dependency(wpilibc)")
|
||||
set(WPILIBJ_DEP_REPLACE "find_dependency(wpilibj)")
|
||||
set(WPILIBNEWCOMMANDS_DEP_REPLACE "find_dependency(wpilibNewCommands)")
|
||||
endif()
|
||||
set(WPIMATH_DEP_REPLACE "find_dependency(wpimath)")
|
||||
set(WPINET_DEP_REPLACE "find_dependency(wpinet)")
|
||||
set(WPIUNITS_DEP_REPLACE "find_dependency(wpiunits)")
|
||||
set(WPIUTIL_DEP_REPLACE "find_dependency(wpiutil)")
|
||||
|
||||
set(FILENAME_DEP_REPLACE "get_filename_component(SELF_DIR \"$\{CMAKE_CURRENT_LIST_FILE\}\" PATH)")
|
||||
set(SELF_DIR "$\{SELF_DIR\}")
|
||||
@@ -220,7 +247,15 @@ if(isMultiConfig)
|
||||
list(APPEND CMAKE_CONFIGURATION_TYPES Ubsan)
|
||||
endif()
|
||||
else()
|
||||
set(allowedBuildTypes Asan Tsan Ubsan Debug Release RelWithDebInfo MinSizeRel)
|
||||
set(allowedBuildTypes
|
||||
Asan
|
||||
Tsan
|
||||
Ubsan
|
||||
Debug
|
||||
Release
|
||||
RelWithDebInfo
|
||||
MinSizeRel
|
||||
)
|
||||
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "${allowedBuildTypes}")
|
||||
|
||||
if(CMAKE_BUILD_TYPE AND NOT CMAKE_BUILD_TYPE IN_LIST allowedBuildTypes)
|
||||
@@ -229,54 +264,90 @@ else()
|
||||
endif()
|
||||
|
||||
set(CMAKE_C_FLAGS_ASAN
|
||||
"${CMAKE_C_FLAGS_DEBUG} -fsanitize=address -fno-omit-frame-pointer" CACHE STRING
|
||||
"Flags used by the C compiler for Asan build type or configuration." FORCE)
|
||||
"${CMAKE_C_FLAGS_DEBUG} -fsanitize=address -fno-omit-frame-pointer"
|
||||
CACHE STRING
|
||||
"Flags used by the C compiler for Asan build type or configuration."
|
||||
FORCE
|
||||
)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_ASAN
|
||||
"${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fno-omit-frame-pointer" CACHE STRING
|
||||
"Flags used by the C++ compiler for Asan build type or configuration." FORCE)
|
||||
"${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=address -fno-omit-frame-pointer"
|
||||
CACHE STRING
|
||||
"Flags used by the C++ compiler for Asan build type or configuration."
|
||||
FORCE
|
||||
)
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS_ASAN
|
||||
"${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=address" CACHE STRING
|
||||
"Linker flags to be used to create executables for Asan build type." FORCE)
|
||||
"${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=address"
|
||||
CACHE STRING
|
||||
"Linker flags to be used to create executables for Asan build type."
|
||||
FORCE
|
||||
)
|
||||
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_ASAN
|
||||
"${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=address" CACHE STRING
|
||||
"Linker lags to be used to create shared libraries for Asan build type." FORCE)
|
||||
"${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=address"
|
||||
CACHE STRING
|
||||
"Linker flags to be used to create shared libraries for Asan build type."
|
||||
FORCE
|
||||
)
|
||||
|
||||
set(CMAKE_C_FLAGS_TSAN
|
||||
"${CMAKE_C_FLAGS_DEBUG} -fsanitize=thread -fno-omit-frame-pointer" CACHE STRING
|
||||
"Flags used by the C compiler for Tsan build type or configuration." FORCE)
|
||||
"${CMAKE_C_FLAGS_DEBUG} -fsanitize=thread -fno-omit-frame-pointer"
|
||||
CACHE STRING
|
||||
"Flags used by the C compiler for Tsan build type or configuration."
|
||||
FORCE
|
||||
)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_TSAN
|
||||
"${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=thread -fno-omit-frame-pointer" CACHE STRING
|
||||
"Flags used by the C++ compiler for Tsan build type or configuration." FORCE)
|
||||
"${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=thread -fno-omit-frame-pointer"
|
||||
CACHE STRING
|
||||
"Flags used by the C++ compiler for Tsan build type or configuration."
|
||||
FORCE
|
||||
)
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS_TSAN
|
||||
"${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=thread" CACHE STRING
|
||||
"Linker flags to be used to create executables for Tsan build type." FORCE)
|
||||
"${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=thread"
|
||||
CACHE STRING
|
||||
"Linker flags to be used to create executables for Tsan build type."
|
||||
FORCE
|
||||
)
|
||||
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_TSAN
|
||||
"${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=thread" CACHE STRING
|
||||
"Linker lags to be used to create shared libraries for Tsan build type." FORCE)
|
||||
"${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=thread"
|
||||
CACHE STRING
|
||||
"Linker flags to be used to create shared libraries for Tsan build type."
|
||||
FORCE
|
||||
)
|
||||
|
||||
set(CMAKE_C_FLAGS_UBSAN
|
||||
"${CMAKE_C_FLAGS_DEBUG} -fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer" CACHE STRING
|
||||
"Flags used by the C compiler for Ubsan build type or configuration." FORCE)
|
||||
"${CMAKE_C_FLAGS_DEBUG} -fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer"
|
||||
CACHE STRING
|
||||
"Flags used by the C compiler for Ubsan build type or configuration."
|
||||
FORCE
|
||||
)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_UBSAN
|
||||
"${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer" CACHE STRING
|
||||
"Flags used by the C++ compiler for Ubsan build type or configuration." FORCE)
|
||||
"${CMAKE_CXX_FLAGS_DEBUG} -fsanitize=undefined -fno-sanitize-recover=all -fno-omit-frame-pointer"
|
||||
CACHE STRING
|
||||
"Flags used by the C++ compiler for Ubsan build type or configuration."
|
||||
FORCE
|
||||
)
|
||||
|
||||
set(CMAKE_EXE_LINKER_FLAGS_UBSAN
|
||||
"${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=undefined -fno-sanitize-recover=all" CACHE STRING
|
||||
"Linker flags to be used to create executables for Ubsan build type." FORCE)
|
||||
"${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=undefined -fno-sanitize-recover=all"
|
||||
CACHE STRING
|
||||
"Linker flags to be used to create executables for Ubsan build type."
|
||||
FORCE
|
||||
)
|
||||
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_UBSAN
|
||||
"${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=undefined" CACHE STRING
|
||||
"Linker lags to be used to create shared libraries for Ubsan build type." FORCE)
|
||||
"${CMAKE_SHARED_LINKER_FLAGS_DEBUG} -fsanitize=undefined"
|
||||
CACHE STRING
|
||||
"Linker flags to be used to create shared libraries for Ubsan build type."
|
||||
FORCE
|
||||
)
|
||||
|
||||
if (WITH_TESTS)
|
||||
if(WITH_TESTS)
|
||||
enable_testing()
|
||||
add_subdirectory(googletest)
|
||||
include(GoogleTest)
|
||||
@@ -284,41 +355,49 @@ endif()
|
||||
|
||||
add_subdirectory(wpiutil)
|
||||
|
||||
if (WITH_NTCORE)
|
||||
if(WITH_NTCORE)
|
||||
add_subdirectory(wpinet)
|
||||
add_subdirectory(ntcore)
|
||||
endif()
|
||||
|
||||
if (WITH_WPIMATH)
|
||||
if(WITH_WPIMATH)
|
||||
if(WITH_JAVA)
|
||||
add_subdirectory(wpiunits)
|
||||
endif()
|
||||
add_subdirectory(wpimath)
|
||||
endif()
|
||||
|
||||
if (WITH_GUI)
|
||||
if(WITH_WPIUNITS AND NOT WITH_WPIMATH)
|
||||
# In case of building wpiunits standalone
|
||||
add_subdirectory(wpiunits)
|
||||
endif()
|
||||
|
||||
if(WITH_GUI)
|
||||
add_subdirectory(fieldImages)
|
||||
add_subdirectory(imgui)
|
||||
add_subdirectory(wpigui)
|
||||
add_subdirectory(glass)
|
||||
add_subdirectory(outlineviewer)
|
||||
add_subdirectory(sysid)
|
||||
if (LIBSSH_FOUND)
|
||||
if(LIBSSH_FOUND)
|
||||
add_subdirectory(roborioteamnumbersetter)
|
||||
add_subdirectory(datalogtool)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (WITH_WPILIB OR WITH_SIMULATION_MODULES)
|
||||
if(WITH_WPILIB OR WITH_SIMULATION_MODULES)
|
||||
set(HAL_DEP_REPLACE ${HAL_DEP_REPLACE_IMPL})
|
||||
add_subdirectory(hal)
|
||||
endif()
|
||||
|
||||
if (WITH_CSCORE)
|
||||
if(WITH_CSCORE)
|
||||
set(CSCORE_DEP_REPLACE ${CSCORE_DEP_REPLACE_IMPL})
|
||||
set(CAMERASERVER_DEP_REPLACE ${CAMERASERVER_DEP_REPLACE_IMPL})
|
||||
add_subdirectory(cscore)
|
||||
add_subdirectory(cameraserver)
|
||||
endif()
|
||||
|
||||
if (WITH_WPILIB)
|
||||
if(WITH_WPILIB)
|
||||
set(WPILIBC_DEP_REPLACE ${WPILIBC_DEP_REPLACE_IMPL})
|
||||
add_subdirectory(apriltag)
|
||||
add_subdirectory(wpilibj)
|
||||
@@ -326,15 +405,15 @@ if (WITH_WPILIB)
|
||||
add_subdirectory(wpilibNewCommands)
|
||||
add_subdirectory(romiVendordep)
|
||||
add_subdirectory(xrpVendordep)
|
||||
if (WITH_EXAMPLES)
|
||||
if(WITH_EXAMPLES)
|
||||
add_subdirectory(wpilibcExamples)
|
||||
endif()
|
||||
add_subdirectory(myRobot)
|
||||
add_subdirectory(developerRobot)
|
||||
endif()
|
||||
|
||||
if (WITH_SIMULATION_MODULES AND NOT WITH_EXTERNAL_HAL)
|
||||
if(WITH_SIMULATION_MODULES AND NOT WITH_EXTERNAL_HAL)
|
||||
add_subdirectory(simulation)
|
||||
endif()
|
||||
|
||||
configure_file(wpilib-config.cmake.in ${WPILIB_BINARY_DIR}/wpilib-config.cmake )
|
||||
install(FILES ${WPILIB_BINARY_DIR}/wpilib-config.cmake DESTINATION ${wpilib_config_dir})
|
||||
configure_file(wpilib-config.cmake.in ${WPILIB_BINARY_DIR}/wpilib-config.cmake)
|
||||
install(FILES ${WPILIB_BINARY_DIR}/wpilib-config.cmake DESTINATION share/wpilib)
|
||||
|
||||
@@ -12,11 +12,11 @@ So you want to contribute your changes back to WPILib. Great! We have a few cont
|
||||
|
||||
## General Contribution Rules
|
||||
|
||||
- Everything in the library must work for the 3000+ teams that will be using it.
|
||||
- Everything in the library must work for the 4000+ teams that will be using it.
|
||||
- We need to be able to maintain submitted changes, even if you are no longer working on the project.
|
||||
- Tool suite changes must be generally useful to a broad range of teams
|
||||
- Excluding bug fixes, changes in one language generally need to have corresponding changes in other languages.
|
||||
- Some features, such the addition of C++11 for WPILibC or Functional Interfaces for WPILibJ, are specific to that version of WPILib only.
|
||||
- Some features, such the addition of C++23 for WPILibC or Functional Interfaces for WPILibJ, are specific to that version of WPILib only. New language features added to C++ must be wrappable in Python for [RobotPy](https://github.com/robotpy).
|
||||
- Substantial changes often need to have corresponding LabVIEW changes. To do this, we will work with NI on these large changes.
|
||||
- Changes should have tests.
|
||||
- Code should be well documented.
|
||||
@@ -27,7 +27,8 @@ So you want to contribute your changes back to WPILib. Great! We have a few cont
|
||||
- Bug reports and fixes
|
||||
- We will generally accept bug fixes without too much question. If they are only implemented for one language, we will implement them for any other necessary languages. Bug reports are also welcome, please submit them to our GitHub issue tracker.
|
||||
- While we do welcome improvements to the API, there are a few important rules to consider:
|
||||
- Features must be added to both WPILibC and WPILibJ, with rare exceptions.
|
||||
- Features must be added to Java (WPILibJ), C++ (WPILibC), with rare exceptions.
|
||||
- Most of Python (RobotPy) is created by wrapping WPILibC with pybind11 via robotpy-build. However, new features to the command framework should also be submitted to [robotpy-commands-v2](https://github.com/robotpy/robotpy-commands-v2) as the command framework is reimplemented in Python.
|
||||
- During competition season, we will not merge any new feature additions. We want to ensure that the API is stable during the season to help minimize issues for teams.
|
||||
- Ask about large changes before spending a bunch of time on them! You can create a new issue on our GitHub tracker for feature request/discussion and talk about it with us there.
|
||||
- Features that make it easier for teams with less experience to be more successful are more likely to be accepted.
|
||||
@@ -79,6 +80,8 @@ xₖ₊₁ = Axₖ + Buₖ
|
||||
|
||||
Changes should be submitted as a Pull Request against the main branch of WPILib. For most changes, commits will be squashed upon merge. For particularly large changes, multiple commits are ok, but assume one commit unless asked otherwise. We may ask you to break a PR into multiple standalone PRs or commits for rebase within one PR to separate unrelated changes. No change will be merged unless it is up to date with the current main branch. We do this to make sure that the git history isn't too cluttered.
|
||||
|
||||
During the build season, breaking changes or other changes intended for the next season can be created as a pull request against the development branch of WPILib. After the season is over, the changes in the development branch will be merged into main.
|
||||
|
||||
### Merge Process
|
||||
|
||||
When you first submit changes, GitHub Actions will attempt to run `./gradlew check` on your change. If this fails, you will need to fix any issues that it sees. Once Actions passes, we will begin the review process in more earnest. One or more WPILib team members will review your change. This will be a back-and-forth process with the WPILib team and the greater community. Once we are satisfied that your change is ready, we will allow our hosted instance to test it. This will run the full gamut of checks, including integration tests on actual hardware. Once all tests have passed and the team is satisfied, we will merge your change into the WPILib repository.
|
||||
|
||||
@@ -19,7 +19,7 @@ To build a project using a development build, find the build.gradle file and ope
|
||||
wpi.maven.useLocal = false
|
||||
wpi.maven.useDevelopment = true
|
||||
wpi.versions.wpilibVersion = 'YEAR.+'
|
||||
wpi.versions.wpimathVersion = 'YEAR.+
|
||||
wpi.versions.wpimathVersion = 'YEAR.+'
|
||||
```
|
||||
|
||||
The top of your ``build.gradle`` file should now look similar to the code below. Ignore any differences in versions.
|
||||
@@ -89,15 +89,4 @@ wpi.versions.wpimathVersion = 'YEAR.424242.+'
|
||||
|
||||
# roboRIO Development
|
||||
|
||||
This repo contains a myRobot project built in way to do full project development without needing to do a full publish into GradleRIO. These also only require building the minimum amount of binaries for the roboRIO, so the builds are much faster as well.
|
||||
|
||||
The setup only works if the roboRIO is USB connected. If an alternate IP address is preferred, the `address` block in myRobot\build.gradle can be changed to point to another address.
|
||||
|
||||
The following 3 tasks can be used for deployment:
|
||||
* `:myRobot:deployShared` deploys the C++ project using shared dependencies. Prefer this one for most C++ development.
|
||||
* `:myRobot:deployStatic` deploys the C++ project with all dependencies statically linked.
|
||||
* `:myRobot:deployJava` deploys the Java project and all required dependencies. Also installs the JRE if not currently installed.
|
||||
|
||||
Deploying any of these to the roboRIO will disable the current startup project until it is redeployed.
|
||||
|
||||
From here, ssh into the roboRIO using the `lvuser` account and run `frcRunRobot.sh` (It's in path).
|
||||
See the [developerRobot](developerRobot/README.md) subproject.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Copyright (c) 2009-2023 FIRST and other WPILib contributors
|
||||
Copyright (c) 2009-2024 FIRST and other WPILib contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
## Publishing Third Party Dependencies
|
||||
Currently the 3rd party deps are imgui, opencv, and google test
|
||||
Currently the 3rd party deps are imgui, opencv, google test, libssh, and apriltaglib
|
||||
|
||||
For publishing these dependencies, the version needs to be manually updated in the publish.gradle file of their respective repository.
|
||||
Then, in the azure build for the dependency you want to build for, manually start a pipeline build (As of current, this is the `Run Pipeline` button).
|
||||
@@ -18,10 +18,10 @@ Desktop tools publish to the development repo on every push to main. To publish
|
||||
|
||||
## Publishing VS Code
|
||||
Before publishing, make sure to update the gradlerio version in `vscode-wpilib/resources/gradle/version.txt` Also make sure the gradle wrapper version matches the wrapper required by gradlerio.
|
||||
Upon pushing a tag, a release will be built, and the files will be uploaded to the releases on GitHub. For publishing to the marketplace, you need a Microsoft account and to be added as a maintainer.
|
||||
Upon pushing a tag, a release will be built, and the files will be uploaded to the releases on GitHub.
|
||||
|
||||
## Publishing GradleRIO
|
||||
Before publishing, make sure to update the version in build.gradle. Publishing must happen locally, using the command `./gradlew publishPlugin`. This does require your API key for publishing to be set.
|
||||
|
||||
## Building the installer
|
||||
Update the GradleRIO version in gradle.properties, and in the scripts folder in vscode, update the vscode extension. Then push, it will build the installer on azure.
|
||||
Update the GradleRIO version in gradle.properties, and in the scripts folder in vscode, update the vscode extension. To publish a release build, upload a new tag, and a release will automatically be built and published to artifactory and cloudflare.
|
||||
|
||||
@@ -145,6 +145,11 @@ All artifacts are based at `edu.wpi.first.artifactname` in the repository.
|
||||
* wpinet
|
||||
* wpiutil
|
||||
|
||||
* wpiunits
|
||||
|
||||
* apriltag
|
||||
* wpiutil
|
||||
* wpimath
|
||||
|
||||
### Third Party Artifacts
|
||||
|
||||
@@ -152,6 +157,7 @@ This repository provides the builds of the following third party software.
|
||||
|
||||
All artifacts are based at `edu.wpi.first.thirdparty.frcYEAR` in the repository.
|
||||
|
||||
* apriltaglib
|
||||
* googletest
|
||||
* imgui
|
||||
* opencv
|
||||
|
||||
152
README-CMAKE.md
152
README-CMAKE.md
@@ -1,30 +1,41 @@
|
||||
# WPILib CMake Support
|
||||
|
||||
WPILib is normally built with Gradle, however for some systems, such as Linux based coprocessors, Gradle doesn't work correctly, especially if cscore is needed, which requires OpenCV. Furthermore, the CMake build can be used for C++ development because it provides better build caching compared to Gradle. We provide the CMake build for these cases. Although it is supported on Windows, these docs will only go over Linux builds.
|
||||
WPILib is normally built with Gradle, however for some systems, such as Linux based coprocessors, Gradle doesn't work correctly, especially if cscore is needed, which requires OpenCV. Furthermore, the CMake build can be used for C++ development because it provides better build caching compared to Gradle. We provide the CMake build for these cases. Although macOS is supported, these docs will only go over Linux and Windows builds, but should mostly work for macOS as well. If you are stuck, you can look at the GitHub workflows for any OS to see how it works.
|
||||
|
||||
## Libraries that get built
|
||||
* wpiutil
|
||||
* ntcore
|
||||
* cscore
|
||||
* apriltag
|
||||
* cameraserver
|
||||
* hal
|
||||
* wpilib
|
||||
* halsim
|
||||
* cscore
|
||||
* hal (simulation HAL only)
|
||||
* ntcore
|
||||
* romiVendordep
|
||||
* simulation extensions
|
||||
* wpigui
|
||||
* wpimath
|
||||
* wpilib (wpilibc, wpilibj, and myRobot)
|
||||
* wpilibNewCommands
|
||||
* wpimath
|
||||
* wpinet
|
||||
* wpiunits
|
||||
* wpiutil
|
||||
* xrpVendordep
|
||||
|
||||
By default, all libraries except for the HAL and WPILib get built with a default CMake setup. The libraries are built as shared libraries, and include the JNI libraries as well as building the Java JARs.
|
||||
## GUI apps that get built
|
||||
* datalogtool
|
||||
* glass
|
||||
* outlineviewer
|
||||
* roborioteamnumbersetter
|
||||
* sysid
|
||||
* halsim_gui (if simulation extensions are enabled)
|
||||
|
||||
By default, all libraries get built with a default CMake setup. The libraries are built as shared libraries, and include the JNI libraries as well as building the Java JARs. Data Log Tool and the roboRIO Team Number Setter are only built if libssh is available.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
The jinja2 pip package is needed to generate classes for NT4's pubsub.
|
||||
|
||||
The protobuf library and compiler are needed for protobuf generation. The QuickBuffers protoc-gen package is also required when Java is being built; this can be obtained from https://github.com/HebiRobotics/QuickBuffers/releases/.
|
||||
The protobuf library and compiler are needed for protobuf generation.
|
||||
|
||||
OpenCV needs to be findable by CMake. On systems like the Jetson, this is installed by default. Otherwise, you will need to build OpenCV from source and install it.
|
||||
|
||||
If you want JNI and Java, you will need a JDK of at least version 11 installed. In addition, you need a `JAVA_HOME` environment variable set properly and set to the JDK directory.
|
||||
If you want JNI and Java, you will need a JDK of at least version 17 installed. In addition, you need a `JAVA_HOME` environment variable set properly and set to the JDK directory.
|
||||
|
||||
If you are building with unit tests or simulation modules, you will also need an Internet connection for the initial setup process, as CMake will clone google-test and imgui from GitHub.
|
||||
|
||||
@@ -32,32 +43,38 @@ If you are building with unit tests or simulation modules, you will also need an
|
||||
|
||||
The following build options are available:
|
||||
|
||||
* `WITH_JAVA` (ON Default)
|
||||
* This option will enable Java and JNI builds. If this is on, `WITH_SHARED_LIBS` must be on. Otherwise CMake will error.
|
||||
* `WITH_SHARED_LIBS` (ON Default)
|
||||
* This option will cause cmake to build static libraries instead of shared libraries. If this is off, `WITH_JAVA` must be off. Otherwise CMake will error.
|
||||
* `BUILD_SHARED_LIBS` (ON Default)
|
||||
* This option will cause CMake to build static libraries instead of shared libraries. If this is off, `WITH_JAVA` must be off. Otherwise CMake will error.
|
||||
* `WITH_CSCORE` (ON Default)
|
||||
* This option will cause cscore to be built. Turning this off will implicitly disable cameraserver, the hal and wpilib as well, irrespective of their specific options. If this is off, the OpenCV build requirement is removed.
|
||||
* This option will cause cscore to be built. Turning this off will implicitly disable cameraserver. If this is off, the OpenCV build requirement is removed.
|
||||
* `WITH_EXAMPLES` (OFF Default)
|
||||
* This option will build C++ examples.
|
||||
* `WITH_GUI` (ON Default)
|
||||
* This option will build GUI items. If this is off, and `WITH_SIMULATION_MODULES` is on, the simulation GUI will not be built.
|
||||
* `WITH_JAVA` (ON Default)
|
||||
* This option will enable Java and JNI builds. If this is on, `BUILD_SHARED_LIBS` must be on. Otherwise CMake will error.
|
||||
* `WITH_JAVA_SOURCE` (`WITH_JAVA` Default)
|
||||
* This option will build Java source JARs for each enabled Java library. This does not require `WITH_JAVA` to be on, allowing source JARs to be built without the compiled JARs if desired.
|
||||
* `WITH_NTCORE` (ON Default)
|
||||
* This option will cause ntcore to be built. Turning this off will implicitly disable wpinet and wpilib as well, irrespective of their specific options.
|
||||
* This option will cause ntcore to be built. Turning this off will implicitly disable wpinet, and will cause an error if `WITH_WPILIB` is enabled.
|
||||
* `WITH_SIMULATION_MODULES` (ON Default)
|
||||
* This option will build simulation modules.
|
||||
* `WITH_TESTS` (ON Default)
|
||||
* This option will build C++ unit tests. These can be run via `ctest -C <config>`, where `<config>` is the build configuration, e.g. `Debug` or `Release`.
|
||||
* `WITH_WPILIB` (ON Default)
|
||||
* This option will build the HAL and wpilibc/j during the build. The HAL is the simulation HAL, unless the external HAL options are used. The CMake build has no capability to build for the roboRIO.
|
||||
* `WITH_WPIMATH` (ON Default)
|
||||
* This option will build the wpimath library. This option must be on to build wpilib.
|
||||
* `WITH_WPILIB` (ON Default)
|
||||
* This option will build the hal and wpilibc/j during the build. The HAL is the simulator hal, unless the external hal options are used. The cmake build has no capability to build for the RoboRIO.
|
||||
* `WITH_EXAMPLES` (ON Default)
|
||||
* This option will build C++ examples.
|
||||
* `WITH_TESTS` (ON Default)
|
||||
* This option will build C++ unit tests. These can be run via `make test`.
|
||||
* `WITH_GUI` (ON Default)
|
||||
* This option will build GUI items.
|
||||
* `WITH_SIMULATION_MODULES` (ON Default)
|
||||
* This option will build simulation modules, including wpigui and the HALSim plugins.
|
||||
* `WITH_WPIUNITS` (ON Default)
|
||||
* This option will build the wpiunits library. This option must be on to build the Java wpimath library and requires `WITH_JAVA` to also be on.
|
||||
* `WITH_EXTERNAL_HAL` (OFF Default)
|
||||
* TODO
|
||||
* This option will build wpilib with an externally built HAL.
|
||||
* `EXTERNAL_HAL_FILE`
|
||||
* TODO
|
||||
* Set this option to the CMake File of the externally built HAL. NOTE: set it to the file itself, not the folder the file is located in!
|
||||
* `OPENCV_JAVA_INSTALL_DIR`
|
||||
* Set this option to the location of the archive of the OpenCV Java bindings (it should be called opencv-xxx.jar, with the x'es being version numbers). NOTE: set it to the LOCATION of the file, not the file itself!
|
||||
* `NO_WERROR` (OFF Default)
|
||||
* This option will disable the `-Werror` compilation flag for non-MSVC builds.
|
||||
|
||||
## Build Setup
|
||||
|
||||
@@ -71,24 +88,28 @@ cmake path/to/allwpilib/root
|
||||
|
||||
If you want to change any of the options, add `-DOPTIONHERE=VALUE` to the `cmake` command. This will check for any dependencies. If everything works properly this will succeed. If not, please check out the troubleshooting section for help.
|
||||
|
||||
If you want, you can also use `ccmake` in order to visually set these properties as well. [Here](https://cmake.org/cmake/help/v3.0/manual/ccmake.1.html) is the link to the documentation for that program.
|
||||
If you want, you can also use `ccmake` in order to visually set these properties as well. [Here](https://cmake.org/cmake/help/v3.0/manual/ccmake.1.html) is the link to the documentation for that program. On Windows, you can use `cmake-gui` instead.
|
||||
|
||||
Note that if you are cross-compiling, you will need to override the protobuf options manually to point to the libraries for the target platform. Leave the protoc binary location as the path to the binary for the host platform, since protoc needs to execute on the host platform.
|
||||
|
||||
## Building
|
||||
|
||||
Once you have cmake setup. run `make` from the directory you configured CMake in. This will build all libraries possible. If you have a multicore system, we recommend running `make` with multiple jobs. The usual rule of thumb is 1.5x the number of cores you have. To run a multiple job build, run the following command with x being the number of jobs you want.
|
||||
Once you have CMake setup. run `cmake --build .` from the directory you configured CMake in. This will build all libraries possible. We recommend running `cmake --build .` with multiple jobs. For allwpilib, a good rule of thumb is one worker for every 2 GB of available RAM. To run a multiple job build, run the following command with x being the number of jobs you want.
|
||||
|
||||
```
|
||||
make -jx
|
||||
cmake --build . --parallel x
|
||||
```
|
||||
|
||||
The `ninja` generator is also supported, and can be enabled by passing `-GNinja` to the initial `cmake` command.
|
||||
Note: wpimath takes gigabytes of RAM to compile. Because of this, the compilers may crash while building due to a lack of memory and your computer may slow down. If you have less than 16 GB of RAM available, you may want to consider building it separately first by adding `--target wpimath` and running it with ~3 jobs to prevent crashes from running out of memory.
|
||||
|
||||
To build with a certain configuration, like `Debug` or `Release`, add `--config <config>`, where `<config>` is the name of the configuration you want to build with.
|
||||
|
||||
## Installing
|
||||
|
||||
After build, the easiest way to use the libraries is to install them. Run the following command to install the libraries. This will install them so that they can be used from external cmake projects.
|
||||
After build, the easiest way to use the libraries is to install them. Run the following command to install the libraries. This will install them so that they can be used from external CMake projects.
|
||||
|
||||
```
|
||||
sudo make install
|
||||
sudo cmake --build . --target install
|
||||
```
|
||||
|
||||
## Using the installed libraries for C++.
|
||||
@@ -97,7 +118,7 @@ Using the libraries from C++ is the easiest way to use the built libraries.
|
||||
|
||||
To do so, create a new folder to contain your project. Add the following code below to a `CMakeLists.txt` file in that directory.
|
||||
|
||||
```
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.11)
|
||||
project(vision_app) # Project Name Here
|
||||
|
||||
@@ -107,7 +128,7 @@ add_executable(my_vision_app main.cpp) # executable name as first parameter
|
||||
target_link_libraries(my_vision_app cameraserver ntcore cscore wpiutil)
|
||||
```
|
||||
|
||||
If you are using them, `wpilibc` and `hal` should be added before the `cameraserver` declaration in the `target_link_libraries` function.
|
||||
If you want to use other libraries or are building a robot program, `wpilibc` and `hal` should be added in the `target_link_libraries` function, along with any other libraries you plan on using, e.g. `wpimath`.
|
||||
|
||||
Add a `main.cpp` file to contain your code, and create a build folder. Move into the build folder, and run
|
||||
|
||||
@@ -115,11 +136,43 @@ Add a `main.cpp` file to contain your code, and create a build folder. Move into
|
||||
cmake /path/to/folder/containing/CMakeLists
|
||||
```
|
||||
|
||||
After that, run `make`. That will create your executable. Then you should be able to run `./my_vision_app` to run your application.
|
||||
After that, run `cmake --build .`. That will create your executable. Then you should be able to run `./my_vision_app` to run your application.
|
||||
|
||||
|
||||
## Using the installed libraries for Java
|
||||
TODO
|
||||
|
||||
Using the built JARs is move involved than using the C++ libraries, but mostly consists of adding the correct directories to PATH.
|
||||
|
||||
Add the directory where the JARs are located (e.g, `/usr/local/java`) to PATH. If you are on Windows, you also need to add the `lib`, `bin`, and `share` directories to PATH. Then, create a new folder to contain your project. Add the following code below to a `CMakeLists.txt` file in that directory.
|
||||
|
||||
```cmake
|
||||
cmake_minimum_required(VERSION 3.11)
|
||||
project(robot)
|
||||
|
||||
find_package(Java REQUIRED COMPONENTS Development)
|
||||
include(UseJava)
|
||||
find_package(wpilib REQUIRED)
|
||||
find_jar(opencvJar opencv-xxx PATHS ENV PATH) # Change to OpenCV version
|
||||
|
||||
file(GLOB_RECURSE JAVA_SOURCES *.java)
|
||||
# If you want Gradle compatibility or you are using one of the templates/examples, comment out the above line and uncomment this line instead:
|
||||
# file(GLOB_RECURSE JAVA_SOURCES src/main/java/*.java)
|
||||
add_jar(robot ${JAVA_SOURCES}
|
||||
INCLUDE_JARS apriltag_jar cscore_jar hal_jar ntcore_jar wpilibNewCommands_jar wpimath_jar wpinet_jar wpiutil_jar wpiunits_jar wpilibj_jar ${opencvJar})
|
||||
export_jars(TARGETS robot FILE robot.jar)
|
||||
```
|
||||
This includes all the built JARs except for the vendordeps. If you are not using a JAR/library, you may remove it.
|
||||
Add a `Main.java` file to contain your code, and create a build folder. Move into the build folder, and run
|
||||
|
||||
```
|
||||
cmake /path/to/folder/containing/CMakeLists
|
||||
```
|
||||
|
||||
After that, run `cmake --build .` to create your JAR file. To execute the JAR file, you need to include the wpilib JARs and your JAR in the classpath, and execute your Java program's entry point. If you are using cscore or cameraserver, you also need to include the path to the OpenCV JAR. If you built it from source, it will be in your OpenCV build directory. If it's installed on the system, CMake may find it from PATH, but you will likely need to locate the JAR and manually give CMake the JAR directory. If you are on Linux, you will also need to add the path of the libraries to `LD_LIBRARY_PATH`. This can be done by prepending `LD_LIBRARY_PATH=/path/to/libraries` to the Java command. If you need to add more paths, separate them with colons. The final command should look like `java -cp "robot.jar:/path/to/library_jars/*" main.package.Main`, using a semicolon to separate paths instead of a colon if you are on Windows. If you are on Linux, the final command should look more like `LD_LIBRARY_PATH=/path/to/libraries java -cp robot.jar:/path/to/library_jars/* main.package.Main`.
|
||||
|
||||
## Using vendordeps
|
||||
|
||||
Vendordeps are not included as part of the `wpilib` CMake package. However, if you want to use a vendordep, you need to use `find_package(VENDORDEP)`, where `VENDORDEP` is the name of the vendordep (case-sensitive), like `xrpVendordep` or `romiVenderdep`. Note that wpilibNewCommands, while a vendordep in normal robot projects, is not built as a vendordep in CMake, and is instead included as part of the `wpilib` CMake package. After you used `find_package`, you can reference the vendordep library like normal, either by using `target_link_libraries` for C++ or `add_jar` for Java.
|
||||
|
||||
## Troubleshooting
|
||||
Below are some common issues that are run into when building.
|
||||
@@ -146,7 +199,7 @@ CMake Error at cscore/CMakeLists.txt:3 (find_package):
|
||||
installed.
|
||||
```
|
||||
|
||||
If you get that, you need make sure opencv was installed, and then reattempt to configure. If that doesn't work, set the `OpenCV_DIR` variable to the directory where you built OpenCV.
|
||||
If you get that, you need make sure OpenCV was installed, and then reattempt to configure. If that doesn't work, set the `OpenCV_DIR` variable to the directory where you built OpenCV.
|
||||
|
||||
#### Missing Java
|
||||
|
||||
@@ -160,3 +213,18 @@ CMake Error at /usr/share/cmake-3.5/Modules/FindPackageHandleStandardArgs.cmake:
|
||||
If this happens, make sure you have a JDK of at least version 8 installed, and that your JAVA_HOME variable is set properly to point to the JDK.
|
||||
|
||||
In addition, if you do not need Java, you can disable it with `-DWITH_JAVA=OFF`.
|
||||
|
||||
#### Java: Can't find dependent libraries
|
||||
|
||||
If one of the libraries can't be found, you will get an error similar to this one:
|
||||
|
||||
```
|
||||
java.io.IOException: wpiHaljni could not be loaded from path or an embedded resource.
|
||||
attempted to load for platform /windows/x86-64/
|
||||
Last Load Error:
|
||||
C:\Program Files (x86)\allwpilib\bin\wpiHaljni.dll: Can't find dependent libraries
|
||||
```
|
||||
|
||||
If you get this error, that's usually an indication that not all your libraries are in your PATH. The two libraries that should be in your PATH are OpenCV and protobuf. If the error is coming from cscore, it's likely you're missing OpenCV. Otherwise, it's likely you're missing protobuf.
|
||||
|
||||
Note that Linux will not have this specific type of error, as it will usually tell you the dependent library you are missing. In that case, you most likely need to add the library to `LD_LIBRARY_PATH`.
|
||||
|
||||
37
README.md
37
README.md
@@ -20,11 +20,11 @@ Welcome to the WPILib project. This repository contains the HAL, WPILibJ, and WP
|
||||
- [Running examples in simulation](#running-examples-in-simulation)
|
||||
- [Publishing](#publishing)
|
||||
- [Structure and Organization](#structure-and-organization)
|
||||
- [Contributing to WPILib](#contributing-to-wpilib)
|
||||
- [Contributing to WPILib](./CONTRIBUTING.md)
|
||||
|
||||
## WPILib Mission
|
||||
|
||||
The WPILib Mission is to enable FIRST Robotics teams to focus on writing game-specific software rather than focusing on hardware details - "raise the floor, don't lower the ceiling". We work to enable teams with limited programming knowledge and/or mentor experience to be as successful as possible, while not hampering the abilities of teams with more advanced programming capabilities. We support Kit of Parts control system components directly in the library. We also strive to keep parity between major features of each language (Java, C++, and NI's LabVIEW), so that teams aren't at a disadvantage for choosing a specific programming language. WPILib is an open source project, licensed under the BSD 3-clause license. You can find a copy of the license [here](LICENSE.md).
|
||||
The WPILib Mission is to enable FIRST Robotics teams to focus on writing game-specific software rather than focusing on hardware details - "raise the floor, don't lower the ceiling". We work to enable teams with limited programming knowledge and/or mentor experience to be as successful as possible, while not hampering the abilities of teams with more advanced programming capabilities. We support Kit of Parts control system components directly in the library. We also strive to keep parity between major features of each language (Java, C++, Python, and NI's LabVIEW), so that teams aren't at a disadvantage for choosing a specific programming language. WPILib is an open source project, licensed under the BSD 3-clause license. You can find a copy of the license [here](LICENSE.md).
|
||||
|
||||
# Quick Start
|
||||
|
||||
@@ -41,11 +41,11 @@ Using Gradle makes building WPILib very straightforward. It only has a few depen
|
||||
|
||||
## Requirements
|
||||
|
||||
- [JDK 11](https://adoptium.net/temurin/releases/?version=11)
|
||||
- [JDK 17](https://adoptium.net/temurin/releases/?version=17)
|
||||
- Note that the JRE is insufficient; the full JDK is required
|
||||
- On Ubuntu, run `sudo apt install openjdk-11-jdk`
|
||||
- On Windows, install the JDK 11 .msi from the link above
|
||||
- On macOS, install the JDK 11 .pkg from the link above
|
||||
- On Ubuntu, run `sudo apt install openjdk-17-jdk`
|
||||
- On Windows, install the JDK 17 .msi from the link above
|
||||
- On macOS, install the JDK 17 .pkg from the link above
|
||||
- C++ compiler
|
||||
- On Linux, install GCC 11 or greater
|
||||
- On Windows, install [Visual Studio Community 2022](https://visualstudio.microsoft.com/vs/community/) and select the C++ programming language during installation (Gradle can't use the build tools for Visual Studio)
|
||||
@@ -60,7 +60,7 @@ On macOS ARM, run `softwareupdate --install-rosetta`. This is necessary to be ab
|
||||
|
||||
## Setup
|
||||
|
||||
Clone the WPILib repository and follow the instructions above for installing any required tooling.
|
||||
Clone the WPILib repository and follow the instructions above for installing any required tooling. The build process uses versioning information from git. Downloading the source is not sufficient to run the build.
|
||||
|
||||
See the [styleguide README](https://github.com/wpilibsuite/styleguide/blob/main/README.md) for wpiformat setup instructions.
|
||||
|
||||
@@ -88,9 +88,24 @@ If opening from a fresh clone, generated java dependencies will not exist. Most
|
||||
|
||||
`./gradlew build` builds _everything_, which includes debug and release builds for desktop and all installed cross compilers. Many developers don't need or want to build all of this. Therefore, common tasks have shortcuts to only build necessary components for common development and testing tasks.
|
||||
|
||||
`./gradlew testDesktopCpp` and `./gradlew testDesktopJava` will build and run the tests for `wpilibc` and `wpilibj` respectively. They will only build the minimum components required to run the tests.
|
||||
`./gradlew testDesktopCpp` and `./gradlew testDesktopJava` will build and run the tests for `wpilibc` and `wpilibj` respectively. They will only build the minimum components required to run the tests. `./gradlew testDesktop` will run both `testDesktopJava` and `testDesktopCpp`.
|
||||
|
||||
`testDesktopCpp` and `testDesktopJava` tasks also exist for the projects `wpiutil`, `ntcore`, `cscore`, `hal` `wpilibNewCommands` and `cameraserver`. These can be ran with `./gradlew :projectName:task`.
|
||||
`testDesktopCpp`, `testDesktopJava`, and `testDesktop` tasks also exist for the following projects:
|
||||
|
||||
- `apriltag`
|
||||
- `cameraserver`
|
||||
- `cscore`
|
||||
- `hal`
|
||||
- `ntcore`
|
||||
- `wpilibNewCommands`
|
||||
- `wpimath`
|
||||
- `wpinet`
|
||||
- `wpiunits`
|
||||
- `wpiutil`
|
||||
- `romiVendordep`
|
||||
- `xrpVendordep`
|
||||
|
||||
These can be ran with `./gradlew :projectName:task`.
|
||||
|
||||
`./gradlew buildDesktopCpp` and `./gradlew buildDesktopJava` will compile `wpilibcExamples` and `wpilibjExamples` respectively. The results can't be ran, but they can compile.
|
||||
|
||||
@@ -164,7 +179,3 @@ The hal directory contains more C++ code meant to run on the roboRIO. HAL is an
|
||||
The upstream_utils directory contains scripts for updating copies of thirdparty code in the repository.
|
||||
|
||||
The [styleguide repository](https://github.com/wpilibsuite/styleguide) contains our style guides for C++ and Java code. Anything submitted to the WPILib project needs to follow the code style guides outlined in there. For details about the style, please see the contributors document [here](CONTRIBUTING.md#coding-guidelines).
|
||||
|
||||
# Contributing to WPILib
|
||||
|
||||
See [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
@@ -43,6 +43,7 @@ Team 254 Library wpilibj/src/main/java/edu/wpi/first/wpilibj/spline/SplineP
|
||||
Portable File Dialogs wpigui/src/main/native/include/portable-file-dialogs.h
|
||||
V8 export-template wpiutil/src/main/native/include/wpi/SymbolExports.h
|
||||
GCEM wpimath/src/main/native/thirdparty/gcem/include/
|
||||
Sleipnir wpimath/src/main/native/thirdparty/sleipnir
|
||||
|
||||
==============================================================================
|
||||
Google Test License
|
||||
@@ -1204,3 +1205,23 @@ distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
================
|
||||
2024 Field Image
|
||||
================
|
||||
2024 Field Image from MikLast: https://www.chiefdelphi.com/t/2024-crescendo-top-down-field-renders/447764
|
||||
|
||||
================
|
||||
Sleipnir License
|
||||
================
|
||||
Copyright (c) Sleipnir contributors
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
@@ -4,106 +4,156 @@ include(CompileWarnings)
|
||||
include(GenResources)
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
fetchcontent_declare(
|
||||
apriltaglib
|
||||
GIT_REPOSITORY https://github.com/wpilibsuite/apriltag.git
|
||||
GIT_TAG 64be6ab26abf5e995321997fd0752c609a7e30f4
|
||||
GIT_REPOSITORY https://github.com/wpilibsuite/apriltag.git
|
||||
GIT_TAG da208cc38c1b78fe89861616d44c0692e76b6b8b
|
||||
)
|
||||
|
||||
# Don't use apriltag's CMakeLists.txt due to conflicting naming and JNI
|
||||
FetchContent_GetProperties(apriltaglib)
|
||||
fetchcontent_getproperties(apriltaglib)
|
||||
if(NOT apriltaglib_POPULATED)
|
||||
FetchContent_Populate(apriltaglib)
|
||||
fetchcontent_populate(apriltaglib)
|
||||
endif()
|
||||
|
||||
aux_source_directory(${apriltaglib_SOURCE_DIR}/common APRILTAGLIB_COMMON_SRC)
|
||||
file(GLOB TAG_FILES ${apriltaglib_SOURCE_DIR}/tag*.c)
|
||||
set(APRILTAGLIB_SRCS ${apriltaglib_SOURCE_DIR}/apriltag.c ${apriltaglib_SOURCE_DIR}/apriltag_pose.c ${apriltaglib_SOURCE_DIR}/apriltag_quad_thresh.c)
|
||||
set(APRILTAGLIB_SRCS
|
||||
${apriltaglib_SOURCE_DIR}/apriltag.c
|
||||
${apriltaglib_SOURCE_DIR}/apriltag_pose.c
|
||||
${apriltaglib_SOURCE_DIR}/apriltag_quad_thresh.c
|
||||
)
|
||||
|
||||
file(GLOB apriltag_jni_src src/main/native/cpp/jni/AprilTagJNI.cpp)
|
||||
|
||||
if (WITH_JAVA)
|
||||
find_package(Java REQUIRED)
|
||||
find_package(JNI REQUIRED)
|
||||
include(UseJava)
|
||||
set(CMAKE_JAVA_COMPILE_FLAGS "-encoding" "UTF8" "-Xlint:unchecked")
|
||||
if(WITH_JAVA)
|
||||
find_package(Java REQUIRED)
|
||||
find_package(JNI REQUIRED)
|
||||
include(UseJava)
|
||||
|
||||
set(CMAKE_JNI_TARGET true)
|
||||
set(CMAKE_JNI_TARGET true)
|
||||
|
||||
file(GLOB EJML_JARS "${WPILIB_BINARY_DIR}/wpimath/thirdparty/ejml/*.jar")
|
||||
file(GLOB JACKSON_JARS "${WPILIB_BINARY_DIR}/wpiutil/thirdparty/jackson/*.jar")
|
||||
find_file(OPENCV_JAR_FILE
|
||||
NAMES opencv-${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}.jar
|
||||
PATHS ${OPENCV_JAVA_INSTALL_DIR} ${OpenCV_INSTALL_PATH}/bin ${OpenCV_INSTALL_PATH}/share/java
|
||||
NO_DEFAULT_PATH)
|
||||
file(GLOB EJML_JARS "${WPILIB_BINARY_DIR}/wpimath/thirdparty/ejml/*.jar")
|
||||
file(GLOB JACKSON_JARS "${WPILIB_BINARY_DIR}/wpiutil/thirdparty/jackson/*.jar")
|
||||
find_file(
|
||||
OPENCV_JAR_FILE
|
||||
NAMES opencv-${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}.jar
|
||||
PATHS
|
||||
${OPENCV_JAVA_INSTALL_DIR}
|
||||
${OpenCV_INSTALL_PATH}/bin
|
||||
${OpenCV_INSTALL_PATH}/share/java
|
||||
${OpenCV_INSTALL_PATH}/share/java/opencv4
|
||||
${OpenCV_INSTALL_PATH}/share/OpenCV/java
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
set(CMAKE_JAVA_INCLUDE_PATH apriltag.jar ${EJML_JARS} ${JACKSON_JARS})
|
||||
set(CMAKE_JAVA_INCLUDE_PATH apriltag.jar ${EJML_JARS} ${JACKSON_JARS})
|
||||
|
||||
file(GLOB_RECURSE JAVA_SOURCES src/main/java/*.java)
|
||||
file(GLOB_RECURSE JAVA_RESOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} src/main/native/resources/*.json)
|
||||
add_jar(apriltag_jar
|
||||
SOURCES ${JAVA_SOURCES}
|
||||
RESOURCES NAMESPACE "edu/wpi/first/apriltag" ${JAVA_RESOURCES}
|
||||
INCLUDE_JARS wpimath_jar ${EJML_JARS} wpiutil_jar ${OPENCV_JAR_FILE}
|
||||
OUTPUT_NAME apriltag
|
||||
GENERATE_NATIVE_HEADERS apriltag_jni_headers)
|
||||
file(GLOB_RECURSE JAVA_SOURCES src/main/java/*.java)
|
||||
file(
|
||||
GLOB_RECURSE JAVA_RESOURCES
|
||||
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
src/main/native/resources/*.json
|
||||
)
|
||||
add_jar(
|
||||
apriltag_jar
|
||||
SOURCES ${JAVA_SOURCES}
|
||||
RESOURCES
|
||||
NAMESPACE "edu/wpi/first/apriltag" ${JAVA_RESOURCES}
|
||||
INCLUDE_JARS wpimath_jar wpiunits_jar ${EJML_JARS} wpiutil_jar ${OPENCV_JAR_FILE}
|
||||
OUTPUT_NAME apriltag
|
||||
GENERATE_NATIVE_HEADERS apriltag_jni_headers
|
||||
)
|
||||
set_property(TARGET apriltag_jar PROPERTY FOLDER "java")
|
||||
|
||||
get_property(APRILTAG_JAR_FILE TARGET apriltag_jar PROPERTY JAR_FILE)
|
||||
install(FILES ${APRILTAG_JAR_FILE} DESTINATION "${java_lib_dest}")
|
||||
install_jar(apriltag_jar DESTINATION ${java_lib_dest})
|
||||
install_jar_exports(TARGETS apriltag_jar FILE apriltag_jar.cmake DESTINATION share/apriltag)
|
||||
|
||||
set_property(TARGET apriltag_jar PROPERTY FOLDER "java")
|
||||
add_library(apriltagjni ${apriltag_jni_src})
|
||||
wpilib_target_warnings(apriltagjni)
|
||||
target_link_libraries(apriltagjni PUBLIC apriltag)
|
||||
|
||||
add_library(apriltagjni ${apriltag_jni_src})
|
||||
wpilib_target_warnings(apriltagjni)
|
||||
target_link_libraries(apriltagjni PUBLIC apriltag)
|
||||
set_property(TARGET apriltagjni PROPERTY FOLDER "libraries")
|
||||
|
||||
set_property(TARGET apriltagjni PROPERTY FOLDER "libraries")
|
||||
|
||||
target_link_libraries(apriltagjni PRIVATE apriltag_jni_headers)
|
||||
add_dependencies(apriltagjni apriltag_jar)
|
||||
|
||||
install(TARGETS apriltagjni EXPORT apriltagjni)
|
||||
target_link_libraries(apriltagjni PRIVATE apriltag_jni_headers)
|
||||
add_dependencies(apriltagjni apriltag_jar)
|
||||
|
||||
install(TARGETS apriltagjni EXPORT apriltagjni)
|
||||
export(TARGETS apriltagjni FILE apriltagjni.cmake NAMESPACE apriltagjni::)
|
||||
endif()
|
||||
|
||||
generate_resources(src/main/native/resources/edu/wpi/first/apriltag generated/main/cpp APRILTAG frc apriltag_resources_src)
|
||||
if(WITH_JAVA_SOURCE)
|
||||
find_package(Java REQUIRED)
|
||||
include(UseJava)
|
||||
file(GLOB APRILTAG_SOURCES src/main/java/edu/wpi/first/apriltag/*.java)
|
||||
add_jar(
|
||||
apriltag_src_jar
|
||||
RESOURCES
|
||||
NAMESPACE "edu/wpi/first/apriltag" ${APRILTAG_SOURCES}
|
||||
NAMESPACE
|
||||
"edu/wpi/first/apriltag/jni"
|
||||
src/main/java/edu/wpi/first/apriltag/jni/AprilTagJNI.java
|
||||
OUTPUT_NAME apriltag-sources
|
||||
)
|
||||
|
||||
get_property(APRILTAG_SRC_JAR_FILE TARGET apriltag_src_jar PROPERTY JAR_FILE)
|
||||
install(FILES ${APRILTAG_SRC_JAR_FILE} DESTINATION "${java_lib_dest}")
|
||||
|
||||
set_property(TARGET apriltag_src_jar PROPERTY FOLDER "java")
|
||||
endif()
|
||||
|
||||
generate_resources(
|
||||
src/main/native/resources/edu/wpi/first/apriltag
|
||||
generated/main/cpp
|
||||
APRILTAG
|
||||
frc
|
||||
apriltag_resources_src
|
||||
)
|
||||
|
||||
file(GLOB apriltag_native_src src/main/native/cpp/*.cpp)
|
||||
|
||||
add_library(apriltag ${apriltag_native_src} ${apriltag_resources_src} ${APRILTAGLIB_SRCS} ${APRILTAGLIB_COMMON_SRC} ${TAG_FILES})
|
||||
add_library(
|
||||
apriltag
|
||||
${apriltag_native_src}
|
||||
${apriltag_resources_src}
|
||||
${APRILTAGLIB_SRCS}
|
||||
${APRILTAGLIB_COMMON_SRC}
|
||||
${TAG_FILES}
|
||||
)
|
||||
set_target_properties(apriltag PROPERTIES DEBUG_POSTFIX "d")
|
||||
|
||||
set_property(TARGET apriltag PROPERTY FOLDER "libraries")
|
||||
target_compile_features(apriltag PUBLIC cxx_std_20)
|
||||
wpilib_target_warnings(apriltag)
|
||||
# disable warnings that apriltaglib can't handle
|
||||
if (MSVC)
|
||||
target_compile_options(apriltag PRIVATE /wd4018 /wd4005 /wd4996)
|
||||
if(MSVC)
|
||||
target_compile_options(apriltag PRIVATE /wd4018 /wd4005 /wd4996)
|
||||
else()
|
||||
target_compile_options(apriltag PRIVATE -Wno-sign-compare -Wno-gnu-zero-variadic-macro-arguments -Wno-type-limits)
|
||||
target_compile_options(
|
||||
apriltag
|
||||
PRIVATE -Wno-sign-compare -Wno-gnu-zero-variadic-macro-arguments -Wno-type-limits
|
||||
)
|
||||
endif()
|
||||
|
||||
target_link_libraries(apriltag wpimath)
|
||||
|
||||
target_include_directories(apriltag PUBLIC
|
||||
$<BUILD_INTERFACE:${apriltaglib_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/include>
|
||||
$<INSTALL_INTERFACE:${include_dest}/apriltag>)
|
||||
target_include_directories(
|
||||
apriltag
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${apriltaglib_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/include>
|
||||
$<INSTALL_INTERFACE:${include_dest}/apriltag>
|
||||
)
|
||||
|
||||
install(TARGETS apriltag EXPORT apriltag)
|
||||
export(TARGETS apriltag FILE apriltag.cmake NAMESPACE apriltag::)
|
||||
install(DIRECTORY src/main/native/include/ DESTINATION "${include_dest}/apriltag")
|
||||
|
||||
if (WITH_FLAT_INSTALL)
|
||||
set (apriltag_config_dir ${wpilib_dest})
|
||||
else()
|
||||
set (apriltag_config_dir share/apriltag)
|
||||
endif()
|
||||
configure_file(apriltag-config.cmake.in ${WPILIB_BINARY_DIR}/apriltag-config.cmake)
|
||||
install(FILES ${WPILIB_BINARY_DIR}/apriltag-config.cmake DESTINATION share/apriltag)
|
||||
install(EXPORT apriltag DESTINATION share/apriltag)
|
||||
|
||||
configure_file(apriltag-config.cmake.in ${WPILIB_BINARY_DIR}/apriltag-config.cmake )
|
||||
install(FILES ${WPILIB_BINARY_DIR}/apriltag-config.cmake DESTINATION ${apriltag_config_dir})
|
||||
install(EXPORT apriltag DESTINATION ${apriltag_config_dir})
|
||||
|
||||
if (WITH_TESTS)
|
||||
if(WITH_TESTS)
|
||||
wpilib_add_test(apriltag src/test/native/cpp)
|
||||
target_include_directories(apriltag_test PRIVATE src/test/native/include)
|
||||
target_link_libraries(apriltag_test apriltag gmock_main)
|
||||
|
||||
28
apriltag/README.md
Normal file
28
apriltag/README.md
Normal file
@@ -0,0 +1,28 @@
|
||||
# AprilTag
|
||||
|
||||
## Adding new field to AprilTagFields
|
||||
|
||||
### Adding field JSON
|
||||
|
||||
1. Add a field layout CSV file to `src/main/native/resources/edu/wpi/first/apriltag`
|
||||
1. See docstring in `convert_apriltag_layouts.py` for more
|
||||
2. Run `convert_apriltag_layouts.py` in the same directory as this readme to generate the JSON
|
||||
3. That script overwrites all generated JSONs, so undo undesired changes if necessary
|
||||
4. Update the field dimensions at the bottom of the JSON
|
||||
1. Length should be in meters from alliance wall to alliance wall
|
||||
2. Width should be in meters from inside guardrail plastic to plastic
|
||||
|
||||
### Java updates
|
||||
|
||||
1. Update `src/main/java/edu/wpi/first/apriltag/AprilTagFields.java`
|
||||
1. Add enum value for new field to `AprilTagFields`
|
||||
2. Update `AprilTagFields.kDefaultField` if necessary
|
||||
|
||||
### C++ updates
|
||||
|
||||
1. Update `src/main/native/include/frc/apriltag/AprilTagFields.h`
|
||||
1. Add enum value for new field to `AprilTagFields`
|
||||
2. Update `AprilTagFields::kDefaultField` if necessary
|
||||
2. Update `src/main/native/cpp/AprilTagFields.cpp`
|
||||
1. Add resource getter prototype like `std::string_view GetResource_2024_crescendo_json()`
|
||||
2. Add case for new field to switch in `LoadAprilTagLayoutField()`
|
||||
@@ -5,3 +5,6 @@ include(CMakeFindDependencyMacro)
|
||||
|
||||
@FILENAME_DEP_REPLACE@
|
||||
include(${SELF_DIR}/apriltag.cmake)
|
||||
if(@WITH_JAVA@)
|
||||
include(${SELF_DIR}/apriltag_jar.cmake)
|
||||
endif()
|
||||
|
||||
89
apriltag/convert_apriltag_layouts.py
Executable file
89
apriltag/convert_apriltag_layouts.py
Executable file
@@ -0,0 +1,89 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
"""
|
||||
This script converts all AprilTag field layout CSV files in
|
||||
src/main/native/resources/edu/wpi/first/apriltag to the JSON format
|
||||
AprilTagFields expects.
|
||||
|
||||
The input CSV has the following format:
|
||||
|
||||
* Columns: ID, X, Y, Z, Rotation
|
||||
* ID is a positive integer
|
||||
* X, Y, and Z are decimal inches
|
||||
* Rotation is yaw in degrees
|
||||
|
||||
The values come from a table in the layout marking diagram (e.g.,
|
||||
https://firstfrc.blob.core.windows.net/frc2024/FieldAssets/2024LayoutMarkingDiagram.pdf).
|
||||
"""
|
||||
|
||||
import csv
|
||||
import json
|
||||
import os
|
||||
|
||||
from wpimath import geometry, units
|
||||
import numpy as np
|
||||
|
||||
|
||||
def main():
|
||||
# Find AprilTag field layout CSVs
|
||||
filenames = [
|
||||
os.path.join(dp, f)
|
||||
for dp, dn, fn in os.walk("src/main/native/resources/edu/wpi/first/apriltag")
|
||||
for f in fn
|
||||
if f.endswith(".csv")
|
||||
]
|
||||
|
||||
for filename in filenames:
|
||||
json_data = {"tags": [], "field": {"length": 0.0, "width": 0.0}}
|
||||
|
||||
# Read CSV and fill in JSON data
|
||||
with open(filename, newline="") as csvfile:
|
||||
reader = csv.reader(csvfile, delimiter=",")
|
||||
|
||||
# Skip header
|
||||
next(reader)
|
||||
|
||||
for row in reader:
|
||||
# Unpack row elements
|
||||
id = int(row[0])
|
||||
x = float(row[1])
|
||||
y = float(row[2])
|
||||
z = float(row[3])
|
||||
rotation = float(row[4])
|
||||
|
||||
# Turn yaw into quaternion
|
||||
q = geometry.Rotation3d(
|
||||
units.radians(0.0),
|
||||
units.radians(0.0),
|
||||
units.degreesToRadians(rotation),
|
||||
).getQuaternion()
|
||||
|
||||
json_data["tags"].append(
|
||||
{
|
||||
"ID": id,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": units.inchesToMeters(x),
|
||||
"y": units.inchesToMeters(y),
|
||||
"z": units.inchesToMeters(z),
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": q.W(),
|
||||
"X": q.X(),
|
||||
"Y": q.Y(),
|
||||
"Z": q.Z(),
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
# Write JSON
|
||||
with open(filename.replace(".csv", ".json"), "w") as f:
|
||||
json.dump(json_data, f, indent=2)
|
||||
f.write("\n")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -6,17 +6,28 @@ package edu.wpi.first.apriltag;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import edu.wpi.first.apriltag.jni.AprilTagJNI;
|
||||
import edu.wpi.first.math.geometry.Pose3d;
|
||||
import edu.wpi.first.util.RawFrame;
|
||||
import java.util.Objects;
|
||||
|
||||
/** Represents an AprilTag's metadata. */
|
||||
@SuppressWarnings("MemberName")
|
||||
public class AprilTag {
|
||||
/** The tag's ID. */
|
||||
@JsonProperty(value = "ID")
|
||||
public int ID;
|
||||
|
||||
/** The tag's pose. */
|
||||
@JsonProperty(value = "pose")
|
||||
public Pose3d pose;
|
||||
|
||||
/**
|
||||
* Constructs an AprilTag.
|
||||
*
|
||||
* @param ID The tag's ID.
|
||||
* @param pose The tag's pose.
|
||||
*/
|
||||
@SuppressWarnings("ParameterName")
|
||||
@JsonCreator
|
||||
public AprilTag(
|
||||
@@ -28,11 +39,7 @@ public class AprilTag {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof AprilTag) {
|
||||
var other = (AprilTag) obj;
|
||||
return ID == other.ID && pose.equals(other.pose);
|
||||
}
|
||||
return false;
|
||||
return obj instanceof AprilTag tag && ID == tag.ID && pose.equals(tag.pose);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -44,4 +51,28 @@ public class AprilTag {
|
||||
public String toString() {
|
||||
return "AprilTag(ID: " + ID + ", pose: " + pose + ")";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a RawFrame containing the apriltag with the id with family 16h5 passed in.
|
||||
*
|
||||
* @param id id
|
||||
* @return A RawFrame containing the AprilTag image
|
||||
*/
|
||||
public static RawFrame generate16h5AprilTagImage(int id) {
|
||||
RawFrame frame = new RawFrame();
|
||||
AprilTagJNI.generate16h5AprilTagImage(frame, frame.getNativeObj(), id);
|
||||
return frame;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a RawFrame containing the apriltag with the id with family 36h11 passed in.
|
||||
*
|
||||
* @param id id
|
||||
* @return A RawFrame containing the AprilTag image
|
||||
*/
|
||||
public static RawFrame generate36h11AprilTagImage(int id) {
|
||||
RawFrame frame = new RawFrame();
|
||||
AprilTagJNI.generate36h11AprilTagImage(frame, frame.getNativeObj(), id);
|
||||
return frame;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ public class AprilTagDetection {
|
||||
* @return Homography matrix
|
||||
*/
|
||||
public Matrix<N3, N3> getHomographyMatrix() {
|
||||
return new MatBuilder<>(Nat.N3(), Nat.N3()).fill(m_homography);
|
||||
return MatBuilder.fill(Nat.N3(), Nat.N3(), m_homography);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -95,7 +95,7 @@ public class AprilTagDetection {
|
||||
|
||||
/**
|
||||
* Gets a corner of the tag in image pixel coordinates. These always wrap counter-clock wise
|
||||
* around the tag.
|
||||
* around the tag. Index 0 is the bottom left corner.
|
||||
*
|
||||
* @param ndx Corner index (range is 0-3, inclusive)
|
||||
* @return Corner point X coordinate
|
||||
@@ -106,7 +106,7 @@ public class AprilTagDetection {
|
||||
|
||||
/**
|
||||
* Gets a corner of the tag in image pixel coordinates. These always wrap counter-clock wise
|
||||
* around the tag.
|
||||
* around the tag. Index 0 is the bottom left corner.
|
||||
*
|
||||
* @param ndx Corner index (range is 0-3, inclusive)
|
||||
* @return Corner point Y coordinate
|
||||
@@ -117,7 +117,8 @@ public class AprilTagDetection {
|
||||
|
||||
/**
|
||||
* Gets the corners of the tag in image pixel coordinates. These always wrap counter-clock wise
|
||||
* around the tag.
|
||||
* around the tag. The first set of corner coordinates are the coordinates for the bottom left
|
||||
* corner.
|
||||
*
|
||||
* @return Corner point array (X and Y for each corner in order)
|
||||
*/
|
||||
|
||||
@@ -57,8 +57,21 @@ public class AprilTagDetector implements AutoCloseable {
|
||||
*/
|
||||
public boolean debug;
|
||||
|
||||
/** Default constructor. */
|
||||
public Config() {}
|
||||
|
||||
/**
|
||||
* Constructs a detector configuration.
|
||||
*
|
||||
* @param numThreads How many threads should be used for computation.
|
||||
* @param quadDecimate Quad decimation.
|
||||
* @param quadSigma What Gaussian blur should be applied to the segmented image (used for quad
|
||||
* detection).
|
||||
* @param refineEdges When true, the edges of the each quad are adjusted to "snap to" strong
|
||||
* gradients nearby.
|
||||
* @param decodeSharpening How much sharpening should be done to decoded images.
|
||||
* @param debug Debug mode.
|
||||
*/
|
||||
Config(
|
||||
int numThreads,
|
||||
float quadDecimate,
|
||||
@@ -86,12 +99,8 @@ public class AprilTagDetector implements AutoCloseable {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Config)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Config other = (Config) obj;
|
||||
return numThreads == other.numThreads
|
||||
return obj instanceof Config other
|
||||
&& numThreads == other.numThreads
|
||||
&& quadDecimate == other.quadDecimate
|
||||
&& quadSigma == other.quadSigma
|
||||
&& refineEdges == other.refineEdges
|
||||
@@ -139,8 +148,21 @@ public class AprilTagDetector implements AutoCloseable {
|
||||
*/
|
||||
public boolean deglitch;
|
||||
|
||||
/** Default constructor. */
|
||||
public QuadThresholdParameters() {}
|
||||
|
||||
/**
|
||||
* Constructs quad threshold parameters.
|
||||
*
|
||||
* @param minClusterPixels Threshold used to reject quads containing too few pixels.
|
||||
* @param maxNumMaxima How many corner candidates to consider when segmenting a group of pixels
|
||||
* into a quad.
|
||||
* @param criticalAngle Critical angle, in radians.
|
||||
* @param maxLineFitMSE When fitting lines to the contours, the maximum mean squared error
|
||||
* allowed.
|
||||
* @param minWhiteBlackDiff Minimum brightness offset.
|
||||
* @param deglitch Whether the thresholded image be should be deglitched.
|
||||
*/
|
||||
QuadThresholdParameters(
|
||||
int minClusterPixels,
|
||||
int maxNumMaxima,
|
||||
@@ -168,12 +190,8 @@ public class AprilTagDetector implements AutoCloseable {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof QuadThresholdParameters)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QuadThresholdParameters other = (QuadThresholdParameters) obj;
|
||||
return minClusterPixels == other.minClusterPixels
|
||||
return obj instanceof QuadThresholdParameters other
|
||||
&& minClusterPixels == other.minClusterPixels
|
||||
&& maxNumMaxima == other.maxNumMaxima
|
||||
&& criticalAngle == other.criticalAngle
|
||||
&& maxLineFitMSE == other.maxLineFitMSE
|
||||
@@ -182,6 +200,7 @@ public class AprilTagDetector implements AutoCloseable {
|
||||
}
|
||||
}
|
||||
|
||||
/** Constructs an AprilTagDetector. */
|
||||
public AprilTagDetector() {
|
||||
m_native = AprilTagJNI.createDetector();
|
||||
}
|
||||
@@ -244,7 +263,7 @@ public class AprilTagDetector implements AutoCloseable {
|
||||
* Adds a family of tags to be detected.
|
||||
*
|
||||
* @param fam Family name, e.g. "tag16h5"
|
||||
* @param bitsCorrected maximum number of bits to correct
|
||||
* @param bitsCorrected Maximum number of bits to correct
|
||||
* @throws IllegalArgumentException if family name not recognized
|
||||
*/
|
||||
public void addFamily(String fam, int bitsCorrected) {
|
||||
@@ -270,6 +289,8 @@ public class AprilTagDetector implements AutoCloseable {
|
||||
/**
|
||||
* Detect tags from an 8-bit image.
|
||||
*
|
||||
* <p>The image must be grayscale.
|
||||
*
|
||||
* @param img 8-bit OpenCV Mat image
|
||||
* @return Results (array of AprilTagDetection)
|
||||
*/
|
||||
|
||||
@@ -16,6 +16,7 @@ import edu.wpi.first.math.geometry.Translation3d;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@@ -44,8 +45,11 @@ import java.util.Optional;
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
@JsonAutoDetect(getterVisibility = JsonAutoDetect.Visibility.NONE)
|
||||
public class AprilTagFieldLayout {
|
||||
/** Common origin positions for the AprilTag coordinate system. */
|
||||
public enum OriginPosition {
|
||||
/** Blue alliance wall, right side. */
|
||||
kBlueAllianceWallRightSide,
|
||||
/** Red alliance wall, right side. */
|
||||
kRedAllianceWallRightSide,
|
||||
}
|
||||
|
||||
@@ -113,6 +117,26 @@ public class AprilTagFieldLayout {
|
||||
return new ArrayList<>(m_apriltags.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the field the layout is representing in meters.
|
||||
*
|
||||
* @return length, in meters
|
||||
*/
|
||||
@JsonIgnore
|
||||
public double getFieldLength() {
|
||||
return m_fieldDimensions.fieldLength;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the field the layout is representing in meters.
|
||||
*
|
||||
* @return width, in meters
|
||||
*/
|
||||
@JsonIgnore
|
||||
public double getFieldWidth() {
|
||||
return m_fieldDimensions.fieldWidth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the origin based on a predefined enumeration of coordinate frame origins. The origins are
|
||||
* calculated from the field dimensions.
|
||||
@@ -123,20 +147,15 @@ public class AprilTagFieldLayout {
|
||||
* @param origin The predefined origin
|
||||
*/
|
||||
@JsonIgnore
|
||||
public void setOrigin(OriginPosition origin) {
|
||||
switch (origin) {
|
||||
case kBlueAllianceWallRightSide:
|
||||
setOrigin(new Pose3d());
|
||||
break;
|
||||
case kRedAllianceWallRightSide:
|
||||
setOrigin(
|
||||
new Pose3d(
|
||||
new Translation3d(m_fieldDimensions.fieldLength, m_fieldDimensions.fieldWidth, 0),
|
||||
new Rotation3d(0, 0, Math.PI)));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported enum value");
|
||||
}
|
||||
public final void setOrigin(OriginPosition origin) {
|
||||
var pose =
|
||||
switch (origin) {
|
||||
case kBlueAllianceWallRightSide -> Pose3d.kZero;
|
||||
case kRedAllianceWallRightSide -> new Pose3d(
|
||||
new Translation3d(m_fieldDimensions.fieldLength, m_fieldDimensions.fieldWidth, 0),
|
||||
new Rotation3d(0, 0, Math.PI));
|
||||
};
|
||||
setOrigin(pose);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -148,10 +167,20 @@ public class AprilTagFieldLayout {
|
||||
* @param origin The new origin for tag transformations
|
||||
*/
|
||||
@JsonIgnore
|
||||
public void setOrigin(Pose3d origin) {
|
||||
public final void setOrigin(Pose3d origin) {
|
||||
m_origin = origin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the origin used for tag pose transformation.
|
||||
*
|
||||
* @return the origin
|
||||
*/
|
||||
@JsonIgnore
|
||||
public Pose3d getOrigin() {
|
||||
return m_origin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an AprilTag pose by its ID.
|
||||
*
|
||||
@@ -188,6 +217,29 @@ public class AprilTagFieldLayout {
|
||||
new ObjectMapper().writeValue(path.toFile(), this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an official {@link AprilTagFieldLayout}.
|
||||
*
|
||||
* @param field The loadable AprilTag field layout.
|
||||
* @return AprilTagFieldLayout of the field.
|
||||
* @throws UncheckedIOException If the layout does not exist.
|
||||
*/
|
||||
public static AprilTagFieldLayout loadField(AprilTagFields field) {
|
||||
if (field.m_fieldLayout == null) {
|
||||
try {
|
||||
field.m_fieldLayout = loadFromResource(field.m_resourceFile);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(
|
||||
"Could not load AprilTagFieldLayout from " + field.m_resourceFile, e);
|
||||
}
|
||||
}
|
||||
// Copy layout because the layout's origin is mutable
|
||||
return new AprilTagFieldLayout(
|
||||
field.m_fieldLayout.getTags(),
|
||||
field.m_fieldLayout.getFieldLength(),
|
||||
field.m_fieldLayout.getFieldWidth());
|
||||
}
|
||||
|
||||
/**
|
||||
* Deserializes a field layout from a resource within a internal jar file.
|
||||
*
|
||||
@@ -214,11 +266,9 @@ public class AprilTagFieldLayout {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (obj instanceof AprilTagFieldLayout) {
|
||||
var other = (AprilTagFieldLayout) obj;
|
||||
return m_apriltags.equals(other.m_apriltags) && m_origin.equals(other.m_origin);
|
||||
}
|
||||
return false;
|
||||
return obj instanceof AprilTagFieldLayout layout
|
||||
&& m_apriltags.equals(layout.m_apriltags)
|
||||
&& m_origin.equals(layout.m_origin);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -231,11 +281,11 @@ public class AprilTagFieldLayout {
|
||||
private static class FieldDimensions {
|
||||
@SuppressWarnings("MemberName")
|
||||
@JsonProperty(value = "length")
|
||||
public double fieldLength;
|
||||
public final double fieldLength;
|
||||
|
||||
@SuppressWarnings("MemberName")
|
||||
@JsonProperty(value = "width")
|
||||
public double fieldWidth;
|
||||
public final double fieldWidth;
|
||||
|
||||
@JsonCreator()
|
||||
FieldDimensions(
|
||||
|
||||
@@ -4,20 +4,28 @@
|
||||
|
||||
package edu.wpi.first.apriltag;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
|
||||
/** Loadable AprilTag field layouts. */
|
||||
public enum AprilTagFields {
|
||||
/** 2022 Rapid React. */
|
||||
k2022RapidReact("2022-rapidreact.json"),
|
||||
k2023ChargedUp("2023-chargedup.json");
|
||||
/** 2023 Charged Up. */
|
||||
k2023ChargedUp("2023-chargedup.json"),
|
||||
/** 2024 Crescendo. */
|
||||
k2024Crescendo("2024-crescendo.json");
|
||||
|
||||
/** Base resource directory. */
|
||||
public static final String kBaseResourceDir = "/edu/wpi/first/apriltag/";
|
||||
|
||||
/** Alias to the current game. */
|
||||
public static final AprilTagFields kDefaultField = k2023ChargedUp;
|
||||
public static final AprilTagFields kDefaultField = k2024Crescendo;
|
||||
|
||||
/** Resource filename. */
|
||||
public final String m_resourceFile;
|
||||
|
||||
AprilTagFieldLayout m_fieldLayout;
|
||||
|
||||
AprilTagFields(String resourceFile) {
|
||||
m_resourceFile = kBaseResourceDir + resourceFile;
|
||||
}
|
||||
@@ -27,13 +35,10 @@ public enum AprilTagFields {
|
||||
*
|
||||
* @return AprilTagFieldLayout of the field
|
||||
* @throws UncheckedIOException If the layout does not exist
|
||||
* @deprecated Use {@link AprilTagFieldLayout#loadField(AprilTagFields)} instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "2025")
|
||||
public AprilTagFieldLayout loadAprilTagLayoutField() {
|
||||
try {
|
||||
return AprilTagFieldLayout.loadFromResource(m_resourceFile);
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(
|
||||
"Could not load AprilTagFieldLayout from " + m_resourceFile, e);
|
||||
}
|
||||
return AprilTagFieldLayout.loadField(this);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,10 +29,19 @@ public class AprilTagPoseEstimator {
|
||||
this.cy = cy;
|
||||
}
|
||||
|
||||
/** Tag size, in meters. */
|
||||
public double tagSize;
|
||||
|
||||
/** Camera horizontal focal length, in pixels. */
|
||||
public double fx;
|
||||
|
||||
/** Camera vertical focal length, in pixels. */
|
||||
public double fy;
|
||||
|
||||
/** Camera horizontal focal center, in pixels. */
|
||||
public double cx;
|
||||
|
||||
/** Camera vertical focal center, in pixels. */
|
||||
public double cy;
|
||||
|
||||
@Override
|
||||
@@ -46,12 +55,8 @@ public class AprilTagPoseEstimator {
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Config)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Config other = (Config) obj;
|
||||
return tagSize == other.tagSize
|
||||
return obj instanceof Config other
|
||||
&& tagSize == other.tagSize
|
||||
&& fx == other.fx
|
||||
&& fy == other.fy
|
||||
&& cx == other.cx
|
||||
|
||||
@@ -8,34 +8,45 @@ import edu.wpi.first.apriltag.AprilTagDetection;
|
||||
import edu.wpi.first.apriltag.AprilTagDetector;
|
||||
import edu.wpi.first.apriltag.AprilTagPoseEstimate;
|
||||
import edu.wpi.first.math.geometry.Transform3d;
|
||||
import edu.wpi.first.util.RawFrame;
|
||||
import edu.wpi.first.util.RuntimeLoader;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
/** AprilTag JNI. */
|
||||
public class AprilTagJNI {
|
||||
static boolean libraryLoaded = false;
|
||||
|
||||
static RuntimeLoader<AprilTagJNI> loader = null;
|
||||
|
||||
/** Sets whether JNI should be loaded in the static block. */
|
||||
public static class Helper {
|
||||
private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true);
|
||||
|
||||
/**
|
||||
* Returns true if the JNI should be loaded in the static block.
|
||||
*
|
||||
* @return True if the JNI should be loaded in the static block.
|
||||
*/
|
||||
public static boolean getExtractOnStaticLoad() {
|
||||
return extractOnStaticLoad.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the JNI should be loaded in the static block.
|
||||
*
|
||||
* @param load Whether the JNI should be loaded in the static block.
|
||||
*/
|
||||
public static void setExtractOnStaticLoad(boolean load) {
|
||||
extractOnStaticLoad.set(load);
|
||||
}
|
||||
|
||||
/** Utility class. */
|
||||
private Helper() {}
|
||||
}
|
||||
|
||||
static {
|
||||
if (Helper.getExtractOnStaticLoad()) {
|
||||
try {
|
||||
loader =
|
||||
new RuntimeLoader<>(
|
||||
"apriltagjni", RuntimeLoader.getDefaultExtractionRoot(), AprilTagJNI.class);
|
||||
loader.loadLibrary();
|
||||
RuntimeLoader.loadLibrary("apriltagjni");
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
System.exit(1);
|
||||
@@ -44,31 +55,119 @@ public class AprilTagJNI {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an AprilTag detector engine.
|
||||
*
|
||||
* @return The detector engine handle
|
||||
*/
|
||||
public static native long createDetector();
|
||||
|
||||
/**
|
||||
* Destroys an AprilTag detector engine.
|
||||
*
|
||||
* @param det The detector engine handle
|
||||
*/
|
||||
public static native void destroyDetector(long det);
|
||||
|
||||
/**
|
||||
* Sets the detector engine configuration.
|
||||
*
|
||||
* @param det The detector engine handle
|
||||
* @param config A configuration
|
||||
*/
|
||||
public static native void setDetectorConfig(long det, AprilTagDetector.Config config);
|
||||
|
||||
/**
|
||||
* Gets the detector engine configuration.
|
||||
*
|
||||
* @param det The detector engine handle
|
||||
* @return The configuration
|
||||
*/
|
||||
public static native AprilTagDetector.Config getDetectorConfig(long det);
|
||||
|
||||
/**
|
||||
* Sets the detector engine quad threshold parameters.
|
||||
*
|
||||
* @param det The detector engine handle
|
||||
* @param params Quad threshold parameters
|
||||
*/
|
||||
public static native void setDetectorQTP(
|
||||
long det, AprilTagDetector.QuadThresholdParameters params);
|
||||
|
||||
/**
|
||||
* Gets the detector engine quad threshold parameters.
|
||||
*
|
||||
* @param det The detector engine handle
|
||||
* @return Quad threshold parameters
|
||||
*/
|
||||
public static native AprilTagDetector.QuadThresholdParameters getDetectorQTP(long det);
|
||||
|
||||
/**
|
||||
* Adds a family of tags to be detected by the detector engine.
|
||||
*
|
||||
* @param det The detector engine handle
|
||||
* @param fam Family name, e.g. "tag16h5"
|
||||
* @param bitsCorrected Maximum number of bits to correct
|
||||
* @return False if family can't be found
|
||||
*/
|
||||
public static native boolean addFamily(long det, String fam, int bitsCorrected);
|
||||
|
||||
/**
|
||||
* Removes a family of tags from the detector.
|
||||
*
|
||||
* @param det The detector engine handle
|
||||
* @param fam Family name, e.g. "tag16h5"
|
||||
*/
|
||||
public static native void removeFamily(long det, String fam);
|
||||
|
||||
/**
|
||||
* Unregister all families.
|
||||
*
|
||||
* @param det The detector engine handle
|
||||
*/
|
||||
public static native void clearFamilies(long det);
|
||||
|
||||
/**
|
||||
* Detect tags from an 8-bit image.
|
||||
*
|
||||
* @param det The detector engine handle
|
||||
* @param width The width of the image
|
||||
* @param height The height of the image
|
||||
* @param stride The number of bytes between image rows (often the same as width)
|
||||
* @param bufAddr The address of the image buffer
|
||||
* @return The results (array of AprilTagDetection)
|
||||
*/
|
||||
public static native AprilTagDetection[] detect(
|
||||
long det, int width, int height, int stride, long bufAddr);
|
||||
|
||||
/**
|
||||
* Estimates the pose of the tag using the homography method described in [1].
|
||||
*
|
||||
* @param homography Homography 3x3 matrix data
|
||||
* @param tagSize The tag size, in meters
|
||||
* @param fx The camera horizontal focal length, in pixels
|
||||
* @param fy The camera vertical focal length, in pixels
|
||||
* @param cx The camera horizontal focal center, in pixels
|
||||
* @param cy The camera vertical focal center, in pixels
|
||||
* @return Pose estimate
|
||||
*/
|
||||
public static native Transform3d estimatePoseHomography(
|
||||
double[] homography, double tagSize, double fx, double fy, double cx, double cy);
|
||||
|
||||
/**
|
||||
* Estimates the pose of the tag. This returns one or two possible poses for the tag, along with
|
||||
* the object-space error of each.
|
||||
*
|
||||
* @param homography Homography 3x3 matrix data
|
||||
* @param corners Corner point array (X and Y for each corner in order)
|
||||
* @param tagSize The tag size, in meters
|
||||
* @param fx The camera horizontal focal length, in pixels
|
||||
* @param fy The camera vertical focal length, in pixels
|
||||
* @param cx The camera horizontal focal center, in pixels
|
||||
* @param cy The camera vertical focal center, in pixels
|
||||
* @param nIters Number of iterations
|
||||
* @return Initial and (possibly) second pose estimates
|
||||
*/
|
||||
public static native AprilTagPoseEstimate estimatePoseOrthogonalIteration(
|
||||
double[] homography,
|
||||
double[] corners,
|
||||
@@ -79,6 +178,20 @@ public class AprilTagJNI {
|
||||
double cy,
|
||||
int nIters);
|
||||
|
||||
/**
|
||||
* Estimates tag pose. This method is an easier to use interface to
|
||||
* EstimatePoseOrthogonalIteration(), running 50 iterations and returning the pose with the lower
|
||||
* object-space error.
|
||||
*
|
||||
* @param homography Homography 3x3 matrix data
|
||||
* @param corners Corner point array (X and Y for each corner in order)
|
||||
* @param tagSize The tag size, in meters
|
||||
* @param fx The camera horizontal focal length, in pixels
|
||||
* @param fy The camera vertical focal length, in pixels
|
||||
* @param cx The camera horizontal focal center, in pixels
|
||||
* @param cy The camera vertical focal center, in pixels
|
||||
* @return Pose estimate
|
||||
*/
|
||||
public static native Transform3d estimatePose(
|
||||
double[] homography,
|
||||
double[] corners,
|
||||
@@ -87,4 +200,25 @@ public class AprilTagJNI {
|
||||
double fy,
|
||||
double cx,
|
||||
double cy);
|
||||
|
||||
/**
|
||||
* Generates a RawFrame containing the apriltag with the id with family 16h5 passed in.
|
||||
*
|
||||
* @param frameObj generated frame (output parameter).
|
||||
* @param frame raw frame handle
|
||||
* @param id id
|
||||
*/
|
||||
public static native void generate16h5AprilTagImage(RawFrame frameObj, long frame, int id);
|
||||
|
||||
/**
|
||||
* Generates a RawFrame containing the apriltag with the id with family 36h11 passed in.
|
||||
*
|
||||
* @param frameObj generated frame (output parameter).
|
||||
* @param frame raw frame handle
|
||||
* @param id id
|
||||
*/
|
||||
public static native void generate36h11AprilTagImage(RawFrame frameObj, long frame, int id);
|
||||
|
||||
/** Utility class. */
|
||||
private AprilTagJNI() {}
|
||||
}
|
||||
|
||||
@@ -4,10 +4,53 @@
|
||||
|
||||
#include "frc/apriltag/AprilTag.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <wpi/json.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#pragma warning(disable : 4200)
|
||||
#elif defined(__clang__)
|
||||
#pragma clang diagnostic ignored "-Wc99-extensions"
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||
#endif
|
||||
|
||||
#include "apriltag.h"
|
||||
#include "tag16h5.h"
|
||||
#include "tag36h11.h"
|
||||
|
||||
using namespace frc;
|
||||
|
||||
static bool FamilyToImage(wpi::RawFrame* frame, apriltag_family_t* family,
|
||||
int id) {
|
||||
image_u8_t* image = apriltag_to_image(family, id);
|
||||
size_t totalDataSize = image->height * image->stride;
|
||||
bool rv = frame->Reserve(totalDataSize);
|
||||
std::memcpy(frame->data, image->buf, totalDataSize);
|
||||
frame->size = totalDataSize;
|
||||
frame->width = image->width;
|
||||
frame->height = image->height;
|
||||
frame->stride = image->stride;
|
||||
frame->pixelFormat = WPI_PIXFMT_GRAY;
|
||||
image_u8_destroy(image);
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool AprilTag::Generate36h11AprilTagImage(wpi::RawFrame* frame, int id) {
|
||||
apriltag_family_t* tagFamily = tag36h11_create();
|
||||
bool rv = FamilyToImage(frame, tagFamily, id);
|
||||
tag36h11_destroy(tagFamily);
|
||||
return rv;
|
||||
}
|
||||
|
||||
bool AprilTag::Generate16h5AprilTagImage(wpi::RawFrame* frame, int id) {
|
||||
apriltag_family_t* tagFamily = tag16h5_create();
|
||||
bool rv = FamilyToImage(frame, tagFamily, id);
|
||||
tag16h5_destroy(tagFamily);
|
||||
return rv;
|
||||
}
|
||||
|
||||
void frc::to_json(wpi::json& json, const AprilTag& apriltag) {
|
||||
json = wpi::json{{"ID", apriltag.ID}, {"pose", apriltag.pose}};
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ AprilTagFieldLayout::AprilTagFieldLayout(std::string_view path) {
|
||||
throw std::runtime_error(fmt::format("Cannot open file: {}", path));
|
||||
}
|
||||
|
||||
wpi::json json = wpi::json::parse(fileBuffer->begin(), fileBuffer->end());
|
||||
wpi::json json = wpi::json::parse(fileBuffer->GetCharBuffer());
|
||||
|
||||
for (const auto& tag : json.at("tags").get<std::vector<AprilTag>>()) {
|
||||
m_apriltags[tag.ID] = tag;
|
||||
@@ -41,6 +41,23 @@ AprilTagFieldLayout::AprilTagFieldLayout(std::vector<AprilTag> apriltags,
|
||||
}
|
||||
}
|
||||
|
||||
units::meter_t AprilTagFieldLayout::GetFieldLength() const {
|
||||
return m_fieldLength;
|
||||
}
|
||||
|
||||
units::meter_t AprilTagFieldLayout::GetFieldWidth() const {
|
||||
return m_fieldWidth;
|
||||
}
|
||||
|
||||
std::vector<AprilTag> AprilTagFieldLayout::GetTags() const {
|
||||
std::vector<AprilTag> tags;
|
||||
tags.reserve(m_apriltags.size());
|
||||
for (const auto& tag : m_apriltags) {
|
||||
tags.emplace_back(tag.second);
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
void AprilTagFieldLayout::SetOrigin(OriginPosition origin) {
|
||||
switch (origin) {
|
||||
case OriginPosition::kBlueAllianceWallRightSide:
|
||||
@@ -59,6 +76,10 @@ void AprilTagFieldLayout::SetOrigin(const Pose3d& origin) {
|
||||
m_origin = origin;
|
||||
}
|
||||
|
||||
Pose3d AprilTagFieldLayout::GetOrigin() const {
|
||||
return m_origin;
|
||||
}
|
||||
|
||||
std::optional<frc::Pose3d> AprilTagFieldLayout::GetTagPose(int ID) const {
|
||||
const auto& it = m_apriltags.find(ID);
|
||||
if (it == m_apriltags.end()) {
|
||||
@@ -104,3 +125,37 @@ void frc::from_json(const wpi::json& json, AprilTagFieldLayout& layout) {
|
||||
layout.m_fieldWidth =
|
||||
units::meter_t{json.at("field").at("width").get<double>()};
|
||||
}
|
||||
|
||||
// Use namespace declaration for forward declaration
|
||||
namespace frc {
|
||||
|
||||
// C++ generated from resource files
|
||||
std::string_view GetResource_2022_rapidreact_json();
|
||||
std::string_view GetResource_2023_chargedup_json();
|
||||
std::string_view GetResource_2024_crescendo_json();
|
||||
|
||||
} // namespace frc
|
||||
|
||||
AprilTagFieldLayout AprilTagFieldLayout::LoadField(AprilTagField field) {
|
||||
std::string_view fieldString;
|
||||
switch (field) {
|
||||
case AprilTagField::k2022RapidReact:
|
||||
fieldString = GetResource_2022_rapidreact_json();
|
||||
break;
|
||||
case AprilTagField::k2023ChargedUp:
|
||||
fieldString = GetResource_2023_chargedup_json();
|
||||
break;
|
||||
case AprilTagField::k2024Crescendo:
|
||||
fieldString = GetResource_2024_crescendo_json();
|
||||
break;
|
||||
case AprilTagField::kNumFields:
|
||||
throw std::invalid_argument("Invalid Field");
|
||||
}
|
||||
|
||||
wpi::json json = wpi::json::parse(fieldString);
|
||||
return json.get<AprilTagFieldLayout>();
|
||||
}
|
||||
|
||||
AprilTagFieldLayout frc::LoadAprilTagLayoutField(AprilTagField field) {
|
||||
return AprilTagFieldLayout::LoadField(field);
|
||||
}
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include "frc/apriltag/AprilTagFields.h"
|
||||
|
||||
#include <wpi/json.h>
|
||||
|
||||
namespace frc {
|
||||
|
||||
// C++ generated from resource files
|
||||
std::string_view GetResource_2022_rapidreact_json();
|
||||
std::string_view GetResource_2023_chargedup_json();
|
||||
|
||||
AprilTagFieldLayout LoadAprilTagLayoutField(AprilTagField field) {
|
||||
std::string_view fieldString;
|
||||
switch (field) {
|
||||
case AprilTagField::k2022RapidReact:
|
||||
fieldString = GetResource_2022_rapidreact_json();
|
||||
break;
|
||||
case AprilTagField::k2023ChargedUp:
|
||||
fieldString = GetResource_2023_chargedup_json();
|
||||
break;
|
||||
case AprilTagField::kNumFields:
|
||||
throw std::invalid_argument("Invalid Field");
|
||||
}
|
||||
|
||||
wpi::json json = wpi::json::parse(fieldString);
|
||||
return json.get<AprilTagFieldLayout>();
|
||||
}
|
||||
|
||||
} // namespace frc
|
||||
@@ -2,12 +2,17 @@
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include <jni.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#define WPI_RAWFRAME_JNI
|
||||
#include <wpi/RawFrame.h>
|
||||
#include <wpi/jni_util.h>
|
||||
|
||||
#include "edu_wpi_first_apriltag_jni_AprilTagJNI.h"
|
||||
#include "frc/apriltag/AprilTag.h"
|
||||
#include "frc/apriltag/AprilTagDetector.h"
|
||||
#include "frc/apriltag/AprilTagPoseEstimator.h"
|
||||
|
||||
@@ -24,6 +29,7 @@ static JClass quaternionCls;
|
||||
static JClass rotation3dCls;
|
||||
static JClass transform3dCls;
|
||||
static JClass translation3dCls;
|
||||
static JClass rawFrameCls;
|
||||
static JException illegalArgEx;
|
||||
static JException nullPointerEx;
|
||||
|
||||
@@ -36,7 +42,8 @@ static const JClassInit classes[] = {
|
||||
{"edu/wpi/first/math/geometry/Quaternion", &quaternionCls},
|
||||
{"edu/wpi/first/math/geometry/Rotation3d", &rotation3dCls},
|
||||
{"edu/wpi/first/math/geometry/Transform3d", &transform3dCls},
|
||||
{"edu/wpi/first/math/geometry/Translation3d", &translation3dCls}};
|
||||
{"edu/wpi/first/math/geometry/Translation3d", &translation3dCls},
|
||||
{"edu/wpi/first/util/RawFrame", &rawFrameCls}};
|
||||
|
||||
static const JExceptionInit exceptions[] = {
|
||||
{"java/lang/IllegalArgumentException", &illegalArgEx},
|
||||
@@ -587,4 +594,41 @@ Java_edu_wpi_first_apriltag_jni_AprilTagJNI_estimatePose
|
||||
return MakeJObject(env, estimator.Estimate(harr, carr));
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_apriltag_jni_AprilTagJNI
|
||||
* Method: generate16h5AprilTagImage
|
||||
* Signature: (Ljava/lang/Object;JI)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_apriltag_jni_AprilTagJNI_generate16h5AprilTagImage
|
||||
(JNIEnv* env, jclass, jobject frameObj, jlong framePtr, jint id)
|
||||
{
|
||||
auto* frame = reinterpret_cast<wpi::RawFrame*>(framePtr);
|
||||
if (!frame) {
|
||||
nullPointerEx.Throw(env, "frame is null");
|
||||
return;
|
||||
}
|
||||
bool newData = AprilTag::Generate16h5AprilTagImage(frame, id);
|
||||
wpi::SetFrameData(env, rawFrameCls, frameObj, *frame, newData);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: edu_wpi_first_apriltag_jni_AprilTagJNI
|
||||
* Method: generate36h11AprilTagImage
|
||||
* Signature: (Ljava/lang/Object;JI)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL
|
||||
Java_edu_wpi_first_apriltag_jni_AprilTagJNI_generate36h11AprilTagImage
|
||||
(JNIEnv* env, jclass, jobject frameObj, jlong framePtr, jint id)
|
||||
{
|
||||
auto* frame = reinterpret_cast<wpi::RawFrame*>(framePtr);
|
||||
if (!frame) {
|
||||
nullPointerEx.Throw(env, "frame is null");
|
||||
return;
|
||||
}
|
||||
// function might reallocate
|
||||
bool newData = AprilTag::Generate36h11AprilTagImage(frame, id);
|
||||
wpi::SetFrameData(env, rawFrameCls, frameObj, *frame, newData);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <wpi/RawFrame.h>
|
||||
#include <wpi/SymbolExports.h>
|
||||
#include <wpi/json_fwd.h>
|
||||
|
||||
@@ -11,15 +12,20 @@
|
||||
|
||||
namespace frc {
|
||||
|
||||
/**
|
||||
* Represents an AprilTag's metadata.
|
||||
*/
|
||||
struct WPILIB_DLLEXPORT AprilTag {
|
||||
/// The tag's ID.
|
||||
int ID;
|
||||
|
||||
/// The tag's pose.
|
||||
Pose3d pose;
|
||||
|
||||
/**
|
||||
* Checks equality between this AprilTag and another object.
|
||||
*/
|
||||
bool operator==(const AprilTag&) const = default;
|
||||
|
||||
static bool Generate36h11AprilTagImage(wpi::RawFrame* frame, int id);
|
||||
static bool Generate16h5AprilTagImage(wpi::RawFrame* frame, int id);
|
||||
};
|
||||
|
||||
WPILIB_DLLEXPORT
|
||||
|
||||
@@ -93,7 +93,7 @@ class WPILIB_DLLEXPORT AprilTagDetection final {
|
||||
|
||||
/**
|
||||
* Gets a corner of the tag in image pixel coordinates. These always
|
||||
* wrap counter-clock wise around the tag.
|
||||
* wrap counter-clock wise around the tag. Index 0 is the bottom left corner.
|
||||
*
|
||||
* @param ndx Corner index (range is 0-3, inclusive)
|
||||
* @return Corner point
|
||||
@@ -104,7 +104,8 @@ class WPILIB_DLLEXPORT AprilTagDetection final {
|
||||
|
||||
/**
|
||||
* Gets the corners of the tag in image pixel coordinates. These always
|
||||
* wrap counter-clock wise around the tag.
|
||||
* wrap counter-clock wise around the tag. The first set of corner coordinates
|
||||
* are the coordinates for the bottom left corner.
|
||||
*
|
||||
* @param cornersBuf Corner point array (X and Y for each corner in order)
|
||||
* @return Corner point array (copy of cornersBuf span)
|
||||
|
||||
@@ -205,7 +205,7 @@ class WPILIB_DLLEXPORT AprilTagDetector {
|
||||
* Adds a family of tags to be detected.
|
||||
*
|
||||
* @param fam Family name, e.g. "tag16h5"
|
||||
* @param bitsCorrected
|
||||
* @param bitsCorrected Maximum number of bits to correct
|
||||
* @return False if family can't be found
|
||||
*/
|
||||
bool AddFamily(std::string_view fam, int bitsCorrected = 2);
|
||||
@@ -226,6 +226,7 @@ class WPILIB_DLLEXPORT AprilTagDetector {
|
||||
|
||||
/**
|
||||
* Detect tags from an 8-bit image.
|
||||
* The image must be grayscale.
|
||||
*
|
||||
* @param width width of the image
|
||||
* @param height height of the image
|
||||
@@ -237,6 +238,7 @@ class WPILIB_DLLEXPORT AprilTagDetector {
|
||||
|
||||
/**
|
||||
* Detect tags from an 8-bit image.
|
||||
* The image must be grayscale.
|
||||
*
|
||||
* @param width width of the image
|
||||
* @param height height of the image
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <wpi/json_fwd.h>
|
||||
|
||||
#include "frc/apriltag/AprilTag.h"
|
||||
#include "frc/apriltag/AprilTagFields.h"
|
||||
#include "frc/geometry/Pose3d.h"
|
||||
|
||||
namespace frc {
|
||||
@@ -38,11 +39,24 @@ namespace frc {
|
||||
* towards the opposing alliance). */
|
||||
class WPILIB_DLLEXPORT AprilTagFieldLayout {
|
||||
public:
|
||||
/**
|
||||
* Common origin positions for the AprilTag coordinate system.
|
||||
*/
|
||||
enum class OriginPosition {
|
||||
/// Blue alliance wall, right side.
|
||||
kBlueAllianceWallRightSide,
|
||||
/// Red alliance wall, right side.
|
||||
kRedAllianceWallRightSide,
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads an AprilTagFieldLayout from a predefined field
|
||||
*
|
||||
* @param field The predefined field
|
||||
* @return AprilTagFieldLayout of the field
|
||||
*/
|
||||
static AprilTagFieldLayout LoadField(AprilTagField field);
|
||||
|
||||
AprilTagFieldLayout() = default;
|
||||
|
||||
/**
|
||||
@@ -62,6 +76,24 @@ class WPILIB_DLLEXPORT AprilTagFieldLayout {
|
||||
AprilTagFieldLayout(std::vector<AprilTag> apriltags,
|
||||
units::meter_t fieldLength, units::meter_t fieldWidth);
|
||||
|
||||
/**
|
||||
* Returns the length of the field the layout is representing.
|
||||
* @return length
|
||||
*/
|
||||
units::meter_t GetFieldLength() const;
|
||||
|
||||
/**
|
||||
* Returns the length of the field the layout is representing.
|
||||
* @return width
|
||||
*/
|
||||
units::meter_t GetFieldWidth() const;
|
||||
|
||||
/**
|
||||
* Returns a vector of all the april tags used in this layout.
|
||||
* @return list of tags
|
||||
*/
|
||||
std::vector<AprilTag> GetTags() const;
|
||||
|
||||
/**
|
||||
* Sets the origin based on a predefined enumeration of coordinate frame
|
||||
* origins. The origins are calculated from the field dimensions.
|
||||
@@ -83,6 +115,12 @@ class WPILIB_DLLEXPORT AprilTagFieldLayout {
|
||||
*/
|
||||
void SetOrigin(const Pose3d& origin);
|
||||
|
||||
/**
|
||||
* Returns the origin used for tag pose transformation.
|
||||
* @return the origin
|
||||
*/
|
||||
Pose3d GetOrigin() const;
|
||||
|
||||
/**
|
||||
* Gets an AprilTag pose by its ID.
|
||||
*
|
||||
@@ -123,4 +161,15 @@ void to_json(wpi::json& json, const AprilTagFieldLayout& layout);
|
||||
WPILIB_DLLEXPORT
|
||||
void from_json(const wpi::json& json, AprilTagFieldLayout& layout);
|
||||
|
||||
/**
|
||||
* Loads an AprilTagFieldLayout from a predefined field
|
||||
*
|
||||
* @param field The predefined field
|
||||
* @return AprilTagFieldLayout of the field
|
||||
* @deprecated Use AprilTagFieldLayout::LoadField() instead
|
||||
*/
|
||||
[[deprecated("Use AprilTagFieldLayout::LoadField() instead")]]
|
||||
WPILIB_DLLEXPORT AprilTagFieldLayout
|
||||
LoadAprilTagLayoutField(AprilTagField field);
|
||||
|
||||
} // namespace frc
|
||||
|
||||
@@ -8,25 +8,22 @@
|
||||
|
||||
#include <wpi/SymbolExports.h>
|
||||
|
||||
#include "frc/apriltag/AprilTagFieldLayout.h"
|
||||
|
||||
namespace frc {
|
||||
|
||||
/**
|
||||
* Loadable AprilTag field layouts.
|
||||
*/
|
||||
enum class AprilTagField {
|
||||
/// 2022 Rapid React.
|
||||
k2022RapidReact,
|
||||
/// 2023 Charged Up.
|
||||
k2023ChargedUp,
|
||||
/// 2024 Crescendo.
|
||||
k2024Crescendo,
|
||||
|
||||
// This is a placeholder for denoting the last supported field. This should
|
||||
// always be the last entry in the enum and should not be used by users
|
||||
kNumFields,
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads an AprilTagFieldLayout from a predefined field
|
||||
*
|
||||
* @param field The predefined field
|
||||
*/
|
||||
WPILIB_DLLEXPORT AprilTagFieldLayout
|
||||
LoadAprilTagLayoutField(AprilTagField field);
|
||||
|
||||
} // namespace frc
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
ID,X,Y,Z,Rotation
|
||||
1,593.68,9.68,53.38,120
|
||||
2,637.21,34.79,53.38,120
|
||||
3,652.73,196.17,57.13,180
|
||||
4,652.73,218.42,57.13,180
|
||||
5,578.77,323.00,53.38,270
|
||||
6,72.5,323.00,53.38,270
|
||||
7,-1.50,218.42,57.13,0
|
||||
8,-1.50,196.17,57.13,0
|
||||
9,14.02,34.79,53.38,60
|
||||
10,57.54,9.68,53.38,60
|
||||
11,468.69,146.19,52.00,300
|
||||
12,468.69,177.10,52.00,60
|
||||
13,441.74,161.62,52.00,180
|
||||
14,209.48,161.62,52.00,0
|
||||
15,182.73,177.10,52.00,120
|
||||
16,182.73,146.19,52.00,240
|
||||
|
@@ -0,0 +1,296 @@
|
||||
{
|
||||
"tags": [
|
||||
{
|
||||
"ID": 1,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 15.079471999999997,
|
||||
"y": 0.24587199999999998,
|
||||
"z": 1.355852
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.5000000000000001,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.8660254037844386
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 2,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 16.185134,
|
||||
"y": 0.883666,
|
||||
"z": 1.355852
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.5000000000000001,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.8660254037844386
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 3,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 16.579342,
|
||||
"y": 4.982717999999999,
|
||||
"z": 1.4511020000000001
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 4,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 16.579342,
|
||||
"y": 5.547867999999999,
|
||||
"z": 1.4511020000000001
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 5,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 14.700757999999999,
|
||||
"y": 8.2042,
|
||||
"z": 1.355852
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.7071067811865475,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 6,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 1.8415,
|
||||
"y": 8.2042,
|
||||
"z": 1.355852
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.7071067811865475,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.7071067811865476
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 7,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": -0.038099999999999995,
|
||||
"y": 5.547867999999999,
|
||||
"z": 1.4511020000000001
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 8,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": -0.038099999999999995,
|
||||
"y": 4.982717999999999,
|
||||
"z": 1.4511020000000001
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 9,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 0.356108,
|
||||
"y": 0.883666,
|
||||
"z": 1.355852
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.8660254037844387,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.49999999999999994
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 10,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 1.4615159999999998,
|
||||
"y": 0.24587199999999998,
|
||||
"z": 1.355852
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.8660254037844387,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.49999999999999994
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 11,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.904726,
|
||||
"y": 3.7132259999999997,
|
||||
"z": 1.3208
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.8660254037844387,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.49999999999999994
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 12,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.904726,
|
||||
"y": 4.49834,
|
||||
"z": 1.3208
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.8660254037844387,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.49999999999999994
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 13,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 11.220196,
|
||||
"y": 4.105148,
|
||||
"z": 1.3208
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 6.123233995736766e-17,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 1.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 14,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 5.320792,
|
||||
"y": 4.105148,
|
||||
"z": 1.3208
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 1.0,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 15,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.641342,
|
||||
"y": 4.49834,
|
||||
"z": 1.3208
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": 0.5000000000000001,
|
||||
"X": 0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.8660254037844386
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"ID": 16,
|
||||
"pose": {
|
||||
"translation": {
|
||||
"x": 4.641342,
|
||||
"y": 3.7132259999999997,
|
||||
"z": 1.3208
|
||||
},
|
||||
"rotation": {
|
||||
"quaternion": {
|
||||
"W": -0.4999999999999998,
|
||||
"X": -0.0,
|
||||
"Y": 0.0,
|
||||
"Z": 0.8660254037844387
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"field": {
|
||||
"length": 16.541,
|
||||
"width": 8.211
|
||||
}
|
||||
}
|
||||
@@ -29,15 +29,10 @@ class AprilTagDetectorTest {
|
||||
@SuppressWarnings("MemberName")
|
||||
AprilTagDetector detector;
|
||||
|
||||
static RuntimeLoader<Core> loader;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeAll() {
|
||||
try {
|
||||
loader =
|
||||
new RuntimeLoader<>(
|
||||
Core.NATIVE_LIBRARY_NAME, RuntimeLoader.getDefaultExtractionRoot(), Core.class);
|
||||
loader.loadLibrary();
|
||||
RuntimeLoader.loadLibrary(Core.NATIVE_LIBRARY_NAME);
|
||||
} catch (IOException ex) {
|
||||
fail(ex);
|
||||
}
|
||||
@@ -158,7 +153,7 @@ class AprilTagDetectorTest {
|
||||
var estimator =
|
||||
new AprilTagPoseEstimator(new AprilTagPoseEstimator.Config(0.2, 500, 500, 320, 240));
|
||||
AprilTagPoseEstimate est = estimator.estimateOrthogonalIteration(results[0], 200);
|
||||
assertEquals(new Transform3d(), est.pose2);
|
||||
assertEquals(Transform3d.kZero, est.pose2);
|
||||
Transform3d pose = estimator.estimate(results[0]);
|
||||
assertEquals(est.pose1, pose);
|
||||
} finally {
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.apriltag;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import edu.wpi.first.util.PixelFormat;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class AprilTagGenerationTest {
|
||||
@Test
|
||||
void test36h11() {
|
||||
var frame = AprilTag.generate36h11AprilTagImage(1);
|
||||
assertEquals(PixelFormat.kGray, frame.getPixelFormat());
|
||||
assertEquals(10, frame.getWidth());
|
||||
assertEquals(10, frame.getHeight());
|
||||
int stride = frame.getStride();
|
||||
assertEquals(stride * 10, frame.getSize());
|
||||
// check the diagonal values
|
||||
var data = frame.getData();
|
||||
assertEquals(-1, data.get(stride * 0 + 0)); // outer border is white
|
||||
assertEquals(0, data.get(stride * 1 + 1)); // inner border is black
|
||||
assertEquals(-1, data.get(stride * 2 + 2));
|
||||
assertEquals(-1, data.get(stride * 3 + 3));
|
||||
assertEquals(-1, data.get(stride * 4 + 4));
|
||||
assertEquals(0, data.get(stride * 5 + 5));
|
||||
assertEquals(0, data.get(stride * 6 + 6));
|
||||
assertEquals(-1, data.get(stride * 7 + 7));
|
||||
assertEquals(0, data.get(stride * 8 + 8)); // inner border
|
||||
assertEquals(-1, data.get(stride * 9 + 9)); // outer border
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ class AprilTagPoseSetOriginTest {
|
||||
var layout =
|
||||
new AprilTagFieldLayout(
|
||||
List.of(
|
||||
new AprilTag(1, new Pose3d(new Translation3d(0, 0, 0), new Rotation3d(0, 0, 0))),
|
||||
new AprilTag(1, Pose3d.kZero),
|
||||
new AprilTag(
|
||||
2,
|
||||
new Pose3d(
|
||||
@@ -40,7 +40,7 @@ class AprilTagPoseSetOriginTest {
|
||||
new Pose3d(
|
||||
new Translation3d(
|
||||
Units.feetToMeters(50.0), Units.feetToMeters(23.0), Units.feetToMeters(4)),
|
||||
new Rotation3d(0.0, 0.0, 0)),
|
||||
Rotation3d.kZero),
|
||||
layout.getTagPose(2).orElse(null));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@ class AprilTagSerializationTest {
|
||||
var layout =
|
||||
new AprilTagFieldLayout(
|
||||
List.of(
|
||||
new AprilTag(1, new Pose3d(0, 0, 0, new Rotation3d(0, 0, 0))),
|
||||
new AprilTag(3, new Pose3d(0, 1, 0, new Rotation3d(0, 0, 0)))),
|
||||
new AprilTag(1, Pose3d.kZero),
|
||||
new AprilTag(3, new Pose3d(0, 1, 0, Rotation3d.kZero))),
|
||||
Units.feetToMeters(54.0),
|
||||
Units.feetToMeters(27.0));
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import edu.wpi.first.math.geometry.Pose3d;
|
||||
import edu.wpi.first.math.geometry.Rotation3d;
|
||||
import edu.wpi.first.math.util.Units;
|
||||
import java.io.IOException;
|
||||
import java.util.Optional;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
@@ -23,13 +22,14 @@ class LoadConfigTest {
|
||||
@ParameterizedTest
|
||||
@EnumSource(AprilTagFields.class)
|
||||
void testLoad(AprilTagFields field) {
|
||||
AprilTagFieldLayout layout = Assertions.assertDoesNotThrow(field::loadAprilTagLayoutField);
|
||||
AprilTagFieldLayout layout =
|
||||
Assertions.assertDoesNotThrow(() -> AprilTagFieldLayout.loadField(field));
|
||||
assertNotNull(layout);
|
||||
}
|
||||
|
||||
@Test
|
||||
void test2022RapidReact() throws IOException {
|
||||
AprilTagFieldLayout layout = AprilTagFields.k2022RapidReact.loadAprilTagLayoutField();
|
||||
void test2022RapidReact() {
|
||||
AprilTagFieldLayout layout = AprilTagFieldLayout.loadField(AprilTagFields.k2022RapidReact);
|
||||
|
||||
// Blue Hangar Truss - Hub
|
||||
Pose3d expectedPose =
|
||||
@@ -37,7 +37,7 @@ class LoadConfigTest {
|
||||
Units.inchesToMeters(127.272),
|
||||
Units.inchesToMeters(216.01),
|
||||
Units.inchesToMeters(67.932),
|
||||
new Rotation3d(0, 0, 0));
|
||||
Rotation3d.kZero);
|
||||
Optional<Pose3d> maybePose = layout.getTagPose(1);
|
||||
assertTrue(maybePose.isPresent());
|
||||
assertEquals(expectedPose, maybePose.get());
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "frc/apriltag/AprilTagFieldLayout.h"
|
||||
#include "frc/apriltag/AprilTagFields.h"
|
||||
|
||||
namespace frc {
|
||||
@@ -20,7 +21,7 @@ std::vector<AprilTagField> GetAllFields() {
|
||||
|
||||
TEST(AprilTagFieldsTest, TestLoad2022RapidReact) {
|
||||
AprilTagFieldLayout layout =
|
||||
LoadAprilTagLayoutField(AprilTagField::k2022RapidReact);
|
||||
AprilTagFieldLayout::LoadField(AprilTagField::k2022RapidReact);
|
||||
|
||||
// Blue Hangar Truss - Hub
|
||||
auto expectedPose =
|
||||
@@ -53,7 +54,7 @@ class AllFieldsFixtureTest : public ::testing::TestWithParam<AprilTagField> {};
|
||||
|
||||
TEST_P(AllFieldsFixtureTest, CheckEntireEnum) {
|
||||
AprilTagField field = GetParam();
|
||||
EXPECT_NO_THROW(LoadAprilTagLayoutField(field));
|
||||
EXPECT_NO_THROW(AprilTagFieldLayout::LoadField(field));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(ValuesEnumTestInstTests, AllFieldsFixtureTest,
|
||||
|
||||
11
build.gradle
11
build.gradle
@@ -23,7 +23,7 @@ plugins {
|
||||
id 'net.ltgt.errorprone' version '3.1.0' apply false
|
||||
id 'com.github.johnrengelman.shadow' version '8.1.1' apply false
|
||||
id 'com.diffplug.spotless' version '6.20.0' apply false
|
||||
id 'com.github.spotbugs' version '5.1.3' apply false
|
||||
id 'com.github.spotbugs' version '6.0.2' apply false
|
||||
id 'com.google.protobuf' version '0.9.3' apply false
|
||||
}
|
||||
|
||||
@@ -50,6 +50,9 @@ buildScan {
|
||||
publishAlways()
|
||||
}
|
||||
|
||||
import com.github.spotbugs.snom.Effort
|
||||
ext.spotbugsEffort = Effort.MAX
|
||||
|
||||
ext.licenseFile = files("$rootDir/LICENSE.md", "$rootDir/ThirdPartyNotices.txt")
|
||||
|
||||
if (project.hasProperty("publishVersion")) {
|
||||
@@ -111,8 +114,8 @@ subprojects {
|
||||
|
||||
plugins.withType(JavaPlugin) {
|
||||
java {
|
||||
sourceCompatibility = 11
|
||||
targetCompatibility = 11
|
||||
sourceCompatibility = 17
|
||||
targetCompatibility = 17
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,5 +174,5 @@ ext.getCurrentArch = {
|
||||
}
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '8.4'
|
||||
gradleVersion = '8.5'
|
||||
}
|
||||
|
||||
@@ -9,5 +9,5 @@ repositories {
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
implementation "edu.wpi.first:native-utils:2024.3.1"
|
||||
implementation "edu.wpi.first:native-utils:2025.1.0"
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ public class WPIJREArtifact extends MavenArtifact {
|
||||
|
||||
private boolean checkJreVersion = true;
|
||||
|
||||
private final String artifactLocation = "edu.wpi.first.jdk:roborio-2023:17.0.5u7-1"
|
||||
private final String artifactLocation = "edu.wpi.first.jdk:roborio-2024:17.0.9u7-1"
|
||||
|
||||
@Inject
|
||||
public WPIJREArtifact(String name, RemoteTarget target) {
|
||||
|
||||
@@ -3,55 +3,86 @@ project(cameraserver)
|
||||
include(CompileWarnings)
|
||||
include(AddTest)
|
||||
|
||||
find_package( OpenCV REQUIRED )
|
||||
find_package(OpenCV REQUIRED)
|
||||
|
||||
# Java bindings
|
||||
if (WITH_JAVA)
|
||||
if(WITH_JAVA)
|
||||
find_package(Java REQUIRED)
|
||||
include(UseJava)
|
||||
set(CMAKE_JAVA_COMPILE_FLAGS "-encoding" "UTF8" "-Xlint:unchecked")
|
||||
|
||||
#find java files, copy them locally
|
||||
|
||||
set(OPENCV_JAVA_INSTALL_DIR ${OpenCV_INSTALL_PATH}/share/OpenCV/java/)
|
||||
set(OPENCV_JAVA_INSTALL_DIR ${OpenCV_INSTALL_PATH}/share/java/opencv4)
|
||||
|
||||
find_file(OPENCV_JAR_FILE NAMES opencv-${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}.jar PATHS ${OPENCV_JAVA_INSTALL_DIR} ${OpenCV_INSTALL_PATH}/bin NO_DEFAULT_PATH)
|
||||
find_file(
|
||||
OPENCV_JAR_FILE
|
||||
NAMES opencv-${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}.jar
|
||||
PATHS
|
||||
${OPENCV_JAVA_INSTALL_DIR}
|
||||
${OpenCV_INSTALL_PATH}/bin
|
||||
${OpenCV_INSTALL_PATH}/share/java
|
||||
${OpenCV_INSTALL_PATH}/share/OpenCV/java
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE JAVA_SOURCES src/main/java/*.java)
|
||||
|
||||
add_jar(cameraserver_jar ${JAVA_SOURCES} INCLUDE_JARS wpiutil_jar cscore_jar ntcore_jar ${OPENCV_JAR_FILE} OUTPUT_NAME cameraserver)
|
||||
|
||||
get_property(CAMERASERVER_JAR_FILE TARGET cameraserver_jar PROPERTY JAR_FILE)
|
||||
install(FILES ${CAMERASERVER_JAR_FILE} DESTINATION "${java_lib_dest}")
|
||||
|
||||
add_jar(
|
||||
cameraserver_jar
|
||||
${JAVA_SOURCES}
|
||||
INCLUDE_JARS wpiutil_jar cscore_jar ntcore_jar ${OPENCV_JAR_FILE}
|
||||
OUTPUT_NAME cameraserver
|
||||
)
|
||||
set_property(TARGET cameraserver_jar PROPERTY FOLDER "java")
|
||||
|
||||
install_jar(cameraserver_jar DESTINATION ${java_lib_dest})
|
||||
install_jar_exports(
|
||||
TARGETS cameraserver_jar
|
||||
FILE cameraserver_jar.cmake
|
||||
DESTINATION share/cameraserver
|
||||
)
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE
|
||||
cameraserver_native_src src/main/native/cpp/*.cpp)
|
||||
if(WITH_JAVA_SOURCE)
|
||||
find_package(Java REQUIRED)
|
||||
include(UseJava)
|
||||
file(GLOB CAMERASERVER_SOURCES src/main/java/edu/wpi/first/cameraserver/*.java)
|
||||
file(GLOB VISION_SOURCES src/main/java/edu/wpi/first/vision/*.java)
|
||||
add_jar(
|
||||
cameraserver_src_jar
|
||||
RESOURCES
|
||||
NAMESPACE "edu/wpi/first/cameraserver" ${CAMERASERVER_SOURCES}
|
||||
NAMESPACE "edu/wpi/first/vision" ${VISION_SOURCES}
|
||||
OUTPUT_NAME cameraserver-sources
|
||||
)
|
||||
|
||||
get_property(CAMERASERVER_SRC_JAR_FILE TARGET cameraserver_src_jar PROPERTY JAR_FILE)
|
||||
install(FILES ${CAMERASERVER_SRC_JAR_FILE} DESTINATION "${java_lib_dest}")
|
||||
|
||||
set_property(TARGET cameraserver_src_jar PROPERTY FOLDER "java")
|
||||
endif()
|
||||
|
||||
file(GLOB_RECURSE cameraserver_native_src src/main/native/cpp/*.cpp)
|
||||
add_library(cameraserver ${cameraserver_native_src})
|
||||
set_target_properties(cameraserver PROPERTIES DEBUG_POSTFIX "d")
|
||||
target_include_directories(cameraserver PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/include>
|
||||
$<INSTALL_INTERFACE:${include_dest}/cameraserver>)
|
||||
target_include_directories(
|
||||
cameraserver
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/include>
|
||||
$<INSTALL_INTERFACE:${include_dest}/cameraserver>
|
||||
)
|
||||
wpilib_target_warnings(cameraserver)
|
||||
target_link_libraries(cameraserver PUBLIC ntcore cscore wpiutil ${OpenCV_LIBS})
|
||||
|
||||
set_property(TARGET cameraserver PROPERTY FOLDER "libraries")
|
||||
|
||||
install(TARGETS cameraserver EXPORT cameraserver)
|
||||
export(TARGETS cameraserver FILE cameraserver.cmake NAMESPACE cameraserver::)
|
||||
install(DIRECTORY src/main/native/include/ DESTINATION "${include_dest}/cameraserver")
|
||||
|
||||
if (WITH_FLAT_INSTALL)
|
||||
set (cameraserver_config_dir ${wpilib_dest})
|
||||
else()
|
||||
set (cameraserver_config_dir share/cameraserver)
|
||||
endif()
|
||||
|
||||
configure_file(cameraserver-config.cmake.in ${WPILIB_BINARY_DIR}/cameraserver-config.cmake )
|
||||
install(FILES ${WPILIB_BINARY_DIR}/cameraserver-config.cmake DESTINATION ${cameraserver_config_dir})
|
||||
install(EXPORT cameraserver DESTINATION ${cameraserver_config_dir})
|
||||
configure_file(cameraserver-config.cmake.in ${WPILIB_BINARY_DIR}/cameraserver-config.cmake)
|
||||
install(FILES ${WPILIB_BINARY_DIR}/cameraserver-config.cmake DESTINATION share/cameraserver)
|
||||
install(EXPORT cameraserver DESTINATION share/cameraserver)
|
||||
|
||||
file(GLOB multiCameraServer_src multiCameraServer/src/main/native/cpp/*.cpp)
|
||||
add_executable(multiCameraServer ${multiCameraServer_src})
|
||||
@@ -60,7 +91,7 @@ target_link_libraries(multiCameraServer cameraserver)
|
||||
|
||||
set_property(TARGET multiCameraServer PROPERTY FOLDER "examples")
|
||||
|
||||
if (WITH_TESTS)
|
||||
if(WITH_TESTS)
|
||||
wpilib_add_test(cameraserver src/test/native/cpp)
|
||||
target_link_libraries(cameraserver_test cameraserver gtest)
|
||||
endif()
|
||||
|
||||
@@ -7,3 +7,6 @@ find_dependency(OpenCV)
|
||||
|
||||
@FILENAME_DEP_REPLACE@
|
||||
include(${SELF_DIR}/cameraserver.cmake)
|
||||
if(@WITH_JAVA@)
|
||||
include(${SELF_DIR}/cameraserver_jar.cmake)
|
||||
endif()
|
||||
|
||||
@@ -98,7 +98,7 @@ public final class Main {
|
||||
// parse file
|
||||
JsonElement top;
|
||||
try {
|
||||
top = new JsonParser().parse(Files.newBufferedReader(Paths.get(configFile)));
|
||||
top = JsonParser.parseReader(Files.newBufferedReader(Paths.get(configFile)));
|
||||
} catch (IOException ex) {
|
||||
System.err.println("could not open '" + configFile + "': " + ex);
|
||||
return false;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <wpi/StringExtras.h>
|
||||
#include <wpi/fmt/raw_ostream.h>
|
||||
#include <wpi/json.h>
|
||||
#include <wpi/print.h>
|
||||
#include <wpi/raw_ostream.h>
|
||||
|
||||
#include "cameraserver/CameraServer.h"
|
||||
@@ -71,7 +72,7 @@ bool ReadCameraConfig(const wpi::json& config) {
|
||||
try {
|
||||
c.name = config.at("name").get<std::string>();
|
||||
} catch (const wpi::json::exception& e) {
|
||||
fmt::print(stderr, "config error in '{}': could not read camera name: {}\n",
|
||||
wpi::print(stderr, "config error in '{}': could not read camera name: {}\n",
|
||||
configFile, e.what());
|
||||
return false;
|
||||
}
|
||||
@@ -80,7 +81,7 @@ bool ReadCameraConfig(const wpi::json& config) {
|
||||
try {
|
||||
c.path = config.at("path").get<std::string>();
|
||||
} catch (const wpi::json::exception& e) {
|
||||
fmt::print(stderr,
|
||||
wpi::print(stderr,
|
||||
"config error in '{}': camera '{}': could not read path: {}\n",
|
||||
configFile, c.name, e.what());
|
||||
return false;
|
||||
@@ -98,23 +99,23 @@ bool ReadConfig() {
|
||||
std::unique_ptr<wpi::MemoryBuffer> fileBuffer =
|
||||
wpi::MemoryBuffer::GetFile(configFile, ec);
|
||||
if (fileBuffer == nullptr || ec) {
|
||||
fmt::print(stderr, "could not open '{}': {}\n", configFile, ec.message());
|
||||
wpi::print(stderr, "could not open '{}': {}\n", configFile, ec.message());
|
||||
return false;
|
||||
}
|
||||
|
||||
// parse file
|
||||
wpi::json j;
|
||||
try {
|
||||
j = wpi::json::parse(fileBuffer->begin(), fileBuffer->end());
|
||||
j = wpi::json::parse(fileBuffer->GetCharBuffer());
|
||||
} catch (const wpi::json::parse_error& e) {
|
||||
fmt::print(stderr, "config error in '{}': byte {}: {}\n", configFile,
|
||||
wpi::print(stderr, "config error in '{}': byte {}: {}\n", configFile,
|
||||
e.byte, e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
// top level must be an object
|
||||
if (!j.is_object()) {
|
||||
fmt::print(stderr, "config error in '{}': must be JSON object\n",
|
||||
wpi::print(stderr, "config error in '{}': must be JSON object\n",
|
||||
configFile);
|
||||
return false;
|
||||
}
|
||||
@@ -123,7 +124,7 @@ bool ReadConfig() {
|
||||
try {
|
||||
team = j.at("team").get<unsigned int>();
|
||||
} catch (const wpi::json::exception& e) {
|
||||
fmt::print(stderr, "config error in '{}': could not read team number: {}\n",
|
||||
wpi::print(stderr, "config error in '{}': could not read team number: {}\n",
|
||||
configFile, e.what());
|
||||
return false;
|
||||
}
|
||||
@@ -137,13 +138,13 @@ bool ReadConfig() {
|
||||
} else if (wpi::equals_lower(str, "server")) {
|
||||
server = true;
|
||||
} else {
|
||||
fmt::print(
|
||||
wpi::print(
|
||||
stderr,
|
||||
"config error in '{}': could not understand ntmode value '{}'\n",
|
||||
configFile, str);
|
||||
}
|
||||
} catch (const wpi::json::exception& e) {
|
||||
fmt::print(stderr, "config error in '{}': could not read ntmode: {}\n",
|
||||
wpi::print(stderr, "config error in '{}': could not read ntmode: {}\n",
|
||||
configFile, e.what());
|
||||
}
|
||||
}
|
||||
@@ -156,7 +157,7 @@ bool ReadConfig() {
|
||||
}
|
||||
}
|
||||
} catch (const wpi::json::exception& e) {
|
||||
fmt::print(stderr, "config error in '{}': could not read cameras: {}\n",
|
||||
wpi::print(stderr, "config error in '{}': could not read cameras: {}\n",
|
||||
configFile, e.what());
|
||||
return false;
|
||||
}
|
||||
@@ -165,7 +166,7 @@ bool ReadConfig() {
|
||||
}
|
||||
|
||||
void StartCamera(const CameraConfig& config) {
|
||||
fmt::print("Starting camera '{}' on {}\n", config.name, config.path);
|
||||
wpi::print("Starting camera '{}' on {}\n", config.name, config.path);
|
||||
auto camera =
|
||||
frc::CameraServer::StartAutomaticCapture(config.name, config.path);
|
||||
|
||||
@@ -189,7 +190,7 @@ int main(int argc, char* argv[]) {
|
||||
std::puts("Setting up NetworkTables server");
|
||||
ntinst.StartServer();
|
||||
} else {
|
||||
fmt::print("Setting up NetworkTables client for team {}\n", team);
|
||||
wpi::print("Setting up NetworkTables client for team {}\n", team);
|
||||
ntinst.StartClient4("multicameraserver");
|
||||
ntinst.SetServerTeam(team);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@ import edu.wpi.first.cscore.VideoEvent;
|
||||
import edu.wpi.first.cscore.VideoException;
|
||||
import edu.wpi.first.cscore.VideoListener;
|
||||
import edu.wpi.first.cscore.VideoMode;
|
||||
import edu.wpi.first.cscore.VideoMode.PixelFormat;
|
||||
import edu.wpi.first.cscore.VideoSink;
|
||||
import edu.wpi.first.cscore.VideoSource;
|
||||
import edu.wpi.first.networktables.BooleanEntry;
|
||||
@@ -27,6 +26,8 @@ import edu.wpi.first.networktables.StringArrayPublisher;
|
||||
import edu.wpi.first.networktables.StringArrayTopic;
|
||||
import edu.wpi.first.networktables.StringEntry;
|
||||
import edu.wpi.first.networktables.StringPublisher;
|
||||
import edu.wpi.first.util.PixelFormat;
|
||||
import java.lang.ref.Reference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@@ -39,6 +40,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
* NetworkTables.
|
||||
*/
|
||||
public final class CameraServer {
|
||||
/** CameraServer base port. */
|
||||
public static final int kBasePort = 1181;
|
||||
|
||||
private static final String kPublishName = "/CameraPublisher";
|
||||
@@ -92,29 +94,29 @@ public final class CameraServer {
|
||||
|
||||
void update(VideoEvent event) {
|
||||
switch (event.propertyKind) {
|
||||
case kBoolean:
|
||||
case kBoolean -> {
|
||||
if (m_booleanValueEntry != null) {
|
||||
m_booleanValueEntry.set(event.value != 0);
|
||||
}
|
||||
break;
|
||||
case kInteger:
|
||||
case kEnum:
|
||||
}
|
||||
case kInteger, kEnum -> {
|
||||
if (m_integerValueEntry != null) {
|
||||
m_integerValueEntry.set(event.value);
|
||||
}
|
||||
break;
|
||||
case kString:
|
||||
}
|
||||
case kString -> {
|
||||
if (m_stringValueEntry != null) {
|
||||
m_stringValueEntry.set(event.valueStr);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
default -> {
|
||||
// NOP
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
public void close() {
|
||||
if (m_booleanValueEntry != null) {
|
||||
m_booleanValueEntry.close();
|
||||
}
|
||||
@@ -139,6 +141,7 @@ public final class CameraServer {
|
||||
if (m_choicesPublisher != null) {
|
||||
m_choicesPublisher.close();
|
||||
}
|
||||
Reference.reachabilityFence(m_videoListener);
|
||||
}
|
||||
|
||||
BooleanEntry m_booleanValueEntry;
|
||||
@@ -222,118 +225,99 @@ public final class CameraServer {
|
||||
// - "PropertyInfo/{Property}" - Property supporting information
|
||||
|
||||
// Listener for video events
|
||||
@SuppressWarnings({"PMD.UnusedPrivateField", "PMD.AvoidCatchingGenericException"})
|
||||
@SuppressWarnings("PMD.AvoidCatchingGenericException")
|
||||
private static final VideoListener m_videoListener =
|
||||
new VideoListener(
|
||||
event -> {
|
||||
synchronized (CameraServer.class) {
|
||||
switch (event.kind) {
|
||||
case kSourceCreated:
|
||||
{
|
||||
// Create subtable for the camera
|
||||
NetworkTable table = m_publishTable.getSubTable(event.name);
|
||||
m_publishers.put(
|
||||
event.sourceHandle, new SourcePublisher(table, event.sourceHandle));
|
||||
break;
|
||||
case kSourceCreated -> {
|
||||
// Create subtable for the camera
|
||||
NetworkTable table = m_publishTable.getSubTable(event.name);
|
||||
m_publishers.put(
|
||||
event.sourceHandle, new SourcePublisher(table, event.sourceHandle));
|
||||
}
|
||||
case kSourceDestroyed -> {
|
||||
SourcePublisher publisher = m_publishers.remove(event.sourceHandle);
|
||||
if (publisher != null) {
|
||||
try {
|
||||
publisher.close();
|
||||
} catch (Exception e) {
|
||||
// ignore (nothing we can do about it)
|
||||
}
|
||||
}
|
||||
case kSourceDestroyed:
|
||||
{
|
||||
SourcePublisher publisher = m_publishers.remove(event.sourceHandle);
|
||||
if (publisher != null) {
|
||||
}
|
||||
case kSourceConnected -> {
|
||||
SourcePublisher publisher = m_publishers.get(event.sourceHandle);
|
||||
if (publisher != null) {
|
||||
// update the description too (as it may have changed)
|
||||
publisher.m_descriptionPublisher.set(
|
||||
CameraServerJNI.getSourceDescription(event.sourceHandle));
|
||||
publisher.m_connectedPublisher.set(true);
|
||||
}
|
||||
}
|
||||
case kSourceDisconnected -> {
|
||||
SourcePublisher publisher = m_publishers.get(event.sourceHandle);
|
||||
if (publisher != null) {
|
||||
publisher.m_connectedPublisher.set(false);
|
||||
}
|
||||
}
|
||||
case kSourceVideoModesUpdated -> {
|
||||
SourcePublisher publisher = m_publishers.get(event.sourceHandle);
|
||||
if (publisher != null) {
|
||||
publisher.m_modesPublisher.set(getSourceModeValues(event.sourceHandle));
|
||||
}
|
||||
}
|
||||
case kSourceVideoModeChanged -> {
|
||||
SourcePublisher publisher = m_publishers.get(event.sourceHandle);
|
||||
if (publisher != null) {
|
||||
publisher.m_modeEntry.set(videoModeToString(event.mode));
|
||||
}
|
||||
}
|
||||
case kSourcePropertyCreated -> {
|
||||
SourcePublisher publisher = m_publishers.get(event.sourceHandle);
|
||||
if (publisher != null) {
|
||||
publisher.m_properties.put(
|
||||
event.propertyHandle, new PropertyPublisher(publisher.m_table, event));
|
||||
}
|
||||
}
|
||||
case kSourcePropertyValueUpdated -> {
|
||||
SourcePublisher publisher = m_publishers.get(event.sourceHandle);
|
||||
if (publisher != null) {
|
||||
PropertyPublisher pp = publisher.m_properties.get(event.propertyHandle);
|
||||
if (pp != null) {
|
||||
pp.update(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
case kSourcePropertyChoicesUpdated -> {
|
||||
SourcePublisher publisher = m_publishers.get(event.sourceHandle);
|
||||
if (publisher != null) {
|
||||
PropertyPublisher pp = publisher.m_properties.get(event.propertyHandle);
|
||||
if (pp != null && pp.m_choicesTopic != null) {
|
||||
try {
|
||||
publisher.close();
|
||||
} catch (Exception e) {
|
||||
// ignore (nothing we can do about it)
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourceConnected:
|
||||
{
|
||||
SourcePublisher publisher = m_publishers.get(event.sourceHandle);
|
||||
if (publisher != null) {
|
||||
// update the description too (as it may have changed)
|
||||
publisher.m_descriptionPublisher.set(
|
||||
CameraServerJNI.getSourceDescription(event.sourceHandle));
|
||||
publisher.m_connectedPublisher.set(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourceDisconnected:
|
||||
{
|
||||
SourcePublisher publisher = m_publishers.get(event.sourceHandle);
|
||||
if (publisher != null) {
|
||||
publisher.m_connectedPublisher.set(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourceVideoModesUpdated:
|
||||
{
|
||||
SourcePublisher publisher = m_publishers.get(event.sourceHandle);
|
||||
if (publisher != null) {
|
||||
publisher.m_modesPublisher.set(getSourceModeValues(event.sourceHandle));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourceVideoModeChanged:
|
||||
{
|
||||
SourcePublisher publisher = m_publishers.get(event.sourceHandle);
|
||||
if (publisher != null) {
|
||||
publisher.m_modeEntry.set(videoModeToString(event.mode));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourcePropertyCreated:
|
||||
{
|
||||
SourcePublisher publisher = m_publishers.get(event.sourceHandle);
|
||||
if (publisher != null) {
|
||||
publisher.m_properties.put(
|
||||
event.propertyHandle, new PropertyPublisher(publisher.m_table, event));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourcePropertyValueUpdated:
|
||||
{
|
||||
SourcePublisher publisher = m_publishers.get(event.sourceHandle);
|
||||
if (publisher != null) {
|
||||
PropertyPublisher pp = publisher.m_properties.get(event.propertyHandle);
|
||||
if (pp != null) {
|
||||
pp.update(event);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourcePropertyChoicesUpdated:
|
||||
{
|
||||
SourcePublisher publisher = m_publishers.get(event.sourceHandle);
|
||||
if (publisher != null) {
|
||||
PropertyPublisher pp = publisher.m_properties.get(event.propertyHandle);
|
||||
if (pp != null && pp.m_choicesTopic != null) {
|
||||
try {
|
||||
String[] choices =
|
||||
CameraServerJNI.getEnumPropertyChoices(event.propertyHandle);
|
||||
if (pp.m_choicesPublisher == null) {
|
||||
pp.m_choicesPublisher = pp.m_choicesTopic.publish();
|
||||
}
|
||||
pp.m_choicesPublisher.set(choices);
|
||||
} catch (VideoException ignored) {
|
||||
// ignore (just don't publish choices if we can't get them)
|
||||
String[] choices =
|
||||
CameraServerJNI.getEnumPropertyChoices(event.propertyHandle);
|
||||
if (pp.m_choicesPublisher == null) {
|
||||
pp.m_choicesPublisher = pp.m_choicesTopic.publish();
|
||||
}
|
||||
pp.m_choicesPublisher.set(choices);
|
||||
} catch (VideoException ignored) {
|
||||
// ignore (just don't publish choices if we can't get them)
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSinkSourceChanged:
|
||||
case kSinkCreated:
|
||||
case kSinkDestroyed:
|
||||
case kNetworkInterfacesChanged:
|
||||
{
|
||||
m_addresses = CameraServerJNI.getNetworkInterfaces();
|
||||
updateStreamValues();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
case kSinkSourceChanged,
|
||||
kSinkCreated,
|
||||
kSinkDestroyed,
|
||||
kNetworkInterfacesChanged -> {
|
||||
m_addresses = CameraServerJNI.getNetworkInterfaces();
|
||||
updateStreamValues();
|
||||
}
|
||||
default -> {
|
||||
// NOP
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -349,23 +333,20 @@ public final class CameraServer {
|
||||
* @param source Source index.
|
||||
*/
|
||||
private static String makeSourceValue(int source) {
|
||||
switch (VideoSource.getKindFromInt(CameraServerJNI.getSourceKind(source))) {
|
||||
case kUsb:
|
||||
return "usb:" + CameraServerJNI.getUsbCameraPath(source);
|
||||
case kHttp:
|
||||
{
|
||||
String[] urls = CameraServerJNI.getHttpCameraUrls(source);
|
||||
if (urls.length > 0) {
|
||||
return "ip:" + urls[0];
|
||||
} else {
|
||||
return "ip:";
|
||||
}
|
||||
return switch (VideoSource.getKindFromInt(CameraServerJNI.getSourceKind(source))) {
|
||||
case kUsb -> "usb:" + CameraServerJNI.getUsbCameraPath(source);
|
||||
case kHttp -> {
|
||||
String[] urls = CameraServerJNI.getHttpCameraUrls(source);
|
||||
if (urls.length > 0) {
|
||||
yield "ip:" + urls[0];
|
||||
} else {
|
||||
yield "ip:";
|
||||
}
|
||||
case kCv:
|
||||
return "cv:";
|
||||
default:
|
||||
return "unknown:";
|
||||
}
|
||||
}
|
||||
case kCv -> "cv:";
|
||||
case kRaw -> "raw:";
|
||||
case kUnknown -> "unknown:";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -499,20 +480,17 @@ public final class CameraServer {
|
||||
|
||||
/** Provide string description of pixel format. */
|
||||
private static String pixelFormatToString(PixelFormat pixelFormat) {
|
||||
switch (pixelFormat) {
|
||||
case kMJPEG:
|
||||
return "MJPEG";
|
||||
case kYUYV:
|
||||
return "YUYV";
|
||||
case kRGB565:
|
||||
return "RGB565";
|
||||
case kBGR:
|
||||
return "BGR";
|
||||
case kGray:
|
||||
return "Gray";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
return switch (pixelFormat) {
|
||||
case kMJPEG -> "MJPEG";
|
||||
case kYUYV -> "YUYV";
|
||||
case kRGB565 -> "RGB565";
|
||||
case kBGR -> "BGR";
|
||||
case kBGRA -> "BGRA";
|
||||
case kGray -> "Gray";
|
||||
case kY16 -> "Y16";
|
||||
case kUYVY -> "UYVY";
|
||||
case kUnknown -> "Unknown";
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -629,7 +607,10 @@ public final class CameraServer {
|
||||
*
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
* @return The Axis camera capturing images.
|
||||
* @deprecated Call startAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "2025")
|
||||
@SuppressWarnings("removal")
|
||||
public static AxisCamera addAxisCamera(String host) {
|
||||
return addAxisCamera("Axis Camera", host);
|
||||
}
|
||||
@@ -641,7 +622,10 @@ public final class CameraServer {
|
||||
*
|
||||
* @param hosts Array of Camera host IPs/DNS names
|
||||
* @return The Axis camera capturing images.
|
||||
* @deprecated Call startAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "2025")
|
||||
@SuppressWarnings("removal")
|
||||
public static AxisCamera addAxisCamera(String[] hosts) {
|
||||
return addAxisCamera("Axis Camera", hosts);
|
||||
}
|
||||
@@ -652,7 +636,10 @@ public final class CameraServer {
|
||||
* @param name The name to give the camera
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
* @return The Axis camera capturing images.
|
||||
* @deprecated Call startAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "2025")
|
||||
@SuppressWarnings("removal")
|
||||
public static AxisCamera addAxisCamera(String name, String host) {
|
||||
AxisCamera camera = new AxisCamera(name, host);
|
||||
// Create a passthrough MJPEG server for USB access
|
||||
@@ -667,7 +654,10 @@ public final class CameraServer {
|
||||
* @param name The name to give the camera
|
||||
* @param hosts Array of Camera host IPs/DNS names
|
||||
* @return The Axis camera capturing images.
|
||||
* @deprecated Call startAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "2025")
|
||||
@SuppressWarnings("removal")
|
||||
public static AxisCamera addAxisCamera(String name, String[] hosts) {
|
||||
AxisCamera camera = new AxisCamera(name, hosts);
|
||||
// Create a passthrough MJPEG server for USB access
|
||||
@@ -686,7 +676,7 @@ public final class CameraServer {
|
||||
*/
|
||||
public static MjpegServer addSwitchedCamera(String name) {
|
||||
// create a dummy CvSource
|
||||
CvSource source = new CvSource(name, VideoMode.PixelFormat.kMJPEG, 160, 120, 30);
|
||||
CvSource source = new CvSource(name, PixelFormat.kMJPEG, 160, 120, 30);
|
||||
MjpegServer server = startAutomaticCapture(source);
|
||||
synchronized (CameraServer.class) {
|
||||
m_fixedSources.put(server.getHandle(), source.getHandle());
|
||||
@@ -745,6 +735,34 @@ public final class CameraServer {
|
||||
return newsink;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get OpenCV access to the specified camera. This allows you to get images from the camera for
|
||||
* image processing on the roboRIO.
|
||||
*
|
||||
* @param camera Camera (e.g. as returned by startAutomaticCapture).
|
||||
* @param pixelFormat Desired pixelFormat of the camera
|
||||
* @return OpenCV sink for the specified camera
|
||||
*/
|
||||
public static CvSink getVideo(VideoSource camera, PixelFormat pixelFormat) {
|
||||
String name = "opencv_" + camera.getName();
|
||||
|
||||
synchronized (CameraServer.class) {
|
||||
VideoSink sink = m_sinks.get(name);
|
||||
if (sink != null) {
|
||||
VideoSink.Kind kind = sink.getKind();
|
||||
if (kind != VideoSink.Kind.kCv) {
|
||||
throw new VideoException("expected OpenCV sink, but got " + kind);
|
||||
}
|
||||
return (CvSink) sink;
|
||||
}
|
||||
}
|
||||
|
||||
CvSink newsink = new CvSink(name, pixelFormat);
|
||||
newsink.setSource(camera);
|
||||
addServer(newsink);
|
||||
return newsink;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get OpenCV access to the specified camera. This allows you to get images from the camera for
|
||||
* image processing on the roboRIO.
|
||||
@@ -773,7 +791,7 @@ public final class CameraServer {
|
||||
* @return OpenCV source for the MJPEG stream
|
||||
*/
|
||||
public static CvSource putVideo(String name, int width, int height) {
|
||||
CvSource source = new CvSource(name, VideoMode.PixelFormat.kMJPEG, width, height, 30);
|
||||
CvSource source = new CvSource(name, PixelFormat.kMJPEG, width, height, 30);
|
||||
startAutomaticCapture(source);
|
||||
return source;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
package edu.wpi.first.cameraserver;
|
||||
|
||||
/** CameraServer shared functions. */
|
||||
public interface CameraServerShared {
|
||||
/**
|
||||
* get the main thread id func.
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
package edu.wpi.first.cameraserver;
|
||||
|
||||
/** Storage for CameraServerShared instance. */
|
||||
public final class CameraServerSharedStore {
|
||||
private static CameraServerShared cameraServerShared;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.opencv.core.Mat;
|
||||
* code. The easiest way to use this is to run it in a {@link VisionThread} and use the listener to
|
||||
* take snapshots of the pipeline's outputs.
|
||||
*
|
||||
* @param <P> Vision pipeline type.
|
||||
* @see VisionPipeline
|
||||
* @see VisionThread
|
||||
* @see <a href="package-summary.html">vision</a>
|
||||
|
||||
@@ -21,6 +21,7 @@ public class VisionThread extends Thread {
|
||||
*
|
||||
* @param visionRunner the runner for a vision pipeline
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
public VisionThread(VisionRunner<?> visionRunner) {
|
||||
super(visionRunner::runForever, "WPILib Vision Thread");
|
||||
setDaemon(true);
|
||||
|
||||
@@ -113,6 +113,8 @@ static std::string_view MakeSourceValue(CS_Source source,
|
||||
}
|
||||
case CS_SOURCE_CV:
|
||||
return "cv:";
|
||||
case CS_SOURCE_RAW:
|
||||
return "raw:";
|
||||
default:
|
||||
return "unknown:";
|
||||
}
|
||||
@@ -502,6 +504,7 @@ cs::UsbCamera CameraServer::StartAutomaticCapture(std::string_view name,
|
||||
return camera;
|
||||
}
|
||||
|
||||
WPI_IGNORE_DEPRECATED
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(std::string_view host) {
|
||||
return AddAxisCamera("Axis Camera", host);
|
||||
}
|
||||
@@ -557,7 +560,7 @@ cs::AxisCamera CameraServer::AddAxisCamera(std::string_view name,
|
||||
csShared->ReportAxisCamera(camera.GetHandle());
|
||||
return camera;
|
||||
}
|
||||
|
||||
WPI_UNIGNORE_DEPRECATED
|
||||
cs::MjpegServer CameraServer::AddSwitchedCamera(std::string_view name) {
|
||||
auto& inst = ::GetInstance();
|
||||
// create a dummy CvSource
|
||||
@@ -622,6 +625,33 @@ cs::CvSink CameraServer::GetVideo(const cs::VideoSource& camera) {
|
||||
return newsink;
|
||||
}
|
||||
|
||||
cs::CvSink CameraServer::GetVideo(const cs::VideoSource& camera,
|
||||
cs::VideoMode::PixelFormat pixelFormat) {
|
||||
auto& inst = ::GetInstance();
|
||||
wpi::SmallString<64> name{"opencv_"};
|
||||
name += camera.GetName();
|
||||
|
||||
{
|
||||
std::scoped_lock lock(inst.m_mutex);
|
||||
auto it = inst.m_sinks.find(name);
|
||||
if (it != inst.m_sinks.end()) {
|
||||
auto kind = it->second.GetKind();
|
||||
if (kind != cs::VideoSink::kCv) {
|
||||
auto csShared = GetCameraServerShared();
|
||||
csShared->SetCameraServerError("expected OpenCV sink, but got {}",
|
||||
static_cast<int>(kind));
|
||||
return cs::CvSink{};
|
||||
}
|
||||
return *static_cast<cs::CvSink*>(&it->second);
|
||||
}
|
||||
}
|
||||
|
||||
cs::CvSink newsink{name.str(), pixelFormat};
|
||||
newsink.SetSource(camera);
|
||||
AddServer(newsink);
|
||||
return newsink;
|
||||
}
|
||||
|
||||
cs::CvSink CameraServer::GetVideo(std::string_view name) {
|
||||
auto& inst = ::GetInstance();
|
||||
cs::VideoSource source;
|
||||
@@ -638,6 +668,23 @@ cs::CvSink CameraServer::GetVideo(std::string_view name) {
|
||||
return GetVideo(source);
|
||||
}
|
||||
|
||||
cs::CvSink CameraServer::GetVideo(std::string_view name,
|
||||
cs::VideoMode::PixelFormat pixelFormat) {
|
||||
auto& inst = ::GetInstance();
|
||||
cs::VideoSource source;
|
||||
{
|
||||
std::scoped_lock lock(inst.m_mutex);
|
||||
auto it = inst.m_sources.find(name);
|
||||
if (it == inst.m_sources.end()) {
|
||||
auto csShared = GetCameraServerShared();
|
||||
csShared->SetCameraServerError("could not find camera {}", name);
|
||||
return cs::CvSink{};
|
||||
}
|
||||
source = it->second;
|
||||
}
|
||||
return GetVideo(source, pixelFormat);
|
||||
}
|
||||
|
||||
cs::CvSource CameraServer::PutVideo(std::string_view name, int width,
|
||||
int height) {
|
||||
::GetInstance();
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <wpi/deprecated.h>
|
||||
|
||||
#include "cscore.h"
|
||||
#include "cscore_cv.h"
|
||||
|
||||
@@ -22,10 +24,8 @@ namespace frc {
|
||||
*/
|
||||
class CameraServer {
|
||||
public:
|
||||
/// CameraServer base port.
|
||||
static constexpr uint16_t kBasePort = 1181;
|
||||
static constexpr int kSize640x480 = 0;
|
||||
static constexpr int kSize320x240 = 1;
|
||||
static constexpr int kSize160x120 = 2;
|
||||
|
||||
/**
|
||||
* Start automatically capturing images to send to the dashboard.
|
||||
@@ -75,13 +75,16 @@ class CameraServer {
|
||||
*/
|
||||
static cs::MjpegServer StartAutomaticCapture(const cs::VideoSource& camera);
|
||||
|
||||
WPI_IGNORE_DEPRECATED
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
*
|
||||
* This overload calls AddAxisCamera() with name "Axis Camera".
|
||||
*
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(std::string_view host);
|
||||
|
||||
/**
|
||||
@@ -90,7 +93,9 @@ class CameraServer {
|
||||
* This overload calls AddAxisCamera() with name "Axis Camera".
|
||||
*
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(const char* host);
|
||||
|
||||
/**
|
||||
@@ -99,7 +104,9 @@ class CameraServer {
|
||||
* This overload calls AddAxisCamera() with name "Axis Camera".
|
||||
*
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(const std::string& host);
|
||||
|
||||
/**
|
||||
@@ -108,7 +115,9 @@ class CameraServer {
|
||||
* This overload calls AddAxisCamera() with name "Axis Camera".
|
||||
*
|
||||
* @param hosts Array of Camera host IPs/DNS names
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(std::span<const std::string> hosts);
|
||||
|
||||
/**
|
||||
@@ -117,8 +126,10 @@ class CameraServer {
|
||||
* This overload calls AddAxisCamera() with name "Axis Camera".
|
||||
*
|
||||
* @param hosts Array of Camera host IPs/DNS names
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
template <typename T>
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(std::initializer_list<T> hosts);
|
||||
|
||||
/**
|
||||
@@ -126,7 +137,9 @@ class CameraServer {
|
||||
*
|
||||
* @param name The name to give the camera
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(std::string_view name,
|
||||
std::string_view host);
|
||||
|
||||
@@ -135,7 +148,9 @@ class CameraServer {
|
||||
*
|
||||
* @param name The name to give the camera
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(std::string_view name, const char* host);
|
||||
|
||||
/**
|
||||
@@ -143,7 +158,9 @@ class CameraServer {
|
||||
*
|
||||
* @param name The name to give the camera
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(std::string_view name,
|
||||
const std::string& host);
|
||||
|
||||
@@ -152,7 +169,9 @@ class CameraServer {
|
||||
*
|
||||
* @param name The name to give the camera
|
||||
* @param hosts Array of Camera host IPs/DNS names
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(std::string_view name,
|
||||
std::span<const std::string> hosts);
|
||||
|
||||
@@ -161,10 +180,13 @@ class CameraServer {
|
||||
*
|
||||
* @param name The name to give the camera
|
||||
* @param hosts Array of Camera host IPs/DNS names
|
||||
* @deprecated Call StartAutomaticCapture with a HttpCamera instead.
|
||||
*/
|
||||
template <typename T>
|
||||
[[deprecated("Call StartAutomaticCapture with a HttpCamera instead.")]]
|
||||
static cs::AxisCamera AddAxisCamera(std::string_view name,
|
||||
std::initializer_list<T> hosts);
|
||||
WPI_UNIGNORE_DEPRECATED
|
||||
|
||||
/**
|
||||
* Adds a virtual camera for switching between two streams. Unlike the
|
||||
@@ -191,6 +213,17 @@ class CameraServer {
|
||||
*/
|
||||
static cs::CvSink GetVideo(const cs::VideoSource& camera);
|
||||
|
||||
/**
|
||||
* Get OpenCV access to the specified camera. This allows you to get
|
||||
* images from the camera for image processing on the roboRIO.
|
||||
*
|
||||
* @param camera Camera (e.g. as returned by startAutomaticCapture).
|
||||
* @param pixelFormat The desired pixelFormat of captured frames from the
|
||||
* camera
|
||||
*/
|
||||
static cs::CvSink GetVideo(const cs::VideoSource& camera,
|
||||
cs::VideoMode::PixelFormat pixelFormat);
|
||||
|
||||
/**
|
||||
* Get OpenCV access to the specified camera. This allows you to get
|
||||
* images from the camera for image processing on the roboRIO.
|
||||
@@ -199,6 +232,17 @@ class CameraServer {
|
||||
*/
|
||||
static cs::CvSink GetVideo(std::string_view name);
|
||||
|
||||
/**
|
||||
* Get OpenCV access to the specified camera. This allows you to get
|
||||
* images from the camera for image processing on the roboRIO.
|
||||
*
|
||||
* @param name Camera name
|
||||
* @param pixelFormat The desired pixelFormat of captured frames from the
|
||||
* camera
|
||||
*/
|
||||
static cs::CvSink GetVideo(std::string_view name,
|
||||
cs::VideoMode::PixelFormat pixelFormat);
|
||||
|
||||
/**
|
||||
* Create a MJPEG stream with OpenCV input. This can be called to pass custom
|
||||
* annotated images to the dashboard.
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
namespace frc {
|
||||
|
||||
WPI_IGNORE_DEPRECATED
|
||||
template <typename T>
|
||||
inline cs::AxisCamera CameraServer::AddAxisCamera(
|
||||
std::initializer_list<T> hosts) {
|
||||
@@ -27,5 +28,6 @@ inline cs::AxisCamera CameraServer::AddAxisCamera(
|
||||
}
|
||||
return AddAxisCamera(name, vec);
|
||||
}
|
||||
WPI_UNIGNORE_DEPRECATED
|
||||
|
||||
} // namespace frc
|
||||
|
||||
@@ -3,11 +3,12 @@ include(CompileWarnings)
|
||||
macro(wpilib_add_test name srcdir)
|
||||
file(GLOB_RECURSE test_src ${srcdir}/*.cpp)
|
||||
add_executable(${name}_test ${test_src})
|
||||
set_property(TARGET ${name}_test PROPERTY FOLDER "tests")
|
||||
wpilib_target_warnings(${name}_test)
|
||||
if (BUILD_SHARED_LIBS)
|
||||
if(BUILD_SHARED_LIBS)
|
||||
target_compile_definitions(${name}_test PRIVATE -DGTEST_LINKED_AS_SHARED_LIBRARY)
|
||||
endif()
|
||||
if (MSVC)
|
||||
if(MSVC)
|
||||
target_compile_options(${name}_test PRIVATE /wd4101 /wd4251)
|
||||
endif()
|
||||
add_test(NAME ${name} COMMAND ${name}_test)
|
||||
|
||||
@@ -1,28 +1,56 @@
|
||||
macro(wpilib_target_warnings target)
|
||||
if(NOT MSVC)
|
||||
target_compile_options(${target} PRIVATE -Wall -pedantic -Wextra -Werror -Wno-unused-parameter ${WPILIB_TARGET_WARNINGS})
|
||||
set(WARNING_FLAGS
|
||||
-Wall
|
||||
-pedantic
|
||||
-Wextra
|
||||
-Wno-unused-parameter
|
||||
${WPILIB_TARGET_WARNINGS}
|
||||
)
|
||||
if(NOT NO_WERROR)
|
||||
set(WARNING_FLAGS ${WARNING_FLAGS} -Werror)
|
||||
endif()
|
||||
|
||||
target_compile_options(${target} PRIVATE ${WARNING_FLAGS})
|
||||
else()
|
||||
target_compile_options(${target} PRIVATE /wd4146 /wd4244 /wd4251 /wd4267 /WX /D_CRT_SECURE_NO_WARNINGS ${WPILIB_TARGET_WARNINGS})
|
||||
target_compile_options(
|
||||
${target}
|
||||
PRIVATE
|
||||
/wd4146
|
||||
/wd4244
|
||||
/wd4251
|
||||
/wd4267
|
||||
/WX
|
||||
/D_CRT_SECURE_NO_WARNINGS
|
||||
${WPILIB_TARGET_WARNINGS}
|
||||
)
|
||||
endif()
|
||||
|
||||
# Suppress C++-specific OpenCV warning; C compiler rejects it with an error
|
||||
# https://github.com/opencv/opencv/issues/20269
|
||||
if(UNIX AND NOT APPLE)
|
||||
target_compile_options(${target} PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-enum-enum-conversion>)
|
||||
target_compile_options(
|
||||
${target}
|
||||
PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-enum-enum-conversion>
|
||||
)
|
||||
elseif(UNIX AND APPLE)
|
||||
target_compile_options(${target} PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-anon-enum-enum-conversion>)
|
||||
target_compile_options(
|
||||
${target}
|
||||
PRIVATE $<$<COMPILE_LANGUAGE:CXX>:-Wno-deprecated-anon-enum-enum-conversion>
|
||||
)
|
||||
endif()
|
||||
|
||||
# Suppress warning "enumeration types with a fixed underlying type are a
|
||||
# Clang extension"
|
||||
if(APPLE)
|
||||
target_compile_options(${target} PRIVATE $<$<COMPILE_LANGUAGE:C>:-Wno-fixed-enum-extension>)
|
||||
target_compile_options(${target} PRIVATE $<$<COMPILE_LANGUAGE:C>:-Wno-fixed-enum-extension>)
|
||||
endif()
|
||||
|
||||
# Compress debug info with GCC
|
||||
if ((${CMAKE_BUILD_TYPE} STREQUAL "Debug" OR
|
||||
${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo") AND
|
||||
${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU")
|
||||
target_compile_options(${target} PRIVATE -gz=zlib)
|
||||
if(
|
||||
(${CMAKE_BUILD_TYPE} STREQUAL "Debug" OR ${CMAKE_BUILD_TYPE} STREQUAL "RelWithDebInfo")
|
||||
AND ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU"
|
||||
)
|
||||
target_compile_options(${target} PRIVATE -gz=zlib)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
macro(download_and_check source destination)
|
||||
file(DOWNLOAD ${source} ${destination} STATUS download_status)
|
||||
list(GET download_status 0 status_code)
|
||||
list(GET download_status 1 status_message)
|
||||
file(DOWNLOAD ${source} ${destination} STATUS download_status)
|
||||
list(GET download_status 0 status_code)
|
||||
list(GET download_status 1 status_message)
|
||||
|
||||
if(${status_code} EQUAL 0)
|
||||
message(VERBOSE "Download of \"${source}\" successful.")
|
||||
else()
|
||||
message(FATAL_ERROR "Download of \"${source}\" failed: ${status_message}")
|
||||
endif()
|
||||
if(${status_code} EQUAL 0)
|
||||
message(VERBOSE "Download of \"${source}\" successful.")
|
||||
else()
|
||||
message(FATAL_ERROR "Download of \"${source}\" failed: ${status_message}")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
@@ -38,30 +38,28 @@ if(LIBSSH_LIBRARIES AND LIBSSH_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(LIBSSH_FOUND TRUE)
|
||||
else()
|
||||
find_path(LIBSSH_INCLUDE_DIR
|
||||
NAMES
|
||||
libssh/libssh.h
|
||||
find_path(
|
||||
LIBSSH_INCLUDE_DIR
|
||||
NAMES libssh/libssh.h
|
||||
PATHS
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
/sw/include
|
||||
${CMAKE_INCLUDE_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/include
|
||||
/usr/include
|
||||
/usr/local/include
|
||||
/opt/local/include
|
||||
/sw/include
|
||||
${CMAKE_INCLUDE_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/include
|
||||
)
|
||||
|
||||
find_library(LIBSSH_LIBRARY
|
||||
NAMES
|
||||
ssh.so
|
||||
libssh.so
|
||||
libssh.dylib
|
||||
find_library(
|
||||
LIBSSH_LIBRARY
|
||||
NAMES ssh.so libssh.so libssh.dylib
|
||||
PATHS
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
${CMAKE_LIBRARY_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
/usr/lib
|
||||
/usr/local/lib
|
||||
/opt/local/lib
|
||||
/sw/lib
|
||||
${CMAKE_LIBRARY_PATH}
|
||||
${CMAKE_INSTALL_PREFIX}/lib
|
||||
)
|
||||
|
||||
if(LIBSSH_INCLUDE_DIR AND LIBSSH_LIBRARY)
|
||||
@@ -71,34 +69,60 @@ else()
|
||||
else()
|
||||
set(LIBSSH_HEADER_PATH ${LIBSSH_INCLUDE_DIR}/libssh/libssh.h)
|
||||
endif()
|
||||
file(STRINGS ${LIBSSH_HEADER_PATH} LIBSSH_VERSION_MAJOR
|
||||
REGEX "#define[ ]+LIBSSH_VERSION_MAJOR[ ]+[0-9]+")
|
||||
file(
|
||||
STRINGS
|
||||
${LIBSSH_HEADER_PATH}
|
||||
LIBSSH_VERSION_MAJOR
|
||||
REGEX "#define[ ]+LIBSSH_VERSION_MAJOR[ ]+[0-9]+"
|
||||
)
|
||||
if(NOT LIBSSH_VERSION_MAJOR)
|
||||
message(STATUS "LIBSSH_VERSION_MAJOR not found, assuming libssh is too old and cannot be used!")
|
||||
message(
|
||||
STATUS
|
||||
"LIBSSH_VERSION_MAJOR not found, assuming libssh is too old and cannot be used!"
|
||||
)
|
||||
set(LIBSSH_INCLUDE_DIR "LIBSSH_INCLUDE_DIR-NOTFOUND")
|
||||
set(LIBSSH_LIBRARY "LIBSSH_LIBRARY-NOTFOUND")
|
||||
else()
|
||||
string(REGEX MATCH "[0-9]+" LIBSSH_VERSION_MAJOR ${LIBSSH_VERSION_MAJOR})
|
||||
file(STRINGS ${LIBSSH_HEADER_PATH} LIBSSH_VERSION_MINOR
|
||||
REGEX "#define[ ]+LIBSSH_VERSION_MINOR[ ]+[0-9]+")
|
||||
file(
|
||||
STRINGS
|
||||
${LIBSSH_HEADER_PATH}
|
||||
LIBSSH_VERSION_MINOR
|
||||
REGEX "#define[ ]+LIBSSH_VERSION_MINOR[ ]+[0-9]+"
|
||||
)
|
||||
string(REGEX MATCH "[0-9]+" LIBSSH_VERSION_MINOR ${LIBSSH_VERSION_MINOR})
|
||||
file(STRINGS ${LIBSSH_HEADER_PATH} LIBSSH_VERSION_PATCH
|
||||
REGEX "#define[ ]+LIBSSH_VERSION_MICRO[ ]+[0-9]+")
|
||||
file(
|
||||
STRINGS
|
||||
${LIBSSH_HEADER_PATH}
|
||||
LIBSSH_VERSION_PATCH
|
||||
REGEX "#define[ ]+LIBSSH_VERSION_MICRO[ ]+[0-9]+"
|
||||
)
|
||||
string(REGEX MATCH "[0-9]+" LIBSSH_VERSION_PATCH ${LIBSSH_VERSION_PATCH})
|
||||
|
||||
set(LIBSSH_VERSION ${LIBSSH_VERSION_MAJOR}.${LIBSSH_VERSION_MINOR}.${LIBSSH_VERSION_PATCH})
|
||||
set(LIBSSH_VERSION
|
||||
${LIBSSH_VERSION_MAJOR}.${LIBSSH_VERSION_MINOR}.${LIBSSH_VERSION_PATCH}
|
||||
)
|
||||
|
||||
if(LIBSSH_VERSION VERSION_LESS 0.8.0)
|
||||
# libssh_threads also needs to be linked for these versions
|
||||
string(REPLACE "libssh.so" "libssh_threads.so"
|
||||
string(
|
||||
REPLACE
|
||||
"libssh.so"
|
||||
"libssh_threads.so"
|
||||
LIBSSH_THREADS_LIBRARY
|
||||
${LIBSSH_LIBRARY}
|
||||
)
|
||||
string(REPLACE "libssh.dylib" "libssh_threads.dylib"
|
||||
string(
|
||||
REPLACE
|
||||
"libssh.dylib"
|
||||
"libssh_threads.dylib"
|
||||
LIBSSH_THREADS_LIBRARY
|
||||
${LIBSSH_THREADS_LIBRARY}
|
||||
)
|
||||
string(REPLACE "ssh.so" "ssh_threads.so"
|
||||
string(
|
||||
REPLACE
|
||||
"ssh.so"
|
||||
"ssh_threads.so"
|
||||
LIBSSH_THREADS_LIBRARY
|
||||
${LIBSSH_THREADS_LIBRARY}
|
||||
)
|
||||
@@ -110,7 +134,10 @@ else()
|
||||
set(LIBSSH_LIBRARIES ${LIBSSH_LIBRARY} ${LIBSSH_THREADS_LIBRARY})
|
||||
mark_as_advanced(LIBSSH_INCLUDE_DIRS LIBSSH_LIBRARIES)
|
||||
|
||||
find_package_handle_standard_args(LIBSSH FOUND_VAR LIBSSH_FOUND
|
||||
find_package_handle_standard_args(
|
||||
LIBSSH
|
||||
FOUND_VAR LIBSSH_FOUND
|
||||
REQUIRED_VARS LIBSSH_INCLUDE_DIRS LIBSSH_LIBRARIES
|
||||
VERSION_VAR LIBSSH_VERSION)
|
||||
VERSION_VAR LIBSSH_VERSION
|
||||
)
|
||||
endif()
|
||||
|
||||
@@ -1,26 +1,30 @@
|
||||
set(scripts_dir "${CMAKE_CURRENT_LIST_DIR}/../scripts")
|
||||
macro(generate_resources inputDir outputDir prefix namespace outputFiles)
|
||||
file(GLOB inputFiles ${inputDir}/*)
|
||||
set(${outputFiles})
|
||||
foreach(input ${inputFiles})
|
||||
get_filename_component(inputBase ${input} NAME)
|
||||
if("${inputBase}" MATCHES "^\\.")
|
||||
continue()
|
||||
endif()
|
||||
set(output "${outputDir}/${inputBase}.cpp")
|
||||
list(APPEND ${outputFiles} "${output}")
|
||||
macro(
|
||||
generate_resources
|
||||
inputDir
|
||||
outputDir
|
||||
prefix
|
||||
namespace
|
||||
outputFiles
|
||||
)
|
||||
file(GLOB inputFiles ${inputDir}/*)
|
||||
set(${outputFiles})
|
||||
foreach(input ${inputFiles})
|
||||
get_filename_component(inputBase ${input} NAME)
|
||||
if("${inputBase}" MATCHES "^\\.")
|
||||
continue()
|
||||
endif()
|
||||
set(output "${outputDir}/${inputBase}.cpp")
|
||||
list(APPEND ${outputFiles} "${output}")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${output}
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
"-Dinput=${input}"
|
||||
"-Doutput=${output}"
|
||||
"-Dprefix=${prefix}"
|
||||
"-Dnamespace=${namespace}"
|
||||
-P "${scripts_dir}/GenResource.cmake"
|
||||
MAIN_DEPENDENCY ${input}
|
||||
DEPENDS ${scripts_dir}/GenResource.cmake
|
||||
VERBATIM
|
||||
)
|
||||
endforeach()
|
||||
add_custom_command(
|
||||
OUTPUT ${output}
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} "-Dinput=${input}" "-Doutput=${output}" "-Dprefix=${prefix}"
|
||||
"-Dnamespace=${namespace}" -P "${scripts_dir}/GenResource.cmake"
|
||||
MAIN_DEPENDENCY ${input}
|
||||
DEPENDS ${scripts_dir}/GenResource.cmake
|
||||
VERBATIM
|
||||
)
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
macro(wpilib_link_macos_gui target)
|
||||
if (APPLE)
|
||||
set_target_properties(${target} PROPERTIES LINK_FLAGS "-framework Metal -framework QuartzCore")
|
||||
if(APPLE)
|
||||
set_target_properties(
|
||||
${target}
|
||||
PROPERTIES LINK_FLAGS "-framework Metal -framework QuartzCore"
|
||||
)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
macro(subdir_list result curdir)
|
||||
file(GLOB children RELATIVE ${curdir} ${curdir}/*)
|
||||
set(dirlist "")
|
||||
foreach(child ${children})
|
||||
if(IS_DIRECTORY ${curdir}/${child})
|
||||
list(APPEND dirlist ${child})
|
||||
endif()
|
||||
endforeach()
|
||||
set(${result} ${dirlist})
|
||||
file(GLOB children RELATIVE ${curdir} ${curdir}/*)
|
||||
set(dirlist "")
|
||||
foreach(child ${children})
|
||||
if(IS_DIRECTORY ${curdir}/${child})
|
||||
list(APPEND dirlist ${child})
|
||||
endif()
|
||||
endforeach()
|
||||
set(${result} ${dirlist})
|
||||
endmacro()
|
||||
|
||||
macro(add_all_subdirectories curdir)
|
||||
subdir_list(_SUBPROJECTS ${curdir})
|
||||
foreach(dir ${_SUBPROJECTS})
|
||||
add_subdirectory(${dir})
|
||||
endforeach()
|
||||
subdir_list(_SUBPROJECTS ${curdir})
|
||||
foreach(dir ${_SUBPROJECTS})
|
||||
add_subdirectory(${dir})
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
@@ -1,23 +1,35 @@
|
||||
# Parameters: input output prefix namespace
|
||||
FILE(READ ${input} fileHex HEX)
|
||||
STRING(LENGTH "${fileHex}" fileHexSize)
|
||||
MATH(EXPR fileSize "${fileHexSize} / 2")
|
||||
file(READ ${input} fileHex HEX)
|
||||
string(LENGTH "${fileHex}" fileHexSize)
|
||||
math(EXPR fileSize "${fileHexSize} / 2")
|
||||
|
||||
GET_FILENAME_COMPONENT(inputBase ${input} NAME)
|
||||
STRING(REGEX REPLACE "[^a-zA-Z0-9]" "_" funcName "${inputBase}")
|
||||
SET(funcName "GetResource_${funcName}")
|
||||
get_filename_component(inputBase ${input} NAME)
|
||||
string(REGEX REPLACE "[^a-zA-Z0-9]" "_" funcName "${inputBase}")
|
||||
set(funcName "GetResource_${funcName}")
|
||||
|
||||
FILE(WRITE "${output}" "#include <stddef.h>\n#include <string_view>\nextern \"C\" {\nstatic const unsigned char contents[] = {")
|
||||
file(
|
||||
WRITE
|
||||
"${output}"
|
||||
"#include <stddef.h>\n#include <string_view>\nextern \"C\" {\nstatic const unsigned char contents[] = {"
|
||||
)
|
||||
|
||||
STRING(REGEX MATCHALL ".." outputData "${fileHex}")
|
||||
STRING(REGEX REPLACE ";" ", 0x" outputData "${outputData}")
|
||||
FILE(APPEND "${output}" " 0x${outputData} };\n")
|
||||
FILE(APPEND "${output}" "const unsigned char* ${prefix}${funcName}(size_t* len) {\n *len = ${fileSize};\n return contents;\n}\n}\n")
|
||||
string(REGEX MATCHALL ".." outputData "${fileHex}")
|
||||
string(REGEX REPLACE ";" ", 0x" outputData "${outputData}")
|
||||
file(APPEND "${output}" " 0x${outputData} };\n")
|
||||
file(
|
||||
APPEND
|
||||
"${output}"
|
||||
"const unsigned char* ${prefix}${funcName}(size_t* len) {\n *len = ${fileSize};\n return contents;\n}\n}\n"
|
||||
)
|
||||
|
||||
IF(NOT namespace STREQUAL "")
|
||||
FILE(APPEND "${output}" "namespace ${namespace} {\n")
|
||||
ENDIF()
|
||||
FILE(APPEND "${output}" "std::string_view ${funcName}() {\n return std::string_view(reinterpret_cast<const char*>(contents), ${fileSize});\n}\n")
|
||||
IF(NOT namespace STREQUAL "")
|
||||
FILE(APPEND "${output}" "}\n")
|
||||
ENDIF()
|
||||
if(NOT namespace STREQUAL "")
|
||||
file(APPEND "${output}" "namespace ${namespace} {\n")
|
||||
endif()
|
||||
file(
|
||||
APPEND
|
||||
"${output}"
|
||||
"std::string_view ${funcName}() {\n return std::string_view(reinterpret_cast<const char*>(contents), ${fileSize});\n}\n"
|
||||
)
|
||||
if(NOT namespace STREQUAL "")
|
||||
file(APPEND "${output}" "}\n")
|
||||
endif()
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <fmt/core.h>
|
||||
#include <gtest/gtest.h>
|
||||
#include <hal/HAL.h>
|
||||
#include <wpi/print.h>
|
||||
|
||||
#include "mockds/MockDS.h"
|
||||
|
||||
@@ -27,7 +28,7 @@ class TestEnvironment : public testing::Environment {
|
||||
m_alreadySetUp = true;
|
||||
|
||||
if (!HAL_Initialize(500, 0)) {
|
||||
fmt::print(stderr, "FATAL ERROR: HAL could not be initialized\n");
|
||||
wpi::print(stderr, "FATAL ERROR: HAL could not be initialized\n");
|
||||
std::exit(-1);
|
||||
}
|
||||
|
||||
@@ -39,7 +40,7 @@ class TestEnvironment : public testing::Environment {
|
||||
// able to run on the hardware.
|
||||
HAL_ObserveUserProgramStarting();
|
||||
|
||||
fmt::print("Started coms\n");
|
||||
wpi::print("Started coms\n");
|
||||
|
||||
int enableCounter = 0;
|
||||
|
||||
@@ -54,13 +55,13 @@ class TestEnvironment : public testing::Environment {
|
||||
if (enableCounter > 50) {
|
||||
// Robot did not enable properly after 5 seconds.
|
||||
// Force exit
|
||||
fmt::print(stderr, " Failed to enable. Aborting\n");
|
||||
wpi::print(stderr, " Failed to enable. Aborting\n");
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(100ms);
|
||||
|
||||
fmt::print("Waiting for enable: {}\n", enableCounter++);
|
||||
wpi::print("Waiting for enable: {}\n", enableCounter++);
|
||||
HAL_RefreshDSData();
|
||||
}
|
||||
std::this_thread::sleep_for(500ms);
|
||||
|
||||
@@ -12,12 +12,13 @@
|
||||
#include <hal/cpp/fpga_clock.h>
|
||||
#include <wpi/Logger.h>
|
||||
#include <wpi/SmallVector.h>
|
||||
#include <wpi/print.h>
|
||||
#include <wpinet/UDPClient.h>
|
||||
|
||||
static void LoggerFunc(unsigned int level, const char* file, unsigned int line,
|
||||
const char* msg) {
|
||||
if (level == 20) {
|
||||
fmt::print(stderr, "DS: {}\n", msg);
|
||||
wpi::print(stderr, "DS: {}\n", msg);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -31,7 +32,7 @@ static void LoggerFunc(unsigned int level, const char* file, unsigned int line,
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
fmt::print(stderr, "DS: {}: {} ({}:{})\n", levelmsg, msg, file, line);
|
||||
wpi::print(stderr, "DS: {}: {} ({}:{})\n", levelmsg, msg, file, line);
|
||||
}
|
||||
|
||||
static void generateEnabledDsPacket(wpi::SmallVectorImpl<uint8_t>& data,
|
||||
|
||||
@@ -193,8 +193,8 @@ struct RelayHandle {
|
||||
#define ASSERT_LAST_ERROR_STATUS(status, x) \
|
||||
do { \
|
||||
ASSERT_EQ(status, HAL_USE_LAST_ERROR); \
|
||||
[[maybe_unused]] \
|
||||
const char* lastErrorMessageInMacro = HAL_GetLastError(&status); \
|
||||
static_cast<void>(lastErrorMessageInMacro); \
|
||||
ASSERT_EQ(status, x); \
|
||||
} while (0)
|
||||
|
||||
|
||||
@@ -5,10 +5,9 @@ include(CompileWarnings)
|
||||
include(AddTest)
|
||||
include(LinkMacOSGUI)
|
||||
|
||||
find_package( OpenCV REQUIRED )
|
||||
find_package(OpenCV REQUIRED)
|
||||
|
||||
file(GLOB
|
||||
cscore_native_src src/main/native/cpp/*.cpp)
|
||||
file(GLOB cscore_native_src src/main/native/cpp/*.cpp)
|
||||
file(GLOB cscore_linux_src src/main/native/linux/*.cpp)
|
||||
file(GLOB cscore_osx_src src/main/native/osx/*.cpp)
|
||||
file(GLOB cscore_osx_objc_src src/main/native/objcpp/*.mm)
|
||||
@@ -18,10 +17,15 @@ add_library(cscore ${cscore_native_src})
|
||||
set_target_properties(cscore PROPERTIES DEBUG_POSTFIX "d")
|
||||
|
||||
if(NOT MSVC)
|
||||
if (APPLE)
|
||||
if(APPLE)
|
||||
target_sources(cscore PRIVATE ${cscore_osx_src} ${cscore_osx_objc_src})
|
||||
target_compile_options(cscore PRIVATE "-fobjc-arc")
|
||||
set_target_properties(cscore PROPERTIES LINK_FLAGS "-framework CoreFoundation -framework AVFoundation -framework Foundation -framework CoreMedia -framework CoreVideo")
|
||||
set_target_properties(
|
||||
cscore
|
||||
PROPERTIES
|
||||
LINK_FLAGS
|
||||
"-framework CoreFoundation -framework AVFoundation -framework Foundation -framework CoreMedia -framework CoreVideo"
|
||||
)
|
||||
else()
|
||||
target_sources(cscore PRIVATE ${cscore_linux_src})
|
||||
endif()
|
||||
@@ -31,9 +35,12 @@ else()
|
||||
target_compile_definitions(cscore PRIVATE -D_CRT_SECURE_NO_WARNINGS)
|
||||
endif()
|
||||
|
||||
target_include_directories(cscore PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/include>
|
||||
$<INSTALL_INTERFACE:${include_dest}/cscore>)
|
||||
target_include_directories(
|
||||
cscore
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/main/native/include>
|
||||
$<INSTALL_INTERFACE:${include_dest}/cscore>
|
||||
)
|
||||
target_include_directories(cscore PRIVATE src/main/native/cpp)
|
||||
wpilib_target_warnings(cscore)
|
||||
target_link_libraries(cscore PUBLIC wpinet wpiutil ${OpenCV_LIBS})
|
||||
@@ -41,17 +48,12 @@ target_link_libraries(cscore PUBLIC wpinet wpiutil ${OpenCV_LIBS})
|
||||
set_property(TARGET cscore PROPERTY FOLDER "libraries")
|
||||
|
||||
install(TARGETS cscore EXPORT cscore)
|
||||
export(TARGETS cscore FILE cscore.cmake NAMESPACE cscore::)
|
||||
install(DIRECTORY src/main/native/include/ DESTINATION "${include_dest}/cscore")
|
||||
|
||||
if (WITH_FLAT_INSTALL)
|
||||
set (cscore_config_dir ${wpilib_dest})
|
||||
else()
|
||||
set (cscore_config_dir share/cscore)
|
||||
endif()
|
||||
|
||||
configure_file(cscore-config.cmake.in ${WPILIB_BINARY_DIR}/cscore-config.cmake )
|
||||
install(FILES ${WPILIB_BINARY_DIR}/cscore-config.cmake DESTINATION ${cscore_config_dir})
|
||||
install(EXPORT cscore DESTINATION ${cscore_config_dir})
|
||||
configure_file(cscore-config.cmake.in ${WPILIB_BINARY_DIR}/cscore-config.cmake)
|
||||
install(FILES ${WPILIB_BINARY_DIR}/cscore-config.cmake DESTINATION share/cscore)
|
||||
install(EXPORT cscore DESTINATION share/cscore)
|
||||
|
||||
subdir_list(cscore_examples "${CMAKE_CURRENT_SOURCE_DIR}/examples")
|
||||
foreach(example ${cscore_examples})
|
||||
@@ -68,7 +70,7 @@ foreach(example ${cscore_examples})
|
||||
add_executable(cscore_${example} ${cscore_example_src})
|
||||
wpilib_target_warnings(cscore_${example})
|
||||
|
||||
if (${example} STREQUAL "usbviewer")
|
||||
if(${example} STREQUAL "usbviewer")
|
||||
wpilib_link_macos_gui(cscore_${example})
|
||||
endif()
|
||||
|
||||
@@ -78,48 +80,85 @@ foreach(example ${cscore_examples})
|
||||
endforeach()
|
||||
|
||||
# Java bindings
|
||||
if (WITH_JAVA)
|
||||
if(WITH_JAVA)
|
||||
find_package(Java REQUIRED)
|
||||
find_package(JNI REQUIRED)
|
||||
include(UseJava)
|
||||
set(CMAKE_JAVA_COMPILE_FLAGS "-encoding" "UTF8" "-Xlint:unchecked")
|
||||
|
||||
#find java files, copy them locally
|
||||
|
||||
if("${OPENCV_JAVA_INSTALL_DIR}" STREQUAL "")
|
||||
set(OPENCV_JAVA_INSTALL_DIR ${OpenCV_INSTALL_PATH}/share/OpenCV/java/)
|
||||
set(OPENCV_JAVA_INSTALL_DIR ${OpenCV_INSTALL_PATH}/share/java/opencv4)
|
||||
endif()
|
||||
|
||||
find_file(OPENCV_JAR_FILE NAMES opencv-${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}.jar PATHS ${OPENCV_JAVA_INSTALL_DIR} ${OpenCV_INSTALL_PATH}/bin ${OpenCV_INSTALL_PATH}/share/java NO_DEFAULT_PATH)
|
||||
find_file(OPENCV_JNI_FILE NAMES libopencv_java${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}.so
|
||||
libopencv_java${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}.dylib
|
||||
opencv_java${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}.dll
|
||||
PATHS ${OPENCV_JAVA_INSTALL_DIR} ${OpenCV_INSTALL_PATH}/bin ${OpenCV_INSTALL_PATH}/bin/Release ${OpenCV_INSTALL_PATH}/bin/Debug ${OpenCV_INSTALL_PATH}/lib ${OpenCV_INSTALL_PATH}/lib/jni NO_DEFAULT_PATH)
|
||||
find_file(
|
||||
OPENCV_JAR_FILE
|
||||
NAMES opencv-${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}.jar
|
||||
PATHS
|
||||
${OPENCV_JAVA_INSTALL_DIR}
|
||||
${OpenCV_INSTALL_PATH}/bin
|
||||
${OpenCV_INSTALL_PATH}/share/java
|
||||
${OpenCV_INSTALL_PATH}/share/OpenCV/java
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
find_file(
|
||||
OPENCV_JNI_FILE
|
||||
NAMES
|
||||
libopencv_java${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}.so
|
||||
libopencv_java${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}.dylib
|
||||
opencv_java${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}.dll
|
||||
PATHS
|
||||
${OPENCV_JAVA_INSTALL_DIR}
|
||||
${OpenCV_INSTALL_PATH}/bin
|
||||
${OpenCV_INSTALL_PATH}/bin/Release
|
||||
${OpenCV_INSTALL_PATH}/bin/Debug
|
||||
${OpenCV_INSTALL_PATH}/lib
|
||||
${OpenCV_INSTALL_PATH}/lib/Release
|
||||
${OpenCV_INSTALL_PATH}/lib/Debug
|
||||
${OpenCV_INSTALL_PATH}/lib/jni
|
||||
${OpenCV_INSTALL_PATH}/share/java/opencv4
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
|
||||
file(GLOB
|
||||
cscore_jni_src src/main/native/cpp/jni/CameraServerJNI.cpp)
|
||||
file(GLOB cscore_jni_src src/main/native/cpp/jni/CameraServerJNI.cpp)
|
||||
|
||||
file(GLOB_RECURSE JAVA_SOURCES src/main/java/*.java)
|
||||
set(CMAKE_JNI_TARGET true)
|
||||
|
||||
add_jar(cscore_jar ${JAVA_SOURCES} INCLUDE_JARS wpiutil_jar ${OPENCV_JAR_FILE} OUTPUT_NAME cscore GENERATE_NATIVE_HEADERS cscore_jni_headers)
|
||||
add_jar(
|
||||
cscore_jar
|
||||
${JAVA_SOURCES}
|
||||
INCLUDE_JARS wpiutil_jar ${OPENCV_JAR_FILE}
|
||||
OUTPUT_NAME cscore
|
||||
GENERATE_NATIVE_HEADERS cscore_jni_headers
|
||||
)
|
||||
set_property(TARGET cscore_jar PROPERTY FOLDER "java")
|
||||
|
||||
get_property(CSCORE_JAR_FILE TARGET cscore_jar PROPERTY JAR_FILE)
|
||||
install(FILES ${CSCORE_JAR_FILE} DESTINATION "${java_lib_dest}")
|
||||
install_jar(cscore_jar DESTINATION ${java_lib_dest})
|
||||
install_jar_exports(TARGETS cscore_jar FILE cscore_jar.cmake DESTINATION share/cscore)
|
||||
install(FILES ${OPENCV_JAR_FILE} DESTINATION "${java_lib_dest}")
|
||||
|
||||
if (MSVC)
|
||||
if(MSVC)
|
||||
install(FILES ${OPENCV_JNI_FILE} DESTINATION "${jni_lib_dest}")
|
||||
|
||||
foreach(cvFile ${OpenCV_LIBS})
|
||||
find_file(${cvFile}Loc NAMES ${cvFile}${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}.dll
|
||||
PATHS ${OPENCV_JAVA_INSTALL_DIR} ${OpenCV_INSTALL_PATH}/bin ${OpenCV_INSTALL_PATH}/bin/Release ${OpenCV_INSTALL_PATH}/bin/Debug ${OpenCV_INSTALL_PATH}/lib NO_DEFAULT_PATH)
|
||||
find_file(
|
||||
${cvFile}Loc
|
||||
NAMES
|
||||
${cvFile}${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}.dll
|
||||
${cvFile}${OpenCV_VERSION_MAJOR}${OpenCV_VERSION_MINOR}${OpenCV_VERSION_PATCH}d.dll
|
||||
PATHS
|
||||
${OPENCV_JAVA_INSTALL_DIR}
|
||||
${OpenCV_INSTALL_PATH}/bin
|
||||
${OpenCV_INSTALL_PATH}/bin/Release
|
||||
${OpenCV_INSTALL_PATH}/bin/Debug
|
||||
${OpenCV_INSTALL_PATH}/lib
|
||||
NO_DEFAULT_PATH
|
||||
)
|
||||
install(FILES ${${cvFile}Loc} DESTINATION "${jni_lib_dest}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
set_property(TARGET cscore_jar PROPERTY FOLDER "java")
|
||||
|
||||
add_library(cscorejni ${cscore_jni_src})
|
||||
wpilib_target_warnings(cscorejni)
|
||||
target_link_libraries(cscorejni PUBLIC cscore wpiutil ${OpenCV_LIBS})
|
||||
@@ -130,10 +169,29 @@ if (WITH_JAVA)
|
||||
add_dependencies(cscorejni cscore_jar)
|
||||
|
||||
install(TARGETS cscorejni EXPORT cscorejni)
|
||||
|
||||
export(TARGETS cscorejni FILE cscorejni.cmake NAMESPACE cscorejni::)
|
||||
endif()
|
||||
|
||||
if (WITH_TESTS)
|
||||
if(WITH_JAVA_SOURCE)
|
||||
find_package(Java REQUIRED)
|
||||
include(UseJava)
|
||||
file(GLOB CSCORE_SOURCES src/main/java/edu/wpi/first/cscore/*.java)
|
||||
file(GLOB CSCORE_RAW_SOURCES src/main/java/edu/wpi/first/cscore/raw/*.java)
|
||||
add_jar(
|
||||
cscore_src_jar
|
||||
RESOURCES
|
||||
NAMESPACE "edu/wpi/first/cscore" ${CSCORE_SOURCES}
|
||||
NAMESPACE "edu/wpi/first/cscore/raw" ${CSCORE_RAW_SOURCES}
|
||||
OUTPUT_NAME cscore-sources
|
||||
)
|
||||
|
||||
get_property(CSCORE_SRC_JAR_FILE TARGET cscore_src_jar PROPERTY JAR_FILE)
|
||||
install(FILES ${CSCORE_SRC_JAR_FILE} DESTINATION "${java_lib_dest}")
|
||||
|
||||
set_property(TARGET cscore_src_jar PROPERTY FOLDER "java")
|
||||
endif()
|
||||
|
||||
if(WITH_TESTS)
|
||||
wpilib_add_test(cscore src/test/native/cpp)
|
||||
target_link_libraries(cscore_test cscore gmock)
|
||||
endif()
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
include(CMakeFindDependencyMacro)
|
||||
@FILENAME_DEP_REPLACE@
|
||||
@WPIUTIL_DEP_REPLACE@
|
||||
@WPINET_DEP_REPLACE@
|
||||
find_dependency(OpenCV)
|
||||
|
||||
@FILENAME_DEP_REPLACE@
|
||||
include(${SELF_DIR}/cscore.cmake)
|
||||
if(@WITH_JAVA@)
|
||||
include(${SELF_DIR}/cscore_jar.cmake)
|
||||
endif()
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <wpi/print.h>
|
||||
|
||||
#include "cscore.h"
|
||||
|
||||
@@ -12,11 +12,11 @@ int main() {
|
||||
CS_Status status = 0;
|
||||
|
||||
for (const auto& caminfo : cs::EnumerateUsbCameras(&status)) {
|
||||
fmt::print("{}: {} ({})\n", caminfo.dev, caminfo.path, caminfo.name);
|
||||
wpi::print("{}: {} ({})\n", caminfo.dev, caminfo.path, caminfo.name);
|
||||
if (!caminfo.otherPaths.empty()) {
|
||||
std::puts("Other device paths:");
|
||||
for (auto&& path : caminfo.otherPaths) {
|
||||
fmt::print(" {}\n", path);
|
||||
wpi::print(" {}\n", path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,26 +24,26 @@ int main() {
|
||||
|
||||
std::puts("Properties:");
|
||||
for (const auto& prop : camera.EnumerateProperties()) {
|
||||
fmt::print(" {}", prop.GetName());
|
||||
wpi::print(" {}", prop.GetName());
|
||||
switch (prop.GetKind()) {
|
||||
case cs::VideoProperty::kBoolean:
|
||||
fmt::print(" (bool): value={} default={}", prop.Get(),
|
||||
wpi::print(" (bool): value={} default={}", prop.Get(),
|
||||
prop.GetDefault());
|
||||
break;
|
||||
case cs::VideoProperty::kInteger:
|
||||
fmt::print(" (int): value={} min={} max={} step={} default={}",
|
||||
wpi::print(" (int): value={} min={} max={} step={} default={}",
|
||||
prop.Get(), prop.GetMin(), prop.GetMax(), prop.GetStep(),
|
||||
prop.GetDefault());
|
||||
break;
|
||||
case cs::VideoProperty::kString:
|
||||
fmt::print(" (string): {}", prop.GetString());
|
||||
wpi::print(" (string): {}", prop.GetString());
|
||||
break;
|
||||
case cs::VideoProperty::kEnum: {
|
||||
fmt::print(" (enum): value={}", prop.Get());
|
||||
wpi::print(" (enum): value={}", prop.Get());
|
||||
auto choices = prop.GetChoices();
|
||||
for (size_t i = 0; i < choices.size(); ++i) {
|
||||
if (!choices[i].empty()) {
|
||||
fmt::print("\n {}: {}", i, choices[i]);
|
||||
wpi::print("\n {}: {}", i, choices[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -71,7 +71,7 @@ int main() {
|
||||
pixelFormat = "Unknown";
|
||||
break;
|
||||
}
|
||||
fmt::print(" PixelFormat:{} Width:{} Height:{} FPS:{}\n", pixelFormat,
|
||||
wpi::print(" PixelFormat:{} Width:{} Height:{} FPS:{}\n", pixelFormat,
|
||||
mode.width, mode.height, mode.fps);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <wpi/print.h>
|
||||
|
||||
#include "cscore.h"
|
||||
#include "cscore_cv.h"
|
||||
@@ -24,10 +24,10 @@ int main() {
|
||||
for (;;) {
|
||||
uint64_t time = cvsink.GrabFrame(test);
|
||||
if (time == 0) {
|
||||
fmt::print("error: {}\n", cvsink.GetError());
|
||||
wpi::print("error: {}\n", cvsink.GetError());
|
||||
continue;
|
||||
}
|
||||
fmt::print("got frame at time {} size ({}, {})\n", time, test.size().width,
|
||||
wpi::print("got frame at time {} size ({}, {})\n", time, test.size().width,
|
||||
test.size().height);
|
||||
cv::flip(test, flip, 0);
|
||||
cvsource.PutFrame(flip);
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
#include <cstdio>
|
||||
#include <thread>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <wpi/StringExtras.h>
|
||||
#include <wpi/print.h>
|
||||
|
||||
#include "cscore.h"
|
||||
|
||||
@@ -73,26 +73,26 @@ int main(int argc, char** argv) {
|
||||
// Print settings
|
||||
std::puts("Properties:");
|
||||
for (const auto& prop : camera.EnumerateProperties()) {
|
||||
fmt::print(" {}", prop.GetName());
|
||||
wpi::print(" {}", prop.GetName());
|
||||
switch (prop.GetKind()) {
|
||||
case cs::VideoProperty::kBoolean:
|
||||
fmt::print(" (bool): value={} default={}", prop.Get(),
|
||||
wpi::print(" (bool): value={} default={}", prop.Get(),
|
||||
prop.GetDefault());
|
||||
break;
|
||||
case cs::VideoProperty::kInteger:
|
||||
fmt::print(" (int): value={} min={} max={} step={} default={}",
|
||||
wpi::print(" (int): value={} min={} max={} step={} default={}",
|
||||
prop.Get(), prop.GetMin(), prop.GetMax(), prop.GetStep(),
|
||||
prop.GetDefault());
|
||||
break;
|
||||
case cs::VideoProperty::kString:
|
||||
fmt::print(" (string): {}", prop.GetString());
|
||||
wpi::print(" (string): {}", prop.GetString());
|
||||
break;
|
||||
case cs::VideoProperty::kEnum: {
|
||||
fmt::print(" (enum): value={}", prop.Get());
|
||||
wpi::print(" (enum): value={}", prop.Get());
|
||||
auto choices = prop.GetChoices();
|
||||
for (size_t i = 0; i < choices.size(); ++i) {
|
||||
if (!choices[i].empty()) {
|
||||
fmt::print("\n {}: {}", i, choices[i]);
|
||||
wpi::print("\n {}: {}", i, choices[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <wpi/print.h>
|
||||
|
||||
#include "cscore.h"
|
||||
#include "cscore_cv.h"
|
||||
@@ -24,10 +24,10 @@ int main() {
|
||||
for (;;) {
|
||||
uint64_t time = cvsink.GrabFrame(test);
|
||||
if (time == 0) {
|
||||
fmt::print("error: {}\n", cvsink.GetError());
|
||||
wpi::print("error: {}\n", cvsink.GetError());
|
||||
continue;
|
||||
}
|
||||
fmt::print("got frame at time {} size ({}, {})\n", time, test.size().width,
|
||||
wpi::print("got frame at time {} size ({}, {})\n", time, test.size().width,
|
||||
test.size().height);
|
||||
cv::flip(test, flip, 0);
|
||||
cvsource.PutFrame(flip);
|
||||
|
||||
@@ -4,15 +4,15 @@
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <wpi/print.h>
|
||||
|
||||
#include "cscore.h"
|
||||
|
||||
int main() {
|
||||
fmt::print("hostname: {}\n", cs::GetHostname());
|
||||
wpi::print("hostname: {}\n", cs::GetHostname());
|
||||
std::puts("IPv4 network addresses:");
|
||||
for (const auto& addr : cs::GetNetworkInterfaces()) {
|
||||
fmt::print(" {}\n", addr);
|
||||
wpi::print(" {}\n", addr);
|
||||
}
|
||||
cs::UsbCamera camera{"usbcam", 0};
|
||||
camera.SetVideoMode(cs::VideoMode::kMJPEG, 320, 240, 30);
|
||||
@@ -22,7 +22,7 @@ int main() {
|
||||
CS_Status status = 0;
|
||||
cs::AddListener(
|
||||
[&](const cs::RawEvent& event) {
|
||||
fmt::print("FPS={} MBPS={}\n", camera.GetActualFPS(),
|
||||
wpi::print("FPS={} MBPS={}\n", camera.GetActualFPS(),
|
||||
(camera.GetActualDataRate() / 1000000.0));
|
||||
},
|
||||
cs::RawEvent::kTelemetryUpdated, false, &status);
|
||||
|
||||
@@ -6,13 +6,12 @@
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/imgproc.hpp>
|
||||
#include <wpi/print.h>
|
||||
#include <wpi/spinlock.h>
|
||||
#include <wpigui.h>
|
||||
|
||||
@@ -39,7 +38,7 @@ int main() {
|
||||
// get frame from camera
|
||||
uint64_t time = cvsink.GrabFrame(frame);
|
||||
if (time == 0) {
|
||||
fmt::print("error: {}\n", cvsink.GetError());
|
||||
wpi::print("error: {}\n", cvsink.GetError());
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,22 +20,12 @@ public class RawCVMatSink extends ImageSink {
|
||||
int bgrValue = PixelFormat.kBGR.getValue();
|
||||
|
||||
private int getCVFormat(PixelFormat pixelFormat) {
|
||||
int type = 0;
|
||||
switch (pixelFormat) {
|
||||
case kYUYV:
|
||||
case kRGB565:
|
||||
type = CvType.CV_8UC2;
|
||||
break;
|
||||
case kBGR:
|
||||
type = CvType.CV_8UC3;
|
||||
break;
|
||||
case kGray:
|
||||
case kMJPEG:
|
||||
default:
|
||||
type = CvType.CV_8UC1;
|
||||
break;
|
||||
}
|
||||
return type;
|
||||
return switch (pixelFormat) {
|
||||
case kYUYV, kRGB565, kY16, kUYVY -> CvType.CV_8UC2;
|
||||
case kBGR -> CvType.CV_8UC3;
|
||||
case kBGRA -> CvType.CV_8UC4;
|
||||
case kGray, kMJPEG, kUnknown -> CvType.CV_8UC1;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
|
||||
package edu.wpi.first.cscore;
|
||||
|
||||
import edu.wpi.first.util.RuntimeDetector;
|
||||
import edu.wpi.first.util.CombinedRuntimeLoader;
|
||||
|
||||
public final class DevMain {
|
||||
/** Main method. */
|
||||
public static void main(String[] args) {
|
||||
System.out.println("Hello World!");
|
||||
System.out.println(RuntimeDetector.getPlatformPath());
|
||||
System.out.println(CombinedRuntimeLoader.getPlatformPath());
|
||||
System.out.println(CameraServerJNI.getHostname());
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <wpi/print.h>
|
||||
|
||||
#include "cscore.h"
|
||||
|
||||
int main() {
|
||||
fmt::print("{}\n", cs::GetHostname());
|
||||
wpi::print("{}\n", cs::GetHostname());
|
||||
}
|
||||
|
||||
@@ -4,7 +4,12 @@
|
||||
|
||||
package edu.wpi.first.cscore;
|
||||
|
||||
/** A source that represents an Axis IP camera. */
|
||||
/**
|
||||
* A source that represents an Axis IP camera.
|
||||
*
|
||||
* @deprecated Use HttpCamera instead.
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "2025")
|
||||
public class AxisCamera extends HttpCamera {
|
||||
private static String hostToUrl(String host) {
|
||||
return "http://" + host + "/mjpg/video.mjpg";
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.cscore;
|
||||
|
||||
import edu.wpi.first.util.RuntimeLoader;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import org.opencv.core.Core;
|
||||
|
||||
public class CameraServerCvJNI {
|
||||
static boolean libraryLoaded = false;
|
||||
|
||||
static RuntimeLoader<Core> loader = null;
|
||||
|
||||
public static class Helper {
|
||||
private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true);
|
||||
|
||||
public static boolean getExtractOnStaticLoad() {
|
||||
return extractOnStaticLoad.get();
|
||||
}
|
||||
|
||||
public static void setExtractOnStaticLoad(boolean load) {
|
||||
extractOnStaticLoad.set(load);
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
String opencvName = Core.NATIVE_LIBRARY_NAME;
|
||||
if (Helper.getExtractOnStaticLoad()) {
|
||||
try {
|
||||
CameraServerJNI.forceLoad();
|
||||
loader =
|
||||
new RuntimeLoader<>(opencvName, RuntimeLoader.getDefaultExtractionRoot(), Core.class);
|
||||
loader.loadLibraryHashed();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
libraryLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Force load the library.
|
||||
*
|
||||
* @throws IOException if library load failed
|
||||
*/
|
||||
public static synchronized void forceLoad() throws IOException {
|
||||
if (libraryLoaded) {
|
||||
return;
|
||||
}
|
||||
CameraServerJNI.forceLoad();
|
||||
loader =
|
||||
new RuntimeLoader<>(
|
||||
Core.NATIVE_LIBRARY_NAME, RuntimeLoader.getDefaultExtractionRoot(), Core.class);
|
||||
loader.loadLibrary();
|
||||
libraryLoaded = true;
|
||||
}
|
||||
|
||||
public static native int createCvSource(
|
||||
String name, int pixelFormat, int width, int height, int fps);
|
||||
|
||||
public static native void putSourceFrame(int source, long imageNativeObj);
|
||||
|
||||
public static native int createCvSink(String name);
|
||||
|
||||
// public static native int createCvSinkCallback(String name,
|
||||
// void (*processFrame)(long time));
|
||||
|
||||
public static native long grabSinkFrame(int sink, long imageNativeObj);
|
||||
|
||||
public static native long grabSinkFrameTimeout(int sink, long imageNativeObj, double timeout);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,10 @@
|
||||
|
||||
package edu.wpi.first.cscore;
|
||||
|
||||
import edu.wpi.first.util.PixelFormat;
|
||||
import edu.wpi.first.util.RawFrame;
|
||||
import java.nio.ByteBuffer;
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
|
||||
/**
|
||||
@@ -11,32 +15,57 @@ import org.opencv.core.Mat;
|
||||
* OpenCV builds. For an alternate OpenCV, see the documentation how to build your own with RawSink.
|
||||
*/
|
||||
public class CvSink extends ImageSink {
|
||||
private final RawFrame m_frame = new RawFrame();
|
||||
private Mat m_tmpMat;
|
||||
private ByteBuffer m_origByteBuffer;
|
||||
private int m_width;
|
||||
private int m_height;
|
||||
private PixelFormat m_pixelFormat;
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (m_tmpMat != null) {
|
||||
m_tmpMat.release();
|
||||
}
|
||||
m_frame.close();
|
||||
super.close();
|
||||
}
|
||||
|
||||
private int getCVFormat(PixelFormat pixelFormat) {
|
||||
return switch (pixelFormat) {
|
||||
case kYUYV, kRGB565, kY16, kUYVY -> CvType.CV_8UC2;
|
||||
case kBGR -> CvType.CV_8UC3;
|
||||
case kBGRA -> CvType.CV_8UC4;
|
||||
case kGray, kMJPEG, kUnknown -> CvType.CV_8UC1;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a sink for accepting OpenCV images. grabFrame() must be called on the created sink to
|
||||
* get each new image.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
* @param pixelFormat Source pixel format
|
||||
*/
|
||||
public CvSink(String name, PixelFormat pixelFormat) {
|
||||
super(CameraServerJNI.createRawSink(name, true));
|
||||
m_pixelFormat = pixelFormat;
|
||||
OpenCvLoader.forceStaticLoad();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a sink for accepting OpenCV images. WaitForFrame() must be called on the created sink to
|
||||
* get each new image.
|
||||
* get each new image. Defaults to kBGR for pixelFormat
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
*/
|
||||
public CvSink(String name) {
|
||||
super(CameraServerCvJNI.createCvSink(name));
|
||||
this(name, PixelFormat.kBGR);
|
||||
}
|
||||
|
||||
/// Create a sink for accepting OpenCV images in a separate thread.
|
||||
/// A thread will be created that calls WaitForFrame() and calls the
|
||||
/// processFrame() callback each time a new frame arrives.
|
||||
/// @param name Source name (arbitrary unique identifier)
|
||||
/// @param processFrame Frame processing function; will be called with a
|
||||
/// time=0 if an error occurred. processFrame should call GetImage()
|
||||
/// or GetError() as needed, but should not call (except in very
|
||||
/// unusual circumstances) WaitForImage().
|
||||
// public CvSink(wpi::StringRef name,
|
||||
// std::function<void(uint64_t time)> processFrame) {
|
||||
// super(CameraServerJNI.createCvSinkCallback(name, processFrame));
|
||||
// }
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image. Times out (returning 0) after 0.225 seconds. The
|
||||
* provided image will have three 3-bit channels stored in BGR order.
|
||||
* provided image will have the pixelFormat this class was constructed with.
|
||||
*
|
||||
* @param image Where to store the image.
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error message)
|
||||
@@ -47,7 +76,7 @@ public class CvSink extends ImageSink {
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image. Times out (returning 0) after timeout seconds. The
|
||||
* provided image will have three 3-bit channels stored in BGR order.
|
||||
* provided image will have the pixelFormat this class was constructed with.
|
||||
*
|
||||
* @param image Where to store the image.
|
||||
* @param timeout Retrieval timeout in seconds.
|
||||
@@ -55,18 +84,140 @@ public class CvSink extends ImageSink {
|
||||
* is in 1 us increments.
|
||||
*/
|
||||
public long grabFrame(Mat image, double timeout) {
|
||||
return CameraServerCvJNI.grabSinkFrameTimeout(m_handle, image.nativeObj, timeout);
|
||||
long rv = grabFrameDirect(timeout);
|
||||
if (rv <= 0) {
|
||||
return rv;
|
||||
}
|
||||
m_tmpMat.copyTo(image);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the next frame and get the image. May block forever. The provided image will have
|
||||
* three 3-bit channels stored in BGR order.
|
||||
* Wait for the next frame and get the image. May block forever. The provided image will have the
|
||||
* pixelFormat this class was constructed with.
|
||||
*
|
||||
* @param image Where to store the image.
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error message); the frame time
|
||||
* is in 1 us increments.
|
||||
*/
|
||||
public long grabFrameNoTimeout(Mat image) {
|
||||
return CameraServerCvJNI.grabSinkFrame(m_handle, image.nativeObj);
|
||||
long rv = grabFrameNoTimeoutDirect();
|
||||
if (rv <= 0) {
|
||||
return rv;
|
||||
}
|
||||
m_tmpMat.copyTo(image);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the direct backing mat for this sink.
|
||||
*
|
||||
* <p>This mat can be invalidated any time any of the grab* methods are called, or when the CvSink
|
||||
* is closed.
|
||||
*
|
||||
* @return The backing mat.
|
||||
*/
|
||||
public Mat getDirectMat() {
|
||||
return m_tmpMat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the next frame and store the image. Times out (returning 0) after 0.225 seconds. The
|
||||
* provided image will have the pixelFormat this class was constructed with. Use getDirectMat() to
|
||||
* grab the image.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error message)
|
||||
*/
|
||||
public long grabFrameDirect() {
|
||||
return grabFrameDirect(0.225);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the next frame and store the image. Times out (returning 0) after timeout seconds. The
|
||||
* provided image will have the pixelFormat this class was constructed with. Use getDirectMat() to
|
||||
* grab the image.
|
||||
*
|
||||
* @param timeout Retrieval timeout in seconds.
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error message); the frame time
|
||||
* is in 1 us increments.
|
||||
*/
|
||||
@SuppressWarnings("PMD.CompareObjectsWithEquals")
|
||||
public long grabFrameDirect(double timeout) {
|
||||
m_frame.setInfo(0, 0, 0, m_pixelFormat);
|
||||
long rv =
|
||||
CameraServerJNI.grabRawSinkFrameTimeout(m_handle, m_frame, m_frame.getNativeObj(), timeout);
|
||||
if (rv <= 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (m_frame.getData() != m_origByteBuffer
|
||||
|| m_width != m_frame.getWidth()
|
||||
|| m_height != m_frame.getHeight()
|
||||
|| m_pixelFormat != m_frame.getPixelFormat()) {
|
||||
m_origByteBuffer = m_frame.getData();
|
||||
m_height = m_frame.getHeight();
|
||||
m_width = m_frame.getWidth();
|
||||
m_pixelFormat = m_frame.getPixelFormat();
|
||||
if (m_frame.getStride() == 0) {
|
||||
m_tmpMat =
|
||||
new Mat(
|
||||
m_frame.getHeight(),
|
||||
m_frame.getWidth(),
|
||||
getCVFormat(m_pixelFormat),
|
||||
m_origByteBuffer);
|
||||
} else {
|
||||
m_tmpMat =
|
||||
new Mat(
|
||||
m_frame.getHeight(),
|
||||
m_frame.getWidth(),
|
||||
getCVFormat(m_pixelFormat),
|
||||
m_origByteBuffer,
|
||||
m_frame.getStride());
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for the next frame and store the image. May block forever. The provided image will have
|
||||
* the pixelFormat this class was constructed with. Use getDirectMat() to grab the image.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error message); the frame time
|
||||
* is in 1 us increments.
|
||||
*/
|
||||
@SuppressWarnings("PMD.CompareObjectsWithEquals")
|
||||
public long grabFrameNoTimeoutDirect() {
|
||||
m_frame.setInfo(0, 0, 0, m_pixelFormat);
|
||||
long rv = CameraServerJNI.grabRawSinkFrame(m_handle, m_frame, m_frame.getNativeObj());
|
||||
if (rv <= 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (m_frame.getData() != m_origByteBuffer
|
||||
|| m_width != m_frame.getWidth()
|
||||
|| m_height != m_frame.getHeight()
|
||||
|| m_pixelFormat != m_frame.getPixelFormat()) {
|
||||
m_origByteBuffer = m_frame.getData();
|
||||
m_height = m_frame.getHeight();
|
||||
m_width = m_frame.getWidth();
|
||||
m_pixelFormat = m_frame.getPixelFormat();
|
||||
if (m_frame.getStride() == 0) {
|
||||
m_tmpMat =
|
||||
new Mat(
|
||||
m_frame.getHeight(),
|
||||
m_frame.getWidth(),
|
||||
getCVFormat(m_pixelFormat),
|
||||
m_origByteBuffer);
|
||||
} else {
|
||||
m_tmpMat =
|
||||
new Mat(
|
||||
m_frame.getHeight(),
|
||||
m_frame.getWidth(),
|
||||
getCVFormat(m_pixelFormat),
|
||||
m_origByteBuffer,
|
||||
m_frame.getStride());
|
||||
}
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
package edu.wpi.first.cscore;
|
||||
|
||||
import edu.wpi.first.util.PixelFormat;
|
||||
import org.opencv.core.Mat;
|
||||
|
||||
/**
|
||||
@@ -19,8 +20,9 @@ public class CvSource extends ImageSource {
|
||||
*/
|
||||
public CvSource(String name, VideoMode mode) {
|
||||
super(
|
||||
CameraServerCvJNI.createCvSource(
|
||||
name, mode.pixelFormat.getValue(), mode.width, mode.height, mode.fps));
|
||||
CameraServerJNI.createRawSource(
|
||||
name, true, mode.pixelFormat.getValue(), mode.width, mode.height, mode.fps));
|
||||
OpenCvLoader.forceStaticLoad();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -32,20 +34,141 @@ public class CvSource extends ImageSource {
|
||||
* @param height height
|
||||
* @param fps fps
|
||||
*/
|
||||
public CvSource(String name, VideoMode.PixelFormat pixelFormat, int width, int height, int fps) {
|
||||
super(CameraServerCvJNI.createCvSource(name, pixelFormat.getValue(), width, height, fps));
|
||||
public CvSource(String name, PixelFormat pixelFormat, int width, int height, int fps) {
|
||||
super(CameraServerJNI.createRawSource(name, true, pixelFormat.getValue(), width, height, fps));
|
||||
OpenCvLoader.forceStaticLoad();
|
||||
}
|
||||
|
||||
/**
|
||||
* Put an OpenCV image and notify sinks
|
||||
*
|
||||
* <p>The image format is guessed from the number of channels. The channel mapping is as follows.
|
||||
* 1: kGray 2: kYUYV 3: BGR 4: BGRA Any other channel numbers will throw an error. If your image
|
||||
* is an in alternate format, use the overload that takes a PixelFormat.
|
||||
*
|
||||
* @param image OpenCV Image
|
||||
*/
|
||||
public void putFrame(Mat image) {
|
||||
// We only support 8 bit channels
|
||||
boolean cleanupRequired = false;
|
||||
Mat finalImage;
|
||||
if (image.depth() == 0) {
|
||||
finalImage = image;
|
||||
} else {
|
||||
finalImage = new Mat();
|
||||
image.convertTo(finalImage, 0);
|
||||
cleanupRequired = true;
|
||||
}
|
||||
|
||||
try {
|
||||
int channels = finalImage.channels();
|
||||
PixelFormat format =
|
||||
switch (channels) {
|
||||
case 1 -> PixelFormat.kGray; // 1 channel is assumed Grayscale
|
||||
case 2 -> PixelFormat.kYUYV; // 2 channels is assumed YUYV
|
||||
case 3 -> PixelFormat.kBGR; // 3 channels is assumed BGR
|
||||
case 4 -> PixelFormat.kBGRA; // 4 channels is assumed BGRA
|
||||
default -> throw new VideoException(
|
||||
"Unable to get pixel format for " + channels + " channels");
|
||||
};
|
||||
|
||||
putFrame(finalImage, format, true);
|
||||
} finally {
|
||||
if (cleanupRequired) {
|
||||
finalImage.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Put an OpenCV image and notify sinks.
|
||||
*
|
||||
* <p>Only 8-bit single-channel or 3-channel (with BGR channel order) images are supported. If the
|
||||
* format, depth or channel order is different, use Mat.convertTo() and/or cvtColor() to convert
|
||||
* it first.
|
||||
* <p>The format of the Mat must match the PixelFormat. You will corrupt memory if they dont. With
|
||||
* skipVerification false, we will verify the number of channels matches the pixel format. If
|
||||
* skipVerification is true, this step is skipped and is passed straight through.
|
||||
*
|
||||
* @param image OpenCV image
|
||||
* @param format The pixel format of the image
|
||||
* @param skipVerification skip verifying pixel format
|
||||
*/
|
||||
public void putFrame(Mat image) {
|
||||
CameraServerCvJNI.putSourceFrame(m_handle, image.nativeObj);
|
||||
public void putFrame(Mat image, PixelFormat format, boolean skipVerification) {
|
||||
// We only support 8-bit images, convert if necessary
|
||||
boolean cleanupRequired = false;
|
||||
Mat finalImage;
|
||||
if (image.depth() == 0) {
|
||||
finalImage = image;
|
||||
} else {
|
||||
finalImage = new Mat();
|
||||
image.convertTo(finalImage, 0);
|
||||
cleanupRequired = true;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!skipVerification) {
|
||||
verifyFormat(finalImage, format);
|
||||
}
|
||||
long step = image.step1() * image.elemSize1();
|
||||
CameraServerJNI.putRawSourceFrameData(
|
||||
m_handle,
|
||||
finalImage.dataAddr(),
|
||||
(int) finalImage.total() * finalImage.channels(),
|
||||
finalImage.width(),
|
||||
finalImage.height(),
|
||||
(int) step,
|
||||
format.getValue());
|
||||
|
||||
} finally {
|
||||
if (cleanupRequired) {
|
||||
finalImage.release();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyFormat(Mat image, PixelFormat pixelFormat) {
|
||||
int channels = image.channels();
|
||||
switch (pixelFormat) {
|
||||
case kBGR:
|
||||
if (channels == 3) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case kBGRA:
|
||||
if (channels == 4) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case kGray:
|
||||
if (channels == 1) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case kRGB565:
|
||||
if (channels == 2) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case kUYVY:
|
||||
if (channels == 2) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case kY16:
|
||||
if (channels == 2) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case kYUYV:
|
||||
if (channels == 2) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case kMJPEG:
|
||||
if (channels == 1) {
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,15 @@ package edu.wpi.first.cscore;
|
||||
|
||||
/** A source that represents a MJPEG-over-HTTP (IP) camera. */
|
||||
public class HttpCamera extends VideoCamera {
|
||||
/** HTTP camera kind. */
|
||||
public enum HttpCameraKind {
|
||||
/** Unknown camera kind. */
|
||||
kUnknown(0),
|
||||
/** MJPG Streamer camera. */
|
||||
kMJPGStreamer(1),
|
||||
/** CS Core camera. */
|
||||
kCSCore(2),
|
||||
/** Axis camera. */
|
||||
kAxis(3);
|
||||
|
||||
private final int value;
|
||||
@@ -18,6 +23,11 @@ public class HttpCamera extends VideoCamera {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns HttpCameraKind value.
|
||||
*
|
||||
* @return HttpCameraKind value.
|
||||
*/
|
||||
public int getValue() {
|
||||
return value;
|
||||
}
|
||||
@@ -30,16 +40,12 @@ public class HttpCamera extends VideoCamera {
|
||||
* @return The kind
|
||||
*/
|
||||
public static HttpCameraKind getHttpCameraKindFromInt(int kind) {
|
||||
switch (kind) {
|
||||
case 1:
|
||||
return HttpCameraKind.kMJPGStreamer;
|
||||
case 2:
|
||||
return HttpCameraKind.kCSCore;
|
||||
case 3:
|
||||
return HttpCameraKind.kAxis;
|
||||
default:
|
||||
return HttpCameraKind.kUnknown;
|
||||
}
|
||||
return switch (kind) {
|
||||
case 1 -> HttpCameraKind.kMJPGStreamer;
|
||||
case 2 -> HttpCameraKind.kCSCore;
|
||||
case 3 -> HttpCameraKind.kAxis;
|
||||
default -> HttpCameraKind.kUnknown;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,7 +4,13 @@
|
||||
|
||||
package edu.wpi.first.cscore;
|
||||
|
||||
/** A base class for single image reading sinks. */
|
||||
public abstract class ImageSink extends VideoSink {
|
||||
/**
|
||||
* Constructs an ImageSink.
|
||||
*
|
||||
* @param handle The image sink handle.
|
||||
*/
|
||||
protected ImageSink(int handle) {
|
||||
super(handle);
|
||||
}
|
||||
|
||||
@@ -4,7 +4,13 @@
|
||||
|
||||
package edu.wpi.first.cscore;
|
||||
|
||||
/** A base class for single image providing sources. */
|
||||
public abstract class ImageSource extends VideoSource {
|
||||
/**
|
||||
* Constructs an ImageSource.
|
||||
*
|
||||
* @param handle The image source handle.
|
||||
*/
|
||||
protected ImageSource(int handle) {
|
||||
super(handle);
|
||||
}
|
||||
|
||||
79
cscore/src/main/java/edu/wpi/first/cscore/OpenCvLoader.java
Normal file
79
cscore/src/main/java/edu/wpi/first/cscore/OpenCvLoader.java
Normal file
@@ -0,0 +1,79 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
package edu.wpi.first.cscore;
|
||||
|
||||
import edu.wpi.first.util.RuntimeLoader;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import org.opencv.core.Core;
|
||||
|
||||
/** OpenCV Native Loader. */
|
||||
public final class OpenCvLoader {
|
||||
@SuppressWarnings("PMD.MutableStaticState")
|
||||
static boolean libraryLoaded;
|
||||
|
||||
/** Sets whether JNI should be loaded in the static block. */
|
||||
public static final class Helper {
|
||||
private static AtomicBoolean extractOnStaticLoad = new AtomicBoolean(true);
|
||||
|
||||
/**
|
||||
* Returns true if the JNI should be loaded in the static block.
|
||||
*
|
||||
* @return True if the JNI should be loaded in the static block.
|
||||
*/
|
||||
public static boolean getExtractOnStaticLoad() {
|
||||
return extractOnStaticLoad.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the JNI should be loaded in the static block.
|
||||
*
|
||||
* @param load Whether the JNI should be loaded in the static block.
|
||||
*/
|
||||
public static void setExtractOnStaticLoad(boolean load) {
|
||||
extractOnStaticLoad.set(load);
|
||||
}
|
||||
|
||||
/** Utility class. */
|
||||
private Helper() {}
|
||||
}
|
||||
|
||||
static {
|
||||
if (Helper.getExtractOnStaticLoad()) {
|
||||
try {
|
||||
RuntimeLoader.loadLibrary(Core.NATIVE_LIBRARY_NAME);
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
libraryLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces a static load.
|
||||
*
|
||||
* @return a garbage value
|
||||
*/
|
||||
public static int forceStaticLoad() {
|
||||
return libraryLoaded ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force load the library.
|
||||
*
|
||||
* @throws IOException if library load failed
|
||||
*/
|
||||
public static synchronized void forceLoad() throws IOException {
|
||||
if (libraryLoaded) {
|
||||
return;
|
||||
}
|
||||
RuntimeLoader.loadLibrary(Core.NATIVE_LIBRARY_NAME);
|
||||
libraryLoaded = true;
|
||||
}
|
||||
|
||||
/** Utility class. */
|
||||
private OpenCvLoader() {}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user