mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-20 00:51:42 +00:00
Compare commits
1100 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f4265facc | ||
|
|
63d1fb3bed | ||
|
|
36af6d25a5 | ||
|
|
8f387f7255 | ||
|
|
792e735e08 | ||
|
|
3b76de83eb | ||
|
|
ad9f738cfa | ||
|
|
49455199e5 | ||
|
|
64426502ea | ||
|
|
8cc112d196 | ||
|
|
e78cd49861 | ||
|
|
cfb4f756d6 | ||
|
|
ba0908216c | ||
|
|
a3a0334fad | ||
|
|
cf7460c3a8 | ||
|
|
db0fbb6448 | ||
|
|
8ac45f20bb | ||
|
|
b3707cca0b | ||
|
|
a69ee3ece9 | ||
|
|
750d9a30c9 | ||
|
|
41c5b2b5ac | ||
|
|
6cf3f9b28e | ||
|
|
269cf03472 | ||
|
|
5ccfc4adbd | ||
|
|
b6f44f98be | ||
|
|
0dca57e9ec | ||
|
|
22c4da152e | ||
|
|
05d66f862d | ||
|
|
b09f5b2cf2 | ||
|
|
a2510aaa0e | ||
|
|
947f589916 | ||
|
|
bbd8980a20 | ||
|
|
831052f118 | ||
|
|
c137569f91 | ||
|
|
dae61226fa | ||
|
|
3ad4594a88 | ||
|
|
112acb9a62 | ||
|
|
ecee224e81 | ||
|
|
a3645dea34 | ||
|
|
7c09f44898 | ||
|
|
f401ea9aae | ||
|
|
bf8517f1e6 | ||
|
|
528087e308 | ||
|
|
1f59ff72f9 | ||
|
|
315be873c4 | ||
|
|
b8d019cdb4 | ||
|
|
102f23bbdb | ||
|
|
b85c24a79c | ||
|
|
eee29daaf9 | ||
|
|
aa9dfabde2 | ||
|
|
5999a26fba | ||
|
|
1e82595ffb | ||
|
|
e373fa476b | ||
|
|
dceb5364f4 | ||
|
|
baacbc8e24 | ||
|
|
84b15f0883 | ||
|
|
c0da9d2d35 | ||
|
|
0fe0be2733 | ||
|
|
eafa947338 | ||
|
|
9d13ae8d01 | ||
|
|
2a64e4bae5 | ||
|
|
c3fd20db59 | ||
|
|
6f91f37cd0 | ||
|
|
5158730b81 | ||
|
|
2ad2d2ca96 | ||
|
|
b5fd29774f | ||
|
|
9f8f330e96 | ||
|
|
1ad3b1b333 | ||
|
|
dfc24425c3 | ||
|
|
c02577bb51 | ||
|
|
c9e6a96a61 | ||
|
|
9778626f34 | ||
|
|
34b2d0dae1 | ||
|
|
59a7528fd6 | ||
|
|
11d9859ef1 | ||
|
|
e44ed752ad | ||
|
|
52b2dd5b89 | ||
|
|
c46636f218 | ||
|
|
dc531462e1 | ||
|
|
92ba98621c | ||
|
|
d41d051f1b | ||
|
|
c5ae0effac | ||
|
|
b3974c6ed3 | ||
|
|
589a00e379 | ||
|
|
8d9836ca02 | ||
|
|
8b5bf8632e | ||
|
|
1846114491 | ||
|
|
2c461c794e | ||
|
|
109363daa4 | ||
|
|
41d26bee8d | ||
|
|
7269a170fb | ||
|
|
441f2ed9b0 | ||
|
|
15275433d4 | ||
|
|
1ac02d2f58 | ||
|
|
8ee6257e92 | ||
|
|
d81ef2bc5c | ||
|
|
acb64dff97 | ||
|
|
3f6cf76a8c | ||
|
|
3ef2dab465 | ||
|
|
a5a56dd067 | ||
|
|
04957a6d30 | ||
|
|
5da54888f8 | ||
|
|
6c93365b0f | ||
|
|
1c4a8bfb66 | ||
|
|
d51a1d3b3d | ||
|
|
aced2e7da6 | ||
|
|
fa1ceca83a | ||
|
|
0ea05d34e6 | ||
|
|
09db4f672b | ||
|
|
4ba80a3a8c | ||
|
|
ae208d2b17 | ||
|
|
6f51cb3b98 | ||
|
|
f6159ee1a2 | ||
|
|
7f401ae895 | ||
|
|
0587b7043a | ||
|
|
0bbf51d566 | ||
|
|
92c6eae6b0 | ||
|
|
141354cd79 | ||
|
|
f6e9fc7d71 | ||
|
|
d8418be7d1 | ||
|
|
82066946e5 | ||
|
|
4b1defc8d8 | ||
|
|
da90c1cd2c | ||
|
|
3aa54fa027 | ||
|
|
b156db400d | ||
|
|
9aba2b7583 | ||
|
|
a9931223f0 | ||
|
|
aacf9442e4 | ||
|
|
7db10ecf00 | ||
|
|
a0a5b2aea5 | ||
|
|
eb835598a4 | ||
|
|
f0ab6df5b6 | ||
|
|
075144faa3 | ||
|
|
32468a40cb | ||
|
|
38611e9dd7 | ||
|
|
4d78def31e | ||
|
|
3be0c1217a | ||
|
|
42d3a50aa2 | ||
|
|
52f1464029 | ||
|
|
68ce62e2e9 | ||
|
|
3dd41c0d37 | ||
|
|
7699a1f827 | ||
|
|
e473a00f97 | ||
|
|
52f2d580eb | ||
|
|
d7b1e3576f | ||
|
|
93799fbe9d | ||
|
|
b84644740d | ||
|
|
2dc35c1399 | ||
|
|
2cb171f6f5 | ||
|
|
a939cd9c89 | ||
|
|
d5270d113b | ||
|
|
b20903960b | ||
|
|
c0cb545b41 | ||
|
|
35c9f66a75 | ||
|
|
796d03d105 | ||
|
|
8723caf78d | ||
|
|
187f50a344 | ||
|
|
8d04606c4d | ||
|
|
b82d4f6e58 | ||
|
|
87e34967ef | ||
|
|
e32499c546 | ||
|
|
aa0b49228d | ||
|
|
57301a7f9c | ||
|
|
d1842ea8fb | ||
|
|
558151061e | ||
|
|
181723e573 | ||
|
|
6bc1db44bc | ||
|
|
737b57ed5f | ||
|
|
4d287d1ae2 | ||
|
|
f26eb5ada4 | ||
|
|
94ed275ba6 | ||
|
|
ac2f44da33 | ||
|
|
75fa1fbfbf | ||
|
|
5e689faea8 | ||
|
|
649a50b401 | ||
|
|
e94397a97d | ||
|
|
4ec58724d7 | ||
|
|
8cb294aa4a | ||
|
|
2b3a9a52b3 | ||
|
|
138cbb94b2 | ||
|
|
e56d6dea81 | ||
|
|
43f30e44e4 | ||
|
|
9e6db17ef4 | ||
|
|
0e631ad2f2 | ||
|
|
6229d8d2ff | ||
|
|
4647d09b50 | ||
|
|
4ad3a54026 | ||
|
|
05e5feac41 | ||
|
|
67df469c58 | ||
|
|
689e9ccfb5 | ||
|
|
9cd4bc407a | ||
|
|
61996c2bbf | ||
|
|
6d3dd99eb2 | ||
|
|
f0b484892c | ||
|
|
8352cbb7a3 | ||
|
|
6da08b71dc | ||
|
|
5d99059bf9 | ||
|
|
fa41b106ab | ||
|
|
4e3fd7d420 | ||
|
|
791d8354da | ||
|
|
10f19e6fc3 | ||
|
|
4c61a13057 | ||
|
|
7b3f62244f | ||
|
|
d347928e4d | ||
|
|
cc31079a11 | ||
|
|
4676648b78 | ||
|
|
c7594c9111 | ||
|
|
173cb7359d | ||
|
|
af295879fb | ||
|
|
95dd20a151 | ||
|
|
b65fce86bf | ||
|
|
3b8d3bbcbf | ||
|
|
f9e976467f | ||
|
|
118a27be2f | ||
|
|
59c89428e5 | ||
|
|
202ca5e782 | ||
|
|
d6f185d8e5 | ||
|
|
54ca474dba | ||
|
|
1ca383b23b | ||
|
|
179fde3a7b | ||
|
|
50198ffcf1 | ||
|
|
a446c25598 | ||
|
|
a7fb831035 | ||
|
|
4f5e0c9f85 | ||
|
|
8164b91dc4 | ||
|
|
4d5fca27ef | ||
|
|
fe59e4b9fe | ||
|
|
5c88685495 | ||
|
|
9359431bad | ||
|
|
72716f51ce | ||
|
|
382deef750 | ||
|
|
161e211734 | ||
|
|
263a248119 | ||
|
|
725251d294 | ||
|
|
4dff873013 | ||
|
|
60ede67abd | ||
|
|
906bfc8464 | ||
|
|
0d4f08ad9c | ||
|
|
a52bf87b7d | ||
|
|
40c7645d6e | ||
|
|
5b886a23fd | ||
|
|
65797caa7b | ||
|
|
66abb39880 | ||
|
|
95a12e0ee8 | ||
|
|
27951442b8 | ||
|
|
c42e053ae9 | ||
|
|
e7048c8c8b | ||
|
|
d8e0b6c977 | ||
|
|
5e6c34c61c | ||
|
|
828f073ebd | ||
|
|
2dd5701ac0 | ||
|
|
531439198e | ||
|
|
3d9a4d585e | ||
|
|
54eda59286 | ||
|
|
5a4f75c9f8 | ||
|
|
7810f665f1 | ||
|
|
697e2dd330 | ||
|
|
936c64ff51 | ||
|
|
1ea6549548 | ||
|
|
32d9949e4d | ||
|
|
01ba56a8a6 | ||
|
|
e109c42515 | ||
|
|
e4c7091647 | ||
|
|
960b6e5897 | ||
|
|
82eef8d5ee | ||
|
|
aa3848b2c8 | ||
|
|
3b5d0d141a | ||
|
|
c8fc715fe2 | ||
|
|
e5fe3a8e16 | ||
|
|
e0c6cd3dcc | ||
|
|
2edd510ab7 | ||
|
|
2b3e2ebc11 | ||
|
|
ab4cb59326 | ||
|
|
57c8615af3 | ||
|
|
b903173211 | ||
|
|
10cc8b89c4 | ||
|
|
5d9ae3cdb4 | ||
|
|
192d251ee8 | ||
|
|
031962608b | ||
|
|
25f6f478a5 | ||
|
|
e80f09f849 | ||
|
|
c159f91f06 | ||
|
|
eb790a74d2 | ||
|
|
e47451f5a0 | ||
|
|
252b8c83bf | ||
|
|
09666ff294 | ||
|
|
baf2e501dc | ||
|
|
5ac60f0a20 | ||
|
|
fb2ee8ec34 | ||
|
|
94e0db7963 | ||
|
|
b253246959 | ||
|
|
1ac73a247e | ||
|
|
2014115bca | ||
|
|
4a944dc397 | ||
|
|
3838cc4ec4 | ||
|
|
85748f2e6f | ||
|
|
d7b8aa56dc | ||
|
|
16e096cf86 | ||
|
|
50af74c38f | ||
|
|
bfc209b120 | ||
|
|
e7f9331e4b | ||
|
|
ab8e8aa2a1 | ||
|
|
1ef826d1da | ||
|
|
52bddaa97b | ||
|
|
e4dc3908bb | ||
|
|
1daadb812f | ||
|
|
9c2723391b | ||
|
|
7a8796414c | ||
|
|
f8f13c536f | ||
|
|
1adb69c0fd | ||
|
|
5f5830b960 | ||
|
|
9fb4f35bb6 | ||
|
|
c002e6f926 | ||
|
|
c154e5262e | ||
|
|
6ddef1cca6 | ||
|
|
9d68d95825 | ||
|
|
a4233e1a16 | ||
|
|
39373c6d2d | ||
|
|
d29acc90a2 | ||
|
|
a371235b0d | ||
|
|
53b4891a5e | ||
|
|
646ded9123 | ||
|
|
ea0b8f48e6 | ||
|
|
2067d7e300 | ||
|
|
866571ab41 | ||
|
|
4e1fa03087 | ||
|
|
b45572167d | ||
|
|
57a160f1b3 | ||
|
|
29ae8640d9 | ||
|
|
ee6377e54b | ||
|
|
b0f1ae7ea3 | ||
|
|
7aae2b72dc | ||
|
|
73fcbbd748 | ||
|
|
e7bedde835 | ||
|
|
7253edb1e1 | ||
|
|
efa28125c6 | ||
|
|
9832fcfe14 | ||
|
|
49c71f9f2d | ||
|
|
791770cf6e | ||
|
|
9ce9188ff6 | ||
|
|
362066a9b7 | ||
|
|
26ff9371d9 | ||
|
|
4a36f86c81 | ||
|
|
85144e47ff | ||
|
|
b417d961ec | ||
|
|
ef4ea84cb5 | ||
|
|
b422665a3c | ||
|
|
186dadf14d | ||
|
|
04e64db945 | ||
|
|
f60994ad24 | ||
|
|
cfa1ca96f2 | ||
|
|
4d9ff76433 | ||
|
|
9e1b7e0464 | ||
|
|
a77c6ff3a2 | ||
|
|
099fde97d5 | ||
|
|
f8fc2463ee | ||
|
|
e246b78846 | ||
|
|
c1e128bd5a | ||
|
|
8284075ee4 | ||
|
|
f7db09a128 | ||
|
|
f9c3d54bd1 | ||
|
|
0773f4033e | ||
|
|
d068fb321f | ||
|
|
8d054c940c | ||
|
|
80f1d79218 | ||
|
|
64f5413253 | ||
|
|
2abbbd9e70 | ||
|
|
a5c471af7e | ||
|
|
edd2f0232c | ||
|
|
b2c3b2dd8e | ||
|
|
4f1cecb8e7 | ||
|
|
b336eac343 | ||
|
|
2a09f6fa45 | ||
|
|
0e702eb799 | ||
|
|
dea841103d | ||
|
|
82856cf816 | ||
|
|
8aecda03ed | ||
|
|
5c817082a0 | ||
|
|
15c521a7fe | ||
|
|
989de4a1bf | ||
|
|
d9eeb45b03 | ||
|
|
fe570e000c | ||
|
|
01dc0249de | ||
|
|
93523d572e | ||
|
|
4f7a4464df | ||
|
|
e09293a15e | ||
|
|
827b17a52b | ||
|
|
a610379965 | ||
|
|
4e2c3051be | ||
|
|
50915cb7ed | ||
|
|
f4e2d26d58 | ||
|
|
cb0051ae60 | ||
|
|
a238cec12b | ||
|
|
393bf23c0c | ||
|
|
e7d9ba135c | ||
|
|
0a0003c110 | ||
|
|
7e1b27554c | ||
|
|
fb2a56e2d6 | ||
|
|
84218bfb45 | ||
|
|
dd78243406 | ||
|
|
484cf9c0e8 | ||
|
|
a04d1b4f97 | ||
|
|
831c10bdfc | ||
|
|
87603e400d | ||
|
|
4426216725 | ||
|
|
bc15b953b4 | ||
|
|
6d20b12043 | ||
|
|
2385c2a430 | ||
|
|
87384ea684 | ||
|
|
04dae799a2 | ||
|
|
0768c39036 | ||
|
|
8dd8d4d2d4 | ||
|
|
49b06beedf | ||
|
|
4c562a4457 | ||
|
|
fdbbf11887 | ||
|
|
f1e64b349a | ||
|
|
224f3a05cf | ||
|
|
ff56d6861d | ||
|
|
1873fbefba | ||
|
|
80b479e502 | ||
|
|
1f7c9adeeb | ||
|
|
9ebc3b058d | ||
|
|
e21b443a45 | ||
|
|
da590120c4 | ||
|
|
561d53885e | ||
|
|
44ad67ca8c | ||
|
|
3fe8fc75aa | ||
|
|
3cc2da3328 | ||
|
|
a3cd90dd71 | ||
|
|
d6cfdd3bae | ||
|
|
ba08baabb9 | ||
|
|
497b712f67 | ||
|
|
f00dfed7ac | ||
|
|
3c08461685 | ||
|
|
5ef2b4fdc0 | ||
|
|
23d2326d1d | ||
|
|
e338f9f190 | ||
|
|
c8ff626fe2 | ||
|
|
4e424d51f4 | ||
|
|
6b50323b07 | ||
|
|
65c148536d | ||
|
|
f99f62bee4 | ||
|
|
365f5449ca | ||
|
|
ff52f207cc | ||
|
|
ee0eed143a | ||
|
|
5127380727 | ||
|
|
ced654880c | ||
|
|
936d3b9f83 | ||
|
|
6e31230adc | ||
|
|
05ebe93180 | ||
|
|
aaf24e2552 | ||
|
|
8d961dfd25 | ||
|
|
659b37ef9d | ||
|
|
0abf6c9045 | ||
|
|
4630191fa4 | ||
|
|
b7b178f49c | ||
|
|
687066af3d | ||
|
|
6b168ab0c8 | ||
|
|
948625de9d | ||
|
|
3848eb8b16 | ||
|
|
3abe0b9d49 | ||
|
|
d7fabe81fe | ||
|
|
1dc81669c2 | ||
|
|
01d0e12603 | ||
|
|
397e569aaf | ||
|
|
79267f9e60 | ||
|
|
48ebe5736a | ||
|
|
c2064c78b2 | ||
|
|
36608a283b | ||
|
|
a1c87e1e15 | ||
|
|
fa7240a501 | ||
|
|
ffb4d38e24 | ||
|
|
f57c188f2e | ||
|
|
8471c4fb26 | ||
|
|
c97acd18e7 | ||
|
|
ffb590bfcc | ||
|
|
6137f98eb5 | ||
|
|
a6f6539691 | ||
|
|
10c038d9bf | ||
|
|
2d2eaa3eff | ||
|
|
4d28b1f0cd | ||
|
|
3de800a607 | ||
|
|
eff5923778 | ||
|
|
a79faace1b | ||
|
|
9550777b9d | ||
|
|
c8521a3c33 | ||
|
|
d71eb2cf39 | ||
|
|
160fb740f4 | ||
|
|
48e9f39513 | ||
|
|
8afa596fdf | ||
|
|
d3e45c297c | ||
|
|
2c98939c18 | ||
|
|
a18a7409fb | ||
|
|
2f19cf4524 | ||
|
|
da96707dca | ||
|
|
c3a8bdc240 | ||
|
|
21624ef273 | ||
|
|
1032c9b917 | ||
|
|
2e07902d76 | ||
|
|
6e23e1840a | ||
|
|
3e22e45066 | ||
|
|
79d1bd6c8f | ||
|
|
fe341a16f5 | ||
|
|
62abf46b3f | ||
|
|
a95a5e0d9b | ||
|
|
d6f6ceaba5 | ||
|
|
0922f8af59 | ||
|
|
6812302ff9 | ||
|
|
f3f86b8e78 | ||
|
|
1a2680b9e5 | ||
|
|
435bbb6a8c | ||
|
|
3cf44e0a53 | ||
|
|
40b367513f | ||
|
|
9f563d584a | ||
|
|
af4adf5379 | ||
|
|
2560146da3 | ||
|
|
eae3a6397a | ||
|
|
959611420b | ||
|
|
9522f2e8c7 | ||
|
|
e42a0b6cf0 | ||
|
|
d1c7032dec | ||
|
|
d241bc81ae | ||
|
|
cb7f39afa1 | ||
|
|
99b5ad9ebb | ||
|
|
c14b237757 | ||
|
|
d447c7dc32 | ||
|
|
247420c9c1 | ||
|
|
04b112e004 | ||
|
|
be0ce99007 | ||
|
|
69e8d0b65d | ||
|
|
94e685e1bd | ||
|
|
5899f3dd28 | ||
|
|
f82aa1d564 | ||
|
|
fe5c2cf4b7 | ||
|
|
43d40c6e9e | ||
|
|
3d44d8f79c | ||
|
|
ba6fe8ff2e | ||
|
|
5337258888 | ||
|
|
29bf9d6ef1 | ||
|
|
483beb6361 | ||
|
|
fdaec77594 | ||
|
|
8494a5761b | ||
|
|
45590eea22 | ||
|
|
834a64920b | ||
|
|
2c2ccb3618 | ||
|
|
fb5c8c39ae | ||
|
|
f7d39193a4 | ||
|
|
aec796b212 | ||
|
|
fb13bb2393 | ||
|
|
c517ec6779 | ||
|
|
e8cbf2a717 | ||
|
|
e9c86df468 | ||
|
|
6ba8c289c5 | ||
|
|
3f1672e89f | ||
|
|
15be5cbf1f | ||
|
|
4cf0e5e6db | ||
|
|
6b1898f12e | ||
|
|
b3426e9c0d | ||
|
|
38c1a1f3e0 | ||
|
|
4488e25f16 | ||
|
|
cfdb3058ee | ||
|
|
64adff5fea | ||
|
|
6efc58e3db | ||
|
|
f393989a5b | ||
|
|
d6ed20c1e4 | ||
|
|
7c524014c8 | ||
|
|
406d055f07 | ||
|
|
04a90b5dd1 | ||
|
|
8c5bfa0132 | ||
|
|
bc80c55353 | ||
|
|
9c3b51ca0f | ||
|
|
26584ff145 | ||
|
|
42c3d52863 | ||
|
|
64e72f7103 | ||
|
|
e955037980 | ||
|
|
fb99910c23 | ||
|
|
e620bd4d3f | ||
|
|
a44e761d9e | ||
|
|
ea1974d576 | ||
|
|
85a0bd43c2 | ||
|
|
278e0f126e | ||
|
|
d8652cfd4f | ||
|
|
377b7065aa | ||
|
|
1e9c79c587 | ||
|
|
78147aa342 | ||
|
|
cd4a2265b9 | ||
|
|
767ac1de10 | ||
|
|
d762215d13 | ||
|
|
1fd09593cf | ||
|
|
e45a0f6ce2 | ||
|
|
94f8525721 | ||
|
|
d73cf64e54 | ||
|
|
f945462bab | ||
|
|
b05946175b | ||
|
|
62f0f8190d | ||
|
|
bf8c0da4be | ||
|
|
dfdd6b3891 | ||
|
|
f5e0fc3e9a | ||
|
|
d741101fe3 | ||
|
|
e1620799c7 | ||
|
|
749c7adb13 | ||
|
|
921a733911 | ||
|
|
26d0004fe1 | ||
|
|
948af6d5b5 | ||
|
|
670a187a3c | ||
|
|
be9f725023 | ||
|
|
daf3f4cb1a | ||
|
|
5acda4cc71 | ||
|
|
8452af606b | ||
|
|
630d449520 | ||
|
|
7372cf7d99 | ||
|
|
b7e46c558f | ||
|
|
bf8f8710ea | ||
|
|
6ffe5b775d | ||
|
|
be0805b85b | ||
|
|
65b2359b27 | ||
|
|
8651aa73e8 | ||
|
|
78b542737a | ||
|
|
fccf86532f | ||
|
|
1857417601 | ||
|
|
ee7114a58c | ||
|
|
00fa91d0d6 | ||
|
|
b7a25bfc33 | ||
|
|
a2e46b9a1b | ||
|
|
a751fa22d2 | ||
|
|
e563a0b7db | ||
|
|
49085ca943 | ||
|
|
560a850a2b | ||
|
|
66782e2317 | ||
|
|
b60eb1544b | ||
|
|
cbe59fa3bf | ||
|
|
c97c6dc065 | ||
|
|
32fa97d68d | ||
|
|
aee4603269 | ||
|
|
29c7da5f1a | ||
|
|
6131f4e32b | ||
|
|
67e03e625d | ||
|
|
b124f9101b | ||
|
|
d11a3a6380 | ||
|
|
4cc0706b06 | ||
|
|
885f5a9781 | ||
|
|
60b5964577 | ||
|
|
6e1919414e | ||
|
|
8c8ec5e63e | ||
|
|
b8413ddd5b | ||
|
|
5d976b6e18 | ||
|
|
2b4317452b | ||
|
|
1c3011ba4b | ||
|
|
574a42f3b4 | ||
|
|
9005cd59e5 | ||
|
|
dd494d4ab7 | ||
|
|
7cca469a12 | ||
|
|
2aed432b4b | ||
|
|
0291a3ff56 | ||
|
|
5d7315280a | ||
|
|
254931b9a8 | ||
|
|
aa89744c95 | ||
|
|
1cda3f5ad7 | ||
|
|
8f1f64ffb6 | ||
|
|
2bc0a7795c | ||
|
|
4204da6ad4 | ||
|
|
7ac39b10f7 | ||
|
|
6b567e0066 | ||
|
|
df299d6edd | ||
|
|
4e34f05238 | ||
|
|
9962f6fd79 | ||
|
|
f9d492f4b1 | ||
|
|
a8bb2ef1c3 | ||
|
|
240c629cda | ||
|
|
952567dd3c | ||
|
|
10b396b4c2 | ||
|
|
699bbe21a4 | ||
|
|
27b67deca6 | ||
|
|
581b7ec553 | ||
|
|
acfbb1a44a | ||
|
|
d85a6d8fe4 | ||
|
|
20fbb5c63b | ||
|
|
1051a06a76 | ||
|
|
98dfc26208 | ||
|
|
1ba0a2cedd | ||
|
|
4afb13f98b | ||
|
|
b27d33675d | ||
|
|
00b9ae77f9 | ||
|
|
65219f3093 | ||
|
|
f78d1d4340 | ||
|
|
941edca597 | ||
|
|
a699435ede | ||
|
|
66d6417189 | ||
|
|
558e37c412 | ||
|
|
4f40d991ea | ||
|
|
549af99007 | ||
|
|
b336930093 | ||
|
|
c9a0edfb8b | ||
|
|
2c5668af46 | ||
|
|
751dea32ae | ||
|
|
cd8f4bfb1f | ||
|
|
a6cfcc6866 | ||
|
|
b8c4f603db | ||
|
|
0075e4b391 | ||
|
|
125af556ce | ||
|
|
963ad5c255 | ||
|
|
387f56cb7b | ||
|
|
b3deda38c9 | ||
|
|
2a5ca77454 | ||
|
|
727940d847 | ||
|
|
8cd42478e1 | ||
|
|
c11d34b26c | ||
|
|
339d7445b3 | ||
|
|
d16f05f2c8 | ||
|
|
5427b32a40 | ||
|
|
f73701239d | ||
|
|
f5a6fc0703 | ||
|
|
bdf5ba91a4 | ||
|
|
bc8f338771 | ||
|
|
3413bfc06a | ||
|
|
2056f0ce09 | ||
|
|
5eb8cfd691 | ||
|
|
e6a4254488 | ||
|
|
d478ad00d0 | ||
|
|
53eda861de | ||
|
|
cc1d86ba63 | ||
|
|
f0528f00e7 | ||
|
|
5cd2ad124d | ||
|
|
6c00e7a902 | ||
|
|
53170bbb58 | ||
|
|
467258e050 | ||
|
|
129be23c9e | ||
|
|
8e9290e86e | ||
|
|
7cf5bebf8e | ||
|
|
f7f9087fb5 | ||
|
|
256e7904fd | ||
|
|
c8ea1b6c38 | ||
|
|
2816b06c05 | ||
|
|
4c695ea088 | ||
|
|
a14d51806d | ||
|
|
0170977914 | ||
|
|
f61726b5ae | ||
|
|
fc27fdac57 | ||
|
|
47c59859ee | ||
|
|
6e76ab9c09 | ||
|
|
5f78b76702 | ||
|
|
5e0808c848 | ||
|
|
508f05a47e | ||
|
|
66b57f0323 | ||
|
|
cfac22b4c0 | ||
|
|
2ef67f20a7 | ||
|
|
7a73946ce1 | ||
|
|
6d22b5a3c6 | ||
|
|
50050a0e53 | ||
|
|
de17422793 | ||
|
|
6b5e83ce1d | ||
|
|
17d75d8a3b | ||
|
|
616405f7ae | ||
|
|
5c2dc043cd | ||
|
|
24a3c12f31 | ||
|
|
3e544282ff | ||
|
|
3c85a40648 | ||
|
|
ac3c336b98 | ||
|
|
f24f282442 | ||
|
|
0dfee4745c | ||
|
|
eb80f7a787 | ||
|
|
68fed2a1a6 | ||
|
|
10d118a8d0 | ||
|
|
e021c33191 | ||
|
|
7b7548196a | ||
|
|
e019c735e1 | ||
|
|
c253f2c7e2 | ||
|
|
0ce9133b55 | ||
|
|
6ac9683a32 | ||
|
|
1d7739d8da | ||
|
|
1de2a6d85c | ||
|
|
0a723a50dc | ||
|
|
34b91318f4 | ||
|
|
b11a7114a5 | ||
|
|
2ca5e1c8d6 | ||
|
|
7ae8c7b247 | ||
|
|
1e17e40868 | ||
|
|
1069019fd2 | ||
|
|
4422904a2e | ||
|
|
5d085b78bd | ||
|
|
0927c73b13 | ||
|
|
5fe8f9017f | ||
|
|
5cdffeaba1 | ||
|
|
6e7c7374fd | ||
|
|
fb7b41793b | ||
|
|
abbf9f01ab | ||
|
|
17698af5e3 | ||
|
|
b66fcdb3f7 | ||
|
|
7fc48b75dd | ||
|
|
07ac5370d8 | ||
|
|
7c8f1cf7af | ||
|
|
57a97e3fb3 | ||
|
|
061432147d | ||
|
|
8f3e5794b3 | ||
|
|
a112b5e231 | ||
|
|
67859aea44 | ||
|
|
37643ab0b2 | ||
|
|
b0ee11f7cc | ||
|
|
7647e29b21 | ||
|
|
a3e672f863 | ||
|
|
9058fe803d | ||
|
|
32f429a819 | ||
|
|
bf26656547 | ||
|
|
96e26247d7 | ||
|
|
8e538aa82f | ||
|
|
fa809b2c4b | ||
|
|
9a63cd36cd | ||
|
|
21d949daa8 | ||
|
|
330b90e046 | ||
|
|
693daafe29 | ||
|
|
c3b3fb8b74 | ||
|
|
62731bea20 | ||
|
|
c55fb583b8 | ||
|
|
9725aff83b | ||
|
|
1320691eb4 | ||
|
|
451f67c63d | ||
|
|
43b1b128b1 | ||
|
|
fc991cb59c | ||
|
|
17d3d2f754 | ||
|
|
73950b9857 | ||
|
|
61ee331f11 | ||
|
|
651319589c | ||
|
|
5479948bd4 | ||
|
|
1ec145ec87 | ||
|
|
8ab47cb075 | ||
|
|
b7b3dcf3ea | ||
|
|
f7da0b4525 | ||
|
|
f9a3380184 | ||
|
|
b61f08d3fa | ||
|
|
0503225928 | ||
|
|
d4d0b5501b | ||
|
|
6c5726c96f | ||
|
|
56972447b2 | ||
|
|
67e1796ef6 | ||
|
|
1ae8da3b3f | ||
|
|
3ed97f45fb | ||
|
|
ae2809cad4 | ||
|
|
b0a296477e | ||
|
|
629a4574db | ||
|
|
4be809499d | ||
|
|
b10063da9a | ||
|
|
5e54e13140 | ||
|
|
8f87c56312 | ||
|
|
1b18560e90 | ||
|
|
f86a5f9b09 | ||
|
|
f1b1bdb121 | ||
|
|
0365557b25 | ||
|
|
883d962838 | ||
|
|
35790a8990 | ||
|
|
8edc17dac9 | ||
|
|
502f5c8b5f | ||
|
|
bc28fb187c | ||
|
|
de0277713b | ||
|
|
1593eb4d47 | ||
|
|
70ba92f917 | ||
|
|
47cc71ea01 | ||
|
|
9453d67273 | ||
|
|
f758af826d | ||
|
|
6a1e5385e5 | ||
|
|
63487dca76 | ||
|
|
7d6f09f5c7 | ||
|
|
148eed3cdc | ||
|
|
05701317b4 | ||
|
|
7548fdae5d | ||
|
|
3e41d92c18 | ||
|
|
ad6c8b882e | ||
|
|
947ff655c5 | ||
|
|
183b7c85a1 | ||
|
|
4cf6947af7 | ||
|
|
b83709b269 | ||
|
|
c699d55175 | ||
|
|
781afaa852 | ||
|
|
007b03a2c2 | ||
|
|
ed18693345 | ||
|
|
7c99224bb7 | ||
|
|
c2c4090902 | ||
|
|
416288061a | ||
|
|
83376bc231 | ||
|
|
c0de98f9f2 | ||
|
|
70db0db221 | ||
|
|
526f26685d | ||
|
|
5d1220e629 | ||
|
|
b80fde4388 | ||
|
|
148f43b4a5 | ||
|
|
0d88213de5 | ||
|
|
36b8d74faa | ||
|
|
5021f28159 | ||
|
|
ee6a814576 | ||
|
|
807de9a0a9 | ||
|
|
9398b6b55b | ||
|
|
932bfcf374 | ||
|
|
e127bac7fd | ||
|
|
bccf13bf67 | ||
|
|
950bbd6dc2 | ||
|
|
e680ba85fa | ||
|
|
b23ede7d50 | ||
|
|
73047d8b35 | ||
|
|
ef5e0c2e75 | ||
|
|
dc9e560f9b | ||
|
|
ae5b07ba01 | ||
|
|
3384c23a56 | ||
|
|
c2259d42a8 | ||
|
|
370e9d089f | ||
|
|
cab8b18c68 | ||
|
|
3b283ab9aa | ||
|
|
e5b84e2f87 | ||
|
|
f86417d791 | ||
|
|
8dc3d23831 | ||
|
|
42993b15c6 | ||
|
|
ad817d4f23 | ||
|
|
77954bb3dd | ||
|
|
52f7a62e1e | ||
|
|
1b8ceb36fc | ||
|
|
ceea1f9d44 | ||
|
|
2f81f2b78a | ||
|
|
aba035eb3d | ||
|
|
5ca2702083 | ||
|
|
af588adce5 | ||
|
|
399684a58f | ||
|
|
5cf4c16f5b | ||
|
|
0fe2319dfc | ||
|
|
e759dad019 | ||
|
|
0c18abed33 | ||
|
|
89dad2fd84 | ||
|
|
a6a71f8c76 | ||
|
|
1fee190fd0 | ||
|
|
23ba3ca19e | ||
|
|
33d8363297 | ||
|
|
49dcf7cf59 | ||
|
|
9778445a74 | ||
|
|
c2cc90b27d | ||
|
|
b9feb81226 | ||
|
|
b06ddcdd86 | ||
|
|
16ef372b53 | ||
|
|
f0a34ea64e | ||
|
|
33f7dec5cf | ||
|
|
3005803598 | ||
|
|
eeaaf5d258 | ||
|
|
15819cc981 | ||
|
|
fe6bfb1ba2 | ||
|
|
5c8d7b2423 | ||
|
|
ff0801d783 | ||
|
|
ac4b0a3118 | ||
|
|
227084e92e | ||
|
|
a175f6e862 | ||
|
|
4043c461d7 | ||
|
|
b3b2aa6359 | ||
|
|
5bd2dca463 | ||
|
|
21740fd2c5 | ||
|
|
c11ef442fb | ||
|
|
b5a38001dd | ||
|
|
5b6f68cf72 | ||
|
|
3050e935a1 | ||
|
|
80a1fa9ece | ||
|
|
1851ba1434 | ||
|
|
c4b8a2505d | ||
|
|
a1d2d40ad3 | ||
|
|
a3881bb452 | ||
|
|
6e4ee8da2b | ||
|
|
2a0f79b90f | ||
|
|
5ccc98bc14 | ||
|
|
b1353e4d6e | ||
|
|
9f4de91554 | ||
|
|
d30d1088da | ||
|
|
c6e6346642 | ||
|
|
e08c8a1fc9 | ||
|
|
e50dbe0c43 | ||
|
|
d9c7bbd046 | ||
|
|
dac0e5b133 | ||
|
|
ce3bc91946 | ||
|
|
22c0e2813a | ||
|
|
9796987d59 | ||
|
|
4d275e4767 | ||
|
|
492d6c2826 | ||
|
|
765f009350 | ||
|
|
629e8b41f2 | ||
|
|
71c187a1ed | ||
|
|
00e991e2a0 | ||
|
|
8a80f97c06 | ||
|
|
3cbec411c7 | ||
|
|
3bcb89fb84 | ||
|
|
62b8a36ce9 | ||
|
|
27566abb06 | ||
|
|
dfb130270a | ||
|
|
1ba616f843 | ||
|
|
11fb0a4cb7 | ||
|
|
1557a4c3b0 | ||
|
|
ab28a7d65f | ||
|
|
d58a5e124a | ||
|
|
762347f005 | ||
|
|
4b76adf15b | ||
|
|
6be1b95241 | ||
|
|
38ad790612 | ||
|
|
86acb27e24 | ||
|
|
1b395fa21d | ||
|
|
92380485c8 | ||
|
|
27f9a21a2c | ||
|
|
cf7088a462 | ||
|
|
67554ef3b0 | ||
|
|
cf20b068ca | ||
|
|
0b9316d94a | ||
|
|
3011ebe547 | ||
|
|
4b77b0773e | ||
|
|
e5935a4737 | ||
|
|
a3a8472b82 | ||
|
|
212182d991 | ||
|
|
c82b8546bc | ||
|
|
fac4e3fcfc | ||
|
|
5b0122fed4 | ||
|
|
b46b5df16a | ||
|
|
cb51029335 | ||
|
|
e504b3ecbd | ||
|
|
0ad0ec0985 | ||
|
|
d1d32ada00 | ||
|
|
8058daa982 | ||
|
|
f4c5c0f5b5 | ||
|
|
2ecb8dab7d | ||
|
|
576d427f03 | ||
|
|
21aafea098 | ||
|
|
3ed2908563 | ||
|
|
2b188b54d8 | ||
|
|
306720e63e | ||
|
|
a308dd4471 | ||
|
|
8f33d21bc2 | ||
|
|
b9ee3ae030 | ||
|
|
c14b87b228 | ||
|
|
8a279aaf20 | ||
|
|
3a5e541b2d | ||
|
|
43574128b3 | ||
|
|
e4a9903844 | ||
|
|
0d30108dcb | ||
|
|
b7a79c70cc | ||
|
|
6e6f28d1ac | ||
|
|
d14978e549 | ||
|
|
1c28b729ad | ||
|
|
303194b08b | ||
|
|
2ee3bfaa25 | ||
|
|
029a94dd33 | ||
|
|
f6df9217b6 | ||
|
|
184fae4ba5 | ||
|
|
35b236651e | ||
|
|
c926770550 | ||
|
|
272eaf184f | ||
|
|
56fbb1fc33 | ||
|
|
33f6bf947e | ||
|
|
07326edb6b | ||
|
|
144610151c | ||
|
|
4228d3609e | ||
|
|
510936a2a0 | ||
|
|
5854e284ea | ||
|
|
a732606e55 | ||
|
|
84e300739c | ||
|
|
8edf9282c3 | ||
|
|
5a1acaaefc | ||
|
|
4fd7c210d8 | ||
|
|
a26a7d217d | ||
|
|
7b7f44d937 | ||
|
|
6cf89aa0f3 | ||
|
|
3be83784cd | ||
|
|
b6c163acd7 | ||
|
|
05a26b7279 | ||
|
|
35eb90c135 | ||
|
|
761f79385a | ||
|
|
554bda3332 | ||
|
|
2a968df779 | ||
|
|
30ccd13b69 | ||
|
|
60c09ea51f | ||
|
|
65eab93527 | ||
|
|
a226ad8509 | ||
|
|
31f4fd70ce | ||
|
|
7275ab9837 | ||
|
|
5b3facc63b | ||
|
|
0f313fb9ab | ||
|
|
05b7593e66 | ||
|
|
1b85066d26 | ||
|
|
e93b64f58d | ||
|
|
f0a18f31e7 | ||
|
|
29c82527a5 | ||
|
|
c165dc5e50 | ||
|
|
42da07396c | ||
|
|
20e6c04059 | ||
|
|
ff5d3e5b36 | ||
|
|
6cc68ab503 | ||
|
|
068465146b | ||
|
|
3bcf8057d4 | ||
|
|
8039a6c525 | ||
|
|
558c020cca | ||
|
|
7797da78f5 | ||
|
|
0ab81d768f | ||
|
|
1cee5ccb93 | ||
|
|
3ce01b5ac2 | ||
|
|
e6aa8f3ff4 | ||
|
|
9d7b087972 | ||
|
|
bb184ed481 | ||
|
|
b9b31069cc | ||
|
|
d0cf4e8882 | ||
|
|
02fb850761 | ||
|
|
ac8177e10d | ||
|
|
2eb5c54476 | ||
|
|
0e206e69cf |
@@ -3,24 +3,29 @@ Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
AccessModifierOffset: -1
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveMacros: false
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: true
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortBlocksOnASingleLine: Never
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: Inline
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: true
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
@@ -29,6 +34,7 @@ BraceWrapping:
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
IndentBraces: false
|
||||
@@ -38,6 +44,7 @@ BraceWrapping:
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
@@ -50,6 +57,7 @@ ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
@@ -58,15 +66,25 @@ ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^<ext/.*\.h>'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentCaseLabels: true
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 2
|
||||
IndentWrappedFunctionNames: false
|
||||
JavaScriptQuotes: Leave
|
||||
@@ -76,32 +94,73 @@ MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCBinPackProtocolList: Never
|
||||
ObjCBlockIndentWidth: 2
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 1
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerAlignment: Left
|
||||
RawStringFormats:
|
||||
- Language: Cpp
|
||||
Delimiters:
|
||||
- cc
|
||||
- CC
|
||||
- cpp
|
||||
- Cpp
|
||||
- CPP
|
||||
- 'c++'
|
||||
- 'C++'
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
- Language: TextProto
|
||||
Delimiters:
|
||||
- pb
|
||||
- PB
|
||||
- proto
|
||||
- PROTO
|
||||
EnclosingFunctions:
|
||||
- EqualsProto
|
||||
- EquivToProto
|
||||
- PARSE_PARTIAL_TEXT_PROTO
|
||||
- PARSE_TEST_PROTO
|
||||
- PARSE_TEXT_PROTO
|
||||
- ParseTextOrDie
|
||||
- ParseTextProtoOrDie
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyBlock: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 2
|
||||
SpacesInAngles: false
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Auto
|
||||
SpaceBeforeSquareBrackets: false
|
||||
Standard: c++17
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
...
|
||||
|
||||
75
.clang-tidy
Normal file
75
.clang-tidy
Normal file
@@ -0,0 +1,75 @@
|
||||
Checks:
|
||||
'bugprone-assert-side-effect,
|
||||
bugprone-bool-pointer-implicit-conversion,
|
||||
bugprone-copy-constructor-init,
|
||||
bugprone-dangling-handle,
|
||||
bugprone-dynamic-static-initializers,
|
||||
bugprone-forward-declaration-namespace,
|
||||
bugprone-forwarding-reference-overload,
|
||||
bugprone-inaccurate-erase,
|
||||
bugprone-incorrect-roundings,
|
||||
bugprone-integer-division,
|
||||
bugprone-lambda-function-name,
|
||||
bugprone-misplaced-operator-in-strlen-in-alloc,
|
||||
bugprone-misplaced-widening-cast,
|
||||
bugprone-move-forwarding-reference,
|
||||
bugprone-multiple-statement-macro,
|
||||
bugprone-parent-virtual-call,
|
||||
bugprone-posix-return,
|
||||
bugprone-sizeof-container,
|
||||
bugprone-sizeof-expression,
|
||||
bugprone-spuriously-wake-up-functions,
|
||||
bugprone-string-constructor,
|
||||
bugprone-string-integer-assignment,
|
||||
bugprone-string-literal-with-embedded-nul,
|
||||
bugprone-suspicious-enum-usage,
|
||||
bugprone-suspicious-include,
|
||||
bugprone-suspicious-memset-usage,
|
||||
bugprone-suspicious-missing-comma,
|
||||
bugprone-suspicious-semicolon,
|
||||
bugprone-suspicious-string-compare,
|
||||
bugprone-throw-keyword-missing,
|
||||
bugprone-too-small-loop-variable,
|
||||
bugprone-undefined-memory-manipulation,
|
||||
bugprone-undelegated-constructor,
|
||||
bugprone-unhandled-self-assignment,
|
||||
bugprone-unused-raii,
|
||||
bugprone-virtual-near-miss,
|
||||
cert-dcl58-cpp,
|
||||
cert-err52-cpp,
|
||||
cert-err60-cpp,
|
||||
cert-mem57-cpp,
|
||||
cert-oop57-cpp,
|
||||
cert-oop58-cpp,
|
||||
clang-diagnostic-*,
|
||||
-clang-diagnostic-deprecated-declarations,
|
||||
-clang-diagnostic-#warnings,
|
||||
-clang-diagnostic-pedantic,
|
||||
clang-analyzer-*,
|
||||
cppcoreguidelines-slicing,
|
||||
google-build-namespaces,
|
||||
google-explicit-constructor,
|
||||
google-global-names-in-headers,
|
||||
google-readability-avoid-underscore-in-googletest-name,
|
||||
google-readability-casting,
|
||||
google-runtime-operator,
|
||||
llvm-twine-local,
|
||||
misc-definitions-in-headers,
|
||||
misc-misplaced-const,
|
||||
misc-new-delete-overloads,
|
||||
misc-non-copyable-objects,
|
||||
modernize-avoid-bind,
|
||||
modernize-concat-nested-namespaces,
|
||||
modernize-make-shared,
|
||||
modernize-make-unique,
|
||||
modernize-pass-by-value,
|
||||
modernize-use-default-member-init,
|
||||
modernize-use-noexcept,
|
||||
modernize-use-nullptr,
|
||||
modernize-use-override,
|
||||
modernize-use-using,
|
||||
readability-braces-around-statements'
|
||||
FormatStyle: file
|
||||
CheckOptions:
|
||||
- key: bugprone-dangling-handle
|
||||
value: 'wpi::StringRef;wpi::Twine'
|
||||
4
.gitattributes
vendored
Normal file
4
.gitattributes
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
*.gradle text eol=lf
|
||||
*.java text eol=lf
|
||||
*.md text eol=lf
|
||||
*.xml text eol=lf
|
||||
38
.github/CODEOWNERS
vendored
Normal file
38
.github/CODEOWNERS
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
# Lines starting with '#' are comments.
|
||||
# Each line is a file pattern followed by one or more owners.
|
||||
|
||||
# More details are here: https://help.github.com/articles/about-codeowners/
|
||||
|
||||
# The '*' pattern is global owners.
|
||||
|
||||
# Order is important. The last matching pattern has the most precedence.
|
||||
|
||||
# The folders are ordered as a tree: by depth then alphabetically.
|
||||
# This should make it easy to add new rules without breaking existing ones.
|
||||
|
||||
# Global rule:
|
||||
* @wpilibsuite/wpilib
|
||||
|
||||
/cameraserver/ @wpilibsuite/camera-server
|
||||
|
||||
/cscore/ @wpilibsuite/camera-server
|
||||
|
||||
/hal/ @wpilibsuite/hardware
|
||||
/hal/src/main/java/**/sim/ @wpilibsuite/simulation
|
||||
/hal/src/main/native/include/mockdata/ @wpilibsuite/simulation
|
||||
/hal/src/main/native/include/simulation/ @wpilibsuite/simulation
|
||||
/hal/src/main/native/sim/ @wpilibsuite/simulation
|
||||
|
||||
/ntcore/ @wpilibsuite/network-tables
|
||||
|
||||
/simulation/ @wpilibsuite/simulation
|
||||
|
||||
/wpilibNewCommands/ @wpilibsuite/commandbased
|
||||
|
||||
/wpilibOldCommands/ @wpilibsuite/commandbased
|
||||
|
||||
/wpilibcExamples/ @wpilibsuite/wpilib @wpilibsuite/documentation
|
||||
|
||||
/wpilibjExamples/ @wpilibsuite/wpilib @wpilibsuite/documentation
|
||||
|
||||
/wpiutil/ @PeterJohnson
|
||||
31
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
31
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: bug
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. ...
|
||||
2. ...
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- WPILib Version: [e.g. 2021.3.1]
|
||||
- OS: [e.g. Windows 11]
|
||||
- Java version [e.g. 1.10.2]
|
||||
- C++ version [e.g. 17]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
20
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
name: Question
|
||||
about: Ask about features or parts of this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the question you have.**
|
||||
A clear and concise description of what you want clarification on.
|
||||
|
||||
**Describe the reason for your confusion.**
|
||||
A clear and concise description of why the question requires clarification and what's confusing.
|
||||
|
||||
**Is your question related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the question here.
|
||||
65
.github/workflows/cmake.yml
vendored
Normal file
65
.github/workflows/cmake.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
name: CMake
|
||||
|
||||
on: [pull_request, push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
name: Linux
|
||||
container: wpilib/roborio-cross-ubuntu:2022-20.04
|
||||
flags: ""
|
||||
- os: macOS-11
|
||||
name: macOS
|
||||
container: ""
|
||||
flags: "-DWITH_JAVA=OFF"
|
||||
name: "Build - ${{ matrix.name }}"
|
||||
runs-on: ${{ matrix.os }}
|
||||
container: ${{ matrix.container }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
if [ "$RUNNER_OS" == "macOS" ]; then
|
||||
brew install opencv
|
||||
fi
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Install jinja
|
||||
run: python -m pip install jinja2
|
||||
- name: configure
|
||||
run: mkdir build && cd build && cmake ${{ matrix.flags }} ..
|
||||
- name: build
|
||||
working-directory: build
|
||||
run: cmake --build . -j$(nproc)
|
||||
- name: test
|
||||
working-directory: build
|
||||
run: ctest --output-on-failure
|
||||
|
||||
build-vcpkg:
|
||||
name: "Build - Windows"
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Prepare vcpkg
|
||||
uses: lukka/run-vcpkg@v7
|
||||
with:
|
||||
vcpkgArguments: opencv
|
||||
vcpkgDirectory: ${{ runner.workspace }}/vcpkg
|
||||
vcpkgTriplet: x64-windows
|
||||
vcpkgGitCommitId: d781bd9ca77ac3dc2f13d88169021d48459c665f # HEAD on 2021-07-25
|
||||
- name: Configure & Build
|
||||
uses: lukka/run-cmake@v3
|
||||
with:
|
||||
buildDirectory: ${{ runner.workspace }}/build
|
||||
cmakeAppendedArgs: -DWITH_JAVA=OFF
|
||||
cmakeListsOrSettingsJson: CMakeListsTxtAdvanced
|
||||
useVcpkgToolchainFile: true
|
||||
- name: Run Tests
|
||||
run: ctest -C "Debug" --output-on-failure
|
||||
working-directory: ${{ runner.workspace }}/build
|
||||
60
.github/workflows/documentation.yml
vendored
Normal file
60
.github/workflows/documentation.yml
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
name: Documentation
|
||||
|
||||
on: [push, workflow_dispatch]
|
||||
|
||||
env:
|
||||
BASE_PATH: allwpilib/docs
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
name: "Documentation - Publish"
|
||||
runs-on: ubuntu-latest
|
||||
if: github.repository_owner == 'wpilibsuite' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 13
|
||||
- name: Install libclang-9
|
||||
run: sudo apt update && sudo apt install -y libclang-cpp9 libclang1-9
|
||||
- name: Set environment variables (Development)
|
||||
run: |
|
||||
echo "TARGET_FOLDER=$BASE_PATH/development" >> $GITHUB_ENV
|
||||
if: github.ref == 'refs/heads/main'
|
||||
- name: Set environment variables (Tag)
|
||||
run: |
|
||||
echo "EXTRA_GRADLE_ARGS=-PreleaseMode" >> $GITHUB_ENV
|
||||
echo "TARGET_FOLDER=$BASE_PATH/beta" >> $GITHUB_ENV
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
- name: Set environment variables (Release)
|
||||
run: |
|
||||
echo "EXTRA_GRADLE_ARGS=-PreleaseMode" >> $GITHUB_ENV
|
||||
echo "TARGET_FOLDER=$BASE_PATH/release" >> $GITHUB_ENV
|
||||
if: startsWith(github.ref, 'refs/tags/v') && !contains(github.ref, 'alpha') && !contains(github.ref, 'beta')
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew docs:generateJavaDocs docs:doxygen -PbuildServer ${{ env.EXTRA_GRADLE_ARGS }}
|
||||
- name: Install SSH Client 🔑
|
||||
uses: webfactory/ssh-agent@v0.4.1
|
||||
with:
|
||||
ssh-private-key: ${{ secrets.GH_DEPLOY_KEY }}
|
||||
- name: Deploy Java 🚀
|
||||
uses: JamesIves/github-pages-deploy-action@3.7.1
|
||||
with:
|
||||
SSH: true
|
||||
REPOSITORY_NAME: wpilibsuite/wpilibsuite.github.io
|
||||
BRANCH: main
|
||||
CLEAN: true
|
||||
FOLDER: docs/build/docs/javadoc
|
||||
TARGET_FOLDER: ${{ env.TARGET_FOLDER }}/java
|
||||
- name: Deploy C++ 🚀
|
||||
uses: JamesIves/github-pages-deploy-action@3.7.1
|
||||
with:
|
||||
SSH: true
|
||||
REPOSITORY_NAME: wpilibsuite/wpilibsuite.github.io
|
||||
BRANCH: main
|
||||
CLEAN: true
|
||||
FOLDER: docs/build/docs/doxygen/html
|
||||
TARGET_FOLDER: ${{ env.TARGET_FOLDER }}/cpp
|
||||
15
.github/workflows/gazebo.yml
vendored
Normal file
15
.github/workflows/gazebo.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
name: Gazebo
|
||||
|
||||
on: [pull_request, push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: "Build"
|
||||
runs-on: ubuntu-latest
|
||||
container: wpilib/gazebo-ubuntu:18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew simulation:frc_gazebo_plugins:build simulation:halsim_gazebo:build -PbuildServer -PforceGazebo
|
||||
@@ -1,5 +1,5 @@
|
||||
name: "Validate Gradle Wrapper"
|
||||
on: [push]
|
||||
on: [pull_request, push]
|
||||
|
||||
jobs:
|
||||
validation:
|
||||
|
||||
164
.github/workflows/gradle.yml
vendored
Normal file
164
.github/workflows/gradle.yml
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
name: Gradle
|
||||
|
||||
on: [pull_request, push]
|
||||
|
||||
jobs:
|
||||
build-docker:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- container: wpilib/roborio-cross-ubuntu:2022-18.04
|
||||
artifact-name: Athena
|
||||
build-options: "-Ponlylinuxathena"
|
||||
- container: wpilib/raspbian-cross-ubuntu:10-18.04
|
||||
artifact-name: Raspbian
|
||||
build-options: "-Ponlylinuxraspbian"
|
||||
- container: wpilib/aarch64-cross-ubuntu:bionic-18.04
|
||||
artifact-name: Aarch64
|
||||
build-options: "-Ponlylinuxaarch64bionic"
|
||||
- container: wpilib/ubuntu-base:18.04
|
||||
artifact-name: Linux
|
||||
build-options: "-Dorg.gradle.jvmargs=-Xmx2g"
|
||||
name: "Build - ${{ matrix.artifact-name }}"
|
||||
runs-on: ubuntu-latest
|
||||
container: ${{ matrix.container }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set release environment variable
|
||||
run: echo "EXTRA_GRADLE_ARGS=-PreleaseMode" >> $GITHUB_ENV
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build -PbuildServer -PskipJavaFormat ${{ matrix.build-options }} ${{ env.EXTRA_GRADLE_ARGS }}
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ matrix.artifact-name }}
|
||||
path: build/allOutputs
|
||||
|
||||
build-host:
|
||||
env:
|
||||
MACOSX_DEPLOYMENT_TARGET: 10.14
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-2019
|
||||
artifact-name: Win64
|
||||
architecture: x64
|
||||
- os: windows-2019
|
||||
artifact-name: Win32
|
||||
architecture: x86
|
||||
- os: macOS-11
|
||||
artifact-name: macOS
|
||||
architecture: x64
|
||||
name: "Build - ${{ matrix.artifact-name }}"
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
architecture: ${{ matrix.architecture }}
|
||||
- name: Import Developer ID Certificate
|
||||
uses: wpilibsuite/import-signing-certificate@v1
|
||||
with:
|
||||
certificate-data: ${{ secrets.APPLE_CERTIFICATE_DATA }}
|
||||
certificate-passphrase: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }}
|
||||
keychain-password: ${{ secrets.APPLE_KEYCHAIN_PASSWORD }}
|
||||
if: |
|
||||
matrix.artifact-name == 'macOS' && (github.repository_owner == 'wpilibsuite' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')))
|
||||
- name: Set Keychain Lock Timeout
|
||||
run: security set-keychain-settings -lut 3600
|
||||
if: |
|
||||
matrix.artifact-name == 'macOS' && (github.repository_owner == 'wpilibsuite' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')))
|
||||
- name: Set release environment variable
|
||||
run: echo "EXTRA_GRADLE_ARGS=-PreleaseMode" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew build -PbuildServer -PskipJavaFormat ${{ env.EXTRA_GRADLE_ARGS }}
|
||||
- name: Sign Libraries with Developer ID
|
||||
run: ./gradlew build -PbuildServer -PskipJavaFormat -PdeveloperID=${{ secrets.APPLE_DEVELOPER_ID }} ${{ env.EXTRA_GRADLE_ARGS }}
|
||||
if: |
|
||||
matrix.artifact-name == 'macOS' && (github.repository_owner == 'wpilibsuite' &&
|
||||
(github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v')))
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ matrix.artifact-name }}
|
||||
path: build/allOutputs
|
||||
|
||||
build-documentation:
|
||||
name: "Build - Documentation"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 13
|
||||
- name: Install libclang-9
|
||||
run: sudo apt update && sudo apt install -y libclang-cpp9 libclang1-9
|
||||
- name: Set release environment variable
|
||||
run: echo "EXTRA_GRADLE_ARGS=-PreleaseMode" >> $GITHUB_ENV
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew docs:zipDocs -PbuildServer ${{ env.EXTRA_GRADLE_ARGS }}
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Documentation
|
||||
path: docs/build/outputs
|
||||
|
||||
combine:
|
||||
name: Combine
|
||||
needs: [build-docker, build-host, build-documentation]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
repository: wpilibsuite/build-tools
|
||||
- uses: actions/download-artifact@v2
|
||||
with:
|
||||
path: combiner/products/build/allOutputs
|
||||
- name: Flatten Artifacts
|
||||
run: rsync -a --delete combiner/products/build/allOutputs/*/* combiner/products/build/allOutputs/
|
||||
- name: Check version number exists
|
||||
run: |
|
||||
cat combiner/products/build/allOutputs/version.txt
|
||||
test -s combiner/products/build/allOutputs/version.txt
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 11
|
||||
- name: Combine
|
||||
if: |
|
||||
!startsWith(github.ref, 'refs/tags/v') &&
|
||||
github.ref != 'refs/heads/main'
|
||||
run: cd combiner && ./gradlew publish -Pallwpilib
|
||||
- name: Combine (Master)
|
||||
if: |
|
||||
github.repository_owner == 'wpilibsuite' &&
|
||||
github.ref == 'refs/heads/main'
|
||||
run: cd combiner && ./gradlew publish -Pallwpilib
|
||||
env:
|
||||
RUN_AZURE_ARTIFACTORY_RELEASE: "TRUE"
|
||||
ARTIFACTORY_PUBLISH_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
|
||||
ARTIFACTORY_PUBLISH_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
|
||||
- name: Combine (Release)
|
||||
if: |
|
||||
github.repository_owner == 'wpilibsuite' &&
|
||||
startsWith(github.ref, 'refs/tags/v')
|
||||
run: cd combiner && ./gradlew publish -Pallwpilib -PreleaseRepoPublish
|
||||
env:
|
||||
RUN_AZURE_ARTIFACTORY_RELEASE: "TRUE"
|
||||
ARTIFACTORY_PUBLISH_USERNAME: ${{ secrets.ARTIFACTORY_USERNAME }}
|
||||
ARTIFACTORY_PUBLISH_PASSWORD: ${{ secrets.ARTIFACTORY_PASSWORD }}
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Maven
|
||||
path: ~/releases
|
||||
100
.github/workflows/lint-format.yml
vendored
Normal file
100
.github/workflows/lint-format.yml
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
name: Lint and Format
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
branches-ignore:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
wpiformat:
|
||||
name: "wpiformat"
|
||||
runs-on: ubuntu-latest
|
||||
container: wpilib/roborio-cross-ubuntu:2022-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- 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.8
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Install clang-format
|
||||
run: |
|
||||
sudo sh -c "echo 'deb http://archive.ubuntu.com/ubuntu/ $(lsb_release -cs)-proposed restricted main multiverse universe' >> /etc/apt/sources.list.d/proposed-repositories.list"
|
||||
sudo apt-get update -q
|
||||
sudo apt-get install -y clang-format-12
|
||||
- name: Install wpiformat
|
||||
run: pip3 install wpiformat
|
||||
- name: Run
|
||||
run: wpiformat -clang 12
|
||||
- name: Check output
|
||||
run: git --no-pager diff --exit-code HEAD
|
||||
- name: Generate diff
|
||||
run: git diff HEAD > wpiformat-fixes.patch
|
||||
if: ${{ failure() }}
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: wpiformat fixes
|
||||
path: wpiformat-fixes.patch
|
||||
if: ${{ failure() }}
|
||||
tidy:
|
||||
name: "clang-tidy"
|
||||
runs-on: ubuntu-latest
|
||||
container: wpilib/roborio-cross-ubuntu:2022-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- 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.8
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Install clang-tidy
|
||||
run: |
|
||||
sudo sh -c "echo 'deb http://archive.ubuntu.com/ubuntu/ $(lsb_release -cs)-proposed restricted main multiverse universe' >> /etc/apt/sources.list.d/proposed-repositories.list"
|
||||
sudo apt-get update -q
|
||||
sudo apt-get install -y clang-tidy-12 clang-format-12
|
||||
- name: Install wpiformat
|
||||
run: pip3 install wpiformat
|
||||
- name: Create compile_commands.json
|
||||
run: ./gradlew generateCompileCommands -Ptoolchain-optional-roboRio
|
||||
- name: List changed files
|
||||
run: wpiformat -list-changed-files
|
||||
- name: Run clang-tidy
|
||||
run: wpiformat -clang 12 -no-format -tidy-changed -compile-commands=build/compile_commands/linuxx86-64 -vv
|
||||
javaformat:
|
||||
name: "Java format"
|
||||
runs-on: ubuntu-latest
|
||||
container: wpilib/ubuntu-base:18.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Run Java format
|
||||
run: ./gradlew javaFormat spotbugsMain spotbugsTest spotbugsDev
|
||||
- name: Check output
|
||||
run: git --no-pager diff --exit-code HEAD
|
||||
- name: Generate diff
|
||||
run: git diff HEAD > javaformat-fixes.patch
|
||||
if: ${{ failure() }}
|
||||
documentation:
|
||||
name: "Documentation"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: actions/setup-java@v1
|
||||
with:
|
||||
java-version: 13
|
||||
- name: Install libclang-9
|
||||
run: sudo apt update && sudo apt install -y libclang-cpp9 libclang1-9
|
||||
- name: Build with Gradle
|
||||
run: ./gradlew docs:zipDocs -PbuildServer -PdocWarningsAsErrors ${{ env.EXTRA_GRADLE_ARGS }}
|
||||
49
.github/workflows/sanitizers.yml
vendored
Normal file
49
.github/workflows/sanitizers.yml
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
name: Sanitizers
|
||||
|
||||
on: [pull_request, push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: asan
|
||||
cmake-flags: "-DCMAKE_BUILD_TYPE=Asan"
|
||||
ctest-env: ""
|
||||
ctest-flags: "-E 'wpiutil|ntcore|wpilibc'"
|
||||
- name: tsan
|
||||
cmake-flags: "-DCMAKE_BUILD_TYPE=Tsan"
|
||||
ctest-env: "TSAN_OPTIONS=second_deadlock_stack=1"
|
||||
ctest-flags: "-E 'ntcore|cscore|cameraserver|wpilibc|wpilibNewCommands'"
|
||||
- name: ubsan
|
||||
cmake-flags: "-DCMAKE_BUILD_TYPE=Ubsan"
|
||||
ctest-env: ""
|
||||
ctest-flags: ""
|
||||
name: "${{ matrix.name }}"
|
||||
runs-on: ubuntu-latest
|
||||
container: wpilib/roborio-cross-ubuntu:2022-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Dependencies
|
||||
run: |
|
||||
sudo add-apt-repository ppa:ubuntu-toolchain-r/test
|
||||
sudo apt install -y gcc-11 g++-11
|
||||
sudo update-alternatives \
|
||||
--install /usr/bin/gcc gcc /usr/bin/gcc-11 11 \
|
||||
--slave /usr/bin/g++ g++ /usr/bin/g++-11
|
||||
sudo update-alternatives --set gcc /usr/bin/gcc-11
|
||||
- name: Set up Python 3.8
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: 3.8
|
||||
- name: Install jinja
|
||||
run: python -m pip install jinja2
|
||||
- name: configure
|
||||
run: mkdir build && cd build && cmake ${{ matrix.cmake-flags }} ..
|
||||
- name: build
|
||||
working-directory: build
|
||||
run: cmake --build . -j$(nproc)
|
||||
- name: test
|
||||
working-directory: build
|
||||
run: ${{ matrix.ctest-env }} ctest --output-on-failure ${{ matrix.ctest-flags }}
|
||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -222,3 +222,12 @@ compile_commands.json
|
||||
# clang configuration and clangd cache
|
||||
.clang
|
||||
.clangd/
|
||||
.cache/
|
||||
|
||||
imgui.ini
|
||||
|
||||
# Bazel
|
||||
/.ijwb/
|
||||
/bazel-*
|
||||
user.bazelrc
|
||||
coverage_report/
|
||||
|
||||
14
.styleguide
14
.styleguide
@@ -2,15 +2,22 @@ cppHeaderFileInclude {
|
||||
\.h$
|
||||
\.hpp$
|
||||
\.inc$
|
||||
\.inl$
|
||||
}
|
||||
|
||||
cppSrcFileInclude {
|
||||
\.cpp$
|
||||
}
|
||||
|
||||
modifiableFileExclude {
|
||||
\.patch$
|
||||
gradlew
|
||||
}
|
||||
|
||||
generatedFileExclude {
|
||||
FRCNetComm\.java$
|
||||
simulation/gz_msgs/src/include/simulation/gz_msgs/msgs\.h$
|
||||
fieldImages/src/main/native/resources/
|
||||
}
|
||||
|
||||
repoRootNameOverride {
|
||||
@@ -18,16 +25,23 @@ repoRootNameOverride {
|
||||
}
|
||||
|
||||
includeOtherLibs {
|
||||
^Eigen/
|
||||
^cameraserver/
|
||||
^cscore
|
||||
^drake/
|
||||
^fmt/
|
||||
^hal/
|
||||
^imgui
|
||||
^implot
|
||||
^mockdata/
|
||||
^networktables/
|
||||
^ntcore
|
||||
^opencv2/
|
||||
^support/
|
||||
^units/
|
||||
^unsupported/
|
||||
^vision/
|
||||
^wpi/
|
||||
^wpigui
|
||||
^wpimath/
|
||||
}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) {year} FIRST. All Rights Reserved.{padding}*/
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"enableCppIntellisense": true,
|
||||
"currentLanguage": "cpp",
|
||||
"projectYear": "2020",
|
||||
"projectYear": "intellisense",
|
||||
"teamNumber": 0
|
||||
}
|
||||
|
||||
233
CMakeLists.txt
233
CMakeLists.txt
@@ -1,29 +1,33 @@
|
||||
# Disable in-source builds to prevent source tree corruption.
|
||||
if(" ${CMAKE_SOURCE_DIR}" STREQUAL " ${CMAKE_BINARY_DIR}")
|
||||
if(" ${CMAKE_CURRENT_SOURCE_DIR}" STREQUAL " ${CMAKE_CURRENT_BINARY_DIR}")
|
||||
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")
|
||||
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()
|
||||
|
||||
project(allwpilib)
|
||||
cmake_minimum_required(VERSION 3.3.0)
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/modules")
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
|
||||
|
||||
message(STATUS "Platform version: ${CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION}")
|
||||
|
||||
set(WPILIB_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
INCLUDE(CPack)
|
||||
|
||||
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT AND MSVC)
|
||||
set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/install" CACHE PATH "Default install dir on windows" FORCE)
|
||||
endif()
|
||||
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
|
||||
set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${CMAKE_BINARY_DIR}/jar)
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${WPILIB_BINARY_DIR}/lib)
|
||||
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${WPILIB_BINARY_DIR}/lib)
|
||||
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)
|
||||
@@ -44,23 +48,80 @@ IF("${isSystemDir}" STREQUAL "-1")
|
||||
SET(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/wpilib/lib")
|
||||
ENDIF("${isSystemDir}" STREQUAL "-1")
|
||||
|
||||
option(WITHOUT_JAVA "don't include java and JNI in the build" OFF)
|
||||
option(BUILD_SHARED_LIBS "build with shared libs (needed for JNI)" ON)
|
||||
option(WITHOUT_CSCORE "Don't build cscore (removes OpenCV requirement)" OFF)
|
||||
option(WITHOUT_ALLWPILIB "Don't build allwpilib (removes OpenCV requirement)" ON)
|
||||
option(WITH_TESTS "build unit tests (requires internet connection)" OFF)
|
||||
option(USE_EXTERNAL_HAL "Use a separately built HAL" OFF)
|
||||
# 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_CSCORE "Build cscore (needs OpenCV)" ON)
|
||||
option(WITH_WPIMATH "Build wpimath" ON)
|
||||
option(WITH_WPILIB "Build hal, wpilibc/j, and myRobot (needs OpenCV)" ON)
|
||||
option(WITH_OLD_COMMANDS "Build old commands" OFF)
|
||||
option(WITH_EXAMPLES "Build examples" OFF)
|
||||
option(WITH_TESTS "Build unit tests (requires internet connection)" ON)
|
||||
option(WITH_GUI "Build GUI items" ON)
|
||||
option(WITH_SIMULATION_MODULES "Build simulation modules" ON)
|
||||
|
||||
# Options for external HAL.
|
||||
option(WITH_EXTERNAL_HAL "Use a separately built HAL" OFF)
|
||||
set(EXTERNAL_HAL_FILE "" CACHE FILEPATH "Location to look for an external HAL CMake File")
|
||||
|
||||
# Options for using a package manager (vcpkg) for certain dependencies.
|
||||
option(USE_VCPKG_FMTLIB "Use vcpkg fmtlib" OFF)
|
||||
option(USE_VCPKG_LIBUV "Use vcpkg libuv" OFF)
|
||||
option(USE_VCPKG_EIGEN "Use vcpkg eigen" OFF)
|
||||
option(FLAT_INSTALL_WPILIB "Use a flat install directory" OFF)
|
||||
option(WITH_SIMULATION_MODULES "build simulation modules" OFF)
|
||||
|
||||
if (NOT WITHOUT_JAVA AND NOT BUILD_SHARED_LIBS)
|
||||
# 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")
|
||||
|
||||
# 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)
|
||||
endif()
|
||||
|
||||
# We always want flat install with MSVC.
|
||||
if (MSVC)
|
||||
set(WITH_FLAT_INSTALL ON)
|
||||
endif()
|
||||
|
||||
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
|
||||
WITHOUT_JAVA=ON
|
||||
WITH_JAVA=OFF
|
||||
")
|
||||
endif()
|
||||
|
||||
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 "${OPENCV_JAVA_INSTALL_DIR}" STREQUAL "")
|
||||
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 "
|
||||
FATAL: Cannot build simulation modules with wpilib disabled.
|
||||
Enable wpilib by setting WITH_WPILIB=ON
|
||||
")
|
||||
endif()
|
||||
|
||||
if (NOT WITH_WPIMATH AND WITH_WPILIB)
|
||||
message(FATAL_ERROR "
|
||||
FATAL: Cannot build wpilib without wpimath.
|
||||
Enable wpimath by setting WITH_WPIMATH=ON
|
||||
")
|
||||
endif()
|
||||
|
||||
@@ -70,7 +131,7 @@ set( main_lib_dest wpilib/lib )
|
||||
set( java_lib_dest wpilib/java )
|
||||
set( jni_lib_dest wpilib/jni )
|
||||
|
||||
if (MSVC OR FLAT_INSTALL_WPILIB)
|
||||
if (WITH_FLAT_INSTALL)
|
||||
set (wpilib_config_dir ${wpilib_dest})
|
||||
else()
|
||||
set (wpilib_config_dir share/wpilib)
|
||||
@@ -84,25 +145,102 @@ if (USE_VCPKG_EIGEN)
|
||||
set (EIGEN_VCPKG_REPLACE "find_package(Eigen3 CONFIG)")
|
||||
endif()
|
||||
|
||||
if (MSVC OR FLAT_INSTALL_WPILIB)
|
||||
find_package(LIBSSH 0.7.1)
|
||||
|
||||
if (WITH_FLAT_INSTALL)
|
||||
set(WPIUTIL_DEP_REPLACE "include($\{SELF_DIR\}/wpiutil-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)")
|
||||
set(WPILIBOLDCOMMANDS_DEP_REPLACE "include(\${SELF_DIR}/wpilibOldcommands-config.cmake)")
|
||||
else()
|
||||
set(WPIUTIL_DEP_REPLACE "find_dependency(wpiutil)")
|
||||
set(NTCORE_DEP_REPLACE "find_dependency(ntcore)")
|
||||
set(CSCORE_DEP_REPLACE_IMPL "find_dependency(cscore)")
|
||||
set(CAMERASERVER_DEP_REPLACE_IMPL "find_dependency(cameraserver)")
|
||||
set(HAL_DEP_REPLACE_IMPL "find_dependency(hal)")
|
||||
set(WPIMATH_DEP_REPLACE "find_dependency(wpimath)")
|
||||
set(WPILIBC_DEP_REPLACE_IMPL "find_dependency(wpilibc)")
|
||||
set(WPILIBNEWCOMMANDS_DEP_REPLACE "find_dependency(wpilibNewCommands)")
|
||||
set(WPILIBOLDCOMMANDS_DEP_REPLACE "find_dependency(wpilibOldCommands)")
|
||||
endif()
|
||||
|
||||
set(FILENAME_DEP_REPLACE "get_filename_component(SELF_DIR \"$\{CMAKE_CURRENT_LIST_FILE\}\" PATH)")
|
||||
set(SELF_DIR "$\{SELF_DIR\}")
|
||||
|
||||
get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
|
||||
if(isMultiConfig)
|
||||
if(NOT "Asan" IN_LIST CMAKE_CONFIGURATION_TYPES)
|
||||
list(APPEND CMAKE_CONFIGURATION_TYPES Asan)
|
||||
endif()
|
||||
if(NOT "Tsan" IN_LIST CMAKE_CONFIGURATION_TYPES)
|
||||
list(APPEND CMAKE_CONFIGURATION_TYPES Tsan)
|
||||
endif()
|
||||
if(NOT "Ubsan" IN_LIST CMAKE_CONFIGURATION_TYPES)
|
||||
list(APPEND CMAKE_CONFIGURATION_TYPES Ubsan)
|
||||
endif()
|
||||
else()
|
||||
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)
|
||||
message(FATAL_ERROR "Invalid build type: ${CMAKE_BUILD_TYPE}")
|
||||
endif()
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
if (WITH_TESTS)
|
||||
enable_testing()
|
||||
add_subdirectory(googletest)
|
||||
@@ -112,25 +250,50 @@ endif()
|
||||
add_subdirectory(wpiutil)
|
||||
add_subdirectory(ntcore)
|
||||
|
||||
if (NOT WITHOUT_CSCORE)
|
||||
if (WITH_WPIMATH)
|
||||
add_subdirectory(wpimath)
|
||||
endif()
|
||||
|
||||
if (WITH_GUI)
|
||||
add_subdirectory(fieldImages)
|
||||
add_subdirectory(imgui)
|
||||
add_subdirectory(wpigui)
|
||||
add_subdirectory(glass)
|
||||
add_subdirectory(outlineviewer)
|
||||
if (LIBSSH_FOUND)
|
||||
add_subdirectory(roborioteamnumbersetter)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (WITH_WPILIB OR WITH_SIMULATION_MODULES)
|
||||
set(HAL_DEP_REPLACE ${HAL_DEP_REPLACE_IMPL})
|
||||
add_subdirectory(hal)
|
||||
endif()
|
||||
|
||||
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)
|
||||
if (NOT WITHOUT_ALLWPILIB)
|
||||
set(HAL_DEP_REPLACE ${HAL_DEP_REPLACE_IMPL})
|
||||
set(WPILIBC_DEP_REPLACE ${WPILIBC_DEP_REPLACE_IMPL})
|
||||
add_subdirectory(hal)
|
||||
add_subdirectory(wpilibj)
|
||||
add_subdirectory(wpilibc)
|
||||
add_subdirectory(myRobot)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (WITH_SIMULATION_MODULES AND NOT USE_EXTERNAL_HAL)
|
||||
add_subdirectory(imgui)
|
||||
if (WITH_WPILIB)
|
||||
set(WPILIBC_DEP_REPLACE ${WPILIBC_DEP_REPLACE_IMPL})
|
||||
add_subdirectory(wpilibj)
|
||||
add_subdirectory(wpilibc)
|
||||
add_subdirectory(wpilibNewCommands)
|
||||
if (WITH_OLD_COMMANDS)
|
||||
add_subdirectory(wpilibOldCommands)
|
||||
endif()
|
||||
if (WITH_EXAMPLES)
|
||||
add_subdirectory(wpilibcExamples)
|
||||
endif()
|
||||
add_subdirectory(myRobot)
|
||||
endif()
|
||||
|
||||
if (WITH_SIMULATION_MODULES AND NOT WITH_EXTERNAL_HAL)
|
||||
add_subdirectory(simulation)
|
||||
endif()
|
||||
|
||||
configure_file(wpilib-config.cmake.in ${CMAKE_BINARY_DIR}/wpilib-config.cmake )
|
||||
install(FILES ${CMAKE_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 ${wpilib_config_dir})
|
||||
|
||||
131
CODE_OF_CONDUCT.md
Normal file
131
CODE_OF_CONDUCT.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
We as members, contributors, and leaders pledge to make participation in our
|
||||
community a harassment-free experience for everyone, regardless of age, body
|
||||
size, visible or invisible disability, ethnicity, sex characteristics, gender
|
||||
identity and expression, level of experience, education, socio-economic status,
|
||||
nationality, personal appearance, race, religion, or sexual identity
|
||||
and orientation.
|
||||
|
||||
We pledge to act and interact in ways that contribute to an open, welcoming,
|
||||
diverse, inclusive, and healthy community.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to a positive environment for our
|
||||
community include:
|
||||
|
||||
* Exhibiting Gracious Professionalism® at all times. Gracious Professionalism
|
||||
is a way of doing things that encourages high-quality work, emphasizes the
|
||||
value of others, and respects individuals and the community.
|
||||
* Demonstrating empathy and kindness toward other people
|
||||
* Being respectful of differing opinions, viewpoints, and experiences
|
||||
* Giving and gracefully accepting constructive feedback
|
||||
* Accepting responsibility and apologizing to those affected by our mistakes,
|
||||
and learning from the experience
|
||||
* Focusing on what is best not just for us as individuals, but for the
|
||||
overall community
|
||||
|
||||
Examples of unacceptable behavior include:
|
||||
|
||||
* The use of sexualized language or imagery, and sexual attention or
|
||||
advances of any kind
|
||||
* Trolling, insulting or derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or email
|
||||
address, without their explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Enforcement Responsibilities
|
||||
|
||||
Community leaders are responsible for clarifying and enforcing our standards of
|
||||
acceptable behavior and will take appropriate and fair corrective action in
|
||||
response to any behavior that they deem inappropriate, threatening, offensive,
|
||||
or harmful.
|
||||
|
||||
Community leaders have the right and responsibility to remove, edit, or reject
|
||||
comments, commits, code, wiki edits, issues, and other contributions that are
|
||||
not aligned to this Code of Conduct, and will communicate reasons for moderation
|
||||
decisions when appropriate.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all community spaces, and also applies when
|
||||
an individual is officially representing the community in public spaces.
|
||||
Examples of representing our community include using an official e-mail address,
|
||||
posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported to the community leaders responsible for enforcement at
|
||||
[conduct@wpilib.org](mailto:conduct@wpilib.org).
|
||||
All complaints will be reviewed and investigated promptly and fairly.
|
||||
|
||||
All community leaders are obligated to respect the privacy and security of the
|
||||
reporter of any incident.
|
||||
|
||||
## Enforcement Guidelines
|
||||
|
||||
Community leaders will follow these Community Impact Guidelines in determining
|
||||
the consequences for any action they deem in violation of this Code of Conduct:
|
||||
|
||||
### 1. Correction
|
||||
|
||||
**Community Impact**: Use of inappropriate language or other behavior deemed
|
||||
unprofessional or unwelcome in the community.
|
||||
|
||||
**Consequence**: A private, written warning from community leaders, providing
|
||||
clarity around the nature of the violation and an explanation of why the
|
||||
behavior was inappropriate. A public apology may be requested.
|
||||
|
||||
### 2. Warning
|
||||
|
||||
**Community Impact**: A violation through a single incident or series
|
||||
of actions.
|
||||
|
||||
**Consequence**: A warning with consequences for continued behavior. No
|
||||
interaction with the people involved, including unsolicited interaction with
|
||||
those enforcing the Code of Conduct, for a specified period of time. This
|
||||
includes avoiding interactions in community spaces as well as external channels
|
||||
like social media. Violating these terms may lead to a temporary or
|
||||
permanent ban.
|
||||
|
||||
### 3. Temporary Ban
|
||||
|
||||
**Community Impact**: A serious violation of community standards, including
|
||||
sustained inappropriate behavior.
|
||||
|
||||
**Consequence**: A temporary ban from any sort of interaction or public
|
||||
communication with the community for a specified period of time. No public or
|
||||
private interaction with the people involved, including unsolicited interaction
|
||||
with those enforcing the Code of Conduct, is allowed during this period.
|
||||
Violating these terms may lead to a permanent ban.
|
||||
|
||||
### 4. Permanent Ban
|
||||
|
||||
**Community Impact**: Demonstrating a pattern of violation of community
|
||||
standards, including sustained inappropriate behavior, harassment of an
|
||||
individual, or aggression toward or disparagement of classes of individuals.
|
||||
|
||||
**Consequence**: A permanent ban from any sort of public interaction within
|
||||
the community.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
||||
version 2.0, available at
|
||||
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
|
||||
|
||||
Community Impact Guidelines were inspired by [Mozilla's code of conduct
|
||||
enforcement ladder](https://github.com/mozilla/diversity).
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see the FAQ at
|
||||
https://www.contributor-covenant.org/faq. Translations are available at
|
||||
https://www.contributor-covenant.org/translations.
|
||||
@@ -1,6 +1,6 @@
|
||||
# Contributing to WPILib
|
||||
|
||||
So you want to contribute your changes back to WPILib. Great! We have a few contributing rules that will help you make sure your changes will be accepted into the project. Please remember to follow the rules written here, and behave with Gracious Professionalism.
|
||||
So you want to contribute your changes back to WPILib. Great! We have a few contributing rules that will help you make sure your changes will be accepted into the project. Please remember to follow the rules in the [code of conduct](https://github.com/wpilibsuite/allwpilib/blob/main/CODE_OF_CONDUCT.md), and behave with Gracious Professionalism.
|
||||
|
||||
- [General Contribution Rules](#general-contribution-rules)
|
||||
- [What to Contribute](#what-to-contribute)
|
||||
@@ -37,20 +37,22 @@ So you want to contribute your changes back to WPILib. Great! We have a few cont
|
||||
|
||||
## Coding Guidelines
|
||||
|
||||
WPILib uses modified Google style guides for both C++ and Java, which can be found in the [styleguide repository](https://github.com/wpilibsuite/styleguide). Autoformatters are available for many popular editors at https://github.com/google/styleguide. Running wpiformat is required for all contributions and is enforced by our continuous integration system. We currently use clang-format 6.0 with wpiformat.
|
||||
WPILib uses modified Google style guides for both C++ and Java, which can be found in the [styleguide repository](https://github.com/wpilibsuite/styleguide). Autoformatters are available for many popular editors at https://github.com/google/styleguide. Running wpiformat is required for all contributions and is enforced by our continuous integration system. We currently use clang-format 10.0 with wpiformat.
|
||||
|
||||
While the library should be fully formatted according to the styles, additional elements of the style guide were not followed when the library was initially created. All new code should follow the guidelines. If you are looking for some easy ramp-up tasks, finding areas that don't follow the style guide and fixing them is very welcome.
|
||||
|
||||
When writing math expressions in documentation, use https://www.unicodeit.net/ to convert LaTeX to a Unicode equivalent that's easier to read. Not all expressions will translate (e.g., superscripts of superscripts) so focus on making it readable by someone who isn't familiar with LaTeX. If content on multiple lines needs to be aligned in Doxygen/Javadoc comments (e.g., integration/summation limits, matrices packed with square brackets and superscripts for them), put them in @verbatim/@endverbatim blocks in Doxygen or `<pre>` tags in Javadoc so they render with monospace font.
|
||||
|
||||
## Submitting Changes
|
||||
|
||||
### Pull Request Format
|
||||
|
||||
Changes should be submitted as a Pull Request against the master branch of WPILib. For most changes, we ask that you squash your changes down to a single commit. For particularly large changes, multiple commits are ok, but assume one commit unless asked otherwise. No change will be merged unless it is up to date with the current master. We will also not merge any changes with merge commits in them; please rebase off of master before submitting a pull request. We do this to make sure that the git history isn't too cluttered.
|
||||
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.
|
||||
|
||||
### Merge Process
|
||||
|
||||
When you first submit changes, Travis-CI will attempt to run `./gradlew check` on your change. If this fails, you will need to fix any issues that it sees. Once Travis 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 Jenkins 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.
|
||||
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.
|
||||
|
||||
## Licensing
|
||||
|
||||
By contributing to WPILib, you agree that your code will be distributed with WPILib, and licensed under the license for the WPILib project. You should not contribute code that you do not have permission to relicense in this manner. This includes code that is licensed under the GPL that you do not have permission to relicense, as WPILib is not released under a copyleft license. Our license is the 3-clause BSD license, which you can find [here](LICENSE.txt).
|
||||
By contributing to WPILib, you agree that your code will be distributed with WPILib, and licensed under the license for the WPILib project. You should not contribute code that you do not have permission to relicense in this manner. This includes code that is licensed under the GPL that you do not have permission to relicense, as WPILib is not released under a copyleft license. Our license is the 3-clause BSD license, which you can find [here](LICENSE.md).
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
# Faster Builds for Developers
|
||||
|
||||
When you run `./gradlew build`, it builds EVERYTHING. This means debug and release builds for desktop and all installed cross compilers. For many developers, this is way too much, and causes much developer pain.
|
||||
|
||||
To help with some of these things, common tasks have shortcuts to only build necessary things for common development and testing tasks.
|
||||
|
||||
## Development (Desktop)
|
||||
|
||||
For projects `wpiutil`, `ntcore`, `cscore`, `hal` `wpilibOldCommands`, `wpilibNewCommands` and `cameraserver`, a `testDesktopJava` and a `testDesktopCpp` task exists. These can be ran with `./gradlew :projectName:task`, and will only build the minimum things required to run those tests.
|
||||
|
||||
For `wpilibc`, a `testDesktopCpp` task exists. For `wpilibj`, a `testDesktopJava` task exists.
|
||||
|
||||
For `wpilibcExamples`, a `buildDesktopCpp` task exists (These can't be ran, but they can compile).
|
||||
|
||||
For `wpilibjExamples`, a `buildDesktopJava` task exists.
|
||||
24
LICENSE.md
Normal file
24
LICENSE.md
Normal file
@@ -0,0 +1,24 @@
|
||||
Copyright (c) 2009-2022 FIRST and other WPILib contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of FIRST, WPILib, nor the names of other WPILib
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY FIRST AND OTHER WPILIB CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST 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.
|
||||
24
LICENSE.txt
24
LICENSE.txt
@@ -1,24 +0,0 @@
|
||||
Copyright (c) 2009-2018 FIRST
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* 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.
|
||||
* Neither the name of the FIRST 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 FIRST AND CONTRIBUTORS``AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY NONINFRINGEMENT AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL FIRST 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.
|
||||
27
MAINTAINERS.md
Normal file
27
MAINTAINERS.md
Normal file
@@ -0,0 +1,27 @@
|
||||
## Publishing Third Party Dependencies
|
||||
Currently the 3rd party deps are imgui, opencv, and google test
|
||||
|
||||
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).
|
||||
A variable needs to be added called `RUN_AZURE_ARTIFACTORY_RELEASE`, with a value of `true`. Then when the pipeline gets started, the final build outputs will be updated to artifactory.
|
||||
|
||||
To use newer versions of C++ dependencies, in `shared/config.gradle`, update the version related to the specific dependency.
|
||||
For Java dependencies, there is likely a file related to the specific dependency in the shared folder. Update the version in there.
|
||||
|
||||
Note, changing artifact locations (This includes changing the artifact year currently, I have an issue open to change this) requires updating the `native-utils` plugin
|
||||
|
||||
## Publishing allwpilib
|
||||
allwpilib publishes to the development repo on every push to main. To publish a release build, upload a new tag, and a release will automatically be built and published.
|
||||
|
||||
## Publishing desktop tools
|
||||
Desktop tools publish to the development repo on every push to main. To publish a release build, upload a new tag, and a release will automatically be built and published.
|
||||
|
||||
## 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.
|
||||
|
||||
## 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.
|
||||
@@ -9,7 +9,7 @@ We provide two repositories. These repositories are:
|
||||
* (Development) https://frcmaven.wpi.edu/artifactory/development/
|
||||
|
||||
The release repository is where official WPILib releases are pushed.
|
||||
The development repository is where development releases of every commit to [master](https://github.com/wpilibsuite/allwpilib/tree/master) is pushed.
|
||||
The development repository is where development releases of every commit to [main](https://github.com/wpilibsuite/allwpilib/tree/main) is pushed.
|
||||
|
||||
## Artifact classifiers
|
||||
We provide two base types of artifacts.
|
||||
@@ -69,12 +69,37 @@ All artifacts are based at `edu.wpi.first.artifactname` in the repository.
|
||||
|
||||
* wpiutil
|
||||
|
||||
* hal
|
||||
* wpiutil
|
||||
* wpigui
|
||||
* imgui
|
||||
|
||||
* ntcore
|
||||
* wpiutil
|
||||
|
||||
* wpimath
|
||||
* wpiutil
|
||||
|
||||
* glass/libglass
|
||||
* wpiutil
|
||||
* wpimath
|
||||
* wpigui
|
||||
|
||||
* glass/libglassnt
|
||||
* wpiutil
|
||||
* ntcore
|
||||
* wpimath
|
||||
* wpigui
|
||||
|
||||
* hal
|
||||
* wpiutil
|
||||
|
||||
* halsim
|
||||
* wpiutil
|
||||
* ntcore
|
||||
* wpimath
|
||||
* wpigui
|
||||
* libglass
|
||||
* libglassnt
|
||||
|
||||
* cscore
|
||||
* opencv
|
||||
* wpiutil
|
||||
@@ -85,7 +110,6 @@ All artifacts are based at `edu.wpi.first.artifactname` in the repository.
|
||||
* opencv
|
||||
* wpiutil
|
||||
|
||||
|
||||
* wpilibj
|
||||
* hal
|
||||
* cameraserver
|
||||
@@ -93,10 +117,39 @@ All artifacts are based at `edu.wpi.first.artifactname` in the repository.
|
||||
* cscore
|
||||
* wpiutil
|
||||
|
||||
|
||||
* wpilibc
|
||||
* hal
|
||||
* cameraserver
|
||||
* ntcore
|
||||
* cscore
|
||||
* wpimath
|
||||
* wpiutil
|
||||
|
||||
* wpilibNewCommands
|
||||
* wpilibc
|
||||
* hal
|
||||
* cameraserver
|
||||
* ntcore
|
||||
* cscore
|
||||
* wpimath
|
||||
* wpiutil
|
||||
|
||||
* wpilibOldCommands
|
||||
* wpilibc
|
||||
* hal
|
||||
* cameraserver
|
||||
* ntcore
|
||||
* cscore
|
||||
* wpiutil
|
||||
|
||||
|
||||
### Third Party Artifacts
|
||||
|
||||
This repository provides the builds of the following third party software.
|
||||
|
||||
All artifacts are based at `edu.wpi.first.thirdparty.frcYEAR` in the repository.
|
||||
|
||||
* googletest
|
||||
* imgui
|
||||
* opencv
|
||||
* libssh
|
||||
|
||||
93
OtherVersions.md
Normal file
93
OtherVersions.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# Installing Development Builds
|
||||
|
||||
This article contains instructions on building projects using a development build and a local WPILib build.
|
||||
|
||||
**Note:** This only applies to Java/C++ teams.
|
||||
|
||||
## Development Build
|
||||
|
||||
Development builds are the per-commit build hosted everytime a commit is pushed to the [allwpilib](https://github.com/wpilibsuite/allwpilib/) repository. These builds are then hosted on [artifactory](https://frcmaven.wpi.edu/artifactory/webapp/#/home).
|
||||
|
||||
In order to build a project using a development build, find the build.gradle file and open it. Then, add the following code below the plugin section and replace YEAR with the year of the development version.
|
||||
|
||||
```groovy
|
||||
wpi.maven.useLocal = false
|
||||
wpi.maven.useDevelopment = true
|
||||
wpi.versions.wpilibVersion = '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.
|
||||
|
||||
Java
|
||||
```groovy
|
||||
plugins {
|
||||
id "java"
|
||||
id "edu.wpi.first.GradleRIO" version "2022.1.1"
|
||||
}
|
||||
|
||||
wpi.maven.useLocal = false
|
||||
wpi.maven.useDevelopment = true
|
||||
wpi.versions.wpilibVersion = '2022.+'
|
||||
wpi.versions.wpimathVersion = '2022.+'
|
||||
```
|
||||
|
||||
C++
|
||||
```groovy
|
||||
plugins {
|
||||
id "cpp"
|
||||
id "google-test-test-suite"
|
||||
id "edu.wpi.first.GradleRIO" version "2022.1.1"
|
||||
}
|
||||
|
||||
wpi.maven.useLocal = false
|
||||
wpi.maven.useDevelopment = true
|
||||
wpi.versions.wpilibVersion = '2022.+'
|
||||
wpi.versions.wpimathVersion = '2022.+'
|
||||
```
|
||||
|
||||
## Local Build
|
||||
|
||||
Building with a local build is very similar to building with a development build. Ensure you have built and published WPILib by following the instructions attached [here](https://github.com/wpilibsuite/allwpilib#building-wpilib). Next, find the ``build.gradle`` file in your robot project and open it. Then, add the following code below the plugin section and replace ``YEAR`` with the year of the local version.
|
||||
|
||||
Java
|
||||
```groovy
|
||||
plugins {
|
||||
id "java"
|
||||
id "edu.wpi.first.GradleRIO" version "2022.1.1"
|
||||
}
|
||||
|
||||
wpi.maven.useLocal = false
|
||||
wpi.maven.useFrcMavenLocalDevelopment = true
|
||||
wpi.versions.wpilibVersion = 'YEAR.424242.+'
|
||||
wpi.versions.wpimathVersion = 'YEAR.424242.+'
|
||||
```
|
||||
|
||||
C++
|
||||
```groovy
|
||||
plugins {
|
||||
id "cpp"
|
||||
id "google-test-test-suite"
|
||||
id "edu.wpi.first.GradleRIO" version "2022.1.1"
|
||||
}
|
||||
|
||||
wpi.maven.useLocal = false
|
||||
wpi.maven.useFrcMavenLocalDevelopment = true
|
||||
wpi.versions.wpilibVersion = 'YEAR.424242.+'
|
||||
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 `admin` account (`lvuser` will fail to run in many cases). In the admin home directory, a file for each deploy type will exist (`myRobotCpp`, `myRobotCppStatic` and `myRobotJavaRun`). These can be run to start up the corresponding project.
|
||||
@@ -1,6 +1,6 @@
|
||||
# WPILib CMake Support
|
||||
|
||||
WPILib is normally built with Gradle, however for some systems, such a linux based coprocessors, Gradle doesn't work correctly, especially if cscore is needed, which requires OpenCV. 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 it is supported on Windows, these docs will only go over Linux builds.
|
||||
|
||||
## Libraries that get built
|
||||
* wpiutil
|
||||
@@ -9,56 +9,69 @@ WPILib is normally built with Gradle, however for some systems, such a linux bas
|
||||
* cameraserver
|
||||
* hal
|
||||
* wpilib
|
||||
* halsim
|
||||
* wpigui
|
||||
* wpimath
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
The most common prerequisite is going to be OpenCV. OpenCV needs to be findable by cmake. On systems like the Jetson, this is installed by default. Otherwise, you will need to build cmake from source and install it.
|
||||
The most common prerequisite is going to be OpenCV. 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.
|
||||
|
||||
In addition, if you want JNI and Java, you will need a JDK of at least version 8 installed. In addition, you need a `JAVA_HOME` environment variable set properly and set to the jdk directory.
|
||||
In addition, 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 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.
|
||||
|
||||
## Build Options
|
||||
|
||||
The following build options are available:
|
||||
|
||||
* WITHOUT_JAVA (OFF Default)
|
||||
* Enabling this option will disable Java and JNI builds. If this is off, `BUILD_SHARED_LIBS` must be on. Otherwise cmake will error.
|
||||
* BUILD_SHARED_LIBS (ON Default)
|
||||
* Disabling this option will cause cmake to build static libraries instead of shared libraries. If this is off, `WITHOUT_JAVA` must be on. Otherwise cmake will error.
|
||||
* WITHOUT_CSCORE (OFF Default)
|
||||
* Enabling this option will cause cscore to not be built. This will also implicitly disable cameraserver, the hal and wpilib as well, irrespective of their specific options. If this is on, the opencv build requirement is removed.
|
||||
* WITHOUT_ALLWPILIB (ON Default)
|
||||
* Disabling this option will build the hal and wpilib 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.
|
||||
* USE_EXTERNAL_HAL (OFF Default)
|
||||
* `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.
|
||||
* `WITH_TESTS` (ON Default)
|
||||
* This option will build C++ unit tests. These can be run via `make test`.
|
||||
* `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.
|
||||
* `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_SIMULATION_MODULES` (ON Default)
|
||||
* This option will build simulation modules, including wpigui and the HALSim plugins.
|
||||
* `WITH_EXTERNAL_HAL` (OFF Default)
|
||||
* TODO
|
||||
* EXTERNAL_HAL_FILE
|
||||
* `EXTERNAL_HAL_FILE`
|
||||
* TODO
|
||||
* `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!
|
||||
|
||||
## Build Setup
|
||||
|
||||
The WPILib CMake build does not allow in source builds. Because the `build` directory is used by gradle, we recommend a `buildcmake` directory in the root. This folder is included in the gitignore.
|
||||
The WPILib CMake build does not allow in source builds. Because the `build` directory is used by Gradle, we recommend a `build-cmake` directory in the root. This folder is included in the gitignore.
|
||||
|
||||
Once you have a build folder, run cmake configuration in that build directory with the following command.
|
||||
Once you have a build folder, run CMake configuration in that build directory with the following command.
|
||||
|
||||
```
|
||||
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 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.
|
||||
https://cmake.org/cmake/help/v3.0/manual/ccmake.1.html
|
||||
Here 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.
|
||||
|
||||
## 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 `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.
|
||||
|
||||
```
|
||||
make -jx
|
||||
```
|
||||
|
||||
The `ninja` generator is also supported, and can be enabled by passing `-GNinja` to the initial `cmake` command.
|
||||
|
||||
## 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.
|
||||
@@ -79,7 +92,7 @@ project(vision_app) # Project Name Here
|
||||
|
||||
find_package(wpilib REQUIRED)
|
||||
|
||||
add_executable(my_vision_app main.cpp) # exectuable name as first parameter
|
||||
add_executable(my_vision_app main.cpp) # executable name as first parameter
|
||||
target_link_libraries(my_vision_app cameraserver ntcore cscore wpiutil)
|
||||
```
|
||||
|
||||
@@ -135,4 +148,4 @@ 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 `-DWITHOUT_JAVA=ON`.
|
||||
In addition, if you do not need Java, you can disable it with `-DWITH_JAVA=OFF`.
|
||||
|
||||
93
README.md
93
README.md
@@ -1,21 +1,30 @@
|
||||
# WPILib Project
|
||||
|
||||
[](https://dev.azure.com/wpilib/wpilib/_build/latest?definitionId=1)
|
||||

|
||||
[](https://first.wpi.edu/wpilib/allwpilib/docs/development/cpp/)
|
||||
[](https://first.wpi.edu/wpilib/allwpilib/docs/development/java/)
|
||||
|
||||
Welcome to the WPILib project. This repository contains the HAL, WPILibJ, and WPILibC projects. These are the core libraries for creating robot programs for the roboRIO.
|
||||
|
||||
- [WPILib Mission](#wpilib-mission)
|
||||
- [WPILib Project](#wpilib-project)
|
||||
- [WPILib Mission](#wpilib-mission)
|
||||
- [Building WPILib](#building-wpilib)
|
||||
- [Requirements](#requirements)
|
||||
- [Setup](#setup)
|
||||
- [Building](#building)
|
||||
- [Publishing](#publishing)
|
||||
- [Structure and Organization](#structure-and-organization)
|
||||
- [Requirements](#requirements)
|
||||
- [Setup](#setup)
|
||||
- [Building](#building)
|
||||
- [Faster builds](#faster-builds)
|
||||
- [Using Development Builds](#using-development-builds)
|
||||
- [Custom toolchain location](#custom-toolchain-location)
|
||||
- [Gazebo simulation](#gazebo-simulation)
|
||||
- [Formatting/linting with wpiformat](#formattinglinting-with-wpiformat)
|
||||
- [CMake](#cmake)
|
||||
- [Publishing](#publishing)
|
||||
- [Structure and Organization](#structure-and-organization)
|
||||
- [Contributing to WPILib](#contributing-to-wpilib)
|
||||
|
||||
## 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.txt).
|
||||
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).
|
||||
|
||||
# Building WPILib
|
||||
|
||||
@@ -23,19 +32,26 @@ Using Gradle makes building WPILib very straightforward. It only has a few depen
|
||||
|
||||
## Requirements
|
||||
|
||||
- A C++ compiler
|
||||
- On Linux, GCC works fine
|
||||
- On Windows, you need Visual Studio 2019 (the free community edition works fine).
|
||||
Make sure to select the C++ Programming Language for installation
|
||||
- [ARM Compiler Toolchain](https://github.com/wpilibsuite/toolchain-builder/releases)
|
||||
* Note that for 2020 and beyond, you should use version 7 or greater of GCC
|
||||
- Doxygen (Only required if you want to build the C++ documentation)
|
||||
- [JDK 11](https://adoptopenjdk.net/)
|
||||
- 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
|
||||
- C++ compiler
|
||||
- On Linux, install GCC 8 or greater
|
||||
- On Windows, install [Visual Studio Community 2022 or 2019](https://visualstudio.microsoft.com/vs/community/) and select the C++ programming language during installation (Gradle can't use the build tools for Visual Studio)
|
||||
- On macOS, install the Xcode command-line build tools via `xcode-select --install`
|
||||
- ARM compiler toolchain
|
||||
- Run `./gradlew installRoboRioToolchain` after cloning this repository
|
||||
- If the WPILib installer was used, this toolchain is already installed
|
||||
- Raspberry Pi toolchain (optional)
|
||||
- Run `./gradlew installRaspbianToolchain` after cloning this repository
|
||||
|
||||
## Setup
|
||||
|
||||
Clone the WPILib repository. If the toolchains are not installed, install them, and make sure they are available on the system PATH.
|
||||
Clone the WPILib repository and follow the instructions above for installing any required tooling.
|
||||
|
||||
See the [styleguide README](https://github.com/wpilibsuite/styleguide/blob/master/README.md) for wpiformat setup instructions.
|
||||
See the [styleguide README](https://github.com/wpilibsuite/styleguide/blob/main/README.md) for wpiformat setup instructions.
|
||||
|
||||
## Building
|
||||
|
||||
@@ -51,16 +67,40 @@ To build a specific subproject, such as WPILibC, you must access the subproject
|
||||
./gradlew :wpilibc:build
|
||||
```
|
||||
|
||||
The gradlew wrapper only exists in the root of the main project, so be sure to run all commands from there. All of the subprojects have build tasks that can be run. Gradle automatically determines and rebuilds dependencies, so if you make a change in the HAL and then run `./gradlew :wpilibc:build`, the HAL will be rebuilt, then WPILibC.
|
||||
|
||||
There are a few tasks other than `build` available. To see them, run the meta-task `tasks`. This will print a list of all available tasks, with a description of each task.
|
||||
|
||||
If opening from a fresh clone, generated java dependencies will not exist. Most IDEs will not run the generation tasks, which will cause lots of IDE errors. Manually run `./gradlew compileJava` from a terminal to run all the compile tasks, and then refresh your IDE's configuration (In VS Code open settings.gradle and save).
|
||||
|
||||
### Faster builds
|
||||
|
||||
`./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.
|
||||
|
||||
`testDesktopCpp` and `testDesktopJava` tasks also exist for the projects `wpiutil`, `ntcore`, `cscore`, `hal` `wpilibOldCommands`, `wpilibNewCommands` and `cameraserver`. 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.
|
||||
|
||||
### Using Development Builds
|
||||
|
||||
Please read the documentation available [here](OtherVersions.md)
|
||||
|
||||
### Custom toolchain location
|
||||
|
||||
If you have installed the FRC Toolchain to a directory other than the default, or if the Toolchain location is not on your System PATH, you can pass the `toolChainPath` property to specify where it is located. Example:
|
||||
|
||||
```bash
|
||||
./gradlew build -PtoolChainPath=some/path/to/frc/toolchain/bin
|
||||
```
|
||||
|
||||
If you also want simulation to be built, add -PmakeSim. This requires gazebo_transport. We have tested on 14.04 and 15.05, but any correct install of Gazebo should work, even on Windows if you build Gazebo from source. Correct means CMake needs to be able to find gazebo-config.cmake. See [The Gazebo website](https://gazebosim.org/) for installation instructions.
|
||||
### Gazebo simulation
|
||||
|
||||
If you also want to force building Gazebo simulation support, add -PforceGazebo. This requires gazebo_transport. We have tested on 14.04 and 15.05, but any correct install of Gazebo should work, even on Windows if you build Gazebo from source. Correct means CMake needs to be able to find gazebo-config.cmake. See [The Gazebo website](https://gazebosim.org/) for installation instructions.
|
||||
|
||||
```bash
|
||||
./gradlew build -PmakeSim
|
||||
./gradlew build -PforceGazebo
|
||||
```
|
||||
|
||||
If you prefer to use CMake directly, the you can still do so.
|
||||
@@ -73,12 +113,21 @@ cmake ..
|
||||
make
|
||||
```
|
||||
|
||||
The gradlew wrapper only exists in the root of the main project, so be sure to run all commands from there. All of the subprojects have build tasks that can be run. Gradle automatically determines and rebuilds dependencies, so if you make a change in the HAL and then run `./gradlew :wpilibc:build`, the HAL will be rebuilt, then WPILibC.
|
||||
|
||||
There are a few tasks other than `build` available. To see them, run the meta-task `tasks`. This will print a list of all available tasks, with a description of each task.
|
||||
### Formatting/linting
|
||||
|
||||
#### wpiformat
|
||||
|
||||
wpiformat can be executed anywhere in the repository via `py -3 -m wpiformat` on Windows or `python3 -m wpiformat` on other platforms.
|
||||
|
||||
#### Java Code Quality Tools
|
||||
|
||||
The Java code quality tools Checkstyle, PMD, and Spotless can be run via `./gradlew javaFormat`. SpotBugs can be run via the `spotbugsMain`, `spotbugsTest`, and `spotbugsDev` tasks. These tools will all be run automatically by the `build` task. To disable this behavior, pass the `-PskipJavaFormat` flag.
|
||||
|
||||
If you only want to run the Java autoformatter, run `./gradlew spotlessApply`.
|
||||
|
||||
### CMake
|
||||
|
||||
CMake is also supported for building. See [README-CMAKE.md](README-CMAKE.md).
|
||||
|
||||
## Publishing
|
||||
@@ -102,6 +151,8 @@ The integration test directories for C++ and Java contain test code that runs on
|
||||
|
||||
The hal directory contains more C++ code meant to run on the roboRIO. HAL is an acronym for "Hardware Abstraction Layer", and it interfaces with the NI Libraries. The NI Libraries contain the low-level code for controlling devices on your robot. The NI Libraries are found in the ni-libraries folder.
|
||||
|
||||
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
|
||||
|
||||
@@ -27,23 +27,33 @@ JSON for Modern C++ wpiutil/src/main/native/include/wpi/json.h
|
||||
libuv wpiutil/src/main/native/include/uv.h
|
||||
wpiutil/src/main/native/include/uv/
|
||||
wpiutil/src/main/native/libuv/
|
||||
fmtlib wpiutil/src/main/native/fmtlib/
|
||||
sigslot wpiutil/src/main/native/include/wpi/Signal.h
|
||||
wpiutil/src/test/native/cpp/sigslot/
|
||||
tcpsockets wpiutil/src/main/native/cpp/TCP{Stream,Connector,Acceptor}.cpp
|
||||
wpiutil/src/main/native/include/wpi/TCP*.h
|
||||
MPack wpiutil/src/main/native/include/mpack.h
|
||||
wpiutil/src/main/native/cpp/mpack.cpp
|
||||
Bootstrap wpiutil/src/main/native/resources/bootstrap-*
|
||||
CoreUI wpiutil/src/main/native/resources/coreui-*
|
||||
Feather Icons wpiutil/src/main/native/resources/feather-*
|
||||
jQuery wpiutil/src/main/native/resources/jquery-*
|
||||
popper.js wpiutil/src/main/native/resources/popper-*
|
||||
units wpiutil/src/main/native/include/units/units.h
|
||||
Eigen wpiutil/src/main/native/eigeninclude/
|
||||
units wpimath/src/main/native/include/units/
|
||||
Eigen wpimath/src/main/native/eigeninclude/
|
||||
wpimath/src/main/native/include/unsupported/
|
||||
StackWalker wpiutil/src/main/native/windows/StackWalker.*
|
||||
TCB span wpiutil/src/main/native/include/wpi/span.h
|
||||
wpiutil/src/test/native/cpp/span/
|
||||
GHC filesystem wpiutil/src/main/native/include/wpi/ghc/
|
||||
Team 254 Library wpilibj/src/main/java/edu/wpi/first/wpilibj/spline/SplineParameterizer.java
|
||||
wpilibj/src/main/java/edu/wpi/first/wpilibj/trajectory/TrajectoryParameterizer.java
|
||||
wpilibc/src/main/native/include/spline/SplineParameterizer.h
|
||||
wpilibc/src/main/native/include/trajectory/TrajectoryParameterizer.h
|
||||
wpilibc/src/main/native/cpp/trajectory/TrajectoryParameterizer.cpp
|
||||
Portable File Dialogs wpigui/src/main/native/include/portable-file-dialogs.h
|
||||
Drake wpimath/src/main/native/cpp/drake/common/drake_assert_and_throw.cpp
|
||||
wpimath/src/main/native/cpp/drake/math/discrete_algebraic_riccati_equation.cpp
|
||||
|
||||
|
||||
==============================================================================
|
||||
@@ -227,6 +237,32 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
==============================================================================
|
||||
MPacks License
|
||||
==============================================================================
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2021 Nicholas Fraser and the MPack authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
|
||||
==============================================================================
|
||||
Bootstrap License
|
||||
==============================================================================
|
||||
@@ -806,3 +842,130 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
=============
|
||||
Drake Library
|
||||
=============
|
||||
All components of Drake are licensed under the BSD 3-Clause License
|
||||
shown below. Where noted in the source code, some portions may
|
||||
be subject to other permissive, non-viral licenses.
|
||||
|
||||
Copyright 2012-2016 Robot Locomotion Group @ CSAIL
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer. 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. Neither the name of
|
||||
the Massachusetts Institute of Technology 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.
|
||||
|
||||
=====================
|
||||
Portable File Dialogs
|
||||
=====================
|
||||
Copyright © 2018—2020 Sam Hocevar <sam@hocevar.net>
|
||||
|
||||
This library is free software. It comes without any warranty, to
|
||||
the extent permitted by applicable law. You can redistribute it
|
||||
and/or modify it under the terms of the Do What the **** You Want
|
||||
to Public License, Version 2, as published by the WTFPL Task Force.
|
||||
See http://www.wtfpl.net/ for more details.
|
||||
|
||||
======================
|
||||
Boost Software License
|
||||
======================
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
|
||||
Permission is hereby granted, free of charge, to any person or organization
|
||||
obtaining a copy of the software and accompanying documentation covered by
|
||||
this license (the "Software") to use, reproduce, display, distribute,
|
||||
execute, and transmit the Software, and to prepare derivative works of the
|
||||
Software, and to permit third-parties to whom the Software is furnished to
|
||||
do so, all subject to the following:
|
||||
|
||||
The copyright notices in the Software and this entire statement, including
|
||||
the above license grant, this restriction and the following disclaimer,
|
||||
must be included in all copies of the Software, in whole or in part, and
|
||||
all derivative works of the Software, unless such copies or derivative
|
||||
works are solely in the form of machine-executable object code generated by
|
||||
a source language processor.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
||||
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
||||
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
|
||||
======
|
||||
fmtlib
|
||||
======
|
||||
Copyright (c) 2012 - present, Victor Zverovich
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
--- Optional exception to the license ---
|
||||
|
||||
As an exception, if, as a result of your compiling your source code, portions
|
||||
of this Software are embedded into a machine-executable object form of such
|
||||
source code, you may redistribute such embedded portions in such object form
|
||||
without including the above copyright and permission notices.
|
||||
|
||||
==============
|
||||
GHC filesystem
|
||||
==============
|
||||
Copyright (c) 2018, Steffen Schümann <s.schuemann@pobox.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
@@ -4,88 +4,88 @@ trigger:
|
||||
batch: true
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
- master
|
||||
|
||||
stages:
|
||||
- stage: Build
|
||||
jobs:
|
||||
- job: IntegrationTests
|
||||
displayName: Integration Tests
|
||||
pool:
|
||||
vmImage: 'Ubuntu 16.04'
|
||||
- stage: Build
|
||||
jobs:
|
||||
- job: IntegrationTests
|
||||
displayName: Integration Tests
|
||||
pool:
|
||||
vmImage: 'ubuntu-latest'
|
||||
|
||||
container:
|
||||
image: wpilib/roborio-cross-ubuntu:2020-18.04
|
||||
container:
|
||||
image: wpilib/roborio-cross-ubuntu:2022-18.04
|
||||
|
||||
timeoutInMinutes: 0
|
||||
timeoutInMinutes: 0
|
||||
|
||||
steps:
|
||||
- task: Gradle@2
|
||||
condition: and(succeeded(), not(startsWith(variables['Build.SourceBranch'], 'refs/tags/v')))
|
||||
inputs:
|
||||
workingDirectory: ''
|
||||
gradleWrapperFile: 'gradlew'
|
||||
gradleOptions: '-Xmx3072m'
|
||||
publishJUnitResults: false
|
||||
testResultsFiles: '**/TEST-*.xml'
|
||||
tasks: 'copyWpilibJIntegrationTestJarToOutput copyWpilibCTestLibrariesToOutput'
|
||||
options: '-Ponlylinuxathena -PbuildServer'
|
||||
steps:
|
||||
- task: Gradle@2
|
||||
condition: and(succeeded(), not(startsWith(variables['Build.SourceBranch'], 'refs/tags/v')))
|
||||
inputs:
|
||||
workingDirectory: ""
|
||||
gradleWrapperFile: "gradlew"
|
||||
gradleOptions: "-Xmx3072m"
|
||||
publishJUnitResults: false
|
||||
testResultsFiles: "**/TEST-*.xml"
|
||||
tasks: "copyWpilibJIntegrationTestJarToOutput copyWpilibCTestLibrariesToOutput"
|
||||
options: "-Ponlylinuxathena -PbuildServer -PskipJavaFormat"
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'Integration Tests'
|
||||
targetPath: 'build/integrationTestFiles'
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: "Integration Tests"
|
||||
targetPath: "build/integrationTestFiles"
|
||||
|
||||
- stage: TestBench
|
||||
displayName: Test Bench
|
||||
jobs:
|
||||
- job: Cpp
|
||||
displayName: C++
|
||||
pool: RoboRioConnections
|
||||
timeoutInMinutes: 30
|
||||
workspace:
|
||||
clean: all
|
||||
steps:
|
||||
- task: DownloadPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'Integration Tests'
|
||||
targetPath: 'build/integrationTestFiles'
|
||||
- stage: TestBench
|
||||
displayName: Test Bench
|
||||
jobs:
|
||||
- job: Cpp
|
||||
displayName: C++
|
||||
pool: RoboRioConnections
|
||||
timeoutInMinutes: 30
|
||||
workspace:
|
||||
clean: all
|
||||
steps:
|
||||
- task: DownloadPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: "Integration Tests"
|
||||
targetPath: "build/integrationTestFiles"
|
||||
|
||||
- task: ShellScript@2
|
||||
displayName: Run C++ Tests
|
||||
inputs:
|
||||
scriptPath: test-scripts/deploy-and-run-test-on-robot.sh
|
||||
args: 'cpp -A "--gtest_output=xml:/home/admin/testResults/cppreport.xml"'
|
||||
- task: ShellScript@2
|
||||
displayName: Run C++ Tests
|
||||
inputs:
|
||||
scriptPath: test-scripts/deploy-and-run-test-on-robot.sh
|
||||
args: 'cpp -A "--gtest_output=xml:/home/admin/testResults/cppreport.xml"'
|
||||
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish C++ Test Results
|
||||
inputs:
|
||||
testResultsFormat: 'JUnit'
|
||||
testResultsFiles: '*.xml'
|
||||
testRunTitle: 'C++ Test Report'
|
||||
searchFolder: '$(System.DefaultWorkingDirectory)/test-reports'
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish C++ Test Results
|
||||
inputs:
|
||||
testResultsFormat: "JUnit"
|
||||
testResultsFiles: "*.xml"
|
||||
testRunTitle: "C++ Test Report"
|
||||
searchFolder: "$(System.DefaultWorkingDirectory)/test-reports"
|
||||
|
||||
- job: Java
|
||||
pool: RoboRioConnections
|
||||
timeoutInMinutes: 30
|
||||
workspace:
|
||||
clean: all
|
||||
steps:
|
||||
- task: DownloadPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'Integration Tests'
|
||||
targetPath: 'build/integrationTestFiles'
|
||||
- job: Java
|
||||
pool: RoboRioConnections
|
||||
timeoutInMinutes: 30
|
||||
workspace:
|
||||
clean: all
|
||||
steps:
|
||||
- task: DownloadPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: "Integration Tests"
|
||||
targetPath: "build/integrationTestFiles"
|
||||
|
||||
- task: ShellScript@2
|
||||
displayName: Run Java Tests
|
||||
inputs:
|
||||
scriptPath: test-scripts/deploy-and-run-test-on-robot.sh
|
||||
args: 'java'
|
||||
- task: ShellScript@2
|
||||
displayName: Run Java Tests
|
||||
inputs:
|
||||
scriptPath: test-scripts/deploy-and-run-test-on-robot.sh
|
||||
args: "java"
|
||||
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish Java Test Results
|
||||
inputs:
|
||||
testResultsFormat: 'JUnit'
|
||||
testResultsFiles: '*.xml'
|
||||
testRunTitle: 'Java Test Report'
|
||||
searchFolder: '$(System.DefaultWorkingDirectory)/test-reports'
|
||||
- task: PublishTestResults@2
|
||||
displayName: Publish Java Test Results
|
||||
inputs:
|
||||
testResultsFormat: "JUnit"
|
||||
testResultsFiles: "*.xml"
|
||||
testRunTitle: "Java Test Report"
|
||||
searchFolder: "$(System.DefaultWorkingDirectory)/test-reports"
|
||||
|
||||
@@ -1,417 +0,0 @@
|
||||
# Gradle
|
||||
# Build your Java projects and run tests with Gradle using a Gradle wrapper script.
|
||||
# Add steps that analyze code, save build artifacts, deploy, and more:
|
||||
# https://docs.microsoft.com/vsts/pipelines/languages/java
|
||||
|
||||
resources:
|
||||
containers:
|
||||
- container: wpilib2020
|
||||
image: wpilib/roborio-cross-ubuntu:2020-18.04
|
||||
- container: raspbian
|
||||
image: wpilib/raspbian-cross-ubuntu:10-18.04
|
||||
- container: aarch64
|
||||
image: wpilib/aarch64-cross-ubuntu:bionic-18.04
|
||||
- container: ubuntu
|
||||
image: wpilib/ubuntu-base:18.04
|
||||
|
||||
variables:
|
||||
- group: Artifactory-Package-Publish
|
||||
|
||||
trigger:
|
||||
batch: true
|
||||
branches:
|
||||
include:
|
||||
- master
|
||||
|
||||
stages:
|
||||
- stage: Build
|
||||
jobs:
|
||||
- job: Linux_Arm
|
||||
pool:
|
||||
vmImage: 'Ubuntu 16.04'
|
||||
|
||||
container: wpilib2020
|
||||
|
||||
timeoutInMinutes: 0
|
||||
|
||||
steps:
|
||||
- task: Gradle@2
|
||||
condition: and(succeeded(), not(startsWith(variables['Build.SourceBranch'], 'refs/tags/v')))
|
||||
inputs:
|
||||
workingDirectory: ''
|
||||
gradleWrapperFile: 'gradlew'
|
||||
gradleOptions: '-Xmx3072m'
|
||||
publishJUnitResults: false
|
||||
testResultsFiles: '**/TEST-*.xml'
|
||||
tasks: 'build'
|
||||
options: '-Ponlylinuxathena -PbuildServer'
|
||||
|
||||
- task: Gradle@2
|
||||
condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
|
||||
inputs:
|
||||
workingDirectory: ''
|
||||
gradleWrapperFile: 'gradlew'
|
||||
gradleOptions: '-Xmx3072m'
|
||||
publishJUnitResults: false
|
||||
testResultsFiles: '**/TEST-*.xml'
|
||||
tasks: 'build'
|
||||
options: '-Ponlylinuxathena -PreleaseMode -PbuildServer'
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'Athena'
|
||||
targetPath: 'build/allOutputs'
|
||||
|
||||
- job: Linux_Raspbian
|
||||
pool:
|
||||
vmImage: 'Ubuntu 16.04'
|
||||
|
||||
container: raspbian
|
||||
|
||||
timeoutInMinutes: 0
|
||||
|
||||
steps:
|
||||
- task: Gradle@2
|
||||
condition: and(succeeded(), not(startsWith(variables['Build.SourceBranch'], 'refs/tags/v')))
|
||||
inputs:
|
||||
workingDirectory: ''
|
||||
gradleWrapperFile: 'gradlew'
|
||||
gradleOptions: '-Xmx3072m'
|
||||
publishJUnitResults: true
|
||||
testResultsFiles: '**/TEST-*.xml'
|
||||
tasks: 'build'
|
||||
options: '-Ponlylinuxraspbian -PbuildServer'
|
||||
|
||||
- task: Gradle@2
|
||||
condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
|
||||
inputs:
|
||||
workingDirectory: ''
|
||||
gradleWrapperFile: 'gradlew'
|
||||
gradleOptions: '-Xmx3072m'
|
||||
publishJUnitResults: true
|
||||
testResultsFiles: '**/TEST-*.xml'
|
||||
tasks: 'build'
|
||||
options: '-Ponlylinuxraspbian -PreleaseMode -PbuildServer'
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'Raspbian'
|
||||
targetPath: 'build/allOutputs'
|
||||
|
||||
- job: Linux_Aarch64
|
||||
pool:
|
||||
vmImage: 'Ubuntu 16.04'
|
||||
|
||||
container: aarch64
|
||||
|
||||
timeoutInMinutes: 0
|
||||
|
||||
steps:
|
||||
- task: Gradle@2
|
||||
condition: and(succeeded(), not(startsWith(variables['Build.SourceBranch'], 'refs/tags/v')))
|
||||
inputs:
|
||||
workingDirectory: ''
|
||||
gradleWrapperFile: 'gradlew'
|
||||
gradleOptions: '-Xmx3072m'
|
||||
publishJUnitResults: true
|
||||
testResultsFiles: '**/TEST-*.xml'
|
||||
tasks: 'build'
|
||||
options: '-Ponlylinuxaarch64bionic -PbuildServer'
|
||||
|
||||
- task: Gradle@2
|
||||
condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
|
||||
inputs:
|
||||
workingDirectory: ''
|
||||
gradleWrapperFile: 'gradlew'
|
||||
gradleOptions: '-Xmx3072m'
|
||||
publishJUnitResults: true
|
||||
testResultsFiles: '**/TEST-*.xml'
|
||||
tasks: 'build'
|
||||
options: '-Ponlylinuxaarch64bionic -PreleaseMode -PbuildServer'
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'Aarch64'
|
||||
targetPath: 'build/allOutputs'
|
||||
|
||||
- job: Linux
|
||||
pool:
|
||||
vmImage: 'Ubuntu 16.04'
|
||||
|
||||
container: ubuntu
|
||||
|
||||
timeoutInMinutes: 0
|
||||
|
||||
steps:
|
||||
- task: Gradle@2
|
||||
condition: and(succeeded(), not(startsWith(variables['Build.SourceBranch'], 'refs/tags/v')))
|
||||
inputs:
|
||||
workingDirectory: ''
|
||||
gradleWrapperFile: 'gradlew'
|
||||
gradleOptions: '-Xmx3072m'
|
||||
publishJUnitResults: true
|
||||
testResultsFiles: '**/TEST-*.xml'
|
||||
tasks: 'build'
|
||||
options: '-PbuildServer'
|
||||
|
||||
- task: Gradle@2
|
||||
condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
|
||||
inputs:
|
||||
workingDirectory: ''
|
||||
gradleWrapperFile: 'gradlew'
|
||||
gradleOptions: '-Xmx3072m'
|
||||
publishJUnitResults: true
|
||||
testResultsFiles: '**/TEST-*.xml'
|
||||
tasks: 'build'
|
||||
options: '-PreleaseMode -PbuildServer'
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'Linux'
|
||||
targetPath: 'build/allOutputs'
|
||||
|
||||
- job: Styleguide
|
||||
pool:
|
||||
vmImage: 'Ubuntu 16.04'
|
||||
|
||||
container: ubuntu
|
||||
|
||||
timeoutInMinutes: 0
|
||||
|
||||
steps:
|
||||
- script: |
|
||||
sudo pip3 install wpiformat
|
||||
displayName: 'Install wpiformat'
|
||||
- script: |
|
||||
git checkout -b master
|
||||
wpiformat -clang 6.0
|
||||
displayName: 'Run wpiformat'
|
||||
- script: |
|
||||
# Ensure formatter made no changes
|
||||
git --no-pager diff --exit-code HEAD
|
||||
displayName: 'Check wpiformat Output'
|
||||
|
||||
- job: CMakeBuild
|
||||
pool:
|
||||
vmImage: 'Ubuntu 16.04'
|
||||
|
||||
container: wpilib2020
|
||||
|
||||
timeoutInMinutes: 0
|
||||
|
||||
steps:
|
||||
- task: CMake@1
|
||||
inputs:
|
||||
cmakeArgs: '-DWITHOUT_ALLWPILIB=OFF ..'
|
||||
- script: |
|
||||
make -j3
|
||||
workingDirectory: 'build'
|
||||
displayName: 'Build'
|
||||
|
||||
- job: Windows_64_Bit
|
||||
pool:
|
||||
vmImage: 'windows-2019'
|
||||
|
||||
timeoutInMinutes: 0
|
||||
steps:
|
||||
- task: Gradle@2
|
||||
condition: and(succeeded(), not(startsWith(variables['Build.SourceBranch'], 'refs/tags/v')))
|
||||
inputs:
|
||||
workingDirectory: ''
|
||||
gradleWrapperFile: 'gradlew'
|
||||
gradleOptions: '-Xmx3072m'
|
||||
jdkVersionOption: '1.11'
|
||||
publishJUnitResults: true
|
||||
testResultsFiles: '**/TEST-*.xml'
|
||||
tasks: 'build'
|
||||
options: '-PskipPMD -PbuildServer'
|
||||
|
||||
- task: Gradle@2
|
||||
condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
|
||||
inputs:
|
||||
workingDirectory: ''
|
||||
gradleWrapperFile: 'gradlew'
|
||||
gradleOptions: '-Xmx3072m'
|
||||
jdkVersionOption: '1.11'
|
||||
publishJUnitResults: true
|
||||
testResultsFiles: '**/TEST-*.xml'
|
||||
tasks: 'build'
|
||||
options: '-PskipPMD -PreleaseMode -PbuildServer'
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'Win64'
|
||||
targetPath: 'build/allOutputs'
|
||||
|
||||
- job: Windows_32_Bit
|
||||
pool:
|
||||
vmImage: 'windows-2019'
|
||||
|
||||
timeoutInMinutes: 0
|
||||
steps:
|
||||
- powershell: |
|
||||
mkdir build
|
||||
$ProgressPreference = 'SilentlyContinue'
|
||||
wget "https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.4%2B11/OpenJDK11U-jdk_x86-32_windows_hotspot_11.0.4_11.zip" -O "build\jdk.zip"
|
||||
displayName: 'Download JDK'
|
||||
- task: JavaToolInstaller@0
|
||||
inputs:
|
||||
jdkSourceOption: localDirectory
|
||||
jdkFile: 'build/jdk.zip'
|
||||
jdkDestinationDirectory: 'build/jdkinst'
|
||||
jdkArchitectureOption: x86
|
||||
|
||||
- task: Gradle@2
|
||||
condition: and(succeeded(), not(startsWith(variables['Build.SourceBranch'], 'refs/tags/v')))
|
||||
inputs:
|
||||
workingDirectory: ''
|
||||
gradleWrapperFile: 'gradlew'
|
||||
gradleOptions: '-Xmx1024m'
|
||||
publishJUnitResults: true
|
||||
testResultsFiles: '**/TEST-*.xml'
|
||||
tasks: 'build'
|
||||
options: '-PskipPMD -PbuildServer'
|
||||
|
||||
- task: Gradle@2
|
||||
condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
|
||||
inputs:
|
||||
workingDirectory: ''
|
||||
gradleWrapperFile: 'gradlew'
|
||||
gradleOptions: '-Xmx1024m'
|
||||
publishJUnitResults: true
|
||||
testResultsFiles: '**/TEST-*.xml'
|
||||
tasks: 'build'
|
||||
options: '-PskipPMD -PreleaseMode -PbuildServer'
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'Win32'
|
||||
targetPath: 'build/allOutputs'
|
||||
|
||||
- job: Mac
|
||||
pool:
|
||||
vmImage: 'macOS-10.14'
|
||||
|
||||
timeoutInMinutes: 0
|
||||
steps:
|
||||
- script: |
|
||||
mkdir build
|
||||
export JAVA_HOME=`/usr/libexec/java_home -v 11`
|
||||
displayName: 'Setup JDK'
|
||||
|
||||
- task: Gradle@2
|
||||
condition: and(succeeded(), not(startsWith(variables['Build.SourceBranch'], 'refs/tags/v')))
|
||||
inputs:
|
||||
workingDirectory: ''
|
||||
gradleWrapperFile: 'gradlew'
|
||||
gradleOptions: '-Xmx3072m'
|
||||
jdkVersionOption: '1.11'
|
||||
publishJUnitResults: true
|
||||
testResultsFiles: '**/TEST-*.xml'
|
||||
tasks: 'build'
|
||||
options: '-PbuildServer'
|
||||
|
||||
- task: Gradle@2
|
||||
condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
|
||||
inputs:
|
||||
workingDirectory: ''
|
||||
gradleWrapperFile: 'gradlew'
|
||||
gradleOptions: '-Xmx3072m'
|
||||
jdkVersionOption: '1.11'
|
||||
publishJUnitResults: true
|
||||
testResultsFiles: '**/TEST-*.xml'
|
||||
tasks: 'build'
|
||||
options: '-PreleaseMode -PbuildServer'
|
||||
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'Mac'
|
||||
targetPath: 'build/allOutputs'
|
||||
|
||||
- stage: Combine
|
||||
jobs:
|
||||
- job: CombineJob
|
||||
pool:
|
||||
vmImage: 'macOS-10.14'
|
||||
|
||||
timeoutInMinutes: 0
|
||||
|
||||
steps:
|
||||
- checkout: none
|
||||
- script: |
|
||||
git clone https://github.com/wpilibsuite/build-tools
|
||||
displayName: 'Clone Combiner'
|
||||
- task: DownloadPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'Mac'
|
||||
targetPath: 'build-tools/combiner/products/build/allOutputs'
|
||||
- task: DownloadPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'Win32'
|
||||
targetPath: 'build-tools/combiner/products/build/allOutputs'
|
||||
- task: DownloadPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'Win64'
|
||||
targetPath: 'build-tools/combiner/products/build/allOutputs'
|
||||
- task: DownloadPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'Linux'
|
||||
targetPath: 'build-tools/combiner/products/build/allOutputs'
|
||||
- task: DownloadPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'Raspbian'
|
||||
targetPath: 'build-tools/combiner/products/build/allOutputs'
|
||||
- task: DownloadPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'Athena'
|
||||
targetPath: 'build-tools/combiner/products/build/allOutputs'
|
||||
- task: DownloadPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'Aarch64'
|
||||
targetPath: 'build-tools/combiner/products/build/allOutputs'
|
||||
|
||||
# PR Builds
|
||||
- task: Gradle@2
|
||||
inputs:
|
||||
workingDirectory: 'build-tools/combiner'
|
||||
gradleWrapperFile: 'build-tools/combiner/gradlew'
|
||||
gradleOptions: '-Xmx3072m'
|
||||
tasks: 'publish '
|
||||
options: '-Pallwpilib'
|
||||
condition: and(succeeded(), and(ne(variables['Build.SourceBranch'], 'refs/heads/master'), not(startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))))
|
||||
|
||||
# Master Builds
|
||||
- task: Gradle@2
|
||||
inputs:
|
||||
workingDirectory: 'build-tools/combiner'
|
||||
gradleWrapperFile: 'build-tools/combiner/gradlew'
|
||||
gradleOptions: '-Xmx3072m'
|
||||
tasks: 'publish '
|
||||
options: '-Pallwpilib'
|
||||
condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
|
||||
env:
|
||||
RUN_AZURE_ARTIFACTORY_RELEASE: 'TRUE'
|
||||
ARTIFACTORY_PUBLISH_USERNAME: $(PublishUserName)
|
||||
ARTIFACTORY_PUBLISH_PASSWORD: $(PublishPassword)
|
||||
|
||||
# Tagged Builds
|
||||
- task: Gradle@2
|
||||
inputs:
|
||||
workingDirectory: 'build-tools/combiner'
|
||||
gradleWrapperFile: 'build-tools/combiner/gradlew'
|
||||
gradleOptions: '-Xmx3072m'
|
||||
tasks: 'publish '
|
||||
options: '-Pallwpilib -PreleaseRepoPublish'
|
||||
condition: and(succeeded(), startsWith(variables['Build.SourceBranch'], 'refs/tags/v'))
|
||||
env:
|
||||
RUN_AZURE_ARTIFACTORY_RELEASE: 'TRUE'
|
||||
ARTIFACTORY_PUBLISH_USERNAME: $(PublishUserName)
|
||||
ARTIFACTORY_PUBLISH_PASSWORD: $(PublishPassword)
|
||||
|
||||
- script: |
|
||||
echo "##vso[task.setvariable variable=UserHome]$HOME"
|
||||
displayName: 'Set Home Variable'
|
||||
- task: PublishPipelineArtifact@0
|
||||
inputs:
|
||||
artifactName: 'Maven'
|
||||
targetPath: $(UserHome)/releases
|
||||
65
build.gradle
65
build.gradle
@@ -1,25 +1,31 @@
|
||||
import edu.wpi.first.toolchain.*
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.hubspot.jinjava:jinjava:2.6.0'
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id 'base'
|
||||
id 'edu.wpi.first.wpilib.versioning.WPILibVersioningPlugin' version '4.0.1'
|
||||
id 'edu.wpi.first.wpilib.versioning.WPILibVersioningPlugin' version '4.1.0'
|
||||
id 'edu.wpi.first.wpilib.repositories.WPILibRepositoriesPlugin' version '2020.2'
|
||||
id 'edu.wpi.first.NativeUtils' apply false
|
||||
id 'edu.wpi.first.GradleJni' version '0.10.1'
|
||||
id 'edu.wpi.first.GradleVsCode' version '0.11.0'
|
||||
id 'edu.wpi.first.GradleJni' version '1.0.0'
|
||||
id 'edu.wpi.first.GradleVsCode'
|
||||
id 'idea'
|
||||
id 'visual-studio'
|
||||
id 'net.ltgt.errorprone' version '1.1.1' apply false
|
||||
id 'com.github.johnrengelman.shadow' version '5.2.0' apply false
|
||||
id 'net.ltgt.errorprone' version '2.0.2' apply false
|
||||
id 'com.github.johnrengelman.shadow' version '7.1.2' apply false
|
||||
id 'com.diffplug.spotless' version '6.1.2' apply false
|
||||
id 'com.github.spotbugs' version '5.0.4' apply false
|
||||
}
|
||||
|
||||
if (project.hasProperty('buildServer')) {
|
||||
wpilibVersioning.buildServerMode = true
|
||||
}
|
||||
|
||||
if (project.hasProperty('releaseMode')) {
|
||||
wpilibVersioning.releaseMode = true
|
||||
}
|
||||
wpilibVersioning.buildServerMode = project.hasProperty('buildServer')
|
||||
wpilibVersioning.releaseMode = project.hasProperty('releaseMode')
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
@@ -39,7 +45,7 @@ buildScan {
|
||||
publishAlways()
|
||||
}
|
||||
|
||||
ext.licenseFile = files("$rootDir/LICENSE.txt", "$rootDir/ThirdPartyNotices.txt")
|
||||
ext.licenseFile = files("$rootDir/LICENSE.md", "$rootDir/ThirdPartyNotices.txt")
|
||||
|
||||
if (project.hasProperty("publishVersion")) {
|
||||
wpilibVersioning.version.set(project.publishVersion)
|
||||
@@ -103,6 +109,37 @@ subprojects {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enables UTF-8 support in Javadoc
|
||||
tasks.withType(Javadoc) {
|
||||
options.addStringOption("charset", "utf-8")
|
||||
options.addStringOption("docencoding", "utf-8")
|
||||
options.addStringOption("encoding", "utf-8")
|
||||
}
|
||||
|
||||
// Sign outputs with Developer ID
|
||||
if (project.hasProperty("developerID")) {
|
||||
tasks.withType(AbstractLinkTask) { task ->
|
||||
// Don't sign any executables because codesign complains
|
||||
// about relative rpath.
|
||||
if (!(task instanceof LinkExecutable)) {
|
||||
doLast {
|
||||
// Get path to binary.
|
||||
String path = task.getLinkedFile().getAsFile().get().getAbsolutePath()
|
||||
exec {
|
||||
workingDir rootDir
|
||||
def args = [
|
||||
"sh",
|
||||
"-c",
|
||||
"codesign --force --strict --timestamp --options=runtime " +
|
||||
"--verbose -s ${project.findProperty("developerID")} ${path}"
|
||||
]
|
||||
commandLine args
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ext.getCurrentArch = {
|
||||
@@ -110,5 +147,5 @@ ext.getCurrentArch = {
|
||||
}
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.0'
|
||||
gradleVersion = '7.3.3'
|
||||
}
|
||||
|
||||
@@ -5,5 +5,5 @@ repositories {
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
implementation "edu.wpi.first:native-utils:2020.7.2"
|
||||
implementation "edu.wpi.first:native-utils:2022.7.1"
|
||||
}
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
import groovy.transform.CompileStatic
|
||||
import javax.inject.Inject
|
||||
import jaci.gradle.deploy.artifact.MavenArtifact
|
||||
import jaci.gradle.deploy.context.DeployContext
|
||||
import org.gradle.api.Project
|
||||
import jaci.gradle.ActionWrapper
|
||||
|
||||
import java.util.function.Function
|
||||
|
||||
@CompileStatic
|
||||
class JREArtifact extends MavenArtifact {
|
||||
Function<DeployContext, Boolean> buildRequiresJre = (Function<DeployContext, Boolean>){ true }
|
||||
|
||||
void setJreDependency(String dep) {
|
||||
dependency = project.dependencies.add(configuration(), dep)
|
||||
}
|
||||
|
||||
@Inject
|
||||
JREArtifact(String name, Project project) {
|
||||
super(name, project)
|
||||
configuration = project.configurations.create(configuration())
|
||||
|
||||
onlyIf = { DeployContext ctx ->
|
||||
(buildRequiresJre.apply(ctx) && jreMissing(ctx)) || project.hasProperty("force-redeploy-jre")
|
||||
}
|
||||
|
||||
predeploy << new ActionWrapper({ DeployContext ctx ->
|
||||
ctx.logger.log('Deploying RoboRIO JRE (this will take a while)...')
|
||||
})
|
||||
|
||||
directory = '/tmp'
|
||||
filename = 'frcjre.ipk'
|
||||
|
||||
postdeploy << new ActionWrapper({ DeployContext ctx ->
|
||||
ctx.logger.log('Installing JRE...')
|
||||
ctx.execute('opkg remove frc2020-openjdk*; opkg install /tmp/frcjre.ipk; rm /tmp/frcjre.ipk')
|
||||
ctx.logger.log('JRE Deployed!')
|
||||
})
|
||||
}
|
||||
|
||||
String configuration() {
|
||||
return name + 'frcjre'
|
||||
}
|
||||
|
||||
boolean jreMissing(DeployContext ctx) {
|
||||
return ctx.execute('if [[ -f "/usr/local/frc/JRE/bin/java" ]]; then echo OK; else echo MISSING; fi').result.contains("MISSING")
|
||||
}
|
||||
}
|
||||
@@ -6,10 +6,14 @@ import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.gradle.api.tasks.Delete
|
||||
|
||||
import org.gradle.api.GradleException;
|
||||
import org.gradle.api.Plugin;
|
||||
import org.gradle.api.Project;
|
||||
import org.gradle.api.Task;
|
||||
import org.gradle.api.tasks.Copy;
|
||||
import org.gradle.api.file.CopySpec;
|
||||
import org.gradle.api.file.FileTree;
|
||||
import org.gradle.api.tasks.compile.JavaCompile;
|
||||
import org.gradle.language.base.internal.ProjectLayout;
|
||||
@@ -32,6 +36,8 @@ import org.gradle.nativeplatform.toolchain.internal.ToolType;
|
||||
import org.gradle.nativeplatform.toolchain.internal.gcc.AbstractGccCompatibleToolChain;
|
||||
import org.gradle.nativeplatform.toolchain.internal.msvcpp.VisualCppToolChain;
|
||||
import org.gradle.nativeplatform.toolchain.internal.tools.ToolRegistry;
|
||||
import org.gradle.nativeplatform.tasks.CreateStaticLibrary;
|
||||
import org.gradle.nativeplatform.tasks.AbstractLinkTask;
|
||||
import org.gradle.platform.base.BinarySpec;
|
||||
import org.gradle.platform.base.ComponentSpec;
|
||||
import org.gradle.platform.base.ComponentSpecContainer;
|
||||
@@ -40,7 +46,7 @@ import org.gradle.platform.base.ComponentType;
|
||||
import org.gradle.platform.base.TypeBuilder;
|
||||
import org.gradle.nativeplatform.tasks.ObjectFilesToBinary;
|
||||
import groovy.transform.CompileStatic;
|
||||
import edu.wpi.first.nativeutils.tasks.ExportsGenerationTask
|
||||
import edu.wpi.first.nativeutils.exports.ExportsGenerationTask
|
||||
|
||||
@CompileStatic
|
||||
class SingleNativeBuild implements Plugin<Project> {
|
||||
@@ -79,10 +85,18 @@ class SingleNativeBuild implements Plugin<Project> {
|
||||
components.each { component ->
|
||||
if (component.name == "${nativeName}Base") {
|
||||
base = (NativeLibrarySpec) component
|
||||
} else if (component.name == "${nativeName}" || component.name == "${nativeName}JNI") {
|
||||
} else if (component.name == "${nativeName}" || component.name == "${nativeName}JNI" || component.name == "${nativeName}JNICvStatic") {
|
||||
subs << component
|
||||
}
|
||||
}
|
||||
Delete deleteObjects = null
|
||||
if (project.hasProperty('buildServer')) {
|
||||
deleteObjects = project.tasks.create('deleteObjects', Delete)
|
||||
project.tasks.named('build').configure { Task t ->
|
||||
t.dependsOn deleteObjects
|
||||
return
|
||||
}
|
||||
}
|
||||
subs.each {
|
||||
((NativeLibrarySpec) it).binaries.each { oBinary ->
|
||||
if (oBinary.buildable == false) {
|
||||
@@ -100,6 +114,23 @@ class SingleNativeBuild implements Plugin<Project> {
|
||||
baseBin = tmpBaseBin
|
||||
}
|
||||
}
|
||||
|
||||
if (binary instanceof StaticLibraryBinarySpec) {
|
||||
File intoDir = ((CreateStaticLibrary)((StaticLibraryBinarySpec)binary).tasks.createStaticLib).outputFile.get().asFile.parentFile
|
||||
File fromDir = ((CreateStaticLibrary)((StaticLibraryBinarySpec)baseBin).tasks.createStaticLib).outputFile.get().asFile.parentFile
|
||||
|
||||
def copyBasePdbName = "copyBasePdbFor" + binary.buildTask.name
|
||||
def copyTask = project.tasks.register(copyBasePdbName, Copy) { Copy t ->
|
||||
t.from (fromDir)
|
||||
t.include '*.pdb'
|
||||
t.into intoDir
|
||||
|
||||
t.dependsOn (((StaticLibraryBinarySpec)baseBin).tasks.createStaticLib)
|
||||
}
|
||||
((CreateStaticLibrary)((StaticLibraryBinarySpec)binary).tasks.createStaticLib).dependsOn(copyTask)
|
||||
|
||||
}
|
||||
|
||||
baseBin.tasks.withType(AbstractNativeSourceCompileTask) { oCompileTask ->
|
||||
def compileTask = (AbstractNativeSourceCompileTask) oCompileTask
|
||||
if (binary instanceof SharedLibraryBinarySpec) {
|
||||
@@ -115,6 +146,10 @@ class SingleNativeBuild implements Plugin<Project> {
|
||||
tree.include '**/*.o'
|
||||
tree.include '**/*.obj'
|
||||
link.source tree
|
||||
if (project.hasProperty('buildServer')) {
|
||||
deleteObjects.dependsOn link
|
||||
deleteObjects.delete tree
|
||||
}
|
||||
} else if (binary instanceof StaticLibraryBinarySpec) {
|
||||
def sBinary = (StaticLibraryBinarySpec) binary
|
||||
ObjectFilesToBinary assemble = (ObjectFilesToBinary) sBinary.tasks.createStaticLib
|
||||
@@ -124,6 +159,10 @@ class SingleNativeBuild implements Plugin<Project> {
|
||||
tree.include '**/*.o'
|
||||
tree.include '**/*.obj'
|
||||
assemble.source tree
|
||||
if (project.hasProperty('buildServer')) {
|
||||
deleteObjects.dependsOn assemble
|
||||
deleteObjects.delete tree
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
48
buildSrc/src/main/groovy/WPIJREArtifact.groovy
Normal file
48
buildSrc/src/main/groovy/WPIJREArtifact.groovy
Normal file
@@ -0,0 +1,48 @@
|
||||
import groovy.transform.CompileStatic
|
||||
import javax.inject.Inject
|
||||
import edu.wpi.first.deployutils.deploy.artifact.MavenArtifact
|
||||
import edu.wpi.first.deployutils.deploy.context.DeployContext
|
||||
import org.gradle.api.Project
|
||||
import edu.wpi.first.deployutils.ActionWrapper
|
||||
import edu.wpi.first.deployutils.deploy.target.RemoteTarget
|
||||
import edu.wpi.first.deployutils.PredicateWrapper
|
||||
|
||||
import java.util.function.Function
|
||||
|
||||
@CompileStatic
|
||||
public class WPIJREArtifact extends MavenArtifact {
|
||||
private final String configName;
|
||||
|
||||
public String getConfigName() {
|
||||
return configName;
|
||||
}
|
||||
|
||||
@Inject
|
||||
public WPIJREArtifact(String name, RemoteTarget target) {
|
||||
super(name, target);
|
||||
String configName = name + "frcjre";
|
||||
this.configName = configName;
|
||||
Project project = target.getProject();
|
||||
getConfiguration().set(project.getConfigurations().create(configName));
|
||||
getDependency().set(project.getDependencies().add(configName, "edu.wpi.first.jdk:roborio-2022:11.0.12u5-1"));
|
||||
|
||||
setOnlyIf(new PredicateWrapper({ DeployContext ctx ->
|
||||
return jreMissing(ctx) || project.hasProperty("force-redeploy-jre");
|
||||
}));
|
||||
|
||||
getDirectory().set("/tmp");
|
||||
getFilename().set("frcjre.ipk");
|
||||
|
||||
getPostdeploy().add(new ActionWrapper({ DeployContext ctx ->
|
||||
ctx.getLogger().log("Installing JRE...");
|
||||
ctx.execute("opkg remove frc2022-openjdk*; opkg install /tmp/frcjre.ipk; rm /tmp/frcjre.ipk");
|
||||
ctx.getLogger().log("JRE Deployed!");
|
||||
}));
|
||||
}
|
||||
|
||||
private boolean jreMissing(DeployContext ctx) {
|
||||
return ctx.execute("if [[ -f \"/usr/local/frc/JRE/bin/java\" ]]; then echo OK; else echo MISSING; fi").getResult().contains("MISSING");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -12,6 +12,7 @@ repoRootNameOverride {
|
||||
}
|
||||
|
||||
includeOtherLibs {
|
||||
^fmt/
|
||||
^hal/
|
||||
^networktables/
|
||||
^opencv2/
|
||||
|
||||
@@ -6,10 +6,10 @@ include(AddTest)
|
||||
find_package( OpenCV REQUIRED )
|
||||
|
||||
# Java bindings
|
||||
if (NOT WITHOUT_JAVA)
|
||||
if (WITH_JAVA)
|
||||
find_package(Java REQUIRED)
|
||||
include(UseJava)
|
||||
set(CMAKE_JAVA_COMPILE_FLAGS "-Xlint:unchecked")
|
||||
set(CMAKE_JAVA_COMPILE_FLAGS "-encoding" "UTF8" "-Xlint:unchecked")
|
||||
|
||||
#find java files, copy them locally
|
||||
|
||||
@@ -43,18 +43,18 @@ set_property(TARGET cameraserver PROPERTY FOLDER "libraries")
|
||||
install(TARGETS cameraserver EXPORT cameraserver DESTINATION "${main_lib_dest}")
|
||||
install(DIRECTORY src/main/native/include/ DESTINATION "${include_dest}/cameraserver")
|
||||
|
||||
if (NOT WITHOUT_JAVA AND MSVC)
|
||||
if (WITH_JAVA AND MSVC)
|
||||
install(TARGETS cameraserver RUNTIME DESTINATION "${jni_lib_dest}" COMPONENT Runtime)
|
||||
endif()
|
||||
|
||||
if (MSVC OR FLAT_INSTALL_WPILIB)
|
||||
if (WITH_FLAT_INSTALL)
|
||||
set (cameraserver_config_dir ${wpilib_dest})
|
||||
else()
|
||||
set (cameraserver_config_dir share/cameraserver)
|
||||
endif()
|
||||
|
||||
configure_file(cameraserver-config.cmake.in ${CMAKE_BINARY_DIR}/cameraserver-config.cmake )
|
||||
install(FILES ${CMAKE_BINARY_DIR}/cameraserver-config.cmake 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 ${cameraserver_config_dir})
|
||||
install(EXPORT cameraserver DESTINATION ${cameraserver_config_dir})
|
||||
|
||||
file(GLOB multiCameraServer_src multiCameraServer/src/main/native/cpp/*.cpp)
|
||||
|
||||
@@ -20,9 +20,9 @@ dependencies {
|
||||
|
||||
ext {
|
||||
sharedCvConfigs = [cameraserver : [],
|
||||
cameraserverBase: [],
|
||||
cameraserverDev : [],
|
||||
cameraserverTest: []]
|
||||
cameraserverBase: [],
|
||||
cameraserverDev : [],
|
||||
cameraserverTest: []]
|
||||
staticCvConfigs = [:]
|
||||
useJava = true
|
||||
useCpp = true
|
||||
@@ -32,14 +32,32 @@ apply from: "${rootDir}/shared/opencv.gradle"
|
||||
|
||||
nativeUtils.exportsConfigs {
|
||||
cameraserver {
|
||||
x86ExcludeSymbols = ['_CT??_R0?AV_System_error', '_CT??_R0?AVexception', '_CT??_R0?AVfailure',
|
||||
'_CT??_R0?AVruntime_error', '_CT??_R0?AVsystem_error', '_CTA5?AVfailure',
|
||||
'_TI5?AVfailure', '_CT??_R0?AVout_of_range', '_CTA3?AVout_of_range',
|
||||
'_TI3?AVout_of_range', '_CT??_R0?AVbad_cast']
|
||||
x64ExcludeSymbols = ['_CT??_R0?AV_System_error', '_CT??_R0?AVexception', '_CT??_R0?AVfailure',
|
||||
'_CT??_R0?AVruntime_error', '_CT??_R0?AVsystem_error', '_CTA5?AVfailure',
|
||||
'_TI5?AVfailure', '_CT??_R0?AVout_of_range', '_CTA3?AVout_of_range',
|
||||
'_TI3?AVout_of_range', '_CT??_R0?AVbad_cast']
|
||||
x86ExcludeSymbols = [
|
||||
'_CT??_R0?AV_System_error',
|
||||
'_CT??_R0?AVexception',
|
||||
'_CT??_R0?AVfailure',
|
||||
'_CT??_R0?AVruntime_error',
|
||||
'_CT??_R0?AVsystem_error',
|
||||
'_CTA5?AVfailure',
|
||||
'_TI5?AVfailure',
|
||||
'_CT??_R0?AVout_of_range',
|
||||
'_CTA3?AVout_of_range',
|
||||
'_TI3?AVout_of_range',
|
||||
'_CT??_R0?AVbad_cast'
|
||||
]
|
||||
x64ExcludeSymbols = [
|
||||
'_CT??_R0?AV_System_error',
|
||||
'_CT??_R0?AVexception',
|
||||
'_CT??_R0?AVfailure',
|
||||
'_CT??_R0?AVruntime_error',
|
||||
'_CT??_R0?AVsystem_error',
|
||||
'_CTA5?AVfailure',
|
||||
'_TI5?AVfailure',
|
||||
'_CT??_R0?AVout_of_range',
|
||||
'_CTA3?AVout_of_range',
|
||||
'_TI3?AVout_of_range',
|
||||
'_CT??_R0?AVbad_cast'
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,4 +5,5 @@ include(CMakeFindDependencyMacro)
|
||||
@CSCORE_DEP_REPLACE@
|
||||
find_dependency(OpenCV)
|
||||
|
||||
@FILENAME_DEP_REPLACE@
|
||||
include(${SELF_DIR}/cameraserver.cmake)
|
||||
|
||||
@@ -18,7 +18,7 @@ ext {
|
||||
|
||||
apply from: "${rootDir}/shared/opencv.gradle"
|
||||
|
||||
mainClassName = 'Main'
|
||||
mainClassName = 'edu.wpi.Main'
|
||||
|
||||
apply plugin: 'com.github.johnrengelman.shadow'
|
||||
|
||||
@@ -27,7 +27,7 @@ repositories {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.google.code.gson:gson:2.8.5'
|
||||
implementation 'com.google.code.gson:gson:2.8.9'
|
||||
|
||||
implementation project(':wpiutil')
|
||||
implementation project(':ntcore')
|
||||
@@ -52,10 +52,10 @@ model {
|
||||
}
|
||||
}
|
||||
binaries.all { binary ->
|
||||
lib project: ':cameraserver', library: 'cameraserver', linkage: 'static'
|
||||
lib project: ':ntcore', library: 'ntcore', linkage: 'static'
|
||||
lib project: ':cscore', library: 'cscore', linkage: 'static'
|
||||
lib project: ':wpiutil', library: 'wpiutil', linkage: 'static'
|
||||
lib project: ':cameraserver', library: 'cameraserver', linkage: 'static'
|
||||
lib project: ':ntcore', library: 'ntcore', linkage: 'static'
|
||||
lib project: ':cscore', library: 'cscore', linkage: 'static'
|
||||
lib project: ':wpiutil', library: 'wpiutil', linkage: 'static'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
|
||||
import edu.wpi.cscore.VideoSource;
|
||||
import edu.wpi.first.cameraserver.CameraServer;
|
||||
import edu.wpi.first.networktables.NetworkTableInstance;
|
||||
|
||||
/*
|
||||
JSON format:
|
||||
{
|
||||
"team": <team number>,
|
||||
"ntmode": <"client" or "server", "client" if unspecified>
|
||||
"cameras": [
|
||||
{
|
||||
"name": <camera name>
|
||||
"path": <path, e.g. "/dev/video0">
|
||||
"pixel format": <"MJPEG", "YUYV", etc> // optional
|
||||
"width": <video mode width> // optional
|
||||
"height": <video mode height> // optional
|
||||
"fps": <video mode fps> // optional
|
||||
"brightness": <percentage brightness> // optional
|
||||
"white balance": <"auto", "hold", value> // optional
|
||||
"exposure": <"auto", "hold", value> // optional
|
||||
"properties": [ // optional
|
||||
{
|
||||
"name": <property name>
|
||||
"value": <property value>
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
|
||||
public final class Main {
|
||||
private static String configFile = "/boot/frc.json";
|
||||
|
||||
@SuppressWarnings("MemberName")
|
||||
public static class CameraConfig {
|
||||
public String name;
|
||||
public String path;
|
||||
public JsonObject config;
|
||||
}
|
||||
|
||||
public static int team;
|
||||
public static boolean server;
|
||||
public static List<CameraConfig> cameras = new ArrayList<>();
|
||||
|
||||
private Main() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Report parse error.
|
||||
*/
|
||||
public static void parseError(String str) {
|
||||
System.err.println("config error in '" + configFile + "': " + str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read single camera configuration.
|
||||
*/
|
||||
public static boolean readCameraConfig(JsonObject config) {
|
||||
CameraConfig cam = new CameraConfig();
|
||||
|
||||
// name
|
||||
JsonElement nameElement = config.get("name");
|
||||
if (nameElement == null) {
|
||||
parseError("could not read camera name");
|
||||
return false;
|
||||
}
|
||||
cam.name = nameElement.getAsString();
|
||||
|
||||
// path
|
||||
JsonElement pathElement = config.get("path");
|
||||
if (pathElement == null) {
|
||||
parseError("camera '" + cam.name + "': could not read path");
|
||||
return false;
|
||||
}
|
||||
cam.path = pathElement.getAsString();
|
||||
|
||||
cam.config = config;
|
||||
|
||||
cameras.add(cam);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read configuration file.
|
||||
*/
|
||||
@SuppressWarnings("PMD.CyclomaticComplexity")
|
||||
public static boolean readConfig() {
|
||||
// parse file
|
||||
JsonElement top;
|
||||
try {
|
||||
top = new JsonParser().parse(Files.newBufferedReader(Paths.get(configFile)));
|
||||
} catch (IOException ex) {
|
||||
System.err.println("could not open '" + configFile + "': " + ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
// top level must be an object
|
||||
if (!top.isJsonObject()) {
|
||||
parseError("must be JSON object");
|
||||
return false;
|
||||
}
|
||||
JsonObject obj = top.getAsJsonObject();
|
||||
|
||||
// team number
|
||||
JsonElement teamElement = obj.get("team");
|
||||
if (teamElement == null) {
|
||||
parseError("could not read team number");
|
||||
return false;
|
||||
}
|
||||
team = teamElement.getAsInt();
|
||||
|
||||
// ntmode (optional)
|
||||
if (obj.has("ntmode")) {
|
||||
String str = obj.get("ntmode").getAsString();
|
||||
if ("client".equalsIgnoreCase(str)) {
|
||||
server = false;
|
||||
} else if ("server".equalsIgnoreCase(str)) {
|
||||
server = true;
|
||||
} else {
|
||||
parseError("could not understand ntmode value '" + str + "'");
|
||||
}
|
||||
}
|
||||
|
||||
// cameras
|
||||
JsonElement camerasElement = obj.get("cameras");
|
||||
if (camerasElement == null) {
|
||||
parseError("could not read cameras");
|
||||
return false;
|
||||
}
|
||||
JsonArray cameras = camerasElement.getAsJsonArray();
|
||||
for (JsonElement camera : cameras) {
|
||||
if (!readCameraConfig(camera.getAsJsonObject())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Start running the camera.
|
||||
*/
|
||||
public static void startCamera(CameraConfig config) {
|
||||
System.out.println("Starting camera '" + config.name + "' on " + config.path);
|
||||
VideoSource camera = CameraServer.getInstance().startAutomaticCapture(
|
||||
config.name, config.path);
|
||||
|
||||
Gson gson = new GsonBuilder().create();
|
||||
|
||||
camera.setConfigJson(gson.toJson(config.config));
|
||||
}
|
||||
|
||||
/**
|
||||
* Main.
|
||||
*/
|
||||
public static void main(String... args) {
|
||||
if (args.length > 0) {
|
||||
configFile = args[0];
|
||||
}
|
||||
|
||||
// read configuration
|
||||
if (!readConfig()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// start NetworkTables
|
||||
NetworkTableInstance ntinst = NetworkTableInstance.getDefault();
|
||||
if (server) {
|
||||
System.out.println("Setting up NetworkTables server");
|
||||
ntinst.startServer();
|
||||
} else {
|
||||
System.out.println("Setting up NetworkTables client for team " + team);
|
||||
ntinst.startClientTeam(team);
|
||||
}
|
||||
|
||||
// start cameras
|
||||
for (CameraConfig camera : cameras) {
|
||||
startCamera(camera);
|
||||
}
|
||||
|
||||
// loop forever
|
||||
for (;;) {
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
} catch (InterruptedException ex) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
195
cameraserver/multiCameraServer/src/main/java/edu/wpi/Main.java
Normal file
195
cameraserver/multiCameraServer/src/main/java/edu/wpi/Main.java
Normal file
@@ -0,0 +1,195 @@
|
||||
// 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;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonParser;
|
||||
import edu.wpi.first.cameraserver.CameraServer;
|
||||
import edu.wpi.first.cscore.VideoSource;
|
||||
import edu.wpi.first.networktables.NetworkTableInstance;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
JSON format:
|
||||
{
|
||||
"team": <team number>,
|
||||
"ntmode": <"client" or "server", "client" if unspecified>
|
||||
"cameras": [
|
||||
{
|
||||
"name": <camera name>
|
||||
"path": <path, e.g. "/dev/video0">
|
||||
"pixel format": <"MJPEG", "YUYV", etc> // optional
|
||||
"width": <video mode width> // optional
|
||||
"height": <video mode height> // optional
|
||||
"fps": <video mode fps> // optional
|
||||
"brightness": <percentage brightness> // optional
|
||||
"white balance": <"auto", "hold", value> // optional
|
||||
"exposure": <"auto", "hold", value> // optional
|
||||
"properties": [ // optional
|
||||
{
|
||||
"name": <property name>
|
||||
"value": <property value>
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
*/
|
||||
|
||||
public final class Main {
|
||||
private static String configFile = "/boot/frc.json";
|
||||
|
||||
@SuppressWarnings("MemberName")
|
||||
public static class CameraConfig {
|
||||
public String name;
|
||||
public String path;
|
||||
public JsonObject config;
|
||||
}
|
||||
|
||||
private static int team;
|
||||
private static boolean server;
|
||||
private static List<CameraConfig> cameras = new ArrayList<>();
|
||||
|
||||
private Main() {}
|
||||
|
||||
/** Report parse error. */
|
||||
public static void parseError(String str) {
|
||||
System.err.println("config error in '" + configFile + "': " + str);
|
||||
}
|
||||
|
||||
/** Read single camera configuration. */
|
||||
public static boolean readCameraConfig(JsonObject config) {
|
||||
CameraConfig cam = new CameraConfig();
|
||||
|
||||
// name
|
||||
JsonElement nameElement = config.get("name");
|
||||
if (nameElement == null) {
|
||||
parseError("could not read camera name");
|
||||
return false;
|
||||
}
|
||||
cam.name = nameElement.getAsString();
|
||||
|
||||
// path
|
||||
JsonElement pathElement = config.get("path");
|
||||
if (pathElement == null) {
|
||||
parseError("camera '" + cam.name + "': could not read path");
|
||||
return false;
|
||||
}
|
||||
cam.path = pathElement.getAsString();
|
||||
|
||||
cam.config = config;
|
||||
|
||||
cameras.add(cam);
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Read configuration file. */
|
||||
public static boolean readConfig() {
|
||||
// parse file
|
||||
JsonElement top;
|
||||
try {
|
||||
top = new JsonParser().parse(Files.newBufferedReader(Paths.get(configFile)));
|
||||
} catch (IOException ex) {
|
||||
System.err.println("could not open '" + configFile + "': " + ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
// top level must be an object
|
||||
if (!top.isJsonObject()) {
|
||||
parseError("must be JSON object");
|
||||
return false;
|
||||
}
|
||||
JsonObject obj = top.getAsJsonObject();
|
||||
|
||||
// team number
|
||||
JsonElement teamElement = obj.get("team");
|
||||
if (teamElement == null) {
|
||||
parseError("could not read team number");
|
||||
return false;
|
||||
}
|
||||
team = teamElement.getAsInt();
|
||||
|
||||
// ntmode (optional)
|
||||
if (obj.has("ntmode")) {
|
||||
String str = obj.get("ntmode").getAsString();
|
||||
if ("client".equalsIgnoreCase(str)) {
|
||||
server = false;
|
||||
} else if ("server".equalsIgnoreCase(str)) {
|
||||
server = true;
|
||||
} else {
|
||||
parseError("could not understand ntmode value '" + str + "'");
|
||||
}
|
||||
}
|
||||
|
||||
// cameras
|
||||
JsonElement camerasElement = obj.get("cameras");
|
||||
if (camerasElement == null) {
|
||||
parseError("could not read cameras");
|
||||
return false;
|
||||
}
|
||||
JsonArray cameras = camerasElement.getAsJsonArray();
|
||||
for (JsonElement camera : cameras) {
|
||||
if (!readCameraConfig(camera.getAsJsonObject())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Start running the camera. */
|
||||
public static void startCamera(CameraConfig config) {
|
||||
System.out.println("Starting camera '" + config.name + "' on " + config.path);
|
||||
VideoSource camera = CameraServer.startAutomaticCapture(config.name, config.path);
|
||||
|
||||
Gson gson = new GsonBuilder().create();
|
||||
|
||||
camera.setConfigJson(gson.toJson(config.config));
|
||||
}
|
||||
|
||||
/** Main. */
|
||||
public static void main(String... args) {
|
||||
if (args.length > 0) {
|
||||
configFile = args[0];
|
||||
}
|
||||
|
||||
// read configuration
|
||||
if (!readConfig()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// start NetworkTables
|
||||
NetworkTableInstance ntinst = NetworkTableInstance.getDefault();
|
||||
if (server) {
|
||||
System.out.println("Setting up NetworkTables server");
|
||||
ntinst.startServer();
|
||||
} else {
|
||||
System.out.println("Setting up NetworkTables client for team " + team);
|
||||
ntinst.startClientTeam(team);
|
||||
}
|
||||
|
||||
// start cameras
|
||||
for (CameraConfig camera : cameras) {
|
||||
startCamera(camera);
|
||||
}
|
||||
|
||||
// loop forever
|
||||
for (; ; ) {
|
||||
try {
|
||||
Thread.sleep(10000);
|
||||
} catch (InterruptedException ex) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,15 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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 <cstdio>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <networktables/NetworkTableInstance.h>
|
||||
#include <wpi/StringRef.h>
|
||||
#include <wpi/StringExtras.h>
|
||||
#include <wpi/fmt/raw_ostream.h>
|
||||
#include <wpi/json.h>
|
||||
#include <wpi/raw_istream.h>
|
||||
#include <wpi/raw_ostream.h>
|
||||
@@ -108,7 +107,7 @@ bool ReadConfig() {
|
||||
try {
|
||||
j = wpi::json::parse(is);
|
||||
} catch (const wpi::json::parse_error& e) {
|
||||
ParseError() << "byte " << e.byte << ": " << e.what() << '\n';
|
||||
fmt::print(ParseError(), "byte {}: {}\n", e.byte, e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -130,10 +129,9 @@ bool ReadConfig() {
|
||||
if (j.count("ntmode") != 0) {
|
||||
try {
|
||||
auto str = j.at("ntmode").get<std::string>();
|
||||
wpi::StringRef s(str);
|
||||
if (s.equals_lower("client")) {
|
||||
if (wpi::equals_lower(str, "client")) {
|
||||
server = false;
|
||||
} else if (s.equals_lower("server")) {
|
||||
} else if (wpi::equals_lower(str, "server")) {
|
||||
server = true;
|
||||
} else {
|
||||
ParseError() << "could not understand ntmode value '" << str << "'\n";
|
||||
@@ -146,7 +144,9 @@ bool ReadConfig() {
|
||||
// cameras
|
||||
try {
|
||||
for (auto&& camera : j.at("cameras")) {
|
||||
if (!ReadCameraConfig(camera)) return false;
|
||||
if (!ReadCameraConfig(camera)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} catch (const wpi::json::exception& e) {
|
||||
ParseError() << "could not read cameras: " << e.what() << '\n';
|
||||
@@ -157,34 +157,41 @@ bool ReadConfig() {
|
||||
}
|
||||
|
||||
void StartCamera(const CameraConfig& config) {
|
||||
wpi::outs() << "Starting camera '" << config.name << "' on " << config.path
|
||||
<< '\n';
|
||||
auto camera = frc::CameraServer::GetInstance()->StartAutomaticCapture(
|
||||
config.name, config.path);
|
||||
fmt::print("Starting camera '{}' on {}\n", config.name, config.path);
|
||||
auto camera =
|
||||
frc::CameraServer::StartAutomaticCapture(config.name, config.path);
|
||||
|
||||
camera.SetConfigJson(config.config);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc >= 2) configFile = argv[1];
|
||||
if (argc >= 2) {
|
||||
configFile = argv[1];
|
||||
}
|
||||
|
||||
// read configuration
|
||||
if (!ReadConfig()) return EXIT_FAILURE;
|
||||
if (!ReadConfig()) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// start NetworkTables
|
||||
auto ntinst = nt::NetworkTableInstance::GetDefault();
|
||||
if (server) {
|
||||
wpi::outs() << "Setting up NetworkTables server\n";
|
||||
std::puts("Setting up NetworkTables server");
|
||||
ntinst.StartServer();
|
||||
} else {
|
||||
wpi::outs() << "Setting up NetworkTables client for team " << team << '\n';
|
||||
fmt::print("Setting up NetworkTables client for team {}\n", team);
|
||||
ntinst.StartClientTeam(team);
|
||||
}
|
||||
|
||||
// start cameras
|
||||
for (auto&& camera : cameras) StartCamera(camera);
|
||||
for (auto&& camera : cameras) {
|
||||
StartCamera(camera);
|
||||
}
|
||||
|
||||
// loop forever
|
||||
for (;;) std::this_thread::sleep_for(std::chrono::seconds(10));
|
||||
for (;;) {
|
||||
std::this_thread::sleep_for(std::chrono::seconds(10));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +1,11 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.cameraserver;
|
||||
|
||||
public final class DevMain {
|
||||
public static void main(String[] args) {
|
||||
public static void main(String[] args) {}
|
||||
|
||||
}
|
||||
|
||||
private DevMain() {
|
||||
}
|
||||
private DevMain() {}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.
|
||||
|
||||
int main() {}
|
||||
|
||||
@@ -1,12 +1,27 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.cameraserver;
|
||||
|
||||
import edu.wpi.first.cscore.AxisCamera;
|
||||
import edu.wpi.first.cscore.CameraServerJNI;
|
||||
import edu.wpi.first.cscore.CvSink;
|
||||
import edu.wpi.first.cscore.CvSource;
|
||||
import edu.wpi.first.cscore.MjpegServer;
|
||||
import edu.wpi.first.cscore.UsbCamera;
|
||||
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.VideoProperty;
|
||||
import edu.wpi.first.cscore.VideoSink;
|
||||
import edu.wpi.first.cscore.VideoSource;
|
||||
import edu.wpi.first.networktables.EntryListenerFlags;
|
||||
import edu.wpi.first.networktables.NetworkTable;
|
||||
import edu.wpi.first.networktables.NetworkTableEntry;
|
||||
import edu.wpi.first.networktables.NetworkTableInstance;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
@@ -14,46 +29,28 @@ import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import edu.wpi.cscore.AxisCamera;
|
||||
import edu.wpi.cscore.CameraServerJNI;
|
||||
import edu.wpi.cscore.CvSink;
|
||||
import edu.wpi.cscore.CvSource;
|
||||
import edu.wpi.cscore.MjpegServer;
|
||||
import edu.wpi.cscore.UsbCamera;
|
||||
import edu.wpi.cscore.VideoEvent;
|
||||
import edu.wpi.cscore.VideoException;
|
||||
import edu.wpi.cscore.VideoListener;
|
||||
import edu.wpi.cscore.VideoMode;
|
||||
import edu.wpi.cscore.VideoMode.PixelFormat;
|
||||
import edu.wpi.cscore.VideoProperty;
|
||||
import edu.wpi.cscore.VideoSink;
|
||||
import edu.wpi.cscore.VideoSource;
|
||||
import edu.wpi.first.networktables.EntryListenerFlags;
|
||||
import edu.wpi.first.networktables.NetworkTable;
|
||||
import edu.wpi.first.networktables.NetworkTableEntry;
|
||||
import edu.wpi.first.networktables.NetworkTableInstance;
|
||||
|
||||
/**
|
||||
* Singleton class for creating and keeping camera servers.
|
||||
* Also publishes camera information to NetworkTables.
|
||||
* Singleton class for creating and keeping camera servers. Also publishes camera information to
|
||||
* NetworkTables.
|
||||
*/
|
||||
@SuppressWarnings("PMD.TooManyMethods")
|
||||
@SuppressWarnings("PMD.UnusedPrivateField")
|
||||
public final class CameraServer {
|
||||
public static final int kBasePort = 1181;
|
||||
|
||||
@Deprecated
|
||||
public static final int kSize640x480 = 0;
|
||||
@Deprecated
|
||||
public static final int kSize320x240 = 1;
|
||||
@Deprecated
|
||||
public static final int kSize160x120 = 2;
|
||||
@Deprecated public static final int kSize640x480 = 0;
|
||||
@Deprecated public static final int kSize320x240 = 1;
|
||||
@Deprecated public static final int kSize160x120 = 2;
|
||||
|
||||
private static final String kPublishName = "/CameraPublisher";
|
||||
private static CameraServer server;
|
||||
|
||||
/**
|
||||
* Get the CameraServer instance.
|
||||
*
|
||||
* @return The CameraServer instance.
|
||||
* @deprecated Use the static methods
|
||||
*/
|
||||
@Deprecated
|
||||
public static synchronized CameraServer getInstance() {
|
||||
if (server == null) {
|
||||
server = new CameraServer();
|
||||
@@ -61,32 +58,226 @@ public final class CameraServer {
|
||||
return server;
|
||||
}
|
||||
|
||||
private final AtomicInteger m_defaultUsbDevice;
|
||||
private String m_primarySourceName;
|
||||
private final Map<String, VideoSource> m_sources;
|
||||
private final Map<String, VideoSink> m_sinks;
|
||||
private final Map<Integer, NetworkTable> m_tables; // indexed by source handle
|
||||
private static final AtomicInteger m_defaultUsbDevice = new AtomicInteger();
|
||||
private static String m_primarySourceName;
|
||||
private static final Map<String, VideoSource> m_sources = new HashMap<>();
|
||||
private static final Map<String, VideoSink> m_sinks = new HashMap<>();
|
||||
private static final Map<Integer, NetworkTable> m_tables =
|
||||
new HashMap<>(); // indexed by source handle
|
||||
// source handle indexed by sink handle
|
||||
private final Map<Integer, Integer> m_fixedSources;
|
||||
private final NetworkTable m_publishTable;
|
||||
private final VideoListener m_videoListener; //NOPMD
|
||||
private final int m_tableListener; //NOPMD
|
||||
private int m_nextPort;
|
||||
private String[] m_addresses;
|
||||
private static final Map<Integer, Integer> m_fixedSources = new HashMap<>();
|
||||
private static final NetworkTable m_publishTable =
|
||||
NetworkTableInstance.getDefault().getTable(kPublishName);
|
||||
|
||||
@SuppressWarnings("JavadocMethod")
|
||||
// We publish sources to NetworkTables using the following structure:
|
||||
// "/CameraPublisher/{Source.Name}/" - root
|
||||
// - "source" (string): Descriptive, prefixed with type (e.g. "usb:0")
|
||||
// - "streams" (string array): URLs that can be used to stream data
|
||||
// - "description" (string): Description of the source
|
||||
// - "connected" (boolean): Whether source is connected
|
||||
// - "mode" (string): Current video mode
|
||||
// - "modes" (string array): Available video modes
|
||||
// - "Property/{Property}" - Property values
|
||||
// - "PropertyInfo/{Property}" - Property supporting information
|
||||
|
||||
// Listener for video events
|
||||
private static final VideoListener m_videoListener =
|
||||
new VideoListener(
|
||||
event -> {
|
||||
switch (event.kind) {
|
||||
case kSourceCreated:
|
||||
{
|
||||
// Create subtable for the camera
|
||||
NetworkTable table = m_publishTable.getSubTable(event.name);
|
||||
m_tables.put(event.sourceHandle, table);
|
||||
table.getEntry("source").setString(makeSourceValue(event.sourceHandle));
|
||||
table
|
||||
.getEntry("description")
|
||||
.setString(CameraServerJNI.getSourceDescription(event.sourceHandle));
|
||||
table
|
||||
.getEntry("connected")
|
||||
.setBoolean(CameraServerJNI.isSourceConnected(event.sourceHandle));
|
||||
table
|
||||
.getEntry("streams")
|
||||
.setStringArray(getSourceStreamValues(event.sourceHandle));
|
||||
try {
|
||||
VideoMode mode = CameraServerJNI.getSourceVideoMode(event.sourceHandle);
|
||||
table.getEntry("mode").setDefaultString(videoModeToString(mode));
|
||||
table.getEntry("modes").setStringArray(getSourceModeValues(event.sourceHandle));
|
||||
} catch (VideoException ignored) {
|
||||
// Do nothing. Let the other event handlers update this if there is an error.
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourceDestroyed:
|
||||
{
|
||||
NetworkTable table = m_tables.get(event.sourceHandle);
|
||||
if (table != null) {
|
||||
table.getEntry("source").setString("");
|
||||
table.getEntry("streams").setStringArray(new String[0]);
|
||||
table.getEntry("modes").setStringArray(new String[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourceConnected:
|
||||
{
|
||||
NetworkTable table = m_tables.get(event.sourceHandle);
|
||||
if (table != null) {
|
||||
// update the description too (as it may have changed)
|
||||
table
|
||||
.getEntry("description")
|
||||
.setString(CameraServerJNI.getSourceDescription(event.sourceHandle));
|
||||
table.getEntry("connected").setBoolean(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourceDisconnected:
|
||||
{
|
||||
NetworkTable table = m_tables.get(event.sourceHandle);
|
||||
if (table != null) {
|
||||
table.getEntry("connected").setBoolean(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourceVideoModesUpdated:
|
||||
{
|
||||
NetworkTable table = m_tables.get(event.sourceHandle);
|
||||
if (table != null) {
|
||||
table.getEntry("modes").setStringArray(getSourceModeValues(event.sourceHandle));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourceVideoModeChanged:
|
||||
{
|
||||
NetworkTable table = m_tables.get(event.sourceHandle);
|
||||
if (table != null) {
|
||||
table.getEntry("mode").setString(videoModeToString(event.mode));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourcePropertyCreated:
|
||||
{
|
||||
NetworkTable table = m_tables.get(event.sourceHandle);
|
||||
if (table != null) {
|
||||
putSourcePropertyValue(table, event, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourcePropertyValueUpdated:
|
||||
{
|
||||
NetworkTable table = m_tables.get(event.sourceHandle);
|
||||
if (table != null) {
|
||||
putSourcePropertyValue(table, event, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourcePropertyChoicesUpdated:
|
||||
{
|
||||
NetworkTable table = m_tables.get(event.sourceHandle);
|
||||
if (table != null) {
|
||||
try {
|
||||
String[] choices =
|
||||
CameraServerJNI.getEnumPropertyChoices(event.propertyHandle);
|
||||
table
|
||||
.getEntry("PropertyInfo/" + event.name + "/choices")
|
||||
.setStringArray(choices);
|
||||
} catch (VideoException ignored) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSinkSourceChanged:
|
||||
case kSinkCreated:
|
||||
case kSinkDestroyed:
|
||||
case kNetworkInterfacesChanged:
|
||||
{
|
||||
m_addresses = CameraServerJNI.getNetworkInterfaces();
|
||||
updateStreamValues();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
0x4fff,
|
||||
true);
|
||||
|
||||
private static final int m_tableListener =
|
||||
NetworkTableInstance.getDefault()
|
||||
.addEntryListener(
|
||||
kPublishName + "/",
|
||||
event -> {
|
||||
String relativeKey = event.name.substring(kPublishName.length() + 1);
|
||||
|
||||
// get source (sourceName/...)
|
||||
int subKeyIndex = relativeKey.indexOf('/');
|
||||
if (subKeyIndex == -1) {
|
||||
return;
|
||||
}
|
||||
String sourceName = relativeKey.substring(0, subKeyIndex);
|
||||
VideoSource source = m_sources.get(sourceName);
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get subkey
|
||||
relativeKey = relativeKey.substring(subKeyIndex + 1);
|
||||
|
||||
// handle standard names
|
||||
String propName;
|
||||
if ("mode".equals(relativeKey)) {
|
||||
// reset to current mode
|
||||
event.getEntry().setString(videoModeToString(source.getVideoMode()));
|
||||
return;
|
||||
} else if (relativeKey.startsWith("Property/")) {
|
||||
propName = relativeKey.substring(9);
|
||||
} else if (relativeKey.startsWith("RawProperty/")) {
|
||||
propName = relativeKey.substring(12);
|
||||
} else {
|
||||
return; // ignore
|
||||
}
|
||||
|
||||
// everything else is a property
|
||||
VideoProperty property = source.getProperty(propName);
|
||||
switch (property.getKind()) {
|
||||
case kNone:
|
||||
return;
|
||||
case kBoolean:
|
||||
// reset to current setting
|
||||
event.getEntry().setBoolean(property.get() != 0);
|
||||
return;
|
||||
case kInteger:
|
||||
case kEnum:
|
||||
// reset to current setting
|
||||
event.getEntry().setDouble(property.get());
|
||||
return;
|
||||
case kString:
|
||||
// reset to current setting
|
||||
event.getEntry().setString(property.getString());
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
},
|
||||
EntryListenerFlags.kImmediate | EntryListenerFlags.kUpdate);
|
||||
private static int m_nextPort = kBasePort;
|
||||
private static String[] m_addresses = new String[0];
|
||||
|
||||
@SuppressWarnings("MissingJavadocMethod")
|
||||
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:";
|
||||
case kHttp:
|
||||
{
|
||||
String[] urls = CameraServerJNI.getHttpCameraUrls(source);
|
||||
if (urls.length > 0) {
|
||||
return "ip:" + urls[0];
|
||||
} else {
|
||||
return "ip:";
|
||||
}
|
||||
}
|
||||
}
|
||||
case kCv:
|
||||
return "cv:";
|
||||
default:
|
||||
@@ -94,13 +285,13 @@ public final class CameraServer {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("JavadocMethod")
|
||||
@SuppressWarnings("MissingJavadocMethod")
|
||||
private static String makeStreamValue(String address, int port) {
|
||||
return "mjpg:http://" + address + ":" + port + "/?action=stream";
|
||||
}
|
||||
|
||||
@SuppressWarnings({"JavadocMethod", "PMD.AvoidUsingHardCodedIP"})
|
||||
private synchronized String[] getSinkStreamValues(int sink) {
|
||||
@SuppressWarnings("MissingJavadocMethod")
|
||||
private static synchronized String[] getSinkStreamValues(int sink) {
|
||||
// Ignore all but MjpegServer
|
||||
if (VideoSink.getKindFromInt(CameraServerJNI.getSinkKind(sink)) != VideoSink.Kind.kMjpeg) {
|
||||
return new String[0];
|
||||
@@ -120,7 +311,7 @@ public final class CameraServer {
|
||||
values.add(makeStreamValue(CameraServerJNI.getHostname() + ".local", port));
|
||||
for (String addr : m_addresses) {
|
||||
if ("127.0.0.1".equals(addr)) {
|
||||
continue; // ignore localhost
|
||||
continue; // ignore localhost
|
||||
}
|
||||
values.add(makeStreamValue(addr, port));
|
||||
}
|
||||
@@ -129,11 +320,11 @@ public final class CameraServer {
|
||||
return values.toArray(new String[0]);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"JavadocMethod", "PMD.AvoidUsingHardCodedIP"})
|
||||
private synchronized String[] getSourceStreamValues(int source) {
|
||||
@SuppressWarnings("MissingJavadocMethod")
|
||||
private static synchronized String[] getSourceStreamValues(int source) {
|
||||
// Ignore all but HttpCamera
|
||||
if (VideoSource.getKindFromInt(CameraServerJNI.getSourceKind(source))
|
||||
!= VideoSource.Kind.kHttp) {
|
||||
!= VideoSource.Kind.kHttp) {
|
||||
return new String[0];
|
||||
}
|
||||
|
||||
@@ -151,7 +342,7 @@ public final class CameraServer {
|
||||
int sinkSource = CameraServerJNI.getSinkSource(sink);
|
||||
if (source == sinkSource
|
||||
&& VideoSink.getKindFromInt(CameraServerJNI.getSinkKind(sink))
|
||||
== VideoSink.Kind.kMjpeg) {
|
||||
== VideoSink.Kind.kMjpeg) {
|
||||
// Add USB-only passthrough
|
||||
String[] finalValues = Arrays.copyOf(values, values.length + 1);
|
||||
int port = CameraServerJNI.getMjpegServerPort(sink);
|
||||
@@ -164,15 +355,16 @@ public final class CameraServer {
|
||||
return values;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"JavadocMethod", "PMD.AvoidUsingHardCodedIP", "PMD.CyclomaticComplexity"})
|
||||
private synchronized void updateStreamValues() {
|
||||
@SuppressWarnings("MissingJavadocMethod")
|
||||
private static synchronized void updateStreamValues() {
|
||||
// Over all the sinks...
|
||||
for (VideoSink i : m_sinks.values()) {
|
||||
int sink = i.getHandle();
|
||||
|
||||
// Get the source's subtable (if none exists, we're done)
|
||||
int source = Objects.requireNonNullElseGet(m_fixedSources.get(sink),
|
||||
() -> CameraServerJNI.getSinkSource(sink));
|
||||
int source =
|
||||
Objects.requireNonNullElseGet(
|
||||
m_fixedSources.get(sink), () -> CameraServerJNI.getSinkSource(sink));
|
||||
|
||||
if (source == 0) {
|
||||
continue;
|
||||
@@ -209,7 +401,7 @@ public final class CameraServer {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("JavadocMethod")
|
||||
@SuppressWarnings("MissingJavadocMethod")
|
||||
private static String pixelFormatToString(PixelFormat pixelFormat) {
|
||||
switch (pixelFormat) {
|
||||
case kMJPEG:
|
||||
@@ -229,13 +421,19 @@ public final class CameraServer {
|
||||
|
||||
/// Provide string description of video mode.
|
||||
/// The returned string is "{width}x{height} {format} {fps} fps".
|
||||
@SuppressWarnings("JavadocMethod")
|
||||
@SuppressWarnings("MissingJavadocMethod")
|
||||
private static String videoModeToString(VideoMode mode) {
|
||||
return mode.width + "x" + mode.height + " " + pixelFormatToString(mode.pixelFormat)
|
||||
+ " " + mode.fps + " fps";
|
||||
return mode.width
|
||||
+ "x"
|
||||
+ mode.height
|
||||
+ " "
|
||||
+ pixelFormatToString(mode.pixelFormat)
|
||||
+ " "
|
||||
+ mode.fps
|
||||
+ " fps";
|
||||
}
|
||||
|
||||
@SuppressWarnings("JavadocMethod")
|
||||
@SuppressWarnings("MissingJavadocMethod")
|
||||
private static String[] getSourceModeValues(int sourceHandle) {
|
||||
VideoMode[] modes = CameraServerJNI.enumerateSourceVideoModes(sourceHandle);
|
||||
String[] modeStrings = new String[modes.length];
|
||||
@@ -245,7 +443,7 @@ public final class CameraServer {
|
||||
return modeStrings;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"JavadocMethod", "PMD.CyclomaticComplexity"})
|
||||
@SuppressWarnings("MissingJavadocMethod")
|
||||
private static void putSourcePropertyValue(NetworkTable table, VideoEvent event, boolean isNew) {
|
||||
String name;
|
||||
String infoName;
|
||||
@@ -271,14 +469,18 @@ public final class CameraServer {
|
||||
case kEnum:
|
||||
if (isNew) {
|
||||
entry.setDefaultDouble(event.value);
|
||||
table.getEntry(infoName + "/min").setDouble(
|
||||
CameraServerJNI.getPropertyMin(event.propertyHandle));
|
||||
table.getEntry(infoName + "/max").setDouble(
|
||||
CameraServerJNI.getPropertyMax(event.propertyHandle));
|
||||
table.getEntry(infoName + "/step").setDouble(
|
||||
CameraServerJNI.getPropertyStep(event.propertyHandle));
|
||||
table.getEntry(infoName + "/default").setDouble(
|
||||
CameraServerJNI.getPropertyDefault(event.propertyHandle));
|
||||
table
|
||||
.getEntry(infoName + "/min")
|
||||
.setDouble(CameraServerJNI.getPropertyMin(event.propertyHandle));
|
||||
table
|
||||
.getEntry(infoName + "/max")
|
||||
.setDouble(CameraServerJNI.getPropertyMax(event.propertyHandle));
|
||||
table
|
||||
.getEntry(infoName + "/step")
|
||||
.setDouble(CameraServerJNI.getPropertyStep(event.propertyHandle));
|
||||
table
|
||||
.getEntry(infoName + "/default")
|
||||
.setDouble(CameraServerJNI.getPropertyDefault(event.propertyHandle));
|
||||
} else {
|
||||
entry.setDouble(event.value);
|
||||
}
|
||||
@@ -298,203 +500,21 @@ public final class CameraServer {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"JavadocMethod", "PMD.UnusedLocalVariable", "PMD.ExcessiveMethodLength",
|
||||
"PMD.NPathComplexity"})
|
||||
private CameraServer() {
|
||||
m_defaultUsbDevice = new AtomicInteger();
|
||||
m_sources = new HashMap<>();
|
||||
m_sinks = new HashMap<>();
|
||||
m_fixedSources = new HashMap<>();
|
||||
m_tables = new HashMap<>();
|
||||
m_publishTable = NetworkTableInstance.getDefault().getTable(kPublishName);
|
||||
m_nextPort = kBasePort;
|
||||
m_addresses = new String[0];
|
||||
|
||||
// We publish sources to NetworkTables using the following structure:
|
||||
// "/CameraPublisher/{Source.Name}/" - root
|
||||
// - "source" (string): Descriptive, prefixed with type (e.g. "usb:0")
|
||||
// - "streams" (string array): URLs that can be used to stream data
|
||||
// - "description" (string): Description of the source
|
||||
// - "connected" (boolean): Whether source is connected
|
||||
// - "mode" (string): Current video mode
|
||||
// - "modes" (string array): Available video modes
|
||||
// - "Property/{Property}" - Property values
|
||||
// - "PropertyInfo/{Property}" - Property supporting information
|
||||
|
||||
// Listener for video events
|
||||
m_videoListener = new VideoListener(event -> {
|
||||
switch (event.kind) {
|
||||
case kSourceCreated: {
|
||||
// Create subtable for the camera
|
||||
NetworkTable table = m_publishTable.getSubTable(event.name);
|
||||
m_tables.put(event.sourceHandle, table);
|
||||
table.getEntry("source").setString(makeSourceValue(event.sourceHandle));
|
||||
table.getEntry("description").setString(
|
||||
CameraServerJNI.getSourceDescription(event.sourceHandle));
|
||||
table.getEntry("connected").setBoolean(
|
||||
CameraServerJNI.isSourceConnected(event.sourceHandle));
|
||||
table.getEntry("streams").setStringArray(getSourceStreamValues(event.sourceHandle));
|
||||
try {
|
||||
VideoMode mode = CameraServerJNI.getSourceVideoMode(event.sourceHandle);
|
||||
table.getEntry("mode").setDefaultString(videoModeToString(mode));
|
||||
table.getEntry("modes").setStringArray(getSourceModeValues(event.sourceHandle));
|
||||
} catch (VideoException ignored) {
|
||||
// Do nothing. Let the other event handlers update this if there is an error.
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourceDestroyed: {
|
||||
NetworkTable table = m_tables.get(event.sourceHandle);
|
||||
if (table != null) {
|
||||
table.getEntry("source").setString("");
|
||||
table.getEntry("streams").setStringArray(new String[0]);
|
||||
table.getEntry("modes").setStringArray(new String[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourceConnected: {
|
||||
NetworkTable table = m_tables.get(event.sourceHandle);
|
||||
if (table != null) {
|
||||
// update the description too (as it may have changed)
|
||||
table.getEntry("description").setString(
|
||||
CameraServerJNI.getSourceDescription(event.sourceHandle));
|
||||
table.getEntry("connected").setBoolean(true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourceDisconnected: {
|
||||
NetworkTable table = m_tables.get(event.sourceHandle);
|
||||
if (table != null) {
|
||||
table.getEntry("connected").setBoolean(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourceVideoModesUpdated: {
|
||||
NetworkTable table = m_tables.get(event.sourceHandle);
|
||||
if (table != null) {
|
||||
table.getEntry("modes").setStringArray(getSourceModeValues(event.sourceHandle));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourceVideoModeChanged: {
|
||||
NetworkTable table = m_tables.get(event.sourceHandle);
|
||||
if (table != null) {
|
||||
table.getEntry("mode").setString(videoModeToString(event.mode));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourcePropertyCreated: {
|
||||
NetworkTable table = m_tables.get(event.sourceHandle);
|
||||
if (table != null) {
|
||||
putSourcePropertyValue(table, event, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourcePropertyValueUpdated: {
|
||||
NetworkTable table = m_tables.get(event.sourceHandle);
|
||||
if (table != null) {
|
||||
putSourcePropertyValue(table, event, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSourcePropertyChoicesUpdated: {
|
||||
NetworkTable table = m_tables.get(event.sourceHandle);
|
||||
if (table != null) {
|
||||
try {
|
||||
String[] choices = CameraServerJNI.getEnumPropertyChoices(event.propertyHandle);
|
||||
table.getEntry("PropertyInfo/" + event.name + "/choices").setStringArray(choices);
|
||||
} catch (VideoException ignored) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSinkSourceChanged:
|
||||
case kSinkCreated:
|
||||
case kSinkDestroyed:
|
||||
case kNetworkInterfacesChanged: {
|
||||
m_addresses = CameraServerJNI.getNetworkInterfaces();
|
||||
updateStreamValues();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}, 0x4fff, true);
|
||||
|
||||
// Listener for NetworkTable events
|
||||
// We don't currently support changing settings via NT due to
|
||||
// synchronization issues, so just update to current setting if someone
|
||||
// else tries to change it.
|
||||
m_tableListener = NetworkTableInstance.getDefault().addEntryListener(kPublishName + "/",
|
||||
event -> {
|
||||
String relativeKey = event.name.substring(kPublishName.length() + 1);
|
||||
|
||||
// get source (sourceName/...)
|
||||
int subKeyIndex = relativeKey.indexOf('/');
|
||||
if (subKeyIndex == -1) {
|
||||
return;
|
||||
}
|
||||
String sourceName = relativeKey.substring(0, subKeyIndex);
|
||||
VideoSource source = m_sources.get(sourceName);
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get subkey
|
||||
relativeKey = relativeKey.substring(subKeyIndex + 1);
|
||||
|
||||
// handle standard names
|
||||
String propName;
|
||||
if ("mode".equals(relativeKey)) {
|
||||
// reset to current mode
|
||||
event.getEntry().setString(videoModeToString(source.getVideoMode()));
|
||||
return;
|
||||
} else if (relativeKey.startsWith("Property/")) {
|
||||
propName = relativeKey.substring(9);
|
||||
} else if (relativeKey.startsWith("RawProperty/")) {
|
||||
propName = relativeKey.substring(12);
|
||||
} else {
|
||||
return; // ignore
|
||||
}
|
||||
|
||||
// everything else is a property
|
||||
VideoProperty property = source.getProperty(propName);
|
||||
switch (property.getKind()) {
|
||||
case kNone:
|
||||
return;
|
||||
case kBoolean:
|
||||
// reset to current setting
|
||||
event.getEntry().setBoolean(property.get() != 0);
|
||||
return;
|
||||
case kInteger:
|
||||
case kEnum:
|
||||
// reset to current setting
|
||||
event.getEntry().setDouble(property.get());
|
||||
return;
|
||||
case kString:
|
||||
// reset to current setting
|
||||
event.getEntry().setString(property.getString());
|
||||
return;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}, EntryListenerFlags.kImmediate | EntryListenerFlags.kUpdate);
|
||||
}
|
||||
private CameraServer() {}
|
||||
|
||||
/**
|
||||
* Start automatically capturing images to send to the dashboard.
|
||||
*
|
||||
* <p>You should call this method to see a camera feed on the dashboard.
|
||||
* If you also want to perform vision processing on the roboRIO, use
|
||||
* getVideo() to get access to the camera images.
|
||||
* <p>You should call this method to see a camera feed on the dashboard. If you also want to
|
||||
* perform vision processing on the roboRIO, use getVideo() to get access to the camera images.
|
||||
*
|
||||
* <p>The first time this overload is called, it calls
|
||||
* {@link #startAutomaticCapture(int)} with device 0, creating a camera
|
||||
* named "USB Camera 0". Subsequent calls increment the device number
|
||||
* <p>The first time this overload is called, it calls {@link #startAutomaticCapture(int)} with
|
||||
* device 0, creating a camera named "USB Camera 0". Subsequent calls increment the device number
|
||||
* (e.g. 1, 2, etc).
|
||||
*
|
||||
* @return The USB camera capturing images.
|
||||
*/
|
||||
public UsbCamera startAutomaticCapture() {
|
||||
public static UsbCamera startAutomaticCapture() {
|
||||
UsbCamera camera = startAutomaticCapture(m_defaultUsbDevice.getAndIncrement());
|
||||
CameraServerSharedStore.getCameraServerShared().reportUsbCamera(camera.getHandle());
|
||||
return camera;
|
||||
@@ -503,12 +523,13 @@ public final class CameraServer {
|
||||
/**
|
||||
* Start automatically capturing images to send to the dashboard.
|
||||
*
|
||||
* <p>This overload calls {@link #startAutomaticCapture(String, int)} with
|
||||
* a name of "USB Camera {dev}".
|
||||
* <p>This overload calls {@link #startAutomaticCapture(String, int)} with a name of "USB Camera
|
||||
* {dev}".
|
||||
*
|
||||
* @param dev The device number of the camera interface
|
||||
* @return The USB camera capturing images.
|
||||
*/
|
||||
public UsbCamera startAutomaticCapture(int dev) {
|
||||
public static UsbCamera startAutomaticCapture(int dev) {
|
||||
UsbCamera camera = new UsbCamera("USB Camera " + dev, dev);
|
||||
startAutomaticCapture(camera);
|
||||
CameraServerSharedStore.getCameraServerShared().reportUsbCamera(camera.getHandle());
|
||||
@@ -520,8 +541,9 @@ public final class CameraServer {
|
||||
*
|
||||
* @param name The name to give the camera
|
||||
* @param dev The device number of the camera interface
|
||||
* @return The USB camera capturing images.
|
||||
*/
|
||||
public UsbCamera startAutomaticCapture(String name, int dev) {
|
||||
public static UsbCamera startAutomaticCapture(String name, int dev) {
|
||||
UsbCamera camera = new UsbCamera(name, dev);
|
||||
startAutomaticCapture(camera);
|
||||
CameraServerSharedStore.getCameraServerShared().reportUsbCamera(camera.getHandle());
|
||||
@@ -533,8 +555,9 @@ public final class CameraServer {
|
||||
*
|
||||
* @param name The name to give the camera
|
||||
* @param path The device path (e.g. "/dev/video0") of the camera
|
||||
* @return The USB camera capturing images.
|
||||
*/
|
||||
public UsbCamera startAutomaticCapture(String name, String path) {
|
||||
public static UsbCamera startAutomaticCapture(String name, String path) {
|
||||
UsbCamera camera = new UsbCamera(name, path);
|
||||
startAutomaticCapture(camera);
|
||||
CameraServerSharedStore.getCameraServerShared().reportUsbCamera(camera.getHandle());
|
||||
@@ -542,12 +565,12 @@ public final class CameraServer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Start automatically capturing images to send to the dashboard from
|
||||
* an existing camera.
|
||||
* Start automatically capturing images to send to the dashboard from an existing camera.
|
||||
*
|
||||
* @param camera Camera
|
||||
* @return The MJPEG server serving images from the given camera.
|
||||
*/
|
||||
public MjpegServer startAutomaticCapture(VideoSource camera) {
|
||||
public static MjpegServer startAutomaticCapture(VideoSource camera) {
|
||||
addCamera(camera);
|
||||
MjpegServer server = addServer("serve_" + camera.getName());
|
||||
server.setSource(camera);
|
||||
@@ -557,24 +580,24 @@ public final class CameraServer {
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
*
|
||||
* <p>This overload calls {@link #addAxisCamera(String, String)} with
|
||||
* name "Axis Camera".
|
||||
* <p>This overload calls {@link #addAxisCamera(String, String)} with name "Axis Camera".
|
||||
*
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
* @return The Axis camera capturing images.
|
||||
*/
|
||||
public AxisCamera addAxisCamera(String host) {
|
||||
public static AxisCamera addAxisCamera(String host) {
|
||||
return addAxisCamera("Axis Camera", host);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
*
|
||||
* <p>This overload calls {@link #addAxisCamera(String, String[])} with
|
||||
* name "Axis Camera".
|
||||
* <p>This overload calls {@link #addAxisCamera(String, String[])} with name "Axis Camera".
|
||||
*
|
||||
* @param hosts Array of Camera host IPs/DNS names
|
||||
* @return The Axis camera capturing images.
|
||||
*/
|
||||
public AxisCamera addAxisCamera(String[] hosts) {
|
||||
public static AxisCamera addAxisCamera(String[] hosts) {
|
||||
return addAxisCamera("Axis Camera", hosts);
|
||||
}
|
||||
|
||||
@@ -583,8 +606,9 @@ 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.
|
||||
*/
|
||||
public AxisCamera addAxisCamera(String name, String host) {
|
||||
public static AxisCamera addAxisCamera(String name, String host) {
|
||||
AxisCamera camera = new AxisCamera(name, host);
|
||||
// Create a passthrough MJPEG server for USB access
|
||||
startAutomaticCapture(camera);
|
||||
@@ -597,8 +621,9 @@ 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.
|
||||
*/
|
||||
public AxisCamera addAxisCamera(String name, String[] hosts) {
|
||||
public static AxisCamera addAxisCamera(String name, String[] hosts) {
|
||||
AxisCamera camera = new AxisCamera(name, hosts);
|
||||
// Create a passthrough MJPEG server for USB access
|
||||
startAutomaticCapture(camera);
|
||||
@@ -607,16 +632,18 @@ public final class CameraServer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a virtual camera for switching between two streams. Unlike the
|
||||
* other addCamera methods, this returns a VideoSink rather than a
|
||||
* VideoSource. Calling setSource() on the returned object can be used
|
||||
* to switch the actual source of the stream.
|
||||
* Adds a virtual camera for switching between two streams. Unlike the other addCamera methods,
|
||||
* this returns a VideoSink rather than a VideoSource. Calling setSource() on the returned object
|
||||
* can be used to switch the actual source of the stream.
|
||||
*
|
||||
* @param name The name to give the camera
|
||||
* @return The MJPEG server serving images from the given camera.
|
||||
*/
|
||||
public MjpegServer addSwitchedCamera(String name) {
|
||||
public static MjpegServer addSwitchedCamera(String name) {
|
||||
// create a dummy CvSource
|
||||
CvSource source = new CvSource(name, VideoMode.PixelFormat.kMJPEG, 160, 120, 30);
|
||||
MjpegServer server = startAutomaticCapture(source);
|
||||
synchronized (this) {
|
||||
synchronized (CameraServer.class) {
|
||||
m_fixedSources.put(server.getHandle(), source.getHandle());
|
||||
}
|
||||
|
||||
@@ -624,15 +651,17 @@ public final class CameraServer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get OpenCV access to the primary camera feed. This allows you to
|
||||
* get images from the camera for image processing on the roboRIO.
|
||||
* Get OpenCV access to the primary camera feed. This allows you to get images from the camera for
|
||||
* image processing on the roboRIO.
|
||||
*
|
||||
* <p>This is only valid to call after a camera feed has been added
|
||||
* with startAutomaticCapture() or addServer().
|
||||
* <p>This is only valid to call after a camera feed has been added with startAutomaticCapture()
|
||||
* or addServer().
|
||||
*
|
||||
* @return OpenCV sink for the primary camera feed
|
||||
*/
|
||||
public CvSink getVideo() {
|
||||
public static CvSink getVideo() {
|
||||
VideoSource source;
|
||||
synchronized (this) {
|
||||
synchronized (CameraServer.class) {
|
||||
if (m_primarySourceName == null) {
|
||||
throw new VideoException("no camera available");
|
||||
}
|
||||
@@ -645,15 +674,16 @@ public final class CameraServer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get OpenCV access to the specified camera. This allows you to get
|
||||
* images from the camera for image processing on the roboRIO.
|
||||
* 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).
|
||||
* @return OpenCV sink for the specified camera
|
||||
*/
|
||||
public CvSink getVideo(VideoSource camera) {
|
||||
public static CvSink getVideo(VideoSource camera) {
|
||||
String name = "opencv_" + camera.getName();
|
||||
|
||||
synchronized (this) {
|
||||
synchronized (CameraServer.class) {
|
||||
VideoSink sink = m_sinks.get(name);
|
||||
if (sink != null) {
|
||||
VideoSink.Kind kind = sink.getKind();
|
||||
@@ -671,14 +701,15 @@ public final class CameraServer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get OpenCV access to the specified camera. This allows you to get
|
||||
* images from the camera for image processing on the roboRIO.
|
||||
* 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
|
||||
* @return OpenCV sink for the specified camera
|
||||
*/
|
||||
public CvSink getVideo(String name) {
|
||||
public static CvSink getVideo(String name) {
|
||||
VideoSource source;
|
||||
synchronized (this) {
|
||||
synchronized (CameraServer.class) {
|
||||
source = m_sources.get(name);
|
||||
if (source == null) {
|
||||
throw new VideoException("could not find camera " + name);
|
||||
@@ -688,14 +719,15 @@ public final class CameraServer {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a MJPEG stream with OpenCV input. This can be called to pass custom
|
||||
* annotated images to the dashboard.
|
||||
* Create a MJPEG stream with OpenCV input. This can be called to pass custom annotated images to
|
||||
* the dashboard.
|
||||
*
|
||||
* @param name Name to give the stream
|
||||
* @param width Width of the image being sent
|
||||
* @param height Height of the image being sent
|
||||
* @return OpenCV source for the MJPEG stream
|
||||
*/
|
||||
public CvSource putVideo(String name, int width, int height) {
|
||||
public static CvSource putVideo(String name, int width, int height) {
|
||||
CvSource source = new CvSource(name, VideoMode.PixelFormat.kMJPEG, width, height, 30);
|
||||
startAutomaticCapture(source);
|
||||
return source;
|
||||
@@ -705,10 +737,11 @@ public final class CameraServer {
|
||||
* Adds a MJPEG server at the next available port.
|
||||
*
|
||||
* @param name Server name
|
||||
* @return The MJPEG server
|
||||
*/
|
||||
public MjpegServer addServer(String name) {
|
||||
public static MjpegServer addServer(String name) {
|
||||
int port;
|
||||
synchronized (this) {
|
||||
synchronized (CameraServer.class) {
|
||||
port = m_nextPort;
|
||||
m_nextPort++;
|
||||
}
|
||||
@@ -719,8 +752,10 @@ public final class CameraServer {
|
||||
* Adds a MJPEG server.
|
||||
*
|
||||
* @param name Server name
|
||||
* @param port Server port
|
||||
* @return The MJPEG server
|
||||
*/
|
||||
public MjpegServer addServer(String name, int port) {
|
||||
public static MjpegServer addServer(String name, int port) {
|
||||
MjpegServer server = new MjpegServer(name, port);
|
||||
addServer(server);
|
||||
return server;
|
||||
@@ -731,8 +766,8 @@ public final class CameraServer {
|
||||
*
|
||||
* @param server Server
|
||||
*/
|
||||
public void addServer(VideoSink server) {
|
||||
synchronized (this) {
|
||||
public static void addServer(VideoSink server) {
|
||||
synchronized (CameraServer.class) {
|
||||
m_sinks.put(server.getName(), server);
|
||||
}
|
||||
}
|
||||
@@ -742,8 +777,8 @@ public final class CameraServer {
|
||||
*
|
||||
* @param name Server name
|
||||
*/
|
||||
public void removeServer(String name) {
|
||||
synchronized (this) {
|
||||
public static void removeServer(String name) {
|
||||
synchronized (CameraServer.class) {
|
||||
m_sinks.remove(name);
|
||||
}
|
||||
}
|
||||
@@ -751,11 +786,13 @@ public final class CameraServer {
|
||||
/**
|
||||
* Get server for the primary camera feed.
|
||||
*
|
||||
* <p>This is only valid to call after a camera feed has been added
|
||||
* with startAutomaticCapture() or addServer().
|
||||
* <p>This is only valid to call after a camera feed has been added with startAutomaticCapture()
|
||||
* or addServer().
|
||||
*
|
||||
* @return The server for the primary camera feed
|
||||
*/
|
||||
public VideoSink getServer() {
|
||||
synchronized (this) {
|
||||
public static VideoSink getServer() {
|
||||
synchronized (CameraServer.class) {
|
||||
if (m_primarySourceName == null) {
|
||||
throw new VideoException("no camera available");
|
||||
}
|
||||
@@ -767,9 +804,10 @@ public final class CameraServer {
|
||||
* Gets a server by name.
|
||||
*
|
||||
* @param name Server name
|
||||
* @return The server
|
||||
*/
|
||||
public VideoSink getServer(String name) {
|
||||
synchronized (this) {
|
||||
public static VideoSink getServer(String name) {
|
||||
synchronized (CameraServer.class) {
|
||||
return m_sinks.get(name);
|
||||
}
|
||||
}
|
||||
@@ -779,9 +817,9 @@ public final class CameraServer {
|
||||
*
|
||||
* @param camera Camera
|
||||
*/
|
||||
public void addCamera(VideoSource camera) {
|
||||
public static void addCamera(VideoSource camera) {
|
||||
String name = camera.getName();
|
||||
synchronized (this) {
|
||||
synchronized (CameraServer.class) {
|
||||
if (m_primarySourceName == null) {
|
||||
m_primarySourceName = name;
|
||||
}
|
||||
@@ -794,8 +832,8 @@ public final class CameraServer {
|
||||
*
|
||||
* @param name Camera name
|
||||
*/
|
||||
public void removeCamera(String name) {
|
||||
synchronized (this) {
|
||||
public static void removeCamera(String name) {
|
||||
synchronized (CameraServer.class) {
|
||||
m_sources.remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.cameraserver;
|
||||
|
||||
|
||||
public interface CameraServerShared {
|
||||
/**
|
||||
* get the main thread id func.
|
||||
|
||||
@@ -1,56 +1,48 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.cameraserver;
|
||||
|
||||
public final class CameraServerSharedStore {
|
||||
private static CameraServerShared cameraServerShared;
|
||||
|
||||
private CameraServerSharedStore() {
|
||||
}
|
||||
private CameraServerSharedStore() {}
|
||||
|
||||
/**
|
||||
* get the CameraServerShared object.
|
||||
* Get the CameraServerShared object.
|
||||
*
|
||||
* @return The CameraServerSharedObject
|
||||
*/
|
||||
public static synchronized CameraServerShared getCameraServerShared() {
|
||||
if (cameraServerShared == null) {
|
||||
cameraServerShared = new CameraServerShared() {
|
||||
cameraServerShared =
|
||||
new CameraServerShared() {
|
||||
@Override
|
||||
public void reportVideoServer(int id) {}
|
||||
|
||||
@Override
|
||||
public void reportVideoServer(int id) {
|
||||
@Override
|
||||
public void reportUsbCamera(int id) {}
|
||||
|
||||
}
|
||||
@Override
|
||||
public void reportDriverStationError(String error) {}
|
||||
|
||||
@Override
|
||||
public void reportUsbCamera(int id) {
|
||||
@Override
|
||||
public void reportAxisCamera(int id) {}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportDriverStationError(String error) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reportAxisCamera(int id) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getRobotMainThreadId() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public Long getRobotMainThreadId() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
return cameraServerShared;
|
||||
}
|
||||
|
||||
/**
|
||||
* set the CameraServerShared object.
|
||||
* Set the CameraServerShared object.
|
||||
*
|
||||
* @param shared The CameraServerShared object.
|
||||
*/
|
||||
public static synchronized void setCameraServerShared(CameraServerShared shared) {
|
||||
cameraServerShared = shared;
|
||||
|
||||
@@ -1,26 +1,24 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.vision;
|
||||
|
||||
import org.opencv.core.Mat;
|
||||
|
||||
/**
|
||||
* A vision pipeline is responsible for running a group of
|
||||
* OpenCV algorithms to extract data from an image.
|
||||
* A vision pipeline is responsible for running a group of OpenCV algorithms to extract data from an
|
||||
* image.
|
||||
*
|
||||
* @see VisionRunner
|
||||
* @see VisionThread
|
||||
*/
|
||||
public interface VisionPipeline {
|
||||
/**
|
||||
* Processes the image input and sets the result objects.
|
||||
* Implementations should make these objects accessible.
|
||||
* Processes the image input and sets the result objects. Implementations should make these
|
||||
* objects accessible.
|
||||
*
|
||||
* @param image The image to process.
|
||||
*/
|
||||
void process(Mat image);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.vision;
|
||||
|
||||
import edu.wpi.first.cameraserver.CameraServerSharedStore;
|
||||
import edu.wpi.first.cscore.CvSink;
|
||||
import edu.wpi.first.cscore.VideoSource;
|
||||
import org.opencv.core.Mat;
|
||||
|
||||
import edu.wpi.cscore.CvSink;
|
||||
import edu.wpi.cscore.VideoSource;
|
||||
import edu.wpi.first.cameraserver.CameraServerSharedStore;
|
||||
|
||||
/**
|
||||
* A vision runner is a convenient wrapper object to make it easy to run vision pipelines
|
||||
* from robot 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.
|
||||
* A vision runner is a convenient wrapper object to make it easy to run vision pipelines from robot
|
||||
* 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.
|
||||
*
|
||||
* @see VisionPipeline
|
||||
* @see VisionThread
|
||||
@@ -45,17 +41,16 @@ public class VisionRunner<P extends VisionPipeline> {
|
||||
* @param pipeline the vision pipeline that ran
|
||||
*/
|
||||
void copyPipelineOutputs(P pipeline);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new vision runner. It will take images from the {@code videoSource}, send them to
|
||||
* the {@code pipeline}, and call the {@code listener} when the pipeline has finished to alert
|
||||
* user code when it is safe to access the pipeline's outputs.
|
||||
* Creates a new vision runner. It will take images from the {@code videoSource}, send them to the
|
||||
* {@code pipeline}, and call the {@code listener} when the pipeline has finished to alert user
|
||||
* code when it is safe to access the pipeline's outputs.
|
||||
*
|
||||
* @param videoSource the video source to use to supply images for the pipeline
|
||||
* @param pipeline the vision pipeline to run
|
||||
* @param listener a function to call after the pipeline has finished running
|
||||
* @param pipeline the vision pipeline to run
|
||||
* @param listener a function to call after the pipeline has finished running
|
||||
*/
|
||||
public VisionRunner(VideoSource videoSource, P pipeline, Listener<? super P> listener) {
|
||||
this.m_pipeline = pipeline;
|
||||
@@ -64,15 +59,15 @@ public class VisionRunner<P extends VisionPipeline> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs the pipeline one time, giving it the next image from the video source specified
|
||||
* in the constructor. This will block until the source either has an image or throws an error.
|
||||
* If the source successfully supplied a frame, the pipeline's image input will be set,
|
||||
* the pipeline will run, and the listener specified in the constructor will be called to notify
|
||||
* it that the pipeline ran.
|
||||
* Runs the pipeline one time, giving it the next image from the video source specified in the
|
||||
* constructor. This will block until the source either has an image or throws an error. If the
|
||||
* source successfully supplied a frame, the pipeline's image input will be set, the pipeline will
|
||||
* run, and the listener specified in the constructor will be called to notify it that the
|
||||
* pipeline ran.
|
||||
*
|
||||
* <p>This method is exposed to allow teams to add additional functionality or have their own
|
||||
* ways to run the pipeline. Most teams, however, should just use {@link #runForever} in its own
|
||||
* thread using a {@link VisionThread}.</p>
|
||||
* <p>This method is exposed to allow teams to add additional functionality or have their own ways
|
||||
* to run the pipeline. Most teams, however, should just use {@link #runForever} in its own thread
|
||||
* using a {@link VisionThread}.
|
||||
*/
|
||||
public void runOnce() {
|
||||
Long id = CameraServerSharedStore.getCameraServerShared().getRobotMainThreadId();
|
||||
@@ -98,11 +93,11 @@ public class VisionRunner<P extends VisionPipeline> {
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method that calls {@link #runOnce()} in an infinite loop. This must
|
||||
* be run in a dedicated thread, and cannot be used in the main robot thread because
|
||||
* it will freeze the robot program.
|
||||
* A convenience method that calls {@link #runOnce()} in an infinite loop. This must be run in a
|
||||
* dedicated thread, and cannot be used in the main robot thread because it will freeze the robot
|
||||
* program.
|
||||
*
|
||||
* <p><strong>Do not call this method directly from the main thread.</strong></p>
|
||||
* <p><strong>Do not call this method directly from the main thread.</strong>
|
||||
*
|
||||
* @throws IllegalStateException if this is called from the main robot thread
|
||||
* @see VisionThread
|
||||
@@ -119,9 +114,7 @@ public class VisionRunner<P extends VisionPipeline> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop a RunForever() loop.
|
||||
*/
|
||||
/** Stop a RunForever() loop. */
|
||||
public void stop() {
|
||||
m_enabled = false;
|
||||
}
|
||||
|
||||
@@ -1,18 +1,15 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.vision;
|
||||
|
||||
import edu.wpi.cscore.VideoSource;
|
||||
import edu.wpi.first.cscore.VideoSource;
|
||||
|
||||
/**
|
||||
* A vision thread is a special thread that runs a vision pipeline. It is a <i>daemon</i> thread;
|
||||
* it does not prevent the program from exiting when all other non-daemon threads
|
||||
* have finished running.
|
||||
* A vision thread is a special thread that runs a vision pipeline. It is a <i>daemon</i> thread; it
|
||||
* does not prevent the program from exiting when all other non-daemon threads have finished
|
||||
* running.
|
||||
*
|
||||
* @see VisionPipeline
|
||||
* @see VisionRunner
|
||||
@@ -34,14 +31,12 @@ public class VisionThread extends Thread {
|
||||
* equivalent to {@code new VisionThread(new VisionRunner<>(videoSource, pipeline, listener))}.
|
||||
*
|
||||
* @param videoSource the source for images the pipeline should process
|
||||
* @param pipeline the pipeline to run
|
||||
* @param listener the listener to copy outputs from the pipeline after it runs
|
||||
* @param <P> the type of the pipeline
|
||||
* @param pipeline the pipeline to run
|
||||
* @param listener the listener to copy outputs from the pipeline after it runs
|
||||
* @param <P> the type of the pipeline
|
||||
*/
|
||||
public <P extends VisionPipeline> VisionThread(VideoSource videoSource,
|
||||
P pipeline,
|
||||
VisionRunner.Listener<? super P> listener) {
|
||||
public <P extends VisionPipeline> VisionThread(
|
||||
VideoSource videoSource, P pipeline, VisionRunner.Listener<? super P> listener) {
|
||||
this(new VisionRunner<>(videoSource, pipeline, listener));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,22 +1,19 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.
|
||||
|
||||
/**
|
||||
* Classes in the {@code edu.wpi.first.vision} package are designed to
|
||||
* simplify using OpenCV vision processing code from a robot program.
|
||||
* Classes in the {@code edu.wpi.first.vision} package are designed to simplify using OpenCV vision
|
||||
* processing code from a robot program.
|
||||
*
|
||||
* <p>An example use case for grabbing a yellow tote from 2015 in autonomous: <br>
|
||||
*
|
||||
* <p>An example use case for grabbing a yellow tote from 2015 in autonomous:
|
||||
* <br>
|
||||
* <pre><code>
|
||||
* public class Robot extends IterativeRobot
|
||||
* implements VisionRunner.Listener<MyFindTotePipeline> {
|
||||
*
|
||||
* // A USB camera connected to the roboRIO.
|
||||
* private {@link edu.wpi.cscore.VideoSource VideoSource} usbCamera;
|
||||
* private {@link edu.wpi.first.cscore.VideoSource VideoSource} usbCamera;
|
||||
*
|
||||
* // A vision pipeline. This could be handwritten or generated by GRIP.
|
||||
* // This has to implement {@link edu.wpi.first.vision.VisionPipeline}.
|
||||
@@ -47,7 +44,7 @@
|
||||
*
|
||||
* {@literal @}Override
|
||||
* public void robotInit() {
|
||||
* usbCamera = CameraServer.getInstance().startAutomaticCapture(0);
|
||||
* usbCamera = CameraServer.startAutomaticCapture(0);
|
||||
* findTotePipeline = new MyFindTotePipeline();
|
||||
* findToteThread = new VisionThread(usbCamera, findTotePipeline, this);
|
||||
* }
|
||||
|
||||
@@ -1,23 +1,20 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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 "cameraserver/CameraServer.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <networktables/NetworkTable.h>
|
||||
#include <networktables/NetworkTableInstance.h>
|
||||
#include <wpi/DenseMap.h>
|
||||
#include <wpi/ManagedStatic.h>
|
||||
#include <wpi/SmallString.h>
|
||||
#include <wpi/StringExtras.h>
|
||||
#include <wpi/StringMap.h>
|
||||
#include <wpi/mutex.h>
|
||||
#include <wpi/raw_ostream.h>
|
||||
|
||||
#include "cameraserver/CameraServerShared.h"
|
||||
#include "ntcore_cpp.h"
|
||||
@@ -26,8 +23,9 @@ using namespace frc;
|
||||
|
||||
static constexpr char const* kPublishName = "/CameraPublisher";
|
||||
|
||||
struct CameraServer::Impl {
|
||||
Impl();
|
||||
namespace {
|
||||
struct Instance {
|
||||
Instance();
|
||||
std::shared_ptr<nt::NetworkTable> GetSourceTable(CS_Source source);
|
||||
std::vector<std::string> GetSinkStreamValues(CS_Sink sink);
|
||||
std::vector<std::string> GetSourceStreamValues(CS_Source source);
|
||||
@@ -40,41 +38,45 @@ struct CameraServer::Impl {
|
||||
wpi::StringMap<cs::VideoSink> m_sinks;
|
||||
wpi::DenseMap<CS_Sink, CS_Source> m_fixedSources;
|
||||
wpi::DenseMap<CS_Source, std::shared_ptr<nt::NetworkTable>> m_tables;
|
||||
std::shared_ptr<nt::NetworkTable> m_publishTable;
|
||||
std::shared_ptr<nt::NetworkTable> m_publishTable{
|
||||
nt::NetworkTableInstance::GetDefault().GetTable(kPublishName)};
|
||||
cs::VideoListener m_videoListener;
|
||||
int m_tableListener;
|
||||
int m_nextPort;
|
||||
int m_nextPort{CameraServer::kBasePort};
|
||||
std::vector<std::string> m_addresses;
|
||||
};
|
||||
} // namespace
|
||||
|
||||
CameraServer* CameraServer::GetInstance() {
|
||||
struct Creator {
|
||||
static void* call() { return new CameraServer{}; }
|
||||
};
|
||||
struct Deleter {
|
||||
static void call(void* ptr) { delete static_cast<CameraServer*>(ptr); }
|
||||
};
|
||||
static wpi::ManagedStatic<CameraServer, Creator, Deleter> instance;
|
||||
return &(*instance);
|
||||
static Instance& GetInstance() {
|
||||
static Instance instance;
|
||||
return instance;
|
||||
}
|
||||
|
||||
static wpi::StringRef MakeSourceValue(CS_Source source,
|
||||
wpi::SmallVectorImpl<char>& buf) {
|
||||
CameraServer* CameraServer::GetInstance() {
|
||||
::GetInstance();
|
||||
static CameraServer instance;
|
||||
return &instance;
|
||||
}
|
||||
|
||||
static std::string_view MakeSourceValue(CS_Source source,
|
||||
wpi::SmallVectorImpl<char>& buf) {
|
||||
CS_Status status = 0;
|
||||
buf.clear();
|
||||
switch (cs::GetSourceKind(source, &status)) {
|
||||
case CS_SOURCE_USB: {
|
||||
wpi::StringRef prefix{"usb:"};
|
||||
std::string_view prefix{"usb:"};
|
||||
buf.append(prefix.begin(), prefix.end());
|
||||
auto path = cs::GetUsbCameraPath(source, &status);
|
||||
buf.append(path.begin(), path.end());
|
||||
break;
|
||||
}
|
||||
case CS_SOURCE_HTTP: {
|
||||
wpi::StringRef prefix{"ip:"};
|
||||
std::string_view prefix{"ip:"};
|
||||
buf.append(prefix.begin(), prefix.end());
|
||||
auto urls = cs::GetHttpCameraUrls(source, &status);
|
||||
if (!urls.empty()) buf.append(urls[0].begin(), urls[0].end());
|
||||
if (!urls.empty()) {
|
||||
buf.append(urls[0].begin(), urls[0].end());
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CS_SOURCE_CV:
|
||||
@@ -83,27 +85,25 @@ static wpi::StringRef MakeSourceValue(CS_Source source,
|
||||
return "unknown:";
|
||||
}
|
||||
|
||||
return wpi::StringRef{buf.begin(), buf.size()};
|
||||
return {buf.begin(), buf.size()};
|
||||
}
|
||||
|
||||
static std::string MakeStreamValue(const wpi::Twine& address, int port) {
|
||||
return ("mjpg:http://" + address + wpi::Twine(':') + wpi::Twine(port) +
|
||||
"/?action=stream")
|
||||
.str();
|
||||
static std::string MakeStreamValue(std::string_view address, int port) {
|
||||
return fmt::format("mjpg:http://{}:{}/?action=stream", address, port);
|
||||
}
|
||||
|
||||
std::shared_ptr<nt::NetworkTable> CameraServer::Impl::GetSourceTable(
|
||||
CS_Source source) {
|
||||
std::shared_ptr<nt::NetworkTable> Instance::GetSourceTable(CS_Source source) {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
return m_tables.lookup(source);
|
||||
}
|
||||
|
||||
std::vector<std::string> CameraServer::Impl::GetSinkStreamValues(CS_Sink sink) {
|
||||
std::vector<std::string> Instance::GetSinkStreamValues(CS_Sink sink) {
|
||||
CS_Status status = 0;
|
||||
|
||||
// Ignore all but MjpegServer
|
||||
if (cs::GetSinkKind(sink, &status) != CS_SINK_MJPEG)
|
||||
return std::vector<std::string>{};
|
||||
if (cs::GetSinkKind(sink, &status) != CS_SINK_MJPEG) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Get port
|
||||
int port = cs::GetMjpegServerPort(sink, &status);
|
||||
@@ -119,7 +119,9 @@ std::vector<std::string> CameraServer::Impl::GetSinkStreamValues(CS_Sink sink) {
|
||||
values.emplace_back(MakeStreamValue(cs::GetHostname() + ".local", port));
|
||||
|
||||
for (const auto& addr : m_addresses) {
|
||||
if (addr == "127.0.0.1") continue; // ignore localhost
|
||||
if (addr == "127.0.0.1") {
|
||||
continue; // ignore localhost
|
||||
}
|
||||
values.emplace_back(MakeStreamValue(addr, port));
|
||||
}
|
||||
}
|
||||
@@ -127,17 +129,19 @@ std::vector<std::string> CameraServer::Impl::GetSinkStreamValues(CS_Sink sink) {
|
||||
return values;
|
||||
}
|
||||
|
||||
std::vector<std::string> CameraServer::Impl::GetSourceStreamValues(
|
||||
CS_Source source) {
|
||||
std::vector<std::string> Instance::GetSourceStreamValues(CS_Source source) {
|
||||
CS_Status status = 0;
|
||||
|
||||
// Ignore all but HttpCamera
|
||||
if (cs::GetSourceKind(source, &status) != CS_SOURCE_HTTP)
|
||||
return std::vector<std::string>{};
|
||||
if (cs::GetSourceKind(source, &status) != CS_SOURCE_HTTP) {
|
||||
return {};
|
||||
}
|
||||
|
||||
// Generate values
|
||||
auto values = cs::GetHttpCameraUrls(source, &status);
|
||||
for (auto& value : values) value = "mjpg:" + value;
|
||||
for (auto& value : values) {
|
||||
value = "mjpg:" + value;
|
||||
}
|
||||
|
||||
#ifdef __FRC_ROBORIO__
|
||||
// Look to see if we have a passthrough server for this source
|
||||
@@ -159,7 +163,7 @@ std::vector<std::string> CameraServer::Impl::GetSourceStreamValues(
|
||||
return values;
|
||||
}
|
||||
|
||||
void CameraServer::Impl::UpdateStreamValues() {
|
||||
void Instance::UpdateStreamValues() {
|
||||
std::scoped_lock lock(m_mutex);
|
||||
// Over all the sinks...
|
||||
for (const auto& i : m_sinks) {
|
||||
@@ -168,16 +172,24 @@ void CameraServer::Impl::UpdateStreamValues() {
|
||||
|
||||
// Get the source's subtable (if none exists, we're done)
|
||||
CS_Source source = m_fixedSources.lookup(sink);
|
||||
if (source == 0) source = cs::GetSinkSource(sink, &status);
|
||||
if (source == 0) continue;
|
||||
if (source == 0) {
|
||||
source = cs::GetSinkSource(sink, &status);
|
||||
}
|
||||
if (source == 0) {
|
||||
continue;
|
||||
}
|
||||
auto table = m_tables.lookup(source);
|
||||
if (table) {
|
||||
// Don't set stream values if this is a HttpCamera passthrough
|
||||
if (cs::GetSourceKind(source, &status) == CS_SOURCE_HTTP) continue;
|
||||
if (cs::GetSourceKind(source, &status) == CS_SOURCE_HTTP) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set table value
|
||||
auto values = GetSinkStreamValues(sink);
|
||||
if (!values.empty()) table->GetEntry("streams").SetStringArray(values);
|
||||
if (!values.empty()) {
|
||||
table->GetEntry("streams").SetStringArray(values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,7 +202,9 @@ void CameraServer::Impl::UpdateStreamValues() {
|
||||
if (table) {
|
||||
// Set table value
|
||||
auto values = GetSourceStreamValues(source);
|
||||
if (!values.empty()) table->GetEntry("streams").SetStringArray(values);
|
||||
if (!values.empty()) {
|
||||
table->GetEntry("streams").SetStringArray(values);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -213,79 +227,72 @@ static std::string PixelFormatToString(int pixelFormat) {
|
||||
}
|
||||
|
||||
static std::string VideoModeToString(const cs::VideoMode& mode) {
|
||||
std::string rv;
|
||||
wpi::raw_string_ostream oss{rv};
|
||||
oss << mode.width << "x" << mode.height;
|
||||
oss << " " << PixelFormatToString(mode.pixelFormat) << " ";
|
||||
oss << mode.fps << " fps";
|
||||
return oss.str();
|
||||
return fmt::format("{}x{} {} {} fps", mode.width, mode.height,
|
||||
PixelFormatToString(mode.pixelFormat), mode.fps);
|
||||
}
|
||||
|
||||
static std::vector<std::string> GetSourceModeValues(int source) {
|
||||
std::vector<std::string> rv;
|
||||
CS_Status status = 0;
|
||||
for (const auto& mode : cs::EnumerateSourceVideoModes(source, &status))
|
||||
for (const auto& mode : cs::EnumerateSourceVideoModes(source, &status)) {
|
||||
rv.emplace_back(VideoModeToString(mode));
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void PutSourcePropertyValue(nt::NetworkTable* table,
|
||||
const cs::VideoEvent& event, bool isNew) {
|
||||
wpi::SmallString<64> name;
|
||||
wpi::SmallString<64> infoName;
|
||||
if (wpi::StringRef{event.name}.startswith("raw_")) {
|
||||
name = "RawProperty/";
|
||||
name += event.name;
|
||||
infoName = "RawPropertyInfo/";
|
||||
infoName += event.name;
|
||||
std::string_view namePrefix;
|
||||
std::string_view infoPrefix;
|
||||
if (wpi::starts_with(event.name, "raw_")) {
|
||||
namePrefix = "RawProperty";
|
||||
infoPrefix = "RawPropertyInfo";
|
||||
} else {
|
||||
name = "Property/";
|
||||
name += event.name;
|
||||
infoName = "PropertyInfo/";
|
||||
infoName += event.name;
|
||||
namePrefix = "Property";
|
||||
infoPrefix = "PropertyInfo";
|
||||
}
|
||||
|
||||
wpi::SmallString<64> buf;
|
||||
CS_Status status = 0;
|
||||
nt::NetworkTableEntry entry = table->GetEntry(name);
|
||||
nt::NetworkTableEntry entry =
|
||||
table->GetEntry(fmt::format("{}/{}", namePrefix, event.name));
|
||||
switch (event.propertyKind) {
|
||||
case CS_PROP_BOOLEAN:
|
||||
if (isNew)
|
||||
if (isNew) {
|
||||
entry.SetDefaultBoolean(event.value != 0);
|
||||
else
|
||||
} else {
|
||||
entry.SetBoolean(event.value != 0);
|
||||
}
|
||||
break;
|
||||
case CS_PROP_INTEGER:
|
||||
case CS_PROP_ENUM:
|
||||
if (isNew) {
|
||||
entry.SetDefaultDouble(event.value);
|
||||
table->GetEntry(infoName + "/min")
|
||||
table->GetEntry(fmt::format("{}/{}/min", infoPrefix, event.name))
|
||||
.SetDouble(cs::GetPropertyMin(event.propertyHandle, &status));
|
||||
table->GetEntry(infoName + "/max")
|
||||
table->GetEntry(fmt::format("{}/{}/max", infoPrefix, event.name))
|
||||
.SetDouble(cs::GetPropertyMax(event.propertyHandle, &status));
|
||||
table->GetEntry(infoName + "/step")
|
||||
table->GetEntry(fmt::format("{}/{}/step", infoPrefix, event.name))
|
||||
.SetDouble(cs::GetPropertyStep(event.propertyHandle, &status));
|
||||
table->GetEntry(infoName + "/default")
|
||||
table->GetEntry(fmt::format("{}/{}/default", infoPrefix, event.name))
|
||||
.SetDouble(cs::GetPropertyDefault(event.propertyHandle, &status));
|
||||
} else {
|
||||
entry.SetDouble(event.value);
|
||||
}
|
||||
break;
|
||||
case CS_PROP_STRING:
|
||||
if (isNew)
|
||||
if (isNew) {
|
||||
entry.SetDefaultString(event.valueStr);
|
||||
else
|
||||
} else {
|
||||
entry.SetString(event.valueStr);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CameraServer::Impl::Impl()
|
||||
: m_publishTable{nt::NetworkTableInstance::GetDefault().GetTable(
|
||||
kPublishName)},
|
||||
m_nextPort(kBasePort) {
|
||||
Instance::Instance() {
|
||||
// We publish sources to NetworkTables using the following structure:
|
||||
// "/CameraPublisher/{Source.Name}/" - root
|
||||
// - "source" (string): Descriptive, prefixed with type (e.g. "usb:0")
|
||||
@@ -351,41 +358,48 @@ CameraServer::Impl::Impl()
|
||||
}
|
||||
case cs::VideoEvent::kSourceDisconnected: {
|
||||
auto table = GetSourceTable(event.sourceHandle);
|
||||
if (table) table->GetEntry("connected").SetBoolean(false);
|
||||
if (table) {
|
||||
table->GetEntry("connected").SetBoolean(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case cs::VideoEvent::kSourceVideoModesUpdated: {
|
||||
auto table = GetSourceTable(event.sourceHandle);
|
||||
if (table)
|
||||
if (table) {
|
||||
table->GetEntry("modes").SetStringArray(
|
||||
GetSourceModeValues(event.sourceHandle));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case cs::VideoEvent::kSourceVideoModeChanged: {
|
||||
auto table = GetSourceTable(event.sourceHandle);
|
||||
if (table)
|
||||
if (table) {
|
||||
table->GetEntry("mode").SetString(VideoModeToString(event.mode));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case cs::VideoEvent::kSourcePropertyCreated: {
|
||||
auto table = GetSourceTable(event.sourceHandle);
|
||||
if (table) PutSourcePropertyValue(table.get(), event, true);
|
||||
if (table) {
|
||||
PutSourcePropertyValue(table.get(), event, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case cs::VideoEvent::kSourcePropertyValueUpdated: {
|
||||
auto table = GetSourceTable(event.sourceHandle);
|
||||
if (table) PutSourcePropertyValue(table.get(), event, false);
|
||||
if (table) {
|
||||
PutSourcePropertyValue(table.get(), event, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case cs::VideoEvent::kSourcePropertyChoicesUpdated: {
|
||||
auto table = GetSourceTable(event.sourceHandle);
|
||||
if (table) {
|
||||
wpi::SmallString<64> name{"PropertyInfo/"};
|
||||
name += event.name;
|
||||
name += "/choices";
|
||||
auto choices =
|
||||
cs::GetEnumPropertyChoices(event.propertyHandle, &status);
|
||||
table->GetEntry(name).SetStringArray(choices);
|
||||
table
|
||||
->GetEntry(fmt::format("PropertyInfo/{}/choices", event.name))
|
||||
.SetStringArray(choices);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -409,32 +423,36 @@ CameraServer::Impl::Impl()
|
||||
// else tries to change it.
|
||||
wpi::SmallString<64> buf;
|
||||
m_tableListener = nt::NetworkTableInstance::GetDefault().AddEntryListener(
|
||||
kPublishName + wpi::Twine('/'),
|
||||
fmt::format("{}/", kPublishName),
|
||||
[=](const nt::EntryNotification& event) {
|
||||
wpi::StringRef relativeKey =
|
||||
event.name.substr(wpi::StringRef(kPublishName).size() + 1);
|
||||
auto relativeKey = wpi::drop_front(
|
||||
event.name, std::string_view{kPublishName}.size() + 1);
|
||||
|
||||
// get source (sourceName/...)
|
||||
auto subKeyIndex = relativeKey.find('/');
|
||||
if (subKeyIndex == wpi::StringRef::npos) return;
|
||||
wpi::StringRef sourceName = relativeKey.slice(0, subKeyIndex);
|
||||
if (subKeyIndex == std::string_view::npos) {
|
||||
return;
|
||||
}
|
||||
auto sourceName = wpi::slice(relativeKey, 0, subKeyIndex);
|
||||
auto sourceIt = m_sources.find(sourceName);
|
||||
if (sourceIt == m_sources.end()) return;
|
||||
if (sourceIt == m_sources.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// get subkey
|
||||
relativeKey = relativeKey.substr(subKeyIndex + 1);
|
||||
relativeKey.remove_prefix(subKeyIndex + 1);
|
||||
|
||||
// handle standard names
|
||||
wpi::StringRef propName;
|
||||
std::string_view propName;
|
||||
nt::NetworkTableEntry entry{event.entry};
|
||||
if (relativeKey == "mode") {
|
||||
// reset to current mode
|
||||
entry.SetString(VideoModeToString(sourceIt->second.GetVideoMode()));
|
||||
return;
|
||||
} else if (relativeKey.startswith("Property/")) {
|
||||
propName = relativeKey.substr(9);
|
||||
} else if (relativeKey.startswith("RawProperty/")) {
|
||||
propName = relativeKey.substr(12);
|
||||
} else if (wpi::starts_with(relativeKey, "Property/")) {
|
||||
propName = wpi::substr(relativeKey, 9);
|
||||
} else if (wpi::starts_with(relativeKey, "RawProperty/")) {
|
||||
propName = wpi::substr(relativeKey, 12);
|
||||
} else {
|
||||
return; // ignore
|
||||
}
|
||||
@@ -461,26 +479,23 @@ CameraServer::Impl::Impl()
|
||||
NT_NOTIFY_IMMEDIATE | NT_NOTIFY_UPDATE);
|
||||
}
|
||||
|
||||
CameraServer::CameraServer() : m_impl(new Impl) {}
|
||||
|
||||
CameraServer::~CameraServer() {}
|
||||
|
||||
cs::UsbCamera CameraServer::StartAutomaticCapture() {
|
||||
cs::UsbCamera camera = StartAutomaticCapture(m_impl->m_defaultUsbDevice++);
|
||||
cs::UsbCamera camera =
|
||||
StartAutomaticCapture(::GetInstance().m_defaultUsbDevice++);
|
||||
auto csShared = GetCameraServerShared();
|
||||
csShared->ReportUsbCamera(camera.GetHandle());
|
||||
return camera;
|
||||
}
|
||||
|
||||
cs::UsbCamera CameraServer::StartAutomaticCapture(int dev) {
|
||||
cs::UsbCamera camera{"USB Camera " + wpi::Twine(dev), dev};
|
||||
cs::UsbCamera camera{fmt::format("USB Camera {}", dev), dev};
|
||||
StartAutomaticCapture(camera);
|
||||
auto csShared = GetCameraServerShared();
|
||||
csShared->ReportUsbCamera(camera.GetHandle());
|
||||
return camera;
|
||||
}
|
||||
|
||||
cs::UsbCamera CameraServer::StartAutomaticCapture(const wpi::Twine& name,
|
||||
cs::UsbCamera CameraServer::StartAutomaticCapture(std::string_view name,
|
||||
int dev) {
|
||||
cs::UsbCamera camera{name, dev};
|
||||
StartAutomaticCapture(camera);
|
||||
@@ -489,8 +504,8 @@ cs::UsbCamera CameraServer::StartAutomaticCapture(const wpi::Twine& name,
|
||||
return camera;
|
||||
}
|
||||
|
||||
cs::UsbCamera CameraServer::StartAutomaticCapture(const wpi::Twine& name,
|
||||
const wpi::Twine& path) {
|
||||
cs::UsbCamera CameraServer::StartAutomaticCapture(std::string_view name,
|
||||
std::string_view path) {
|
||||
cs::UsbCamera camera{name, path};
|
||||
StartAutomaticCapture(camera);
|
||||
auto csShared = GetCameraServerShared();
|
||||
@@ -498,7 +513,7 @@ cs::UsbCamera CameraServer::StartAutomaticCapture(const wpi::Twine& name,
|
||||
return camera;
|
||||
}
|
||||
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(const wpi::Twine& host) {
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(std::string_view host) {
|
||||
return AddAxisCamera("Axis Camera", host);
|
||||
}
|
||||
|
||||
@@ -510,12 +525,12 @@ cs::AxisCamera CameraServer::AddAxisCamera(const std::string& host) {
|
||||
return AddAxisCamera("Axis Camera", host);
|
||||
}
|
||||
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(wpi::ArrayRef<std::string> hosts) {
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(wpi::span<const std::string> hosts) {
|
||||
return AddAxisCamera("Axis Camera", hosts);
|
||||
}
|
||||
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(const wpi::Twine& name,
|
||||
const wpi::Twine& host) {
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(std::string_view name,
|
||||
std::string_view host) {
|
||||
cs::AxisCamera camera{name, host};
|
||||
StartAutomaticCapture(camera);
|
||||
auto csShared = GetCameraServerShared();
|
||||
@@ -523,7 +538,7 @@ cs::AxisCamera CameraServer::AddAxisCamera(const wpi::Twine& name,
|
||||
return camera;
|
||||
}
|
||||
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(const wpi::Twine& name,
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(std::string_view name,
|
||||
const char* host) {
|
||||
cs::AxisCamera camera{name, host};
|
||||
StartAutomaticCapture(camera);
|
||||
@@ -532,7 +547,7 @@ cs::AxisCamera CameraServer::AddAxisCamera(const wpi::Twine& name,
|
||||
return camera;
|
||||
}
|
||||
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(const wpi::Twine& name,
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(std::string_view name,
|
||||
const std::string& host) {
|
||||
cs::AxisCamera camera{name, host};
|
||||
StartAutomaticCapture(camera);
|
||||
@@ -541,8 +556,8 @@ cs::AxisCamera CameraServer::AddAxisCamera(const wpi::Twine& name,
|
||||
return camera;
|
||||
}
|
||||
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(const wpi::Twine& name,
|
||||
wpi::ArrayRef<std::string> hosts) {
|
||||
cs::AxisCamera CameraServer::AddAxisCamera(std::string_view name,
|
||||
wpi::span<const std::string> hosts) {
|
||||
cs::AxisCamera camera{name, hosts};
|
||||
StartAutomaticCapture(camera);
|
||||
auto csShared = GetCameraServerShared();
|
||||
@@ -550,11 +565,11 @@ cs::AxisCamera CameraServer::AddAxisCamera(const wpi::Twine& name,
|
||||
return camera;
|
||||
}
|
||||
|
||||
cs::MjpegServer CameraServer::AddSwitchedCamera(const wpi::Twine& name) {
|
||||
cs::MjpegServer CameraServer::AddSwitchedCamera(std::string_view name) {
|
||||
// create a dummy CvSource
|
||||
cs::CvSource source{name, cs::VideoMode::PixelFormat::kMJPEG, 160, 120, 30};
|
||||
cs::MjpegServer server = StartAutomaticCapture(source);
|
||||
m_impl->m_fixedSources[server.GetHandle()] = source.GetHandle();
|
||||
::GetInstance().m_fixedSources[server.GetHandle()] = source.GetHandle();
|
||||
|
||||
return server;
|
||||
}
|
||||
@@ -562,22 +577,23 @@ cs::MjpegServer CameraServer::AddSwitchedCamera(const wpi::Twine& name) {
|
||||
cs::MjpegServer CameraServer::StartAutomaticCapture(
|
||||
const cs::VideoSource& camera) {
|
||||
AddCamera(camera);
|
||||
auto server = AddServer(wpi::Twine("serve_") + camera.GetName());
|
||||
auto server = AddServer(fmt::format("serve_{}", camera.GetName()));
|
||||
server.SetSource(camera);
|
||||
return server;
|
||||
}
|
||||
|
||||
cs::CvSink CameraServer::GetVideo() {
|
||||
auto& inst = ::GetInstance();
|
||||
cs::VideoSource source;
|
||||
{
|
||||
auto csShared = GetCameraServerShared();
|
||||
std::scoped_lock lock(m_impl->m_mutex);
|
||||
if (m_impl->m_primarySourceName.empty()) {
|
||||
std::scoped_lock lock(inst.m_mutex);
|
||||
if (inst.m_primarySourceName.empty()) {
|
||||
csShared->SetCameraServerError("no camera available");
|
||||
return cs::CvSink{};
|
||||
}
|
||||
auto it = m_impl->m_sources.find(m_impl->m_primarySourceName);
|
||||
if (it == m_impl->m_sources.end()) {
|
||||
auto it = inst.m_sources.find(inst.m_primarySourceName);
|
||||
if (it == inst.m_sources.end()) {
|
||||
csShared->SetCameraServerError("no camera available");
|
||||
return cs::CvSink{};
|
||||
}
|
||||
@@ -587,40 +603,40 @@ cs::CvSink CameraServer::GetVideo() {
|
||||
}
|
||||
|
||||
cs::CvSink CameraServer::GetVideo(const cs::VideoSource& camera) {
|
||||
auto& inst = ::GetInstance();
|
||||
wpi::SmallString<64> name{"opencv_"};
|
||||
name += camera.GetName();
|
||||
|
||||
{
|
||||
std::scoped_lock lock(m_impl->m_mutex);
|
||||
auto it = m_impl->m_sinks.find(name);
|
||||
if (it != m_impl->m_sinks.end()) {
|
||||
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 " +
|
||||
wpi::Twine(kind));
|
||||
csShared->SetCameraServerError("expected OpenCV sink, but got {}",
|
||||
kind);
|
||||
return cs::CvSink{};
|
||||
}
|
||||
return *static_cast<cs::CvSink*>(&it->second);
|
||||
}
|
||||
}
|
||||
|
||||
cs::CvSink newsink{name};
|
||||
cs::CvSink newsink{name.str()};
|
||||
newsink.SetSource(camera);
|
||||
AddServer(newsink);
|
||||
return newsink;
|
||||
}
|
||||
|
||||
cs::CvSink CameraServer::GetVideo(const wpi::Twine& name) {
|
||||
wpi::SmallString<64> nameBuf;
|
||||
wpi::StringRef nameStr = name.toStringRef(nameBuf);
|
||||
cs::CvSink CameraServer::GetVideo(std::string_view name) {
|
||||
auto& inst = ::GetInstance();
|
||||
cs::VideoSource source;
|
||||
{
|
||||
std::scoped_lock lock(m_impl->m_mutex);
|
||||
auto it = m_impl->m_sources.find(nameStr);
|
||||
if (it == m_impl->m_sources.end()) {
|
||||
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 " + nameStr);
|
||||
csShared->SetCameraServerError("could not find camera {}", name);
|
||||
return cs::CvSink{};
|
||||
}
|
||||
source = it->second;
|
||||
@@ -628,89 +644,99 @@ cs::CvSink CameraServer::GetVideo(const wpi::Twine& name) {
|
||||
return GetVideo(source);
|
||||
}
|
||||
|
||||
cs::CvSource CameraServer::PutVideo(const wpi::Twine& name, int width,
|
||||
cs::CvSource CameraServer::PutVideo(std::string_view name, int width,
|
||||
int height) {
|
||||
cs::CvSource source{name, cs::VideoMode::kMJPEG, width, height, 30};
|
||||
StartAutomaticCapture(source);
|
||||
return source;
|
||||
}
|
||||
|
||||
cs::MjpegServer CameraServer::AddServer(const wpi::Twine& name) {
|
||||
cs::MjpegServer CameraServer::AddServer(std::string_view name) {
|
||||
auto& inst = ::GetInstance();
|
||||
int port;
|
||||
{
|
||||
std::scoped_lock lock(m_impl->m_mutex);
|
||||
port = m_impl->m_nextPort++;
|
||||
std::scoped_lock lock(inst.m_mutex);
|
||||
port = inst.m_nextPort++;
|
||||
}
|
||||
return AddServer(name, port);
|
||||
}
|
||||
|
||||
cs::MjpegServer CameraServer::AddServer(const wpi::Twine& name, int port) {
|
||||
cs::MjpegServer CameraServer::AddServer(std::string_view name, int port) {
|
||||
cs::MjpegServer server{name, port};
|
||||
AddServer(server);
|
||||
return server;
|
||||
}
|
||||
|
||||
void CameraServer::AddServer(const cs::VideoSink& server) {
|
||||
std::scoped_lock lock(m_impl->m_mutex);
|
||||
m_impl->m_sinks.try_emplace(server.GetName(), server);
|
||||
auto& inst = ::GetInstance();
|
||||
std::scoped_lock lock(inst.m_mutex);
|
||||
inst.m_sinks.try_emplace(server.GetName(), server);
|
||||
}
|
||||
|
||||
void CameraServer::RemoveServer(const wpi::Twine& name) {
|
||||
std::scoped_lock lock(m_impl->m_mutex);
|
||||
wpi::SmallString<64> nameBuf;
|
||||
m_impl->m_sinks.erase(name.toStringRef(nameBuf));
|
||||
void CameraServer::RemoveServer(std::string_view name) {
|
||||
auto& inst = ::GetInstance();
|
||||
std::scoped_lock lock(inst.m_mutex);
|
||||
inst.m_sinks.erase(name);
|
||||
}
|
||||
|
||||
cs::VideoSink CameraServer::GetServer() {
|
||||
wpi::SmallString<64> name;
|
||||
auto& inst = ::GetInstance();
|
||||
std::string name;
|
||||
{
|
||||
std::scoped_lock lock(m_impl->m_mutex);
|
||||
if (m_impl->m_primarySourceName.empty()) {
|
||||
std::scoped_lock lock(inst.m_mutex);
|
||||
if (inst.m_primarySourceName.empty()) {
|
||||
auto csShared = GetCameraServerShared();
|
||||
csShared->SetCameraServerError("no camera available");
|
||||
return cs::VideoSink{};
|
||||
}
|
||||
name = "serve_";
|
||||
name += m_impl->m_primarySourceName;
|
||||
name = fmt::format("serve_{}", inst.m_primarySourceName);
|
||||
}
|
||||
return GetServer(name);
|
||||
}
|
||||
|
||||
cs::VideoSink CameraServer::GetServer(const wpi::Twine& name) {
|
||||
wpi::SmallString<64> nameBuf;
|
||||
wpi::StringRef nameStr = name.toStringRef(nameBuf);
|
||||
std::scoped_lock lock(m_impl->m_mutex);
|
||||
auto it = m_impl->m_sinks.find(nameStr);
|
||||
if (it == m_impl->m_sinks.end()) {
|
||||
cs::VideoSink CameraServer::GetServer(std::string_view name) {
|
||||
auto& inst = ::GetInstance();
|
||||
std::scoped_lock lock(inst.m_mutex);
|
||||
auto it = inst.m_sinks.find(name);
|
||||
if (it == inst.m_sinks.end()) {
|
||||
auto csShared = GetCameraServerShared();
|
||||
csShared->SetCameraServerError("could not find server " + nameStr);
|
||||
csShared->SetCameraServerError("could not find server {}", name);
|
||||
return cs::VideoSink{};
|
||||
}
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void CameraServer::AddCamera(const cs::VideoSource& camera) {
|
||||
auto& inst = ::GetInstance();
|
||||
std::string name = camera.GetName();
|
||||
std::scoped_lock lock(m_impl->m_mutex);
|
||||
if (m_impl->m_primarySourceName.empty()) m_impl->m_primarySourceName = name;
|
||||
m_impl->m_sources.try_emplace(name, camera);
|
||||
std::scoped_lock lock(inst.m_mutex);
|
||||
if (inst.m_primarySourceName.empty()) {
|
||||
inst.m_primarySourceName = name;
|
||||
}
|
||||
inst.m_sources.try_emplace(name, camera);
|
||||
}
|
||||
|
||||
void CameraServer::RemoveCamera(const wpi::Twine& name) {
|
||||
std::scoped_lock lock(m_impl->m_mutex);
|
||||
wpi::SmallString<64> nameBuf;
|
||||
m_impl->m_sources.erase(name.toStringRef(nameBuf));
|
||||
void CameraServer::RemoveCamera(std::string_view name) {
|
||||
auto& inst = ::GetInstance();
|
||||
std::scoped_lock lock(inst.m_mutex);
|
||||
inst.m_sources.erase(name);
|
||||
}
|
||||
|
||||
void CameraServer::SetSize(int size) {
|
||||
std::scoped_lock lock(m_impl->m_mutex);
|
||||
if (m_impl->m_primarySourceName.empty()) return;
|
||||
auto it = m_impl->m_sources.find(m_impl->m_primarySourceName);
|
||||
if (it == m_impl->m_sources.end()) return;
|
||||
if (size == kSize160x120)
|
||||
auto& inst = ::GetInstance();
|
||||
std::scoped_lock lock(inst.m_mutex);
|
||||
if (inst.m_primarySourceName.empty()) {
|
||||
return;
|
||||
}
|
||||
auto it = inst.m_sources.find(inst.m_primarySourceName);
|
||||
if (it == inst.m_sources.end()) {
|
||||
return;
|
||||
}
|
||||
if (size == kSize160x120) {
|
||||
it->second.SetResolution(160, 120);
|
||||
else if (size == kSize320x240)
|
||||
} else if (size == kSize320x240) {
|
||||
it->second.SetResolution(320, 240);
|
||||
else if (size == kSize640x480)
|
||||
} else if (size == kSize640x480) {
|
||||
it->second.SetResolution(640, 480);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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 "cameraserver/CameraServerShared.h"
|
||||
|
||||
@@ -15,9 +12,12 @@ class DefaultCameraServerShared : public frc::CameraServerShared {
|
||||
void ReportUsbCamera(int id) override {}
|
||||
void ReportAxisCamera(int id) override {}
|
||||
void ReportVideoServer(int id) override {}
|
||||
void SetCameraServerError(const wpi::Twine& error) override {}
|
||||
void SetVisionRunnerError(const wpi::Twine& error) override {}
|
||||
void ReportDriverStationError(const wpi::Twine& error) override {}
|
||||
void SetCameraServerErrorV(fmt::string_view format,
|
||||
fmt::format_args args) override {}
|
||||
void SetVisionRunnerErrorV(fmt::string_view format,
|
||||
fmt::format_args args) override {}
|
||||
void ReportDriverStationErrorV(fmt::string_view format,
|
||||
fmt::format_args args) override {}
|
||||
std::pair<std::thread::id, bool> GetRobotMainThreadId() const override {
|
||||
return std::make_pair(std::thread::id(), false);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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 "vision/VisionRunner.h"
|
||||
|
||||
@@ -23,7 +20,7 @@ VisionRunnerBase::VisionRunnerBase(cs::VideoSource videoSource)
|
||||
}
|
||||
|
||||
// Located here and not in header due to cv::Mat forward declaration.
|
||||
VisionRunnerBase::~VisionRunnerBase() {}
|
||||
VisionRunnerBase::~VisionRunnerBase() = default;
|
||||
|
||||
void VisionRunnerBase::RunOnce() {
|
||||
auto csShared = frc::GetCameraServerShared();
|
||||
@@ -36,7 +33,7 @@ void VisionRunnerBase::RunOnce() {
|
||||
auto frameTime = m_cvSink.GrabFrame(*m_image);
|
||||
if (frameTime == 0) {
|
||||
auto error = m_cvSink.GetError();
|
||||
csShared->ReportDriverStationError(error);
|
||||
csShared->ReportDriverStationError(error.c_str());
|
||||
} else {
|
||||
DoProcess(*m_image);
|
||||
}
|
||||
@@ -56,4 +53,6 @@ void VisionRunnerBase::RunForever() {
|
||||
}
|
||||
}
|
||||
|
||||
void VisionRunnerBase::Stop() { m_enabled = false; }
|
||||
void VisionRunnerBase::Stop() {
|
||||
m_enabled = false;
|
||||
}
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2014-2019 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <wpi/ArrayRef.h>
|
||||
#include <wpi/Twine.h>
|
||||
#include <wpi/deprecated.h>
|
||||
#include <wpi/span.h>
|
||||
|
||||
#include "cscore.h"
|
||||
#include "cscore_cv.h"
|
||||
@@ -34,7 +31,9 @@ class CameraServer {
|
||||
|
||||
/**
|
||||
* Get the CameraServer instance.
|
||||
* @deprecated Use the static methods
|
||||
*/
|
||||
WPI_DEPRECATED("Use static methods")
|
||||
static CameraServer* GetInstance();
|
||||
|
||||
/**
|
||||
@@ -48,7 +47,7 @@ class CameraServer {
|
||||
* with device 0, creating a camera named "USB Camera 0". Subsequent calls
|
||||
* increment the device number (e.g. 1, 2, etc).
|
||||
*/
|
||||
cs::UsbCamera StartAutomaticCapture();
|
||||
static cs::UsbCamera StartAutomaticCapture();
|
||||
|
||||
/**
|
||||
* Start automatically capturing images to send to the dashboard.
|
||||
@@ -58,7 +57,7 @@ class CameraServer {
|
||||
*
|
||||
* @param dev The device number of the camera interface
|
||||
*/
|
||||
cs::UsbCamera StartAutomaticCapture(int dev);
|
||||
static cs::UsbCamera StartAutomaticCapture(int dev);
|
||||
|
||||
/**
|
||||
* Start automatically capturing images to send to the dashboard.
|
||||
@@ -66,7 +65,7 @@ class CameraServer {
|
||||
* @param name The name to give the camera
|
||||
* @param dev The device number of the camera interface
|
||||
*/
|
||||
cs::UsbCamera StartAutomaticCapture(const wpi::Twine& name, int dev);
|
||||
static cs::UsbCamera StartAutomaticCapture(std::string_view name, int dev);
|
||||
|
||||
/**
|
||||
* Start automatically capturing images to send to the dashboard.
|
||||
@@ -74,8 +73,8 @@ class CameraServer {
|
||||
* @param name The name to give the camera
|
||||
* @param path The device path (e.g. "/dev/video0") of the camera
|
||||
*/
|
||||
cs::UsbCamera StartAutomaticCapture(const wpi::Twine& name,
|
||||
const wpi::Twine& path);
|
||||
static cs::UsbCamera StartAutomaticCapture(std::string_view name,
|
||||
std::string_view path);
|
||||
|
||||
/**
|
||||
* Start automatically capturing images to send to the dashboard from
|
||||
@@ -83,7 +82,7 @@ class CameraServer {
|
||||
*
|
||||
* @param camera Camera
|
||||
*/
|
||||
cs::MjpegServer StartAutomaticCapture(const cs::VideoSource& camera);
|
||||
static cs::MjpegServer StartAutomaticCapture(const cs::VideoSource& camera);
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
@@ -92,7 +91,7 @@ class CameraServer {
|
||||
*
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
*/
|
||||
cs::AxisCamera AddAxisCamera(const wpi::Twine& host);
|
||||
static cs::AxisCamera AddAxisCamera(std::string_view host);
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
@@ -101,7 +100,7 @@ class CameraServer {
|
||||
*
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
*/
|
||||
cs::AxisCamera AddAxisCamera(const char* host);
|
||||
static cs::AxisCamera AddAxisCamera(const char* host);
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
@@ -110,7 +109,7 @@ class CameraServer {
|
||||
*
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
*/
|
||||
cs::AxisCamera AddAxisCamera(const std::string& host);
|
||||
static cs::AxisCamera AddAxisCamera(const std::string& host);
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
@@ -119,7 +118,7 @@ class CameraServer {
|
||||
*
|
||||
* @param hosts Array of Camera host IPs/DNS names
|
||||
*/
|
||||
cs::AxisCamera AddAxisCamera(wpi::ArrayRef<std::string> hosts);
|
||||
static cs::AxisCamera AddAxisCamera(wpi::span<const std::string> hosts);
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
@@ -129,7 +128,7 @@ class CameraServer {
|
||||
* @param hosts Array of Camera host IPs/DNS names
|
||||
*/
|
||||
template <typename T>
|
||||
cs::AxisCamera AddAxisCamera(std::initializer_list<T> hosts);
|
||||
static cs::AxisCamera AddAxisCamera(std::initializer_list<T> hosts);
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
@@ -137,7 +136,8 @@ class CameraServer {
|
||||
* @param name The name to give the camera
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
*/
|
||||
cs::AxisCamera AddAxisCamera(const wpi::Twine& name, const wpi::Twine& host);
|
||||
static cs::AxisCamera AddAxisCamera(std::string_view name,
|
||||
std::string_view host);
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
@@ -145,7 +145,7 @@ class CameraServer {
|
||||
* @param name The name to give the camera
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
*/
|
||||
cs::AxisCamera AddAxisCamera(const wpi::Twine& name, const char* host);
|
||||
static cs::AxisCamera AddAxisCamera(std::string_view name, const char* host);
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
@@ -153,7 +153,8 @@ class CameraServer {
|
||||
* @param name The name to give the camera
|
||||
* @param host Camera host IP or DNS name (e.g. "10.x.y.11")
|
||||
*/
|
||||
cs::AxisCamera AddAxisCamera(const wpi::Twine& name, const std::string& host);
|
||||
static cs::AxisCamera AddAxisCamera(std::string_view name,
|
||||
const std::string& host);
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
@@ -161,8 +162,8 @@ class CameraServer {
|
||||
* @param name The name to give the camera
|
||||
* @param hosts Array of Camera host IPs/DNS names
|
||||
*/
|
||||
cs::AxisCamera AddAxisCamera(const wpi::Twine& name,
|
||||
wpi::ArrayRef<std::string> hosts);
|
||||
static cs::AxisCamera AddAxisCamera(std::string_view name,
|
||||
wpi::span<const std::string> hosts);
|
||||
|
||||
/**
|
||||
* Adds an Axis IP camera.
|
||||
@@ -171,8 +172,8 @@ class CameraServer {
|
||||
* @param hosts Array of Camera host IPs/DNS names
|
||||
*/
|
||||
template <typename T>
|
||||
cs::AxisCamera AddAxisCamera(const wpi::Twine& name,
|
||||
std::initializer_list<T> hosts);
|
||||
static cs::AxisCamera AddAxisCamera(std::string_view name,
|
||||
std::initializer_list<T> hosts);
|
||||
|
||||
/**
|
||||
* Adds a virtual camera for switching between two streams. Unlike the
|
||||
@@ -180,7 +181,7 @@ class CameraServer {
|
||||
* VideoSource. Calling SetSource() on the returned object can be used
|
||||
* to switch the actual source of the stream.
|
||||
*/
|
||||
cs::MjpegServer AddSwitchedCamera(const wpi::Twine& name);
|
||||
static cs::MjpegServer AddSwitchedCamera(std::string_view name);
|
||||
|
||||
/**
|
||||
* Get OpenCV access to the primary camera feed. This allows you to
|
||||
@@ -189,7 +190,7 @@ class CameraServer {
|
||||
* <p>This is only valid to call after a camera feed has been added
|
||||
* with startAutomaticCapture() or addServer().
|
||||
*/
|
||||
cs::CvSink GetVideo();
|
||||
static cs::CvSink GetVideo();
|
||||
|
||||
/**
|
||||
* Get OpenCV access to the specified camera. This allows you to get
|
||||
@@ -197,7 +198,7 @@ class CameraServer {
|
||||
*
|
||||
* @param camera Camera (e.g. as returned by startAutomaticCapture).
|
||||
*/
|
||||
cs::CvSink GetVideo(const cs::VideoSource& camera);
|
||||
static cs::CvSink GetVideo(const cs::VideoSource& camera);
|
||||
|
||||
/**
|
||||
* Get OpenCV access to the specified camera. This allows you to get
|
||||
@@ -205,7 +206,7 @@ class CameraServer {
|
||||
*
|
||||
* @param name Camera name
|
||||
*/
|
||||
cs::CvSink GetVideo(const wpi::Twine& name);
|
||||
static cs::CvSink GetVideo(std::string_view name);
|
||||
|
||||
/**
|
||||
* Create a MJPEG stream with OpenCV input. This can be called to pass custom
|
||||
@@ -215,35 +216,36 @@ class CameraServer {
|
||||
* @param width Width of the image being sent
|
||||
* @param height Height of the image being sent
|
||||
*/
|
||||
cs::CvSource PutVideo(const wpi::Twine& name, int width, int height);
|
||||
static cs::CvSource PutVideo(std::string_view name, int width, int height);
|
||||
|
||||
/**
|
||||
* Adds a MJPEG server at the next available port.
|
||||
*
|
||||
* @param name Server name
|
||||
*/
|
||||
cs::MjpegServer AddServer(const wpi::Twine& name);
|
||||
static cs::MjpegServer AddServer(std::string_view name);
|
||||
|
||||
/**
|
||||
* Adds a MJPEG server.
|
||||
*
|
||||
* @param name Server name
|
||||
* @param port Port number
|
||||
*/
|
||||
cs::MjpegServer AddServer(const wpi::Twine& name, int port);
|
||||
static cs::MjpegServer AddServer(std::string_view name, int port);
|
||||
|
||||
/**
|
||||
* Adds an already created server.
|
||||
*
|
||||
* @param server Server
|
||||
*/
|
||||
void AddServer(const cs::VideoSink& server);
|
||||
static void AddServer(const cs::VideoSink& server);
|
||||
|
||||
/**
|
||||
* Removes a server by name.
|
||||
*
|
||||
* @param name Server name
|
||||
*/
|
||||
void RemoveServer(const wpi::Twine& name);
|
||||
static void RemoveServer(std::string_view name);
|
||||
|
||||
/**
|
||||
* Get server for the primary camera feed.
|
||||
@@ -251,28 +253,28 @@ class CameraServer {
|
||||
* This is only valid to call after a camera feed has been added with
|
||||
* StartAutomaticCapture() or AddServer().
|
||||
*/
|
||||
cs::VideoSink GetServer();
|
||||
static cs::VideoSink GetServer();
|
||||
|
||||
/**
|
||||
* Gets a server by name.
|
||||
*
|
||||
* @param name Server name
|
||||
*/
|
||||
cs::VideoSink GetServer(const wpi::Twine& name);
|
||||
static cs::VideoSink GetServer(std::string_view name);
|
||||
|
||||
/**
|
||||
* Adds an already created camera.
|
||||
*
|
||||
* @param camera Camera
|
||||
*/
|
||||
void AddCamera(const cs::VideoSource& camera);
|
||||
static void AddCamera(const cs::VideoSource& camera);
|
||||
|
||||
/**
|
||||
* Removes a camera by name.
|
||||
*
|
||||
* @param name Camera name
|
||||
*/
|
||||
void RemoveCamera(const wpi::Twine& name);
|
||||
static void RemoveCamera(std::string_view name);
|
||||
|
||||
/**
|
||||
* Sets the size of the image to use. Use the public kSize constants to set
|
||||
@@ -283,14 +285,10 @@ class CameraServer {
|
||||
* StartAutomaticCapture() instead.
|
||||
* @param size The size to use
|
||||
*/
|
||||
void SetSize(int size);
|
||||
static void SetSize(int size);
|
||||
|
||||
private:
|
||||
CameraServer();
|
||||
~CameraServer();
|
||||
|
||||
struct Impl;
|
||||
std::unique_ptr<Impl> m_impl;
|
||||
CameraServer() = default;
|
||||
};
|
||||
|
||||
} // namespace frc
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "cameraserver/CameraServer.h"
|
||||
|
||||
namespace frc {
|
||||
|
||||
template <typename T>
|
||||
@@ -20,10 +19,12 @@ inline cs::AxisCamera CameraServer::AddAxisCamera(
|
||||
|
||||
template <typename T>
|
||||
inline cs::AxisCamera CameraServer::AddAxisCamera(
|
||||
const wpi::Twine& name, std::initializer_list<T> hosts) {
|
||||
std::string_view name, std::initializer_list<T> hosts) {
|
||||
std::vector<std::string> vec;
|
||||
vec.reserve(hosts.size());
|
||||
for (const auto& host : hosts) vec.emplace_back(host);
|
||||
for (const auto& host : hosts) {
|
||||
vec.emplace_back(host);
|
||||
}
|
||||
return AddAxisCamera(name, vec);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -11,7 +8,7 @@
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
#include <wpi/Twine.h>
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace frc {
|
||||
class CameraServerShared {
|
||||
@@ -20,10 +17,31 @@ class CameraServerShared {
|
||||
virtual void ReportUsbCamera(int id) = 0;
|
||||
virtual void ReportAxisCamera(int id) = 0;
|
||||
virtual void ReportVideoServer(int id) = 0;
|
||||
virtual void SetCameraServerError(const wpi::Twine& error) = 0;
|
||||
virtual void SetVisionRunnerError(const wpi::Twine& error) = 0;
|
||||
virtual void ReportDriverStationError(const wpi::Twine& error) = 0;
|
||||
virtual void SetCameraServerErrorV(fmt::string_view format,
|
||||
fmt::format_args args) = 0;
|
||||
virtual void SetVisionRunnerErrorV(fmt::string_view format,
|
||||
fmt::format_args args) = 0;
|
||||
virtual void ReportDriverStationErrorV(fmt::string_view format,
|
||||
fmt::format_args args) = 0;
|
||||
virtual std::pair<std::thread::id, bool> GetRobotMainThreadId() const = 0;
|
||||
|
||||
template <typename S, typename... Args>
|
||||
inline void SetCameraServerError(const S& format, Args&&... args) {
|
||||
SetCameraServerErrorV(format,
|
||||
fmt::make_args_checked<Args...>(format, args...));
|
||||
}
|
||||
|
||||
template <typename S, typename... Args>
|
||||
inline void SetVisionRunnerError(const S& format, Args&&... args) {
|
||||
SetVisionRunnerErrorV(format,
|
||||
fmt::make_args_checked<Args...>(format, args...));
|
||||
}
|
||||
|
||||
template <typename S, typename... Args>
|
||||
inline void ReportDriverStationError(const S& format, Args&&... args) {
|
||||
ReportDriverStationErrorV(format,
|
||||
fmt::make_args_checked<Args...>(format, args...));
|
||||
}
|
||||
};
|
||||
|
||||
CameraServerShared* GetCameraServerShared();
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2019 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
@@ -47,14 +44,14 @@ class VisionRunnerBase {
|
||||
*
|
||||
* <p>This method is exposed to allow teams to add additional functionality or
|
||||
* have their own ways to run the pipeline. Most teams, however, should just
|
||||
* use {@link #runForever} in its own thread using a std::thread.</p>
|
||||
* use RunForever() in its own thread using a std::thread.</p>
|
||||
*/
|
||||
void RunOnce();
|
||||
|
||||
/**
|
||||
* A convenience method that calls {@link #runOnce()} in an infinite loop.
|
||||
* This must be run in a dedicated thread, and cannot be used in the main
|
||||
* robot thread because it will freeze the robot program.
|
||||
* A convenience method that calls runOnce() in an infinite loop. This must be
|
||||
* run in a dedicated thread, and cannot be used in the main robot thread
|
||||
* because it will freeze the robot program.
|
||||
*
|
||||
* <strong>Do not call this method directly from the main thread.</strong>
|
||||
*/
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2016-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "vision/VisionRunner.h"
|
||||
|
||||
namespace frc {
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.
|
||||
|
||||
int main() { return 0; }
|
||||
int main() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ macro(wpilib_add_test name srcdir)
|
||||
target_compile_definitions(${name}_test PRIVATE -DGTEST_LINKED_AS_SHARED_LIBRARY)
|
||||
endif()
|
||||
if (MSVC)
|
||||
target_compile_options(${name}_test PRIVATE /wd4251 /wd4101)
|
||||
target_compile_options(${name}_test PRIVATE /wd4101 /wd4251)
|
||||
endif()
|
||||
add_test(NAME ${name} COMMAND ${name}_test)
|
||||
endmacro()
|
||||
|
||||
@@ -2,6 +2,6 @@ macro(wpilib_target_warnings target)
|
||||
if(NOT MSVC)
|
||||
target_compile_options(${target} PRIVATE -Wall -pedantic -Wextra -Werror -Wno-unused-parameter -Wno-error=deprecated-declarations)
|
||||
else()
|
||||
target_compile_options(${target} PRIVATE /wd4244 /wd4267 /wd4146 /WX /wd4996)
|
||||
target_compile_options(${target} PRIVATE /wd4146 /wd4244 /wd4251 /wd4267 /wd4996 /WX)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
116
cmake/modules/FindLIBSSH.cmake
Normal file
116
cmake/modules/FindLIBSSH.cmake
Normal file
@@ -0,0 +1,116 @@
|
||||
# - Try to find LibSSH
|
||||
# Once done this will define
|
||||
#
|
||||
# LIBSSH_FOUND - system has LibSSH
|
||||
# LIBSSH_INCLUDE_DIRS - the LibSSH include directory
|
||||
# LIBSSH_LIBRARIES - link these to use LibSSH
|
||||
# LIBSSH_VERSION -
|
||||
#
|
||||
# Author Michal Vasko <mvasko@cesnet.cz>
|
||||
# Copyright (c) 2020 CESNET, z.s.p.o.
|
||||
#
|
||||
# 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 copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. The name of the author may not be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
||||
#
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
if(LIBSSH_LIBRARIES AND LIBSSH_INCLUDE_DIRS)
|
||||
# in cache already
|
||||
set(LIBSSH_FOUND TRUE)
|
||||
else()
|
||||
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
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
|
||||
if(LIBSSH_INCLUDE_DIR AND LIBSSH_LIBRARY)
|
||||
# learn libssh version
|
||||
if(EXISTS ${LIBSSH_INCLUDE_DIR}/libssh/libssh_version.h)
|
||||
set(LIBSSH_HEADER_PATH ${LIBSSH_INCLUDE_DIR}/libssh/libssh_version.h)
|
||||
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]+")
|
||||
if(NOT LIBSSH_VERSION_MAJOR)
|
||||
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]+")
|
||||
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]+")
|
||||
string(REGEX MATCH "[0-9]+" LIBSSH_VERSION_PATCH ${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"
|
||||
LIBSSH_THREADS_LIBRARY
|
||||
${LIBSSH_LIBRARY}
|
||||
)
|
||||
string(REPLACE "libssh.dylib" "libssh_threads.dylib"
|
||||
LIBSSH_THREADS_LIBRARY
|
||||
${LIBSSH_THREADS_LIBRARY}
|
||||
)
|
||||
string(REPLACE "ssh.so" "ssh_threads.so"
|
||||
LIBSSH_THREADS_LIBRARY
|
||||
${LIBSSH_THREADS_LIBRARY}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(LIBSSH_INCLUDE_DIRS ${LIBSSH_INCLUDE_DIR})
|
||||
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
|
||||
REQUIRED_VARS LIBSSH_INCLUDE_DIRS LIBSSH_LIBRARIES
|
||||
VERSION_VAR LIBSSH_VERSION)
|
||||
endif()
|
||||
5
cmake/modules/LinkMacOSGUI.cmake
Normal file
5
cmake/modules/LinkMacOSGUI.cmake
Normal file
@@ -0,0 +1,5 @@
|
||||
macro(wpilib_link_macos_gui target)
|
||||
if (APPLE)
|
||||
set_target_properties(${target} PROPERTIES LINK_FLAGS "-framework Metal -framework QuartzCore")
|
||||
endif()
|
||||
endmacro()
|
||||
@@ -7,7 +7,7 @@ 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 <wpi/StringRef.h>\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}")
|
||||
@@ -17,7 +17,7 @@ FILE(APPEND "${output}" "const unsigned char* ${prefix}${funcName}(size_t* len)
|
||||
IF(NOT namespace STREQUAL "")
|
||||
FILE(APPEND "${output}" "namespace ${namespace} {\n")
|
||||
ENDIF()
|
||||
FILE(APPEND "${output}" "wpi::StringRef ${funcName}() {\n return wpi::StringRef(reinterpret_cast<const char*>(contents), ${fileSize});\n}\n")
|
||||
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()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
set(GCC_COMPILER_VERSION "" CACHE STRING "GCC Compiler version")
|
||||
set(GNU_MACHINE "arm-frc2020-linux-gnueabi" CACHE STRING "GNU compiler triple")
|
||||
set(GNU_MACHINE "arm-frc2022-linux-gnueabi" CACHE STRING "GNU compiler triple")
|
||||
set(SOFTFP yes)
|
||||
include("${CMAKE_CURRENT_LIST_DIR}/arm.toolchain.cmake")
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
cmake_minimum_required(VERSION 2.8)
|
||||
|
||||
# load settings in case of "try compile"
|
||||
set(TOOLCHAIN_CONFIG_FILE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/toolchain.config.cmake")
|
||||
set(TOOLCHAIN_CONFIG_FILE "${WPILIB_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/toolchain.config.cmake")
|
||||
get_property(__IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE)
|
||||
if(__IN_TRY_COMPILE)
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/../toolchain.config.cmake" OPTIONAL) # CMAKE_BINARY_DIR is different
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/../toolchain.config.cmake" OPTIONAL) # WPILIB_BINARY_DIR is different
|
||||
macro(toolchain_save_config)
|
||||
# nothing
|
||||
endmacro()
|
||||
|
||||
119
crossConnIntegrationTests/build.gradle
Normal file
119
crossConnIntegrationTests/build.gradle
Normal file
@@ -0,0 +1,119 @@
|
||||
import org.gradle.language.base.internal.ProjectLayout
|
||||
import edu.wpi.first.deployutils.deploy.target.RemoteTarget
|
||||
import edu.wpi.first.deployutils.deploy.target.location.SshDeployLocation
|
||||
import edu.wpi.first.deployutils.deploy.artifact.*
|
||||
import org.gradle.internal.os.OperatingSystem
|
||||
|
||||
apply plugin: 'cpp'
|
||||
apply plugin: 'visual-studio'
|
||||
apply plugin: 'edu.wpi.first.NativeUtils'
|
||||
apply plugin: ExtraTasks
|
||||
|
||||
apply plugin: 'edu.wpi.first.DeployUtils'
|
||||
|
||||
apply from: '../shared/config.gradle'
|
||||
|
||||
ext {
|
||||
sharedCvConfigs = [crossConnIntegrationTests: []]
|
||||
staticCvConfigs = [:]
|
||||
useJava = false
|
||||
useCpp = true
|
||||
staticGtestConfigs = [crossConnIntegrationTests: []]
|
||||
}
|
||||
|
||||
apply from: "${rootDir}/shared/opencv.gradle"
|
||||
|
||||
apply from: "${rootDir}/shared/googletest.gradle"
|
||||
|
||||
deploy {
|
||||
targets {
|
||||
roborio(RemoteTarget) {
|
||||
directory = '/home/admin'
|
||||
maxChannels = 4
|
||||
locations {
|
||||
ssh(SshDeployLocation) {
|
||||
address = "172.22.11.2"
|
||||
user = 'admin'
|
||||
password = ''
|
||||
ipv6 = false
|
||||
}
|
||||
}
|
||||
|
||||
artifacts {
|
||||
all {
|
||||
predeploy << { ctx ->
|
||||
ctx.execute('/usr/local/frc/bin/frcKillRobot.sh -t')
|
||||
}
|
||||
postdeploy << { ctx ->
|
||||
ctx.execute("sync")
|
||||
ctx.execute("ldconfig")
|
||||
}
|
||||
}
|
||||
|
||||
crossConnIntegrationTests(NativeExecutableArtifact) {
|
||||
libraryDirectory = '/usr/local/frc/third-party/lib'
|
||||
postdeploy << { ctx ->
|
||||
ctx.execute('chmod +x crossConnIntegrationTests')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
model {
|
||||
components {
|
||||
crossConnIntegrationTests(NativeExecutableSpec) {
|
||||
targetBuildTypes 'debug'
|
||||
nativeUtils.useRequiredLibrary(it, 'googletest_static')
|
||||
binaries.all { binary ->
|
||||
if (binary.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
|
||||
if (binary.buildType.name == 'debug') {
|
||||
deploy.targets.roborio.artifacts.crossConnIntegrationTests.binary = binary
|
||||
}
|
||||
|
||||
binary.sources {
|
||||
athenaCpp(CppSourceSet) {
|
||||
source {
|
||||
srcDirs = ['src/main/native/cpp']
|
||||
includes = ['**/*.cpp']
|
||||
}
|
||||
exportedHeaders {
|
||||
srcDirs = ['src/main/native/include']
|
||||
includes = ['**/*.h']
|
||||
}
|
||||
}
|
||||
}
|
||||
binary.tasks.withType(CppCompile) {
|
||||
cppCompiler.args "-Wno-missing-field-initializers"
|
||||
cppCompiler.args "-Wno-unused-variable"
|
||||
cppCompiler.args "-Wno-error=deprecated-declarations"
|
||||
}
|
||||
project(':hal').addHalDependency(binary, 'shared')
|
||||
project(':hal').addHalJniDependency(binary)
|
||||
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
|
||||
if (binary.targetPlatform.name == nativeUtils.wpi.platforms.roborio) {
|
||||
nativeUtils.useRequiredLibrary(binary, 'ni_link_libraries', 'ni_runtime_libraries')
|
||||
}
|
||||
} else {
|
||||
binary.sources {
|
||||
simCpp(CppSourceSet) {
|
||||
source {
|
||||
srcDirs 'src/main/native/dt'
|
||||
includes = ['**/*.cpp']
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tasks.register('deployTests') {
|
||||
try {
|
||||
dependsOn tasks.named('deployCrossConnIntegrationTestsLibrariesRoborio')
|
||||
dependsOn tasks.named('deployCrossConnIntegrationTestsRoborio')
|
||||
} catch (ignored) {
|
||||
}
|
||||
}
|
||||
112
crossConnIntegrationTests/src/main/native/cpp/AnalogTest.cpp
Normal file
112
crossConnIntegrationTests/src/main/native/cpp/AnalogTest.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
// 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 <hal/AnalogInput.h>
|
||||
#include <hal/AnalogOutput.h>
|
||||
#include <wpi/SmallVector.h>
|
||||
|
||||
#include "CrossConnects.h"
|
||||
#include "LifetimeWrappers.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace hlt;
|
||||
|
||||
class AnalogCrossTest : public ::testing::TestWithParam<std::pair<int, int>> {};
|
||||
|
||||
TEST_P(AnalogCrossTest, AnalogCross) {
|
||||
auto param = GetParam();
|
||||
|
||||
int32_t status = 0;
|
||||
AnalogInputHandle input{param.first, &status};
|
||||
ASSERT_EQ(0, status);
|
||||
AnalogOutputHandle output{param.second, &status};
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
for (double i = 0; i < 5; i += 0.1) {
|
||||
HAL_SetAnalogOutput(output, i, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
usleep(1000);
|
||||
ASSERT_NEAR(i, HAL_GetAnalogVoltage(input, &status), 0.01);
|
||||
ASSERT_EQ(0, status);
|
||||
}
|
||||
|
||||
for (double i = 5; i > 0; i -= 0.1) {
|
||||
HAL_SetAnalogOutput(output, i, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
usleep(1000);
|
||||
ASSERT_NEAR(i, HAL_GetAnalogVoltage(input, &status), 0.01);
|
||||
ASSERT_EQ(0, status);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AnalogInputTest, AllocateAll) {
|
||||
wpi::SmallVector<AnalogInputHandle, 21> analogHandles;
|
||||
for (int i = 0; i < HAL_GetNumAnalogInputs(); i++) {
|
||||
int32_t status = 0;
|
||||
analogHandles.emplace_back(AnalogInputHandle(i, &status));
|
||||
ASSERT_EQ(status, 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AnalogInputTest, MultipleAllocateFails) {
|
||||
int32_t status = 0;
|
||||
AnalogInputHandle handle(0, &status);
|
||||
ASSERT_NE(handle, HAL_kInvalidHandle);
|
||||
ASSERT_EQ(status, 0);
|
||||
|
||||
AnalogInputHandle handle2(0, &status);
|
||||
ASSERT_EQ(handle2, HAL_kInvalidHandle);
|
||||
ASSERT_LAST_ERROR_STATUS(status, RESOURCE_IS_ALLOCATED);
|
||||
}
|
||||
|
||||
TEST(AnalogInputTest, OverAllocateFails) {
|
||||
int32_t status = 0;
|
||||
AnalogInputHandle handle(HAL_GetNumAnalogInputs(), &status);
|
||||
ASSERT_EQ(handle, HAL_kInvalidHandle);
|
||||
ASSERT_LAST_ERROR_STATUS(status, RESOURCE_OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
TEST(AnalogInputTest, UnderAllocateFails) {
|
||||
int32_t status = 0;
|
||||
AnalogInputHandle handle(-1, &status);
|
||||
ASSERT_EQ(handle, HAL_kInvalidHandle);
|
||||
ASSERT_LAST_ERROR_STATUS(status, RESOURCE_OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
TEST(AnalogOutputTest, AllocateAll) {
|
||||
wpi::SmallVector<AnalogOutputHandle, 21> analogHandles;
|
||||
for (int i = 0; i < HAL_GetNumAnalogOutputs(); i++) {
|
||||
int32_t status = 0;
|
||||
analogHandles.emplace_back(AnalogOutputHandle(i, &status));
|
||||
ASSERT_EQ(status, 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(AnalogOutputTest, MultipleAllocateFails) {
|
||||
int32_t status = 0;
|
||||
AnalogOutputHandle handle(0, &status);
|
||||
ASSERT_NE(handle, HAL_kInvalidHandle);
|
||||
ASSERT_EQ(status, 0);
|
||||
|
||||
AnalogOutputHandle handle2(0, &status);
|
||||
ASSERT_EQ(handle2, HAL_kInvalidHandle);
|
||||
ASSERT_LAST_ERROR_STATUS(status, RESOURCE_IS_ALLOCATED);
|
||||
}
|
||||
|
||||
TEST(AnalogOutputTest, OverAllocateFails) {
|
||||
int32_t status = 0;
|
||||
AnalogOutputHandle handle(HAL_GetNumAnalogOutputs(), &status);
|
||||
ASSERT_EQ(handle, HAL_kInvalidHandle);
|
||||
ASSERT_LAST_ERROR_STATUS(status, RESOURCE_OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
TEST(AnalogOutputTest, UnderAllocateFails) {
|
||||
int32_t status = 0;
|
||||
AnalogOutputHandle handle(-1, &status);
|
||||
ASSERT_EQ(handle, HAL_kInvalidHandle);
|
||||
ASSERT_LAST_ERROR_STATUS(status, RESOURCE_OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(AnalogCrossConnectsTests, AnalogCrossTest,
|
||||
::testing::ValuesIn(AnalogCrossConnects));
|
||||
101
crossConnIntegrationTests/src/main/native/cpp/DIOTest.cpp
Normal file
101
crossConnIntegrationTests/src/main/native/cpp/DIOTest.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
// 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 <hal/DIO.h>
|
||||
#include <wpi/SmallVector.h>
|
||||
|
||||
#include "CrossConnects.h"
|
||||
#include "LifetimeWrappers.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace hlt;
|
||||
|
||||
class DIOTest : public ::testing::TestWithParam<std::pair<int, int>> {};
|
||||
|
||||
TEST_P(DIOTest, DIOCross) {
|
||||
auto param = GetParam();
|
||||
int32_t status = 0;
|
||||
DIOHandle first{param.first, false, &status};
|
||||
ASSERT_EQ(0, status);
|
||||
DIOHandle second{param.second, true, &status};
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
HAL_SetDIO(first, false, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
usleep(1000);
|
||||
ASSERT_FALSE(HAL_GetDIO(first, &status));
|
||||
ASSERT_EQ(0, status);
|
||||
ASSERT_FALSE(HAL_GetDIO(second, &status));
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
HAL_SetDIO(first, true, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
usleep(1000);
|
||||
ASSERT_TRUE(HAL_GetDIO(second, &status));
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
HAL_SetDIODirection(first, true, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
HAL_SetDIODirection(second, false, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
HAL_SetDIO(second, false, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
usleep(1000);
|
||||
ASSERT_FALSE(HAL_GetDIO(first, &status));
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
HAL_SetDIO(second, true, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
usleep(1000);
|
||||
ASSERT_TRUE(HAL_GetDIO(first, &status));
|
||||
ASSERT_EQ(0, status);
|
||||
}
|
||||
|
||||
TEST(DIOTest, AllocateAll) {
|
||||
wpi::SmallVector<DIOHandle, 32> dioHandles;
|
||||
for (int i = 0; i < HAL_GetNumDigitalChannels(); i++) {
|
||||
int32_t status = 0;
|
||||
dioHandles.emplace_back(i, true, &status);
|
||||
ASSERT_EQ(status, 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(DIOTest, MultipleAllocateFails) {
|
||||
int32_t status = 0;
|
||||
DIOHandle handle(0, true, &status);
|
||||
ASSERT_NE(handle, HAL_kInvalidHandle);
|
||||
ASSERT_EQ(status, 0);
|
||||
|
||||
DIOHandle handle2(0, true, &status);
|
||||
ASSERT_EQ(handle2, HAL_kInvalidHandle);
|
||||
ASSERT_LAST_ERROR_STATUS(status, RESOURCE_IS_ALLOCATED);
|
||||
}
|
||||
|
||||
TEST(DIOTest, OverAllocateFails) {
|
||||
int32_t status = 0;
|
||||
DIOHandle handle(HAL_GetNumDigitalChannels(), true, &status);
|
||||
ASSERT_EQ(handle, HAL_kInvalidHandle);
|
||||
ASSERT_LAST_ERROR_STATUS(status, RESOURCE_OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
TEST(DIOTest, UnderAllocateFails) {
|
||||
int32_t status = 0;
|
||||
DIOHandle handle(-1, true, &status);
|
||||
ASSERT_EQ(handle, HAL_kInvalidHandle);
|
||||
ASSERT_LAST_ERROR_STATUS(status, RESOURCE_OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
TEST(DIOTest, CrossAllocationFails) {
|
||||
int32_t status = 0;
|
||||
PWMHandle pwmHandle(10, &status);
|
||||
ASSERT_NE(pwmHandle, HAL_kInvalidHandle);
|
||||
ASSERT_EQ(status, 0);
|
||||
DIOHandle handle(10, true, &status);
|
||||
ASSERT_EQ(handle, HAL_kInvalidHandle);
|
||||
ASSERT_LAST_ERROR_STATUS(status, RESOURCE_IS_ALLOCATED);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DIOCrossConnectsTests, DIOTest,
|
||||
::testing::ValuesIn(DIOCrossConnects));
|
||||
@@ -0,0 +1,51 @@
|
||||
// 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 <hal/HAL.h>
|
||||
|
||||
#include "CrossConnects.h"
|
||||
#include "LifetimeWrappers.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace hlt;
|
||||
|
||||
class DutyCycleTest : public ::testing::TestWithParam<std::pair<int, int>> {};
|
||||
|
||||
TEST_P(DutyCycleTest, DutyCycle) {
|
||||
auto param = GetParam();
|
||||
|
||||
int32_t status = 0;
|
||||
PWMHandle pwmHandle(param.first, &status);
|
||||
ASSERT_NE(pwmHandle, HAL_kInvalidHandle);
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
// Ensure our PWM is disabled, and set up properly
|
||||
HAL_SetPWMRaw(pwmHandle, 0, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
HAL_SetPWMConfig(pwmHandle, 2.0, 1.0, 1.0, 0, 0, &status);
|
||||
HAL_SetPWMConfig(pwmHandle, 5.05, 2.525, 2.525, 2.525, 0, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
HAL_SetPWMPeriodScale(pwmHandle, 0, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
DIOHandle dioHandle{param.second, true, &status};
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
DutyCycleHandle dutyCycle{dioHandle, &status};
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
HAL_SetPWMSpeed(pwmHandle, 0.5, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
// Sleep enough time for the frequency to converge
|
||||
usleep(3500000);
|
||||
|
||||
ASSERT_NEAR(1000 / 5.05,
|
||||
(double)HAL_GetDutyCycleFrequency(dutyCycle, &status), 1);
|
||||
|
||||
// TODO measure output
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(DutyCycleCrossConnTests, DutyCycleTest,
|
||||
::testing::ValuesIn(PWMCrossConnects));
|
||||
10
crossConnIntegrationTests/src/main/native/cpp/Main.cpp
Normal file
10
crossConnIntegrationTests/src/main/native/cpp/Main.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
// 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 "gtest/gtest.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
357
crossConnIntegrationTests/src/main/native/cpp/PWMTest.cpp
Normal file
357
crossConnIntegrationTests/src/main/native/cpp/PWMTest.cpp
Normal file
@@ -0,0 +1,357 @@
|
||||
// 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 <atomic>
|
||||
#include <thread>
|
||||
|
||||
#include <hal/DMA.h>
|
||||
#include <hal/HAL.h>
|
||||
#include <wpi/SmallVector.h>
|
||||
#include <wpi/condition_variable.h>
|
||||
#include <wpi/priority_mutex.h>
|
||||
|
||||
#include "CrossConnects.h"
|
||||
#include "LifetimeWrappers.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace hlt;
|
||||
|
||||
class PWMTest : public ::testing::TestWithParam<std::pair<int, int>> {};
|
||||
|
||||
void TestTimingDMA(int squelch, std::pair<int, int> param) {
|
||||
// Initialize DMA
|
||||
int32_t status = 0;
|
||||
DMAHandle dmaHandle(&status);
|
||||
ASSERT_NE(dmaHandle, HAL_kInvalidHandle);
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
status = 0;
|
||||
PWMHandle pwmHandle(param.first, &status);
|
||||
ASSERT_NE(pwmHandle, HAL_kInvalidHandle);
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
// Ensure our PWM is disabled, and set up properly
|
||||
HAL_SetPWMRaw(pwmHandle, 0, &status);
|
||||
HAL_SetPWMConfig(pwmHandle, 2.0, 1.0, 1.0, 0, 0, &status);
|
||||
HAL_SetPWMPeriodScale(pwmHandle, squelch, &status);
|
||||
|
||||
unsigned int checkPeriod = 0;
|
||||
switch (squelch) {
|
||||
case (0):
|
||||
checkPeriod = 5050;
|
||||
break;
|
||||
case (1):
|
||||
checkPeriod = 10100;
|
||||
break;
|
||||
case (3):
|
||||
checkPeriod = 20200;
|
||||
break;
|
||||
}
|
||||
|
||||
status = 0;
|
||||
DIOHandle dioHandle(param.second, true, &status);
|
||||
ASSERT_NE(dioHandle, HAL_kInvalidHandle);
|
||||
|
||||
HAL_AddDMADigitalSource(dmaHandle, dioHandle, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
HAL_SetDMAExternalTrigger(dmaHandle, dioHandle,
|
||||
HAL_AnalogTriggerType::HAL_Trigger_kInWindow, true,
|
||||
true, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
// Loop to test 5 speeds
|
||||
for (unsigned int testWidth = 1000; testWidth < 2100; testWidth += 250) {
|
||||
HAL_StartDMA(dmaHandle, 1024, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
while (true) {
|
||||
int32_t remaining = 0;
|
||||
HAL_DMASample testSample;
|
||||
HAL_ReadDMA(dmaHandle, &testSample, 0.01, &remaining, &status);
|
||||
if (remaining == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
HAL_SetPWMSpeed(pwmHandle, (testWidth - 1000) / 1000.0, &status);
|
||||
|
||||
constexpr const int kSampleCount = 15;
|
||||
HAL_DMASample dmaSamples[kSampleCount];
|
||||
int readCount = 0;
|
||||
while (readCount < kSampleCount) {
|
||||
status = 0;
|
||||
int32_t remaining = 0;
|
||||
HAL_DMAReadStatus readStatus = HAL_ReadDMA(
|
||||
dmaHandle, &dmaSamples[readCount], 1.0, &remaining, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
ASSERT_EQ(HAL_DMAReadStatus::HAL_DMA_OK, readStatus);
|
||||
readCount++;
|
||||
}
|
||||
|
||||
HAL_SetPWMSpeed(pwmHandle, 0, &status);
|
||||
HAL_StopDMA(dmaHandle, &status);
|
||||
|
||||
// Find first rising edge
|
||||
int startIndex = 4;
|
||||
while (startIndex < 6) {
|
||||
status = 0;
|
||||
auto value = HAL_GetDMASampleDigitalSource(&dmaSamples[startIndex],
|
||||
dioHandle, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
if (value)
|
||||
break;
|
||||
startIndex++;
|
||||
}
|
||||
ASSERT_LT(startIndex, 6);
|
||||
|
||||
// Check that samples alternate
|
||||
bool previous = false;
|
||||
int iterationCount = 0;
|
||||
for (int i = startIndex; i < startIndex + 8; i++) {
|
||||
auto value =
|
||||
HAL_GetDMASampleDigitalSource(&dmaSamples[i], dioHandle, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
ASSERT_NE(previous, value);
|
||||
previous = !previous;
|
||||
iterationCount++;
|
||||
}
|
||||
ASSERT_EQ(iterationCount, 8);
|
||||
iterationCount = 0;
|
||||
|
||||
// Check width between samples
|
||||
for (int i = startIndex; i < startIndex + 8; i += 2) {
|
||||
auto width = HAL_GetDMASampleTime(&dmaSamples[i + 1], &status) -
|
||||
HAL_GetDMASampleTime(&dmaSamples[i], &status);
|
||||
ASSERT_NEAR(testWidth, width, 10);
|
||||
iterationCount++;
|
||||
}
|
||||
ASSERT_EQ(iterationCount, 4);
|
||||
iterationCount = 0;
|
||||
|
||||
// Check period between samples
|
||||
for (int i = startIndex; i < startIndex + 6; i += 2) {
|
||||
auto period = HAL_GetDMASampleTime(&dmaSamples[i + 2], &status) -
|
||||
HAL_GetDMASampleTime(&dmaSamples[i], &status);
|
||||
ASSERT_NEAR(checkPeriod, period, 10);
|
||||
iterationCount++;
|
||||
}
|
||||
ASSERT_EQ(iterationCount, 3);
|
||||
}
|
||||
}
|
||||
|
||||
struct InterruptCheckData {
|
||||
wpi::SmallVector<uint64_t, 8> risingStamps;
|
||||
wpi::SmallVector<uint64_t, 8> fallingStamps;
|
||||
wpi::priority_mutex mutex;
|
||||
wpi::condition_variable cond;
|
||||
HAL_InterruptHandle handle;
|
||||
};
|
||||
|
||||
// TODO switch this to DMA
|
||||
void TestTiming(int squelch, std::pair<int, int> param) {
|
||||
// Initialize interrupt
|
||||
int32_t status = 0;
|
||||
InterruptHandle interruptHandle(&status);
|
||||
// Ensure we have a valid interrupt handle
|
||||
ASSERT_NE(interruptHandle, HAL_kInvalidHandle);
|
||||
|
||||
status = 0;
|
||||
PWMHandle pwmHandle(param.first, &status);
|
||||
ASSERT_NE(pwmHandle, HAL_kInvalidHandle);
|
||||
|
||||
// Ensure our PWM is disabled, and set up properly
|
||||
HAL_SetPWMRaw(pwmHandle, 0, &status);
|
||||
HAL_SetPWMConfig(pwmHandle, 2.0, 1.0, 1.0, 0, 0, &status);
|
||||
HAL_SetPWMPeriodScale(pwmHandle, squelch, &status);
|
||||
|
||||
unsigned int checkPeriod = 0;
|
||||
switch (squelch) {
|
||||
case (0):
|
||||
checkPeriod = 5050;
|
||||
break;
|
||||
case (1):
|
||||
checkPeriod = 10100;
|
||||
break;
|
||||
case (3):
|
||||
checkPeriod = 20200;
|
||||
break;
|
||||
}
|
||||
|
||||
status = 0;
|
||||
DIOHandle dioHandle(param.second, true, &status);
|
||||
ASSERT_NE(dioHandle, HAL_kInvalidHandle);
|
||||
|
||||
InterruptCheckData interruptData;
|
||||
interruptData.handle = interruptHandle;
|
||||
|
||||
// Can use any type for the interrupt handle
|
||||
HAL_RequestInterrupts(interruptHandle, dioHandle,
|
||||
HAL_AnalogTriggerType::HAL_Trigger_kInWindow, &status);
|
||||
|
||||
HAL_SetInterruptUpSourceEdge(interruptHandle, true, true, &status);
|
||||
|
||||
// Loop to test 5 speeds
|
||||
for (unsigned int i = 1000; i < 2100; i += 250) {
|
||||
interruptData.risingStamps.clear();
|
||||
interruptData.fallingStamps.clear();
|
||||
|
||||
std::atomic_bool runThread{true};
|
||||
|
||||
status = 0;
|
||||
std::thread interruptThread([&]() {
|
||||
while (runThread) {
|
||||
int32_t threadStatus = 0;
|
||||
auto mask =
|
||||
HAL_WaitForInterrupt(interruptHandle, 5, true, &threadStatus);
|
||||
|
||||
if ((mask & 0x100) == 0x100 && interruptData.risingStamps.size() == 0 &&
|
||||
interruptData.fallingStamps.size() == 0) {
|
||||
// Falling edge at start of tracking. Skip
|
||||
continue;
|
||||
}
|
||||
|
||||
int32_t status = 0;
|
||||
if ((mask & 0x1) == 0x1) {
|
||||
auto ts = HAL_ReadInterruptRisingTimestamp(interruptHandle, &status);
|
||||
// Rising Edge
|
||||
interruptData.risingStamps.push_back(ts);
|
||||
} else if ((mask & 0x100) == 0x100) {
|
||||
auto ts = HAL_ReadInterruptFallingTimestamp(interruptHandle, &status);
|
||||
// Falling Edge
|
||||
interruptData.fallingStamps.push_back(ts);
|
||||
}
|
||||
|
||||
if (interruptData.risingStamps.size() >= 4 &&
|
||||
interruptData.fallingStamps.size() >= 4) {
|
||||
interruptData.cond.notify_all();
|
||||
runThread = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Ensure our interrupt actually got created correctly.
|
||||
ASSERT_EQ(status, 0);
|
||||
HAL_SetPWMSpeed(pwmHandle, (i - 1000) / 1000.0, &status);
|
||||
ASSERT_EQ(status, 0);
|
||||
{
|
||||
std::unique_lock<wpi::priority_mutex> lock(interruptData.mutex);
|
||||
// Wait for lock
|
||||
// TODO: Add Timeout
|
||||
auto timeout = interruptData.cond.wait_for(lock, std::chrono::seconds(2));
|
||||
if (timeout == std::cv_status::timeout) {
|
||||
runThread = false;
|
||||
if (interruptThread.joinable()) {
|
||||
interruptThread.join();
|
||||
}
|
||||
ASSERT_TRUE(false); // Exit test as failure on timeout
|
||||
}
|
||||
}
|
||||
|
||||
HAL_SetPWMRaw(pwmHandle, 0, &status);
|
||||
|
||||
// Ensure our interrupts have the proper counts
|
||||
ASSERT_EQ(interruptData.risingStamps.size(),
|
||||
interruptData.fallingStamps.size());
|
||||
|
||||
ASSERT_GT(interruptData.risingStamps.size(), 0u);
|
||||
|
||||
ASSERT_EQ(interruptData.risingStamps.size() % 2, 0u);
|
||||
ASSERT_EQ(interruptData.fallingStamps.size() % 2, 0u);
|
||||
|
||||
for (size_t j = 0; j < interruptData.risingStamps.size(); j++) {
|
||||
uint64_t width =
|
||||
interruptData.fallingStamps[j] - interruptData.risingStamps[j];
|
||||
ASSERT_NEAR(width, i, 10);
|
||||
}
|
||||
|
||||
for (unsigned int j = 0; j < interruptData.risingStamps.size() - 1; j++) {
|
||||
uint64_t period =
|
||||
interruptData.risingStamps[j + 1] - interruptData.risingStamps[j];
|
||||
ASSERT_NEAR(period, checkPeriod, 10);
|
||||
}
|
||||
runThread = false;
|
||||
if (interruptThread.joinable()) {
|
||||
interruptThread.join();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_P(PWMTest, Timing4x) {
|
||||
auto param = GetParam();
|
||||
TestTiming(3, param);
|
||||
}
|
||||
|
||||
TEST_P(PWMTest, Timing2x) {
|
||||
auto param = GetParam();
|
||||
TestTiming(1, param);
|
||||
}
|
||||
|
||||
TEST_P(PWMTest, Timing1x) {
|
||||
auto param = GetParam();
|
||||
TestTiming(0, param);
|
||||
}
|
||||
|
||||
TEST_P(PWMTest, TimingDMA4x) {
|
||||
auto param = GetParam();
|
||||
TestTimingDMA(3, param);
|
||||
}
|
||||
|
||||
TEST_P(PWMTest, TimingDMA2x) {
|
||||
auto param = GetParam();
|
||||
TestTimingDMA(1, param);
|
||||
}
|
||||
|
||||
TEST_P(PWMTest, TimingDMA1x) {
|
||||
auto param = GetParam();
|
||||
TestTimingDMA(0, param);
|
||||
}
|
||||
|
||||
TEST(PWMTest, AllocateAll) {
|
||||
wpi::SmallVector<PWMHandle, 21> pwmHandles;
|
||||
for (int i = 0; i < HAL_GetNumPWMChannels(); i++) {
|
||||
int32_t status = 0;
|
||||
pwmHandles.emplace_back(PWMHandle(i, &status));
|
||||
ASSERT_EQ(status, 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PWMTest, MultipleAllocateFails) {
|
||||
int32_t status = 0;
|
||||
PWMHandle handle(0, &status);
|
||||
ASSERT_NE(handle, HAL_kInvalidHandle);
|
||||
ASSERT_EQ(status, 0);
|
||||
|
||||
PWMHandle handle2(0, &status);
|
||||
ASSERT_EQ(handle2, HAL_kInvalidHandle);
|
||||
ASSERT_LAST_ERROR_STATUS(status, RESOURCE_IS_ALLOCATED);
|
||||
}
|
||||
|
||||
TEST(PWMTest, OverAllocateFails) {
|
||||
int32_t status = 0;
|
||||
PWMHandle handle(HAL_GetNumPWMChannels(), &status);
|
||||
ASSERT_EQ(handle, HAL_kInvalidHandle);
|
||||
ASSERT_LAST_ERROR_STATUS(status, RESOURCE_OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
TEST(PWMTest, UnderAllocateFails) {
|
||||
int32_t status = 0;
|
||||
PWMHandle handle(-1, &status);
|
||||
ASSERT_EQ(handle, HAL_kInvalidHandle);
|
||||
ASSERT_LAST_ERROR_STATUS(status, RESOURCE_OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
TEST(PWMTest, CrossAllocationFails) {
|
||||
int32_t status = 0;
|
||||
DIOHandle dioHandle(10, true, &status);
|
||||
ASSERT_NE(dioHandle, HAL_kInvalidHandle);
|
||||
ASSERT_EQ(status, 0);
|
||||
PWMHandle handle(10, &status);
|
||||
ASSERT_EQ(handle, HAL_kInvalidHandle);
|
||||
ASSERT_LAST_ERROR_STATUS(status, RESOURCE_IS_ALLOCATED);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(PWMCrossConnectTests, PWMTest,
|
||||
::testing::ValuesIn(PWMCrossConnects));
|
||||
@@ -0,0 +1,50 @@
|
||||
// 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 <hal/AnalogInput.h>
|
||||
#include <hal/Relay.h>
|
||||
#include <wpi/SmallVector.h>
|
||||
|
||||
#include "CrossConnects.h"
|
||||
#include "LifetimeWrappers.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace hlt;
|
||||
|
||||
class RelayAnalogTest : public ::testing::TestWithParam<std::pair<int, int>> {};
|
||||
|
||||
TEST_P(RelayAnalogTest, RelayAnalogCross) {
|
||||
auto param = GetParam();
|
||||
|
||||
int32_t status = 0;
|
||||
RelayHandle relay{param.first, true, &status};
|
||||
ASSERT_EQ(0, status);
|
||||
AnalogInputHandle analog{param.second, &status};
|
||||
ASSERT_EQ(0, status);
|
||||
AnalogTriggerHandle trigger{analog, &status};
|
||||
ASSERT_EQ(0, status);
|
||||
HAL_SetAnalogTriggerLimitsVoltage(trigger, 1.5, 3.0, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
HAL_SetRelay(relay, false, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
usleep(1000);
|
||||
ASSERT_FALSE(HAL_GetAnalogTriggerTriggerState(trigger, &status));
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
HAL_SetRelay(relay, true, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
usleep(1000);
|
||||
ASSERT_TRUE(HAL_GetAnalogTriggerTriggerState(trigger, &status));
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
HAL_SetRelay(relay, false, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
usleep(1000);
|
||||
ASSERT_FALSE(HAL_GetAnalogTriggerTriggerState(trigger, &status));
|
||||
ASSERT_EQ(0, status);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(RelayAnalogCrossConnectsTests, RelayAnalogTest,
|
||||
::testing::ValuesIn(RelayAnalogCrossConnects));
|
||||
@@ -0,0 +1,104 @@
|
||||
// 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 <hal/Relay.h>
|
||||
#include <wpi/SmallVector.h>
|
||||
|
||||
#include "CrossConnects.h"
|
||||
#include "LifetimeWrappers.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using namespace hlt;
|
||||
|
||||
class RelayDigitalTest : public ::testing::TestWithParam<RelayCross> {};
|
||||
|
||||
TEST_P(RelayDigitalTest, RelayCross) {
|
||||
auto param = GetParam();
|
||||
int32_t status = 0;
|
||||
RelayHandle fwd{param.Relay, true, &status};
|
||||
ASSERT_EQ(0, status);
|
||||
RelayHandle rev{param.Relay, false, &status};
|
||||
ASSERT_EQ(0, status);
|
||||
DIOHandle fwdInput{param.FwdDio, true, &status};
|
||||
ASSERT_EQ(0, status);
|
||||
DIOHandle revInput{param.RevDio, true, &status};
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
HAL_SetRelay(fwd, false, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
HAL_SetRelay(rev, false, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
usleep(1000);
|
||||
ASSERT_FALSE(HAL_GetDIO(fwdInput, &status));
|
||||
ASSERT_EQ(0, status);
|
||||
ASSERT_FALSE(HAL_GetDIO(revInput, &status));
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
HAL_SetRelay(fwd, false, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
HAL_SetRelay(rev, true, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
usleep(1000);
|
||||
ASSERT_FALSE(HAL_GetDIO(fwdInput, &status));
|
||||
ASSERT_EQ(0, status);
|
||||
ASSERT_TRUE(HAL_GetDIO(revInput, &status));
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
HAL_SetRelay(fwd, true, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
HAL_SetRelay(rev, false, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
usleep(1000);
|
||||
ASSERT_TRUE(HAL_GetDIO(fwdInput, &status));
|
||||
ASSERT_EQ(0, status);
|
||||
ASSERT_FALSE(HAL_GetDIO(revInput, &status));
|
||||
ASSERT_EQ(0, status);
|
||||
|
||||
HAL_SetRelay(fwd, true, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
HAL_SetRelay(rev, true, &status);
|
||||
ASSERT_EQ(0, status);
|
||||
usleep(1000);
|
||||
ASSERT_TRUE(HAL_GetDIO(fwdInput, &status));
|
||||
ASSERT_EQ(0, status);
|
||||
ASSERT_TRUE(HAL_GetDIO(revInput, &status));
|
||||
ASSERT_EQ(0, status);
|
||||
}
|
||||
|
||||
TEST(RelayDigitalTest, AllocateAll) {
|
||||
wpi::SmallVector<RelayHandle, 32> relayHandles;
|
||||
for (int i = 0; i < HAL_GetNumRelayChannels(); i++) {
|
||||
int32_t status = 0;
|
||||
relayHandles.emplace_back(i / 2, i % 2, &status);
|
||||
ASSERT_EQ(status, 0);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(RelayDigitalTest, MultipleAllocateFails) {
|
||||
int32_t status = 0;
|
||||
RelayHandle handle(0, true, &status);
|
||||
ASSERT_NE(handle, HAL_kInvalidHandle);
|
||||
ASSERT_EQ(status, 0);
|
||||
|
||||
RelayHandle handle2(0, true, &status);
|
||||
ASSERT_EQ(handle2, HAL_kInvalidHandle);
|
||||
ASSERT_LAST_ERROR_STATUS(status, RESOURCE_IS_ALLOCATED);
|
||||
}
|
||||
|
||||
TEST(RelayDigitalTest, OverAllocateFails) {
|
||||
int32_t status = 0;
|
||||
RelayHandle handle(HAL_GetNumRelayChannels(), true, &status);
|
||||
ASSERT_EQ(handle, HAL_kInvalidHandle);
|
||||
ASSERT_LAST_ERROR_STATUS(status, RESOURCE_OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
TEST(RelayDigitalTest, UnderAllocateFails) {
|
||||
int32_t status = 0;
|
||||
RelayHandle handle(-1, true, &status);
|
||||
ASSERT_EQ(handle, HAL_kInvalidHandle);
|
||||
ASSERT_LAST_ERROR_STATUS(status, RESOURCE_OUT_OF_RANGE);
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_SUITE_P(RelayDigitalCrossConnectsTests, RelayDigitalTest,
|
||||
::testing::ValuesIn(RelayCrossConnects));
|
||||
@@ -0,0 +1,71 @@
|
||||
// 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 <cstdlib>
|
||||
#include <thread>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <hal/HAL.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "mockds/MockDS.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
class TestEnvironment : public testing::Environment {
|
||||
bool m_alreadySetUp = false;
|
||||
MockDS m_mockDS;
|
||||
|
||||
public:
|
||||
TestEnvironment() {
|
||||
// Only set up once. This allows gtest_repeat to be used to automatically
|
||||
// repeat tests.
|
||||
if (m_alreadySetUp) {
|
||||
return;
|
||||
}
|
||||
m_alreadySetUp = true;
|
||||
|
||||
if (!HAL_Initialize(500, 0)) {
|
||||
fmt::print(stderr, "FATAL ERROR: HAL could not be initialized\n");
|
||||
std::exit(-1);
|
||||
}
|
||||
|
||||
m_mockDS.Start();
|
||||
|
||||
// This sets up the network communications library to enable the driver
|
||||
// station. After starting network coms, it will loop until the driver
|
||||
// station returns that the robot is enabled, to ensure that tests will be
|
||||
// able to run on the hardware.
|
||||
HAL_ObserveUserProgramStarting();
|
||||
|
||||
fmt::print("Started coms\n");
|
||||
|
||||
int enableCounter = 0;
|
||||
|
||||
auto checkEnabled = []() {
|
||||
HAL_ControlWord controlWord;
|
||||
std::memset(&controlWord, 0, sizeof(controlWord));
|
||||
HAL_GetControlWord(&controlWord);
|
||||
return controlWord.enabled && controlWord.dsAttached;
|
||||
};
|
||||
while (!checkEnabled()) {
|
||||
if (enableCounter > 50) {
|
||||
// Robot did not enable properly after 5 seconds.
|
||||
// Force exit
|
||||
fmt::print(stderr, " Failed to enable. Aborting\n");
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(100ms);
|
||||
|
||||
fmt::print("Waiting for enable: {}\n", enableCounter++);
|
||||
}
|
||||
std::this_thread::sleep_for(500ms);
|
||||
}
|
||||
|
||||
~TestEnvironment() override { m_mockDS.Stop(); }
|
||||
};
|
||||
|
||||
testing::Environment* const environment =
|
||||
testing::AddGlobalTestEnvironment(new TestEnvironment);
|
||||
@@ -0,0 +1,86 @@
|
||||
// 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 "MockDS.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <string_view>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <hal/cpp/fpga_clock.h>
|
||||
#include <wpi/Logger.h>
|
||||
#include <wpi/SmallVector.h>
|
||||
#include <wpi/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);
|
||||
return;
|
||||
}
|
||||
|
||||
std::string_view levelmsg;
|
||||
if (level >= 50) {
|
||||
levelmsg = "CRITICAL";
|
||||
} else if (level >= 40) {
|
||||
levelmsg = "ERROR";
|
||||
} else if (level >= 30) {
|
||||
levelmsg = "WARNING";
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
fmt::print(stderr, "DS: {}: {} ({}:{})\n", levelmsg, msg, file, line);
|
||||
}
|
||||
|
||||
static void generateEnabledDsPacket(wpi::SmallVectorImpl<uint8_t>& data,
|
||||
uint16_t sendCount) {
|
||||
data.clear();
|
||||
data.push_back(sendCount >> 8);
|
||||
data.push_back(sendCount);
|
||||
data.push_back(0x01); // general data tag
|
||||
data.push_back(0x04); // teleop enabled
|
||||
data.push_back(0x10); // normal data request
|
||||
data.push_back(0x00); // red 1 station
|
||||
}
|
||||
|
||||
void MockDS::Start() {
|
||||
if (m_active) {
|
||||
return;
|
||||
}
|
||||
m_active = true;
|
||||
m_thread = std::thread([&]() {
|
||||
wpi::Logger logger(LoggerFunc);
|
||||
wpi::UDPClient client(logger);
|
||||
client.start();
|
||||
auto timeout_time = hal::fpga_clock::now();
|
||||
int initCount = 0;
|
||||
uint16_t sendCount = 0;
|
||||
wpi::SmallVector<uint8_t, 8> data;
|
||||
while (m_active) {
|
||||
// Keep 20ms intervals, and increase time to next interval
|
||||
auto current = hal::fpga_clock::now();
|
||||
while (timeout_time <= current) {
|
||||
timeout_time += std::chrono::milliseconds(20);
|
||||
}
|
||||
std::this_thread::sleep_until(timeout_time);
|
||||
generateEnabledDsPacket(data, sendCount++);
|
||||
// ~10 disabled packets are required to make the robot actually enable
|
||||
// 1 is definitely not enough.
|
||||
if (initCount < 10) {
|
||||
initCount++;
|
||||
data[3] = 0;
|
||||
}
|
||||
client.send(data, "127.0.0.1", 1110);
|
||||
}
|
||||
client.shutdown();
|
||||
});
|
||||
}
|
||||
|
||||
void MockDS::Stop() {
|
||||
m_active = false;
|
||||
if (m_thread.joinable()) {
|
||||
m_thread.join();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
class MockDS {
|
||||
public:
|
||||
MockDS() = default;
|
||||
~MockDS() { Stop(); }
|
||||
MockDS(const MockDS& other) = delete;
|
||||
MockDS& operator=(const MockDS& other) = delete;
|
||||
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
private:
|
||||
std::thread m_thread;
|
||||
std::atomic_bool m_active{false};
|
||||
};
|
||||
5
crossConnIntegrationTests/src/main/native/dt/Main.cpp
Normal file
5
crossConnIntegrationTests/src/main/native/dt/Main.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
// 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.
|
||||
|
||||
int main() {}
|
||||
@@ -0,0 +1,62 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <utility>
|
||||
|
||||
namespace hlt {
|
||||
|
||||
constexpr static std::array<std::pair<int, int>, 22> DIOCrossConnects{
|
||||
std::pair{20, 25},
|
||||
std::pair{19, 24},
|
||||
std::pair{17, 13},
|
||||
std::pair{16, 12},
|
||||
std::pair{15, 11},
|
||||
std::pair{14, 10},
|
||||
std::pair{26, 2},
|
||||
std::pair{27, 1},
|
||||
std::pair{28, 0},
|
||||
std::pair{29, 3},
|
||||
std::pair{30, 4},
|
||||
|
||||
// Opposite direction
|
||||
std::pair{25, 20},
|
||||
std::pair{24, 19},
|
||||
std::pair{13, 17},
|
||||
std::pair{12, 16},
|
||||
std::pair{11, 15},
|
||||
std::pair{10, 14},
|
||||
std::pair{2, 26},
|
||||
std::pair{1, 27},
|
||||
std::pair{0, 28},
|
||||
std::pair{3, 29},
|
||||
std::pair{4, 30},
|
||||
};
|
||||
|
||||
// PWM on left, DIO on right
|
||||
constexpr static std::array<std::pair<int, int>, 2> PWMCrossConnects{
|
||||
std::pair{0, 18},
|
||||
std::pair{16, 25},
|
||||
};
|
||||
|
||||
// FWD only, relay on left
|
||||
constexpr static std::array<std::pair<int, int>, 2> RelayAnalogCrossConnects{
|
||||
std::pair{2, 0}, std::pair{3, 1}};
|
||||
|
||||
struct RelayCross {
|
||||
int Relay;
|
||||
int FwdDio;
|
||||
int RevDio;
|
||||
};
|
||||
|
||||
constexpr static std::array<RelayCross, 1> RelayCrossConnects{
|
||||
RelayCross{0, 23, 22}};
|
||||
|
||||
// input on left
|
||||
constexpr static std::array<std::pair<int, int>, 2> AnalogCrossConnects{
|
||||
std::pair{2, 0}, std::pair{4, 1}};
|
||||
|
||||
} // namespace hlt
|
||||
@@ -0,0 +1,200 @@
|
||||
// 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <hal/DMA.h>
|
||||
#include <hal/DutyCycle.h>
|
||||
#include <hal/HAL.h>
|
||||
|
||||
namespace hlt {
|
||||
|
||||
struct InterruptHandle {
|
||||
public:
|
||||
explicit InterruptHandle(int32_t* status) {
|
||||
handle = HAL_InitializeInterrupts(status);
|
||||
}
|
||||
InterruptHandle(const InterruptHandle&) = delete;
|
||||
InterruptHandle operator=(const InterruptHandle&) = delete;
|
||||
|
||||
InterruptHandle(InterruptHandle&&) = default;
|
||||
InterruptHandle& operator=(InterruptHandle&&) = default;
|
||||
|
||||
~InterruptHandle() { HAL_CleanInterrupts(handle); }
|
||||
|
||||
operator HAL_InterruptHandle() const { return handle; }
|
||||
|
||||
private:
|
||||
HAL_InterruptHandle handle = 0;
|
||||
};
|
||||
|
||||
struct DMAHandle {
|
||||
public:
|
||||
explicit DMAHandle(int32_t* status) { handle = HAL_InitializeDMA(status); }
|
||||
DMAHandle(const DMAHandle&) = delete;
|
||||
DMAHandle operator=(const DMAHandle&) = delete;
|
||||
|
||||
DMAHandle(DMAHandle&&) = default;
|
||||
DMAHandle& operator=(DMAHandle&&) = default;
|
||||
|
||||
~DMAHandle() { HAL_FreeDMA(handle); }
|
||||
|
||||
operator HAL_DMAHandle() const { return handle; }
|
||||
|
||||
private:
|
||||
HAL_DMAHandle handle = 0;
|
||||
};
|
||||
|
||||
struct AnalogInputHandle {
|
||||
public:
|
||||
AnalogInputHandle(int32_t port, int32_t* status) {
|
||||
handle = HAL_InitializeAnalogInputPort(HAL_GetPort(port), nullptr, status);
|
||||
}
|
||||
AnalogInputHandle(const AnalogInputHandle&) = delete;
|
||||
AnalogInputHandle operator=(const AnalogInputHandle&) = delete;
|
||||
|
||||
AnalogInputHandle(AnalogInputHandle&&) = default;
|
||||
AnalogInputHandle& operator=(AnalogInputHandle&&) = default;
|
||||
|
||||
~AnalogInputHandle() { HAL_FreeAnalogInputPort(handle); }
|
||||
|
||||
operator HAL_AnalogInputHandle() const { return handle; }
|
||||
|
||||
private:
|
||||
HAL_AnalogInputHandle handle = 0;
|
||||
};
|
||||
|
||||
struct AnalogOutputHandle {
|
||||
public:
|
||||
AnalogOutputHandle(int32_t port, int32_t* status) {
|
||||
handle = HAL_InitializeAnalogOutputPort(HAL_GetPort(port), nullptr, status);
|
||||
}
|
||||
AnalogOutputHandle(const AnalogOutputHandle&) = delete;
|
||||
AnalogOutputHandle operator=(const AnalogOutputHandle&) = delete;
|
||||
|
||||
AnalogOutputHandle(AnalogOutputHandle&&) = default;
|
||||
AnalogOutputHandle& operator=(AnalogOutputHandle&&) = default;
|
||||
|
||||
~AnalogOutputHandle() { HAL_FreeAnalogOutputPort(handle); }
|
||||
|
||||
operator HAL_AnalogOutputHandle() const { return handle; }
|
||||
|
||||
private:
|
||||
HAL_AnalogOutputHandle handle = 0;
|
||||
};
|
||||
|
||||
struct AnalogTriggerHandle {
|
||||
public:
|
||||
explicit AnalogTriggerHandle(HAL_AnalogInputHandle port, int32_t* status) {
|
||||
handle = HAL_InitializeAnalogTrigger(port, status);
|
||||
}
|
||||
AnalogTriggerHandle(const AnalogTriggerHandle&) = delete;
|
||||
AnalogTriggerHandle operator=(const AnalogTriggerHandle&) = delete;
|
||||
|
||||
AnalogTriggerHandle(AnalogTriggerHandle&&) = default;
|
||||
AnalogTriggerHandle& operator=(AnalogTriggerHandle&&) = default;
|
||||
|
||||
~AnalogTriggerHandle() {
|
||||
int32_t status = 0;
|
||||
HAL_CleanAnalogTrigger(handle, &status);
|
||||
}
|
||||
|
||||
operator HAL_AnalogTriggerHandle() const { return handle; }
|
||||
|
||||
private:
|
||||
HAL_AnalogTriggerHandle handle = 0;
|
||||
};
|
||||
|
||||
struct DutyCycleHandle {
|
||||
public:
|
||||
DutyCycleHandle(HAL_DigitalHandle port, int32_t* status) {
|
||||
handle = HAL_InitializeDutyCycle(
|
||||
port, HAL_AnalogTriggerType::HAL_Trigger_kInWindow, status);
|
||||
}
|
||||
DutyCycleHandle(const DutyCycleHandle&) = delete;
|
||||
DutyCycleHandle operator=(const DutyCycleHandle&) = delete;
|
||||
|
||||
DutyCycleHandle(DutyCycleHandle&&) = default;
|
||||
DutyCycleHandle& operator=(DutyCycleHandle&&) = default;
|
||||
|
||||
~DutyCycleHandle() { HAL_FreeDutyCycle(handle); }
|
||||
|
||||
operator HAL_DutyCycleHandle() const { return handle; }
|
||||
|
||||
private:
|
||||
HAL_DutyCycleHandle handle = 0;
|
||||
};
|
||||
|
||||
struct DIOHandle {
|
||||
public:
|
||||
DIOHandle() {}
|
||||
DIOHandle(const DIOHandle&) = delete;
|
||||
DIOHandle operator=(const DIOHandle&) = delete;
|
||||
|
||||
DIOHandle(DIOHandle&&) = default;
|
||||
DIOHandle& operator=(DIOHandle&&) = default;
|
||||
|
||||
DIOHandle(int32_t port, HAL_Bool input, int32_t* status) {
|
||||
handle = HAL_InitializeDIOPort(HAL_GetPort(port), input, nullptr, status);
|
||||
}
|
||||
|
||||
~DIOHandle() { HAL_FreeDIOPort(handle); }
|
||||
|
||||
operator HAL_DigitalHandle() const { return handle; }
|
||||
|
||||
private:
|
||||
HAL_DigitalHandle handle = 0;
|
||||
};
|
||||
|
||||
struct PWMHandle {
|
||||
public:
|
||||
PWMHandle() {}
|
||||
PWMHandle(const PWMHandle&) = delete;
|
||||
PWMHandle operator=(const PWMHandle&) = delete;
|
||||
|
||||
PWMHandle(PWMHandle&&) = default;
|
||||
PWMHandle& operator=(PWMHandle&&) = default;
|
||||
|
||||
PWMHandle(int32_t port, int32_t* status) {
|
||||
handle = HAL_InitializePWMPort(HAL_GetPort(port), nullptr, status);
|
||||
}
|
||||
|
||||
~PWMHandle() {
|
||||
int32_t status = 0;
|
||||
HAL_FreePWMPort(handle, &status);
|
||||
}
|
||||
|
||||
operator HAL_DigitalHandle() const { return handle; }
|
||||
|
||||
private:
|
||||
HAL_DigitalHandle handle = 0;
|
||||
};
|
||||
|
||||
struct RelayHandle {
|
||||
public:
|
||||
RelayHandle(int32_t port, HAL_Bool fwd, int32_t* status) {
|
||||
handle = HAL_InitializeRelayPort(HAL_GetPort(port), fwd, nullptr, status);
|
||||
}
|
||||
RelayHandle(const RelayHandle&) = delete;
|
||||
RelayHandle operator=(const RelayHandle&) = delete;
|
||||
|
||||
RelayHandle(RelayHandle&&) = default;
|
||||
RelayHandle& operator=(RelayHandle&&) = default;
|
||||
|
||||
~RelayHandle() { HAL_FreeRelayPort(handle); }
|
||||
|
||||
operator HAL_RelayHandle() const { return handle; }
|
||||
|
||||
private:
|
||||
HAL_RelayHandle handle = 0;
|
||||
};
|
||||
|
||||
#define ASSERT_LAST_ERROR_STATUS(status, x) \
|
||||
do { \
|
||||
ASSERT_EQ(status, HAL_USE_LAST_ERROR); \
|
||||
const char* lastErrorMessageInMacro = HAL_GetLastError(&status); \
|
||||
ASSERT_EQ(status, x); \
|
||||
} while (0)
|
||||
|
||||
} // namespace hlt
|
||||
@@ -6,6 +6,7 @@ cppHeaderFileInclude {
|
||||
(?<!_c)\.h$
|
||||
\.hpp$
|
||||
\.inc$
|
||||
\.inl$
|
||||
}
|
||||
|
||||
cppSrcFileInclude {
|
||||
@@ -30,6 +31,7 @@ repoRootNameOverride {
|
||||
}
|
||||
|
||||
includeOtherLibs {
|
||||
^fmt/
|
||||
^opencv2/
|
||||
^support/
|
||||
^tcpsockets/
|
||||
|
||||
@@ -3,6 +3,7 @@ project(cscore)
|
||||
include(SubDirList)
|
||||
include(CompileWarnings)
|
||||
include(AddTest)
|
||||
include(LinkMacOSGUI)
|
||||
|
||||
find_package( OpenCV REQUIRED )
|
||||
|
||||
@@ -39,43 +40,58 @@ set_property(TARGET cscore PROPERTY FOLDER "libraries")
|
||||
install(TARGETS cscore EXPORT cscore DESTINATION "${main_lib_dest}")
|
||||
install(DIRECTORY src/main/native/include/ DESTINATION "${include_dest}/cscore")
|
||||
|
||||
if (MSVC OR FLAT_INSTALL_WPILIB)
|
||||
if (WITH_FLAT_INSTALL)
|
||||
set (cscore_config_dir ${wpilib_dest})
|
||||
else()
|
||||
set (cscore_config_dir share/cscore)
|
||||
endif()
|
||||
|
||||
configure_file(cscore-config.cmake.in ${CMAKE_BINARY_DIR}/cscore-config.cmake )
|
||||
install(FILES ${CMAKE_BINARY_DIR}/cscore-config.cmake 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 ${cscore_config_dir})
|
||||
install(EXPORT cscore DESTINATION ${cscore_config_dir})
|
||||
|
||||
SUBDIR_LIST(cscore_examples "${CMAKE_CURRENT_SOURCE_DIR}/examples")
|
||||
foreach(example ${cscore_examples})
|
||||
file(GLOB cscore_example_src examples/${example}/*.cpp)
|
||||
unset(add_libs)
|
||||
if(${example} STREQUAL "usbviewer")
|
||||
if(TARGET wpigui)
|
||||
set(add_libs wpigui)
|
||||
else()
|
||||
unset(cscore_example_src)
|
||||
endif()
|
||||
endif()
|
||||
if(cscore_example_src)
|
||||
add_executable(cscore_${example} ${cscore_example_src})
|
||||
wpilib_target_warnings(cscore_${example})
|
||||
target_link_libraries(cscore_${example} cscore)
|
||||
|
||||
if (${example} STREQUAL "usbviewer")
|
||||
wpilib_link_macos_gui(cscore_${example})
|
||||
endif()
|
||||
|
||||
target_link_libraries(cscore_${example} cscore ${add_libs})
|
||||
set_property(TARGET cscore_${example} PROPERTY FOLDER "examples")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Java bindings
|
||||
if (NOT WITHOUT_JAVA)
|
||||
if (WITH_JAVA)
|
||||
find_package(Java REQUIRED)
|
||||
find_package(JNI REQUIRED)
|
||||
include(UseJava)
|
||||
set(CMAKE_JAVA_COMPILE_FLAGS "-Xlint:unchecked")
|
||||
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/)
|
||||
if("${OPENCV_JAVA_INSTALL_DIR}" STREQUAL "")
|
||||
set(OPENCV_JAVA_INSTALL_DIR ${OpenCV_INSTALL_PATH}/share/OpenCV/java/)
|
||||
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 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 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 NO_DEFAULT_PATH)
|
||||
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)
|
||||
|
||||
file(GLOB
|
||||
cscore_jni_src src/main/native/cpp/jni/CameraServerJNI.cpp)
|
||||
|
||||
@@ -15,15 +15,60 @@ ext {
|
||||
|
||||
apply from: "${rootDir}/shared/jni/setupBuild.gradle"
|
||||
|
||||
model {
|
||||
components {
|
||||
cscoreJNICvStatic(JniNativeLibrarySpec) {
|
||||
baseName = 'cscorejnicvstatic'
|
||||
|
||||
enableCheckTask true
|
||||
javaCompileTasks << compileJava
|
||||
jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.roborio)
|
||||
jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.raspbian)
|
||||
jniCrossCompileOptions << JniCrossCompileOptions(nativeUtils.wpi.platforms.aarch64bionic)
|
||||
|
||||
sources {
|
||||
cpp {
|
||||
source {
|
||||
srcDirs 'src/main/native/cpp'
|
||||
include '**/jni/*.cpp'
|
||||
}
|
||||
exportedHeaders {
|
||||
srcDir 'src/main/native/include'
|
||||
include '**/*.h'
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
binaries.all {
|
||||
if (it instanceof StaticLibraryBinarySpec) {
|
||||
it.buildable = false
|
||||
return
|
||||
}
|
||||
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
|
||||
|
||||
if (it.targetPlatform.operatingSystem.linux) {
|
||||
it.linker.args '-Wl,--version-script=' + file('src/main/native/LinuxSymbolScript.txt')
|
||||
} else if (it.targetPlatform.operatingSystem.macOsX) {
|
||||
it.linker.args '-exported_symbols_list'
|
||||
it.linker.args file('src/main/native/MacSymbolScript.txt').toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ext {
|
||||
sharedCvConfigs = [cscore : [],
|
||||
cscoreBase: [],
|
||||
cscoreDev : [],
|
||||
cscoreTest: [],
|
||||
cscoreJNIShared: []]
|
||||
staticCvConfigs = [cscoreJNI: []]
|
||||
cscoreBase: [],
|
||||
cscoreDev : [],
|
||||
cscoreTest: [],
|
||||
cscoreJNIShared: []]
|
||||
staticCvConfigs = [cscoreJNI: [],
|
||||
cscoreJNICvStatic: []]
|
||||
useJava = true
|
||||
useCpp = true
|
||||
cvStaticBuild = true
|
||||
splitSetup = {
|
||||
if (it.targetPlatform.operatingSystem.isMacOsX()) {
|
||||
it.sources {
|
||||
@@ -82,52 +127,107 @@ def examplesMap = [:];
|
||||
|
||||
File examplesTree = file("$projectDir/examples")
|
||||
examplesTree.list(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File current, String name) {
|
||||
return new File(current, name).isDirectory();
|
||||
}
|
||||
}).each {
|
||||
sharedCvConfigs.put(it, [])
|
||||
examplesMap.put(it, [])
|
||||
}
|
||||
@Override
|
||||
public boolean accept(File current, String name) {
|
||||
return new File(current, name).isDirectory();
|
||||
}
|
||||
}).each {
|
||||
sharedCvConfigs.put(it, [])
|
||||
examplesMap.put(it, [])
|
||||
}
|
||||
|
||||
apply from: "${rootDir}/shared/opencv.gradle"
|
||||
|
||||
Action<List<String>> symbolFilter = { symbols ->
|
||||
symbols.removeIf({ !it.startsWith('CS_') })
|
||||
} as Action<List<String>>;
|
||||
|
||||
nativeUtils.exportsConfigs {
|
||||
cscore {
|
||||
x86ExcludeSymbols = ['_CT??_R0?AV_System_error', '_CT??_R0?AVexception', '_CT??_R0?AVfailure',
|
||||
'_CT??_R0?AVruntime_error', '_CT??_R0?AVsystem_error', '_CTA5?AVfailure',
|
||||
'_TI5?AVfailure', '_CT??_R0?AVout_of_range', '_CTA3?AVout_of_range',
|
||||
'_TI3?AVout_of_range', '_CT??_R0?AVbad_cast']
|
||||
x64ExcludeSymbols = ['_CT??_R0?AV_System_error', '_CT??_R0?AVexception', '_CT??_R0?AVfailure',
|
||||
'_CT??_R0?AVruntime_error', '_CT??_R0?AVsystem_error', '_CTA5?AVfailure',
|
||||
'_TI5?AVfailure', '_CT??_R0?AVout_of_range', '_CTA3?AVout_of_range',
|
||||
'_TI3?AVout_of_range', '_CT??_R0?AVbad_cast']
|
||||
x86ExcludeSymbols = [
|
||||
'_CT??_R0?AV_System_error',
|
||||
'_CT??_R0?AVexception',
|
||||
'_CT??_R0?AVfailure',
|
||||
'_CT??_R0?AVruntime_error',
|
||||
'_CT??_R0?AVsystem_error',
|
||||
'_CTA5?AVfailure',
|
||||
'_TI5?AVfailure',
|
||||
'_CT??_R0?AVout_of_range',
|
||||
'_CTA3?AVout_of_range',
|
||||
'_TI3?AVout_of_range',
|
||||
'_CT??_R0?AVbad_cast'
|
||||
]
|
||||
x64ExcludeSymbols = [
|
||||
'_CT??_R0?AV_System_error',
|
||||
'_CT??_R0?AVexception',
|
||||
'_CT??_R0?AVfailure',
|
||||
'_CT??_R0?AVruntime_error',
|
||||
'_CT??_R0?AVsystem_error',
|
||||
'_CTA5?AVfailure',
|
||||
'_TI5?AVfailure',
|
||||
'_CT??_R0?AVout_of_range',
|
||||
'_CTA3?AVout_of_range',
|
||||
'_TI3?AVout_of_range',
|
||||
'_CT??_R0?AVbad_cast'
|
||||
]
|
||||
}
|
||||
cscoreJNI {
|
||||
x86SymbolFilter = { symbols ->
|
||||
symbols.removeIf({ !it.startsWith('CS_') })
|
||||
}
|
||||
x64SymbolFilter = { symbols ->
|
||||
symbols.removeIf({ !it.startsWith('CS_') })
|
||||
}
|
||||
x86SymbolFilter = symbolFilter
|
||||
x64SymbolFilter = symbolFilter
|
||||
}
|
||||
cscoreJNICvStatic {
|
||||
x86SymbolFilter = symbolFilter
|
||||
x64SymbolFilter = symbolFilter
|
||||
}
|
||||
}
|
||||
|
||||
model {
|
||||
components {
|
||||
examplesMap.each { key, value ->
|
||||
"${key}"(NativeExecutableSpec) {
|
||||
targetBuildTypes 'debug'
|
||||
binaries.all {
|
||||
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
|
||||
lib library: 'cscore', linkage: 'shared'
|
||||
if (key == "usbviewer") {
|
||||
if (!project.hasProperty('onlylinuxathena') && !project.hasProperty('onlylinuxraspbian') && !project.hasProperty('onlylinuxaarch64bionic')) {
|
||||
"${key}"(NativeExecutableSpec) {
|
||||
targetBuildTypes 'debug'
|
||||
binaries.all {
|
||||
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
|
||||
lib project: ':wpigui', library: 'wpigui', linkage: 'static'
|
||||
lib library: 'cscore', linkage: 'shared'
|
||||
nativeUtils.useRequiredLibrary(it, 'imgui_static')
|
||||
if (it.targetPlatform.name == nativeUtils.wpi.platforms.roborio || it.targetPlatform.name == nativeUtils.wpi.platforms.raspbian || it.targetPlatform.name == nativeUtils.wpi.platforms.aarch64bionic) {
|
||||
it.buildable = false
|
||||
return
|
||||
}
|
||||
if (it.targetPlatform.operatingSystem.isWindows()) {
|
||||
it.linker.args << 'Gdi32.lib' << 'Shell32.lib' << 'd3d11.lib' << 'd3dcompiler.lib'
|
||||
} else if (it.targetPlatform.operatingSystem.isMacOsX()) {
|
||||
it.linker.args << '-framework' << 'Metal' << '-framework' << 'MetalKit' << '-framework' << 'Cocoa' << '-framework' << 'IOKit' << '-framework' << 'CoreFoundation' << '-framework' << 'CoreVideo' << '-framework' << 'QuartzCore'
|
||||
} else {
|
||||
it.linker.args << '-lX11'
|
||||
}
|
||||
}
|
||||
sources {
|
||||
cpp {
|
||||
source {
|
||||
srcDirs 'examples/' + "${key}"
|
||||
include '**/*.cpp'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sources {
|
||||
cpp {
|
||||
source {
|
||||
srcDirs 'examples/' + "${key}"
|
||||
include '**/*.cpp'
|
||||
} else {
|
||||
"${key}"(NativeExecutableSpec) {
|
||||
targetBuildTypes 'debug'
|
||||
binaries.all {
|
||||
lib project: ':wpiutil', library: 'wpiutil', linkage: 'shared'
|
||||
lib library: 'cscore', linkage: 'shared'
|
||||
}
|
||||
sources {
|
||||
cpp {
|
||||
source {
|
||||
srcDirs 'examples/' + "${key}"
|
||||
include '**/*.cpp'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,5 @@ include(CMakeFindDependencyMacro)
|
||||
@WPIUTIL_DEP_REPLACE@
|
||||
find_dependency(OpenCV)
|
||||
|
||||
@FILENAME_DEP_REPLACE@
|
||||
include(${SELF_DIR}/cscore.cmake)
|
||||
|
||||
@@ -1,84 +1,78 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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 <wpi/SmallString.h>
|
||||
#include <wpi/raw_ostream.h>
|
||||
#include <cstdio>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "cscore.h"
|
||||
|
||||
int main() {
|
||||
CS_Status status = 0;
|
||||
wpi::SmallString<64> buf;
|
||||
|
||||
for (const auto& caminfo : cs::EnumerateUsbCameras(&status)) {
|
||||
wpi::outs() << caminfo.dev << ": " << caminfo.path << " (" << caminfo.name
|
||||
<< ")\n";
|
||||
fmt::print("{}: {} ({})\n", caminfo.dev, caminfo.path, caminfo.name);
|
||||
if (!caminfo.otherPaths.empty()) {
|
||||
wpi::outs() << "Other device paths:\n";
|
||||
for (auto&& path : caminfo.otherPaths)
|
||||
wpi::outs() << " " << path << '\n';
|
||||
std::puts("Other device paths:");
|
||||
for (auto&& path : caminfo.otherPaths) {
|
||||
fmt::print(" {}\n", path);
|
||||
}
|
||||
}
|
||||
|
||||
cs::UsbCamera camera{"usbcam", caminfo.dev};
|
||||
|
||||
wpi::outs() << "Properties:\n";
|
||||
std::puts("Properties:");
|
||||
for (const auto& prop : camera.EnumerateProperties()) {
|
||||
wpi::outs() << " " << prop.GetName();
|
||||
fmt::print(" {}", prop.GetName());
|
||||
switch (prop.GetKind()) {
|
||||
case cs::VideoProperty::kBoolean:
|
||||
wpi::outs() << " (bool): "
|
||||
<< "value=" << prop.Get()
|
||||
<< " default=" << prop.GetDefault();
|
||||
fmt::print(" (bool): value={} default={}", prop.Get(),
|
||||
prop.GetDefault());
|
||||
break;
|
||||
case cs::VideoProperty::kInteger:
|
||||
wpi::outs() << " (int): "
|
||||
<< "value=" << prop.Get() << " min=" << prop.GetMin()
|
||||
<< " max=" << prop.GetMax() << " step=" << prop.GetStep()
|
||||
<< " default=" << prop.GetDefault();
|
||||
fmt::print(" (int): value={} min={} max={} step={} default={}",
|
||||
prop.Get(), prop.GetMin(), prop.GetMax(), prop.GetStep(),
|
||||
prop.GetDefault());
|
||||
break;
|
||||
case cs::VideoProperty::kString:
|
||||
wpi::outs() << " (string): " << prop.GetString(buf);
|
||||
fmt::print(" (string): {}", prop.GetString());
|
||||
break;
|
||||
case cs::VideoProperty::kEnum: {
|
||||
wpi::outs() << " (enum): "
|
||||
<< "value=" << prop.Get();
|
||||
fmt::print(" (enum): value={}", prop.Get());
|
||||
auto choices = prop.GetChoices();
|
||||
for (size_t i = 0; i < choices.size(); ++i) {
|
||||
if (choices[i].empty()) continue;
|
||||
wpi::outs() << "\n " << i << ": " << choices[i];
|
||||
if (!choices[i].empty()) {
|
||||
fmt::print("\n {}: {}", i, choices[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
wpi::outs() << '\n';
|
||||
std::fputc('\n', stdout);
|
||||
}
|
||||
|
||||
wpi::outs() << "Video Modes:\n";
|
||||
std::puts("Video Modes:");
|
||||
for (const auto& mode : camera.EnumerateVideoModes()) {
|
||||
wpi::outs() << " PixelFormat:";
|
||||
const char* pixelFormat;
|
||||
switch (mode.pixelFormat) {
|
||||
case cs::VideoMode::kMJPEG:
|
||||
wpi::outs() << "MJPEG";
|
||||
pixelFormat = "MJPEG";
|
||||
break;
|
||||
case cs::VideoMode::kYUYV:
|
||||
wpi::outs() << "YUYV";
|
||||
pixelFormat = "YUYV";
|
||||
break;
|
||||
case cs::VideoMode::kRGB565:
|
||||
wpi::outs() << "RGB565";
|
||||
pixelFormat = "RGB565";
|
||||
break;
|
||||
default:
|
||||
wpi::outs() << "Unknown";
|
||||
pixelFormat = "Unknown";
|
||||
break;
|
||||
}
|
||||
wpi::outs() << " Width:" << mode.width;
|
||||
wpi::outs() << " Height:" << mode.height;
|
||||
wpi::outs() << " FPS:" << mode.fps << '\n';
|
||||
fmt::print(" PixelFormat:{} Width:{} Height:{} FPS:{}\n", pixelFormat,
|
||||
mode.width, mode.height, mode.fps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,10 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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 <cstdio>
|
||||
#include <iostream>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <opencv2/core/core.hpp>
|
||||
|
||||
#include "cscore.h"
|
||||
@@ -27,11 +24,11 @@ int main() {
|
||||
for (;;) {
|
||||
uint64_t time = cvsink.GrabFrame(test);
|
||||
if (time == 0) {
|
||||
std::cout << "error: " << cvsink.GetError() << std::endl;
|
||||
fmt::print("error: {}\n", cvsink.GetError());
|
||||
continue;
|
||||
}
|
||||
std::cout << "got frame at time " << time << " size " << test.size()
|
||||
<< std::endl;
|
||||
fmt::print("got frame at time {} size ({}, {})\n", time, test.size().width,
|
||||
test.size().height);
|
||||
cv::flip(test, flip, 0);
|
||||
cvsource.PutFrame(flip);
|
||||
}
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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 <chrono>
|
||||
#include <cstdio>
|
||||
#include <thread>
|
||||
|
||||
#include <wpi/SmallString.h>
|
||||
#include <wpi/raw_ostream.h>
|
||||
#include <fmt/format.h>
|
||||
#include <wpi/StringExtras.h>
|
||||
|
||||
#include "cscore.h"
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
if (argc < 2) {
|
||||
wpi::errs() << "Usage: settings camera [prop val] ... -- [prop val]...\n";
|
||||
wpi::errs() << " Example: settings 1 brightness 30 raw_contrast 10\n";
|
||||
std::fputs("Usage: settings camera [prop val] ... -- [prop val]...\n",
|
||||
stderr);
|
||||
std::fputs(" Example: settings 1 brightness 30 raw_contrast 10\n", stderr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int id;
|
||||
if (wpi::StringRef{argv[1]}.getAsInteger(10, id)) {
|
||||
wpi::errs() << "Expected number for camera\n";
|
||||
if (auto v = wpi::parse_integer<int>(argv[1], 10)) {
|
||||
id = v.value();
|
||||
} else {
|
||||
std::fputs("Expected number for camera\n", stderr);
|
||||
return 2;
|
||||
}
|
||||
|
||||
@@ -30,75 +31,75 @@ int main(int argc, char** argv) {
|
||||
|
||||
// Set prior to connect
|
||||
int arg = 2;
|
||||
wpi::StringRef propName;
|
||||
for (; arg < argc && wpi::StringRef{argv[arg]} != "--"; ++arg) {
|
||||
std::string_view propName;
|
||||
for (; arg < argc && std::string_view{argv[arg]} != "--"; ++arg) {
|
||||
if (propName.empty()) {
|
||||
propName = argv[arg];
|
||||
} else {
|
||||
wpi::StringRef propVal{argv[arg]};
|
||||
int intVal;
|
||||
if (propVal.getAsInteger(10, intVal))
|
||||
std::string_view propVal{argv[arg]};
|
||||
if (auto v = wpi::parse_integer<int>(propVal, 10)) {
|
||||
camera.GetProperty(propName).Set(v.value());
|
||||
} else {
|
||||
camera.GetProperty(propName).SetString(propVal);
|
||||
else
|
||||
camera.GetProperty(propName).Set(intVal);
|
||||
propName = wpi::StringRef{};
|
||||
}
|
||||
propName = {};
|
||||
}
|
||||
}
|
||||
if (arg < argc && wpi::StringRef{argv[arg]} == "--") ++arg;
|
||||
if (arg < argc && std::string_view{argv[arg]} == "--") {
|
||||
++arg;
|
||||
}
|
||||
|
||||
// Wait to connect
|
||||
while (!camera.IsConnected())
|
||||
while (!camera.IsConnected()) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
// Set rest
|
||||
propName = wpi::StringRef{};
|
||||
propName = {};
|
||||
for (; arg < argc; ++arg) {
|
||||
if (propName.empty()) {
|
||||
propName = argv[arg];
|
||||
} else {
|
||||
wpi::StringRef propVal{argv[arg]};
|
||||
int intVal;
|
||||
if (propVal.getAsInteger(10, intVal))
|
||||
std::string_view propVal{argv[arg]};
|
||||
if (auto v = wpi::parse_integer<int>(propVal, 10)) {
|
||||
camera.GetProperty(propName).Set(v.value());
|
||||
} else {
|
||||
camera.GetProperty(propName).SetString(propVal);
|
||||
else
|
||||
camera.GetProperty(propName).Set(intVal);
|
||||
propName = wpi::StringRef{};
|
||||
}
|
||||
propName = {};
|
||||
}
|
||||
}
|
||||
|
||||
// Print settings
|
||||
wpi::SmallString<64> buf;
|
||||
wpi::outs() << "Properties:\n";
|
||||
std::puts("Properties:");
|
||||
for (const auto& prop : camera.EnumerateProperties()) {
|
||||
wpi::outs() << " " << prop.GetName();
|
||||
fmt::print(" {}", prop.GetName());
|
||||
switch (prop.GetKind()) {
|
||||
case cs::VideoProperty::kBoolean:
|
||||
wpi::outs() << " (bool): "
|
||||
<< "value=" << prop.Get()
|
||||
<< " default=" << prop.GetDefault();
|
||||
fmt::print(" (bool): value={} default={}", prop.Get(),
|
||||
prop.GetDefault());
|
||||
break;
|
||||
case cs::VideoProperty::kInteger:
|
||||
wpi::outs() << " (int): "
|
||||
<< "value=" << prop.Get() << " min=" << prop.GetMin()
|
||||
<< " max=" << prop.GetMax() << " step=" << prop.GetStep()
|
||||
<< " default=" << prop.GetDefault();
|
||||
fmt::print(" (int): value={} min={} max={} step={} default={}",
|
||||
prop.Get(), prop.GetMin(), prop.GetMax(), prop.GetStep(),
|
||||
prop.GetDefault());
|
||||
break;
|
||||
case cs::VideoProperty::kString:
|
||||
wpi::outs() << " (string): " << prop.GetString(buf);
|
||||
fmt::print(" (string): {}", prop.GetString());
|
||||
break;
|
||||
case cs::VideoProperty::kEnum: {
|
||||
wpi::outs() << " (enum): "
|
||||
<< "value=" << prop.Get();
|
||||
fmt::print(" (enum): value={}", prop.Get());
|
||||
auto choices = prop.GetChoices();
|
||||
for (size_t i = 0; i < choices.size(); ++i) {
|
||||
if (choices[i].empty()) continue;
|
||||
wpi::outs() << "\n " << i << ": " << choices[i];
|
||||
if (!choices[i].empty()) {
|
||||
fmt::print("\n {}: {}", i, choices[i]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
wpi::outs() << '\n';
|
||||
std::fputc('\n', stdout);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,8 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
// 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 <fmt/core.h>
|
||||
#include <opencv2/core/core.hpp>
|
||||
|
||||
#include "cscore.h"
|
||||
@@ -29,11 +24,11 @@ int main() {
|
||||
for (;;) {
|
||||
uint64_t time = cvsink.GrabFrame(test);
|
||||
if (time == 0) {
|
||||
std::cout << "error: " << cvsink.GetError() << std::endl;
|
||||
fmt::print("error: {}\n", cvsink.GetError());
|
||||
continue;
|
||||
}
|
||||
std::cout << "got frame at time " << time << " size " << test.size()
|
||||
<< std::endl;
|
||||
fmt::print("got frame at time {} size ({}, {})\n", time, test.size().width,
|
||||
test.size().height);
|
||||
cv::flip(test, flip, 0);
|
||||
cvsource.PutFrame(flip);
|
||||
}
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2017-2018 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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 <cstdio>
|
||||
|
||||
#include <wpi/raw_ostream.h>
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "cscore.h"
|
||||
|
||||
int main() {
|
||||
wpi::outs() << "hostname: " << cs::GetHostname() << '\n';
|
||||
wpi::outs() << "IPv4 network addresses:\n";
|
||||
for (const auto& addr : cs::GetNetworkInterfaces())
|
||||
wpi::outs() << " " << addr << '\n';
|
||||
fmt::print("hostname: {}\n", cs::GetHostname());
|
||||
std::puts("IPv4 network addresses:");
|
||||
for (const auto& addr : cs::GetNetworkInterfaces()) {
|
||||
fmt::print(" {}\n", addr);
|
||||
}
|
||||
cs::UsbCamera camera{"usbcam", 0};
|
||||
camera.SetVideoMode(cs::VideoMode::kMJPEG, 320, 240, 30);
|
||||
cs::MjpegServer mjpegServer{"httpserver", 8081};
|
||||
@@ -24,9 +22,8 @@ int main() {
|
||||
CS_Status status = 0;
|
||||
cs::AddListener(
|
||||
[&](const cs::RawEvent& event) {
|
||||
wpi::outs() << "FPS=" << camera.GetActualFPS()
|
||||
<< " MBPS=" << (camera.GetActualDataRate() / 1000000.0)
|
||||
<< '\n';
|
||||
fmt::print("FPS={} MBPS={}\n", camera.GetActualFPS(),
|
||||
(camera.GetActualDataRate() / 1000000.0));
|
||||
},
|
||||
cs::RawEvent::kTelemetryUpdated, false, &status);
|
||||
cs::SetTelemetryPeriod(1.0);
|
||||
|
||||
116
cscore/examples/usbviewer/usbviewer.cpp
Normal file
116
cscore/examples/usbviewer/usbviewer.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
// 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 <atomic>
|
||||
#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/spinlock.h>
|
||||
#include <wpigui.h>
|
||||
|
||||
#include "cscore.h"
|
||||
#include "cscore_cv.h"
|
||||
|
||||
namespace gui = wpi::gui;
|
||||
|
||||
int main() {
|
||||
std::atomic<cv::Mat*> latestFrame{nullptr};
|
||||
std::vector<cv::Mat*> sharedFreeList;
|
||||
wpi::spinlock sharedFreeListMutex;
|
||||
std::vector<cv::Mat*> sourceFreeList;
|
||||
std::atomic<bool> stopCamera{false};
|
||||
|
||||
cs::UsbCamera camera{"usbcam", 0};
|
||||
camera.SetVideoMode(cs::VideoMode::kMJPEG, 640, 480, 30);
|
||||
cs::CvSink cvsink{"cvsink"};
|
||||
cvsink.SetSource(camera);
|
||||
|
||||
std::thread thr([&] {
|
||||
cv::Mat frame;
|
||||
while (!stopCamera) {
|
||||
// get frame from camera
|
||||
uint64_t time = cvsink.GrabFrame(frame);
|
||||
if (time == 0) {
|
||||
fmt::print("error: {}\n", cvsink.GetError());
|
||||
continue;
|
||||
}
|
||||
|
||||
// get or create a mat, prefer sourceFreeList over sharedFreeList
|
||||
cv::Mat* out;
|
||||
if (!sourceFreeList.empty()) {
|
||||
out = sourceFreeList.back();
|
||||
sourceFreeList.pop_back();
|
||||
} else {
|
||||
{
|
||||
std::scoped_lock lock(sharedFreeListMutex);
|
||||
for (auto mat : sharedFreeList) {
|
||||
sourceFreeList.emplace_back(mat);
|
||||
}
|
||||
sharedFreeList.clear();
|
||||
}
|
||||
if (!sourceFreeList.empty()) {
|
||||
out = sourceFreeList.back();
|
||||
sourceFreeList.pop_back();
|
||||
} else {
|
||||
out = new cv::Mat;
|
||||
}
|
||||
}
|
||||
|
||||
// convert to RGBA
|
||||
cv::cvtColor(frame, *out, cv::COLOR_BGR2RGBA);
|
||||
|
||||
// make available
|
||||
auto prev = latestFrame.exchange(out);
|
||||
|
||||
// put prev on free list
|
||||
if (prev) {
|
||||
sourceFreeList.emplace_back(prev);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
gui::CreateContext();
|
||||
gui::Initialize("Hello World", 1024, 768);
|
||||
gui::Texture tex;
|
||||
gui::AddEarlyExecute([&] {
|
||||
auto frame = latestFrame.exchange(nullptr);
|
||||
if (frame) {
|
||||
// create or update texture
|
||||
if (!tex || frame->cols != tex.GetWidth() ||
|
||||
frame->rows != tex.GetHeight()) {
|
||||
tex = gui::Texture(gui::kPixelRGBA, frame->cols, frame->rows,
|
||||
frame->data);
|
||||
} else {
|
||||
tex.Update(frame->data);
|
||||
}
|
||||
// put back on shared freelist
|
||||
std::scoped_lock lock(sharedFreeListMutex);
|
||||
sharedFreeList.emplace_back(frame);
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowSize(ImVec2(640, 480), ImGuiCond_FirstUseEver);
|
||||
if (ImGui::Begin("Video")) {
|
||||
// render to window (best fit)
|
||||
if (tex && tex.GetWidth() != 0 && tex.GetHeight() != 0) {
|
||||
auto drawList = ImGui::GetWindowDrawList();
|
||||
ImVec2 windowPos = ImGui::GetWindowPos();
|
||||
ImVec2 imageMin = ImGui::GetWindowContentRegionMin();
|
||||
ImVec2 imageMax = ImGui::GetWindowContentRegionMax();
|
||||
gui::MaxFit(&imageMin, &imageMax, tex.GetWidth(), tex.GetHeight());
|
||||
drawList->AddImage(tex, windowPos + imageMin, windowPos + imageMax);
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
});
|
||||
gui::Main();
|
||||
stopCamera = true;
|
||||
thr.join();
|
||||
}
|
||||
@@ -1,19 +1,14 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.cscore;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
|
||||
import edu.wpi.cscore.VideoMode.PixelFormat;
|
||||
import edu.wpi.cscore.raw.RawFrame;
|
||||
import java.nio.ByteBuffer;
|
||||
import org.opencv.core.CvType;
|
||||
import org.opencv.core.Mat;
|
||||
|
||||
public class RawCVMatSink extends ImageSink {
|
||||
RawFrame frame = new RawFrame();
|
||||
@@ -27,26 +22,25 @@ public class RawCVMatSink extends ImageSink {
|
||||
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;
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a sink for accepting OpenCV images.
|
||||
* WaitForFrame() must be called on the created sink to get each new
|
||||
* image.
|
||||
* Create a sink for accepting OpenCV images. WaitForFrame() must be called on the created sink to
|
||||
* get each new image.
|
||||
*
|
||||
* @param name Source name (arbitrary unique identifier)
|
||||
*/
|
||||
@@ -55,24 +49,21 @@ public class RawCVMatSink extends ImageSink {
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error
|
||||
* message)
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error message)
|
||||
*/
|
||||
public long grabFrame(Mat image) {
|
||||
return grabFrame(image, 0.225);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* 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.
|
||||
*
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error
|
||||
* message); the frame time is in 1 us increments.
|
||||
* @return Frame time, or 0 on error (call GetError() to obtain the error message); the frame time
|
||||
* is in 1 us increments.
|
||||
*/
|
||||
public long grabFrame(Mat image, double timeout) {
|
||||
frame.setWidth(0);
|
||||
@@ -83,12 +74,20 @@ public class RawCVMatSink extends ImageSink {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (frame.getDataByteBuffer() != origByteBuffer || width != frame.getWidth() || height != frame.getHeight() || pixelFormat != frame.getPixelFormat()) {
|
||||
if (frame.getDataByteBuffer() != origByteBuffer
|
||||
|| width != frame.getWidth()
|
||||
|| height != frame.getHeight()
|
||||
|| pixelFormat != frame.getPixelFormat()) {
|
||||
origByteBuffer = frame.getDataByteBuffer();
|
||||
height = frame.getHeight();
|
||||
width = frame.getWidth();
|
||||
pixelFormat = frame.getPixelFormat();
|
||||
tmpMat = new Mat(frame.getHeight(), frame.getWidth(), getCVFormat(VideoMode.getPixelFormatFromInt(pixelFormat)), origByteBuffer);
|
||||
tmpMat =
|
||||
new Mat(
|
||||
frame.getHeight(),
|
||||
frame.getWidth(),
|
||||
getCVFormat(VideoMode.getPixelFormatFromInt(pixelFormat)),
|
||||
origByteBuffer);
|
||||
}
|
||||
tmpMat.copyTo(image);
|
||||
return rv;
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2018-2019 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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.cscore;
|
||||
|
||||
import org.opencv.core.Mat;
|
||||
|
||||
import edu.wpi.cscore.VideoMode.PixelFormat;
|
||||
import org.opencv.core.Mat;
|
||||
|
||||
public class RawCVMatSource extends ImageSource {
|
||||
/**
|
||||
@@ -19,11 +15,9 @@ public class RawCVMatSource extends ImageSource {
|
||||
* @param mode Video mode being generated
|
||||
*/
|
||||
public RawCVMatSource(String name, VideoMode mode) {
|
||||
super(CameraServerJNI.createRawSource(name,
|
||||
mode.pixelFormat.getValue(),
|
||||
mode.width,
|
||||
mode.height,
|
||||
mode.fps));
|
||||
super(
|
||||
CameraServerJNI.createRawSource(
|
||||
name, mode.pixelFormat.getValue(), mode.width, mode.height, mode.fps));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -35,16 +29,17 @@ public class RawCVMatSource extends ImageSource {
|
||||
* @param height height
|
||||
* @param fps fps
|
||||
*/
|
||||
public RawCVMatSource(String name, VideoMode.PixelFormat pixelFormat, int width, int height, int fps) {
|
||||
public RawCVMatSource(
|
||||
String name, VideoMode.PixelFormat pixelFormat, int width, int height, int fps) {
|
||||
super(CameraServerJNI.createRawSource(name, pixelFormat.getValue(), width, height, fps));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>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.
|
||||
*
|
||||
* @param image OpenCV image
|
||||
*/
|
||||
@@ -54,6 +49,12 @@ public class RawCVMatSource extends ImageSource {
|
||||
throw new VideoException("Unsupported Image Type");
|
||||
}
|
||||
int imgType = channels == 1 ? PixelFormat.kGray.getValue() : PixelFormat.kBGR.getValue();
|
||||
CameraServerJNI.putRawSourceFrame(m_handle, image.dataAddr(), image.width(), image.height(), imgType, (int)image.total() * channels);
|
||||
CameraServerJNI.putRawSourceFrame(
|
||||
m_handle,
|
||||
image.dataAddr(),
|
||||
image.width(),
|
||||
image.height(),
|
||||
imgType,
|
||||
(int) image.total() * channels);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
|
||||
package edu.wpi.cscore;
|
||||
|
||||
import edu.wpi.first.wpiutil.RuntimeDetector;
|
||||
|
||||
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(CameraServerJNI.getHostname());
|
||||
}
|
||||
|
||||
private DevMain() {
|
||||
}
|
||||
}
|
||||
18
cscore/src/dev/java/edu/wpi/first/cscore/DevMain.java
Normal file
18
cscore/src/dev/java/edu/wpi/first/cscore/DevMain.java
Normal file
@@ -0,0 +1,18 @@
|
||||
// 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.RuntimeDetector;
|
||||
|
||||
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(CameraServerJNI.getHostname());
|
||||
}
|
||||
|
||||
private DevMain() {}
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
/*----------------------------------------------------------------------------*/
|
||||
/* Copyright (c) 2017-2019 FIRST. All Rights Reserved. */
|
||||
/* Open Source Software - may be modified and shared by FRC teams. The code */
|
||||
/* must be accompanied by the FIRST BSD license file in the root directory of */
|
||||
/* the project. */
|
||||
/*----------------------------------------------------------------------------*/
|
||||
// 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 <iostream>
|
||||
#include <fmt/core.h>
|
||||
|
||||
#include "cscore.h"
|
||||
|
||||
int main() { std::cout << cs::GetHostname() << std::endl; }
|
||||
int main() {
|
||||
fmt::print("{}\n", cs::GetHostname());
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user