Compare commits
1183 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
849a3b7329 | |
|
|
b842f4a8ed | |
|
|
6fc48a8cef | |
|
|
2e83305229 | |
|
|
d0e87cc219 | |
|
|
ac7b5759f7 | |
|
|
350664a13a | |
|
|
f24c932cf8 | |
|
|
c35135cabf | |
|
|
86885c2480 | |
|
|
3be128877d | |
|
|
a13356d801 | |
|
|
855f71918e | |
|
|
f5185cbebe | |
|
|
765b295479 | |
|
|
778d85e75f | |
|
|
fb959f0fc7 | |
|
|
fec0da4f0b | |
|
|
52cdd32d0f | |
|
|
4601566886 | |
|
|
23f5dfef2c | |
|
|
42a5c2a978 | |
|
|
65cd5fe441 | |
|
|
f932baa5fa | |
|
|
fa8a066b4c | |
|
|
b645f7d4f2 | |
|
|
bc72177c8b | |
|
|
24c0248fc0 | |
|
|
cdbd6c77a9 | |
|
|
9b2cd0a5ba | |
|
|
059e48b82b | |
|
|
5f7e7cf8e0 | |
|
|
752a7aeac0 | |
|
|
08c7ccbc8e | |
|
|
9788588aba | |
|
|
8b9dd42676 | |
|
|
14e6d5c3fa | |
|
|
e8eeac4654 | |
|
|
abf8fa2b00 | |
|
|
06bc3c34cf | |
|
|
88fec00f17 | |
|
|
ae042eeb27 | |
|
|
f45b2c6475 | |
|
|
2ba2f4da71 | |
|
|
29a6ae5102 | |
|
|
0aac23e049 | |
|
|
ef70374126 | |
|
|
7d552a2ede | |
|
|
8b0e8ce6e3 | |
|
|
e02d0d5ffa | |
|
|
871a7e685f | |
|
|
dd53b36bdf | |
|
|
26924e4efe | |
|
|
6785c56348 | |
|
|
21d1fe0f11 | |
|
|
3367cc5a82 | |
|
|
fe36349083 | |
|
|
e0f794b1a5 | |
|
|
95ab1c0faa | |
|
|
fab8081322 | |
|
|
9d4e2230d2 | |
|
|
825f959e4d | |
|
|
c148fdca84 | |
|
|
9f146fcb71 | |
|
|
cdc818a9f3 | |
|
|
e3a8e00412 | |
|
|
6b8cac3922 | |
|
|
899ee2530c | |
|
|
d6405ddefd | |
|
|
e058929977 | |
|
|
7b1771cdad | |
|
|
017e5d391b | |
|
|
5bd1718bb2 | |
|
|
f3e498a62a | |
|
|
d4b3b03fe0 | |
|
|
ec69b94544 | |
|
|
3069f3d99f | |
|
|
4cf8eb254e | |
|
|
be3c9930f1 | |
|
|
e0f7a33df4 | |
|
|
9e671a14e4 | |
|
|
4e21610c50 | |
|
|
603da245bd | |
|
|
6e5f2595e0 | |
|
|
2480e5169c | |
|
|
1cb4284e6c | |
|
|
ac97423249 | |
|
|
fd8f2d77e1 | |
|
|
b3172181d5 | |
|
|
56625449e8 | |
|
|
b775f2b326 | |
|
|
8d877eeed8 | |
|
|
88741d097b | |
|
|
24c425c968 | |
|
|
acde5b4a91 | |
|
|
f7b6f7aefc | |
|
|
a4cd5bb42d | |
|
|
465d436174 | |
|
|
223283863f | |
|
|
b4acf08738 | |
|
|
265055106b | |
|
|
80acb91dbc | |
|
|
3d013c4251 | |
|
|
86bb40a31c | |
|
|
8dd83d2e7e | |
|
|
c433463392 | |
|
|
455896e86d | |
|
|
037fe4f37f | |
|
|
c97b83d3ed | |
|
|
462dee56f3 | |
|
|
d3c692f630 | |
|
|
f862b530c8 | |
|
|
740d73ac71 | |
|
|
2a62c514f1 | |
|
|
fe91fbc3a4 | |
|
|
bd3ec0cbdc | |
|
|
988489fae1 | |
|
|
63df5a262d | |
|
|
e7f9401722 | |
|
|
f9e252c110 | |
|
|
e7d39c9abb | |
|
|
2c47717360 | |
|
|
047c193da6 | |
|
|
bd43fec71e | |
|
|
cb25eb2cb8 | |
|
|
f36a0c6d38 | |
|
|
9c2531a98d | |
|
|
db53a09dbf | |
|
|
9c67290562 | |
|
|
005e3db2ba | |
|
|
1653ce9ca2 | |
|
|
a75296ae72 | |
|
|
1c7db21349 | |
|
|
a135d2b915 | |
|
|
29d6569ee3 | |
|
|
d90426e1ce | |
|
|
408a3e617a | |
|
|
a59af7385c | |
|
|
5db6efd62d | |
|
|
77ab9f04ba | |
|
|
e8fe48485e | |
|
|
e23cd7e73b | |
|
|
74b1a39aa0 | |
|
|
9f07a81dfa | |
|
|
ff7aafe0bb | |
|
|
c23438a5cf | |
|
|
b84f427732 | |
|
|
3773acf4c0 | |
|
|
e111303b1e | |
|
|
45e13b20ba | |
|
|
22d21cd013 | |
|
|
3324f072cd | |
|
|
5a33b4ee8f | |
|
|
d8d5f2a117 | |
|
|
33bb2d929b | |
|
|
d1f6d02e9a | |
|
|
c4e346698e | |
|
|
4eab12497e | |
|
|
b7205e2e64 | |
|
|
c421c31152 | |
|
|
132702cfa7 | |
|
|
40c24b1c55 | |
|
|
5600d3fc71 | |
|
|
fa80e7c917 | |
|
|
270c629515 | |
|
|
8c892973be | |
|
|
d5184efa6e | |
|
|
c2e1c1f6d5 | |
|
|
2308c1d196 | |
|
|
d8cca659e7 | |
|
|
4ad6c7b4d3 | |
|
|
1b0bcefae6 | |
|
|
1b1f9de119 | |
|
|
0aedcffc5b | |
|
|
2e59e8f1d6 | |
|
|
d1fc00a273 | |
|
|
6a11387861 | |
|
|
11fb727325 | |
|
|
5782ad7468 | |
|
|
fdc1ac731d | |
|
|
2c7b331352 | |
|
|
f1c576b657 | |
|
|
490b5ce36f | |
|
|
ab7aa856bc | |
|
|
5e8be14f2e | |
|
|
2ea75a345d | |
|
|
1eab1fc04b | |
|
|
dbdf18dcc0 | |
|
|
3eb2783cdf | |
|
|
c06c697e26 | |
|
|
bff71dc820 | |
|
|
c7675b3cd1 | |
|
|
b3fcf82473 | |
|
|
e8adeb3414 | |
|
|
8c325e04a0 | |
|
|
3577cb4057 | |
|
|
9950e72d1a | |
|
|
8f9abe57be | |
|
|
930d2534a2 | |
|
|
22e02dbc62 | |
|
|
af4951a494 | |
|
|
ea5a2b8740 | |
|
|
a0dc843842 | |
|
|
16b3d12670 | |
|
|
829fe1b5e2 | |
|
|
47e4df2b7b | |
|
|
1916fc6648 | |
|
|
ad56c1363b | |
|
|
9b85a30c91 | |
|
|
cd6d3a373b | |
|
|
c466a4724f | |
|
|
e2b2ce3f63 | |
|
|
d3459b1697 | |
|
|
0fddde5126 | |
|
|
f4f2f3ddad | |
|
|
c1eeda612e | |
|
|
5c043e8496 | |
|
|
e48006311b | |
|
|
f0055c978d | |
|
|
66f26846b8 | |
|
|
9fb1e5b9e8 | |
|
|
4cde98e063 | |
|
|
c3cd1ec0de | |
|
|
016cb8f9d2 | |
|
|
dc2f47796c | |
|
|
e00935c8d2 | |
|
|
68e95c06cc | |
|
|
4f5f637dc1 | |
|
|
863694761a | |
|
|
3167459bfc | |
|
|
398728439b | |
|
|
be9174a352 | |
|
|
ff190286a6 | |
|
|
14ccaa93bd | |
|
|
774c3cdd55 | |
|
|
24e58762b5 | |
|
|
6714148c45 | |
|
|
6a4a239d0f | |
|
|
418e13e6b6 | |
|
|
303dcc9915 | |
|
|
7356676c5b | |
|
|
9b06099971 | |
|
|
da3e9766de | |
|
|
ec90edcd8d | |
|
|
bc9336e0be | |
|
|
917aa6a0e2 | |
|
|
c89930b4b9 | |
|
|
992f036fc2 | |
|
|
d25103361a | |
|
|
ee552eb058 | |
|
|
1dbb8ab234 | |
|
|
fba10d3262 | |
|
|
798c0a3fa5 | |
|
|
1d3e5c03e9 | |
|
|
ddce32849d | |
|
|
1d04174f37 | |
|
|
e00d12f817 | |
|
|
10b9bc6614 | |
|
|
9237086b38 | |
|
|
da3557fcfe | |
|
|
d353568c59 | |
|
|
a0b0038df7 | |
|
|
af1f4f84a9 | |
|
|
286a6301f8 | |
|
|
74e11bd26f | |
|
|
c3017cc0a4 | |
|
|
799b568dfb | |
|
|
1174841f71 | |
|
|
5a30efb137 | |
|
|
c8d96acbdc | |
|
|
48af886e46 | |
|
|
efb4c1f60f | |
|
|
6dc0741481 | |
|
|
84dd2dfe0e | |
|
|
ce521f715a | |
|
|
ce5cf89e60 | |
|
|
2fa793d0d7 | |
|
|
f1bd1a5829 | |
|
|
653ad6127a | |
|
|
d5d04060de | |
|
|
1761b8ddc1 | |
|
|
e857d042aa | |
|
|
c1f526b76d | |
|
|
74607b31ed | |
|
|
aa2929196d | |
|
|
104575c602 | |
|
|
89a83767f3 | |
|
|
8b21104d66 | |
|
|
f82b7b7a8c | |
|
|
01587a114a | |
|
|
e8b5be519c | |
|
|
8734ec9992 | |
|
|
bf8d6db148 | |
|
|
84b1975e76 | |
|
|
d59e3bb136 | |
|
|
5db1f1e9ba | |
|
|
64abbd02db | |
|
|
84c2d67601 | |
|
|
26e3c23e6a | |
|
|
9520740a12 | |
|
|
b70898cd27 | |
|
|
66ba823493 | |
|
|
6a9700a58c | |
|
|
238bb2bb5d | |
|
|
8b6239fab7 | |
|
|
699576f3de | |
|
|
9b79daadaf | |
|
|
5261b98c95 | |
|
|
49d95744f2 | |
|
|
8d56c0af9d | |
|
|
c890bb6125 | |
|
|
5b964f67b8 | |
|
|
92889d3497 | |
|
|
bb158d929c | |
|
|
95ae1a92be | |
|
|
c32ed2866e | |
|
|
da1aeeeea6 | |
|
|
eb476d2e75 | |
|
|
7267d8aff9 | |
|
|
f314e20342 | |
|
|
53183c0b2a | |
|
|
c89e3b9e9e | |
|
|
f2f19d49fb | |
|
|
0dae3e4b4a | |
|
|
74ef2e92bd | |
|
|
bce7e35e0e | |
|
|
0df937e9c6 | |
|
|
ae12414eed | |
|
|
d3658b9fe6 | |
|
|
ba8f3e6af0 | |
|
|
651d6a4e0d | |
|
|
0793c64ee8 | |
|
|
79c9877232 | |
|
|
8879bcac86 | |
|
|
0ff1275bf9 | |
|
|
f1507d8f2e | |
|
|
258e3f9d65 | |
|
|
8ba24e8c3b | |
|
|
eb1d42e47a | |
|
|
2f9c3fe0e1 | |
|
|
52338202d1 | |
|
|
b6f007a104 | |
|
|
d6b8065c3b | |
|
|
4241a9f1a0 | |
|
|
aa8f3b3c27 | |
|
|
2efbf20177 | |
|
|
a273f72246 | |
|
|
bfc45dc81d | |
|
|
888e7de16d | |
|
|
f13b96dc6b | |
|
|
8bb95e9956 | |
|
|
08a326eb7c | |
|
|
c71c39b0d7 | |
|
|
263e03f7c2 | |
|
|
9406fa7a2e | |
|
|
070bc9f23c | |
|
|
e5a87e91b7 | |
|
|
dfbe32559e | |
|
|
439f615552 | |
|
|
c3541bcbea | |
|
|
940c8e47ea | |
|
|
81e6f680ee | |
|
|
1223f7f29a | |
|
|
d471249f17 | |
|
|
886b0d3f81 | |
|
|
404ac5dced | |
|
|
0f0696c97b | |
|
|
4a21198081 | |
|
|
f45e657583 | |
|
|
497776c642 | |
|
|
0878bd2ddc | |
|
|
1a0ba50c4a | |
|
|
201cb2f466 | |
|
|
105ec2098c | |
|
|
aa59af32aa | |
|
|
21743b03b7 | |
|
|
f7123c41e5 | |
|
|
ae29613d85 | |
|
|
a224f6f783 | |
|
|
fb110802d6 | |
|
|
59170cbacb | |
|
|
4ab1938f97 | |
|
|
c853db67d0 | |
|
|
f868e4c010 | |
|
|
ea9f81c605 | |
|
|
19327926f1 | |
|
|
b2e9153653 | |
|
|
a8737f7916 | |
|
|
8ffa43b65c | |
|
|
54409b4836 | |
|
|
dfc588335a | |
|
|
54f2c54d8f | |
|
|
9500a2f2f7 | |
|
|
429e34db21 | |
|
|
ce89cd08d9 | |
|
|
dda442c121 | |
|
|
3c76eeb51c | |
|
|
620cb3a720 | |
|
|
a11576710d | |
|
|
f1fef5b8fc | |
|
|
36ae24838f | |
|
|
f67a31823b | |
|
|
aa2b205481 | |
|
|
af786e6e85 | |
|
|
ffff5d6646 | |
|
|
089684e20f | |
|
|
25b3a34fff | |
|
|
ae4a89b707 | |
|
|
dabb6fc135 | |
|
|
0ba4ba3fd7 | |
|
|
0a0fb46b5d | |
|
|
1d29f5e059 | |
|
|
18d47fd5ff | |
|
|
4edb2e8e35 | |
|
|
a1a7d42e90 | |
|
|
e2761fc21d | |
|
|
6a0df00e2d | |
|
|
d0094d5abd | |
|
|
35299c47ba | |
|
|
0d2bd6ae34 | |
|
|
1ecc925ed5 | |
|
|
d9a78636a6 | |
|
|
9cef820dfc | |
|
|
f1cb09d0e3 | |
|
|
207ca0c401 | |
|
|
76ab0a7ebe | |
|
|
b01f42097d | |
|
|
5cc04d4ca8 | |
|
|
de6d671ba4 | |
|
|
f4537bd49a | |
|
|
ef125bd5f0 | |
|
|
e444d2eb5c | |
|
|
a0bd957274 | |
|
|
fa65517ada | |
|
|
64236c55d8 | |
|
|
40614778bc | |
|
|
17f1054dff | |
|
|
7c57d8095b | |
|
|
e30b3e87f5 | |
|
|
68ca0dc800 | |
|
|
01b07ec50a | |
|
|
16f1d450ae | |
|
|
930e158208 | |
|
|
61f483c3e7 | |
|
|
39aeb7a48c | |
|
|
5eb0bd10ea | |
|
|
f968fea390 | |
|
|
d5741bf8c8 | |
|
|
c9bea6a21c | |
|
|
27f41c178f | |
|
|
b8fb5e5fe5 | |
|
|
0306c7edfd | |
|
|
564f033087 | |
|
|
d33b1160f2 | |
|
|
1b5b0dfa03 | |
|
|
74d7ead41b | |
|
|
d575cc0d00 | |
|
|
b84fffc443 | |
|
|
f573b843c3 | |
|
|
da41d820f6 | |
|
|
e419719731 | |
|
|
19f26968c7 | |
|
|
34bfe10317 | |
|
|
f13f8dfce8 | |
|
|
4d683ac50c | |
|
|
857c56ca7b | |
|
|
0f23e514c6 | |
|
|
a24718feca | |
|
|
37e49906d1 | |
|
|
d54c452683 | |
|
|
82c5ff6724 | |
|
|
b281ceee7b | |
|
|
d6bafd64a2 | |
|
|
f497d7481f | |
|
|
a2480a2769 | |
|
|
8a6261d7c2 | |
|
|
91e9635563 | |
|
|
883399cee3 | |
|
|
0f2215c2ce | |
|
|
91f3c3ce67 | |
|
|
a654c60d65 | |
|
|
18c0758a67 | |
|
|
77c8f9aafa | |
|
|
f46640a5c2 | |
|
|
56aa2f7d1e | |
|
|
45886edc40 | |
|
|
14c458db8c | |
|
|
9136766b9c | |
|
|
719e004c7a | |
|
|
d66a05b019 | |
|
|
0946d5165d | |
|
|
9dfc3e7aa6 | |
|
|
47e43778a6 | |
|
|
28e7ccca8e | |
|
|
10cfc13c3a | |
|
|
bd50f5d689 | |
|
|
324491b0e6 | |
|
|
6abcebd0e4 | |
|
|
f04a71640a | |
|
|
671aac5f50 | |
|
|
c05aea65a4 | |
|
|
9c124b3f2b | |
|
|
983829bff6 | |
|
|
bd14c822e3 | |
|
|
9063761dd1 | |
|
|
c8501cb41c | |
|
|
3c02e8419d | |
|
|
b327848d75 | |
|
|
cdba7566fd | |
|
|
2a7a1e16f6 | |
|
|
d0cfbdf3cf | |
|
|
8829b65ab2 | |
|
|
f4692a3784 | |
|
|
e2c8d361f8 | |
|
|
7d17d8e1ff | |
|
|
ed23dbd6db | |
|
|
e31bee1909 | |
|
|
8eeb29ec32 | |
|
|
8985b5ab86 | |
|
|
bf05a94f3e | |
|
|
4fbb336fa3 | |
|
|
43fedd9c6d | |
|
|
e0bb6e11e7 | |
|
|
7d61b2aaab | |
|
|
7bb2cfe01f | |
|
|
65f44d99bf | |
|
|
963cb1aefb | |
|
|
71f2c99e96 | |
|
|
540e5f8e95 | |
|
|
3ec6ec1a9d | |
|
|
974e962a55 | |
|
|
ea7a2c1c09 | |
|
|
12151ed8f5 | |
|
|
6af6ff7c2b | |
|
|
01a4477c92 | |
|
|
0983766a6c | |
|
|
3298eb77b4 | |
|
|
3e4012e958 | |
|
|
20a16d50bd | |
|
|
41fa394278 | |
|
|
6c055c8c23 | |
|
|
2b00c05465 | |
|
|
1caabc5ad8 | |
|
|
b82922e81c | |
|
|
d3448b0efb | |
|
|
dfdee153ef | |
|
|
655d311a37 | |
|
|
fffd3c9913 | |
|
|
39b008472f | |
|
|
6e7c32bde0 | |
|
|
f81044cc01 | |
|
|
9101d5017d | |
|
|
60c762c843 | |
|
|
3340e6315c | |
|
|
fcbf32dc49 | |
|
|
f4fa94f842 | |
|
|
c9997a783f | |
|
|
c9e729a48a | |
|
|
084acd2951 | |
|
|
9efd6b3470 | |
|
|
7749316540 | |
|
|
d5eccc30a4 | |
|
|
0b9f7e4cef | |
|
|
d267d2257a | |
|
|
213d769bf9 | |
|
|
d8f568e0ce | |
|
|
0608e31965 | |
|
|
a8fe04f856 | |
|
|
5a9350a6a1 | |
|
|
94824fbb98 | |
|
|
04b940d45b | |
|
|
f323745ead | |
|
|
abfb88b124 | |
|
|
5cdf9157db | |
|
|
f1036702ce | |
|
|
a256833e17 | |
|
|
7059c0f64a | |
|
|
aa78020410 | |
|
|
286d8e7a10 | |
|
|
d6c0612767 | |
|
|
1d5db2fd76 | |
|
|
44e8913c2d | |
|
|
daebc372a9 | |
|
|
0c3671429b | |
|
|
2ce2af1685 | |
|
|
571ea7ac41 | |
|
|
63d1b4b553 | |
|
|
a947163dee | |
|
|
ea1e9c336b | |
|
|
079061df3c | |
|
|
161d2d8ded | |
|
|
6986b3847f | |
|
|
232a64e5fd | |
|
|
d62f4c2ff5 | |
|
|
a125155074 | |
|
|
a38acc3dff | |
|
|
ee7d879130 | |
|
|
20c3c4b597 | |
|
|
3e207b5379 | |
|
|
220bbf5057 | |
|
|
51e3e1d677 | |
|
|
14bbf09230 | |
|
|
74c9cb564c | |
|
|
567600889f | |
|
|
43b0f5a75a | |
|
|
18b455fbf0 | |
|
|
196ef89aca | |
|
|
417aee9dc5 | |
|
|
a3cdd47d80 | |
|
|
634d806686 | |
|
|
4baae970ae | |
|
|
c6d7f1ec6f | |
|
|
2f53b57278 | |
|
|
f45a7d61a5 | |
|
|
8a52108d77 | |
|
|
382554a250 | |
|
|
e3c8c91852 | |
|
|
17c8265ce8 | |
|
|
c7855c5ab6 | |
|
|
1ec32903ba | |
|
|
05e9601903 | |
|
|
27b0e9c40f | |
|
|
2142d2edf5 | |
|
|
98d64483d6 | |
|
|
2e0aba4f1f | |
|
|
80eca0ff9a | |
|
|
d225b9bc3f | |
|
|
0d7177fe9a | |
|
|
bd96af9827 | |
|
|
f1192e9414 | |
|
|
fbb87b909f | |
|
|
02b9e635b5 | |
|
|
c404e33198 | |
|
|
5ba613dd44 | |
|
|
06cdc5071b | |
|
|
0aa1822262 | |
|
|
9486c14842 | |
|
|
0c5472043e | |
|
|
d790600a86 | |
|
|
84383e2209 | |
|
|
17c3a3fb6b | |
|
|
f6dfe2616f | |
|
|
87689cf6eb | |
|
|
cfcb329a2f | |
|
|
9621cadbd3 | |
|
|
f23bdb21f6 | |
|
|
3987cd59bc | |
|
|
630136a1eb | |
|
|
effca83150 | |
|
|
3a819a5aeb | |
|
|
e0e09ed3a4 | |
|
|
fddb2298ee | |
|
|
09f6bed7c0 | |
|
|
0722edc2bc | |
|
|
d40e69ee42 | |
|
|
2e6b4eb4b6 | |
|
|
b929821fe8 | |
|
|
484765a119 | |
|
|
888c939a75 | |
|
|
aa5885b6df | |
|
|
7700cd90d3 | |
|
|
0a6dc372ad | |
|
|
44129dca12 | |
|
|
2a8d6db055 | |
|
|
417cda7061 | |
|
|
8a41bcb730 | |
|
|
bad821f5de | |
|
|
cf9e3005e8 | |
|
|
234beb0bc4 | |
|
|
5d781785aa | |
|
|
bc2415bc5d | |
|
|
cc92afd4f0 | |
|
|
0511d6fd3a | |
|
|
0e1e5df326 | |
|
|
06ab0502fe | |
|
|
773668f510 | |
|
|
973182c75e | |
|
|
908d794238 | |
|
|
c34b1c38fb | |
|
|
fbf8af2236 | |
|
|
75b221c0e3 | |
|
|
bfc4b742af | |
|
|
b1149f344d | |
|
|
b1a1771bb0 | |
|
|
ee23816428 | |
|
|
9d3f3bdf84 | |
|
|
bee850061e | |
|
|
6b699bffc3 | |
|
|
6d4300848f | |
|
|
d332f477b8 | |
|
|
d6898dbc49 | |
|
|
cde047aac3 | |
|
|
a7be17a5d7 | |
|
|
4cbb1ab437 | |
|
|
e4a94aa574 | |
|
|
bbfdd45cc3 | |
|
|
8b9f984a54 | |
|
|
71b9b659d0 | |
|
|
0afe1441de | |
|
|
ac9249b293 | |
|
|
e2fcc58bf2 | |
|
|
8228050ca4 | |
|
|
924bcaa044 | |
|
|
c2c43b9f6b | |
|
|
e5fcd4035f | |
|
|
cf6fcdce6a | |
|
|
cc75121d37 | |
|
|
6c86d4f276 | |
|
|
b0dc4f8a4f | |
|
|
a0c11c4156 | |
|
|
72e786af35 | |
|
|
58e227897b | |
|
|
9c935d95a5 | |
|
|
298525adc9 | |
|
|
382b28767c | |
|
|
814b4109f5 | |
|
|
f2872d6c15 | |
|
|
1f0e75bce1 | |
|
|
52464b97c1 | |
|
|
64fd61cffc | |
|
|
6336611bc7 | |
|
|
cbdfd9dc5d | |
|
|
34aeb29347 | |
|
|
0526388bdc | |
|
|
11b6cdba06 | |
|
|
4517055320 | |
|
|
4bb070be50 | |
|
|
5063efe064 | |
|
|
32231cf142 | |
|
|
5ef2612bb4 | |
|
|
cc47718a2d | |
|
|
8182dc9a8f | |
|
|
8f1663cb98 | |
|
|
14748b1e8f | |
|
|
a4cf02a728 | |
|
|
fe60f982cc | |
|
|
c294ac1327 | |
|
|
8f3b7c8fde | |
|
|
78f88c6f8a | |
|
|
74ca8b838b | |
|
|
d3fad32d5e | |
|
|
2b47fe5b68 | |
|
|
4cb17c194c | |
|
|
f6b1b94c7d | |
|
|
25ea6d398b | |
|
|
60f1f3bcb6 | |
|
|
10b5cde505 | |
|
|
85d3ecee62 | |
|
|
eece2a54a0 | |
|
|
edb1eaeee2 | |
|
|
344415b91f | |
|
|
52fe01c860 | |
|
|
617a71e36b | |
|
|
dda5411882 | |
|
|
7cd66c36d2 | |
|
|
f6075212f4 | |
|
|
5d681f4819 | |
|
|
812e4486a4 | |
|
|
197fb2625a | |
|
|
6f2e4fa891 | |
|
|
0c71b3db27 | |
|
|
14a003710e | |
|
|
2bcd0741c9 | |
|
|
c144507471 | |
|
|
802f1f9404 | |
|
|
cfb02c1a7c | |
|
|
abc30ff656 | |
|
|
c56245a954 | |
|
|
36e7ec4cd8 | |
|
|
b38061c3c4 | |
|
|
d4e1300b1f | |
|
|
32c8358bc1 | |
|
|
2a2c1a805e | |
|
|
662c19568e | |
|
|
6e4eb4b35c | |
|
|
73a3b5113e | |
|
|
bef563b8a3 | |
|
|
b213ab9a50 | |
|
|
daa3e00ade | |
|
|
2a708ef848 | |
|
|
b2375468cb | |
|
|
df9648911e | |
|
|
4eb8e3d96a | |
|
|
bfa70415a3 | |
|
|
4839372642 | |
|
|
2843f85ed6 | |
|
|
9bba9ce579 | |
|
|
227dce4af0 | |
|
|
fa17c472e7 | |
|
|
efc47651e7 | |
|
|
2a4ee685a2 | |
|
|
729d91c1ab | |
|
|
7c1fed98d2 | |
|
|
7e003097a0 | |
|
|
fb454c0a10 | |
|
|
92136f3807 | |
|
|
001f4956ea | |
|
|
9653d365db | |
|
|
5b8a943cee | |
|
|
5445ce143c | |
|
|
46f0c15471 | |
|
|
d0f9b870cd | |
|
|
f8a2896e76 | |
|
|
5fca9eed4b | |
|
|
77ae0387ea | |
|
|
ad39d1b90c | |
|
|
4989111f67 | |
|
|
69031408f3 | |
|
|
d1790cd411 | |
|
|
b59d0b6bcb | |
|
|
256049f93a | |
|
|
394b4d586e | |
|
|
809fcd9c59 | |
|
|
51b1851778 | |
|
|
7dee192157 | |
|
|
d3d0912f03 | |
|
|
c0de65fe21 | |
|
|
b260e1341e | |
|
|
50a606d23f | |
|
|
4dacb291ab | |
|
|
8441cf7d90 | |
|
|
0ae2c5efc8 | |
|
|
8d8443f3dc | |
|
|
2a4aa29f03 | |
|
|
10641303cb | |
|
|
9e179d46bf | |
|
|
b827806ce8 | |
|
|
f1428530c3 | |
|
|
20951fd23b | |
|
|
6934c0dbcc | |
|
|
2245aab7d1 | |
|
|
08e0bd28f6 | |
|
|
976302e3ca | |
|
|
647319d141 | |
|
|
e784b529a8 | |
|
|
ac2b977168 | |
|
|
8e8b8588bf | |
|
|
d75cc94e40 | |
|
|
65a0f7f963 | |
|
|
9b0d40fd4f | |
|
|
2a3e4a0a0d | |
|
|
f45430e3b5 | |
|
|
2f12447fda | |
|
|
aa916439e4 | |
|
|
d1a33f4655 | |
|
|
1ce66eb884 | |
|
|
83874f32ee | |
|
|
e5912c322f | |
|
|
5b4ad4d8d9 | |
|
|
15c66a379a | |
|
|
1958b23a93 | |
|
|
2636353e4a | |
|
|
4ddb129b5e | |
|
|
f9419f13d5 | |
|
|
a1fdc07db2 | |
|
|
cd8b48c282 | |
|
|
ffd661be84 | |
|
|
6199003fa1 | |
|
|
303d3c3fef | |
|
|
e5902f2820 | |
|
|
bf1d1280ec | |
|
|
6934b8899a | |
|
|
ab8cc6be58 | |
|
|
7363152b93 | |
|
|
f2ea5a75bb | |
|
|
a37c75bf83 | |
|
|
5de3bffcfa | |
|
|
d5bd164169 | |
|
|
3588a47058 | |
|
|
6accc36fd2 | |
|
|
d5293cc0ed | |
|
|
e13b09f1a4 | |
|
|
d7f7ffa70a | |
|
|
b04aec0ea1 | |
|
|
413441e36d | |
|
|
7541d89533 | |
|
|
5e786e6cad | |
|
|
d17f027035 | |
|
|
08fba4e3b0 | |
|
|
3e08de91ed | |
|
|
fa91b24ffa | |
|
|
08887642ea | |
|
|
954034855a | |
|
|
244ea9851d | |
|
|
4d47ada055 | |
|
|
4c79319145 | |
|
|
158a8298fc | |
|
|
ca57fb27f0 | |
|
|
54ca2c7fb2 | |
|
|
f152bf633e | |
|
|
812de53ec1 | |
|
|
36a5c16dd2 | |
|
|
8b8f8d7a40 | |
|
|
08ffda1aa8 | |
|
|
08c14484cd | |
|
|
a910454c02 | |
|
|
308b928f8c | |
|
|
43906f994b | |
|
|
568e843b9f | |
|
|
8d998b2525 | |
|
|
5290b58940 | |
|
|
55bad33718 | |
|
|
6b2c238a54 | |
|
|
e243a2bf1a | |
|
|
4cc3fe4515 | |
|
|
a2ca647062 | |
|
|
70e86384f0 | |
|
|
96fe1e0ee5 | |
|
|
c99375d51c | |
|
|
2215a98a08 | |
|
|
1c2bea38df | |
|
|
876e6874b4 | |
|
|
639b514e19 | |
|
|
31f99fac19 | |
|
|
b416f4bb7e | |
|
|
8bb5b42a02 | |
|
|
fe2f837217 | |
|
|
bc8ba5b73a | |
|
|
8766a58811 | |
|
|
50fd2ac2af | |
|
|
56397d6d78 | |
|
|
e136f30e32 | |
|
|
ad71d8b76c | |
|
|
1887386149 | |
|
|
ca3c4979f5 | |
|
|
426e77a252 | |
|
|
4305c99b01 | |
|
|
d3565b407e | |
|
|
a06b13d42a | |
|
|
b0452ab556 | |
|
|
ccb96af1b6 | |
|
|
5d83077af2 | |
|
|
1e5a6fd854 | |
|
|
474b564385 | |
|
|
4c6f0f156b | |
|
|
7c3a300e60 | |
|
|
ebd066d883 | |
|
|
238b9d9e22 | |
|
|
1272f6ba0a | |
|
|
0aa404b928 | |
|
|
29dd58c2f8 | |
|
|
0dde884ac7 | |
|
|
d6e42290de | |
|
|
de94839339 | |
|
|
1cb3e81989 | |
|
|
bf2b8efee6 | |
|
|
b2aaa23984 | |
|
|
ad3d0e4d74 | |
|
|
9012b46ee1 | |
|
|
ebfa6f63be | |
|
|
e4ceea33da | |
|
|
9a10ef4886 | |
|
|
d84bb22c24 | |
|
|
a2d5d4abf7 | |
|
|
68ef9ce3be | |
|
|
b05510ccc5 | |
|
|
6e1372708c | |
|
|
b93ada6196 | |
|
|
ae6a7acb67 | |
|
|
abab5f5440 | |
|
|
2bbc117528 | |
|
|
381ce5f280 | |
|
|
6676bc8172 | |
|
|
4862010d42 | |
|
|
6e8b7cff57 | |
|
|
a357b9676d | |
|
|
2e68341106 | |
|
|
49cb77ac8f | |
|
|
986c910a73 | |
|
|
54dc91adc5 | |
|
|
5cf512cf63 | |
|
|
b7fc52bcb3 | |
|
|
fc95719f2e | |
|
|
90f5a7d4e3 | |
|
|
18bd8b630d | |
|
|
98564ab6d0 | |
|
|
8639ab3837 | |
|
|
5acecbaf6f | |
|
|
b1acfcf26a | |
|
|
da437b3295 | |
|
|
22c90415be | |
|
|
dfe3d7af12 | |
|
|
5d71b0dae7 | |
|
|
999e55504a | |
|
|
75b69452ef | |
|
|
d9408f96d3 | |
|
|
bf042642c3 | |
|
|
42bf39e652 | |
|
|
7c9320ad97 | |
|
|
ee4dc696df | |
|
|
88cbd0acf7 | |
|
|
e175e6593d | |
|
|
43e380912d | |
|
|
8b341f39e5 | |
|
|
56e80581f1 | |
|
|
8f82e61f17 | |
|
|
b8dc3973d1 | |
|
|
acd38708cc | |
|
|
d419b62a65 | |
|
|
93c135ea66 | |
|
|
c701b46559 | |
|
|
824954aeca | |
|
|
62119c3306 | |
|
|
2b292ca224 | |
|
|
a628369228 | |
|
|
22fb17caf9 | |
|
|
50d67ff722 | |
|
|
7987598a72 | |
|
|
bd1c82a445 | |
|
|
162bf9d0b7 | |
|
|
1269d73690 | |
|
|
859ba3b422 | |
|
|
e1278c36f7 | |
|
|
d663094985 | |
|
|
5417fa6a53 | |
|
|
e8919eada3 | |
|
|
e01b7b6740 | |
|
|
83322511ad | |
|
|
953a5e0641 | |
|
|
e0c15ea7e8 | |
|
|
94706763e5 | |
|
|
ebce0fdda6 | |
|
|
e509e76294 | |
|
|
d00b07f361 | |
|
|
dfc253bebf | |
|
|
f53bca99e4 | |
|
|
5f237db650 | |
|
|
bdc1613512 | |
|
|
03c29a3721 | |
|
|
5781e6ab96 | |
|
|
f6bdb61b13 | |
|
|
0dc8336c14 | |
|
|
7a58e3cdc5 | |
|
|
85aa200947 | |
|
|
a434e1d076 | |
|
|
bbb0e4553b | |
|
|
c218bb9dfa | |
|
|
ccb9a6c034 | |
|
|
c6fff0ff32 | |
|
|
214bc0e587 | |
|
|
f7c9aed8b0 | |
|
|
a283ab2786 | |
|
|
3a98bf0d00 | |
|
|
1d723b0731 | |
|
|
99696cfac0 | |
|
|
b19c1f9dd2 | |
|
|
ad3e4facb4 | |
|
|
008c1ee51b | |
|
|
7e317eac23 | |
|
|
2ea2181f30 | |
|
|
5b746d1414 | |
|
|
2dfd1320a6 | |
|
|
b3769c241b | |
|
|
1c1b496a7a | |
|
|
ce38ddf127 | |
|
|
eb16ac2028 | |
|
|
a2eb71d49a | |
|
|
108b402918 | |
|
|
577fe9b52e | |
|
|
8f58d0621c | |
|
|
20effc8cb8 | |
|
|
e101351b6e | |
|
|
356cda2917 | |
|
|
5de8a7b5f8 | |
|
|
c510adbc94 | |
|
|
f9aa0398e5 | |
|
|
4711eaf741 | |
|
|
cd86032be2 | |
|
|
2a07897354 | |
|
|
2b466535de | |
|
|
1a2926b311 | |
|
|
cc04f315b4 | |
|
|
d02893fe3c | |
|
|
c4e162287d | |
|
|
d9eec668cf | |
|
|
1170ed9620 | |
|
|
5632a2ccdb | |
|
|
ecbdbf23d6 | |
|
|
5c3692a513 | |
|
|
b433a521bf | |
|
|
9479a5c9be | |
|
|
c99e4d9aed | |
|
|
efd6b94310 | |
|
|
c4a2a5c9fb | |
|
|
75ddd87408 | |
|
|
779c66e2e9 | |
|
|
457761f060 | |
|
|
497f88fe1c | |
|
|
f84e9a8de1 | |
|
|
91fce10f30 | |
|
|
ecc45517d6 | |
|
|
f8a3c46139 | |
|
|
482d3a1d38 | |
|
|
416c8591b7 | |
|
|
72e511594d | |
|
|
a6cb388eef | |
|
|
c55c71b57c | |
|
|
3b4c872ea6 | |
|
|
3d4455948f | |
|
|
f8c6513294 | |
|
|
f66420b275 | |
|
|
217e6f9216 | |
|
|
541f12fb21 | |
|
|
90adaf22f7 | |
|
|
267e5d6909 | |
|
|
37677f1557 | |
|
|
392054a27b | |
|
|
909f1ad1e5 | |
|
|
b51cafb91b | |
|
|
1c80d1b784 | |
|
|
ae126d1009 | |
|
|
ef34c4ce0f | |
|
|
46f3b722c9 | |
|
|
221f8bbb92 | |
|
|
937e0ae3ca | |
|
|
4f24e008ba | |
|
|
976dc44d11 | |
|
|
b5960fd44a | |
|
|
7bebcc558f | |
|
|
05c8bc5d9f | |
|
|
84ad8a2788 | |
|
|
0858fa2af4 | |
|
|
9e00c2d0d3 | |
|
|
402e40fc36 | |
|
|
b5d49b451b | |
|
|
8a1c08cafb | |
|
|
95f90fe799 | |
|
|
de426ba823 | |
|
|
c95e5775ff | |
|
|
899e072cf1 | |
|
|
00f3f3723e | |
|
|
9e94a6dc1a | |
|
|
baddeb9034 | |
|
|
1babb5b55c | |
|
|
1a5e6e2187 | |
|
|
687720386f | |
|
|
725fd31249 | |
|
|
31ccabe952 | |
|
|
849fc1acf2 | |
|
|
37c58322e5 | |
|
|
bb576566ca | |
|
|
d7bb5f10b5 | |
|
|
ee36258f49 | |
|
|
e438e1e0c5 | |
|
|
6d37952b14 | |
|
|
3b4c5c5889 | |
|
|
3f4d35f04c | |
|
|
e907a068f2 | |
|
|
54be82c50c | |
|
|
c3e3130da8 | |
|
|
c62dda5136 | |
|
|
5eaa62d59c | |
|
|
8d815b7a9c | |
|
|
b4490c7b47 | |
|
|
45d645a864 | |
|
|
e5053ac5c9 | |
|
|
32f87412d6 | |
|
|
de4e233969 | |
|
|
f1f76cb8e3 | |
|
|
98a55c8dec | |
|
|
f6ff1c853b | |
|
|
1a3f65eaab | |
|
|
bd96d40e4e | |
|
|
51b5f4af24 | |
|
|
b793f83a29 | |
|
|
803760ca80 | |
|
|
75851778c0 | |
|
|
934dfee6a4 | |
|
|
12a7d45e75 | |
|
|
8f08c1b87f | |
|
|
c7722f2b97 | |
|
|
8d1df036ae | |
|
|
5c2ec7106e | |
|
|
99dd290352 | |
|
|
278448179d | |
|
|
5fa039a2d4 | |
|
|
656df98a76 | |
|
|
e7e9cecc1a | |
|
|
21bdc45bf0 | |
|
|
7d4eaf6a48 | |
|
|
4f861f653a | |
|
|
03b53c2d29 | |
|
|
05469fbff8 |
|
|
@ -0,0 +1,4 @@
|
||||||
|
*.xz binary
|
||||||
|
dsp/generated/* merge=binary linguist-generated
|
||||||
|
cpu_features/** linguist-vendored
|
||||||
|
starch/** linguist-vendored
|
||||||
|
|
@ -9,3 +9,11 @@ frames.js
|
||||||
*.orig
|
*.orig
|
||||||
untrackedDeveloperSettings.js
|
untrackedDeveloperSettings.js
|
||||||
view1090
|
view1090
|
||||||
|
faup1090
|
||||||
|
package-wheezy
|
||||||
|
oneoff/convert_benchmark
|
||||||
|
oneoff/uc8_capture_stats
|
||||||
|
oneoff/dsp_error_measurement
|
||||||
|
oneoff/decode_comm_b
|
||||||
|
starch-benchmark
|
||||||
|
wisdom.local
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,31 @@
|
||||||
|
language: c
|
||||||
|
|
||||||
|
sudo: required
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: linux
|
||||||
|
dist: trusty
|
||||||
|
- os: osx
|
||||||
|
osx_image: xcode7.3
|
||||||
|
- os: osx
|
||||||
|
osx_image: xcode7.1
|
||||||
|
- os: osx
|
||||||
|
osx_image: beta-xcode6.2
|
||||||
|
|
||||||
|
before_install:
|
||||||
|
- if [ `uname` = "Linux" ]; then
|
||||||
|
sudo apt-get update -qq;
|
||||||
|
sudo apt-get install -y build-essential debhelper librtlsdr-dev libusb-1.0-0-dev pkg-config fakeroot libbladerf-dev dh-systemd;
|
||||||
|
elif [ `uname` = "Darwin" ]; then
|
||||||
|
brew update;
|
||||||
|
brew install -v librtlsdr;
|
||||||
|
fi
|
||||||
|
|
||||||
|
script:
|
||||||
|
- if [ `uname` = "Linux" ]; then
|
||||||
|
dpkg-buildpackage -b -us -uc;
|
||||||
|
elif [ `uname` = "Darwin" ]; then
|
||||||
|
make;
|
||||||
|
make test;
|
||||||
|
fi
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
node(label: 'raspberrypi') {
|
||||||
|
properties([
|
||||||
|
pipelineTriggers([
|
||||||
|
upstream(threshold: 'SUCCESS',
|
||||||
|
upstreamProjects: "bladeRF/${env.BRANCH_NAME}")
|
||||||
|
]),
|
||||||
|
disableConcurrentBuilds(),
|
||||||
|
durabilityHint(hint: 'PERFORMANCE_OPTIMIZED')
|
||||||
|
])
|
||||||
|
|
||||||
|
def dists = ["bullseye", "buster", "stretch"]
|
||||||
|
def srcdir = "${WORKSPACE}/src"
|
||||||
|
|
||||||
|
stage('Checkout') {
|
||||||
|
sh "rm -fr ${srcdir}"
|
||||||
|
sh "mkdir ${srcdir}"
|
||||||
|
dir(srcdir) {
|
||||||
|
checkout scm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < dists.size(); ++i) {
|
||||||
|
def dist = dists[i]
|
||||||
|
def pkgdir = "package-${dist}"
|
||||||
|
def results = "results-${dist}"
|
||||||
|
|
||||||
|
stage("Prepare source for ${dist}") {
|
||||||
|
sh "rm -fr ${pkgdir}"
|
||||||
|
sh "${srcdir}/prepare-build.sh ${dist} ${pkgdir}"
|
||||||
|
}
|
||||||
|
|
||||||
|
stage("Build for ${dist}") {
|
||||||
|
sh "rm -fr ${results}"
|
||||||
|
sh "mkdir -p ${results}"
|
||||||
|
dir(pkgdir) {
|
||||||
|
sh "DIST=${dist} BRANCH=${env.BRANCH_NAME} pdebuild --use-pdebuild-internal --debbuildopts -b --buildresult ${WORKSPACE}/${results} -- --override-config"
|
||||||
|
}
|
||||||
|
archiveArtifacts artifacts: "${results}/*.deb", fingerprint: true
|
||||||
|
}
|
||||||
|
|
||||||
|
stage("Test install on ${dist}") {
|
||||||
|
sh "BRANCH=${env.BRANCH_NAME} /build/pi-builder/scripts/validate-packages.sh ${dist} ${results}/dump1090-fa_*.deb"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Deploy to internal repository') {
|
||||||
|
for (int i = 0; i < dists.size(); ++i) {
|
||||||
|
def dist = dists[i]
|
||||||
|
def results = "results-${dist}"
|
||||||
|
sh "/build/pi-builder/scripts/deploy.sh -distribution ${dist} -branch ${env.BRANCH_NAME} ${results}/*.deb"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
254
Makefile
254
Makefile
|
|
@ -1,44 +1,250 @@
|
||||||
#
|
|
||||||
# When building a package or installing otherwise in the system, make
|
|
||||||
# sure that the variable PREFIX is defined, e.g. make PREFIX=/usr/local
|
|
||||||
#
|
|
||||||
PROGNAME=dump1090
|
PROGNAME=dump1090
|
||||||
|
|
||||||
ifndef DUMP1090_VERSION
|
DUMP1090_VERSION ?= unknown
|
||||||
DUMP1090_VERSION=$(shell git describe --tags)
|
|
||||||
|
CFLAGS ?= -O3 -g
|
||||||
|
DUMP1090_CFLAGS := -std=c11 -fno-common -Wall -Wmissing-declarations -Werror -W
|
||||||
|
DUMP1090_CPPFLAGS := -I. -D_POSIX_C_SOURCE=200112L -DMODES_DUMP1090_VERSION=\"$(DUMP1090_VERSION)\" -DMODES_DUMP1090_VARIANT=\"dump1090-fa\"
|
||||||
|
|
||||||
|
LIBS = -lpthread -lm
|
||||||
|
SDR_OBJ = cpu.o sdr.o fifo.o sdr_ifile.o dsp/helpers/tables.o
|
||||||
|
|
||||||
|
# Try to autodetect available libraries via pkg-config if no explicit setting was used
|
||||||
|
PKGCONFIG=$(shell pkg-config --version >/dev/null 2>&1 && echo "yes" || echo "no")
|
||||||
|
ifeq ($(PKGCONFIG), yes)
|
||||||
|
ifndef RTLSDR
|
||||||
|
ifdef RTLSDR_PREFIX
|
||||||
|
RTLSDR := yes
|
||||||
|
else
|
||||||
|
RTLSDR := $(shell pkg-config --exists librtlsdr && echo "yes" || echo "no")
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifdef PREFIX
|
ifndef BLADERF
|
||||||
BINDIR=$(PREFIX)/bin
|
BLADERF := $(shell pkg-config --exists libbladeRF && echo "yes" || echo "no")
|
||||||
SHAREDIR=$(PREFIX)/share/$(PROGNAME)
|
|
||||||
EXTRACFLAGS=-DHTMLPATH=\"$(SHAREDIR)\"
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CPPFLAGS+=-DMODES_DUMP1090_VERSION=\"$(DUMP1090_VERSION)\"
|
ifndef HACKRF
|
||||||
CFLAGS+=-O2 -g -Wall -Werror -W `pkg-config --cflags librtlsdr`
|
HACKRF := $(shell pkg-config --exists libhackrf && echo "yes" || echo "no")
|
||||||
LIBS=-lpthread -lm -lrt
|
endif
|
||||||
LIBS_RTL=`pkg-config --libs librtlsdr`
|
|
||||||
CC=gcc
|
|
||||||
|
|
||||||
all: dump1090 view1090
|
ifndef LIMESDR
|
||||||
|
LIMESDR := $(shell pkg-config --exists LimeSuite && echo "yes" || echo "no")
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
# pkg-config not available. Only use explicitly enabled libraries.
|
||||||
|
RTLSDR ?= no
|
||||||
|
BLADERF ?= no
|
||||||
|
HACKRF ?= no
|
||||||
|
LIMESDR ?= no
|
||||||
|
endif
|
||||||
|
|
||||||
|
HOST_UNAME := $(shell uname)
|
||||||
|
HOST_ARCH := $(shell uname -m)
|
||||||
|
|
||||||
|
UNAME ?= $(HOST_UNAME)
|
||||||
|
ARCH ?= $(HOST_ARCH)
|
||||||
|
|
||||||
|
ifeq ($(UNAME), Linux)
|
||||||
|
DUMP1090_CPPFLAGS += -D_DEFAULT_SOURCE
|
||||||
|
LIBS += -lrt
|
||||||
|
LIBS_USB += -lusb-1.0
|
||||||
|
LIBS_CURSES := -lncurses
|
||||||
|
CPUFEATURES ?= yes
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(UNAME), Darwin)
|
||||||
|
ifneq ($(shell sw_vers -productVersion | egrep '^10\.([0-9]|1[01])\.'),) # Mac OS X ver <= 10.11
|
||||||
|
DUMP1090_CPPFLAGS += -DMISSING_GETTIME
|
||||||
|
COMPAT += compat/clock_gettime/clock_gettime.o
|
||||||
|
endif
|
||||||
|
DUMP1090_CPPFLAGS += -DMISSING_NANOSLEEP
|
||||||
|
COMPAT += compat/clock_nanosleep/clock_nanosleep.o
|
||||||
|
LIBS_USB += -lusb-1.0
|
||||||
|
LIBS_CURSES := -lncurses
|
||||||
|
# cpufeatures reportedly does not work (yet) on darwin arm64
|
||||||
|
ifneq ($(ARCH),arm64)
|
||||||
|
CPUFEATURES ?= yes
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(UNAME), OpenBSD)
|
||||||
|
DUMP1090_CPPFLAGS += -DMISSING_NANOSLEEP
|
||||||
|
COMPAT += compat/clock_nanosleep/clock_nanosleep.o
|
||||||
|
LIBS_USB += -lusb-1.0
|
||||||
|
LIBS_CURSES := -lncurses
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(UNAME), FreeBSD)
|
||||||
|
DUMP1090_CPPFLAGS += -D_DEFAULT_SOURCE
|
||||||
|
LIBS += -lrt
|
||||||
|
LIBS_USB += -lusb
|
||||||
|
LIBS_CURSES := -lncurses
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(UNAME), NetBSD)
|
||||||
|
DUMP1090_CPPFLAGS += -D_DEFAULT_SOURCE
|
||||||
|
LIBS += -lrt
|
||||||
|
LIBS_USB += -lusb-1.0
|
||||||
|
LIBS_CURSES := -lcurses
|
||||||
|
endif
|
||||||
|
|
||||||
|
CPUFEATURES ?= no
|
||||||
|
|
||||||
|
ifeq ($(CPUFEATURES),yes)
|
||||||
|
include Makefile.cpufeatures
|
||||||
|
DUMP1090_CPPFLAGS += -DENABLE_CPUFEATURES -Icpu_features/include
|
||||||
|
endif
|
||||||
|
|
||||||
|
RTLSDR ?= yes
|
||||||
|
BLADERF ?= yes
|
||||||
|
|
||||||
|
ifeq ($(RTLSDR), yes)
|
||||||
|
SDR_OBJ += sdr_rtlsdr.o
|
||||||
|
DUMP1090_CPPFLAGS += -DENABLE_RTLSDR
|
||||||
|
|
||||||
|
ifdef RTLSDR_PREFIX
|
||||||
|
DUMP1090_CPPFLAGS += -I$(RTLSDR_PREFIX)/include
|
||||||
|
ifeq ($(STATIC), yes)
|
||||||
|
LIBS_SDR += -L$(RTLSDR_PREFIX)/lib -Wl,-Bstatic -lrtlsdr -Wl,-Bdynamic $(LIBS_USB)
|
||||||
|
else
|
||||||
|
LIBS_SDR += -L$(RTLSDR_PREFIX)/lib -lrtlsdr $(LIBS_USB)
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
# some packaged .pc files are massively broken, try to handle it
|
||||||
|
|
||||||
|
# FreeBSD's librtlsdr.pc includes -std=gnu89 in cflags
|
||||||
|
# some linux librtlsdr packages return a bare -I/ with no path in --cflags
|
||||||
|
RTLSDR_CFLAGS := $(shell pkg-config --cflags librtlsdr)
|
||||||
|
RTLSDR_CFLAGS := $(filter-out -std=%,$(RTLSDR_CFLAGS))
|
||||||
|
RTLSDR_CFLAGS := $(filter-out -I/,$(RTLSDR_CFLAGS))
|
||||||
|
DUMP1090_CFLAGS += $(RTLSDR_CFLAGS)
|
||||||
|
|
||||||
|
# some linux librtlsdr packages return a bare -L with no path in --libs
|
||||||
|
# which horribly confuses things because it eats the next option on the command line
|
||||||
|
RTLSDR_LFLAGS := $(shell pkg-config --libs-only-L librtlsdr)
|
||||||
|
ifeq ($(RTLSDR_LFLAGS),-L)
|
||||||
|
LIBS_SDR += $(shell pkg-config --libs-only-l --libs-only-other librtlsdr)
|
||||||
|
else
|
||||||
|
LIBS_SDR += $(shell pkg-config --libs librtlsdr)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(BLADERF), yes)
|
||||||
|
SDR_OBJ += sdr_bladerf.o
|
||||||
|
DUMP1090_CPPFLAGS += -DENABLE_BLADERF
|
||||||
|
DUMP1090_CFLAGS += $(shell pkg-config --cflags libbladeRF)
|
||||||
|
LIBS_SDR += $(shell pkg-config --libs libbladeRF)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(HACKRF), yes)
|
||||||
|
SDR_OBJ += sdr_hackrf.o
|
||||||
|
DUMP1090_CPPFLAGS += -DENABLE_HACKRF
|
||||||
|
DUMP1090_CFLAGS += $(shell pkg-config --cflags libhackrf)
|
||||||
|
LIBS_SDR += $(shell pkg-config --libs libhackrf)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(LIMESDR), yes)
|
||||||
|
SDR_OBJ += sdr_limesdr.o
|
||||||
|
DUMP1090_CPPFLAGS += -DENABLE_LIMESDR
|
||||||
|
DUMP1090_CFLAGS += $(shell pkg-config --cflags LimeSuite)
|
||||||
|
LIBS_SDR += $(shell pkg-config --libs LimeSuite)
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## starch (runtime DSP code selection) mix, architecture-specific
|
||||||
|
##
|
||||||
|
|
||||||
|
ifneq ($(CPUFEATURES),yes)
|
||||||
|
# need to be able to detect CPU features at runtime to enable any non-standard compiler flags
|
||||||
|
STARCH_MIX := generic
|
||||||
|
DUMP1090_CPPFLAGS += -DSTARCH_MIX_GENERIC
|
||||||
|
else
|
||||||
|
ifeq ($(ARCH),x86_64)
|
||||||
|
# AVX, AVX2
|
||||||
|
STARCH_MIX := x86
|
||||||
|
DUMP1090_CPPFLAGS += -DSTARCH_MIX_X86
|
||||||
|
else ifeq ($(findstring aarch,$(ARCH)),aarch)
|
||||||
|
STARCH_MIX := aarch64
|
||||||
|
DUMP1090_CPPFLAGS += -DSTARCH_MIX_AARCH64
|
||||||
|
else ifeq ($(findstring arm64,$(ARCH)),arm64)
|
||||||
|
# Apple calls this arm64, not aarch64
|
||||||
|
STARCH_MIX := aarch64
|
||||||
|
DUMP1090_CPPFLAGS += -DSTARCH_MIX_AARCH64
|
||||||
|
else ifeq ($(findstring arm,$(ARCH)),arm)
|
||||||
|
# ARMv7 NEON
|
||||||
|
STARCH_MIX := arm
|
||||||
|
DUMP1090_CPPFLAGS += -DSTARCH_MIX_ARM
|
||||||
|
else
|
||||||
|
STARCH_MIX := generic
|
||||||
|
DUMP1090_CPPFLAGS += -DSTARCH_MIX_GENERIC
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
all: showconfig dump1090 view1090 starch-benchmark
|
||||||
|
|
||||||
|
ALL_CCFLAGS := $(CPPFLAGS) $(DUMP1090_CPPFLAGS) $(CFLAGS) $(DUMP1090_CFLAGS)
|
||||||
|
|
||||||
|
STARCH_COMPILE := $(CC) $(ALL_CCFLAGS) -c
|
||||||
|
include dsp/generated/makefile.$(STARCH_MIX)
|
||||||
|
|
||||||
|
showconfig:
|
||||||
|
@echo "Building with:" >&2
|
||||||
|
@echo " Version string: $(DUMP1090_VERSION)" >&2
|
||||||
|
@echo " Architecture: $(ARCH)" >&2
|
||||||
|
@echo " DSP mix: $(STARCH_MIX)" >&2
|
||||||
|
@echo " RTLSDR support: $(RTLSDR)" >&2
|
||||||
|
@echo " BladeRF support: $(BLADERF)" >&2
|
||||||
|
@echo " HackRF support: $(HACKRF)" >&2
|
||||||
|
@echo " LimeSDR support: $(LIMESDR)" >&2
|
||||||
|
|
||||||
%.o: %.c *.h
|
%.o: %.c *.h
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRACFLAGS) -c $< -o $@
|
$(CC) $(ALL_CCFLAGS) -c $< -o $@
|
||||||
|
|
||||||
dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o demod_2000.o demod_2400.o stats.o cpr.o icao_filter.o track.o util.o
|
dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o comm_b.o net_io.o crc.o demod_2400.o stats.o cpr.o icao_filter.o track.o util.o convert.o ais_charset.o adaptive.o $(SDR_OBJ) $(COMPAT) $(CPUFEATURES_OBJS) $(STARCH_OBJS)
|
||||||
$(CC) -g -o $@ $^ $(LIBS) $(LIBS_RTL) $(LDFLAGS)
|
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS) $(LIBS_SDR) $(LIBS_CURSES)
|
||||||
|
|
||||||
view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o stats.o cpr.o icao_filter.o track.o util.o
|
view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o comm_b.o net_io.o crc.o stats.o cpr.o icao_filter.o track.o util.o ais_charset.o sdr_stub.o $(COMPAT)
|
||||||
$(CC) -g -o $@ $^ $(LIBS) $(LDFLAGS)
|
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS) $(LIBS_CURSES)
|
||||||
|
|
||||||
|
faup1090: faup1090.o anet.o mode_ac.o mode_s.o comm_b.o net_io.o crc.o stats.o cpr.o icao_filter.o track.o util.o ais_charset.o sdr_stub.o $(COMPAT)
|
||||||
|
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS)
|
||||||
|
|
||||||
|
starch-benchmark: cpu.o dsp/helpers/tables.o $(CPUFEATURES_OBJS) $(STARCH_OBJS) $(STARCH_BENCHMARK_OBJ)
|
||||||
|
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o dump1090 view1090 cprtests crctests
|
rm -f *.o oneoff/*.o compat/clock_gettime/*.o compat/clock_nanosleep/*.o cpu_features/src/*.o dsp/generated/*.o dsp/helpers/*.o $(CPUFEATURES_OBJS) dump1090 view1090 faup1090 cprtests crctests oneoff/convert_benchmark oneoff/decode_comm_b oneoff/dsp_error_measurement oneoff/uc8_capture_stats starch-benchmark
|
||||||
|
|
||||||
test: cprtests
|
test: cprtests
|
||||||
./cprtests
|
./cprtests
|
||||||
|
|
||||||
cprtests: cpr.o cprtests.o
|
cprtests: cpr.o cprtests.o
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRACFLAGS) -g -o $@ $^ -lm
|
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm
|
||||||
|
|
||||||
crctests: crc.c crc.h
|
crctests: crc.c crc.h
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRACFLAGS) -g -DCRCDEBUG -o $@ $<
|
$(CC) $(ALL_CCFLAGS) -g -DCRCDEBUG -o $@ $<
|
||||||
|
|
||||||
|
benchmarks: oneoff/convert_benchmark
|
||||||
|
oneoff/convert_benchmark
|
||||||
|
|
||||||
|
oneoff/convert_benchmark: oneoff/convert_benchmark.o convert.o util.o dsp/helpers/tables.o cpu.o $(CPUFEATURES_OBJS) $(STARCH_OBJS)
|
||||||
|
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm -lpthread
|
||||||
|
|
||||||
|
oneoff/decode_comm_b: oneoff/decode_comm_b.o comm_b.o ais_charset.o
|
||||||
|
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm
|
||||||
|
|
||||||
|
oneoff/dsp_error_measurement: oneoff/dsp_error_measurement.o dsp/helpers/tables.o cpu.o $(CPUFEATURES_OBJS) $(STARCH_OBJS)
|
||||||
|
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm
|
||||||
|
|
||||||
|
oneoff/uc8_capture_stats: oneoff/uc8_capture_stats.o
|
||||||
|
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm
|
||||||
|
|
||||||
|
starchgen:
|
||||||
|
dsp/starchgen.py .
|
||||||
|
|
||||||
|
.PHONY: wisdom.local
|
||||||
|
wisdom.local: starch-benchmark
|
||||||
|
./starch-benchmark -i 5 -o wisdom.local mean_power_u16 mean_power_u16_aligned magnitude_uc8 magnitude_uc8_aligned
|
||||||
|
./starch-benchmark -i 5 -r wisdom.local -o wisdom.local
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
# -*- makefile -*-
|
||||||
|
|
||||||
|
# cmake integration is a little tricky, so let's do this by hand for now
|
||||||
|
|
||||||
|
CPUFEATURES_UNAME ?= $(UNAME)
|
||||||
|
CPUFEATURES_ARCH ?= $(ARCH)
|
||||||
|
CPUFEATURES_CFLAGS ?= $(CFLAGS)
|
||||||
|
|
||||||
|
CPUFEATURES_OBJS := cpu_features/src/filesystem.o cpu_features/src/stack_line_reader.o cpu_features/src/string_view.o
|
||||||
|
CPUFEATURES_EXTRA_CFLAGS := -std=c99
|
||||||
|
CPUFEATURES_EXTRA_CPPFLAGS := -DSTACK_LINE_READER_BUFFER_SIZE=1024 -DNDEBUG -Icpu_features/include
|
||||||
|
|
||||||
|
ifeq ($(CPUFEATURES_UNAME),Linux)
|
||||||
|
CPUFEATURES_OBJS += cpu_features/src/hwcaps.o
|
||||||
|
CPUFEATURES_EXTRA_CPPFLAGS += -DHAVE_STRONG_GETAUXVAL
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CPUFEATURES_UNAME),Darwin)
|
||||||
|
CPUFEATURES_EXTRA_CPPFLAGS += -DHAVE_SYSCTLBYNAME
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CPUFEATURES_ARCH),x86_64)
|
||||||
|
CPUFEATURES_OBJS += cpu_features/src/cpuinfo_x86.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter i%86,$(CPUFEATURES_ARCH)))
|
||||||
|
CPUFEATURES_OBJS += cpu_features/src/cpuinfo_x86.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring arm,$(CPUFEATURES_ARCH)))
|
||||||
|
CPUFEATURES_OBJS += cpu_features/src/cpuinfo_arm.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring aarch64,$(CPUFEATURES_ARCH)))
|
||||||
|
CPUFEATURES_OBJS += cpu_features/src/cpuinfo_aarch64.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(CPUFEATURES_OBJS): override ALL_CCFLAGS := $(CPUFEATURES_CPPFLAGS) $(CPUFEATURES_EXTRA_CPPFLAGS) $(CPUFEATURES_CFLAGS) $(CPUFEATURES_EXTRA_CFLAGS)
|
||||||
|
|
@ -1,287 +0,0 @@
|
||||||
Dump1090 README
|
|
||||||
===
|
|
||||||
|
|
||||||
Dump 1090 is a Mode S decoder specifically designed for RTLSDR devices.
|
|
||||||
|
|
||||||
The main features are:
|
|
||||||
|
|
||||||
* Robust decoding of weak messages, with mode1090 many users observed
|
|
||||||
improved range compared to other popular decoders.
|
|
||||||
* Network support: TCP30003 stream (MSG5...), Raw packets, HTTP.
|
|
||||||
* Embedded HTTP server that displays the currently detected aircrafts on
|
|
||||||
Google Map.
|
|
||||||
* Single bit errors correction using the 24 bit CRC.
|
|
||||||
* Ability to decode DF11, DF17 messages.
|
|
||||||
* Ability to decode DF formats like DF0, DF4, DF5, DF16, DF20 and DF21
|
|
||||||
where the checksum is xored with the ICAO address by brute forcing the
|
|
||||||
checksum field using recently seen ICAO addresses.
|
|
||||||
* Decode raw IQ samples from file (using --ifile command line switch).
|
|
||||||
* Interactive command-line-interfae mode where aircrafts currently detected
|
|
||||||
are shown as a list refreshing as more data arrives.
|
|
||||||
* CPR coordinates decoding and track calculation from velocity.
|
|
||||||
* TCP server streaming and recceiving raw data to/from connected clients
|
|
||||||
(using --net).
|
|
||||||
|
|
||||||
Installation
|
|
||||||
---
|
|
||||||
|
|
||||||
Type "make".
|
|
||||||
|
|
||||||
Normal usage
|
|
||||||
---
|
|
||||||
|
|
||||||
To capture traffic directly from your RTL device and show the captured traffic
|
|
||||||
on standard output, just run the program without options at all:
|
|
||||||
|
|
||||||
./dump1090
|
|
||||||
|
|
||||||
To just output hexadecimal messages:
|
|
||||||
|
|
||||||
./dump1090 --raw
|
|
||||||
|
|
||||||
To run the program in interactive mode:
|
|
||||||
|
|
||||||
./dump1090 --interactive
|
|
||||||
|
|
||||||
To run the program in interactive mode, with networking support, and connect
|
|
||||||
with your browser to http://localhost:8080 to see live traffic:
|
|
||||||
|
|
||||||
./dump1090 --interactive --net
|
|
||||||
|
|
||||||
In iteractive mode it is possible to have a less information dense but more
|
|
||||||
"arcade style" output, where the screen is refreshed every second displaying
|
|
||||||
all the recently seen aircrafts with some additional information such as
|
|
||||||
altitude and flight number, extracted from the received Mode S packets.
|
|
||||||
|
|
||||||
Using files as source of data
|
|
||||||
---
|
|
||||||
|
|
||||||
To decode data from file, use:
|
|
||||||
|
|
||||||
./dump1090 --ifile /path/to/binfile
|
|
||||||
|
|
||||||
The binary file should be created using `rtl_sdr` like this (or with any other
|
|
||||||
program that is able to output 8-bit unsigned IQ samples at 2Mhz sample rate).
|
|
||||||
|
|
||||||
rtl_sdr -f 1090000000 -s 2000000 -g 50 output.bin
|
|
||||||
|
|
||||||
In the example `rtl_sdr` a gain of 50 is used, simply you should use the highest
|
|
||||||
gain availabe for your tuner. This is not needed when calling Dump1090 itself
|
|
||||||
as it is able to select the highest gain supported automatically.
|
|
||||||
|
|
||||||
It is possible to feed the program with data via standard input using
|
|
||||||
the --ifile option with "-" as argument.
|
|
||||||
|
|
||||||
Additional options
|
|
||||||
---
|
|
||||||
|
|
||||||
Dump1090 can be called with other command line options to set a different
|
|
||||||
gain, frequency, and so forth. For a list of options use:
|
|
||||||
|
|
||||||
./dump1090 --help
|
|
||||||
|
|
||||||
Everything is not documented here should be obvious, and for most users calling
|
|
||||||
it without arguments at all is the best thing to do.
|
|
||||||
|
|
||||||
Reliability
|
|
||||||
---
|
|
||||||
|
|
||||||
By default Dump1090 checks for decoding errors using the 24-bit CRC checksum,
|
|
||||||
where available. Messages with errors are discarded.
|
|
||||||
|
|
||||||
The --fix command line switch enables fixing single bit error correction
|
|
||||||
based on the CRC checksum. Technically, it uses a table of precomputed
|
|
||||||
checksum differences resulting from single bit errors to look up the
|
|
||||||
wrong bit position.
|
|
||||||
|
|
||||||
This is indeed able to fix errors and works reliably in my experience,
|
|
||||||
however if you are interested in very reliable data I suggest to use
|
|
||||||
the --no-fix command line switch in order to disable error fixing.
|
|
||||||
|
|
||||||
Performances and sensibility of detection
|
|
||||||
---
|
|
||||||
|
|
||||||
In my limited experience Dump1090 was able to decode a big number of messages
|
|
||||||
even in conditions where I encountered problems using other programs, however
|
|
||||||
no formal test was performed so I can't really claim that this program is
|
|
||||||
better or worse compared to other similar programs.
|
|
||||||
|
|
||||||
If you can capture traffic that Dump1090 is not able to decode properly, drop
|
|
||||||
me an email with a download link. I may try to improve the detection during
|
|
||||||
my free time (this is just an hobby project).
|
|
||||||
|
|
||||||
Network server features
|
|
||||||
---
|
|
||||||
|
|
||||||
By enabling the networking support with --net Dump1090 starts listening
|
|
||||||
for clients connections on port 30002 and 30001 (you can change both the
|
|
||||||
ports if you want, see --help output).
|
|
||||||
|
|
||||||
Port 30002
|
|
||||||
---
|
|
||||||
|
|
||||||
Connected clients are served with data ASAP as they arrive from the device
|
|
||||||
(or from file if --ifile is used) in the raw format similar to the following:
|
|
||||||
|
|
||||||
*8D451E8B99019699C00B0A81F36E;
|
|
||||||
|
|
||||||
Every entry is separated by a simple newline (LF character, hex 0x0A).
|
|
||||||
|
|
||||||
Port 30001
|
|
||||||
---
|
|
||||||
|
|
||||||
Port 30001 is the raw input port, and can be used to feed Dump1090 with
|
|
||||||
data in the same format as specified above, with hex messages starting with
|
|
||||||
a `*` and ending with a `;` character.
|
|
||||||
|
|
||||||
So for instance if there is another remote Dump1090 instance collecting data
|
|
||||||
it is possible to sum the output to a local Dump1090 instance doing something
|
|
||||||
like this:
|
|
||||||
|
|
||||||
nc remote-dump1090.example.net 30002 | nc localhost 30001
|
|
||||||
|
|
||||||
It is important to note that what is received via port 30001 is also
|
|
||||||
broadcasted to clients listening to port 30002.
|
|
||||||
|
|
||||||
In general everything received from port 30001 is handled exactly like the
|
|
||||||
normal traffic from RTL devices or from file when --ifile is used.
|
|
||||||
|
|
||||||
It is possible to use Dump1090 just as an hub using --ifile with /dev/zero
|
|
||||||
as argument as in the following example:
|
|
||||||
|
|
||||||
./dump1090 --net-only
|
|
||||||
|
|
||||||
Or alternatively to see what's happening on the screen:
|
|
||||||
|
|
||||||
./dump1090 --net-only --interactive
|
|
||||||
|
|
||||||
Then you can feed it from different data sources from the internet.
|
|
||||||
|
|
||||||
Port 30003
|
|
||||||
---
|
|
||||||
|
|
||||||
Connected clients are served with messages in SBS1 (BaseStation) format,
|
|
||||||
similar to:
|
|
||||||
|
|
||||||
MSG,4,,,738065,,,,,,,,420,179,,,0,,0,0,0,0
|
|
||||||
MSG,3,,,738065,,,,,,,35000,,,34.81609,34.07810,,,0,0,0,0
|
|
||||||
|
|
||||||
This can be used to feed data to various sharing sites without the need to use another decoder.
|
|
||||||
|
|
||||||
Antenna
|
|
||||||
---
|
|
||||||
|
|
||||||
Mode S messages are transmitted in the 1090 Mhz frequency. If you have a decent
|
|
||||||
antenna you'll be able to pick up signals from aircrafts pretty far from your
|
|
||||||
position, especially if you are outdoor and in a position with a good sky view.
|
|
||||||
|
|
||||||
You can easily build a very cheap antenna following the istructions at:
|
|
||||||
|
|
||||||
http://antirez.com/news/46
|
|
||||||
|
|
||||||
With this trivial antenna I was able to pick up signals of aircrafts 200+ Km
|
|
||||||
away from me.
|
|
||||||
|
|
||||||
If you are interested in a more serious antenna check the following
|
|
||||||
resources:
|
|
||||||
|
|
||||||
* http://gnuradio.org/redmine/attachments/download/246/06-foster-adsb.pdf
|
|
||||||
* http://www.lll.lu/~edward/edward/adsb/antenna/ADSBantenna.html
|
|
||||||
* http://modesbeast.com/pix/adsb-ant-drawing.gif
|
|
||||||
|
|
||||||
Aggressive mode
|
|
||||||
---
|
|
||||||
|
|
||||||
With --aggressive it is possible to activate the *aggressive mode* that is a
|
|
||||||
modified version of the Mode S packet detection and decoding.
|
|
||||||
The aggresive mode uses more CPU usually (especially if there are many planes
|
|
||||||
sending DF17 packets), but can detect a few more messages.
|
|
||||||
|
|
||||||
The algorithm in aggressive mode is modified in the following ways:
|
|
||||||
|
|
||||||
* Up to two demodulation errors are tolerated (adjacent entires in the
|
|
||||||
magnitude vector with the same eight). Normally only messages without
|
|
||||||
errors are checked.
|
|
||||||
* It tries to fix DF17 messages with CRC errors resulting from any two bit
|
|
||||||
errors.
|
|
||||||
|
|
||||||
The use of aggressive mdoe is only advised in places where there is
|
|
||||||
low traffic in order to have a chance to capture some more messages.
|
|
||||||
|
|
||||||
Debug mode
|
|
||||||
---
|
|
||||||
|
|
||||||
The Debug mode is a visual help to improve the detection algorithm or to
|
|
||||||
understand why the program is not working for a given input.
|
|
||||||
|
|
||||||
In this mode messages are displayed in an ASCII-art style graphical
|
|
||||||
representation, where the individial magnitude bars sampled at 2Mhz are
|
|
||||||
displayed.
|
|
||||||
|
|
||||||
An index shows the sample number, where 0 is the sample where the first
|
|
||||||
Mode S peak was found. Some additional background noise is also added
|
|
||||||
before the first peak to provide some context.
|
|
||||||
|
|
||||||
To enable debug mode and check what combinations of packets you can
|
|
||||||
log, use `mode1090 --help` to obtain a list of available debug flags.
|
|
||||||
|
|
||||||
Debug mode includes an optional javascript output that is used to visualize
|
|
||||||
packets using a web browser, you can use the file debug.html under the
|
|
||||||
'tools' directory to load the generated frames.js file.
|
|
||||||
|
|
||||||
How this program works?
|
|
||||||
---
|
|
||||||
|
|
||||||
The code is very documented and written in order to be easy to understand.
|
|
||||||
For the diligent programmer with a Mode S specification on his hands it
|
|
||||||
should be trivial to understand how it works.
|
|
||||||
|
|
||||||
The algorithms I used were obtained basically looking at many messages
|
|
||||||
as displayed using a trow-away SDL program, and trying to model the algorithm
|
|
||||||
based on how the messages look graphically.
|
|
||||||
|
|
||||||
How to test the program?
|
|
||||||
---
|
|
||||||
|
|
||||||
If you have an RTLSDR device and you happen to be in an area where there
|
|
||||||
are aircrafts flying over your head, just run the program and check for signals.
|
|
||||||
|
|
||||||
However if you don't have an RTLSDR device, or if in your area the presence
|
|
||||||
of aircrafts is very limited, you may want to try the sample file distributed
|
|
||||||
with the Dump1090 distribution under the "testfiles" directory.
|
|
||||||
|
|
||||||
Just run it like this:
|
|
||||||
|
|
||||||
./dump1090 --ifile testfiles/modes1.bin
|
|
||||||
|
|
||||||
What is --strip mode?
|
|
||||||
---
|
|
||||||
|
|
||||||
It is just a simple filter that will get raw IQ 8 bit samples in input
|
|
||||||
and will output a file missing all the parts of the file where I and Q
|
|
||||||
are lower than the specified <level> for more than 32 samples.
|
|
||||||
|
|
||||||
Use it like this:
|
|
||||||
|
|
||||||
cat big.bin | ./dump1090 --snip 25 > small.bin
|
|
||||||
|
|
||||||
I used it in order to create a small test file to include inside this
|
|
||||||
program source code distribution.
|
|
||||||
|
|
||||||
Contributing
|
|
||||||
---
|
|
||||||
|
|
||||||
Dump1090 was written during some free time during xmas 2012, it is an hobby
|
|
||||||
project so I'll be able to address issues and improve it only during
|
|
||||||
free time, however you are incouraged to send pull requests in order to
|
|
||||||
improve the program. A good starting point can be the TODO list included in
|
|
||||||
the source distribution.
|
|
||||||
|
|
||||||
Credits
|
|
||||||
---
|
|
||||||
|
|
||||||
The original version of dump1090 was written by Salvatore Sanfilippo
|
|
||||||
<antirez@gmail.com> and was released under the BSD three clause license.
|
|
||||||
|
|
||||||
This modified version of dump1090 is maintained by Oliver Jowett
|
|
||||||
<oliver@mutability.co.uk> and is released under the GPL (v2 or later).
|
|
||||||
|
|
@ -7,15 +7,15 @@ about dump1090's operation to collectd for later graphing.
|
||||||
|
|
||||||
## Reading the json files
|
## Reading the json files
|
||||||
|
|
||||||
There are two ways to obtain the json files:
|
dump1090-fa writes json files periodically to the location specified by the `--write-json` command line option.
|
||||||
|
These json files can then be exposed via a separate standalone webserver e.g. lighttpd.
|
||||||
|
|
||||||
* By HTTP from dump1090's internal webserver, which defaults to running on port 8080. The json is served from the data/ path, e.g. http://somehost:8080/data/aircraft.json
|
The files are written periodically; for aircraft, typically once a second, for stats, once a minute.
|
||||||
* As a file in the directory specified by --write-json on dump1090's command line. These can be exposed via a
|
The interval between file updates can be controlled by the `--write-json-every` and `--json-stats-every` options.
|
||||||
separate webserver.
|
As these files are frequently updated, it's a good idea to put them in RAM rather than on disk. Package installs
|
||||||
|
default to putting the file under `/run`, which is in RAM.
|
||||||
|
|
||||||
The HTTP versions are always up to date.
|
New versions of each file are written to a temporary file, then atomically renamed to the right path, so you should never see partial copies.
|
||||||
The file versions are written periodically; for aircraft, typically once a second, for stats, once a minute.
|
|
||||||
The file versions are updated to a temporary file, then atomically renamed to the right path, so you should never see partial copies.
|
|
||||||
|
|
||||||
Each file contains a single JSON object. The file formats are:
|
Each file contains a single JSON object. The file formats are:
|
||||||
|
|
||||||
|
|
@ -38,19 +38,59 @@ This file contains dump1090's list of recently seen aircraft. The keys are:
|
||||||
* messages: the total number of Mode S messages processed since dump1090 started.
|
* messages: the total number of Mode S messages processed since dump1090 started.
|
||||||
* aircraft: an array of JSON objects, one per known aircraft. Each aircraft has the following keys. Keys will be omitted if data is not available.
|
* aircraft: an array of JSON objects, one per known aircraft. Each aircraft has the following keys. Keys will be omitted if data is not available.
|
||||||
* hex: the 24-bit ICAO identifier of the aircraft, as 6 hex digits. The identifier may start with '~', this means that the address is a non-ICAO address (e.g. from TIS-B).
|
* hex: the 24-bit ICAO identifier of the aircraft, as 6 hex digits. The identifier may start with '~', this means that the address is a non-ICAO address (e.g. from TIS-B).
|
||||||
* squawk: the 4-digit squawk (octal representation)
|
* type: type of underlying message, one of:
|
||||||
* flight: the flight name / callsign
|
* adsb_icao: messages from a Mode S or ADS-B transponder, using a 24-bit ICAO address
|
||||||
* lat, lon: the aircraft position in decimal degrees
|
* adsb_icao_nt: messages from an ADS-B equipped "non-transponder" emitter e.g. a ground vehicle, using a 24-bit ICAO address
|
||||||
* nucp: the NUCp (navigational uncertainty category) reported for the position
|
* adsr_icao: rebroadcast of ADS-B messages originally sent via another data link e.g. UAT, using a 24-bit ICAO address
|
||||||
* seen_pos: how long ago (in seconds before "now") the position was last updated
|
* tisb_icao: traffic information about a non-ADS-B target identified by a 24-bit ICAO address, e.g. a Mode S target tracked by secondary radar
|
||||||
* altitude: the aircraft altitude in feet, or "ground" if it is reporting it is on the ground
|
* adsb_other: messages from an ADS-B transponder using a non-ICAO address, e.g. anonymized address
|
||||||
* vert_rate: vertical rate in feet/minute
|
* adsr_other: rebroadcast of ADS-B messages originally sent via another data link e.g. UAT, using a non-ICAO address
|
||||||
|
* tisb_other: traffic information about a non-ADS-B target using a non-ICAO address
|
||||||
|
* tisb_trackfile: traffic information about a non-ADS-B target using a track/file identifier, typically from primary or Mode A/C radar
|
||||||
|
* flight: callsign, the flight name or aircraft registration as 8 chars (2.2.8.2.6)
|
||||||
|
* alt_baro: the aircraft barometric altitude in feet
|
||||||
|
* alt_geom: geometric (GNSS / INS) altitude in feet referenced to the WGS84 ellipsoid
|
||||||
|
* gs: ground speed in knots
|
||||||
|
* ias: indicated air speed in knots
|
||||||
|
* tas: true air speed in knots
|
||||||
|
* mach: Mach number
|
||||||
* track: true track over ground in degrees (0-359)
|
* track: true track over ground in degrees (0-359)
|
||||||
* speed: reported speed in kt. This is usually speed over ground, but might be IAS - you can't tell the difference here, sorry!
|
* track_rate: Rate of change of track, degrees/second
|
||||||
|
* roll: Roll, degrees, negative is left roll
|
||||||
|
* mag_heading: Heading, degrees clockwise from magnetic north
|
||||||
|
* true_heading: Heading, degrees clockwise from true north
|
||||||
|
* baro_rate: Rate of change of barometric altitude, feet/minute
|
||||||
|
* geom_rate: Rate of change of geometric (GNSS / INS) altitude, feet/minute
|
||||||
|
* squawk: Mode A code (Squawk), encoded as 4 octal digits
|
||||||
|
* emergency: ADS-B emergency/priority status, a superset of the 7x00 squawks (2.2.3.2.7.8.1.1)
|
||||||
|
* category: emitter category to identify particular aircraft or vehicle classes (values A0 - D7) (2.2.3.2.5.2)
|
||||||
|
* nav_qnh: altimeter setting (QFE or QNH/QNE), hPa
|
||||||
|
* nav_altitude_mcp: selected altitude from the Mode Control Panel / Flight Control Unit (MCP/FCU) or equivalent equipment
|
||||||
|
* nav_altitude_fms: selected altitude from the Flight Manaagement System (FMS) (2.2.3.2.7.1.3.3)
|
||||||
|
* nav_heading: selected heading (True or Magnetic is not defined in DO-260B, mostly Magnetic as that is the de facto standard) (2.2.3.2.7.1.3.7)
|
||||||
|
* nav_modes: set of engaged automation modes: 'autopilot', 'vnav', 'althold', 'approach', 'lnav', 'tcas'
|
||||||
|
* lat, lon: the aircraft position in decimal degrees
|
||||||
|
* nic: Navigation Integrity Category (2.2.3.2.7.2.6)
|
||||||
|
* rc: Radius of Containment, meters; a measure of position integrity derived from NIC & supplementary bits. (2.2.3.2.7.2.6, Table 2-69)
|
||||||
|
* seen_pos: how long ago (in seconds before "now") the position was last updated
|
||||||
|
* version: ADS-B Version Number 0, 1, 2 (3-7 are reserved) (2.2.3.2.7.5)
|
||||||
|
* nic_baro: Navigation Integrity Category for Barometric Altitude (2.2.5.1.35)
|
||||||
|
* nac_p: Navigation Accuracy for Position (2.2.5.1.35)
|
||||||
|
* nac_v: Navigation Accuracy for Velocity (2.2.5.1.19)
|
||||||
|
* sil: Source Integity Level (2.2.5.1.40)
|
||||||
|
* sil_type: interpretation of SIL: unknown, perhour, persample
|
||||||
|
* gva: Geometric Vertical Accuracy (2.2.3.2.7.2.8)
|
||||||
|
* sda: System Design Assurance (2.2.3.2.7.2.4.6)
|
||||||
|
* modea: true if we seem to be also receiving Mode A responses from this aircraft
|
||||||
|
* modec: true if we seem to be also receiving Mode C responses from this aircraft
|
||||||
|
* mlat: list of fields derived from MLAT data
|
||||||
|
* tisb: list of fields derived from TIS-B data
|
||||||
* messages: total number of Mode S messages received from this aircraft
|
* messages: total number of Mode S messages received from this aircraft
|
||||||
* seen: how long ago (in seconds before "now") a message was last received from this aircraft
|
* seen: how long ago (in seconds before "now") a message was last received from this aircraft
|
||||||
* rssi: recent average RSSI (signal power), in dbFS; this will always be negative.
|
* rssi: recent average RSSI (signal power), in dbFS; this will always be negative.
|
||||||
|
|
||||||
|
Section references (2.2.xyz) refer to DO-260B.
|
||||||
|
|
||||||
## history_0.json, history_1.json, ..., history_119.json
|
## history_0.json, history_1.json, ..., history_119.json
|
||||||
|
|
||||||
These files are historical copies of aircraft.json at (by default) 30 second intervals. They follow exactly the
|
These files are historical copies of aircraft.json at (by default) 30 second intervals. They follow exactly the
|
||||||
|
|
@ -124,3 +164,4 @@ Each period has the following subkeys:
|
||||||
* all: total tracks created
|
* all: total tracks created
|
||||||
* single_message: tracks consisting of only a single message. These are usually due to message decoding errors that produce a bad aircraft address.
|
* single_message: tracks consisting of only a single message. These are usually due to message decoding errors that produce a bad aircraft address.
|
||||||
* messages: total number of messages accepted by dump1090 from any source
|
* messages: total number of messages accepted by dump1090 from any source
|
||||||
|
* messages_by_df: an array of integers where entry N (0..31) is the total number of messages accepted with downlink format (DF) = N.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,191 @@
|
||||||
|
# Adaptive gain configuration
|
||||||
|
|
||||||
|
dump1090-fa can optionally tune the receiver gain automatically to try to
|
||||||
|
pick a gain value for the particular hardware and RF environment without
|
||||||
|
manual tuning. This README covers some of the background for why this is
|
||||||
|
useful, and how to configure dump1090 to enable this feature.
|
||||||
|
|
||||||
|
## Background
|
||||||
|
|
||||||
|
In general, more receiver gain means better reception. Most ADS-B transmitters
|
||||||
|
within line of sight transmit with enough power that their messages can
|
||||||
|
potentially be decoded, but if the receiver gain setting is too low then very
|
||||||
|
weak signals may still be too weak to be decoded even after amplification.
|
||||||
|
Adding extra receiver gain helps in this case.
|
||||||
|
|
||||||
|
However, there are two problems with just adding more gain to a wideband SDR.
|
||||||
|
First, _everything_ is amplified, not only the signals of interest. Noise and
|
||||||
|
RF interference is also amplified. At high gain settings or in noisy RF
|
||||||
|
environments, this can interfere with receiving the ADS-B signals themselves.
|
||||||
|
|
||||||
|
Second, there is a wide range of possible ADS-B signal strengths. There can be
|
||||||
|
a 60dB or more difference between the weakest signals (a distant aircraft at
|
||||||
|
the limit of receiver range) and the strongest signals (a nearby aircraft on
|
||||||
|
the ramp 100m from the receiver). Increasing the receiver gain to handle the
|
||||||
|
weakest signals can mean that the strongest signals overload the receiver.
|
||||||
|
A rtlsdr receiver only has about 30-35dB of dynamic range available at a
|
||||||
|
particular gain setting, so there is no single gain setting that can
|
||||||
|
simultaneously handle both the weakest and strongest signals.
|
||||||
|
|
||||||
|
Adaptive gain tries to deal with these cases by changing the receiver gain
|
||||||
|
on the fly to handle the signal and noise levels that are currently being seen
|
||||||
|
without human intervention. It is not perfect and it's not a substitute for
|
||||||
|
hand-tuning of gain settings, but it aims at picking a reasonable setting for
|
||||||
|
cases where individual hand-tuning isn't possible.
|
||||||
|
|
||||||
|
## Where to configure adaptive gain options
|
||||||
|
|
||||||
|
How to configure adaptive gain varies depending on how you have installed
|
||||||
|
dump1090.
|
||||||
|
|
||||||
|
If you are using a PiAware sdcard image, adaptive gain can be configured by
|
||||||
|
editing `/boot/piaware-config.txt` or by using the `piaware-config` command.
|
||||||
|
|
||||||
|
If you are using the Debian package, adaptive gain can be configured by editing
|
||||||
|
`/etc/default/dump1090-fa`.
|
||||||
|
|
||||||
|
If running dump1090 directly, adaptive gain options are set directly by
|
||||||
|
command-line options.
|
||||||
|
|
||||||
|
## Default settings
|
||||||
|
|
||||||
|
For new PiAware or Debian package installations, adaptive dynamic range mode
|
||||||
|
is enabled by default and adaptive burst mode is disabled by default.
|
||||||
|
|
||||||
|
For _upgrades_ of PiAware or the Debian package from versions older than 6.0,
|
||||||
|
both adaptive gain modes are disabled by default.
|
||||||
|
|
||||||
|
These defaults can be overridden as described below.
|
||||||
|
|
||||||
|
## Adaptive gain in dynamic range mode
|
||||||
|
|
||||||
|
The dynamic range adaptive gain mode attempts to set the receiver gain to
|
||||||
|
maintain a given dynamic range - that is, it tries to set the gain so that
|
||||||
|
general noise is at or below a given level. This takes into account different
|
||||||
|
or changing RF environments and different receiver hardware (antenna,
|
||||||
|
preamplifiers, etc) that affects the overall gain of the system, and usually
|
||||||
|
will pick a reasonable gain setting without intervention.
|
||||||
|
|
||||||
|
To enable this mode:
|
||||||
|
|
||||||
|
* Set `adaptive-dynamic-range yes` in piaware-config; or
|
||||||
|
* Set `ADAPTIVE_DYNAMIC_RANGE=yes` in `/etc/default/dump1090-fa`; or
|
||||||
|
* Pass the `--adaptive-range` option on the command line.
|
||||||
|
|
||||||
|
The default settings for dynamic range will use a dynamic range target chosen
|
||||||
|
based on SDR type (e.g. 30dB for rtlsdr receivers). This is usually a good
|
||||||
|
default. To override this target:
|
||||||
|
|
||||||
|
* Set `adaptive-dynamic-range-target` in piaware-config; or
|
||||||
|
* Set `ADAPTIVE_DYNAMIC_RANGE_TARGET` in `/etc/default/dump1090-fa`; or
|
||||||
|
* Pass the `--adaptive-range-target` option on the command line.
|
||||||
|
|
||||||
|
## Adaptive gain in "burst" / loud signal mode
|
||||||
|
|
||||||
|
The "burst" adaptive gain mode listens for loud bursts of signal that were
|
||||||
|
_not_ successfully decoded as ADS-B messages, but which have approximately
|
||||||
|
the right timing to be possible messages that were lost due to receiver
|
||||||
|
overloading. When enough overly-loud signals are heard in a short period of
|
||||||
|
time, dump1090 will _reduce_ the receiver gain to try to allow them to be
|
||||||
|
received.
|
||||||
|
|
||||||
|
This is a more situational setting. It may allow reception of loud nearby
|
||||||
|
aircraft (e.g. if you are close to an airport). The tradeoff is that when
|
||||||
|
there are nearby aircraft, overall receiver range may be reduced. Whether
|
||||||
|
this is a good tradeoff depends on the aircraft you're interested in.
|
||||||
|
By default, adaptive gain burst mode is disabled.
|
||||||
|
|
||||||
|
To enable burst mode:
|
||||||
|
|
||||||
|
* Set `adaptive-burst yes` in piaware-config; or
|
||||||
|
* Set `ADAPTIVE_BURST=yes` in `/etc/default/dump1090-fa`; or
|
||||||
|
* Pass the `--adaptive-burst` option on the command line.
|
||||||
|
|
||||||
|
This mode is more experimental than the dynamic range mode and tweaking of
|
||||||
|
the advanced burst options may be needed depending on your local installation.
|
||||||
|
In particular, `--adaptive-burst-loud-rate` and `adaptive-burst-quiet-rate`
|
||||||
|
may need adjusting. Feedback on what works for you and what doesn't would
|
||||||
|
be appreciated!
|
||||||
|
|
||||||
|
Burst mode and dynamic range mode can be enabled at the same time.
|
||||||
|
|
||||||
|
## Limiting the gain range
|
||||||
|
|
||||||
|
If you know in advance approximately what the gain setting should be, so
|
||||||
|
you want to allow adaptive gain to change the gain only within a certain range,
|
||||||
|
you can set minimum and maximum gain settings in dB. Adaptive gain will only
|
||||||
|
adjust the gain within this range. To set this:
|
||||||
|
|
||||||
|
* Set `adaptive-min-gain` and `adaptive-max-gain` in piaware-config; or
|
||||||
|
* Set `ADAPTIVE_MIN_GAIN` and `ADAPTIVE_MAX_GAIN` in `/etc/default/dump1090-fa`; or
|
||||||
|
* Pass the `--adaptive-min-gain` and `--adaptive-max-gain` options on the command line.
|
||||||
|
|
||||||
|
If you know approximately where the gain should be, then a good starting point would be
|
||||||
|
to set the max and min adaptive gain to +/- 10dB around your gain setting.
|
||||||
|
|
||||||
|
## Reducing the CPU cost of adaptive gain
|
||||||
|
|
||||||
|
The measurements needed to adjust gain have a CPU cost, and on slower
|
||||||
|
devices it may be useful to reduce the amount of work that adaptive gain does.
|
||||||
|
This can be done by adjusting the adaptive gain duty cycle. This is a
|
||||||
|
percentage that controls what fraction of incoming data adaptive gain inspects.
|
||||||
|
100% means that every sample is inspected. Lower values reduce CPU use, with
|
||||||
|
a tradeoff that adaptive gain has a less accurate picture of the RF
|
||||||
|
environment. The default duty cycle is 50% on "fast" CPUs and 10% on "slow"
|
||||||
|
CPUs (where currently "slow" means "armv6 architecture", for example the
|
||||||
|
Pi Zero or Pi 1). To reduce the duty cycle further:
|
||||||
|
|
||||||
|
* Set `slow-cpu yes` in piaware-config; or
|
||||||
|
* Set `SLOW_CPU=yes` in `/etc/default/dump1090-fa`; or
|
||||||
|
* Pass the `--adaptive-duty-cycle` option on the command line
|
||||||
|
|
||||||
|
## Advanced options
|
||||||
|
|
||||||
|
There are a number of advanced options that are only supported as
|
||||||
|
command-line options or via the EXTRA_OPTIONS setting in
|
||||||
|
`/etc/default/dump1090-fa`. They tweak settings that require some knowledge of
|
||||||
|
dump1090 internals to make sense of, so YMMV.
|
||||||
|
|
||||||
|
For a complete list of options, run `dump1090-fa --help` and look at the
|
||||||
|
adaptive gain section.
|
||||||
|
|
||||||
|
## Device support
|
||||||
|
|
||||||
|
Currently, adaptive gain is only supported on rtlsdr devices. Support for other
|
||||||
|
SDRs is planned for the future.
|
||||||
|
|
||||||
|
If you're a developer and want to add support for your SDR, you'll need
|
||||||
|
to implement the gain control API used in `sdr.[ch]`. See `sdr_rtlsdr.c`
|
||||||
|
(`rtlsdrGetGain`, `rtlsdrSetGain`, etc) for examples.
|
||||||
|
|
||||||
|
## Comparison with wiedehopf's auto-gain scripts
|
||||||
|
|
||||||
|
There is an [auto-gain script](https://github.com/wiedehopf/adsb-scripts/wiki/Automatic-gain-optimization-for-readsb-and-dump1090-fa)
|
||||||
|
written by [wiedehopf](https://github.com/wiedehopf) that aims to solve similar
|
||||||
|
problems. The implementation approaches are quite different, and which one works best
|
||||||
|
for you will depend on the problem you're trying to solve.
|
||||||
|
|
||||||
|
The major differences between adaptive gain and the auto-gain script are:
|
||||||
|
|
||||||
|
* Adaptive gain works on short-term data (seconds or minutes) and can react to
|
||||||
|
changes in a similar timeframe. It tries to set an appropriate gain for the
|
||||||
|
_current_ environment without much regard for longer-term trends. The auto-gain
|
||||||
|
script looks at data over longer timeframes (1+ days) and reacts more slowly,
|
||||||
|
but takes into account data across that whole period.
|
||||||
|
|
||||||
|
* Adaptive gain in dynamic range mode looks at an estimate of the noise floor
|
||||||
|
to decide whether to increase gain. Adaptive gain in burst mode looks at the
|
||||||
|
signal strength of samples that were _not_ successfully decoded to decide when
|
||||||
|
to reduce gain. The auto-gain scripts look at the signal strength of _successfully_
|
||||||
|
decoded messages to decide when to increase or decrease gain. These are each measuring
|
||||||
|
something different, and which is most effective will depend on the exact RF
|
||||||
|
environment.
|
||||||
|
|
||||||
|
* Adaptive gain burst mode and the auto-gain script superfically measure similar things,
|
||||||
|
but the difference in measurement timeframe mean they react quite differently. Burst mode
|
||||||
|
tries to react to transient loud signals i.e. temporarily nearby aircraft. The auto-gain
|
||||||
|
script uses the loud-messages fraction as an estimate for messages lost to excessive
|
||||||
|
gain over the long term, not only the transient case.
|
||||||
|
|
||||||
|
* Adaptive gain has a few less moving parts (i.e. no external scripts, no config changes over
|
||||||
|
time) as it's built directly into dump1090 itself.
|
||||||
206
README.md
206
README.md
|
|
@ -1,154 +1,122 @@
|
||||||
# dump1090-mutability Debian/Raspbian packages
|
# dump1090-fa Debian/Raspbian packages
|
||||||
|
|
||||||
This is a fork of MalcolmRobb's version of dump1090
|
dump1090-fa is a ADS-B, Mode S, and Mode 3A/3C demodulator and decoder that
|
||||||
that adds new functionality and is designed to be built as
|
will receive and decode aircraft transponder messages received via
|
||||||
a Debian/Raspbian package.
|
a directly connected software defined radio, or from data provided over a
|
||||||
|
network connection.
|
||||||
|
|
||||||
This version is licensed under the GPL (v2 or later).
|
It is the successor to
|
||||||
See the file COPYING for details.
|
[dump1090-mutability](https://github.com/mutability/dump1090) and is
|
||||||
|
maintained by [FlightAware](http://flightaware.com/).
|
||||||
|
|
||||||
# Features
|
It can provide a display of locally received aircraft data in a terminal or
|
||||||
|
via a browser map. Together with [PiAware](http://flightaware.com/adsb/piaware)
|
||||||
|
it can be used to contribute crowd-sourced flight tracking data to FlightAware.
|
||||||
|
|
||||||
* 2.4MHz "oversampling" support
|
It is designed to build as a Debian package, but should also be buildable on
|
||||||
* doesn't run as root
|
many other Linux or Unix-like systems.
|
||||||
* supports FlightAware-TSV-format connections directly (same as the FlightAware version - no faup1090 needed)
|
|
||||||
* can start from init.d, with detailed config via debconf or `/etc/default/dump1090-mutability`
|
|
||||||
* can serve the virtual radar map via an external webserver (lighttpd integration included by default)
|
|
||||||
* map view uses receiver lat/long given to dump1090 automatically
|
|
||||||
* somewhat cleaned-up network code
|
|
||||||
* tries to do things "the debian way" when it comes to config, package structure, etc
|
|
||||||
* probably a bunch of other things I've forgotten..
|
|
||||||
|
|
||||||
# Simple install via apt-get
|
## Building under bullseye, buster, or stretch
|
||||||
|
|
||||||
There is a repository that contains the current releases. To set up the repository:
|
```bash
|
||||||
|
$ sudo apt-get install build-essential fakeroot debhelper librtlsdr-dev pkg-config libncurses5-dev libbladerf-dev libhackrf-dev liblimesuite-dev
|
||||||
|
$ ./prepare-build.sh bullseye # or buster, or stretch
|
||||||
|
$ cd package-bullseye # or buster, or stretch
|
||||||
|
$ dpkg-buildpackage -b --no-sign
|
||||||
|
```
|
||||||
|
|
||||||
````
|
## Building with limited dependencies
|
||||||
$ wget https://github.com/mutability/mutability-repo/releases/download/v0.1.0/mutability-repo_0.1.0_armhf.deb
|
|
||||||
$ sudo dpkg -i mutability-repo_0.1.0_armhf.deb
|
|
||||||
````
|
|
||||||
|
|
||||||
Then you can install and upgrade packages via apt-get as needed:
|
(Supported for bullseye and buster builds only)
|
||||||
|
|
||||||
````
|
The package supports some build profiles to allow building without all
|
||||||
$ sudo apt-get update && sudo apt-get install dump1090-mutability
|
required SDR libraries being present. This will produce a package with
|
||||||
$ sudo dpkg-reconfigure dump1090-mutability # for detailed configuration
|
limited SDR support only.
|
||||||
$ sudo apt-get install lighttpd && sudo lighty-enable-mod dump1090 # if you want to use the external webserver integration
|
|
||||||
````
|
|
||||||
|
|
||||||
Installing the mutability-repo package also installs the public key used to sign the packages; the signatures will be verified automatically by apt-get.
|
Pass `--build-profiles` to `dpkg-buildpackage` with a comma-separated list of
|
||||||
|
profiles. The list of profiles should include `custom` and zero or more of
|
||||||
|
`rtlsdr`, `bladerf`, `hackrf`, `limesdr` depending on what you want:
|
||||||
|
|
||||||
# Manual repository setup
|
```bash
|
||||||
|
$ dpkg-buildpackage -b --no-sign --build-profiles=custom,rtlsdr # builds with rtlsdr support only
|
||||||
|
$ dpkg-buildpackage -b --no-sign --build-profiles=custom,rtlsdr,bladerf # builds with rtlsdr and bladeRF support
|
||||||
|
$ dpkg-buildpackage -b --no-sign --build-profiles=custom # builds with _no_ SDR support (network support only)
|
||||||
|
```
|
||||||
|
|
||||||
Add a suitable entry to sources.list:
|
## Building manually
|
||||||
|
|
||||||
````
|
You can probably just run "make" after installing the required dependencies.
|
||||||
# echo "deb http://repo.mutability.co.uk/raspbian wheezy rpi" >/etc/apt/sources.list.d/mutabiltiy.list
|
Binaries are built in the source directory; you will need to arrange to
|
||||||
````
|
install them (and a method for starting them) yourself.
|
||||||
|
|
||||||
Obtain the public key used to sign the repository release by a method of your choice. This is the signing key:
|
``make BLADERF=no`` will disable bladeRF support and remove the dependency on
|
||||||
|
libbladeRF.
|
||||||
|
|
||||||
````
|
``make RTLSDR=no`` will disable rtl-sdr support and remove the dependency on
|
||||||
pub 2048R/4D731812 2014-12-28 [expires: 2015-12-28]
|
librtlsdr.
|
||||||
Key fingerprint = 2098 7C8D D31A 6107 E033 7CC3 80D5 57AA 4D73 1812
|
|
||||||
uid Oliver Jowett (repo.mutability.co.uk archive signing key) <oliver@mutability.co.uk>
|
|
||||||
````
|
|
||||||
|
|
||||||
which is available from:
|
``make HACKRF=no`` will disable HackRF support and remove the dependency on
|
||||||
|
libhackrf.
|
||||||
|
|
||||||
* [GitHub](https://github.com/mutability/mutability-repo/raw/master/mutability.gpg)
|
``make LIMESDR=no`` will disable LimeSDR support and remove the dependency on
|
||||||
* [repo.mutability.co.uk](http://repo.mutability.co.uk/mutability.gpg) (caution - not HTTPS!)
|
libLimeSuite.
|
||||||
* keys.gnupg.net (`gpg --keyserver keys.gnupg.net --recv-keys 4D731812`)
|
|
||||||
|
|
||||||
Install the key with `apt-key add` or by placing the keyring in `/etc/apt/trusted.gpg.d/`
|
## Building on OSX
|
||||||
|
|
||||||
# Manual installation
|
Minimal testing on Mojave 10.14.6, YMMV.
|
||||||
|
|
||||||
To install from packages directly:
|
```
|
||||||
|
$ brew install librtlsdr
|
||||||
|
$ brew install libbladerf
|
||||||
|
$ brew install hackrf
|
||||||
|
$ brew install pkg-config
|
||||||
|
$ make
|
||||||
|
```
|
||||||
|
|
||||||
You will need a librtlsdr0 package for Raspbian.
|
## Building on FreeBSD
|
||||||
There is no standard build of this.
|
|
||||||
I have built suitable packages that are available from
|
|
||||||
[this release page](https://github.com/mutability/librtlsdr/releases)
|
|
||||||
|
|
||||||
Then you will need the dump1090-mutability package itself from
|
Minimal testing on 12.1-RELEASE, YMMV.
|
||||||
[this release page](https://github.com/mutability/dump1090/releases)
|
|
||||||
|
|
||||||
Install the packages with dpkg.
|
```
|
||||||
|
# pkg install gmake
|
||||||
|
# pkg install pkgconf
|
||||||
|
# pkg install rtl-sdr
|
||||||
|
# pkg install bladerf
|
||||||
|
# pkg install hackrf
|
||||||
|
$ gmake
|
||||||
|
```
|
||||||
|
|
||||||
# Configuration
|
## Generating wisdom files
|
||||||
|
|
||||||
By default it'll only ask you whether to start automatically and assume sensible defaults for everything else.
|
dump1090-fa uses [starch](https://github.com/flightaware/starch) to build
|
||||||
Notable defaults that are perhaps not what you'd first expect:
|
multiple versions of the DSP code and choose the fastest supported by the
|
||||||
|
hardware at runtime. The implementations chosen can been seen by running
|
||||||
|
`dump1090-fa --version`.
|
||||||
|
|
||||||
* All network ports are bound to the localhost interface only.
|
The implementations used are controlled by "wisdom files", a list of
|
||||||
If you need remote access to the ADS-B data ports, you will want to change this to bind to the wildcard address.
|
implementations to use in order of priority. For each DSP function, the first
|
||||||
* The internal HTTP server is disabled. I recommend using an external webserver (see below).
|
implementation listed that's supported by the current hardware is used.
|
||||||
You can reconfigure to enable the internal one if you don't want to use an external one.
|
By default dump1090-fa provides compiled-in wisdom for [x86](wisdom.x86),
|
||||||
|
[ARM 32-bit](wisdom.arm), and [ARM 64-bit](wisdom.aarch64). If the defaults
|
||||||
|
are not suitable for your hardware or if you're building on a different
|
||||||
|
architecture, you may want to generate your own external wisdom file.
|
||||||
|
|
||||||
To reconfigure, either use `dpkg-reconfigure dump1090-mutability` or edit `/etc/default/dump1090-mutability`. Both should be self-explanatory.
|
Ideally, to get stable results, you want to do this on an idle system
|
||||||
|
with CPU frequency scaling disabled. Running the benchmarks will take
|
||||||
|
some time (10s of minutes).
|
||||||
|
|
||||||
## External webserver configuration
|
### Package installs
|
||||||
|
|
||||||
This is the recommended configuration; a dedicated webserver is almost always going to be better and more secure than the collection of hacks that is the dump1090 webserver.
|
Run `/usr/share/dump1090-fa/generate-wisdom`. Wait.
|
||||||
It works by having dump1090 write json files to a path under `/run` once a second (this is on tmpfs and will not write to the sdcard).
|
|
||||||
Then an external webserver is used to serve both the static html/javascript files making up the map view, and the json files that provide the dynamic data.
|
|
||||||
|
|
||||||
The package includes a config file for lighttpd (which is what I happen to use on my system).
|
Follow the instructions to copy the resulting wisdom file to `/etc/dump1090-fa/wisdom.local`.
|
||||||
To use this:
|
|
||||||
|
|
||||||
````
|
Restart dump1090.
|
||||||
# apt-get install lighttpd # if you don't have it already
|
|
||||||
# lighty-enable-mod dump1090
|
|
||||||
# service lighttpd force-reload
|
|
||||||
````
|
|
||||||
|
|
||||||
This uses a configuration file installed by the package at `/etc/lighttpd/conf-available/89-dump1090.conf`.
|
### Manual installs
|
||||||
It makes the map view available at http://<pi address>/dump1090/
|
|
||||||
|
|
||||||
This should also work fine with other webservers, you will need to write a similar config to the lighttpd one (it's basically just a couple of aliases).
|
Run `make wisdom.local`. Wait.
|
||||||
If you do set up a config for something else, please send me a copy so I can integrate it into the package!
|
|
||||||
|
|
||||||
## Logging
|
Copy the resulting `wisdom.local` file somewhere appropriate.
|
||||||
|
|
||||||
The default configuration logs to `/var/log/dump1090-mutability.log` (this can be reconfigured).
|
Update the dump1090-fa command-line options to include `--wisdom /path/to/wisdom.local`
|
||||||
The only real logging other than any startup problems is hourly stats.
|
|
||||||
There is a logrotate configuration installed by the package at `/etc/logrotate.d/dump1090-mutability` that will rotate that logfile weekly.
|
|
||||||
|
|
||||||
# Bug reports, feedback etc
|
|
||||||
|
|
||||||
Please use the [github issues page](https://github.com/mutability/dump1090/issues) to report any problems.
|
|
||||||
Or you can [email me](mailto:oliver@mutability.co.uk).
|
|
||||||
|
|
||||||
# Future plans
|
|
||||||
|
|
||||||
Packages following the same model for MalcolmRobb & FlightAware's forks of dump1090 are in the pipeline.
|
|
||||||
So is a repackaged version of piaware.
|
|
||||||
|
|
||||||
# Building from source
|
|
||||||
|
|
||||||
While there is a Makefile that you can use, the preferred way to build is via the Debian package building system:
|
|
||||||
|
|
||||||
````
|
|
||||||
$ sudo apt-get install librtlsdr-dev libusb-1.0-0-dev pkg-config debhelper
|
|
||||||
$ dpkg-buildpackage -b
|
|
||||||
````
|
|
||||||
|
|
||||||
Or you can use debuild/pdebuild. I find building via qemubuilder quite effective for building images for Raspbian (it's actually faster to build on an emulated ARM running on my PC than to build directly on real hardware).
|
|
||||||
|
|
||||||
Here's the pbuilder config I use to build the Raspbian packages:
|
|
||||||
|
|
||||||
````
|
|
||||||
MIRRORSITE=http://mirrordirector.raspbian.org/raspbian/
|
|
||||||
PDEBUILD_PBUILDER=cowbuilder
|
|
||||||
BASEPATH=/var/cache/pbuilder/armhf-raspbian-wheezy-base.cow
|
|
||||||
DISTRIBUTION=wheezy
|
|
||||||
OTHERMIRROR="deb http://repo.mutability.co.uk/raspbian wheezy rpi"
|
|
||||||
ARCHITECTURE=armhf
|
|
||||||
DEBOOTSTRAP=qemu-debootstrap
|
|
||||||
DEBOOTSTRAPOPTS="--variant=buildd --keyring=/usr/share/keyrings/raspbian-archive-keyring.gpg"
|
|
||||||
COMPONENTS="main contrib non-free rpi"
|
|
||||||
EXTRAPACKAGES="eatmydata debhelper fakeroot"
|
|
||||||
ALLOWUNTRUSTED="no"
|
|
||||||
APTKEYRINGS=("/home/oliver/ppa/mutability.gpg")
|
|
||||||
````
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,645 @@
|
||||||
|
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// adaptive.c: adaptive gain control
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 FlightAware, LLC
|
||||||
|
//
|
||||||
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the
|
||||||
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
|
// option) any later version.
|
||||||
|
//
|
||||||
|
// This file is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "dump1090.h"
|
||||||
|
#include "adaptive.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// gain limits
|
||||||
|
//
|
||||||
|
static int adaptive_gain_min;
|
||||||
|
static int adaptive_gain_max;
|
||||||
|
|
||||||
|
// gain steps relative to current gain
|
||||||
|
static float adaptive_gain_up_db;
|
||||||
|
static float adaptive_gain_down_db;
|
||||||
|
|
||||||
|
//
|
||||||
|
// block handling
|
||||||
|
//
|
||||||
|
// 1 block = approx 1 second of samples. Control updates are done at the end of each block only.
|
||||||
|
// Each block is made up of an integer number of subblocks (currently 20)
|
||||||
|
//
|
||||||
|
// 1 subblock = approx 50ms of samples. Duty cycle decisions are made at the subblock level;
|
||||||
|
// either the whole subblock is processed, or the whole subblock is skipped.
|
||||||
|
// Each subblock is made up of an integer number of windows (currently 1250)
|
||||||
|
//
|
||||||
|
// 1 window = approx 40us of samples. Burst measurements are made by counting samples within each window.
|
||||||
|
//
|
||||||
|
// All three levels are aligned, i.e. every block boundary is also a subblock boundary;
|
||||||
|
// every subblock boundary is also a window boundary.
|
||||||
|
|
||||||
|
|
||||||
|
static const unsigned adaptive_subblocks_per_block = 20; // subblocks per block
|
||||||
|
static unsigned adaptive_subblocks_remaining; // subblocks remaining in the current block
|
||||||
|
|
||||||
|
// Duty cycle is expressed as N/D
|
||||||
|
// where N = adaptive_subblbock_dutycycle_N = adaptive_subblocks_per_block * Modes.adaptive_duty_cycle
|
||||||
|
// and D = adaptive_subblocks_dutycycle_D = adaptive_subblocks_per_block
|
||||||
|
//
|
||||||
|
// i.e. within each block, there are exactly N active subblocks out of D total subblocks
|
||||||
|
//
|
||||||
|
// The active subblocks are distributed evenly across the block by increasing a counter by N on each
|
||||||
|
// subblock, modulo D, and marking the subblock as active each time the counter rolls over.
|
||||||
|
|
||||||
|
static unsigned adaptive_subblock_dutycycle_N; // subblock duty cycle numerator N
|
||||||
|
|
||||||
|
// stretch gcc doesn't like this as a separate const
|
||||||
|
#define adaptive_subblock_dutycycle_D adaptive_subblocks_per_block
|
||||||
|
|
||||||
|
static unsigned adaptive_subblock_dutycycle_counter; // subblock duty cycle counter (modulo D)
|
||||||
|
static bool adaptive_subblock_active; // is the current subblock active i.e. samples should be processed, not skipped?
|
||||||
|
|
||||||
|
static unsigned adaptive_samples_per_subblock; // samples per subblock
|
||||||
|
static unsigned adaptive_subblock_samples_remaining; // samples remaining in the current subblock
|
||||||
|
|
||||||
|
static unsigned adaptive_samples_per_window; // samples per window
|
||||||
|
|
||||||
|
void adaptive_init();
|
||||||
|
void adaptive_update(uint16_t *buf, unsigned length, struct modesMessage *decoded);
|
||||||
|
static void adaptive_update_subblock(uint16_t *buf, unsigned length, struct modesMessage *decoded);
|
||||||
|
static void adaptive_end_of_block();
|
||||||
|
static void adaptive_control_update();
|
||||||
|
|
||||||
|
//
|
||||||
|
// burst handling
|
||||||
|
//
|
||||||
|
|
||||||
|
static unsigned adaptive_burst_window_remaining; // samples remaining in the current burst window
|
||||||
|
static unsigned adaptive_burst_window_counter; // loud samples seen in current burst window
|
||||||
|
static unsigned adaptive_burst_runlength; // consecutive loud burst windows seen
|
||||||
|
static unsigned adaptive_burst_block_loud_undecoded; // loud undecoded bursts seen in this block so far
|
||||||
|
static unsigned adaptive_burst_block_loud_decoded; // loud decoded messages seen in this block so far
|
||||||
|
static double adaptive_burst_loud_undecoded_smoothed; // smoothed rate of loud misdecodes per block
|
||||||
|
static double adaptive_burst_loud_decoded_smoothed; // smoothed rate of loud successful decodes per block
|
||||||
|
static unsigned adaptive_burst_change_timer; // countdown inhibiting control after changing gain
|
||||||
|
static double adaptive_burst_loud_threshold; // current signal level threshold for a "loud decode"
|
||||||
|
static unsigned adaptive_burst_loud_blocks = 0; // consecutive blocks with loud rate
|
||||||
|
static unsigned adaptive_burst_quiet_blocks = 0; // consecutive blocks with quiet rate
|
||||||
|
|
||||||
|
static void adaptive_burst_update(uint16_t *buf, unsigned length);
|
||||||
|
static void adaptive_burst_skip(unsigned length);
|
||||||
|
static unsigned adaptive_burst_count_samples(uint16_t *buf, unsigned n);
|
||||||
|
static void adaptive_burst_scan_windows(uint16_t *buf, unsigned windows);
|
||||||
|
static void adaptive_burst_end_of_window(unsigned counter);
|
||||||
|
static void adaptive_burst_end_of_block();
|
||||||
|
|
||||||
|
//
|
||||||
|
// noise floor measurement (adaptive dynamic range)
|
||||||
|
//
|
||||||
|
|
||||||
|
static unsigned *adaptive_range_radix; // radix-sort buckets for current block
|
||||||
|
static unsigned adaptive_range_radix_counter; // sum of all radix-sort buckets (= number of samples sorted)
|
||||||
|
static double adaptive_range_smoothed; // smoothed noise floor estimate, dBFS
|
||||||
|
static enum { RANGE_SCAN_IDLE, RANGE_SCAN_UP, RANGE_SCAN_DOWN, RANGE_RESCAN_UP, RANGE_RESCAN_DOWN } adaptive_range_state = RANGE_SCAN_UP;
|
||||||
|
static unsigned adaptive_range_change_timer; // countdown inhibiting control after changing gain
|
||||||
|
static unsigned adaptive_range_rescan_timer; // countdown to next upwards gain reprobe
|
||||||
|
static int adaptive_range_gain_limit; // probed maximum gain step with acceptable dynamic range
|
||||||
|
|
||||||
|
static void adaptive_range_update(uint16_t *buf, unsigned length);
|
||||||
|
static void adaptive_range_end_of_block();
|
||||||
|
|
||||||
|
// Try to change the SDR gain to 'step' and tell the user about it,
|
||||||
|
// with 'why' as the reason to show. Return true if the gain actually changed.
|
||||||
|
static bool adaptive_set_gain(int step, const char *why)
|
||||||
|
{
|
||||||
|
if (step < adaptive_gain_min)
|
||||||
|
step = adaptive_gain_min;
|
||||||
|
if (step > adaptive_gain_max)
|
||||||
|
step = adaptive_gain_max;
|
||||||
|
|
||||||
|
int current_gain = sdrGetGain();
|
||||||
|
if (current_gain == step)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
fprintf(stderr, "adaptive: changing gain from %.1fdB (step %d) to %.1fdB (step %d) because: %s\n",
|
||||||
|
sdrGetGainDb(current_gain), current_gain, sdrGetGainDb(step), step, why);
|
||||||
|
|
||||||
|
int new_gain = sdrSetGain(step);
|
||||||
|
bool changed = (current_gain != new_gain);
|
||||||
|
if (changed)
|
||||||
|
++Modes.stats_current.adaptive_gain_changes;
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update internal state to reflect a gain change
|
||||||
|
// (usually after adaptive_set_gain returns true, but also called during init)
|
||||||
|
static void adaptive_gain_changed()
|
||||||
|
{
|
||||||
|
int new_gain = sdrGetGain();
|
||||||
|
adaptive_gain_up_db = sdrGetGainDb(new_gain + 1) - sdrGetGainDb(new_gain);
|
||||||
|
adaptive_gain_down_db = sdrGetGainDb(new_gain) - sdrGetGainDb(new_gain - 1);
|
||||||
|
|
||||||
|
double loud_threshold_dbfs = 0 - adaptive_gain_up_db - 3.0;
|
||||||
|
adaptive_burst_loud_threshold = pow(10, loud_threshold_dbfs / 10.0);
|
||||||
|
|
||||||
|
adaptive_range_change_timer = Modes.adaptive_range_change_delay;
|
||||||
|
adaptive_burst_change_timer = Modes.adaptive_burst_change_delay;
|
||||||
|
adaptive_burst_loud_blocks = 0;
|
||||||
|
adaptive_burst_quiet_blocks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// External init entry point
|
||||||
|
void adaptive_init()
|
||||||
|
{
|
||||||
|
int maxgain = sdrGetMaxGain();
|
||||||
|
|
||||||
|
// If the SDR doesn't support gain control, disable ourselves
|
||||||
|
if (maxgain < 0) {
|
||||||
|
if (Modes.adaptive_burst_control || Modes.adaptive_range_control) {
|
||||||
|
fprintf(stderr, "warning: adaptive gain control requested, but SDR gain control not available, ignored.\n");
|
||||||
|
}
|
||||||
|
Modes.adaptive_burst_control = false;
|
||||||
|
Modes.adaptive_range_control = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're disabled, do nothing
|
||||||
|
if (!Modes.adaptive_burst_control && !Modes.adaptive_range_control)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Set up window, subblock, and block sizes
|
||||||
|
// Look for 40us bursts
|
||||||
|
adaptive_samples_per_window = Modes.sample_rate / 25000;
|
||||||
|
|
||||||
|
// Use ~50ms subblocks; ensure it's an exact multiple of window size
|
||||||
|
adaptive_samples_per_subblock = adaptive_samples_per_window * 1250;
|
||||||
|
|
||||||
|
adaptive_subblocks_remaining = adaptive_subblocks_per_block;
|
||||||
|
adaptive_subblock_samples_remaining = adaptive_samples_per_subblock;
|
||||||
|
adaptive_subblock_active = false;
|
||||||
|
|
||||||
|
float N = roundf(adaptive_subblock_dutycycle_D * Modes.adaptive_duty_cycle);
|
||||||
|
if (N <= 0)
|
||||||
|
N = 1;
|
||||||
|
if (N > adaptive_subblock_dutycycle_D)
|
||||||
|
N = adaptive_subblock_dutycycle_D;
|
||||||
|
fprintf(stderr, "adaptive: using %.0f%% duty cycle\n", 100.0 * N / adaptive_subblock_dutycycle_D);
|
||||||
|
adaptive_subblock_dutycycle_N = (unsigned)N;
|
||||||
|
|
||||||
|
adaptive_burst_window_remaining = adaptive_samples_per_window;
|
||||||
|
adaptive_burst_window_counter = 0;
|
||||||
|
|
||||||
|
adaptive_range_radix = calloc(sizeof(unsigned), 65536);
|
||||||
|
adaptive_range_state = RANGE_RESCAN_UP;
|
||||||
|
|
||||||
|
// select and enforce gain limits
|
||||||
|
for (adaptive_gain_min = 0; adaptive_gain_min < maxgain; ++adaptive_gain_min) {
|
||||||
|
if (sdrGetGainDb(adaptive_gain_min) >= Modes.adaptive_min_gain_db)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (adaptive_gain_max = maxgain; adaptive_gain_max > adaptive_gain_min; --adaptive_gain_max) {
|
||||||
|
if (sdrGetGainDb(adaptive_gain_max) <= Modes.adaptive_max_gain_db)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "adaptive: enabled adaptive gain control with gain limits %.1fdB (step %d) .. %.1fdB (step %d)\n",
|
||||||
|
sdrGetGainDb(adaptive_gain_min), adaptive_gain_min, sdrGetGainDb(adaptive_gain_max), adaptive_gain_max);
|
||||||
|
if (Modes.adaptive_range_control)
|
||||||
|
fprintf(stderr, "adaptive: enabled dynamic range control, target dynamic range %.1fdB\n", Modes.adaptive_range_target);
|
||||||
|
if (Modes.adaptive_burst_control)
|
||||||
|
fprintf(stderr, "adaptive: enabled burst control\n");
|
||||||
|
adaptive_set_gain(sdrGetGain(), "constraining gain to adaptive gain limits");
|
||||||
|
adaptive_gain_changed();
|
||||||
|
|
||||||
|
adaptive_range_gain_limit = sdrGetGain();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feed some samples into the adaptive system. Any number of samples might be passed in.
|
||||||
|
void adaptive_update(uint16_t *buf, unsigned length, struct modesMessage *decoded)
|
||||||
|
{
|
||||||
|
if (!Modes.adaptive_burst_control && !Modes.adaptive_range_control)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// process complete subblocks
|
||||||
|
while (length >= adaptive_subblock_samples_remaining) {
|
||||||
|
if (adaptive_subblock_active)
|
||||||
|
adaptive_update_subblock(buf, adaptive_subblock_samples_remaining, decoded);
|
||||||
|
|
||||||
|
buf += adaptive_subblock_samples_remaining;
|
||||||
|
length -= adaptive_subblock_samples_remaining;
|
||||||
|
adaptive_subblock_samples_remaining = adaptive_samples_per_subblock;
|
||||||
|
|
||||||
|
adaptive_subblock_dutycycle_counter += adaptive_subblock_dutycycle_N;
|
||||||
|
if (adaptive_subblock_dutycycle_counter >= adaptive_subblock_dutycycle_D) {
|
||||||
|
adaptive_subblock_dutycycle_counter -= adaptive_subblock_dutycycle_D;
|
||||||
|
adaptive_subblock_active = true;
|
||||||
|
} else {
|
||||||
|
adaptive_subblock_active = false;
|
||||||
|
// fake a quiet window to reset any existing run
|
||||||
|
adaptive_burst_end_of_window(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!--adaptive_subblocks_remaining) {
|
||||||
|
// Block completed, do a control update
|
||||||
|
adaptive_subblocks_remaining = adaptive_subblocks_per_block;
|
||||||
|
adaptive_end_of_block();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// process final samples that don't complete a subblock
|
||||||
|
if (length > 0) {
|
||||||
|
if (adaptive_subblock_active)
|
||||||
|
adaptive_update_subblock(buf, length, decoded);
|
||||||
|
adaptive_subblock_samples_remaining -= length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feed some samples into the adaptive system. The samples are guaranteed to not cross a subblock boundary.
|
||||||
|
// The samples should be processsed (i.e. duty cycle is in the active part)
|
||||||
|
static void adaptive_update_subblock(uint16_t *buf, unsigned length, struct modesMessage *decoded)
|
||||||
|
{
|
||||||
|
if (decoded) {
|
||||||
|
if (/* decoded->msgbits == 112 && */ decoded->signalLevel >= adaptive_burst_loud_threshold)
|
||||||
|
++adaptive_burst_block_loud_decoded;
|
||||||
|
adaptive_burst_skip(length);
|
||||||
|
} else {
|
||||||
|
adaptive_burst_update(buf, length);
|
||||||
|
adaptive_range_update(buf, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Burst measurement: ignore the next 'length' samples (they are a successfully decoded message)
|
||||||
|
static void adaptive_burst_skip(unsigned length)
|
||||||
|
{
|
||||||
|
if (!Modes.adaptive_burst_control)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// first window
|
||||||
|
if (length < adaptive_burst_window_remaining) {
|
||||||
|
// partial fill
|
||||||
|
adaptive_burst_window_remaining -= length;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip remainder of first window, dispatch it
|
||||||
|
adaptive_burst_end_of_window(adaptive_burst_window_counter);
|
||||||
|
length -= adaptive_burst_window_remaining;
|
||||||
|
|
||||||
|
// skip remaining windows, dispatch them
|
||||||
|
unsigned windows = length / adaptive_samples_per_window;
|
||||||
|
unsigned samples = windows * adaptive_samples_per_window;
|
||||||
|
while (windows--)
|
||||||
|
adaptive_burst_end_of_window(0);
|
||||||
|
|
||||||
|
length -= samples;
|
||||||
|
|
||||||
|
// final partial window
|
||||||
|
adaptive_burst_window_counter = 0;
|
||||||
|
adaptive_burst_window_remaining = adaptive_samples_per_window - length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Burst measurement: process 'length' samples from 'buf', look for loud bursts;
|
||||||
|
// the samples might cross burst window boundaries;
|
||||||
|
// the samples will not cross a block boundary.
|
||||||
|
static void adaptive_burst_update(uint16_t *buf, unsigned length)
|
||||||
|
{
|
||||||
|
if (!Modes.adaptive_burst_control)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// first window
|
||||||
|
if (length < adaptive_burst_window_remaining) {
|
||||||
|
// partial fill
|
||||||
|
adaptive_burst_window_counter += adaptive_burst_count_samples(buf, length);
|
||||||
|
adaptive_burst_window_remaining -= length;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// complete fill of first partial window
|
||||||
|
unsigned n = adaptive_burst_window_remaining;
|
||||||
|
unsigned counter = adaptive_burst_window_counter + adaptive_burst_count_samples(buf, n);
|
||||||
|
adaptive_burst_end_of_window(counter);
|
||||||
|
buf += n;
|
||||||
|
length -= n;
|
||||||
|
|
||||||
|
// remaining windows
|
||||||
|
unsigned windows = length / adaptive_samples_per_window;
|
||||||
|
unsigned samples = windows * adaptive_samples_per_window;
|
||||||
|
adaptive_burst_scan_windows(buf, windows);
|
||||||
|
buf += samples;
|
||||||
|
length -= samples;
|
||||||
|
|
||||||
|
// final partial window
|
||||||
|
adaptive_burst_window_counter = adaptive_burst_count_samples(buf, length);
|
||||||
|
adaptive_burst_window_remaining = adaptive_samples_per_window - length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Burst measurement: process 'windows' complete burst windows starting at 'buf';
|
||||||
|
// 'buf' is aligned to the start of a burst window
|
||||||
|
static void adaptive_burst_scan_windows(uint16_t *buf, unsigned windows)
|
||||||
|
{
|
||||||
|
while (windows--) {
|
||||||
|
unsigned counter = adaptive_burst_count_samples(buf, adaptive_samples_per_window);
|
||||||
|
buf += adaptive_samples_per_window;
|
||||||
|
adaptive_burst_end_of_window(counter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Burst measurement: process 'n' samples from 'buf', look for loud samples;
|
||||||
|
// the samples are guaranteed not to cross window boundaries;
|
||||||
|
// return the number of loud samples seen
|
||||||
|
static inline unsigned adaptive_burst_count_samples(uint16_t *buf, unsigned n)
|
||||||
|
{
|
||||||
|
unsigned counter;
|
||||||
|
starch_count_above_u16(buf, n, 46395 /* -3dBFS */, &counter);
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Burst measurement: we reached the end of a burst window with 'counter'
|
||||||
|
// loud samples seen, handle that window.
|
||||||
|
static void adaptive_burst_end_of_window(unsigned counter)
|
||||||
|
{
|
||||||
|
if (counter > adaptive_samples_per_window / 4) {
|
||||||
|
// This window is loud, extend any existing run of loud windows
|
||||||
|
++adaptive_burst_runlength;
|
||||||
|
} else {
|
||||||
|
// Quiet window. If we saw a run of loud windows >= 80us long, count
|
||||||
|
// that as a candidate for an over-amplified message that was
|
||||||
|
// not decoded.
|
||||||
|
if (adaptive_burst_runlength >= 2 && adaptive_burst_runlength <= 5)
|
||||||
|
++adaptive_burst_block_loud_undecoded;
|
||||||
|
adaptive_burst_runlength = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Noise measurement: process 'length' samples from 'buf'.
|
||||||
|
// The samples will not cross a block boundary.
|
||||||
|
static void adaptive_range_update(uint16_t *buf, unsigned length)
|
||||||
|
{
|
||||||
|
if (!Modes.adaptive_range_control)
|
||||||
|
return;
|
||||||
|
|
||||||
|
adaptive_range_radix_counter += length;
|
||||||
|
while (length--) {
|
||||||
|
// do a very simple radix sort of sample magnitudes
|
||||||
|
// so we can later find the Nth percentile value
|
||||||
|
++adaptive_range_radix[buf[0]];
|
||||||
|
++buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Noise measurement: we reached the end of a block, update
|
||||||
|
// our noise estimate
|
||||||
|
static void adaptive_range_end_of_block()
|
||||||
|
{
|
||||||
|
if (!Modes.adaptive_range_control)
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned n = 0, i = 0;
|
||||||
|
|
||||||
|
// measure Nth percentile magnitude
|
||||||
|
unsigned count_n = adaptive_range_radix_counter * Modes.adaptive_range_percentile / 100;
|
||||||
|
while (i < 65536 && n <= count_n)
|
||||||
|
n += adaptive_range_radix[i++];
|
||||||
|
uint16_t percentile_n = i - 1;
|
||||||
|
|
||||||
|
// maintain an EMA of the Nth percentile
|
||||||
|
adaptive_range_smoothed = adaptive_range_smoothed * (1 - Modes.adaptive_range_alpha) + percentile_n * Modes.adaptive_range_alpha;
|
||||||
|
// .. report to stats in dBFS
|
||||||
|
if (adaptive_range_smoothed > 0) {
|
||||||
|
Modes.stats_current.adaptive_noise_dbfs = 20 * log10(adaptive_range_smoothed / 65536.0);
|
||||||
|
} else {
|
||||||
|
Modes.stats_current.adaptive_noise_dbfs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset radix sort for the next block
|
||||||
|
memset(adaptive_range_radix, 0, 65536 * sizeof(unsigned));
|
||||||
|
adaptive_range_radix_counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Burst measurement: we reached the end of a block, update our burst rate estimate
|
||||||
|
static void adaptive_burst_end_of_block()
|
||||||
|
{
|
||||||
|
if (!Modes.adaptive_burst_control)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// scale rates based on the actual duty cycle fraction
|
||||||
|
// (e.g. if we are only inspecting 2/5 of samples, then scale the rate by 5/2)
|
||||||
|
double scale = (double)adaptive_subblock_dutycycle_D / adaptive_subblock_dutycycle_N;
|
||||||
|
|
||||||
|
// maintain an EMA of the number of undecoded loud bursts seen per block
|
||||||
|
Modes.stats_current.adaptive_loud_undecoded += adaptive_burst_block_loud_undecoded;
|
||||||
|
adaptive_burst_loud_undecoded_smoothed = adaptive_burst_loud_undecoded_smoothed * (1 - Modes.adaptive_burst_alpha) + scale * adaptive_burst_block_loud_undecoded * Modes.adaptive_burst_alpha;
|
||||||
|
adaptive_burst_block_loud_undecoded = 0;
|
||||||
|
|
||||||
|
// maintain an EMA of the number of decoded, but loud, messages seen per block
|
||||||
|
Modes.stats_current.adaptive_loud_decoded += adaptive_burst_block_loud_decoded;
|
||||||
|
adaptive_burst_loud_decoded_smoothed = adaptive_burst_loud_decoded_smoothed * (1 - Modes.adaptive_burst_alpha) + scale * adaptive_burst_block_loud_decoded * Modes.adaptive_burst_alpha;
|
||||||
|
adaptive_burst_block_loud_decoded = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void flush_stats(uint64_t now);
|
||||||
|
|
||||||
|
static void adaptive_increase_gain(const char *why)
|
||||||
|
{
|
||||||
|
if (adaptive_set_gain(sdrGetGain() + 1, why))
|
||||||
|
adaptive_gain_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void adaptive_decrease_gain(const char *why)
|
||||||
|
{
|
||||||
|
if (adaptive_set_gain(sdrGetGain() - 1, why))
|
||||||
|
adaptive_gain_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adaptive gain: we reached a block boundary. Update measurements and act on them.
|
||||||
|
static void adaptive_end_of_block()
|
||||||
|
{
|
||||||
|
adaptive_range_end_of_block();
|
||||||
|
adaptive_burst_end_of_block();
|
||||||
|
|
||||||
|
adaptive_control_update();
|
||||||
|
|
||||||
|
Modes.stats_current.adaptive_valid = true;
|
||||||
|
unsigned current = Modes.stats_current.adaptive_gain = sdrGetGain();
|
||||||
|
Modes.stats_current.adaptive_range_gain_limit = adaptive_range_gain_limit;
|
||||||
|
++Modes.stats_current.adaptive_gain_seconds[current < STATS_GAIN_COUNT ? current : STATS_GAIN_COUNT-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void adaptive_control_update()
|
||||||
|
{
|
||||||
|
// votes for what to do with the gain
|
||||||
|
// "gain_not_up" overlaps somewhat with "gain_down", but they are not identical;
|
||||||
|
// burst control may want to prevent gain from increasing, but not necessarily
|
||||||
|
// decrease gain.
|
||||||
|
|
||||||
|
bool gain_up = false;
|
||||||
|
const char *gain_up_reason = NULL;
|
||||||
|
bool gain_down = false;
|
||||||
|
const char *gain_down_reason = NULL;
|
||||||
|
bool gain_not_up = false;
|
||||||
|
|
||||||
|
int current_gain = sdrGetGain();
|
||||||
|
|
||||||
|
if (adaptive_burst_change_timer)
|
||||||
|
--adaptive_burst_change_timer;
|
||||||
|
if (adaptive_range_change_timer > 0)
|
||||||
|
--adaptive_range_change_timer;
|
||||||
|
if (adaptive_range_rescan_timer > 0)
|
||||||
|
--adaptive_range_rescan_timer;
|
||||||
|
|
||||||
|
if (Modes.adaptive_burst_control && !adaptive_burst_change_timer) {
|
||||||
|
if (adaptive_burst_loud_undecoded_smoothed > Modes.adaptive_burst_loud_rate) {
|
||||||
|
adaptive_burst_quiet_blocks = 0;
|
||||||
|
++adaptive_burst_loud_blocks;
|
||||||
|
} else if (adaptive_burst_loud_decoded_smoothed < Modes.adaptive_burst_quiet_rate) {
|
||||||
|
adaptive_burst_loud_blocks = 0;
|
||||||
|
++adaptive_burst_quiet_blocks;
|
||||||
|
} else {
|
||||||
|
adaptive_burst_loud_blocks = 0;
|
||||||
|
adaptive_burst_quiet_blocks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adaptive_burst_loud_blocks >= Modes.adaptive_burst_loud_runlength) {
|
||||||
|
// we need to reduce gain (further)
|
||||||
|
gain_down = gain_not_up = true;
|
||||||
|
gain_down_reason = "high rate of loud undecoded messages";
|
||||||
|
|
||||||
|
// if we're currently doing a downward scan, reducing gain further may confuse it;
|
||||||
|
// stop that scan and restart it once we are no longer in a reduced-gain state
|
||||||
|
if (adaptive_range_state == RANGE_SCAN_DOWN || adaptive_range_state == RANGE_RESCAN_DOWN) {
|
||||||
|
adaptive_range_state = RANGE_SCAN_IDLE;
|
||||||
|
adaptive_range_rescan_timer = 0;
|
||||||
|
}
|
||||||
|
} else if (adaptive_burst_quiet_blocks < Modes.adaptive_burst_quiet_runlength) {
|
||||||
|
// we're OK at the current gain, but should not increase it
|
||||||
|
gain_not_up = true;
|
||||||
|
} else if (current_gain < adaptive_range_gain_limit) {
|
||||||
|
// we're OK at the current gain, and can increase gain to the previously discovered
|
||||||
|
// dynamic range limit
|
||||||
|
gain_up = true;
|
||||||
|
gain_up_reason = "low loud message rate and gain below dynamic range limit";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Modes.adaptive_range_control && !adaptive_range_change_timer) {
|
||||||
|
float available_range = -20 * log10(adaptive_range_smoothed / 65536.0);
|
||||||
|
// allow the gain limit to increase if this gain setting is acceptable
|
||||||
|
// (decreasing the limit is done separately depending on the current state as we make slightly different decisions in IDLE
|
||||||
|
// to provide hysteresis)
|
||||||
|
if (available_range >= Modes.adaptive_range_target && current_gain > adaptive_range_gain_limit) {
|
||||||
|
adaptive_range_gain_limit = current_gain;
|
||||||
|
}
|
||||||
|
switch (adaptive_range_state) {
|
||||||
|
case RANGE_SCAN_UP:
|
||||||
|
case RANGE_RESCAN_UP:
|
||||||
|
if (available_range < Modes.adaptive_range_target) {
|
||||||
|
// Current gain fails to meet our target. Switch to downward scanning.
|
||||||
|
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) < required dynamic range (%.1fdB), switching to downward scan\n", available_range, Modes.adaptive_range_target);
|
||||||
|
gain_down = gain_not_up = true;
|
||||||
|
gain_down_reason = "probing dynamic range gain lower bound";
|
||||||
|
adaptive_range_state = (adaptive_range_state == RANGE_RESCAN_UP ? RANGE_RESCAN_DOWN : RANGE_SCAN_DOWN);
|
||||||
|
if (adaptive_range_gain_limit >= current_gain) {
|
||||||
|
adaptive_range_gain_limit = current_gain - 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sdrGetGain() >= adaptive_gain_max) {
|
||||||
|
// We have reached our upper gain limit
|
||||||
|
fprintf(stderr, "adaptive: reached upper gain limit, halting dynamic range scan here\n");
|
||||||
|
adaptive_range_state = RANGE_SCAN_IDLE;
|
||||||
|
adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This gain step is OK and we have more to try, try the next gain step up.
|
||||||
|
// (But if burst detection has inhibited increasing gain, don't do anything yet, just try again next block)
|
||||||
|
if (!gain_not_up) {
|
||||||
|
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) >= required dynamic range (%.1fdB), continuing upward scan\n", available_range, Modes.adaptive_range_target);
|
||||||
|
gain_up = true;
|
||||||
|
gain_up_reason = "probing dynamic range gain upper bound";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RANGE_SCAN_DOWN:
|
||||||
|
case RANGE_RESCAN_DOWN:
|
||||||
|
if (available_range >= Modes.adaptive_range_target) {
|
||||||
|
// Current gain meets our target; we are done with the scan.
|
||||||
|
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) >= required dynamic range (%.1fdB), stopping downwards scan here\n", available_range, Modes.adaptive_range_target);
|
||||||
|
adaptive_range_state = RANGE_SCAN_IDLE;
|
||||||
|
adaptive_range_rescan_timer = (adaptive_range_state == RANGE_SCAN_DOWN ? Modes.adaptive_range_scan_delay : Modes.adaptive_range_rescan_delay);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adaptive_range_gain_limit >= current_gain) {
|
||||||
|
adaptive_range_gain_limit = current_gain - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sdrGetGain() <= adaptive_gain_min) {
|
||||||
|
fprintf(stderr, "adaptive: reached lower gain limit, halting dynamic range scan here\n");
|
||||||
|
adaptive_range_state = RANGE_SCAN_IDLE;
|
||||||
|
adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This gain step is too loud and we have more to try, try the next gain step down
|
||||||
|
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) < required dynamic range (%.1fdB), continuing downwards scan\n", available_range, Modes.adaptive_range_target);
|
||||||
|
gain_down = gain_not_up = true;
|
||||||
|
gain_down_reason = "probing dynamic range gain lower bound";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RANGE_SCAN_IDLE:
|
||||||
|
// Look for increased noise that could be compensated for by decreasing gain.
|
||||||
|
// Do this even if we're waiting to rescan or if burst control is also active
|
||||||
|
if (available_range + adaptive_gain_down_db / 2 < Modes.adaptive_range_target && sdrGetGain() > adaptive_gain_min) {
|
||||||
|
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) + half gain step down (%.1fdB) < required dynamic range (%.1fdB), starting downward scan\n",
|
||||||
|
available_range, Modes.adaptive_range_target, adaptive_gain_down_db);
|
||||||
|
if (adaptive_range_gain_limit >= current_gain) {
|
||||||
|
adaptive_range_gain_limit = current_gain - 1;
|
||||||
|
}
|
||||||
|
adaptive_range_state = RANGE_SCAN_DOWN;
|
||||||
|
gain_down = gain_not_up = true;
|
||||||
|
gain_down_reason = "dynamic range fell below target value";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infrequently consider increasing gain to handle the case where we've selected a too-low gain where the noise floor is dominated by noise unrelated to the gain setting.
|
||||||
|
// But don't do this while burst control is preventing gain increases.
|
||||||
|
if (!adaptive_range_rescan_timer && !gain_not_up) {
|
||||||
|
if (available_range >= Modes.adaptive_range_target && sdrGetGain() < adaptive_gain_max) {
|
||||||
|
fprintf(stderr, "adaptive: start periodic scan for acceptable dynamic range at increased gain\n");
|
||||||
|
gain_up = true;
|
||||||
|
gain_up_reason = "periodic re-probing of dynamic range gain upper bound";
|
||||||
|
adaptive_range_state = RANGE_RESCAN_UP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing to do for a while.
|
||||||
|
adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "adaptive: in a weird state (%d), trying to fix it\n", adaptive_range_state);
|
||||||
|
adaptive_range_state = RANGE_SCAN_IDLE;
|
||||||
|
adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now actually perform any gain changes
|
||||||
|
|
||||||
|
if (gain_down)
|
||||||
|
adaptive_decrease_gain(gain_down_reason);
|
||||||
|
else if (gain_up && !gain_not_up)
|
||||||
|
adaptive_increase_gain(gain_up_reason);
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||||
//
|
//
|
||||||
// demod_2000.h: 2MHz Mode S demodulator prototypes.
|
// adaptive.h: adaptive gain control prototypes
|
||||||
//
|
//
|
||||||
// Copyright (c) 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
|
// Copyright (c) 2021 FlightAware, LLC
|
||||||
//
|
//
|
||||||
// This file is free software: you may copy, redistribute and/or modify it
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
// under the terms of the GNU General Public License as published by the
|
// under the terms of the GNU General Public License as published by the
|
||||||
|
|
@ -17,13 +17,14 @@
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#ifndef DUMP1090_DEMOD_2000_H
|
#ifndef ADAPTIVE_H
|
||||||
#define DUMP1090_DEMOD_2000_H
|
#define ADAPTIVE_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
struct mag_buf;
|
struct modesMessage;
|
||||||
|
|
||||||
void demodulate2000(struct mag_buf *mag);
|
void adaptive_init();
|
||||||
|
void adaptive_update(uint16_t *buf, unsigned length, struct modesMessage *decoded);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
#include "ais_charset.h"
|
||||||
|
|
||||||
|
char ais_charset[64] = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?";
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef AIS_CHARSET_H
|
||||||
|
#define AIS_CHARSET_H
|
||||||
|
|
||||||
|
extern char ais_charset[64];
|
||||||
|
|
||||||
|
#endif
|
||||||
231
anet.c
231
anet.c
|
|
@ -1,3 +1,26 @@
|
||||||
|
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// anet.c: Basic TCP socket stuff made a bit less boring
|
||||||
|
//
|
||||||
|
// Copyright (c) 2016 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
|
//
|
||||||
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the
|
||||||
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
|
// option) any later version.
|
||||||
|
//
|
||||||
|
// This file is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// This file incorporates work covered by the following copyright and
|
||||||
|
// permission notice:
|
||||||
|
//
|
||||||
|
|
||||||
/* anet.c -- Basic TCP socket stuff made a bit less boring
|
/* anet.c -- Basic TCP socket stuff made a bit less boring
|
||||||
*
|
*
|
||||||
* Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
* Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||||
|
|
@ -28,7 +51,6 @@
|
||||||
* POSSIBILITY OF SUCH DAMAGE.
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _WIN32
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
@ -43,10 +65,6 @@
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#else
|
|
||||||
#include "winstubs.h" //Put everything Windows specific in here
|
|
||||||
#include "dump1090.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "anet.h"
|
#include "anet.h"
|
||||||
|
|
||||||
|
|
@ -63,7 +81,7 @@ static void anetSetError(char *err, const char *fmt, ...)
|
||||||
int anetNonBlock(char *err, int fd)
|
int anetNonBlock(char *err, int fd)
|
||||||
{
|
{
|
||||||
int flags;
|
int flags;
|
||||||
#ifndef _WIN32
|
|
||||||
/* Set the socket nonblocking.
|
/* Set the socket nonblocking.
|
||||||
* Note that fcntl(2) for F_GETFL and F_SETFL can't be
|
* Note that fcntl(2) for F_GETFL and F_SETFL can't be
|
||||||
* interrupted by a signal. */
|
* interrupted by a signal. */
|
||||||
|
|
@ -75,14 +93,7 @@ int anetNonBlock(char *err, int fd)
|
||||||
anetSetError(err, "fcntl(F_SETFL,O_NONBLOCK): %s", strerror(errno));
|
anetSetError(err, "fcntl(F_SETFL,O_NONBLOCK): %s", strerror(errno));
|
||||||
return ANET_ERR;
|
return ANET_ERR;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
flags = 1;
|
|
||||||
if (ioctlsocket(fd, FIONBIO, &flags)) {
|
|
||||||
errno = WSAGetLastError();
|
|
||||||
anetSetError(err, "ioctlsocket(FIONBIO): %s", strerror(errno));
|
|
||||||
return ANET_ERR;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return ANET_OK;
|
return ANET_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,31 +128,10 @@ int anetTcpKeepAlive(char *err, int fd)
|
||||||
return ANET_OK;
|
return ANET_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int anetResolve(char *err, char *host, char *ipbuf)
|
static int anetCreateSocket(char *err, int domain)
|
||||||
{
|
{
|
||||||
struct sockaddr_in sa;
|
|
||||||
|
|
||||||
sa.sin_family = AF_INET;
|
|
||||||
if (inet_aton(host, (void*)&sa.sin_addr) == 0) {
|
|
||||||
struct hostent *he;
|
|
||||||
|
|
||||||
he = gethostbyname(host);
|
|
||||||
if (he == NULL) {
|
|
||||||
anetSetError(err, "can't resolve: %s", host);
|
|
||||||
return ANET_ERR;
|
|
||||||
}
|
|
||||||
memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr));
|
|
||||||
}
|
|
||||||
strcpy(ipbuf,inet_ntoa(sa.sin_addr));
|
|
||||||
return ANET_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int anetCreateSocket(char *err, int domain) {
|
|
||||||
int s, on = 1;
|
int s, on = 1;
|
||||||
if ((s = socket(domain, SOCK_STREAM, 0)) == -1) {
|
if ((s = socket(domain, SOCK_STREAM, 0)) == -1) {
|
||||||
#ifdef _WIN32
|
|
||||||
errno = WSAGetLastError();
|
|
||||||
#endif
|
|
||||||
anetSetError(err, "creating socket: %s", strerror(errno));
|
anetSetError(err, "creating socket: %s", strerror(errno));
|
||||||
return ANET_ERR;
|
return ANET_ERR;
|
||||||
}
|
}
|
||||||
|
|
@ -157,52 +147,63 @@ static int anetCreateSocket(char *err, int domain) {
|
||||||
|
|
||||||
#define ANET_CONNECT_NONE 0
|
#define ANET_CONNECT_NONE 0
|
||||||
#define ANET_CONNECT_NONBLOCK 1
|
#define ANET_CONNECT_NONBLOCK 1
|
||||||
static int anetTcpGenericConnect(char *err, char *addr, int port, int flags)
|
static int anetTcpGenericConnect(char *err, char *addr, char *service, int flags)
|
||||||
{
|
{
|
||||||
int s;
|
int s;
|
||||||
struct sockaddr_in sa;
|
struct addrinfo gai_hints;
|
||||||
|
struct addrinfo *gai_result, *p;
|
||||||
|
int gai_error;
|
||||||
|
|
||||||
if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR)
|
gai_hints.ai_family = AF_UNSPEC;
|
||||||
return ANET_ERR;
|
gai_hints.ai_socktype = SOCK_STREAM;
|
||||||
|
gai_hints.ai_protocol = 0;
|
||||||
|
gai_hints.ai_flags = 0;
|
||||||
|
gai_hints.ai_addrlen = 0;
|
||||||
|
gai_hints.ai_addr = NULL;
|
||||||
|
gai_hints.ai_canonname = NULL;
|
||||||
|
gai_hints.ai_next = NULL;
|
||||||
|
|
||||||
memset(&sa,0,sizeof(sa));
|
gai_error = getaddrinfo(addr, service, &gai_hints, &gai_result);
|
||||||
sa.sin_family = AF_INET;
|
if (gai_error != 0) {
|
||||||
sa.sin_port = htons((uint16_t)port);
|
anetSetError(err, "can't resolve %s: %s", addr, gai_strerror(gai_error));
|
||||||
if (inet_aton(addr, (void*)&sa.sin_addr) == 0) {
|
|
||||||
struct hostent *he;
|
|
||||||
|
|
||||||
he = gethostbyname(addr);
|
|
||||||
if (he == NULL) {
|
|
||||||
anetSetError(err, "can't resolve: %s", addr);
|
|
||||||
close(s);
|
|
||||||
return ANET_ERR;
|
return ANET_ERR;
|
||||||
}
|
}
|
||||||
memcpy(&sa.sin_addr, he->h_addr, sizeof(struct in_addr));
|
|
||||||
}
|
for (p = gai_result; p != NULL; p = p->ai_next) {
|
||||||
|
if ((s = anetCreateSocket(err, p->ai_family)) == ANET_ERR)
|
||||||
|
continue;
|
||||||
|
|
||||||
if (flags & ANET_CONNECT_NONBLOCK) {
|
if (flags & ANET_CONNECT_NONBLOCK) {
|
||||||
if (anetNonBlock(err,s) != ANET_OK)
|
if (anetNonBlock(err,s) != ANET_OK)
|
||||||
return ANET_ERR;
|
return ANET_ERR;
|
||||||
}
|
}
|
||||||
if (connect(s, (struct sockaddr*)&sa, sizeof(sa)) == -1) {
|
|
||||||
if (errno == EINPROGRESS &&
|
if (connect(s, p->ai_addr, p->ai_addrlen) >= 0) {
|
||||||
flags & ANET_CONNECT_NONBLOCK)
|
freeaddrinfo(gai_result);
|
||||||
return s;
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errno == EINPROGRESS && (flags & ANET_CONNECT_NONBLOCK)) {
|
||||||
|
freeaddrinfo(gai_result);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
anetSetError(err, "connect: %s", strerror(errno));
|
anetSetError(err, "connect: %s", strerror(errno));
|
||||||
close(s);
|
close(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(gai_result);
|
||||||
return ANET_ERR;
|
return ANET_ERR;
|
||||||
}
|
}
|
||||||
return s;
|
|
||||||
|
int anetTcpConnect(char *err, char *addr, char *service)
|
||||||
|
{
|
||||||
|
return anetTcpGenericConnect(err,addr,service,ANET_CONNECT_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int anetTcpConnect(char *err, char *addr, int port)
|
int anetTcpNonBlockConnect(char *err, char *addr, char *service)
|
||||||
{
|
{
|
||||||
return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONE);
|
return anetTcpGenericConnect(err,addr,service,ANET_CONNECT_NONBLOCK);
|
||||||
}
|
|
||||||
|
|
||||||
int anetTcpNonBlockConnect(char *err, char *addr, int port)
|
|
||||||
{
|
|
||||||
return anetTcpGenericConnect(err,addr,port,ANET_CONNECT_NONBLOCK);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Like read(2) but make sure 'count' is read before to return
|
/* Like read(2) but make sure 'count' is read before to return
|
||||||
|
|
@ -236,10 +237,12 @@ int anetWrite(int fd, char *buf, int count)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len) {
|
static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len) {
|
||||||
|
if (sa->sa_family == AF_INET6) {
|
||||||
|
int on = 1;
|
||||||
|
setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on));
|
||||||
|
}
|
||||||
|
|
||||||
if (bind(s,sa,len) == -1) {
|
if (bind(s,sa,len) == -1) {
|
||||||
#ifdef _WIN32
|
|
||||||
errno = WSAGetLastError();
|
|
||||||
#endif
|
|
||||||
anetSetError(err, "bind: %s", strerror(errno));
|
anetSetError(err, "bind: %s", strerror(errno));
|
||||||
close(s);
|
close(s);
|
||||||
return ANET_ERR;
|
return ANET_ERR;
|
||||||
|
|
@ -249,9 +252,6 @@ static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len) {
|
||||||
* the kernel does: backlogsize = roundup_pow_of_two(backlogsize + 1);
|
* the kernel does: backlogsize = roundup_pow_of_two(backlogsize + 1);
|
||||||
* which will thus give us a backlog of 512 entries */
|
* which will thus give us a backlog of 512 entries */
|
||||||
if (listen(s, 511) == -1) {
|
if (listen(s, 511) == -1) {
|
||||||
#ifdef _WIN32
|
|
||||||
errno = WSAGetLastError();
|
|
||||||
#endif
|
|
||||||
anetSetError(err, "listen: %s", strerror(errno));
|
anetSetError(err, "listen: %s", strerror(errno));
|
||||||
close(s);
|
close(s);
|
||||||
return ANET_ERR;
|
return ANET_ERR;
|
||||||
|
|
@ -259,40 +259,52 @@ static int anetListen(char *err, int s, struct sockaddr *sa, socklen_t len) {
|
||||||
return ANET_OK;
|
return ANET_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int anetTcpServer(char *err, int port, char *bindaddr)
|
int anetTcpServer(char *err, char *service, char *bindaddr, int *fds, int nfds)
|
||||||
{
|
{
|
||||||
int s;
|
int s;
|
||||||
struct sockaddr_in sa;
|
int i = 0;
|
||||||
|
struct addrinfo gai_hints;
|
||||||
|
struct addrinfo *gai_result, *p;
|
||||||
|
int gai_error;
|
||||||
|
|
||||||
if ((s = anetCreateSocket(err,AF_INET)) == ANET_ERR)
|
gai_hints.ai_family = AF_UNSPEC;
|
||||||
return ANET_ERR;
|
gai_hints.ai_socktype = SOCK_STREAM;
|
||||||
|
gai_hints.ai_protocol = 0;
|
||||||
|
gai_hints.ai_flags = AI_PASSIVE;
|
||||||
|
gai_hints.ai_addrlen = 0;
|
||||||
|
gai_hints.ai_addr = NULL;
|
||||||
|
gai_hints.ai_canonname = NULL;
|
||||||
|
gai_hints.ai_next = NULL;
|
||||||
|
|
||||||
memset(&sa,0,sizeof(sa));
|
gai_error = getaddrinfo(bindaddr, service, &gai_hints, &gai_result);
|
||||||
sa.sin_family = AF_INET;
|
if (gai_error != 0) {
|
||||||
sa.sin_port = htons((uint16_t)port);
|
anetSetError(err, "can't resolve %s: %s", bindaddr, gai_strerror(gai_error));
|
||||||
sa.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
||||||
if (bindaddr && inet_aton(bindaddr, (void*)&sa.sin_addr) == 0) {
|
|
||||||
anetSetError(err, "invalid bind address");
|
|
||||||
close(s);
|
|
||||||
return ANET_ERR;
|
return ANET_ERR;
|
||||||
}
|
}
|
||||||
if (anetListen(err,s,(struct sockaddr*)&sa,sizeof(sa)) == ANET_ERR)
|
|
||||||
return ANET_ERR;
|
for (p = gai_result; p != NULL && i < nfds; p = p->ai_next) {
|
||||||
return s;
|
if ((s = anetCreateSocket(err, p->ai_family)) == ANET_ERR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (anetListen(err, s, p->ai_addr, p->ai_addrlen) == ANET_ERR) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len) {
|
fds[i++] = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(gai_result);
|
||||||
|
return (i > 0 ? i : ANET_ERR);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *len)
|
||||||
|
{
|
||||||
int fd;
|
int fd;
|
||||||
while(1) {
|
while(1) {
|
||||||
fd = accept(s,sa,len);
|
fd = accept(s,sa,len);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
#ifndef _WIN32
|
|
||||||
if (errno == EINTR) {
|
if (errno == EINTR) {
|
||||||
continue;
|
continue;
|
||||||
#else
|
|
||||||
errno = WSAGetLastError();
|
|
||||||
if (errno == WSAEWOULDBLOCK) {
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
anetSetError(err, "accept: %s", strerror(errno));
|
anetSetError(err, "accept: %s", strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
@ -302,44 +314,13 @@ static int anetGenericAccept(char *err, int s, struct sockaddr *sa, socklen_t *l
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
int anetTcpAccept(char *err, int s, char *ip, int *port) {
|
int anetTcpAccept(char *err, int s) {
|
||||||
int fd;
|
int fd;
|
||||||
struct sockaddr_in sa;
|
struct sockaddr_storage ss;
|
||||||
socklen_t salen = sizeof(sa);
|
socklen_t sslen = sizeof(ss);
|
||||||
if ((fd = anetGenericAccept(err,s,(struct sockaddr*)&sa,&salen)) == ANET_ERR)
|
|
||||||
|
if ((fd = anetGenericAccept(err, s, (struct sockaddr*)&ss, &sslen)) == ANET_ERR)
|
||||||
return ANET_ERR;
|
return ANET_ERR;
|
||||||
|
|
||||||
if (ip) strcpy(ip,inet_ntoa(sa.sin_addr));
|
|
||||||
if (port) *port = ntohs(sa.sin_port);
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
int anetPeerToString(int fd, char *ip, int *port) {
|
|
||||||
struct sockaddr_in sa;
|
|
||||||
socklen_t salen = sizeof(sa);
|
|
||||||
|
|
||||||
if (getpeername(fd,(struct sockaddr*)&sa,&salen) == -1) {
|
|
||||||
*port = 0;
|
|
||||||
ip[0] = '?';
|
|
||||||
ip[1] = '\0';
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (ip) strcpy(ip,inet_ntoa(sa.sin_addr));
|
|
||||||
if (port) *port = ntohs(sa.sin_port);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int anetSockName(int fd, char *ip, int *port) {
|
|
||||||
struct sockaddr_in sa;
|
|
||||||
socklen_t salen = sizeof(sa);
|
|
||||||
|
|
||||||
if (getsockname(fd,(struct sockaddr*)&sa,&salen) == -1) {
|
|
||||||
*port = 0;
|
|
||||||
ip[0] = '?';
|
|
||||||
ip[1] = '\0';
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (ip) strcpy(ip,inet_ntoa(sa.sin_addr));
|
|
||||||
if (port) *port = ntohs(sa.sin_port);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
|
||||||
37
anet.h
37
anet.h
|
|
@ -1,3 +1,26 @@
|
||||||
|
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// anet.h: Basic TCP socket stuff made a bit less boring
|
||||||
|
//
|
||||||
|
// Copyright (c) 2016 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
|
//
|
||||||
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the
|
||||||
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
|
// option) any later version.
|
||||||
|
//
|
||||||
|
// This file is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
// This file incorporates work covered by the following copyright and
|
||||||
|
// permission notice:
|
||||||
|
//
|
||||||
|
|
||||||
/* anet.c -- Basic TCP socket stuff made a bit less boring
|
/* anet.c -- Basic TCP socket stuff made a bit less boring
|
||||||
*
|
*
|
||||||
* Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
* Copyright (c) 2006-2012, Salvatore Sanfilippo <antirez at gmail dot com>
|
||||||
|
|
@ -39,21 +62,15 @@
|
||||||
#define AF_LOCAL AF_UNIX
|
#define AF_LOCAL AF_UNIX
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int anetTcpConnect(char *err, char *addr, int port);
|
int anetTcpConnect(char *err, char *addr, char *service);
|
||||||
int anetTcpNonBlockConnect(char *err, char *addr, int port);
|
int anetTcpNonBlockConnect(char *err, char *addr, char *service);
|
||||||
int anetUnixConnect(char *err, char *path);
|
|
||||||
int anetUnixNonBlockConnect(char *err, char *path);
|
|
||||||
int anetRead(int fd, char *buf, int count);
|
int anetRead(int fd, char *buf, int count);
|
||||||
int anetResolve(char *err, char *host, char *ipbuf);
|
int anetTcpServer(char *err, char *service, char *bindaddr, int *fds, int nfds);
|
||||||
int anetTcpServer(char *err, int port, char *bindaddr);
|
int anetTcpAccept(char *err, int serversock);
|
||||||
int anetUnixServer(char *err, char *path, mode_t perm);
|
|
||||||
int anetTcpAccept(char *err, int serversock, char *ip, int *port);
|
|
||||||
int anetUnixAccept(char *err, int serversock);
|
|
||||||
int anetWrite(int fd, char *buf, int count);
|
int anetWrite(int fd, char *buf, int count);
|
||||||
int anetNonBlock(char *err, int fd);
|
int anetNonBlock(char *err, int fd);
|
||||||
int anetTcpNoDelay(char *err, int fd);
|
int anetTcpNoDelay(char *err, int fd);
|
||||||
int anetTcpKeepAlive(char *err, int fd);
|
int anetTcpKeepAlive(char *err, int fd);
|
||||||
int anetPeerToString(int fd, char *ip, int *port);
|
|
||||||
int anetSetSendBuffer(char *err, int fd, int buffsize);
|
int anetSetSendBuffer(char *err, int fd, int buffsize);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
bladeRF support
|
||||||
|
---------------
|
||||||
|
|
||||||
|
There is basic support for the bladeRF included in dump1090-fa.
|
||||||
|
It uses the same demodulator as the regular rtlsdr version and it does not
|
||||||
|
take advantage of the bladeRF's improved sampling rate or FPGA (but see below)
|
||||||
|
|
||||||
|
To use it:
|
||||||
|
|
||||||
|
$ dump1090-fa --device-type bladerf --gain 66 (.. other options ..)
|
||||||
|
|
||||||
|
The bladeRF has sensitivity problems when receiving ADS-B and will benefit
|
||||||
|
from all the gain you can give it. 66dB is the maximum configurable gain on
|
||||||
|
the board itself, you may want to add an external LNA too.
|
||||||
|
|
||||||
|
|
||||||
|
bladeRF custom FPGA bitstream
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
The package includes a custom FPGA bitstream for the bladeRF which can
|
||||||
|
improve ADS-B reception with dump1090.
|
||||||
|
|
||||||
|
It adds a Fs/4 mixer step to avoid the DC offset of the bladeRF, and
|
||||||
|
decimate-by-8 downsampling step to improve sensitivity. Some of the bladeRF
|
||||||
|
parameters need to be adjusted so that it produces correctly tuned/downsampled
|
||||||
|
data in the form that dump1090 is expecting.
|
||||||
|
|
||||||
|
To use it:
|
||||||
|
|
||||||
|
$ dump1090-fa --device-type bladerf --gain 66 \
|
||||||
|
--bladerf-fpga /usr/share/dump1090-fa/bladerf/decimate8-x40.rbf \
|
||||||
|
--bladerf-decimation 8 \
|
||||||
|
--bladerf-bandwidth 14000000 \
|
||||||
|
--freq 1085200000 \
|
||||||
|
(other options ...)
|
||||||
|
|
||||||
|
The bladeRF will be configured for a 19.2MHz sampling rate and will tune to
|
||||||
|
1085.2MHz so that the 1090MHz signal appears around 4.8MHz in the baseband
|
||||||
|
samples. The FPGA Fs/4 mixing step shifts the baseband signal so that it is centered
|
||||||
|
around 0, and the FPGA downsampling step produces samples at 2.4MHz, which is what
|
||||||
|
dump1090 is expecting.
|
||||||
|
|
||||||
|
This FPGA bitstream is built for the 40kLE bladeRF.
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,985 @@
|
||||||
|
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// comm_b.c: Comm-B message decoding
|
||||||
|
//
|
||||||
|
// Copyright (c) 2017 FlightAware, LLC
|
||||||
|
// Copyright (c) 2017 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
|
//
|
||||||
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the
|
||||||
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
|
// option) any later version.
|
||||||
|
//
|
||||||
|
// This file is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "dump1090.h"
|
||||||
|
#include "ais_charset.h"
|
||||||
|
|
||||||
|
typedef int (*CommBDecoderFn)(struct modesMessage *,bool);
|
||||||
|
|
||||||
|
static int decodeEmptyResponse(struct modesMessage *mm, bool store);
|
||||||
|
static int decodeBDS10(struct modesMessage *mm, bool store);
|
||||||
|
static int decodeBDS17(struct modesMessage *mm, bool store);
|
||||||
|
static int decodeBDS20(struct modesMessage *mm, bool store);
|
||||||
|
static int decodeBDS30(struct modesMessage *mm, bool store);
|
||||||
|
static int decodeBDS40(struct modesMessage *mm, bool store);
|
||||||
|
static int decodeBDS44(struct modesMessage *mm, bool store);
|
||||||
|
static int decodeBDS50(struct modesMessage *mm, bool store);
|
||||||
|
static int decodeBDS60(struct modesMessage *mm, bool store);
|
||||||
|
static int decodeBDS05(struct modesMessage *mm, bool store);
|
||||||
|
|
||||||
|
static CommBDecoderFn comm_b_decoders[] = {
|
||||||
|
&decodeEmptyResponse,
|
||||||
|
&decodeBDS10,
|
||||||
|
&decodeBDS20,
|
||||||
|
&decodeBDS30,
|
||||||
|
&decodeBDS17,
|
||||||
|
&decodeBDS40,
|
||||||
|
&decodeBDS50,
|
||||||
|
&decodeBDS60,
|
||||||
|
&decodeBDS44,
|
||||||
|
&decodeBDS05
|
||||||
|
};
|
||||||
|
|
||||||
|
void decodeCommB(struct modesMessage *mm)
|
||||||
|
{
|
||||||
|
// If DR or UM are set, this message is _probably_ noise
|
||||||
|
// as nothing really seems to use the multisite broadcast stuff?
|
||||||
|
// Also skip anything that had errors corrected
|
||||||
|
if (mm->DR != 0 || mm->UM != 0 || mm->correctedbits > 0) {
|
||||||
|
mm->commb_format = COMMB_NOT_DECODED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a bit hairy as we don't know what the requested register was
|
||||||
|
int bestScore = 0;
|
||||||
|
CommBDecoderFn bestDecoder = NULL;
|
||||||
|
int ambiguous = 0;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < (sizeof(comm_b_decoders) / sizeof(comm_b_decoders[0])); ++i) {
|
||||||
|
int score = comm_b_decoders[i](mm, false);
|
||||||
|
if (score > bestScore) {
|
||||||
|
bestScore = score;
|
||||||
|
bestDecoder = comm_b_decoders[i];
|
||||||
|
ambiguous = 0;
|
||||||
|
} else if (score == bestScore) {
|
||||||
|
ambiguous = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bestDecoder) {
|
||||||
|
if (ambiguous) {
|
||||||
|
mm->commb_format = COMMB_AMBIGUOUS;
|
||||||
|
} else {
|
||||||
|
// decode it
|
||||||
|
bestDecoder(mm, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mm->commb_format = COMMB_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int decodeEmptyResponse(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
// 00000000000000 is a common response. Ignore it.
|
||||||
|
//
|
||||||
|
// Also, it's common to see responses that look like this:
|
||||||
|
// 40000000000000
|
||||||
|
// 50000000000000
|
||||||
|
// 60000000000000
|
||||||
|
// typically in grouped bursts (one of each message) from
|
||||||
|
// the same aircraft.
|
||||||
|
//
|
||||||
|
// I speculate that these are response to interrogations for
|
||||||
|
// BDS 4,0 5,0 and 6,0 respectively where the transponder
|
||||||
|
// doesn't support the register or has no data loaded for it.
|
||||||
|
// Treat them like empty responses.
|
||||||
|
|
||||||
|
switch (mm->MB[0]) {
|
||||||
|
case 0x00:
|
||||||
|
case 0x40:
|
||||||
|
case 0x50:
|
||||||
|
case 0x60:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 1; i < 7; ++i) {
|
||||||
|
if (mm->MB[i] != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_EMPTY_RESPONSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 56;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BDS1,0 Datalink capabilities
|
||||||
|
static int decodeBDS10(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
unsigned char *msg = mm->MB;
|
||||||
|
|
||||||
|
// BDS identifier
|
||||||
|
if (msg[0] != 0x10) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reserved bits
|
||||||
|
if (getbits(msg, 10, 14) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks plausible.
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_DATALINK_CAPS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 56;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BDS1,7 Common usage GICB capability report
|
||||||
|
static int decodeBDS17(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
unsigned char *msg = mm->MB;
|
||||||
|
|
||||||
|
// reserved bits
|
||||||
|
if (getbits(msg, 25, 56) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int score = 0;
|
||||||
|
if (getbit(msg, 7)) {
|
||||||
|
score += 1; // 2,0 aircraft identification
|
||||||
|
} else {
|
||||||
|
// BDS2,0 is on almost everything
|
||||||
|
score -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// unlikely bits
|
||||||
|
if (getbit(msg, 10)) { // 4,1 next waypoint identifier
|
||||||
|
score -= 2;
|
||||||
|
}
|
||||||
|
if (getbit(msg, 11)) { // 4,2 next waypoint position
|
||||||
|
score -= 2;
|
||||||
|
}
|
||||||
|
if (getbit(msg, 12)) { // 4,3 next waypoint information
|
||||||
|
score -= 2;
|
||||||
|
}
|
||||||
|
if (getbit(msg, 13)) { // 4,4 meterological routine report
|
||||||
|
score -= 1;
|
||||||
|
}
|
||||||
|
if (getbit(msg, 14)) { // 4,4 meterological hazard report
|
||||||
|
score -= 1;
|
||||||
|
}
|
||||||
|
if (getbit(msg, 20)) { // 5,4 waypoint 1
|
||||||
|
score -= 2;
|
||||||
|
}
|
||||||
|
if (getbit(msg, 21)) { // 5,5 waypoint 2
|
||||||
|
score -= 2;
|
||||||
|
}
|
||||||
|
if (getbit(msg, 22)) { // 5,6 waypoint 3
|
||||||
|
score -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getbit(msg, 1) && getbit(msg, 2) && getbit(msg, 3) && getbit(msg, 4) && getbit(msg, 5)) {
|
||||||
|
// looks like ES capable
|
||||||
|
score += 5;
|
||||||
|
if (getbit(msg, 6)) {
|
||||||
|
// ES EDI
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
|
} else if (!getbit(msg, 1) && !getbit(msg, 2) && !getbit(msg, 3) && !getbit(msg, 4) && !getbit(msg, 5) && !getbit(msg, 6)) {
|
||||||
|
// not ES capable
|
||||||
|
score += 1;
|
||||||
|
} else if (!getbit(msg, 1) && !getbit(msg, 2) && getbit(msg, 3) && getbit(msg, 4) && getbit(msg, 5)) {
|
||||||
|
// ES with no position data
|
||||||
|
score += 3;
|
||||||
|
} else {
|
||||||
|
// other combinations, unlikely
|
||||||
|
score -= 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getbit(msg, 16) && getbit(msg, 24)) {
|
||||||
|
// track/turn, heading/speed
|
||||||
|
score += 2;
|
||||||
|
if (getbit(msg, 9)) {
|
||||||
|
// vertical intent
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
|
} else if (!getbit(msg, 16) && !getbit(msg, 24) && !getbit(msg, 9)) {
|
||||||
|
// neither
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
// unlikely
|
||||||
|
score -= 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_GICB_CAPS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BDS2,0 Aircraft identification
|
||||||
|
static int decodeBDS20(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
char callsign[9];
|
||||||
|
unsigned char *msg = mm->MB;
|
||||||
|
|
||||||
|
// BDS identifier
|
||||||
|
if (msg[0] != 0x20) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
callsign[0] = ais_charset[getbits(msg, 9, 14)];
|
||||||
|
callsign[1] = ais_charset[getbits(msg, 15, 20)];
|
||||||
|
callsign[2] = ais_charset[getbits(msg, 21, 26)];
|
||||||
|
callsign[3] = ais_charset[getbits(msg, 27, 32)];
|
||||||
|
callsign[4] = ais_charset[getbits(msg, 33, 38)];
|
||||||
|
callsign[5] = ais_charset[getbits(msg, 39, 44)];
|
||||||
|
callsign[6] = ais_charset[getbits(msg, 45, 50)];
|
||||||
|
callsign[7] = ais_charset[getbits(msg, 51, 56)];
|
||||||
|
callsign[8] = 0;
|
||||||
|
|
||||||
|
// score based on number of valid characters
|
||||||
|
int score = 8;
|
||||||
|
int valid = 1;
|
||||||
|
for (unsigned i = 0; i < 8; ++i) {
|
||||||
|
if ((callsign[i] >= 'A' && callsign[i] <= 'Z') || (callsign[i] >= '0' && callsign[i] <= '9') || callsign[i] == ' ') {
|
||||||
|
score += 6;
|
||||||
|
} else if (callsign[i] == '@') {
|
||||||
|
// Padding (sometimes we get @@@@@@@@, i.e. BDS2,0 with all zeros - we do want to accept this as a BDS2,0 but not actually use the callsign)
|
||||||
|
valid = 0;
|
||||||
|
} else {
|
||||||
|
// Invalid
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_AIRCRAFT_IDENT;
|
||||||
|
if (valid) {
|
||||||
|
memcpy(mm->callsign, callsign, sizeof(mm->callsign));
|
||||||
|
mm->callsign_valid = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BDS3,0 ACAS RA
|
||||||
|
static int decodeBDS30(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
unsigned char *msg = mm->MB;
|
||||||
|
|
||||||
|
// BDS identifier
|
||||||
|
if (msg[0] != 0x30) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_ACAS_RA;
|
||||||
|
}
|
||||||
|
|
||||||
|
// just accept it.
|
||||||
|
return 56;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BDS4,0 Selected vertical intention
|
||||||
|
static int decodeBDS40(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
unsigned char *msg = mm->MB;
|
||||||
|
|
||||||
|
unsigned mcp_valid = getbit(msg, 1);
|
||||||
|
unsigned mcp_raw = getbits(msg, 2, 13);
|
||||||
|
unsigned fms_valid = getbit(msg, 14);
|
||||||
|
unsigned fms_raw = getbits(msg, 15, 26);
|
||||||
|
unsigned baro_valid = getbit(msg, 27);
|
||||||
|
unsigned baro_raw = getbits(msg, 28, 39);
|
||||||
|
unsigned reserved_1 = getbits(msg, 40, 47);
|
||||||
|
unsigned mode_valid = getbit(msg, 48);
|
||||||
|
unsigned mode_raw = getbits(msg, 49, 51);
|
||||||
|
unsigned reserved_2 = getbits(msg, 52, 53);
|
||||||
|
unsigned source_valid = getbit(msg, 54);
|
||||||
|
unsigned source_raw = getbits(msg, 55, 56);
|
||||||
|
|
||||||
|
if (!mcp_valid && !fms_valid && !baro_valid && !mode_valid && !source_valid) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int score = 0;
|
||||||
|
|
||||||
|
unsigned mcp_alt = 0;
|
||||||
|
if (mcp_valid && mcp_raw != 0) {
|
||||||
|
mcp_alt = mcp_raw * 16;
|
||||||
|
if (mcp_alt >= 1000 && mcp_alt <= 50000) {
|
||||||
|
score += 13;
|
||||||
|
} else {
|
||||||
|
// unlikely altitude
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!mcp_valid && mcp_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned fms_alt = 0;
|
||||||
|
if (fms_valid && fms_raw != 0) {
|
||||||
|
fms_alt = fms_raw * 16;
|
||||||
|
if (fms_alt >= 1000 && fms_alt <= 50000) {
|
||||||
|
score += 13;
|
||||||
|
} else {
|
||||||
|
// unlikely altitude
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!fms_valid && fms_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float baro_setting = 0;
|
||||||
|
if (baro_valid && baro_raw != 0) {
|
||||||
|
baro_setting = 800 + baro_raw * 0.1;
|
||||||
|
if (baro_setting >= 900 && baro_setting <= 1100) {
|
||||||
|
score += 13;
|
||||||
|
} else {
|
||||||
|
// unlikely pressure setting
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!baro_valid && baro_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reserved_1 != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode_valid) {
|
||||||
|
score += 4;
|
||||||
|
} else if (!mode_valid && mode_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reserved_2 != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source_valid) {
|
||||||
|
score += 3;
|
||||||
|
} else if (!source_valid && source_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// small penalty for inconsistent data
|
||||||
|
if (mcp_valid && fms_valid && mcp_alt != fms_alt) {
|
||||||
|
score -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mcp_valid) {
|
||||||
|
unsigned remainder = mcp_alt % 500;
|
||||||
|
if (!(remainder < 16 || remainder > 484)) {
|
||||||
|
// mcp altitude is not a multiple of 500
|
||||||
|
score -= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fms_valid) {
|
||||||
|
unsigned remainder = fms_alt % 500;
|
||||||
|
if (!(remainder < 16 || remainder > 484)) {
|
||||||
|
// fms altitude is not a multiple of 500
|
||||||
|
score -= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_VERTICAL_INTENT;
|
||||||
|
|
||||||
|
if (mcp_valid) {
|
||||||
|
mm->nav.mcp_altitude_valid = 1;
|
||||||
|
mm->nav.mcp_altitude = mcp_alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fms_valid) {
|
||||||
|
mm->nav.fms_altitude_valid = 1;
|
||||||
|
mm->nav.fms_altitude = fms_alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baro_valid) {
|
||||||
|
mm->nav.qnh_valid = 1;
|
||||||
|
mm->nav.qnh = baro_setting;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode_valid) {
|
||||||
|
mm->nav.modes_valid = 1;
|
||||||
|
mm->nav.modes =
|
||||||
|
((mode_raw & 4) ? NAV_MODE_VNAV : 0) |
|
||||||
|
((mode_raw & 2) ? NAV_MODE_ALT_HOLD : 0) |
|
||||||
|
((mode_raw & 1) ? NAV_MODE_APPROACH : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source_valid) {
|
||||||
|
switch (source_raw) {
|
||||||
|
case 0:
|
||||||
|
mm->nav.altitude_source = NAV_ALT_UNKNOWN;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
mm->nav.altitude_source = NAV_ALT_AIRCRAFT;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mm->nav.altitude_source = NAV_ALT_MCP;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
mm->nav.altitude_source = NAV_ALT_FMS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mm->nav.altitude_source = NAV_ALT_INVALID;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mm->nav.altitude_source = NAV_ALT_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BDS5,0 Track and turn report
|
||||||
|
static int decodeBDS50(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
unsigned char *msg = mm->MB;
|
||||||
|
|
||||||
|
unsigned roll_valid = getbit(msg, 1);
|
||||||
|
unsigned roll_sign = getbit(msg, 2);
|
||||||
|
unsigned roll_raw = getbits(msg, 3, 11);
|
||||||
|
|
||||||
|
unsigned track_valid = getbit(msg, 12);
|
||||||
|
unsigned track_sign = getbit(msg, 13);
|
||||||
|
unsigned track_raw = getbits(msg, 14, 23);
|
||||||
|
|
||||||
|
unsigned gs_valid = getbit(msg, 24);
|
||||||
|
unsigned gs_raw = getbits(msg, 25, 34);
|
||||||
|
|
||||||
|
unsigned track_rate_valid = getbit(msg, 35);
|
||||||
|
unsigned track_rate_sign = getbit(msg, 36);
|
||||||
|
unsigned track_rate_raw = getbits(msg, 37, 45);
|
||||||
|
|
||||||
|
unsigned tas_valid = getbit(msg, 46);
|
||||||
|
unsigned tas_raw = getbits(msg, 47, 56);
|
||||||
|
|
||||||
|
if (!roll_valid || !track_valid || !gs_valid || !tas_valid) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int score = 0;
|
||||||
|
|
||||||
|
float roll = 0;
|
||||||
|
if (roll_valid) {
|
||||||
|
roll = roll_raw * 45.0 / 256.0;
|
||||||
|
if (roll_sign) {
|
||||||
|
roll -= 90.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roll >= -40 && roll < 40) {
|
||||||
|
score += 11;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!roll_valid && roll_raw == 0 && !roll_sign) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float track = 0;
|
||||||
|
if (track_valid) {
|
||||||
|
score += 12;
|
||||||
|
track = track_raw * 90.0 / 512.0;
|
||||||
|
if (track_sign) {
|
||||||
|
track += 180.0;
|
||||||
|
}
|
||||||
|
} else if (!track_valid && track_raw == 0 && !track_sign) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned gs = 0;
|
||||||
|
if (gs_valid && gs_raw != 0) {
|
||||||
|
gs = gs_raw * 2;
|
||||||
|
|
||||||
|
if (gs >= 50 && gs <= 700) {
|
||||||
|
score += 11;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!gs_valid && gs_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float track_rate = 0;
|
||||||
|
if (track_rate_valid) {
|
||||||
|
track_rate = track_rate_raw * 8.0 / 256.0;
|
||||||
|
if (track_rate_sign) {
|
||||||
|
track_rate -= 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (track_rate >= -10.0 && track_rate <= 10.0) {
|
||||||
|
score += 11;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!track_rate_valid && track_rate_raw == 0 && !track_rate_sign) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned tas = 0;
|
||||||
|
if (tas_valid && tas_raw != 0) {
|
||||||
|
tas = tas_raw * 2;
|
||||||
|
|
||||||
|
if (tas >= 50 && tas <= 700) {
|
||||||
|
score += 11;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!tas_valid && tas_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// small penalty for inconsistent data
|
||||||
|
if (gs_valid && tas_valid) {
|
||||||
|
int delta = abs((int)gs_valid - (int)tas_valid);
|
||||||
|
if (delta > 150) {
|
||||||
|
score -= 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute the theoretical turn rate and compare to track angle rate
|
||||||
|
if (roll_valid && tas_valid && tas > 0 && track_rate_valid) {
|
||||||
|
double turn_rate = 68625 * tan(roll * M_PI / 180.0) / (tas * 20 * M_PI);
|
||||||
|
double delta = fabs(turn_rate - track_rate);
|
||||||
|
if (delta > 2.0) {
|
||||||
|
score -= 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_TRACK_TURN;
|
||||||
|
|
||||||
|
if (roll_valid) {
|
||||||
|
mm->roll_valid = 1;
|
||||||
|
mm->roll = roll;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (track_valid) {
|
||||||
|
mm->heading_valid = 1;
|
||||||
|
mm->heading = track;
|
||||||
|
mm->heading_type = HEADING_GROUND_TRACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gs_valid) {
|
||||||
|
mm->gs_valid = 1;
|
||||||
|
mm->gs.v0 = mm->gs.v2 = mm->gs.selected = gs;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (track_rate_valid) {
|
||||||
|
mm->track_rate_valid = 1;
|
||||||
|
mm->track_rate = track_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tas_valid) {
|
||||||
|
mm->tas_valid = 1;
|
||||||
|
mm->tas = tas;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BDS6,0 Heading and speed report
|
||||||
|
static int decodeBDS60(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
unsigned char *msg = mm->MB;
|
||||||
|
|
||||||
|
unsigned heading_valid = getbit(msg, 1);
|
||||||
|
unsigned heading_sign = getbit(msg, 2);
|
||||||
|
unsigned heading_raw = getbits(msg, 3, 12);
|
||||||
|
|
||||||
|
unsigned ias_valid = getbit(msg, 13);
|
||||||
|
unsigned ias_raw = getbits(msg, 14, 23);
|
||||||
|
|
||||||
|
unsigned mach_valid = getbit(msg, 24);
|
||||||
|
unsigned mach_raw = getbits(msg, 25, 34);
|
||||||
|
|
||||||
|
unsigned baro_rate_valid = getbit(msg, 35);
|
||||||
|
unsigned baro_rate_sign = getbit(msg, 36);
|
||||||
|
unsigned baro_rate_raw = getbits(msg, 37, 45);
|
||||||
|
|
||||||
|
unsigned inertial_rate_valid = getbit(msg, 46);
|
||||||
|
unsigned inertial_rate_sign = getbit(msg, 47);
|
||||||
|
unsigned inertial_rate_raw = getbits(msg, 48, 56);
|
||||||
|
|
||||||
|
if (!heading_valid || !ias_valid || !mach_valid || (!baro_rate_valid && !inertial_rate_valid)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int score = 0;
|
||||||
|
|
||||||
|
float heading = 0;
|
||||||
|
if (heading_valid) {
|
||||||
|
heading = heading_raw * 90.0 / 512.0;
|
||||||
|
if (heading_sign) {
|
||||||
|
heading += 180.0;
|
||||||
|
}
|
||||||
|
score += 12;
|
||||||
|
} else if (!heading_valid && heading_raw == 0 && !heading_sign) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned ias = 0;
|
||||||
|
if (ias_valid && ias_raw != 0) {
|
||||||
|
ias = ias_raw;
|
||||||
|
if (ias >= 50 && ias <= 700) {
|
||||||
|
score += 11;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!ias_valid && ias_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float mach = 0;
|
||||||
|
if (mach_valid && mach_raw != 0) {
|
||||||
|
mach = mach_raw * 2.048 / 512;
|
||||||
|
if (mach >= 0.1 && mach <= 0.9) {
|
||||||
|
score += 11;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!mach_valid && mach_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int baro_rate = 0;
|
||||||
|
if (baro_rate_valid) {
|
||||||
|
baro_rate = baro_rate_raw * 32;
|
||||||
|
if (baro_rate_sign) {
|
||||||
|
baro_rate -= 16384;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baro_rate >= -6000 && baro_rate <= 6000) {
|
||||||
|
score += 11;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!baro_rate_valid && baro_rate_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int inertial_rate = 0;
|
||||||
|
if (inertial_rate_valid) {
|
||||||
|
inertial_rate = inertial_rate_raw * 32;
|
||||||
|
if (inertial_rate_sign) {
|
||||||
|
inertial_rate -= 16384;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inertial_rate >= -6000 && inertial_rate <= 6000) {
|
||||||
|
score += 11;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!inertial_rate_valid && inertial_rate_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// small penalty for inconsistent data
|
||||||
|
|
||||||
|
// Should check IAS vs Mach at given altitude, but the maths is a little involved
|
||||||
|
|
||||||
|
if (baro_rate_valid && inertial_rate_valid) {
|
||||||
|
int delta = abs(baro_rate - inertial_rate);
|
||||||
|
if (delta > 2000) {
|
||||||
|
score -= 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_HEADING_SPEED;
|
||||||
|
|
||||||
|
if (heading_valid) {
|
||||||
|
mm->heading_valid = 1;
|
||||||
|
mm->heading = heading;
|
||||||
|
mm->heading_type = HEADING_MAGNETIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ias_valid) {
|
||||||
|
mm->ias_valid = 1;
|
||||||
|
mm->ias = ias;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mach_valid) {
|
||||||
|
mm->mach_valid = 1;
|
||||||
|
mm->mach = mach;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baro_rate_valid) {
|
||||||
|
mm->baro_rate_valid = 1;
|
||||||
|
mm->baro_rate = baro_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inertial_rate_valid) {
|
||||||
|
// INS-derived data is treated as a "geometric rate" / "geometric altitude"
|
||||||
|
// elsewhere, so do the same here.
|
||||||
|
mm->geom_rate_valid = 1;
|
||||||
|
mm->geom_rate = inertial_rate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BDS4,4 Meterological routine air report
|
||||||
|
static int decodeBDS44(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
unsigned char *msg = mm->MB;
|
||||||
|
|
||||||
|
unsigned source = getbits(msg, 1, 4);
|
||||||
|
|
||||||
|
unsigned wind_valid = getbit(msg, 5);
|
||||||
|
unsigned windspeed_raw = getbits(msg, 6, 14);
|
||||||
|
unsigned winddir_raw = getbits(msg, 15, 23);
|
||||||
|
|
||||||
|
// ICAO 9871 is inconsistent, it claims:
|
||||||
|
// bit 24 sign
|
||||||
|
// bits 25..34 static air temperature, MSB = 64C, LSB=0.25C, range -128C..+128C
|
||||||
|
//
|
||||||
|
// .. but this does not actually work, there is one too many bits in the bitfield
|
||||||
|
// for the claimed values.
|
||||||
|
//
|
||||||
|
// Based on observed data, the most plausible actual layout is:
|
||||||
|
//
|
||||||
|
// bit 24 status
|
||||||
|
// bit 25 sign
|
||||||
|
// bits 26..34 static air temperature, MSB=64C, LSB=0.25C, range -128C..+128C
|
||||||
|
|
||||||
|
unsigned sat_valid = getbit(msg, 24);
|
||||||
|
unsigned sat_sign = getbit(msg, 25);
|
||||||
|
unsigned sat_raw = getbits(msg, 26, 34);
|
||||||
|
|
||||||
|
unsigned asp_valid = getbit(msg, 35);
|
||||||
|
unsigned asp_raw = getbits(msg, 36, 46);
|
||||||
|
|
||||||
|
unsigned turbulence_valid = getbit(msg, 47);
|
||||||
|
unsigned turbulence_raw = getbits(msg, 48, 49);
|
||||||
|
|
||||||
|
unsigned humidity_valid = getbit(msg, 50);
|
||||||
|
unsigned humidity_raw = getbits(msg, 51, 56);
|
||||||
|
|
||||||
|
if (source == MRAR_SOURCE_INVALID || source >= MRAR_SOURCE_RESERVED)
|
||||||
|
return 0; // invalid or reserved source
|
||||||
|
|
||||||
|
if (!wind_valid || !sat_valid)
|
||||||
|
return 0; // all valid messages seen in the wild have at least temp + wind
|
||||||
|
|
||||||
|
if (!asp_valid && asp_raw != 0)
|
||||||
|
return 0; // ASP not valid, but non-zero values in the ASP field
|
||||||
|
|
||||||
|
if (!turbulence_valid && turbulence_raw != 0)
|
||||||
|
return 0; // turbulence not valid, but non-zero values in the turbulence field
|
||||||
|
|
||||||
|
if (!humidity_valid && humidity_raw != 0)
|
||||||
|
return 0; // humidity not valid, but non-zero values in the humidity field
|
||||||
|
|
||||||
|
int score = 0;
|
||||||
|
|
||||||
|
float wind_speed = 0;
|
||||||
|
float wind_dir = 0;
|
||||||
|
if (wind_valid) {
|
||||||
|
wind_dir = winddir_raw * (180.0 / 256.0);
|
||||||
|
wind_speed = windspeed_raw;
|
||||||
|
|
||||||
|
if (windspeed_raw == 0) // possible but uncommon
|
||||||
|
score += 2;
|
||||||
|
else if (wind_speed <= 250)
|
||||||
|
score += 19;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float sat = 0;
|
||||||
|
if (sat_valid) {
|
||||||
|
sat = sat_raw * 0.25;
|
||||||
|
if (sat_sign)
|
||||||
|
sat -= 128;
|
||||||
|
if (sat == 0) // possible but uncommon
|
||||||
|
score += 2;
|
||||||
|
else if (sat >= -80 && sat <= 60)
|
||||||
|
score += 11;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float asp = 0;
|
||||||
|
if (asp_valid) {
|
||||||
|
asp = asp_raw;
|
||||||
|
if (asp >= 25 && asp <= 1100)
|
||||||
|
score += 12;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hazard_t turbulence = HAZARD_NIL;
|
||||||
|
if (turbulence_valid) {
|
||||||
|
turbulence = (hazard_t) turbulence_raw;
|
||||||
|
score += 3;
|
||||||
|
} else {
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float humidity = 0;
|
||||||
|
if (humidity_valid) {
|
||||||
|
humidity = humidity_raw * (100.0 / 64.0);
|
||||||
|
score += 7;
|
||||||
|
} else {
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source == MRAR_SOURCE_DMEDME && wind_valid && sat_valid && score > 0) {
|
||||||
|
// Some GICB messages can be easily mistaken for a MRAR:
|
||||||
|
//
|
||||||
|
// GICB bit 1: BDS 0,5 ES airborne position = 0 ]
|
||||||
|
// GICB bit 2: BDS 0,6 ES surface position = 0 ]
|
||||||
|
// GICB bit 3: BDS 0,7 ES status = 1 ]
|
||||||
|
// GICB bit 4: BDS 0,8 ES type & identification = 1 ] -> MRAR source = 3
|
||||||
|
// GICB bit 5: BDS 0,9 ES airborne velocity = 1 -> MRAR wind valid bit
|
||||||
|
// GICB bit 24: BDS 6,0 heading and speed report = 1 -> MRAR temp valid bit
|
||||||
|
// most trailing bits = 0
|
||||||
|
//
|
||||||
|
// so only treat this as MRAR as a last resort
|
||||||
|
score = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_MRAR;
|
||||||
|
mm->mrar_source_valid = 1;
|
||||||
|
mm->mrar_source = (mrar_source_t) source;
|
||||||
|
|
||||||
|
if (wind_valid) {
|
||||||
|
mm->wind_valid = 1;
|
||||||
|
mm->wind_speed = wind_speed;
|
||||||
|
mm->wind_dir = wind_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sat_valid) {
|
||||||
|
mm->temperature_valid = 1;
|
||||||
|
mm->temperature = sat;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asp_valid) {
|
||||||
|
mm->pressure_valid = 1;
|
||||||
|
mm->pressure = asp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (turbulence_valid) {
|
||||||
|
mm->turbulence_valid = 1;
|
||||||
|
mm->turbulence = turbulence;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (humidity_valid) {
|
||||||
|
mm->humidity_valid = 1;
|
||||||
|
mm->humidity = humidity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BDS0,5 extended squitter airborne position
|
||||||
|
// (apparently this gets queried via comm-b sometimes??)
|
||||||
|
// We don't try to _use_ this as a position, but we can
|
||||||
|
// at least try to recognize it, to exclude other
|
||||||
|
// comm-b types (in particular they can be mistaken for MRAR)
|
||||||
|
static int decodeBDS05(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
// We recognize these by matching the position altitude against
|
||||||
|
// the altitude in the surrounding message, so we need a
|
||||||
|
// DF20 not a DF21
|
||||||
|
if (mm->msgtype != 20)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
unsigned char *msg = mm->MB;
|
||||||
|
|
||||||
|
unsigned typecode = getbits(msg, 1, 5);
|
||||||
|
if (typecode < 9 || typecode > 18)
|
||||||
|
return 0; // only consider typecodes that could be an airborne position with baro altitude
|
||||||
|
|
||||||
|
unsigned t_bit = getbit(msg, 21);
|
||||||
|
if (t_bit) // unlikely
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
unsigned ac12 = getbits(msg, 9, 20);
|
||||||
|
if (!ac12)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Insert M=0 to make an AC13 value, match against the
|
||||||
|
// AC13 value in the surrounding message
|
||||||
|
unsigned ac13 = ((ac12 & 0x0FC0) << 1) | (ac12 & 0x003F);
|
||||||
|
if (mm->AC != ac13)
|
||||||
|
return 0; // no altitude match
|
||||||
|
|
||||||
|
unsigned lat = getbits(msg, 23, 39);
|
||||||
|
unsigned lon = getbits(msg, 40, 56);
|
||||||
|
if (lat == 0 || lon == 0) // unlikely position
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_AIRBORNE_POSITION;
|
||||||
|
// No further decoding done, we don't really trust this
|
||||||
|
// enough to use as real input to CPR
|
||||||
|
}
|
||||||
|
|
||||||
|
// Score this high enough to override everything else
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// comm_b.h: Comm-B message decoding (prototypes)
|
||||||
|
//
|
||||||
|
// Copyright (c) 2017 FlightAware, LLC
|
||||||
|
// Copyright (c) 2017 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
|
//
|
||||||
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the
|
||||||
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
|
// option) any later version.
|
||||||
|
//
|
||||||
|
// This file is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef COMM_B_H
|
||||||
|
#define COMM_B_H
|
||||||
|
|
||||||
|
void decodeCommB(struct modesMessage *mm);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c), MM Weiss
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the MM Weiss 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 OWNER 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.
|
||||||
|
*/
|
||||||
|
|
@ -0,0 +1,138 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c), MM Weiss
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
* are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the MM Weiss 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 OWNER 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* clock_gettime_stub.c
|
||||||
|
* gcc -Wall -c clock_gettime_stub.c
|
||||||
|
* posix realtime functions; MacOS user space glue
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* @comment
|
||||||
|
* other possible implementation using intel builtin rdtsc
|
||||||
|
* rdtsc-workaround: http://www.mcs.anl.gov/~kazutomo/rdtsc.html
|
||||||
|
*
|
||||||
|
* we could get the ticks by doing this
|
||||||
|
*
|
||||||
|
* __asm __volatile("mov %%ebx, %%esi\n\t"
|
||||||
|
* "cpuid\n\t"
|
||||||
|
* "xchg %%esi, %%ebx\n\t"
|
||||||
|
* "rdtsc"
|
||||||
|
* : "=a" (a),
|
||||||
|
* "=d" (d)
|
||||||
|
* );
|
||||||
|
* we could even replace our tricky sched_yield call by assembly code to get a better accurency,
|
||||||
|
* anyway the following C stub will satisfy 99% of apps using posix clock_gettime call,
|
||||||
|
* moreover, the setter version (clock_settime) could be easly written using mach primitives:
|
||||||
|
* http://www.opensource.apple.com/source/xnu/xnu-${VERSION}/osfmk/man/ (clock_[set|get]_time)
|
||||||
|
*
|
||||||
|
* hackers don't be crackers, don't you use a flush toilet?
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @see draft: ./posix-realtime-stub/posix-realtime-stub.c
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "../compat.h"
|
||||||
|
#include <mach/mach_time.h>
|
||||||
|
#include <mach/clock.h> // for clock_get_time
|
||||||
|
#include <mach/clock_types.h> // for mach_timespec_t, CALENDAR_CLOCK, etc
|
||||||
|
#include <mach/kern_return.h> // for KERN_SUCCESS, kern_return_t
|
||||||
|
#include <mach/mach_host.h> // for host_get_clock_service
|
||||||
|
#include <mach/mach_init.h> // for mach_host_self
|
||||||
|
#include <mach/mach_types.h> // for clock_serv_t
|
||||||
|
#include <sched.h> // for sched_yield
|
||||||
|
#include <errno.h> // for EINVAL, errno
|
||||||
|
#include <unistd.h> // for getpid
|
||||||
|
|
||||||
|
static mach_timebase_info_data_t __clock_gettime_inf;
|
||||||
|
|
||||||
|
int clock_gettime(clockid_t clk_id, struct timespec *tp)
|
||||||
|
{
|
||||||
|
kern_return_t ret;
|
||||||
|
clock_serv_t clk;
|
||||||
|
clock_id_t clk_serv_id;
|
||||||
|
mach_timespec_t tm;
|
||||||
|
|
||||||
|
uint64_t start, end, delta, nano;
|
||||||
|
|
||||||
|
/*
|
||||||
|
task_basic_info_data_t tinfo;
|
||||||
|
task_thread_times_info_data_t ttinfo;
|
||||||
|
mach_msg_type_number_t tflag;
|
||||||
|
*/
|
||||||
|
|
||||||
|
int retval = -1;
|
||||||
|
switch (clk_id)
|
||||||
|
{
|
||||||
|
case CLOCK_REALTIME:
|
||||||
|
case CLOCK_MONOTONIC:
|
||||||
|
clk_serv_id = clk_id == CLOCK_REALTIME ? CALENDAR_CLOCK : SYSTEM_CLOCK;
|
||||||
|
if (KERN_SUCCESS == (ret = host_get_clock_service(mach_host_self(), clk_serv_id, &clk)))
|
||||||
|
{
|
||||||
|
if (KERN_SUCCESS == (ret = clock_get_time(clk, &tm)))
|
||||||
|
{
|
||||||
|
tp->tv_sec = tm.tv_sec;
|
||||||
|
tp->tv_nsec = tm.tv_nsec;
|
||||||
|
retval = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (KERN_SUCCESS != ret)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
retval = -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CLOCK_PROCESS_CPUTIME_ID:
|
||||||
|
case CLOCK_THREAD_CPUTIME_ID:
|
||||||
|
start = mach_absolute_time();
|
||||||
|
if (clk_id == CLOCK_PROCESS_CPUTIME_ID)
|
||||||
|
{
|
||||||
|
getpid();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sched_yield();
|
||||||
|
}
|
||||||
|
end = mach_absolute_time();
|
||||||
|
delta = end - start;
|
||||||
|
if (0 == __clock_gettime_inf.denom)
|
||||||
|
{
|
||||||
|
mach_timebase_info(&__clock_gettime_inf);
|
||||||
|
}
|
||||||
|
nano = delta * __clock_gettime_inf.numer / __clock_gettime_inf.denom;
|
||||||
|
tp->tv_sec = nano * 1e-9;
|
||||||
|
tp->tv_nsec = nano - (tp->tv_sec * 1e9);
|
||||||
|
retval = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errno = EINVAL;
|
||||||
|
retval = -1;
|
||||||
|
}
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef CLOCK_GETTIME_H
|
||||||
|
#define CLOCK_GETTIME_H
|
||||||
|
|
||||||
|
int clock_gettime(clockid_t clk_id, struct timespec *tp);
|
||||||
|
|
||||||
|
#endif // CLOCK_GETTIME_H
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
/***********************************************************************
|
||||||
|
* Copyright © 2006 Rémi Denis-Courmont. *
|
||||||
|
* This program is free software; you can redistribute and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published *
|
||||||
|
* by the Free Software Foundation; version 2 of the license, or (at *
|
||||||
|
* your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
||||||
|
* See the GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, you can get it from: *
|
||||||
|
* http://www.gnu.org/copyleft/gpl.html *
|
||||||
|
***********************************************************************/
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* clock_nanosleep.c - clock_nanosleep() replacement
|
||||||
|
*/
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* Copyright © 2006 Rémi Denis-Courmont. *
|
||||||
|
* This program is free software; you can redistribute and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published *
|
||||||
|
* by the Free Software Foundation; version 2 of the license, or (at *
|
||||||
|
* your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
|
||||||
|
* See the GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, you can get it from: *
|
||||||
|
* http://www.gnu.org/copyleft/gpl.html *
|
||||||
|
***********************************************************************/
|
||||||
|
|
||||||
|
#include <errno.h> // for errno, EINVAL
|
||||||
|
#include <time.h> // for nanosleep, NULL
|
||||||
|
|
||||||
|
#include "../compat.h"
|
||||||
|
|
||||||
|
int clock_nanosleep(clockid_t id, int flags, const struct timespec *ts,
|
||||||
|
struct timespec *ots) {
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (id != CLOCK_REALTIME)
|
||||||
|
return EINVAL;
|
||||||
|
|
||||||
|
if (flags & TIMER_ABSTIME) {
|
||||||
|
struct timespec mine;
|
||||||
|
|
||||||
|
if (clock_gettime(id, &mine))
|
||||||
|
return errno;
|
||||||
|
|
||||||
|
if (mine.tv_sec > ts->tv_sec)
|
||||||
|
return 0; // behind schedule
|
||||||
|
|
||||||
|
if (mine.tv_nsec > ts->tv_nsec) {
|
||||||
|
if (mine.tv_sec == ts->tv_sec)
|
||||||
|
return 0; // behind schedule too
|
||||||
|
|
||||||
|
mine.tv_nsec = 1000000000 + ts->tv_nsec - mine.tv_nsec;
|
||||||
|
mine.tv_sec++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
mine.tv_nsec = ts->tv_nsec - mine.tv_nsec;
|
||||||
|
|
||||||
|
mine.tv_sec = ts->tv_sec - mine.tv_sec;
|
||||||
|
|
||||||
|
/* With TIMER_ABSTIME, clock_nanosleep ignores <ots> */
|
||||||
|
ret = nanosleep(&mine, NULL);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ret = nanosleep(ts, ots);
|
||||||
|
|
||||||
|
return ret ? errno : 0;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef CLOCK_NANOSLEEP_H
|
||||||
|
#define CLOCK_NANOSLEEP_H
|
||||||
|
|
||||||
|
int clock_nanosleep (clockid_t id, int flags, const struct timespec *ts,
|
||||||
|
struct timespec *ots);
|
||||||
|
|
||||||
|
#endif //CLOCK_NANOSLEEP_H
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
#ifndef COMPAT_UTIL_H
|
||||||
|
#define COMPAT_UTIL_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Platform-specific bits
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mach endian conversion
|
||||||
|
*/
|
||||||
|
# include <libkern/OSByteOrder.h>
|
||||||
|
# define bswap_16 OSSwapInt16
|
||||||
|
# define bswap_32 OSSwapInt32
|
||||||
|
# define bswap_64 OSSwapInt64
|
||||||
|
# include <machine/endian.h>
|
||||||
|
# define le16toh(x) OSSwapLittleToHostInt16(x)
|
||||||
|
# define le32toh(x) OSSwapLittleToHostInt32(x)
|
||||||
|
# define le64toh(x) OSSwapLittleToHostInt64(x)
|
||||||
|
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
#include <sys/endian.h>
|
||||||
|
|
||||||
|
#else // other platforms
|
||||||
|
|
||||||
|
# include <endian.h>
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* clock_* and time-related types */
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#if defined(CLOCK_REALTIME)
|
||||||
|
# define HAVE_CLOCKID_T
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_CLOCKID_T
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
CLOCK_REALTIME,
|
||||||
|
CLOCK_MONOTONIC,
|
||||||
|
CLOCK_PROCESS_CPUTIME_ID,
|
||||||
|
CLOCK_THREAD_CPUTIME_ID
|
||||||
|
} clockid_t;
|
||||||
|
#endif // !HAVE_CLOCKID_T
|
||||||
|
|
||||||
|
#ifndef TIMER_ABSTIME
|
||||||
|
#define TIMER_ABSTIME 1
|
||||||
|
#endif // !TIMER_ABSTIME
|
||||||
|
|
||||||
|
struct timespec;
|
||||||
|
|
||||||
|
#ifdef MISSING_NANOSLEEP
|
||||||
|
#include "clock_nanosleep/clock_nanosleep.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef MISSING_GETTIME
|
||||||
|
#include "clock_gettime/clock_gettime.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //COMPAT_UTIL_H
|
||||||
|
|
@ -0,0 +1,123 @@
|
||||||
|
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// convert.c: support for various IQ -> magnitude conversions
|
||||||
|
//
|
||||||
|
// Copyright (c) 2015 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
|
//
|
||||||
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the
|
||||||
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
|
// option) any later version.
|
||||||
|
//
|
||||||
|
// This file is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "dump1090.h"
|
||||||
|
|
||||||
|
static void convert_uc8(void *iq_data,
|
||||||
|
uint16_t *mag_data,
|
||||||
|
unsigned nsamples,
|
||||||
|
struct converter_state *state,
|
||||||
|
double *out_mean_level,
|
||||||
|
double *out_mean_power)
|
||||||
|
{
|
||||||
|
MODES_NOTUSED(state);
|
||||||
|
|
||||||
|
const uc8_t *in = (const uc8_t *) iq_data;
|
||||||
|
|
||||||
|
if (out_mean_level && out_mean_power) {
|
||||||
|
if (STARCH_IS_ALIGNED(in) && STARCH_IS_ALIGNED(mag_data))
|
||||||
|
starch_magnitude_power_uc8_aligned(in, mag_data, nsamples, out_mean_level, out_mean_power);
|
||||||
|
else
|
||||||
|
starch_magnitude_power_uc8(in, mag_data, nsamples, out_mean_level, out_mean_power);
|
||||||
|
} else {
|
||||||
|
if (STARCH_IS_ALIGNED(in) && STARCH_IS_ALIGNED(mag_data))
|
||||||
|
starch_magnitude_uc8_aligned(in, mag_data, nsamples);
|
||||||
|
else
|
||||||
|
starch_magnitude_uc8(in, mag_data, nsamples);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void convert_sc16(void *iq_data,
|
||||||
|
uint16_t *mag_data,
|
||||||
|
unsigned nsamples,
|
||||||
|
struct converter_state *state,
|
||||||
|
double *out_mean_level,
|
||||||
|
double *out_mean_power)
|
||||||
|
{
|
||||||
|
MODES_NOTUSED(state);
|
||||||
|
|
||||||
|
const sc16_t *in = (const sc16_t *) iq_data;
|
||||||
|
|
||||||
|
if (STARCH_IS_ALIGNED(in) && STARCH_IS_ALIGNED(mag_data))
|
||||||
|
starch_magnitude_sc16_aligned(in, mag_data, nsamples);
|
||||||
|
else
|
||||||
|
starch_magnitude_sc16(in, mag_data, nsamples);
|
||||||
|
|
||||||
|
if (out_mean_level && out_mean_power) {
|
||||||
|
if (STARCH_IS_ALIGNED(mag_data))
|
||||||
|
starch_mean_power_u16_aligned(mag_data, nsamples, out_mean_level, out_mean_power);
|
||||||
|
else
|
||||||
|
starch_mean_power_u16(mag_data, nsamples, out_mean_level, out_mean_power);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void convert_sc16q11(void *iq_data,
|
||||||
|
uint16_t *mag_data,
|
||||||
|
unsigned nsamples,
|
||||||
|
struct converter_state *state,
|
||||||
|
double *out_mean_level,
|
||||||
|
double *out_mean_power)
|
||||||
|
{
|
||||||
|
MODES_NOTUSED(state);
|
||||||
|
|
||||||
|
const sc16_t *in = (const sc16_t *) iq_data;
|
||||||
|
|
||||||
|
if (STARCH_IS_ALIGNED(in) && STARCH_IS_ALIGNED(mag_data))
|
||||||
|
starch_magnitude_sc16q11_aligned(in, mag_data, nsamples);
|
||||||
|
else
|
||||||
|
starch_magnitude_sc16q11(in, mag_data, nsamples);
|
||||||
|
|
||||||
|
if (out_mean_level && out_mean_power) {
|
||||||
|
if (STARCH_IS_ALIGNED(mag_data))
|
||||||
|
starch_mean_power_u16_aligned(mag_data, nsamples, out_mean_level, out_mean_power);
|
||||||
|
else
|
||||||
|
starch_mean_power_u16(mag_data, nsamples, out_mean_level, out_mean_power);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iq_convert_fn init_converter(input_format_t format,
|
||||||
|
double sample_rate,
|
||||||
|
int filter_dc,
|
||||||
|
struct converter_state **out_state)
|
||||||
|
{
|
||||||
|
MODES_NOTUSED(sample_rate);
|
||||||
|
MODES_NOTUSED(out_state);
|
||||||
|
|
||||||
|
if (filter_dc) {
|
||||||
|
fprintf(stderr, "DC filtering not supported (yet)\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (format) {
|
||||||
|
case INPUT_UC8:
|
||||||
|
return convert_uc8;
|
||||||
|
case INPUT_SC16:
|
||||||
|
return convert_sc16;
|
||||||
|
case INPUT_SC16Q11:
|
||||||
|
return convert_sc16q11;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "no suitable converter for format=%d\n", format);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup_converter(struct converter_state *state)
|
||||||
|
{
|
||||||
|
MODES_NOTUSED(state);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// convert.h: support for various IQ -> magnitude conversions
|
||||||
|
//
|
||||||
|
// Copyright (c) 2015 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
|
//
|
||||||
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the
|
||||||
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
|
// option) any later version.
|
||||||
|
//
|
||||||
|
// This file is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef DUMP1090_CONVERT_H
|
||||||
|
#define DUMP1090_CONVERT_H
|
||||||
|
|
||||||
|
struct converter_state;
|
||||||
|
typedef enum { INPUT_UC8=0, INPUT_SC16, INPUT_SC16Q11 } input_format_t;
|
||||||
|
|
||||||
|
typedef void (*iq_convert_fn)(void *iq_data,
|
||||||
|
uint16_t *mag_data,
|
||||||
|
unsigned nsamples,
|
||||||
|
struct converter_state *state,
|
||||||
|
double *out_mean_level,
|
||||||
|
double *out_mean_power);
|
||||||
|
|
||||||
|
iq_convert_fn init_converter(input_format_t format,
|
||||||
|
double sample_rate,
|
||||||
|
int filter_dc,
|
||||||
|
struct converter_state **out_state);
|
||||||
|
|
||||||
|
void cleanup_converter(struct converter_state *state);
|
||||||
|
|
||||||
|
#endif
|
||||||
24
cpr.c
24
cpr.c
|
|
@ -47,6 +47,8 @@
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include "cpr.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
@ -250,8 +252,26 @@ int decodeCPRsurface(double reflat, double reflon,
|
||||||
// reflat=-40, rlat=4, use rlat=4
|
// reflat=-40, rlat=4, use rlat=4
|
||||||
// reflat=-40, rlat=6, use rlat=6-90 = -84
|
// reflat=-40, rlat=6, use rlat=6-90 = -84
|
||||||
|
|
||||||
if ( (rlat0 - reflat) > 45 ) rlat0 -= 90;
|
// As a special case, -90, 0 and +90 all encode to zero, so
|
||||||
if ( (rlat1 - reflat) > 45 ) rlat1 -= 90;
|
// there's a little extra work to do there.
|
||||||
|
|
||||||
|
if (rlat0 == 0) {
|
||||||
|
if (reflat < -45)
|
||||||
|
rlat0 = -90;
|
||||||
|
else if (reflat > 45)
|
||||||
|
rlat0 = 90;
|
||||||
|
} else if ((rlat0 - reflat) > 45) {
|
||||||
|
rlat0 -= 90;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rlat1 == 0) {
|
||||||
|
if (reflat < -45)
|
||||||
|
rlat1 = -90;
|
||||||
|
else if (reflat > 45)
|
||||||
|
rlat1 = 90;
|
||||||
|
} else if ((rlat1 - reflat) > 45) {
|
||||||
|
rlat1 -= 90;
|
||||||
|
}
|
||||||
|
|
||||||
// Check to see that the latitude is in range: -90 .. +90
|
// Check to see that the latitude is in range: -90 .. +90
|
||||||
if (rlat0 < -90 || rlat0 > 90 || rlat1 < -90 || rlat1 > 90)
|
if (rlat0 < -90 || rlat0 > 90 || rlat1 < -90 || rlat1 > 90)
|
||||||
|
|
|
||||||
28
cprtests.c
28
cprtests.c
|
|
@ -73,6 +73,13 @@ static const struct {
|
||||||
{ 7.00, 0.00, 105730, 9259, 29693, 8997, 0, 52.209984 - 90.0, 0.135269, 0, 52.209976 - 90.0, 0.134299 },
|
{ 7.00, 0.00, 105730, 9259, 29693, 8997, 0, 52.209984 - 90.0, 0.135269, 0, 52.209976 - 90.0, 0.134299 },
|
||||||
{ -52.00, 0.00, 105730, 9259, 29693, 8997, 0, 52.209984 - 90.0, 0.135269, 0, 52.209976 - 90.0, 0.134299 },
|
{ -52.00, 0.00, 105730, 9259, 29693, 8997, 0, 52.209984 - 90.0, 0.135269, 0, 52.209976 - 90.0, 0.134299 },
|
||||||
{ -90.00, 0.00, 105730, 9259, 29693, 8997, 0, 52.209984 - 90.0, 0.135269, 0, 52.209976 - 90.0, 0.134299 },
|
{ -90.00, 0.00, 105730, 9259, 29693, 8997, 0, 52.209984 - 90.0, 0.135269, 0, 52.209976 - 90.0, 0.134299 },
|
||||||
|
|
||||||
|
// poles/equator cases
|
||||||
|
{ -46.00, -180.00, 0, 0, 0, 0, 0, -90.0, -180.000000, 0, -90.0, -180.0 }, // south pole
|
||||||
|
{ -44.00, -180.00, 0, 0, 0, 0, 0, 0.0, -180.000000, 0, 0.0, -180.0 }, // equator
|
||||||
|
{ 44.00, -180.00, 0, 0, 0, 0, 0, 0.0, -180.000000, 0, 0.0, -180.0 }, // equator
|
||||||
|
{ 46.00, -180.00, 0, 0, 0, 0, 0, 90.0, -180.000000, 0, 90.0, -180.0 }, // north pole
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Relative CPR test data:
|
// Relative CPR test data:
|
||||||
|
|
@ -138,7 +145,6 @@ static const struct {
|
||||||
{ 52.00, 1.40, 29693, 8997, 1, 1, 0, 52.209976, 0.176507 }, // odd, surface
|
{ 52.00, 1.40, 29693, 8997, 1, 1, 0, 52.209976, 0.176507 }, // odd, surface
|
||||||
{ 52.00, -1.05, 105730, 9259, 0, 1, 0, 52.209984, 0.176601 }, // even, surface
|
{ 52.00, -1.05, 105730, 9259, 0, 1, 0, 52.209984, 0.176601 }, // even, surface
|
||||||
{ 52.00, -1.05, 29693, 8997, 1, 1, 0, 52.209976, 0.176507 }, // odd, surface
|
{ 52.00, -1.05, 29693, 8997, 1, 1, 0, 52.209976, 0.176507 }, // odd, surface
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static int testCPRGlobalAirborne() {
|
static int testCPRGlobalAirborne() {
|
||||||
|
|
@ -157,7 +163,7 @@ static int testCPRGlobalAirborne() {
|
||||||
|| fabs(rlon - cprGlobalAirborneTests[i].even_rlon) > 1e-6) {
|
|| fabs(rlon - cprGlobalAirborneTests[i].even_rlon) > 1e-6) {
|
||||||
ok = 0;
|
ok = 0;
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"testCPRGlobalAirborne[%d,EVEN]: FAIL: decodeCPRairborne(%d,%d,%d,%d,EVEN) failed:\n"
|
"testCPRGlobalAirborne[%u,EVEN]: FAIL: decodeCPRairborne(%d,%d,%d,%d,EVEN) failed:\n"
|
||||||
" result %d (expected %d)\n"
|
" result %d (expected %d)\n"
|
||||||
" lat %.6f (expected %.6f)\n"
|
" lat %.6f (expected %.6f)\n"
|
||||||
" lon %.6f (expected %.6f)\n",
|
" lon %.6f (expected %.6f)\n",
|
||||||
|
|
@ -168,7 +174,7 @@ static int testCPRGlobalAirborne() {
|
||||||
rlat, cprGlobalAirborneTests[i].even_rlat,
|
rlat, cprGlobalAirborneTests[i].even_rlat,
|
||||||
rlon, cprGlobalAirborneTests[i].even_rlon);
|
rlon, cprGlobalAirborneTests[i].even_rlon);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "testCPRGlobalAirborne[%d,EVEN]: PASS\n", i);
|
fprintf(stderr, "testCPRGlobalAirborne[%u,EVEN]: PASS\n", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = decodeCPRairborne(cprGlobalAirborneTests[i].even_cprlat, cprGlobalAirborneTests[i].even_cprlon,
|
res = decodeCPRairborne(cprGlobalAirborneTests[i].even_cprlat, cprGlobalAirborneTests[i].even_cprlon,
|
||||||
|
|
@ -180,7 +186,7 @@ static int testCPRGlobalAirborne() {
|
||||||
|| fabs(rlon - cprGlobalAirborneTests[i].odd_rlon) > 1e-6) {
|
|| fabs(rlon - cprGlobalAirborneTests[i].odd_rlon) > 1e-6) {
|
||||||
ok = 0;
|
ok = 0;
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"testCPRGlobalAirborne[%d,ODD]: FAIL: decodeCPRairborne(%d,%d,%d,%d,ODD) failed:\n"
|
"testCPRGlobalAirborne[%u,ODD]: FAIL: decodeCPRairborne(%d,%d,%d,%d,ODD) failed:\n"
|
||||||
" result %d (expected %d)\n"
|
" result %d (expected %d)\n"
|
||||||
" lat %.6f (expected %.6f)\n"
|
" lat %.6f (expected %.6f)\n"
|
||||||
" lon %.6f (expected %.6f)\n",
|
" lon %.6f (expected %.6f)\n",
|
||||||
|
|
@ -191,7 +197,7 @@ static int testCPRGlobalAirborne() {
|
||||||
rlat, cprGlobalAirborneTests[i].odd_rlat,
|
rlat, cprGlobalAirborneTests[i].odd_rlat,
|
||||||
rlon, cprGlobalAirborneTests[i].odd_rlon);
|
rlon, cprGlobalAirborneTests[i].odd_rlon);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "testCPRGlobalAirborne[%d,ODD]: PASS\n", i);
|
fprintf(stderr, "testCPRGlobalAirborne[%u,ODD]: PASS\n", i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -215,7 +221,7 @@ static int testCPRGlobalSurface() {
|
||||||
|| fabs(rlon - cprGlobalSurfaceTests[i].even_rlon) > 1e-6) {
|
|| fabs(rlon - cprGlobalSurfaceTests[i].even_rlon) > 1e-6) {
|
||||||
ok = 0;
|
ok = 0;
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"testCPRGlobalSurface[%d]: FAIL: decodeCPRsurface(%.6f,%.6f,%d,%d,%d,%d,EVEN) failed:\n"
|
"testCPRGlobalSurface[%u,EVEN]: FAIL: decodeCPRsurface(%.6f,%.6f,%d,%d,%d,%d,EVEN) failed:\n"
|
||||||
" result %d (expected %d)\n"
|
" result %d (expected %d)\n"
|
||||||
" lat %.6f (expected %.6f)\n"
|
" lat %.6f (expected %.6f)\n"
|
||||||
" lon %.6f (expected %.6f)\n",
|
" lon %.6f (expected %.6f)\n",
|
||||||
|
|
@ -227,7 +233,7 @@ static int testCPRGlobalSurface() {
|
||||||
rlat, cprGlobalSurfaceTests[i].even_rlat,
|
rlat, cprGlobalSurfaceTests[i].even_rlat,
|
||||||
rlon, cprGlobalSurfaceTests[i].even_rlon);
|
rlon, cprGlobalSurfaceTests[i].even_rlon);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "testCPRGlobalSurface[%d,EVEN]: PASS\n", i);
|
fprintf(stderr, "testCPRGlobalSurface[%u,EVEN]: PASS\n", i);
|
||||||
}
|
}
|
||||||
|
|
||||||
res = decodeCPRsurface(cprGlobalSurfaceTests[i].reflat, cprGlobalSurfaceTests[i].reflon,
|
res = decodeCPRsurface(cprGlobalSurfaceTests[i].reflat, cprGlobalSurfaceTests[i].reflon,
|
||||||
|
|
@ -240,7 +246,7 @@ static int testCPRGlobalSurface() {
|
||||||
|| fabs(rlon - cprGlobalSurfaceTests[i].odd_rlon) > 1e-6) {
|
|| fabs(rlon - cprGlobalSurfaceTests[i].odd_rlon) > 1e-6) {
|
||||||
ok = 0;
|
ok = 0;
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"testCPRGlobalSurface[%d,ODD]: FAIL: decodeCPRsurface(%.6f,%.6f,%d,%d,%d,%d,ODD) failed:\n"
|
"testCPRGlobalSurface[%u,ODD]: FAIL: decodeCPRsurface(%.6f,%.6f,%d,%d,%d,%d,ODD) failed:\n"
|
||||||
" result %d (expected %d)\n"
|
" result %d (expected %d)\n"
|
||||||
" lat %.6f (expected %.6f)\n"
|
" lat %.6f (expected %.6f)\n"
|
||||||
" lon %.6f (expected %.6f)\n",
|
" lon %.6f (expected %.6f)\n",
|
||||||
|
|
@ -252,7 +258,7 @@ static int testCPRGlobalSurface() {
|
||||||
rlat, cprGlobalSurfaceTests[i].odd_rlat,
|
rlat, cprGlobalSurfaceTests[i].odd_rlat,
|
||||||
rlon, cprGlobalSurfaceTests[i].odd_rlon);
|
rlon, cprGlobalSurfaceTests[i].odd_rlon);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "testCPRGlobalSurface[%d,ODD]: PASS\n", i);
|
fprintf(stderr, "testCPRGlobalSurface[%u,ODD]: PASS\n", i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -275,7 +281,7 @@ static int testCPRRelative() {
|
||||||
|| fabs(rlon - cprRelativeTests[i].rlon) > 1e-6) {
|
|| fabs(rlon - cprRelativeTests[i].rlon) > 1e-6) {
|
||||||
ok = 0;
|
ok = 0;
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"testCPRRelative[%d]: FAIL: decodeCPRrelative(%.6f,%.6f,%d,%d,%d,%d) failed:\n"
|
"testCPRRelative[%u]: FAIL: decodeCPRrelative(%.6f,%.6f,%d,%d,%d,%d) failed:\n"
|
||||||
" result %d (expected %d)\n"
|
" result %d (expected %d)\n"
|
||||||
" lat %.6f (expected %.6f)\n"
|
" lat %.6f (expected %.6f)\n"
|
||||||
" lon %.6f (expected %.6f)\n",
|
" lon %.6f (expected %.6f)\n",
|
||||||
|
|
@ -287,7 +293,7 @@ static int testCPRRelative() {
|
||||||
rlat, cprRelativeTests[i].rlat,
|
rlat, cprRelativeTests[i].rlat,
|
||||||
rlon, cprRelativeTests[i].rlon);
|
rlon, cprRelativeTests[i].rlon);
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "testCPRRelative[%d]: PASS\n", i);
|
fprintf(stderr, "testCPRRelative[%u]: PASS\n", i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
#include "cpu.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef ENABLE_CPUFEATURES
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// x86
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef CPU_FEATURES_ARCH_X86
|
||||||
|
#include "cpuinfo_x86.h"
|
||||||
|
|
||||||
|
static X86Info *x86_info()
|
||||||
|
{
|
||||||
|
static bool valid = false;
|
||||||
|
static X86Info cache;
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
cache = GetX86Info();
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int cpu_supports_avx(void)
|
||||||
|
{
|
||||||
|
#ifdef CPU_FEATURES_ARCH_X86
|
||||||
|
return x86_info()->features.avx;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int cpu_supports_avx2(void)
|
||||||
|
{
|
||||||
|
#ifdef CPU_FEATURES_ARCH_X86
|
||||||
|
return x86_info()->features.avx2;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ARM
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef CPU_FEATURES_ARCH_ARM
|
||||||
|
#include "cpuinfo_arm.h"
|
||||||
|
|
||||||
|
static ArmInfo *arm_info()
|
||||||
|
{
|
||||||
|
static bool valid = false;
|
||||||
|
static ArmInfo cache;
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
cache = GetArmInfo();
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int cpu_supports_armv7_neon_vfpv4(void)
|
||||||
|
{
|
||||||
|
#ifdef CPU_FEATURES_ARCH_ARM
|
||||||
|
return arm_info()->architecture >= 7 && arm_info()->features.neon && arm_info()->features.vfpv4 && arm_info()->features.vfpd32;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// AARCH64
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef CPU_FEATURES_ARCH_AARCH64
|
||||||
|
#include "cpuinfo_aarch64.h"
|
||||||
|
|
||||||
|
static Aarch64Info *aarch64_info()
|
||||||
|
{
|
||||||
|
static bool valid = false;
|
||||||
|
static Aarch64Info cache;
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
cache = GetAarch64Info();
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int cpu_supports_armv8_simd(void)
|
||||||
|
{
|
||||||
|
#ifdef CPU_FEATURES_ARCH_AARCH64
|
||||||
|
return aarch64_info()->features.asimd;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef DUMP1090_CPU_H
|
||||||
|
#define DUMP1090_CPU_H
|
||||||
|
|
||||||
|
// x86
|
||||||
|
int cpu_supports_avx(void);
|
||||||
|
int cpu_supports_avx2(void);
|
||||||
|
|
||||||
|
// ARM
|
||||||
|
int cpu_supports_armv7_neon_vfpv4(void);
|
||||||
|
|
||||||
|
// AARCH64
|
||||||
|
int cpu_supports_armv8_simd(void);
|
||||||
|
int cpu_supports_armv8_simd_sve(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
BasedOnStyle: Google
|
||||||
|
...
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
cmake_build/
|
||||||
|
build/
|
||||||
|
|
||||||
|
*.swp
|
||||||
|
|
@ -0,0 +1,121 @@
|
||||||
|
language: c
|
||||||
|
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
cache:
|
||||||
|
timeout: 1000
|
||||||
|
directories:
|
||||||
|
- $HOME/cpu_features_archives
|
||||||
|
|
||||||
|
addons:
|
||||||
|
apt_packages:
|
||||||
|
- ninja-build
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
TOOLCHAIN=NATIVE
|
||||||
|
CMAKE_GENERATOR=Ninja
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: linux
|
||||||
|
compiler: gcc
|
||||||
|
env:
|
||||||
|
TARGET=x86_64-linux-gnu
|
||||||
|
- os: linux
|
||||||
|
compiler: clang
|
||||||
|
env:
|
||||||
|
TARGET=x86_64-linux-gnu
|
||||||
|
- os: osx
|
||||||
|
compiler: gcc
|
||||||
|
env:
|
||||||
|
TARGET=x86_64-osx
|
||||||
|
CMAKE_GENERATOR="Unix Makefiles"
|
||||||
|
- os: osx
|
||||||
|
compiler: clang
|
||||||
|
env:
|
||||||
|
TARGET=x86_64-osx
|
||||||
|
CMAKE_GENERATOR="Unix Makefiles"
|
||||||
|
- os: windows
|
||||||
|
env:
|
||||||
|
TARGET=x86_64-windows
|
||||||
|
CMAKE_GENERATOR="Visual Studio 15 2017 Win64"
|
||||||
|
|
||||||
|
# see: https://docs.travis-ci.com/user/multi-cpu-architectures/
|
||||||
|
- os: linux
|
||||||
|
arch: ppc64le
|
||||||
|
compiler: gcc
|
||||||
|
env:
|
||||||
|
TARGET=ppc64le-linux-gnu
|
||||||
|
- os: linux
|
||||||
|
arch: ppc64le
|
||||||
|
compiler: clang
|
||||||
|
env:
|
||||||
|
TARGET=ppc64le-linux-gnu
|
||||||
|
|
||||||
|
# Toolchains for little-endian, 64-bit ARMv8 for GNU/Linux systems
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=aarch64-linux-gnu
|
||||||
|
QEMU_ARCH=aarch64
|
||||||
|
# Toolchains for little-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=arm-linux-gnueabihf
|
||||||
|
QEMU_ARCH=arm
|
||||||
|
# Toolchains for little-endian, 32-bit ARMv8 for GNU/Linux systems
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=armv8l-linux-gnueabihf
|
||||||
|
QEMU_ARCH=arm
|
||||||
|
# Toolchains for little-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=arm-linux-gnueabi
|
||||||
|
QEMU_ARCH=arm
|
||||||
|
# Toolchains for big-endian, 64-bit ARMv8 for GNU/Linux systems
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=aarch64_be-linux-gnu
|
||||||
|
QEMU_ARCH=DISABLED
|
||||||
|
# Toolchains for big-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=armeb-linux-gnueabihf
|
||||||
|
QEMU_ARCH=DISABLED
|
||||||
|
# Toolchains for big-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=armeb-linux-gnueabi
|
||||||
|
QEMU_ARCH=DISABLED
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=CODESCAPE
|
||||||
|
TARGET=mips32
|
||||||
|
QEMU_ARCH=mips
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=CODESCAPE
|
||||||
|
TARGET=mips32el
|
||||||
|
QEMU_ARCH=mipsel
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=CODESCAPE
|
||||||
|
TARGET=mips64
|
||||||
|
QEMU_ARCH=mips64
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=CODESCAPE
|
||||||
|
TARGET=mips64el
|
||||||
|
QEMU_ARCH=mips64el
|
||||||
|
|
||||||
|
script:
|
||||||
|
- cmake --version
|
||||||
|
- bash -e -x ./scripts/run_integration.sh
|
||||||
|
|
@ -0,0 +1,259 @@
|
||||||
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
|
||||||
|
# option() honors normal variables.
|
||||||
|
# see: https://cmake.org/cmake/help/git-stage/policy/CMP0077.html
|
||||||
|
if(POLICY CMP0077)
|
||||||
|
cmake_policy(SET CMP0077 NEW)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
project(CpuFeatures VERSION 0.6.0 LANGUAGES C)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 99)
|
||||||
|
|
||||||
|
# Default Build Type to be Release
|
||||||
|
if(NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE "Release" CACHE STRING
|
||||||
|
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
|
||||||
|
FORCE)
|
||||||
|
endif(NOT CMAKE_BUILD_TYPE)
|
||||||
|
|
||||||
|
# BUILD_TESTING is a standard CMake variable, but we declare it here to make it
|
||||||
|
# prominent in the GUI.
|
||||||
|
option(BUILD_TESTING "Enable test (depends on googletest)." OFF)
|
||||||
|
# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to make
|
||||||
|
# it prominent in the GUI.
|
||||||
|
# cpu_features uses bit-fields which are - to some extends - implementation-defined (see https://en.cppreference.com/w/c/language/bit_field).
|
||||||
|
# As a consequence it is discouraged to use cpu_features as a shared library because different compilers may interpret the code in different ways.
|
||||||
|
# Prefer static linking from source whenever possible.
|
||||||
|
option(BUILD_SHARED_LIBS "Build library as shared." OFF)
|
||||||
|
# PIC
|
||||||
|
option(BUILD_PIC "Build with Position Independant Code." OFF) # Default is off at least for GCC
|
||||||
|
|
||||||
|
# Force PIC on unix when building shared libs
|
||||||
|
# see: https://en.wikipedia.org/wiki/Position-independent_code
|
||||||
|
if(BUILD_SHARED_LIBS AND UNIX)
|
||||||
|
set(BUILD_PIC ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(CheckIncludeFile)
|
||||||
|
include(CheckSymbolExists)
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
macro(setup_include_and_definitions TARGET_NAME)
|
||||||
|
target_include_directories(${TARGET_NAME}
|
||||||
|
PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||||
|
PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include/internal>
|
||||||
|
)
|
||||||
|
target_compile_definitions(${TARGET_NAME}
|
||||||
|
PUBLIC STACK_LINE_READER_BUFFER_SIZE=1024
|
||||||
|
)
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
set(PROCESSOR_IS_MIPS FALSE)
|
||||||
|
set(PROCESSOR_IS_ARM FALSE)
|
||||||
|
set(PROCESSOR_IS_AARCH64 FALSE)
|
||||||
|
set(PROCESSOR_IS_X86 FALSE)
|
||||||
|
set(PROCESSOR_IS_POWER FALSE)
|
||||||
|
|
||||||
|
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips")
|
||||||
|
set(PROCESSOR_IS_MIPS TRUE)
|
||||||
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm")
|
||||||
|
set(PROCESSOR_IS_ARM TRUE)
|
||||||
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64")
|
||||||
|
set(PROCESSOR_IS_AARCH64 TRUE)
|
||||||
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(AMD64|amd64)|(^i.86$)")
|
||||||
|
set(PROCESSOR_IS_X86 TRUE)
|
||||||
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)")
|
||||||
|
set(PROCESSOR_IS_POWER TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME)
|
||||||
|
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpu_features_macros.h)
|
||||||
|
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpu_features_cache_info.h)
|
||||||
|
if(PROCESSOR_IS_MIPS)
|
||||||
|
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_mips.h)
|
||||||
|
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_mips.c)
|
||||||
|
elseif(PROCESSOR_IS_ARM)
|
||||||
|
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_arm.h)
|
||||||
|
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_arm.c)
|
||||||
|
elseif(PROCESSOR_IS_AARCH64)
|
||||||
|
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_aarch64.h)
|
||||||
|
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_aarch64.c)
|
||||||
|
elseif(PROCESSOR_IS_X86)
|
||||||
|
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_x86.h)
|
||||||
|
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/cpuid_x86.h)
|
||||||
|
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_x86.c)
|
||||||
|
elseif(PROCESSOR_IS_POWER)
|
||||||
|
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_ppc.h)
|
||||||
|
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_ppc.c)
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Unsupported architectures ${CMAKE_SYSTEM_PROCESSOR}")
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
#
|
||||||
|
# library : utils
|
||||||
|
#
|
||||||
|
|
||||||
|
add_library(utils OBJECT
|
||||||
|
${PROJECT_SOURCE_DIR}/include/internal/bit_utils.h
|
||||||
|
${PROJECT_SOURCE_DIR}/include/internal/filesystem.h
|
||||||
|
${PROJECT_SOURCE_DIR}/include/internal/stack_line_reader.h
|
||||||
|
${PROJECT_SOURCE_DIR}/include/internal/string_view.h
|
||||||
|
${PROJECT_SOURCE_DIR}/src/filesystem.c
|
||||||
|
${PROJECT_SOURCE_DIR}/src/stack_line_reader.c
|
||||||
|
${PROJECT_SOURCE_DIR}/src/string_view.c
|
||||||
|
)
|
||||||
|
set_property(TARGET utils PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC})
|
||||||
|
setup_include_and_definitions(utils)
|
||||||
|
|
||||||
|
#
|
||||||
|
# library : unix_based_hardware_detection
|
||||||
|
#
|
||||||
|
|
||||||
|
if(UNIX)
|
||||||
|
add_library(unix_based_hardware_detection OBJECT
|
||||||
|
${PROJECT_SOURCE_DIR}/include/internal/hwcaps.h
|
||||||
|
${PROJECT_SOURCE_DIR}/src/hwcaps.c
|
||||||
|
)
|
||||||
|
setup_include_and_definitions(unix_based_hardware_detection)
|
||||||
|
check_include_file(dlfcn.h HAVE_DLFCN_H)
|
||||||
|
if(HAVE_DLFCN_H)
|
||||||
|
target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_DLFCN_H)
|
||||||
|
endif()
|
||||||
|
check_symbol_exists(getauxval "sys/auxv.h" HAVE_STRONG_GETAUXVAL)
|
||||||
|
if(HAVE_STRONG_GETAUXVAL)
|
||||||
|
target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_STRONG_GETAUXVAL)
|
||||||
|
endif()
|
||||||
|
set_property(TARGET unix_based_hardware_detection PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#
|
||||||
|
# library : cpu_features
|
||||||
|
#
|
||||||
|
set (CPU_FEATURES_HDRS)
|
||||||
|
set (CPU_FEATURES_SRCS)
|
||||||
|
add_cpu_features_headers_and_sources(CPU_FEATURES_HDRS CPU_FEATURES_SRCS)
|
||||||
|
list(APPEND CPU_FEATURES_SRCS $<TARGET_OBJECTS:utils>)
|
||||||
|
if(NOT PROCESSOR_IS_X86 AND UNIX)
|
||||||
|
list(APPEND CPU_FEATURES_SRCS $<TARGET_OBJECTS:unix_based_hardware_detection>)
|
||||||
|
endif()
|
||||||
|
add_library(cpu_features ${CPU_FEATURES_HDRS} ${CPU_FEATURES_SRCS})
|
||||||
|
set_target_properties(cpu_features PROPERTIES PUBLIC_HEADER "${CPU_FEATURES_HDRS}")
|
||||||
|
setup_include_and_definitions(cpu_features)
|
||||||
|
target_link_libraries(cpu_features PUBLIC ${CMAKE_DL_LIBS})
|
||||||
|
set_property(TARGET cpu_features PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC})
|
||||||
|
target_include_directories(cpu_features
|
||||||
|
PUBLIC $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cpu_features>
|
||||||
|
)
|
||||||
|
if(PROCESSOR_IS_X86)
|
||||||
|
if(APPLE)
|
||||||
|
target_compile_definitions(cpu_features PRIVATE HAVE_SYSCTLBYNAME)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
add_library(CpuFeature::cpu_features ALIAS cpu_features)
|
||||||
|
|
||||||
|
#
|
||||||
|
# program : list_cpu_features
|
||||||
|
#
|
||||||
|
|
||||||
|
add_executable(list_cpu_features ${PROJECT_SOURCE_DIR}/src/utils/list_cpu_features.c)
|
||||||
|
target_link_libraries(list_cpu_features PRIVATE cpu_features)
|
||||||
|
add_executable(CpuFeature::list_cpu_features ALIAS list_cpu_features)
|
||||||
|
|
||||||
|
#
|
||||||
|
# ndk_compat
|
||||||
|
#
|
||||||
|
|
||||||
|
if(ANDROID)
|
||||||
|
add_subdirectory(ndk_compat)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#
|
||||||
|
# tests
|
||||||
|
#
|
||||||
|
|
||||||
|
include(CTest)
|
||||||
|
if(BUILD_TESTING)
|
||||||
|
# Automatically incorporate googletest into the CMake Project if target not
|
||||||
|
# found.
|
||||||
|
enable_language(CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF) # prefer use of -std11 instead of -gnustd11
|
||||||
|
|
||||||
|
if(NOT TARGET gtest OR NOT TARGET gmock_main)
|
||||||
|
# Download and unpack googletest at configure time.
|
||||||
|
configure_file(
|
||||||
|
cmake/googletest.CMakeLists.txt.in
|
||||||
|
googletest-download/CMakeLists.txt
|
||||||
|
)
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
|
||||||
|
RESULT_VARIABLE result
|
||||||
|
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
|
||||||
|
|
||||||
|
if(result)
|
||||||
|
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_COMMAND} --build .
|
||||||
|
RESULT_VARIABLE result
|
||||||
|
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
|
||||||
|
|
||||||
|
if(result)
|
||||||
|
message(FATAL_ERROR "Build step for googletest failed: ${result}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Prevent overriding the parent project's compiler/linker settings on
|
||||||
|
# Windows.
|
||||||
|
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||||
|
|
||||||
|
# Add googletest directly to our build. This defines the gtest and
|
||||||
|
# gtest_main targets.
|
||||||
|
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
|
||||||
|
${CMAKE_BINARY_DIR}/googletest-build
|
||||||
|
EXCLUDE_FROM_ALL)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(test)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Install cpu_features and list_cpu_features
|
||||||
|
#
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
install(TARGETS cpu_features list_cpu_features
|
||||||
|
EXPORT CpuFeaturesTargets
|
||||||
|
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cpu_features
|
||||||
|
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
)
|
||||||
|
install(EXPORT CpuFeaturesTargets
|
||||||
|
NAMESPACE CpuFeatures::
|
||||||
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures
|
||||||
|
COMPONENT Devel
|
||||||
|
)
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
configure_package_config_file(cmake/CpuFeaturesConfig.cmake.in
|
||||||
|
"${PROJECT_BINARY_DIR}/CpuFeaturesConfig.cmake"
|
||||||
|
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures"
|
||||||
|
NO_SET_AND_CHECK_MACRO
|
||||||
|
NO_CHECK_REQUIRED_COMPONENTS_MACRO
|
||||||
|
)
|
||||||
|
write_basic_package_version_file(
|
||||||
|
"${PROJECT_BINARY_DIR}/CpuFeaturesConfigVersion.cmake"
|
||||||
|
COMPATIBILITY SameMajorVersion
|
||||||
|
)
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
"${PROJECT_BINARY_DIR}/CpuFeaturesConfig.cmake"
|
||||||
|
"${PROJECT_BINARY_DIR}/CpuFeaturesConfigVersion.cmake"
|
||||||
|
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures"
|
||||||
|
COMPONENT Devel
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
# How to Contribute
|
||||||
|
|
||||||
|
We'd love to accept your patches and contributions to this project. There are
|
||||||
|
just a few small guidelines you need to follow.
|
||||||
|
|
||||||
|
## Contributor License Agreement
|
||||||
|
|
||||||
|
Contributions to this project must be accompanied by a Contributor License
|
||||||
|
Agreement. You (or your employer) retain the copyright to your contribution;
|
||||||
|
this simply gives us permission to use and redistribute your contributions as
|
||||||
|
part of the project. Head over to <https://cla.developers.google.com/> to see
|
||||||
|
your current agreements on file or to sign a new one.
|
||||||
|
|
||||||
|
You generally only need to submit a CLA once, so if you've already submitted one
|
||||||
|
(even if it was for a different project), you probably don't need to do it
|
||||||
|
again.
|
||||||
|
|
||||||
|
## Code reviews
|
||||||
|
|
||||||
|
All submissions, including submissions by project members, require review. We
|
||||||
|
use GitHub pull requests for this purpose. Consult
|
||||||
|
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
|
||||||
|
information on using pull requests.
|
||||||
|
|
@ -0,0 +1,230 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
For files in the `ndk_compat` folder:
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (C) 2010 The Android Open Source Project
|
||||||
|
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.
|
||||||
|
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 OWNER 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.
|
||||||
|
|
@ -0,0 +1,199 @@
|
||||||
|
# cpu_features [](https://travis-ci.org/google/cpu_features) [](https://ci.appveyor.com/project/gchatelet/cpu-features/branch/master)
|
||||||
|
|
||||||
|
A cross-platform C library to retrieve CPU features (such as available
|
||||||
|
instructions) at runtime.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Design Rationale](#rationale)
|
||||||
|
- [Code samples](#codesample)
|
||||||
|
- [Running sample code](#usagesample)
|
||||||
|
- [What's supported](#support)
|
||||||
|
- [Android NDK's drop in replacement](#ndk)
|
||||||
|
- [License](#license)
|
||||||
|
- [Build with cmake](#cmake)
|
||||||
|
|
||||||
|
<a name="rationale"></a>
|
||||||
|
## Design Rationale
|
||||||
|
|
||||||
|
- **Simple to use.** See the snippets below for examples.
|
||||||
|
- **Extensible.** Easy to add missing features or architectures.
|
||||||
|
- **Compatible with old compilers** and available on many architectures so it
|
||||||
|
can be used widely. To ensure that cpu_features works on as many platforms
|
||||||
|
as possible, we implemented it in a highly portable version of C: C99.
|
||||||
|
- **Sandbox-compatible.** The library uses a variety of strategies to cope
|
||||||
|
with sandboxed environments or when `cpuid` is unavailable. This is useful
|
||||||
|
when running integration tests in hermetic environments.
|
||||||
|
- **Thread safe, no memory allocation, and raises no exceptions.**
|
||||||
|
cpu_features is suitable for implementing fundamental libc functions like
|
||||||
|
`malloc`, `memcpy`, and `memcmp`.
|
||||||
|
- **Unit tested.**
|
||||||
|
|
||||||
|
<a name="codesample"></a>
|
||||||
|
## Code samples
|
||||||
|
|
||||||
|
**Note:** For C++ code, the library functions are defined in the `CpuFeatures` namespace.
|
||||||
|
|
||||||
|
### Checking features at runtime
|
||||||
|
|
||||||
|
Here's a simple example that executes a codepath if the CPU supports both the
|
||||||
|
AES and the SSE4.2 instruction sets:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "cpuinfo_x86.h"
|
||||||
|
|
||||||
|
// For C++, add `using namespace CpuFeatures;`
|
||||||
|
static const X86Features features = GetX86Info().features;
|
||||||
|
|
||||||
|
void Compute(void) {
|
||||||
|
if (features.aes && features.sse4_2) {
|
||||||
|
// Run optimized code.
|
||||||
|
} else {
|
||||||
|
// Run standard code.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Caching for faster evaluation of complex checks
|
||||||
|
|
||||||
|
If you wish, you can read all the features at once into a global variable, and
|
||||||
|
then query for the specific features you care about. Below, we store all the ARM
|
||||||
|
features and then check whether AES and NEON are supported.
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "cpuinfo_arm.h"
|
||||||
|
|
||||||
|
// For C++, add `using namespace CpuFeatures;`
|
||||||
|
static const ArmFeatures features = GetArmInfo().features;
|
||||||
|
static const bool has_aes_and_neon = features.aes && features.neon;
|
||||||
|
|
||||||
|
// use has_aes_and_neon.
|
||||||
|
```
|
||||||
|
|
||||||
|
This is a good approach to take if you're checking for combinations of features
|
||||||
|
when using a compiler that is slow to extract individual bits from bit-packed
|
||||||
|
structures.
|
||||||
|
|
||||||
|
### Checking compile time flags
|
||||||
|
|
||||||
|
The following code determines whether the compiler was told to use the AVX
|
||||||
|
instruction set (e.g., `g++ -mavx`) and sets `has_avx` accordingly.
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "cpuinfo_x86.h"
|
||||||
|
|
||||||
|
// For C++, add `using namespace CpuFeatures;`
|
||||||
|
static const X86Features features = GetX86Info().features;
|
||||||
|
static const bool has_avx = CPU_FEATURES_COMPILED_X86_AVX || features.avx;
|
||||||
|
|
||||||
|
// use has_avx.
|
||||||
|
```
|
||||||
|
|
||||||
|
`CPU_FEATURES_COMPILED_X86_AVX` is set to 1 if the compiler was instructed to
|
||||||
|
use AVX and 0 otherwise, combining compile time and runtime knowledge.
|
||||||
|
|
||||||
|
### Rejecting poor hardware implementations based on microarchitecture
|
||||||
|
|
||||||
|
On x86, the first incarnation of a feature in a microarchitecture might not be
|
||||||
|
the most efficient (e.g. AVX on Sandy Bridge). We provide a function to retrieve
|
||||||
|
the underlying microarchitecture so you can decide whether to use it.
|
||||||
|
|
||||||
|
Below, `has_fast_avx` is set to 1 if the CPU supports the AVX instruction
|
||||||
|
set—but only if it's not Sandy Bridge.
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "cpuinfo_x86.h"
|
||||||
|
|
||||||
|
// For C++, add `using namespace CpuFeatures;`
|
||||||
|
static const X86Info info = GetX86Info();
|
||||||
|
static const X86Microarchitecture uarch = GetX86Microarchitecture(&info);
|
||||||
|
static const bool has_fast_avx = info.features.avx && uarch != INTEL_SNB;
|
||||||
|
|
||||||
|
// use has_fast_avx.
|
||||||
|
```
|
||||||
|
|
||||||
|
This feature is currently available only for x86 microarchitectures.
|
||||||
|
|
||||||
|
<a name="usagesample"></a>
|
||||||
|
### Running sample code
|
||||||
|
|
||||||
|
Building `cpu_features` (check [quickstart](#quickstart) below) brings a small executable to test the library.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
% ./build/list_cpu_features
|
||||||
|
arch : x86
|
||||||
|
brand : Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz
|
||||||
|
family : 6 (0x06)
|
||||||
|
model : 45 (0x2D)
|
||||||
|
stepping : 7 (0x07)
|
||||||
|
uarch : INTEL_SNB
|
||||||
|
flags : aes,avx,cx16,smx,sse4_1,sse4_2,ssse3
|
||||||
|
```
|
||||||
|
|
||||||
|
```shell
|
||||||
|
% ./build/list_cpu_features --json
|
||||||
|
{"arch":"x86","brand":" Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz","family":6,"model":45,"stepping":7,"uarch":"INTEL_SNB","flags":["aes","avx","cx16","smx","sse4_1","sse4_2","ssse3"]}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="support"></a>
|
||||||
|
## What's supported
|
||||||
|
|
||||||
|
| | x86³ | ARM | AArch64 | MIPS⁴ | POWER |
|
||||||
|
|---------|:----:|:-------:|:-------:|:------:|:-------:|
|
||||||
|
| Android | yes² | yes¹ | yes¹ | yes¹ | N/A |
|
||||||
|
| iOS | N/A | not yet | not yet | N/A | N/A |
|
||||||
|
| Linux | yes² | yes¹ | yes¹ | yes¹ | yes¹ |
|
||||||
|
| MacOs | yes² | N/A | not yet | N/A | no |
|
||||||
|
| Windows | yes² | not yet | not yet | N/A | N/A |
|
||||||
|
|
||||||
|
1. **Features revealed from Linux.** We gather data from several sources
|
||||||
|
depending on availability:
|
||||||
|
+ from glibc's
|
||||||
|
[getauxval](https://www.gnu.org/software/libc/manual/html_node/Auxiliary-Vector.html)
|
||||||
|
+ by parsing `/proc/self/auxv`
|
||||||
|
+ by parsing `/proc/cpuinfo`
|
||||||
|
2. **Features revealed from CPU.** features are retrieved by using the `cpuid`
|
||||||
|
instruction.
|
||||||
|
3. **Microarchitecture detection.** On x86 some features are not always
|
||||||
|
implemented efficiently in hardware (e.g. AVX on Sandybridge). Exposing the
|
||||||
|
microarchitecture allows the client to reject particular microarchitectures.
|
||||||
|
4. All flavors of Mips are supported, little and big endian as well as 32/64
|
||||||
|
bits.
|
||||||
|
|
||||||
|
<a name="ndk"></a>
|
||||||
|
## Android NDK's drop in replacement
|
||||||
|
|
||||||
|
[cpu_features](https://github.com/google/cpu_features) is now officially
|
||||||
|
supporting Android and offers a drop in replacement of for the NDK's [cpu-features.h](https://android.googlesource.com/platform/ndk/+/master/sources/android/cpufeatures/cpu-features.h)
|
||||||
|
, see [ndk_compat](ndk_compat) folder for details.
|
||||||
|
|
||||||
|
<a name="license"></a>
|
||||||
|
## License
|
||||||
|
|
||||||
|
The cpu_features library is licensed under the terms of the Apache license.
|
||||||
|
See [LICENSE](LICENSE) for more information.
|
||||||
|
|
||||||
|
<a name="cmake"></a>
|
||||||
|
## Build with CMake
|
||||||
|
|
||||||
|
Please check the [CMake build instructions](cmake/README.md).
|
||||||
|
|
||||||
|
<a name="quickstart"></a>
|
||||||
|
### Quickstart with `Ninja`
|
||||||
|
|
||||||
|
- build `list_cpu_features`
|
||||||
|
```
|
||||||
|
cmake -B/tmp/cpu_features -H. -GNinja -DCMAKE_BUILD_TYPE=Release
|
||||||
|
ninja -C/tmp/cpu_features
|
||||||
|
/tmp/cpu_features/list_cpu_features --json
|
||||||
|
```
|
||||||
|
|
||||||
|
- run tests
|
||||||
|
```
|
||||||
|
cmake -B/tmp/cpu_features -H. -GNinja -DBUILD_TESTING=ON
|
||||||
|
ninja -C/tmp/cpu_features
|
||||||
|
ninja -C/tmp/cpu_features test
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
# ===== googletest =====
|
||||||
|
|
||||||
|
git_repository(
|
||||||
|
name = "com_google_googletest",
|
||||||
|
remote = "https://github.com/google/googletest.git",
|
||||||
|
commit = "c3f65335b79f47b05629e79a54685d899bc53b93",
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
version: '{build}'
|
||||||
|
shallow_clone: true
|
||||||
|
|
||||||
|
platform: x64
|
||||||
|
|
||||||
|
environment:
|
||||||
|
matrix:
|
||||||
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||||
|
CMAKE_GENERATOR: "Visual Studio 15 2017 Win64"
|
||||||
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||||
|
CMAKE_GENERATOR: "Visual Studio 14 2015 Win64"
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
|
||||||
|
before_build:
|
||||||
|
- cmake --version
|
||||||
|
- cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON -H. -Bcmake_build -G "%CMAKE_GENERATOR%"
|
||||||
|
|
||||||
|
build_script:
|
||||||
|
- cmake --build cmake_build --config Debug --target ALL_BUILD
|
||||||
|
|
||||||
|
test_script:
|
||||||
|
- cmake --build cmake_build --config Debug --target RUN_TESTS
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
# CpuFeatures CMake configuration file
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/CpuFeaturesTargets.cmake")
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
# CpuFeaturesNdkCompat CMake configuration file
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/CpuFeaturesNdkCompatTargets.cmake")
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
# CMake build instructions
|
||||||
|
|
||||||
|
## Recommended usage : Incorporating cpu_features into a CMake project
|
||||||
|
|
||||||
|
For API / ABI compatibility reasons, it is recommended to build and use
|
||||||
|
cpu_features in a subdirectory of your project or as an embedded dependency.
|
||||||
|
|
||||||
|
This is similar to the recommended usage of the googletest framework
|
||||||
|
( https://github.com/google/googletest/blob/master/googletest/README.md )
|
||||||
|
|
||||||
|
Build and use step-by-step
|
||||||
|
|
||||||
|
|
||||||
|
1- Download cpu_features and copy it in a sub-directory in your project.
|
||||||
|
or add cpu_features as a git-submodule in your project
|
||||||
|
|
||||||
|
2- You can then use the cmake command `add_subdirectory()` to include
|
||||||
|
cpu_features directly and use the `cpu_features` target in your project.
|
||||||
|
|
||||||
|
3- Add the `cpu_features` target to the `target_link_libraries()` section of
|
||||||
|
your executable or of your library.
|
||||||
|
|
||||||
|
## Enabling tests
|
||||||
|
|
||||||
|
CMake default options for cpu_features is Release built type with tests
|
||||||
|
disabled. To enable testing set cmake `BUILD_TESTING` variable to `ON`,
|
||||||
|
[.travis.yml](../.travis.yml) and [appveyor.yml](../appveyor.yml) have up to
|
||||||
|
date examples.
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
cmake_minimum_required(VERSION 2.8.2)
|
||||||
|
|
||||||
|
project(googletest-download NONE)
|
||||||
|
|
||||||
|
include(ExternalProject)
|
||||||
|
ExternalProject_Add(googletest
|
||||||
|
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||||
|
GIT_TAG master
|
||||||
|
SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
|
||||||
|
BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
|
||||||
|
CONFIGURE_COMMAND ""
|
||||||
|
BUILD_COMMAND ""
|
||||||
|
INSTALL_COMMAND ""
|
||||||
|
TEST_COMMAND ""
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CPU_FEATURE_CACHE_NULL = 0,
|
||||||
|
CPU_FEATURE_CACHE_DATA = 1,
|
||||||
|
CPU_FEATURE_CACHE_INSTRUCTION = 2,
|
||||||
|
CPU_FEATURE_CACHE_UNIFIED = 3,
|
||||||
|
CPU_FEATURE_CACHE_TLB = 4,
|
||||||
|
CPU_FEATURE_CACHE_DTLB = 5,
|
||||||
|
CPU_FEATURE_CACHE_STLB = 6,
|
||||||
|
CPU_FEATURE_CACHE_PREFETCH = 7
|
||||||
|
} CacheType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int level;
|
||||||
|
CacheType cache_type;
|
||||||
|
int cache_size; // Cache size in bytes
|
||||||
|
int ways; // Associativity, 0 undefined, 0xFF fully associative
|
||||||
|
int line_size; // Cache line size in bytes
|
||||||
|
int tlb_entries; // number of entries for TLB
|
||||||
|
int partitioning; // number of lines per sector
|
||||||
|
} CacheLevelInfo;
|
||||||
|
|
||||||
|
// Increase this value if more cache levels are needed.
|
||||||
|
#ifndef CPU_FEATURES_MAX_CACHE_LEVEL
|
||||||
|
#define CPU_FEATURES_MAX_CACHE_LEVEL 10
|
||||||
|
#endif
|
||||||
|
typedef struct {
|
||||||
|
int size;
|
||||||
|
CacheLevelInfo levels[CPU_FEATURES_MAX_CACHE_LEVEL];
|
||||||
|
} CacheInfo;
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_
|
||||||
|
|
@ -0,0 +1,216 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Architectures
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#if defined(__pnacl__) || defined(__CLR_VER)
|
||||||
|
#define CPU_FEATURES_ARCH_VM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(_M_IX86) || defined(__i386__)) && !defined(CPU_FEATURES_ARCH_VM)
|
||||||
|
#define CPU_FEATURES_ARCH_X86_32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(_M_X64) || defined(__x86_64__)) && !defined(CPU_FEATURES_ARCH_VM)
|
||||||
|
#define CPU_FEATURES_ARCH_X86_64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_ARCH_X86_32) || defined(CPU_FEATURES_ARCH_X86_64)
|
||||||
|
#define CPU_FEATURES_ARCH_X86
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__arm__) || defined(_M_ARM))
|
||||||
|
#define CPU_FEATURES_ARCH_ARM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__aarch64__)
|
||||||
|
#define CPU_FEATURES_ARCH_AARCH64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(CPU_FEATURES_ARCH_AARCH64) || defined(CPU_FEATURES_ARCH_ARM))
|
||||||
|
#define CPU_FEATURES_ARCH_ANY_ARM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__mips64)
|
||||||
|
#define CPU_FEATURES_ARCH_MIPS64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__mips__) && !defined(__mips64) // mips64 also declares __mips__
|
||||||
|
#define CPU_FEATURES_ARCH_MIPS32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_ARCH_MIPS32) || defined(CPU_FEATURES_ARCH_MIPS64)
|
||||||
|
#define CPU_FEATURES_ARCH_MIPS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__powerpc__)
|
||||||
|
#define CPU_FEATURES_ARCH_PPC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Os
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
#define CPU_FEATURES_OS_LINUX_OR_ANDROID
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
#define CPU_FEATURES_OS_ANDROID
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(_WIN64) || defined(_WIN32))
|
||||||
|
#define CPU_FEATURES_OS_WINDOWS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__apple__) || defined(__APPLE__) || defined(__MACH__))
|
||||||
|
#define CPU_FEATURES_OS_DARWIN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Compilers
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#define CPU_FEATURES_COMPILER_CLANG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
|
#define CPU_FEATURES_COMPILER_GCC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#define CPU_FEATURES_COMPILER_MSC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Cpp
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
#define CPU_FEATURES_START_CPP_NAMESPACE \
|
||||||
|
namespace cpu_features { \
|
||||||
|
extern "C" {
|
||||||
|
#define CPU_FEATURES_END_CPP_NAMESPACE \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
#define CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Compiler flags
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Use the following to check if a feature is known to be available at
|
||||||
|
// compile time. See README.md for an example.
|
||||||
|
#if defined(CPU_FEATURES_ARCH_X86)
|
||||||
|
|
||||||
|
#if defined(__AES__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_AES 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_AES 0
|
||||||
|
#endif // defined(__AES__)
|
||||||
|
|
||||||
|
#if defined(__F16C__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_F16C 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_F16C 0
|
||||||
|
#endif // defined(__F16C__)
|
||||||
|
|
||||||
|
#if defined(__BMI__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_BMI 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_BMI 0
|
||||||
|
#endif // defined(__BMI__)
|
||||||
|
|
||||||
|
#if defined(__BMI2__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_BMI2 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_BMI2 0
|
||||||
|
#endif // defined(__BMI2__)
|
||||||
|
|
||||||
|
#if (defined(__SSE__) || (_M_IX86_FP >= 1))
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__SSE2__) || (_M_IX86_FP >= 2))
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE2 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE2 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__SSE3__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE3 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE3 0
|
||||||
|
#endif // defined(__SSE3__)
|
||||||
|
|
||||||
|
#if defined(__SSSE3__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSSE3 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSSE3 0
|
||||||
|
#endif // defined(__SSSE3__)
|
||||||
|
|
||||||
|
#if defined(__SSE4_1__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE4_1 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE4_1 0
|
||||||
|
#endif // defined(__SSE4_1__)
|
||||||
|
|
||||||
|
#if defined(__SSE4_2__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE4_2 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE4_2 0
|
||||||
|
#endif // defined(__SSE4_2__)
|
||||||
|
|
||||||
|
#if defined(__AVX__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_AVX 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_AVX 0
|
||||||
|
#endif // defined(__AVX__)
|
||||||
|
|
||||||
|
#if defined(__AVX2__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_AVX2 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_AVX2 0
|
||||||
|
#endif // defined(__AVX2__)
|
||||||
|
|
||||||
|
#endif // defined(CPU_FEATURES_ARCH_X86)
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_ARCH_ANY_ARM)
|
||||||
|
#if defined(__ARM_NEON__)
|
||||||
|
#define CPU_FEATURES_COMPILED_ANY_ARM_NEON 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_ANY_ARM_NEON 0
|
||||||
|
#endif // defined(__ARM_NEON__)
|
||||||
|
#endif // defined(CPU_FEATURES_ARCH_ANY_ARM)
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_ARCH_MIPS)
|
||||||
|
#if defined(__mips_msa)
|
||||||
|
#define CPU_FEATURES_COMPILED_MIPS_MSA 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_MIPS_MSA 0
|
||||||
|
#endif // defined(__mips_msa)
|
||||||
|
#endif // defined(CPU_FEATURES_ARCH_MIPS)
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
|
||||||
|
|
||||||
|
#include "cpu_features_cache_info.h"
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int fp : 1; // Floating-point.
|
||||||
|
int asimd : 1; // Advanced SIMD.
|
||||||
|
int evtstrm : 1; // Generic timer generated events.
|
||||||
|
int aes : 1; // Hardware-accelerated Advanced Encryption Standard.
|
||||||
|
int pmull : 1; // Polynomial multiply long.
|
||||||
|
int sha1 : 1; // Hardware-accelerated SHA1.
|
||||||
|
int sha2 : 1; // Hardware-accelerated SHA2-256.
|
||||||
|
int crc32 : 1; // Hardware-accelerated CRC-32.
|
||||||
|
int atomics : 1; // Armv8.1 atomic instructions.
|
||||||
|
int fphp : 1; // Half-precision floating point support.
|
||||||
|
int asimdhp : 1; // Advanced SIMD half-precision support.
|
||||||
|
int cpuid : 1; // Access to certain ID registers.
|
||||||
|
int asimdrdm : 1; // Rounding Double Multiply Accumulate/Subtract.
|
||||||
|
int jscvt : 1; // Support for JavaScript conversion.
|
||||||
|
int fcma : 1; // Floating point complex numbers.
|
||||||
|
int lrcpc : 1; // Support for weaker release consistency.
|
||||||
|
int dcpop : 1; // Data persistence writeback.
|
||||||
|
int sha3 : 1; // Hardware-accelerated SHA3.
|
||||||
|
int sm3 : 1; // Hardware-accelerated SM3.
|
||||||
|
int sm4 : 1; // Hardware-accelerated SM4.
|
||||||
|
int asimddp : 1; // Dot product instruction.
|
||||||
|
int sha512 : 1; // Hardware-accelerated SHA512.
|
||||||
|
int sve : 1; // Scalable Vector Extension.
|
||||||
|
int asimdfhm : 1; // Additional half-precision instructions.
|
||||||
|
int dit : 1; // Data independent timing.
|
||||||
|
int uscat : 1; // Unaligned atomics support.
|
||||||
|
int ilrcpc : 1; // Additional support for weaker release consistency.
|
||||||
|
int flagm : 1; // Flag manipulation instructions.
|
||||||
|
int ssbs : 1; // Speculative Store Bypass Safe PSTATE bit.
|
||||||
|
int sb : 1; // Speculation barrier.
|
||||||
|
int paca : 1; // Address authentication.
|
||||||
|
int pacg : 1; // Generic authentication.
|
||||||
|
int dcpodp : 1; // Data cache clean to point of persistence.
|
||||||
|
int sve2 : 1; // Scalable Vector Extension (version 2).
|
||||||
|
int sveaes : 1; // SVE AES instructions.
|
||||||
|
int svepmull : 1; // SVE polynomial multiply long instructions.
|
||||||
|
int svebitperm : 1; // SVE bit permute instructions.
|
||||||
|
int svesha3 : 1; // SVE SHA3 instructions.
|
||||||
|
int svesm4 : 1; // SVE SM4 instructions.
|
||||||
|
int flagm2 : 1; // Additional flag manipulation instructions.
|
||||||
|
int frint : 1; // Floating point to integer rounding.
|
||||||
|
int svei8mm : 1; // SVE Int8 matrix multiplication instructions.
|
||||||
|
int svef32mm : 1; // SVE FP32 matrix multiplication instruction.
|
||||||
|
int svef64mm : 1; // SVE FP64 matrix multiplication instructions.
|
||||||
|
int svebf16 : 1; // SVE BFloat16 instructions.
|
||||||
|
int i8mm : 1; // Int8 matrix multiplication instructions.
|
||||||
|
int bf16 : 1; // BFloat16 instructions.
|
||||||
|
int dgh : 1; // Data Gathering Hint instruction.
|
||||||
|
int rng : 1; // True random number generator support.
|
||||||
|
int bti : 1; // Branch target identification.
|
||||||
|
|
||||||
|
// Make sure to update Aarch64FeaturesEnum below if you add a field here.
|
||||||
|
} Aarch64Features;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Aarch64Features features;
|
||||||
|
int implementer;
|
||||||
|
int variant;
|
||||||
|
int part;
|
||||||
|
int revision;
|
||||||
|
} Aarch64Info;
|
||||||
|
|
||||||
|
Aarch64Info GetAarch64Info(void);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introspection functions
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
AARCH64_FP,
|
||||||
|
AARCH64_ASIMD,
|
||||||
|
AARCH64_EVTSTRM,
|
||||||
|
AARCH64_AES,
|
||||||
|
AARCH64_PMULL,
|
||||||
|
AARCH64_SHA1,
|
||||||
|
AARCH64_SHA2,
|
||||||
|
AARCH64_CRC32,
|
||||||
|
AARCH64_ATOMICS,
|
||||||
|
AARCH64_FPHP,
|
||||||
|
AARCH64_ASIMDHP,
|
||||||
|
AARCH64_CPUID,
|
||||||
|
AARCH64_ASIMDRDM,
|
||||||
|
AARCH64_JSCVT,
|
||||||
|
AARCH64_FCMA,
|
||||||
|
AARCH64_LRCPC,
|
||||||
|
AARCH64_DCPOP,
|
||||||
|
AARCH64_SHA3,
|
||||||
|
AARCH64_SM3,
|
||||||
|
AARCH64_SM4,
|
||||||
|
AARCH64_ASIMDDP,
|
||||||
|
AARCH64_SHA512,
|
||||||
|
AARCH64_SVE,
|
||||||
|
AARCH64_ASIMDFHM,
|
||||||
|
AARCH64_DIT,
|
||||||
|
AARCH64_USCAT,
|
||||||
|
AARCH64_ILRCPC,
|
||||||
|
AARCH64_FLAGM,
|
||||||
|
AARCH64_SSBS,
|
||||||
|
AARCH64_SB,
|
||||||
|
AARCH64_PACA,
|
||||||
|
AARCH64_PACG,
|
||||||
|
AARCH64_DCPODP,
|
||||||
|
AARCH64_SVE2,
|
||||||
|
AARCH64_SVEAES,
|
||||||
|
AARCH64_SVEPMULL,
|
||||||
|
AARCH64_SVEBITPERM,
|
||||||
|
AARCH64_SVESHA3,
|
||||||
|
AARCH64_SVESM4,
|
||||||
|
AARCH64_FLAGM2,
|
||||||
|
AARCH64_FRINT,
|
||||||
|
AARCH64_SVEI8MM,
|
||||||
|
AARCH64_SVEF32MM,
|
||||||
|
AARCH64_SVEF64MM,
|
||||||
|
AARCH64_SVEBF16,
|
||||||
|
AARCH64_I8MM,
|
||||||
|
AARCH64_BF16,
|
||||||
|
AARCH64_DGH,
|
||||||
|
AARCH64_RNG,
|
||||||
|
AARCH64_BTI,
|
||||||
|
AARCH64_LAST_,
|
||||||
|
} Aarch64FeaturesEnum;
|
||||||
|
|
||||||
|
int GetAarch64FeaturesEnumValue(const Aarch64Features* features,
|
||||||
|
Aarch64FeaturesEnum value);
|
||||||
|
|
||||||
|
const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#if !defined(CPU_FEATURES_ARCH_AARCH64)
|
||||||
|
#error "Including cpuinfo_aarch64.h from a non-aarch64 target."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
|
||||||
|
|
@ -0,0 +1,121 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_
|
||||||
|
|
||||||
|
#include <stdint.h> // uint32_t
|
||||||
|
|
||||||
|
#include "cpu_features_cache_info.h"
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int swp : 1; // SWP instruction (atomic read-modify-write)
|
||||||
|
int half : 1; // Half-word loads and stores
|
||||||
|
int thumb : 1; // Thumb (16-bit instruction set)
|
||||||
|
int _26bit : 1; // "26 Bit" Model (Processor status register folded into
|
||||||
|
// program counter)
|
||||||
|
int fastmult : 1; // 32x32->64-bit multiplication
|
||||||
|
int fpa : 1; // Floating point accelerator
|
||||||
|
int vfp : 1; // Vector Floating Point.
|
||||||
|
int edsp : 1; // DSP extensions (the 'e' variant of the ARM9 CPUs, and all
|
||||||
|
// others above)
|
||||||
|
int java : 1; // Jazelle (Java bytecode accelerator)
|
||||||
|
int iwmmxt : 1; // Intel Wireless MMX Technology.
|
||||||
|
int crunch : 1; // MaverickCrunch coprocessor
|
||||||
|
int thumbee : 1; // ThumbEE
|
||||||
|
int neon : 1; // Advanced SIMD.
|
||||||
|
int vfpv3 : 1; // VFP version 3
|
||||||
|
int vfpv3d16 : 1; // VFP version 3 with 16 D-registers
|
||||||
|
int tls : 1; // TLS register
|
||||||
|
int vfpv4 : 1; // VFP version 4 with fast context switching
|
||||||
|
int idiva : 1; // SDIV and UDIV hardware division in ARM mode.
|
||||||
|
int idivt : 1; // SDIV and UDIV hardware division in Thumb mode.
|
||||||
|
int vfpd32 : 1; // VFP with 32 D-registers
|
||||||
|
int lpae : 1; // Large Physical Address Extension (>4GB physical memory on
|
||||||
|
// 32-bit architecture)
|
||||||
|
int evtstrm : 1; // kernel event stream using generic architected timer
|
||||||
|
int aes : 1; // Hardware-accelerated Advanced Encryption Standard.
|
||||||
|
int pmull : 1; // Polynomial multiply long.
|
||||||
|
int sha1 : 1; // Hardware-accelerated SHA1.
|
||||||
|
int sha2 : 1; // Hardware-accelerated SHA2-256.
|
||||||
|
int crc32 : 1; // Hardware-accelerated CRC-32.
|
||||||
|
|
||||||
|
// Make sure to update ArmFeaturesEnum below if you add a field here.
|
||||||
|
} ArmFeatures;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ArmFeatures features;
|
||||||
|
int implementer;
|
||||||
|
int architecture;
|
||||||
|
int variant;
|
||||||
|
int part;
|
||||||
|
int revision;
|
||||||
|
} ArmInfo;
|
||||||
|
|
||||||
|
// TODO(user): Add macros to know which features are present at compile
|
||||||
|
// time.
|
||||||
|
|
||||||
|
ArmInfo GetArmInfo(void);
|
||||||
|
|
||||||
|
// Compute CpuId from ArmInfo.
|
||||||
|
uint32_t GetArmCpuId(const ArmInfo* const info);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introspection functions
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ARM_SWP,
|
||||||
|
ARM_HALF,
|
||||||
|
ARM_THUMB,
|
||||||
|
ARM_26BIT,
|
||||||
|
ARM_FASTMULT,
|
||||||
|
ARM_FPA,
|
||||||
|
ARM_VFP,
|
||||||
|
ARM_EDSP,
|
||||||
|
ARM_JAVA,
|
||||||
|
ARM_IWMMXT,
|
||||||
|
ARM_CRUNCH,
|
||||||
|
ARM_THUMBEE,
|
||||||
|
ARM_NEON,
|
||||||
|
ARM_VFPV3,
|
||||||
|
ARM_VFPV3D16,
|
||||||
|
ARM_TLS,
|
||||||
|
ARM_VFPV4,
|
||||||
|
ARM_IDIVA,
|
||||||
|
ARM_IDIVT,
|
||||||
|
ARM_VFPD32,
|
||||||
|
ARM_LPAE,
|
||||||
|
ARM_EVTSTRM,
|
||||||
|
ARM_AES,
|
||||||
|
ARM_PMULL,
|
||||||
|
ARM_SHA1,
|
||||||
|
ARM_SHA2,
|
||||||
|
ARM_CRC32,
|
||||||
|
ARM_LAST_,
|
||||||
|
} ArmFeaturesEnum;
|
||||||
|
|
||||||
|
int GetArmFeaturesEnumValue(const ArmFeatures* features, ArmFeaturesEnum value);
|
||||||
|
|
||||||
|
const char* GetArmFeaturesEnumName(ArmFeaturesEnum);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#if !defined(CPU_FEATURES_ARCH_ARM)
|
||||||
|
#error "Including cpuinfo_arm.h from a non-arm target."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_
|
||||||
|
|
||||||
|
#include "cpu_features_cache_info.h"
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int msa : 1; // MIPS SIMD Architecture
|
||||||
|
// https://www.mips.com/products/architectures/ase/simd/
|
||||||
|
int eva : 1; // Enhanced Virtual Addressing
|
||||||
|
// https://www.mips.com/products/architectures/mips64/
|
||||||
|
int r6 : 1; // True if is release 6 of the processor.
|
||||||
|
|
||||||
|
// Make sure to update MipsFeaturesEnum below if you add a field here.
|
||||||
|
} MipsFeatures;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MipsFeatures features;
|
||||||
|
} MipsInfo;
|
||||||
|
|
||||||
|
MipsInfo GetMipsInfo(void);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introspection functions
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MIPS_MSA,
|
||||||
|
MIPS_EVA,
|
||||||
|
MIPS_R6,
|
||||||
|
MIPS_LAST_,
|
||||||
|
} MipsFeaturesEnum;
|
||||||
|
|
||||||
|
int GetMipsFeaturesEnumValue(const MipsFeatures* features,
|
||||||
|
MipsFeaturesEnum value);
|
||||||
|
|
||||||
|
const char* GetMipsFeaturesEnumName(MipsFeaturesEnum);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#if !defined(CPU_FEATURES_ARCH_MIPS)
|
||||||
|
#error "Including cpuinfo_mips.h from a non-mips target."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_
|
||||||
|
|
@ -0,0 +1,146 @@
|
||||||
|
// Copyright 2018 IBM
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_
|
||||||
|
|
||||||
|
#include "cpu_features_cache_info.h"
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
#include "internal/hwcaps.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int ppc32 : 1;
|
||||||
|
int ppc64 : 1;
|
||||||
|
int ppc601 : 1;
|
||||||
|
int altivec : 1;
|
||||||
|
int fpu : 1;
|
||||||
|
int mmu : 1;
|
||||||
|
int mac_4xx : 1;
|
||||||
|
int unifiedcache : 1;
|
||||||
|
int spe : 1;
|
||||||
|
int efpsingle : 1;
|
||||||
|
int efpdouble : 1;
|
||||||
|
int no_tb : 1;
|
||||||
|
int power4 : 1;
|
||||||
|
int power5 : 1;
|
||||||
|
int power5plus : 1;
|
||||||
|
int cell : 1;
|
||||||
|
int booke : 1;
|
||||||
|
int smt : 1;
|
||||||
|
int icachesnoop : 1;
|
||||||
|
int arch205 : 1;
|
||||||
|
int pa6t : 1;
|
||||||
|
int dfp : 1;
|
||||||
|
int power6ext : 1;
|
||||||
|
int arch206 : 1;
|
||||||
|
int vsx : 1;
|
||||||
|
int pseries_perfmon_compat : 1;
|
||||||
|
int truele : 1;
|
||||||
|
int ppcle : 1;
|
||||||
|
int arch207 : 1;
|
||||||
|
int htm : 1;
|
||||||
|
int dscr : 1;
|
||||||
|
int ebb : 1;
|
||||||
|
int isel : 1;
|
||||||
|
int tar : 1;
|
||||||
|
int vcrypto : 1;
|
||||||
|
int htm_nosc : 1;
|
||||||
|
int arch300 : 1;
|
||||||
|
int ieee128 : 1;
|
||||||
|
int darn : 1;
|
||||||
|
int scv : 1;
|
||||||
|
int htm_no_suspend : 1;
|
||||||
|
|
||||||
|
// Make sure to update PPCFeaturesEnum below if you add a field here.
|
||||||
|
} PPCFeatures;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PPCFeatures features;
|
||||||
|
} PPCInfo;
|
||||||
|
|
||||||
|
// This function is guaranteed to be malloc, memset and memcpy free.
|
||||||
|
PPCInfo GetPPCInfo(void);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char platform[64]; // 0 terminated string
|
||||||
|
char model[64]; // 0 terminated string
|
||||||
|
char machine[64]; // 0 terminated string
|
||||||
|
char cpu[64]; // 0 terminated string
|
||||||
|
PlatformType type;
|
||||||
|
} PPCPlatformStrings;
|
||||||
|
|
||||||
|
PPCPlatformStrings GetPPCPlatformStrings(void);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introspection functions
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PPC_32, /* 32 bit mode execution */
|
||||||
|
PPC_64, /* 64 bit mode execution */
|
||||||
|
PPC_601_INSTR, /* Old POWER ISA */
|
||||||
|
PPC_HAS_ALTIVEC, /* SIMD Unit*/
|
||||||
|
PPC_HAS_FPU, /* Floating Point Unit */
|
||||||
|
PPC_HAS_MMU, /* Memory management unit */
|
||||||
|
PPC_HAS_4xxMAC,
|
||||||
|
PPC_UNIFIED_CACHE, /* Unified instruction and data cache */
|
||||||
|
PPC_HAS_SPE, /* Signal processing extention unit */
|
||||||
|
PPC_HAS_EFP_SINGLE, /* SPE single precision fpu */
|
||||||
|
PPC_HAS_EFP_DOUBLE, /* SPE double precision fpu */
|
||||||
|
PPC_NO_TB, /* No timebase */
|
||||||
|
PPC_POWER4,
|
||||||
|
PPC_POWER5,
|
||||||
|
PPC_POWER5_PLUS,
|
||||||
|
PPC_CELL, /* Cell broadband engine */
|
||||||
|
PPC_BOOKE, /* Embedded ISA */
|
||||||
|
PPC_SMT, /* Simultaneous multi-threading */
|
||||||
|
PPC_ICACHE_SNOOP,
|
||||||
|
PPC_ARCH_2_05, /* ISA 2.05 - POWER6 */
|
||||||
|
PPC_PA6T, /* PA Semi 6T core ISA */
|
||||||
|
PPC_HAS_DFP, /* Decimal floating point unit */
|
||||||
|
PPC_POWER6_EXT,
|
||||||
|
PPC_ARCH_2_06, /* ISA 2.06 - POWER7 */
|
||||||
|
PPC_HAS_VSX, /* Vector-scalar extension */
|
||||||
|
PPC_PSERIES_PERFMON_COMPAT, /* Set of backwards compatibile performance
|
||||||
|
monitoring events */
|
||||||
|
PPC_TRUE_LE,
|
||||||
|
PPC_PPC_LE,
|
||||||
|
PPC_ARCH_2_07, /* ISA 2.07 - POWER8 */
|
||||||
|
PPC_HTM, /* Hardware Transactional Memory */
|
||||||
|
PPC_DSCR, /* Data stream control register */
|
||||||
|
PPC_EBB, /* Event base branching */
|
||||||
|
PPC_ISEL, /* Integer select instructions */
|
||||||
|
PPC_TAR, /* Target address register */
|
||||||
|
PPC_VEC_CRYPTO, /* Vector cryptography instructions */
|
||||||
|
PPC_HTM_NOSC, /* Transactions aborted when syscall made*/
|
||||||
|
PPC_ARCH_3_00, /* ISA 3.00 - POWER9 */
|
||||||
|
PPC_HAS_IEEE128, /* VSX IEEE Binary Float 128-bit */
|
||||||
|
PPC_DARN, /* Deliver a random number instruction */
|
||||||
|
PPC_SCV, /* scv syscall */
|
||||||
|
PPC_HTM_NO_SUSPEND, /* TM w/out suspended state */
|
||||||
|
PPC_LAST_,
|
||||||
|
} PPCFeaturesEnum;
|
||||||
|
|
||||||
|
int GetPPCFeaturesEnumValue(const PPCFeatures* features, PPCFeaturesEnum value);
|
||||||
|
|
||||||
|
const char* GetPPCFeaturesEnumName(PPCFeaturesEnum);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#if !defined(CPU_FEATURES_ARCH_PPC)
|
||||||
|
#error "Including cpuinfo_ppc.h from a non-ppc target."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_
|
||||||
|
|
@ -0,0 +1,231 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
// Copyright 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
|
||||||
|
|
||||||
|
#include "cpu_features_cache_info.h"
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
// See https://en.wikipedia.org/wiki/CPUID for a list of x86 cpu features.
|
||||||
|
// The field names are based on the short name provided in the wikipedia tables.
|
||||||
|
typedef struct {
|
||||||
|
int fpu : 1;
|
||||||
|
int tsc : 1;
|
||||||
|
int cx8 : 1;
|
||||||
|
int clfsh : 1;
|
||||||
|
int mmx : 1;
|
||||||
|
int aes : 1;
|
||||||
|
int erms : 1;
|
||||||
|
int f16c : 1;
|
||||||
|
int fma4 : 1;
|
||||||
|
int fma3 : 1;
|
||||||
|
int vaes : 1;
|
||||||
|
int vpclmulqdq : 1;
|
||||||
|
int bmi1 : 1;
|
||||||
|
int hle : 1;
|
||||||
|
int bmi2 : 1;
|
||||||
|
int rtm : 1;
|
||||||
|
int rdseed : 1;
|
||||||
|
int clflushopt : 1;
|
||||||
|
int clwb : 1;
|
||||||
|
|
||||||
|
int sse : 1;
|
||||||
|
int sse2 : 1;
|
||||||
|
int sse3 : 1;
|
||||||
|
int ssse3 : 1;
|
||||||
|
int sse4_1 : 1;
|
||||||
|
int sse4_2 : 1;
|
||||||
|
int sse4a : 1;
|
||||||
|
|
||||||
|
int avx : 1;
|
||||||
|
int avx2 : 1;
|
||||||
|
|
||||||
|
int avx512f : 1;
|
||||||
|
int avx512cd : 1;
|
||||||
|
int avx512er : 1;
|
||||||
|
int avx512pf : 1;
|
||||||
|
int avx512bw : 1;
|
||||||
|
int avx512dq : 1;
|
||||||
|
int avx512vl : 1;
|
||||||
|
int avx512ifma : 1;
|
||||||
|
int avx512vbmi : 1;
|
||||||
|
int avx512vbmi2 : 1;
|
||||||
|
int avx512vnni : 1;
|
||||||
|
int avx512bitalg : 1;
|
||||||
|
int avx512vpopcntdq : 1;
|
||||||
|
int avx512_4vnniw : 1;
|
||||||
|
int avx512_4vbmi2 : 1;
|
||||||
|
int avx512_second_fma : 1;
|
||||||
|
int avx512_4fmaps : 1;
|
||||||
|
int avx512_bf16 : 1;
|
||||||
|
int avx512_vp2intersect : 1;
|
||||||
|
int amx_bf16 : 1;
|
||||||
|
int amx_tile : 1;
|
||||||
|
int amx_int8 : 1;
|
||||||
|
|
||||||
|
int pclmulqdq : 1;
|
||||||
|
int smx : 1;
|
||||||
|
int sgx : 1;
|
||||||
|
int cx16 : 1; // aka. CMPXCHG16B
|
||||||
|
int sha : 1;
|
||||||
|
int popcnt : 1;
|
||||||
|
int movbe : 1;
|
||||||
|
int rdrnd : 1;
|
||||||
|
|
||||||
|
int dca : 1;
|
||||||
|
int ss : 1;
|
||||||
|
// Make sure to update X86FeaturesEnum below if you add a field here.
|
||||||
|
} X86Features;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
X86Features features;
|
||||||
|
int family;
|
||||||
|
int model;
|
||||||
|
int stepping;
|
||||||
|
char vendor[13]; // 0 terminated string
|
||||||
|
} X86Info;
|
||||||
|
|
||||||
|
// Calls cpuid and returns an initialized X86info.
|
||||||
|
// This function is guaranteed to be malloc, memset and memcpy free.
|
||||||
|
X86Info GetX86Info(void);
|
||||||
|
|
||||||
|
// Returns cache hierarchy informations.
|
||||||
|
// Can call cpuid multiple times.
|
||||||
|
// Only works on Intel CPU at the moment.
|
||||||
|
// This function is guaranteed to be malloc, memset and memcpy free.
|
||||||
|
CacheInfo GetX86CacheInfo(void);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
X86_UNKNOWN,
|
||||||
|
INTEL_CORE, // CORE
|
||||||
|
INTEL_PNR, // PENRYN
|
||||||
|
INTEL_NHM, // NEHALEM
|
||||||
|
INTEL_ATOM_BNL, // BONNELL
|
||||||
|
INTEL_WSM, // WESTMERE
|
||||||
|
INTEL_SNB, // SANDYBRIDGE
|
||||||
|
INTEL_IVB, // IVYBRIDGE
|
||||||
|
INTEL_ATOM_SMT, // SILVERMONT
|
||||||
|
INTEL_HSW, // HASWELL
|
||||||
|
INTEL_BDW, // BROADWELL
|
||||||
|
INTEL_SKL, // SKYLAKE
|
||||||
|
INTEL_ATOM_GMT, // GOLDMONT
|
||||||
|
INTEL_KBL, // KABY LAKE
|
||||||
|
INTEL_CFL, // COFFEE LAKE
|
||||||
|
INTEL_WHL, // WHISKEY LAKE
|
||||||
|
INTEL_CNL, // CANNON LAKE
|
||||||
|
INTEL_ICL, // ICE LAKE
|
||||||
|
INTEL_TGL, // TIGER LAKE
|
||||||
|
INTEL_SPR, // SAPPHIRE RAPIDS
|
||||||
|
AMD_HAMMER, // K8
|
||||||
|
AMD_K10, // K10
|
||||||
|
AMD_BOBCAT, // K14
|
||||||
|
AMD_BULLDOZER, // K15
|
||||||
|
AMD_JAGUAR, // K16
|
||||||
|
AMD_ZEN, // K17
|
||||||
|
} X86Microarchitecture;
|
||||||
|
|
||||||
|
// Returns the underlying microarchitecture by looking at X86Info's vendor,
|
||||||
|
// family and model.
|
||||||
|
X86Microarchitecture GetX86Microarchitecture(const X86Info* info);
|
||||||
|
|
||||||
|
// Calls cpuid and fills the brand_string.
|
||||||
|
// - brand_string *must* be of size 49 (beware of array decaying).
|
||||||
|
// - brand_string will be zero terminated.
|
||||||
|
// - This function calls memcpy.
|
||||||
|
void FillX86BrandString(char brand_string[49]);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introspection functions
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
X86_FPU,
|
||||||
|
X86_TSC,
|
||||||
|
X86_CX8,
|
||||||
|
X86_CLFSH,
|
||||||
|
X86_MMX,
|
||||||
|
X86_AES,
|
||||||
|
X86_ERMS,
|
||||||
|
X86_F16C,
|
||||||
|
X86_FMA4,
|
||||||
|
X86_FMA3,
|
||||||
|
X86_VAES,
|
||||||
|
X86_VPCLMULQDQ,
|
||||||
|
X86_BMI1,
|
||||||
|
X86_HLE,
|
||||||
|
X86_BMI2,
|
||||||
|
X86_RTM,
|
||||||
|
X86_RDSEED,
|
||||||
|
X86_CLFLUSHOPT,
|
||||||
|
X86_CLWB,
|
||||||
|
X86_SSE,
|
||||||
|
X86_SSE2,
|
||||||
|
X86_SSE3,
|
||||||
|
X86_SSSE3,
|
||||||
|
X86_SSE4_1,
|
||||||
|
X86_SSE4_2,
|
||||||
|
X86_SSE4A,
|
||||||
|
X86_AVX,
|
||||||
|
X86_AVX2,
|
||||||
|
X86_AVX512F,
|
||||||
|
X86_AVX512CD,
|
||||||
|
X86_AVX512ER,
|
||||||
|
X86_AVX512PF,
|
||||||
|
X86_AVX512BW,
|
||||||
|
X86_AVX512DQ,
|
||||||
|
X86_AVX512VL,
|
||||||
|
X86_AVX512IFMA,
|
||||||
|
X86_AVX512VBMI,
|
||||||
|
X86_AVX512VBMI2,
|
||||||
|
X86_AVX512VNNI,
|
||||||
|
X86_AVX512BITALG,
|
||||||
|
X86_AVX512VPOPCNTDQ,
|
||||||
|
X86_AVX512_4VNNIW,
|
||||||
|
X86_AVX512_4VBMI2,
|
||||||
|
X86_AVX512_SECOND_FMA,
|
||||||
|
X86_AVX512_4FMAPS,
|
||||||
|
X86_AVX512_BF16,
|
||||||
|
X86_AVX512_VP2INTERSECT,
|
||||||
|
X86_AMX_BF16,
|
||||||
|
X86_AMX_TILE,
|
||||||
|
X86_AMX_INT8,
|
||||||
|
X86_PCLMULQDQ,
|
||||||
|
X86_SMX,
|
||||||
|
X86_SGX,
|
||||||
|
X86_CX16,
|
||||||
|
X86_SHA,
|
||||||
|
X86_POPCNT,
|
||||||
|
X86_MOVBE,
|
||||||
|
X86_RDRND,
|
||||||
|
X86_DCA,
|
||||||
|
X86_SS,
|
||||||
|
X86_LAST_,
|
||||||
|
} X86FeaturesEnum;
|
||||||
|
|
||||||
|
int GetX86FeaturesEnumValue(const X86Features* features, X86FeaturesEnum value);
|
||||||
|
|
||||||
|
const char* GetX86FeaturesEnumName(X86FeaturesEnum);
|
||||||
|
|
||||||
|
const char* GetX86MicroarchitectureName(X86Microarchitecture);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#if !defined(CPU_FEATURES_ARCH_X86)
|
||||||
|
#error "Including cpuinfo_x86.h from a non-x86 target."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
inline static bool IsBitSet(uint32_t reg, uint32_t bit) {
|
||||||
|
return (reg >> bit) & 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static uint32_t ExtractBitRange(uint32_t reg, uint32_t msb,
|
||||||
|
uint32_t lsb) {
|
||||||
|
const uint64_t bits = msb - lsb + 1ULL;
|
||||||
|
const uint64_t mask = (1ULL << bits) - 1ULL;
|
||||||
|
assert(msb >= lsb);
|
||||||
|
return (reg >> lsb) & mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
// A struct to hold the result of a call to cpuid.
|
||||||
|
typedef struct {
|
||||||
|
uint32_t eax, ebx, ecx, edx;
|
||||||
|
} Leaf;
|
||||||
|
|
||||||
|
// Returns the result of a call to the cpuid instruction.
|
||||||
|
Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx);
|
||||||
|
|
||||||
|
// Returns the eax value of the XCR0 register.
|
||||||
|
uint32_t GetXCR0Eax(void);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// An interface for the filesystem that allows mocking the filesystem in
|
||||||
|
// unittests.
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
// Same as linux "open(filename, O_RDONLY)", retries automatically on EINTR.
|
||||||
|
int CpuFeatures_OpenFile(const char* filename);
|
||||||
|
|
||||||
|
// Same as linux "read(file_descriptor, buffer, buffer_size)", retries
|
||||||
|
// automatically on EINTR.
|
||||||
|
int CpuFeatures_ReadFile(int file_descriptor, void* buffer, size_t buffer_size);
|
||||||
|
|
||||||
|
// Same as linux "close(file_descriptor)".
|
||||||
|
void CpuFeatures_CloseFile(int file_descriptor);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_
|
||||||
|
|
@ -0,0 +1,186 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Interface to retrieve hardware capabilities. It relies on Linux's getauxval
|
||||||
|
// or `/proc/self/auxval` under the hood.
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
// To avoid depending on the linux kernel we reproduce the architecture specific
|
||||||
|
// constants here.
|
||||||
|
|
||||||
|
// http://elixir.free-electrons.com/linux/latest/source/arch/arm64/include/uapi/asm/hwcap.h
|
||||||
|
#define AARCH64_HWCAP_FP (1UL << 0)
|
||||||
|
#define AARCH64_HWCAP_ASIMD (1UL << 1)
|
||||||
|
#define AARCH64_HWCAP_EVTSTRM (1UL << 2)
|
||||||
|
#define AARCH64_HWCAP_AES (1UL << 3)
|
||||||
|
#define AARCH64_HWCAP_PMULL (1UL << 4)
|
||||||
|
#define AARCH64_HWCAP_SHA1 (1UL << 5)
|
||||||
|
#define AARCH64_HWCAP_SHA2 (1UL << 6)
|
||||||
|
#define AARCH64_HWCAP_CRC32 (1UL << 7)
|
||||||
|
#define AARCH64_HWCAP_ATOMICS (1UL << 8)
|
||||||
|
#define AARCH64_HWCAP_FPHP (1UL << 9)
|
||||||
|
#define AARCH64_HWCAP_ASIMDHP (1UL << 10)
|
||||||
|
#define AARCH64_HWCAP_CPUID (1UL << 11)
|
||||||
|
#define AARCH64_HWCAP_ASIMDRDM (1UL << 12)
|
||||||
|
#define AARCH64_HWCAP_JSCVT (1UL << 13)
|
||||||
|
#define AARCH64_HWCAP_FCMA (1UL << 14)
|
||||||
|
#define AARCH64_HWCAP_LRCPC (1UL << 15)
|
||||||
|
#define AARCH64_HWCAP_DCPOP (1UL << 16)
|
||||||
|
#define AARCH64_HWCAP_SHA3 (1UL << 17)
|
||||||
|
#define AARCH64_HWCAP_SM3 (1UL << 18)
|
||||||
|
#define AARCH64_HWCAP_SM4 (1UL << 19)
|
||||||
|
#define AARCH64_HWCAP_ASIMDDP (1UL << 20)
|
||||||
|
#define AARCH64_HWCAP_SHA512 (1UL << 21)
|
||||||
|
#define AARCH64_HWCAP_SVE (1UL << 22)
|
||||||
|
#define AARCH64_HWCAP_ASIMDFHM (1UL << 23)
|
||||||
|
#define AARCH64_HWCAP_DIT (1UL << 24)
|
||||||
|
#define AARCH64_HWCAP_USCAT (1UL << 25)
|
||||||
|
#define AARCH64_HWCAP_ILRCPC (1UL << 26)
|
||||||
|
#define AARCH64_HWCAP_FLAGM (1UL << 27)
|
||||||
|
#define AARCH64_HWCAP_SSBS (1UL << 28)
|
||||||
|
#define AARCH64_HWCAP_SB (1UL << 29)
|
||||||
|
#define AARCH64_HWCAP_PACA (1UL << 30)
|
||||||
|
#define AARCH64_HWCAP_PACG (1UL << 31)
|
||||||
|
|
||||||
|
#define AARCH64_HWCAP2_DCPODP (1UL << 0)
|
||||||
|
#define AARCH64_HWCAP2_SVE2 (1UL << 1)
|
||||||
|
#define AARCH64_HWCAP2_SVEAES (1UL << 2)
|
||||||
|
#define AARCH64_HWCAP2_SVEPMULL (1UL << 3)
|
||||||
|
#define AARCH64_HWCAP2_SVEBITPERM (1UL << 4)
|
||||||
|
#define AARCH64_HWCAP2_SVESHA3 (1UL << 5)
|
||||||
|
#define AARCH64_HWCAP2_SVESM4 (1UL << 6)
|
||||||
|
#define AARCH64_HWCAP2_FLAGM2 (1UL << 7)
|
||||||
|
#define AARCH64_HWCAP2_FRINT (1UL << 8)
|
||||||
|
#define AARCH64_HWCAP2_SVEI8MM (1UL << 9)
|
||||||
|
#define AARCH64_HWCAP2_SVEF32MM (1UL << 10)
|
||||||
|
#define AARCH64_HWCAP2_SVEF64MM (1UL << 11)
|
||||||
|
#define AARCH64_HWCAP2_SVEBF16 (1UL << 12)
|
||||||
|
#define AARCH64_HWCAP2_I8MM (1UL << 13)
|
||||||
|
#define AARCH64_HWCAP2_BF16 (1UL << 14)
|
||||||
|
#define AARCH64_HWCAP2_DGH (1UL << 15)
|
||||||
|
#define AARCH64_HWCAP2_RNG (1UL << 16)
|
||||||
|
#define AARCH64_HWCAP2_BTI (1UL << 17)
|
||||||
|
|
||||||
|
// http://elixir.free-electrons.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h
|
||||||
|
#define ARM_HWCAP_SWP (1UL << 0)
|
||||||
|
#define ARM_HWCAP_HALF (1UL << 1)
|
||||||
|
#define ARM_HWCAP_THUMB (1UL << 2)
|
||||||
|
#define ARM_HWCAP_26BIT (1UL << 3)
|
||||||
|
#define ARM_HWCAP_FAST_MULT (1UL << 4)
|
||||||
|
#define ARM_HWCAP_FPA (1UL << 5)
|
||||||
|
#define ARM_HWCAP_VFP (1UL << 6)
|
||||||
|
#define ARM_HWCAP_EDSP (1UL << 7)
|
||||||
|
#define ARM_HWCAP_JAVA (1UL << 8)
|
||||||
|
#define ARM_HWCAP_IWMMXT (1UL << 9)
|
||||||
|
#define ARM_HWCAP_CRUNCH (1UL << 10)
|
||||||
|
#define ARM_HWCAP_THUMBEE (1UL << 11)
|
||||||
|
#define ARM_HWCAP_NEON (1UL << 12)
|
||||||
|
#define ARM_HWCAP_VFPV3 (1UL << 13)
|
||||||
|
#define ARM_HWCAP_VFPV3D16 (1UL << 14)
|
||||||
|
#define ARM_HWCAP_TLS (1UL << 15)
|
||||||
|
#define ARM_HWCAP_VFPV4 (1UL << 16)
|
||||||
|
#define ARM_HWCAP_IDIVA (1UL << 17)
|
||||||
|
#define ARM_HWCAP_IDIVT (1UL << 18)
|
||||||
|
#define ARM_HWCAP_VFPD32 (1UL << 19)
|
||||||
|
#define ARM_HWCAP_LPAE (1UL << 20)
|
||||||
|
#define ARM_HWCAP_EVTSTRM (1UL << 21)
|
||||||
|
#define ARM_HWCAP2_AES (1UL << 0)
|
||||||
|
#define ARM_HWCAP2_PMULL (1UL << 1)
|
||||||
|
#define ARM_HWCAP2_SHA1 (1UL << 2)
|
||||||
|
#define ARM_HWCAP2_SHA2 (1UL << 3)
|
||||||
|
#define ARM_HWCAP2_CRC32 (1UL << 4)
|
||||||
|
|
||||||
|
// http://elixir.free-electrons.com/linux/latest/source/arch/mips/include/uapi/asm/hwcap.h
|
||||||
|
#define MIPS_HWCAP_R6 (1UL << 0)
|
||||||
|
#define MIPS_HWCAP_MSA (1UL << 1)
|
||||||
|
#define MIPS_HWCAP_CRC32 (1UL << 2)
|
||||||
|
|
||||||
|
// http://elixir.free-electrons.com/linux/latest/source/arch/powerpc/include/uapi/asm/cputable.h
|
||||||
|
#ifndef _UAPI__ASM_POWERPC_CPUTABLE_H
|
||||||
|
/* in AT_HWCAP */
|
||||||
|
#define PPC_FEATURE_32 0x80000000
|
||||||
|
#define PPC_FEATURE_64 0x40000000
|
||||||
|
#define PPC_FEATURE_601_INSTR 0x20000000
|
||||||
|
#define PPC_FEATURE_HAS_ALTIVEC 0x10000000
|
||||||
|
#define PPC_FEATURE_HAS_FPU 0x08000000
|
||||||
|
#define PPC_FEATURE_HAS_MMU 0x04000000
|
||||||
|
#define PPC_FEATURE_HAS_4xxMAC 0x02000000
|
||||||
|
#define PPC_FEATURE_UNIFIED_CACHE 0x01000000
|
||||||
|
#define PPC_FEATURE_HAS_SPE 0x00800000
|
||||||
|
#define PPC_FEATURE_HAS_EFP_SINGLE 0x00400000
|
||||||
|
#define PPC_FEATURE_HAS_EFP_DOUBLE 0x00200000
|
||||||
|
#define PPC_FEATURE_NO_TB 0x00100000
|
||||||
|
#define PPC_FEATURE_POWER4 0x00080000
|
||||||
|
#define PPC_FEATURE_POWER5 0x00040000
|
||||||
|
#define PPC_FEATURE_POWER5_PLUS 0x00020000
|
||||||
|
#define PPC_FEATURE_CELL 0x00010000
|
||||||
|
#define PPC_FEATURE_BOOKE 0x00008000
|
||||||
|
#define PPC_FEATURE_SMT 0x00004000
|
||||||
|
#define PPC_FEATURE_ICACHE_SNOOP 0x00002000
|
||||||
|
#define PPC_FEATURE_ARCH_2_05 0x00001000
|
||||||
|
#define PPC_FEATURE_PA6T 0x00000800
|
||||||
|
#define PPC_FEATURE_HAS_DFP 0x00000400
|
||||||
|
#define PPC_FEATURE_POWER6_EXT 0x00000200
|
||||||
|
#define PPC_FEATURE_ARCH_2_06 0x00000100
|
||||||
|
#define PPC_FEATURE_HAS_VSX 0x00000080
|
||||||
|
|
||||||
|
#define PPC_FEATURE_PSERIES_PERFMON_COMPAT 0x00000040
|
||||||
|
|
||||||
|
/* Reserved - do not use 0x00000004 */
|
||||||
|
#define PPC_FEATURE_TRUE_LE 0x00000002
|
||||||
|
#define PPC_FEATURE_PPC_LE 0x00000001
|
||||||
|
|
||||||
|
/* in AT_HWCAP2 */
|
||||||
|
#define PPC_FEATURE2_ARCH_2_07 0x80000000
|
||||||
|
#define PPC_FEATURE2_HTM 0x40000000
|
||||||
|
#define PPC_FEATURE2_DSCR 0x20000000
|
||||||
|
#define PPC_FEATURE2_EBB 0x10000000
|
||||||
|
#define PPC_FEATURE2_ISEL 0x08000000
|
||||||
|
#define PPC_FEATURE2_TAR 0x04000000
|
||||||
|
#define PPC_FEATURE2_VEC_CRYPTO 0x02000000
|
||||||
|
#define PPC_FEATURE2_HTM_NOSC 0x01000000
|
||||||
|
#define PPC_FEATURE2_ARCH_3_00 0x00800000
|
||||||
|
#define PPC_FEATURE2_HAS_IEEE128 0x00400000
|
||||||
|
#define PPC_FEATURE2_DARN 0x00200000
|
||||||
|
#define PPC_FEATURE2_SCV 0x00100000
|
||||||
|
#define PPC_FEATURE2_HTM_NO_SUSPEND 0x00080000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned long hwcaps;
|
||||||
|
unsigned long hwcaps2;
|
||||||
|
} HardwareCapabilities;
|
||||||
|
|
||||||
|
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void);
|
||||||
|
bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask,
|
||||||
|
const HardwareCapabilities hwcaps);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char platform[64]; // 0 terminated string
|
||||||
|
char base_platform[64]; // 0 terminated string
|
||||||
|
} PlatformType;
|
||||||
|
|
||||||
|
PlatformType CpuFeatures_GetPlatformType(void);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Reads a file line by line and stores the data on the stack. This allows
|
||||||
|
// parsing files in one go without allocating.
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char buffer[STACK_LINE_READER_BUFFER_SIZE];
|
||||||
|
StringView view;
|
||||||
|
int fd;
|
||||||
|
bool skip_mode;
|
||||||
|
} StackLineReader;
|
||||||
|
|
||||||
|
// Initializes a StackLineReader.
|
||||||
|
void StackLineReader_Initialize(StackLineReader* reader, int fd);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
StringView line; // A view of the line.
|
||||||
|
bool eof; // Nothing more to read, we reached EOF.
|
||||||
|
bool full_line; // If false the line was truncated to
|
||||||
|
// STACK_LINE_READER_BUFFER_SIZE.
|
||||||
|
} LineResult;
|
||||||
|
|
||||||
|
// Reads the file pointed to by fd and tries to read a full line.
|
||||||
|
LineResult StackLineReader_NextLine(StackLineReader* reader);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// A view over a piece of string. The view is not 0 terminated.
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* ptr;
|
||||||
|
size_t size;
|
||||||
|
} StringView;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
static const StringView kEmptyStringView = {NULL, 0};
|
||||||
|
#else
|
||||||
|
static const StringView kEmptyStringView;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Returns a StringView from the provided string.
|
||||||
|
// Passing NULL is valid only if size is 0.
|
||||||
|
static inline StringView view(const char* str, const size_t size) {
|
||||||
|
StringView view;
|
||||||
|
view.ptr = str;
|
||||||
|
view.size = size;
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline StringView str(const char* str) { return view(str, strlen(str)); }
|
||||||
|
|
||||||
|
// Returns the index of the first occurrence of c in view or -1 if not found.
|
||||||
|
int CpuFeatures_StringView_IndexOfChar(const StringView view, char c);
|
||||||
|
|
||||||
|
// Returns the index of the first occurrence of sub_view in view or -1 if not
|
||||||
|
// found.
|
||||||
|
int CpuFeatures_StringView_IndexOf(const StringView view,
|
||||||
|
const StringView sub_view);
|
||||||
|
|
||||||
|
// Returns whether a is equal to b (same content).
|
||||||
|
bool CpuFeatures_StringView_IsEquals(const StringView a, const StringView b);
|
||||||
|
|
||||||
|
// Returns whether a starts with b.
|
||||||
|
bool CpuFeatures_StringView_StartsWith(const StringView a, const StringView b);
|
||||||
|
|
||||||
|
// Removes count characters from the beginning of view or kEmptyStringView if
|
||||||
|
// count if greater than view.size.
|
||||||
|
StringView CpuFeatures_StringView_PopFront(const StringView str_view,
|
||||||
|
size_t count);
|
||||||
|
|
||||||
|
// Removes count characters from the end of view or kEmptyStringView if count if
|
||||||
|
// greater than view.size.
|
||||||
|
StringView CpuFeatures_StringView_PopBack(const StringView str_view,
|
||||||
|
size_t count);
|
||||||
|
|
||||||
|
// Keeps the count first characters of view or view if count if greater than
|
||||||
|
// view.size.
|
||||||
|
StringView CpuFeatures_StringView_KeepFront(const StringView str_view,
|
||||||
|
size_t count);
|
||||||
|
|
||||||
|
// Retrieves the first character of view. If view is empty the behavior is
|
||||||
|
// undefined.
|
||||||
|
char CpuFeatures_StringView_Front(const StringView view);
|
||||||
|
|
||||||
|
// Retrieves the last character of view. If view is empty the behavior is
|
||||||
|
// undefined.
|
||||||
|
char CpuFeatures_StringView_Back(const StringView view);
|
||||||
|
|
||||||
|
// Removes leading and tailing space characters.
|
||||||
|
StringView CpuFeatures_StringView_TrimWhitespace(StringView view);
|
||||||
|
|
||||||
|
// Convert StringView to positive integer. e.g. "42", "0x2a".
|
||||||
|
// Returns -1 on error.
|
||||||
|
int CpuFeatures_StringView_ParsePositiveNumber(const StringView view);
|
||||||
|
|
||||||
|
// Copies src StringView to dst buffer.
|
||||||
|
void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
|
||||||
|
size_t dst_size);
|
||||||
|
|
||||||
|
// Checks if line contains the specified whitespace separated word.
|
||||||
|
bool CpuFeatures_StringView_HasWord(const StringView line,
|
||||||
|
const char* const word);
|
||||||
|
|
||||||
|
// Get key/value from line. key and value are separated by ": ".
|
||||||
|
// key and value are cleaned up from leading and trailing whitespaces.
|
||||||
|
bool CpuFeatures_StringView_GetAttributeKeyValue(const StringView line,
|
||||||
|
StringView* key,
|
||||||
|
StringView* value);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
|
||||||
|
#
|
||||||
|
# library : NDK compat
|
||||||
|
#
|
||||||
|
find_package(Threads REQUIRED)
|
||||||
|
set (NDK_COMPAT_HDRS cpu-features.h)
|
||||||
|
set (NDK_COMPAT_SRCS
|
||||||
|
cpu-features.c
|
||||||
|
$<TARGET_OBJECTS:utils>
|
||||||
|
$<TARGET_OBJECTS:unix_based_hardware_detection>
|
||||||
|
)
|
||||||
|
# Note that following `add_cpu_features_headers_and_sources` will use
|
||||||
|
# NDK_COMPAT_SRCS in lieu of NDK_COMPAT_HDRS because we don't want cpu_features
|
||||||
|
# headers to be installed alongside ndk_compat.
|
||||||
|
add_cpu_features_headers_and_sources(NDK_COMPAT_SRCS NDK_COMPAT_SRCS)
|
||||||
|
add_library(ndk_compat ${NDK_COMPAT_HDRS} ${NDK_COMPAT_SRCS})
|
||||||
|
setup_include_and_definitions(ndk_compat)
|
||||||
|
target_include_directories(ndk_compat PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||||
|
target_link_libraries(ndk_compat PUBLIC ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
set_target_properties(ndk_compat PROPERTIES PUBLIC_HEADER "${NDK_COMPAT_HDRS}")
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
install(TARGETS ndk_compat
|
||||||
|
EXPORT CpuFeaturesNdkCompatTargets
|
||||||
|
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ndk_compat
|
||||||
|
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
)
|
||||||
|
install(EXPORT CpuFeaturesNdkCompatTargets
|
||||||
|
NAMESPACE CpuFeatures::
|
||||||
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeaturesNdkCompat
|
||||||
|
COMPONENT Devel
|
||||||
|
)
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/CpuFeaturesNdkCompatConfig.cmake.in
|
||||||
|
"${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfig.cmake"
|
||||||
|
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeaturesNdkCompat"
|
||||||
|
NO_SET_AND_CHECK_MACRO
|
||||||
|
NO_CHECK_REQUIRED_COMPONENTS_MACRO
|
||||||
|
)
|
||||||
|
write_basic_package_version_file(
|
||||||
|
"${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfigVersion.cmake"
|
||||||
|
COMPATIBILITY SameMajorVersion
|
||||||
|
)
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
"${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfig.cmake"
|
||||||
|
"${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfigVersion.cmake"
|
||||||
|
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeaturesNdkCompat"
|
||||||
|
COMPONENT Devel
|
||||||
|
)
|
||||||
|
|
||||||
|
#
|
||||||
|
# program : NDK compat test program
|
||||||
|
#
|
||||||
|
if(ENABLE_TESTING)
|
||||||
|
add_executable(ndk-compat-test ndk-compat-test.c)
|
||||||
|
target_link_libraries(ndk-compat-test PRIVATE ndk_compat)
|
||||||
|
endif()
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
Provides a header compatible with [android's NDK cpu-features.h](https://android.googlesource.com/platform/ndk/+/master/sources/android/cpufeatures/cpu-features.h).
|
||||||
|
|
||||||
|
It is intended to be a drop in replacement for this header and help users
|
||||||
|
transition from the NDK to [Google's cpu_features library](https://github.com/google/cpu_features).
|
||||||
|
|
@ -0,0 +1,205 @@
|
||||||
|
#include "cpu-features.h"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
#include "internal/filesystem.h"
|
||||||
|
#include "internal/stack_line_reader.h"
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_ARCH_ARM)
|
||||||
|
#include "cpuinfo_arm.h"
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_X86)
|
||||||
|
#include "cpuinfo_x86.h"
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_MIPS)
|
||||||
|
#include "cpuinfo_mips.h"
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||||
|
#include "cpuinfo_aarch64.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static pthread_once_t g_once;
|
||||||
|
static int g_inited;
|
||||||
|
static uint64_t g_cpuFeatures;
|
||||||
|
static int g_cpuCount;
|
||||||
|
|
||||||
|
#ifdef CPU_FEATURES_ARCH_ARM
|
||||||
|
static uint32_t g_cpuIdArm;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void set_cpu_mask_bit(uint32_t index, uint32_t* cpu_mask) {
|
||||||
|
*cpu_mask |= 1UL << index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Examples of valid inputs: "31", "4-31"
|
||||||
|
static void parse_cpu_mask(const StringView text, uint32_t* cpu_mask) {
|
||||||
|
int separator_index = CpuFeatures_StringView_IndexOfChar(text, '-');
|
||||||
|
if (separator_index < 0) { // A single cpu index
|
||||||
|
int cpu_index = CpuFeatures_StringView_ParsePositiveNumber(text);
|
||||||
|
if (cpu_index < 0) return;
|
||||||
|
set_cpu_mask_bit(cpu_index, cpu_mask);
|
||||||
|
} else {
|
||||||
|
int cpu_index_a = CpuFeatures_StringView_ParsePositiveNumber(
|
||||||
|
CpuFeatures_StringView_KeepFront(text, separator_index));
|
||||||
|
int cpu_index_b = CpuFeatures_StringView_ParsePositiveNumber(
|
||||||
|
CpuFeatures_StringView_PopFront(text, separator_index + 1));
|
||||||
|
int i;
|
||||||
|
if (cpu_index_a < 0 || cpu_index_b < 0) return;
|
||||||
|
for (i = cpu_index_a; i <= cpu_index_b; ++i) {
|
||||||
|
if (i < 32) {
|
||||||
|
set_cpu_mask_bit(i, cpu_mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format specification from
|
||||||
|
// https://www.kernel.org/doc/Documentation/cputopology.txt
|
||||||
|
// Examples of valid inputs: "31", "2,4-31,32-63", "0-1,3"
|
||||||
|
static void parse_cpu_mask_line(const LineResult result, uint32_t* cpu_mask) {
|
||||||
|
if (!result.full_line || result.eof) return;
|
||||||
|
StringView line = result.line;
|
||||||
|
for (; line.size > 0;) {
|
||||||
|
int next_entry_index = CpuFeatures_StringView_IndexOfChar(line, ',');
|
||||||
|
if (next_entry_index < 0) {
|
||||||
|
parse_cpu_mask(line, cpu_mask);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
StringView entry = CpuFeatures_StringView_KeepFront(line, next_entry_index);
|
||||||
|
parse_cpu_mask(entry, cpu_mask);
|
||||||
|
line = CpuFeatures_StringView_PopFront(line, next_entry_index + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_cpu_mask_from_file(const char* filename,
|
||||||
|
uint32_t* cpu_mask) {
|
||||||
|
const int fd = CpuFeatures_OpenFile(filename);
|
||||||
|
if (fd >= 0) {
|
||||||
|
StackLineReader reader;
|
||||||
|
StackLineReader_Initialize(&reader, fd);
|
||||||
|
parse_cpu_mask_line(StackLineReader_NextLine(&reader), cpu_mask);
|
||||||
|
CpuFeatures_CloseFile(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_cpu_count(void) {
|
||||||
|
uint32_t cpu_mask = 0;
|
||||||
|
update_cpu_mask_from_file("/sys/devices/system/cpu/present", &cpu_mask);
|
||||||
|
update_cpu_mask_from_file("/sys/devices/system/cpu/possible", &cpu_mask);
|
||||||
|
return __builtin_popcount(cpu_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void android_cpuInit(void) {
|
||||||
|
g_cpuFeatures = 0;
|
||||||
|
g_cpuCount = 1;
|
||||||
|
g_inited = 1;
|
||||||
|
|
||||||
|
g_cpuCount = get_cpu_count();
|
||||||
|
if (g_cpuCount == 0) {
|
||||||
|
g_cpuCount = 1;
|
||||||
|
}
|
||||||
|
#if defined(CPU_FEATURES_ARCH_ARM)
|
||||||
|
ArmInfo info = GetArmInfo();
|
||||||
|
if (info.architecture == 7) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7;
|
||||||
|
if (info.features.vfpv3) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3;
|
||||||
|
if (info.features.neon) {
|
||||||
|
g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON;
|
||||||
|
g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_D32;
|
||||||
|
}
|
||||||
|
if (info.features.vfpv3d16) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_FP16;
|
||||||
|
if (info.features.idiva) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_ARM;
|
||||||
|
if (info.features.idivt) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2;
|
||||||
|
if (info.features.iwmmxt) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_iWMMXt;
|
||||||
|
if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_AES;
|
||||||
|
if (info.features.pmull) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_PMULL;
|
||||||
|
if (info.features.sha1) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_SHA1;
|
||||||
|
if (info.features.sha2) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_SHA2;
|
||||||
|
if (info.features.crc32) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_CRC32;
|
||||||
|
if (info.architecture >= 6)
|
||||||
|
g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_LDREX_STREX;
|
||||||
|
if (info.features.vfp) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv2;
|
||||||
|
if (info.features.vfpv4) {
|
||||||
|
g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_FMA;
|
||||||
|
g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON_FMA;
|
||||||
|
}
|
||||||
|
g_cpuIdArm = GetArmCpuId(&info);
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_X86)
|
||||||
|
X86Info info = GetX86Info();
|
||||||
|
if (info.features.ssse3) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSSE3;
|
||||||
|
if (info.features.popcnt) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_POPCNT;
|
||||||
|
if (info.features.movbe) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_MOVBE;
|
||||||
|
if (info.features.sse4_1) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSE4_1;
|
||||||
|
if (info.features.sse4_2) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSE4_2;
|
||||||
|
if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AES_NI;
|
||||||
|
if (info.features.avx) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AVX;
|
||||||
|
if (info.features.rdrnd) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_RDRAND;
|
||||||
|
if (info.features.avx2) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AVX2;
|
||||||
|
if (info.features.sha) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SHA_NI;
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_MIPS)
|
||||||
|
MipsInfo info = GetMipsInfo();
|
||||||
|
if (info.features.r6) g_cpuFeatures |= ANDROID_CPU_MIPS_FEATURE_R6;
|
||||||
|
if (info.features.msa) g_cpuFeatures |= ANDROID_CPU_MIPS_FEATURE_MSA;
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||||
|
Aarch64Info info = GetAarch64Info();
|
||||||
|
if (info.features.fp) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_FP;
|
||||||
|
if (info.features.asimd) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_ASIMD;
|
||||||
|
if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_AES;
|
||||||
|
if (info.features.pmull) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_PMULL;
|
||||||
|
if (info.features.sha1) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_SHA1;
|
||||||
|
if (info.features.sha2) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_SHA2;
|
||||||
|
if (info.features.crc32) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_CRC32;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
AndroidCpuFamily android_getCpuFamily(void) {
|
||||||
|
#if defined(CPU_FEATURES_ARCH_ARM)
|
||||||
|
return ANDROID_CPU_FAMILY_ARM;
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_X86_32)
|
||||||
|
return ANDROID_CPU_FAMILY_X86;
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_MIPS64)
|
||||||
|
return ANDROID_CPU_FAMILY_MIPS64;
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_MIPS32)
|
||||||
|
return ANDROID_CPU_FAMILY_MIPS;
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||||
|
return ANDROID_CPU_FAMILY_ARM64;
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_X86_64)
|
||||||
|
return ANDROID_CPU_FAMILY_X86_64;
|
||||||
|
#else
|
||||||
|
return ANDROID_CPU_FAMILY_UNKNOWN;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t android_getCpuFeatures(void) {
|
||||||
|
pthread_once(&g_once, android_cpuInit);
|
||||||
|
return g_cpuFeatures;
|
||||||
|
}
|
||||||
|
|
||||||
|
int android_getCpuCount(void) {
|
||||||
|
pthread_once(&g_once, android_cpuInit);
|
||||||
|
return g_cpuCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void android_cpuInitDummy(void) { g_inited = 1; }
|
||||||
|
|
||||||
|
int android_setCpu(int cpu_count, uint64_t cpu_features) {
|
||||||
|
/* Fail if the library was already initialized. */
|
||||||
|
if (g_inited) return 0;
|
||||||
|
g_cpuCount = (cpu_count <= 0 ? 1 : cpu_count);
|
||||||
|
g_cpuFeatures = cpu_features;
|
||||||
|
pthread_once(&g_once, android_cpuInitDummy);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CPU_FEATURES_ARCH_ARM
|
||||||
|
|
||||||
|
uint32_t android_getCpuIdArm(void) {
|
||||||
|
pthread_once(&g_once, android_cpuInit);
|
||||||
|
return g_cpuIdArm;
|
||||||
|
}
|
||||||
|
|
||||||
|
int android_setCpuArm(int cpu_count, uint64_t cpu_features, uint32_t cpu_id) {
|
||||||
|
if (!android_setCpu(cpu_count, cpu_features)) return 0;
|
||||||
|
g_cpuIdArm = cpu_id;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_ARCH_ARM
|
||||||
|
|
@ -0,0 +1,320 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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 OWNER 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.
|
||||||
|
*/
|
||||||
|
#ifndef GOOGLE_CPU_FEATURES_H
|
||||||
|
#define GOOGLE_CPU_FEATURES_H
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
/* A list of valid values returned by android_getCpuFamily().
|
||||||
|
* They describe the CPU Architecture of the current process.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
ANDROID_CPU_FAMILY_UNKNOWN = 0,
|
||||||
|
ANDROID_CPU_FAMILY_ARM,
|
||||||
|
ANDROID_CPU_FAMILY_X86,
|
||||||
|
ANDROID_CPU_FAMILY_MIPS,
|
||||||
|
ANDROID_CPU_FAMILY_ARM64,
|
||||||
|
ANDROID_CPU_FAMILY_X86_64,
|
||||||
|
ANDROID_CPU_FAMILY_MIPS64,
|
||||||
|
ANDROID_CPU_FAMILY_MAX /* do not remove */
|
||||||
|
} AndroidCpuFamily;
|
||||||
|
|
||||||
|
/* Return the CPU family of the current process.
|
||||||
|
*
|
||||||
|
* Note that this matches the bitness of the current process. I.e. when
|
||||||
|
* running a 32-bit binary on a 64-bit capable CPU, this will return the
|
||||||
|
* 32-bit CPU family value.
|
||||||
|
*/
|
||||||
|
extern AndroidCpuFamily android_getCpuFamily(void);
|
||||||
|
|
||||||
|
/* Return a bitmap describing a set of optional CPU features that are
|
||||||
|
* supported by the current device's CPU. The exact bit-flags returned
|
||||||
|
* depend on the value returned by android_getCpuFamily(). See the
|
||||||
|
* documentation for the ANDROID_CPU_*_FEATURE_* flags below for details.
|
||||||
|
*/
|
||||||
|
extern uint64_t android_getCpuFeatures(void);
|
||||||
|
|
||||||
|
/* The list of feature flags for ANDROID_CPU_FAMILY_ARM that can be
|
||||||
|
* recognized by the library (see note below for 64-bit ARM). Value details
|
||||||
|
* are:
|
||||||
|
*
|
||||||
|
* VFPv2:
|
||||||
|
* CPU supports the VFPv2 instruction set. Many, but not all, ARMv6 CPUs
|
||||||
|
* support these instructions. VFPv2 is a subset of VFPv3 so this will
|
||||||
|
* be set whenever VFPv3 is set too.
|
||||||
|
*
|
||||||
|
* ARMv7:
|
||||||
|
* CPU supports the ARMv7-A basic instruction set.
|
||||||
|
* This feature is mandated by the 'armeabi-v7a' ABI.
|
||||||
|
*
|
||||||
|
* VFPv3:
|
||||||
|
* CPU supports the VFPv3-D16 instruction set, providing hardware FPU
|
||||||
|
* support for single and double precision floating point registers.
|
||||||
|
* Note that only 16 FPU registers are available by default, unless
|
||||||
|
* the D32 bit is set too. This feature is also mandated by the
|
||||||
|
* 'armeabi-v7a' ABI.
|
||||||
|
*
|
||||||
|
* VFP_D32:
|
||||||
|
* CPU VFP optional extension that provides 32 FPU registers,
|
||||||
|
* instead of 16. Note that ARM mandates this feature is the 'NEON'
|
||||||
|
* feature is implemented by the CPU.
|
||||||
|
*
|
||||||
|
* NEON:
|
||||||
|
* CPU FPU supports "ARM Advanced SIMD" instructions, also known as
|
||||||
|
* NEON. Note that this mandates the VFP_D32 feature as well, per the
|
||||||
|
* ARM Architecture specification.
|
||||||
|
*
|
||||||
|
* VFP_FP16:
|
||||||
|
* Half-width floating precision VFP extension. If set, the CPU
|
||||||
|
* supports instructions to perform floating-point operations on
|
||||||
|
* 16-bit registers. This is part of the VFPv4 specification, but
|
||||||
|
* not mandated by any Android ABI.
|
||||||
|
*
|
||||||
|
* VFP_FMA:
|
||||||
|
* Fused multiply-accumulate VFP instructions extension. Also part of
|
||||||
|
* the VFPv4 specification, but not mandated by any Android ABI.
|
||||||
|
*
|
||||||
|
* NEON_FMA:
|
||||||
|
* Fused multiply-accumulate NEON instructions extension. Optional
|
||||||
|
* extension from the VFPv4 specification, but not mandated by any
|
||||||
|
* Android ABI.
|
||||||
|
*
|
||||||
|
* IDIV_ARM:
|
||||||
|
* Integer division available in ARM mode. Only available
|
||||||
|
* on recent CPUs (e.g. Cortex-A15).
|
||||||
|
*
|
||||||
|
* IDIV_THUMB2:
|
||||||
|
* Integer division available in Thumb-2 mode. Only available
|
||||||
|
* on recent CPUs (e.g. Cortex-A15).
|
||||||
|
*
|
||||||
|
* iWMMXt:
|
||||||
|
* Optional extension that adds MMX registers and operations to an
|
||||||
|
* ARM CPU. This is only available on a few XScale-based CPU designs
|
||||||
|
* sold by Marvell. Pretty rare in practice.
|
||||||
|
*
|
||||||
|
* AES:
|
||||||
|
* CPU supports AES instructions. These instructions are only
|
||||||
|
* available for 32-bit applications running on ARMv8 CPU.
|
||||||
|
*
|
||||||
|
* CRC32:
|
||||||
|
* CPU supports CRC32 instructions. These instructions are only
|
||||||
|
* available for 32-bit applications running on ARMv8 CPU.
|
||||||
|
*
|
||||||
|
* SHA2:
|
||||||
|
* CPU supports SHA2 instructions. These instructions are only
|
||||||
|
* available for 32-bit applications running on ARMv8 CPU.
|
||||||
|
*
|
||||||
|
* SHA1:
|
||||||
|
* CPU supports SHA1 instructions. These instructions are only
|
||||||
|
* available for 32-bit applications running on ARMv8 CPU.
|
||||||
|
*
|
||||||
|
* PMULL:
|
||||||
|
* CPU supports 64-bit PMULL and PMULL2 instructions. These
|
||||||
|
* instructions are only available for 32-bit applications
|
||||||
|
* running on ARMv8 CPU.
|
||||||
|
*
|
||||||
|
* If you want to tell the compiler to generate code that targets one of
|
||||||
|
* the feature set above, you should probably use one of the following
|
||||||
|
* flags (for more details, see technical note at the end of this file):
|
||||||
|
*
|
||||||
|
* -mfpu=vfp
|
||||||
|
* -mfpu=vfpv2
|
||||||
|
* These are equivalent and tell GCC to use VFPv2 instructions for
|
||||||
|
* floating-point operations. Use this if you want your code to
|
||||||
|
* run on *some* ARMv6 devices, and any ARMv7-A device supported
|
||||||
|
* by Android.
|
||||||
|
*
|
||||||
|
* Generated code requires VFPv2 feature.
|
||||||
|
*
|
||||||
|
* -mfpu=vfpv3-d16
|
||||||
|
* Tell GCC to use VFPv3 instructions (using only 16 FPU registers).
|
||||||
|
* This should be generic code that runs on any CPU that supports the
|
||||||
|
* 'armeabi-v7a' Android ABI. Note that no ARMv6 CPU supports this.
|
||||||
|
*
|
||||||
|
* Generated code requires VFPv3 feature.
|
||||||
|
*
|
||||||
|
* -mfpu=vfpv3
|
||||||
|
* Tell GCC to use VFPv3 instructions with 32 FPU registers.
|
||||||
|
* Generated code requires VFPv3|VFP_D32 features.
|
||||||
|
*
|
||||||
|
* -mfpu=neon
|
||||||
|
* Tell GCC to use VFPv3 instructions with 32 FPU registers, and
|
||||||
|
* also support NEON intrinsics (see <arm_neon.h>).
|
||||||
|
* Generated code requires VFPv3|VFP_D32|NEON features.
|
||||||
|
*
|
||||||
|
* -mfpu=vfpv4-d16
|
||||||
|
* Generated code requires VFPv3|VFP_FP16|VFP_FMA features.
|
||||||
|
*
|
||||||
|
* -mfpu=vfpv4
|
||||||
|
* Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32 features.
|
||||||
|
*
|
||||||
|
* -mfpu=neon-vfpv4
|
||||||
|
* Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32|NEON|NEON_FMA
|
||||||
|
* features.
|
||||||
|
*
|
||||||
|
* -mcpu=cortex-a7
|
||||||
|
* -mcpu=cortex-a15
|
||||||
|
* Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32|
|
||||||
|
* NEON|NEON_FMA|IDIV_ARM|IDIV_THUMB2
|
||||||
|
* This flag implies -mfpu=neon-vfpv4.
|
||||||
|
*
|
||||||
|
* -mcpu=iwmmxt
|
||||||
|
* Allows the use of iWMMXt instrinsics with GCC.
|
||||||
|
*
|
||||||
|
* IMPORTANT NOTE: These flags should only be tested when
|
||||||
|
* android_getCpuFamily() returns ANDROID_CPU_FAMILY_ARM, i.e. this is a
|
||||||
|
* 32-bit process.
|
||||||
|
*
|
||||||
|
* When running a 64-bit ARM process on an ARMv8 CPU,
|
||||||
|
* android_getCpuFeatures() will return a different set of bitflags
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
ANDROID_CPU_ARM_FEATURE_ARMv7 = (1 << 0),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_VFPv3 = (1 << 1),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_NEON = (1 << 2),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_LDREX_STREX = (1 << 3),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_VFPv2 = (1 << 4),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_VFP_D32 = (1 << 5),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_VFP_FP16 = (1 << 6),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_VFP_FMA = (1 << 7),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_NEON_FMA = (1 << 8),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_IDIV_ARM = (1 << 9),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2 = (1 << 10),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_iWMMXt = (1 << 11),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_AES = (1 << 12),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_PMULL = (1 << 13),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_SHA1 = (1 << 14),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_SHA2 = (1 << 15),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_CRC32 = (1 << 16),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The bit flags corresponding to the output of android_getCpuFeatures()
|
||||||
|
* when android_getCpuFamily() returns ANDROID_CPU_FAMILY_ARM64. Value details
|
||||||
|
* are:
|
||||||
|
*
|
||||||
|
* FP:
|
||||||
|
* CPU has Floating-point unit.
|
||||||
|
*
|
||||||
|
* ASIMD:
|
||||||
|
* CPU has Advanced SIMD unit.
|
||||||
|
*
|
||||||
|
* AES:
|
||||||
|
* CPU supports AES instructions.
|
||||||
|
*
|
||||||
|
* CRC32:
|
||||||
|
* CPU supports CRC32 instructions.
|
||||||
|
*
|
||||||
|
* SHA2:
|
||||||
|
* CPU supports SHA2 instructions.
|
||||||
|
*
|
||||||
|
* SHA1:
|
||||||
|
* CPU supports SHA1 instructions.
|
||||||
|
*
|
||||||
|
* PMULL:
|
||||||
|
* CPU supports 64-bit PMULL and PMULL2 instructions.
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
ANDROID_CPU_ARM64_FEATURE_FP = (1 << 0),
|
||||||
|
ANDROID_CPU_ARM64_FEATURE_ASIMD = (1 << 1),
|
||||||
|
ANDROID_CPU_ARM64_FEATURE_AES = (1 << 2),
|
||||||
|
ANDROID_CPU_ARM64_FEATURE_PMULL = (1 << 3),
|
||||||
|
ANDROID_CPU_ARM64_FEATURE_SHA1 = (1 << 4),
|
||||||
|
ANDROID_CPU_ARM64_FEATURE_SHA2 = (1 << 5),
|
||||||
|
ANDROID_CPU_ARM64_FEATURE_CRC32 = (1 << 6),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The bit flags corresponding to the output of android_getCpuFeatures()
|
||||||
|
* when android_getCpuFamily() returns ANDROID_CPU_FAMILY_X86 or
|
||||||
|
* ANDROID_CPU_FAMILY_X86_64.
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
ANDROID_CPU_X86_FEATURE_SSSE3 = (1 << 0),
|
||||||
|
ANDROID_CPU_X86_FEATURE_POPCNT = (1 << 1),
|
||||||
|
ANDROID_CPU_X86_FEATURE_MOVBE = (1 << 2),
|
||||||
|
ANDROID_CPU_X86_FEATURE_SSE4_1 = (1 << 3),
|
||||||
|
ANDROID_CPU_X86_FEATURE_SSE4_2 = (1 << 4),
|
||||||
|
ANDROID_CPU_X86_FEATURE_AES_NI = (1 << 5),
|
||||||
|
ANDROID_CPU_X86_FEATURE_AVX = (1 << 6),
|
||||||
|
ANDROID_CPU_X86_FEATURE_RDRAND = (1 << 7),
|
||||||
|
ANDROID_CPU_X86_FEATURE_AVX2 = (1 << 8),
|
||||||
|
ANDROID_CPU_X86_FEATURE_SHA_NI = (1 << 9),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The bit flags corresponding to the output of android_getCpuFeatures()
|
||||||
|
* when android_getCpuFamily() returns ANDROID_CPU_FAMILY_MIPS
|
||||||
|
* or ANDROID_CPU_FAMILY_MIPS64. Values are:
|
||||||
|
*
|
||||||
|
* R6:
|
||||||
|
* CPU executes MIPS Release 6 instructions natively, and
|
||||||
|
* supports obsoleted R1..R5 instructions only via kernel traps.
|
||||||
|
*
|
||||||
|
* MSA:
|
||||||
|
* CPU supports Mips SIMD Architecture instructions.
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
ANDROID_CPU_MIPS_FEATURE_R6 = (1 << 0),
|
||||||
|
ANDROID_CPU_MIPS_FEATURE_MSA = (1 << 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Return the number of CPU cores detected on this device.
|
||||||
|
* Please note the current implementation supports up to 32 cpus.
|
||||||
|
*/
|
||||||
|
extern int android_getCpuCount(void);
|
||||||
|
|
||||||
|
/* The following is used to force the CPU count and features
|
||||||
|
* mask in sandboxed processes. Under 4.1 and higher, these processes
|
||||||
|
* cannot access /proc, which is the only way to get information from
|
||||||
|
* the kernel about the current hardware (at least on ARM).
|
||||||
|
*
|
||||||
|
* It _must_ be called only once, and before any android_getCpuXXX
|
||||||
|
* function, any other case will fail.
|
||||||
|
*
|
||||||
|
* This function return 1 on success, and 0 on failure.
|
||||||
|
*/
|
||||||
|
extern int android_setCpu(int cpu_count, uint64_t cpu_features);
|
||||||
|
|
||||||
|
#ifdef __arm__
|
||||||
|
|
||||||
|
/* Retrieve the ARM 32-bit CPUID value from the kernel.
|
||||||
|
* Note that this cannot work on sandboxed processes under 4.1 and
|
||||||
|
* higher, unless you called android_setCpuArm() before.
|
||||||
|
*/
|
||||||
|
extern uint32_t android_getCpuIdArm(void);
|
||||||
|
|
||||||
|
/* An ARM-specific variant of android_setCpu() that also allows you
|
||||||
|
* to set the ARM CPUID field.
|
||||||
|
*/
|
||||||
|
extern int android_setCpuArm(int cpu_count, uint64_t cpu_features,
|
||||||
|
uint32_t cpu_id);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__END_DECLS
|
||||||
|
#endif /* GOOGLE_CPU_FEATURES_H */
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "cpu-features.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
printf("android_getCpuFamily()=%d\n", android_getCpuFamily());
|
||||||
|
printf("android_getCpuFeatures()=0x%08llx\n", android_getCpuFeatures());
|
||||||
|
printf("android_getCpuCount()=%d\n", android_getCpuCount());
|
||||||
|
#ifdef __arm__
|
||||||
|
printf("android_getCpuIdArm()=0x%04x\n", android_getCpuIdArm());
|
||||||
|
#endif //__arm__
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,209 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
readonly SCRIPT_FOLDER=$(cd -P -- "$(dirname -- "$0")" && pwd -P)
|
||||||
|
readonly PROJECT_FOLDER="${SCRIPT_FOLDER}/.."
|
||||||
|
readonly ARCHIVE_FOLDER=~/cpu_features_archives
|
||||||
|
readonly QEMU_INSTALL=${ARCHIVE_FOLDER}/qemu
|
||||||
|
readonly DEFAULT_CMAKE_ARGS=" -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON"
|
||||||
|
|
||||||
|
function extract() {
|
||||||
|
case $1 in
|
||||||
|
*.tar.bz2) tar xjf "$1" ;;
|
||||||
|
*.tar.xz) tar xJf "$1" ;;
|
||||||
|
*.tar.gz) tar xzf "$1" ;;
|
||||||
|
*)
|
||||||
|
echo "don't know how to extract '$1'..."
|
||||||
|
exit 1
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
function unpackifnotexists() {
|
||||||
|
mkdir -p "${ARCHIVE_FOLDER}"
|
||||||
|
cd "${ARCHIVE_FOLDER}" || exit
|
||||||
|
local URL=$1
|
||||||
|
local RELATIVE_FOLDER=$2
|
||||||
|
local DESTINATION="${ARCHIVE_FOLDER}/${RELATIVE_FOLDER}"
|
||||||
|
if [[ ! -d "${DESTINATION}" ]] ; then
|
||||||
|
local ARCHIVE_NAME=$(echo ${URL} | sed 's/.*\///')
|
||||||
|
test -f "${ARCHIVE_NAME}" || wget -q "${URL}"
|
||||||
|
extract "${ARCHIVE_NAME}"
|
||||||
|
rm -f "${ARCHIVE_NAME}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function installqemuifneeded() {
|
||||||
|
local VERSION=${QEMU_VERSION:=2.11.1}
|
||||||
|
local ARCHES=${QEMU_ARCHES:=arm aarch64 i386 x86_64 mips mipsel mips64 mips64el}
|
||||||
|
local TARGETS=${QEMU_TARGETS:=$(echo "$ARCHES" | sed 's#$# #;s#\([^ ]*\) #\1-linux-user #g')}
|
||||||
|
|
||||||
|
if echo "${VERSION} ${TARGETS}" | cmp --silent ${QEMU_INSTALL}/.build -; then
|
||||||
|
echo "qemu ${VERSION} up to date!"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "VERSION: ${VERSION}"
|
||||||
|
echo "TARGETS: ${TARGETS}"
|
||||||
|
|
||||||
|
rm -rf ${QEMU_INSTALL}
|
||||||
|
|
||||||
|
# Checking for a tarball before downloading makes testing easier :-)
|
||||||
|
local QEMU_URL="http://wiki.qemu-project.org/download/qemu-${VERSION}.tar.xz"
|
||||||
|
local QEMU_FOLDER="qemu-${VERSION}"
|
||||||
|
unpackifnotexists ${QEMU_URL} ${QEMU_FOLDER}
|
||||||
|
cd ${QEMU_FOLDER} || exit
|
||||||
|
|
||||||
|
./configure \
|
||||||
|
--prefix="${QEMU_INSTALL}" \
|
||||||
|
--target-list="${TARGETS}" \
|
||||||
|
--disable-docs \
|
||||||
|
--disable-sdl \
|
||||||
|
--disable-gtk \
|
||||||
|
--disable-gnutls \
|
||||||
|
--disable-gcrypt \
|
||||||
|
--disable-nettle \
|
||||||
|
--disable-curses \
|
||||||
|
--static
|
||||||
|
|
||||||
|
make -j4
|
||||||
|
make install
|
||||||
|
|
||||||
|
echo "$VERSION $TARGETS" > ${QEMU_INSTALL}/.build
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert_defined(){
|
||||||
|
local VALUE=${1}
|
||||||
|
: "${VALUE?"${1} needs to be defined"}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function integrate() {
|
||||||
|
cd "${PROJECT_FOLDER}"
|
||||||
|
case "${OS}" in
|
||||||
|
"Windows_NT") CMAKE_BUILD_ARGS="--config Debug --target ALL_BUILD"
|
||||||
|
CMAKE_TEST_FILES="${BUILD_DIR}/test/Debug/*_test.exe"
|
||||||
|
DEMO=${BUILD_DIR}/Debug/list_cpu_features.exe
|
||||||
|
;;
|
||||||
|
*) CMAKE_BUILD_ARGS="--target all"
|
||||||
|
CMAKE_TEST_FILES="${BUILD_DIR}/test/*_test"
|
||||||
|
DEMO=${BUILD_DIR}/list_cpu_features
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Generating CMake configuration
|
||||||
|
cmake -H. -B"${BUILD_DIR}" ${DEFAULT_CMAKE_ARGS} "${CMAKE_ADDITIONAL_ARGS[@]}" -G"${CMAKE_GENERATOR:-Unix Makefiles}"
|
||||||
|
|
||||||
|
# Building
|
||||||
|
cmake --build "${BUILD_DIR}" ${CMAKE_BUILD_ARGS}
|
||||||
|
|
||||||
|
# Running tests if needed
|
||||||
|
if [[ "${QEMU_ARCH}" == "DISABLED" ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
RUN_CMD=""
|
||||||
|
if [[ -n "${QEMU_ARCH}" ]]; then
|
||||||
|
installqemuifneeded
|
||||||
|
RUN_CMD="${QEMU_INSTALL}/bin/qemu-${QEMU_ARCH} ${QEMU_ARGS[@]}"
|
||||||
|
fi
|
||||||
|
for test_binary in ${CMAKE_TEST_FILES}; do
|
||||||
|
${RUN_CMD} ${test_binary}
|
||||||
|
done
|
||||||
|
${RUN_CMD} ${DEMO}
|
||||||
|
}
|
||||||
|
|
||||||
|
function expand_linaro_config() {
|
||||||
|
assert_defined TARGET
|
||||||
|
local LINARO_ROOT_URL=https://releases.linaro.org/components/toolchain/binaries/7.2-2017.11
|
||||||
|
|
||||||
|
local GCC_URL=${LINARO_ROOT_URL}/${TARGET}/gcc-linaro-7.2.1-2017.11-x86_64_${TARGET}.tar.xz
|
||||||
|
local GCC_RELATIVE_FOLDER="gcc-linaro-7.2.1-2017.11-x86_64_${TARGET}"
|
||||||
|
unpackifnotexists "${GCC_URL}" "${GCC_RELATIVE_FOLDER}"
|
||||||
|
|
||||||
|
local SYSROOT_URL=${LINARO_ROOT_URL}/${TARGET}/sysroot-glibc-linaro-2.25-2017.11-${TARGET}.tar.xz
|
||||||
|
local SYSROOT_RELATIVE_FOLDER=sysroot-glibc-linaro-2.25-2017.11-${TARGET}
|
||||||
|
unpackifnotexists "${SYSROOT_URL}" "${SYSROOT_RELATIVE_FOLDER}"
|
||||||
|
|
||||||
|
local SYSROOT_FOLDER=${ARCHIVE_FOLDER}/${SYSROOT_RELATIVE_FOLDER}
|
||||||
|
local GCC_FOLDER=${ARCHIVE_FOLDER}/${GCC_RELATIVE_FOLDER}
|
||||||
|
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_NAME=Linux)
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_PROCESSOR=${TARGET})
|
||||||
|
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSROOT=${SYSROOT_FOLDER})
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_C_COMPILER=${GCC_FOLDER}/bin/${TARGET}-gcc)
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_CXX_COMPILER=${GCC_FOLDER}/bin/${TARGET}-g++)
|
||||||
|
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER)
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY)
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY)
|
||||||
|
|
||||||
|
QEMU_ARGS+=(-L ${SYSROOT_FOLDER})
|
||||||
|
QEMU_ARGS+=(-E LD_LIBRARY_PATH=/lib)
|
||||||
|
}
|
||||||
|
|
||||||
|
function expand_codescape_config() {
|
||||||
|
assert_defined TARGET
|
||||||
|
local DATE=2017.10-08
|
||||||
|
local CODESCAPE_URL=https://codescape.mips.com/components/toolchain/${DATE}/Codescape.GNU.Tools.Package.${DATE}.for.MIPS.MTI.Linux.CentOS-5.x86_64.tar.gz
|
||||||
|
local GCC_URL=${CODESCAPE_URL}
|
||||||
|
local GCC_RELATIVE_FOLDER="mips-mti-linux-gnu/${DATE}"
|
||||||
|
unpackifnotexists "${GCC_URL}" "${GCC_RELATIVE_FOLDER}"
|
||||||
|
|
||||||
|
local GCC_FOLDER=${ARCHIVE_FOLDER}/${GCC_RELATIVE_FOLDER}
|
||||||
|
local MIPS_FLAGS=""
|
||||||
|
local LIBC_FOLDER_SUFFIX=""
|
||||||
|
local FLAVOUR=""
|
||||||
|
case "${TARGET}" in
|
||||||
|
"mips32") MIPS_FLAGS="-EB -mabi=32"; FLAVOUR="mips-r2-hard"; LIBC_FOLDER_SUFFIX="lib" ;;
|
||||||
|
"mips32el") MIPS_FLAGS="-EL -mabi=32"; FLAVOUR="mipsel-r2-hard"; LIBC_FOLDER_SUFFIX="lib" ;;
|
||||||
|
"mips64") MIPS_FLAGS="-EB -mabi=64"; FLAVOUR="mips-r2-hard"; LIBC_FOLDER_SUFFIX="lib64" ;;
|
||||||
|
"mips64el") MIPS_FLAGS="-EL -mabi=64"; FLAVOUR="mipsel-r2-hard"; LIBC_FOLDER_SUFFIX="lib64" ;;
|
||||||
|
*) echo 'unknown mips platform'; exit 1;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH=${GCC_FOLDER})
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_NAME=Linux)
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_PROCESSOR=${TARGET})
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_C_COMPILER=mips-mti-linux-gnu-gcc)
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_CXX_COMPILER=mips-mti-linux-gnu-g++)
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_C_COMPILER_ARG1="${MIPS_FLAGS}")
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_CXX_COMPILER_ARG1="${MIPS_FLAGS}")
|
||||||
|
|
||||||
|
local SYSROOT_FOLDER=${GCC_FOLDER}/sysroot/${FLAVOUR}
|
||||||
|
|
||||||
|
# Keeping only the sysroot of interest to save on travis cache.
|
||||||
|
if [[ "${CONTINUOUS_INTEGRATION}" = "true" ]]; then
|
||||||
|
for folder in ${GCC_FOLDER}/sysroot/*; do
|
||||||
|
if [[ "${folder}" != "${SYSROOT_FOLDER}" ]]; then
|
||||||
|
rm -rf ${folder}
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
local LIBC_FOLDER=${GCC_FOLDER}/mips-mti-linux-gnu/lib/${FLAVOUR}/${LIBC_FOLDER_SUFFIX}
|
||||||
|
QEMU_ARGS+=(-L ${SYSROOT_FOLDER})
|
||||||
|
QEMU_ARGS+=(-E LD_PRELOAD=${LIBC_FOLDER}/libstdc++.so.6:${LIBC_FOLDER}/libgcc_s.so.1)
|
||||||
|
}
|
||||||
|
|
||||||
|
function expand_environment_and_integrate() {
|
||||||
|
assert_defined PROJECT_FOLDER
|
||||||
|
assert_defined TARGET
|
||||||
|
|
||||||
|
BUILD_DIR="${PROJECT_FOLDER}/cmake_build/${TARGET}"
|
||||||
|
mkdir -p "${BUILD_DIR}"
|
||||||
|
|
||||||
|
declare -a CONFIG_NAMES=()
|
||||||
|
declare -a QEMU_ARGS=()
|
||||||
|
declare -a CMAKE_ADDITIONAL_ARGS=()
|
||||||
|
|
||||||
|
case ${TOOLCHAIN} in
|
||||||
|
LINARO) expand_linaro_config ;;
|
||||||
|
CODESCAPE) expand_codescape_config ;;
|
||||||
|
NATIVE) QEMU_ARCH="" ;;
|
||||||
|
*) echo "Unknown toolchain '${TOOLCHAIN}'..."; exit 1;;
|
||||||
|
esac
|
||||||
|
integrate
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "${CONTINUOUS_INTEGRATION}" = "true" ]; then
|
||||||
|
QEMU_ARCHES=${QEMU_ARCH}
|
||||||
|
expand_environment_and_integrate
|
||||||
|
fi
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
source "$(dirname -- "$0")"/run_integration.sh
|
||||||
|
|
||||||
|
# Toolchains for little-endian, 64-bit ARMv8 for GNU/Linux systems
|
||||||
|
function set_aarch64-linux-gnu() {
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=aarch64-linux-gnu
|
||||||
|
QEMU_ARCH=aarch64
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toolchains for little-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
|
||||||
|
function set_arm-linux-gnueabihf() {
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=arm-linux-gnueabihf
|
||||||
|
QEMU_ARCH=arm
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toolchains for little-endian, 32-bit ARMv8 for GNU/Linux systems
|
||||||
|
function set_armv8l-linux-gnueabihf() {
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=armv8l-linux-gnueabihf
|
||||||
|
QEMU_ARCH=arm
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toolchains for little-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
|
||||||
|
function set_arm-linux-gnueabi() {
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=arm-linux-gnueabi
|
||||||
|
QEMU_ARCH=arm
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toolchains for big-endian, 64-bit ARMv8 for GNU/Linux systems
|
||||||
|
function set_aarch64_be-linux-gnu() {
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=aarch64_be-linux-gnu
|
||||||
|
QEMU_ARCH=DISABLED
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toolchains for big-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
|
||||||
|
function set_armeb-linux-gnueabihf() {
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=armeb-linux-gnueabihf
|
||||||
|
QEMU_ARCH=DISABLED
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toolchains for big-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
|
||||||
|
function set_armeb-linux-gnueabi() {
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=armeb-linux-gnueabi
|
||||||
|
QEMU_ARCH=DISABLED
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_mips32() {
|
||||||
|
TOOLCHAIN=CODESCAPE
|
||||||
|
TARGET=mips32
|
||||||
|
QEMU_ARCH=mips
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_mips32el() {
|
||||||
|
TOOLCHAIN=CODESCAPE
|
||||||
|
TARGET=mips32el
|
||||||
|
QEMU_ARCH=mipsel
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_mips64() {
|
||||||
|
TOOLCHAIN=CODESCAPE
|
||||||
|
TARGET=mips64
|
||||||
|
QEMU_ARCH=mips64
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_mips64el() {
|
||||||
|
TOOLCHAIN=CODESCAPE
|
||||||
|
TARGET=mips64el
|
||||||
|
QEMU_ARCH=mips64el
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_native() {
|
||||||
|
TOOLCHAIN=NATIVE
|
||||||
|
TARGET=native
|
||||||
|
QEMU_ARCH=""
|
||||||
|
}
|
||||||
|
|
||||||
|
ENVIRONMENTS="
|
||||||
|
set_aarch64-linux-gnu
|
||||||
|
set_arm-linux-gnueabihf
|
||||||
|
set_armv8l-linux-gnueabihf
|
||||||
|
set_arm-linux-gnueabi
|
||||||
|
set_aarch64_be-linux-gnu
|
||||||
|
set_armeb-linux-gnueabihf
|
||||||
|
set_armeb-linux-gnueabi
|
||||||
|
set_mips32
|
||||||
|
set_mips32el
|
||||||
|
set_mips64
|
||||||
|
set_mips64el
|
||||||
|
set_native
|
||||||
|
"
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CMAKE_GENERATOR="Ninja"
|
||||||
|
|
||||||
|
for SET_ENVIRONMENT in ${ENVIRONMENTS}; do
|
||||||
|
${SET_ENVIRONMENT}
|
||||||
|
expand_environment_and_integrate
|
||||||
|
done
|
||||||
|
|
@ -0,0 +1,150 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "cpuinfo_aarch64.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "internal/filesystem.h"
|
||||||
|
#include "internal/hwcaps.h"
|
||||||
|
#include "internal/stack_line_reader.h"
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
// Generation of feature's getters/setters functions and kGetters, kSetters,
|
||||||
|
// kCpuInfoFlags and kHardwareCapabilities global tables.
|
||||||
|
#define DEFINE_TABLE_FEATURES \
|
||||||
|
FEATURE(AARCH64_FP, fp, "fp", AARCH64_HWCAP_FP, 0) \
|
||||||
|
FEATURE(AARCH64_ASIMD, asimd, "asimd", AARCH64_HWCAP_ASIMD, 0) \
|
||||||
|
FEATURE(AARCH64_EVTSTRM, evtstrm, "evtstrm", AARCH64_HWCAP_EVTSTRM, 0) \
|
||||||
|
FEATURE(AARCH64_AES, aes, "aes", AARCH64_HWCAP_AES, 0) \
|
||||||
|
FEATURE(AARCH64_PMULL, pmull, "pmull", AARCH64_HWCAP_PMULL, 0) \
|
||||||
|
FEATURE(AARCH64_SHA1, sha1, "sha1", AARCH64_HWCAP_SHA1, 0) \
|
||||||
|
FEATURE(AARCH64_SHA2, sha2, "sha2", AARCH64_HWCAP_SHA2, 0) \
|
||||||
|
FEATURE(AARCH64_CRC32, crc32, "crc32", AARCH64_HWCAP_CRC32, 0) \
|
||||||
|
FEATURE(AARCH64_ATOMICS, atomics, "atomics", AARCH64_HWCAP_ATOMICS, 0) \
|
||||||
|
FEATURE(AARCH64_FPHP, fphp, "fphp", AARCH64_HWCAP_FPHP, 0) \
|
||||||
|
FEATURE(AARCH64_ASIMDHP, asimdhp, "asimdhp", AARCH64_HWCAP_ASIMDHP, 0) \
|
||||||
|
FEATURE(AARCH64_CPUID, cpuid, "cpuid", AARCH64_HWCAP_CPUID, 0) \
|
||||||
|
FEATURE(AARCH64_ASIMDRDM, asimdrdm, "asimdrdm", AARCH64_HWCAP_ASIMDRDM, 0) \
|
||||||
|
FEATURE(AARCH64_JSCVT, jscvt, "jscvt", AARCH64_HWCAP_JSCVT, 0) \
|
||||||
|
FEATURE(AARCH64_FCMA, fcma, "fcma", AARCH64_HWCAP_FCMA, 0) \
|
||||||
|
FEATURE(AARCH64_LRCPC, lrcpc, "lrcpc", AARCH64_HWCAP_LRCPC, 0) \
|
||||||
|
FEATURE(AARCH64_DCPOP, dcpop, "dcpop", AARCH64_HWCAP_DCPOP, 0) \
|
||||||
|
FEATURE(AARCH64_SHA3, sha3, "sha3", AARCH64_HWCAP_SHA3, 0) \
|
||||||
|
FEATURE(AARCH64_SM3, sm3, "sm3", AARCH64_HWCAP_SM3, 0) \
|
||||||
|
FEATURE(AARCH64_SM4, sm4, "sm4", AARCH64_HWCAP_SM4, 0) \
|
||||||
|
FEATURE(AARCH64_ASIMDDP, asimddp, "asimddp", AARCH64_HWCAP_ASIMDDP, 0) \
|
||||||
|
FEATURE(AARCH64_SHA512, sha512, "sha512", AARCH64_HWCAP_SHA512, 0) \
|
||||||
|
FEATURE(AARCH64_SVE, sve, "sve", AARCH64_HWCAP_SVE, 0) \
|
||||||
|
FEATURE(AARCH64_ASIMDFHM, asimdfhm, "asimdfhm", AARCH64_HWCAP_ASIMDFHM, 0) \
|
||||||
|
FEATURE(AARCH64_DIT, dit, "dit", AARCH64_HWCAP_DIT, 0) \
|
||||||
|
FEATURE(AARCH64_USCAT, uscat, "uscat", AARCH64_HWCAP_USCAT, 0) \
|
||||||
|
FEATURE(AARCH64_ILRCPC, ilrcpc, "ilrcpc", AARCH64_HWCAP_ILRCPC, 0) \
|
||||||
|
FEATURE(AARCH64_FLAGM, flagm, "flagm", AARCH64_HWCAP_FLAGM, 0) \
|
||||||
|
FEATURE(AARCH64_SSBS, ssbs, "ssbs", AARCH64_HWCAP_SSBS, 0) \
|
||||||
|
FEATURE(AARCH64_SB, sb, "sb", AARCH64_HWCAP_SB, 0) \
|
||||||
|
FEATURE(AARCH64_PACA, paca, "paca", AARCH64_HWCAP_PACA, 0) \
|
||||||
|
FEATURE(AARCH64_PACG, pacg, "pacg", AARCH64_HWCAP_PACG, 0) \
|
||||||
|
FEATURE(AARCH64_DCPODP, dcpodp, "dcpodp", 0, AARCH64_HWCAP2_DCPODP) \
|
||||||
|
FEATURE(AARCH64_SVE2, sve2, "sve2", 0, AARCH64_HWCAP2_SVE2) \
|
||||||
|
FEATURE(AARCH64_SVEAES, sveaes, "sveaes", 0, AARCH64_HWCAP2_SVEAES) \
|
||||||
|
FEATURE(AARCH64_SVEPMULL, svepmull, "svepmull", 0, AARCH64_HWCAP2_SVEPMULL) \
|
||||||
|
FEATURE(AARCH64_SVEBITPERM, svebitperm, "svebitperm", 0, \
|
||||||
|
AARCH64_HWCAP2_SVEBITPERM) \
|
||||||
|
FEATURE(AARCH64_SVESHA3, svesha3, "svesha3", 0, AARCH64_HWCAP2_SVESHA3) \
|
||||||
|
FEATURE(AARCH64_SVESM4, svesm4, "svesm4", 0, AARCH64_HWCAP2_SVESM4) \
|
||||||
|
FEATURE(AARCH64_FLAGM2, flagm2, "flagm2", 0, AARCH64_HWCAP2_FLAGM2) \
|
||||||
|
FEATURE(AARCH64_FRINT, frint, "frint", 0, AARCH64_HWCAP2_FRINT) \
|
||||||
|
FEATURE(AARCH64_SVEI8MM, svei8mm, "svei8mm", 0, AARCH64_HWCAP2_SVEI8MM) \
|
||||||
|
FEATURE(AARCH64_SVEF32MM, svef32mm, "svef32mm", 0, AARCH64_HWCAP2_SVEF32MM) \
|
||||||
|
FEATURE(AARCH64_SVEF64MM, svef64mm, "svef64mm", 0, AARCH64_HWCAP2_SVEF64MM) \
|
||||||
|
FEATURE(AARCH64_SVEBF16, svebf16, "svebf16", 0, AARCH64_HWCAP2_SVEBF16) \
|
||||||
|
FEATURE(AARCH64_I8MM, i8mm, "i8mm", 0, AARCH64_HWCAP2_I8MM) \
|
||||||
|
FEATURE(AARCH64_BF16, bf16, "bf16", 0, AARCH64_HWCAP2_BF16) \
|
||||||
|
FEATURE(AARCH64_DGH, dgh, "dgh", 0, AARCH64_HWCAP2_DGH) \
|
||||||
|
FEATURE(AARCH64_RNG, rng, "rng", 0, AARCH64_HWCAP2_RNG) \
|
||||||
|
FEATURE(AARCH64_BTI, bti, "bti", 0, AARCH64_HWCAP2_BTI)
|
||||||
|
#define DEFINE_TABLE_FEATURE_TYPE Aarch64Features
|
||||||
|
#include "define_tables.h"
|
||||||
|
|
||||||
|
static bool HandleAarch64Line(const LineResult result,
|
||||||
|
Aarch64Info* const info) {
|
||||||
|
StringView line = result.line;
|
||||||
|
StringView key, value;
|
||||||
|
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
|
||||||
|
if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
|
||||||
|
for (size_t i = 0; i < AARCH64_LAST_; ++i) {
|
||||||
|
kSetters[i](&info->features,
|
||||||
|
CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i]));
|
||||||
|
}
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
|
||||||
|
info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) {
|
||||||
|
info->variant = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) {
|
||||||
|
info->part = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) {
|
||||||
|
info->revision = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !result.eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FillProcCpuInfoData(Aarch64Info* const info) {
|
||||||
|
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||||
|
if (fd >= 0) {
|
||||||
|
StackLineReader reader;
|
||||||
|
StackLineReader_Initialize(&reader, fd);
|
||||||
|
for (;;) {
|
||||||
|
if (!HandleAarch64Line(StackLineReader_NextLine(&reader), info)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CpuFeatures_CloseFile(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Aarch64Info kEmptyAarch64Info;
|
||||||
|
|
||||||
|
Aarch64Info GetAarch64Info(void) {
|
||||||
|
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
|
||||||
|
// have some information if the executable is sandboxed (aka no access to
|
||||||
|
// /proc/cpuinfo).
|
||||||
|
Aarch64Info info = kEmptyAarch64Info;
|
||||||
|
|
||||||
|
FillProcCpuInfoData(&info);
|
||||||
|
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
|
||||||
|
for (size_t i = 0; i < AARCH64_LAST_; ++i) {
|
||||||
|
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
|
||||||
|
kSetters[i](&info.features, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introspection functions
|
||||||
|
|
||||||
|
int GetAarch64FeaturesEnumValue(const Aarch64Features* features,
|
||||||
|
Aarch64FeaturesEnum value) {
|
||||||
|
if (value >= AARCH64_LAST_) return false;
|
||||||
|
return kGetters[value](features);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum value) {
|
||||||
|
if (value >= AARCH64_LAST_) return "unknown feature";
|
||||||
|
return kCpuInfoFlags[value];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,212 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "cpuinfo_arm.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "internal/bit_utils.h"
|
||||||
|
#include "internal/filesystem.h"
|
||||||
|
#include "internal/hwcaps.h"
|
||||||
|
#include "internal/stack_line_reader.h"
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
// Generation of feature's getters/setters functions and kGetters, kSetters,
|
||||||
|
// kCpuInfoFlags and kHardwareCapabilities global tables.
|
||||||
|
#define DEFINE_TABLE_FEATURES \
|
||||||
|
FEATURE(ARM_SWP, swp, "swp", ARM_HWCAP_SWP, 0) \
|
||||||
|
FEATURE(ARM_HALF, half, "half", ARM_HWCAP_HALF, 0) \
|
||||||
|
FEATURE(ARM_THUMB, thumb, "thumb", ARM_HWCAP_THUMB, 0) \
|
||||||
|
FEATURE(ARM_26BIT, _26bit, "26bit", ARM_HWCAP_26BIT, 0) \
|
||||||
|
FEATURE(ARM_FASTMULT, fastmult, "fastmult", ARM_HWCAP_FAST_MULT, 0) \
|
||||||
|
FEATURE(ARM_FPA, fpa, "fpa", ARM_HWCAP_FPA, 0) \
|
||||||
|
FEATURE(ARM_VFP, vfp, "vfp", ARM_HWCAP_VFP, 0) \
|
||||||
|
FEATURE(ARM_EDSP, edsp, "edsp", ARM_HWCAP_EDSP, 0) \
|
||||||
|
FEATURE(ARM_JAVA, java, "java", ARM_HWCAP_JAVA, 0) \
|
||||||
|
FEATURE(ARM_IWMMXT, iwmmxt, "iwmmxt", ARM_HWCAP_IWMMXT, 0) \
|
||||||
|
FEATURE(ARM_CRUNCH, crunch, "crunch", ARM_HWCAP_CRUNCH, 0) \
|
||||||
|
FEATURE(ARM_THUMBEE, thumbee, "thumbee", ARM_HWCAP_THUMBEE, 0) \
|
||||||
|
FEATURE(ARM_NEON, neon, "neon", ARM_HWCAP_NEON, 0) \
|
||||||
|
FEATURE(ARM_VFPV3, vfpv3, "vfpv3", ARM_HWCAP_VFPV3, 0) \
|
||||||
|
FEATURE(ARM_VFPV3D16, vfpv3d16, "vfpv3d16", ARM_HWCAP_VFPV3D16, 0) \
|
||||||
|
FEATURE(ARM_TLS, tls, "tls", ARM_HWCAP_TLS, 0) \
|
||||||
|
FEATURE(ARM_VFPV4, vfpv4, "vfpv4", ARM_HWCAP_VFPV4, 0) \
|
||||||
|
FEATURE(ARM_IDIVA, idiva, "idiva", ARM_HWCAP_IDIVA, 0) \
|
||||||
|
FEATURE(ARM_IDIVT, idivt, "idivt", ARM_HWCAP_IDIVT, 0) \
|
||||||
|
FEATURE(ARM_VFPD32, vfpd32, "vfpd32", ARM_HWCAP_VFPD32, 0) \
|
||||||
|
FEATURE(ARM_LPAE, lpae, "lpae", ARM_HWCAP_LPAE, 0) \
|
||||||
|
FEATURE(ARM_EVTSTRM, evtstrm, "evtstrm", ARM_HWCAP_EVTSTRM, 0) \
|
||||||
|
FEATURE(ARM_AES, aes, "aes", 0, ARM_HWCAP2_AES) \
|
||||||
|
FEATURE(ARM_PMULL, pmull, "pmull", 0, ARM_HWCAP2_PMULL) \
|
||||||
|
FEATURE(ARM_SHA1, sha1, "sha1", 0, ARM_HWCAP2_SHA1) \
|
||||||
|
FEATURE(ARM_SHA2, sha2, "sha2", 0, ARM_HWCAP2_SHA2) \
|
||||||
|
FEATURE(ARM_CRC32, crc32, "crc32", 0, ARM_HWCAP2_CRC32)
|
||||||
|
#define DEFINE_TABLE_FEATURE_TYPE ArmFeatures
|
||||||
|
#include "define_tables.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool processor_reports_armv6;
|
||||||
|
bool hardware_reports_goldfish;
|
||||||
|
} ProcCpuInfoData;
|
||||||
|
|
||||||
|
static int IndexOfNonDigit(StringView str) {
|
||||||
|
size_t index = 0;
|
||||||
|
while (str.size && isdigit(CpuFeatures_StringView_Front(str))) {
|
||||||
|
str = CpuFeatures_StringView_PopFront(str, 1);
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HandleArmLine(const LineResult result, ArmInfo* const info,
|
||||||
|
ProcCpuInfoData* const proc_info) {
|
||||||
|
StringView line = result.line;
|
||||||
|
StringView key, value;
|
||||||
|
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
|
||||||
|
if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
|
||||||
|
for (size_t i = 0; i < ARM_LAST_; ++i) {
|
||||||
|
kSetters[i](&info->features,
|
||||||
|
CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i]));
|
||||||
|
}
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
|
||||||
|
info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) {
|
||||||
|
info->variant = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) {
|
||||||
|
info->part = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) {
|
||||||
|
info->revision = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU architecture"))) {
|
||||||
|
// CPU architecture is a number that may be followed by letters. e.g.
|
||||||
|
// "6TEJ", "7".
|
||||||
|
const StringView digits =
|
||||||
|
CpuFeatures_StringView_KeepFront(value, IndexOfNonDigit(value));
|
||||||
|
info->architecture = CpuFeatures_StringView_ParsePositiveNumber(digits);
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("Processor")) ||
|
||||||
|
CpuFeatures_StringView_IsEquals(key, str("model name"))) {
|
||||||
|
// Android reports this in a non-Linux standard "Processor" but sometimes
|
||||||
|
// also in "model name", Linux reports it only in "model name"
|
||||||
|
// see RaspberryPiZero (Linux) vs InvalidArmv7 (Android) test-cases
|
||||||
|
proc_info->processor_reports_armv6 =
|
||||||
|
CpuFeatures_StringView_IndexOf(value, str("(v6l)")) >= 0;
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("Hardware"))) {
|
||||||
|
proc_info->hardware_reports_goldfish =
|
||||||
|
CpuFeatures_StringView_IsEquals(value, str("Goldfish"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !result.eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GetArmCpuId(const ArmInfo* const info) {
|
||||||
|
return (ExtractBitRange(info->implementer, 7, 0) << 24) |
|
||||||
|
(ExtractBitRange(info->variant, 3, 0) << 20) |
|
||||||
|
(ExtractBitRange(info->part, 11, 0) << 4) |
|
||||||
|
(ExtractBitRange(info->revision, 3, 0) << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FixErrors(ArmInfo* const info,
|
||||||
|
ProcCpuInfoData* const proc_cpu_info_data) {
|
||||||
|
// Fixing Samsung kernel reporting invalid cpu architecture.
|
||||||
|
// http://code.google.com/p/android/issues/detail?id=10812
|
||||||
|
if (proc_cpu_info_data->processor_reports_armv6 && info->architecture >= 7) {
|
||||||
|
info->architecture = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle kernel configuration bugs that prevent the correct reporting of CPU
|
||||||
|
// features.
|
||||||
|
switch (GetArmCpuId(info)) {
|
||||||
|
case 0x4100C080:
|
||||||
|
// Special case: The emulator-specific Android 4.2 kernel fails to report
|
||||||
|
// support for the 32-bit ARM IDIV instruction. Technically, this is a
|
||||||
|
// feature of the virtual CPU implemented by the emulator. Note that it
|
||||||
|
// could also support Thumb IDIV in the future, and this will have to be
|
||||||
|
// slightly updated.
|
||||||
|
if (info->architecture >= 7 &&
|
||||||
|
proc_cpu_info_data->hardware_reports_goldfish) {
|
||||||
|
info->features.idiva = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x511004D0:
|
||||||
|
// https://crbug.com/341598.
|
||||||
|
info->features.neon = false;
|
||||||
|
break;
|
||||||
|
case 0x510006F2:
|
||||||
|
case 0x510006F3:
|
||||||
|
// The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report
|
||||||
|
// IDIV support.
|
||||||
|
info->features.idiva = true;
|
||||||
|
info->features.idivt = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Propagate cpu features.
|
||||||
|
if (info->features.vfpv4) info->features.vfpv3 = true;
|
||||||
|
if (info->features.neon) info->features.vfpv3 = true;
|
||||||
|
if (info->features.vfpv3) info->features.vfp = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FillProcCpuInfoData(ArmInfo* const info,
|
||||||
|
ProcCpuInfoData* proc_cpu_info_data) {
|
||||||
|
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||||
|
if (fd >= 0) {
|
||||||
|
StackLineReader reader;
|
||||||
|
StackLineReader_Initialize(&reader, fd);
|
||||||
|
for (;;) {
|
||||||
|
if (!HandleArmLine(StackLineReader_NextLine(&reader), info,
|
||||||
|
proc_cpu_info_data)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CpuFeatures_CloseFile(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const ArmInfo kEmptyArmInfo;
|
||||||
|
|
||||||
|
static const ProcCpuInfoData kEmptyProcCpuInfoData;
|
||||||
|
|
||||||
|
ArmInfo GetArmInfo(void) {
|
||||||
|
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
|
||||||
|
// have some information if the executable is sandboxed (aka no access to
|
||||||
|
// /proc/cpuinfo).
|
||||||
|
ArmInfo info = kEmptyArmInfo;
|
||||||
|
ProcCpuInfoData proc_cpu_info_data = kEmptyProcCpuInfoData;
|
||||||
|
|
||||||
|
FillProcCpuInfoData(&info, &proc_cpu_info_data);
|
||||||
|
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
|
||||||
|
for (size_t i = 0; i < ARM_LAST_; ++i) {
|
||||||
|
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
|
||||||
|
kSetters[i](&info.features, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FixErrors(&info, &proc_cpu_info_data);
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introspection functions
|
||||||
|
|
||||||
|
int GetArmFeaturesEnumValue(const ArmFeatures* features,
|
||||||
|
ArmFeaturesEnum value) {
|
||||||
|
if (value >= ARM_LAST_) return false;
|
||||||
|
return kGetters[value](features);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* GetArmFeaturesEnumName(ArmFeaturesEnum value) {
|
||||||
|
if (value >= ARM_LAST_) return "unknown feature";
|
||||||
|
return kCpuInfoFlags[value];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "cpuinfo_mips.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "internal/filesystem.h"
|
||||||
|
#include "internal/hwcaps.h"
|
||||||
|
#include "internal/stack_line_reader.h"
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
// Generation of feature's getters/setters functions and kGetters, kSetters,
|
||||||
|
// kCpuInfoFlags and kHardwareCapabilities global tables.
|
||||||
|
#define DEFINE_TABLE_FEATURES \
|
||||||
|
FEATURE(MIPS_MSA, msa, "msa", MIPS_HWCAP_MSA, 0) \
|
||||||
|
FEATURE(MIPS_EVA, eva, "eva", 0, 0) \
|
||||||
|
FEATURE(MIPS_R6, r6, "r6", MIPS_HWCAP_R6, 0)
|
||||||
|
#define DEFINE_TABLE_FEATURE_TYPE MipsFeatures
|
||||||
|
#include "define_tables.h"
|
||||||
|
|
||||||
|
static bool HandleMipsLine(const LineResult result,
|
||||||
|
MipsFeatures* const features) {
|
||||||
|
StringView key, value;
|
||||||
|
// See tests for an example.
|
||||||
|
if (CpuFeatures_StringView_GetAttributeKeyValue(result.line, &key, &value)) {
|
||||||
|
if (CpuFeatures_StringView_IsEquals(key, str("ASEs implemented"))) {
|
||||||
|
for (size_t i = 0; i < MIPS_LAST_; ++i) {
|
||||||
|
kSetters[i](features,
|
||||||
|
CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !result.eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FillProcCpuInfoData(MipsFeatures* const features) {
|
||||||
|
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||||
|
if (fd >= 0) {
|
||||||
|
StackLineReader reader;
|
||||||
|
StackLineReader_Initialize(&reader, fd);
|
||||||
|
for (;;) {
|
||||||
|
if (!HandleMipsLine(StackLineReader_NextLine(&reader), features)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CpuFeatures_CloseFile(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MipsInfo kEmptyMipsInfo;
|
||||||
|
|
||||||
|
MipsInfo GetMipsInfo(void) {
|
||||||
|
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
|
||||||
|
// have some information if the executable is sandboxed (aka no access to
|
||||||
|
// /proc/cpuinfo).
|
||||||
|
MipsInfo info = kEmptyMipsInfo;
|
||||||
|
|
||||||
|
FillProcCpuInfoData(&info.features);
|
||||||
|
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
|
||||||
|
for (size_t i = 0; i < MIPS_LAST_; ++i) {
|
||||||
|
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
|
||||||
|
kSetters[i](&info.features, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introspection functions
|
||||||
|
|
||||||
|
int GetMipsFeaturesEnumValue(const MipsFeatures* features,
|
||||||
|
MipsFeaturesEnum value) {
|
||||||
|
if (value >= MIPS_LAST_) return false;
|
||||||
|
return kGetters[value](features);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* GetMipsFeaturesEnumName(MipsFeaturesEnum value) {
|
||||||
|
if (value >= MIPS_LAST_) return "unknown feature";
|
||||||
|
return kCpuInfoFlags[value];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,154 @@
|
||||||
|
// Copyright 2018 IBM.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "cpuinfo_ppc.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "internal/bit_utils.h"
|
||||||
|
#include "internal/filesystem.h"
|
||||||
|
#include "internal/stack_line_reader.h"
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
// Generation of feature's getters/setters functions and kGetters, kSetters,
|
||||||
|
// kCpuInfoFlags and kHardwareCapabilities global tables.
|
||||||
|
#define DEFINE_TABLE_FEATURES \
|
||||||
|
FEATURE(PPC_32, ppc32, "ppc32", PPC_FEATURE_32, 0) \
|
||||||
|
FEATURE(PPC_64, ppc64, "ppc64", PPC_FEATURE_64, 0) \
|
||||||
|
FEATURE(PPC_601_INSTR, ppc601, "ppc601", PPC_FEATURE_601_INSTR, 0) \
|
||||||
|
FEATURE(PPC_HAS_ALTIVEC, altivec, "altivec", PPC_FEATURE_HAS_ALTIVEC, 0) \
|
||||||
|
FEATURE(PPC_HAS_FPU, fpu, "fpu", PPC_FEATURE_HAS_FPU, 0) \
|
||||||
|
FEATURE(PPC_HAS_MMU, mmu, "mmu", PPC_FEATURE_HAS_MMU, 0) \
|
||||||
|
FEATURE(PPC_HAS_4xxMAC, mac_4xx, "4xxmac", PPC_FEATURE_HAS_4xxMAC, 0) \
|
||||||
|
FEATURE(PPC_UNIFIED_CACHE, unifiedcache, "ucache", \
|
||||||
|
PPC_FEATURE_UNIFIED_CACHE, 0) \
|
||||||
|
FEATURE(PPC_HAS_SPE, spe, "spe", PPC_FEATURE_HAS_SPE, 0) \
|
||||||
|
FEATURE(PPC_HAS_EFP_SINGLE, efpsingle, "efpsingle", \
|
||||||
|
PPC_FEATURE_HAS_EFP_SINGLE, 0) \
|
||||||
|
FEATURE(PPC_HAS_EFP_DOUBLE, efpdouble, "efpdouble", \
|
||||||
|
PPC_FEATURE_HAS_EFP_DOUBLE, 0) \
|
||||||
|
FEATURE(PPC_NO_TB, no_tb, "notb", PPC_FEATURE_NO_TB, 0) \
|
||||||
|
FEATURE(PPC_POWER4, power4, "power4", PPC_FEATURE_POWER4, 0) \
|
||||||
|
FEATURE(PPC_POWER5, power5, "power5", PPC_FEATURE_POWER5, 0) \
|
||||||
|
FEATURE(PPC_POWER5_PLUS, power5plus, "power5+", PPC_FEATURE_POWER5_PLUS, 0) \
|
||||||
|
FEATURE(PPC_CELL, cell, "cellbe", PPC_FEATURE_CELL, 0) \
|
||||||
|
FEATURE(PPC_BOOKE, booke, "booke", PPC_FEATURE_BOOKE, 0) \
|
||||||
|
FEATURE(PPC_SMT, smt, "smt", PPC_FEATURE_SMT, 0) \
|
||||||
|
FEATURE(PPC_ICACHE_SNOOP, icachesnoop, "ic_snoop", PPC_FEATURE_ICACHE_SNOOP, \
|
||||||
|
0) \
|
||||||
|
FEATURE(PPC_ARCH_2_05, arch205, "arch_2_05", PPC_FEATURE_ARCH_2_05, 0) \
|
||||||
|
FEATURE(PPC_PA6T, pa6t, "pa6t", PPC_FEATURE_PA6T, 0) \
|
||||||
|
FEATURE(PPC_HAS_DFP, dfp, "dfp", PPC_FEATURE_HAS_DFP, 0) \
|
||||||
|
FEATURE(PPC_POWER6_EXT, power6ext, "power6x", PPC_FEATURE_POWER6_EXT, 0) \
|
||||||
|
FEATURE(PPC_ARCH_2_06, arch206, "arch_2_06", PPC_FEATURE_ARCH_2_06, 0) \
|
||||||
|
FEATURE(PPC_HAS_VSX, vsx, "vsx", PPC_FEATURE_HAS_VSX, 0) \
|
||||||
|
FEATURE(PPC_PSERIES_PERFMON_COMPAT, pseries_perfmon_compat, "archpmu", \
|
||||||
|
PPC_FEATURE_PSERIES_PERFMON_COMPAT, 0) \
|
||||||
|
FEATURE(PPC_TRUE_LE, truele, "true_le", PPC_FEATURE_TRUE_LE, 0) \
|
||||||
|
FEATURE(PPC_PPC_LE, ppcle, "ppcle", PPC_FEATURE_PPC_LE, 0) \
|
||||||
|
FEATURE(PPC_ARCH_2_07, arch207, "arch_2_07", 0, PPC_FEATURE2_ARCH_2_07) \
|
||||||
|
FEATURE(PPC_HTM, htm, "htm", 0, PPC_FEATURE2_HTM) \
|
||||||
|
FEATURE(PPC_DSCR, dscr, "dscr", 0, PPC_FEATURE2_DSCR) \
|
||||||
|
FEATURE(PPC_EBB, ebb, "ebb", 0, PPC_FEATURE2_EBB) \
|
||||||
|
FEATURE(PPC_ISEL, isel, "isel", 0, PPC_FEATURE2_ISEL) \
|
||||||
|
FEATURE(PPC_TAR, tar, "tar", 0, PPC_FEATURE2_TAR) \
|
||||||
|
FEATURE(PPC_VEC_CRYPTO, vcrypto, "vcrypto", 0, PPC_FEATURE2_VEC_CRYPTO) \
|
||||||
|
FEATURE(PPC_HTM_NOSC, htm_nosc, "htm-nosc", 0, PPC_FEATURE2_HTM_NOSC) \
|
||||||
|
FEATURE(PPC_ARCH_3_00, arch300, "arch_3_00", 0, PPC_FEATURE2_ARCH_3_00) \
|
||||||
|
FEATURE(PPC_HAS_IEEE128, ieee128, "ieee128", 0, PPC_FEATURE2_HAS_IEEE128) \
|
||||||
|
FEATURE(PPC_DARN, darn, "darn", 0, PPC_FEATURE2_DARN) \
|
||||||
|
FEATURE(PPC_SCV, scv, "scv", 0, PPC_FEATURE2_SCV) \
|
||||||
|
FEATURE(PPC_HTM_NO_SUSPEND, htm_no_suspend, "htm-no-suspend", 0, \
|
||||||
|
PPC_FEATURE2_HTM_NO_SUSPEND)
|
||||||
|
#define DEFINE_TABLE_FEATURE_TYPE PPCFeatures
|
||||||
|
#include "define_tables.h"
|
||||||
|
|
||||||
|
static bool HandlePPCLine(const LineResult result,
|
||||||
|
PPCPlatformStrings* const strings) {
|
||||||
|
StringView line = result.line;
|
||||||
|
StringView key, value;
|
||||||
|
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
|
||||||
|
if (CpuFeatures_StringView_HasWord(key, "platform")) {
|
||||||
|
CpuFeatures_StringView_CopyString(value, strings->platform,
|
||||||
|
sizeof(strings->platform));
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("model"))) {
|
||||||
|
CpuFeatures_StringView_CopyString(value, strings->model,
|
||||||
|
sizeof(strings->platform));
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("machine"))) {
|
||||||
|
CpuFeatures_StringView_CopyString(value, strings->machine,
|
||||||
|
sizeof(strings->platform));
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("cpu"))) {
|
||||||
|
CpuFeatures_StringView_CopyString(value, strings->cpu,
|
||||||
|
sizeof(strings->platform));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !result.eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FillProcCpuInfoData(PPCPlatformStrings* const strings) {
|
||||||
|
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||||
|
if (fd >= 0) {
|
||||||
|
StackLineReader reader;
|
||||||
|
StackLineReader_Initialize(&reader, fd);
|
||||||
|
for (;;) {
|
||||||
|
if (!HandlePPCLine(StackLineReader_NextLine(&reader), strings)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CpuFeatures_CloseFile(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const PPCInfo kEmptyPPCInfo;
|
||||||
|
|
||||||
|
PPCInfo GetPPCInfo(void) {
|
||||||
|
/*
|
||||||
|
* On Power feature flags aren't currently in cpuinfo so we only look at
|
||||||
|
* the auxilary vector.
|
||||||
|
*/
|
||||||
|
PPCInfo info = kEmptyPPCInfo;
|
||||||
|
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
|
||||||
|
for (size_t i = 0; i < PPC_LAST_; ++i) {
|
||||||
|
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
|
||||||
|
kSetters[i](&info.features, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const PPCPlatformStrings kEmptyPPCPlatformStrings;
|
||||||
|
|
||||||
|
PPCPlatformStrings GetPPCPlatformStrings(void) {
|
||||||
|
PPCPlatformStrings strings = kEmptyPPCPlatformStrings;
|
||||||
|
|
||||||
|
FillProcCpuInfoData(&strings);
|
||||||
|
strings.type = CpuFeatures_GetPlatformType();
|
||||||
|
return strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introspection functions
|
||||||
|
|
||||||
|
int GetPPCFeaturesEnumValue(const PPCFeatures* features,
|
||||||
|
PPCFeaturesEnum value) {
|
||||||
|
if (value >= PPC_LAST_) return false;
|
||||||
|
return kGetters[value](features);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* GetPPCFeaturesEnumName(PPCFeaturesEnum value) {
|
||||||
|
if (value >= PPC_LAST_) return "unknown feature";
|
||||||
|
return kCpuInfoFlags[value];
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,67 @@
|
||||||
|
// Copyright 2020 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// The following preprocessor constants must be defined before including this
|
||||||
|
// file:
|
||||||
|
// - DEFINE_TABLE_FEATURE_TYPE, the underlying type (e.g. X86Features)
|
||||||
|
// - DEFINE_TABLE_FEATURES, the list of FEATURE macros to be inserted.
|
||||||
|
|
||||||
|
// This file is to be included once per `cpuinfo_XXX.c` in order to construct
|
||||||
|
// feature getters and setters functions as well as several enum indexed tables
|
||||||
|
// from the db file.
|
||||||
|
// - `kGetters` a table of getters function pointers from feature enum to
|
||||||
|
// retrieve a feature,
|
||||||
|
// - `kSetters` a table of setters function pointers from feature enum to set a
|
||||||
|
// feature,
|
||||||
|
// - `kCpuInfoFlags` a table of strings from feature enum to /proc/cpuinfo
|
||||||
|
// flags,
|
||||||
|
// - `kHardwareCapabilities` a table of HardwareCapabilities structs indexed by
|
||||||
|
// their feature enum.
|
||||||
|
|
||||||
|
#ifndef SRC_DEFINE_TABLES_H_
|
||||||
|
#define SRC_DEFINE_TABLES_H_
|
||||||
|
|
||||||
|
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = CPUINFO_FLAG,
|
||||||
|
static const char* kCpuInfoFlags[] = {DEFINE_TABLE_FEATURES};
|
||||||
|
#undef FEATURE
|
||||||
|
|
||||||
|
#ifndef DEFINE_TABLE_DONT_GENERATE_HWCAPS
|
||||||
|
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) \
|
||||||
|
[ENUM] = (HardwareCapabilities){HWCAP, HWCAP2},
|
||||||
|
static const HardwareCapabilities kHardwareCapabilities[] = {
|
||||||
|
DEFINE_TABLE_FEATURES};
|
||||||
|
#undef FEATURE
|
||||||
|
#endif // DEFINE_TABLE_DONT_GENERATE_HWCAPS
|
||||||
|
|
||||||
|
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) \
|
||||||
|
static void set_##ENUM(DEFINE_TABLE_FEATURE_TYPE* features, bool value) { \
|
||||||
|
features->NAME = value; \
|
||||||
|
} \
|
||||||
|
static int get_##ENUM(const DEFINE_TABLE_FEATURE_TYPE* features) { \
|
||||||
|
return features->NAME; \
|
||||||
|
}
|
||||||
|
DEFINE_TABLE_FEATURES
|
||||||
|
#undef FEATURE
|
||||||
|
|
||||||
|
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = set_##ENUM,
|
||||||
|
static void (*const kSetters[])(DEFINE_TABLE_FEATURE_TYPE*,
|
||||||
|
bool) = {DEFINE_TABLE_FEATURES};
|
||||||
|
#undef FEATURE
|
||||||
|
|
||||||
|
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = get_##ENUM,
|
||||||
|
static int (*const kGetters[])(const DEFINE_TABLE_FEATURE_TYPE*) = {
|
||||||
|
DEFINE_TABLE_FEATURES};
|
||||||
|
#undef FEATURE
|
||||||
|
|
||||||
|
#endif // SRC_DEFINE_TABLES_H_
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "internal/filesystem.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_MOCK_FILESYSTEM)
|
||||||
|
// Implementation will be provided by test/filesystem_for_testing.cc.
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#include <io.h>
|
||||||
|
int CpuFeatures_OpenFile(const char* filename) {
|
||||||
|
int fd = -1;
|
||||||
|
_sopen_s(&fd, filename, _O_RDONLY, _SH_DENYWR, _S_IREAD);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CpuFeatures_CloseFile(int file_descriptor) { _close(file_descriptor); }
|
||||||
|
|
||||||
|
int CpuFeatures_ReadFile(int file_descriptor, void* buffer,
|
||||||
|
size_t buffer_size) {
|
||||||
|
return _read(file_descriptor, buffer, (unsigned int)buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int CpuFeatures_OpenFile(const char* filename) {
|
||||||
|
int result;
|
||||||
|
do {
|
||||||
|
result = open(filename, O_RDONLY);
|
||||||
|
} while (result == -1L && errno == EINTR);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CpuFeatures_CloseFile(int file_descriptor) { close(file_descriptor); }
|
||||||
|
|
||||||
|
int CpuFeatures_ReadFile(int file_descriptor, void* buffer,
|
||||||
|
size_t buffer_size) {
|
||||||
|
int result;
|
||||||
|
do {
|
||||||
|
result = read(file_descriptor, buffer, buffer_size);
|
||||||
|
} while (result == -1L && errno == EINTR);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,182 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "internal/hwcaps.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
#include "internal/filesystem.h"
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
static bool IsSet(const uint32_t mask, const uint32_t value) {
|
||||||
|
if (mask == 0) return false;
|
||||||
|
return (value & mask) == mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask,
|
||||||
|
const HardwareCapabilities hwcaps) {
|
||||||
|
return IsSet(hwcaps_mask.hwcaps, hwcaps.hwcaps) ||
|
||||||
|
IsSet(hwcaps_mask.hwcaps2, hwcaps.hwcaps2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CPU_FEATURES_TEST
|
||||||
|
// In test mode, hwcaps_for_testing will define the following functions.
|
||||||
|
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void);
|
||||||
|
PlatformType CpuFeatures_GetPlatformType(void);
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Debug facilities
|
||||||
|
#if defined(NDEBUG)
|
||||||
|
#define D(...)
|
||||||
|
#else
|
||||||
|
#include <stdio.h>
|
||||||
|
#define D(...) \
|
||||||
|
do { \
|
||||||
|
printf(__VA_ARGS__); \
|
||||||
|
fflush(stdout); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Implementation of GetElfHwcapFromGetauxval
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define AT_HWCAP 16
|
||||||
|
#define AT_HWCAP2 26
|
||||||
|
#define AT_PLATFORM 15
|
||||||
|
#define AT_BASE_PLATFORM 24
|
||||||
|
|
||||||
|
#if defined(HAVE_STRONG_GETAUXVAL)
|
||||||
|
#include <sys/auxv.h>
|
||||||
|
static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
|
||||||
|
return getauxval(hwcap_type);
|
||||||
|
}
|
||||||
|
#elif defined(HAVE_DLFCN_H)
|
||||||
|
// On Android we probe the system's C library for a 'getauxval' function and
|
||||||
|
// call it if it exits, or return 0 for failure. This function is available
|
||||||
|
// since API level 20.
|
||||||
|
//
|
||||||
|
// This code does *NOT* check for '__ANDROID_API__ >= 20' to support the edge
|
||||||
|
// case where some NDK developers use headers for a platform that is newer than
|
||||||
|
// the one really targetted by their application. This is typically done to use
|
||||||
|
// newer native APIs only when running on more recent Android versions, and
|
||||||
|
// requires careful symbol management.
|
||||||
|
//
|
||||||
|
// Note that getauxval() can't really be re-implemented here, because its
|
||||||
|
// implementation does not parse /proc/self/auxv. Instead it depends on values
|
||||||
|
// that are passed by the kernel at process-init time to the C runtime
|
||||||
|
// initialization layer.
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
typedef unsigned long getauxval_func_t(unsigned long);
|
||||||
|
|
||||||
|
static uint32_t GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
|
||||||
|
uint32_t ret = 0;
|
||||||
|
void *libc_handle = NULL;
|
||||||
|
getauxval_func_t *func = NULL;
|
||||||
|
|
||||||
|
dlerror(); // Cleaning error state before calling dlopen.
|
||||||
|
libc_handle = dlopen("libc.so", RTLD_NOW);
|
||||||
|
if (!libc_handle) {
|
||||||
|
D("Could not dlopen() C library: %s\n", dlerror());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
func = (getauxval_func_t *)dlsym(libc_handle, "getauxval");
|
||||||
|
if (!func) {
|
||||||
|
D("Could not find getauxval() in C library\n");
|
||||||
|
} else {
|
||||||
|
// Note: getauxval() returns 0 on failure. Doesn't touch errno.
|
||||||
|
ret = (uint32_t)(*func)(hwcap_type);
|
||||||
|
}
|
||||||
|
dlclose(libc_handle);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error "This platform does not provide hardware capabilities."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Implementation of GetHardwareCapabilities for OS that provide
|
||||||
|
// GetElfHwcapFromGetauxval().
|
||||||
|
|
||||||
|
// Fallback when getauxval is not available, retrieves hwcaps from
|
||||||
|
// "/proc/self/auxv".
|
||||||
|
static uint32_t GetElfHwcapFromProcSelfAuxv(uint32_t hwcap_type) {
|
||||||
|
struct {
|
||||||
|
uint32_t tag;
|
||||||
|
uint32_t value;
|
||||||
|
} entry;
|
||||||
|
uint32_t result = 0;
|
||||||
|
const char filepath[] = "/proc/self/auxv";
|
||||||
|
const int fd = CpuFeatures_OpenFile(filepath);
|
||||||
|
if (fd < 0) {
|
||||||
|
D("Could not open %s\n", filepath);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
const int ret = CpuFeatures_ReadFile(fd, (char *)&entry, sizeof entry);
|
||||||
|
if (ret < 0) {
|
||||||
|
D("Error while reading %s\n", filepath);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Detect end of list.
|
||||||
|
if (ret == 0 || (entry.tag == 0 && entry.value == 0)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (entry.tag == hwcap_type) {
|
||||||
|
result = entry.value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CpuFeatures_CloseFile(fd);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieves hardware capabilities by first trying to call getauxval, if not
|
||||||
|
// available falls back to reading "/proc/self/auxv".
|
||||||
|
static unsigned long GetHardwareCapabilitiesFor(uint32_t type) {
|
||||||
|
unsigned long hwcaps = GetElfHwcapFromGetauxval(type);
|
||||||
|
if (!hwcaps) {
|
||||||
|
D("Parsing /proc/self/auxv to extract ELF hwcaps!\n");
|
||||||
|
hwcaps = GetElfHwcapFromProcSelfAuxv(type);
|
||||||
|
}
|
||||||
|
return hwcaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) {
|
||||||
|
HardwareCapabilities capabilities;
|
||||||
|
capabilities.hwcaps = GetHardwareCapabilitiesFor(AT_HWCAP);
|
||||||
|
capabilities.hwcaps2 = GetHardwareCapabilitiesFor(AT_HWCAP2);
|
||||||
|
return capabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlatformType kEmptyPlatformType;
|
||||||
|
|
||||||
|
PlatformType CpuFeatures_GetPlatformType(void) {
|
||||||
|
PlatformType type = kEmptyPlatformType;
|
||||||
|
char *platform = (char *)GetHardwareCapabilitiesFor(AT_PLATFORM);
|
||||||
|
char *base_platform = (char *)GetHardwareCapabilitiesFor(AT_BASE_PLATFORM);
|
||||||
|
|
||||||
|
if (platform != NULL)
|
||||||
|
CpuFeatures_StringView_CopyString(str(platform), type.platform,
|
||||||
|
sizeof(type.platform));
|
||||||
|
if (base_platform != NULL)
|
||||||
|
CpuFeatures_StringView_CopyString(str(base_platform), type.base_platform,
|
||||||
|
sizeof(type.base_platform));
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_TEST
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "internal/stack_line_reader.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "internal/filesystem.h"
|
||||||
|
|
||||||
|
void StackLineReader_Initialize(StackLineReader* reader, int fd) {
|
||||||
|
reader->view.ptr = reader->buffer;
|
||||||
|
reader->view.size = 0;
|
||||||
|
reader->skip_mode = false;
|
||||||
|
reader->fd = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replaces the content of buffer with bytes from the file.
|
||||||
|
static int LoadFullBuffer(StackLineReader* reader) {
|
||||||
|
const int read = CpuFeatures_ReadFile(reader->fd, reader->buffer,
|
||||||
|
STACK_LINE_READER_BUFFER_SIZE);
|
||||||
|
assert(read >= 0);
|
||||||
|
reader->view.ptr = reader->buffer;
|
||||||
|
reader->view.size = read;
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appends with bytes from the file to buffer, filling the remaining space.
|
||||||
|
static int LoadMore(StackLineReader* reader) {
|
||||||
|
char* const ptr = reader->buffer + reader->view.size;
|
||||||
|
const size_t size_to_read = STACK_LINE_READER_BUFFER_SIZE - reader->view.size;
|
||||||
|
const int read = CpuFeatures_ReadFile(reader->fd, ptr, size_to_read);
|
||||||
|
assert(read >= 0);
|
||||||
|
assert(read <= (int)size_to_read);
|
||||||
|
reader->view.size += read;
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int IndexOfEol(StackLineReader* reader) {
|
||||||
|
return CpuFeatures_StringView_IndexOfChar(reader->view, '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relocate buffer's pending bytes at the beginning of the array and fills the
|
||||||
|
// remaining space with bytes from the file.
|
||||||
|
static int BringToFrontAndLoadMore(StackLineReader* reader) {
|
||||||
|
if (reader->view.size && reader->view.ptr != reader->buffer) {
|
||||||
|
memmove(reader->buffer, reader->view.ptr, reader->view.size);
|
||||||
|
}
|
||||||
|
reader->view.ptr = reader->buffer;
|
||||||
|
return LoadMore(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loads chunks of buffer size from disks until it contains a newline character
|
||||||
|
// or end of file.
|
||||||
|
static void SkipToNextLine(StackLineReader* reader) {
|
||||||
|
for (;;) {
|
||||||
|
const int read = LoadFullBuffer(reader);
|
||||||
|
if (read == 0) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
const int eol_index = IndexOfEol(reader);
|
||||||
|
if (eol_index >= 0) {
|
||||||
|
reader->view =
|
||||||
|
CpuFeatures_StringView_PopFront(reader->view, eol_index + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static LineResult CreateLineResult(bool eof, bool full_line, StringView view) {
|
||||||
|
LineResult result;
|
||||||
|
result.eof = eof;
|
||||||
|
result.full_line = full_line;
|
||||||
|
result.line = view;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper methods to provide clearer semantic in StackLineReader_NextLine.
|
||||||
|
static LineResult CreateEOFLineResult(StringView view) {
|
||||||
|
return CreateLineResult(true, true, view);
|
||||||
|
}
|
||||||
|
|
||||||
|
static LineResult CreateTruncatedLineResult(StringView view) {
|
||||||
|
return CreateLineResult(false, false, view);
|
||||||
|
}
|
||||||
|
|
||||||
|
static LineResult CreateValidLineResult(StringView view) {
|
||||||
|
return CreateLineResult(false, true, view);
|
||||||
|
}
|
||||||
|
|
||||||
|
LineResult StackLineReader_NextLine(StackLineReader* reader) {
|
||||||
|
if (reader->skip_mode) {
|
||||||
|
SkipToNextLine(reader);
|
||||||
|
reader->skip_mode = false;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const bool can_load_more =
|
||||||
|
reader->view.size < STACK_LINE_READER_BUFFER_SIZE;
|
||||||
|
int eol_index = IndexOfEol(reader);
|
||||||
|
if (eol_index < 0 && can_load_more) {
|
||||||
|
const int read = BringToFrontAndLoadMore(reader);
|
||||||
|
if (read == 0) {
|
||||||
|
return CreateEOFLineResult(reader->view);
|
||||||
|
}
|
||||||
|
eol_index = IndexOfEol(reader);
|
||||||
|
}
|
||||||
|
if (eol_index < 0) {
|
||||||
|
reader->skip_mode = true;
|
||||||
|
return CreateTruncatedLineResult(reader->view);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
StringView line =
|
||||||
|
CpuFeatures_StringView_KeepFront(reader->view, eol_index);
|
||||||
|
reader->view =
|
||||||
|
CpuFeatures_StringView_PopFront(reader->view, eol_index + 1);
|
||||||
|
return CreateValidLineResult(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,182 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int CpuFeatures_StringView_IndexOfChar(const StringView view, char c) {
|
||||||
|
if (view.ptr && view.size) {
|
||||||
|
const char* const found = (const char*)memchr(view.ptr, c, view.size);
|
||||||
|
if (found) {
|
||||||
|
return (int)(found - view.ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CpuFeatures_StringView_IndexOf(const StringView view,
|
||||||
|
const StringView sub_view) {
|
||||||
|
if (sub_view.size) {
|
||||||
|
StringView remainder = view;
|
||||||
|
while (remainder.size >= sub_view.size) {
|
||||||
|
const int found_index =
|
||||||
|
CpuFeatures_StringView_IndexOfChar(remainder, sub_view.ptr[0]);
|
||||||
|
if (found_index < 0) break;
|
||||||
|
remainder = CpuFeatures_StringView_PopFront(remainder, found_index);
|
||||||
|
if (CpuFeatures_StringView_StartsWith(remainder, sub_view)) {
|
||||||
|
return (int)(remainder.ptr - view.ptr);
|
||||||
|
}
|
||||||
|
remainder = CpuFeatures_StringView_PopFront(remainder, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CpuFeatures_StringView_IsEquals(const StringView a, const StringView b) {
|
||||||
|
if (a.size == b.size) {
|
||||||
|
return a.ptr == b.ptr || memcmp(a.ptr, b.ptr, b.size) == 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CpuFeatures_StringView_StartsWith(const StringView a, const StringView b) {
|
||||||
|
return a.ptr && b.ptr && b.size && a.size >= b.size
|
||||||
|
? memcmp(a.ptr, b.ptr, b.size) == 0
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringView CpuFeatures_StringView_PopFront(const StringView str_view,
|
||||||
|
size_t count) {
|
||||||
|
if (count > str_view.size) {
|
||||||
|
return kEmptyStringView;
|
||||||
|
}
|
||||||
|
return view(str_view.ptr + count, str_view.size - count);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringView CpuFeatures_StringView_PopBack(const StringView str_view,
|
||||||
|
size_t count) {
|
||||||
|
if (count > str_view.size) {
|
||||||
|
return kEmptyStringView;
|
||||||
|
}
|
||||||
|
return view(str_view.ptr, str_view.size - count);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringView CpuFeatures_StringView_KeepFront(const StringView str_view,
|
||||||
|
size_t count) {
|
||||||
|
return count <= str_view.size ? view(str_view.ptr, count) : str_view;
|
||||||
|
}
|
||||||
|
|
||||||
|
char CpuFeatures_StringView_Front(const StringView view) {
|
||||||
|
assert(view.size);
|
||||||
|
assert(view.ptr);
|
||||||
|
return view.ptr[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
char CpuFeatures_StringView_Back(const StringView view) {
|
||||||
|
assert(view.size);
|
||||||
|
return view.ptr[view.size - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
StringView CpuFeatures_StringView_TrimWhitespace(StringView view) {
|
||||||
|
while (view.size && isspace(CpuFeatures_StringView_Front(view)))
|
||||||
|
view = CpuFeatures_StringView_PopFront(view, 1);
|
||||||
|
while (view.size && isspace(CpuFeatures_StringView_Back(view)))
|
||||||
|
view = CpuFeatures_StringView_PopBack(view, 1);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int HexValue(const char c) {
|
||||||
|
if (c >= '0' && c <= '9') return c - '0';
|
||||||
|
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||||
|
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns -1 if view contains non digits.
|
||||||
|
static int ParsePositiveNumberWithBase(const StringView view, int base) {
|
||||||
|
int result = 0;
|
||||||
|
StringView remainder = view;
|
||||||
|
for (; remainder.size;
|
||||||
|
remainder = CpuFeatures_StringView_PopFront(remainder, 1)) {
|
||||||
|
const int value = HexValue(CpuFeatures_StringView_Front(remainder));
|
||||||
|
if (value < 0 || value >= base) return -1;
|
||||||
|
result = (result * base) + value;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CpuFeatures_StringView_ParsePositiveNumber(const StringView view) {
|
||||||
|
if (view.size) {
|
||||||
|
const StringView hex_prefix = str("0x");
|
||||||
|
if (CpuFeatures_StringView_StartsWith(view, hex_prefix)) {
|
||||||
|
const StringView span_no_prefix =
|
||||||
|
CpuFeatures_StringView_PopFront(view, hex_prefix.size);
|
||||||
|
return ParsePositiveNumberWithBase(span_no_prefix, 16);
|
||||||
|
}
|
||||||
|
return ParsePositiveNumberWithBase(view, 10);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
|
||||||
|
size_t dst_size) {
|
||||||
|
if (dst_size > 0) {
|
||||||
|
const size_t max_copy_size = dst_size - 1;
|
||||||
|
const size_t copy_size =
|
||||||
|
src.size > max_copy_size ? max_copy_size : src.size;
|
||||||
|
memcpy(dst, src.ptr, copy_size);
|
||||||
|
dst[copy_size] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CpuFeatures_StringView_HasWord(const StringView line,
|
||||||
|
const char* const word_str) {
|
||||||
|
const StringView word = str(word_str);
|
||||||
|
StringView remainder = line;
|
||||||
|
for (;;) {
|
||||||
|
const int index_of_word = CpuFeatures_StringView_IndexOf(remainder, word);
|
||||||
|
if (index_of_word < 0) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
const StringView before =
|
||||||
|
CpuFeatures_StringView_KeepFront(line, index_of_word);
|
||||||
|
const StringView after =
|
||||||
|
CpuFeatures_StringView_PopFront(line, index_of_word + word.size);
|
||||||
|
const bool valid_before =
|
||||||
|
before.size == 0 || CpuFeatures_StringView_Back(before) == ' ';
|
||||||
|
const bool valid_after =
|
||||||
|
after.size == 0 || CpuFeatures_StringView_Front(after) == ' ';
|
||||||
|
if (valid_before && valid_after) return true;
|
||||||
|
remainder =
|
||||||
|
CpuFeatures_StringView_PopFront(remainder, index_of_word + word.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CpuFeatures_StringView_GetAttributeKeyValue(const StringView line,
|
||||||
|
StringView* key,
|
||||||
|
StringView* value) {
|
||||||
|
const StringView sep = str(": ");
|
||||||
|
const int index_of_separator = CpuFeatures_StringView_IndexOf(line, sep);
|
||||||
|
if (index_of_separator < 0) return false;
|
||||||
|
*value = CpuFeatures_StringView_TrimWhitespace(
|
||||||
|
CpuFeatures_StringView_PopFront(line, index_of_separator + sep.size));
|
||||||
|
*key = CpuFeatures_StringView_TrimWhitespace(
|
||||||
|
CpuFeatures_StringView_KeepFront(line, index_of_separator));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,438 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// This program dumps current host data to the standard output.
|
||||||
|
// Output can be text or json if the `--json` flag is passed.
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_ARCH_X86)
|
||||||
|
#include "cpuinfo_x86.h"
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_ARM)
|
||||||
|
#include "cpuinfo_arm.h"
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||||
|
#include "cpuinfo_aarch64.h"
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_MIPS)
|
||||||
|
#include "cpuinfo_mips.h"
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_PPC)
|
||||||
|
#include "cpuinfo_ppc.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Design principles
|
||||||
|
// -----------------
|
||||||
|
// We build a tree structure containing all the data to be displayed.
|
||||||
|
// Then depending on the output type (text or json) we walk the tree and display
|
||||||
|
// the data accordingly.
|
||||||
|
|
||||||
|
// We use a bump allocator to allocate strings and nodes of the tree,
|
||||||
|
// Memory is not intended to be reclaimed.
|
||||||
|
typedef struct {
|
||||||
|
char* ptr;
|
||||||
|
size_t size;
|
||||||
|
} BumpAllocator;
|
||||||
|
|
||||||
|
char gGlobalBuffer[64 * 1024];
|
||||||
|
BumpAllocator gBumpAllocator = {.ptr = gGlobalBuffer,
|
||||||
|
.size = sizeof(gGlobalBuffer)};
|
||||||
|
|
||||||
|
static void internal_error() {
|
||||||
|
fputs("internal error\n", stderr);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ALIGN 8
|
||||||
|
|
||||||
|
static void assertAligned() {
|
||||||
|
if ((uintptr_t)(gBumpAllocator.ptr) % ALIGN) internal_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void BA_Align() {
|
||||||
|
while (gBumpAllocator.size && (uintptr_t)(gBumpAllocator.ptr) % ALIGN) {
|
||||||
|
--gBumpAllocator.size;
|
||||||
|
++gBumpAllocator.ptr;
|
||||||
|
}
|
||||||
|
assertAligned();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the available memory left in the BumpAllocator.
|
||||||
|
static void* BA_Bump(size_t size) {
|
||||||
|
assertAligned();
|
||||||
|
// Align size to next 8B boundary.
|
||||||
|
size = (size + ALIGN - 1) / ALIGN * ALIGN;
|
||||||
|
if (gBumpAllocator.size < size) internal_error();
|
||||||
|
void* ptr = gBumpAllocator.ptr;
|
||||||
|
gBumpAllocator.size -= size;
|
||||||
|
gBumpAllocator.ptr += size;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The type of the nodes in the tree.
|
||||||
|
typedef enum {
|
||||||
|
NT_INVALID,
|
||||||
|
NT_INT,
|
||||||
|
NT_MAP,
|
||||||
|
NT_MAP_ENTRY,
|
||||||
|
NT_ARRAY,
|
||||||
|
NT_ARRAY_ELEMENT,
|
||||||
|
NT_STRING,
|
||||||
|
} NodeType;
|
||||||
|
|
||||||
|
// The node in the tree.
|
||||||
|
typedef struct Node {
|
||||||
|
NodeType type;
|
||||||
|
unsigned integer;
|
||||||
|
const char* string;
|
||||||
|
struct Node* value;
|
||||||
|
struct Node* next;
|
||||||
|
} Node;
|
||||||
|
|
||||||
|
// Creates an initialized Node.
|
||||||
|
static Node* BA_CreateNode(NodeType type) {
|
||||||
|
Node* tv = (Node*)BA_Bump(sizeof(Node));
|
||||||
|
assert(tv);
|
||||||
|
*tv = (Node){.type = type};
|
||||||
|
return tv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds an integer node.
|
||||||
|
static Node* CreateInt(int value) {
|
||||||
|
Node* tv = BA_CreateNode(NT_INT);
|
||||||
|
tv->integer = value;
|
||||||
|
return tv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a string node.
|
||||||
|
// `value` must outlive the tree.
|
||||||
|
static Node* CreateConstantString(const char* value) {
|
||||||
|
Node* tv = BA_CreateNode(NT_STRING);
|
||||||
|
tv->string = value;
|
||||||
|
return tv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a map node.
|
||||||
|
static Node* CreateMap() { return BA_CreateNode(NT_MAP); }
|
||||||
|
|
||||||
|
// Adds an array node.
|
||||||
|
static Node* CreateArray() { return BA_CreateNode(NT_ARRAY); }
|
||||||
|
|
||||||
|
// Adds a formatted string node.
|
||||||
|
static Node* CreatePrintfString(const char* format, ...) {
|
||||||
|
va_list arglist;
|
||||||
|
va_start(arglist, format);
|
||||||
|
char* const ptr = gBumpAllocator.ptr;
|
||||||
|
const int written = vsnprintf(ptr, gBumpAllocator.size, format, arglist);
|
||||||
|
va_end(arglist);
|
||||||
|
if (written < 0 || written >= (int)gBumpAllocator.size) internal_error();
|
||||||
|
return CreateConstantString((char*)BA_Bump(written));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a string node.
|
||||||
|
static Node* CreateString(const char* value) {
|
||||||
|
return CreatePrintfString("%s", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a map entry node.
|
||||||
|
static void AddMapEntry(Node* map, const char* key, Node* value) {
|
||||||
|
assert(map && map->type == NT_MAP);
|
||||||
|
Node* current = map;
|
||||||
|
while (current->next) current = current->next;
|
||||||
|
current->next = (Node*)BA_Bump(sizeof(Node));
|
||||||
|
*current->next = (Node){.type = NT_MAP_ENTRY, .string = key, .value = value};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds an array element node.
|
||||||
|
static void AddArrayElement(Node* array, Node* value) {
|
||||||
|
assert(array && array->type == NT_ARRAY);
|
||||||
|
Node* current = array;
|
||||||
|
while (current->next) current = current->next;
|
||||||
|
current->next = (Node*)BA_Bump(sizeof(Node));
|
||||||
|
*current->next = (Node){.type = NT_ARRAY_ELEMENT, .value = value};
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmp(const void* p1, const void* p2) {
|
||||||
|
return strcmp(*(const char* const*)p1, *(const char* const*)p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEFINE_ADD_FLAGS(HasFeature, FeatureName, FeatureType, LastEnum) \
|
||||||
|
static void AddFlags(Node* map, const FeatureType* features) { \
|
||||||
|
size_t i; \
|
||||||
|
const char* ptrs[LastEnum] = {0}; \
|
||||||
|
size_t count = 0; \
|
||||||
|
for (i = 0; i < LastEnum; ++i) { \
|
||||||
|
if (HasFeature(features, i)) { \
|
||||||
|
ptrs[count] = FeatureName(i); \
|
||||||
|
++count; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
qsort((void*)ptrs, count, sizeof(char*), cmp); \
|
||||||
|
Node* const array = CreateArray(); \
|
||||||
|
for (i = 0; i < count; ++i) \
|
||||||
|
AddArrayElement(array, CreateConstantString(ptrs[i])); \
|
||||||
|
AddMapEntry(map, "flags", array); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_ARCH_X86)
|
||||||
|
DEFINE_ADD_FLAGS(GetX86FeaturesEnumValue, GetX86FeaturesEnumName, X86Features,
|
||||||
|
X86_LAST_)
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_ARM)
|
||||||
|
DEFINE_ADD_FLAGS(GetArmFeaturesEnumValue, GetArmFeaturesEnumName, ArmFeatures,
|
||||||
|
ARM_LAST_)
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||||
|
DEFINE_ADD_FLAGS(GetAarch64FeaturesEnumValue, GetAarch64FeaturesEnumName,
|
||||||
|
Aarch64Features, AARCH64_LAST_)
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_MIPS)
|
||||||
|
DEFINE_ADD_FLAGS(GetMipsFeaturesEnumValue, GetMipsFeaturesEnumName,
|
||||||
|
MipsFeatures, MIPS_LAST_)
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_PPC)
|
||||||
|
DEFINE_ADD_FLAGS(GetPPCFeaturesEnumValue, GetPPCFeaturesEnumName, PPCFeatures,
|
||||||
|
PPC_LAST_)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Prints a json string with characters escaping.
|
||||||
|
static void printJsonString(const char* str) {
|
||||||
|
putchar('"');
|
||||||
|
for (; str && *str; ++str) {
|
||||||
|
switch (*str) {
|
||||||
|
case '\"':
|
||||||
|
case '\\':
|
||||||
|
case '/':
|
||||||
|
case '\b':
|
||||||
|
case '\f':
|
||||||
|
case '\n':
|
||||||
|
case '\r':
|
||||||
|
case '\t':
|
||||||
|
putchar('\\');
|
||||||
|
}
|
||||||
|
putchar(*str);
|
||||||
|
}
|
||||||
|
putchar('"');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walks a Node and print it as json.
|
||||||
|
static void printJson(const Node* current) {
|
||||||
|
assert(current);
|
||||||
|
switch (current->type) {
|
||||||
|
case NT_INVALID:
|
||||||
|
break;
|
||||||
|
case NT_INT:
|
||||||
|
printf("%d", current->integer);
|
||||||
|
break;
|
||||||
|
case NT_STRING:
|
||||||
|
printJsonString(current->string);
|
||||||
|
break;
|
||||||
|
case NT_ARRAY:
|
||||||
|
putchar('[');
|
||||||
|
if (current->next) printJson(current->next);
|
||||||
|
putchar(']');
|
||||||
|
break;
|
||||||
|
case NT_MAP:
|
||||||
|
putchar('{');
|
||||||
|
if (current->next) printJson(current->next);
|
||||||
|
putchar('}');
|
||||||
|
break;
|
||||||
|
case NT_MAP_ENTRY:
|
||||||
|
printf("\"%s\":", current->string);
|
||||||
|
printJson(current->value);
|
||||||
|
if (current->next) {
|
||||||
|
putchar(',');
|
||||||
|
printJson(current->next);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NT_ARRAY_ELEMENT:
|
||||||
|
printJson(current->value);
|
||||||
|
if (current->next) {
|
||||||
|
putchar(',');
|
||||||
|
printJson(current->next);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walks a Node and print it as text.
|
||||||
|
static void printTextField(const Node* current) {
|
||||||
|
switch (current->type) {
|
||||||
|
case NT_INVALID:
|
||||||
|
break;
|
||||||
|
case NT_INT:
|
||||||
|
printf("%3d (0x%02X)", current->integer, current->integer);
|
||||||
|
break;
|
||||||
|
case NT_STRING:
|
||||||
|
fputs(current->string, stdout);
|
||||||
|
break;
|
||||||
|
case NT_ARRAY:
|
||||||
|
if (current->next) printTextField(current->next);
|
||||||
|
break;
|
||||||
|
case NT_MAP:
|
||||||
|
if (current->next) {
|
||||||
|
printf("{");
|
||||||
|
printJson(current->next);
|
||||||
|
printf("}");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NT_MAP_ENTRY:
|
||||||
|
printf("%-15s : ", current->string);
|
||||||
|
printTextField(current->value);
|
||||||
|
if (current->next) {
|
||||||
|
putchar('\n');
|
||||||
|
printTextField(current->next);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NT_ARRAY_ELEMENT:
|
||||||
|
printTextField(current->value);
|
||||||
|
if (current->next) {
|
||||||
|
putchar(',');
|
||||||
|
printTextField(current->next);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printTextRoot(const Node* current) {
|
||||||
|
if (current->type == NT_MAP && current->next) printTextField(current->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void showUsage(const char* name) {
|
||||||
|
printf(
|
||||||
|
"\n"
|
||||||
|
"Usage: %s [options]\n"
|
||||||
|
" Options:\n"
|
||||||
|
" -h | --help Show help message.\n"
|
||||||
|
" -j | --json Format output as json instead of plain text.\n"
|
||||||
|
"\n",
|
||||||
|
name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Node* GetCacheTypeString(CacheType cache_type) {
|
||||||
|
switch (cache_type) {
|
||||||
|
case CPU_FEATURE_CACHE_NULL:
|
||||||
|
return CreateConstantString("null");
|
||||||
|
case CPU_FEATURE_CACHE_DATA:
|
||||||
|
return CreateConstantString("data");
|
||||||
|
case CPU_FEATURE_CACHE_INSTRUCTION:
|
||||||
|
return CreateConstantString("instruction");
|
||||||
|
case CPU_FEATURE_CACHE_UNIFIED:
|
||||||
|
return CreateConstantString("unified");
|
||||||
|
case CPU_FEATURE_CACHE_TLB:
|
||||||
|
return CreateConstantString("tlb");
|
||||||
|
case CPU_FEATURE_CACHE_DTLB:
|
||||||
|
return CreateConstantString("dtlb");
|
||||||
|
case CPU_FEATURE_CACHE_STLB:
|
||||||
|
return CreateConstantString("stlb");
|
||||||
|
case CPU_FEATURE_CACHE_PREFETCH:
|
||||||
|
return CreateConstantString("prefetch");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void AddCacheInfo(Node* root, const CacheInfo* cache_info) {
|
||||||
|
Node* array = CreateArray();
|
||||||
|
for (int i = 0; i < cache_info->size; ++i) {
|
||||||
|
CacheLevelInfo info = cache_info->levels[i];
|
||||||
|
Node* map = CreateMap();
|
||||||
|
AddMapEntry(map, "level", CreateInt(info.level));
|
||||||
|
AddMapEntry(map, "cache_type", GetCacheTypeString(info.cache_type));
|
||||||
|
AddMapEntry(map, "cache_size", CreateInt(info.cache_size));
|
||||||
|
AddMapEntry(map, "ways", CreateInt(info.ways));
|
||||||
|
AddMapEntry(map, "line_size", CreateInt(info.line_size));
|
||||||
|
AddMapEntry(map, "tlb_entries", CreateInt(info.tlb_entries));
|
||||||
|
AddMapEntry(map, "partitioning", CreateInt(info.partitioning));
|
||||||
|
AddArrayElement(array, map);
|
||||||
|
}
|
||||||
|
AddMapEntry(root, "cache_info", array);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Node* CreateTree() {
|
||||||
|
Node* root = CreateMap();
|
||||||
|
#if defined(CPU_FEATURES_ARCH_X86)
|
||||||
|
char brand_string[49];
|
||||||
|
const X86Info info = GetX86Info();
|
||||||
|
const CacheInfo cache_info = GetX86CacheInfo();
|
||||||
|
FillX86BrandString(brand_string);
|
||||||
|
AddMapEntry(root, "arch", CreateString("x86"));
|
||||||
|
AddMapEntry(root, "brand", CreateString(brand_string));
|
||||||
|
AddMapEntry(root, "family", CreateInt(info.family));
|
||||||
|
AddMapEntry(root, "model", CreateInt(info.model));
|
||||||
|
AddMapEntry(root, "stepping", CreateInt(info.stepping));
|
||||||
|
AddMapEntry(root, "uarch",
|
||||||
|
CreateString(
|
||||||
|
GetX86MicroarchitectureName(GetX86Microarchitecture(&info))));
|
||||||
|
AddFlags(root, &info.features);
|
||||||
|
AddCacheInfo(root, &cache_info);
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_ARM)
|
||||||
|
const ArmInfo info = GetArmInfo();
|
||||||
|
AddMapEntry(root, "arch", CreateString("ARM"));
|
||||||
|
AddMapEntry(root, "implementer", CreateInt(info.implementer));
|
||||||
|
AddMapEntry(root, "architecture", CreateInt(info.architecture));
|
||||||
|
AddMapEntry(root, "variant", CreateInt(info.variant));
|
||||||
|
AddMapEntry(root, "part", CreateInt(info.part));
|
||||||
|
AddMapEntry(root, "revision", CreateInt(info.revision));
|
||||||
|
AddFlags(root, &info.features);
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||||
|
const Aarch64Info info = GetAarch64Info();
|
||||||
|
AddMapEntry(root, "arch", CreateString("aarch64"));
|
||||||
|
AddMapEntry(root, "implementer", CreateInt(info.implementer));
|
||||||
|
AddMapEntry(root, "variant", CreateInt(info.variant));
|
||||||
|
AddMapEntry(root, "part", CreateInt(info.part));
|
||||||
|
AddMapEntry(root, "revision", CreateInt(info.revision));
|
||||||
|
AddFlags(root, &info.features);
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_MIPS)
|
||||||
|
const MipsInfo info = GetMipsInfo();
|
||||||
|
AddMapEntry(root, "arch", CreateString("mips"));
|
||||||
|
AddFlags(root, &info.features);
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_PPC)
|
||||||
|
const PPCInfo info = GetPPCInfo();
|
||||||
|
const PPCPlatformStrings strings = GetPPCPlatformStrings();
|
||||||
|
AddMapEntry(root, "arch", CreateString("ppc"));
|
||||||
|
AddMapEntry(root, "platform", CreateString(strings.platform));
|
||||||
|
AddMapEntry(root, "model", CreateString(strings.model));
|
||||||
|
AddMapEntry(root, "machine", CreateString(strings.machine));
|
||||||
|
AddMapEntry(root, "cpu", CreateString(strings.cpu));
|
||||||
|
AddMapEntry(root, "instruction", CreateString(strings.type.platform));
|
||||||
|
AddMapEntry(root, "microarchitecture",
|
||||||
|
CreateString(strings.type.base_platform));
|
||||||
|
AddFlags(root, &info.features);
|
||||||
|
#endif
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
BA_Align();
|
||||||
|
const Node* const root = CreateTree();
|
||||||
|
bool outputJson = false;
|
||||||
|
int i = 1;
|
||||||
|
for (; i < argc; ++i) {
|
||||||
|
const char* arg = argv[i];
|
||||||
|
if (strcmp(arg, "-j") == 0 || strcmp(arg, "--json") == 0) {
|
||||||
|
outputJson = true;
|
||||||
|
} else {
|
||||||
|
showUsage(argv[0]);
|
||||||
|
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0)
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (outputJson)
|
||||||
|
printJson(root);
|
||||||
|
else
|
||||||
|
printTextRoot(root);
|
||||||
|
putchar('\n');
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
#
|
||||||
|
# libraries for tests
|
||||||
|
#
|
||||||
|
|
||||||
|
include_directories(../include)
|
||||||
|
add_definitions(-DCPU_FEATURES_TEST)
|
||||||
|
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
add_library(string_view ../src/string_view.c)
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
add_library(filesystem_for_testing filesystem_for_testing.cc)
|
||||||
|
target_compile_definitions(filesystem_for_testing PUBLIC CPU_FEATURES_MOCK_FILESYSTEM)
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
add_library(hwcaps_for_testing hwcaps_for_testing.cc)
|
||||||
|
target_link_libraries(hwcaps_for_testing filesystem_for_testing)
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
add_library(stack_line_reader ../src/stack_line_reader.c)
|
||||||
|
target_compile_definitions(stack_line_reader PUBLIC STACK_LINE_READER_BUFFER_SIZE=1024)
|
||||||
|
target_link_libraries(stack_line_reader string_view)
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
add_library(stack_line_reader_for_test ../src/stack_line_reader.c)
|
||||||
|
target_compile_definitions(stack_line_reader_for_test PUBLIC STACK_LINE_READER_BUFFER_SIZE=16)
|
||||||
|
target_link_libraries(stack_line_reader_for_test string_view filesystem_for_testing)
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
add_library(all_libraries ../src/hwcaps.c ../src/stack_line_reader.c)
|
||||||
|
target_link_libraries(all_libraries hwcaps_for_testing stack_line_reader string_view)
|
||||||
|
|
||||||
|
#
|
||||||
|
# tests
|
||||||
|
#
|
||||||
|
link_libraries(gtest gmock_main)
|
||||||
|
|
||||||
|
## bit_utils_test
|
||||||
|
add_executable(bit_utils_test bit_utils_test.cc)
|
||||||
|
target_link_libraries(bit_utils_test)
|
||||||
|
add_test(NAME bit_utils_test COMMAND bit_utils_test)
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
## string_view_test
|
||||||
|
add_executable(string_view_test string_view_test.cc ../src/string_view.c)
|
||||||
|
target_link_libraries(string_view_test string_view)
|
||||||
|
add_test(NAME string_view_test COMMAND string_view_test)
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
## stack_line_reader_test
|
||||||
|
add_executable(stack_line_reader_test stack_line_reader_test.cc)
|
||||||
|
target_link_libraries(stack_line_reader_test stack_line_reader_for_test)
|
||||||
|
add_test(NAME stack_line_reader_test COMMAND stack_line_reader_test)
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
## cpuinfo_x86_test
|
||||||
|
if(PROCESSOR_IS_X86)
|
||||||
|
add_executable(cpuinfo_x86_test cpuinfo_x86_test.cc ../src/cpuinfo_x86.c)
|
||||||
|
target_compile_definitions(cpuinfo_x86_test PUBLIC CPU_FEATURES_MOCK_CPUID_X86)
|
||||||
|
if(APPLE)
|
||||||
|
target_compile_definitions(cpuinfo_x86_test PRIVATE HAVE_SYSCTLBYNAME)
|
||||||
|
endif()
|
||||||
|
target_link_libraries(cpuinfo_x86_test all_libraries)
|
||||||
|
add_test(NAME cpuinfo_x86_test COMMAND cpuinfo_x86_test)
|
||||||
|
endif()
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
## cpuinfo_arm_test
|
||||||
|
if(PROCESSOR_IS_ARM)
|
||||||
|
add_executable(cpuinfo_arm_test cpuinfo_arm_test.cc ../src/cpuinfo_arm.c)
|
||||||
|
target_link_libraries(cpuinfo_arm_test all_libraries)
|
||||||
|
add_test(NAME cpuinfo_arm_test COMMAND cpuinfo_arm_test)
|
||||||
|
endif()
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
## cpuinfo_aarch64_test
|
||||||
|
if(PROCESSOR_IS_AARCH64)
|
||||||
|
add_executable(cpuinfo_aarch64_test cpuinfo_aarch64_test.cc ../src/cpuinfo_aarch64.c)
|
||||||
|
target_link_libraries(cpuinfo_aarch64_test all_libraries)
|
||||||
|
add_test(NAME cpuinfo_aarch64_test COMMAND cpuinfo_aarch64_test)
|
||||||
|
endif()
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
## cpuinfo_mips_test
|
||||||
|
if(PROCESSOR_IS_MIPS)
|
||||||
|
add_executable(cpuinfo_mips_test cpuinfo_mips_test.cc ../src/cpuinfo_mips.c)
|
||||||
|
target_link_libraries(cpuinfo_mips_test all_libraries)
|
||||||
|
add_test(NAME cpuinfo_mips_test COMMAND cpuinfo_mips_test)
|
||||||
|
endif()
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
## cpuinfo_ppc_test
|
||||||
|
if(PROCESSOR_IS_POWER)
|
||||||
|
add_executable(cpuinfo_ppc_test cpuinfo_ppc_test.cc ../src/cpuinfo_ppc.c)
|
||||||
|
target_link_libraries(cpuinfo_ppc_test all_libraries)
|
||||||
|
add_test(NAME cpuinfo_ppc_test COMMAND cpuinfo_ppc_test)
|
||||||
|
endif()
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "internal/bit_utils.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(UtilsTest, IsBitSet) {
|
||||||
|
for (size_t bit_set = 0; bit_set < 32; ++bit_set) {
|
||||||
|
const uint32_t value = 1UL << bit_set;
|
||||||
|
for (uint32_t i = 0; i < 32; ++i) {
|
||||||
|
EXPECT_EQ(IsBitSet(value, i), i == bit_set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// testing 0, all bits should be 0.
|
||||||
|
for (uint32_t i = 0; i < 32; ++i) {
|
||||||
|
EXPECT_FALSE(IsBitSet(0, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// testing ~0, all bits should be 1.
|
||||||
|
for (uint32_t i = 0; i < 32; ++i) {
|
||||||
|
EXPECT_TRUE(IsBitSet(-1, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UtilsTest, ExtractBitRange) {
|
||||||
|
// Extracting all bits gives the same number.
|
||||||
|
EXPECT_EQ(ExtractBitRange(123, 31, 0), 123);
|
||||||
|
// Extracting 1 bit gives parity.
|
||||||
|
EXPECT_EQ(ExtractBitRange(123, 0, 0), 1);
|
||||||
|
EXPECT_EQ(ExtractBitRange(122, 0, 0), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(ExtractBitRange(0xF0, 7, 4), 0xF);
|
||||||
|
EXPECT_EQ(ExtractBitRange(0x42 << 2, 10, 2), 0x42);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
@ -0,0 +1,171 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "cpuinfo_aarch64.h"
|
||||||
|
|
||||||
|
#include "filesystem_for_testing.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "hwcaps_for_testing.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
|
||||||
|
|
||||||
|
TEST(CpuinfoAarch64Test, FromHardwareCap) {
|
||||||
|
SetHardwareCapabilities(AARCH64_HWCAP_FP | AARCH64_HWCAP_AES, 0);
|
||||||
|
GetEmptyFilesystem(); // disabling /proc/cpuinfo
|
||||||
|
const auto info = GetAarch64Info();
|
||||||
|
EXPECT_TRUE(info.features.fp);
|
||||||
|
EXPECT_FALSE(info.features.asimd);
|
||||||
|
EXPECT_FALSE(info.features.evtstrm);
|
||||||
|
EXPECT_TRUE(info.features.aes);
|
||||||
|
EXPECT_FALSE(info.features.pmull);
|
||||||
|
EXPECT_FALSE(info.features.sha1);
|
||||||
|
EXPECT_FALSE(info.features.sha2);
|
||||||
|
EXPECT_FALSE(info.features.crc32);
|
||||||
|
EXPECT_FALSE(info.features.atomics);
|
||||||
|
EXPECT_FALSE(info.features.fphp);
|
||||||
|
EXPECT_FALSE(info.features.asimdhp);
|
||||||
|
EXPECT_FALSE(info.features.cpuid);
|
||||||
|
EXPECT_FALSE(info.features.asimdrdm);
|
||||||
|
EXPECT_FALSE(info.features.jscvt);
|
||||||
|
EXPECT_FALSE(info.features.fcma);
|
||||||
|
EXPECT_FALSE(info.features.lrcpc);
|
||||||
|
EXPECT_FALSE(info.features.dcpop);
|
||||||
|
EXPECT_FALSE(info.features.sha3);
|
||||||
|
EXPECT_FALSE(info.features.sm3);
|
||||||
|
EXPECT_FALSE(info.features.sm4);
|
||||||
|
EXPECT_FALSE(info.features.asimddp);
|
||||||
|
EXPECT_FALSE(info.features.sha512);
|
||||||
|
EXPECT_FALSE(info.features.sve);
|
||||||
|
EXPECT_FALSE(info.features.asimdfhm);
|
||||||
|
EXPECT_FALSE(info.features.dit);
|
||||||
|
EXPECT_FALSE(info.features.uscat);
|
||||||
|
EXPECT_FALSE(info.features.ilrcpc);
|
||||||
|
EXPECT_FALSE(info.features.flagm);
|
||||||
|
EXPECT_FALSE(info.features.ssbs);
|
||||||
|
EXPECT_FALSE(info.features.sb);
|
||||||
|
EXPECT_FALSE(info.features.paca);
|
||||||
|
EXPECT_FALSE(info.features.pacg);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpuinfoAarch64Test, FromHardwareCap2) {
|
||||||
|
SetHardwareCapabilities(AARCH64_HWCAP_FP,
|
||||||
|
AARCH64_HWCAP2_SVE2 | AARCH64_HWCAP2_BTI);
|
||||||
|
GetEmptyFilesystem(); // disabling /proc/cpuinfo
|
||||||
|
const auto info = GetAarch64Info();
|
||||||
|
EXPECT_TRUE(info.features.fp);
|
||||||
|
|
||||||
|
EXPECT_TRUE(info.features.sve2);
|
||||||
|
EXPECT_TRUE(info.features.bti);
|
||||||
|
|
||||||
|
EXPECT_FALSE(info.features.dcpodp);
|
||||||
|
EXPECT_FALSE(info.features.sveaes);
|
||||||
|
EXPECT_FALSE(info.features.svepmull);
|
||||||
|
EXPECT_FALSE(info.features.svebitperm);
|
||||||
|
EXPECT_FALSE(info.features.svesha3);
|
||||||
|
EXPECT_FALSE(info.features.svesm4);
|
||||||
|
EXPECT_FALSE(info.features.flagm2);
|
||||||
|
EXPECT_FALSE(info.features.frint);
|
||||||
|
EXPECT_FALSE(info.features.svei8mm);
|
||||||
|
EXPECT_FALSE(info.features.svef32mm);
|
||||||
|
EXPECT_FALSE(info.features.svef64mm);
|
||||||
|
EXPECT_FALSE(info.features.svebf16);
|
||||||
|
EXPECT_FALSE(info.features.i8mm);
|
||||||
|
EXPECT_FALSE(info.features.bf16);
|
||||||
|
EXPECT_FALSE(info.features.dgh);
|
||||||
|
EXPECT_FALSE(info.features.rng);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpuinfoAarch64Test, ARMCortexA53) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(Processor : AArch64 Processor rev 3 (aarch64)
|
||||||
|
processor : 0
|
||||||
|
processor : 1
|
||||||
|
processor : 2
|
||||||
|
processor : 3
|
||||||
|
processor : 4
|
||||||
|
processor : 5
|
||||||
|
processor : 6
|
||||||
|
processor : 7
|
||||||
|
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
|
||||||
|
CPU implementer : 0x41
|
||||||
|
CPU architecture: AArch64
|
||||||
|
CPU variant : 0x0
|
||||||
|
CPU part : 0xd03
|
||||||
|
CPU revision : 3)");
|
||||||
|
const auto info = GetAarch64Info();
|
||||||
|
EXPECT_EQ(info.implementer, 0x41);
|
||||||
|
EXPECT_EQ(info.variant, 0x0);
|
||||||
|
EXPECT_EQ(info.part, 0xd03);
|
||||||
|
EXPECT_EQ(info.revision, 3);
|
||||||
|
|
||||||
|
EXPECT_TRUE(info.features.fp);
|
||||||
|
EXPECT_TRUE(info.features.asimd);
|
||||||
|
EXPECT_TRUE(info.features.evtstrm);
|
||||||
|
EXPECT_TRUE(info.features.aes);
|
||||||
|
EXPECT_TRUE(info.features.pmull);
|
||||||
|
EXPECT_TRUE(info.features.sha1);
|
||||||
|
EXPECT_TRUE(info.features.sha2);
|
||||||
|
EXPECT_TRUE(info.features.crc32);
|
||||||
|
|
||||||
|
EXPECT_FALSE(info.features.atomics);
|
||||||
|
EXPECT_FALSE(info.features.fphp);
|
||||||
|
EXPECT_FALSE(info.features.asimdhp);
|
||||||
|
EXPECT_FALSE(info.features.cpuid);
|
||||||
|
EXPECT_FALSE(info.features.asimdrdm);
|
||||||
|
EXPECT_FALSE(info.features.jscvt);
|
||||||
|
EXPECT_FALSE(info.features.fcma);
|
||||||
|
EXPECT_FALSE(info.features.lrcpc);
|
||||||
|
EXPECT_FALSE(info.features.dcpop);
|
||||||
|
EXPECT_FALSE(info.features.sha3);
|
||||||
|
EXPECT_FALSE(info.features.sm3);
|
||||||
|
EXPECT_FALSE(info.features.sm4);
|
||||||
|
EXPECT_FALSE(info.features.asimddp);
|
||||||
|
EXPECT_FALSE(info.features.sha512);
|
||||||
|
EXPECT_FALSE(info.features.sve);
|
||||||
|
EXPECT_FALSE(info.features.asimdfhm);
|
||||||
|
EXPECT_FALSE(info.features.dit);
|
||||||
|
EXPECT_FALSE(info.features.uscat);
|
||||||
|
EXPECT_FALSE(info.features.ilrcpc);
|
||||||
|
EXPECT_FALSE(info.features.flagm);
|
||||||
|
EXPECT_FALSE(info.features.ssbs);
|
||||||
|
EXPECT_FALSE(info.features.sb);
|
||||||
|
EXPECT_FALSE(info.features.paca);
|
||||||
|
EXPECT_FALSE(info.features.pacg);
|
||||||
|
EXPECT_FALSE(info.features.dcpodp);
|
||||||
|
EXPECT_FALSE(info.features.sve2);
|
||||||
|
EXPECT_FALSE(info.features.sveaes);
|
||||||
|
EXPECT_FALSE(info.features.svepmull);
|
||||||
|
EXPECT_FALSE(info.features.svebitperm);
|
||||||
|
EXPECT_FALSE(info.features.svesha3);
|
||||||
|
EXPECT_FALSE(info.features.svesm4);
|
||||||
|
EXPECT_FALSE(info.features.flagm2);
|
||||||
|
EXPECT_FALSE(info.features.frint);
|
||||||
|
EXPECT_FALSE(info.features.svei8mm);
|
||||||
|
EXPECT_FALSE(info.features.svef32mm);
|
||||||
|
EXPECT_FALSE(info.features.svef64mm);
|
||||||
|
EXPECT_FALSE(info.features.svebf16);
|
||||||
|
EXPECT_FALSE(info.features.i8mm);
|
||||||
|
EXPECT_FALSE(info.features.bf16);
|
||||||
|
EXPECT_FALSE(info.features.dgh);
|
||||||
|
EXPECT_FALSE(info.features.rng);
|
||||||
|
EXPECT_FALSE(info.features.bti);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
@ -0,0 +1,354 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "cpuinfo_arm.h"
|
||||||
|
|
||||||
|
#include "filesystem_for_testing.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "hwcaps_for_testing.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
|
||||||
|
|
||||||
|
TEST(CpuinfoArmTest, FromHardwareCap) {
|
||||||
|
SetHardwareCapabilities(ARM_HWCAP_NEON, ARM_HWCAP2_AES | ARM_HWCAP2_CRC32);
|
||||||
|
GetEmptyFilesystem(); // disabling /proc/cpuinfo
|
||||||
|
const auto info = GetArmInfo();
|
||||||
|
EXPECT_TRUE(info.features.vfp); // triggered by vfpv3
|
||||||
|
EXPECT_TRUE(info.features.vfpv3); // triggered by neon
|
||||||
|
EXPECT_TRUE(info.features.neon);
|
||||||
|
EXPECT_TRUE(info.features.aes);
|
||||||
|
EXPECT_TRUE(info.features.crc32);
|
||||||
|
|
||||||
|
EXPECT_FALSE(info.features.vfpv4);
|
||||||
|
EXPECT_FALSE(info.features.iwmmxt);
|
||||||
|
EXPECT_FALSE(info.features.crunch);
|
||||||
|
EXPECT_FALSE(info.features.thumbee);
|
||||||
|
EXPECT_FALSE(info.features.vfpv3d16);
|
||||||
|
EXPECT_FALSE(info.features.idiva);
|
||||||
|
EXPECT_FALSE(info.features.idivt);
|
||||||
|
EXPECT_FALSE(info.features.pmull);
|
||||||
|
EXPECT_FALSE(info.features.sha1);
|
||||||
|
EXPECT_FALSE(info.features.sha2);
|
||||||
|
|
||||||
|
// check some random features with EnumValue():
|
||||||
|
EXPECT_TRUE(GetArmFeaturesEnumValue(&info.features, ARM_VFP));
|
||||||
|
EXPECT_FALSE(GetArmFeaturesEnumValue(&info.features, ARM_VFPV4));
|
||||||
|
// out of bound EnumValue() check
|
||||||
|
EXPECT_FALSE(GetArmFeaturesEnumValue(&info.features, (ArmFeaturesEnum)~0x0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpuinfoArmTest, ODroidFromCpuInfo) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo", R"(processor : 0
|
||||||
|
model name : ARMv7 Processor rev 3 (v71)
|
||||||
|
BogoMIPS : 120.00
|
||||||
|
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
|
||||||
|
CPU implementer : 0x41
|
||||||
|
CPU architecture: 7
|
||||||
|
CPU variant : 0x2
|
||||||
|
CPU part : 0xc0f
|
||||||
|
CPU revision : 3)");
|
||||||
|
const auto info = GetArmInfo();
|
||||||
|
EXPECT_EQ(info.implementer, 0x41);
|
||||||
|
EXPECT_EQ(info.variant, 0x2);
|
||||||
|
EXPECT_EQ(info.part, 0xc0f);
|
||||||
|
EXPECT_EQ(info.revision, 3);
|
||||||
|
EXPECT_EQ(info.architecture, 7);
|
||||||
|
|
||||||
|
EXPECT_FALSE(info.features.swp);
|
||||||
|
EXPECT_TRUE(info.features.half);
|
||||||
|
EXPECT_TRUE(info.features.thumb);
|
||||||
|
EXPECT_FALSE(info.features._26bit);
|
||||||
|
EXPECT_TRUE(info.features.fastmult);
|
||||||
|
EXPECT_FALSE(info.features.fpa);
|
||||||
|
EXPECT_TRUE(info.features.vfp);
|
||||||
|
EXPECT_TRUE(info.features.edsp);
|
||||||
|
EXPECT_FALSE(info.features.java);
|
||||||
|
EXPECT_FALSE(info.features.iwmmxt);
|
||||||
|
EXPECT_FALSE(info.features.crunch);
|
||||||
|
EXPECT_FALSE(info.features.thumbee);
|
||||||
|
EXPECT_TRUE(info.features.neon);
|
||||||
|
EXPECT_TRUE(info.features.vfpv3);
|
||||||
|
EXPECT_FALSE(info.features.vfpv3d16);
|
||||||
|
EXPECT_TRUE(info.features.tls);
|
||||||
|
EXPECT_TRUE(info.features.vfpv4);
|
||||||
|
EXPECT_TRUE(info.features.idiva);
|
||||||
|
EXPECT_TRUE(info.features.idivt);
|
||||||
|
EXPECT_TRUE(info.features.vfpd32);
|
||||||
|
EXPECT_TRUE(info.features.lpae);
|
||||||
|
EXPECT_FALSE(info.features.evtstrm);
|
||||||
|
EXPECT_FALSE(info.features.aes);
|
||||||
|
EXPECT_FALSE(info.features.pmull);
|
||||||
|
EXPECT_FALSE(info.features.sha1);
|
||||||
|
EXPECT_FALSE(info.features.sha2);
|
||||||
|
EXPECT_FALSE(info.features.crc32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Linux test-case
|
||||||
|
TEST(CpuinfoArmTest, RaspberryPiZeroFromCpuInfo) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo", R"(processor : 0
|
||||||
|
model name : ARMv6-compatible processor rev 7 (v6l)
|
||||||
|
BogoMIPS : 697.95
|
||||||
|
Features : half thumb fastmult vfp edsp java tls
|
||||||
|
CPU implementer : 0x41
|
||||||
|
CPU architecture: 7
|
||||||
|
CPU variant : 0x0
|
||||||
|
CPU part : 0xb76
|
||||||
|
CPU revision : 7
|
||||||
|
|
||||||
|
Hardware : BCM2835
|
||||||
|
Revision : 9000c1
|
||||||
|
Serial : 000000006cd946f3)");
|
||||||
|
const auto info = GetArmInfo();
|
||||||
|
EXPECT_EQ(info.implementer, 0x41);
|
||||||
|
EXPECT_EQ(info.variant, 0x0);
|
||||||
|
EXPECT_EQ(info.part, 0xb76);
|
||||||
|
EXPECT_EQ(info.revision, 7);
|
||||||
|
EXPECT_EQ(info.architecture, 6);
|
||||||
|
|
||||||
|
EXPECT_FALSE(info.features.swp);
|
||||||
|
EXPECT_TRUE(info.features.half);
|
||||||
|
EXPECT_TRUE(info.features.thumb);
|
||||||
|
EXPECT_FALSE(info.features._26bit);
|
||||||
|
EXPECT_TRUE(info.features.fastmult);
|
||||||
|
EXPECT_FALSE(info.features.fpa);
|
||||||
|
EXPECT_TRUE(info.features.vfp);
|
||||||
|
EXPECT_TRUE(info.features.edsp);
|
||||||
|
EXPECT_TRUE(info.features.java);
|
||||||
|
EXPECT_FALSE(info.features.iwmmxt);
|
||||||
|
EXPECT_FALSE(info.features.crunch);
|
||||||
|
EXPECT_FALSE(info.features.thumbee);
|
||||||
|
EXPECT_FALSE(info.features.neon);
|
||||||
|
EXPECT_FALSE(info.features.vfpv3);
|
||||||
|
EXPECT_FALSE(info.features.vfpv3d16);
|
||||||
|
EXPECT_TRUE(info.features.tls);
|
||||||
|
EXPECT_FALSE(info.features.vfpv4);
|
||||||
|
EXPECT_FALSE(info.features.idiva);
|
||||||
|
EXPECT_FALSE(info.features.idivt);
|
||||||
|
EXPECT_FALSE(info.features.vfpd32);
|
||||||
|
EXPECT_FALSE(info.features.lpae);
|
||||||
|
EXPECT_FALSE(info.features.evtstrm);
|
||||||
|
EXPECT_FALSE(info.features.aes);
|
||||||
|
EXPECT_FALSE(info.features.pmull);
|
||||||
|
EXPECT_FALSE(info.features.sha1);
|
||||||
|
EXPECT_FALSE(info.features.sha2);
|
||||||
|
EXPECT_FALSE(info.features.crc32);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpuinfoArmTest, MarvellArmadaFromCpuInfo) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo", R"(processor : 0
|
||||||
|
model name : ARMv7 Processor rev 1 (v7l)
|
||||||
|
BogoMIPS : 50.00
|
||||||
|
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpd32
|
||||||
|
CPU implementer : 0x41
|
||||||
|
CPU architecture: 7
|
||||||
|
CPU variant : 0x4
|
||||||
|
CPU part : 0xc09
|
||||||
|
CPU revision : 1
|
||||||
|
|
||||||
|
processor : 1
|
||||||
|
model name : ARMv7 Processor rev 1 (v7l)
|
||||||
|
BogoMIPS : 50.00
|
||||||
|
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpd32
|
||||||
|
CPU implementer : 0x41
|
||||||
|
CPU architecture: 7
|
||||||
|
CPU variant : 0x4
|
||||||
|
CPU part : 0xc09
|
||||||
|
CPU revision : 1
|
||||||
|
|
||||||
|
Hardware : Marvell Armada 380/385 (Device Tree)
|
||||||
|
Revision : 0000
|
||||||
|
Serial : 0000000000000000)");
|
||||||
|
const auto info = GetArmInfo();
|
||||||
|
EXPECT_EQ(info.implementer, 0x41);
|
||||||
|
EXPECT_EQ(info.variant, 0x4);
|
||||||
|
EXPECT_EQ(info.part, 0xc09);
|
||||||
|
EXPECT_EQ(info.revision, 1);
|
||||||
|
EXPECT_EQ(info.architecture, 7);
|
||||||
|
|
||||||
|
EXPECT_FALSE(info.features.swp);
|
||||||
|
EXPECT_TRUE(info.features.half);
|
||||||
|
EXPECT_TRUE(info.features.thumb);
|
||||||
|
EXPECT_FALSE(info.features._26bit);
|
||||||
|
EXPECT_TRUE(info.features.fastmult);
|
||||||
|
EXPECT_FALSE(info.features.fpa);
|
||||||
|
EXPECT_TRUE(info.features.vfp);
|
||||||
|
EXPECT_TRUE(info.features.edsp);
|
||||||
|
EXPECT_FALSE(info.features.java);
|
||||||
|
EXPECT_FALSE(info.features.iwmmxt);
|
||||||
|
EXPECT_FALSE(info.features.crunch);
|
||||||
|
EXPECT_FALSE(info.features.thumbee);
|
||||||
|
EXPECT_TRUE(info.features.neon);
|
||||||
|
EXPECT_TRUE(info.features.vfpv3);
|
||||||
|
EXPECT_FALSE(info.features.vfpv3d16);
|
||||||
|
EXPECT_TRUE(info.features.tls);
|
||||||
|
EXPECT_FALSE(info.features.vfpv4);
|
||||||
|
EXPECT_FALSE(info.features.idiva);
|
||||||
|
EXPECT_FALSE(info.features.idivt);
|
||||||
|
EXPECT_TRUE(info.features.vfpd32);
|
||||||
|
EXPECT_FALSE(info.features.lpae);
|
||||||
|
EXPECT_FALSE(info.features.evtstrm);
|
||||||
|
EXPECT_FALSE(info.features.aes);
|
||||||
|
EXPECT_FALSE(info.features.pmull);
|
||||||
|
EXPECT_FALSE(info.features.sha1);
|
||||||
|
EXPECT_FALSE(info.features.sha2);
|
||||||
|
EXPECT_FALSE(info.features.crc32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Android test-case
|
||||||
|
// http://code.google.com/p/android/issues/detail?id=10812
|
||||||
|
TEST(CpuinfoArmTest, InvalidArmv7) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(Processor : ARMv6-compatible processor rev 6 (v6l)
|
||||||
|
BogoMIPS : 199.47
|
||||||
|
Features : swp half thumb fastmult vfp edsp java
|
||||||
|
CPU implementer : 0x41
|
||||||
|
CPU architecture: 7
|
||||||
|
CPU variant : 0x0
|
||||||
|
CPU part : 0xb76
|
||||||
|
CPU revision : 6
|
||||||
|
|
||||||
|
Hardware : SPICA
|
||||||
|
Revision : 0020
|
||||||
|
Serial : 33323613546d00ec )");
|
||||||
|
const auto info = GetArmInfo();
|
||||||
|
EXPECT_EQ(info.architecture, 6);
|
||||||
|
|
||||||
|
EXPECT_TRUE(info.features.swp);
|
||||||
|
EXPECT_TRUE(info.features.half);
|
||||||
|
EXPECT_TRUE(info.features.thumb);
|
||||||
|
EXPECT_FALSE(info.features._26bit);
|
||||||
|
EXPECT_TRUE(info.features.fastmult);
|
||||||
|
EXPECT_FALSE(info.features.fpa);
|
||||||
|
EXPECT_TRUE(info.features.vfp);
|
||||||
|
EXPECT_TRUE(info.features.edsp);
|
||||||
|
EXPECT_TRUE(info.features.java);
|
||||||
|
EXPECT_FALSE(info.features.iwmmxt);
|
||||||
|
EXPECT_FALSE(info.features.crunch);
|
||||||
|
EXPECT_FALSE(info.features.thumbee);
|
||||||
|
EXPECT_FALSE(info.features.neon);
|
||||||
|
EXPECT_FALSE(info.features.vfpv3);
|
||||||
|
EXPECT_FALSE(info.features.vfpv3d16);
|
||||||
|
EXPECT_FALSE(info.features.tls);
|
||||||
|
EXPECT_FALSE(info.features.vfpv4);
|
||||||
|
EXPECT_FALSE(info.features.idiva);
|
||||||
|
EXPECT_FALSE(info.features.idivt);
|
||||||
|
EXPECT_FALSE(info.features.vfpd32);
|
||||||
|
EXPECT_FALSE(info.features.lpae);
|
||||||
|
EXPECT_FALSE(info.features.evtstrm);
|
||||||
|
EXPECT_FALSE(info.features.aes);
|
||||||
|
EXPECT_FALSE(info.features.pmull);
|
||||||
|
EXPECT_FALSE(info.features.sha1);
|
||||||
|
EXPECT_FALSE(info.features.sha2);
|
||||||
|
EXPECT_FALSE(info.features.crc32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Android test-case
|
||||||
|
// https://crbug.com/341598.
|
||||||
|
TEST(CpuinfoArmTest, InvalidNeon) {
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(Processor: ARMv7 Processory rev 0 (v71)
|
||||||
|
processor: 0
|
||||||
|
BogoMIPS: 13.50
|
||||||
|
|
||||||
|
Processor: 1
|
||||||
|
BogoMIPS: 13.50
|
||||||
|
|
||||||
|
Features: swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt
|
||||||
|
CPU implementer : 0x51
|
||||||
|
CPU architecture: 7
|
||||||
|
CPU variant: 0x1
|
||||||
|
CPU part: 0x04d
|
||||||
|
CPU revision: 0
|
||||||
|
|
||||||
|
Hardware: SAMSUNG M2
|
||||||
|
Revision: 0010
|
||||||
|
Serial: 00001e030000354e)");
|
||||||
|
const auto info = GetArmInfo();
|
||||||
|
EXPECT_TRUE(info.features.swp);
|
||||||
|
EXPECT_FALSE(info.features.neon);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report IDIV
|
||||||
|
// support.
|
||||||
|
TEST(CpuinfoArmTest, Nexus4_0x510006f2) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(CPU implementer : 0x51
|
||||||
|
CPU architecture: 7
|
||||||
|
CPU variant : 0x0
|
||||||
|
CPU part : 0x6f
|
||||||
|
CPU revision : 2)");
|
||||||
|
const auto info = GetArmInfo();
|
||||||
|
EXPECT_TRUE(info.features.idiva);
|
||||||
|
EXPECT_TRUE(info.features.idivt);
|
||||||
|
|
||||||
|
EXPECT_EQ(GetArmCpuId(&info), 0x510006f2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report IDIV
|
||||||
|
// support.
|
||||||
|
TEST(CpuinfoArmTest, Nexus4_0x510006f3) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(CPU implementer : 0x51
|
||||||
|
CPU architecture: 7
|
||||||
|
CPU variant : 0x0
|
||||||
|
CPU part : 0x6f
|
||||||
|
CPU revision : 3)");
|
||||||
|
const auto info = GetArmInfo();
|
||||||
|
EXPECT_TRUE(info.features.idiva);
|
||||||
|
EXPECT_TRUE(info.features.idivt);
|
||||||
|
|
||||||
|
EXPECT_EQ(GetArmCpuId(&info), 0x510006f3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The emulator-specific Android 4.2 kernel fails to report support for the
|
||||||
|
// 32-bit ARM IDIV instruction. Technically, this is a feature of the virtual
|
||||||
|
// CPU implemented by the emulator.
|
||||||
|
TEST(CpuinfoArmTest, EmulatorSpecificIdiv) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(Processor : ARMv7 Processor rev 0 (v7l)
|
||||||
|
BogoMIPS : 629.14
|
||||||
|
Features : swp half thumb fastmult vfp edsp neon vfpv3
|
||||||
|
CPU implementer : 0x41
|
||||||
|
CPU architecture: 7
|
||||||
|
CPU variant : 0x0
|
||||||
|
CPU part : 0xc08
|
||||||
|
CPU revision : 0
|
||||||
|
|
||||||
|
Hardware : Goldfish
|
||||||
|
Revision : 0000
|
||||||
|
Serial : 0000000000000000)");
|
||||||
|
const auto info = GetArmInfo();
|
||||||
|
EXPECT_TRUE(info.features.idiva);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "cpuinfo_mips.h"
|
||||||
|
|
||||||
|
#include "filesystem_for_testing.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "hwcaps_for_testing.h"
|
||||||
|
#include "internal/stack_line_reader.h"
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
|
||||||
|
|
||||||
|
TEST(CpuinfoMipsTest, FromHardwareCapBoth) {
|
||||||
|
SetHardwareCapabilities(MIPS_HWCAP_MSA | MIPS_HWCAP_R6, 0);
|
||||||
|
GetEmptyFilesystem(); // disabling /proc/cpuinfo
|
||||||
|
const auto info = GetMipsInfo();
|
||||||
|
EXPECT_TRUE(info.features.msa);
|
||||||
|
EXPECT_FALSE(info.features.eva);
|
||||||
|
EXPECT_TRUE(info.features.r6);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpuinfoMipsTest, FromHardwareCapOnlyOne) {
|
||||||
|
SetHardwareCapabilities(MIPS_HWCAP_MSA, 0);
|
||||||
|
GetEmptyFilesystem(); // disabling /proc/cpuinfo
|
||||||
|
const auto info = GetMipsInfo();
|
||||||
|
EXPECT_TRUE(info.features.msa);
|
||||||
|
EXPECT_FALSE(info.features.eva);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpuinfoMipsTest, Ci40) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo", R"(system type : IMG Pistachio SoC (B0)
|
||||||
|
machine : IMG Marduk – Ci40 with cc2520
|
||||||
|
processor : 0
|
||||||
|
cpu model : MIPS interAptiv (multi) V2.0 FPU V0.0
|
||||||
|
BogoMIPS : 363.72
|
||||||
|
wait instruction : yes
|
||||||
|
microsecond timers : yes
|
||||||
|
tlb_entries : 64
|
||||||
|
extra interrupt vector : yes
|
||||||
|
hardware watchpoint : yes, count: 4, address/irw mask: [0x0ffc, 0x0ffc, 0x0ffb, 0x0ffb]
|
||||||
|
isa : mips1 mips2 mips32r1 mips32r2
|
||||||
|
ASEs implemented : mips16 dsp mt eva
|
||||||
|
shadow register sets : 1
|
||||||
|
kscratch registers : 0
|
||||||
|
package : 0
|
||||||
|
core : 0
|
||||||
|
VCED exceptions : not available
|
||||||
|
VCEI exceptions : not available
|
||||||
|
VPE : 0
|
||||||
|
)");
|
||||||
|
const auto info = GetMipsInfo();
|
||||||
|
EXPECT_FALSE(info.features.msa);
|
||||||
|
EXPECT_TRUE(info.features.eva);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpuinfoMipsTest, AR7161) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(system type : Atheros AR7161 rev 2
|
||||||
|
machine : NETGEAR WNDR3700/WNDR3800/WNDRMAC
|
||||||
|
processor : 0
|
||||||
|
cpu model : MIPS 24Kc V7.4
|
||||||
|
BogoMIPS : 452.19
|
||||||
|
wait instruction : yes
|
||||||
|
microsecond timers : yes
|
||||||
|
tlb_entries : 16
|
||||||
|
extra interrupt vector : yes
|
||||||
|
hardware watchpoint : yes, count: 4, address/irw mask: [0x0000, 0x0f98, 0x0f78, 0x0df8]
|
||||||
|
ASEs implemented : mips16
|
||||||
|
shadow register sets : 1
|
||||||
|
kscratch registers : 0
|
||||||
|
core : 0
|
||||||
|
VCED exceptions : not available
|
||||||
|
VCEI exceptions : not available
|
||||||
|
)");
|
||||||
|
const auto info = GetMipsInfo();
|
||||||
|
EXPECT_FALSE(info.features.msa);
|
||||||
|
EXPECT_FALSE(info.features.eva);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpuinfoMipsTest, Goldfish) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo", R"(system type : MIPS-Goldfish
|
||||||
|
Hardware : goldfish
|
||||||
|
Revison : 1
|
||||||
|
processor : 0
|
||||||
|
cpu model : MIPS 24Kc V0.0 FPU V0.0
|
||||||
|
BogoMIPS : 1042.02
|
||||||
|
wait instruction : yes
|
||||||
|
microsecond timers : yes
|
||||||
|
tlb_entries : 16
|
||||||
|
extra interrupt vector : yes
|
||||||
|
hardware watchpoint : yes, count: 1, address/irw mask: [0x0ff8]
|
||||||
|
ASEs implemented :
|
||||||
|
shadow register sets : 1
|
||||||
|
core : 0
|
||||||
|
VCED exceptions : not available
|
||||||
|
VCEI exceptions : not available
|
||||||
|
)");
|
||||||
|
const auto info = GetMipsInfo();
|
||||||
|
EXPECT_FALSE(info.features.msa);
|
||||||
|
EXPECT_FALSE(info.features.eva);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
// Copyright 2018 IBM.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "cpuinfo_ppc.h"
|
||||||
|
|
||||||
|
#include "filesystem_for_testing.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "hwcaps_for_testing.h"
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
|
||||||
|
|
||||||
|
TEST(CpustringsPPCTest, FromHardwareCap) {
|
||||||
|
SetHardwareCapabilities(PPC_FEATURE_HAS_FPU | PPC_FEATURE_HAS_VSX,
|
||||||
|
PPC_FEATURE2_ARCH_3_00);
|
||||||
|
GetEmptyFilesystem(); // disabling /proc/cpuinfo
|
||||||
|
const auto info = GetPPCInfo();
|
||||||
|
EXPECT_TRUE(info.features.fpu);
|
||||||
|
EXPECT_FALSE(info.features.mmu);
|
||||||
|
EXPECT_TRUE(info.features.vsx);
|
||||||
|
EXPECT_TRUE(info.features.arch300);
|
||||||
|
EXPECT_FALSE(info.features.power4);
|
||||||
|
EXPECT_FALSE(info.features.altivec);
|
||||||
|
EXPECT_FALSE(info.features.vcrypto);
|
||||||
|
EXPECT_FALSE(info.features.htm);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpustringsPPCTest, Blade) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(processor : 14
|
||||||
|
cpu : POWER7 (architected), altivec supported
|
||||||
|
clock : 3000.000000MHz
|
||||||
|
revision : 2.1 (pvr 003f 0201)
|
||||||
|
|
||||||
|
processor : 15
|
||||||
|
cpu : POWER7 (architected), altivec supported
|
||||||
|
clock : 3000.000000MHz
|
||||||
|
revision : 2.1 (pvr 003f 0201)
|
||||||
|
|
||||||
|
timebase : 512000000
|
||||||
|
platform : pSeries
|
||||||
|
model : IBM,8406-70Y
|
||||||
|
machine : CHRP IBM,8406-70Y)");
|
||||||
|
SetPlatformTypes("power7", "power8");
|
||||||
|
const auto strings = GetPPCPlatformStrings();
|
||||||
|
ASSERT_STREQ(strings.platform, "pSeries");
|
||||||
|
ASSERT_STREQ(strings.model, "IBM,8406-70Y");
|
||||||
|
ASSERT_STREQ(strings.machine, "CHRP IBM,8406-70Y");
|
||||||
|
ASSERT_STREQ(strings.cpu, "POWER7 (architected), altivec supported");
|
||||||
|
ASSERT_STREQ(strings.type.platform, "power7");
|
||||||
|
ASSERT_STREQ(strings.type.base_platform, "power8");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpustringsPPCTest, Firestone) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(processor : 126
|
||||||
|
cpu : POWER8 (raw), altivec supported
|
||||||
|
clock : 2061.000000MHz
|
||||||
|
revision : 2.0 (pvr 004d 0200)
|
||||||
|
|
||||||
|
processor : 127
|
||||||
|
cpu : POWER8 (raw), altivec supported
|
||||||
|
clock : 2061.000000MHz
|
||||||
|
revision : 2.0 (pvr 004d 0200)
|
||||||
|
|
||||||
|
timebase : 512000000
|
||||||
|
platform : PowerNV
|
||||||
|
model : 8335-GTA
|
||||||
|
machine : PowerNV 8335-GTA
|
||||||
|
firmware : OPAL v3)");
|
||||||
|
const auto strings = GetPPCPlatformStrings();
|
||||||
|
ASSERT_STREQ(strings.platform, "PowerNV");
|
||||||
|
ASSERT_STREQ(strings.model, "8335-GTA");
|
||||||
|
ASSERT_STREQ(strings.machine, "PowerNV 8335-GTA");
|
||||||
|
ASSERT_STREQ(strings.cpu, "POWER8 (raw), altivec supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpustringsPPCTest, w8) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(processor : 143
|
||||||
|
cpu : POWER9, altivec supported
|
||||||
|
clock : 2300.000000MHz
|
||||||
|
revision : 2.2 (pvr 004e 1202)
|
||||||
|
|
||||||
|
timebase : 512000000
|
||||||
|
platform : PowerNV
|
||||||
|
model : 0000000000000000
|
||||||
|
machine : PowerNV 0000000000000000
|
||||||
|
firmware : OPAL
|
||||||
|
MMU : Radix)");
|
||||||
|
const auto strings = GetPPCPlatformStrings();
|
||||||
|
ASSERT_STREQ(strings.platform, "PowerNV");
|
||||||
|
ASSERT_STREQ(strings.model, "0000000000000000");
|
||||||
|
ASSERT_STREQ(strings.machine, "PowerNV 0000000000000000");
|
||||||
|
ASSERT_STREQ(strings.cpu, "POWER9, altivec supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
@ -0,0 +1,533 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "cpuinfo_x86.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#if defined(CPU_FEATURES_OS_WINDOWS)
|
||||||
|
#include <windows.h> // IsProcessorFeaturePresent
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
|
||||||
|
#include "filesystem_for_testing.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "internal/cpuid_x86.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
|
||||||
|
class FakeCpu {
|
||||||
|
public:
|
||||||
|
Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) const {
|
||||||
|
const auto itr = cpuid_leaves_.find(std::make_pair(leaf_id, ecx));
|
||||||
|
if (itr != cpuid_leaves_.end()) {
|
||||||
|
return itr->second;
|
||||||
|
}
|
||||||
|
return {0, 0, 0, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GetXCR0Eax() const { return xcr0_eax_; }
|
||||||
|
|
||||||
|
void SetLeaves(std::map<std::pair<uint32_t, int>, Leaf> configuration) {
|
||||||
|
cpuid_leaves_ = std::move(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetOsBackupsExtendedRegisters(bool os_backups_extended_registers) {
|
||||||
|
xcr0_eax_ = os_backups_extended_registers ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_OS_DARWIN)
|
||||||
|
bool GetDarwinSysCtlByName(std::string name) const {
|
||||||
|
return darwin_sysctlbyname_.count(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetDarwinSysCtlByName(std::string name) {
|
||||||
|
darwin_sysctlbyname_.insert(name);
|
||||||
|
}
|
||||||
|
#endif // CPU_FEATURES_OS_DARWIN
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_OS_WINDOWS)
|
||||||
|
bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) {
|
||||||
|
return windows_isprocessorfeaturepresent_.count(ProcessorFeature);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) {
|
||||||
|
windows_isprocessorfeaturepresent_.insert(ProcessorFeature);
|
||||||
|
}
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<std::pair<uint32_t, int>, Leaf> cpuid_leaves_;
|
||||||
|
#if defined(CPU_FEATURES_OS_DARWIN)
|
||||||
|
std::set<std::string> darwin_sysctlbyname_;
|
||||||
|
#endif // CPU_FEATURES_OS_DARWIN
|
||||||
|
#if defined(CPU_FEATURES_OS_WINDOWS)
|
||||||
|
std::set<DWORD> windows_isprocessorfeaturepresent_;
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
uint32_t xcr0_eax_;
|
||||||
|
};
|
||||||
|
|
||||||
|
FakeCpu* g_fake_cpu = nullptr;
|
||||||
|
|
||||||
|
extern "C" Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) {
|
||||||
|
return g_fake_cpu->GetCpuidLeaf(leaf_id, ecx);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" uint32_t GetXCR0Eax(void) { return g_fake_cpu->GetXCR0Eax(); }
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_OS_DARWIN)
|
||||||
|
extern "C" bool GetDarwinSysCtlByName(const char* name) {
|
||||||
|
return g_fake_cpu->GetDarwinSysCtlByName(name);
|
||||||
|
}
|
||||||
|
#endif // CPU_FEATURES_OS_DARWIN
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_OS_WINDOWS)
|
||||||
|
extern "C" bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) {
|
||||||
|
return g_fake_cpu->GetWindowsIsProcessorFeaturePresent(ProcessorFeature);
|
||||||
|
}
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class CpuidX86Test : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
void SetUp() override { g_fake_cpu = new FakeCpu(); }
|
||||||
|
void TearDown() override { delete g_fake_cpu; }
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(CpuidX86Test, SandyBridge) {
|
||||||
|
g_fake_cpu->SetOsBackupsExtendedRegisters(true);
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}},
|
||||||
|
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
});
|
||||||
|
const auto info = GetX86Info();
|
||||||
|
EXPECT_STREQ(info.vendor, "GenuineIntel");
|
||||||
|
EXPECT_EQ(info.family, 0x06);
|
||||||
|
EXPECT_EQ(info.model, 0x02A);
|
||||||
|
EXPECT_EQ(info.stepping, 0x06);
|
||||||
|
// Leaf 7 is zeroed out so none of the Leaf 7 flags are set.
|
||||||
|
const auto features = info.features;
|
||||||
|
EXPECT_FALSE(features.erms);
|
||||||
|
EXPECT_FALSE(features.avx2);
|
||||||
|
EXPECT_FALSE(features.avx512f);
|
||||||
|
EXPECT_FALSE(features.avx512cd);
|
||||||
|
EXPECT_FALSE(features.avx512er);
|
||||||
|
EXPECT_FALSE(features.avx512pf);
|
||||||
|
EXPECT_FALSE(features.avx512bw);
|
||||||
|
EXPECT_FALSE(features.avx512dq);
|
||||||
|
EXPECT_FALSE(features.avx512vl);
|
||||||
|
EXPECT_FALSE(features.avx512ifma);
|
||||||
|
EXPECT_FALSE(features.avx512vbmi);
|
||||||
|
EXPECT_FALSE(features.avx512vbmi2);
|
||||||
|
EXPECT_FALSE(features.avx512vnni);
|
||||||
|
EXPECT_FALSE(features.avx512bitalg);
|
||||||
|
EXPECT_FALSE(features.avx512vpopcntdq);
|
||||||
|
EXPECT_FALSE(features.avx512_4vnniw);
|
||||||
|
EXPECT_FALSE(features.avx512_4fmaps);
|
||||||
|
// All old cpu features should be set.
|
||||||
|
EXPECT_TRUE(features.aes);
|
||||||
|
EXPECT_TRUE(features.ssse3);
|
||||||
|
EXPECT_TRUE(features.sse4_1);
|
||||||
|
EXPECT_TRUE(features.sse4_2);
|
||||||
|
EXPECT_TRUE(features.avx);
|
||||||
|
EXPECT_FALSE(features.sha);
|
||||||
|
EXPECT_TRUE(features.popcnt);
|
||||||
|
EXPECT_FALSE(features.movbe);
|
||||||
|
EXPECT_FALSE(features.rdrnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int KiB = 1024;
|
||||||
|
const int MiB = 1024 * KiB;
|
||||||
|
|
||||||
|
TEST_F(CpuidX86Test, SandyBridgeTestOsSupport) {
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}},
|
||||||
|
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
});
|
||||||
|
// avx is disabled if os does not support backing up ymm registers.
|
||||||
|
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
|
||||||
|
EXPECT_FALSE(GetX86Info().features.avx);
|
||||||
|
// avx is disabled if os does not support backing up ymm registers.
|
||||||
|
g_fake_cpu->SetOsBackupsExtendedRegisters(true);
|
||||||
|
EXPECT_TRUE(GetX86Info().features.avx);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CpuidX86Test, SkyLake) {
|
||||||
|
g_fake_cpu->SetOsBackupsExtendedRegisters(true);
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
|
||||||
|
{{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
|
||||||
|
});
|
||||||
|
const auto info = GetX86Info();
|
||||||
|
EXPECT_STREQ(info.vendor, "GenuineIntel");
|
||||||
|
EXPECT_EQ(info.family, 0x06);
|
||||||
|
EXPECT_EQ(info.model, 0x04E);
|
||||||
|
EXPECT_EQ(info.stepping, 0x03);
|
||||||
|
EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_SKL);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CpuidX86Test, Branding) {
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
|
||||||
|
{{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}},
|
||||||
|
{{0x80000002, 0}, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}},
|
||||||
|
{{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}},
|
||||||
|
{{0x80000004, 0}, Leaf{0x352E3220, 0x7A484730, 0x00000000, 0x00000000}},
|
||||||
|
});
|
||||||
|
char brand_string[49];
|
||||||
|
FillX86BrandString(brand_string);
|
||||||
|
EXPECT_STREQ(brand_string, "Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CpuidX86Test, KabyLakeCache) {
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
|
||||||
|
{{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}},
|
||||||
|
{{0x00000004, 1}, Leaf{0x1C004122, 0x01C0003F, 0x0000003F, 0x00000000}},
|
||||||
|
{{0x00000004, 2}, Leaf{0x1C004143, 0x00C0003F, 0x000003FF, 0x00000000}},
|
||||||
|
{{0x00000004, 3}, Leaf{0x1C03C163, 0x02C0003F, 0x00001FFF, 0x00000002}},
|
||||||
|
{{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}},
|
||||||
|
{{0x80000002, 0}, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}},
|
||||||
|
{{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}},
|
||||||
|
});
|
||||||
|
const auto info = GetX86CacheInfo();
|
||||||
|
EXPECT_EQ(info.size, 4);
|
||||||
|
EXPECT_EQ(info.levels[0].level, 1);
|
||||||
|
EXPECT_EQ(info.levels[0].cache_type, 1);
|
||||||
|
EXPECT_EQ(info.levels[0].cache_size, 32 * KiB);
|
||||||
|
EXPECT_EQ(info.levels[0].ways, 8);
|
||||||
|
EXPECT_EQ(info.levels[0].line_size, 64);
|
||||||
|
EXPECT_EQ(info.levels[0].tlb_entries, 64);
|
||||||
|
EXPECT_EQ(info.levels[0].partitioning, 1);
|
||||||
|
|
||||||
|
EXPECT_EQ(info.levels[1].level, 1);
|
||||||
|
EXPECT_EQ(info.levels[1].cache_type, 2);
|
||||||
|
EXPECT_EQ(info.levels[1].cache_size, 32 * KiB);
|
||||||
|
EXPECT_EQ(info.levels[1].ways, 8);
|
||||||
|
EXPECT_EQ(info.levels[1].line_size, 64);
|
||||||
|
EXPECT_EQ(info.levels[1].tlb_entries, 64);
|
||||||
|
EXPECT_EQ(info.levels[1].partitioning, 1);
|
||||||
|
|
||||||
|
EXPECT_EQ(info.levels[2].level, 2);
|
||||||
|
EXPECT_EQ(info.levels[2].cache_type, 3);
|
||||||
|
EXPECT_EQ(info.levels[2].cache_size, 256 * KiB);
|
||||||
|
EXPECT_EQ(info.levels[2].ways, 4);
|
||||||
|
EXPECT_EQ(info.levels[2].line_size, 64);
|
||||||
|
EXPECT_EQ(info.levels[2].tlb_entries, 1024);
|
||||||
|
EXPECT_EQ(info.levels[2].partitioning, 1);
|
||||||
|
|
||||||
|
EXPECT_EQ(info.levels[3].level, 3);
|
||||||
|
EXPECT_EQ(info.levels[3].cache_type, 3);
|
||||||
|
EXPECT_EQ(info.levels[3].cache_size, 6 * MiB);
|
||||||
|
EXPECT_EQ(info.levels[3].ways, 12);
|
||||||
|
EXPECT_EQ(info.levels[3].line_size, 64);
|
||||||
|
EXPECT_EQ(info.levels[3].tlb_entries, 8192);
|
||||||
|
EXPECT_EQ(info.levels[3].partitioning, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CpuidX86Test, HSWCache) {
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
|
||||||
|
{{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}},
|
||||||
|
{{0x00000004, 1}, Leaf{0x1C004122, 0x01C0003F, 0x0000003F, 0x00000000}},
|
||||||
|
{{0x00000004, 2}, Leaf{0x1C004143, 0x01C0003F, 0x000001FF, 0x00000000}},
|
||||||
|
{{0x00000004, 3}, Leaf{0x1C03C163, 0x02C0003F, 0x00001FFF, 0x00000006}},
|
||||||
|
{{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}},
|
||||||
|
{{0x80000002, 0}, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}},
|
||||||
|
{{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}},
|
||||||
|
});
|
||||||
|
const auto info = GetX86CacheInfo();
|
||||||
|
EXPECT_EQ(info.size, 4);
|
||||||
|
EXPECT_EQ(info.levels[0].level, 1);
|
||||||
|
EXPECT_EQ(info.levels[0].cache_type, 1);
|
||||||
|
EXPECT_EQ(info.levels[0].cache_size, 32 * KiB);
|
||||||
|
EXPECT_EQ(info.levels[0].ways, 8);
|
||||||
|
EXPECT_EQ(info.levels[0].line_size, 64);
|
||||||
|
EXPECT_EQ(info.levels[0].tlb_entries, 64);
|
||||||
|
EXPECT_EQ(info.levels[0].partitioning, 1);
|
||||||
|
|
||||||
|
EXPECT_EQ(info.levels[1].level, 1);
|
||||||
|
EXPECT_EQ(info.levels[1].cache_type, 2);
|
||||||
|
EXPECT_EQ(info.levels[1].cache_size, 32 * KiB);
|
||||||
|
EXPECT_EQ(info.levels[1].ways, 8);
|
||||||
|
EXPECT_EQ(info.levels[1].line_size, 64);
|
||||||
|
EXPECT_EQ(info.levels[1].tlb_entries, 64);
|
||||||
|
EXPECT_EQ(info.levels[1].partitioning, 1);
|
||||||
|
|
||||||
|
EXPECT_EQ(info.levels[2].level, 2);
|
||||||
|
EXPECT_EQ(info.levels[2].cache_type, 3);
|
||||||
|
EXPECT_EQ(info.levels[2].cache_size, 256 * KiB);
|
||||||
|
EXPECT_EQ(info.levels[2].ways, 8);
|
||||||
|
EXPECT_EQ(info.levels[2].line_size, 64);
|
||||||
|
EXPECT_EQ(info.levels[2].tlb_entries, 512);
|
||||||
|
EXPECT_EQ(info.levels[2].partitioning, 1);
|
||||||
|
|
||||||
|
EXPECT_EQ(info.levels[3].level, 3);
|
||||||
|
EXPECT_EQ(info.levels[3].cache_type, 3);
|
||||||
|
EXPECT_EQ(info.levels[3].cache_size, 6 * MiB);
|
||||||
|
EXPECT_EQ(info.levels[3].ways, 12);
|
||||||
|
EXPECT_EQ(info.levels[3].line_size, 64);
|
||||||
|
EXPECT_EQ(info.levels[3].tlb_entries, 8192);
|
||||||
|
EXPECT_EQ(info.levels[3].partitioning, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://users.atw.hu/instlatx64/AuthenticAMD0630F81_K15_Godavari_CPUID.txt
|
||||||
|
TEST_F(CpuidX86Test, AMD_K15) {
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x00630F81, 0x00040800, 0x3E98320B, 0x178BFBFF}},
|
||||||
|
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||||
|
{{0x80000001, 0}, Leaf{0x00630F81, 0x10000000, 0x0FEBBFFF, 0x2FD3FBFF}},
|
||||||
|
{{0x80000002, 0}, Leaf{0x20444D41, 0x372D3841, 0x4B303736, 0x64615220}},
|
||||||
|
{{0x80000003, 0}, Leaf{0x206E6F65, 0x202C3752, 0x43203031, 0x75706D6F}},
|
||||||
|
{{0x80000004, 0}, Leaf{0x43206574, 0x7365726F, 0x2B433420, 0x00204736}},
|
||||||
|
{{0x80000005, 0}, Leaf{0xFF40FF18, 0xFF40FF30, 0x10040140, 0x60030140}},
|
||||||
|
});
|
||||||
|
const auto info = GetX86Info();
|
||||||
|
|
||||||
|
EXPECT_STREQ(info.vendor, "AuthenticAMD");
|
||||||
|
EXPECT_EQ(info.family, 0x15);
|
||||||
|
EXPECT_EQ(info.model, 0x38);
|
||||||
|
EXPECT_EQ(info.stepping, 0x01);
|
||||||
|
EXPECT_EQ(GetX86Microarchitecture(&info),
|
||||||
|
X86Microarchitecture::AMD_BULLDOZER);
|
||||||
|
|
||||||
|
char brand_string[49];
|
||||||
|
FillX86BrandString(brand_string);
|
||||||
|
EXPECT_STREQ(brand_string, "AMD A8-7670K Radeon R7, 10 Compute Cores 4C+6G ");
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel00106A1_Nehalem_CPUID.txt
|
||||||
|
TEST_F(CpuidX86Test, Nehalem) {
|
||||||
|
// Pre AVX cpus don't have xsave
|
||||||
|
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
|
||||||
|
#if defined(CPU_FEATURES_OS_WINDOWS)
|
||||||
|
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||||
|
PF_XMMI_INSTRUCTIONS_AVAILABLE);
|
||||||
|
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||||
|
PF_XMMI64_INSTRUCTIONS_AVAILABLE);
|
||||||
|
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||||
|
PF_SSE3_INSTRUCTIONS_AVAILABLE);
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
#if defined(CPU_FEATURES_OS_DARWIN)
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse2");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse3");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.supplementalsse3");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_1");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_2");
|
||||||
|
#endif // CPU_FEATURES_OS_DARWIN
|
||||||
|
#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo", R"(processor :
|
||||||
|
flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
|
||||||
|
)");
|
||||||
|
#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x000106A2, 0x00100800, 0x00BCE3BD, 0xBFEBFBFF}},
|
||||||
|
{{0x00000002, 0}, Leaf{0x55035A01, 0x00F0B0E3, 0x00000000, 0x09CA212C}},
|
||||||
|
{{0x00000003, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}},
|
||||||
|
{{0x00000004, 0}, Leaf{0x1C004122, 0x00C0003F, 0x0000007F, 0x00000000}},
|
||||||
|
{{0x00000004, 0}, Leaf{0x1C004143, 0x01C0003F, 0x000001FF, 0x00000000}},
|
||||||
|
{{0x00000004, 0}, Leaf{0x1C03C163, 0x03C0003F, 0x00000FFF, 0x00000002}},
|
||||||
|
{{0x00000005, 0}, Leaf{0x00000040, 0x00000040, 0x00000003, 0x00021120}},
|
||||||
|
{{0x00000006, 0}, Leaf{0x00000001, 0x00000002, 0x00000001, 0x00000000}},
|
||||||
|
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x00000008, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x00000009, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x0000000A, 0}, Leaf{0x07300403, 0x00000000, 0x00000000, 0x00000603}},
|
||||||
|
{{0x0000000B, 0}, Leaf{0x00000001, 0x00000001, 0x00000100, 0x00000000}},
|
||||||
|
{{0x0000000B, 0}, Leaf{0x00000004, 0x00000002, 0x00000201, 0x00000000}},
|
||||||
|
{{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000001, 0x28100000}},
|
||||||
|
{{0x80000002, 0}, Leaf{0x756E6547, 0x20656E69, 0x65746E49, 0x2952286C}},
|
||||||
|
{{0x80000003, 0}, Leaf{0x55504320, 0x20202020, 0x20202020, 0x40202020}},
|
||||||
|
{{0x80000004, 0}, Leaf{0x30303020, 0x20402030, 0x37382E31, 0x007A4847}},
|
||||||
|
{{0x80000005, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000006, 0}, Leaf{0x00000000, 0x00000000, 0x01006040, 0x00000000}},
|
||||||
|
{{0x80000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000100}},
|
||||||
|
{{0x80000008, 0}, Leaf{0x00003028, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
});
|
||||||
|
const auto info = GetX86Info();
|
||||||
|
|
||||||
|
EXPECT_STREQ(info.vendor, "GenuineIntel");
|
||||||
|
EXPECT_EQ(info.family, 0x06);
|
||||||
|
EXPECT_EQ(info.model, 0x1A);
|
||||||
|
EXPECT_EQ(info.stepping, 0x02);
|
||||||
|
EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_NHM);
|
||||||
|
|
||||||
|
char brand_string[49];
|
||||||
|
FillX86BrandString(brand_string);
|
||||||
|
EXPECT_STREQ(brand_string, "Genuine Intel(R) CPU @ 0000 @ 1.87GHz");
|
||||||
|
|
||||||
|
EXPECT_TRUE(info.features.sse);
|
||||||
|
EXPECT_TRUE(info.features.sse2);
|
||||||
|
EXPECT_TRUE(info.features.sse3);
|
||||||
|
#ifndef CPU_FEATURES_OS_WINDOWS
|
||||||
|
// Currently disabled on Windows as IsProcessorFeaturePresent do not support
|
||||||
|
// feature detection > sse3.
|
||||||
|
EXPECT_TRUE(info.features.ssse3);
|
||||||
|
EXPECT_TRUE(info.features.sse4_1);
|
||||||
|
EXPECT_TRUE(info.features.sse4_2);
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0030673_Silvermont3_CPUID.txt
|
||||||
|
TEST_F(CpuidX86Test, Atom) {
|
||||||
|
// Pre AVX cpus don't have xsave
|
||||||
|
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
|
||||||
|
#if defined(CPU_FEATURES_OS_WINDOWS)
|
||||||
|
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||||
|
PF_XMMI_INSTRUCTIONS_AVAILABLE);
|
||||||
|
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||||
|
PF_XMMI64_INSTRUCTIONS_AVAILABLE);
|
||||||
|
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||||
|
PF_SSE3_INSTRUCTIONS_AVAILABLE);
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
#if defined(CPU_FEATURES_OS_DARWIN)
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse2");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse3");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.supplementalsse3");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_1");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_2");
|
||||||
|
#endif // CPU_FEATURES_OS_DARWIN
|
||||||
|
#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo", R"(
|
||||||
|
flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
|
||||||
|
)");
|
||||||
|
#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x00030673, 0x00100800, 0x41D8E3BF, 0xBFEBFBFF}},
|
||||||
|
{{0x00000002, 0}, Leaf{0x61B3A001, 0x0000FFC2, 0x00000000, 0x00000000}},
|
||||||
|
{{0x00000003, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x00000004, 0}, Leaf{0x1C000121, 0x0140003F, 0x0000003F, 0x00000001}},
|
||||||
|
{{0x00000004, 1}, Leaf{0x1C000122, 0x01C0003F, 0x0000003F, 0x00000001}},
|
||||||
|
{{0x00000004, 2}, Leaf{0x1C00C143, 0x03C0003F, 0x000003FF, 0x00000001}},
|
||||||
|
{{0x00000005, 0}, Leaf{0x00000040, 0x00000040, 0x00000003, 0x33000020}},
|
||||||
|
{{0x00000006, 0}, Leaf{0x00000005, 0x00000002, 0x00000009, 0x00000000}},
|
||||||
|
{{0x00000007, 0}, Leaf{0x00000000, 0x00002282, 0x00000000, 0x00000000}},
|
||||||
|
{{0x00000008, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x00000009, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x0000000A, 0}, Leaf{0x07280203, 0x00000000, 0x00000000, 0x00004503}},
|
||||||
|
{{0x0000000B, 0}, Leaf{0x00000001, 0x00000001, 0x00000100, 0x00000000}},
|
||||||
|
{{0x0000000B, 1}, Leaf{0x00000004, 0x00000004, 0x00000201, 0x00000000}},
|
||||||
|
{{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000101, 0x28100000}},
|
||||||
|
{{0x80000002, 0}, Leaf{0x20202020, 0x6E492020, 0x286C6574, 0x43202952}},
|
||||||
|
{{0x80000003, 0}, Leaf{0x72656C65, 0x52286E6F, 0x50432029, 0x4A202055}},
|
||||||
|
{{0x80000004, 0}, Leaf{0x30303931, 0x20402020, 0x39392E31, 0x007A4847}},
|
||||||
|
{{0x80000005, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000006, 0}, Leaf{0x00000000, 0x00000000, 0x04008040, 0x00000000}},
|
||||||
|
{{0x80000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000100}},
|
||||||
|
{{0x80000008, 0}, Leaf{0x00003024, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
});
|
||||||
|
const auto info = GetX86Info();
|
||||||
|
|
||||||
|
EXPECT_STREQ(info.vendor, "GenuineIntel");
|
||||||
|
EXPECT_EQ(info.family, 0x06);
|
||||||
|
EXPECT_EQ(info.model, 0x37);
|
||||||
|
EXPECT_EQ(info.stepping, 0x03);
|
||||||
|
EXPECT_EQ(GetX86Microarchitecture(&info),
|
||||||
|
X86Microarchitecture::INTEL_ATOM_SMT);
|
||||||
|
|
||||||
|
char brand_string[49];
|
||||||
|
FillX86BrandString(brand_string);
|
||||||
|
EXPECT_STREQ(brand_string, " Intel(R) Celeron(R) CPU J1900 @ 1.99GHz");
|
||||||
|
|
||||||
|
EXPECT_TRUE(info.features.sse);
|
||||||
|
EXPECT_TRUE(info.features.sse2);
|
||||||
|
EXPECT_TRUE(info.features.sse3);
|
||||||
|
#ifndef CPU_FEATURES_OS_WINDOWS
|
||||||
|
// Currently disabled on Windows as IsProcessorFeaturePresent do not support
|
||||||
|
// feature detection > sse3.
|
||||||
|
EXPECT_TRUE(info.features.ssse3);
|
||||||
|
EXPECT_TRUE(info.features.sse4_1);
|
||||||
|
EXPECT_TRUE(info.features.sse4_2);
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000673_P3_KatmaiDP_CPUID.txt
|
||||||
|
TEST_F(CpuidX86Test, P3) {
|
||||||
|
// Pre AVX cpus don't have xsave
|
||||||
|
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
|
||||||
|
#if defined(CPU_FEATURES_OS_WINDOWS)
|
||||||
|
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||||
|
PF_XMMI_INSTRUCTIONS_AVAILABLE);
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
#if defined(CPU_FEATURES_OS_DARWIN)
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
|
||||||
|
#endif // CPU_FEATURES_OS_DARWIN
|
||||||
|
#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo", R"(
|
||||||
|
flags : fpu mmx sse
|
||||||
|
)");
|
||||||
|
#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x00000003, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x00000673, 0x00000000, 0x00000000, 0x0387FBFF}},
|
||||||
|
{{0x00000002, 0}, Leaf{0x03020101, 0x00000000, 0x00000000, 0x0C040843}},
|
||||||
|
{{0x00000003, 0}, Leaf{0x00000000, 0x00000000, 0x4CECC782, 0x00006778}},
|
||||||
|
});
|
||||||
|
const auto info = GetX86Info();
|
||||||
|
|
||||||
|
EXPECT_STREQ(info.vendor, "GenuineIntel");
|
||||||
|
EXPECT_EQ(info.family, 0x06);
|
||||||
|
EXPECT_EQ(info.model, 0x07);
|
||||||
|
EXPECT_EQ(info.stepping, 0x03);
|
||||||
|
EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::X86_UNKNOWN);
|
||||||
|
|
||||||
|
char brand_string[49];
|
||||||
|
FillX86BrandString(brand_string);
|
||||||
|
EXPECT_STREQ(brand_string, "");
|
||||||
|
|
||||||
|
EXPECT_TRUE(info.features.mmx);
|
||||||
|
EXPECT_TRUE(info.features.sse);
|
||||||
|
EXPECT_FALSE(info.features.sse2);
|
||||||
|
EXPECT_FALSE(info.features.sse3);
|
||||||
|
#ifndef CPU_FEATURES_OS_WINDOWS
|
||||||
|
// Currently disabled on Windows as IsProcessorFeaturePresent do not support
|
||||||
|
// feature detection > sse3.
|
||||||
|
EXPECT_FALSE(info.features.ssse3);
|
||||||
|
EXPECT_FALSE(info.features.sse4_1);
|
||||||
|
EXPECT_FALSE(info.features.sse4_2);
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(user): test what happens when xsave/osxsave are not present.
|
||||||
|
// TODO(user): test what happens when xmm/ymm/zmm os support are not
|
||||||
|
// present.
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "filesystem_for_testing.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <climits>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
|
||||||
|
FakeFile::FakeFile(int file_descriptor, const char* content)
|
||||||
|
: file_descriptor_(file_descriptor), content_(content) {}
|
||||||
|
|
||||||
|
FakeFile::~FakeFile() { assert(!opened_); }
|
||||||
|
|
||||||
|
void FakeFile::Open() {
|
||||||
|
assert(!opened_);
|
||||||
|
opened_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FakeFile::Close() {
|
||||||
|
assert(opened_);
|
||||||
|
opened_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FakeFile::Read(int fd, void* buf, size_t count) {
|
||||||
|
assert(count < INT_MAX);
|
||||||
|
assert(fd == file_descriptor_);
|
||||||
|
const size_t remainder = content_.size() - head_index_;
|
||||||
|
const size_t read = count > remainder ? remainder : count;
|
||||||
|
memcpy(buf, content_.data() + head_index_, read);
|
||||||
|
head_index_ += read;
|
||||||
|
assert(read < INT_MAX);
|
||||||
|
return (int)read;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FakeFilesystem::Reset() { files_.clear(); }
|
||||||
|
|
||||||
|
FakeFile* FakeFilesystem::CreateFile(const std::string& filename,
|
||||||
|
const char* content) {
|
||||||
|
auto& file = files_[filename];
|
||||||
|
file =
|
||||||
|
std::unique_ptr<FakeFile>(new FakeFile(next_file_descriptor_++, content));
|
||||||
|
return file.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
FakeFile* FakeFilesystem::FindFileOrNull(const std::string& filename) const {
|
||||||
|
const auto itr = files_.find(filename);
|
||||||
|
return itr == files_.end() ? nullptr : itr->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
FakeFile* FakeFilesystem::FindFileOrDie(const int file_descriptor) const {
|
||||||
|
for (const auto& filename_file_pair : files_) {
|
||||||
|
FakeFile* const file_ptr = filename_file_pair.second.get();
|
||||||
|
if (file_ptr->GetFileDescriptor() == file_descriptor) {
|
||||||
|
return file_ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(false);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FakeFilesystem* kFilesystem = new FakeFilesystem();
|
||||||
|
|
||||||
|
FakeFilesystem& GetEmptyFilesystem() {
|
||||||
|
kFilesystem->Reset();
|
||||||
|
return *kFilesystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int CpuFeatures_OpenFile(const char* filename) {
|
||||||
|
auto* const file = kFilesystem->FindFileOrNull(filename);
|
||||||
|
if (file) {
|
||||||
|
file->Open();
|
||||||
|
return file->GetFileDescriptor();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void CpuFeatures_CloseFile(int file_descriptor) {
|
||||||
|
kFilesystem->FindFileOrDie(file_descriptor)->Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int CpuFeatures_ReadFile(int file_descriptor, void* buffer,
|
||||||
|
size_t buffer_size) {
|
||||||
|
return kFilesystem->FindFileOrDie(file_descriptor)
|
||||||
|
->Read(file_descriptor, buffer, buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Implements a fake filesystem, useful for tests.
|
||||||
|
#ifndef CPU_FEATURES_TEST_FILESYSTEM_FOR_TESTING_H_
|
||||||
|
#define CPU_FEATURES_TEST_FILESYSTEM_FOR_TESTING_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "internal/filesystem.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
|
||||||
|
class FakeFile {
|
||||||
|
public:
|
||||||
|
explicit FakeFile(int file_descriptor, const char* content);
|
||||||
|
~FakeFile();
|
||||||
|
|
||||||
|
void Open();
|
||||||
|
void Close();
|
||||||
|
int Read(int fd, void* buf, size_t count);
|
||||||
|
|
||||||
|
int GetFileDescriptor() const { return file_descriptor_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const int file_descriptor_;
|
||||||
|
const std::string content_;
|
||||||
|
bool opened_ = false;
|
||||||
|
size_t head_index_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FakeFilesystem {
|
||||||
|
public:
|
||||||
|
void Reset();
|
||||||
|
FakeFile* CreateFile(const std::string& filename, const char* content);
|
||||||
|
FakeFile* FindFileOrDie(const int file_descriptor) const;
|
||||||
|
FakeFile* FindFileOrNull(const std::string& filename) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int next_file_descriptor_ = 0;
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<FakeFile>> files_;
|
||||||
|
};
|
||||||
|
|
||||||
|
FakeFilesystem& GetEmptyFilesystem();
|
||||||
|
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_TEST_FILESYSTEM_FOR_TESTING_H_
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "hwcaps_for_testing.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
static auto* const g_hardware_capabilities = new HardwareCapabilities();
|
||||||
|
static auto* const g_platform_types = new PlatformType();
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void SetHardwareCapabilities(uint32_t hwcaps, uint32_t hwcaps2) {
|
||||||
|
g_hardware_capabilities->hwcaps = hwcaps;
|
||||||
|
g_hardware_capabilities->hwcaps2 = hwcaps2;
|
||||||
|
}
|
||||||
|
|
||||||
|
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) {
|
||||||
|
return *g_hardware_capabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPlatformTypes(const char* platform, const char* base_platform) {
|
||||||
|
CpuFeatures_StringView_CopyString(str(platform), g_platform_types->platform,
|
||||||
|
sizeof(g_platform_types->platform));
|
||||||
|
CpuFeatures_StringView_CopyString(str(base_platform),
|
||||||
|
g_platform_types->base_platform,
|
||||||
|
sizeof(g_platform_types->base_platform));
|
||||||
|
}
|
||||||
|
|
||||||
|
PlatformType CpuFeatures_GetPlatformType(void) { return *g_platform_types; }
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_
|
||||||
|
#define CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_
|
||||||
|
|
||||||
|
#include "internal/hwcaps.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
|
||||||
|
void SetHardwareCapabilities(uint32_t hwcaps, uint32_t hwcaps2);
|
||||||
|
void SetPlatformTypes(const char *platform, const char *base_platform);
|
||||||
|
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "internal/stack_line_reader.h"
|
||||||
|
|
||||||
|
#include "filesystem_for_testing.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
|
||||||
|
bool operator==(const StringView& a, const StringView& b) {
|
||||||
|
return CpuFeatures_StringView_IsEquals(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::string ToString(StringView view) { return {view.ptr, view.size}; }
|
||||||
|
|
||||||
|
TEST(StackLineReaderTest, Empty) {
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
auto* file = fs.CreateFile("/proc/cpuinfo", "");
|
||||||
|
StackLineReader reader;
|
||||||
|
StackLineReader_Initialize(&reader, file->GetFileDescriptor());
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_TRUE(result.eof);
|
||||||
|
EXPECT_TRUE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str(""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StackLineReaderTest, ManySmallLines) {
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
auto* file = fs.CreateFile("/proc/cpuinfo", "a\nb\nc");
|
||||||
|
|
||||||
|
StackLineReader reader;
|
||||||
|
StackLineReader_Initialize(&reader, file->GetFileDescriptor());
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_FALSE(result.eof);
|
||||||
|
EXPECT_TRUE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str("a"));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_FALSE(result.eof);
|
||||||
|
EXPECT_TRUE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str("b"));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_TRUE(result.eof);
|
||||||
|
EXPECT_TRUE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str("c"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StackLineReaderTest, TruncatedLine) {
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
auto* file = fs.CreateFile("/proc/cpuinfo", R"(First
|
||||||
|
Second
|
||||||
|
More than 16 characters, this will be truncated.
|
||||||
|
last)");
|
||||||
|
|
||||||
|
StackLineReader reader;
|
||||||
|
StackLineReader_Initialize(&reader, file->GetFileDescriptor());
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_FALSE(result.eof);
|
||||||
|
EXPECT_TRUE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str("First"));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_FALSE(result.eof);
|
||||||
|
EXPECT_TRUE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str("Second"));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_FALSE(result.eof);
|
||||||
|
EXPECT_FALSE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str("More than 16 cha"));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_TRUE(result.eof);
|
||||||
|
EXPECT_TRUE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str("last"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StackLineReaderTest, TruncatedLines) {
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
auto* file = fs.CreateFile("/proc/cpuinfo", R"(More than 16 characters
|
||||||
|
Another line that is too long)");
|
||||||
|
|
||||||
|
StackLineReader reader;
|
||||||
|
StackLineReader_Initialize(&reader, file->GetFileDescriptor());
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_FALSE(result.eof);
|
||||||
|
EXPECT_FALSE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str("More than 16 cha"));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_FALSE(result.eof);
|
||||||
|
EXPECT_FALSE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str("Another line tha"));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_TRUE(result.eof);
|
||||||
|
EXPECT_TRUE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str(""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
@ -0,0 +1,192 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
|
||||||
|
bool operator==(const StringView& a, const StringView& b) {
|
||||||
|
return CpuFeatures_StringView_IsEquals(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(StringViewTest, Empty) {
|
||||||
|
EXPECT_EQ(kEmptyStringView.ptr, nullptr);
|
||||||
|
EXPECT_EQ(kEmptyStringView.size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, Build) {
|
||||||
|
const auto view = str("test");
|
||||||
|
EXPECT_EQ(view.ptr[0], 't');
|
||||||
|
EXPECT_EQ(view.size, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_IndexOfChar) {
|
||||||
|
// Found.
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 'e'), 1);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 't'), 0);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("beef"), 'e'), 1);
|
||||||
|
// Not found.
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 'z'), -1);
|
||||||
|
// Empty.
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(kEmptyStringView, 'z'), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_IndexOf) {
|
||||||
|
// Found.
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("es")), 1);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("test")), 0);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("tesstest"), str("test")), 4);
|
||||||
|
// Not found.
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("aa")), -1);
|
||||||
|
// Empty.
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOf(kEmptyStringView, str("aa")), -1);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("aa"), kEmptyStringView), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_StartsWith) {
|
||||||
|
EXPECT_TRUE(CpuFeatures_StringView_StartsWith(str("test"), str("te")));
|
||||||
|
EXPECT_TRUE(CpuFeatures_StringView_StartsWith(str("test"), str("test")));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("st")));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("est")));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("")));
|
||||||
|
EXPECT_FALSE(
|
||||||
|
CpuFeatures_StringView_StartsWith(str("test"), kEmptyStringView));
|
||||||
|
EXPECT_FALSE(
|
||||||
|
CpuFeatures_StringView_StartsWith(kEmptyStringView, str("test")));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_IsEquals) {
|
||||||
|
EXPECT_TRUE(
|
||||||
|
CpuFeatures_StringView_IsEquals(kEmptyStringView, kEmptyStringView));
|
||||||
|
EXPECT_TRUE(CpuFeatures_StringView_IsEquals(kEmptyStringView, str("")));
|
||||||
|
EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str(""), kEmptyStringView));
|
||||||
|
EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str("test"), str("test")));
|
||||||
|
EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str("a"), str("a")));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), str("b")));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("aa"), str("a")));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), str("aa")));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), kEmptyStringView));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(kEmptyStringView, str("a")));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_PopFront) {
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 2), str("st"));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 0), str("test"));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 4), str(""));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 100), str(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_PopBack) {
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 2), str("te"));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 0), str("test"));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 4), str(""));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 100), str(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_KeepFront) {
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 2), str("te"));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 0), str(""));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 4), str("test"));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 6), str("test"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_Front) {
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_Front(str("apple")), 'a');
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_Front(str("a")), 'a');
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_Back) {
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_Back(str("apple")), 'e');
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_Back(str("a")), 'a');
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_TrimWhitespace) {
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str(" first middle last ")),
|
||||||
|
str("first middle last"));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("first middle last ")),
|
||||||
|
str("first middle last"));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str(" first middle last")),
|
||||||
|
str("first middle last"));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("first middle last")),
|
||||||
|
str("first middle last"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_ParsePositiveNumber) {
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("42")), 42);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2a")), 42);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2A")), 42);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2A2a")), 10794);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2a2A")), 10794);
|
||||||
|
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("-10")), -1);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("-0x2A")), -1);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("abc")), -1);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("")), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_CopyString) {
|
||||||
|
char buf[4];
|
||||||
|
buf[0] = 'X';
|
||||||
|
|
||||||
|
// Empty
|
||||||
|
CpuFeatures_StringView_CopyString(str(""), buf, sizeof(buf));
|
||||||
|
EXPECT_STREQ(buf, "");
|
||||||
|
|
||||||
|
// Less
|
||||||
|
CpuFeatures_StringView_CopyString(str("a"), buf, sizeof(buf));
|
||||||
|
EXPECT_STREQ(buf, "a");
|
||||||
|
|
||||||
|
// exact
|
||||||
|
CpuFeatures_StringView_CopyString(str("abc"), buf, sizeof(buf));
|
||||||
|
EXPECT_STREQ(buf, "abc");
|
||||||
|
|
||||||
|
// More
|
||||||
|
CpuFeatures_StringView_CopyString(str("abcd"), buf, sizeof(buf));
|
||||||
|
EXPECT_STREQ(buf, "abc");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_HasWord) {
|
||||||
|
// Find flags at beginning, middle and end.
|
||||||
|
EXPECT_TRUE(
|
||||||
|
CpuFeatures_StringView_HasWord(str("first middle last"), "first"));
|
||||||
|
EXPECT_TRUE(
|
||||||
|
CpuFeatures_StringView_HasWord(str("first middle last"), "middle"));
|
||||||
|
EXPECT_TRUE(CpuFeatures_StringView_HasWord(str("first middle last"), "last"));
|
||||||
|
// Do not match partial flags
|
||||||
|
EXPECT_FALSE(
|
||||||
|
CpuFeatures_StringView_HasWord(str("first middle last"), "irst"));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_HasWord(str("first middle last"), "mid"));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_HasWord(str("first middle last"), "las"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_GetAttributeKeyValue) {
|
||||||
|
const StringView line = str(" key : first middle last ");
|
||||||
|
StringView key, value;
|
||||||
|
EXPECT_TRUE(CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value));
|
||||||
|
EXPECT_EQ(key, str("key"));
|
||||||
|
EXPECT_EQ(value, str("first middle last"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, FailingGetAttributeKeyValue) {
|
||||||
|
const StringView line = str("key first middle last");
|
||||||
|
StringView key, value;
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace cpu_features
|
||||||
11
crc.c
11
crc.c
|
|
@ -62,7 +62,7 @@ static void initLookupTables()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t modesChecksum(uint8_t *message, int bits)
|
uint32_t modesChecksum(const uint8_t *message, int bits)
|
||||||
{
|
{
|
||||||
uint32_t rem = 0;
|
uint32_t rem = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -197,7 +197,7 @@ static struct errorinfo *prepareErrorTable(int bits, int max_correct, int max_de
|
||||||
|
|
||||||
maxsize = 0;
|
maxsize = 0;
|
||||||
for (i = 1; i <= max_correct; ++i) {
|
for (i = 1; i <= max_correct; ++i) {
|
||||||
maxsize += combinations(bits - 5, i); // space needed for all i-bit errors
|
maxsize += combinations(bits, i); // space needed for all i-bit errors
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CRCDEBUG
|
#ifdef CRCDEBUG
|
||||||
|
|
@ -210,8 +210,7 @@ static struct errorinfo *prepareErrorTable(int bits, int max_correct, int max_de
|
||||||
for (i = 0; i < MODES_MAX_BITERRORS; ++i)
|
for (i = 0; i < MODES_MAX_BITERRORS; ++i)
|
||||||
base_entry.bit[i] = -1;
|
base_entry.bit[i] = -1;
|
||||||
|
|
||||||
// ignore the first 5 bits (DF type)
|
usedsize = prepareSubtable(table, 0, maxsize, 112 - bits, 0, bits, &base_entry, 0, max_correct);
|
||||||
usedsize = prepareSubtable(table, 0, maxsize, 112 - bits, 5, bits, &base_entry, 0, max_correct);
|
|
||||||
|
|
||||||
#ifdef CRCDEBUG
|
#ifdef CRCDEBUG
|
||||||
fprintf(stderr, "%d syndromes (expected %d).\n", usedsize, maxsize);
|
fprintf(stderr, "%d syndromes (expected %d).\n", usedsize, maxsize);
|
||||||
|
|
@ -273,7 +272,7 @@ static struct errorinfo *prepareErrorTable(int bits, int max_correct, int max_de
|
||||||
fprintf(stderr, "Flagging collisions between %d - %d bits..\n", max_correct+1, max_detect);
|
fprintf(stderr, "Flagging collisions between %d - %d bits..\n", max_correct+1, max_detect);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
flagged = flagCollisions(table, usedsize, 112 - bits, 5, bits, 0, 1, max_correct+1, max_detect);
|
flagged = flagCollisions(table, usedsize, 112 - bits, 0, bits, 0, 1, max_correct+1, max_detect);
|
||||||
|
|
||||||
#ifdef CRCDEBUG
|
#ifdef CRCDEBUG
|
||||||
fprintf(stderr, "Flagged %d collisions for removal.\n", flagged);
|
fprintf(stderr, "Flagged %d collisions for removal.\n", flagged);
|
||||||
|
|
@ -341,7 +340,7 @@ static struct errorinfo *prepareErrorTable(int bits, int max_correct, int max_de
|
||||||
if (table[j].errors == i)
|
if (table[j].errors == i)
|
||||||
++count;
|
++count;
|
||||||
|
|
||||||
possible = combinations(bits-5, i);
|
possible = combinations(bits, i);
|
||||||
fprintf(stderr, " %d entries for %d-bit errors (%d possible, %d%% coverage)\n", count, i, possible, 100 * count / possible);
|
fprintf(stderr, " %d entries for %d-bit errors (%d possible, %d%% coverage)\n", count, i, possible, 100 * count / possible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
2
crc.h
2
crc.h
|
|
@ -32,7 +32,7 @@ struct errorinfo {
|
||||||
};
|
};
|
||||||
|
|
||||||
void modesChecksumInit(int fixBits);
|
void modesChecksumInit(int fixBits);
|
||||||
uint32_t modesChecksum(uint8_t *msg, int bitlen);
|
uint32_t modesChecksum(const uint8_t *msg, int bitlen);
|
||||||
struct errorinfo *modesChecksumDiagnose(uint32_t syndrome, int bitlen);
|
struct errorinfo *modesChecksumDiagnose(uint32_t syndrome, int bitlen);
|
||||||
void modesChecksumFix(uint8_t *msg, struct errorinfo *info);
|
void modesChecksumFix(uint8_t *msg, struct errorinfo *info);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
Source: dump1090-fa
|
||||||
|
Section: embedded
|
||||||
|
Priority: extra
|
||||||
|
Maintainer: Oliver Jowett <oliver.jowett@flightaware.com>
|
||||||
|
Build-Depends: debhelper(>=10), librtlsdr-dev, libusb-1.0-0-dev, pkg-config, libncurses5-dev, libbladerf-dev
|
||||||
|
Standards-Version: 3.9.3
|
||||||
|
Homepage: http://www.flightaware.com/
|
||||||
|
Vcs-Git: https://github.com/flightaware/dump1090.git
|
||||||
|
|
||||||
|
Package: dump1090
|
||||||
|
Architecture: all
|
||||||
|
Depends: dump1090-fa, ${misc:Depends}
|
||||||
|
Priority: extra
|
||||||
|
Section: oldlibs
|
||||||
|
Description: transitional dummy package for dump1090
|
||||||
|
This is a transitional dummy package to handle upgrades from
|
||||||
|
the old package name of "dump1090" to the new package name of
|
||||||
|
"dump1090-fa". It can safely be removed.
|
||||||
|
|
||||||
|
Package: dump1090-fa
|
||||||
|
Architecture: any
|
||||||
|
Depends: ${shlibs:Depends}, ${misc:Depends}, libbladerf1 (>= 0.2016.06), adduser, lighttpd
|
||||||
|
Replaces: dump1090 (<< 3.0)
|
||||||
|
Breaks: dump1090 (<< 3.0)
|
||||||
|
Description: ADS-B Ground Station System for RTL-SDR
|
||||||
|
Networked Aviation Mode S / ADS-B decoder/translator with RTL-SDR software
|
||||||
|
defined radio USB device support.
|
||||||
|
.
|
||||||
|
This is FlightAware's fork of dump1090-mutability, customized for use
|
||||||
|
in the PiAware sdcard images.
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
#!/usr/bin/make -f
|
||||||
|
# -*- makefile -*-
|
||||||
|
# Sample debian/rules that uses debhelper.
|
||||||
|
# This file was originally written by Joey Hess and Craig Small.
|
||||||
|
# As a special exception, when this file is copied by dh-make into a
|
||||||
|
# dh-make output file, you may use that output file without restriction.
|
||||||
|
# This special exception was added by Craig Small in version 0.37 of dh-make.
|
||||||
|
|
||||||
|
# Uncomment this to turn on verbose mode.
|
||||||
|
export DH_VERBOSE=1
|
||||||
|
|
||||||
|
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||||
|
|
||||||
|
DPKG_EXPORT_BUILDFLAGS = 1
|
||||||
|
include /usr/share/dpkg/default.mk
|
||||||
|
|
||||||
|
override_dh_auto_build:
|
||||||
|
# starch's gcc doesn't support the compiler flags needed for ARM-specific starch flavors;
|
||||||
|
# turn off runtime CPU detection
|
||||||
|
dh_auto_build -- RTLSDR=yes BLADERF=yes HACKRF=no LIMESDR=no DUMP1090_VERSION=$(DEB_VERSION) CPUFEATURES=no
|
||||||
|
|
||||||
|
override_dh_install:
|
||||||
|
dh_install
|
||||||
|
install -d debian/dump1090-fa/usr/bin
|
||||||
|
cp -a dump1090 debian/dump1090-fa/usr/bin/dump1090-fa
|
||||||
|
cp -a view1090 debian/dump1090-fa/usr/bin/view1090-fa
|
||||||
|
|
||||||
|
override_dh_installinit:
|
||||||
|
dh_installinit --no-stop-on-upgrade --no-restart-after-upgrade
|
||||||
|
|
||||||
|
override_dh_systemd_start:
|
||||||
|
dh_systemd_start --no-stop-on-upgrade --no-restart-after-upgrade --name=dump1090-fa.service
|
||||||
|
|
||||||
|
%:
|
||||||
|
dh $@ --with=systemd
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
This package includes binaries that are statically linked against librtlsdr,
|
||||||
|
which is licensed under the GPL:
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along
|
||||||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||||||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
|
||||||
|
The upstream source is available at https://github.com/steve-m/librtlsdr
|
||||||
|
|
@ -1,331 +1,425 @@
|
||||||
dump1090-mutability (1.15~dev) UNRELEASED; urgency=medium
|
dump1090-fa (7.2) stable; urgency=medium
|
||||||
|
|
||||||
* In development.
|
* dump1090: Fix Makefile syntax error for Darwin OS build (courtesy @CodyCodeman, PR #170)
|
||||||
* Validate that the username given to debconf is syntactically OK and
|
* dump1090: set _POSIX_C_SOURCE to fix build failure with uclibc-ng (courtesy @ffontaine, PR #169)
|
||||||
isn't root. (github issue #24)
|
* SkyAware: Remove obselete map interface at /dump1090-fa
|
||||||
* Don't fail on postinst if the given user exists but is outside
|
* SkyAware: Remove OSM Black & White layer which is no longer in service
|
||||||
the usual system user UID range. (github issue #24)
|
|
||||||
* Fix timestamp correction when sample blocks are dropped. (github
|
|
||||||
issue #43)
|
|
||||||
* Rearrangements to the receive thread. Magnitude conversion now happens
|
|
||||||
immediately when sample data is received, so there is no risk of newly
|
|
||||||
received data clobbering old data under CPU overload.
|
|
||||||
* Fix endian issues affecting big-endian hosts in Beast input/output
|
|
||||||
and avrmlat output. (github issue #44)
|
|
||||||
* Fix queueing/resending very old Mode A/C messages (github issue #47)
|
|
||||||
|
|
||||||
-- Oliver Jowett <oliver@mutability.co.uk> Thu, 19 Feb 2015 22:39:19 +0000
|
-- Eric Tran <eric.tran@flightaware.com> Wed, 09 Mar 2022 20:09:55 -0600
|
||||||
|
|
||||||
dump1090-mutability (1.14) unstable; urgency=medium
|
dump1090-fa (7.1) stable; urgency=medium
|
||||||
|
|
||||||
* Position reporting:
|
* Preserve start/upgrade postinst logic for pre 7.1 updates until we support compat 10 behavior
|
||||||
* Use the correct maximum inter-position-message intervals for surface
|
|
||||||
position messages (github issue #18).
|
|
||||||
* Disable receiver-relative position decoding entirely if the receiver
|
|
||||||
max range is larger than 360NM.
|
|
||||||
* Implement speed checks on position updates; implausible position
|
|
||||||
changes are discarded, unless they improve NUCp. Fixes most cases
|
|
||||||
of "spikes" in position tracks for aircraft with poor GPS data, and
|
|
||||||
helps with many cases where aircraft are transmitting garbage position
|
|
||||||
data. (github issue #17)
|
|
||||||
* If a position update is considered implausible, discard all the other
|
|
||||||
data in the same message too, just in case - often altitude will be
|
|
||||||
wrong in this case, too.
|
|
||||||
|
|
||||||
* Message decoding/forwarding:
|
-- Eric Tran <eric.tran@flightaware.com> Wed, 12 Jan 2022 11:37:20 -0600
|
||||||
* NUCp (navigational uncertainty) is extracted from position messages
|
|
||||||
(github issue #16)
|
|
||||||
* Improved support for DF18 ADS-R/TIS-B message formats and
|
|
||||||
cases where they use non-ICAO addresses (handle the IMF bit)
|
|
||||||
* Don't forward the first message for an aircraft to network clients
|
|
||||||
until we have seen a second message from the same aircraft.
|
|
||||||
This should handle most of the "garbage ICAO address" cases.
|
|
||||||
Disabled in --net-verbatim mode.
|
|
||||||
* Aircraft with only one message seen are pruned more aggressively
|
|
||||||
(60 second timeout vs. 300 second timeout normally)
|
|
||||||
* Don't emit SBS output for non-ICAO addresses (github issue #9)
|
|
||||||
* Improved the calculation of message reception time seen in SBS output.
|
|
||||||
Now message reception time should be strictly before current time.
|
|
||||||
* Don't try to correct more than one error in DF11 messages as these
|
|
||||||
messages have reduced CRC coverage and multiple-bit errors are
|
|
||||||
ambiguous.
|
|
||||||
* Fix some undecodable altitudes that would be interpreted as a valid
|
|
||||||
altitude of 0ft.
|
|
||||||
|
|
||||||
* Stats & JSON:
|
dump1090-fa (7.0) stable; urgency=medium
|
||||||
* Documented the JSON formats (see README-json.md)
|
|
||||||
* Fix "-infdB" in stats if no signal peaks have been recorded.
|
|
||||||
* NUCp is reported in aircraft.json
|
|
||||||
* Fix "unrecognised ICAO address" stat counter to count the right thing.
|
|
||||||
* Gather stats on number of unique aircraft tracks seen, and number of
|
|
||||||
tracks where only a single message was seen (which are probably
|
|
||||||
garbage).
|
|
||||||
* Fix stats timestamp output during the period shortly after restart.
|
|
||||||
* Include timezone in timestamps shown with --stats
|
|
||||||
* Add various stats for CPR position-decoding details.
|
|
||||||
|
|
||||||
* Webmap:
|
* dump1090: Allow env vars (not only command line overrdies) to set CPU_FEATURES_{ARCH,UNAME}
|
||||||
* Fix webmap history loading when no history is present.
|
* dump1090: Treat ARCH=arm64 like ARCH=aarch64
|
||||||
* Better handling of long refresh times in the webmap.
|
* dump1090: Try to respect CFLAGS/CPPFLAGS as far as possible; move required extra flags into a separate var
|
||||||
|
* dump1090: Adaptive gain - more aggressively re-probe for higher gain after a decrease in gain due to increased noise floor
|
||||||
|
* dump1090: Cleanup AVR parsing
|
||||||
|
* SkyAware: Update aircraft db to 20211210
|
||||||
|
* SkyAware: Cleanup unused Openlayers files
|
||||||
|
|
||||||
* Packaging/misc:
|
-- Eric Tran <eric.tran@flightaware.com> Mon, 20 Dec 2021 11:00:00 -0600
|
||||||
* Fix config handling of lat/lon between -0.999 and 0 (github issue #14)
|
|
||||||
* Add --oversample option to help text (github issue #11)
|
|
||||||
* More options now accept fractional seconds (--stats-every,
|
|
||||||
--net-heartbeat, --net-ro-interval, --write-json-every)
|
|
||||||
* Start dump1090 with a niceness of -5 to reduce the chance of dropped
|
|
||||||
sample data, except in --net-only mode where it's not using a RTLSDR
|
|
||||||
dongle (github issue #19)
|
|
||||||
* Make sure background tasks have a chance to run even if the sample rx
|
|
||||||
thread is blocked waiting for a USB reconnect. (github issue #20)
|
|
||||||
* Include timestamps in logging of USB disconnects/reconnects (github
|
|
||||||
issue #21)
|
|
||||||
* Catch SIGTERM and do clean shutdown like SIGINT does. Also log about
|
|
||||||
it. (github issue #22)
|
|
||||||
* Log (with timestamps) on startup/shutdown so it's more obvious in logs
|
|
||||||
where dump1090 restarted.
|
|
||||||
* Mark all HTML/Javascript as conffiles to avoid overwriting user changes
|
|
||||||
on package upgrade, as many people seem to modify these files.
|
|
||||||
(github issue #15)
|
|
||||||
|
|
||||||
-- Oliver Jowett <oliver@mutability.co.uk> Thu, 19 Feb 2015 19:41:39 +0000
|
dump1090-fa (6.1) stable; urgency=medium
|
||||||
|
|
||||||
dump1090-mutability (1.13) unstable; urgency=medium
|
* No-change 6.1 release for PiAware 6.1
|
||||||
|
|
||||||
* Moved to a simpler versioning scheme rather than trying
|
-- Oliver Jowett <oliver.jowett@flightaware.com> Mon, 06 Sep 2021 16:06:00 +0800
|
||||||
to put suffixes on the end of the upstream version scheme.
|
|
||||||
|
|
||||||
* Statistics updates for the stats junkies amongst us.
|
dump1090-fa (6.0) stable; urgency=medium
|
||||||
Note that many of these apply to the 2.4MHz demodulator only.
|
|
||||||
* Rationalized the demodulation stats that are collected.
|
|
||||||
* Collect mean signal level, peak signal values.
|
|
||||||
* Collect a count of signals stronger than -3dBFS.
|
|
||||||
* Collect stats on remotely-received messages.
|
|
||||||
* Collect stats on CPR position decoding.
|
|
||||||
* Collect more CPU stats.
|
|
||||||
* Stat buckets for the last 1, 5, 15 mins are maintained.
|
|
||||||
* Stats display due to --stats-every does not reset the "total" stats.
|
|
||||||
* All stats are now exported via JSON at /data/stats.json.
|
|
||||||
|
|
||||||
* When --oversample --phase-enhance is in use, all phase positions are
|
* dump1090: Adaptive gain feature with associated dump1090-fa config parameters
|
||||||
evaluated and the best result is used, rather than stopping at the first
|
* dump1090: Add support for decoding BDS 4,4 - Meteorological Routine Air Report (MRAR) Comm-B messages
|
||||||
error-free message. This increases CPU by about 1/4 but recovers about
|
* dump1090: Stratux output: include current receiver gain (courtesy @b3nn0, PR #144)
|
||||||
5% more messages.
|
* dump1090: Enable rtlsdr bounce buffers on aarch64 (courtesy @wiedehopf for suggestion)
|
||||||
* Error correction in --aggressive mode is now more conservative:
|
* dump1090: New default dump1090-fa config file format
|
||||||
it will only fix 2-bit errors that can't be confused with a 4-bit error.
|
* dump1090: Use compat/compat.h for endian-swapping functions in DSP code
|
||||||
* DF11 messages can now be partially error-corrected (only for errors that
|
* dump1090: Report json write errors, with some rate limiting (fixes issue #129)
|
||||||
do not result in a syndrome in the final 7 CRC bits)
|
* starch: Update starch to upstream commit 0c8249fa4bc523345c156885542e9192e8bf68fd
|
||||||
* Partial TIS-B support. Feedback sought from people who actually receive
|
* SkyAware: restrict overlay rendering to covered areas (reduce source load) (courtesy @wiedehopf, PR #137)
|
||||||
TIS-B messages!
|
* SkyAware: Fix ignored DisplayUnits in config.js (courtesy @paulyc, PR #76)
|
||||||
* Support for non-alphanumeric characters in callsigns.
|
* SkyAware: Update aircraft db to 20210817 with better Australian aircraft & types
|
||||||
* RSSI measured for individual messages.
|
|
||||||
* Simple filtering for bogus messages that make it past CRC checks: don't
|
|
||||||
display or emit aircraft state until we have seen at least two messages
|
|
||||||
from the same aircraft.
|
|
||||||
* --net-verbatim option added; if enabled, for messages that have
|
|
||||||
repairable CRC errors the unrepaired version of the message is forwarded
|
|
||||||
to network clients. This lets the client decide what policy to impose on
|
|
||||||
damaged messages.
|
|
||||||
* Made 2.4MHz sampling the default for new installs.
|
|
||||||
|
|
||||||
* Internal changes:
|
-- Eric Tran <eric.tran@flightaware.com> Tue, 31 Aug 2021 12:41:06 -0600
|
||||||
* Restructuring of the code to be a bit more modular.
|
|
||||||
* Mode S message decoder and output formatting cleanups.
|
|
||||||
* 2.4MHz demodulator main loop unrolled to demodulate a byte at a time;
|
|
||||||
this helps compensate a little for the --phase-enhance change above.
|
|
||||||
* CRC calculation switched to a faster byte-at-a-time table lookup.
|
|
||||||
* ICAO address filter rewritten to be a bit smarter, and to support
|
|
||||||
Comm-B overlay control in the future.
|
|
||||||
* Non-ICAO addresses (e.g. from TIS-B and ModeA/C) are flagged internally
|
|
||||||
so they cannot be confused with a real ICAO address.
|
|
||||||
* More changes to try to work around libusb crashes on exit.
|
|
||||||
|
|
||||||
* Webmap changes:
|
dump1090-fa (5.0) stable; urgency=medium
|
||||||
* Show recent RSSI for the selected aircraft.
|
|
||||||
* Non-ICAO addresses are shown italicized.
|
|
||||||
* Fix webmap stable sort of rows with no sortable values (would cause
|
|
||||||
"jumping" rows at the end of the table)
|
|
||||||
* Doubleclick on an aircraft marker or table row to follow that aircraft,
|
|
||||||
recentering the map as it moves. Or click on the selected aircraft's
|
|
||||||
callsign or the arrow next to it.
|
|
||||||
* config.js cleanups. Page title and site name can be specified here now.
|
|
||||||
* Added vertical rate indicators to altitudes on the webmap.
|
|
||||||
* Linked from the aircraft ICAO to airframes.org. (Other site
|
|
||||||
recommendations welcome!)
|
|
||||||
* Infoblock layout changes.
|
|
||||||
|
|
||||||
* License for my modifications changed to GPL2+. Previous binary
|
* SkyAware: New Altitude, Speed, Aircraft Ident, and Aircraft Type filters to fine tune the select aircraft you want see
|
||||||
releases were effectively already GPL2+ due to linking with librtlsdr.
|
* SkyAware: Ability to toggle visibility of ADS-B, MLAT, UAT, TIS-B, and Other aircraft on SkyAware using the check boxes under the aircraft table
|
||||||
|
* SkyAware: Ability to show Aircraft Ident labels for all aircraft on your display (found in the View Toggles list in the settings menu)
|
||||||
|
* SkyAware: A merged SkyAware map of 1090 and UAT aircraft for those with dual 1090/978 setups.
|
||||||
|
* SkyAware: Direct link on the SkyAware map to go to your My ADS-B statistics page on FlightAware.com or a direct link to claim your receiver if it has not been claimed
|
||||||
|
* SkyAware: Bold aircraft Idents are used to indicate tail numbers in the aircraft table rather than using the previous prepended underscore syntax
|
||||||
|
* SkyAware: Default SkyAware link now at <local ip>/skyaware
|
||||||
|
|
||||||
-- Oliver Jowett <oliver@mutability.co.uk> Sun, 25 Jan 2015 16:45:00 +0000
|
* dump1090: limesdr: use --gain value if --limesdr-gain is not specified
|
||||||
|
* dump1090: Switch sample-conversion DSP code to use starch. Provide NEON implementations for ARM when the
|
||||||
|
hardware supports it. Update 8-bit unsigned zero offset to reflect actual rtlsdr behavior. This gives a
|
||||||
|
substantial speedup to sample processing for the 12/16-bit case, and a small speedup for the 8-bit case.
|
||||||
|
Default wisdom provided for arm, aarch64, and x86; see the README for details on generating hardware-
|
||||||
|
specific wisdom files.
|
||||||
|
* dump1090: Make console stats display fixed-width (courtesy @gtjoseph)
|
||||||
|
* dump1090: Add `--json-stats-every` option to control the update cycle of `stats.json`
|
||||||
|
* dump1090: Don't expire data when reading a capture at full speed via `--ifile`
|
||||||
|
* dump1090: Count received messages for each DF type, emit in console stats / `stats.json`
|
||||||
|
* dump1090: Write final stats.json on process exit (mostly useful for `--ifile`)
|
||||||
|
* dump1090: Attempt to correct DF11/17/18 messages where the DF field itself is damaged. This requires
|
||||||
|
a lot more CRC checks when receiving messages off-the-air, but slightly increases the decode rate for
|
||||||
|
DF11/17/18.
|
||||||
|
* dump1090: Add a `--no-df-fix` option to disable the extra DF field correction, for cases where the extra
|
||||||
|
messages are not worth the extra CPU
|
||||||
|
* dump1090: Track recently-seen DF18 addresses, but only count them as recently-seen for DF18 decoding,
|
||||||
|
not for Mode S / DF17
|
||||||
|
|
||||||
dump1090-mutability (1.10.3010.14mu-12) unstable; urgency=medium
|
* dump1090: Support `--stats-every` intervals of less than 1 minute correctly
|
||||||
|
* dump1090: Don't erroneously consider ICAO 000000 as "recently seen" when decoding
|
||||||
|
* dump1090: Fix rare hang (1 in 1e9) in FIFO code due to an off-by-one error in normalize_timespec
|
||||||
|
* dump1090: Correctly expire stale emergency, nac_v data (courtesy @wiedehopf, issue #96)
|
||||||
|
* dump1090: Fix FIFO bounded memory leak / effective reduction in size of the FIFO, triggered if the
|
||||||
|
demodulator couldn't keep up with the input rate
|
||||||
|
* dump1090: Set at least airground = AG_UNCERTAIN for airborne position messages with valid altitudes (issue #113)
|
||||||
|
|
||||||
* Add generation of history JSON.
|
* view1090: Interactive mode enhancements to show min/max RSSI, distances (courtesy @gtjoseph, PR #81)
|
||||||
* Load history when the webmap is initialized.
|
* view1090: Fix table alignment with `--interactive-ttl` > 99 (courtesy @MavEtJu, PR #99)
|
||||||
* Display stats on exit in --net-only mode.
|
* view1090: Tweak Mode column to display more data-source info
|
||||||
* Explicitly pick the closest tuner gain to the one requested.
|
* view1090: Fix librtlsdr output interfering with interactive mode display (courtesy @VasiliyTurchenko, PR #116)
|
||||||
* Include a status message in HTTP response headers.
|
|
||||||
* Fix sort-by-message-count in the webmap.
|
|
||||||
* Always sort missing values at the end of the table, even in a descending sort.
|
|
||||||
* Avoid a (rare) divide-by-zero crash in 2MHz --phase-enhance.
|
|
||||||
* Try to work around a libusb crash on exit after SIGINT.
|
|
||||||
|
|
||||||
-- Oliver Jowett <oliver@mutability.co.uk> Sat, 17 Jan 2015 21:03:55 +0000
|
* general: Fix linking against NetBSD curses library (courtesy @jvanwouw, PR #111)
|
||||||
|
|
||||||
dump1090-mutability (1.10.3010.14mu-11) unstable; urgency=medium
|
-- Eric Tran <eric.tran@flightaware.com> Thu, 11 Mar 2021 19:26:07 -6000
|
||||||
|
|
||||||
* Fix UTC clock display in non-UTC timezones.
|
dump1090-fa (4.0) stable; urgency=medium
|
||||||
* Layout tweaks in the info panel.
|
|
||||||
* Change plane color if we have not seen a recent position update
|
|
||||||
(previously, any type of message was enough).
|
|
||||||
* Fix thinko in skipping over decoded message samples in the 2.4MHz demodulator.
|
|
||||||
* Fix a couple of problems found by valgrind.
|
|
||||||
* Fix several problems with surface position decoding and relative
|
|
||||||
position decoding.
|
|
||||||
* Fix hang on exit after SIGINT.
|
|
||||||
* Add --max-range parameter. Use it for relative position limits, and to
|
|
||||||
discard bad position results.
|
|
||||||
* Display message rate (30 sec average) on the webmap.
|
|
||||||
* Restart lighttpd on package upgrade if we changed its config files.
|
|
||||||
* Require that the JSON refresh interval is at least 1, as it is used
|
|
||||||
to control the webmap refresh rate even if JSON files are not being written.
|
|
||||||
|
|
||||||
-- Oliver Jowett <oliver@mutability.co.uk> Wed, 14 Jan 2015 01:17:51 +0000
|
* dump1090: Build support for OS X, FreeBSD, OpenBSD [courtesy @mikenor / @apparentorder on Github, PRs #33 / #38]
|
||||||
|
* dump1090: Overhaul of SDR / ring buffer / demodulator interface to make it easier to add new SDR types
|
||||||
|
* dump1090: LimeSDR support [courtesy @Glutton on Github, PR #75]
|
||||||
|
* dump1090: HackRF support [courtesy @kr105 on Github, PR #57]
|
||||||
|
* dump1090: Stratux-compatible network output [courtesy @Determinant on Github, PR #61]
|
||||||
|
* dump1090: Change option syntax for 2-bit correction from --fix --fix (introduced in 3.8.0) to --fix-2bit. Any number of --fix options now yields 1-bit correction.
|
||||||
|
* dump1090: Support building under GCC 10 (github issue #65)
|
||||||
|
* dump1090: Include a (disabled by default) example HTTPS configuration [courtesy @jwbernin on Github, PR #66)
|
||||||
|
* dump1090: For manual builds, if no explicit SDR choice is made, autodetect available libraries via pkg-config
|
||||||
|
* dump1090: Add a --version command-line option that shows just the version without needing to show the full help screen
|
||||||
|
* dump1090: Only emit verbose command-line option help if --help is requested, not on any error
|
||||||
|
* dump1090: List supported device types if --device-type is given without a device type
|
||||||
|
* dump1090: Removed Debian Wheezy support (distribution is no longer supported upstream)
|
||||||
|
* dump1090: Remove the "dump1090" Debian metapackage that exists only to provide an upgrade path from very very old installs
|
||||||
|
* dump1090: Add package profiles to selectively build packages with reduced SDR library dependencies. See the README for details.
|
||||||
|
* dump1090: If a network port option (--net-bo-port et al) is given on the command line, implicitly enable networking, but don't enable the default port assignments
|
||||||
|
* dump1090: Provide Mode A / Mode C hit count in aircraft.json
|
||||||
|
* SkyAware: Update aircraft registry to 20200924
|
||||||
|
* SkyAware: Update to OpenLayers6
|
||||||
|
* SkyAware: New basemap layers added/enabled
|
||||||
|
* SkyAware: Added customizable aircraft table columns
|
||||||
|
* SkyAware: Added URL query parameter feature to customize display [courtesy @sigwx on Github, PR #58)
|
||||||
|
* SkyAware: Display registration number in aircraft table if ident is not present
|
||||||
|
* SkyAware: Fix duplicated Access-Control-Allow-Origin header [courtesy @ianrenton on Github, PR #74)
|
||||||
|
|
||||||
dump1090-mutability (1.10.3010.14mu-10) unstable; urgency=medium
|
-- Eric Tran <eric.tran@flightaware.com> Thu, 24 Sep 2020 10:21:00 -6000
|
||||||
|
|
||||||
* Many changes to aircraft.json and the webserver code:
|
dump1090-fa (3.8.1) stable; urgency=medium
|
||||||
|
|
||||||
* Restructure to include the current timestamp, and move
|
* SkyAware: Fixed SkyAware banner aspect ratio
|
||||||
aircraft data down a level. If you're processing the JSON yourself,
|
* SkyAware: Fixed issue with "Group By Data Type" and "All Aircraft Trails" checkboxes
|
||||||
you will need to adjust your code to handle this.
|
not saving across browser refreshes
|
||||||
* Only include aircraft data when we are sure it's valid.
|
* SkyAware: Fixed bug with ShowFlags=False config.js setting
|
||||||
* Include the time of the last position report in.
|
* SkyAware: Added position age to aircraft detail pane
|
||||||
* If the aircraft is on the ground, report altitude as "ground".
|
* SkyAware: Added ability to customize range ring distances in SkyAware
|
||||||
* Strip trailing query strings from URLs before matching, to allow AJAX
|
|
||||||
cache-busting query strings to work.
|
|
||||||
* Disable the lighttpd stat cache in the provided config fragment, to
|
|
||||||
avoid problems with partial content being served if lighttpd caches an
|
|
||||||
old size for the JSON data. This would manifest as "bad content length"
|
|
||||||
or JSON parse errors in the webmap.
|
|
||||||
|
|
||||||
* Many changes to the webmap javascript:
|
-- Eric Tran <eric.tran@flightaware.com> Thu, 19 Mar 2020 09:20:00 -6000
|
||||||
|
|
||||||
* Internal restructuring of how the plane table and map markers are
|
dump1090-fa (3.8.0) stable; urgency=medium
|
||||||
maintained. Should be faster and less memory-hungry.
|
|
||||||
* Sorting the plane table now sorts missing data high (end of the table for an
|
|
||||||
ascending sort).
|
|
||||||
* On-the-ground aircraft display an altitude of "ground".
|
|
||||||
* Dashed tracks are used when there are lots of missing position reports (more
|
|
||||||
than 5 seconds between positions).
|
|
||||||
* Green tracks are used for on-the-ground aircraft.
|
|
||||||
* Limit history storage requirements by only retaining at most one position
|
|
||||||
per 5 seconds.
|
|
||||||
* Removal of old aircraft should be much more reliable now, even across
|
|
||||||
long pauses (e.g. browser hibernation).
|
|
||||||
* Change the clocks to be two UTC clocks: one from local browser time,
|
|
||||||
one reflecting the receiver timestamp in the last update.
|
|
||||||
* Add "total aircraft" and "total aircraft with positions" counters to the
|
|
||||||
infobox when no aircraft is selected.
|
|
||||||
* Add a "history positions" counter to the infobox when no aircraft is
|
|
||||||
selected; this shows the number of points making up the historical track
|
|
||||||
lines.
|
|
||||||
* When an aircraft is selected, show both metric and imperial units in the
|
|
||||||
infobox (metric setting controls which is shown first).
|
|
||||||
* When an aircraft is selected, show the time since last message and time
|
|
||||||
since last position message in the infobox.
|
|
||||||
* If aircraft.json can't be retrieved, display a warning.
|
|
||||||
* If aircraft.json can be retrieved but doesn't appear to be being updated
|
|
||||||
(e.g. external webserver, and dump1090 has stopped), display a warning.
|
|
||||||
* config.js: Change the default map zoom setting to be more zoomed in.
|
|
||||||
* config.js: Add some comments.
|
|
||||||
* config.js: Add an option to hide the clocks.
|
|
||||||
* Remove extension.js and options.js, as they aren't really maintained.
|
|
||||||
* Enable strict mode for script.js / planeObject.js.
|
|
||||||
|
|
||||||
* Fix initial map centering to correctly use the receiver location.
|
* general: Added support for building on Buster.
|
||||||
|
* general: Replace use of usleep with nanosleep (PR #53)
|
||||||
|
|
||||||
-- Oliver Jowett <oliver@mutability.co.uk> Wed, 07 Jan 2015 23:54:10 +0000
|
* dump1090: When applying CRC correction to a DF11 message, assume that the interrogator
|
||||||
|
overlay value was 0 (e.g. as in an acquisiton squitter) and use the full 24-bit syndrome
|
||||||
|
to correct errors; do not zero out the low 7 bits of the syndrome.
|
||||||
|
* dump1090: Changes in aircraft tracking to try to reduce the number of bogus aircraft seen
|
||||||
|
due to noise; this replaces the crude "require 2 messages" metric used previously.
|
||||||
|
* dump1090: Added a new statistic for "unreliable tracks", aircraft that were tracked but
|
||||||
|
which never passed the threshold for being considered a real aircraft.
|
||||||
|
* dump1090: Added support for per-connection verbatim mode. "--net-verbatim" now controls the
|
||||||
|
default connection setting, and the per-connection mode can be changed by a Beast settings
|
||||||
|
command.
|
||||||
|
* dump1090: Replaced "--aggressive" with "--fix --fix" for 2-bit CRC correction; include
|
||||||
|
support for this in the standard build. 2-bit corrected messages are only emitted on
|
||||||
|
verbatim connections.
|
||||||
|
* dump1090: Update package default options: include "--fix", increase "--net-ro-size",
|
||||||
|
decrease "--net-ro-interval", remove a duplicated "--net-bo-port" option.
|
||||||
|
* dump1090: Fixes to CPR decoding when multiple position sources (e.g. ADS-B and MLAT) are
|
||||||
|
being simultaneously received (PR #55)
|
||||||
|
* dump1090: Track ADS-B, ADS-R, and TIS-B versions independently; use the appropriate version
|
||||||
|
when decoding version-dependent messages.
|
||||||
|
|
||||||
dump1090-mutability (1.10.3010.14mu-9) unstable; urgency=medium
|
* view1090: Include ADS-B version in interactive display
|
||||||
|
* view1090: Display a warning in the header in interactive mode if the dump1090 connection
|
||||||
|
has been lost
|
||||||
|
* view1090: Request verbatim mode when connecting to dump1090
|
||||||
|
* view1090: Exit on connection loss in --no-interactive mode
|
||||||
|
|
||||||
* Fix warnings. Add -Werror so they break the build in future.
|
* SkyAware: Corrected icon selection for some aircraft types
|
||||||
* Remove dead tracking code related to the removed PlanePlotter feed.
|
* SkyAware: Fixed display of settings checkboxes on high-DPI displays (PR #54)
|
||||||
|
* SkyAware: Fixes to info box display (PR #51)
|
||||||
|
* SkyAware: Hide scroll bar when not needed (PR #22)
|
||||||
|
* SkyAware: Update aircraft registry to 20191216
|
||||||
|
|
||||||
-- Oliver Jowett <oliver@mutability.co.uk> Sun, 04 Jan 2015 20:23:26 +0000
|
-- Oliver Jowett <oliver.jowett@flightaware.com> Mon, 30 Dec 2019 22:11:52 +0800
|
||||||
|
|
||||||
dump1090-mutability (1.10.3010.14mu-8) unstable; urgency=medium
|
dump1090-fa (3.7.2) stable; urgency=medium
|
||||||
|
|
||||||
* Version-only rebuild to reflect the upstream dump1090 version we
|
* dump1090: Fix reversed sense of Track Angle/Heading bit in surface opstatus messages
|
||||||
have merged from. Retaining the trailing build number to avoid
|
* dump1090: Have filter-regs emit a special value "-COMPUTED-" for filtered data
|
||||||
confusion (as far as that's possible given this versioning system!)
|
values, rather than blanking them out entirely
|
||||||
|
* Fix registration side mappings with a non-zero offset
|
||||||
|
* dump1090: Update aircraft DB to 20190816
|
||||||
|
* dump1090: Reject outright libbladerf that's too old
|
||||||
|
* dump1090: Trigger build after bladeRF build; turn off build durability; turn
|
||||||
|
off concurrent builds
|
||||||
|
* SkyAware: SkyAware Renaming
|
||||||
|
* SkyAware: Fix some display errors for ground vehicles
|
||||||
|
* SkyAware: Fix aircraft trail handling
|
||||||
|
|
||||||
-- Oliver Jowett <oliver@mutability.co.uk> Sun, 04 Jan 2015 12:32:30 +0000
|
-- Eric Tran <eric.tran@flightaware.com> Mon, 09 Sep 2019 09:25:00 -6000
|
||||||
|
|
||||||
dump1090-mutability (1.08.2302.14+1mu-7) unstable; urgency=medium
|
dump1090-fa (3.7.1) stable; urgency=medium
|
||||||
|
|
||||||
* Notice if we lose the RTLSDR device, and try to reconnect when that happens.
|
* dump1090: TSV buffer overflow fix/increase max TSV packet size
|
||||||
This lets you unplug/replug the RTLSDR without dump1090 exiting, and also
|
* dump1090: Fix incorrect mode_s bit number usage
|
||||||
lets dump1090 tolerate occasional USB glitches that make the dongle reset
|
* dump1090: Rework use of pkg-config to work around librtlsdr packaging bugs
|
||||||
itself.
|
in Ubuntu distro
|
||||||
* Fix some of the more glaring pthread bugs.
|
* dump1090: Minimal polyfill to support building older bladeRF libs
|
||||||
* Center the webmap on the receiver location.
|
* dump1090: Add COMMB_AMBIGUOUS enum type for Comm-B messages we're unsure of
|
||||||
* Mark config.js as a conffile, so user changes won't get overwritten.
|
* dump1090: Comm-b message decoding updates
|
||||||
|
* dump1090: Require more fields to be populated in BDS5,0/BDS6,0 before accepting
|
||||||
|
* dump1090: Update aircraft DB to 20190502
|
||||||
|
* dump1090: Doc/README updates
|
||||||
|
|
||||||
-- Oliver Jowett <oliver@mutability.co.uk> Fri, 02 Jan 2015 22:53:55 +0000
|
-- Eric Tran <eric.tran@flightaware.com> Fri, 03 May 2019 12:35:00 -6000
|
||||||
|
|
||||||
dump1090-mutability (1.08.2302.14+1mu-6) unstable; urgency=medium
|
dump1090-fa (3.7.0.1) stable; urgency=medium
|
||||||
|
|
||||||
* Add support for LOG_DECODED_MESSAGES option to log all messages (disables --quiet).
|
* dump1090: Fix piaware lat/lon variable
|
||||||
|
|
||||||
-- Oliver Jowett <oliver@mutability.co.uk> Tue, 30 Dec 2014 17:09:36 +0000
|
-- Eric Tran <eric.tran@flightaware.com> Fri, 29 Mar 2019 7:04:00 -6000
|
||||||
|
|
||||||
dump1090-mutability (1.08.2302.14+1mu-5) unstable; urgency=medium
|
dump1090-fa (3.7.0) stable; urgency=medium
|
||||||
|
|
||||||
* Add Provides: fatsv-data-source
|
* dump1090: Fix Rc decoding errors
|
||||||
|
* dump1090: Compute ADS-B v0 NACp/SIL
|
||||||
|
* dump1090: When generating aircraft.json, leave space for the final line;
|
||||||
|
otherwise the generated json may have trailing garbage
|
||||||
|
* dump1090: Don't update the known-address-set from DF18 messages
|
||||||
|
* Skyview: use heading data for icon orientation if track data is unavailable
|
||||||
|
* Skyview: don't spin forever if there's no history to load / receiver.json
|
||||||
|
is missing
|
||||||
|
* dump1090: Bail out if rtlsdr_read_async() returns early; it probably means we lost
|
||||||
|
the USB device. There was a workaround for this (originally implemented
|
||||||
|
in dump1090-mutability) that got lost in the refactoring needed to support
|
||||||
|
different SDRs. librtlsdr can still be flaky under disconnect conditions, so
|
||||||
|
this won't catch everything.
|
||||||
|
* dump1090: add ENABLED to /etc/default/dump1090-fa
|
||||||
|
* dump1090: track FMS and MCP selected altitudes separately
|
||||||
|
* skyview: use whichever selected altitude is available
|
||||||
|
* faup1090: updates to support PiAware 3.7.0
|
||||||
|
|
||||||
-- Oliver Jowett <oliver@mutability.co.uk> Tue, 30 Dec 2014 00:01:51 +0000
|
-- Oliver Jowett <oliver@mutability.co.uk> Fri, 22 Mar 2019 15:58:04 +0000
|
||||||
|
|
||||||
dump1090-mutability (1.08.2302.14+1mu-4) unstable; urgency=medium
|
dump1090-fa (3.6.3) stable; urgency=medium
|
||||||
|
|
||||||
* Remove half-implemented --no-decode option.
|
* Fix port 30003 output (Basestation) timestamp formatting broken in 3.6.0
|
||||||
* Remove Windows support files that aren't needed for the Debian package.
|
* Ignore altitudes in DF17 "airborne" positions with airGround = ground
|
||||||
* Remove some legacy support scripts not needed by the Debian package.
|
* SkyView layout change and proper support for extended data fields
|
||||||
* Add support for controlling the accuracy of the receiver location
|
|
||||||
written in the JSON metadata used by the webmap.
|
|
||||||
* Oversampling is now less scary!
|
|
||||||
* Warn if --modeac is used together with --oversample.
|
|
||||||
* Link to github from the webmap.
|
|
||||||
|
|
||||||
-- Oliver Jowett <oliver@mutability.co.uk> Sat, 27 Dec 2014 22:24:39 +0000
|
-- Oliver Jowett <oliver@mutability.co.uk> Tue, 11 Sep 2018 14:52:20 +0100
|
||||||
|
|
||||||
dump1090-mutability (1.08.2302.14+1mu-3) unstable; urgency=medium
|
dump1090-fa (3.6.2) stable; urgency=medium
|
||||||
|
|
||||||
* Ask about json interval before json dir and skip the dir question if
|
* Update SkyView flags for Libya, Serbia, Montenegro
|
||||||
the interval is disabled, it makes more sense that way.
|
* Improve handling of bad callsigns in ADS-B messages
|
||||||
* Be much more cautious about missing config settings so we don't explode
|
* Update FlightAware aircraft static data export
|
||||||
so badly if something is omitted.
|
* Add --direct option to enable rtlsdr direct sampling mode
|
||||||
* Use the package version as the version number compiled into the binary.
|
|
||||||
* Add data/receiver.json (generated once) and support for it in script.js.
|
|
||||||
* Internal webserver rearrangement to support multiple json files.
|
|
||||||
* Dongle "device index" actually accepts serial numbers too, document that.
|
|
||||||
* Add input validation to most of the config questions.
|
|
||||||
|
|
||||||
-- Oliver Jowett <oliver@mutability.co.uk> Wed, 10 Dec 2014 21:58:12 +0000
|
-- Oliver Jowett <oliver@mutability.co.uk> Fri, 27 Jul 2018 18:32:30 +0100
|
||||||
|
|
||||||
dump1090-mutability (1.08.2302.14+1mu-2) unstable; urgency=medium
|
dump1090-fa (3.6.1) stable; urgency=medium
|
||||||
|
|
||||||
* Fix a memory leak from use of realpath() in HTTP request processing.
|
* Fix tracking of NICbaro
|
||||||
* Add direct support for FATSV-format output, adapted from the FlightAware
|
* Don't translate 7x00 to emergency status, it obscures the source of the
|
||||||
fork.
|
data (squawk vs ADS-B v2)
|
||||||
* Big rearrangement of configuration to add debconf support.
|
* Support for building on stretch
|
||||||
* Update Build-Depends based on glitches found building under pbuilder.
|
|
||||||
|
|
||||||
-- Oliver Jowett <oliver@mutability.co.uk> Wed, 10 Dec 2014 01:06:56 +0000
|
-- Oliver Jowett <oliver@mutability.co.uk> Mon, 16 Jul 2018 14:58:59 +0100
|
||||||
|
|
||||||
dump1090-mutability (1.08.2302.14+1mu-1) unstable; urgency=medium
|
dump1090-fa (3.6.0) stable; urgency=medium
|
||||||
|
|
||||||
* Initial release.
|
* dump1090: implement speculative decoding for Comm-B messages, capturing
|
||||||
|
most of the Mode S EHS data:
|
||||||
|
BDS 1,0 (datalink capabilities); BDS 1,7 (GICB capabilities);
|
||||||
|
BDS 2,0 (aircraft identification); BDS 3,0 (ACAS RA);
|
||||||
|
BDS 4,0 (vertical intention); BDS 5,0 (track and turn);
|
||||||
|
BDS 6,0 (heading and speed)
|
||||||
|
* dump1090: implement decoding of most of DO-260A/DO-260B including
|
||||||
|
ADS-B version, autopilot settings, NIC/Rc, NAC, SIL, GVA, etc.
|
||||||
|
* dump1090: aircraft state tracking overhaul; track data age in milliseconds
|
||||||
|
* dump1090: emit newly decoded fields in aircraft.json
|
||||||
|
* Skyview: experimental display of new fields, disabled by default; to
|
||||||
|
enable, set ExtendedData = true in config.js or add #extended to the URL
|
||||||
|
* Skyview: Remove obsolete chartbundle WAC layer, add heli layer
|
||||||
|
* Skyview: Remove Mapzen layer as Mapzen is shutting down
|
||||||
|
* faup1090: Restructure emitted data to include data age and source
|
||||||
|
* faup1090: Include newly decoded fields in reports
|
||||||
|
* dump1090, faup1090: fix use of snprintf to correctly handle buffer overruns
|
||||||
|
* dump1090: don't bother tracking ICAO 000000
|
||||||
|
|
||||||
-- Oliver Jowett <oliver@mutability.co.uk> Sat, 06 Dec 2014 23:07:02 +0000
|
-- Oliver Jowett <oliver@mutability.co.uk> Wed, 09 May 2018 22:34:24 +0100
|
||||||
|
|
||||||
|
dump1090-fa (3.5.3) stable; urgency=medium
|
||||||
|
|
||||||
|
* Skip 3.5.2 to align with piaware versioning
|
||||||
|
* Skyview: Update OpenLayers to fix performance problems on some browsers
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Fri, 03 Nov 2017 22:44:40 +0000
|
||||||
|
|
||||||
|
dump1090-fa (3.5.1) stable; urgency=medium
|
||||||
|
|
||||||
|
* Skyview: fix font mappings
|
||||||
|
* Skyview: mark tisb_icao and tisb_other addresses as TIS-B
|
||||||
|
* Skyview: fix unit selection on Firefox
|
||||||
|
* Skyview: report data source correctly in popup
|
||||||
|
* Skyview: change default color for grounded aircraft to brown
|
||||||
|
* Skyview: initial history load speedups (Steven Davies)
|
||||||
|
* Skyview: fix L2T/L2P icon selection
|
||||||
|
* Makefile cleanups (Michael Tatarinov)
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Mon, 31 Jul 2017 13:43:32 +0100
|
||||||
|
|
||||||
|
dump1090-fa (3.5.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* SkyView map UI added.
|
||||||
|
* Only enable lighttpd config once, not on every package upgrade in case the
|
||||||
|
user has deliberately disabled it.
|
||||||
|
* Fix AGC gain setting.
|
||||||
|
* Updated the FlightAware aircraft data export.
|
||||||
|
* Minor bugfixes.
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Mon, 03 Apr 2017 17:53:48 +0100
|
||||||
|
|
||||||
|
dump1090-fa (3.4.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* Add bladeRF support.
|
||||||
|
* Clean up the FlightAware photos link so it works for registrations containing
|
||||||
|
non-alphanumeric characters.
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Thu, 09 Feb 2017 17:41:43 +0000
|
||||||
|
|
||||||
|
dump1090-fa (3.3.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* Improvements to the Mode A/C demodulator.
|
||||||
|
* Automatically enable Mode A/C if a Beast command requesting it is received.
|
||||||
|
(disable with --no-modeac-auto)
|
||||||
|
* Process the radarcape position message, emit it from faup1090.
|
||||||
|
* If view1090 is started with --modeac, request Mode A/C data from dump1090.
|
||||||
|
* Remove the last traces of the internal webserver.
|
||||||
|
* Updated the FlightAware aircraft data export.
|
||||||
|
* Updated the default package-based maximum range to 360NM to match what
|
||||||
|
piaware-support configured for sdcard installs.
|
||||||
|
* Remove internal webserver code entirely (previously, it was just disabled
|
||||||
|
at compile time).
|
||||||
|
* Tweak the timing reported for Mode S and Mode A/C messages to match how
|
||||||
|
the Beast/Radarcape does it. This affects the interval between Mode S
|
||||||
|
and Mode A/C messages only; intervals between Mode S messages and other
|
||||||
|
Mode S messages, or A/C and other A/C, are unchanged.
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Sun, 15 Jan 2017 13:35:56 +0000
|
||||||
|
|
||||||
|
dump1090-fa (3.2.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* Fix a stray extra comma in port 30003 output if only GNSS altitude
|
||||||
|
was available
|
||||||
|
* Track CPR encoding type directly rather than inferring it from airground;
|
||||||
|
using airground meant some position messages that should be usable were
|
||||||
|
not used
|
||||||
|
* Mode A/C aircraft association tuning, allows dump1090 to handle much
|
||||||
|
higher A/C rates without chewing tons of CPU
|
||||||
|
* Map: Decrease the maximum marker size shown
|
||||||
|
* Map: Show additional datasource information (TIS-B etc) in table mode
|
||||||
|
* Map: Move the datablock so it doesn't overlap the zoom control
|
||||||
|
* Map: Allow skipping the history load by adding a #nohistory fragment
|
||||||
|
to the URL (e.g. for high latency connections)
|
||||||
|
* view1090-fa: Use ncurses to reduce flicker on remote connections
|
||||||
|
* view1090-fa: Fix knots -> km/h conversion in interactive mode
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Tue, 25 Oct 2016 23:40:01 +0100
|
||||||
|
|
||||||
|
dump1090-fa (3.1.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* Update to latest dump1090-mutability master
|
||||||
|
* Preserve more map settings in browser local storage
|
||||||
|
* Add a NEXRAD weather layer (US only) to the map
|
||||||
|
* Decoder overhaul/cleanup
|
||||||
|
* Prefer ES data over Mode S data when both are available
|
||||||
|
* Improved air/ground detection
|
||||||
|
* Lots of map interface changes:
|
||||||
|
* aircraft info moves to a draggable popup rather than top of the sidebar
|
||||||
|
* sidebar is resizeable / hideable
|
||||||
|
* table-only (no map) mode
|
||||||
|
* improved FlightAware aircraft links
|
||||||
|
* configurable units display (metric / imperial / aeronautical)
|
||||||
|
* filter displayed aircraft by altitude
|
||||||
|
* option to show all aircraft tracks
|
||||||
|
* more aircraft markers
|
||||||
|
* use aircraft markers based on aircraft type info where available
|
||||||
|
* scale marker size based on zoom to avoid overlap when zoomed out
|
||||||
|
* Include a greatly expanded aircraft type/registration database (used by the
|
||||||
|
map display) based on the publically-distributable parts of FlightAware's
|
||||||
|
internal database
|
||||||
|
* Try to compute a registration from ICAO address for aircraft where there
|
||||||
|
is a predictable mapping (e.g. US N-registrations)
|
||||||
|
* Try to coexist with other packages (e.g. dump1090-mutability) that also
|
||||||
|
provide a lighttpd config that changes the server.stat-cache-engine setting
|
||||||
|
* Serve actual map data on port 8080, not just a redirect
|
||||||
|
* Redirect requests for /dump1090-fa to /dump1090-fa/ rather than 404ing.
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Thu, 22 Sep 2016 17:19:01 +0100
|
||||||
|
|
||||||
|
dump1090-fa (3.0.5) stable; urgency=medium
|
||||||
|
|
||||||
|
* No-change release for PiAware 3.0.5
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Wed, 31 Aug 2016 13:02:42 +0100
|
||||||
|
|
||||||
|
dump1090-fa (3.0.3) stable; urgency=medium
|
||||||
|
|
||||||
|
* No-change release for PiAware 3.0.3
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Mon, 01 Aug 2016 12:23:47 +0100
|
||||||
|
|
||||||
|
dump1090-fa (3.0.2) stable; urgency=medium
|
||||||
|
|
||||||
|
* Release for PiAware 3.0.2
|
||||||
|
* Correct the radius of the receiver range circles
|
||||||
|
* Fix errors when selecting a positionless aircraft via the table
|
||||||
|
* Improve Mode A/C reception
|
||||||
|
* Add a Bing roadmap layer option (with a Bing API key)
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Wed, 27 Jul 2016 17:12:53 +0100
|
||||||
|
|
||||||
|
dump1090-fa (3.0.1) stable; urgency=medium
|
||||||
|
|
||||||
|
* PiAware 3.0.1
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Fri, 15 Jul 2016 13:04:47 +0100
|
||||||
|
|
||||||
|
dump1090-fa (3.0~flightfeeder) stable; urgency=medium
|
||||||
|
|
||||||
|
* New release series based on dump1090-mutability.
|
||||||
|
* Initial 3.0 release for FlightFeeder images.
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Mon, 11 Jan 2016 17:20:05 +0000
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
8
|
10
|
||||||
|
|
|
||||||
|
|
@ -1,128 +0,0 @@
|
||||||
## TEMPLATE FILE - This is used to create /etc/default/dump1090-mutability ##
|
|
||||||
## The first three lines will be discarded ##
|
|
||||||
|
|
||||||
# dump1090-mutability configuration file
|
|
||||||
# This is a POSIX shell fragment.
|
|
||||||
# You can edit this file directly, or use
|
|
||||||
# "dpkg-reconfigure dump1090-mutability"
|
|
||||||
|
|
||||||
# Set to "yes" to start dump1090 on boot.
|
|
||||||
START_DUMP1090=
|
|
||||||
|
|
||||||
# User to run dump1090 as.
|
|
||||||
DUMP1090_USER=
|
|
||||||
|
|
||||||
# Logfile to log to
|
|
||||||
LOGFILE=
|
|
||||||
|
|
||||||
#
|
|
||||||
# Receiver options
|
|
||||||
#
|
|
||||||
|
|
||||||
# RTLSDR device index or serial number to use
|
|
||||||
# If set to "none", dump1090 will be started in --net-only mode
|
|
||||||
DEVICE=
|
|
||||||
|
|
||||||
# RTLSDR gain in dB.
|
|
||||||
# If set to "max" (the default) the maximum supported gain is used.
|
|
||||||
# If set to "agc", the tuner AGC is used to set the gain.
|
|
||||||
GAIN=
|
|
||||||
|
|
||||||
# RTLSDR frequency correction in PPM
|
|
||||||
PPM=
|
|
||||||
|
|
||||||
# If yes, enable sampling at 2.4MHz. Otherwise, 2.0MHz is used.
|
|
||||||
OVERSAMPLE=
|
|
||||||
|
|
||||||
# If yes, enables phase-enhancement of messages
|
|
||||||
PHASE_ENHANCE=
|
|
||||||
|
|
||||||
#
|
|
||||||
# Decoding options
|
|
||||||
#
|
|
||||||
|
|
||||||
# If yes, fixes messages with correctable CRC errors.
|
|
||||||
FIX_CRC=
|
|
||||||
|
|
||||||
# If yes, enables aggressive fixes to damaged messages.
|
|
||||||
# Use with caution - it can increase the rate of undetected errors.
|
|
||||||
AGGRESSIVE=
|
|
||||||
|
|
||||||
# If set, supplies a reference location for local position decoding.
|
|
||||||
LAT=
|
|
||||||
LON=
|
|
||||||
|
|
||||||
# If set, provides the absolute maximum receiver range used to
|
|
||||||
# filter bad position reports, and to determine when local position
|
|
||||||
# decoding is safe to use. Specify this in nautical miles (NM).
|
|
||||||
MAX_RANGE=
|
|
||||||
|
|
||||||
#
|
|
||||||
# Networking options
|
|
||||||
#
|
|
||||||
|
|
||||||
# Port to listen on for HTTP connections. 0 disables.
|
|
||||||
# HTTP defaults to being disabled unless you specify something here. I
|
|
||||||
# that you do not enable this, and instead serve the contents of
|
|
||||||
# /usr/share/dump1090-mutability and JSON_DIR (below) using a proper
|
|
||||||
# webserver. See /etc/lighttpd/conf-available/90-dump1090.conf
|
|
||||||
# for an example configuration ("sudo lighty-enable-mod dump1090" to enable)
|
|
||||||
HTTP_PORT=
|
|
||||||
|
|
||||||
# Port to listen on for raw (AVR-format) input connections. 0 disables.
|
|
||||||
RAW_INPUT_PORT=
|
|
||||||
|
|
||||||
# Port to listen on for raw (AVR-format) output connections. 0 disables.
|
|
||||||
RAW_OUTPUT_PORT=
|
|
||||||
|
|
||||||
# Port to listen on for SBS-format output connections. 0 disables.
|
|
||||||
SBS_OUTPUT_PORT=
|
|
||||||
|
|
||||||
# Port to listen on for Beast-format input connections. 0 disables.
|
|
||||||
BEAST_INPUT_PORT=
|
|
||||||
|
|
||||||
# Port to listen on for Beast-format output connections. 0 disables.
|
|
||||||
BEAST_OUTPUT_PORT=
|
|
||||||
|
|
||||||
# Port to listen on for FATSV-format output connections. 0 disables.
|
|
||||||
FATSV_OUTPUT_PORT=
|
|
||||||
|
|
||||||
# TCP heartbeat interval in seconds. 0 disables.
|
|
||||||
NET_HEARTBEAT=
|
|
||||||
|
|
||||||
# Minimum output buffer size per write, in bytes.
|
|
||||||
NET_OUTPUT_SIZE=
|
|
||||||
|
|
||||||
# Maximum buffering time before writing, in seconds.
|
|
||||||
NET_OUTPUT_INTERVAL=
|
|
||||||
|
|
||||||
# TCP buffer size, in bytes
|
|
||||||
NET_BUFFER=
|
|
||||||
|
|
||||||
# Bind ports on a particular address. If unset, binds to all interfaces.
|
|
||||||
# This defaults to binding to localhost. If you need to allow remote
|
|
||||||
# connections, change this.
|
|
||||||
NET_BIND_ADDRESS=
|
|
||||||
|
|
||||||
#
|
|
||||||
# Misc options
|
|
||||||
#
|
|
||||||
|
|
||||||
# Interval (in seconds) between logging stats to the logfile. 0 disables.
|
|
||||||
STATS_INTERVAL=
|
|
||||||
|
|
||||||
# Path to write json state to (for use with an external webserver). Blank disables.
|
|
||||||
JSON_DIR=
|
|
||||||
|
|
||||||
# Interval between writing json state (in seconds). 0 disables.
|
|
||||||
JSON_INTERVAL=
|
|
||||||
|
|
||||||
# Accuracy of receiver location to write to json state, one of "exact" / "approximate" / "none"
|
|
||||||
JSON_LOCATION_ACCURACY=
|
|
||||||
|
|
||||||
# Set to yes to log all decoded messages
|
|
||||||
# This can get large fast!
|
|
||||||
LOG_DECODED_MESSAGES=
|
|
||||||
|
|
||||||
# Additional options that are passed to the Daemon.
|
|
||||||
EXTRA_ARGS=
|
|
||||||
|
|
@ -1,21 +1,22 @@
|
||||||
Source: dump1090-mutability
|
Source: dump1090-fa
|
||||||
Section: embedded
|
Section: embedded
|
||||||
Priority: extra
|
Priority: extra
|
||||||
Maintainer: Oliver Jowett <oliver@mutability.co.uk>
|
Maintainer: Oliver Jowett <oliver.jowett@flightaware.com>
|
||||||
Build-Depends: debhelper(>=8), librtlsdr-dev, libusb-1.0-0-dev, pkg-config
|
Build-Depends: debhelper(>=10),
|
||||||
|
librtlsdr-dev <!custom> <rtlsdr>,
|
||||||
|
libbladerf-dev <!custom> <bladerf>,
|
||||||
|
libhackrf-dev <!custom> <hackrf>,
|
||||||
|
liblimesuite-dev <!custom> <limesdr>,
|
||||||
|
libusb-1.0-0-dev <!custom> <rtlsdr> <bladerf> <hackrf> <limesdr>,
|
||||||
|
pkg-config, libncurses5-dev
|
||||||
Standards-Version: 3.9.3
|
Standards-Version: 3.9.3
|
||||||
Homepage: https://github.com/mutability/dump1090
|
Homepage: http://www.flightaware.com/
|
||||||
Vcs-Git: https://github.com/mutability/dump1090.git
|
Vcs-Git: https://github.com/flightaware/dump1090.git
|
||||||
|
|
||||||
Package: dump1090-mutability
|
Package: dump1090-fa
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, adduser
|
Depends: ${shlibs:Depends}, ${misc:Depends}, adduser, lighttpd
|
||||||
Recommends: python(>=2.5), cron | cron-daemon
|
Description: FlightAware ADS-B Ground Station System for SDRs
|
||||||
Suggests: lighttpd
|
Networked Aviation Mode S / ADS-B decoder/translator with support
|
||||||
Provides: fatsv-data-source
|
for RTL-SDR, BladeRF, HackRF, and LimeSDR software defined radio USB
|
||||||
Description: ADS-B Ground Station System for RTL-SDR
|
device support.
|
||||||
Networked Aviation Mode S / ADS-B decoder/translator with RTL-SDR software
|
|
||||||
defined radio USB device support.
|
|
||||||
.
|
|
||||||
This is a packaging of the "mutability" fork of dump1090 that includes
|
|
||||||
sampling at 2.4MHz and other improvements.
|
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,61 @@ Copyright: Copyright 2012 Salvatore Sanfilippo <antirez@gmail.com>
|
||||||
Copyright 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
|
Copyright 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
License: BSD-3-Clause and GPL-2+
|
License: BSD-3-Clause and GPL-2+
|
||||||
|
|
||||||
Files: cprtests.c cpr.h crc.c crc.h demod_2000.h demod_2400.c demod_2000.h icao_filter.c icao_filter.h demod_2400.h demod_2000.h crc.h
|
Files: cprtests.c cpr.h crc.c crc.h demod_2000.h demod_2400.c demod_2000.h icao_filter.c icao_filter.h demod_2400.h demod_2000.h
|
||||||
Copyright: Copyright 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
|
Copyright: Copyright 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
License: GPL-2+
|
License: GPL-2+
|
||||||
|
|
||||||
Files: debian/*
|
Files: compat/clock_gettime/*
|
||||||
|
Copyright: Copyright (c), MM Weiss
|
||||||
|
License: BSD-3-Clause
|
||||||
|
|
||||||
|
Files: compat/clock_nanosleep/*
|
||||||
|
Copyright: Copyright © 2006 Rémi Denis-Courmont.
|
||||||
|
License: GPL-2+
|
||||||
|
|
||||||
|
Files: public_html/coolclock/*
|
||||||
|
Copyright: Copyright 2010, Simon Baird
|
||||||
|
License: BSD-3-Clause
|
||||||
|
Comment: 3-clause clarified with https://github.com/simonbaird/CoolClock/blob/a3e6d1a6fcf9d5bfd81d862d91d83a3892cb6923/LICENSE
|
||||||
|
|
||||||
|
Files: public_html/coolclock/excanvas.js
|
||||||
|
Copyright: Copyright 2006 Google Inc.
|
||||||
|
License: Apache-2.0
|
||||||
|
|
||||||
|
Files: public_html/flags-tiny/*
|
||||||
|
Copyright: Gang of the Coconuts
|
||||||
|
License: CC-BY-SA-3.0
|
||||||
|
|
||||||
|
Files: public_html/markers.js
|
||||||
|
Copyright: Kaboldy
|
||||||
|
Icons made by Freepik
|
||||||
|
License: CC-BY-SA-3.0 and CC-BY-3.0
|
||||||
|
Comment: _generic_plane_svg was added with https://github.com/mutability/dump1090/commit/5f0e295580c34da34ecef3a37f03e9a9d57485ff
|
||||||
|
https://github.com/DE8MSH
|
||||||
|
|
||||||
|
Files: public_html/jquery/*
|
||||||
|
Copyright: 2015 jQuery Foundation and other contributors
|
||||||
|
License: MIT
|
||||||
|
Source: http://www.jquery.com/
|
||||||
|
|
||||||
|
Files: public_html/ol3/ol-3.17.1.css public_html/ol3/ol-3.17.1.js
|
||||||
|
Copyright: 2005-2016 OpenLayers Contributors
|
||||||
|
License: BSD-2-Clause-OpenLayers
|
||||||
|
Source: http://openlayers.org
|
||||||
|
|
||||||
|
Files: public_html/ol3/ol3-layerswitcher.js public_html/ol3/ol3-layerswitcher.css
|
||||||
|
Copyright: Matt Walker
|
||||||
|
License: MIT
|
||||||
|
Source: https://github.com/walkermatt/ol3-layerswitcher
|
||||||
|
|
||||||
|
Files: debian/* debian-wheezy/*
|
||||||
Copyright: 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
|
Copyright: 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
License: BSD-3-Clause
|
License: BSD-3-Clause
|
||||||
|
|
||||||
|
Files: debian-wheezy/dump1090-fa.udev
|
||||||
|
Copyright: 2012-2013 Osmocom rtl-sdr project
|
||||||
|
License: GPL-3+
|
||||||
|
|
||||||
License: GPL-2+
|
License: GPL-2+
|
||||||
This program is free software; you can redistribute it
|
This program is free software; you can redistribute it
|
||||||
and/or modify it under the terms of the GNU General Public
|
and/or modify it under the terms of the GNU General Public
|
||||||
|
|
@ -39,6 +86,50 @@ License: GPL-2+
|
||||||
License version 2 can be found in the file
|
License version 2 can be found in the file
|
||||||
`/usr/share/common-licenses/GPL-2'.
|
`/usr/share/common-licenses/GPL-2'.
|
||||||
|
|
||||||
|
License: GPL-3+
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
.
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
.
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
.
|
||||||
|
On Debian systems, the full text of the GNU General Public
|
||||||
|
License version 3 can be found in the file
|
||||||
|
`/usr/share/common-licenses/GPL-3'.
|
||||||
|
|
||||||
|
License: BSD-2-Clause-OpenLayers
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
.
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation and/or
|
||||||
|
other materials provided with the distribution.
|
||||||
|
.
|
||||||
|
THIS SOFTWARE IS PROVIDED BY OPENLAYERS 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 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.
|
||||||
|
.
|
||||||
|
The views and conclusions contained in the software and documentation are those
|
||||||
|
of the authors and should not be interpreted as representing official policies,
|
||||||
|
either expressed or implied, of OpenLayers Contributors.
|
||||||
|
|
||||||
License: BSD-3-Clause
|
License: BSD-3-Clause
|
||||||
Redistribution and use in source and binary forms, with or without
|
Redistribution and use in source and binary forms, with or without
|
||||||
modification, are permitted provided that the following conditions
|
modification, are permitted provided that the following conditions
|
||||||
|
|
@ -63,3 +154,674 @@ License: BSD-3-Clause
|
||||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
License: Apache-2.0
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
||||||
|
contributor license agreements. See the NOTICE file distributed with
|
||||||
|
this work for additional information regarding copyright ownership.
|
||||||
|
The ASF licenses this file to You under the Apache License, Version 2.0
|
||||||
|
(the "License"); you may not use this file except in compliance with
|
||||||
|
the License. You may obtain a copy of the License at
|
||||||
|
.
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
.
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
.
|
||||||
|
On Debian systems, the full text of the Apache Software License version 2
|
||||||
|
can be found in the file `/usr/share/common-licenses/Apache-2.0'.
|
||||||
|
|
||||||
|
License: CC-BY-SA-3.0
|
||||||
|
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE LEGAL
|
||||||
|
SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN ATTORNEY-CLIENT
|
||||||
|
RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS"
|
||||||
|
BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE INFORMATION
|
||||||
|
PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM ITS USE.
|
||||||
|
.
|
||||||
|
License
|
||||||
|
.
|
||||||
|
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
|
||||||
|
COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
|
||||||
|
COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
|
||||||
|
AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
|
||||||
|
.
|
||||||
|
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE TO
|
||||||
|
BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY BE
|
||||||
|
CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED
|
||||||
|
HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
|
||||||
|
.
|
||||||
|
1. Definitions
|
||||||
|
"Adaptation" means a work based upon the Work, or upon the Work and
|
||||||
|
other pre-existing works, such as a translation, adaptation, derivative
|
||||||
|
work, arrangement of music or other alterations of a literary or
|
||||||
|
artistic work, or phonogram or performance and includes cinematographic
|
||||||
|
adaptations or any other form in which the Work may be recast,
|
||||||
|
transformed, or adapted including in any form recognizably derived from
|
||||||
|
the original, except that a work that constitutes a Collection will not
|
||||||
|
be considered an Adaptation for the purpose of this License. For the
|
||||||
|
avoidance of doubt, where the Work is a musical work, performance or
|
||||||
|
phonogram, the synchronization of the Work in timed-relation with a
|
||||||
|
moving image ("synching") will be considered an Adaptation for the
|
||||||
|
purpose of this License.
|
||||||
|
"Collection" means a collection of literary or artistic works, such as
|
||||||
|
encyclopedias and anthologies, or performances, phonograms or
|
||||||
|
broadcasts, or other works or subject matter other than works listed in
|
||||||
|
Section 1(f) below, which, by reason of the selection and arrangement of
|
||||||
|
their contents, constitute intellectual creations, in which the Work is
|
||||||
|
included in its entirety in unmodified form along with one or more other
|
||||||
|
contributions, each constituting separate and independent works in
|
||||||
|
themselves, which together are assembled into a collective whole. A work
|
||||||
|
that constitutes a Collection will not be considered an Adaptation (as
|
||||||
|
defined below) for the purposes of this License.
|
||||||
|
"Creative Commons Compatible License" means a license that is listed at
|
||||||
|
http://creativecommons.org/compatiblelicenses that has been approved by
|
||||||
|
Creative Commons as being essentially equivalent to this License,
|
||||||
|
including, at a minimum, because that license: (i) contains terms that
|
||||||
|
have the same purpose, meaning and effect as the License Elements of
|
||||||
|
this License; and, (ii) explicitly permits the relicensing of
|
||||||
|
adaptations of works made available under that license under this
|
||||||
|
License or a Creative Commons jurisdiction license with the same License
|
||||||
|
Elements as this License.
|
||||||
|
"Distribute" means to make available to the public the original and
|
||||||
|
copies of the Work or Adaptation, as appropriate, through sale or other
|
||||||
|
transfer of ownership.
|
||||||
|
"License Elements" means the following high-level license attributes as
|
||||||
|
selected by Licensor and indicated in the title of this License:
|
||||||
|
Attribution, ShareAlike.
|
||||||
|
"Licensor" means the individual, individuals, entity or entities that
|
||||||
|
offer(s) the Work under the terms of this License.
|
||||||
|
"Original Author" means, in the case of a literary or artistic work, the
|
||||||
|
individual, individuals, entity or entities who created the Work or if
|
||||||
|
no individual or entity can be identified, the publisher; and in
|
||||||
|
addition (i) in the case of a performance the actors, singers,
|
||||||
|
musicians, dancers, and other persons who act, sing, deliver, declaim,
|
||||||
|
play in, interpret or otherwise perform literary or artistic works or
|
||||||
|
expressions of folklore; (ii) in the case of a phonogram the producer
|
||||||
|
being the person or legal entity who first fixes the sounds of a
|
||||||
|
performance or other sounds; and, (iii) in the case of broadcasts, the
|
||||||
|
organization that transmits the broadcast.
|
||||||
|
"Work" means the literary and/or artistic work offered under the terms
|
||||||
|
of this License including without limitation any production in the
|
||||||
|
literary, scientific and artistic domain, whatever may be the mode or
|
||||||
|
form of its expression including digital form, such as a book, pamphlet
|
||||||
|
and other writing; a lecture, address, sermon or other work of the same
|
||||||
|
nature; a dramatic or dramatico-musical work; a choreographic work or
|
||||||
|
entertainment in dumb show; a musical composition with or without words;
|
||||||
|
a cinematographic work to which are assimilated works expressed by a
|
||||||
|
process analogous to cinematography; a work of drawing, painting,
|
||||||
|
architecture, sculpture, engraving or lithography; a photographic work
|
||||||
|
to which are assimilated works expressed by a process analogous to
|
||||||
|
photography; a work of applied art; an illustration, map, plan, sketch
|
||||||
|
or three-dimensional work relative to geography, topography,
|
||||||
|
architecture or science; a performance; a broadcast; a phonogram; a
|
||||||
|
compilation of data to the extent it is protected as a copyrightable
|
||||||
|
work; or a work performed by a variety or circus performer to the extent
|
||||||
|
it is not otherwise considered a literary or artistic work.
|
||||||
|
"You" means an individual or entity exercising rights under this License
|
||||||
|
who has not previously violated the terms of this License with respect
|
||||||
|
to the Work, or who has received express permission from the Licensor to
|
||||||
|
exercise rights under this License despite a previous violation.
|
||||||
|
"Publicly Perform" means to perform public recitations of the Work and
|
||||||
|
to communicate to the public those public recitations, by any means or
|
||||||
|
process, including by wire or wireless means or public digital
|
||||||
|
performances; to make available to the public Works in such a way that
|
||||||
|
members of the public may access these Works from a place and at a place
|
||||||
|
individually chosen by them; to perform the Work to the public by any
|
||||||
|
means or process and the communication to the public of the performances
|
||||||
|
of the Work, including by public digital performance; to broadcast and
|
||||||
|
rebroadcast the Work by any means including signs, sounds or images.
|
||||||
|
"Reproduce" means to make copies of the Work by any means including
|
||||||
|
without limitation by sound or visual recordings and the right of
|
||||||
|
fixation and reproducing fixations of the Work, including storage of a
|
||||||
|
protected performance or phonogram in digital form or other electronic
|
||||||
|
medium.
|
||||||
|
.
|
||||||
|
2. Fair Dealing Rights. Nothing in this License is intended to reduce,
|
||||||
|
limit, or restrict any uses free from copyright or rights arising from
|
||||||
|
limitations or exceptions that are provided for in connection with the
|
||||||
|
copyright protection under copyright law or other applicable laws.
|
||||||
|
.
|
||||||
|
3. License Grant. Subject to the terms and conditions of this License,
|
||||||
|
Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
|
||||||
|
perpetual (for the duration of the applicable copyright) license to
|
||||||
|
exercise the rights in the Work as stated below:
|
||||||
|
.
|
||||||
|
to Reproduce the Work, to incorporate the Work into one or more
|
||||||
|
Collections, and to Reproduce the Work as incorporated in the
|
||||||
|
Collections;
|
||||||
|
to create and Reproduce Adaptations provided that any such Adaptation,
|
||||||
|
including any translation in any medium, takes reasonable steps to
|
||||||
|
clearly label, demarcate or otherwise identify that changes were made to
|
||||||
|
the original Work. For example, a translation could be marked "The
|
||||||
|
original work was translated from English to Spanish," or a modification
|
||||||
|
could indicate "The original work has been modified.";
|
||||||
|
to Distribute and Publicly Perform the Work including as incorporated in
|
||||||
|
Collections; and,
|
||||||
|
to Distribute and Publicly Perform Adaptations.
|
||||||
|
.
|
||||||
|
For the avoidance of doubt:
|
||||||
|
Non-waivable Compulsory License Schemes. In those jurisdictions in
|
||||||
|
which the right to collect royalties through any statutory or
|
||||||
|
compulsory licensing scheme cannot be waived, the Licensor reserves
|
||||||
|
the exclusive right to collect such royalties for any exercise by
|
||||||
|
You of the rights granted under this License;
|
||||||
|
Waivable Compulsory License Schemes. In those jurisdictions in which
|
||||||
|
the right to collect royalties through any statutory or compulsory
|
||||||
|
licensing scheme can be waived, the Licensor waives the exclusive
|
||||||
|
right to collect such royalties for any exercise by You of the
|
||||||
|
rights granted under this License; and,
|
||||||
|
Voluntary License Schemes. The Licensor waives the right to collect
|
||||||
|
royalties, whether individually or, in the event that the Licensor
|
||||||
|
is a member of a collecting society that administers voluntary
|
||||||
|
licensing schemes, via that society, from any exercise by You of the
|
||||||
|
rights granted under this License.
|
||||||
|
.
|
||||||
|
The above rights may be exercised in all media and formats whether now
|
||||||
|
known or hereafter devised. The above rights include the right to make such
|
||||||
|
modifications as are technically necessary to exercise the rights in other
|
||||||
|
media and formats. Subject to Section 8(f), all rights not expressly
|
||||||
|
granted by Licensor are hereby reserved.
|
||||||
|
.
|
||||||
|
4. Restrictions. The license granted in Section 3 above is expressly made
|
||||||
|
subject to and limited by the following restrictions:
|
||||||
|
.
|
||||||
|
You may Distribute or Publicly Perform the Work only under the terms of
|
||||||
|
this License. You must include a copy of, or the Uniform Resource
|
||||||
|
Identifier (URI) for, this License with every copy of the Work You
|
||||||
|
Distribute or Publicly Perform. You may not offer or impose any terms on
|
||||||
|
the Work that restrict the terms of this License or the ability of the
|
||||||
|
recipient of the Work to exercise the rights granted to that recipient
|
||||||
|
under the terms of the License. You may not sublicense the Work. You
|
||||||
|
must keep intact all notices that refer to this License and to the
|
||||||
|
disclaimer of warranties with every copy of the Work You Distribute or
|
||||||
|
Publicly Perform. When You Distribute or Publicly Perform the Work, You
|
||||||
|
may not impose any effective technological measures on the Work that
|
||||||
|
restrict the ability of a recipient of the Work from You to exercise the
|
||||||
|
rights granted to that recipient under the terms of the License. This
|
||||||
|
Section 4(a) applies to the Work as incorporated in a Collection, but
|
||||||
|
this does not require the Collection apart from the Work itself to be
|
||||||
|
made subject to the terms of this License. If You create a Collection,
|
||||||
|
upon notice from any Licensor You must, to the extent practicable,
|
||||||
|
remove from the Collection any credit as required by Section 4(c), as
|
||||||
|
requested. If You create an Adaptation, upon notice from any Licensor
|
||||||
|
You must, to the extent practicable, remove from the Adaptation any
|
||||||
|
credit as required by Section 4(c), as requested.
|
||||||
|
You may Distribute or Publicly Perform an Adaptation only under the
|
||||||
|
terms of: (i) this License; (ii) a later version of this License with
|
||||||
|
the same License Elements as this License; (iii) a Creative Commons
|
||||||
|
jurisdiction license (either this or a later license version) that
|
||||||
|
contains the same License Elements as this License (e.g.,
|
||||||
|
Attribution-ShareAlike 3.0 US)); (iv) a Creative Commons Compatible
|
||||||
|
License. If you license the Adaptation under one of the licenses
|
||||||
|
mentioned in (iv), you must comply with the terms of that license. If
|
||||||
|
you license the Adaptation under the terms of any of the licenses
|
||||||
|
mentioned in (i), (ii) or (iii) (the "Applicable License"), you must
|
||||||
|
comply with the terms of the Applicable License generally and the
|
||||||
|
following provisions: (I) You must include a copy of, or the URI for,
|
||||||
|
the Applicable License with every copy of each Adaptation You Distribute
|
||||||
|
or Publicly Perform; (II) You may not offer or impose any terms on the
|
||||||
|
Adaptation that restrict the terms of the Applicable License or the
|
||||||
|
ability of the recipient of the Adaptation to exercise the rights
|
||||||
|
granted to that recipient under the terms of the Applicable License;
|
||||||
|
(III) You must keep intact all notices that refer to the Applicable
|
||||||
|
License and to the disclaimer of warranties with every copy of the Work
|
||||||
|
as included in the Adaptation You Distribute or Publicly Perform; (IV)
|
||||||
|
when You Distribute or Publicly Perform the Adaptation, You may not
|
||||||
|
impose any effective technological measures on the Adaptation that
|
||||||
|
restrict the ability of a recipient of the Adaptation from You to
|
||||||
|
exercise the rights granted to that recipient under the terms of the
|
||||||
|
Applicable License. This Section 4(b) applies to the Adaptation as
|
||||||
|
incorporated in a Collection, but this does not require the Collection
|
||||||
|
apart from the Adaptation itself to be made subject to the terms of the
|
||||||
|
Applicable License.
|
||||||
|
If You Distribute, or Publicly Perform the Work or any Adaptations or
|
||||||
|
Collections, You must, unless a request has been made pursuant to
|
||||||
|
Section 4(a), keep intact all copyright notices for the Work and
|
||||||
|
provide, reasonable to the medium or means You are utilizing: (i) the
|
||||||
|
name of the Original Author (or pseudonym, if applicable) if supplied,
|
||||||
|
and/or if the Original Author and/or Licensor designate another party or
|
||||||
|
parties (e.g., a sponsor institute, publishing entity, journal) for
|
||||||
|
attribution ("Attribution Parties") in Licensor's copyright notice,
|
||||||
|
terms of service or by other reasonable means, the name of such party or
|
||||||
|
parties; (ii) the title of the Work if supplied; (iii) to the extent
|
||||||
|
reasonably practicable, the URI, if any, that Licensor specifies to be
|
||||||
|
associated with the Work, unless such URI does not refer to the
|
||||||
|
copyright notice or licensing information for the Work; and (iv) ,
|
||||||
|
consistent with Ssection 3(b), in the case of an Adaptation, a credit
|
||||||
|
identifying the use of the Work in the Adaptation (e.g., "French
|
||||||
|
translation of the Work by Original Author," or "Screenplay based on
|
||||||
|
original Work by Original Author"). The credit required by this Section
|
||||||
|
4(c) may be implemented in any reasonable manner; provided, however,
|
||||||
|
that in the case of a Adaptation or Collection, at a minimum such credit
|
||||||
|
will appear, if a credit for all contributing authors of the Adaptation
|
||||||
|
or Collection appears, then as part of these credits and in a manner at
|
||||||
|
least as prominent as the credits for the other contributing authors.
|
||||||
|
For the avoidance of doubt, You may only use the credit required by this
|
||||||
|
Section for the purpose of attribution in the manner set out above and,
|
||||||
|
by exercising Your rights under this License, You may not implicitly or
|
||||||
|
explicitly assert or imply any connection with, sponsorship or
|
||||||
|
endorsement by the Original Author, Licensor and/or Attribution Parties,
|
||||||
|
as appropriate, of You or Your use of the Work, without the separate,
|
||||||
|
express prior written permission of the Original Author, Licensor and/or
|
||||||
|
Attribution Parties.
|
||||||
|
Except as otherwise agreed in writing by the Licensor or as may be
|
||||||
|
otherwise permitted by applicable law, if You Reproduce, Distribute or
|
||||||
|
Publicly Perform the Work either by itself or as part of any Adaptations
|
||||||
|
or Collections, You must not distort, mutilate, modify or take other
|
||||||
|
derogatory action in relation to the Work which would be prejudicial to
|
||||||
|
the Original Author's honor or reputation. Licensor agrees that in those
|
||||||
|
jurisdictions (e.g. Japan), in which any exercise of the right granted
|
||||||
|
in Section 3(b) of this License (the right to make Adaptations) would be
|
||||||
|
deemed to be a distortion, mutilation, modification or other derogatory
|
||||||
|
action prejudicial to the Original Author's honor and reputation, the
|
||||||
|
Licensor will waive or not assert, as appropriate, this Section, to the
|
||||||
|
fullest extent permitted by the applicable national law, to enable You
|
||||||
|
to reasonably exercise Your right under Section 3(b) of this License
|
||||||
|
(right to make Adaptations) but not otherwise.
|
||||||
|
.
|
||||||
|
5. Representations, Warranties and Disclaimer
|
||||||
|
.
|
||||||
|
UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR
|
||||||
|
OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY
|
||||||
|
KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE,
|
||||||
|
INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF LATENT
|
||||||
|
OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER
|
||||||
|
OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF
|
||||||
|
IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
|
||||||
|
.
|
||||||
|
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE
|
||||||
|
LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY
|
||||||
|
SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES ARISING
|
||||||
|
OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS BEEN
|
||||||
|
ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
.
|
||||||
|
7. Termination
|
||||||
|
.
|
||||||
|
This License and the rights granted hereunder will terminate
|
||||||
|
automatically upon any breach by You of the terms of this License.
|
||||||
|
Individuals or entities who have received Adaptations or Collections
|
||||||
|
from You under this License, however, will not have their licenses
|
||||||
|
terminated provided such individuals or entities remain in full
|
||||||
|
compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will
|
||||||
|
survive any termination of this License.
|
||||||
|
Subject to the above terms and conditions, the license granted here is
|
||||||
|
perpetual (for the duration of the applicable copyright in the Work).
|
||||||
|
Notwithstanding the above, Licensor reserves the right to release the
|
||||||
|
Work under different license terms or to stop distributing the Work at
|
||||||
|
any time; provided, however that any such election will not serve to
|
||||||
|
withdraw this License (or any other license that has been, or is
|
||||||
|
required to be, granted under the terms of this License), and this
|
||||||
|
License will continue in full force and effect unless terminated as
|
||||||
|
stated above.
|
||||||
|
.
|
||||||
|
8. Miscellaneous
|
||||||
|
.
|
||||||
|
Each time You Distribute or Publicly Perform the Work or a Collection,
|
||||||
|
the Licensor offers to the recipient a license to the Work on the same
|
||||||
|
terms and conditions as the license granted to You under this License.
|
||||||
|
Each time You Distribute or Publicly Perform an Adaptation, Licensor
|
||||||
|
offers to the recipient a license to the original Work on the same terms
|
||||||
|
and conditions as the license granted to You under this License.
|
||||||
|
If any provision of this License is invalid or unenforceable under
|
||||||
|
applicable law, it shall not affect the validity or enforceability of
|
||||||
|
the remainder of the terms of this License, and without further action
|
||||||
|
by the parties to this agreement, such provision shall be reformed to
|
||||||
|
the minimum extent necessary to make such provision valid and
|
||||||
|
enforceable.
|
||||||
|
No term or provision of this License shall be deemed waived and no
|
||||||
|
breach consented to unless such waiver or consent shall be in writing
|
||||||
|
and signed by the party to be charged with such waiver or consent.
|
||||||
|
This License constitutes the entire agreement between the parties with
|
||||||
|
respect to the Work licensed here. There are no understandings,
|
||||||
|
agreements or representations with respect to the Work not specified
|
||||||
|
here. Licensor shall not be bound by any additional provisions that may
|
||||||
|
appear in any communication from You. This License may not be modified
|
||||||
|
without the mutual written agreement of the Licensor and You.
|
||||||
|
The rights granted under, and the subject matter referenced, in this
|
||||||
|
License were drafted utilizing the terminology of the Berne Convention
|
||||||
|
for t Protection of Literary and Artistic Works (as amended on
|
||||||
|
September 28, 1979), the Rome Convention of 1961, the WIPO Copyright
|
||||||
|
Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and
|
||||||
|
the Universal Copyright Convention (as revised on July 24, 1971). These
|
||||||
|
rights and subject matter take effect in the relevant jurisdiction in
|
||||||
|
which the License terms are sought to be enforced according to the
|
||||||
|
corresponding provisions of the implementation of those treaty
|
||||||
|
provisions in the applicable national law. If the standard suite of
|
||||||
|
rights granted under applicable copyright law includes additional rights
|
||||||
|
not granted under this License, such additional rights are deemed to be
|
||||||
|
included in the License; this License is not intended to restrict the
|
||||||
|
license of any rights under applicable law.
|
||||||
|
|
||||||
|
License: CC-BY-3.0
|
||||||
|
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE
|
||||||
|
LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN
|
||||||
|
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION
|
||||||
|
ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE
|
||||||
|
INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM
|
||||||
|
ITS USE.
|
||||||
|
.
|
||||||
|
License
|
||||||
|
.
|
||||||
|
THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE
|
||||||
|
COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY
|
||||||
|
COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
|
||||||
|
AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED.
|
||||||
|
.
|
||||||
|
BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE
|
||||||
|
TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY
|
||||||
|
BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS
|
||||||
|
CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
|
||||||
|
CONDITIONS.
|
||||||
|
.
|
||||||
|
1. Definitions
|
||||||
|
.
|
||||||
|
a. "Adaptation" means a work based upon the Work, or upon the Work and
|
||||||
|
other pre-existing works, such as a translation, adaptation, derivative
|
||||||
|
work, arrangement of music or other alterations of a literary or
|
||||||
|
artistic work, or phonogram or performance and includes cinematographic
|
||||||
|
adaptations or any other form in which the Work may be recast,
|
||||||
|
transformed, or adapted including in any form recognizably derived from
|
||||||
|
the original, except that a work that constitutes a Collection will not
|
||||||
|
be considered an Adaptation for the purpose of this License. For the
|
||||||
|
avoidance of doubt, where the Work is a musical work, performance or
|
||||||
|
phonogram, the synchronization of the Work in timed-relation with a
|
||||||
|
moving image ("synching") will be considered an Adaptation for the
|
||||||
|
purpose of this License.
|
||||||
|
.
|
||||||
|
b. "Collection" means a collection of literary or artistic works, such
|
||||||
|
as encyclopedias and anthologies, or performances, phonograms or
|
||||||
|
broadcasts, or other works or subject matter other than works listed in
|
||||||
|
Section 1(f) below, which, by reason of the selection and arrangement of
|
||||||
|
their contents, constitute intellectual creations, in which the Work is
|
||||||
|
included in its entirety in unmodified form along with one or more other
|
||||||
|
contributions, each constituting separate and independent works in
|
||||||
|
themselves, which together are assembled into a collective whole. A work
|
||||||
|
that constitutes a Collection will not be considered an Adaptation (as
|
||||||
|
defined above) for the purposes of this License.
|
||||||
|
.
|
||||||
|
c. "Distribute" means to make available to the public the original and
|
||||||
|
copies of the Work or Adaptation, as appropriate, through sale or other
|
||||||
|
transfer of ownership.
|
||||||
|
.
|
||||||
|
d. "Licensor" means the individual, individuals, entity or entities that
|
||||||
|
offer(s) the Work under the terms of this License.
|
||||||
|
.
|
||||||
|
e. "Original Author" means, in the case of a literary or artistic work,
|
||||||
|
the individual, individuals, entity or entities who created the Work or
|
||||||
|
if no individual or entity can be identified, the publisher; and in
|
||||||
|
addition (i) in the case of a performance the actors, singers,
|
||||||
|
musicians, dancers, and other persons who act, sing, deliver, declaim,
|
||||||
|
play in, interpret or otherwise perform literary or artistic works or
|
||||||
|
expressions of folklore; (ii) in the case of a phonogram the producer
|
||||||
|
being the person or legal entity who first fixes the sounds of a
|
||||||
|
performance or other sounds; and, (iii) in the case of broadcasts, the
|
||||||
|
organization that transmits the broadcast.
|
||||||
|
.
|
||||||
|
f. "Work" means the literary and/or artistic work offered under the
|
||||||
|
terms of this License including without limitation any production in the
|
||||||
|
literary, scientific and artistic domain, whatever may be the mode or
|
||||||
|
form of its expression including digital form, such as a book, pamphlet
|
||||||
|
and other writing; a lecture, address, sermon or other work of the same
|
||||||
|
nature; a dramatic or dramatico-musical work; a choreographic work or
|
||||||
|
entertainment in dumb show; a musical composition with or without words;
|
||||||
|
a cinematographic work to which are assimilated works expressed by a
|
||||||
|
process analogous to cinematography; a work of drawing, painting,
|
||||||
|
architecture, sculpture, engraving or lithography; a photographic work
|
||||||
|
to which are assimilated works expressed by a process analogous to
|
||||||
|
photography; a work of applied art; an illustration, map, plan, sketch
|
||||||
|
or three-dimensional work relative to geography, topography,
|
||||||
|
architecture or science; a performance; a broadcast; a phonogram; a
|
||||||
|
compilation of data to the extent it is protected as a copyrightable
|
||||||
|
work; or a work performed by a variety or circus performer to the extent
|
||||||
|
it is not otherwise considered a literary or artistic work.
|
||||||
|
.
|
||||||
|
g. "You" means an individual or entity exercising rights under this
|
||||||
|
License who has not previously violated the terms of this License with
|
||||||
|
respect to the Work, or who has received express permission from the
|
||||||
|
Licensor to exercise rights under this License despite a previous
|
||||||
|
violation.
|
||||||
|
.
|
||||||
|
h. "Publicly Perform" means to perform public recitations of the Work
|
||||||
|
and to communicate to the public those public recitations, by any means
|
||||||
|
or process, including by wire or wireless means or public digital
|
||||||
|
performances; to make available to the public Works in such a way that
|
||||||
|
members of the public may access these Works from a place and at a place
|
||||||
|
individually chosen by them; to perform the Work to the public by any
|
||||||
|
means or process and the communication to the public of the performances
|
||||||
|
of the Work, including by public digital performance; to broadcast and
|
||||||
|
rebroadcast the Work by any means including signs, sounds or images.
|
||||||
|
.
|
||||||
|
i. "Reproduce" means to make copies of the Work by any means including
|
||||||
|
without limitation by sound or visual recordings and the right of
|
||||||
|
fixation and reproducing fixations of the Work, including storage of a
|
||||||
|
protected performance or phonogram in digital form or other electronic
|
||||||
|
medium.
|
||||||
|
.
|
||||||
|
2. Fair Dealing Rights. Nothing in this License is intended to reduce,
|
||||||
|
limit, or restrict any uses free from copyright or rights arising from
|
||||||
|
limitations or exceptions that are provided for in connection with the
|
||||||
|
copyright protection under copyright law or other applicable laws.
|
||||||
|
.
|
||||||
|
3. License Grant. Subject to the terms and conditions of this License,
|
||||||
|
Licensor hereby grants You a worldwide, royalty-free, non-exclusive,
|
||||||
|
perpetual (for the duration of the applicable copyright) license to
|
||||||
|
exercise the rights in the Work as stated below:
|
||||||
|
.
|
||||||
|
a. to Reproduce the Work, to incorporate the Work into one or more
|
||||||
|
Collections, and to Reproduce the Work as incorporated in the
|
||||||
|
Collections;
|
||||||
|
.
|
||||||
|
b. to create and Reproduce Adaptations provided that any such
|
||||||
|
Adaptation, including any translation in any medium, takes reasonable
|
||||||
|
steps to clearly label, demarcate or otherwise identify that changes
|
||||||
|
were made to the original Work. For example, a translation could be
|
||||||
|
marked "The original work was translated from English to Spanish," or a
|
||||||
|
modification could indicate "The original work has been modified.";
|
||||||
|
.
|
||||||
|
c. to Distribute and Publicly Perform the Work including as incorporated
|
||||||
|
in Collections; and,
|
||||||
|
.
|
||||||
|
d. to Distribute and Publicly Perform Adaptations.
|
||||||
|
.
|
||||||
|
e. For the avoidance of doubt:
|
||||||
|
.
|
||||||
|
i. Non-waivable Compulsory License Schemes. In those jurisdictions in
|
||||||
|
which the right to collect royalties through any statutory or compulsory
|
||||||
|
licensing scheme cannot be waived, the Licensor reserves the exclusive
|
||||||
|
right to collect such royalties for any exercise by You of the rights
|
||||||
|
granted under this License;
|
||||||
|
.
|
||||||
|
ii. Waivable Compulsory License Schemes. In those jurisdictions in which
|
||||||
|
the right to collect royalties through any statutory or compulsory
|
||||||
|
licensing scheme can be waived, the Licensor waives the exclusive right
|
||||||
|
to collect such royalties for any exercise by You of the rights granted
|
||||||
|
under this License; and,
|
||||||
|
.
|
||||||
|
iii. Voluntary License Schemes. The Licensor waives the right to collect
|
||||||
|
royalties, whether individually or, in the event that the Licensor is a
|
||||||
|
member of a collecting society that administers voluntary licensing
|
||||||
|
schemes, via that society, from any exercise by You of the rights
|
||||||
|
granted under this License.
|
||||||
|
.
|
||||||
|
The above rights may be exercised in all media and formats whether now
|
||||||
|
known or hereafter devised. The above rights include the right to make
|
||||||
|
such modifications as are technically necessary to exercise the rights
|
||||||
|
in other media and formats. Subject to Section 8(f), all rights not
|
||||||
|
expressly granted by Licensor are hereby reserved.
|
||||||
|
.
|
||||||
|
4. Restrictions. The license granted in Section 3 above is expressly
|
||||||
|
made subject to and limited by the following restrictions:
|
||||||
|
.
|
||||||
|
a. You may Distribute or Publicly Perform the Work only under the terms
|
||||||
|
of this License. You must include a copy of, or the Uniform Resource
|
||||||
|
Identifier (URI) for, this License with every copy of the Work You
|
||||||
|
Distribute or Publicly Perform. You may not offer or impose any terms on
|
||||||
|
the Work that restrict the terms of this License or the ability of the
|
||||||
|
recipient of the Work to exercise the rights granted to that recipient
|
||||||
|
under the terms of the License. You may not sublicense the Work. You
|
||||||
|
must keep intact all notices that refer to this License and to the
|
||||||
|
disclaimer of warranties with every copy of the Work You Distribute or
|
||||||
|
Publicly Perform. When You Distribute or Publicly Perform the Work, You
|
||||||
|
may not impose any effective technological measures on the Work that
|
||||||
|
restrict the ability of a recipient of the Work from You to exercise the
|
||||||
|
rights granted to that recipient under the terms of the License. This
|
||||||
|
Section 4(a) applies to the Work as incorporated in a Collection, but
|
||||||
|
this does not require the Collection apart from the Work itself to be
|
||||||
|
made subject to the terms of this License. If You create a Collection,
|
||||||
|
upon notice from any Licensor You must, to the extent practicable,
|
||||||
|
remove from the Collection any credit as required by Section 4(b), as
|
||||||
|
requested. If You create an Adaptation, upon notice from any Licensor
|
||||||
|
You must, to the extent practicable, remove from the Adaptation any
|
||||||
|
credit as required by Section 4(b), as requested.
|
||||||
|
.
|
||||||
|
b. If You Distribute, or Publicly Perform the Work or any Adaptations or
|
||||||
|
Collections, You must, unless a request has been made pursuant to
|
||||||
|
Section 4(a), keep intact all copyright notices for the Work and
|
||||||
|
provide, reasonable to the medium or means You are utilizing: (i) the
|
||||||
|
name of the Original Author (or pseudonym, if applicable) if supplied,
|
||||||
|
and/or if the Original Author and/or Licensor designate another party or
|
||||||
|
parties (e.g., a sponsor institute, publishing entity, journal) for
|
||||||
|
attribution ("Attribution Parties") in Licensor's copyright notice,
|
||||||
|
terms of service or by other reasonable means, the name of such party or
|
||||||
|
parties; (ii) the title of the Work if supplied; (iii) to the extent
|
||||||
|
reasonably practicable, the URI, if any, that Licensor specifies to be
|
||||||
|
associated with the Work, unless such URI does not refer to the
|
||||||
|
copyright notice or licensing information for the Work; and (iv) ,
|
||||||
|
consistent with Section 3(b), in the case of an Adaptation, a credit
|
||||||
|
identifying the use of the Work in the Adaptation (e.g., "French
|
||||||
|
translation of the Work by Original Author," or "Screenplay based on
|
||||||
|
original Work by Original Author"). The credit required by this Section
|
||||||
|
4 (b) may be implemented in any reasonable manner; provided, however,
|
||||||
|
that in the case of a Adaptation or Collection, at a minimum such credit
|
||||||
|
will appear, if a credit for all contributing authors of the Adaptation
|
||||||
|
or Collection appears, then as part of these credits and in a manner at
|
||||||
|
least as prominent as the credits for the other contributing authors.
|
||||||
|
For the avoidance of doubt, You may only use the credit required by this
|
||||||
|
Section for the purpose of attribution in the manner set out above and,
|
||||||
|
by exercising Your rights under this License, You may not implicitly or
|
||||||
|
explicitly assert or imply any connection with, sponsorship or
|
||||||
|
endorsement by the Original Author, Licensor and/or Attribution Parties,
|
||||||
|
as appropriate, of You or Your use of the Work, without the separate,
|
||||||
|
express prior written permission of the Original Author, Licensor and/or
|
||||||
|
Attribution Parties.
|
||||||
|
.
|
||||||
|
c. Except as otherwise agreed in writing by the Licensor or as may be
|
||||||
|
otherwise permitted by applicable law, if You Reproduce, Distribute or
|
||||||
|
Publicly Perform the Work either by itself or as part of any Adaptations
|
||||||
|
or Collections, You must not distort, mutilate, modify or take other
|
||||||
|
derogatory action in relation to the Work which would be prejudicial to
|
||||||
|
the Original Author's honor or reputation. Licensor agrees that in those
|
||||||
|
jurisdictions (e.g. Japan), in which any exercise of the right granted
|
||||||
|
in Section 3(b) of this License (the right to make Adaptations) would be
|
||||||
|
deemed to be a distortion, mutilation, modification or other derogatory
|
||||||
|
action prejudicial to the Original Author's honor and reputation, the
|
||||||
|
Licensor will waive or not assert, as appropriate, this Section, to the
|
||||||
|
fullest extent permitted by the applicable national law, to enable You
|
||||||
|
to reasonably exercise Your right under Section 3(b) of this License
|
||||||
|
(right to make Adaptations) but not otherwise.
|
||||||
|
.
|
||||||
|
5. Representations, Warranties and Disclaimer
|
||||||
|
.
|
||||||
|
UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR
|
||||||
|
OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY
|
||||||
|
KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE,
|
||||||
|
INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF
|
||||||
|
LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS,
|
||||||
|
WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE
|
||||||
|
EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU.
|
||||||
|
.
|
||||||
|
6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE
|
||||||
|
LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR
|
||||||
|
ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES
|
||||||
|
ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS
|
||||||
|
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
||||||
|
.
|
||||||
|
7. Termination
|
||||||
|
.
|
||||||
|
a. This License and the rights granted hereunder will terminate
|
||||||
|
automatically upon any breach by You of the terms of this License.
|
||||||
|
Individuals or entities who have received Adaptations or Collections
|
||||||
|
from You under this License, however, will not have their licenses
|
||||||
|
terminated provided such individuals or entities remain in full
|
||||||
|
compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will
|
||||||
|
survive any termination of this License.
|
||||||
|
.
|
||||||
|
b. Subject to the above terms and conditions, the license granted here
|
||||||
|
is perpetual (for the duration of the applicable copyright in the Work).
|
||||||
|
Notwithstanding the above, Licensor reserves the right to release the
|
||||||
|
Work under different license terms or to stop distributing the Work at
|
||||||
|
any time; provided, however that any such election will not serve to
|
||||||
|
withdraw this License (or any other license that has been, or is
|
||||||
|
required to be, granted under the terms of this License), and this
|
||||||
|
License will continue in full force and effect unless terminated as
|
||||||
|
stated above.
|
||||||
|
.
|
||||||
|
8. Miscellaneous
|
||||||
|
.
|
||||||
|
a. Each time You Distribute or Publicly Perform the Work or a
|
||||||
|
Collection, the Licensor offers to the recipient a license to the Work
|
||||||
|
on the same terms and conditions as the license granted to You under
|
||||||
|
this License.
|
||||||
|
.
|
||||||
|
b. Each time You Distribute or Publicly Perform an Adaptation, Licensor
|
||||||
|
offers to the recipient a license to the original Work on the same terms
|
||||||
|
and conditions as the license granted to You under this License.
|
||||||
|
.
|
||||||
|
c. If any provision of this License is invalid or unenforceable under
|
||||||
|
applicable law, it shall not affect the validity or enforceability of
|
||||||
|
the remainder of the terms of this License, and without further action
|
||||||
|
by the parties to this agreement, such provision shall be reformed to
|
||||||
|
the minimum extent necessary to make such provision valid and
|
||||||
|
enforceable.
|
||||||
|
.
|
||||||
|
d. No term or provision of this License shall be deemed waived and no
|
||||||
|
breach consented to unless such waiver or consent shall be in writing
|
||||||
|
and signed by the party to be charged with such waiver or consent. This
|
||||||
|
License constitutes the entire agreement between the parties with
|
||||||
|
respect to the Work licensed here. There are no understandings,
|
||||||
|
agreements or representatio Work not specified
|
||||||
|
here. Licensor shall not be bound by any additional provisions that may
|
||||||
|
appear in any communication from You.
|
||||||
|
.
|
||||||
|
e. This License may not be modified without the mutual written agreement
|
||||||
|
of the Licensor and You.
|
||||||
|
.
|
||||||
|
f. The rights granted under, and the subject matter referenced, in this
|
||||||
|
License were drafted utilizing the terminology of the Berne Convention
|
||||||
|
for the Protection of Literary and Artistic Works (as amended on
|
||||||
|
September 28, 1979), the Rome Convention of 1961, the WIPO Copyright
|
||||||
|
Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 and
|
||||||
|
the Universal Copyright Convention (as revised on July 24, 1971). These
|
||||||
|
rights and subject matter take effect in the relevant jurisdiction in
|
||||||
|
which the License terms are sought to be enforced according to the
|
||||||
|
corresponding provisions of the implementation of those treaty
|
||||||
|
provisions in the applicable national law. If the standard suite of
|
||||||
|
rights granted under applicable copyright law includes additional rights
|
||||||
|
not granted under this License, such additional rights are deemed to be
|
||||||
|
included in the License; this License is not intended to restrict the
|
||||||
|
license of any rights under applicable law.
|
||||||
|
|
||||||
|
License: MIT
|
||||||
|
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.
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue