mirror of
https://gitea.osmocom.org/cellular-infrastructure/osmo-trx.git
synced 2025-11-03 21:53:18 +00:00
Compare commits
680 Commits
ttsou/sigg
...
1.7.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4f6e9eb4cf | ||
|
|
24f938bfa5 | ||
|
|
132ec7452d | ||
|
|
553d6b0b51 | ||
|
|
a7f5826351 | ||
|
|
75cf9254a3 | ||
|
|
c5f623f966 | ||
|
|
8fd51cb7c9 | ||
|
|
e6dc78e5c5 | ||
|
|
9982b33597 | ||
|
|
52ef221657 | ||
|
|
ec13193cae | ||
|
|
3d8598d460 | ||
|
|
1d7f5a9175 | ||
|
|
511d62733e | ||
|
|
8f19df3bd7 | ||
|
|
b7cde0f6a2 | ||
|
|
25590be470 | ||
|
|
f1ce0e7692 | ||
|
|
99e0746f37 | ||
|
|
1f8eb7c658 | ||
|
|
d8a1dee2c9 | ||
|
|
56c7b777f3 | ||
|
|
989fe75038 | ||
|
|
8aea236c56 | ||
|
|
a2d76f1d2f | ||
|
|
a118d98ec3 | ||
|
|
c7fc94dff6 | ||
|
|
06c0810e98 | ||
|
|
6ee9dccddb | ||
|
|
242ceb25d1 | ||
|
|
b52650f157 | ||
|
|
992a49e586 | ||
|
|
ad9b8b4211 | ||
|
|
0f4381d480 | ||
|
|
2ada887367 | ||
|
|
5042156437 | ||
|
|
70ed3d586e | ||
|
|
3dfbb6d9f6 | ||
|
|
58294fde4b | ||
|
|
d372eb2f0b | ||
|
|
287ae681b7 | ||
|
|
cca5d93f66 | ||
|
|
a5a2275a08 | ||
|
|
1499f0343a | ||
|
|
8c1d59086e | ||
|
|
f57a86131e | ||
|
|
7d5c16590c | ||
|
|
f8c7a52521 | ||
|
|
c0f78a37ed | ||
|
|
19e134a626 | ||
|
|
a98521ac05 | ||
|
|
df4520df77 | ||
|
|
2f40abd8f5 | ||
|
|
6a3e4b32f0 | ||
|
|
c3e515a28b | ||
|
|
bcaafcaa9d | ||
|
|
ea7bd5fb91 | ||
|
|
135d64b1a9 | ||
|
|
e44cf44af4 | ||
|
|
c0f0a6105a | ||
|
|
da5ffd6e01 | ||
|
|
40978041ad | ||
|
|
3e7f4b0da9 | ||
|
|
4080cd05ba | ||
|
|
b3157b91bb | ||
|
|
805e0d9c6b | ||
|
|
4b2b98b067 | ||
|
|
2e6c362b9c | ||
|
|
7e47a521ef | ||
|
|
f35515c015 | ||
|
|
874542ca7c | ||
|
|
f476a6755b | ||
|
|
1ddd727bb4 | ||
|
|
8a4362459d | ||
|
|
5ba130c381 | ||
|
|
fed58d97b8 | ||
|
|
0e13bfd18c | ||
|
|
cf1ca2e92e | ||
|
|
20ecc4f531 | ||
|
|
097a16e384 | ||
|
|
c9af0b0ba0 | ||
|
|
621a49eb69 | ||
|
|
f538397826 | ||
|
|
8c4336dba9 | ||
|
|
fe1b9cef40 | ||
|
|
5e63151f9f | ||
|
|
10b4e31655 | ||
|
|
0c433350da | ||
|
|
d0c1055051 | ||
|
|
0ce64705e0 | ||
|
|
d0b947a0c4 | ||
|
|
4a867be165 | ||
|
|
fdcce1fc6e | ||
|
|
2ca77d7ff2 | ||
|
|
b6fd0709f4 | ||
|
|
d3e3bba2cd | ||
|
|
5561f1129d | ||
|
|
b7253c6fdc | ||
|
|
5a23a24bb1 | ||
|
|
b60fb8e1e3 | ||
|
|
934e1016ff | ||
|
|
ac726b1147 | ||
|
|
508270d83d | ||
|
|
7d897cb5b0 | ||
|
|
94dcf6d29c | ||
|
|
040497e0a4 | ||
|
|
8984d7f2ca | ||
|
|
aa7a40ee84 | ||
|
|
f2f35fc592 | ||
|
|
00ddcfaf50 | ||
|
|
2f20c564bf | ||
|
|
19faae85c6 | ||
|
|
1c6a3459cd | ||
|
|
32311d8635 | ||
|
|
71c46e91df | ||
|
|
a39fa875a3 | ||
|
|
9a3e3fceb8 | ||
|
|
1a19caf002 | ||
|
|
424c74d006 | ||
|
|
a7143d3cd0 | ||
|
|
019d698126 | ||
|
|
a686277c72 | ||
|
|
683f140739 | ||
|
|
5e40d92400 | ||
|
|
bb2cb9d54b | ||
|
|
b9423b25b6 | ||
|
|
069f5cd857 | ||
|
|
c90b207803 | ||
|
|
985694175d | ||
|
|
ac8a4e7297 | ||
|
|
e16d0e1330 | ||
|
|
e6fdf8fcad | ||
|
|
cdd77a447d | ||
|
|
7f696801ae | ||
|
|
d16eb314ed | ||
|
|
27bd2f6dd1 | ||
|
|
8803f923f9 | ||
|
|
ecea734b97 | ||
|
|
0c34c64a16 | ||
|
|
0a038223d0 | ||
|
|
5e6b10cd9e | ||
|
|
b6f238c0f2 | ||
|
|
c27fe60a25 | ||
|
|
a1ea63f777 | ||
|
|
c7930b0b22 | ||
|
|
17ce7740e5 | ||
|
|
d06259f348 | ||
|
|
6c646c35b9 | ||
|
|
90d841748e | ||
|
|
e2404f4e41 | ||
|
|
309ad4d901 | ||
|
|
3b8f7c4d97 | ||
|
|
48cad832ea | ||
|
|
56237bce95 | ||
|
|
5738940535 | ||
|
|
cec9eda227 | ||
|
|
ad202d72e1 | ||
|
|
0f4d5791df | ||
|
|
2a637a5c9c | ||
|
|
819cad1776 | ||
|
|
54a98b5b52 | ||
|
|
fca503d0b4 | ||
|
|
e8edd1fcae | ||
|
|
7e27deb8cb | ||
|
|
a9512d963a | ||
|
|
c6220741b1 | ||
|
|
4a4e607a19 | ||
|
|
1587307a99 | ||
|
|
7e83f18bba | ||
|
|
57db77f185 | ||
|
|
94def47fdf | ||
|
|
3fb4d31ecb | ||
|
|
744e44eaa1 | ||
|
|
faacb1987e | ||
|
|
c0e7ce922a | ||
|
|
ab6e7f35ab | ||
|
|
5d6504c45a | ||
|
|
c620ced36d | ||
|
|
ef79fd9b95 | ||
|
|
e0bdb6b47b | ||
|
|
948b4e4096 | ||
|
|
c7a750d428 | ||
|
|
0ff9c9fca3 | ||
|
|
24cb0c9948 | ||
|
|
6be2d15541 | ||
|
|
bc5263cee1 | ||
|
|
6b4acc12f7 | ||
|
|
d1ca287d83 | ||
|
|
a0d862ba1d | ||
|
|
c5989fe180 | ||
|
|
08970c562f | ||
|
|
e91544d740 | ||
|
|
93fee1f163 | ||
|
|
e69a56cec5 | ||
|
|
76795401fb | ||
|
|
30863e8720 | ||
|
|
0fbdfefebc | ||
|
|
b7c6f1e83f | ||
|
|
4d43684194 | ||
|
|
54bde5a8ba | ||
|
|
fd88564acb | ||
|
|
82c72218fd | ||
|
|
1f37e4dd74 | ||
|
|
7d8676a144 | ||
|
|
8808fa86f0 | ||
|
|
2a0fb962c7 | ||
|
|
03334967c9 | ||
|
|
e30e0ad9be | ||
|
|
7a52e42ee0 | ||
|
|
4080eb76f8 | ||
|
|
1e17c4fb0a | ||
|
|
f9a2f44272 | ||
|
|
3bf2c5de8d | ||
|
|
553a25033e | ||
|
|
1d165a043e | ||
|
|
199a306d27 | ||
|
|
c249ce2a58 | ||
|
|
761da1a08a | ||
|
|
9032c87d80 | ||
|
|
df675784a7 | ||
|
|
99330740dd | ||
|
|
b70686c13d | ||
|
|
1d0c6fe752 | ||
|
|
8b0c5368f5 | ||
|
|
c0d6fd27ff | ||
|
|
032c1d8da9 | ||
|
|
c62a05140c | ||
|
|
a71c5d073f | ||
|
|
92ba59dacf | ||
|
|
6a3a2b8647 | ||
|
|
fb96767ac5 | ||
|
|
394053e599 | ||
|
|
68d8db4d8c | ||
|
|
58d80a014e | ||
|
|
5bd3d4263b | ||
|
|
f68f19b110 | ||
|
|
8ac169f7ed | ||
|
|
405f17a98c | ||
|
|
b536ab9bdf | ||
|
|
174fb03b8e | ||
|
|
b899c19f1f | ||
|
|
992c9bd1ce | ||
|
|
056ce136e6 | ||
|
|
0e09e7c98a | ||
|
|
1b3a8881eb | ||
|
|
fdefbfac39 | ||
|
|
5e16f79f0f | ||
|
|
f3155e33b9 | ||
|
|
7bbe19ee9d | ||
|
|
f669bf43e7 | ||
|
|
4a575b02b5 | ||
|
|
cf35c37c94 | ||
|
|
6e369348b0 | ||
|
|
546516d79c | ||
|
|
6879bb0db9 | ||
|
|
a7143bf7a1 | ||
|
|
4ffdca10d4 | ||
|
|
1a26b4f085 | ||
|
|
c5d5586fbd | ||
|
|
cc971aa1a6 | ||
|
|
748d8edbf8 | ||
|
|
dfc6e5ffc7 | ||
|
|
f8c0c464b8 | ||
|
|
93707d0227 | ||
|
|
5291e8a654 | ||
|
|
7a07de1efd | ||
|
|
fd67262df8 | ||
|
|
0569845a08 | ||
|
|
c69b87f9bd | ||
|
|
a7bf6cd8a4 | ||
|
|
e7f6a27ab6 | ||
|
|
a979f5f32b | ||
|
|
b0e54265ad | ||
|
|
62c9280590 | ||
|
|
1421adbc61 | ||
|
|
dccc82491c | ||
|
|
bf58370675 | ||
|
|
7c84925ea4 | ||
|
|
fd99c6ce05 | ||
|
|
e947db8d98 | ||
|
|
9279e0e123 | ||
|
|
84231bd8b7 | ||
|
|
aebbfe0ee7 | ||
|
|
da7fee8ea8 | ||
|
|
9f2baf3e04 | ||
|
|
0a2a40f43c | ||
|
|
501d053b70 | ||
|
|
0fafe03199 | ||
|
|
9a87d90c1e | ||
|
|
066fd04f47 | ||
|
|
aeaba02e02 | ||
|
|
b7e992703c | ||
|
|
928141b7d6 | ||
|
|
e503c988d8 | ||
|
|
ee2ba19cec | ||
|
|
80d053acb9 | ||
|
|
18a615176e | ||
|
|
25383a3610 | ||
|
|
e2ac20a96e | ||
|
|
62845241a2 | ||
|
|
2ab921812e | ||
|
|
752055c7c1 | ||
|
|
705a348326 | ||
|
|
331c88ae82 | ||
|
|
ca0892d822 | ||
|
|
17e6cd0394 | ||
|
|
a801ae5d94 | ||
|
|
923b4bc9a2 | ||
|
|
0d56d75dbb | ||
|
|
94c5241403 | ||
|
|
e3a2516280 | ||
|
|
1fba10409b | ||
|
|
77f3396d04 | ||
|
|
e0010fa425 | ||
|
|
bfc1d0bed7 | ||
|
|
76ff96e210 | ||
|
|
4e6ec4554d | ||
|
|
e4166be76f | ||
|
|
e7195ac7d0 | ||
|
|
ca6a78e193 | ||
|
|
67aa91b2c0 | ||
|
|
3eed8ebb0d | ||
|
|
d0cbb16a93 | ||
|
|
e774d52504 | ||
|
|
72a75f3e43 | ||
|
|
27424a39ee | ||
|
|
c7ac63afa5 | ||
|
|
cbc02086d5 | ||
|
|
3d29b4d5b0 | ||
|
|
06d3ba0445 | ||
|
|
8a784c7145 | ||
|
|
7758542087 | ||
|
|
68a78099a0 | ||
|
|
50c78dfe85 | ||
|
|
207911bcde | ||
|
|
2c673e0f3e | ||
|
|
b4c749b32b | ||
|
|
c641f781dc | ||
|
|
6b30ab0c34 | ||
|
|
720b912ba9 | ||
|
|
c3325b9aeb | ||
|
|
88f86a14ba | ||
|
|
21d03d3912 | ||
|
|
bdb970e495 | ||
|
|
e6319ed32a | ||
|
|
1830705e67 | ||
|
|
46d0be06ab | ||
|
|
2896cecefb | ||
|
|
5c6ca1739f | ||
|
|
80ca1de44a | ||
|
|
2a3d8ba71a | ||
|
|
6fa906c280 | ||
|
|
a7ba484fb2 | ||
|
|
758381bad4 | ||
|
|
56c5f2959b | ||
|
|
dd571c6db1 | ||
|
|
b31232537a | ||
|
|
8d771d24e7 | ||
|
|
cf6113b2fe | ||
|
|
13c81098f8 | ||
|
|
15fa64bce4 | ||
|
|
c9202ab0be | ||
|
|
b49a42e70b | ||
|
|
c3d68c159f | ||
|
|
7ee2d10113 | ||
|
|
252564b50e | ||
|
|
2ded53c440 | ||
|
|
95c8318d5d | ||
|
|
9bb24a1103 | ||
|
|
d6dbb1b987 | ||
|
|
be9cd66020 | ||
|
|
b9d2515704 | ||
|
|
7dc07b9425 | ||
|
|
07ddce5c1f | ||
|
|
25ae190dc6 | ||
|
|
607a414967 | ||
|
|
0e67cf24eb | ||
|
|
ff6aeb7f62 | ||
|
|
ddd18a5e33 | ||
|
|
778b30a530 | ||
|
|
e9ce77b871 | ||
|
|
c27d9f88df | ||
|
|
ac0487eb66 | ||
|
|
6a305feb0f | ||
|
|
bde55afd29 | ||
|
|
4c50bf435b | ||
|
|
63e872a701 | ||
|
|
b426e4abb4 | ||
|
|
4456b6f132 | ||
|
|
76a5013c91 | ||
|
|
9281771256 | ||
|
|
dcbcfa58e4 | ||
|
|
b5def414b8 | ||
|
|
fc73c073a1 | ||
|
|
a7919265f5 | ||
|
|
9b394e0cc0 | ||
|
|
580c48b7d5 | ||
|
|
7214fde085 | ||
|
|
51509b3895 | ||
|
|
ef192d303c | ||
|
|
ac927b2690 | ||
|
|
3e9179a55e | ||
|
|
87b7d098e5 | ||
|
|
7bef2346c4 | ||
|
|
2876785f50 | ||
|
|
713b4d81cd | ||
|
|
b96d9ddee3 | ||
|
|
048c3ba300 | ||
|
|
75cb0b9dd6 | ||
|
|
46324d3597 | ||
|
|
bab1583a2c | ||
|
|
541496b65b | ||
|
|
c785fb130a | ||
|
|
2875290d95 | ||
|
|
4ce4555d0e | ||
|
|
2d130fb15d | ||
|
|
6c5f4bae46 | ||
|
|
71df42550a | ||
|
|
24f05ea1f7 | ||
|
|
d280045884 | ||
|
|
5e6f3e0cad | ||
|
|
21032b75c0 | ||
|
|
d01c7b98b6 | ||
|
|
158ea5bc66 | ||
|
|
3733ed5097 | ||
|
|
a8b3565246 | ||
|
|
a3934a11a4 | ||
|
|
acf804c034 | ||
|
|
d20b7fa579 | ||
|
|
77e18352fb | ||
|
|
f97d75b355 | ||
|
|
a944001873 | ||
|
|
42c165605a | ||
|
|
affd351787 | ||
|
|
03b11620d9 | ||
|
|
25185886f0 | ||
|
|
47031405f5 | ||
|
|
0646b3ce75 | ||
|
|
46cf9efc8e | ||
|
|
871713bf6a | ||
|
|
8d9a05ce5b | ||
|
|
fe865f45d7 | ||
|
|
e5b6664419 | ||
|
|
1595ddaa5f | ||
|
|
441d82add9 | ||
|
|
867cea575b | ||
|
|
2f53ea4cf2 | ||
|
|
138caaf09d | ||
|
|
3fadcad33e | ||
|
|
eaa0144dcb | ||
|
|
f7331764ac | ||
|
|
800c029c70 | ||
|
|
522cbe91d3 | ||
|
|
ed361f9912 | ||
|
|
2d085e290b | ||
|
|
5cea18e5cb | ||
|
|
4adc4eb8d0 | ||
|
|
41c68aa41c | ||
|
|
39e0bbacca | ||
|
|
b4ea7b5211 | ||
|
|
69869bd58f | ||
|
|
ebb37693a5 | ||
|
|
55928f23cb | ||
|
|
0277b58f6d | ||
|
|
be8a83f681 | ||
|
|
d9a460dce9 | ||
|
|
f570b4af62 | ||
|
|
46560ea254 | ||
|
|
038ab45137 | ||
|
|
6b50b62b12 | ||
|
|
3984256273 | ||
|
|
d06172ce32 | ||
|
|
762c951faa | ||
|
|
e47d7e964a | ||
|
|
3cee25ac68 | ||
|
|
0bd0782a39 | ||
|
|
8072650406 | ||
|
|
c6541e6c26 | ||
|
|
1e2c0105e2 | ||
|
|
32b3c2e4b2 | ||
|
|
1c4bbadda6 | ||
|
|
08dfe237c8 | ||
|
|
444ff34396 | ||
|
|
a79bc70737 | ||
|
|
a439fed166 | ||
|
|
8fb0c3dce4 | ||
|
|
f5e1cf8790 | ||
|
|
e7d267f178 | ||
|
|
06f3b622b8 | ||
|
|
74bcc562a9 | ||
|
|
55dd2aa5ab | ||
|
|
5b60c98769 | ||
|
|
207d8a2624 | ||
|
|
92fc186450 | ||
|
|
4d179abfd0 | ||
|
|
6fdfb68b9e | ||
|
|
5ac2cb3662 | ||
|
|
f4ee021b8c | ||
|
|
e62555370e | ||
|
|
1f15152968 | ||
|
|
21ce05c54f | ||
|
|
5e68cde779 | ||
|
|
1f4a009c67 | ||
|
|
544ce0d6b7 | ||
|
|
b148d05542 | ||
|
|
970096932e | ||
|
|
db936b9b55 | ||
|
|
49ad759072 | ||
|
|
8e498bfd35 | ||
|
|
46444637c6 | ||
|
|
86be40b4eb | ||
|
|
288d8af070 | ||
|
|
aae403f0c9 | ||
|
|
5cc8858d8f | ||
|
|
70d0344b31 | ||
|
|
62002fb8ac | ||
|
|
03b3c30533 | ||
|
|
a4b569d936 | ||
|
|
eb0945d85d | ||
|
|
f968507912 | ||
|
|
58c89fb8d6 | ||
|
|
16e7e20f85 | ||
|
|
c7756e73b7 | ||
|
|
7ed686b223 | ||
|
|
2ab6ddb0de | ||
|
|
b229439b31 | ||
|
|
ffb3301bd8 | ||
|
|
62b7900fd7 | ||
|
|
61707e8b23 | ||
|
|
ce70ba529c | ||
|
|
cfb9dac70d | ||
|
|
105a61e689 | ||
|
|
2407314f2e | ||
|
|
ff4418539c | ||
|
|
0494d05916 | ||
|
|
fd268b6f5a | ||
|
|
43f3678b40 | ||
|
|
6493dc838b | ||
|
|
f7905ac548 | ||
|
|
0c27938d44 | ||
|
|
587916e810 | ||
|
|
79024867de | ||
|
|
4aec1f1cf5 | ||
|
|
68f054169b | ||
|
|
ea8be22e50 | ||
|
|
a5054b398b | ||
|
|
a438114173 | ||
|
|
9cb4f27112 | ||
|
|
c38e45e9dc | ||
|
|
1f50fedb5f | ||
|
|
c7a0bf1ffc | ||
|
|
940738e86a | ||
|
|
8c1e2bddff | ||
|
|
01eea0aa42 | ||
|
|
55df1e43e3 | ||
|
|
e9424e241f | ||
|
|
d0ac926b56 | ||
|
|
00d5114717 | ||
|
|
3a496f3b8a | ||
|
|
fad2e09840 | ||
|
|
e09e80f5ee | ||
|
|
2e276e7edd | ||
|
|
dffc21725c | ||
|
|
96f0f2cf7e | ||
|
|
225b16d48e | ||
|
|
0ebbb2ed2e | ||
|
|
2fea950644 | ||
|
|
d0a97a5f73 | ||
|
|
295b938d51 | ||
|
|
e8605202ab | ||
|
|
2a8183bdf0 | ||
|
|
478f82f47e | ||
|
|
f37b0ad652 | ||
|
|
3b78cbfdc1 | ||
|
|
f3d7f443a0 | ||
|
|
e564f0fd84 | ||
|
|
0fc20d14b3 | ||
|
|
a4316ee4c5 | ||
|
|
2128a308eb | ||
|
|
43fedb656b | ||
|
|
53bdb7f82a | ||
|
|
6462dd3963 | ||
|
|
e1977fcd22 | ||
|
|
f97296e0ce | ||
|
|
20259cb307 | ||
|
|
ffa4e5938c | ||
|
|
c0c6d70fe9 | ||
|
|
8c6c5d2bcd | ||
|
|
a62fcf786a | ||
|
|
4d9b59c3ef | ||
|
|
bd0efb0bea | ||
|
|
8fbbd656c7 | ||
|
|
b35cba613a | ||
|
|
8dffadb8da | ||
|
|
408f25081e | ||
|
|
2001550f7d | ||
|
|
a3ab8c263d | ||
|
|
efac20b6bb | ||
|
|
0bbd8922ea | ||
|
|
28b8cc6283 | ||
|
|
3f52f0e6c5 | ||
|
|
3da1f8352e | ||
|
|
5ea1817dc2 | ||
|
|
49d42e979e | ||
|
|
3a3b220751 | ||
|
|
ab22f4c421 | ||
|
|
8b843e5bed | ||
|
|
c92dad32dd | ||
|
|
61837c0420 | ||
|
|
f83e11fefd | ||
|
|
01aff88ce9 | ||
|
|
11d50d950c | ||
|
|
8bd111c942 | ||
|
|
3808e479aa | ||
|
|
bd45a979f8 | ||
|
|
b7095c7bc5 | ||
|
|
77ce99ac67 | ||
|
|
f58cd8ac83 | ||
|
|
99eb07e232 | ||
|
|
89be118a3b | ||
|
|
6fafd33b13 | ||
|
|
6e55d51747 | ||
|
|
6cae1d7b4b | ||
|
|
28ce315a32 | ||
|
|
10d76b6863 | ||
|
|
708b8b44ae | ||
|
|
cb0fc9b21a | ||
|
|
8639fee504 | ||
|
|
ca46896cfe | ||
|
|
4a25d6b8f6 | ||
|
|
79baee3a8f | ||
|
|
c2ba427b52 | ||
|
|
611212676b | ||
|
|
4ebb289c90 | ||
|
|
2f376a3edf | ||
|
|
2edbe4d366 | ||
|
|
a3694bd303 | ||
|
|
2652f2bc39 | ||
|
|
93d9b114b7 | ||
|
|
2ac788b2c3 | ||
|
|
d36ef2f57b | ||
|
|
caf2abc58f | ||
|
|
de1685f6d7 | ||
|
|
f3837d26f9 | ||
|
|
ddf4743306 | ||
|
|
82f83ced73 | ||
|
|
cff4ed9b4c | ||
|
|
6ec26bb788 | ||
|
|
a1ff991402 | ||
|
|
d09843c692 | ||
|
|
e5448ff972 | ||
|
|
e48c1367dc | ||
|
|
aa60dda99a | ||
|
|
1468a5c3dc | ||
|
|
b0e1bd8c22 | ||
|
|
78e1cd20e2 | ||
|
|
db9c1b54cb | ||
|
|
099a44abfb | ||
|
|
8c80095017 | ||
|
|
d49a6aa136 | ||
|
|
81486e053c | ||
|
|
28d8081e25 | ||
|
|
87ed77b937 | ||
|
|
f9d996813d | ||
|
|
aa5acc953c | ||
|
|
934da48618 | ||
|
|
7c405a0c1f | ||
|
|
4cafb0fa15 | ||
|
|
f611569018 | ||
|
|
354741326c | ||
|
|
d2e5c5694e | ||
|
|
a3dce85ffc | ||
|
|
bb0c68ae61 | ||
|
|
87d158cc2d | ||
|
|
7278a87767 | ||
|
|
63eef9faf2 | ||
|
|
d67bd603e9 | ||
|
|
988a464d5d | ||
|
|
1b6ab7d7ee |
5
.checkpatch.conf
Normal file
5
.checkpatch.conf
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
--exclude osmocom-bb/.*
|
||||||
|
--exclude .*h
|
||||||
|
--exclude Transceiver52M/grgsm_vitac/.*
|
||||||
|
--exclude utils/va-test/.*
|
||||||
|
--ignore FUNCTION_WITHOUT_ARGS
|
||||||
521
.clang-format
Normal file
521
.clang-format
Normal file
@@ -0,0 +1,521 @@
|
|||||||
|
# SPDX-License-Identifier: GPL-2.0
|
||||||
|
#
|
||||||
|
# clang-format configuration file. Intended for clang-format >= 4.
|
||||||
|
#
|
||||||
|
# For more information, see:
|
||||||
|
#
|
||||||
|
# Documentation/process/clang-format.rst
|
||||||
|
# https://clang.llvm.org/docs/ClangFormat.html
|
||||||
|
# https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||||
|
#
|
||||||
|
---
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
AlignAfterOpenBracket: Align
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
AlignConsecutiveDeclarations: false
|
||||||
|
#AlignEscapedNewlines: Left # Unknown to clang-format-4.0
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
AlwaysBreakTemplateDeclarations: true
|
||||||
|
BinPackArguments: true
|
||||||
|
BinPackParameters: true
|
||||||
|
BraceWrapping:
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: false
|
||||||
|
AfterEnum: false
|
||||||
|
AfterFunction: true
|
||||||
|
AfterNamespace: true
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
#AfterExternBlock: false # Unknown to clang-format-5.0
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
IndentBraces: false
|
||||||
|
#SplitEmptyFunction: true # Unknown to clang-format-4.0
|
||||||
|
#SplitEmptyRecord: true # Unknown to clang-format-4.0
|
||||||
|
#SplitEmptyNamespace: true # Unknown to clang-format-4.0
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Custom
|
||||||
|
#BreakBeforeInheritanceComma: false # Unknown to clang-format-4.0
|
||||||
|
BreakBeforeTernaryOperators: false
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
#BreakConstructorInitializers: BeforeComma # Unknown to clang-format-4.0
|
||||||
|
BreakAfterJavaFieldAnnotations: false
|
||||||
|
BreakStringLiterals: false
|
||||||
|
ColumnLimit: 120
|
||||||
|
CommentPragmas: '^ IWYU pragma:'
|
||||||
|
#CompactNamespaces: false # Unknown to clang-format-4.0
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 8
|
||||||
|
ContinuationIndentWidth: 8
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
#FixNamespaceComments: false # Unknown to clang-format-4.0
|
||||||
|
|
||||||
|
# Taken from:
|
||||||
|
# git grep -h '^#define [^[:space:]]*for_each[^[:space:]]*(' include/ \
|
||||||
|
# | sed "s,^#define \([^[:space:]]*for_each[^[:space:]]*\)(.*$, - '\1'," \
|
||||||
|
# | sort | uniq
|
||||||
|
ForEachMacros:
|
||||||
|
- 'apei_estatus_for_each_section'
|
||||||
|
- 'ata_for_each_dev'
|
||||||
|
- 'ata_for_each_link'
|
||||||
|
- '__ata_qc_for_each'
|
||||||
|
- 'ata_qc_for_each'
|
||||||
|
- 'ata_qc_for_each_raw'
|
||||||
|
- 'ata_qc_for_each_with_internal'
|
||||||
|
- 'ax25_for_each'
|
||||||
|
- 'ax25_uid_for_each'
|
||||||
|
- '__bio_for_each_bvec'
|
||||||
|
- 'bio_for_each_bvec'
|
||||||
|
- 'bio_for_each_integrity_vec'
|
||||||
|
- '__bio_for_each_segment'
|
||||||
|
- 'bio_for_each_segment'
|
||||||
|
- 'bio_for_each_segment_all'
|
||||||
|
- 'bio_list_for_each'
|
||||||
|
- 'bip_for_each_vec'
|
||||||
|
- 'bitmap_for_each_clear_region'
|
||||||
|
- 'bitmap_for_each_set_region'
|
||||||
|
- 'blkg_for_each_descendant_post'
|
||||||
|
- 'blkg_for_each_descendant_pre'
|
||||||
|
- 'blk_queue_for_each_rl'
|
||||||
|
- 'bond_for_each_slave'
|
||||||
|
- 'bond_for_each_slave_rcu'
|
||||||
|
- 'bpf_for_each_spilled_reg'
|
||||||
|
- 'btree_for_each_safe128'
|
||||||
|
- 'btree_for_each_safe32'
|
||||||
|
- 'btree_for_each_safe64'
|
||||||
|
- 'btree_for_each_safel'
|
||||||
|
- 'card_for_each_dev'
|
||||||
|
- 'cgroup_taskset_for_each'
|
||||||
|
- 'cgroup_taskset_for_each_leader'
|
||||||
|
- 'cpufreq_for_each_entry'
|
||||||
|
- 'cpufreq_for_each_entry_idx'
|
||||||
|
- 'cpufreq_for_each_valid_entry'
|
||||||
|
- 'cpufreq_for_each_valid_entry_idx'
|
||||||
|
- 'css_for_each_child'
|
||||||
|
- 'css_for_each_descendant_post'
|
||||||
|
- 'css_for_each_descendant_pre'
|
||||||
|
- 'device_for_each_child_node'
|
||||||
|
- 'dma_fence_chain_for_each'
|
||||||
|
- 'drm_atomic_crtc_for_each_plane'
|
||||||
|
- 'drm_atomic_crtc_state_for_each_plane'
|
||||||
|
- 'drm_atomic_crtc_state_for_each_plane_state'
|
||||||
|
- 'drm_atomic_for_each_plane_damage'
|
||||||
|
- 'drm_client_for_each_connector_iter'
|
||||||
|
- 'drm_client_for_each_modeset'
|
||||||
|
- 'drm_connector_for_each_possible_encoder'
|
||||||
|
- 'drm_for_each_bridge_in_chain'
|
||||||
|
- 'drm_for_each_connector_iter'
|
||||||
|
- 'drm_for_each_crtc'
|
||||||
|
- 'drm_for_each_encoder'
|
||||||
|
- 'drm_for_each_encoder_mask'
|
||||||
|
- 'drm_for_each_fb'
|
||||||
|
- 'drm_for_each_legacy_plane'
|
||||||
|
- 'drm_for_each_plane'
|
||||||
|
- 'drm_for_each_plane_mask'
|
||||||
|
- 'drm_for_each_privobj'
|
||||||
|
- 'drm_mm_for_each_hole'
|
||||||
|
- 'drm_mm_for_each_node'
|
||||||
|
- 'drm_mm_for_each_node_in_range'
|
||||||
|
- 'drm_mm_for_each_node_safe'
|
||||||
|
- 'flow_action_for_each'
|
||||||
|
- 'for_each_active_dev_scope'
|
||||||
|
- 'for_each_active_drhd_unit'
|
||||||
|
- 'for_each_active_iommu'
|
||||||
|
- 'for_each_available_child_of_node'
|
||||||
|
- 'for_each_bio'
|
||||||
|
- 'for_each_board_func_rsrc'
|
||||||
|
- 'for_each_bvec'
|
||||||
|
- 'for_each_card_auxs'
|
||||||
|
- 'for_each_card_auxs_safe'
|
||||||
|
- 'for_each_card_components'
|
||||||
|
- 'for_each_card_pre_auxs'
|
||||||
|
- 'for_each_card_prelinks'
|
||||||
|
- 'for_each_card_rtds'
|
||||||
|
- 'for_each_card_rtds_safe'
|
||||||
|
- 'for_each_cgroup_storage_type'
|
||||||
|
- 'for_each_child_of_node'
|
||||||
|
- 'for_each_clear_bit'
|
||||||
|
- 'for_each_clear_bit_from'
|
||||||
|
- 'for_each_cmsghdr'
|
||||||
|
- 'for_each_compatible_node'
|
||||||
|
- 'for_each_component_dais'
|
||||||
|
- 'for_each_component_dais_safe'
|
||||||
|
- 'for_each_comp_order'
|
||||||
|
- 'for_each_console'
|
||||||
|
- 'for_each_cpu'
|
||||||
|
- 'for_each_cpu_and'
|
||||||
|
- 'for_each_cpu_not'
|
||||||
|
- 'for_each_cpu_wrap'
|
||||||
|
- 'for_each_dev_addr'
|
||||||
|
- 'for_each_dev_scope'
|
||||||
|
- 'for_each_displayid_db'
|
||||||
|
- 'for_each_dma_cap_mask'
|
||||||
|
- 'for_each_dpcm_be'
|
||||||
|
- 'for_each_dpcm_be_rollback'
|
||||||
|
- 'for_each_dpcm_be_safe'
|
||||||
|
- 'for_each_dpcm_fe'
|
||||||
|
- 'for_each_drhd_unit'
|
||||||
|
- 'for_each_dss_dev'
|
||||||
|
- 'for_each_efi_handle'
|
||||||
|
- 'for_each_efi_memory_desc'
|
||||||
|
- 'for_each_efi_memory_desc_in_map'
|
||||||
|
- 'for_each_element'
|
||||||
|
- 'for_each_element_extid'
|
||||||
|
- 'for_each_element_id'
|
||||||
|
- 'for_each_endpoint_of_node'
|
||||||
|
- 'for_each_evictable_lru'
|
||||||
|
- 'for_each_fib6_node_rt_rcu'
|
||||||
|
- 'for_each_fib6_walker_rt'
|
||||||
|
- 'for_each_free_mem_pfn_range_in_zone'
|
||||||
|
- 'for_each_free_mem_pfn_range_in_zone_from'
|
||||||
|
- 'for_each_free_mem_range'
|
||||||
|
- 'for_each_free_mem_range_reverse'
|
||||||
|
- 'for_each_func_rsrc'
|
||||||
|
- 'for_each_hstate'
|
||||||
|
- 'for_each_if'
|
||||||
|
- 'for_each_iommu'
|
||||||
|
- 'for_each_ip_tunnel_rcu'
|
||||||
|
- 'for_each_irq_nr'
|
||||||
|
- 'for_each_link_codecs'
|
||||||
|
- 'for_each_link_platforms'
|
||||||
|
- 'for_each_lru'
|
||||||
|
- 'for_each_matching_node'
|
||||||
|
- 'for_each_matching_node_and_match'
|
||||||
|
- 'for_each_member'
|
||||||
|
- 'for_each_memblock'
|
||||||
|
- 'for_each_memblock_type'
|
||||||
|
- 'for_each_memcg_cache_index'
|
||||||
|
- 'for_each_mem_pfn_range'
|
||||||
|
- 'for_each_mem_range'
|
||||||
|
- 'for_each_mem_range_rev'
|
||||||
|
- 'for_each_migratetype_order'
|
||||||
|
- 'for_each_msi_entry'
|
||||||
|
- 'for_each_msi_entry_safe'
|
||||||
|
- 'for_each_net'
|
||||||
|
- 'for_each_net_continue_reverse'
|
||||||
|
- 'for_each_netdev'
|
||||||
|
- 'for_each_netdev_continue'
|
||||||
|
- 'for_each_netdev_continue_rcu'
|
||||||
|
- 'for_each_netdev_continue_reverse'
|
||||||
|
- 'for_each_netdev_feature'
|
||||||
|
- 'for_each_netdev_in_bond_rcu'
|
||||||
|
- 'for_each_netdev_rcu'
|
||||||
|
- 'for_each_netdev_reverse'
|
||||||
|
- 'for_each_netdev_safe'
|
||||||
|
- 'for_each_net_rcu'
|
||||||
|
- 'for_each_new_connector_in_state'
|
||||||
|
- 'for_each_new_crtc_in_state'
|
||||||
|
- 'for_each_new_mst_mgr_in_state'
|
||||||
|
- 'for_each_new_plane_in_state'
|
||||||
|
- 'for_each_new_private_obj_in_state'
|
||||||
|
- 'for_each_node'
|
||||||
|
- 'for_each_node_by_name'
|
||||||
|
- 'for_each_node_by_type'
|
||||||
|
- 'for_each_node_mask'
|
||||||
|
- 'for_each_node_state'
|
||||||
|
- 'for_each_node_with_cpus'
|
||||||
|
- 'for_each_node_with_property'
|
||||||
|
- 'for_each_of_allnodes'
|
||||||
|
- 'for_each_of_allnodes_from'
|
||||||
|
- 'for_each_of_cpu_node'
|
||||||
|
- 'for_each_of_pci_range'
|
||||||
|
- 'for_each_old_connector_in_state'
|
||||||
|
- 'for_each_old_crtc_in_state'
|
||||||
|
- 'for_each_old_mst_mgr_in_state'
|
||||||
|
- 'for_each_oldnew_connector_in_state'
|
||||||
|
- 'for_each_oldnew_crtc_in_state'
|
||||||
|
- 'for_each_oldnew_mst_mgr_in_state'
|
||||||
|
- 'for_each_oldnew_plane_in_state'
|
||||||
|
- 'for_each_oldnew_plane_in_state_reverse'
|
||||||
|
- 'for_each_oldnew_private_obj_in_state'
|
||||||
|
- 'for_each_old_plane_in_state'
|
||||||
|
- 'for_each_old_private_obj_in_state'
|
||||||
|
- 'for_each_online_cpu'
|
||||||
|
- 'for_each_online_node'
|
||||||
|
- 'for_each_online_pgdat'
|
||||||
|
- 'for_each_pci_bridge'
|
||||||
|
- 'for_each_pci_dev'
|
||||||
|
- 'for_each_pci_msi_entry'
|
||||||
|
- 'for_each_populated_zone'
|
||||||
|
- 'for_each_possible_cpu'
|
||||||
|
- 'for_each_present_cpu'
|
||||||
|
- 'for_each_prime_number'
|
||||||
|
- 'for_each_prime_number_from'
|
||||||
|
- 'for_each_process'
|
||||||
|
- 'for_each_process_thread'
|
||||||
|
- 'for_each_property_of_node'
|
||||||
|
- 'for_each_registered_fb'
|
||||||
|
- 'for_each_reserved_mem_region'
|
||||||
|
- 'for_each_rtd_codec_dai'
|
||||||
|
- 'for_each_rtd_codec_dai_rollback'
|
||||||
|
- 'for_each_rtd_components'
|
||||||
|
- 'for_each_set_bit'
|
||||||
|
- 'for_each_set_bit_from'
|
||||||
|
- 'for_each_set_clump8'
|
||||||
|
- 'for_each_sg'
|
||||||
|
- 'for_each_sg_dma_page'
|
||||||
|
- 'for_each_sg_page'
|
||||||
|
- 'for_each_sibling_event'
|
||||||
|
- 'for_each_subelement'
|
||||||
|
- 'for_each_subelement_extid'
|
||||||
|
- 'for_each_subelement_id'
|
||||||
|
- '__for_each_thread'
|
||||||
|
- 'for_each_thread'
|
||||||
|
- 'for_each_wakeup_source'
|
||||||
|
- 'for_each_zone'
|
||||||
|
- 'for_each_zone_zonelist'
|
||||||
|
- 'for_each_zone_zonelist_nodemask'
|
||||||
|
- 'fwnode_for_each_available_child_node'
|
||||||
|
- 'fwnode_for_each_child_node'
|
||||||
|
- 'fwnode_graph_for_each_endpoint'
|
||||||
|
- 'gadget_for_each_ep'
|
||||||
|
- 'genradix_for_each'
|
||||||
|
- 'genradix_for_each_from'
|
||||||
|
- 'hash_for_each'
|
||||||
|
- 'hash_for_each_possible'
|
||||||
|
- 'hash_for_each_possible_rcu'
|
||||||
|
- 'hash_for_each_possible_rcu_notrace'
|
||||||
|
- 'hash_for_each_possible_safe'
|
||||||
|
- 'hash_for_each_rcu'
|
||||||
|
- 'hash_for_each_safe'
|
||||||
|
- 'hctx_for_each_ctx'
|
||||||
|
- 'hlist_bl_for_each_entry'
|
||||||
|
- 'hlist_bl_for_each_entry_rcu'
|
||||||
|
- 'hlist_bl_for_each_entry_safe'
|
||||||
|
- 'hlist_for_each'
|
||||||
|
- 'hlist_for_each_entry'
|
||||||
|
- 'hlist_for_each_entry_continue'
|
||||||
|
- 'hlist_for_each_entry_continue_rcu'
|
||||||
|
- 'hlist_for_each_entry_continue_rcu_bh'
|
||||||
|
- 'hlist_for_each_entry_from'
|
||||||
|
- 'hlist_for_each_entry_from_rcu'
|
||||||
|
- 'hlist_for_each_entry_rcu'
|
||||||
|
- 'hlist_for_each_entry_rcu_bh'
|
||||||
|
- 'hlist_for_each_entry_rcu_notrace'
|
||||||
|
- 'hlist_for_each_entry_safe'
|
||||||
|
- '__hlist_for_each_rcu'
|
||||||
|
- 'hlist_for_each_safe'
|
||||||
|
- 'hlist_nulls_for_each_entry'
|
||||||
|
- 'hlist_nulls_for_each_entry_from'
|
||||||
|
- 'hlist_nulls_for_each_entry_rcu'
|
||||||
|
- 'hlist_nulls_for_each_entry_safe'
|
||||||
|
- 'i3c_bus_for_each_i2cdev'
|
||||||
|
- 'i3c_bus_for_each_i3cdev'
|
||||||
|
- 'ide_host_for_each_port'
|
||||||
|
- 'ide_port_for_each_dev'
|
||||||
|
- 'ide_port_for_each_present_dev'
|
||||||
|
- 'idr_for_each_entry'
|
||||||
|
- 'idr_for_each_entry_continue'
|
||||||
|
- 'idr_for_each_entry_continue_ul'
|
||||||
|
- 'idr_for_each_entry_ul'
|
||||||
|
- 'in_dev_for_each_ifa_rcu'
|
||||||
|
- 'in_dev_for_each_ifa_rtnl'
|
||||||
|
- 'inet_bind_bucket_for_each'
|
||||||
|
- 'inet_lhash2_for_each_icsk_rcu'
|
||||||
|
- 'key_for_each'
|
||||||
|
- 'key_for_each_safe'
|
||||||
|
- 'klp_for_each_func'
|
||||||
|
- 'klp_for_each_func_safe'
|
||||||
|
- 'klp_for_each_func_static'
|
||||||
|
- 'klp_for_each_object'
|
||||||
|
- 'klp_for_each_object_safe'
|
||||||
|
- 'klp_for_each_object_static'
|
||||||
|
- 'kvm_for_each_memslot'
|
||||||
|
- 'kvm_for_each_vcpu'
|
||||||
|
- 'list_for_each'
|
||||||
|
- 'list_for_each_codec'
|
||||||
|
- 'list_for_each_codec_safe'
|
||||||
|
- 'list_for_each_continue'
|
||||||
|
- 'list_for_each_entry'
|
||||||
|
- 'list_for_each_entry_continue'
|
||||||
|
- 'list_for_each_entry_continue_rcu'
|
||||||
|
- 'list_for_each_entry_continue_reverse'
|
||||||
|
- 'list_for_each_entry_from'
|
||||||
|
- 'list_for_each_entry_from_rcu'
|
||||||
|
- 'list_for_each_entry_from_reverse'
|
||||||
|
- 'list_for_each_entry_lockless'
|
||||||
|
- 'list_for_each_entry_rcu'
|
||||||
|
- 'list_for_each_entry_reverse'
|
||||||
|
- 'list_for_each_entry_safe'
|
||||||
|
- 'list_for_each_entry_safe_continue'
|
||||||
|
- 'list_for_each_entry_safe_from'
|
||||||
|
- 'list_for_each_entry_safe_reverse'
|
||||||
|
- 'list_for_each_prev'
|
||||||
|
- 'list_for_each_prev_safe'
|
||||||
|
- 'list_for_each_safe'
|
||||||
|
- 'llist_for_each'
|
||||||
|
- 'llist_for_each_entry'
|
||||||
|
- 'llist_for_each_entry_safe'
|
||||||
|
- 'llist_for_each_safe'
|
||||||
|
- 'mci_for_each_dimm'
|
||||||
|
- 'media_device_for_each_entity'
|
||||||
|
- 'media_device_for_each_intf'
|
||||||
|
- 'media_device_for_each_link'
|
||||||
|
- 'media_device_for_each_pad'
|
||||||
|
- 'nanddev_io_for_each_page'
|
||||||
|
- 'netdev_for_each_lower_dev'
|
||||||
|
- 'netdev_for_each_lower_private'
|
||||||
|
- 'netdev_for_each_lower_private_rcu'
|
||||||
|
- 'netdev_for_each_mc_addr'
|
||||||
|
- 'netdev_for_each_uc_addr'
|
||||||
|
- 'netdev_for_each_upper_dev_rcu'
|
||||||
|
- 'netdev_hw_addr_list_for_each'
|
||||||
|
- 'nft_rule_for_each_expr'
|
||||||
|
- 'nla_for_each_attr'
|
||||||
|
- 'nla_for_each_nested'
|
||||||
|
- 'nlmsg_for_each_attr'
|
||||||
|
- 'nlmsg_for_each_msg'
|
||||||
|
- 'nr_neigh_for_each'
|
||||||
|
- 'nr_neigh_for_each_safe'
|
||||||
|
- 'nr_node_for_each'
|
||||||
|
- 'nr_node_for_each_safe'
|
||||||
|
- 'of_for_each_phandle'
|
||||||
|
- 'of_property_for_each_string'
|
||||||
|
- 'of_property_for_each_u32'
|
||||||
|
- 'pci_bus_for_each_resource'
|
||||||
|
- 'ping_portaddr_for_each_entry'
|
||||||
|
- 'plist_for_each'
|
||||||
|
- 'plist_for_each_continue'
|
||||||
|
- 'plist_for_each_entry'
|
||||||
|
- 'plist_for_each_entry_continue'
|
||||||
|
- 'plist_for_each_entry_safe'
|
||||||
|
- 'plist_for_each_safe'
|
||||||
|
- 'pnp_for_each_card'
|
||||||
|
- 'pnp_for_each_dev'
|
||||||
|
- 'protocol_for_each_card'
|
||||||
|
- 'protocol_for_each_dev'
|
||||||
|
- 'queue_for_each_hw_ctx'
|
||||||
|
- 'radix_tree_for_each_slot'
|
||||||
|
- 'radix_tree_for_each_tagged'
|
||||||
|
- 'rbtree_postorder_for_each_entry_safe'
|
||||||
|
- 'rdma_for_each_block'
|
||||||
|
- 'rdma_for_each_port'
|
||||||
|
- 'resource_list_for_each_entry'
|
||||||
|
- 'resource_list_for_each_entry_safe'
|
||||||
|
- 'rhl_for_each_entry_rcu'
|
||||||
|
- 'rhl_for_each_rcu'
|
||||||
|
- 'rht_for_each'
|
||||||
|
- 'rht_for_each_entry'
|
||||||
|
- 'rht_for_each_entry_from'
|
||||||
|
- 'rht_for_each_entry_rcu'
|
||||||
|
- 'rht_for_each_entry_rcu_from'
|
||||||
|
- 'rht_for_each_entry_safe'
|
||||||
|
- 'rht_for_each_from'
|
||||||
|
- 'rht_for_each_rcu'
|
||||||
|
- 'rht_for_each_rcu_from'
|
||||||
|
- '__rq_for_each_bio'
|
||||||
|
- 'rq_for_each_bvec'
|
||||||
|
- 'rq_for_each_segment'
|
||||||
|
- 'scsi_for_each_prot_sg'
|
||||||
|
- 'scsi_for_each_sg'
|
||||||
|
- 'sctp_for_each_hentry'
|
||||||
|
- 'sctp_skb_for_each'
|
||||||
|
- 'shdma_for_each_chan'
|
||||||
|
- '__shost_for_each_device'
|
||||||
|
- 'shost_for_each_device'
|
||||||
|
- 'sk_for_each'
|
||||||
|
- 'sk_for_each_bound'
|
||||||
|
- 'sk_for_each_entry_offset_rcu'
|
||||||
|
- 'sk_for_each_from'
|
||||||
|
- 'sk_for_each_rcu'
|
||||||
|
- 'sk_for_each_safe'
|
||||||
|
- 'sk_nulls_for_each'
|
||||||
|
- 'sk_nulls_for_each_from'
|
||||||
|
- 'sk_nulls_for_each_rcu'
|
||||||
|
- 'snd_array_for_each'
|
||||||
|
- 'snd_pcm_group_for_each_entry'
|
||||||
|
- 'snd_soc_dapm_widget_for_each_path'
|
||||||
|
- 'snd_soc_dapm_widget_for_each_path_safe'
|
||||||
|
- 'snd_soc_dapm_widget_for_each_sink_path'
|
||||||
|
- 'snd_soc_dapm_widget_for_each_source_path'
|
||||||
|
- 'tb_property_for_each'
|
||||||
|
- 'tcf_exts_for_each_action'
|
||||||
|
- 'udp_portaddr_for_each_entry'
|
||||||
|
- 'udp_portaddr_for_each_entry_rcu'
|
||||||
|
- 'usb_hub_for_each_child'
|
||||||
|
- 'v4l2_device_for_each_subdev'
|
||||||
|
- 'v4l2_m2m_for_each_dst_buf'
|
||||||
|
- 'v4l2_m2m_for_each_dst_buf_safe'
|
||||||
|
- 'v4l2_m2m_for_each_src_buf'
|
||||||
|
- 'v4l2_m2m_for_each_src_buf_safe'
|
||||||
|
- 'virtio_device_for_each_vq'
|
||||||
|
- 'xa_for_each'
|
||||||
|
- 'xa_for_each_marked'
|
||||||
|
- 'xa_for_each_range'
|
||||||
|
- 'xa_for_each_start'
|
||||||
|
- 'xas_for_each'
|
||||||
|
- 'xas_for_each_conflict'
|
||||||
|
- 'xas_for_each_marked'
|
||||||
|
- 'xbc_array_for_each_value'
|
||||||
|
- 'xbc_for_each_key_value'
|
||||||
|
- 'xbc_node_for_each_array_value'
|
||||||
|
- 'xbc_node_for_each_child'
|
||||||
|
- 'xbc_node_for_each_key_value'
|
||||||
|
- 'zorro_for_each_dev'
|
||||||
|
|
||||||
|
#IncludeBlocks: Preserve # Unknown to clang-format-5.0
|
||||||
|
IncludeCategories:
|
||||||
|
- Regex: '.*'
|
||||||
|
Priority: 1
|
||||||
|
IncludeIsMainRegex: '(Test)?$'
|
||||||
|
IndentCaseLabels: false
|
||||||
|
#IndentPPDirectives: None # Unknown to clang-format-5.0
|
||||||
|
IndentWidth: 8
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
JavaScriptQuotes: Leave
|
||||||
|
JavaScriptWrapImports: true
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: Inner
|
||||||
|
#ObjCBinPackProtocolList: Auto # Unknown to clang-format-5.0
|
||||||
|
ObjCBlockIndentWidth: 8
|
||||||
|
ObjCSpaceAfterProperty: true
|
||||||
|
ObjCSpaceBeforeProtocolList: true
|
||||||
|
|
||||||
|
# Taken from git's rules
|
||||||
|
#PenaltyBreakAssignment: 10 # Unknown to clang-format-4.0
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 30
|
||||||
|
PenaltyBreakComment: 10
|
||||||
|
PenaltyBreakFirstLessLess: 0
|
||||||
|
PenaltyBreakString: 10
|
||||||
|
PenaltyExcessCharacter: 100
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 60
|
||||||
|
|
||||||
|
PointerAlignment: Right
|
||||||
|
ReflowComments: false
|
||||||
|
SortIncludes: false
|
||||||
|
#SortUsingDeclarations: false # Unknown to clang-format-4.0
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterTemplateKeyword: true
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
#SpaceBeforeCtorInitializerColon: true # Unknown to clang-format-5.0
|
||||||
|
#SpaceBeforeInheritanceColon: true # Unknown to clang-format-5.0
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
#SpaceBeforeRangeBasedForLoopColon: true # Unknown to clang-format-5.0
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Cpp11
|
||||||
|
TabWidth: 8
|
||||||
|
UseTab: Always
|
||||||
|
...
|
||||||
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
open_collective: osmocom
|
||||||
68
.gitignore
vendored
68
.gitignore
vendored
@@ -2,26 +2,43 @@
|
|||||||
*.o
|
*.o
|
||||||
*.lo
|
*.lo
|
||||||
*.la
|
*.la
|
||||||
Transceiver52M/osmo-trx
|
Transceiver52M/osmo-trx-uhd
|
||||||
|
Transceiver52M/osmo-trx-usrp1
|
||||||
|
Transceiver52M/osmo-trx-lms
|
||||||
|
Transceiver52M/osmo-trx-ipc
|
||||||
|
Transceiver52M/osmo-trx-blade
|
||||||
|
Transceiver52M/osmo-trx-ipc2
|
||||||
|
Transceiver52M/osmo-trx-syncthing-blade
|
||||||
|
Transceiver52M/osmo-trx-syncthing-uhd
|
||||||
|
Transceiver52M/osmo-trx-syncthing-ipc
|
||||||
|
Transceiver52M/osmo-trx-ms-blade
|
||||||
|
Transceiver52M/osmo-trx-ms-uhd
|
||||||
|
Transceiver52M/osmo-trx-ms-ipc
|
||||||
|
Transceiver52M/device/ipc/uhddev_ipc.cpp
|
||||||
|
|
||||||
|
.clang-format
|
||||||
|
|
||||||
# tests
|
# tests
|
||||||
CommonLibs/BitVectorTest
|
tests/CommonLibs/BitVectorTest
|
||||||
CommonLibs/ConfigurationTest
|
tests/CommonLibs/F16Test
|
||||||
CommonLibs/F16Test
|
tests/CommonLibs/InterthreadTest
|
||||||
CommonLibs/InterthreadTest
|
tests/CommonLibs/LogTest
|
||||||
CommonLibs/LogTest
|
tests/CommonLibs/RegexpTest
|
||||||
CommonLibs/RegexpTest
|
tests/CommonLibs/SocketsTest
|
||||||
CommonLibs/SocketsTest
|
tests/CommonLibs/TimevalTest
|
||||||
CommonLibs/TimevalTest
|
tests/CommonLibs/URLEncodeTest
|
||||||
CommonLibs/URLEncodeTest
|
tests/CommonLibs/VectorTest
|
||||||
CommonLibs/VectorTest
|
tests/CommonLibs/PRBSTest
|
||||||
CommonLibs/PRBSTest
|
tests/Transceiver52M/convolve_test
|
||||||
|
tests/Transceiver52M/LMSDeviceTest
|
||||||
|
Transceiver52M/device/ipc/ipc-driver-test
|
||||||
|
|
||||||
# automake/autoconf
|
# automake/autoconf
|
||||||
*.in
|
*.in
|
||||||
.deps
|
.deps
|
||||||
.libs
|
.libs
|
||||||
.dirstamp
|
.dirstamp
|
||||||
|
.version
|
||||||
*~
|
*~
|
||||||
Makefile
|
Makefile
|
||||||
config.log
|
config.log
|
||||||
@@ -41,6 +58,33 @@ ltmain.sh
|
|||||||
missing
|
missing
|
||||||
stamp-h1
|
stamp-h1
|
||||||
INSTALL
|
INSTALL
|
||||||
|
tests/package.m4
|
||||||
|
tests/testsuite
|
||||||
|
tests/atconfig
|
||||||
|
tests/testsuite.dir
|
||||||
|
tests/testsuite.log
|
||||||
|
|
||||||
# vim
|
# vim
|
||||||
*.sw?
|
*.sw?
|
||||||
|
|
||||||
|
# manuals
|
||||||
|
doc/manuals/*.html
|
||||||
|
doc/manuals/*.svg
|
||||||
|
doc/manuals/*.pdf
|
||||||
|
doc/manuals/*__*.png
|
||||||
|
doc/manuals/*.check
|
||||||
|
doc/manuals/generated/
|
||||||
|
doc/manuals/vty/osmotrx-*-vty-reference.xml
|
||||||
|
doc/manuals/vty/osmotrx-*-vty-reference.xml.inc.gen
|
||||||
|
doc/manuals/vty/osmotrx-*-vty-reference.xml.inc.merged
|
||||||
|
doc/manuals/common
|
||||||
|
doc/manuals/build
|
||||||
|
|
||||||
|
contrib/osmo-trx.spec
|
||||||
|
!contrib/osmo-trx.spec.in
|
||||||
|
|
||||||
|
utils/osmo-prbs-tool
|
||||||
|
utils/va-test/osmo-burst-gen
|
||||||
|
/.qtc_clangd/*
|
||||||
|
/.cache/*
|
||||||
|
/.vscode/*
|
||||||
|
|||||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "osmocom-bb"]
|
||||||
|
path = osmocom-bb
|
||||||
|
url = https://gitea.osmocom.org/phone-side/osmocom-bb.git
|
||||||
192
AUTHORS
192
AUTHORS
@@ -1,192 +0,0 @@
|
|||||||
#
|
|
||||||
# Copyright 2008, 2009 Free Software Foundation, Inc.
|
|
||||||
#
|
|
||||||
# This file is part of GNU Radio
|
|
||||||
#
|
|
||||||
# GNU Radio 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, or (at your option)
|
|
||||||
# any later version.
|
|
||||||
#
|
|
||||||
# GNU Radio 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.
|
|
||||||
#
|
|
||||||
|
|
||||||
David A. Burgess, dburgess@kestrelsp.com:
|
|
||||||
CLI/CLI.cpp
|
|
||||||
CLI/CLI.h
|
|
||||||
CommonLibs/Assert.h
|
|
||||||
CommonLibs/BitVector.cpp
|
|
||||||
CommonLibs/BitVectorTest.cpp
|
|
||||||
CommonLibs/Configuration.cpp
|
|
||||||
CommonLibs/Configuration.h
|
|
||||||
CommonLibs/ConfigurationTest.cpp
|
|
||||||
CommonLibs/Interthread.h
|
|
||||||
CommonLibs/InterthreadTest.cpp
|
|
||||||
CommonLibs/LinkedLists.cpp
|
|
||||||
CommonLibs/LinkedLists.h
|
|
||||||
CommonLibs/Regexp.h
|
|
||||||
CommonLibs/RegexpTest.cpp
|
|
||||||
CommonLibs/Sockets.cpp
|
|
||||||
CommonLibs/Sockets.h
|
|
||||||
CommonLibs/SocketsTest.cpp
|
|
||||||
CommonLibs/Threads.cpp
|
|
||||||
CommonLibs/Threads.h
|
|
||||||
CommonLibs/Timeval.cpp
|
|
||||||
CommonLibs/Timeval.h
|
|
||||||
CommonLibs/TimevalTest.cpp
|
|
||||||
CommonLibs/Vector.h
|
|
||||||
CommonLibs/VectorTest.cpp
|
|
||||||
Control/CallControl.cpp
|
|
||||||
Control/ControlCommon.cpp
|
|
||||||
Control/ControlCommon.h
|
|
||||||
Control/FACCHDispatch.cpp
|
|
||||||
Control/MobilityManagement.cpp
|
|
||||||
Control/PagerTest.cpp
|
|
||||||
Control/RadioResource.cpp
|
|
||||||
Control/SDCCHDispatch.cpp
|
|
||||||
GSM/GSM610Tables.cpp
|
|
||||||
GSM/GSM610Tables.h
|
|
||||||
GSM/GSMCommon.cpp
|
|
||||||
GSM/GSMCommon.h
|
|
||||||
GSM/GSMConfig.h
|
|
||||||
GSM/GSML1FEC.cpp
|
|
||||||
GSM/GSML1FEC.h
|
|
||||||
GSM/GSML2LAPDm.cpp
|
|
||||||
GSM/GSML2LAPDm.h
|
|
||||||
GSM/GSML3CCElements.cpp
|
|
||||||
GSM/GSML3CCElements.h
|
|
||||||
GSM/GSML3CCMessages.cpp
|
|
||||||
GSM/GSML3CCMessages.h
|
|
||||||
GSM/GSML3CommonElements.cpp
|
|
||||||
GSM/GSML3CommonElements.h
|
|
||||||
GSM/GSML3MMElements.cpp
|
|
||||||
GSM/GSML3MMElements.h
|
|
||||||
GSM/GSML3MMMessages.cpp
|
|
||||||
GSM/GSML3MMMessages.h
|
|
||||||
GSM/GSML3Message.cpp
|
|
||||||
GSM/GSML3Message.h
|
|
||||||
GSM/GSML3RRElements.cpp
|
|
||||||
GSM/GSML3RRElements.h
|
|
||||||
GSM/GSML3RRMessages.cpp
|
|
||||||
GSM/GSML3RRMessages.h
|
|
||||||
GSM/GSMLogicalChannel.h
|
|
||||||
GSM/GSMTDMA.cpp
|
|
||||||
GSM/GSMTDMA.h
|
|
||||||
GSM/GSMTransfer.cpp
|
|
||||||
GSM/GSMTransfer.h
|
|
||||||
LICENSEBLOCK
|
|
||||||
SIP/SIPEngine.h
|
|
||||||
SIP/SIPInterface.h
|
|
||||||
SMS/SMSMessages.cpp
|
|
||||||
SMS/SMSMessages.h
|
|
||||||
SMS/SMSTransfer.cpp
|
|
||||||
SMS/SMSTransfer.h
|
|
||||||
TRXManager/TRXManager.cpp
|
|
||||||
Transceiver/Complex.h
|
|
||||||
apps/OpenBTS900.cpp
|
|
||||||
apps/OpenBTS850.cpp
|
|
||||||
apps/OpenBTS25c3.cpp
|
|
||||||
tests/AGCHTest.cpp
|
|
||||||
tests/BeaconTest.cpp
|
|
||||||
tests/CallTest.cpp
|
|
||||||
tests/CallTest2.cpp
|
|
||||||
tests/LAPDmTest.cpp
|
|
||||||
tests/LoopbackTest.cpp
|
|
||||||
tests/RegistrationTest.cpp
|
|
||||||
tests/TRXSimulator.cpp
|
|
||||||
|
|
||||||
Harvind S. Samra, hssamra@kestrelsp.com:
|
|
||||||
Control/PagerTest.cpp
|
|
||||||
Control/RadioResource.cpp
|
|
||||||
GSM/GSMConfig.h
|
|
||||||
GSM/GSMTransfer.h
|
|
||||||
LICENSEBLOCK
|
|
||||||
Transceiver/ComplexTest.cpp
|
|
||||||
Transceiver/Transceiver.cpp
|
|
||||||
Transceiver/Transceiver.h
|
|
||||||
Transceiver/USRPDevice.cpp
|
|
||||||
Transceiver/USRPDevice.h
|
|
||||||
Transceiver/USRPping.cpp
|
|
||||||
Transceiver/radioInterface.cpp
|
|
||||||
Transceiver/radioInterface.h
|
|
||||||
Transceiver/rcvLPF_651.h
|
|
||||||
Transceiver/runTransceiver.cpp
|
|
||||||
Transceiver/sendLPF_961.h
|
|
||||||
Transceiver/sigProcLib.cpp
|
|
||||||
Transceiver/sigProcLib.h
|
|
||||||
Transceiver/sigProcLibTest.cpp
|
|
||||||
Transceiver/sweepGenerator.cpp
|
|
||||||
Transceiver/testRadio.cpp
|
|
||||||
|
|
||||||
Raffi Sevlian, raffisev@gmail.com:
|
|
||||||
Control/CallControl.cpp
|
|
||||||
Control/ControlCommon.cpp
|
|
||||||
Control/ControlCommon.h
|
|
||||||
Control/FACCHDispatch.cpp
|
|
||||||
Control/MobilityManagement.cpp
|
|
||||||
Control/PagerTest.cpp
|
|
||||||
Control/RadioResource.cpp
|
|
||||||
GSM/GSMCommon.h
|
|
||||||
GSM/GSMConfig.h
|
|
||||||
GSM/GSML1FEC.h
|
|
||||||
GSM/GSML3CCElements.cpp
|
|
||||||
GSM/GSML3CCElements.h
|
|
||||||
GSM/GSML3CCMessages.cpp
|
|
||||||
GSM/GSML3CCMessages.h
|
|
||||||
GSM/GSML3CommonElements.cpp
|
|
||||||
GSM/GSML3CommonElements.h
|
|
||||||
GSM/GSML3MMElements.cpp
|
|
||||||
GSM/GSML3MMElements.h
|
|
||||||
GSM/GSML3MMMessages.cpp
|
|
||||||
GSM/GSML3MMMessages.h
|
|
||||||
GSM/GSML3Message.cpp
|
|
||||||
GSM/GSML3Message.h
|
|
||||||
GSM/GSML3RRElements.cpp
|
|
||||||
GSM/GSML3RRElements.h
|
|
||||||
GSM/GSML3RRMessages.cpp
|
|
||||||
GSM/GSML3RRMessages.h
|
|
||||||
GSM/GSMLogicalChannel.h
|
|
||||||
GSM/GSMSAPMux.cpp
|
|
||||||
GSM/GSMSAPMux.h
|
|
||||||
GSM/GSMTransfer.h
|
|
||||||
LICENSEBLOCK
|
|
||||||
SIP/SIPEngine.cpp
|
|
||||||
SIP/SIPInterface.cpp
|
|
||||||
SIP/SIPInterface.h
|
|
||||||
SIP/SIPMessage.cpp
|
|
||||||
SIP/SIPMessage.h
|
|
||||||
SIP/SIPUtility.cpp
|
|
||||||
SIP/SIPUtility.h
|
|
||||||
SMS/CMMessage.cpp
|
|
||||||
SMS/CMMessage.h
|
|
||||||
SMS/CMProcessor.cpp
|
|
||||||
SMS/CMProcessor.h
|
|
||||||
SMS/CMTest.cpp
|
|
||||||
SMS/RLMessage.cpp
|
|
||||||
SMS/RLMessage.h
|
|
||||||
SMS/RLProcessor.cpp
|
|
||||||
SMS/RLProcessor.h
|
|
||||||
SMS/SMSMessages.cpp
|
|
||||||
SMS/SMSMessages.h
|
|
||||||
SMS/SMSProcessors.cpp
|
|
||||||
SMS/SMSProcessors.h
|
|
||||||
SMS/SMSTransfer.cpp
|
|
||||||
SMS/SMSTransfer.h
|
|
||||||
SMS/TLMessage.cpp
|
|
||||||
SMS/TLMessage.h
|
|
||||||
SMS/TLProcessor.cpp
|
|
||||||
SMS/TLProcessor.h
|
|
||||||
TRXManager/TRXManager.h
|
|
||||||
|
|
||||||
Alon Levy, alonlevy1@gmail.com
|
|
||||||
RRLPMessages.cpp
|
|
||||||
RRLPMessages.h
|
|
||||||
RRLPTest.cpp
|
|
||||||
|
|
||||||
30
COPYING
30
COPYING
@@ -666,23 +666,23 @@ For more information on this, and how to apply and follow the GNU AGPL, see
|
|||||||
=========================================================================
|
=========================================================================
|
||||||
|
|
||||||
This marks the end of the AGPLv3 text. The following text is appended to the
|
This marks the end of the AGPLv3 text. The following text is appended to the
|
||||||
same file for convience but constituting a distinct document, not part of the
|
same file for convenience but constituting a distinct document, not part of the
|
||||||
actual AGPL text and not part of an attempt to create a deriviative work based
|
actual AGPL text and not part of an attempt to create a deriviative work based
|
||||||
on the AGPLv3 text.
|
on the AGPLv3 text.
|
||||||
|
|
||||||
=========================================================================
|
=========================================================================
|
||||||
|
|
||||||
|
|
||||||
ADDITIONAL TERMS TO THE AGPLv3 LICENSE FOR OPENBTS
|
ADDITIONAL TERMS TO THE AGPLv3 LICENSE FOR OsmoTRX
|
||||||
|
|
||||||
|
|
||||||
Permissive Terms Supplementing the License
|
Permissive Terms Supplementing the License
|
||||||
|
|
||||||
1. Remote Interaction Through IP Networks.
|
1. Remote Interaction Through IP Networks.
|
||||||
|
|
||||||
OpenBTS includes an implementation of the GSM network cellular air interface,
|
OsmoTRX is an implementation of the GSM network cellular air interface,
|
||||||
as well as other interfaces to IP networks. The interaction of cellular
|
as well as other interfaces to IP networks. The interaction of cellular
|
||||||
handsets with the OpenBTS software is considered "remote network interaction"
|
handsets with the OsmoTRX software is considered "remote network interaction"
|
||||||
for the purposes of the Affero General Public License and cellular users are
|
for the purposes of the Affero General Public License and cellular users are
|
||||||
subject to the source code access requirements of Section 13 of AGPLv3 ("Remote
|
subject to the source code access requirements of Section 13 of AGPLv3 ("Remote
|
||||||
Network Interaction; Use with the GNU General Public License").
|
Network Interaction; Use with the GNU General Public License").
|
||||||
@@ -694,17 +694,6 @@ interfaces other than the GSM air interface from the requirements of Section 13
|
|||||||
is an additional permission granted to you.
|
is an additional permission granted to you.
|
||||||
|
|
||||||
|
|
||||||
Non-Permissive Terms Supplementing The License
|
|
||||||
|
|
||||||
1. Trademarks.
|
|
||||||
|
|
||||||
"OpenBTS" is a trademark of Range Networks, Inc., registered with
|
|
||||||
the US Patent and Trademark Office. Your use of OpenBTS software under a GPL
|
|
||||||
license does not include the right to use the OpenBTS trademark in commerce.
|
|
||||||
This additional non-permissive term is consistent with Section 7 of the AGPLv3
|
|
||||||
license.
|
|
||||||
|
|
||||||
|
|
||||||
END OF ADDITIONAL TERMS
|
END OF ADDITIONAL TERMS
|
||||||
|
|
||||||
|
|
||||||
@@ -712,13 +701,8 @@ END OF ADDITIONAL TERMS
|
|||||||
How to comply with Section 13 of the AGPLv3 license.
|
How to comply with Section 13 of the AGPLv3 license.
|
||||||
|
|
||||||
The recommended method for compliance with Section 13 of the AGPLv3 license is
|
The recommended method for compliance with Section 13 of the AGPLv3 license is
|
||||||
to deliver a text message to each handset that attaches to the OpenBTS cellular
|
to deliver a text message to each handset that attaches to the cellular
|
||||||
network. At a minimum, that text message should include the string "OpenBTS
|
network which uses OsmoTRX. At a minimum, that text message should include the string
|
||||||
AGPLv3" and a URL that can be used to access the OpenBTS source code. This
|
"OsmoTRX AGPLv3" and a URL that can be used to access the OsmoBTS source code. This
|
||||||
message need not be delivered to handsets that are denied registration with the
|
message need not be delivered to handsets that are denied registration with the
|
||||||
network, since those handsets have been denied service.
|
network, since those handsets have been denied service.
|
||||||
|
|
||||||
In OpenBTS 2.6, such text messages can be delivered with the "Welcome Message"
|
|
||||||
feature. See the OpenBTS.config.example file for more information on the use of
|
|
||||||
this feature for AGPLv3 compliance.
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008, 2009 Free Software Foundation, Inc.
|
* Copyright 2008, 2009 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
*
|
*
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
* This software is distributed under the terms of the GNU Affero Public License.
|
||||||
* See the COPYING file in the main directory for details.
|
* See the COPYING file in the main directory for details.
|
||||||
@@ -36,7 +37,7 @@ using namespace std;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Apply a Galois polymonial to a binary seqeunce.
|
Apply a Galois polymonial to a binary sequence.
|
||||||
@param val The input sequence.
|
@param val The input sequence.
|
||||||
@param poly The polynomial.
|
@param poly The polynomial.
|
||||||
@param order The order of the polynomial.
|
@param order The order of the polynomial.
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008, 2009 Free Software Foundation, Inc.
|
* Copyright 2008, 2009 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
* This software is distributed under the terms of the GNU Affero Public License.
|
||||||
* See the COPYING file in the main directory for details.
|
* See the COPYING file in the main directory for details.
|
||||||
*
|
*
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,422 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2009, 2010 Free Software Foundation, Inc.
|
|
||||||
* Copyright 2010 Kestrel Signal Processing, Inc.
|
|
||||||
* Copyright 2011, 2012 Range Networks, Inc.
|
|
||||||
*
|
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
|
||||||
* See the COPYING file in the main directory for details.
|
|
||||||
*
|
|
||||||
* This use of this software may be subject to additional restrictions.
|
|
||||||
* See the LEGAL file in the main directory for details.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef CONFIGURATION_H
|
|
||||||
#define CONFIGURATION_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "sqlite3util.h"
|
|
||||||
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <netinet/in.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <regex.h>
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <sstream>
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include <Threads.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
|
|
||||||
/** A class for configuration file errors. */
|
|
||||||
class ConfigurationTableError {};
|
|
||||||
extern char gCmdName[]; // Gotta be global, gotta be char*, gotta love it.
|
|
||||||
|
|
||||||
/** An exception thrown when a given config key isn't found. */
|
|
||||||
class ConfigurationTableKeyNotFound : public ConfigurationTableError {
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
std::string mKey;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
ConfigurationTableKeyNotFound(const std::string& wKey)
|
|
||||||
:mKey(wKey)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
const std::string& key() const { return mKey; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigurationRecord {
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
std::string mValue;
|
|
||||||
long mNumber;
|
|
||||||
bool mDefined;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
ConfigurationRecord(bool wDefined=true):
|
|
||||||
mDefined(wDefined)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
ConfigurationRecord(const std::string& wValue):
|
|
||||||
mValue(wValue),
|
|
||||||
mNumber(strtol(wValue.c_str(),NULL,0)),
|
|
||||||
mDefined(true)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
ConfigurationRecord(const char* wValue):
|
|
||||||
mValue(std::string(wValue)),
|
|
||||||
mNumber(strtol(wValue,NULL,0)),
|
|
||||||
mDefined(true)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
|
|
||||||
const std::string& value() const { return mValue; }
|
|
||||||
long number() const { return mNumber; }
|
|
||||||
bool defined() const { return mDefined; }
|
|
||||||
|
|
||||||
float floatNumber() const;
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/** A string class that uses a hash function for comparison. */
|
|
||||||
class HashString : public std::string {
|
|
||||||
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
uint64_t mHash;
|
|
||||||
|
|
||||||
void computeHash();
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
HashString(const char* src)
|
|
||||||
:std::string(src)
|
|
||||||
{
|
|
||||||
computeHash();
|
|
||||||
}
|
|
||||||
|
|
||||||
HashString(const std::string& src)
|
|
||||||
:std::string(src)
|
|
||||||
{
|
|
||||||
computeHash();
|
|
||||||
}
|
|
||||||
|
|
||||||
HashString()
|
|
||||||
{
|
|
||||||
mHash=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
HashString& operator=(std::string& src)
|
|
||||||
{
|
|
||||||
std::string::operator=(src);
|
|
||||||
computeHash();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
HashString& operator=(const char* src)
|
|
||||||
{
|
|
||||||
std::string::operator=(src);
|
|
||||||
computeHash();
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const HashString& other)
|
|
||||||
{
|
|
||||||
return mHash==other.mHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator<(const HashString& other)
|
|
||||||
{
|
|
||||||
return mHash<other.mHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator>(const HashString& other)
|
|
||||||
{
|
|
||||||
return mHash<other.mHash;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t hash() const { return mHash; }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
typedef std::map<std::string, ConfigurationRecord> ConfigurationRecordMap;
|
|
||||||
typedef std::map<HashString, ConfigurationRecord> ConfigurationMap;
|
|
||||||
class ConfigurationKey;
|
|
||||||
typedef std::map<std::string, ConfigurationKey> ConfigurationKeyMap;
|
|
||||||
|
|
||||||
/**
|
|
||||||
A class for maintaining a configuration key-value table,
|
|
||||||
based on sqlite3 and a local map-based cache.
|
|
||||||
Thread-safe, too.
|
|
||||||
*/
|
|
||||||
class ConfigurationTable {
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
sqlite3* mDB; ///< database connection
|
|
||||||
ConfigurationMap mCache; ///< cache of recently access configuration values
|
|
||||||
mutable Mutex mLock; ///< control for multithreaded access to the cache
|
|
||||||
std::vector<std::string> (*mCrossCheck)(const std::string&); ///< cross check callback pointer
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
ConfigurationKeyMap mSchema;///< definition of configuration default values and validation logic
|
|
||||||
|
|
||||||
ConfigurationTable(const char* filename = ":memory:", const char *wCmdName = 0, ConfigurationKeyMap wSchema = ConfigurationKeyMap());
|
|
||||||
|
|
||||||
/** Generate an up-to-date example sql file for new installs. */
|
|
||||||
std::string getDefaultSQL(const std::string& program, const std::string& version);
|
|
||||||
|
|
||||||
/** Generate an up-to-date TeX snippet. */
|
|
||||||
std::string getTeX(const std::string& program, const std::string& version);
|
|
||||||
|
|
||||||
/** Return true if the key is used in the table. */
|
|
||||||
bool defines(const std::string& key);
|
|
||||||
|
|
||||||
/** Return true if the application's schema knows about this key. */
|
|
||||||
bool keyDefinedInSchema(const std::string& name);
|
|
||||||
|
|
||||||
/** Return true if the provided value validates correctly against the defined schema. */
|
|
||||||
bool isValidValue(const std::string& name, const std::string& val);
|
|
||||||
|
|
||||||
/** Return true if the provided value validates correctly against the defined schema. */
|
|
||||||
bool isValidValue(const std::string& name, const int val) { std::stringstream ss; ss << val; return isValidValue(name, ss.str()); }
|
|
||||||
|
|
||||||
/** Return a map of all similar keys in the defined schema. */
|
|
||||||
ConfigurationKeyMap getSimilarKeys(const std::string& snippet);
|
|
||||||
|
|
||||||
/** Return true if this key is identified as static. */
|
|
||||||
bool isStatic(const std::string& key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get a string parameter from the table.
|
|
||||||
Throw ConfigurationTableKeyNotFound if not found.
|
|
||||||
*/
|
|
||||||
std::string getStr(const std::string& key);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get a boolean from the table.
|
|
||||||
Return false if NULL or 0, true otherwise.
|
|
||||||
*/
|
|
||||||
bool getBool(const std::string& key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get a numeric parameter from the table.
|
|
||||||
Throw ConfigurationTableKeyNotFound if not found.
|
|
||||||
*/
|
|
||||||
long getNum(const std::string& key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get a vector of strings from the table.
|
|
||||||
*/
|
|
||||||
std::vector<std::string> getVectorOfStrings(const std::string& key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get a float from the table.
|
|
||||||
Throw ConfigurationTableKeyNotFound if not found.
|
|
||||||
*/
|
|
||||||
float getFloat(const std::string& key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Get a numeric vector from the table.
|
|
||||||
*/
|
|
||||||
std::vector<unsigned> getVector(const std::string& key);
|
|
||||||
|
|
||||||
/** Get length of a vector */
|
|
||||||
unsigned getVectorLength(const std::string &key)
|
|
||||||
{ return getVector(key).size(); }
|
|
||||||
|
|
||||||
/** Set or change a value in the table. */
|
|
||||||
bool set(const std::string& key, const std::string& value);
|
|
||||||
|
|
||||||
/** Set or change a value in the table. */
|
|
||||||
bool set(const std::string& key, long value);
|
|
||||||
|
|
||||||
/** Create an entry in the table, no value though. */
|
|
||||||
bool set(const std::string& key);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Remove an entry from the table.
|
|
||||||
Will not alter required values.
|
|
||||||
@param key The key of the item to be removed.
|
|
||||||
@return true if anything was actually removed.
|
|
||||||
*/
|
|
||||||
bool remove(const std::string& key);
|
|
||||||
|
|
||||||
/** Search the table, dumping to a stream. */
|
|
||||||
void find(const std::string& pattern, std::ostream&) const;
|
|
||||||
|
|
||||||
/** Return all key/value pairs stored in the ConfigurationTable */
|
|
||||||
ConfigurationRecordMap getAllPairs() const;
|
|
||||||
|
|
||||||
/** Define the callback to purge the cache whenever the database changes. */
|
|
||||||
void setUpdateHook(void(*)(void *,int ,char const *,char const *,sqlite3_int64));
|
|
||||||
|
|
||||||
/** Define the callback for cross checking. */
|
|
||||||
void setCrossCheckHook(std::vector<std::string> (*wCrossCheck)(const std::string&));
|
|
||||||
|
|
||||||
/** Execute the application specific value cross checking logic. */
|
|
||||||
std::vector<std::string> crossCheck(const std::string& key);
|
|
||||||
|
|
||||||
/** purege cache if it exceeds a certain age */
|
|
||||||
void checkCacheAge();
|
|
||||||
|
|
||||||
/** Delete all records from the cache. */
|
|
||||||
void purge();
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
/**
|
|
||||||
Attempt to lookup a record, cache if needed.
|
|
||||||
Throw ConfigurationTableKeyNotFound if not found.
|
|
||||||
Caller should hold mLock because the returned reference points into the cache.
|
|
||||||
*/
|
|
||||||
const ConfigurationRecord& lookup(const std::string& key);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
typedef std::map<HashString, std::string> HashStringMap;
|
|
||||||
|
|
||||||
class SimpleKeyValue {
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
HashStringMap mMap;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/** Take a C string "A=B" and set map["A"]="B". */
|
|
||||||
void addItem(const char*);
|
|
||||||
|
|
||||||
/** Take a C string "A=B C=D E=F ..." and add all of the pairs to the map. */
|
|
||||||
void addItems(const char*s);
|
|
||||||
|
|
||||||
/** Return a reference to the string at map["key"]. */
|
|
||||||
const char* get(const char*) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigurationKey {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
enum VisibilityLevel
|
|
||||||
{
|
|
||||||
CUSTOMER,
|
|
||||||
CUSTOMERSITE,
|
|
||||||
CUSTOMERTUNE,
|
|
||||||
CUSTOMERWARN,
|
|
||||||
DEVELOPER,
|
|
||||||
FACTORY
|
|
||||||
};
|
|
||||||
|
|
||||||
enum Type
|
|
||||||
{
|
|
||||||
BOOLEAN,
|
|
||||||
CHOICE_OPT,
|
|
||||||
CHOICE,
|
|
||||||
CIDR_OPT,
|
|
||||||
CIDR,
|
|
||||||
FILEPATH_OPT,
|
|
||||||
FILEPATH,
|
|
||||||
IPADDRESS_OPT,
|
|
||||||
IPADDRESS,
|
|
||||||
IPANDPORT,
|
|
||||||
MIPADDRESS_OPT,
|
|
||||||
MIPADDRESS,
|
|
||||||
PORT_OPT,
|
|
||||||
PORT,
|
|
||||||
REGEX_OPT,
|
|
||||||
REGEX,
|
|
||||||
STRING_OPT,
|
|
||||||
STRING,
|
|
||||||
VALRANGE
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
std::string mName;
|
|
||||||
std::string mDefaultValue;
|
|
||||||
std::string mUnits;
|
|
||||||
VisibilityLevel mVisibility;
|
|
||||||
Type mType;
|
|
||||||
std::string mValidValues;
|
|
||||||
bool mIsStatic;
|
|
||||||
std::string mDescription;
|
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
ConfigurationKey(const std::string& wName, const std::string& wDefaultValue, const std::string& wUnits, const VisibilityLevel wVisibility, const Type wType, const std::string& wValidValues, bool wIsStatic, const std::string& wDescription):
|
|
||||||
mName(wName),
|
|
||||||
mDefaultValue(wDefaultValue),
|
|
||||||
mUnits(wUnits),
|
|
||||||
mVisibility(wVisibility),
|
|
||||||
mType(wType),
|
|
||||||
mValidValues(wValidValues),
|
|
||||||
mIsStatic(wIsStatic),
|
|
||||||
mDescription(wDescription)
|
|
||||||
{ }
|
|
||||||
|
|
||||||
ConfigurationKey()
|
|
||||||
{ }
|
|
||||||
|
|
||||||
const std::string& getName() const { return mName; }
|
|
||||||
const std::string& getDefaultValue() const { return mDefaultValue; }
|
|
||||||
void updateDefaultValue(const std::string& newValue) { mDefaultValue = newValue; }
|
|
||||||
void updateDefaultValue(const int newValue) { std::stringstream ss; ss << newValue; updateDefaultValue(ss.str()); }
|
|
||||||
const std::string& getUnits() const { return mUnits; }
|
|
||||||
const VisibilityLevel& getVisibility() const { return mVisibility; }
|
|
||||||
const Type& getType() const { return mType; }
|
|
||||||
const std::string& getValidValues() const { return mValidValues; }
|
|
||||||
bool isStatic() const { return mIsStatic; }
|
|
||||||
const std::string& getDescription() const { return mDescription; }
|
|
||||||
|
|
||||||
static bool isValidIP(const std::string& ip);
|
|
||||||
static void getMinMaxStepping(const ConfigurationKey &key, std::string &min, std::string &max, std::string &stepping);
|
|
||||||
template<class T> static bool isInValRange(const ConfigurationKey &key, const std::string& val, const bool isInteger);
|
|
||||||
static const std::string visibilityLevelToString(const VisibilityLevel& visibility);
|
|
||||||
static const std::string typeToString(const ConfigurationKey::Type& type);
|
|
||||||
static void printKey(const ConfigurationKey &key, const std::string& currentValue, std::ostream& os);
|
|
||||||
static void printDescription(const ConfigurationKey &key, std::ostream& os);
|
|
||||||
static const std::string getARFCNsString();
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// vim: ts=4 sw=4
|
|
||||||
@@ -1,149 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2009, 2010 Free Software Foundation, Inc.
|
|
||||||
* Copyright 2010 Kestrel Signal Processing, Inc.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
|
||||||
* See the COPYING file in the main directory for details.
|
|
||||||
*
|
|
||||||
* This use of this software may be subject to additional restrictions.
|
|
||||||
* See the LEGAL file in the main directory for details.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "Configuration.h"
|
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
ConfigurationKeyMap getConfigurationKeys();
|
|
||||||
ConfigurationTable gConfig("exampleconfig.db","test", getConfigurationKeys());
|
|
||||||
|
|
||||||
void purgeConfig(void*,int,char const*, char const*, sqlite3_int64)
|
|
||||||
{
|
|
||||||
//cout << "update hook" << endl;
|
|
||||||
gConfig.purge();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
|
|
||||||
gConfig.setUpdateHook(purgeConfig);
|
|
||||||
|
|
||||||
const char *keys[5] = {"key1", "key2", "key3", "key4", "key5"};
|
|
||||||
|
|
||||||
for (int i=0; i<5; i++) {
|
|
||||||
gConfig.set(keys[i],i);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i=0; i<5; i++) {
|
|
||||||
cout << "table[" << keys[i] << "]=" << gConfig.getStr(keys[i]) << endl;
|
|
||||||
cout << "table[" << keys[i] << "]=" << gConfig.getNum(keys[i]) << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i=0; i<5; i++) {
|
|
||||||
cout << "defined table[" << keys[i] << "]=" << gConfig.defines(keys[i]) << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
gConfig.set("key5","100 200 300 400 ");
|
|
||||||
std::vector<unsigned> vect = gConfig.getVector("key5");
|
|
||||||
cout << "vect length " << vect.size() << ": ";
|
|
||||||
for (unsigned i=0; i<vect.size(); i++) cout << " " << vect[i];
|
|
||||||
cout << endl;
|
|
||||||
std::vector<string> svect = gConfig.getVectorOfStrings("key5");
|
|
||||||
cout << "vect length " << svect.size() << ": ";
|
|
||||||
for (unsigned i=0; i<svect.size(); i++) cout << " " << svect[i] << ":";
|
|
||||||
cout << endl;
|
|
||||||
|
|
||||||
cout << "bool " << gConfig.getBool("booltest") << endl;
|
|
||||||
gConfig.set("booltest",1);
|
|
||||||
cout << "bool " << gConfig.getBool("booltest") << endl;
|
|
||||||
gConfig.set("booltest",0);
|
|
||||||
cout << "bool " << gConfig.getBool("booltest") << endl;
|
|
||||||
|
|
||||||
gConfig.getStr("newstring");
|
|
||||||
gConfig.getNum("numnumber");
|
|
||||||
|
|
||||||
|
|
||||||
SimpleKeyValue pairs;
|
|
||||||
pairs.addItems(" a=1 b=34 dd=143 ");
|
|
||||||
cout<< pairs.get("a") << endl;
|
|
||||||
cout<< pairs.get("b") << endl;
|
|
||||||
cout<< pairs.get("dd") << endl;
|
|
||||||
|
|
||||||
gConfig.set("fkey","123.456");
|
|
||||||
float fval = gConfig.getFloat("fkey");
|
|
||||||
cout << "fkey " << fval << endl;
|
|
||||||
|
|
||||||
cout << "search fkey:" << endl;
|
|
||||||
gConfig.find("fkey",cout);
|
|
||||||
cout << "search fkey:" << endl;
|
|
||||||
gConfig.find("fkey",cout);
|
|
||||||
gConfig.remove("fkey");
|
|
||||||
cout << "search fkey:" << endl;
|
|
||||||
gConfig.find("fkey",cout);
|
|
||||||
|
|
||||||
try {
|
|
||||||
gConfig.getNum("supposedtoabort");
|
|
||||||
} catch (ConfigurationTableKeyNotFound) {
|
|
||||||
cout << "ConfigurationTableKeyNotFound exception successfully caught." << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ConfigurationKeyMap getConfigurationKeys()
|
|
||||||
{
|
|
||||||
ConfigurationKeyMap map;
|
|
||||||
ConfigurationKey *tmp;
|
|
||||||
|
|
||||||
tmp = new ConfigurationKey("booltest","0",
|
|
||||||
"",
|
|
||||||
ConfigurationKey::DEVELOPER,
|
|
||||||
ConfigurationKey::BOOLEAN,
|
|
||||||
"",
|
|
||||||
false,
|
|
||||||
""
|
|
||||||
);
|
|
||||||
map[tmp->getName()] = *tmp;
|
|
||||||
free(tmp);
|
|
||||||
|
|
||||||
tmp = new ConfigurationKey("numnumber","42",
|
|
||||||
"",
|
|
||||||
ConfigurationKey::DEVELOPER,
|
|
||||||
ConfigurationKey::VALRANGE,
|
|
||||||
"0-100",
|
|
||||||
false,
|
|
||||||
""
|
|
||||||
);
|
|
||||||
map[tmp->getName()] = *tmp;
|
|
||||||
free(tmp);
|
|
||||||
|
|
||||||
tmp = new ConfigurationKey("newstring","new string value",
|
|
||||||
"",
|
|
||||||
ConfigurationKey::DEVELOPER,
|
|
||||||
ConfigurationKey::STRING,
|
|
||||||
"",
|
|
||||||
false,
|
|
||||||
""
|
|
||||||
);
|
|
||||||
map[tmp->getName()] = *tmp;
|
|
||||||
free(tmp);
|
|
||||||
|
|
||||||
return map;
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008, 2011 Free Software Foundation, Inc.
|
* Copyright 2008, 2011 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
* This software is distributed under the terms of the GNU Affero Public License.
|
||||||
* See the COPYING file in the main directory for details.
|
* See the COPYING file in the main directory for details.
|
||||||
*
|
*
|
||||||
@@ -45,7 +47,7 @@
|
|||||||
// (pat) The elements in the queue are type T*, and
|
// (pat) The elements in the queue are type T*, and
|
||||||
// the Fifo class implements the underlying queue.
|
// the Fifo class implements the underlying queue.
|
||||||
// The default is class PointerFIFO, which does not place any restrictions on the type of T,
|
// The default is class PointerFIFO, which does not place any restrictions on the type of T,
|
||||||
// and is implemented by allocating auxilliary structures for the queue,
|
// and is implemented by allocating auxiliary structures for the queue,
|
||||||
// or SingleLinkedList, which implements the queue using an internal pointer in type T,
|
// or SingleLinkedList, which implements the queue using an internal pointer in type T,
|
||||||
// which must implement the functional interface of class SingleLinkListNode,
|
// which must implement the functional interface of class SingleLinkListNode,
|
||||||
// namely: functions T*next() and void setNext(T*).
|
// namely: functions T*next() and void setNext(T*).
|
||||||
@@ -53,7 +55,7 @@ template <class T, class Fifo=PointerFIFO> class InterthreadQueue {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
Fifo mQ;
|
Fifo mQ;
|
||||||
mutable Mutex mLock;
|
mutable Mutex mLock;
|
||||||
mutable Signal mWriteSignal;
|
mutable Signal mWriteSignal;
|
||||||
|
|
||||||
@@ -160,7 +162,7 @@ template <class T, class Fifo=PointerFIFO> class InterthreadQueue2 {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
Fifo mQ;
|
Fifo mQ;
|
||||||
mutable Mutex mLock;
|
mutable Mutex mLock;
|
||||||
mutable Signal mWriteSignal;
|
mutable Signal mWriteSignal;
|
||||||
|
|
||||||
@@ -256,7 +258,7 @@ template <class T, class Fifo=PointerFIFO> class InterthreadQueue2 {
|
|||||||
// This recurs (and the InterthreadQueue fills up with data)
|
// This recurs (and the InterthreadQueue fills up with data)
|
||||||
// until the read thread's accumulated temporary priority causes it to
|
// until the read thread's accumulated temporary priority causes it to
|
||||||
// get a second pre-emptive activation over the writing thread,
|
// get a second pre-emptive activation over the writing thread,
|
||||||
// resulting in bursts of activity by the read thread.
|
// resulting in bursts of activity by the read thread.
|
||||||
{ ScopedLock lock(mLock);
|
{ ScopedLock lock(mLock);
|
||||||
mQ.put(val);
|
mQ.put(val);
|
||||||
}
|
}
|
||||||
@@ -281,7 +283,7 @@ template <class T> class InterthreadQueueWithWait {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
PointerFIFO mQ;
|
PointerFIFO mQ;
|
||||||
mutable Mutex mLock;
|
mutable Mutex mLock;
|
||||||
mutable Signal mWriteSignal;
|
mutable Signal mWriteSignal;
|
||||||
mutable Signal mReadSignal;
|
mutable Signal mReadSignal;
|
||||||
@@ -515,7 +517,7 @@ public:
|
|||||||
@param timeout The blocking timeout in ms.
|
@param timeout The blocking timeout in ms.
|
||||||
@return Pointer at key or NULL on timeout.
|
@return Pointer at key or NULL on timeout.
|
||||||
*/
|
*/
|
||||||
D* read(const K &key, unsigned timeout) const
|
D* read(const K &key, unsigned timeout)
|
||||||
{
|
{
|
||||||
if (timeout==0) return readNoBlock(key);
|
if (timeout==0) return readNoBlock(key);
|
||||||
ScopedLock lock(mLock);
|
ScopedLock lock(mLock);
|
||||||
@@ -535,7 +537,7 @@ public:
|
|||||||
@param key The key to read from.
|
@param key The key to read from.
|
||||||
@return Pointer at key.
|
@return Pointer at key.
|
||||||
*/
|
*/
|
||||||
D* read(const K &key) const
|
D* read(const K &key)
|
||||||
{
|
{
|
||||||
ScopedLock lock(mLock);
|
ScopedLock lock(mLock);
|
||||||
typename Map::const_iterator iter = mMap.find(key);
|
typename Map::const_iterator iter = mMap.find(key);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008 Free Software Foundation, Inc.
|
* Copyright 2008 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
*
|
*
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
* This software is distributed under the terms of the GNU Affero Public License.
|
||||||
* See the COPYING file in the main directory for details.
|
* See the COPYING file in the main directory for details.
|
||||||
@@ -29,6 +30,25 @@
|
|||||||
#include "LinkedLists.h"
|
#include "LinkedLists.h"
|
||||||
|
|
||||||
|
|
||||||
|
PointerFIFO::~PointerFIFO()
|
||||||
|
{
|
||||||
|
ListNode *node, *next;
|
||||||
|
|
||||||
|
node = mHead;
|
||||||
|
while (node != NULL) {
|
||||||
|
next = node->next();
|
||||||
|
delete node;
|
||||||
|
node = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
node = mFreeList;
|
||||||
|
while (node != NULL) {
|
||||||
|
next = node->next();
|
||||||
|
delete node;
|
||||||
|
node = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void PointerFIFO::push_front(void* val) // by pat
|
void PointerFIFO::push_front(void* val) // by pat
|
||||||
{
|
{
|
||||||
// Pat added this routine for completeness, but never used or tested.
|
// Pat added this routine for completeness, but never used or tested.
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008 Free Software Foundation, Inc.
|
* Copyright 2008 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
|
* This software is distributed under multiple licenses; see the COPYING file in
|
||||||
|
* the main directory for licensing information for this specific distribution.
|
||||||
*
|
*
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
* This software is distributed under the terms of the GNU Affero Public License.
|
||||||
* See the COPYING file in the main directory for details.
|
* See the COPYING file in the main directory for details.
|
||||||
@@ -70,6 +73,7 @@ class PointerFIFO {
|
|||||||
:mHead(NULL),mTail(NULL),mFreeList(NULL),
|
:mHead(NULL),mTail(NULL),mFreeList(NULL),
|
||||||
mSize(0)
|
mSize(0)
|
||||||
{}
|
{}
|
||||||
|
~PointerFIFO();
|
||||||
|
|
||||||
unsigned size() const { return mSize; }
|
unsigned size() const { return mSize; }
|
||||||
unsigned totalSize() const { return 0; } // Not used in this version.
|
unsigned totalSize() const { return 0; } // Not used in this version.
|
||||||
|
|||||||
@@ -1,69 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2009 Free Software Foundation, Inc.
|
|
||||||
* Copyright 2010 Kestrel Signal Processing, Inc.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
|
||||||
* See the COPYING file in the main directory for details.
|
|
||||||
*
|
|
||||||
* This use of this software may be subject to additional restrictions.
|
|
||||||
* See the LEGAL file in the main directory for details.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <iterator>
|
|
||||||
|
|
||||||
#include "Logger.h"
|
|
||||||
#include "Configuration.h"
|
|
||||||
|
|
||||||
ConfigurationTable gConfig;
|
|
||||||
//ConfigurationTable gConfig("example.config");
|
|
||||||
|
|
||||||
void printAlarms()
|
|
||||||
{
|
|
||||||
std::ostream_iterator<std::string> output( std::cout, "\n" );
|
|
||||||
std::list<std::string> alarms = gGetLoggerAlarms();
|
|
||||||
std::cout << "# alarms = " << alarms.size() << std::endl;
|
|
||||||
std::copy( alarms.begin(), alarms.end(), output );
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
gLogInit("LogTest","NOTICE",LOG_LOCAL7);
|
|
||||||
|
|
||||||
LOG(EMERG) << " testing the logger.";
|
|
||||||
LOG(ALERT) << " testing the logger.";
|
|
||||||
LOG(CRIT) << " testing the logger.";
|
|
||||||
LOG(ERR) << " testing the logger.";
|
|
||||||
LOG(WARNING) << " testing the logger.";
|
|
||||||
LOG(NOTICE) << " testing the logger.";
|
|
||||||
LOG(INFO) << " testing the logger.";
|
|
||||||
LOG(DEBUG) << " testing the logger.";
|
|
||||||
std::cout << "\n\n\n";
|
|
||||||
std::cout << "testing Alarms\n";
|
|
||||||
std::cout << "you should see three lines:" << std::endl;
|
|
||||||
printAlarms();
|
|
||||||
std::cout << "----------- generating 20 alarms ----------" << std::endl;
|
|
||||||
for (int i = 0 ; i < 20 ; ++i) {
|
|
||||||
LOG(ALERT) << i;
|
|
||||||
}
|
|
||||||
std::cout << "you should see ten lines with the numbers 10..19:" << std::endl;
|
|
||||||
printAlarms();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2009, 2010 Free Software Foundation, Inc.
|
* Copyright (C) 2018 sysmocom - s.f.m.c. GmbH
|
||||||
* Copyright 2010 Kestrel Signal Processing, Inc.
|
|
||||||
* Copyright 2011, 2012 Range Networks, Inc.
|
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
*
|
*
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
* This software is distributed under the terms of the GNU Affero Public License.
|
||||||
* See the COPYING file in the main directory for details.
|
* See the COPYING file in the main directory for details.
|
||||||
@@ -32,300 +31,33 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <sys/time.h> // For gettimeofday
|
#include <sys/time.h> // For gettimeofday
|
||||||
|
|
||||||
#include "Configuration.h"
|
|
||||||
#include "Logger.h"
|
#include "Logger.h"
|
||||||
#include "Threads.h" // pat added
|
#include "Threads.h" // pat added
|
||||||
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
// Switches to enable/disable logging targets
|
|
||||||
// MUST BE DEFINED BEFORE gConfig FOR gLogEarly() TO WORK CORRECTLY
|
|
||||||
bool gLogToConsole = true;
|
|
||||||
bool gLogToSyslog = false;
|
|
||||||
FILE *gLogToFile = NULL;
|
|
||||||
Mutex gLogToLock;
|
|
||||||
|
|
||||||
|
|
||||||
// Reference to a global config table, used all over the system.
|
|
||||||
extern ConfigurationTable gConfig;
|
|
||||||
|
|
||||||
|
|
||||||
/**@ The global alarms table. */
|
|
||||||
//@{
|
|
||||||
Mutex alarmsLock;
|
|
||||||
list<string> alarmsList;
|
|
||||||
void addAlarm(const string&);
|
|
||||||
//@}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// (pat) If Log messages are printed before the classes in this module are inited
|
|
||||||
// (which happens when static classes have constructors that do work)
|
|
||||||
// the OpenBTS just crashes.
|
|
||||||
// Prevent that by setting sLoggerInited to true when this module is inited.
|
|
||||||
static bool sLoggerInited = 0;
|
|
||||||
static struct CheckLoggerInitStatus {
|
|
||||||
CheckLoggerInitStatus() { sLoggerInited = 1; }
|
|
||||||
} sCheckloggerInitStatus;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Names of the logging levels. */
|
|
||||||
const char *levelNames[] = {
|
|
||||||
"EMERG", "ALERT", "CRIT", "ERR", "WARNING", "NOTICE", "INFO", "DEBUG"
|
|
||||||
};
|
|
||||||
int numLevels = 8;
|
|
||||||
|
|
||||||
|
|
||||||
int levelStringToInt(const string& name)
|
|
||||||
{
|
|
||||||
// Reverse search, since the numerically larger levels are more common.
|
|
||||||
for (int i=numLevels-1; i>=0; i--) {
|
|
||||||
if (name == levelNames[i]) return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Common substitutions.
|
|
||||||
if (name=="INFORMATION") return 6;
|
|
||||||
if (name=="WARN") return 4;
|
|
||||||
if (name=="ERROR") return 3;
|
|
||||||
if (name=="CRITICAL") return 2;
|
|
||||||
if (name=="EMERGENCY") return 0;
|
|
||||||
|
|
||||||
// Unknown level.
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Given a string, return the corresponding level name. */
|
|
||||||
int lookupLevel(const string& key)
|
|
||||||
{
|
|
||||||
string val = gConfig.getStr(key);
|
|
||||||
int level = levelStringToInt(val);
|
|
||||||
|
|
||||||
if (level == -1) {
|
|
||||||
string defaultLevel = gConfig.mSchema["Log.Level"].getDefaultValue();
|
|
||||||
level = levelStringToInt(defaultLevel);
|
|
||||||
_LOG(CRIT) << "undefined logging level (" << key << " = \"" << val << "\") defaulting to \"" << defaultLevel << ".\" Valid levels are: EMERG, ALERT, CRIT, ERR, WARNING, NOTICE, INFO or DEBUG";
|
|
||||||
gConfig.set(key, defaultLevel);
|
|
||||||
}
|
|
||||||
|
|
||||||
return level;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string format(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list ap;
|
|
||||||
char buf[300];
|
|
||||||
va_start(ap,fmt);
|
|
||||||
int n = vsnprintf(buf,300,fmt,ap);
|
|
||||||
va_end(ap);
|
|
||||||
if (n >= (300-4)) { strcpy(&buf[(300-4)],"..."); }
|
|
||||||
return std::string(buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
const std::string timestr()
|
|
||||||
{
|
|
||||||
struct timeval tv;
|
|
||||||
struct tm tm;
|
|
||||||
gettimeofday(&tv,NULL);
|
|
||||||
localtime_r(&tv.tv_sec,&tm);
|
|
||||||
unsigned tenths = tv.tv_usec / 100000; // Rounding down is ok.
|
|
||||||
return format(" %02d:%02d:%02d.%1d",tm.tm_hour,tm.tm_min,tm.tm_sec,tenths);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, std::ostringstream& ss)
|
std::ostream& operator<<(std::ostream& os, std::ostringstream& ss)
|
||||||
{
|
{
|
||||||
return os << ss.str();
|
return os << ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
int getLoggingLevel(const char* filename)
|
|
||||||
{
|
|
||||||
// Default level?
|
|
||||||
if (!filename) return lookupLevel("Log.Level");
|
|
||||||
|
|
||||||
// This can afford to be inefficient since it is not called that often.
|
|
||||||
const string keyName = string("Log.Level.") + string(filename);
|
|
||||||
if (gConfig.defines(keyName)) return lookupLevel(keyName);
|
|
||||||
return lookupLevel("Log.Level");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int gGetLoggingLevel(const char* filename)
|
|
||||||
{
|
|
||||||
// This is called a lot and needs to be efficient.
|
|
||||||
|
|
||||||
static Mutex sLogCacheLock;
|
|
||||||
static map<uint64_t,int> sLogCache;
|
|
||||||
static unsigned sCacheCount;
|
|
||||||
static const unsigned sCacheRefreshCount = 1000;
|
|
||||||
|
|
||||||
if (filename==NULL) return gGetLoggingLevel("");
|
|
||||||
|
|
||||||
HashString hs(filename);
|
|
||||||
uint64_t key = hs.hash();
|
|
||||||
|
|
||||||
sLogCacheLock.lock();
|
|
||||||
// Time for a cache flush?
|
|
||||||
if (sCacheCount>sCacheRefreshCount) {
|
|
||||||
sLogCache.clear();
|
|
||||||
sCacheCount=0;
|
|
||||||
}
|
|
||||||
// Is it cached already?
|
|
||||||
map<uint64_t,int>::const_iterator where = sLogCache.find(key);
|
|
||||||
sCacheCount++;
|
|
||||||
if (where!=sLogCache.end()) {
|
|
||||||
int retVal = where->second;
|
|
||||||
sLogCacheLock.unlock();
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
// Look it up in the config table and cache it.
|
|
||||||
// FIXME: Figure out why unlock and lock below fix the config table deadlock.
|
|
||||||
// (pat) Probably because getLoggingLevel may call LOG recursively via lookupLevel().
|
|
||||||
sLogCacheLock.unlock();
|
|
||||||
int level = getLoggingLevel(filename);
|
|
||||||
sLogCacheLock.lock();
|
|
||||||
sLogCache.insert(pair<uint64_t,int>(key,level));
|
|
||||||
sLogCacheLock.unlock();
|
|
||||||
return level;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// copies the alarm list and returns it. list supposed to be small.
|
|
||||||
list<string> gGetLoggerAlarms()
|
|
||||||
{
|
|
||||||
alarmsLock.lock();
|
|
||||||
list<string> ret;
|
|
||||||
// excuse the "complexity", but to use std::copy with a list you need
|
|
||||||
// an insert_iterator - copy technically overwrites, doesn't insert.
|
|
||||||
insert_iterator< list<string> > ii(ret, ret.begin());
|
|
||||||
copy(alarmsList.begin(), alarmsList.end(), ii);
|
|
||||||
alarmsLock.unlock();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Add an alarm to the alarm list. */
|
|
||||||
void addAlarm(const string& s)
|
|
||||||
{
|
|
||||||
alarmsLock.lock();
|
|
||||||
alarmsList.push_back(s);
|
|
||||||
unsigned maxAlarms = gConfig.getNum("Log.Alarms.Max");
|
|
||||||
while (alarmsList.size() > maxAlarms) alarmsList.pop_front();
|
|
||||||
alarmsLock.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Log::~Log()
|
Log::~Log()
|
||||||
{
|
{
|
||||||
if (mDummyInit) return;
|
int old_state;
|
||||||
// Anything at or above LOG_CRIT is an "alarm".
|
int mlen = mStream.str().size();
|
||||||
// Save alarms in the local list and echo them to stderr.
|
int neednl = (mlen==0 || mStream.str()[mlen-1] != '\n');
|
||||||
if (mPriority <= LOG_ERR) {
|
const char *fmt = neednl ? "%s\n" : "%s";
|
||||||
if (sLoggerInited) addAlarm(mStream.str().c_str());
|
|
||||||
cerr << mStream.str() << endl;
|
/* print related function called inside a C++ destructor, use pthread_setcancelstate() APIs.
|
||||||
}
|
See osmo-trx commit 86be40b4eb762d5c12e8e3f7388ca9f254e77b36 for more information */
|
||||||
// Current logging level was already checked by the macro. So just log.
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &old_state);
|
||||||
// Log to syslog
|
LOGPSRC(mCategory, mPriority, filename, line, fmt, mStream.str().c_str());
|
||||||
if (gLogToSyslog) {
|
pthread_setcancelstate(old_state, NULL);
|
||||||
syslog(mPriority, "%s", mStream.str().c_str());
|
|
||||||
}
|
|
||||||
// Log to file and console
|
|
||||||
if (gLogToConsole||gLogToFile) {
|
|
||||||
int mlen = mStream.str().size();
|
|
||||||
int neednl = (mlen==0 || mStream.str()[mlen-1] != '\n');
|
|
||||||
ScopedLock lock(gLogToLock);
|
|
||||||
if (gLogToConsole) {
|
|
||||||
// The COUT() macro prevents messages from stomping each other but adds uninteresting thread numbers,
|
|
||||||
// so just use std::cout.
|
|
||||||
std::cout << mStream.str();
|
|
||||||
if (neednl) std::cout<<"\n";
|
|
||||||
}
|
|
||||||
if (gLogToFile) {
|
|
||||||
fputs(mStream.str().c_str(),gLogToFile);
|
|
||||||
if (neednl) {fputc('\n',gLogToFile);}
|
|
||||||
fflush(gLogToFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Log::Log(const char* name, const char* level, int facility)
|
|
||||||
{
|
|
||||||
mDummyInit = true;
|
|
||||||
gLogInit(name, level, facility);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ostringstream& Log::get()
|
ostringstream& Log::get()
|
||||||
{
|
{
|
||||||
assert(mPriority<numLevels);
|
|
||||||
mStream << levelNames[mPriority] << ' ';
|
|
||||||
return mStream;
|
return mStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void gLogInit(const char* name, const char* level, int facility)
|
|
||||||
{
|
|
||||||
// Set the level if one has been specified.
|
|
||||||
if (level) {
|
|
||||||
gConfig.set("Log.Level",level);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Both the transceiver and OpenBTS use this same facility, but only OpenBTS/OpenNodeB may use this log file:
|
|
||||||
string str = gConfig.getStr("Log.File");
|
|
||||||
if (gLogToFile==NULL && str.length() && 0==strncmp(gCmdName,"Open",4)) {
|
|
||||||
const char *fn = str.c_str();
|
|
||||||
if (fn && *fn && strlen(fn)>3) { // strlen because a garbage char is getting in sometimes.
|
|
||||||
gLogToFile = fopen(fn,"w"); // New log file each time we start.
|
|
||||||
if (gLogToFile) {
|
|
||||||
time_t now;
|
|
||||||
time(&now);
|
|
||||||
fprintf(gLogToFile,"Starting at %s",ctime(&now));
|
|
||||||
fflush(gLogToFile);
|
|
||||||
std::cout << "Logging to file: " << fn << "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open the log connection.
|
|
||||||
openlog(name,0,facility);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void gLogEarly(int level, const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
|
|
||||||
if (gLogToSyslog) {
|
|
||||||
va_list args_copy;
|
|
||||||
va_copy(args_copy, args);
|
|
||||||
vsyslog(level | LOG_USER, fmt, args_copy);
|
|
||||||
va_end(args_copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gLogToConsole) {
|
|
||||||
va_list args_copy;
|
|
||||||
va_copy(args_copy, args);
|
|
||||||
vprintf(fmt, args_copy);
|
|
||||||
printf("\n");
|
|
||||||
va_end(args_copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (gLogToFile) {
|
|
||||||
va_list args_copy;
|
|
||||||
va_copy(args_copy, args);
|
|
||||||
vfprintf(gLogToFile, fmt, args_copy);
|
|
||||||
fprintf(gLogToFile, "\n");
|
|
||||||
va_end(args_copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// vim: ts=4 sw=4
|
// vim: ts=4 sw=4
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
* Copyright 2009, 2010 Free Software Foundation, Inc.
|
* Copyright 2009, 2010 Free Software Foundation, Inc.
|
||||||
* Copyright 2010 Kestrel Signal Processing, Inc.
|
* Copyright 2010 Kestrel Signal Processing, Inc.
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
* This software is distributed under the terms of the GNU Affero Public License.
|
||||||
* See the COPYING file in the main directory for details.
|
* See the COPYING file in the main directory for details.
|
||||||
*
|
*
|
||||||
@@ -23,71 +25,47 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// (pat) WARNING is stupidly defined in /usr/local/include/osipparser2/osip_const.h.
|
|
||||||
// This must be outside the #ifndef LOGGER_H to fix it as long as Logger.h included after the above file.
|
|
||||||
#ifdef WARNING
|
|
||||||
#undef WARNING
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef LOGGER_H
|
#ifndef LOGGER_H
|
||||||
#define LOGGER_H
|
#define LOGGER_H
|
||||||
|
|
||||||
#include <syslog.h>
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <list>
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#define _LOG(level) \
|
extern "C" {
|
||||||
Log(LOG_##level).get() << pthread_self() \
|
#include <osmocom/core/logging.h>
|
||||||
<< timestr() << " " __FILE__ ":" << __LINE__ << ":" << __FUNCTION__ << ": "
|
#include "debug.h"
|
||||||
|
}
|
||||||
|
|
||||||
#define IS_LOG_LEVEL(wLevel) (gGetLoggingLevel(__FILE__)>=LOG_##wLevel)
|
/* Translation for old log statements */
|
||||||
|
#ifndef LOGL_ALERT
|
||||||
#ifdef NDEBUG
|
#define LOGL_ALERT LOGL_FATAL
|
||||||
#define LOG(wLevel) \
|
#endif
|
||||||
if (LOG_##wLevel!=LOG_DEBUG && IS_LOG_LEVEL(wLevel)) _LOG(wLevel)
|
#ifndef LOGL_ERR
|
||||||
#else
|
#define LOGL_ERR LOGL_ERROR
|
||||||
#define LOG(wLevel) \
|
#endif
|
||||||
if (IS_LOG_LEVEL(wLevel)) _LOG(wLevel)
|
#ifndef LOGL_WARNING
|
||||||
|
#define LOGL_WARNING LOGL_NOTICE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// pat: And for your edification here are the 'levels' as defined in syslog.h:
|
#define LOG(level) \
|
||||||
// LOG_EMERG 0 system is unusable
|
Log(DMAIN, LOGL_##level, __BASE_FILE__, __LINE__).get()
|
||||||
// LOG_ALERT 1 action must be taken immediately
|
|
||||||
// LOG_CRIT 2 critical conditions
|
|
||||||
// LOG_ERR 3 error conditions
|
|
||||||
// LOG_WARNING 4 warning conditions
|
|
||||||
// LOG_NOTICE 5 normal, but significant, condition
|
|
||||||
// LOG_INFO 6 informational message
|
|
||||||
// LOG_DEBUG 7 debug-level message
|
|
||||||
|
|
||||||
// (pat) added - print out a var and its name.
|
#define LOGC(category, level) \
|
||||||
// Use like this: int descriptive_name; LOG(INFO)<<LOGVAR(descriptive_name);
|
Log(category, LOGL_##level, __BASE_FILE__, __LINE__).get()
|
||||||
#define LOGVAR2(name,val) " " << name << "=" << (val)
|
|
||||||
#define LOGVAR(var) (" " #var "=") << var
|
|
||||||
#define LOGHEX(var) (" " #var "=0x") << hex << ((unsigned)var) << dec
|
|
||||||
#define LOGHEX2(name,val) " " << name << "=0x" << hex << ((unsigned)(val)) << dec
|
|
||||||
// These are kind of cheesy, but you can use for bitvector
|
|
||||||
#define LOGBV2(name,val) " " << name << "=(" << val<<" size:"<<val.size()<<")"
|
|
||||||
#define LOGBV(bv) LOGBV2(#bv,bv)
|
|
||||||
#define LOGVARRANGE(name,cur,lo,hi) " "<<name <<"=("<<(cur) << " range:"<<(lo) << " to "<<(hi) <<")"
|
|
||||||
|
|
||||||
|
#define LOGLV(category, level) \
|
||||||
|
Log(category, level, __BASE_FILE__, __LINE__).get()
|
||||||
|
|
||||||
#define OBJLOG(wLevel) \
|
#define LOGSRC(category, level, file, line) \
|
||||||
LOG(wLevel) << "obj: " << this << ' '
|
Log(category, level, file, line).get()
|
||||||
|
|
||||||
#define LOG_ASSERT(x) { if (!(x)) LOG(EMERG) << "assertion " #x " failed"; } assert(x);
|
#define LOGCHAN(chan, category, level) \
|
||||||
|
Log(category, LOGL_##level, __BASE_FILE__, __LINE__).get() << "[chan=" << chan << "] "
|
||||||
|
|
||||||
#include "Threads.h" // must be after defines above, if these files are to be allowed to use LOG()
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A C++ stream-based thread-safe logger.
|
A C++ stream-based thread-safe logger.
|
||||||
Derived from Dr. Dobb's Sept. 2007 issue.
|
|
||||||
Updated to use syslog.
|
|
||||||
This object is NOT the global logger;
|
This object is NOT the global logger;
|
||||||
every log record is an object of this class.
|
every log record is an object of this class.
|
||||||
*/
|
*/
|
||||||
@@ -97,45 +75,28 @@ class Log {
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
std::ostringstream mStream; ///< This is where we buffer up the log entry.
|
std::ostringstream mStream; ///< This is where we buffer up the log entry.
|
||||||
int mPriority; ///< Priority of current report.
|
int mCategory; ///< Priority of current report.
|
||||||
bool mDummyInit;
|
int mPriority; ///< Category of current report.
|
||||||
|
const char *filename; ///< Source File Name of current report.
|
||||||
|
int line; ///< Line number in source file of current report.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Log(int wPriority)
|
Log(int wCategory, int wPriority, const char* filename, int line)
|
||||||
:mPriority(wPriority), mDummyInit(false)
|
: mCategory(wCategory), mPriority(wPriority),
|
||||||
|
filename(filename), line(line)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
Log(const char* name, const char* level=NULL, int facility=LOG_USER);
|
|
||||||
|
|
||||||
// Most of the work is in the destructor.
|
// Most of the work is in the destructor.
|
||||||
/** The destructor actually generates the log entry. */
|
/** The destructor actually generates the log entry. */
|
||||||
~Log();
|
~Log();
|
||||||
|
|
||||||
std::ostringstream& get();
|
std::ostringstream& get();
|
||||||
};
|
};
|
||||||
extern bool gLogToConsole; // Output log messages to stdout
|
|
||||||
extern bool gLogToSyslog; // Output log messages to syslog
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
std::list<std::string> gGetLoggerAlarms(); ///< Get a copy of the recent alarm list.
|
|
||||||
|
|
||||||
const std::string timestr(); // A timestamp to print in messages.
|
|
||||||
std::ostream& operator<<(std::ostream& os, std::ostringstream& ss);
|
std::ostream& operator<<(std::ostream& os, std::ostringstream& ss);
|
||||||
|
|
||||||
/**@ Global control and initialization of the logging system. */
|
|
||||||
//@{
|
|
||||||
/** Initialize the global logging system. */
|
|
||||||
void gLogInit(const char* name, const char* level=NULL, int facility=LOG_USER);
|
|
||||||
/** Get the logging level associated with a given file. */
|
|
||||||
int gGetLoggingLevel(const char *filename=NULL);
|
|
||||||
/** Allow early logging when still in constructors */
|
|
||||||
void gLogEarly(int level, const char *fmt, ...) __attribute__((format(printf, 2, 3)));
|
|
||||||
//@}
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// vim: ts=4 sw=4
|
// vim: ts=4 sw=4
|
||||||
|
|||||||
@@ -22,77 +22,40 @@
|
|||||||
include $(top_srcdir)/Makefile.common
|
include $(top_srcdir)/Makefile.common
|
||||||
|
|
||||||
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
|
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES)
|
||||||
AM_CXXFLAGS = -Wall -O3 -g -ldl -lpthread
|
AM_CXXFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)
|
||||||
|
AM_CFLAGS = -Wall $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)
|
||||||
EXTRA_DIST = \
|
|
||||||
example.config \
|
|
||||||
README.common
|
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libcommon.la
|
noinst_LTLIBRARIES = libcommon.la
|
||||||
|
|
||||||
libcommon_la_SOURCES = \
|
libcommon_la_SOURCES = \
|
||||||
BitVector.cpp \
|
BitVector.cpp \
|
||||||
LinkedLists.cpp \
|
LinkedLists.cpp \
|
||||||
Sockets.cpp \
|
|
||||||
Threads.cpp \
|
Threads.cpp \
|
||||||
Timeval.cpp \
|
Timeval.cpp \
|
||||||
Logger.cpp \
|
Logger.cpp \
|
||||||
Configuration.cpp \
|
Utils.cpp \
|
||||||
sqlite3util.cpp
|
trx_rate_ctr.cpp \
|
||||||
|
trx_vty.c \
|
||||||
noinst_PROGRAMS = \
|
debug.c
|
||||||
BitVectorTest \
|
libcommon_la_LIBADD = \
|
||||||
PRBSTest \
|
$(LIBOSMOCORE_LIBS) \
|
||||||
InterthreadTest \
|
$(LIBOSMOCTRL_LIBS) \
|
||||||
SocketsTest \
|
$(LIBOSMOVTY_LIBS) \
|
||||||
TimevalTest \
|
-lpthread \
|
||||||
VectorTest \
|
$(NULL)
|
||||||
ConfigurationTest \
|
|
||||||
LogTest
|
|
||||||
|
|
||||||
# ReportingTest
|
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
BitVector.h \
|
BitVector.h \
|
||||||
PRBS.h \
|
PRBS.h \
|
||||||
Interthread.h \
|
Interthread.h \
|
||||||
LinkedLists.h \
|
LinkedLists.h \
|
||||||
Sockets.h \
|
|
||||||
Threads.h \
|
Threads.h \
|
||||||
Timeval.h \
|
Timeval.h \
|
||||||
Vector.h \
|
Vector.h \
|
||||||
Configuration.h \
|
|
||||||
Logger.h \
|
Logger.h \
|
||||||
sqlite3util.h
|
Utils.h \
|
||||||
|
trx_rate_ctr.h \
|
||||||
BitVectorTest_SOURCES = BitVectorTest.cpp
|
trx_vty.h \
|
||||||
BitVectorTest_LDADD = libcommon.la $(SQLITE3_LIBS)
|
debug.h \
|
||||||
|
osmo_signal.h \
|
||||||
PRBSTest_SOURCES = PRBSTest.cpp
|
config_defs.h
|
||||||
|
|
||||||
InterthreadTest_SOURCES = InterthreadTest.cpp
|
|
||||||
InterthreadTest_LDADD = libcommon.la
|
|
||||||
InterthreadTest_LDFLAGS = -lpthread
|
|
||||||
|
|
||||||
SocketsTest_SOURCES = SocketsTest.cpp
|
|
||||||
SocketsTest_LDADD = libcommon.la
|
|
||||||
SocketsTest_LDFLAGS = -lpthread
|
|
||||||
|
|
||||||
TimevalTest_SOURCES = TimevalTest.cpp
|
|
||||||
TimevalTest_LDADD = libcommon.la
|
|
||||||
|
|
||||||
VectorTest_SOURCES = VectorTest.cpp
|
|
||||||
VectorTest_LDADD = libcommon.la $(SQLITE3_LIBS)
|
|
||||||
|
|
||||||
ConfigurationTest_SOURCES = ConfigurationTest.cpp
|
|
||||||
ConfigurationTest_LDADD = libcommon.la $(SQLITE3_LIBS)
|
|
||||||
|
|
||||||
# ReportingTest_SOURCES = ReportingTest.cpp
|
|
||||||
# ReportingTest_LDADD = libcommon.la $(SQLITE_LA)
|
|
||||||
|
|
||||||
LogTest_SOURCES = LogTest.cpp
|
|
||||||
LogTest_LDADD = libcommon.la $(SQLITE3_LIBS)
|
|
||||||
|
|
||||||
MOSTLYCLEANFILES += testSource testDestination
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2017 Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
|
* Copyright (C) 2017 Alexander Chemeris <Alexander.Chemeris@fairwaves.co>
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
@@ -10,10 +12,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef PRBS_H
|
#ifndef PRBS_H
|
||||||
|
|||||||
@@ -1,333 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2008, 2010 Free Software Foundation, Inc.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
|
||||||
* See the COPYING file in the main directory for details.
|
|
||||||
*
|
|
||||||
* This use of this software may be subject to additional restrictions.
|
|
||||||
* See the LEGAL file in the main directory for details.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include <config.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <sys/select.h>
|
|
||||||
|
|
||||||
#include "Threads.h"
|
|
||||||
#include "Sockets.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool resolveAddress(struct sockaddr_in *address, const char *hostAndPort)
|
|
||||||
{
|
|
||||||
assert(address);
|
|
||||||
assert(hostAndPort);
|
|
||||||
char *copy = strdup(hostAndPort);
|
|
||||||
char *colon = strchr(copy,':');
|
|
||||||
if (!colon) return false;
|
|
||||||
*colon = '\0';
|
|
||||||
char *host = copy;
|
|
||||||
unsigned port = strtol(colon+1,NULL,10);
|
|
||||||
bool retVal = resolveAddress(address,host,port);
|
|
||||||
free(copy);
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool resolveAddress(struct sockaddr_in *address, const char *host, unsigned short port)
|
|
||||||
{
|
|
||||||
assert(address);
|
|
||||||
assert(host);
|
|
||||||
// FIXME -- Need to ignore leading/trailing spaces in hostname.
|
|
||||||
struct hostent *hp;
|
|
||||||
int h_errno_local;
|
|
||||||
#ifdef HAVE_GETHOSTBYNAME2_R
|
|
||||||
struct hostent hostData;
|
|
||||||
char tmpBuffer[2048];
|
|
||||||
|
|
||||||
// There are different flavors of gethostbyname_r(), but
|
|
||||||
// latest Linux use the following form:
|
|
||||||
if (gethostbyname2_r(host, AF_INET, &hostData, tmpBuffer, sizeof(tmpBuffer), &hp, &h_errno_local)!=0) {
|
|
||||||
CERR("WARNING -- gethostbyname2_r() failed for " << host << ", " << hstrerror(h_errno_local));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
static Mutex sGethostbynameMutex;
|
|
||||||
// gethostbyname() is NOT thread-safe, so we should use a mutex here.
|
|
||||||
// Ideally it should be a global mutex for all non thread-safe socket
|
|
||||||
// operations and it should protect access to variables such as
|
|
||||||
// global h_errno.
|
|
||||||
sGethostbynameMutex.lock();
|
|
||||||
hp = gethostbyname(host);
|
|
||||||
h_errno_local = h_errno;
|
|
||||||
sGethostbynameMutex.unlock();
|
|
||||||
#endif
|
|
||||||
if (hp==NULL) {
|
|
||||||
CERR("WARNING -- gethostbyname() failed for " << host << ", " << hstrerror(h_errno_local));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (hp->h_addrtype != AF_INET) {
|
|
||||||
CERR("WARNING -- gethostbyname() resolved " << host << " to something other then AF_INET");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
address->sin_family = hp->h_addrtype;
|
|
||||||
assert(sizeof(address->sin_addr) == hp->h_length);
|
|
||||||
memcpy(&(address->sin_addr), hp->h_addr_list[0], hp->h_length);
|
|
||||||
address->sin_port = htons(port);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
DatagramSocket::DatagramSocket()
|
|
||||||
{
|
|
||||||
memset(mDestination, 0, sizeof(mDestination));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void DatagramSocket::nonblocking()
|
|
||||||
{
|
|
||||||
fcntl(mSocketFD,F_SETFL,O_NONBLOCK);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DatagramSocket::blocking()
|
|
||||||
{
|
|
||||||
fcntl(mSocketFD,F_SETFL,0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DatagramSocket::close()
|
|
||||||
{
|
|
||||||
::close(mSocketFD);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
DatagramSocket::~DatagramSocket()
|
|
||||||
{
|
|
||||||
close();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int DatagramSocket::write( const char * message, size_t length )
|
|
||||||
{
|
|
||||||
assert(length<=MAX_UDP_LENGTH);
|
|
||||||
int retVal = sendto(mSocketFD, message, length, 0,
|
|
||||||
(struct sockaddr *)mDestination, addressSize());
|
|
||||||
if (retVal == -1 ) perror("DatagramSocket::write() failed");
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DatagramSocket::writeBack( const char * message, size_t length )
|
|
||||||
{
|
|
||||||
assert(length<=MAX_UDP_LENGTH);
|
|
||||||
int retVal = sendto(mSocketFD, message, length, 0,
|
|
||||||
(struct sockaddr *)mSource, addressSize());
|
|
||||||
if (retVal == -1 ) perror("DatagramSocket::write() failed");
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int DatagramSocket::write( const char * message)
|
|
||||||
{
|
|
||||||
size_t length=strlen(message)+1;
|
|
||||||
return write(message,length);
|
|
||||||
}
|
|
||||||
|
|
||||||
int DatagramSocket::writeBack( const char * message)
|
|
||||||
{
|
|
||||||
size_t length=strlen(message)+1;
|
|
||||||
return writeBack(message,length);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int DatagramSocket::send(const struct sockaddr* dest, const char * message, size_t length )
|
|
||||||
{
|
|
||||||
assert(length<=MAX_UDP_LENGTH);
|
|
||||||
int retVal = sendto(mSocketFD, message, length, 0, dest, addressSize());
|
|
||||||
if (retVal == -1 ) perror("DatagramSocket::send() failed");
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DatagramSocket::send(const struct sockaddr* dest, const char * message)
|
|
||||||
{
|
|
||||||
size_t length=strlen(message)+1;
|
|
||||||
return send(dest,message,length);
|
|
||||||
}
|
|
||||||
|
|
||||||
int DatagramSocket::read(char* buffer, size_t length)
|
|
||||||
{
|
|
||||||
socklen_t addr_len = sizeof(mSource);
|
|
||||||
int rd_length = recvfrom(mSocketFD, (void *) buffer, length, 0,
|
|
||||||
(struct sockaddr*) &mSource, &addr_len);
|
|
||||||
|
|
||||||
if ((rd_length==-1) && (errno!=EAGAIN)) {
|
|
||||||
perror("DatagramSocket::read() failed");
|
|
||||||
throw SocketError();
|
|
||||||
}
|
|
||||||
return rd_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DatagramSocket::read(char* buffer, size_t length, unsigned timeout)
|
|
||||||
{
|
|
||||||
fd_set fds;
|
|
||||||
FD_ZERO(&fds);
|
|
||||||
FD_SET(mSocketFD,&fds);
|
|
||||||
struct timeval tv;
|
|
||||||
tv.tv_sec = timeout/1000;
|
|
||||||
tv.tv_usec = (timeout%1000)*1000;
|
|
||||||
int sel = select(mSocketFD+1,&fds,NULL,NULL,&tv);
|
|
||||||
if (sel<0) {
|
|
||||||
perror("DatagramSocket::read() select() failed");
|
|
||||||
throw SocketError();
|
|
||||||
}
|
|
||||||
if (sel==0) return -1;
|
|
||||||
if (FD_ISSET(mSocketFD,&fds)) return read(buffer, length);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
UDPSocket::UDPSocket(unsigned short wSrcPort)
|
|
||||||
:DatagramSocket()
|
|
||||||
{
|
|
||||||
open(wSrcPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
UDPSocket::UDPSocket(unsigned short wSrcPort,
|
|
||||||
const char * wDestIP, unsigned short wDestPort )
|
|
||||||
:DatagramSocket()
|
|
||||||
{
|
|
||||||
open(wSrcPort);
|
|
||||||
destination(wDestPort, wDestIP);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void UDPSocket::destination( unsigned short wDestPort, const char * wDestIP )
|
|
||||||
{
|
|
||||||
resolveAddress((sockaddr_in*)mDestination, wDestIP, wDestPort );
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void UDPSocket::open(unsigned short localPort)
|
|
||||||
{
|
|
||||||
// create
|
|
||||||
mSocketFD = socket(AF_INET,SOCK_DGRAM,0);
|
|
||||||
if (mSocketFD<0) {
|
|
||||||
perror("socket() failed");
|
|
||||||
throw SocketError();
|
|
||||||
}
|
|
||||||
|
|
||||||
// pat added: This lets the socket be reused immediately, which is needed if OpenBTS crashes.
|
|
||||||
int on = 1;
|
|
||||||
setsockopt(mSocketFD, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
|
|
||||||
|
|
||||||
|
|
||||||
// bind
|
|
||||||
struct sockaddr_in address;
|
|
||||||
size_t length = sizeof(address);
|
|
||||||
bzero(&address,length);
|
|
||||||
address.sin_family = AF_INET;
|
|
||||||
address.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
|
||||||
address.sin_port = htons(localPort);
|
|
||||||
if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
|
|
||||||
perror("bind() failed");
|
|
||||||
throw SocketError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
unsigned short UDPSocket::port() const
|
|
||||||
{
|
|
||||||
struct sockaddr_in name;
|
|
||||||
socklen_t nameSize = sizeof(name);
|
|
||||||
int retVal = getsockname(mSocketFD, (struct sockaddr*)&name, &nameSize);
|
|
||||||
if (retVal==-1) throw SocketError();
|
|
||||||
return ntohs(name.sin_port);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
UDDSocket::UDDSocket(const char* localPath, const char* remotePath)
|
|
||||||
:DatagramSocket()
|
|
||||||
{
|
|
||||||
if (localPath!=NULL) open(localPath);
|
|
||||||
if (remotePath!=NULL) destination(remotePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void UDDSocket::open(const char* localPath)
|
|
||||||
{
|
|
||||||
// create
|
|
||||||
mSocketFD = socket(AF_UNIX,SOCK_DGRAM,0);
|
|
||||||
if (mSocketFD<0) {
|
|
||||||
perror("socket() failed");
|
|
||||||
throw SocketError();
|
|
||||||
}
|
|
||||||
|
|
||||||
// bind
|
|
||||||
struct sockaddr_un address;
|
|
||||||
size_t length = sizeof(address);
|
|
||||||
bzero(&address,length);
|
|
||||||
address.sun_family = AF_UNIX;
|
|
||||||
strcpy(address.sun_path,localPath);
|
|
||||||
unlink(localPath);
|
|
||||||
if (bind(mSocketFD,(struct sockaddr*)&address,length)<0) {
|
|
||||||
perror("bind() failed");
|
|
||||||
throw SocketError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void UDDSocket::destination(const char* remotePath)
|
|
||||||
{
|
|
||||||
struct sockaddr_un* unAddr = (struct sockaddr_un*)mDestination;
|
|
||||||
strcpy(unAddr->sun_path,remotePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// vim:ts=4:sw=4
|
|
||||||
@@ -1,193 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2008, 2010 Free Software Foundation, Inc.
|
|
||||||
*
|
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
|
||||||
* See the COPYING file in the main directory for details.
|
|
||||||
*
|
|
||||||
* This use of this software may be subject to additional restrictions.
|
|
||||||
* See the LEGAL file in the main directory for details.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef SOCKETS_H
|
|
||||||
#define SOCKETS_H
|
|
||||||
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <netdb.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <list>
|
|
||||||
#include <assert.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define MAX_UDP_LENGTH 1500
|
|
||||||
|
|
||||||
/** A function to resolve IP host names. */
|
|
||||||
bool resolveAddress(struct sockaddr_in *address, const char *host, unsigned short port);
|
|
||||||
|
|
||||||
/** Resolve an address of the form "<host>:<port>". */
|
|
||||||
bool resolveAddress(struct sockaddr_in *address, const char *hostAndPort);
|
|
||||||
|
|
||||||
/** An exception to throw when a critical socket operation fails. */
|
|
||||||
class SocketError {};
|
|
||||||
#define SOCKET_ERROR {throw SocketError(); }
|
|
||||||
|
|
||||||
/** Abstract class for connectionless sockets. */
|
|
||||||
class DatagramSocket {
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
int mSocketFD; ///< underlying file descriptor
|
|
||||||
char mDestination[256]; ///< address to which packets are sent
|
|
||||||
char mSource[256]; ///< return address of most recent received packet
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/** An almost-does-nothing constructor. */
|
|
||||||
DatagramSocket();
|
|
||||||
|
|
||||||
virtual ~DatagramSocket();
|
|
||||||
|
|
||||||
/** Return the address structure size for this socket type. */
|
|
||||||
virtual size_t addressSize() const = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Send a binary packet.
|
|
||||||
@param buffer The data bytes to send to mDestination.
|
|
||||||
@param length Number of bytes to send, or strlen(buffer) if defaulted to -1.
|
|
||||||
@return number of bytes written, or -1 on error.
|
|
||||||
*/
|
|
||||||
int write( const char * buffer, size_t length);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Send a C-style string packet.
|
|
||||||
@param buffer The data bytes to send to mDestination.
|
|
||||||
@return number of bytes written, or -1 on error.
|
|
||||||
*/
|
|
||||||
int write( const char * buffer);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Send a binary packet.
|
|
||||||
@param buffer The data bytes to send to mSource.
|
|
||||||
@param length Number of bytes to send, or strlen(buffer) if defaulted to -1.
|
|
||||||
@return number of bytes written, or -1 on error.
|
|
||||||
*/
|
|
||||||
int writeBack(const char * buffer, size_t length);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Send a C-style string packet.
|
|
||||||
@param buffer The data bytes to send to mSource.
|
|
||||||
@return number of bytes written, or -1 on error.
|
|
||||||
*/
|
|
||||||
int writeBack(const char * buffer);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
Receive a packet.
|
|
||||||
@param buffer A char[MAX_UDP_LENGTH] procured by the caller.
|
|
||||||
@return The number of bytes received or -1 on non-blocking pass.
|
|
||||||
*/
|
|
||||||
int read(char* buffer, size_t length);
|
|
||||||
|
|
||||||
/**
|
|
||||||
Receive a packet with a timeout.
|
|
||||||
@param buffer A char[MAX_UDP_LENGTH] procured by the caller.
|
|
||||||
@param maximum wait time in milliseconds
|
|
||||||
@return The number of bytes received or -1 on timeout.
|
|
||||||
*/
|
|
||||||
int read(char* buffer, size_t length, unsigned timeout);
|
|
||||||
|
|
||||||
|
|
||||||
/** Send a packet to a given destination, other than the default. */
|
|
||||||
int send(const struct sockaddr *dest, const char * buffer, size_t length);
|
|
||||||
|
|
||||||
/** Send a C-style string to a given destination, other than the default. */
|
|
||||||
int send(const struct sockaddr *dest, const char * buffer);
|
|
||||||
|
|
||||||
/** Make the socket non-blocking. */
|
|
||||||
void nonblocking();
|
|
||||||
|
|
||||||
/** Make the socket blocking (the default). */
|
|
||||||
void blocking();
|
|
||||||
|
|
||||||
/** Close the socket. */
|
|
||||||
void close();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** UDP/IP User Datagram Socket */
|
|
||||||
class UDPSocket : public DatagramSocket {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/** Open a USP socket with an OS-assigned port and no default destination. */
|
|
||||||
UDPSocket( unsigned short localPort=0);
|
|
||||||
|
|
||||||
/** Given a full specification, open the socket and set the dest address. */
|
|
||||||
UDPSocket( unsigned short localPort,
|
|
||||||
const char * remoteIP, unsigned short remotePort);
|
|
||||||
|
|
||||||
/** Set the destination port. */
|
|
||||||
void destination( unsigned short wDestPort, const char * wDestIP );
|
|
||||||
|
|
||||||
/** Return the actual port number in use. */
|
|
||||||
unsigned short port() const;
|
|
||||||
|
|
||||||
/** Open and bind the UDP socket to a local port. */
|
|
||||||
void open(unsigned short localPort=0);
|
|
||||||
|
|
||||||
/** Give the return address of the most recently received packet. */
|
|
||||||
const struct sockaddr_in* source() const { return (const struct sockaddr_in*)mSource; }
|
|
||||||
|
|
||||||
size_t addressSize() const { return sizeof(struct sockaddr_in); }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/** Unix Domain Datagram Socket */
|
|
||||||
class UDDSocket : public DatagramSocket {
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
UDDSocket(const char* localPath=NULL, const char* remotePath=NULL);
|
|
||||||
|
|
||||||
void destination(const char* remotePath);
|
|
||||||
|
|
||||||
void open(const char* localPath);
|
|
||||||
|
|
||||||
/** Give the return address of the most recently received packet. */
|
|
||||||
const struct sockaddr_un* source() const { return (const struct sockaddr_un*)mSource; }
|
|
||||||
|
|
||||||
size_t addressSize() const { return sizeof(struct sockaddr_un); }
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// vim:ts=4:sw=4
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2008 Free Software Foundation, Inc.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
|
||||||
* See the COPYING file in the main directory for details.
|
|
||||||
*
|
|
||||||
* This use of this software may be subject to additional restrictions.
|
|
||||||
* See the LEGAL file in the main directory for details.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "Sockets.h"
|
|
||||||
#include "Threads.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
|
|
||||||
static const int gNumToSend = 10;
|
|
||||||
|
|
||||||
|
|
||||||
void *testReaderIP(void *)
|
|
||||||
{
|
|
||||||
UDPSocket readSocket(5934, "localhost", 5061);
|
|
||||||
readSocket.nonblocking();
|
|
||||||
int rc = 0;
|
|
||||||
while (rc<gNumToSend) {
|
|
||||||
char buf[MAX_UDP_LENGTH];
|
|
||||||
int count = readSocket.read(buf, MAX_UDP_LENGTH);
|
|
||||||
if (count>0) {
|
|
||||||
COUT("read: " << buf);
|
|
||||||
rc++;
|
|
||||||
} else {
|
|
||||||
sleep(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void *testReaderUnix(void *)
|
|
||||||
{
|
|
||||||
UDDSocket readSocket("testDestination");
|
|
||||||
readSocket.nonblocking();
|
|
||||||
int rc = 0;
|
|
||||||
while (rc<gNumToSend) {
|
|
||||||
char buf[MAX_UDP_LENGTH];
|
|
||||||
int count = readSocket.read(buf, MAX_UDP_LENGTH);
|
|
||||||
if (count>0) {
|
|
||||||
COUT("read: " << buf);
|
|
||||||
rc++;
|
|
||||||
} else {
|
|
||||||
sleep(2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char * argv[] )
|
|
||||||
{
|
|
||||||
|
|
||||||
Thread readerThreadIP;
|
|
||||||
readerThreadIP.start(testReaderIP,NULL);
|
|
||||||
Thread readerThreadUnix;
|
|
||||||
readerThreadUnix.start(testReaderUnix,NULL);
|
|
||||||
|
|
||||||
UDPSocket socket1(5061, "127.0.0.1",5934);
|
|
||||||
UDDSocket socket1U("testSource","testDestination");
|
|
||||||
|
|
||||||
COUT("socket1: " << socket1.port());
|
|
||||||
|
|
||||||
// give the readers time to open
|
|
||||||
sleep(1);
|
|
||||||
|
|
||||||
for (int i=0; i<gNumToSend; i++) {
|
|
||||||
socket1.write("Hello IP land");
|
|
||||||
socket1U.write("Hello Unix domain");
|
|
||||||
sleep(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
readerThreadIP.join();
|
|
||||||
readerThreadUnix.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
// vim: ts=4 sw=4
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008 Free Software Foundation, Inc.
|
* Copyright 2008 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
*
|
*
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
* This software is distributed under the terms of the GNU Affero Public License.
|
||||||
* See the COPYING file in the main directory for details.
|
* See the COPYING file in the main directory for details.
|
||||||
@@ -24,85 +25,45 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "Threads.h"
|
#include "Threads.h"
|
||||||
#include "Timeval.h"
|
#include "Timeval.h"
|
||||||
|
#include "Logger.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <osmocom/core/thread.h>
|
||||||
|
}
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
#ifndef HAVE_ATOMIC_OPS
|
||||||
|
pthread_mutex_t atomic_ops_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Mutex gStreamLock; ///< Global lock to control access to cout and cerr.
|
void set_selfthread_name(const char *name)
|
||||||
|
|
||||||
void lockCout()
|
|
||||||
{
|
{
|
||||||
gStreamLock.lock();
|
pthread_t selfid = pthread_self();
|
||||||
Timeval entryTime;
|
pid_t tid = osmo_gettid();
|
||||||
cout << entryTime << " " << pthread_self() << ": ";
|
if (pthread_setname_np(selfid, name) == 0) {
|
||||||
|
LOG(INFO) << "Thread "<< selfid << " (task " << tid << ") set name: " << name;
|
||||||
|
} else {
|
||||||
|
char buf[256];
|
||||||
|
int err = errno;
|
||||||
|
char* err_str = strerror_r(err, buf, sizeof(buf));
|
||||||
|
LOG(NOTICE) << "Thread "<< selfid << " (task " << tid << ") set name \"" << name << "\" failed: (" << err << ") " << err_str;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void thread_enable_cancel(bool cancel)
|
||||||
void unlockCout()
|
|
||||||
{
|
{
|
||||||
cout << dec << endl << flush;
|
cancel ? pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) :
|
||||||
gStreamLock.unlock();
|
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void lockCerr()
|
|
||||||
{
|
|
||||||
gStreamLock.lock();
|
|
||||||
Timeval entryTime;
|
|
||||||
cerr << entryTime << " " << pthread_self() << ": ";
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlockCerr()
|
|
||||||
{
|
|
||||||
cerr << dec << endl << flush;
|
|
||||||
gStreamLock.unlock();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Mutex::Mutex()
|
|
||||||
{
|
|
||||||
bool res;
|
|
||||||
res = pthread_mutexattr_init(&mAttribs);
|
|
||||||
assert(!res);
|
|
||||||
res = pthread_mutexattr_settype(&mAttribs,PTHREAD_MUTEX_RECURSIVE);
|
|
||||||
assert(!res);
|
|
||||||
res = pthread_mutex_init(&mMutex,&mAttribs);
|
|
||||||
assert(!res);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Mutex::~Mutex()
|
|
||||||
{
|
|
||||||
pthread_mutex_destroy(&mMutex);
|
|
||||||
bool res = pthread_mutexattr_destroy(&mAttribs);
|
|
||||||
assert(!res);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/** Block for the signal up to the cancellation timeout. */
|
|
||||||
void Signal::wait(Mutex& wMutex, unsigned timeout) const
|
|
||||||
{
|
|
||||||
Timeval then(timeout);
|
|
||||||
struct timespec waitTime = then.timespec();
|
|
||||||
pthread_cond_timedwait(&mSignal,&wMutex.mMutex,&waitTime);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void Thread::start(void *(*task)(void*), void *arg)
|
void Thread::start(void *(*task)(void*), void *arg)
|
||||||
{
|
{
|
||||||
assert(mThread==((pthread_t)0));
|
assert(mThread==((pthread_t)0));
|
||||||
@@ -110,8 +71,10 @@ void Thread::start(void *(*task)(void*), void *arg)
|
|||||||
// (pat) Moved initialization to constructor to avoid crash in destructor.
|
// (pat) Moved initialization to constructor to avoid crash in destructor.
|
||||||
//res = pthread_attr_init(&mAttrib);
|
//res = pthread_attr_init(&mAttrib);
|
||||||
//assert(!res);
|
//assert(!res);
|
||||||
res = pthread_attr_setstacksize(&mAttrib, mStackSize);
|
if (mStackSize != 0) {
|
||||||
assert(!res);
|
res = pthread_attr_setstacksize(&mAttrib, mStackSize);
|
||||||
|
assert(!res);
|
||||||
|
}
|
||||||
res = pthread_create(&mThread, &mAttrib, task, arg);
|
res = pthread_create(&mThread, &mAttrib, task, arg);
|
||||||
assert(!res);
|
assert(!res);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008, 2011 Free Software Foundation, Inc.
|
* Copyright 2008, 2011 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
* This software is distributed under the terms of the GNU Affero Public License.
|
||||||
* See the COPYING file in the main directory for details.
|
* See the COPYING file in the main directory for details.
|
||||||
*
|
*
|
||||||
@@ -26,138 +28,96 @@
|
|||||||
#ifndef THREADS_H
|
#ifndef THREADS_H
|
||||||
#define THREADS_H
|
#define THREADS_H
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <assert.h>
|
#include <cassert>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "Timeval.h"
|
||||||
|
|
||||||
class Mutex;
|
class Mutex;
|
||||||
|
|
||||||
|
|
||||||
/**@name Multithreaded access for standard streams. */
|
|
||||||
//@{
|
|
||||||
|
|
||||||
/**@name Functions for gStreamLock. */
|
|
||||||
//@{
|
|
||||||
extern Mutex gStreamLock; ///< global lock for cout and cerr
|
|
||||||
void lockCerr(); ///< call prior to writing cerr
|
|
||||||
void unlockCerr(); ///< call after writing cerr
|
|
||||||
void lockCout(); ///< call prior to writing cout
|
|
||||||
void unlockCout(); ///< call after writing cout
|
|
||||||
//@}
|
|
||||||
|
|
||||||
/**@name Macros for standard messages. */
|
|
||||||
//@{
|
|
||||||
#define COUT(text) { lockCout(); std::cout << text; unlockCout(); }
|
|
||||||
#define CERR(text) { lockCerr(); std::cerr << __FILE__ << ":" << __LINE__ << ": " << text; unlockCerr(); }
|
|
||||||
#ifdef NDEBUG
|
|
||||||
#define DCOUT(text) {}
|
|
||||||
#define OBJDCOUT(text) {}
|
|
||||||
#else
|
|
||||||
#define DCOUT(text) { COUT(__FILE__ << ":" << __LINE__ << " " << text); }
|
|
||||||
#define OBJDCOUT(text) { DCOUT(this << " " << text); }
|
|
||||||
#endif
|
|
||||||
//@}
|
|
||||||
//@}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**@defgroup C++ wrappers for pthread mechanisms. */
|
/**@defgroup C++ wrappers for pthread mechanisms. */
|
||||||
//@{
|
//@{
|
||||||
|
|
||||||
/** A class for recursive mutexes based on pthread_mutex. */
|
/** A class for recursive mutexes. */
|
||||||
class Mutex {
|
class Mutex {
|
||||||
|
std::recursive_mutex m;
|
||||||
|
|
||||||
private:
|
public:
|
||||||
|
|
||||||
pthread_mutex_t mMutex;
|
void lock() {
|
||||||
pthread_mutexattr_t mAttribs;
|
m.lock();
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
bool trylock() {
|
||||||
|
return m.try_lock();
|
||||||
|
}
|
||||||
|
|
||||||
Mutex();
|
void unlock() {
|
||||||
|
m.unlock();
|
||||||
~Mutex();
|
}
|
||||||
|
|
||||||
void lock() { pthread_mutex_lock(&mMutex); }
|
|
||||||
|
|
||||||
bool trylock() { return pthread_mutex_trylock(&mMutex)==0; }
|
|
||||||
|
|
||||||
void unlock() { pthread_mutex_unlock(&mMutex); }
|
|
||||||
|
|
||||||
friend class Signal;
|
friend class Signal;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class ScopedLock {
|
class ScopedLock {
|
||||||
|
Mutex &mMutex;
|
||||||
|
|
||||||
private:
|
public:
|
||||||
Mutex& mMutex;
|
ScopedLock(Mutex &wMutex) : mMutex(wMutex) {
|
||||||
|
mMutex.lock();
|
||||||
public:
|
}
|
||||||
ScopedLock(Mutex& wMutex) :mMutex(wMutex) { mMutex.lock(); }
|
~ScopedLock() {
|
||||||
~ScopedLock() { mMutex.unlock(); }
|
mMutex.unlock();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** A C++ interthread signal. */
|
||||||
|
|
||||||
|
|
||||||
/** A C++ interthread signal based on pthread condition variables. */
|
|
||||||
class Signal {
|
class Signal {
|
||||||
|
/* any, because for some reason our mutex is recursive... */
|
||||||
|
std::condition_variable_any mSignal;
|
||||||
|
|
||||||
private:
|
public:
|
||||||
|
|
||||||
mutable pthread_cond_t mSignal;
|
void wait(Mutex &wMutex, unsigned timeout) {
|
||||||
|
mSignal.wait_for(wMutex.m, std::chrono::milliseconds(timeout));
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
void wait(Mutex &wMutex) {
|
||||||
|
mSignal.wait(wMutex.m);
|
||||||
|
}
|
||||||
|
|
||||||
Signal() { int s = pthread_cond_init(&mSignal,NULL); assert(!s); }
|
void signal() {
|
||||||
|
mSignal.notify_one();
|
||||||
~Signal() { pthread_cond_destroy(&mSignal); }
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
Block for the signal up to the cancellation timeout.
|
|
||||||
Under Linux, spurious returns are possible.
|
|
||||||
*/
|
|
||||||
void wait(Mutex& wMutex, unsigned timeout) const;
|
|
||||||
|
|
||||||
/**
|
|
||||||
Block for the signal.
|
|
||||||
Under Linux, spurious returns are possible.
|
|
||||||
*/
|
|
||||||
void wait(Mutex& wMutex) const
|
|
||||||
{ pthread_cond_wait(&mSignal,&wMutex.mMutex); }
|
|
||||||
|
|
||||||
void signal() { pthread_cond_signal(&mSignal); }
|
|
||||||
|
|
||||||
void broadcast() { pthread_cond_broadcast(&mSignal); }
|
|
||||||
|
|
||||||
|
void broadcast() {
|
||||||
|
mSignal.notify_all();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void set_selfthread_name(const char *name);
|
||||||
|
void thread_enable_cancel(bool cancel);
|
||||||
#define START_THREAD(thread,function,argument) \
|
|
||||||
thread.start((void *(*)(void*))function, (void*)argument);
|
|
||||||
|
|
||||||
/** A C++ wrapper for pthread threads. */
|
/** A C++ wrapper for pthread threads. */
|
||||||
class Thread {
|
class Thread {
|
||||||
|
private:
|
||||||
private:
|
|
||||||
|
|
||||||
pthread_t mThread;
|
pthread_t mThread;
|
||||||
pthread_attr_t mAttrib;
|
pthread_attr_t mAttrib;
|
||||||
// FIXME -- Can this be reduced now?
|
// FIXME -- Can this be reduced now?
|
||||||
size_t mStackSize;
|
size_t mStackSize;
|
||||||
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
|
public:
|
||||||
/** Create a thread in a non-running state. */
|
/** Create a thread in a non-running state. */
|
||||||
Thread(size_t wStackSize = (65536*4)):mThread((pthread_t)0) {
|
Thread(size_t wStackSize = 0) : mThread((pthread_t)0)
|
||||||
pthread_attr_init(&mAttrib); // (pat) moved this here.
|
{
|
||||||
mStackSize=wStackSize;
|
pthread_attr_init(&mAttrib); // (pat) moved this here.
|
||||||
|
mStackSize = wStackSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -165,26 +125,54 @@ class Thread {
|
|||||||
It should be stopped and joined.
|
It should be stopped and joined.
|
||||||
*/
|
*/
|
||||||
// (pat) If the Thread is destroyed without being started, then mAttrib is undefined. Oops.
|
// (pat) If the Thread is destroyed without being started, then mAttrib is undefined. Oops.
|
||||||
~Thread() { pthread_attr_destroy(&mAttrib); }
|
~Thread()
|
||||||
|
{
|
||||||
|
pthread_attr_destroy(&mAttrib);
|
||||||
|
}
|
||||||
|
|
||||||
/** Start the thread on a task. */
|
/** Start the thread on a task. */
|
||||||
void start(void *(*task)(void*), void *arg);
|
void start(void *(*task)(void *), void *arg);
|
||||||
|
|
||||||
/** Join a thread that will stop on its own. */
|
/** Join a thread that will stop on its own. */
|
||||||
void join() {
|
void join()
|
||||||
|
{
|
||||||
if (mThread) {
|
if (mThread) {
|
||||||
int s = pthread_join(mThread, NULL);
|
int s = pthread_join(mThread, NULL);
|
||||||
assert(!s);
|
assert(!s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Send cancelation to thread */
|
/** Send cancellation to thread */
|
||||||
void cancel() { pthread_cancel(mThread); }
|
void cancel()
|
||||||
|
{
|
||||||
|
pthread_cancel(mThread);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef HAVE_ATOMIC_OPS
|
||||||
|
#define osmo_trx_sync_fetch_and_and(ptr, value) __sync_fetch_and_and((ptr), (value))
|
||||||
|
#define osmo_trx_sync_or_and_fetch(ptr, value) __sync_or_and_fetch((ptr), (value))
|
||||||
|
#else
|
||||||
|
extern pthread_mutex_t atomic_ops_mutex;
|
||||||
|
static inline int osmo_trx_sync_fetch_and_and(int *ptr, int value)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&atomic_ops_mutex);
|
||||||
|
int tmp = *ptr;
|
||||||
|
*ptr &= value;
|
||||||
|
pthread_mutex_unlock(&atomic_ops_mutex);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int osmo_trx_sync_or_and_fetch(int *ptr, int value)
|
||||||
|
{
|
||||||
|
int tmp;
|
||||||
|
pthread_mutex_lock(&atomic_ops_mutex);
|
||||||
|
*ptr |= value;
|
||||||
|
tmp = *ptr;
|
||||||
|
pthread_mutex_unlock(&atomic_ops_mutex);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
// vim: ts=4 sw=4
|
// vim: ts=4 sw=4
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008 Free Software Foundation, Inc.
|
* Copyright 2008 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
*
|
*
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
* This software is distributed under the terms of the GNU Affero Public License.
|
||||||
* See the COPYING file in the main directory for details.
|
* See the COPYING file in the main directory for details.
|
||||||
@@ -27,43 +28,49 @@
|
|||||||
|
|
||||||
#include "Timeval.h"
|
#include "Timeval.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <osmocom/core/timer.h>
|
||||||
|
}
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
void Timeval::now()
|
||||||
|
{
|
||||||
|
osmo_clock_gettime(CLOCK_REALTIME, &mTimespec);
|
||||||
|
}
|
||||||
|
|
||||||
void Timeval::future(unsigned offset)
|
void Timeval::future(unsigned offset)
|
||||||
{
|
{
|
||||||
now();
|
now();
|
||||||
unsigned sec = offset/1000;
|
unsigned sec = offset/1000;
|
||||||
unsigned msec = offset%1000;
|
unsigned msec = offset%1000;
|
||||||
mTimeval.tv_usec += msec*1000;
|
mTimespec.tv_nsec += msec*1000*1000;
|
||||||
mTimeval.tv_sec += sec;
|
mTimespec.tv_sec += sec;
|
||||||
if (mTimeval.tv_usec>1000000) {
|
if (mTimespec.tv_nsec > 1000*1000*1000) {
|
||||||
mTimeval.tv_usec -= 1000000;
|
mTimespec.tv_nsec -= 1000*1000*1000;
|
||||||
mTimeval.tv_sec += 1;
|
mTimespec.tv_sec += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
struct timespec Timeval::timespec() const
|
struct timespec Timeval::timespec() const
|
||||||
{
|
{
|
||||||
struct timespec retVal;
|
return mTimespec;
|
||||||
retVal.tv_sec = mTimeval.tv_sec;
|
|
||||||
retVal.tv_nsec = 1000 * (long)mTimeval.tv_usec;
|
|
||||||
return retVal;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool Timeval::passed() const
|
bool Timeval::passed() const
|
||||||
{
|
{
|
||||||
Timeval nowTime;
|
Timeval nowTime;
|
||||||
if (nowTime.mTimeval.tv_sec < mTimeval.tv_sec) return false;
|
if (nowTime.mTimespec.tv_sec < mTimespec.tv_sec) return false;
|
||||||
if (nowTime.mTimeval.tv_sec > mTimeval.tv_sec) return true;
|
if (nowTime.mTimespec.tv_sec > mTimespec.tv_sec) return true;
|
||||||
if (nowTime.mTimeval.tv_usec > mTimeval.tv_usec) return true;
|
if (nowTime.mTimespec.tv_nsec >= mTimespec.tv_nsec) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
double Timeval::seconds() const
|
double Timeval::seconds() const
|
||||||
{
|
{
|
||||||
return ((double)mTimeval.tv_sec) + 1e-6*((double)mTimeval.tv_usec);
|
return ((double)mTimespec.tv_sec) + 1e-9*((double)mTimespec.tv_nsec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -72,24 +79,25 @@ long Timeval::delta(const Timeval& other) const
|
|||||||
{
|
{
|
||||||
// 2^31 milliseconds is just over 4 years.
|
// 2^31 milliseconds is just over 4 years.
|
||||||
int32_t deltaS = other.sec() - sec();
|
int32_t deltaS = other.sec() - sec();
|
||||||
int32_t deltaUs = other.usec() - usec();
|
int32_t deltaNs = other.nsec() - nsec();
|
||||||
return 1000*deltaS + deltaUs/1000;
|
return 1000*deltaS + deltaNs/1000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ostream& operator<<(ostream& os, const Timeval& tv)
|
ostream& operator<<(ostream& os, const Timeval& tv)
|
||||||
{
|
{
|
||||||
os.setf( ios::fixed, ios::floatfield );
|
ios_base::fmtflags flags_backup = os.setf( ios::fixed, ios::floatfield );
|
||||||
os << tv.seconds();
|
os << tv.seconds();
|
||||||
|
os.flags( flags_backup );
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ostream& operator<<(ostream& os, const struct timespec& ts)
|
ostream& operator<<(ostream& os, const struct timespec& ts)
|
||||||
{
|
{
|
||||||
os << ts.tv_sec << "," << ts.tv_nsec;
|
os << ts.tv_sec << "," << ts.tv_nsec/1000;
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008 Free Software Foundation, Inc.
|
* Copyright 2008 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
* This software is distributed under the terms of the GNU Affero Public License.
|
||||||
* See the COPYING file in the main directory for details.
|
* See the COPYING file in the main directory for details.
|
||||||
*
|
*
|
||||||
@@ -42,12 +44,12 @@ class Timeval {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
struct timeval mTimeval;
|
struct timespec mTimespec;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/** Set the value to gettimeofday. */
|
/** Set the value to current time. */
|
||||||
void now() { gettimeofday(&mTimeval,NULL); }
|
void now();
|
||||||
|
|
||||||
/** Set the value to gettimeofday plus an offset. */
|
/** Set the value to gettimeofday plus an offset. */
|
||||||
void future(unsigned ms);
|
void future(unsigned ms);
|
||||||
@@ -55,16 +57,18 @@ class Timeval {
|
|||||||
//@{
|
//@{
|
||||||
Timeval(unsigned sec, unsigned usec)
|
Timeval(unsigned sec, unsigned usec)
|
||||||
{
|
{
|
||||||
mTimeval.tv_sec = sec;
|
mTimespec.tv_sec = sec;
|
||||||
mTimeval.tv_usec = usec;
|
mTimespec.tv_nsec = usec*1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
Timeval(const struct timeval& wTimeval)
|
Timeval(const struct timeval& wTimeval)
|
||||||
:mTimeval(wTimeval)
|
{
|
||||||
{}
|
mTimespec.tv_sec = wTimeval.tv_sec;
|
||||||
|
mTimespec.tv_nsec = wTimeval.tv_sec*1000;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Create a Timeval offset into the future.
|
Create a Timespec offset into the future.
|
||||||
@param offset milliseconds
|
@param offset milliseconds
|
||||||
*/
|
*/
|
||||||
Timeval(unsigned offset=0) { future(offset); }
|
Timeval(unsigned offset=0) { future(offset); }
|
||||||
@@ -76,10 +80,11 @@ class Timeval {
|
|||||||
/** Return total seconds. */
|
/** Return total seconds. */
|
||||||
double seconds() const;
|
double seconds() const;
|
||||||
|
|
||||||
uint32_t sec() const { return mTimeval.tv_sec; }
|
uint32_t sec() const { return mTimespec.tv_sec; }
|
||||||
uint32_t usec() const { return mTimeval.tv_usec; }
|
uint32_t usec() const { return mTimespec.tv_nsec / 1000; }
|
||||||
|
uint32_t nsec() const { return mTimespec.tv_nsec; }
|
||||||
|
|
||||||
/** Return differnce from other (other-self), in ms. */
|
/** Return difference from other (other-self), in ms. */
|
||||||
long delta(const Timeval& other) const;
|
long delta(const Timeval& other) const;
|
||||||
|
|
||||||
/** Elapsed time in ms. */
|
/** Elapsed time in ms. */
|
||||||
@@ -88,11 +93,11 @@ class Timeval {
|
|||||||
/** Remaining time in ms. */
|
/** Remaining time in ms. */
|
||||||
long remaining() const { return -elapsed(); }
|
long remaining() const { return -elapsed(); }
|
||||||
|
|
||||||
/** Return true if the time has passed, as per gettimeofday. */
|
/** Return true if the time has passed, as per clock_gettime(CLOCK_REALTIME). */
|
||||||
bool passed() const;
|
bool passed() const;
|
||||||
|
|
||||||
/** Add a given number of minutes to the time. */
|
/** Add a given number of minutes to the time. */
|
||||||
void addMinutes(unsigned minutes) { mTimeval.tv_sec += minutes*60; }
|
void addMinutes(unsigned minutes) { mTimespec.tv_sec += minutes*60; }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2008 Free Software Foundation, Inc.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
|
||||||
* See the COPYING file in the main directory for details.
|
|
||||||
*
|
|
||||||
* This use of this software may be subject to additional restrictions.
|
|
||||||
* See the LEGAL file in the main directory for details.
|
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Affero General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#include "Timeval.h"
|
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
|
|
||||||
Timeval then(10000);
|
|
||||||
cout << then.elapsed() << endl;
|
|
||||||
|
|
||||||
while (!then.passed()) {
|
|
||||||
cout << "now: " << Timeval() << " then: " << then << " remaining: " << then.remaining() << endl;
|
|
||||||
usleep(500000);
|
|
||||||
}
|
|
||||||
cout << "now: " << Timeval() << " then: " << then << " remaining: " << then.remaining() << endl;
|
|
||||||
}
|
|
||||||
34
CommonLibs/Utils.cpp
Normal file
34
CommonLibs/Utils.cpp
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 sysmocom - s.f.m.c. GmbH
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
|
std::vector<std::string> comma_delimited_to_vector(const char* opt)
|
||||||
|
{
|
||||||
|
std::string str = std::string(opt);
|
||||||
|
std::vector<std::string> result;
|
||||||
|
std::stringstream ss(str);
|
||||||
|
|
||||||
|
while( ss.good() )
|
||||||
|
{
|
||||||
|
std::string substr;
|
||||||
|
getline(ss, substr, ',');
|
||||||
|
result.push_back(substr);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
22
CommonLibs/Utils.h
Normal file
22
CommonLibs/Utils.h
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2018 sysmocom - s.f.m.c. GmbH
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*
|
||||||
|
* This library is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
|
* License as published by the Free Software Foundation; either
|
||||||
|
* version 2.1 of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This library is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
* Lesser General Public License for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
std::vector<std::string> comma_delimited_to_vector(const char* opt);
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008 Free Software Foundation, Inc.
|
* Copyright 2008 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
* This software is distributed under the terms of the GNU Affero Public License.
|
||||||
* See the COPYING file in the main directory for details.
|
* See the COPYING file in the main directory for details.
|
||||||
*
|
*
|
||||||
@@ -32,11 +34,19 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
// We cant use Logger.h in this file...
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#ifndef __OPTIMIZE__
|
||||||
|
#define assert_no_opt(x) assert(x)
|
||||||
|
#else
|
||||||
|
#define assert_no_opt(x)
|
||||||
|
#endif
|
||||||
|
// We can't use Logger.h in this file...
|
||||||
extern int gVectorDebug;
|
extern int gVectorDebug;
|
||||||
#define BVDEBUG(msg) if (gVectorDebug) {std::cout << msg;}
|
#define BVDEBUG(msg) if (gVectorDebug) {std::cout << msg;}
|
||||||
|
|
||||||
|
typedef void (*vector_free_func)(void* wData);
|
||||||
|
typedef void *(*vector_alloc_func)(size_t newSize);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
A simplified Vector template with aliases.
|
A simplified Vector template with aliases.
|
||||||
@@ -60,6 +70,8 @@ template <class T> class Vector {
|
|||||||
T* mData; ///< allocated data block, if any
|
T* mData; ///< allocated data block, if any
|
||||||
T* mStart; ///< start of useful data
|
T* mStart; ///< start of useful data
|
||||||
T* mEnd; ///< end of useful data + 1
|
T* mEnd; ///< end of useful data + 1
|
||||||
|
vector_alloc_func mAllocFunc; ///< function used to alloc new mData during resize.
|
||||||
|
vector_free_func mFreeFunc; ///< function used to free mData.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -74,8 +86,8 @@ template <class T> class Vector {
|
|||||||
/** Return the size of the Vector. */
|
/** Return the size of the Vector. */
|
||||||
size_t size() const
|
size_t size() const
|
||||||
{
|
{
|
||||||
assert(mStart>=mData);
|
assert_no_opt(mStart>=mData);
|
||||||
assert(mEnd>=mStart);
|
assert_no_opt(mEnd>=mStart);
|
||||||
return mEnd - mStart;
|
return mEnd - mStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -85,9 +97,19 @@ template <class T> class Vector {
|
|||||||
/** Change the size of the Vector, discarding content. */
|
/** Change the size of the Vector, discarding content. */
|
||||||
void resize(size_t newSize)
|
void resize(size_t newSize)
|
||||||
{
|
{
|
||||||
if (mData!=NULL) delete[] mData;
|
if (mData!=NULL) {
|
||||||
|
if (mFreeFunc)
|
||||||
|
mFreeFunc(mData);
|
||||||
|
else
|
||||||
|
delete[] mData;
|
||||||
|
}
|
||||||
if (newSize==0) mData=NULL;
|
if (newSize==0) mData=NULL;
|
||||||
else mData = new T[newSize];
|
else {
|
||||||
|
if (mAllocFunc)
|
||||||
|
mData = (T*) mAllocFunc(newSize);
|
||||||
|
else
|
||||||
|
mData = new T[newSize];
|
||||||
|
}
|
||||||
mStart = mData;
|
mStart = mData;
|
||||||
mEnd = mStart + newSize;
|
mEnd = mStart + newSize;
|
||||||
}
|
}
|
||||||
@@ -95,7 +117,7 @@ template <class T> class Vector {
|
|||||||
/** Reduce addressable size of the Vector, keeping content. */
|
/** Reduce addressable size of the Vector, keeping content. */
|
||||||
void shrink(size_t newSize)
|
void shrink(size_t newSize)
|
||||||
{
|
{
|
||||||
assert(newSize <= mEnd - mStart);
|
assert_no_opt(newSize <= mEnd - mStart);
|
||||||
mEnd = mStart + newSize;
|
mEnd = mStart + newSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +129,7 @@ template <class T> class Vector {
|
|||||||
void clone(const Vector<T>& other)
|
void clone(const Vector<T>& other)
|
||||||
{
|
{
|
||||||
resize(other.size());
|
resize(other.size());
|
||||||
memcpy(mData,other.mStart,other.bytes());
|
other.copyTo(*this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -116,29 +138,31 @@ template <class T> class Vector {
|
|||||||
//@{
|
//@{
|
||||||
|
|
||||||
/** Build an empty Vector of a given size. */
|
/** Build an empty Vector of a given size. */
|
||||||
Vector(size_t wSize=0):mData(NULL) { resize(wSize); }
|
Vector(size_t wSize=0, vector_alloc_func wAllocFunc=NULL, vector_free_func wFreeFunc=NULL)
|
||||||
|
:mData(NULL), mAllocFunc(wAllocFunc), mFreeFunc(wFreeFunc)
|
||||||
|
{ resize(wSize); }
|
||||||
|
|
||||||
/** Build a Vector by shifting the data block. */
|
/** Build a Vector by moving another. */
|
||||||
Vector(Vector<T>& other)
|
Vector(Vector<T>&& other)
|
||||||
:mData(other.mData),mStart(other.mStart),mEnd(other.mEnd)
|
:mData(other.mData),mStart(other.mStart),mEnd(other.mEnd), mAllocFunc(other.mAllocFunc), mFreeFunc(other.mFreeFunc)
|
||||||
{ other.mData=NULL; }
|
{ other.mData=NULL; }
|
||||||
|
|
||||||
/** Build a Vector by copying another. */
|
/** Build a Vector by copying another. */
|
||||||
Vector(const Vector<T>& other):mData(NULL) { clone(other); }
|
Vector(const Vector<T>& other):mData(NULL), mAllocFunc(other.mAllocFunc), mFreeFunc(other.mFreeFunc) { clone(other); }
|
||||||
|
|
||||||
/** Build a Vector with explicit values. */
|
/** Build a Vector with explicit values. */
|
||||||
Vector(T* wData, T* wStart, T* wEnd)
|
Vector(T* wData, T* wStart, T* wEnd, vector_alloc_func wAllocFunc=NULL, vector_free_func wFreeFunc=NULL)
|
||||||
:mData(wData),mStart(wStart),mEnd(wEnd)
|
:mData(wData),mStart(wStart),mEnd(wEnd), mAllocFunc(wAllocFunc), mFreeFunc(wFreeFunc)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/** Build a vector from an existing block, NOT to be deleted upon destruction. */
|
/** Build a vector from an existing block, NOT to be deleted upon destruction. */
|
||||||
Vector(T* wStart, size_t span)
|
Vector(T* wStart, size_t span, vector_alloc_func wAllocFunc=NULL, vector_free_func wFreeFunc=NULL)
|
||||||
:mData(NULL),mStart(wStart),mEnd(wStart+span)
|
:mData(NULL),mStart(wStart),mEnd(wStart+span),mAllocFunc(wAllocFunc), mFreeFunc(wFreeFunc)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/** Build a Vector by concatenation. */
|
/** Build a Vector by concatenation. */
|
||||||
Vector(const Vector<T>& other1, const Vector<T>& other2)
|
Vector(const Vector<T>& other1, const Vector<T>& other2, vector_alloc_func wAllocFunc=NULL, vector_free_func wFreeFunc=NULL)
|
||||||
:mData(NULL)
|
:mData(NULL), mAllocFunc(wAllocFunc), mFreeFunc(wFreeFunc)
|
||||||
{
|
{
|
||||||
resize(other1.size()+other2.size());
|
resize(other1.size()+other2.size());
|
||||||
memcpy(mStart, other1.mStart, other1.bytes());
|
memcpy(mStart, other1.mStart, other1.bytes());
|
||||||
@@ -162,6 +186,8 @@ template <class T> class Vector {
|
|||||||
mData=other.mData;
|
mData=other.mData;
|
||||||
mStart=other.mStart;
|
mStart=other.mStart;
|
||||||
mEnd=other.mEnd;
|
mEnd=other.mEnd;
|
||||||
|
mAllocFunc=other.mAllocFunc;
|
||||||
|
mFreeFunc=other.mFreeFunc;
|
||||||
other.mData=NULL;
|
other.mData=NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +204,7 @@ template <class T> class Vector {
|
|||||||
{
|
{
|
||||||
T* wStart = mStart + start;
|
T* wStart = mStart + start;
|
||||||
T* wEnd = wStart + span;
|
T* wEnd = wStart + span;
|
||||||
assert(wEnd<=mEnd);
|
assert_no_opt(wEnd<=mEnd);
|
||||||
return Vector<T>(NULL,wStart,wEnd);
|
return Vector<T>(NULL,wStart,wEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,7 +213,7 @@ template <class T> class Vector {
|
|||||||
{
|
{
|
||||||
T* wStart = mStart + start;
|
T* wStart = mStart + start;
|
||||||
T* wEnd = wStart + span;
|
T* wEnd = wStart + span;
|
||||||
assert(wEnd<=mEnd);
|
assert_no_opt(wEnd<=mEnd);
|
||||||
return Vector<T>(NULL,wStart,wEnd);
|
return Vector<T>(NULL,wStart,wEnd);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -204,10 +230,15 @@ template <class T> class Vector {
|
|||||||
*/
|
*/
|
||||||
void copyToSegment(Vector<T>& other, size_t start, size_t span) const
|
void copyToSegment(Vector<T>& other, size_t start, size_t span) const
|
||||||
{
|
{
|
||||||
T* base = other.mStart + start;
|
unsigned int i;
|
||||||
assert(base+span<=other.mEnd);
|
T* dst = other.mStart + start;
|
||||||
assert(mStart+span<=mEnd);
|
T* src = mStart;
|
||||||
memcpy(base,mStart,span*sizeof(T));
|
assert_no_opt(dst+span<=other.mEnd);
|
||||||
|
assert_no_opt(mStart+span<=mEnd);
|
||||||
|
for (i = 0; i < span; i++, src++, dst++)
|
||||||
|
*dst = *src;
|
||||||
|
/*TODO if not non-trivially copiable type class, optimize:
|
||||||
|
memcpy(dst,mStart,span*sizeof(T)); */
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Copy all of this Vector to a segment of another Vector. */
|
/** Copy all of this Vector to a segment of another Vector. */
|
||||||
@@ -224,8 +255,8 @@ template <class T> class Vector {
|
|||||||
void segmentCopyTo(Vector<T>& other, size_t start, size_t span) const
|
void segmentCopyTo(Vector<T>& other, size_t start, size_t span) const
|
||||||
{
|
{
|
||||||
const T* base = mStart + start;
|
const T* base = mStart + start;
|
||||||
assert(base+span<=mEnd);
|
assert_no_opt(base+span<=mEnd);
|
||||||
assert(other.mStart+span<=other.mEnd);
|
assert_no_opt(other.mStart+span<=other.mEnd);
|
||||||
memcpy(other.mStart,base,span*sizeof(T));
|
memcpy(other.mStart,base,span*sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,8 +270,8 @@ template <class T> class Vector {
|
|||||||
{
|
{
|
||||||
const T* baseFrom = mStart + from;
|
const T* baseFrom = mStart + from;
|
||||||
T* baseTo = mStart + to;
|
T* baseTo = mStart + to;
|
||||||
assert(baseFrom+span<=mEnd);
|
assert_no_opt(baseFrom+span<=mEnd);
|
||||||
assert(baseTo+span<=mEnd);
|
assert_no_opt(baseTo+span<=mEnd);
|
||||||
memmove(baseTo,baseFrom,span*sizeof(T));
|
memmove(baseTo,baseFrom,span*sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +285,7 @@ template <class T> class Vector {
|
|||||||
{
|
{
|
||||||
T* dp=mStart+start;
|
T* dp=mStart+start;
|
||||||
T* end=dp+length;
|
T* end=dp+length;
|
||||||
assert(end<=mEnd);
|
assert_no_opt(end<=mEnd);
|
||||||
while (dp<end) *dp++=val;
|
while (dp<end) *dp++=val;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,13 +297,13 @@ template <class T> class Vector {
|
|||||||
|
|
||||||
T& operator[](size_t index)
|
T& operator[](size_t index)
|
||||||
{
|
{
|
||||||
assert(mStart+index<mEnd);
|
assert_no_opt(mStart+index<mEnd);
|
||||||
return mStart[index];
|
return mStart[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
const T& operator[](size_t index) const
|
const T& operator[](size_t index) const
|
||||||
{
|
{
|
||||||
assert(mStart+index<mEnd);
|
assert_no_opt(mStart+index<mEnd);
|
||||||
return mStart[index];
|
return mStart[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,7 +313,7 @@ template <class T> class Vector {
|
|||||||
T* end() { return mEnd; }
|
T* end() { return mEnd; }
|
||||||
bool isOwner() { return !!mData; } // Do we own any memory ourselves?
|
bool isOwner() { return !!mData; } // Do we own any memory ourselves?
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
71
CommonLibs/config_defs.h
Normal file
71
CommonLibs/config_defs.h
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This file contains structures used by both VTY (C, dir CommonLibs) and
|
||||||
|
* osmo-trx (CXX, dir Transceiver52)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
enum FillerType {
|
||||||
|
FILLER_DUMMY,
|
||||||
|
FILLER_ZERO,
|
||||||
|
FILLER_NORM_RAND,
|
||||||
|
FILLER_EDGE_RAND,
|
||||||
|
FILLER_ACCESS_RAND,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ReferenceType {
|
||||||
|
REF_INTERNAL,
|
||||||
|
REF_EXTERNAL,
|
||||||
|
REF_GPS,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Maximum number of physical RF channels */
|
||||||
|
#define TRX_CHAN_MAX 8
|
||||||
|
|
||||||
|
struct trx_ctx;
|
||||||
|
|
||||||
|
struct trx_chan {
|
||||||
|
struct trx_ctx *trx; /* backpointer */
|
||||||
|
unsigned int idx; /* channel index */
|
||||||
|
char *rx_path;
|
||||||
|
char *tx_path;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct trx_cfg {
|
||||||
|
char *bind_addr;
|
||||||
|
char *remote_addr;
|
||||||
|
char *dev_args;
|
||||||
|
unsigned int base_port;
|
||||||
|
unsigned int tx_sps;
|
||||||
|
unsigned int rx_sps;
|
||||||
|
unsigned int rtsc;
|
||||||
|
unsigned int rach_delay;
|
||||||
|
enum ReferenceType clock_ref;
|
||||||
|
enum FillerType filler;
|
||||||
|
bool multi_arfcn;
|
||||||
|
double offset;
|
||||||
|
double freq_offset_khz;
|
||||||
|
double rssi_offset;
|
||||||
|
int ul_fn_offset;
|
||||||
|
bool force_rssi_offset; /* Force value set in VTY? */
|
||||||
|
bool swap_channels;
|
||||||
|
bool ext_rach;
|
||||||
|
bool egprs;
|
||||||
|
unsigned int sched_rr;
|
||||||
|
unsigned int stack_size;
|
||||||
|
unsigned int num_chans;
|
||||||
|
struct trx_chan chans[TRX_CHAN_MAX];
|
||||||
|
struct {
|
||||||
|
bool ul_freq_override;
|
||||||
|
bool dl_freq_override;
|
||||||
|
bool ul_gain_override;
|
||||||
|
bool dl_gain_override;
|
||||||
|
double ul_freq;
|
||||||
|
double dl_freq;
|
||||||
|
double ul_gain;
|
||||||
|
double dl_gain;
|
||||||
|
} overrides;
|
||||||
|
bool use_va;
|
||||||
|
};
|
||||||
83
CommonLibs/debug.c
Normal file
83
CommonLibs/debug.c
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018-2019 sysmocom - s.f.m.c. GmbH
|
||||||
|
* All Rights Reserved
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
|
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* See the COPYING file in the main directory for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <osmocom/core/logging.h>
|
||||||
|
#include <osmocom/core/utils.h>
|
||||||
|
#include "debug.h"
|
||||||
|
|
||||||
|
/* default categories */
|
||||||
|
static const struct log_info_cat default_categories[] = {
|
||||||
|
[DMAIN] = {
|
||||||
|
.name = "DMAIN",
|
||||||
|
.description = "Main generic category",
|
||||||
|
.color = NULL,
|
||||||
|
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||||
|
},
|
||||||
|
[DTRXCLK] = {
|
||||||
|
.name = "DTRXCLK",
|
||||||
|
.description = "TRX Master Clock",
|
||||||
|
.color = NULL,
|
||||||
|
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||||
|
},
|
||||||
|
[DTRXCTRL] = {
|
||||||
|
.name = "DTRXCTRL",
|
||||||
|
.description = "TRX CTRL interface",
|
||||||
|
.color = "\033[1;33m",
|
||||||
|
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||||
|
},
|
||||||
|
[DTRXDDL] = {
|
||||||
|
.name = "DTRXDDL",
|
||||||
|
.description = "TRX Data interface Downlink",
|
||||||
|
.color = NULL,
|
||||||
|
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||||
|
},
|
||||||
|
[DTRXDUL] = {
|
||||||
|
.name = "DTRXDUL",
|
||||||
|
.description = "TRX CTRL interface Uplink",
|
||||||
|
.color = NULL,
|
||||||
|
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||||
|
},
|
||||||
|
[DDEV] = {
|
||||||
|
.name = "DDEV",
|
||||||
|
.description = "Device/Driver specific code",
|
||||||
|
.color = NULL,
|
||||||
|
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||||
|
},
|
||||||
|
[DDEVDRV] = {
|
||||||
|
.name = "DDEVDRV",
|
||||||
|
.description = "Logging from external device driver library implementing lower level specifics",
|
||||||
|
.color = NULL,
|
||||||
|
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||||
|
},
|
||||||
|
[DCTR] = {
|
||||||
|
.name = "DCTR",
|
||||||
|
.description = "Rate counter related logging",
|
||||||
|
.color = NULL,
|
||||||
|
.enabled = 1, .loglevel = LOGL_NOTICE,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct log_info log_info = {
|
||||||
|
.cat = default_categories,
|
||||||
|
.num_cat = ARRAY_SIZE(default_categories),
|
||||||
|
};
|
||||||
23
CommonLibs/debug.h
Normal file
23
CommonLibs/debug.h
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include <osmocom/core/logging.h>
|
||||||
|
|
||||||
|
extern const struct log_info log_info;
|
||||||
|
|
||||||
|
/* Debug Areas of the code */
|
||||||
|
enum {
|
||||||
|
DMAIN,
|
||||||
|
DTRXCLK,
|
||||||
|
DTRXCTRL,
|
||||||
|
DTRXDDL,
|
||||||
|
DTRXDUL,
|
||||||
|
DDEV,
|
||||||
|
DDEVDRV,
|
||||||
|
DCTR,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CLOGCHAN(chan, category, level, fmt, args...) do { \
|
||||||
|
LOGP(category, level, "[chan=%zu] " fmt, chan, ##args); \
|
||||||
|
} while(0)
|
||||||
71
CommonLibs/osmo_signal.h
Normal file
71
CommonLibs/osmo_signal.h
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
/* Generic signalling/notification infrastructure */
|
||||||
|
/* (C) 2018 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||||
|
*
|
||||||
|
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||||
|
*
|
||||||
|
* All Rights Reserved
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <osmocom/core/signal.h>
|
||||||
|
|
||||||
|
/* Signalling subsystems */
|
||||||
|
enum signal_subsystems {
|
||||||
|
SS_MAIN,
|
||||||
|
SS_DEVICE,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SS_MAIN signals */
|
||||||
|
enum SS_MAIN {
|
||||||
|
S_MAIN_STOP_REQUIRED, /* TRX fatal error, it should be stopped */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* SS_DEVICE signals */
|
||||||
|
enum SS_DEVICE {
|
||||||
|
/* Device internal counters changed. Counters are provided as cb data
|
||||||
|
(struct device_counters). Must be sent with PTHREAD_CANCEL_DISABLE
|
||||||
|
to avoid deadlocks in case osmo-trx process is asked to exit. */
|
||||||
|
S_DEVICE_COUNTER_CHANGE,
|
||||||
|
S_TRX_COUNTER_CHANGE, /* same, but for Transceiver class */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* signal cb for signal <SS_DEVICE,S_DEVICE_COUNTER_CHANGE> */
|
||||||
|
struct device_counters {
|
||||||
|
size_t chan;
|
||||||
|
unsigned int rx_overruns;
|
||||||
|
unsigned int tx_underruns;
|
||||||
|
unsigned int rx_dropped_events;
|
||||||
|
unsigned int rx_dropped_samples;
|
||||||
|
unsigned int tx_dropped_events;
|
||||||
|
unsigned int tx_dropped_samples;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* signal cb for signal <SS_DEVICE,S_TRX_COUNTER_CHANGE> */
|
||||||
|
struct trx_counters {
|
||||||
|
size_t chan;
|
||||||
|
unsigned int tx_stale_bursts;
|
||||||
|
unsigned int tx_unavailable_bursts;
|
||||||
|
unsigned int tx_trxd_fn_repeated;
|
||||||
|
unsigned int tx_trxd_fn_outoforder;
|
||||||
|
unsigned int tx_trxd_fn_skipped;
|
||||||
|
unsigned int rx_empty_burst;
|
||||||
|
unsigned int rx_clipping;
|
||||||
|
unsigned int rx_no_burst_detected;
|
||||||
|
};
|
||||||
@@ -1,154 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010 Kestrel Signal Processing, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#include <sqlite3.h>
|
|
||||||
#include "sqlite3util.h"
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
|
|
||||||
// Wrappers to sqlite operations.
|
|
||||||
// These will eventually get moved to commonlibs.
|
|
||||||
|
|
||||||
int sqlite3_prepare_statement(sqlite3* DB, sqlite3_stmt **stmt, const char* query)
|
|
||||||
{
|
|
||||||
int src = SQLITE_BUSY;
|
|
||||||
while (src==SQLITE_BUSY) {
|
|
||||||
src = sqlite3_prepare_v2(DB,query,strlen(query),stmt,NULL);
|
|
||||||
if (src==SQLITE_BUSY) {
|
|
||||||
usleep(100000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (src) {
|
|
||||||
fprintf(stderr,"sqlite3_prepare_v2 failed for \"%s\": %s\n",query,sqlite3_errmsg(DB));
|
|
||||||
sqlite3_finalize(*stmt);
|
|
||||||
}
|
|
||||||
return src;
|
|
||||||
}
|
|
||||||
|
|
||||||
int sqlite3_run_query(sqlite3* DB, sqlite3_stmt *stmt)
|
|
||||||
{
|
|
||||||
int src = SQLITE_BUSY;
|
|
||||||
while (src==SQLITE_BUSY) {
|
|
||||||
src = sqlite3_step(stmt);
|
|
||||||
if (src==SQLITE_BUSY) {
|
|
||||||
usleep(100000);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((src!=SQLITE_DONE) && (src!=SQLITE_ROW)) {
|
|
||||||
fprintf(stderr,"sqlite3_run_query failed: %s: %s\n", sqlite3_sql(stmt), sqlite3_errmsg(DB));
|
|
||||||
}
|
|
||||||
return src;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool sqlite3_exists(sqlite3* DB, const char *tableName,
|
|
||||||
const char* keyName, const char* keyData)
|
|
||||||
{
|
|
||||||
size_t stringSize = 100 + strlen(tableName) + strlen(keyName) + strlen(keyData);
|
|
||||||
char query[stringSize];
|
|
||||||
sprintf(query,"SELECT * FROM %s WHERE %s == \"%s\"",tableName,keyName,keyData);
|
|
||||||
// Prepare the statement.
|
|
||||||
sqlite3_stmt *stmt;
|
|
||||||
if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
|
|
||||||
// Read the result.
|
|
||||||
int src = sqlite3_run_query(DB,stmt);
|
|
||||||
sqlite3_finalize(stmt);
|
|
||||||
// Anything there?
|
|
||||||
return (src == SQLITE_ROW);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool sqlite3_single_lookup(sqlite3* DB, const char *tableName,
|
|
||||||
const char* keyName, const char* keyData,
|
|
||||||
const char* valueName, unsigned &valueData)
|
|
||||||
{
|
|
||||||
size_t stringSize = 100 + strlen(valueName) + strlen(tableName) + strlen(keyName) + strlen(keyData);
|
|
||||||
char query[stringSize];
|
|
||||||
sprintf(query,"SELECT %s FROM %s WHERE %s == \"%s\"",valueName,tableName,keyName,keyData);
|
|
||||||
// Prepare the statement.
|
|
||||||
sqlite3_stmt *stmt;
|
|
||||||
if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
|
|
||||||
// Read the result.
|
|
||||||
int src = sqlite3_run_query(DB,stmt);
|
|
||||||
bool retVal = false;
|
|
||||||
if (src == SQLITE_ROW) {
|
|
||||||
valueData = (unsigned)sqlite3_column_int64(stmt,0);
|
|
||||||
retVal = true;
|
|
||||||
}
|
|
||||||
sqlite3_finalize(stmt);
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// This function returns an allocated string that must be free'd by the caller.
|
|
||||||
bool sqlite3_single_lookup(sqlite3* DB, const char* tableName,
|
|
||||||
const char* keyName, const char* keyData,
|
|
||||||
const char* valueName, char* &valueData)
|
|
||||||
{
|
|
||||||
valueData=NULL;
|
|
||||||
size_t stringSize = 100 + strlen(valueName) + strlen(tableName) + strlen(keyName) + strlen(keyData);
|
|
||||||
char query[stringSize];
|
|
||||||
sprintf(query,"SELECT %s FROM %s WHERE %s == \"%s\"",valueName,tableName,keyName,keyData);
|
|
||||||
// Prepare the statement.
|
|
||||||
sqlite3_stmt *stmt;
|
|
||||||
if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
|
|
||||||
// Read the result.
|
|
||||||
int src = sqlite3_run_query(DB,stmt);
|
|
||||||
bool retVal = false;
|
|
||||||
if (src == SQLITE_ROW) {
|
|
||||||
const char* ptr = (const char*)sqlite3_column_text(stmt,0);
|
|
||||||
if (ptr) valueData = strdup(ptr);
|
|
||||||
retVal = true;
|
|
||||||
}
|
|
||||||
sqlite3_finalize(stmt);
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// This function returns an allocated string that must be free'd by tha caller.
|
|
||||||
bool sqlite3_single_lookup(sqlite3* DB, const char* tableName,
|
|
||||||
const char* keyName, unsigned keyData,
|
|
||||||
const char* valueName, char* &valueData)
|
|
||||||
{
|
|
||||||
valueData=NULL;
|
|
||||||
size_t stringSize = 100 + strlen(valueName) + strlen(tableName) + strlen(keyName) + 20;
|
|
||||||
char query[stringSize];
|
|
||||||
sprintf(query,"SELECT %s FROM %s WHERE %s == %u",valueName,tableName,keyName,keyData);
|
|
||||||
// Prepare the statement.
|
|
||||||
sqlite3_stmt *stmt;
|
|
||||||
if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
|
|
||||||
// Read the result.
|
|
||||||
int src = sqlite3_run_query(DB,stmt);
|
|
||||||
bool retVal = false;
|
|
||||||
if (src == SQLITE_ROW) {
|
|
||||||
const char* ptr = (const char*)sqlite3_column_text(stmt,0);
|
|
||||||
if (ptr) valueData = strdup(ptr);
|
|
||||||
retVal = true;
|
|
||||||
}
|
|
||||||
sqlite3_finalize(stmt);
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool sqlite3_command(sqlite3* DB, const char* query)
|
|
||||||
{
|
|
||||||
// Prepare the statement.
|
|
||||||
sqlite3_stmt *stmt;
|
|
||||||
if (sqlite3_prepare_statement(DB,&stmt,query)) return false;
|
|
||||||
// Run the query.
|
|
||||||
int src = sqlite3_run_query(DB,stmt);
|
|
||||||
sqlite3_finalize(stmt);
|
|
||||||
return src==SQLITE_DONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
#ifndef SQLITE3UTIL_H
|
|
||||||
#define SQLITE3UTIL_H
|
|
||||||
|
|
||||||
#include <sqlite3.h>
|
|
||||||
|
|
||||||
int sqlite3_prepare_statement(sqlite3* DB, sqlite3_stmt **stmt, const char* query);
|
|
||||||
|
|
||||||
int sqlite3_run_query(sqlite3* DB, sqlite3_stmt *stmt);
|
|
||||||
|
|
||||||
bool sqlite3_single_lookup(sqlite3* DB, const char *tableName,
|
|
||||||
const char* keyName, const char* keyData,
|
|
||||||
const char* valueName, unsigned &valueData);
|
|
||||||
|
|
||||||
bool sqlite3_single_lookup(sqlite3* DB, const char* tableName,
|
|
||||||
const char* keyName, const char* keyData,
|
|
||||||
const char* valueName, char* &valueData);
|
|
||||||
|
|
||||||
// This function returns an allocated string that must be free'd by the caller.
|
|
||||||
bool sqlite3_single_lookup(sqlite3* DB, const char* tableName,
|
|
||||||
const char* keyName, unsigned keyData,
|
|
||||||
const char* valueName, char* &valueData);
|
|
||||||
|
|
||||||
bool sqlite3_exists(sqlite3* DB, const char* tableName,
|
|
||||||
const char* keyName, const char* keyData);
|
|
||||||
|
|
||||||
/** Run a query, ignoring the result; return true on success. */
|
|
||||||
bool sqlite3_command(sqlite3* DB, const char* query);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
409
CommonLibs/trx_rate_ctr.cpp
Normal file
409
CommonLibs/trx_rate_ctr.cpp
Normal file
@@ -0,0 +1,409 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 sysmocom - s.f.m.c. GmbH
|
||||||
|
* All Rights Reserved
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
|
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* See the COPYING file in the main directory for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* rate_ctr API uses several osmocom select loop features, and as a result,
|
||||||
|
* calls to it must be done through the main thread (the one running the osmocom
|
||||||
|
* loop in osmo-trx).
|
||||||
|
* Since read/write from/to SDR is done in separate threads (even read and write
|
||||||
|
* each use a different thread), we must use some sort of message passing system
|
||||||
|
* between main thread feeding rate_ctr structures and the Rx/Tx threads
|
||||||
|
* generating the events.
|
||||||
|
* The idea is that upon read/write issues, lower layers (SDR APIs) provide us with
|
||||||
|
* underrun/overrun/droppedPackets information, and in that case we pass that up
|
||||||
|
* the stack through signal <SS_DEVICE,S_DEVICE_COUNTER_CHANGE> with signal_cb
|
||||||
|
* being a pointer to a "struct device_counters" structure, which contains
|
||||||
|
* device (implementation agnostic) statful counters for different kind of
|
||||||
|
* statistics.
|
||||||
|
* That signal is processed here in device_sig_cb, where a copy of the "struct
|
||||||
|
* device_counters" structure is held and the main thread is instructed through
|
||||||
|
* a timerfd to update rate_ctr APIs against this copy. All this is done inside
|
||||||
|
* a mutex to avoid different race conditions (between Rx andTx threads, and
|
||||||
|
* between Rx/Tx and main thread). For the same reason, callers of signal
|
||||||
|
* <SS_DEVICE,S_DEVICE_COUNTER_CHANGE> (device_sig_cb), that is Rx/Tx threads,
|
||||||
|
* must do so with PTHREAD_CANCEL_DISABLE, in order to avoid possible deadlocks
|
||||||
|
* in case the main thread decides to cancel other threads due to a shutdown
|
||||||
|
* operation (fi SIGKILL received)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <osmocom/core/talloc.h>
|
||||||
|
#include <osmocom/core/utils.h>
|
||||||
|
#include <osmocom/core/rate_ctr.h>
|
||||||
|
#include <osmocom/core/select.h>
|
||||||
|
#include <osmocom/core/stats.h>
|
||||||
|
#include <osmocom/core/timer.h>
|
||||||
|
|
||||||
|
#include "osmo_signal.h"
|
||||||
|
#include "trx_vty.h"
|
||||||
|
#include "trx_rate_ctr.h"
|
||||||
|
}
|
||||||
|
#include "Threads.h"
|
||||||
|
#include "Logger.h"
|
||||||
|
|
||||||
|
/* Used in dev_ctrs_pending, when set it means that channel slot contains unused
|
||||||
|
(non-pending) counter data */
|
||||||
|
#define PENDING_CHAN_NONE SIZE_MAX
|
||||||
|
|
||||||
|
static void *trx_rate_ctr_ctx;
|
||||||
|
|
||||||
|
static struct rate_ctr_group** rate_ctrs;
|
||||||
|
static struct device_counters* dev_ctrs_pending;
|
||||||
|
static struct trx_counters* trx_ctrs_pending;
|
||||||
|
static size_t chan_len;
|
||||||
|
static struct osmo_fd dev_rate_ctr_timerfd;
|
||||||
|
static struct osmo_fd trx_rate_ctr_timerfd;
|
||||||
|
static Mutex dev_rate_ctr_mutex;
|
||||||
|
static Mutex trx_rate_ctr_mutex;
|
||||||
|
|
||||||
|
struct osmo_timer_list threshold_timer;
|
||||||
|
static LLIST_HEAD(threshold_list);
|
||||||
|
static unsigned int threshold_timer_sched_secs;
|
||||||
|
static bool threshold_initied;
|
||||||
|
|
||||||
|
const struct value_string rate_ctr_intv[] = {
|
||||||
|
{ RATE_CTR_INTV_SEC, "per-second" },
|
||||||
|
{ RATE_CTR_INTV_MIN, "per-minute" },
|
||||||
|
{ RATE_CTR_INTV_HOUR, "per-hour" },
|
||||||
|
{ RATE_CTR_INTV_DAY, "per-day" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct value_string trx_chan_ctr_names[] = {
|
||||||
|
{ TRX_CTR_DEV_RX_OVERRUNS, "rx_overruns" },
|
||||||
|
{ TRX_CTR_DEV_TX_UNDERRUNS, "tx_underruns" },
|
||||||
|
{ TRX_CTR_DEV_RX_DROP_EV, "rx_drop_events" },
|
||||||
|
{ TRX_CTR_DEV_RX_DROP_SMPL, "rx_drop_samples" },
|
||||||
|
{ TRX_CTR_DEV_TX_DROP_EV, "tx_drop_events" },
|
||||||
|
{ TRX_CTR_DEV_TX_DROP_SMPL, "tx_drop_samples" },
|
||||||
|
{ TRX_CTR_TRX_TX_STALE_BURSTS, "tx_stale_bursts" },
|
||||||
|
{ TRX_CTR_TRX_TX_UNAVAILABLE_BURSTS, "tx_unavailable_bursts" },
|
||||||
|
{ TRX_CTR_TRX_TRXD_FN_REPEATED, "tx_trxd_fn_repeated" },
|
||||||
|
{ TRX_CTR_TRX_TRXD_FN_OUTOFORDER, "tx_trxd_fn_outoforder" },
|
||||||
|
{ TRX_CTR_TRX_TRXD_FN_SKIPPED, "tx_trxd_fn_skipped" },
|
||||||
|
{ TRX_CTR_TRX_RX_EMPTY_BURST, "rx_empty_burst" },
|
||||||
|
{ TRX_CTR_TRX_RX_CLIPPING, "rx_clipping" },
|
||||||
|
{ TRX_CTR_TRX_RX_NO_BURST_DETECTED, "rx_no_burst_detected" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct rate_ctr_desc trx_chan_ctr_desc[] = {
|
||||||
|
[TRX_CTR_DEV_RX_OVERRUNS] = { "device:rx_overruns", "Number of Rx overruns in FIFO queue" },
|
||||||
|
[TRX_CTR_DEV_TX_UNDERRUNS] = { "device:tx_underruns", "Number of Tx underruns in FIFO queue" },
|
||||||
|
[TRX_CTR_DEV_RX_DROP_EV] = { "device:rx_drop_events", "Number of times Rx samples were dropped by HW" },
|
||||||
|
[TRX_CTR_DEV_RX_DROP_SMPL] = { "device:rx_drop_samples", "Number of Rx samples dropped by HW" },
|
||||||
|
[TRX_CTR_DEV_TX_DROP_EV] = { "device:tx_drop_events", "Number of times Tx samples were dropped by HW" },
|
||||||
|
[TRX_CTR_DEV_TX_DROP_SMPL] = { "device:tx_drop_samples", "Number of Tx samples dropped by HW" },
|
||||||
|
[TRX_CTR_TRX_TX_STALE_BURSTS] = { "trx:tx_stale_bursts", "Number of Tx burts dropped by TRX due to arriving too late" },
|
||||||
|
[TRX_CTR_TRX_TX_UNAVAILABLE_BURSTS] = { "trx:tx_unavailable_bursts","Number of Tx burts unavailable (not enqueued) at the time they should be transmitted" },
|
||||||
|
[TRX_CTR_TRX_TRXD_FN_REPEATED] = { "trx:tx_trxd_fn_repeated", "Number of Tx burts received from TRXD with repeated FN" },
|
||||||
|
[TRX_CTR_TRX_TRXD_FN_OUTOFORDER] = { "trx:tx_trxd_fn_outoforder","Number of Tx burts received from TRXD with a past FN" },
|
||||||
|
[TRX_CTR_TRX_TRXD_FN_SKIPPED] = { "trx:tx_trxd_fn_skipped", "Number of Tx burts potentially skipped due to FN jumps" },
|
||||||
|
[TRX_CTR_TRX_RX_EMPTY_BURST] = { "trx:rx_empty_burst", "Number of Rx bursts empty" },
|
||||||
|
[TRX_CTR_TRX_RX_CLIPPING] = { "trx:rx_clipping", "Number of Rx bursts discarded due to clipping" },
|
||||||
|
[TRX_CTR_TRX_RX_NO_BURST_DETECTED] = { "trx:rx_no_burst_detected", "Number of Rx burts discarded due to burst detection error" },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct rate_ctr_group_desc trx_chan_ctr_group_desc = {
|
||||||
|
.group_name_prefix = "trx:chan",
|
||||||
|
.group_description = "osmo-trx statistics",
|
||||||
|
.class_id = OSMO_STATS_CLASS_GLOBAL,
|
||||||
|
.num_ctr = ARRAY_SIZE(trx_chan_ctr_desc),
|
||||||
|
.ctr_desc = trx_chan_ctr_desc,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int dev_rate_ctr_timerfd_cb(struct osmo_fd *ofd, unsigned int what) {
|
||||||
|
size_t chan;
|
||||||
|
struct rate_ctr *ctr;
|
||||||
|
LOGC(DCTR, INFO) << "Main thread is updating Device counters";
|
||||||
|
dev_rate_ctr_mutex.lock();
|
||||||
|
for (chan = 0; chan < chan_len; chan++) {
|
||||||
|
if (dev_ctrs_pending[chan].chan == PENDING_CHAN_NONE)
|
||||||
|
continue;
|
||||||
|
LOGCHAN(chan, DCTR, DEBUG) << "rate_ctr update";
|
||||||
|
ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_DEV_RX_OVERRUNS);
|
||||||
|
rate_ctr_add(ctr, dev_ctrs_pending[chan].rx_overruns - ctr->current);
|
||||||
|
ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_DEV_TX_UNDERRUNS);
|
||||||
|
rate_ctr_add(ctr, dev_ctrs_pending[chan].tx_underruns - ctr->current);
|
||||||
|
ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_DEV_RX_DROP_EV);
|
||||||
|
rate_ctr_add(ctr, dev_ctrs_pending[chan].rx_dropped_events - ctr->current);
|
||||||
|
ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_DEV_RX_DROP_SMPL);
|
||||||
|
rate_ctr_add(ctr, dev_ctrs_pending[chan].rx_dropped_samples - ctr->current);
|
||||||
|
ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_DEV_TX_DROP_EV);
|
||||||
|
rate_ctr_add(ctr, dev_ctrs_pending[chan].tx_dropped_events - ctr->current);
|
||||||
|
ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_DEV_TX_DROP_SMPL);
|
||||||
|
rate_ctr_add(ctr, dev_ctrs_pending[chan].tx_dropped_samples - ctr->current);
|
||||||
|
|
||||||
|
/* Mark as done */
|
||||||
|
dev_ctrs_pending[chan].chan = PENDING_CHAN_NONE;
|
||||||
|
}
|
||||||
|
if (osmo_timerfd_disable(&dev_rate_ctr_timerfd) < 0)
|
||||||
|
LOGC(DCTR, ERROR) << "Failed to disable timerfd";
|
||||||
|
dev_rate_ctr_mutex.unlock();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int trx_rate_ctr_timerfd_cb(struct osmo_fd *ofd, unsigned int what) {
|
||||||
|
size_t chan;
|
||||||
|
struct rate_ctr *ctr;
|
||||||
|
LOGC(DCTR, INFO) << "Main thread is updating Transceiver counters";
|
||||||
|
trx_rate_ctr_mutex.lock();
|
||||||
|
for (chan = 0; chan < chan_len; chan++) {
|
||||||
|
if (trx_ctrs_pending[chan].chan == PENDING_CHAN_NONE)
|
||||||
|
continue;
|
||||||
|
LOGCHAN(chan, DCTR, DEBUG) << "rate_ctr update";
|
||||||
|
ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_TRX_TX_STALE_BURSTS);
|
||||||
|
rate_ctr_add(ctr, trx_ctrs_pending[chan].tx_stale_bursts - ctr->current);
|
||||||
|
ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_TRX_TX_UNAVAILABLE_BURSTS);
|
||||||
|
rate_ctr_add(ctr, trx_ctrs_pending[chan].tx_unavailable_bursts - ctr->current);
|
||||||
|
ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_TRX_TRXD_FN_REPEATED);
|
||||||
|
rate_ctr_add(ctr, trx_ctrs_pending[chan].tx_trxd_fn_repeated - ctr->current);
|
||||||
|
ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_TRX_TRXD_FN_OUTOFORDER);
|
||||||
|
rate_ctr_add(ctr, trx_ctrs_pending[chan].tx_trxd_fn_outoforder - ctr->current);
|
||||||
|
ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_TRX_TRXD_FN_SKIPPED);
|
||||||
|
rate_ctr_add(ctr, trx_ctrs_pending[chan].tx_trxd_fn_skipped - ctr->current);
|
||||||
|
ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_TRX_RX_EMPTY_BURST);
|
||||||
|
rate_ctr_add(ctr, trx_ctrs_pending[chan].rx_empty_burst - ctr->current);
|
||||||
|
ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_TRX_RX_CLIPPING);
|
||||||
|
rate_ctr_add(ctr, trx_ctrs_pending[chan].rx_clipping - ctr->current);
|
||||||
|
ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], TRX_CTR_TRX_RX_NO_BURST_DETECTED);
|
||||||
|
rate_ctr_add(ctr, trx_ctrs_pending[chan].rx_no_burst_detected - ctr->current);
|
||||||
|
/* Mark as done */
|
||||||
|
trx_ctrs_pending[chan].chan = PENDING_CHAN_NONE;
|
||||||
|
}
|
||||||
|
if (osmo_timerfd_disable(&trx_rate_ctr_timerfd) < 0)
|
||||||
|
LOGC(DCTR, ERROR) << "Failed to disable timerfd";
|
||||||
|
trx_rate_ctr_mutex.unlock();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Callback function to be called every time we receive a signal from DEVICE */
|
||||||
|
static int device_sig_cb(unsigned int subsys, unsigned int signal,
|
||||||
|
void *handler_data, void *signal_data)
|
||||||
|
{
|
||||||
|
struct device_counters *dev_ctr;
|
||||||
|
struct trx_counters *trx_ctr;
|
||||||
|
/* Delay sched around 20 ms, in case we receive several calls from several
|
||||||
|
* channels batched */
|
||||||
|
struct timespec next_sched = {.tv_sec = 0, .tv_nsec = 20*1000*1000};
|
||||||
|
/* no automatic re-trigger */
|
||||||
|
struct timespec intv_sched = {.tv_sec = 0, .tv_nsec = 0};
|
||||||
|
char err_buf[256];
|
||||||
|
|
||||||
|
switch (signal) {
|
||||||
|
case S_DEVICE_COUNTER_CHANGE:
|
||||||
|
dev_ctr = (struct device_counters *)signal_data;
|
||||||
|
LOGCHAN(dev_ctr->chan, DCTR, INFO) << "Received counter change from radioDevice";
|
||||||
|
dev_rate_ctr_mutex.lock();
|
||||||
|
dev_ctrs_pending[dev_ctr->chan] = *dev_ctr;
|
||||||
|
if (osmo_timerfd_schedule(&dev_rate_ctr_timerfd, &next_sched, &intv_sched) < 0) {
|
||||||
|
LOGC(DCTR, ERROR) << "Failed to schedule timerfd: " << errno
|
||||||
|
<< " = "<< strerror_r(errno, err_buf, sizeof(err_buf));
|
||||||
|
}
|
||||||
|
dev_rate_ctr_mutex.unlock();
|
||||||
|
break;
|
||||||
|
case S_TRX_COUNTER_CHANGE:
|
||||||
|
trx_ctr = (struct trx_counters *)signal_data;
|
||||||
|
LOGCHAN(trx_ctr->chan, DCTR, INFO) << "Received counter change from Transceiver";
|
||||||
|
trx_rate_ctr_mutex.lock();
|
||||||
|
trx_ctrs_pending[trx_ctr->chan] = *trx_ctr;
|
||||||
|
if (osmo_timerfd_schedule(&trx_rate_ctr_timerfd, &next_sched, &intv_sched) < 0) {
|
||||||
|
LOGC(DCTR, ERROR) << "Failed to schedule timerfd: " << errno
|
||||||
|
<< " = "<< strerror_r(errno, err_buf, sizeof(err_buf));
|
||||||
|
}
|
||||||
|
trx_rate_ctr_mutex.unlock();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************
|
||||||
|
* ctr_threshold APIs
|
||||||
|
************************************/
|
||||||
|
static const char* ctr_threshold_2_vty_str(struct ctr_threshold *ctr)
|
||||||
|
{
|
||||||
|
static char buf[256];
|
||||||
|
int rc = 0;
|
||||||
|
rc += snprintf(buf, sizeof(buf), "ctr-error-threshold %s", get_value_string(trx_chan_ctr_names, ctr->ctr_id));
|
||||||
|
rc += snprintf(buf + rc, sizeof(buf) - rc, " %d %s", ctr->val, get_value_string(rate_ctr_intv, ctr->intv));
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void threshold_timer_cb(void *data)
|
||||||
|
{
|
||||||
|
struct ctr_threshold *ctr_thr;
|
||||||
|
struct rate_ctr *rate_ctr;
|
||||||
|
size_t chan;
|
||||||
|
LOGC(DCTR, DEBUG) << "threshold_timer_cb fired!";
|
||||||
|
|
||||||
|
llist_for_each_entry(ctr_thr, &threshold_list, list) {
|
||||||
|
for (chan = 0; chan < chan_len; chan++) {
|
||||||
|
rate_ctr = rate_ctr_group_get_ctr(rate_ctrs[chan], ctr_thr->ctr_id);
|
||||||
|
LOGCHAN(chan, DCTR, INFO) << "checking threshold: " << ctr_threshold_2_vty_str(ctr_thr)
|
||||||
|
<< " ("<< rate_ctr->intv[ctr_thr->intv].rate << " vs " << ctr_thr->val << ")";
|
||||||
|
if (rate_ctr->intv[ctr_thr->intv].rate >= ctr_thr->val) {
|
||||||
|
LOGCHAN(chan, DCTR, FATAL) << "threshold reached, stopping! " << ctr_threshold_2_vty_str(ctr_thr)
|
||||||
|
<< " ("<< rate_ctr->intv[ctr_thr->intv].rate << " vs " << ctr_thr->val << ")";
|
||||||
|
osmo_signal_dispatch(SS_MAIN, S_MAIN_STOP_REQUIRED, NULL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
osmo_timer_schedule(&threshold_timer, threshold_timer_sched_secs, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t ctr_threshold_2_seconds(struct ctr_threshold *ctr)
|
||||||
|
{
|
||||||
|
size_t mult = 0;
|
||||||
|
switch (ctr->intv) {
|
||||||
|
case RATE_CTR_INTV_SEC:
|
||||||
|
mult = 1;
|
||||||
|
break;
|
||||||
|
case RATE_CTR_INTV_MIN:
|
||||||
|
mult = 60;
|
||||||
|
break;
|
||||||
|
case RATE_CTR_INTV_HOUR:
|
||||||
|
mult = 60*60;
|
||||||
|
break;
|
||||||
|
case RATE_CTR_INTV_DAY:
|
||||||
|
mult = 60*60*24;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
OSMO_ASSERT(false);
|
||||||
|
}
|
||||||
|
return mult;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void threshold_timer_update_intv() {
|
||||||
|
struct ctr_threshold *ctr, *min_ctr;
|
||||||
|
size_t secs, min_secs;
|
||||||
|
|
||||||
|
/* Avoid scheduling timer until itself and other structures are prepared
|
||||||
|
by trx_rate_ctr_init */
|
||||||
|
if (!threshold_initied)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (llist_empty(&threshold_list)) {
|
||||||
|
osmo_timer_del(&threshold_timer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
min_ctr = llist_first_entry(&threshold_list, struct ctr_threshold, list);
|
||||||
|
min_secs = ctr_threshold_2_seconds(min_ctr);
|
||||||
|
|
||||||
|
llist_for_each_entry(ctr, &threshold_list, list) {
|
||||||
|
secs = ctr_threshold_2_seconds(ctr);
|
||||||
|
if (min_secs > secs)
|
||||||
|
min_secs = secs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
threshold_timer_sched_secs = OSMO_MAX((int)(min_secs / 2 - 1), 1);
|
||||||
|
LOGC(DCTR, INFO) << "New ctr-error-threshold check interval: "
|
||||||
|
<< threshold_timer_sched_secs << " seconds";
|
||||||
|
osmo_timer_schedule(&threshold_timer, threshold_timer_sched_secs, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Init rate_ctr subsystem. Expected to be called during process start by main thread before VTY is ready */
|
||||||
|
void trx_rate_ctr_init(void *ctx, struct trx_ctx* trx_ctx)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
trx_rate_ctr_ctx = ctx;
|
||||||
|
chan_len = trx_ctx->cfg.num_chans;
|
||||||
|
dev_ctrs_pending = (struct device_counters*) talloc_zero_size(ctx, chan_len * sizeof(struct device_counters));
|
||||||
|
trx_ctrs_pending = (struct trx_counters*) talloc_zero_size(ctx, chan_len * sizeof(struct trx_counters));
|
||||||
|
rate_ctrs = (struct rate_ctr_group**) talloc_zero_size(ctx, chan_len * sizeof(struct rate_ctr_group*));
|
||||||
|
|
||||||
|
for (i = 0; i < chan_len; i++) {
|
||||||
|
dev_ctrs_pending[i].chan = PENDING_CHAN_NONE;
|
||||||
|
trx_ctrs_pending[i].chan = PENDING_CHAN_NONE;
|
||||||
|
rate_ctrs[i] = rate_ctr_group_alloc(ctx, &trx_chan_ctr_group_desc, i);
|
||||||
|
if (!rate_ctrs[i]) {
|
||||||
|
LOGCHAN(i, DCTR, ERROR) << "Failed to allocate rate ctr";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dev_rate_ctr_timerfd.fd = -1;
|
||||||
|
if (osmo_timerfd_setup(&dev_rate_ctr_timerfd, dev_rate_ctr_timerfd_cb, NULL) < 0) {
|
||||||
|
LOGC(DCTR, ERROR) << "Failed to setup timerfd";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
trx_rate_ctr_timerfd.fd = -1;
|
||||||
|
if (osmo_timerfd_setup(&trx_rate_ctr_timerfd, trx_rate_ctr_timerfd_cb, NULL) < 0) {
|
||||||
|
LOGC(DCTR, ERROR) << "Failed to setup timerfd";
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
osmo_signal_register_handler(SS_DEVICE, device_sig_cb, NULL);
|
||||||
|
|
||||||
|
/* Now set up threshold checks */
|
||||||
|
threshold_initied = true;
|
||||||
|
osmo_timer_setup(&threshold_timer, threshold_timer_cb, NULL);
|
||||||
|
threshold_timer_update_intv();
|
||||||
|
}
|
||||||
|
|
||||||
|
void trx_rate_ctr_threshold_add(struct ctr_threshold *ctr)
|
||||||
|
{
|
||||||
|
struct ctr_threshold *new_ctr;
|
||||||
|
|
||||||
|
new_ctr = talloc_zero(trx_rate_ctr_ctx, struct ctr_threshold);
|
||||||
|
*new_ctr = *ctr;
|
||||||
|
LOGC(DCTR, NOTICE) << "Adding new threshold check: " << ctr_threshold_2_vty_str(new_ctr);
|
||||||
|
llist_add(&new_ctr->list, &threshold_list);
|
||||||
|
threshold_timer_update_intv();
|
||||||
|
}
|
||||||
|
|
||||||
|
int trx_rate_ctr_threshold_del(struct ctr_threshold *del_ctr)
|
||||||
|
{
|
||||||
|
struct ctr_threshold *ctr;
|
||||||
|
|
||||||
|
llist_for_each_entry(ctr, &threshold_list, list) {
|
||||||
|
if (ctr->intv != del_ctr->intv ||
|
||||||
|
ctr->ctr_id != del_ctr->ctr_id ||
|
||||||
|
ctr->val != del_ctr->val)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
LOGC(DCTR, NOTICE) << "Deleting threshold check: " << ctr_threshold_2_vty_str(del_ctr);
|
||||||
|
llist_del(&ctr->list);
|
||||||
|
talloc_free(ctr);
|
||||||
|
threshold_timer_update_intv();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void trx_rate_ctr_threshold_write_config(struct vty *vty, char *indent_prefix)
|
||||||
|
{
|
||||||
|
struct ctr_threshold *ctr;
|
||||||
|
|
||||||
|
llist_for_each_entry(ctr, &threshold_list, list) {
|
||||||
|
vty_out(vty, "%s%s%s", indent_prefix, ctr_threshold_2_vty_str(ctr), VTY_NEWLINE);
|
||||||
|
}
|
||||||
|
}
|
||||||
38
CommonLibs/trx_rate_ctr.h
Normal file
38
CommonLibs/trx_rate_ctr.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <osmocom/core/rate_ctr.h>
|
||||||
|
#include <osmocom/vty/command.h>
|
||||||
|
|
||||||
|
enum TrxCtr {
|
||||||
|
TRX_CTR_DEV_RX_OVERRUNS,
|
||||||
|
TRX_CTR_DEV_TX_UNDERRUNS,
|
||||||
|
TRX_CTR_DEV_RX_DROP_EV,
|
||||||
|
TRX_CTR_DEV_RX_DROP_SMPL,
|
||||||
|
TRX_CTR_DEV_TX_DROP_EV,
|
||||||
|
TRX_CTR_DEV_TX_DROP_SMPL,
|
||||||
|
TRX_CTR_TRX_TX_STALE_BURSTS,
|
||||||
|
TRX_CTR_TRX_TX_UNAVAILABLE_BURSTS,
|
||||||
|
TRX_CTR_TRX_TRXD_FN_REPEATED,
|
||||||
|
TRX_CTR_TRX_TRXD_FN_OUTOFORDER,
|
||||||
|
TRX_CTR_TRX_TRXD_FN_SKIPPED,
|
||||||
|
TRX_CTR_TRX_RX_EMPTY_BURST,
|
||||||
|
TRX_CTR_TRX_RX_CLIPPING,
|
||||||
|
TRX_CTR_TRX_RX_NO_BURST_DETECTED,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ctr_threshold {
|
||||||
|
/*! Linked list of all counter groups in the system */
|
||||||
|
struct llist_head list;
|
||||||
|
enum rate_ctr_intv intv;
|
||||||
|
enum TrxCtr ctr_id;
|
||||||
|
uint32_t val;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const struct value_string rate_ctr_intv[];
|
||||||
|
extern const struct value_string trx_chan_ctr_names[];
|
||||||
|
|
||||||
|
struct trx_ctx;
|
||||||
|
void trx_rate_ctr_init(void *ctx, struct trx_ctx* trx_ctx);
|
||||||
|
void trx_rate_ctr_threshold_add(struct ctr_threshold *ctr);
|
||||||
|
int trx_rate_ctr_threshold_del(struct ctr_threshold *del_ctr);
|
||||||
|
void trx_rate_ctr_threshold_write_config(struct vty *vty, char *indent_prefix);
|
||||||
901
CommonLibs/trx_vty.c
Normal file
901
CommonLibs/trx_vty.c
Normal file
@@ -0,0 +1,901 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2018-2019 sysmocom - s.f.m.c. GmbH
|
||||||
|
* All Rights Reserved
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
|
* Author: Pau Espin Pedrol <pespin@sysmocom.de>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* See the COPYING file in the main directory for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
|
#include <osmocom/core/talloc.h>
|
||||||
|
#include <osmocom/core/utils.h>
|
||||||
|
#include <osmocom/core/rate_ctr.h>
|
||||||
|
|
||||||
|
#include <osmocom/vty/command.h>
|
||||||
|
#include <osmocom/vty/logging.h>
|
||||||
|
#include <osmocom/vty/vty.h>
|
||||||
|
#include <osmocom/vty/misc.h>
|
||||||
|
|
||||||
|
#include "trx_rate_ctr.h"
|
||||||
|
#include "trx_vty.h"
|
||||||
|
#include "../config.h"
|
||||||
|
|
||||||
|
static struct trx_ctx* g_trx_ctx;
|
||||||
|
|
||||||
|
const struct value_string clock_ref_names[] = {
|
||||||
|
{ REF_INTERNAL, "internal" },
|
||||||
|
{ REF_EXTERNAL, "external" },
|
||||||
|
{ REF_GPS, "gpsdo" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct value_string filler_names[] = {
|
||||||
|
{ FILLER_DUMMY, "Dummy bursts (C0 only)" },
|
||||||
|
{ FILLER_ZERO, "Empty bursts" },
|
||||||
|
{ FILLER_NORM_RAND, "GMSK Normal Bursts with random payload" },
|
||||||
|
{ FILLER_EDGE_RAND, "8-PSK Normal Bursts with random payload" },
|
||||||
|
{ FILLER_ACCESS_RAND, "Access Bursts with random payload" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct value_string filler_types[] = {
|
||||||
|
{ FILLER_DUMMY, "dummy" },
|
||||||
|
{ FILLER_ZERO, "zero" },
|
||||||
|
{ FILLER_NORM_RAND, "random-nb-gmsk" },
|
||||||
|
{ FILLER_EDGE_RAND, "random-nb-8psk" },
|
||||||
|
{ FILLER_ACCESS_RAND, "random-ab" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct value_string filler_docs[] = {
|
||||||
|
{ FILLER_DUMMY, "Send a Dummy Burst on C0 (TRX0) and empty burst on other channels" },
|
||||||
|
{ FILLER_ZERO, "Send an empty burst (default)" },
|
||||||
|
{ FILLER_NORM_RAND, "Send a GMSK modulated Normal Burst with random bits (spectrum mask testing)" },
|
||||||
|
{ FILLER_EDGE_RAND, "Send an 8-PSK modulated Normal Burst with random bits (spectrum mask testing)" },
|
||||||
|
{ FILLER_ACCESS_RAND, "Send an Access Burst with random bits (Rx/Tx alignment testing)" },
|
||||||
|
{ 0, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct trx_ctx *trx_from_vty(struct vty *v)
|
||||||
|
{
|
||||||
|
/* It can't hurt to force callers to continue to pass the vty instance
|
||||||
|
* to this function, in case we'd like to retrieve the global
|
||||||
|
* trx instance from the vty at some point in the future. But
|
||||||
|
* until then, just return the global pointer, which should have been
|
||||||
|
* initialized by trx_vty_init().
|
||||||
|
*/
|
||||||
|
OSMO_ASSERT(g_trx_ctx);
|
||||||
|
return g_trx_ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum trx_vty_node {
|
||||||
|
TRX_NODE = _LAST_OSMOVTY_NODE + 1,
|
||||||
|
CHAN_NODE,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct cmd_node trx_node = {
|
||||||
|
TRX_NODE,
|
||||||
|
"%s(config-trx)# ",
|
||||||
|
1,
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct cmd_node chan_node = {
|
||||||
|
CHAN_NODE,
|
||||||
|
"%s(config-trx-chan)# ",
|
||||||
|
1,
|
||||||
|
};
|
||||||
|
|
||||||
|
DEFUN(cfg_trx, cfg_trx_cmd,
|
||||||
|
"trx",
|
||||||
|
"Configure the TRX\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
if (!trx)
|
||||||
|
return CMD_WARNING;
|
||||||
|
|
||||||
|
vty->node = TRX_NODE;
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_bind_ip, cfg_bind_ip_cmd,
|
||||||
|
"bind-ip " VTY_IPV4_CMD,
|
||||||
|
"Set the IP address for the local bind\n"
|
||||||
|
"IPv4 Address\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
osmo_talloc_replace_string(trx, &trx->cfg.bind_addr, argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_remote_ip, cfg_remote_ip_cmd,
|
||||||
|
"remote-ip " VTY_IPV4_CMD,
|
||||||
|
"Set the IP address for the remote BTS\n"
|
||||||
|
"IPv4 Address\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
osmo_talloc_replace_string(trx, &trx->cfg.remote_addr, argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_base_port, cfg_base_port_cmd,
|
||||||
|
"base-port <1-65535>",
|
||||||
|
"Set the TRX Base Port\n"
|
||||||
|
"TRX Base Port\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.base_port = atoi(argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_dev_args, cfg_dev_args_cmd,
|
||||||
|
"dev-args DESC",
|
||||||
|
"Set the device-specific arguments to pass to the device\n"
|
||||||
|
"Device-specific arguments\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
osmo_talloc_replace_string(trx, &trx->cfg.dev_args, argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_tx_sps, cfg_tx_sps_cmd,
|
||||||
|
"tx-sps (1|4)",
|
||||||
|
"Set the Tx Samples-per-Symbol\n"
|
||||||
|
"Tx Samples-per-Symbol\n"
|
||||||
|
"1 Sample-per-Symbol\n"
|
||||||
|
"4 Samples-per-Symbol\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.tx_sps = atoi(argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_rx_sps, cfg_rx_sps_cmd,
|
||||||
|
"rx-sps (1|4)",
|
||||||
|
"Set the Rx Samples-per-Symbol\n"
|
||||||
|
"Rx Samples-per-Symbol\n"
|
||||||
|
"1 Sample-per-Symbol\n"
|
||||||
|
"4 Samples-per-Symbol\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.rx_sps = atoi(argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_clock_ref, cfg_clock_ref_cmd,
|
||||||
|
"clock-ref (internal|external|gpsdo)",
|
||||||
|
"Set the Reference Clock\n"
|
||||||
|
"Enable internal reference (default)\n"
|
||||||
|
"Enable external 10 MHz reference\n"
|
||||||
|
"Enable GPSDO reference\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.clock_ref = get_string_value(clock_ref_names, argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_multi_arfcn, cfg_multi_arfcn_cmd,
|
||||||
|
"multi-arfcn (disable|enable)",
|
||||||
|
"Multi-ARFCN transceiver mode (default=disable)\n"
|
||||||
|
"Enable multi-ARFCN mode\n" "Disable multi-ARFCN mode\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
if (strcmp("disable", argv[0]) == 0) {
|
||||||
|
trx->cfg.multi_arfcn = false;
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trx->cfg.num_chans > TRX_MCHAN_MAX) {
|
||||||
|
vty_out(vty, "Up to %i channels are supported for multi-TRX mode%s",
|
||||||
|
TRX_MCHAN_MAX, VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
trx->cfg.multi_arfcn = true;
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_offset, cfg_offset_cmd,
|
||||||
|
"offset FLOAT",
|
||||||
|
"Set the baseband frequency offset (default=0, auto)\n"
|
||||||
|
"Baseband Frequency Offset\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.offset = atof(argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN_ATTR(cfg_freq_offset, cfg_freq_offset_cmd,
|
||||||
|
"freq-offset FLOAT",
|
||||||
|
"Apply an artificial offset to Rx/Tx carrier frequency\n"
|
||||||
|
"Frequency offset in kHz (e.g. -145300)\n",
|
||||||
|
CMD_ATTR_HIDDEN)
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.freq_offset_khz = atof(argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_rssi_offset, cfg_rssi_offset_cmd,
|
||||||
|
"rssi-offset FLOAT [relative]",
|
||||||
|
"Set the RSSI to dBm offset in dB (default=0)\n"
|
||||||
|
"RSSI to dBm offset in dB\n"
|
||||||
|
"Add to the default rssi-offset value instead of completely replacing it\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.rssi_offset = atof(argv[0]);
|
||||||
|
trx->cfg.force_rssi_offset = (argc == 1);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DEFUN_ATTR(cfg_ul_fn_offset, cfg_ul_fn_offset_cmd,
|
||||||
|
"ul-fn-offset <-10-10>",
|
||||||
|
"Adjusts the uplink frame FN by the specified amount\n"
|
||||||
|
"Frame Number offset\n",
|
||||||
|
CMD_ATTR_HIDDEN)
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.ul_fn_offset = atoi(argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN_ATTR(cfg_ul_freq_override, cfg_ul_freq_override_cmd,
|
||||||
|
"ul-freq-override FLOAT",
|
||||||
|
"Overrides Rx carrier frequency\n"
|
||||||
|
"Frequency in Hz (e.g. 145300000)\n",
|
||||||
|
CMD_ATTR_HIDDEN)
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.overrides.ul_freq_override = true;
|
||||||
|
trx->cfg.overrides.ul_freq = atof(argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
DEFUN_ATTR(cfg_dl_freq_override, cfg_dl_freq_override_cmd,
|
||||||
|
"dl-freq-override FLOAT",
|
||||||
|
"Overrides Tx carrier frequency\n"
|
||||||
|
"Frequency in Hz (e.g. 145300000)\n",
|
||||||
|
CMD_ATTR_HIDDEN)
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.overrides.dl_freq_override = true;
|
||||||
|
trx->cfg.overrides.dl_freq = atof(argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN_ATTR(cfg_ul_gain_override, cfg_ul_gain_override_cmd,
|
||||||
|
"ul-gain-override FLOAT",
|
||||||
|
"Overrides Rx gain\n"
|
||||||
|
"gain in dB\n",
|
||||||
|
CMD_ATTR_HIDDEN)
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.overrides.ul_gain_override = true;
|
||||||
|
trx->cfg.overrides.ul_gain = atof(argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
DEFUN_ATTR(cfg_dl_gain_override, cfg_dl_gain_override_cmd,
|
||||||
|
"dl-gain-override FLOAT",
|
||||||
|
"Overrides Tx gain\n"
|
||||||
|
"gain in dB\n",
|
||||||
|
CMD_ATTR_HIDDEN)
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.overrides.dl_gain_override = true;
|
||||||
|
trx->cfg.overrides.dl_gain = atof(argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN_ATTR(cfg_use_viterbi, cfg_use_viterbi_cmd,
|
||||||
|
"viterbi-eq (disable|enable)",
|
||||||
|
"Use viterbi equalizer for gmsk (default=disable)\n"
|
||||||
|
"Disable VA\n"
|
||||||
|
"Enable VA\n",
|
||||||
|
CMD_ATTR_HIDDEN)
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
if (strcmp("disable", argv[0]) == 0)
|
||||||
|
trx->cfg.use_va = false;
|
||||||
|
else if (strcmp("enable", argv[0]) == 0)
|
||||||
|
trx->cfg.use_va = true;
|
||||||
|
else
|
||||||
|
return CMD_WARNING;
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_swap_channels, cfg_swap_channels_cmd,
|
||||||
|
"swap-channels (disable|enable)",
|
||||||
|
"Swap primary and secondary channels of the PHY (if any)\n"
|
||||||
|
"Do not swap primary and secondary channels (default)\n"
|
||||||
|
"Swap primary and secondary channels\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
if (strcmp("disable", argv[0]) == 0) {
|
||||||
|
trx->cfg.swap_channels = false;
|
||||||
|
} else if (strcmp("enable", argv[0]) == 0) {
|
||||||
|
trx->cfg.swap_channels = true;
|
||||||
|
} else {
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_egprs, cfg_egprs_cmd,
|
||||||
|
"egprs (disable|enable)",
|
||||||
|
"EGPRS (8-PSK demodulation) support (default=disable)\n"
|
||||||
|
"Disable EGPRS (8-PSK demodulation) support\n"
|
||||||
|
"Enable EGPRS (8-PSK demodulation) support\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
if (strcmp("disable", argv[0]) == 0) {
|
||||||
|
trx->cfg.egprs = false;
|
||||||
|
} else if (strcmp("enable", argv[0]) == 0) {
|
||||||
|
trx->cfg.egprs = true;
|
||||||
|
} else {
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_ext_rach, cfg_ext_rach_cmd,
|
||||||
|
"ext-rach (disable|enable)",
|
||||||
|
"11-bit Access Burst correlation support (default=disable)\n"
|
||||||
|
"Disable 11-bit Access Burst (TS1 & TS2) correlation\n"
|
||||||
|
"Enable 11-bit Access Burst (TS1 & TS2) correlation\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
if (strcmp("disable", argv[0]) == 0)
|
||||||
|
trx->cfg.ext_rach = false;
|
||||||
|
|
||||||
|
if (strcmp("enable", argv[0]) == 0)
|
||||||
|
trx->cfg.ext_rach = true;
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN_DEPRECATED(cfg_rt_prio, cfg_rt_prio_cmd,
|
||||||
|
"rt-prio <1-32>",
|
||||||
|
"Set the SCHED_RR real-time priority\n"
|
||||||
|
"Real time priority\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.sched_rr = atoi(argv[0]);
|
||||||
|
vty_out (vty, "%% 'rt-prio %u' is deprecated, use 'policy rr %u' under 'sched' node instead%s",
|
||||||
|
trx->cfg.sched_rr, trx->cfg.sched_rr, VTY_NEWLINE);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_stack_size, cfg_stack_size_cmd,
|
||||||
|
"stack-size <0-2147483647>",
|
||||||
|
"Set the stack size per thread in BYTE, 0 = OS default\n"
|
||||||
|
"Stack size per thread in BYTE\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.stack_size = atoi(argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CFG_FILLER_DOC_STR \
|
||||||
|
"Filler burst settings\n"
|
||||||
|
|
||||||
|
DEFUN(cfg_filler, cfg_filler_type_cmd,
|
||||||
|
"AUTO-GENERATED", "AUTO-GENERATED")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
// trx->cfg.filler is unsigned, so we need an interim int var to detect errors
|
||||||
|
int type = get_string_value(filler_types, argv[0]);
|
||||||
|
|
||||||
|
if (type < 0) {
|
||||||
|
trx->cfg.filler = FILLER_ZERO;
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
trx->cfg.filler = type;
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_test_rtsc, cfg_filler_tsc_cmd,
|
||||||
|
"filler tsc <0-7>",
|
||||||
|
CFG_FILLER_DOC_STR
|
||||||
|
"Set the TSC for GMSK/8-PSK Normal Burst random fillers. Used only with 'random-nb-gmsk' and"
|
||||||
|
" 'random-nb-8psk' filler types. (default=0)\n"
|
||||||
|
"TSC\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.rtsc = atoi(argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_test_rach_delay, cfg_filler_rach_delay_cmd,
|
||||||
|
"filler access-burst-delay <0-68>",
|
||||||
|
CFG_FILLER_DOC_STR
|
||||||
|
"Set the delay for Access Burst random fillers. Used only with 'random-ab' filler type. (default=0)\n"
|
||||||
|
"RACH delay in symbols\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
trx->cfg.rach_delay = atoi(argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vty_ctr_name_2_id(const char* str) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; trx_chan_ctr_names[i].str; i++) {
|
||||||
|
if (strstr(trx_chan_ctr_names[i].str, str)) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int vty_intv_name_2_id(const char* str) {
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; rate_ctr_intv[i].str; i++) {
|
||||||
|
if (strcmp(rate_ctr_intv[i].str, str) == 0) {
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define THRESHOLD_ARGS "(rx_overruns|tx_underruns|rx_drop_events|rx_drop_samples|tx_drop_events|tx_drop_samples|tx_stale_bursts|tx_unavailable_bursts|tx_trxd_fn_repeated|tx_trxd_fn_outoforder|tx_trxd_fn_skipped)"
|
||||||
|
#define THRESHOLD_STR_VAL(s) "Set threshold value for rate_ctr device:" OSMO_STRINGIFY_VAL(s) "\n"
|
||||||
|
#define THRESHOLD_STRS \
|
||||||
|
THRESHOLD_STR_VAL(rx_overruns) \
|
||||||
|
THRESHOLD_STR_VAL(tx_underruns) \
|
||||||
|
THRESHOLD_STR_VAL(rx_drop_events) \
|
||||||
|
THRESHOLD_STR_VAL(rx_drop_samples) \
|
||||||
|
THRESHOLD_STR_VAL(tx_drop_events) \
|
||||||
|
THRESHOLD_STR_VAL(tx_drop_samples) \
|
||||||
|
THRESHOLD_STR_VAL(tx_stale_bursts) \
|
||||||
|
THRESHOLD_STR_VAL(tx_unavailable_bursts) \
|
||||||
|
THRESHOLD_STR_VAL(tx_trxd_fn_repeated) \
|
||||||
|
THRESHOLD_STR_VAL(tx_trxd_fn_outoforder) \
|
||||||
|
THRESHOLD_STR_VAL(tx_trxd_fn_skipped) \
|
||||||
|
""
|
||||||
|
#define INTV_ARGS "(per-second|per-minute|per-hour|per-day)"
|
||||||
|
#define INTV_STR_VAL(s) "Threshold value sampled " OSMO_STRINGIFY_VAL(s) "\n"
|
||||||
|
#define INTV_STRS \
|
||||||
|
INTV_STR_VAL(per-second) \
|
||||||
|
INTV_STR_VAL(per-minute) \
|
||||||
|
INTV_STR_VAL(per-hour) \
|
||||||
|
INTV_STR_VAL(per-day)
|
||||||
|
|
||||||
|
DEFUN_ATTR(cfg_ctr_error_threshold, cfg_ctr_error_threshold_cmd,
|
||||||
|
"ctr-error-threshold " THRESHOLD_ARGS " <0-65535> " INTV_ARGS,
|
||||||
|
"Threshold rate for error counter\n"
|
||||||
|
THRESHOLD_STRS
|
||||||
|
"Value to set for threshold\n"
|
||||||
|
INTV_STRS,
|
||||||
|
CMD_ATTR_IMMEDIATE)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct ctr_threshold ctr;
|
||||||
|
|
||||||
|
rc = vty_ctr_name_2_id(argv[0]);
|
||||||
|
if (rc < 0) {
|
||||||
|
vty_out(vty, "No valid ctr_name found for ctr-error-threshold %s%s",
|
||||||
|
argv[0], VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
ctr.ctr_id = (enum TrxCtr)rc;
|
||||||
|
ctr.val = atoi(argv[1]);
|
||||||
|
rc = vty_intv_name_2_id(argv[2]);
|
||||||
|
if (rc < 0) {
|
||||||
|
vty_out(vty, "No valid time frame found for ctr-error-threshold %s %d %s%s",
|
||||||
|
argv[0], ctr.val, argv[2], VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
ctr.intv = (enum rate_ctr_intv) rc;
|
||||||
|
trx_rate_ctr_threshold_add(&ctr);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN_ATTR(cfg_no_ctr_error_threshold, cfg_no_ctr_error_threshold_cmd,
|
||||||
|
"no ctr-error-threshold " THRESHOLD_ARGS " <0-65535> " INTV_ARGS,
|
||||||
|
NO_STR "Threshold rate for error counter\n"
|
||||||
|
THRESHOLD_STRS
|
||||||
|
"Value to set for threshold\n"
|
||||||
|
INTV_STRS,
|
||||||
|
CMD_ATTR_IMMEDIATE)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
struct ctr_threshold ctr;
|
||||||
|
|
||||||
|
rc = vty_ctr_name_2_id(argv[0]);
|
||||||
|
if (rc < 0) {
|
||||||
|
vty_out(vty, "No valid ctr_name found for ctr-error-threshold %s%s",
|
||||||
|
argv[0], VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
ctr.ctr_id = (enum TrxCtr)rc;
|
||||||
|
ctr.val = atoi(argv[1]);
|
||||||
|
rc = vty_intv_name_2_id(argv[2]);
|
||||||
|
if (rc < 0) {
|
||||||
|
vty_out(vty, "No valid time frame found for ctr-error-threshold %s %d %s%s",
|
||||||
|
argv[0], ctr.val, argv[2], VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
ctr.intv = (enum rate_ctr_intv) rc;
|
||||||
|
if (trx_rate_ctr_threshold_del(&ctr) < 0) {
|
||||||
|
vty_out(vty, "no ctr-error-threshold: Entry to delete not found%s", VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_chan, cfg_chan_cmd,
|
||||||
|
"chan <0-100>",
|
||||||
|
"Select a channel to configure\n"
|
||||||
|
"Channel index\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
int idx = atoi(argv[0]);
|
||||||
|
|
||||||
|
if (idx >= TRX_CHAN_MAX) {
|
||||||
|
vty_out(vty, "Chan list full.%s", VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
} else if (trx->cfg.multi_arfcn && trx->cfg.num_chans >= TRX_MCHAN_MAX) {
|
||||||
|
vty_out(vty, "Up to %i channels are supported for multi-TRX mode%s",
|
||||||
|
TRX_MCHAN_MAX, VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (trx->cfg.num_chans < idx) { /* Unexisting or creating non-consecutive */
|
||||||
|
vty_out(vty, "Non-existent or non-consecutive chan %d.%s",
|
||||||
|
idx, VTY_NEWLINE);
|
||||||
|
return CMD_WARNING;
|
||||||
|
} else if (trx->cfg.num_chans == idx) { /* creating it */
|
||||||
|
trx->cfg.num_chans++;
|
||||||
|
trx->cfg.chans[idx].trx = trx;
|
||||||
|
trx->cfg.chans[idx].idx = idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
vty->node = CHAN_NODE;
|
||||||
|
vty->index = &trx->cfg.chans[idx];
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_chan_rx_path, cfg_chan_rx_path_cmd,
|
||||||
|
"rx-path NAME",
|
||||||
|
"Set the Rx Path\n"
|
||||||
|
"Rx Path name\n")
|
||||||
|
{
|
||||||
|
struct trx_chan *chan = vty->index;
|
||||||
|
|
||||||
|
if (chan->trx->cfg.multi_arfcn && chan->idx > 0) {
|
||||||
|
vty_out(vty, "%% Setting 'rx-path' for chan %u in multi-ARFCN mode "
|
||||||
|
"does not make sense, because only chan 0 is used%s",
|
||||||
|
chan->idx, VTY_NEWLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
osmo_talloc_replace_string(chan->trx, &chan->rx_path, argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(cfg_chan_tx_path, cfg_chan_tx_path_cmd,
|
||||||
|
"tx-path NAME",
|
||||||
|
"Set the Tx Path\n"
|
||||||
|
"Tx Path name\n")
|
||||||
|
{
|
||||||
|
struct trx_chan *chan = vty->index;
|
||||||
|
|
||||||
|
if (chan->trx->cfg.multi_arfcn && chan->idx > 0) {
|
||||||
|
vty_out(vty, "%% Setting 'tx-path' for chan %u in multi-ARFCN mode "
|
||||||
|
"does not make sense, because only chan 0 is used%s",
|
||||||
|
chan->idx, VTY_NEWLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
osmo_talloc_replace_string(chan->trx, &chan->tx_path, argv[0]);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int dummy_config_write(struct vty *v)
|
||||||
|
{
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int config_write_trx(struct vty *vty)
|
||||||
|
{
|
||||||
|
struct trx_chan *chan;
|
||||||
|
int i;
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
vty_out(vty, "trx%s", VTY_NEWLINE);
|
||||||
|
if (trx->cfg.bind_addr)
|
||||||
|
vty_out(vty, " bind-ip %s%s", trx->cfg.bind_addr, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.remote_addr)
|
||||||
|
vty_out(vty, " remote-ip %s%s", trx->cfg.remote_addr, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.base_port != DEFAULT_TRX_PORT)
|
||||||
|
vty_out(vty, " base-port %u%s", trx->cfg.base_port, VTY_NEWLINE);
|
||||||
|
if (strlen(trx->cfg.dev_args))
|
||||||
|
vty_out(vty, " dev-args %s%s", trx->cfg.dev_args, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.tx_sps != DEFAULT_TX_SPS)
|
||||||
|
vty_out(vty, " tx-sps %u%s", trx->cfg.tx_sps, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.rx_sps != DEFAULT_RX_SPS)
|
||||||
|
vty_out(vty, " rx-sps %u%s", trx->cfg.rx_sps, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.clock_ref != REF_INTERNAL)
|
||||||
|
vty_out(vty, " clock-ref %s%s", get_value_string(clock_ref_names, trx->cfg.clock_ref), VTY_NEWLINE);
|
||||||
|
vty_out(vty, " multi-arfcn %s%s", trx->cfg.multi_arfcn ? "enable" : "disable", VTY_NEWLINE);
|
||||||
|
if (trx->cfg.offset != 0)
|
||||||
|
vty_out(vty, " offset %f%s", trx->cfg.offset, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.freq_offset_khz != 0)
|
||||||
|
vty_out(vty, " freq-offset %f%s", trx->cfg.freq_offset_khz, VTY_NEWLINE);
|
||||||
|
if (!(trx->cfg.rssi_offset == 0 && !trx->cfg.force_rssi_offset))
|
||||||
|
vty_out(vty, " rssi-offset %f%s%s", trx->cfg.rssi_offset,
|
||||||
|
trx->cfg.force_rssi_offset ? " relative": "", VTY_NEWLINE);
|
||||||
|
vty_out(vty, " swap-channels %s%s", trx->cfg.swap_channels ? "enable" : "disable", VTY_NEWLINE);
|
||||||
|
vty_out(vty, " egprs %s%s", trx->cfg.egprs ? "enable" : "disable", VTY_NEWLINE);
|
||||||
|
vty_out(vty, " ext-rach %s%s", trx->cfg.ext_rach ? "enable" : "disable", VTY_NEWLINE);
|
||||||
|
if (trx->cfg.sched_rr != 0)
|
||||||
|
vty_out(vty, " rt-prio %u%s", trx->cfg.sched_rr, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.filler != FILLER_ZERO)
|
||||||
|
vty_out(vty, " filler type %s%s", get_value_string(filler_types, trx->cfg.filler), VTY_NEWLINE);
|
||||||
|
if (trx->cfg.rtsc > 0)
|
||||||
|
vty_out(vty, " filler tsc %u%s", trx->cfg.rtsc, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.rach_delay > 0)
|
||||||
|
vty_out(vty, " filler access-burst-delay %u%s", trx->cfg.rach_delay, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.stack_size != 0)
|
||||||
|
vty_out(vty, " stack-size %u%s", trx->cfg.stack_size, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.ul_fn_offset != 0)
|
||||||
|
vty_out(vty, " ul-fn-offset %d%s", trx->cfg.ul_fn_offset, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.overrides.dl_freq_override)
|
||||||
|
vty_out(vty, " dl-freq-override %f%s", trx->cfg.overrides.dl_freq, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.overrides.ul_freq_override)
|
||||||
|
vty_out(vty, " ul-freq-override %f%s", trx->cfg.overrides.ul_freq, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.overrides.dl_gain_override)
|
||||||
|
vty_out(vty, " dl-gain-override %f%s", trx->cfg.overrides.dl_gain, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.overrides.ul_gain_override)
|
||||||
|
vty_out(vty, " ul-gain-override %f%s", trx->cfg.overrides.ul_gain, VTY_NEWLINE);
|
||||||
|
if (trx->cfg.use_va)
|
||||||
|
vty_out(vty, " viterbi-eq %s%s", trx->cfg.use_va ? "enable" : "disable", VTY_NEWLINE);
|
||||||
|
trx_rate_ctr_threshold_write_config(vty, " ");
|
||||||
|
|
||||||
|
for (i = 0; i < trx->cfg.num_chans; i++) {
|
||||||
|
chan = &trx->cfg.chans[i];
|
||||||
|
vty_out(vty, " chan %u%s", chan->idx, VTY_NEWLINE);
|
||||||
|
if (chan->rx_path)
|
||||||
|
vty_out(vty, " rx-path %s%s", chan->rx_path, VTY_NEWLINE);
|
||||||
|
if (chan->tx_path)
|
||||||
|
vty_out(vty, " tx-path %s%s", chan->tx_path, VTY_NEWLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void trx_dump_vty(struct vty *vty, struct trx_ctx *trx)
|
||||||
|
{
|
||||||
|
struct trx_chan *chan;
|
||||||
|
int i;
|
||||||
|
vty_out(vty, "TRX Config:%s", VTY_NEWLINE);
|
||||||
|
vty_out(vty, " Local IP: %s%s", trx->cfg.bind_addr, VTY_NEWLINE);
|
||||||
|
vty_out(vty, " Remote IP: %s%s", trx->cfg.remote_addr, VTY_NEWLINE);
|
||||||
|
vty_out(vty, " TRX Base Port: %u%s", trx->cfg.base_port, VTY_NEWLINE);
|
||||||
|
vty_out(vty, " Device args: %s%s", trx->cfg.dev_args, VTY_NEWLINE);
|
||||||
|
vty_out(vty, " Tx Samples-per-Symbol: %u%s", trx->cfg.tx_sps, VTY_NEWLINE);
|
||||||
|
vty_out(vty, " Rx Samples-per-Symbol: %u%s", trx->cfg.rx_sps, VTY_NEWLINE);
|
||||||
|
vty_out(vty, " Filler Burst Type: %s%s", get_value_string(filler_names, trx->cfg.filler), VTY_NEWLINE);
|
||||||
|
vty_out(vty, " Filler Burst TSC: %u%s", trx->cfg.rtsc, VTY_NEWLINE);
|
||||||
|
vty_out(vty, " Filler Burst RACH Delay: %u%s", trx->cfg.rach_delay, VTY_NEWLINE);
|
||||||
|
vty_out(vty, " Clock Reference: %s%s", get_value_string(clock_ref_names, trx->cfg.clock_ref), VTY_NEWLINE);
|
||||||
|
vty_out(vty, " Multi-Carrier: %s%s", trx->cfg.multi_arfcn ? "Enabled" : "Disabled", VTY_NEWLINE);
|
||||||
|
vty_out(vty, " Tuning offset: %f%s", trx->cfg.offset, VTY_NEWLINE);
|
||||||
|
vty_out(vty, " RSSI to dBm offset: %f%s", trx->cfg.rssi_offset, VTY_NEWLINE);
|
||||||
|
vty_out(vty, " Swap channels: %s%s", trx->cfg.swap_channels ? "Enabled" : "Disabled", VTY_NEWLINE);
|
||||||
|
vty_out(vty, " EDGE support: %s%s", trx->cfg.egprs ? "Enabled" : "Disabled", VTY_NEWLINE);
|
||||||
|
vty_out(vty, " Extended RACH support: %s%s", trx->cfg.ext_rach ? "Enabled" : "Disabled", VTY_NEWLINE);
|
||||||
|
vty_out(vty, " Real Time Priority: %u (%s)%s", trx->cfg.sched_rr,
|
||||||
|
trx->cfg.sched_rr ? "Enabled" : "Disabled", VTY_NEWLINE);
|
||||||
|
vty_out(vty, " Stack size per Thread in BYTE (0 = OS default): %u%s", trx->cfg.stack_size, VTY_NEWLINE);
|
||||||
|
vty_out(vty, " Channels: %u%s", trx->cfg.num_chans, VTY_NEWLINE);
|
||||||
|
for (i = 0; i < trx->cfg.num_chans; i++) {
|
||||||
|
chan = &trx->cfg.chans[i];
|
||||||
|
vty_out(vty, " Channel %u:%s", chan->idx, VTY_NEWLINE);
|
||||||
|
if (chan->rx_path)
|
||||||
|
vty_out(vty, " Rx Path: %s%s", chan->rx_path, VTY_NEWLINE);
|
||||||
|
if (chan->tx_path)
|
||||||
|
vty_out(vty, " Tx Path: %s%s", chan->tx_path, VTY_NEWLINE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEFUN(show_trx, show_trx_cmd,
|
||||||
|
"show trx",
|
||||||
|
SHOW_STR "Display information on the TRX\n")
|
||||||
|
{
|
||||||
|
struct trx_ctx *trx = trx_from_vty(vty);
|
||||||
|
|
||||||
|
trx_dump_vty(vty, trx);
|
||||||
|
|
||||||
|
return CMD_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int trx_vty_is_config_node(struct vty *vty, int node)
|
||||||
|
{
|
||||||
|
switch (node) {
|
||||||
|
case TRX_NODE:
|
||||||
|
case CHAN_NODE:
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int trx_vty_go_parent(struct vty *vty)
|
||||||
|
{
|
||||||
|
switch (vty->node) {
|
||||||
|
case TRX_NODE:
|
||||||
|
vty->node = CONFIG_NODE;
|
||||||
|
vty->index = NULL;
|
||||||
|
vty->index_sub = NULL;
|
||||||
|
break;
|
||||||
|
case CHAN_NODE:
|
||||||
|
vty->node = TRX_NODE;
|
||||||
|
vty->index = NULL;
|
||||||
|
vty->index_sub = NULL;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vty->node = CONFIG_NODE;
|
||||||
|
vty->index = NULL;
|
||||||
|
vty->index_sub = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vty->node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const char trx_copyright[] =
|
||||||
|
"Copyright (C) 2007-2014 Free Software Foundation, Inc.\r\n"
|
||||||
|
"Copyright (C) 2013 Thomas Tsou <tom@tsou.cc>\r\n"
|
||||||
|
"Copyright (C) 2013-2019 Fairwaves, Inc.\r\n"
|
||||||
|
"Copyright (C) 2015 Ettus Research LLC\r\n"
|
||||||
|
"Copyright (C) 2017-2018 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>\r\n"
|
||||||
|
"License AGPLv3+: GNU AGPL version 3 or later <http://gnu.org/licenses/agpl-3.0.html>\r\n"
|
||||||
|
"This is free software: you are free to change and redistribute it.\r\n"
|
||||||
|
"There is NO WARRANTY, to the extent permitted by law.\r\n";
|
||||||
|
|
||||||
|
struct vty_app_info g_vty_info = {
|
||||||
|
.name = "OsmoTRX",
|
||||||
|
.version = PACKAGE_VERSION,
|
||||||
|
.copyright = trx_copyright,
|
||||||
|
.go_parent_cb = trx_vty_go_parent,
|
||||||
|
.is_config_node = trx_vty_is_config_node,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct trx_ctx *vty_trx_ctx_alloc(void *talloc_ctx)
|
||||||
|
{
|
||||||
|
struct trx_ctx * trx = talloc_zero(talloc_ctx, struct trx_ctx);
|
||||||
|
|
||||||
|
trx->cfg.bind_addr = talloc_strdup(trx, DEFAULT_TRX_IP);
|
||||||
|
trx->cfg.remote_addr = talloc_strdup(trx, DEFAULT_TRX_IP);
|
||||||
|
trx->cfg.base_port = DEFAULT_TRX_PORT;
|
||||||
|
trx->cfg.tx_sps = DEFAULT_TX_SPS;
|
||||||
|
trx->cfg.rx_sps = DEFAULT_RX_SPS;
|
||||||
|
trx->cfg.filler = FILLER_ZERO;
|
||||||
|
trx->cfg.rssi_offset = 0.0f;
|
||||||
|
trx->cfg.dev_args = talloc_strdup(trx, "");
|
||||||
|
|
||||||
|
return trx;
|
||||||
|
}
|
||||||
|
|
||||||
|
int trx_vty_init(struct trx_ctx* trx)
|
||||||
|
{
|
||||||
|
cfg_filler_type_cmd.string = vty_cmd_string_from_valstr(trx, filler_types,
|
||||||
|
"filler type (", "|", ")", 0);
|
||||||
|
cfg_filler_type_cmd.doc = vty_cmd_string_from_valstr(trx, filler_docs,
|
||||||
|
CFG_FILLER_DOC_STR "What to do when there is nothing to send "
|
||||||
|
"(filler type, default=zero)\n", "\n", "", 0);
|
||||||
|
|
||||||
|
g_trx_ctx = trx;
|
||||||
|
install_element_ve(&show_trx_cmd);
|
||||||
|
|
||||||
|
install_element(CONFIG_NODE, &cfg_trx_cmd);
|
||||||
|
|
||||||
|
install_node(&trx_node, config_write_trx);
|
||||||
|
install_element(TRX_NODE, &cfg_bind_ip_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_remote_ip_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_base_port_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_dev_args_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_tx_sps_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_rx_sps_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_clock_ref_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_multi_arfcn_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_offset_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_freq_offset_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_rssi_offset_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_swap_channels_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_egprs_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_ext_rach_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_rt_prio_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_filler_type_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_filler_tsc_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_filler_rach_delay_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_ctr_error_threshold_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_no_ctr_error_threshold_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_stack_size_cmd);
|
||||||
|
|
||||||
|
install_element(TRX_NODE, &cfg_chan_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_ul_fn_offset_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_ul_freq_override_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_dl_freq_override_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_ul_gain_override_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_dl_gain_override_cmd);
|
||||||
|
install_element(TRX_NODE, &cfg_use_viterbi_cmd);
|
||||||
|
install_node(&chan_node, dummy_config_write);
|
||||||
|
install_element(CHAN_NODE, &cfg_chan_rx_path_cmd);
|
||||||
|
install_element(CHAN_NODE, &cfg_chan_tx_path_cmd);
|
||||||
|
|
||||||
|
logging_vty_add_deprecated_subsys(g_trx_ctx, "lms");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
41
CommonLibs/trx_vty.h
Normal file
41
CommonLibs/trx_vty.h
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <osmocom/vty/command.h>
|
||||||
|
|
||||||
|
#include "config_defs.h"
|
||||||
|
|
||||||
|
extern struct vty_app_info g_vty_info;
|
||||||
|
extern const struct value_string clock_ref_names[];
|
||||||
|
extern const struct value_string filler_names[];
|
||||||
|
|
||||||
|
/* Maximum number of carriers in multi-ARFCN mode */
|
||||||
|
#define TRX_MCHAN_MAX 3
|
||||||
|
|
||||||
|
/* Samples-per-symbol for downlink path
|
||||||
|
* 4 - Uses precision modulator (more computation, less distortion)
|
||||||
|
* 1 - Uses minimized modulator (less computation, more distortion)
|
||||||
|
*
|
||||||
|
* Other values are invalid. Receive path (uplink) is always
|
||||||
|
* downsampled to 1 sps. Default to 4 sps for all cases.
|
||||||
|
*/
|
||||||
|
#define DEFAULT_TX_SPS 4
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Samples-per-symbol for uplink (receiver) path
|
||||||
|
* Do not modify this value. EDGE configures 4 sps automatically on
|
||||||
|
* B200/B210 devices only. Use of 4 sps on the receive path for other
|
||||||
|
* configurations is not supported.
|
||||||
|
*/
|
||||||
|
#define DEFAULT_RX_SPS 1
|
||||||
|
|
||||||
|
/* Default configuration parameters */
|
||||||
|
#define DEFAULT_TRX_PORT 5700
|
||||||
|
#define DEFAULT_TRX_IP "127.0.0.1"
|
||||||
|
#define DEFAULT_CHANS 1
|
||||||
|
|
||||||
|
struct trx_ctx {
|
||||||
|
struct trx_cfg cfg;
|
||||||
|
};
|
||||||
|
|
||||||
|
int trx_vty_init(struct trx_ctx* trx);
|
||||||
|
struct trx_ctx *vty_trx_ctx_alloc(void *talloc_ctx);
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
* Copyright 2008 Free Software Foundation, Inc.
|
* Copyright 2008 Free Software Foundation, Inc.
|
||||||
* Copyright 2011 Range Networks, Inc.
|
* Copyright 2011 Range Networks, Inc.
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
* This software is distributed under the terms of the GNU Affero Public License.
|
||||||
* See the COPYING file in the main directory for details.
|
* See the COPYING file in the main directory for details.
|
||||||
*
|
*
|
||||||
@@ -53,8 +55,14 @@ const BitVector GSM::gEdgeTrainingSequence[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const BitVector GSM::gDummyBurst("0001111101101110110000010100100111000001001000100000001111100011100010111000101110001010111010010100011001100111001111010011111000100101111101010000");
|
const BitVector GSM::gDummyBurst("0001111101101110110000010100100111000001001000100000001111100011100010111000101110001010111010010100011001100111001111010011111000100101111101010000");
|
||||||
|
const BitVector GSM::gDummyBurstTSC("01110001011100010111000101");
|
||||||
|
|
||||||
const BitVector GSM::gRACHSynchSequence("01001011011111111001100110101010001111000");
|
/* 3GPP TS 05.02, section 5.2.7 "Access burst (AB)", synch. sequence bits */
|
||||||
|
const BitVector GSM::gRACHSynchSequenceTS0("01001011011111111001100110101010001111000"); /* GSM, GMSK (default) */
|
||||||
|
const BitVector GSM::gRACHSynchSequenceTS1("01010100111110001000011000101111001001101"); /* EGPRS, 8-PSK */
|
||||||
|
const BitVector GSM::gRACHSynchSequenceTS2("11101111001001110101011000001101101110111"); /* EGPRS, GMSK */
|
||||||
|
|
||||||
|
const BitVector GSM::gSCHSynchSequence("1011100101100010000001000000111100101101010001010111011000011011");
|
||||||
|
|
||||||
// |-head-||---------midamble----------------------||--------------data----------------||t|
|
// |-head-||---------midamble----------------------||--------------data----------------||t|
|
||||||
const BitVector GSM::gRACHBurst("0011101001001011011111111001100110101010001111000110111101111110000111001001010110011000");
|
const BitVector GSM::gRACHBurst("0011101001001011011111111001100110101010001111000110111101111110000111001001010110011000");
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008-2011 Free Software Foundation, Inc.
|
* Copyright 2008-2011 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
* This software is distributed under the terms of the GNU Affero Public License.
|
* This software is distributed under the terms of the GNU Affero Public License.
|
||||||
* See the COPYING file in the main directory for details.
|
* See the COPYING file in the main directory for details.
|
||||||
*
|
*
|
||||||
@@ -50,9 +52,16 @@ extern const BitVector gEdgeTrainingSequence[];
|
|||||||
|
|
||||||
/** C0T0 filler burst, GSM 05.02, 5.2.6 */
|
/** C0T0 filler burst, GSM 05.02, 5.2.6 */
|
||||||
extern const BitVector gDummyBurst;
|
extern const BitVector gDummyBurst;
|
||||||
|
extern const BitVector gDummyBurstTSC;
|
||||||
|
|
||||||
/** Random access burst synch. sequence */
|
/** Random access burst synch. sequence */
|
||||||
extern const BitVector gRACHSynchSequence;
|
extern const BitVector gRACHSynchSequenceTS0;
|
||||||
|
extern const BitVector gRACHSynchSequenceTS1;
|
||||||
|
extern const BitVector gRACHSynchSequenceTS2;
|
||||||
|
|
||||||
|
/** Synchronization burst sync sequence */
|
||||||
|
extern const BitVector gSCHSynchSequence;
|
||||||
|
|
||||||
/** Random access burst synch. sequence, GSM 05.02 5.2.7 */
|
/** Random access burst synch. sequence, GSM 05.02 5.2.7 */
|
||||||
extern const BitVector gRACHBurst;
|
extern const BitVector gRACHBurst;
|
||||||
|
|
||||||
@@ -164,7 +173,7 @@ class Time {
|
|||||||
unsigned newTN = (mTN + other.mTN) % 8;
|
unsigned newTN = (mTN + other.mTN) % 8;
|
||||||
uint64_t newFN = (mFN+other.mFN + (mTN + other.mTN)/8) % gHyperframe;
|
uint64_t newFN = (mFN+other.mFN + (mTN + other.mTN)/8) % gHyperframe;
|
||||||
return Time(newFN,newTN);
|
return Time(newFN,newTN);
|
||||||
}
|
}
|
||||||
|
|
||||||
int operator-(const Time& other) const
|
int operator-(const Time& other) const
|
||||||
{
|
{
|
||||||
|
|||||||
33
INSTALLATION
33
INSTALLATION
@@ -1,33 +0,0 @@
|
|||||||
Installation Requirements
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
OpenBTS compiles to a simple Unix binary and does not require special
|
|
||||||
installation.
|
|
||||||
|
|
||||||
One some systems (Ubuntu), you will need to define LIBS = -lpthread prior to
|
|
||||||
running configure.
|
|
||||||
|
|
||||||
To run OpenBTS, the following should be installed:
|
|
||||||
|
|
||||||
Asterisk (http://www.asterisk.org), running SIP on port 5060.
|
|
||||||
|
|
||||||
libosip2 (http://www.gnu.org/software/osip/)
|
|
||||||
|
|
||||||
libortp (http://freshmeat.net/projects/ortp/)
|
|
||||||
|
|
||||||
libusrp (http://gnuradio.org).
|
|
||||||
This is part of the GNURadio installation.
|
|
||||||
It is the only part used by OpenBTS.
|
|
||||||
|
|
||||||
|
|
||||||
OpenBTS logs to syslogd as facility LOG_LOCAL7. Please set your /etc/syslog.conf
|
|
||||||
accordingly.
|
|
||||||
|
|
||||||
|
|
||||||
For information on specific executables, see tests/README.tests and
|
|
||||||
apps/README.apps.
|
|
||||||
|
|
||||||
See http://gnuradio.org/redmine/wiki/gnuradio/OpenBTS/BuildingAndRunning for more
|
|
||||||
information.
|
|
||||||
|
|
||||||
20
LEGAL
20
LEGAL
@@ -1,5 +1,8 @@
|
|||||||
OpenBTS
|
OpenBTS
|
||||||
|
|
||||||
|
The OsmoTRX project is direved from OpenBTS transceiver code. See http://openbts.org/ for details.
|
||||||
|
|
||||||
|
The related copyrights:
|
||||||
Most parts copyright 2008-2011 Free Software Foundation.
|
Most parts copyright 2008-2011 Free Software Foundation.
|
||||||
Some parts copyright 2010 Kestrel Signal Processing, Inc.
|
Some parts copyright 2010 Kestrel Signal Processing, Inc.
|
||||||
Some parts copyright 2011 Range Networks, Inc.
|
Some parts copyright 2011 Range Networks, Inc.
|
||||||
@@ -12,17 +15,9 @@ patented technologies. The user of this software is required to take whatever
|
|||||||
actions are necessary to avoid patent infringement.
|
actions are necessary to avoid patent infringement.
|
||||||
|
|
||||||
|
|
||||||
Trademark
|
|
||||||
|
|
||||||
"OpenBTS" is a registered trademark of Range Networks, Inc. (Range), a
|
|
||||||
California corporation. Range reserves the right to control the use of this
|
|
||||||
trademark. Do not use this trademark in commerce without permission and do not
|
|
||||||
rebrand OpenBTS under a different trademark.
|
|
||||||
|
|
||||||
|
|
||||||
Telecom and Radio Spectrum Laws
|
Telecom and Radio Spectrum Laws
|
||||||
|
|
||||||
The primary function of OpenBTS is the provision of telecommunications service
|
The primary function of OsmoTRX is the provision of telecommunications service
|
||||||
over a radio link. This activity is heavily regulated nearly everywhere in
|
over a radio link. This activity is heavily regulated nearly everywhere in
|
||||||
the world. Users of this software are expected to comply with local and national
|
the world. Users of this software are expected to comply with local and national
|
||||||
regulations in the jurisdictions where this sortware is used with radio equipment.
|
regulations in the jurisdictions where this sortware is used with radio equipment.
|
||||||
@@ -39,7 +34,7 @@ The legal restrictions listed here are not necessarily exhaustive.
|
|||||||
|
|
||||||
Note to US Government Users
|
Note to US Government Users
|
||||||
|
|
||||||
The OpenBTS software applications and associated documentation are "Commercial
|
The OsmoTRX software applications and associated documentation are "Commercial
|
||||||
Item(s)," as that term is defined at 48 C.F.R. Section 2.101, consisting of
|
Item(s)," as that term is defined at 48 C.F.R. Section 2.101, consisting of
|
||||||
"Commercial Computer Software" and "Commercial Computer Software Documentation,"
|
"Commercial Computer Software" and "Commercial Computer Software Documentation,"
|
||||||
as such terms are used in 48 C.F.R. 12.212 or 48 C.F.R. 227.7202, as
|
as such terms are used in 48 C.F.R. 12.212 or 48 C.F.R. 227.7202, as
|
||||||
@@ -54,13 +49,12 @@ and AGPLv3.
|
|||||||
Note to US Government Contractors
|
Note to US Government Contractors
|
||||||
|
|
||||||
GPL is not compatible with "government purpose rights" (GPR). If you receive
|
GPL is not compatible with "government purpose rights" (GPR). If you receive
|
||||||
OpenBTS software under a GPL and deliver it under GPR, you will be in violation
|
OsmoTRX software under a GPL and deliver it under GPR, you will be in violation
|
||||||
of GPL and possibly subject to enforcement actions by the original authors and
|
of GPL and possibly subject to enforcement actions by the original authors and
|
||||||
copyright holders, including the Free Software Foundation, Inc.
|
copyright holders, including the Free Software Foundation, Inc.
|
||||||
|
|
||||||
|
|
||||||
Software Licensing and Distribution
|
Software Licensing and Distribution
|
||||||
|
|
||||||
A subset of OpenBTS is distributed publicly under AGPLv3. Range reserves the right to
|
The OsmoTRX is distributed publicly under AGPLv3. See the COPYING file
|
||||||
distribute most of this source code other licenses as well. See the COPYING file
|
|
||||||
for more information on the license for this distribution.
|
for more information on the license for this distribution.
|
||||||
|
|||||||
43
Makefile.am
43
Makefile.am
@@ -21,24 +21,49 @@
|
|||||||
include $(top_srcdir)/Makefile.common
|
include $(top_srcdir)/Makefile.common
|
||||||
|
|
||||||
ACLOCAL_AMFLAGS = -I config
|
ACLOCAL_AMFLAGS = -I config
|
||||||
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(USB_INCLUDES) $(WITH_INCLUDES) $(SQLITE3_CFLAGS)
|
AM_CPPFLAGS = $(STD_DEFINES_AND_INCLUDES) $(USB_INCLUDES) $(WITH_INCLUDES)
|
||||||
AM_CXXFLAGS = -Wall -pthread -ldl
|
AM_CXXFLAGS = -Wall -pthread
|
||||||
#AM_CXXFLAGS = -Wall -O2 -NDEBUG -pthread -ldl
|
#AM_CXXFLAGS = -Wall -O2 -NDEBUG -pthread
|
||||||
#AM_CFLAGS = -Wall -O2 -NDEBUG -pthread -ldl
|
#AM_CFLAGS = -Wall -O2 -NDEBUG -pthread
|
||||||
|
|
||||||
|
SUBDIRS =
|
||||||
|
|
||||||
|
if ENABLE_MS_TRX
|
||||||
|
SUBDIRS += $(LIBTRXCON_DIR)
|
||||||
|
endif
|
||||||
|
|
||||||
# Order must be preserved
|
# Order must be preserved
|
||||||
SUBDIRS = \
|
SUBDIRS += \
|
||||||
CommonLibs \
|
CommonLibs \
|
||||||
GSM \
|
GSM \
|
||||||
Transceiver52M
|
Transceiver52M \
|
||||||
|
contrib \
|
||||||
|
tests \
|
||||||
|
utils \
|
||||||
|
doc \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
BUILT_SOURCES = $(top_srcdir)/.version
|
||||||
|
$(top_srcdir)/.version:
|
||||||
|
echo $(VERSION) > $@-t && mv $@-t $@
|
||||||
|
dist-hook:
|
||||||
|
echo $(VERSION) > $(distdir)/.tarball-version
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
autogen.sh \
|
.version \
|
||||||
INSTALLATION \
|
|
||||||
LEGAL \
|
LEGAL \
|
||||||
COPYING \
|
COPYING \
|
||||||
README
|
README.md \
|
||||||
|
debian \
|
||||||
|
git-version-gen \
|
||||||
|
$(NULL)
|
||||||
|
|
||||||
|
AM_DISTCHECK_CONFIGURE_FLAGS = \
|
||||||
|
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
|
||||||
|
|
||||||
|
.PHONY: release
|
||||||
|
|
||||||
|
@RELMAKE@
|
||||||
|
|
||||||
dox: FORCE
|
dox: FORCE
|
||||||
doxygen doxconfig
|
doxygen doxconfig
|
||||||
|
|||||||
@@ -18,9 +18,6 @@
|
|||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
#
|
#
|
||||||
|
|
||||||
top_srcdir = $(abs_top_srcdir)
|
|
||||||
top_builddir = $(abs_top_builddir)
|
|
||||||
|
|
||||||
COMMON_INCLUDEDIR = $(top_srcdir)/CommonLibs
|
COMMON_INCLUDEDIR = $(top_srcdir)/CommonLibs
|
||||||
GSM_INCLUDEDIR = $(top_srcdir)/GSM
|
GSM_INCLUDEDIR = $(top_srcdir)/GSM
|
||||||
|
|
||||||
@@ -32,4 +29,10 @@ STD_DEFINES_AND_INCLUDES = \
|
|||||||
COMMON_LA = $(top_builddir)/CommonLibs/libcommon.la
|
COMMON_LA = $(top_builddir)/CommonLibs/libcommon.la
|
||||||
GSM_LA = $(top_builddir)/GSM/libGSM.la
|
GSM_LA = $(top_builddir)/GSM/libGSM.la
|
||||||
|
|
||||||
|
if ARCH_ARM
|
||||||
|
ARCH_LA = $(top_builddir)/Transceiver52M/arch/arm/libarch.la
|
||||||
|
else
|
||||||
|
ARCH_LA = $(top_builddir)/Transceiver52M/arch/x86/libarch.la
|
||||||
|
endif
|
||||||
|
|
||||||
MOSTLYCLEANFILES = *~
|
MOSTLYCLEANFILES = *~
|
||||||
|
|||||||
116
README
116
README
@@ -1,116 +0,0 @@
|
|||||||
This is the interface to the transcevier.
|
|
||||||
|
|
||||||
Each TRX Manager UDP socket interface represents a single ARFCN.
|
|
||||||
Each of these per-ARFCN interfaces is a pair of UDP sockets, one for control and one for data.
|
|
||||||
Give a base port B (5700), the master clock interface is at port P=B.
|
|
||||||
The TRX-side control interface for C(N) is on port P=B+2N+1 and the data interface is on an odd numbered port P=B+2N+2.
|
|
||||||
The corresponding core-side interface for every socket is at P+100.
|
|
||||||
For any given build, the number of ARFCN interfaces can be fixed.
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Indications on the Master Clock Interface
|
|
||||||
|
|
||||||
The master clock interface is output only (from the radio).
|
|
||||||
Messages are "indications".
|
|
||||||
|
|
||||||
CLOCK gives the current value of the transceiver clock to be used by the core.
|
|
||||||
This message is sent whenever a trasmission packet arrives that is too late or too early. The clock value is NOT the current transceiver time. It is a time setting the the core should use to give better packet arrival times.
|
|
||||||
IND CLOCK <totalFrames>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Commands on the Per-ARFCN Control Interface
|
|
||||||
|
|
||||||
The per-ARFCN control interface uses a command-reponse protocol.
|
|
||||||
Commands are NULL-terminated ASCII strings, one per UDP socket.
|
|
||||||
Each command has a corresponding response.
|
|
||||||
Every command is of the form:
|
|
||||||
|
|
||||||
CMD <cmdtype> [params]
|
|
||||||
|
|
||||||
The <cmdtype> is the actual command.
|
|
||||||
Parameters are optional depending on the commands type.
|
|
||||||
Every response is of the form:
|
|
||||||
|
|
||||||
RSP <cmdtype> <status> [result]
|
|
||||||
|
|
||||||
The <status> is 0 for success and a non-zero error code for failure.
|
|
||||||
Successful responses may include results, depending on the command type.
|
|
||||||
|
|
||||||
|
|
||||||
Power Control
|
|
||||||
|
|
||||||
POWEROFF shuts off transmitter power and stops the demodulator.
|
|
||||||
CMD POWEROFF
|
|
||||||
RSP POWEROFF <status>
|
|
||||||
|
|
||||||
POWERON starts the transmitter and starts the demodulator. Initial power level is very low.
|
|
||||||
This command fails if the transmitter and receiver are not yet tuned.
|
|
||||||
This command fails if the transmit or receive frequency creates a conflict with another ARFCN that is already runnng.
|
|
||||||
If the transceiver is already on, it response with success to this command.
|
|
||||||
CMD POWERON
|
|
||||||
RSP POWERON <status>
|
|
||||||
|
|
||||||
SETPOWER sets output power in dB wrt full scale.
|
|
||||||
This command fails if the transmitter and receiver are not running.
|
|
||||||
CMD SETPOWER <dB>
|
|
||||||
RSP SETPOWER <status> <dB>
|
|
||||||
|
|
||||||
ADJPOWER adjusts power by the given dB step. Response returns resulting power level wrt full scale.
|
|
||||||
This command fails if the transmitter and receiver are not running.
|
|
||||||
CMD ADJPOWER <dBStep>
|
|
||||||
RSP ADJPOWER <status> <dBLevel>
|
|
||||||
|
|
||||||
|
|
||||||
Tuning Control
|
|
||||||
|
|
||||||
RXTUNE tunes the receiver to a given frequency in kHz.
|
|
||||||
This command fails if the receiver is already running.
|
|
||||||
(To re-tune you stop the radio, re-tune, and restart.)
|
|
||||||
This command fails if the transmit or receive frequency creates a conflict with another ARFCN that is already runnng.
|
|
||||||
CMD RXTUNE <kHz>
|
|
||||||
RSP RXTUNE <status> <kHz>
|
|
||||||
|
|
||||||
TXTUNE tunes the transmitter to a given frequency in kHz.
|
|
||||||
This command fails if the transmitter is already running.
|
|
||||||
(To re-tune you stop the radio, re-tune, and restart.)
|
|
||||||
This command fails if the transmit or receive frequency creates a conflict with another ARFCN that is already runnng.
|
|
||||||
CMD TXTUNE <kHz>
|
|
||||||
RSP TXTUNE <status> <kHz>
|
|
||||||
|
|
||||||
|
|
||||||
Timeslot Control
|
|
||||||
|
|
||||||
SETSLOT sets the format of the uplink timeslots in the ARFCN.
|
|
||||||
The <timeslot> indicates the timeslot of interest.
|
|
||||||
The <chantype> indicates the type of channel that occupies the timeslot.
|
|
||||||
A chantype of zero indicates the timeslot is off.
|
|
||||||
CMD SETSLOT <timeslot> <chantype>
|
|
||||||
RSP SETSLOT <status> <timeslot> <chantype>
|
|
||||||
|
|
||||||
|
|
||||||
Messages on the per-ARFCN Data Interface
|
|
||||||
|
|
||||||
Messages on the data interface carry one radio burst per UDP message.
|
|
||||||
|
|
||||||
|
|
||||||
Received Data Burst
|
|
||||||
|
|
||||||
1 byte timeslot index
|
|
||||||
4 bytes GSM frame number, big endian
|
|
||||||
1 byte RSSI in -dBm
|
|
||||||
2 bytes correlator timing offset in 1/256 symbol steps, 2's-comp, big endian
|
|
||||||
148 bytes soft symbol estimates, 0 -> definite "0", 255 -> definite "1"
|
|
||||||
|
|
||||||
|
|
||||||
Transmit Data Burst
|
|
||||||
|
|
||||||
1 byte timeslot index
|
|
||||||
4 bytes GSM frame number, big endian
|
|
||||||
1 byte transmit level wrt ARFCN max, -dB (attenuation)
|
|
||||||
148 bytes output symbol values, 0 & 1
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
78
README.md
Normal file
78
README.md
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
About OsmoTRX
|
||||||
|
=============
|
||||||
|
|
||||||
|
OsmoTRX is a software-defined radio transceiver that implements the Layer 1
|
||||||
|
physical layer of a BTS comprising the following 3GPP specifications:
|
||||||
|
|
||||||
|
* TS 05.01 *Physical layer on the radio path*
|
||||||
|
* TS 05.02 *Multiplexing and Multiple Access on the Radio Path*
|
||||||
|
* TS 05.04 *Modulation*
|
||||||
|
* TS 05.10 *Radio subsystem synchronization*
|
||||||
|
|
||||||
|
OsmoTRX is originally based on the transceiver code from the
|
||||||
|
[OpenBTS](https://osmocom.org/projects/osmobts/wiki/OpenBTS) project, but setup
|
||||||
|
to operate independently with the purpose of using with non-OpenBTS software and
|
||||||
|
projects, specifically within the Osmocom stack. Used together with
|
||||||
|
[OsmoBTS](https://osmocom.org/projects/osmobts/wiki) you can get a pretty
|
||||||
|
standard GSM/GPRS/EGPRS BTS with Abis interface as per the relevant 3GPP specifications.
|
||||||
|
|
||||||
|
Homepage
|
||||||
|
--------
|
||||||
|
|
||||||
|
The official homepage of the project is
|
||||||
|
<https://osmocom.org/projects/osmotrx/wiki/OsmoTRX>
|
||||||
|
|
||||||
|
GIT Repository
|
||||||
|
--------------
|
||||||
|
|
||||||
|
You can clone from the official osmo-trx.git repository using
|
||||||
|
|
||||||
|
git clone https://gitea.osmocom.org/cellular-infrastructure/osmo-trx
|
||||||
|
|
||||||
|
There is a web interface at <https://gitea.osmocom.org/cellular-infrastructure/osmo-trx>
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Doxygen-generated API documentation is generated during the build process, but
|
||||||
|
also available online for each of the sub-libraries at User Manual for OsmoTRX
|
||||||
|
can be generated during the build process, and is also available online at
|
||||||
|
<https://ftp.osmocom.org/docs/latest/osmotrx-usermanual.pdf>.
|
||||||
|
|
||||||
|
Forum
|
||||||
|
-----
|
||||||
|
|
||||||
|
We welcome any osmo-trx related discussions in the
|
||||||
|
[Cellular Network Infrastructure -> 2 RAN (GERAN)](https://discourse.osmocom.org/c/cni/geran)
|
||||||
|
section of the osmocom discourse (web based Forum).
|
||||||
|
|
||||||
|
Mailing List
|
||||||
|
------------
|
||||||
|
|
||||||
|
Discussions related to OsmoTRX are happening on the openbsc@lists.osmocom.org
|
||||||
|
mailing list, please see <https://lists.osmocom.org/mailman/listinfo/openbsc>
|
||||||
|
for subscription options and the list archive.
|
||||||
|
|
||||||
|
Please observe the [Osmocom Mailing List
|
||||||
|
Rules](https://osmocom.org/projects/cellular-infrastructure/wiki/Mailing_List_Rules)
|
||||||
|
when posting.
|
||||||
|
|
||||||
|
Issue Tracker
|
||||||
|
-------------
|
||||||
|
|
||||||
|
We use the [issue tracker of the osmo-trx project on osmocom.org](https://osmocom.org/projects/osmotrx/issues) for
|
||||||
|
tracking the state of bug reports and feature requests. Feel free to submit any issues you may find, or help
|
||||||
|
us out by resolving existing issues.
|
||||||
|
|
||||||
|
Contributing
|
||||||
|
------------
|
||||||
|
|
||||||
|
Our coding standards are described at
|
||||||
|
<https://osmocom.org/projects/cellular-infrastructure/wiki/Coding_standards>
|
||||||
|
|
||||||
|
We use a Gerrit based patch submission/review process for managing contributions.
|
||||||
|
Please see <https://osmocom.org/projects/cellular-infrastructure/wiki/Gerrit>
|
||||||
|
for more details
|
||||||
|
|
||||||
|
The current patch queue for OsmoTRX can be seen at
|
||||||
|
<https://gerrit.osmocom.org/q/project:osmo-trx+status:open>
|
||||||
9
TODO-RELEASE
Normal file
9
TODO-RELEASE
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# When cleaning up this file: bump API version in corresponding Makefile.am and rename corresponding debian/lib*.install
|
||||||
|
# according to https://osmocom.org/projects/cellular-infrastructure/wiki/Make_a_new_release
|
||||||
|
# In short: https://www.gnu.org/software/libtool/manual/html_node/Updating-version-info.html#Updating-version-info
|
||||||
|
# LIBVERSION=c:r:a
|
||||||
|
# If the library source code has changed at all since the last update, then increment revision: c:r + 1:a.
|
||||||
|
# If any interfaces have been added, removed, or changed since the last update: c + 1:0:a.
|
||||||
|
# If any interfaces have been added since the last public release: c:r:a + 1.
|
||||||
|
# If any interfaces have been removed or changed since the last public release: c:r:0.
|
||||||
|
#library what description / commit summary line
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* Polyphase channelizer
|
* Polyphase channelizer
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2014 Tom Tsou <tom@tsou.cc>
|
* Copyright (C) 2012-2014 Tom Tsou <tom@tsou.cc>
|
||||||
* Copyright (C) 2015 Ettus Research LLC
|
* Copyright (C) 2015 Ettus Research LLC
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -25,12 +27,11 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#include "Logger.h"
|
|
||||||
#include "Channelizer.h"
|
#include "Channelizer.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "common/fft.h"
|
#include "fft.h"
|
||||||
#include "common/convolve.h"
|
#include "convolve.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
static void deinterleave(const float *in, size_t ilen,
|
static void deinterleave(const float *in, size_t ilen,
|
||||||
@@ -64,7 +65,7 @@ float *Channelizer::outputBuffer(size_t chan) const
|
|||||||
return hInputs[chan];
|
return hInputs[chan];
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Implementation based on material found in:
|
* Implementation based on material found in:
|
||||||
*
|
*
|
||||||
* "harris, fred, Multirate Signal Processing, Upper Saddle River, NJ,
|
* "harris, fred, Multirate Signal Processing, Upper Saddle River, NJ,
|
||||||
@@ -79,8 +80,8 @@ bool Channelizer::rotate(const float *in, size_t len)
|
|||||||
|
|
||||||
deinterleave(in, len, hInputs, blockLen, m);
|
deinterleave(in, len, hInputs, blockLen, m);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convolve through filterbank while applying and saving sample history
|
* Convolve through filterbank while applying and saving sample history
|
||||||
*/
|
*/
|
||||||
for (size_t i = 0; i < m; i++) {
|
for (size_t i = 0; i < m; i++) {
|
||||||
memcpy(&hInputs[i][2 * -hLen], hist[i], hSize);
|
memcpy(&hInputs[i][2 * -hLen], hist[i], hSize);
|
||||||
@@ -89,7 +90,7 @@ bool Channelizer::rotate(const float *in, size_t len)
|
|||||||
convolve_real(hInputs[i], blockLen,
|
convolve_real(hInputs[i], blockLen,
|
||||||
subFilters[i], hLen,
|
subFilters[i], hLen,
|
||||||
hOutputs[i], blockLen,
|
hOutputs[i], blockLen,
|
||||||
0, blockLen, 1, 0);
|
0, blockLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
cxvec_fft(fftHandle);
|
cxvec_fft(fftHandle);
|
||||||
@@ -97,7 +98,7 @@ bool Channelizer::rotate(const float *in, size_t len)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Setup channelizer paramaters */
|
/* Setup channelizer parameters */
|
||||||
Channelizer::Channelizer(size_t m, size_t blockLen, size_t hLen)
|
Channelizer::Channelizer(size_t m, size_t blockLen, size_t hLen)
|
||||||
: ChannelizerBase(m, blockLen, hLen)
|
: ChannelizerBase(m, blockLen, hLen)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
* Polyphase channelizer
|
* Polyphase channelizer
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2014 Tom Tsou <tom@tsou.cc>
|
* Copyright (C) 2012-2014 Tom Tsou <tom@tsou.cc>
|
||||||
* Copyright (C) 2015 Ettus Research LLC
|
* Copyright (C) 2015 Ettus Research LLC
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
@@ -29,7 +31,7 @@
|
|||||||
#include "ChannelizerBase.h"
|
#include "ChannelizerBase.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "common/fft.h"
|
#include "fft.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
static float sinc(float x)
|
static float sinc(float x)
|
||||||
@@ -55,10 +57,10 @@ static void reverse(float *buf, size_t len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create polyphase filterbank
|
* Create polyphase filterbank
|
||||||
*
|
*
|
||||||
* Implementation based material found in,
|
* Implementation based material found in,
|
||||||
*
|
*
|
||||||
* "harris, fred, Multirate Signal Processing, Upper Saddle River, NJ,
|
* "harris, fred, Multirate Signal Processing, Upper Saddle River, NJ,
|
||||||
* Prentice Hall, 2006."
|
* Prentice Hall, 2006."
|
||||||
@@ -70,7 +72,7 @@ bool ChannelizerBase::initFilters()
|
|||||||
float sum = 0.0f, scale = 0.0f;
|
float sum = 0.0f, scale = 0.0f;
|
||||||
float midpt = (float) (protoLen - 1.0) / 2.0;
|
float midpt = (float) (protoLen - 1.0) / 2.0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate 'M' partition filters and the temporary prototype
|
* Allocate 'M' partition filters and the temporary prototype
|
||||||
* filter. Coefficients are real only and must be 16-byte memory
|
* filter. Coefficients are real only and must be 16-byte memory
|
||||||
* aligned for SSE usage.
|
* aligned for SSE usage.
|
||||||
@@ -90,7 +92,7 @@ bool ChannelizerBase::initFilters()
|
|||||||
memalign(16, hLen * 2 * sizeof(float));
|
memalign(16, hLen * 2 * sizeof(float));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate the prototype filter with a Blackman-harris window.
|
* Generate the prototype filter with a Blackman-harris window.
|
||||||
* Scale coefficients with DC filter gain set to unity divided
|
* Scale coefficients with DC filter gain set to unity divided
|
||||||
* by the number of channels.
|
* by the number of channels.
|
||||||
@@ -110,7 +112,7 @@ bool ChannelizerBase::initFilters()
|
|||||||
}
|
}
|
||||||
scale = (float) m / sum;
|
scale = (float) m / sum;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Populate partition filters and reverse the coefficients per
|
* Populate partition filters and reverse the coefficients per
|
||||||
* convolution requirements.
|
* convolution requirements.
|
||||||
*/
|
*/
|
||||||
@@ -174,7 +176,7 @@ bool ChannelizerBase::mapBuffers()
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup filterbank internals
|
* Setup filterbank internals
|
||||||
*/
|
*/
|
||||||
bool ChannelizerBase::init()
|
bool ChannelizerBase::init()
|
||||||
@@ -222,11 +224,12 @@ bool ChannelizerBase::checkLen(size_t innerLen, size_t outerLen)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup channelizer paramaters
|
* Setup channelizer parameters
|
||||||
*/
|
*/
|
||||||
ChannelizerBase::ChannelizerBase(size_t m, size_t blockLen, size_t hLen)
|
ChannelizerBase::ChannelizerBase(size_t m, size_t blockLen, size_t hLen)
|
||||||
: fftInput(NULL), fftOutput(NULL), fftHandle(NULL)
|
: subFilters(NULL), hInputs(NULL), hOutputs(NULL), hist(NULL),
|
||||||
|
fftInput(NULL), fftOutput(NULL), fftHandle(NULL)
|
||||||
{
|
{
|
||||||
this->m = m;
|
this->m = m;
|
||||||
this->hLen = hLen;
|
this->hLen = hLen;
|
||||||
@@ -239,8 +242,9 @@ ChannelizerBase::~ChannelizerBase()
|
|||||||
|
|
||||||
for (size_t i = 0; i < m; i++) {
|
for (size_t i = 0; i < m; i++) {
|
||||||
free(subFilters[i]);
|
free(subFilters[i]);
|
||||||
delete hist[i];
|
delete[] hist[i];
|
||||||
}
|
}
|
||||||
|
free(subFilters);
|
||||||
|
|
||||||
fft_free(fftInput);
|
fft_free(fftInput);
|
||||||
fft_free(fftOutput);
|
fft_free(fftOutput);
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ protected:
|
|||||||
/* Buffer length validity checking */
|
/* Buffer length validity checking */
|
||||||
bool checkLen(size_t innerLen, size_t outerLen);
|
bool checkLen(size_t innerLen, size_t outerLen);
|
||||||
public:
|
public:
|
||||||
/* Initilize channelizer/synthesis filter internals */
|
/* Initialize channelizer/synthesis filter internals */
|
||||||
bool init();
|
bool init();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ unlike the built-in complex<> templates, these inline most operations for speed
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008 Free Software Foundation, Inc.
|
* Copyright 2008 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
|
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribution.
|
||||||
*
|
*
|
||||||
* This use of this software may be subject to additional restrictions.
|
* This use of this software may be subject to additional restrictions.
|
||||||
* See the LEGAL file in the main directory for details.
|
* See the LEGAL file in the main directory for details.
|
||||||
@@ -29,7 +29,7 @@ unlike the built-in complex<> templates, these inline most operations for speed
|
|||||||
template<class Real> class Complex {
|
template<class Real> class Complex {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
typedef Real value_type;
|
||||||
Real r, i;
|
Real r, i;
|
||||||
|
|
||||||
/**@name constructors */
|
/**@name constructors */
|
||||||
|
|||||||
@@ -21,34 +21,13 @@
|
|||||||
|
|
||||||
include $(top_srcdir)/Makefile.common
|
include $(top_srcdir)/Makefile.common
|
||||||
|
|
||||||
AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/common
|
SUBDIRS = arch device
|
||||||
AM_CXXFLAGS = -ldl -lpthread
|
|
||||||
|
|
||||||
SUBDIRS = arm x86
|
AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/arch/common -I${srcdir}/device/common
|
||||||
|
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)
|
||||||
|
AM_CFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOCTRL_CFLAGS) $(LIBOSMOVTY_CFLAGS)
|
||||||
|
|
||||||
if ARCH_ARM
|
noinst_LTLIBRARIES = libtransceiver_common.la
|
||||||
ARCH_LA = arm/libarch.la
|
|
||||||
else
|
|
||||||
ARCH_LA = x86/libarch.la
|
|
||||||
endif
|
|
||||||
|
|
||||||
if USRP1
|
|
||||||
AM_CPPFLAGS += $(USRP_CFLAGS)
|
|
||||||
else
|
|
||||||
AM_CPPFLAGS += $(UHD_CFLAGS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
rev2dir = $(datadir)/usrp/rev2
|
|
||||||
rev4dir = $(datadir)/usrp/rev4
|
|
||||||
|
|
||||||
dist_rev2_DATA = std_inband.rbf
|
|
||||||
dist_rev4_DATA = std_inband.rbf
|
|
||||||
|
|
||||||
EXTRA_DIST = \
|
|
||||||
README \
|
|
||||||
README.Talgorithm
|
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libtransceiver.la
|
|
||||||
|
|
||||||
COMMON_SOURCES = \
|
COMMON_SOURCES = \
|
||||||
radioInterface.cpp \
|
radioInterface.cpp \
|
||||||
@@ -61,56 +40,151 @@ COMMON_SOURCES = \
|
|||||||
ChannelizerBase.cpp \
|
ChannelizerBase.cpp \
|
||||||
Channelizer.cpp \
|
Channelizer.cpp \
|
||||||
Synthesis.cpp \
|
Synthesis.cpp \
|
||||||
common/fft.c
|
proto_trxd.c \
|
||||||
|
grgsm_vitac/grgsm_vitac.cpp \
|
||||||
|
grgsm_vitac/viterbi_detector.cc
|
||||||
|
|
||||||
libtransceiver_la_SOURCES = \
|
libtransceiver_common_la_SOURCES = \
|
||||||
$(COMMON_SOURCES) \
|
$(COMMON_SOURCES) \
|
||||||
Resampler.cpp \
|
Resampler.cpp \
|
||||||
radioInterfaceResamp.cpp \
|
radioInterfaceResamp.cpp \
|
||||||
radioInterfaceMulti.cpp
|
radioInterfaceMulti.cpp
|
||||||
|
|
||||||
bin_PROGRAMS = osmo-trx osmo-siggen
|
|
||||||
|
|
||||||
noinst_HEADERS = \
|
noinst_HEADERS = \
|
||||||
Complex.h \
|
Complex.h \
|
||||||
radioInterface.h \
|
radioInterface.h \
|
||||||
radioVector.h \
|
radioVector.h \
|
||||||
radioClock.h \
|
radioClock.h \
|
||||||
radioDevice.h \
|
|
||||||
radioBuffer.h \
|
radioBuffer.h \
|
||||||
sigProcLib.h \
|
sigProcLib.h \
|
||||||
signalVector.h \
|
signalVector.h \
|
||||||
Transceiver.h \
|
Transceiver.h \
|
||||||
USRPDevice.h \
|
|
||||||
Resampler.h \
|
Resampler.h \
|
||||||
ChannelizerBase.h \
|
ChannelizerBase.h \
|
||||||
Channelizer.h \
|
Channelizer.h \
|
||||||
Synthesis.h \
|
Synthesis.h \
|
||||||
common/convolve.h \
|
proto_trxd.h
|
||||||
common/convert.h \
|
|
||||||
common/scale.h \
|
|
||||||
common/mult.h \
|
|
||||||
common/fft.h
|
|
||||||
|
|
||||||
osmo_trx_SOURCES = osmo-trx.cpp
|
COMMON_LDADD = \
|
||||||
osmo_trx_LDADD = \
|
libtransceiver_common.la \
|
||||||
libtransceiver.la \
|
|
||||||
$(ARCH_LA) \
|
$(ARCH_LA) \
|
||||||
$(GSM_LA) \
|
$(GSM_LA) \
|
||||||
$(COMMON_LA) $(SQLITE3_LIBS)
|
$(COMMON_LA) \
|
||||||
|
$(FFTWF_LIBS) \
|
||||||
|
$(LIBOSMOCORE_LIBS) \
|
||||||
|
$(LIBOSMOCTRL_LIBS) \
|
||||||
|
$(LIBOSMOVTY_LIBS)
|
||||||
|
|
||||||
osmo_siggen_SOURCES = osmo-siggen.cpp
|
if ENABLE_MS_TRX
|
||||||
osmo_siggen_LDADD = \
|
AM_CPPFLAGS += -I$(top_srcdir)/osmocom-bb/src/host/trxcon/include/
|
||||||
libtransceiver.la \
|
AM_CPPFLAGS += -I${srcdir}
|
||||||
$(ARCH_LA) \
|
|
||||||
$(GSM_LA) \
|
TRXCON_LDADD = \
|
||||||
$(COMMON_LA) $(SQLITE3_LIBS)
|
$(top_builddir)/osmocom-bb/src/host/trxcon/src/.libs/libtrxcon.a \
|
||||||
|
$(top_builddir)/osmocom-bb/src/host/trxcon/src/.libs/libl1sched.a \
|
||||||
|
$(top_builddir)/osmocom-bb/src/host/trxcon/src/.libs/libl1gprs.a \
|
||||||
|
$(LIBOSMOCODING_LIBS)
|
||||||
|
|
||||||
|
MS_LOWER_SRC = \
|
||||||
|
ms/sch.c \
|
||||||
|
ms/ms.cpp \
|
||||||
|
ms/threadsched.cpp \
|
||||||
|
ms/ms_rx_lower.cpp \
|
||||||
|
grgsm_vitac/grgsm_vitac.cpp \
|
||||||
|
grgsm_vitac/viterbi_detector.cc
|
||||||
|
|
||||||
|
MS_UPPER_SRC = \
|
||||||
|
ms/ms_upper.cpp \
|
||||||
|
ms/l1ctl_server.c \
|
||||||
|
ms/logging.c \
|
||||||
|
ms/l1ctl_server_cb.cpp \
|
||||||
|
ms/ms_trxcon_if.cpp
|
||||||
|
|
||||||
|
noinst_HEADERS += \
|
||||||
|
ms/ms.h \
|
||||||
|
ms/threadsched.h \
|
||||||
|
ms/bladerf_specific.h \
|
||||||
|
ms/uhd_specific.h \
|
||||||
|
ms/ms_upper.h \
|
||||||
|
ms/ms_trxcon_if.h \
|
||||||
|
ms/itrq.h \
|
||||||
|
ms/sch.h \
|
||||||
|
ms/threadpool.h \
|
||||||
|
grgsm_vitac/viterbi_detector.h \
|
||||||
|
grgsm_vitac/constants.h \
|
||||||
|
grgsm_vitac/grgsm_vitac.h
|
||||||
|
|
||||||
if USRP1
|
endif
|
||||||
libtransceiver_la_SOURCES += USRPDevice.cpp
|
|
||||||
osmo_trx_LDADD += $(USRP_LIBS)
|
bin_PROGRAMS =
|
||||||
else
|
|
||||||
libtransceiver_la_SOURCES += UHDDevice.cpp
|
if DEVICE_UHD
|
||||||
osmo_trx_LDADD += $(UHD_LIBS) $(FFTWF_LIBS)
|
bin_PROGRAMS += osmo-trx-uhd
|
||||||
osmo_siggen_LDADD += $(UHD_LIBS) $(FFTWF_LIBS)
|
osmo_trx_uhd_SOURCES = osmo-trx.cpp
|
||||||
|
osmo_trx_uhd_LDADD = \
|
||||||
|
$(builddir)/device/uhd/libdevice.la \
|
||||||
|
$(COMMON_LDADD) \
|
||||||
|
$(UHD_LIBS)
|
||||||
|
osmo_trx_uhd_CPPFLAGS = $(AM_CPPFLAGS) $(UHD_CFLAGS)
|
||||||
|
|
||||||
|
#if ENABLE_MS_TRX
|
||||||
|
#bin_PROGRAMS += osmo-trx-ms-uhd
|
||||||
|
#osmo_trx_ms_uhd_SOURCES = $(MS_LOWER_SRC) $(MS_UPPER_SRC)
|
||||||
|
#osmo_trx_ms_uhd_LDADD = \
|
||||||
|
# $(builddir)/device/uhd/libdevice.la \
|
||||||
|
# $(COMMON_LDADD) \
|
||||||
|
# $(UHD_LIBS) \
|
||||||
|
# $(TRXCON_LDADD)
|
||||||
|
#osmo_trx_ms_uhd_CPPFLAGS = $(AM_CPPFLAGS) $(UHD_CFLAGS) -DBUILDUHD
|
||||||
|
#endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if DEVICE_USRP1
|
||||||
|
bin_PROGRAMS += osmo-trx-usrp1
|
||||||
|
osmo_trx_usrp1_SOURCES = osmo-trx.cpp
|
||||||
|
osmo_trx_usrp1_LDADD = \
|
||||||
|
$(builddir)/device/usrp1/libdevice.la \
|
||||||
|
$(COMMON_LDADD) \
|
||||||
|
$(USRP_LIBS)
|
||||||
|
osmo_trx_usrp1_CPPFLAGS = $(AM_CPPFLAGS) $(USRP_CFLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if DEVICE_LMS
|
||||||
|
bin_PROGRAMS += osmo-trx-lms
|
||||||
|
osmo_trx_lms_SOURCES = osmo-trx.cpp
|
||||||
|
osmo_trx_lms_LDADD = \
|
||||||
|
$(builddir)/device/lms/libdevice.la \
|
||||||
|
$(COMMON_LDADD) \
|
||||||
|
$(LMS_LIBS)
|
||||||
|
osmo_trx_lms_CPPFLAGS = $(AM_CPPFLAGS) $(LMS_CFLAGS)
|
||||||
|
endif
|
||||||
|
|
||||||
|
if DEVICE_BLADE
|
||||||
|
bin_PROGRAMS += osmo-trx-blade
|
||||||
|
osmo_trx_blade_SOURCES = osmo-trx.cpp
|
||||||
|
osmo_trx_blade_LDADD = \
|
||||||
|
$(builddir)/device/bladerf/libdevice.la \
|
||||||
|
$(COMMON_LDADD) \
|
||||||
|
$(BLADE_LIBS)
|
||||||
|
osmo_trx_blade_CPPFLAGS = $(AM_CPPFLAGS) $(LMS_CFLAGS)
|
||||||
|
|
||||||
|
if ENABLE_MS_TRX
|
||||||
|
bin_PROGRAMS += osmo-trx-ms-blade
|
||||||
|
osmo_trx_ms_blade_SOURCES = $(MS_LOWER_SRC) $(MS_UPPER_SRC)
|
||||||
|
osmo_trx_ms_blade_LDADD = \
|
||||||
|
$(builddir)/device/bladerf/libdevice.la \
|
||||||
|
$(COMMON_LDADD) \
|
||||||
|
$(BLADE_LIBS) \
|
||||||
|
$(TRXCON_LDADD)
|
||||||
|
osmo_trx_ms_blade_CPPFLAGS = $(AM_CPPFLAGS) $(BLADE_CFLAGS) -DBUILDBLADE
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if DEVICE_IPC
|
||||||
|
bin_PROGRAMS += osmo-trx-ipc
|
||||||
|
osmo_trx_ipc_SOURCES = osmo-trx.cpp
|
||||||
|
osmo_trx_ipc_LDADD = \
|
||||||
|
$(builddir)/device/ipc/libdevice.la \
|
||||||
|
$(COMMON_LDADD)
|
||||||
|
osmo_trx_ipc_CPPFLAGS = $(AM_CPPFLAGS)
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -1,35 +0,0 @@
|
|||||||
The Transceiver
|
|
||||||
|
|
||||||
The transceiver consists of three modules:
|
|
||||||
--- transceiver
|
|
||||||
--- radioInterface
|
|
||||||
--- USRPDevice
|
|
||||||
|
|
||||||
The USRPDevice module is basically a driver that reads/writes
|
|
||||||
packets to a USRP with two RFX900 daughterboards, board
|
|
||||||
A is the Tx chain and board B is the Rx chain.
|
|
||||||
|
|
||||||
The radioInterface module is basically an interface b/w the
|
|
||||||
transceiver and the USRP. It operates the basestation clock
|
|
||||||
based upon the sample count of received USRP samples. Packets
|
|
||||||
from the USRP are queued and segmented into GSM bursts that are
|
|
||||||
passed up to the transceiver; bursts from the transceiver are
|
|
||||||
passed down to the USRP.
|
|
||||||
|
|
||||||
The transceiver basically operates "layer 0" of the GSM stack,
|
|
||||||
performing the modulation, detection, and demodulation of GSM
|
|
||||||
bursts. It communicates with the GSM stack via three UDP sockets,
|
|
||||||
one socket for data, one for control messages, and one socket to
|
|
||||||
pass clocking information. The transceiver contains a priority
|
|
||||||
queue to sort to-be-transmitted bursts, and a filler table to fill
|
|
||||||
in timeslots that do not have bursts in the priority queue. The
|
|
||||||
transceiver tries to stay ahead of the basestation clock, adapting
|
|
||||||
its latency when underruns are reported by the radioInterface/USRP.
|
|
||||||
Received bursts (from the radioInterface) pass through a simple
|
|
||||||
energy detector, a RACH or midamble correlator, and a DFE-based demodulator.
|
|
||||||
|
|
||||||
NOTE: There's a SWLOOPBACK #define statement, where the USRP is replaced
|
|
||||||
with a memory buffer. In this mode, data written to the USRP is actually stored
|
|
||||||
in a buffer, and read commands to the USRP simply pull data from this buffer.
|
|
||||||
This was very useful in early testing, and still may be useful in testing basic
|
|
||||||
Transceiver and radioInterface functionality.
|
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
* Rational Sample Rate Conversion
|
* Rational Sample Rate Conversion
|
||||||
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
|
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
@@ -11,10 +13,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -22,6 +20,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "Resampler.h"
|
#include "Resampler.h"
|
||||||
|
|
||||||
@@ -33,7 +32,9 @@ extern "C" {
|
|||||||
#define M_PI 3.14159265358979323846264338327f
|
#define M_PI 3.14159265358979323846264338327f
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAX_OUTPUT_LEN 4096
|
#define MAX_OUTPUT_LEN 4096*4
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
static float sinc(float x)
|
static float sinc(float x)
|
||||||
{
|
{
|
||||||
@@ -43,37 +44,24 @@ static float sinc(float x)
|
|||||||
return sin(M_PI * x) / (M_PI * x);
|
return sin(M_PI * x) / (M_PI * x);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Resampler::initFilters(float bw)
|
void Resampler::initFilters(float bw)
|
||||||
{
|
{
|
||||||
size_t proto_len = p * filt_len;
|
float cutoff;
|
||||||
float *proto, val, cutoff;
|
|
||||||
float sum = 0.0f, scale = 0.0f;
|
float sum = 0.0f, scale = 0.0f;
|
||||||
float midpt = (float) (proto_len - 1.0) / 2.0;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate partition filters and the temporary prototype filter
|
* Allocate partition filters and the temporary prototype filter
|
||||||
* according to numerator of the rational rate. Coefficients are
|
* according to numerator of the rational rate. Coefficients are
|
||||||
* real only and must be 16-byte memory aligned for SSE usage.
|
* real only and must be 16-byte memory aligned for SSE usage.
|
||||||
*/
|
*/
|
||||||
proto = new float[proto_len];
|
auto proto = vector<float>(p * filt_len);
|
||||||
if (!proto)
|
for (auto &part : partitions)
|
||||||
return false;
|
part = (complex<float> *) memalign(16, filt_len * sizeof(complex<float>));
|
||||||
|
|
||||||
partitions = (float **) malloc(sizeof(float *) * p);
|
/*
|
||||||
if (!partitions) {
|
|
||||||
delete[] proto;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (size_t i = 0; i < p; i++) {
|
|
||||||
partitions[i] = (float *)
|
|
||||||
memalign(16, filt_len * 2 * sizeof(float));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Generate the prototype filter with a Blackman-harris window.
|
* Generate the prototype filter with a Blackman-harris window.
|
||||||
* Scale coefficients with DC filter gain set to unity divided
|
* Scale coefficients with DC filter gain set to unity divided
|
||||||
* by the number of filter partitions.
|
* by the number of filter partitions.
|
||||||
*/
|
*/
|
||||||
float a0 = 0.35875;
|
float a0 = 0.35875;
|
||||||
float a1 = 0.48829;
|
float a1 = 0.48829;
|
||||||
@@ -85,49 +73,29 @@ bool Resampler::initFilters(float bw)
|
|||||||
else
|
else
|
||||||
cutoff = (float) q;
|
cutoff = (float) q;
|
||||||
|
|
||||||
for (size_t i = 0; i < proto_len; i++) {
|
float midpt = (proto.size() - 1) / 2.0;
|
||||||
|
for (size_t i = 0; i < proto.size(); i++) {
|
||||||
proto[i] = sinc(((float) i - midpt) / cutoff * bw);
|
proto[i] = sinc(((float) i - midpt) / cutoff * bw);
|
||||||
proto[i] *= a0 -
|
proto[i] *= a0 -
|
||||||
a1 * cos(2 * M_PI * i / (proto_len - 1)) +
|
a1 * cos(2 * M_PI * i / (proto.size() - 1)) +
|
||||||
a2 * cos(4 * M_PI * i / (proto_len - 1)) -
|
a2 * cos(4 * M_PI * i / (proto.size() - 1)) -
|
||||||
a3 * cos(6 * M_PI * i / (proto_len - 1));
|
a3 * cos(6 * M_PI * i / (proto.size() - 1));
|
||||||
sum += proto[i];
|
sum += proto[i];
|
||||||
}
|
}
|
||||||
scale = p / sum;
|
scale = p / sum;
|
||||||
|
|
||||||
/* Populate filter partitions from the prototype filter */
|
/* Populate filter partitions from the prototype filter */
|
||||||
for (size_t i = 0; i < filt_len; i++) {
|
for (size_t i = 0; i < filt_len; i++) {
|
||||||
for (size_t n = 0; n < p; n++) {
|
for (size_t n = 0; n < p; n++)
|
||||||
partitions[n][2 * i + 0] = proto[i * p + n] * scale;
|
partitions[n][i] = complex<float>(proto[i * p + n] * scale);
|
||||||
partitions[n][2 * i + 1] = 0.0f;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For convolution, we store the filter taps in reverse */
|
/* Store filter taps in reverse */
|
||||||
for (size_t n = 0; n < p; n++) {
|
for (auto &part : partitions)
|
||||||
for (size_t i = 0; i < filt_len / 2; i++) {
|
reverse(&part[0], &part[filt_len]);
|
||||||
val = partitions[n][2 * i];
|
|
||||||
partitions[n][2 * i] = partitions[n][2 * (filt_len - 1 - i)];
|
|
||||||
partitions[n][2 * (filt_len - 1 - i)] = val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delete[] proto;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Resampler::releaseFilters()
|
|
||||||
{
|
|
||||||
if (partitions) {
|
|
||||||
for (size_t i = 0; i < p; i++)
|
|
||||||
free(partitions[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(partitions);
|
|
||||||
partitions = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef __OPTIMIZE__
|
||||||
static bool check_vec_len(int in_len, int out_len, int p, int q)
|
static bool check_vec_len(int in_len, int out_len, int p, int q)
|
||||||
{
|
{
|
||||||
if (in_len % q) {
|
if (in_len % q) {
|
||||||
@@ -158,31 +126,24 @@ static bool check_vec_len(int in_len, int out_len, int p, int q)
|
|||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
void Resampler::computePath()
|
|
||||||
{
|
|
||||||
for (int i = 0; i < MAX_OUTPUT_LEN; i++) {
|
|
||||||
in_index[i] = (q * i) / p;
|
|
||||||
out_path[i] = (q * i) % p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int Resampler::rotate(const float *in, size_t in_len, float *out, size_t out_len)
|
int Resampler::rotate(const float *in, size_t in_len, float *out, size_t out_len)
|
||||||
{
|
{
|
||||||
int n, path;
|
int n, path;
|
||||||
|
#ifndef __OPTIMIZE__
|
||||||
if (!check_vec_len(in_len, out_len, p, q))
|
if (!check_vec_len(in_len, out_len, p, q))
|
||||||
return -1;
|
return -1;
|
||||||
|
#endif
|
||||||
/* Generate output from precomputed input/output paths */
|
/* Generate output from precomputed input/output paths */
|
||||||
for (size_t i = 0; i < out_len; i++) {
|
for (size_t i = 0; i < out_len; i++) {
|
||||||
n = in_index[i];
|
n = in_index[i];
|
||||||
path = out_path[i];
|
path = out_path[i];
|
||||||
|
|
||||||
convolve_real(in, in_len,
|
convolve_real(in, in_len,
|
||||||
partitions[path], filt_len,
|
reinterpret_cast<float *>(partitions[path]),
|
||||||
&out[2 * i], out_len - i,
|
filt_len, &out[2 * i], out_len - i,
|
||||||
n, 1, 1, 0);
|
n, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return out_len;
|
return out_len;
|
||||||
@@ -190,14 +151,18 @@ int Resampler::rotate(const float *in, size_t in_len, float *out, size_t out_len
|
|||||||
|
|
||||||
bool Resampler::init(float bw)
|
bool Resampler::init(float bw)
|
||||||
{
|
{
|
||||||
|
if (p == 0 || q == 0 || filt_len == 0) return false;
|
||||||
|
|
||||||
/* Filterbank filter internals */
|
/* Filterbank filter internals */
|
||||||
if (!initFilters(bw))
|
initFilters(bw);
|
||||||
return false;
|
|
||||||
|
|
||||||
/* Precompute filterbank paths */
|
/* Precompute filterbank paths */
|
||||||
in_index = new size_t[MAX_OUTPUT_LEN];
|
int i = 0;
|
||||||
out_path = new size_t[MAX_OUTPUT_LEN];
|
for (auto &index : in_index)
|
||||||
computePath();
|
index = (q * i++) / p;
|
||||||
|
i = 0;
|
||||||
|
for (auto &path : out_path)
|
||||||
|
path = (q * i++) % p;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -208,7 +173,7 @@ size_t Resampler::len()
|
|||||||
}
|
}
|
||||||
|
|
||||||
Resampler::Resampler(size_t p, size_t q, size_t filt_len)
|
Resampler::Resampler(size_t p, size_t q, size_t filt_len)
|
||||||
: in_index(NULL), out_path(NULL), partitions(NULL)
|
: in_index(MAX_OUTPUT_LEN), out_path(MAX_OUTPUT_LEN), partitions(p)
|
||||||
{
|
{
|
||||||
this->p = p;
|
this->p = p;
|
||||||
this->q = q;
|
this->q = q;
|
||||||
@@ -217,8 +182,6 @@ Resampler::Resampler(size_t p, size_t q, size_t filt_len)
|
|||||||
|
|
||||||
Resampler::~Resampler()
|
Resampler::~Resampler()
|
||||||
{
|
{
|
||||||
releaseFilters();
|
for (auto &part : partitions)
|
||||||
|
free(part);
|
||||||
delete in_index;
|
|
||||||
delete out_path;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
* Rational Sample Rate Conversion
|
* Rational Sample Rate Conversion
|
||||||
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
|
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
@@ -11,31 +13,30 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _RESAMPLER_H_
|
#ifndef _RESAMPLER_H_
|
||||||
#define _RESAMPLER_H_
|
#define _RESAMPLER_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <complex>
|
||||||
|
|
||||||
class Resampler {
|
class Resampler {
|
||||||
public:
|
public:
|
||||||
/* Constructor for rational sample rate conversion
|
/* Constructor for rational sample rate conversion
|
||||||
* @param p numerator of resampling ratio
|
* @param p numerator of resampling ratio
|
||||||
* @param q denominator of resampling ratio
|
* @param q denominator of resampling ratio
|
||||||
* @param filt_len length of each polyphase subfilter
|
* @param filt_len length of each polyphase subfilter
|
||||||
*/
|
*/
|
||||||
Resampler(size_t p, size_t q, size_t filt_len = 16);
|
Resampler(size_t p, size_t q, size_t filt_len = 16);
|
||||||
~Resampler();
|
~Resampler();
|
||||||
|
|
||||||
/* Initilize resampler filterbank.
|
/* Initialize resampler filterbank.
|
||||||
* @param bw bandwidth factor on filter generation (pre-window)
|
* @param bw bandwidth factor on filter generation (pre-window)
|
||||||
* @return false on error, zero otherwise
|
* @return false on error, zero otherwise
|
||||||
*
|
*
|
||||||
* Automatic setting is to compute the filter to prevent aliasing with
|
* Automatic setting is to compute the filter to prevent aliasing with
|
||||||
* a Blackman-Harris window. Adjustment is made through a bandwith
|
* a Blackman-Harris window. Adjustment is made through a bandwidth
|
||||||
* factor to shift the cutoff and/or the constituent filter lengths.
|
* factor to shift the cutoff and/or the constituent filter lengths.
|
||||||
* Calculation of specific rolloff factors or 3-dB cutoff points is
|
* Calculation of specific rolloff factors or 3-dB cutoff points is
|
||||||
* left as an excersize for the reader.
|
* left as an excersize for the reader.
|
||||||
@@ -55,7 +56,7 @@ public:
|
|||||||
int rotate(const float *in, size_t in_len, float *out, size_t out_len);
|
int rotate(const float *in, size_t in_len, float *out, size_t out_len);
|
||||||
|
|
||||||
/* Get filter length
|
/* Get filter length
|
||||||
* @return number of taps in each filter partition
|
* @return number of taps in each filter partition
|
||||||
*/
|
*/
|
||||||
size_t len();
|
size_t len();
|
||||||
|
|
||||||
@@ -63,14 +64,11 @@ private:
|
|||||||
size_t p;
|
size_t p;
|
||||||
size_t q;
|
size_t q;
|
||||||
size_t filt_len;
|
size_t filt_len;
|
||||||
size_t *in_index;
|
std::vector<size_t> in_index;
|
||||||
size_t *out_path;
|
std::vector<size_t> out_path;
|
||||||
|
std::vector<std::complex<float> *> partitions;
|
||||||
|
|
||||||
float **partitions;
|
void initFilters(float bw);
|
||||||
|
|
||||||
bool initFilters(float bw);
|
|
||||||
void releaseFilters();
|
|
||||||
void computePath();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _RESAMPLER_H_ */
|
#endif /* _RESAMPLER_H_ */
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
* Polyphase synthesis filter
|
* Polyphase synthesis filter
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2014 Tom Tsou <tom@tsou.cc>
|
* Copyright (C) 2012-2014 Tom Tsou <tom@tsou.cc>
|
||||||
* Copyright (C) 2015 Ettus Research LLC
|
* Copyright (C) 2015 Ettus Research LLC
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
@@ -24,13 +26,13 @@
|
|||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "Logger.h"
|
|
||||||
#include "Synthesis.h"
|
#include "Synthesis.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "common/fft.h"
|
#include "fft.h"
|
||||||
#include "common/convolve.h"
|
#include "convolve.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
static void interleave(float **in, size_t ilen,
|
static void interleave(float **in, size_t ilen,
|
||||||
@@ -74,7 +76,7 @@ bool Synthesis::resetBuffer(size_t chan)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Implementation based on material found in:
|
* Implementation based on material found in:
|
||||||
*
|
*
|
||||||
* "harris, fred, Multirate Signal Processing, Upper Saddle River, NJ,
|
* "harris, fred, Multirate Signal Processing, Upper Saddle River, NJ,
|
||||||
@@ -92,8 +94,8 @@ bool Synthesis::rotate(float *out, size_t len)
|
|||||||
|
|
||||||
cxvec_fft(fftHandle);
|
cxvec_fft(fftHandle);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convolve through filterbank while applying and saving sample history
|
* Convolve through filterbank while applying and saving sample history
|
||||||
*/
|
*/
|
||||||
for (size_t i = 0; i < m; i++) {
|
for (size_t i = 0; i < m; i++) {
|
||||||
memcpy(&hInputs[i][2 * -hLen], hist[i], hSize);
|
memcpy(&hInputs[i][2 * -hLen], hist[i], hSize);
|
||||||
@@ -102,7 +104,7 @@ bool Synthesis::rotate(float *out, size_t len)
|
|||||||
convolve_real(hInputs[i], blockLen,
|
convolve_real(hInputs[i], blockLen,
|
||||||
subFilters[i], hLen,
|
subFilters[i], hLen,
|
||||||
hOutputs[i], blockLen,
|
hOutputs[i], blockLen,
|
||||||
0, blockLen, 1, 0);
|
0, blockLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Interleave into output vector */
|
/* Interleave into output vector */
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008 Free Software Foundation, Inc.
|
* Copyright 2008 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-3.0+
|
||||||
|
*
|
||||||
* This software is distributed under the terms of the GNU Public License.
|
* This software is distributed under the terms of the GNU Public License.
|
||||||
* See the COPYING file in the main directory for details.
|
* See the COPYING file in the main directory for details.
|
||||||
*
|
*
|
||||||
@@ -25,27 +27,24 @@
|
|||||||
#include "radioInterface.h"
|
#include "radioInterface.h"
|
||||||
#include "Interthread.h"
|
#include "Interthread.h"
|
||||||
#include "GSMCommon.h"
|
#include "GSMCommon.h"
|
||||||
#include "Sockets.h"
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <osmocom/core/signal.h>
|
||||||
|
#include <osmocom/core/select.h>
|
||||||
|
#include "config_defs.h"
|
||||||
|
}
|
||||||
|
|
||||||
class Transceiver;
|
class Transceiver;
|
||||||
|
|
||||||
|
extern Transceiver *transceiver;
|
||||||
|
|
||||||
/** Channel descriptor for transceiver object and channel number pair */
|
/** Channel descriptor for transceiver object and channel number pair */
|
||||||
struct TransceiverChannel {
|
struct TrxChanThParams {
|
||||||
TransceiverChannel(Transceiver *trx, int num)
|
Transceiver *trx;
|
||||||
{
|
size_t num;
|
||||||
this->trx = trx;
|
|
||||||
this->num = num;
|
|
||||||
}
|
|
||||||
|
|
||||||
~TransceiverChannel()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Transceiver *trx;
|
|
||||||
size_t num;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Internal transceiver state variables */
|
/** Internal transceiver state variables */
|
||||||
@@ -54,7 +53,7 @@ struct TransceiverState {
|
|||||||
~TransceiverState();
|
~TransceiverState();
|
||||||
|
|
||||||
/* Initialize a multiframe slot in the filler table */
|
/* Initialize a multiframe slot in the filler table */
|
||||||
bool init(int filler, size_t sps, float scale, size_t rtsc, unsigned rach_delay);
|
bool init(FillerType filler, size_t sps, float scale, size_t rtsc, unsigned rach_delay);
|
||||||
|
|
||||||
int chanType[8];
|
int chanType[8];
|
||||||
|
|
||||||
@@ -64,6 +63,7 @@ struct TransceiverState {
|
|||||||
/* The filler table */
|
/* The filler table */
|
||||||
signalVector *fillerTable[102][8];
|
signalVector *fillerTable[102][8];
|
||||||
int fillerModulus[8];
|
int fillerModulus[8];
|
||||||
|
FillerType mFiller;
|
||||||
bool mRetrans;
|
bool mRetrans;
|
||||||
|
|
||||||
/* Most recent channel estimate of all timeslots */
|
/* Most recent channel estimate of all timeslots */
|
||||||
@@ -80,34 +80,39 @@ struct TransceiverState {
|
|||||||
|
|
||||||
/* Received noise energy levels */
|
/* Received noise energy levels */
|
||||||
float mNoiseLev;
|
float mNoiseLev;
|
||||||
noiseVector mNoises;
|
avgVector mNoises;
|
||||||
|
|
||||||
/* Shadowed downlink attenuation */
|
/* Shadowed downlink attenuation */
|
||||||
int mPower;
|
int mPower;
|
||||||
|
|
||||||
|
/* RF emission and reception disabled, as per NM Administrative State Locked */
|
||||||
|
bool mMuted;
|
||||||
|
|
||||||
|
/* counters */
|
||||||
|
struct trx_counters ctrs;
|
||||||
|
|
||||||
|
/* Used to keep track of lost and out of order frames */
|
||||||
|
bool first_dl_fn_rcv[8];
|
||||||
|
GSM::Time last_dl_time_rcv[8];
|
||||||
};
|
};
|
||||||
|
|
||||||
/** The Transceiver class, responsible for physical layer of basestation */
|
/** The Transceiver class, responsible for physical layer of basestation */
|
||||||
class Transceiver {
|
class Transceiver {
|
||||||
public:
|
public:
|
||||||
/** Transceiver constructor
|
/** Transceiver constructor
|
||||||
@param wBasePort base port number of UDP sockets
|
@param cfg VTY populated config
|
||||||
@param TRXAddress IP address of the TRX manager, as a string
|
|
||||||
@param wSPS number of samples per GSM symbol
|
|
||||||
@param wTransmitLatency initial setting of transmit latency
|
@param wTransmitLatency initial setting of transmit latency
|
||||||
@param radioInterface associated radioInterface object
|
@param radioInterface associated radioInterface object
|
||||||
*/
|
*/
|
||||||
Transceiver(int wBasePort,
|
Transceiver(const struct trx_cfg *cfg,
|
||||||
const char *TRXAddress,
|
|
||||||
size_t tx_sps, size_t rx_sps, size_t chans,
|
|
||||||
GSM::Time wTransmitLatency,
|
GSM::Time wTransmitLatency,
|
||||||
RadioInterface *wRadioInterface,
|
RadioInterface *wRadioInterface);
|
||||||
double wRssiOffset);
|
|
||||||
|
|
||||||
/** Destructor */
|
/** Destructor */
|
||||||
~Transceiver();
|
~Transceiver();
|
||||||
|
|
||||||
/** Start the control loop */
|
/** Start the control loop */
|
||||||
bool init(int filler, size_t rtsc, unsigned rach_delay, bool edge);
|
bool init(void);
|
||||||
|
|
||||||
/** attach the radioInterface receive FIFO */
|
/** attach the radioInterface receive FIFO */
|
||||||
bool receiveFIFO(VectorFIFO *wFIFO, size_t chan)
|
bool receiveFIFO(VectorFIFO *wFIFO, size_t chan)
|
||||||
@@ -120,7 +125,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** accessor for number of channels */
|
/** accessor for number of channels */
|
||||||
size_t numChans() const { return mChans; };
|
size_t numChans() const { return cfg->num_chans; };
|
||||||
|
|
||||||
/** Codes for channel combinations */
|
/** Codes for channel combinations */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -142,21 +147,32 @@ public:
|
|||||||
LOOPBACK ///< similar go VII, used in loopback testing
|
LOOPBACK ///< similar go VII, used in loopback testing
|
||||||
} ChannelCombination;
|
} ChannelCombination;
|
||||||
|
|
||||||
enum FillerType {
|
|
||||||
FILLER_DUMMY,
|
|
||||||
FILLER_ZERO,
|
|
||||||
FILLER_NORM_RAND,
|
|
||||||
FILLER_EDGE_RAND,
|
|
||||||
FILLER_ACCESS_RAND,
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int mBasePort;
|
size_t mChans;
|
||||||
std::string mAddr;
|
struct ctrl_msg {
|
||||||
|
char data[101];
|
||||||
|
ctrl_msg() {};
|
||||||
|
};
|
||||||
|
|
||||||
std::vector<UDPSocket *> mDataSockets; ///< socket for writing to/reading from GSM core
|
struct ctrl_sock_state {
|
||||||
std::vector<UDPSocket *> mCtrlSockets; ///< socket for writing/reading control commands from GSM core
|
osmo_fd conn_bfd;
|
||||||
UDPSocket mClockSocket; ///< socket for writing clock updates to GSM core
|
std::deque<ctrl_msg> txmsgqueue;
|
||||||
|
ctrl_sock_state() {
|
||||||
|
conn_bfd.fd = -1;
|
||||||
|
}
|
||||||
|
~ctrl_sock_state() {
|
||||||
|
if(conn_bfd.fd >= 0) {
|
||||||
|
osmo_fd_unregister(&conn_bfd);
|
||||||
|
close(conn_bfd.fd);
|
||||||
|
conn_bfd.fd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const struct trx_cfg *cfg; ///< VTY populated config
|
||||||
|
std::vector<int> mDataSockets; ///< socket for writing to/reading from GSM core
|
||||||
|
std::vector<ctrl_sock_state> mCtrlSockets; ///< socket for writing/reading control commands from GSM core
|
||||||
|
int mClockSocket; ///< socket for writing clock updates to GSM core
|
||||||
|
|
||||||
std::vector<VectorQueue> mTxPriorityQueues; ///< priority queue of transmit bursts received from GSM core
|
std::vector<VectorQueue> mTxPriorityQueues; ///< priority queue of transmit bursts received from GSM core
|
||||||
std::vector<VectorFIFO *> mReceiveFIFO; ///< radioInterface FIFO of receive bursts
|
std::vector<VectorFIFO *> mReceiveFIFO; ///< radioInterface FIFO of receive bursts
|
||||||
@@ -164,20 +180,17 @@ private:
|
|||||||
std::vector<Thread *> mRxServiceLoopThreads; ///< thread to pull bursts into receive FIFO
|
std::vector<Thread *> mRxServiceLoopThreads; ///< thread to pull bursts into receive FIFO
|
||||||
Thread *mRxLowerLoopThread; ///< thread to pull bursts into receive FIFO
|
Thread *mRxLowerLoopThread; ///< thread to pull bursts into receive FIFO
|
||||||
Thread *mTxLowerLoopThread; ///< thread to push bursts into transmit FIFO
|
Thread *mTxLowerLoopThread; ///< thread to push bursts into transmit FIFO
|
||||||
std::vector<Thread *> mControlServiceLoopThreads; ///< thread to process control messages from GSM core
|
|
||||||
std::vector<Thread *> mTxPriorityQueueServiceLoopThreads; ///< thread to process transmit bursts from GSM core
|
std::vector<Thread *> mTxPriorityQueueServiceLoopThreads; ///< thread to process transmit bursts from GSM core
|
||||||
|
|
||||||
GSM::Time mTransmitLatency; ///< latency between basestation clock and transmit deadline clock
|
GSM::Time mTransmitLatency; ///< latency between basestation clock and transmit deadline clock
|
||||||
GSM::Time mLatencyUpdateTime; ///< last time latency was updated
|
GSM::Time mLatencyUpdateTime; ///< last time latency was updated
|
||||||
GSM::Time mTransmitDeadlineClock; ///< deadline for pushing bursts into transmit FIFO
|
GSM::Time mTransmitDeadlineClock; ///< deadline for pushing bursts into transmit FIFO
|
||||||
GSM::Time mLastClockUpdateTime; ///< last time clock update was sent up to core
|
GSM::Time mLastClockUpdateTime; ///< last time clock update was sent up to core
|
||||||
|
|
||||||
RadioInterface *mRadioInterface; ///< associated radioInterface object
|
RadioInterface *mRadioInterface; ///< associated radioInterface object
|
||||||
double txFullScale; ///< full scale input to radio
|
double txFullScale; ///< full scale input to radio
|
||||||
double rxFullScale; ///< full scale output to radio
|
double rxFullScale; ///< full scale output to radio
|
||||||
|
|
||||||
double rssiOffset; ///< RSSI to dBm conversion offset
|
|
||||||
|
|
||||||
/** modulate and add a burst to the transmit queue */
|
/** modulate and add a burst to the transmit queue */
|
||||||
void addRadioVector(size_t chan, BitVector &bits,
|
void addRadioVector(size_t chan, BitVector &bits,
|
||||||
int RSSI, GSM::Time &wTime);
|
int RSSI, GSM::Time &wTime);
|
||||||
@@ -189,9 +202,7 @@ private:
|
|||||||
void pushRadioVector(GSM::Time &nowTime);
|
void pushRadioVector(GSM::Time &nowTime);
|
||||||
|
|
||||||
/** Pull and demodulate a burst from the receive FIFO */
|
/** Pull and demodulate a burst from the receive FIFO */
|
||||||
SoftVector *pullRadioVector(GSM::Time &wTime, double &RSSI, bool &isRssiValid,
|
int pullRadioVector(size_t chan, struct trx_ul_burst_ind *ind);
|
||||||
double &timingOffset, double &noise,
|
|
||||||
size_t chan = 0);
|
|
||||||
|
|
||||||
/** Set modulus for specific timeslot */
|
/** Set modulus for specific timeslot */
|
||||||
void setModulus(size_t timeslot, size_t chan);
|
void setModulus(size_t timeslot, size_t chan);
|
||||||
@@ -200,14 +211,17 @@ private:
|
|||||||
CorrType expectedCorrType(GSM::Time currTime, size_t chan);
|
CorrType expectedCorrType(GSM::Time currTime, size_t chan);
|
||||||
|
|
||||||
/** send messages over the clock socket */
|
/** send messages over the clock socket */
|
||||||
void writeClockInterface(void);
|
bool writeClockInterface(void);
|
||||||
|
|
||||||
|
static int ctrl_sock_cb(struct osmo_fd *bfd, unsigned int flags);
|
||||||
|
int ctrl_sock_write(int chan);
|
||||||
|
void ctrl_sock_send(ctrl_msg& m, int chan);
|
||||||
|
/** drive handling of control messages from GSM core */
|
||||||
|
int ctrl_sock_handle_rx(int chan);
|
||||||
|
|
||||||
int mSPSTx; ///< number of samples per Tx symbol
|
|
||||||
int mSPSRx; ///< number of samples per Rx symbol
|
|
||||||
size_t mChans;
|
|
||||||
|
|
||||||
bool mEdge;
|
|
||||||
bool mOn; ///< flag to indicate that transceiver is powered on
|
bool mOn; ///< flag to indicate that transceiver is powered on
|
||||||
|
bool mForceClockInterface; ///< flag to indicate whether IND CLOCK shall be sent unconditionally after transceiver is started
|
||||||
bool mHandover[8][8]; ///< expect handover to the timeslot/subslot
|
bool mHandover[8][8]; ///< expect handover to the timeslot/subslot
|
||||||
double mTxFreq; ///< the transmit frequency
|
double mTxFreq; ///< the transmit frequency
|
||||||
double mRxFreq; ///< the receive frequency
|
double mRxFreq; ///< the receive frequency
|
||||||
@@ -216,63 +230,48 @@ private:
|
|||||||
unsigned mMaxExpectedDelayNB; ///< maximum expected time-of-arrival offset in GSM symbols for Normal Bursts
|
unsigned mMaxExpectedDelayNB; ///< maximum expected time-of-arrival offset in GSM symbols for Normal Bursts
|
||||||
unsigned mWriteBurstToDiskMask; ///< debug: bitmask to indicate which timeslots to dump to disk
|
unsigned mWriteBurstToDiskMask; ///< debug: bitmask to indicate which timeslots to dump to disk
|
||||||
|
|
||||||
|
std::vector<unsigned> mVersionTRXD; ///< Format version to use for TRXD protocol communication, per channel
|
||||||
std::vector<TransceiverState> mStates;
|
std::vector<TransceiverState> mStates;
|
||||||
|
|
||||||
/** Start and stop I/O threads through the control socket API */
|
/** Start and stop I/O threads through the control socket API */
|
||||||
bool start();
|
bool start();
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
/** Protect destructor accessable stop call */
|
/** Protect destructor accessible stop call */
|
||||||
Mutex mLock;
|
Mutex mLock;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** drive lower receive I/O and burst generation */
|
/** drive lower receive I/O and burst generation */
|
||||||
void driveReceiveRadio();
|
bool driveReceiveRadio();
|
||||||
|
|
||||||
/** drive demodulation of GSM bursts */
|
/** drive demodulation of GSM bursts */
|
||||||
void driveReceiveFIFO(size_t chan);
|
bool driveReceiveFIFO(size_t chan);
|
||||||
|
|
||||||
/** drive transmission of GSM bursts */
|
/** drive transmission of GSM bursts */
|
||||||
void driveTxFIFO();
|
void driveTxFIFO();
|
||||||
|
|
||||||
/** drive handling of control messages from GSM core */
|
|
||||||
void driveControl(size_t chan);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
drive modulation and sorting of GSM bursts from GSM core
|
drive modulation and sorting of GSM bursts from GSM core
|
||||||
@return true if a burst was transferred successfully
|
@return true if a burst was transferred successfully
|
||||||
*/
|
*/
|
||||||
bool driveTxPriorityQueue(size_t chan);
|
bool driveTxPriorityQueue(size_t chan);
|
||||||
|
|
||||||
friend void *RxUpperLoopAdapter(TransceiverChannel *);
|
friend void *RxUpperLoopAdapter(TrxChanThParams *params);
|
||||||
|
friend void *TxUpperLoopAdapter(TrxChanThParams *params);
|
||||||
friend void *TxUpperLoopAdapter(TransceiverChannel *);
|
friend void *RxLowerLoopAdapter(Transceiver *transceiver);
|
||||||
|
friend void *TxLowerLoopAdapter(Transceiver *transceiver);
|
||||||
friend void *RxLowerLoopAdapter(Transceiver *);
|
|
||||||
|
|
||||||
friend void *TxLowerLoopAdapter(Transceiver *);
|
|
||||||
|
|
||||||
friend void *ControlServiceLoopAdapter(TransceiverChannel *);
|
|
||||||
|
|
||||||
|
|
||||||
|
double rssiOffset(size_t chan);
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
/** set priority on current thread */
|
void logRxBurst(size_t chan, const struct trx_ul_burst_ind *bi);
|
||||||
void setPriority(float prio = 0.5) { mRadioInterface->setPriority(prio); }
|
|
||||||
|
|
||||||
void logRxBurst(size_t chan, SoftVector *burst, GSM::Time time, double dbm,
|
|
||||||
double rssi, double noise, double toa);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void *RxUpperLoopAdapter(TransceiverChannel *);
|
void *RxUpperLoopAdapter(TrxChanThParams *params);
|
||||||
|
|
||||||
/** Main drive threads */
|
/** Main drive threads */
|
||||||
void *RxLowerLoopAdapter(Transceiver *);
|
void *RxLowerLoopAdapter(Transceiver *transceiver);
|
||||||
void *TxLowerLoopAdapter(Transceiver *);
|
void *TxLowerLoopAdapter(Transceiver *transceiver);
|
||||||
|
|
||||||
/** control message handler thread loop */
|
|
||||||
void *ControlServiceLoopAdapter(TransceiverChannel *);
|
|
||||||
|
|
||||||
/** transmit queueing thread loop */
|
/** transmit queueing thread loop */
|
||||||
void *TxUpperLoopAdapter(TransceiverChannel *);
|
void *TxUpperLoopAdapter(TrxChanThParams *params);
|
||||||
|
|
||||||
|
|||||||
8
Transceiver52M/arch/Makefile.am
Normal file
8
Transceiver52M/arch/Makefile.am
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
include $(top_srcdir)/Makefile.common
|
||||||
|
|
||||||
|
SUBDIRS = common
|
||||||
|
if ARCH_ARM
|
||||||
|
SUBDIRS += arm
|
||||||
|
else
|
||||||
|
SUBDIRS += x86
|
||||||
|
endif
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
if ARCH_ARM
|
|
||||||
if ARCH_ARM_A15
|
if ARCH_ARM_A15
|
||||||
ARCH_FLAGS = -mfpu=neon-vfpv4
|
ARCH_FLAGS = -mfpu=neon-vfpv4
|
||||||
else
|
else
|
||||||
ARCH_FLAGS = -mfpu=neon
|
ARCH_FLAGS = -mfpu=neon
|
||||||
endif
|
endif
|
||||||
|
|
||||||
AM_CFLAGS = -Wall $(ARCH_FLAGS) -std=gnu99 -I../common
|
AM_CFLAGS = -Wall $(ARCH_FLAGS) -std=gnu99 -I${srcdir}/../common
|
||||||
AM_CCASFLAGS = $(ARCH_FLAGS)
|
AM_CCASFLAGS = $(ARCH_FLAGS)
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libarch.la
|
noinst_LTLIBRARIES = libarch.la
|
||||||
|
|
||||||
|
libarch_la_LIBADD = $(top_builddir)/Transceiver52M/arch/common/libarch_common.la
|
||||||
|
|
||||||
libarch_la_SOURCES = \
|
libarch_la_SOURCES = \
|
||||||
../common/convolve_base.c \
|
|
||||||
convert.c \
|
convert.c \
|
||||||
convert_neon.S \
|
convert_neon.S \
|
||||||
convolve.c \
|
convolve.c \
|
||||||
@@ -20,4 +20,3 @@ libarch_la_SOURCES = \
|
|||||||
scale_neon.S \
|
scale_neon.S \
|
||||||
mult.c \
|
mult.c \
|
||||||
mult_neon.S
|
mult_neon.S
|
||||||
endif
|
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
* NEON type conversions
|
* NEON type conversions
|
||||||
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
|
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
@@ -11,10 +13,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
@@ -28,6 +26,9 @@
|
|||||||
void neon_convert_ps_si16_4n(short *, const float *, const float *, int);
|
void neon_convert_ps_si16_4n(short *, const float *, const float *, int);
|
||||||
void neon_convert_si16_ps_4n(float *, const short *, int);
|
void neon_convert_si16_ps_4n(float *, const short *, int);
|
||||||
|
|
||||||
|
void convert_init(void) {
|
||||||
|
}
|
||||||
|
|
||||||
/* 4*N 16-bit signed integer conversion with remainder */
|
/* 4*N 16-bit signed integer conversion with remainder */
|
||||||
static void neon_convert_si16_ps(float *out,
|
static void neon_convert_si16_ps(float *out,
|
||||||
const short *in,
|
const short *in,
|
||||||
@@ -54,7 +55,6 @@ static void neon_convert_ps_si16(short *out,
|
|||||||
for (int i = 0; i < len % 4; i++)
|
for (int i = 0; i < len % 4; i++)
|
||||||
out[start + i] = (short) (in[start + i] * (*scale));
|
out[start + i] = (short) (in[start + i] * (*scale));
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
void convert_float_short(short *out, const float *in, float scale, int len)
|
void convert_float_short(short *out, const float *in, float scale, int len)
|
||||||
{
|
{
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
* NEON type conversions
|
* NEON type conversions
|
||||||
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
|
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
@@ -11,10 +13,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.syntax unified
|
.syntax unified
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
* NEON Convolution
|
* NEON Convolution
|
||||||
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
|
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
@@ -11,10 +13,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
@@ -29,17 +27,15 @@
|
|||||||
int _base_convolve_real(float *x, int x_len,
|
int _base_convolve_real(float *x, int x_len,
|
||||||
float *h, int h_len,
|
float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len,
|
int start, int len);
|
||||||
int step, int offset);
|
|
||||||
|
|
||||||
int _base_convolve_complex(float *x, int x_len,
|
int _base_convolve_complex(float *x, int x_len,
|
||||||
float *h, int h_len,
|
float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len,
|
int start, int len);
|
||||||
int step, int offset);
|
|
||||||
|
|
||||||
int bounds_check(int x_len, int h_len, int y_len,
|
int bounds_check(int x_len, int h_len, int y_len,
|
||||||
int start, int len, int step);
|
int start, int len);
|
||||||
|
|
||||||
#ifdef HAVE_NEON
|
#ifdef HAVE_NEON
|
||||||
/* Calls into NEON assembler */
|
/* Calls into NEON assembler */
|
||||||
@@ -58,7 +54,7 @@ static void neon_conv_cmplx_4n(float *x, float *h, float *y, int h_len, int len)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* API: Initalize convolve module */
|
/* API: Initialize convolve module */
|
||||||
void convolve_init(void)
|
void convolve_init(void)
|
||||||
{
|
{
|
||||||
/* Stub */
|
/* Stub */
|
||||||
@@ -69,35 +65,32 @@ void convolve_init(void)
|
|||||||
int convolve_real(float *x, int x_len,
|
int convolve_real(float *x, int x_len,
|
||||||
float *h, int h_len,
|
float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len,
|
int start, int len)
|
||||||
int step, int offset)
|
|
||||||
{
|
{
|
||||||
void (*conv_func)(float *, float *, float *, int) = NULL;
|
void (*conv_func)(float *, float *, float *, int) = NULL;
|
||||||
|
|
||||||
if (bounds_check(x_len, h_len, y_len, start, len, step) < 0)
|
if (bounds_check(x_len, h_len, y_len, start, len) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
memset(y, 0, len * 2 * sizeof(float));
|
memset(y, 0, len * 2 * sizeof(float));
|
||||||
|
|
||||||
#ifdef HAVE_NEON
|
#ifdef HAVE_NEON
|
||||||
if (step <= 4) {
|
switch (h_len) {
|
||||||
switch (h_len) {
|
case 4:
|
||||||
case 4:
|
conv_func = neon_conv_real4;
|
||||||
conv_func = neon_conv_real4;
|
break;
|
||||||
break;
|
case 8:
|
||||||
case 8:
|
conv_func = neon_conv_real8;
|
||||||
conv_func = neon_conv_real8;
|
break;
|
||||||
break;
|
case 12:
|
||||||
case 12:
|
conv_func = neon_conv_real12;
|
||||||
conv_func = neon_conv_real12;
|
break;
|
||||||
break;
|
case 16:
|
||||||
case 16:
|
conv_func = neon_conv_real16;
|
||||||
conv_func = neon_conv_real16;
|
break;
|
||||||
break;
|
case 20:
|
||||||
case 20:
|
conv_func = neon_conv_real20;
|
||||||
conv_func = neon_conv_real20;
|
break;
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (conv_func) {
|
if (conv_func) {
|
||||||
@@ -107,7 +100,7 @@ int convolve_real(float *x, int x_len,
|
|||||||
_base_convolve_real(x, x_len,
|
_base_convolve_real(x, x_len,
|
||||||
h, h_len,
|
h, h_len,
|
||||||
y, y_len,
|
y, y_len,
|
||||||
start, len, step, offset);
|
start, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
@@ -118,18 +111,17 @@ int convolve_real(float *x, int x_len,
|
|||||||
int convolve_complex(float *x, int x_len,
|
int convolve_complex(float *x, int x_len,
|
||||||
float *h, int h_len,
|
float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len,
|
int start, int len)
|
||||||
int step, int offset)
|
|
||||||
{
|
{
|
||||||
void (*conv_func)(float *, float *, float *, int, int) = NULL;
|
void (*conv_func)(float *, float *, float *, int, int) = NULL;
|
||||||
|
|
||||||
if (bounds_check(x_len, h_len, y_len, start, len, step) < 0)
|
if (bounds_check(x_len, h_len, y_len, start, len) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
memset(y, 0, len * 2 * sizeof(float));
|
memset(y, 0, len * 2 * sizeof(float));
|
||||||
|
|
||||||
#ifdef HAVE_NEON
|
#ifdef HAVE_NEON
|
||||||
if (step <= 4 && !(h_len % 4))
|
if (!(h_len % 4))
|
||||||
conv_func = neon_conv_cmplx_4n;
|
conv_func = neon_conv_cmplx_4n;
|
||||||
#endif
|
#endif
|
||||||
if (conv_func) {
|
if (conv_func) {
|
||||||
@@ -139,7 +131,7 @@ int convolve_complex(float *x, int x_len,
|
|||||||
_base_convolve_complex(x, x_len,
|
_base_convolve_complex(x, x_len,
|
||||||
h, h_len,
|
h, h_len,
|
||||||
y, y_len,
|
y, y_len,
|
||||||
start, len, step, offset);
|
start, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
* NEON Convolution
|
* NEON Convolution
|
||||||
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
|
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
@@ -11,10 +13,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
@@ -92,8 +90,8 @@ neon_conv_real12:
|
|||||||
vld2.32 {q8-q9}, [r4], r6
|
vld2.32 {q8-q9}, [r4], r6
|
||||||
vld2.32 {q10-q11}, [r5], r6
|
vld2.32 {q10-q11}, [r5], r6
|
||||||
#ifdef HAVE_NEON_FMA
|
#ifdef HAVE_NEON_FMA
|
||||||
vfma.f32 q1, q6, q0
|
vmul.f32 q1, q6, q0
|
||||||
vfma.f32 q3, q7, q0
|
vmul.f32 q3, q7, q0
|
||||||
vfma.f32 q1, q8, q2
|
vfma.f32 q1, q8, q2
|
||||||
vfma.f32 q3, q9, q2
|
vfma.f32 q3, q9, q2
|
||||||
vfma.f32 q1, q10, q4
|
vfma.f32 q1, q10, q4
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
* NEON scaling
|
* NEON scaling
|
||||||
* Copyright (C) 2012,2013 Thomas Tsou <tom@tsou.cc>
|
* Copyright (C) 2012,2013 Thomas Tsou <tom@tsou.cc>
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
@@ -11,10 +13,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* NEON complex multiplication
|
* NEON complex multiplication
|
||||||
* Copyright (C) 2012,2013 Thomas Tsou <tom@tsou.cc>
|
* Copyright (C) 2012,2013 Thomas Tsou <tom@tsou.cc>
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
@@ -11,10 +13,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.syntax unified
|
.syntax unified
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
* NEON scaling
|
* NEON scaling
|
||||||
* Copyright (C) 2012,2013 Thomas Tsou <tom@tsou.cc>
|
* Copyright (C) 2012,2013 Thomas Tsou <tom@tsou.cc>
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
@@ -11,10 +13,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
* ARM NEON Scaling
|
* ARM NEON Scaling
|
||||||
* Copyright (C) 2013 Thomas Tsou <tom@tsou.cc>
|
* Copyright (C) 2013 Thomas Tsou <tom@tsou.cc>
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
@@ -11,10 +13,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.syntax unified
|
.syntax unified
|
||||||
15
Transceiver52M/arch/common/Makefile.am
Normal file
15
Transceiver52M/arch/common/Makefile.am
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
AM_CFLAGS = -Wall -std=gnu99
|
||||||
|
|
||||||
|
noinst_LTLIBRARIES = libarch_common.la
|
||||||
|
|
||||||
|
noinst_HEADERS = \
|
||||||
|
convolve.h \
|
||||||
|
convert.h \
|
||||||
|
scale.h \
|
||||||
|
mult.h \
|
||||||
|
fft.h
|
||||||
|
|
||||||
|
libarch_common_la_SOURCES = \
|
||||||
|
convolve_base.c \
|
||||||
|
convert_base.c \
|
||||||
|
fft.c
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
* Conversion
|
* Conversion
|
||||||
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
|
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
@@ -11,10 +13,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "convert.h"
|
#include "convert.h"
|
||||||
@@ -31,4 +29,3 @@ void base_convert_short_float(float *out, const short *in, int len)
|
|||||||
for (int i = 0; i < len; i++)
|
for (int i = 0; i < len; i++)
|
||||||
out[i] = in[i];
|
out[i] = in[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,31 +1,27 @@
|
|||||||
#ifndef _CONVOLVE_H_
|
#ifndef _CONVOLVE_H_
|
||||||
#define _CONVOLVE_H_
|
#define _CONVOLVE_H_
|
||||||
|
|
||||||
void *convolve_h_alloc(int num);
|
void *convolve_h_alloc(size_t num);
|
||||||
|
|
||||||
int convolve_real(const float *x, int x_len,
|
int convolve_real(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len,
|
int start, int len);
|
||||||
int step, int offset);
|
|
||||||
|
|
||||||
int convolve_complex(const float *x, int x_len,
|
int convolve_complex(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len,
|
int start, int len);
|
||||||
int step, int offset);
|
|
||||||
|
|
||||||
int base_convolve_real(const float *x, int x_len,
|
int base_convolve_real(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len,
|
int start, int len);
|
||||||
int step, int offset);
|
|
||||||
|
|
||||||
int base_convolve_complex(const float *x, int x_len,
|
int base_convolve_complex(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len,
|
int start, int len);
|
||||||
int step, int offset);
|
|
||||||
|
|
||||||
void convolve_init(void);
|
void convolve_init(void);
|
||||||
|
|
||||||
@@ -2,6 +2,8 @@
|
|||||||
* Convolution
|
* Convolution
|
||||||
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
|
* Copyright (C) 2012, 2013 Thomas Tsou <tom@tsou.cc>
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*
|
||||||
* This library is free software; you can redistribute it and/or
|
* This library is free software; you can redistribute it and/or
|
||||||
* modify it under the terms of the GNU Lesser General Public
|
* modify it under the terms of the GNU Lesser General Public
|
||||||
* License as published by the Free Software Foundation; either
|
* License as published by the Free Software Foundation; either
|
||||||
@@ -11,10 +13,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
@@ -41,17 +39,17 @@ static void mac_cmplx(const float *x, const float *h, float *y)
|
|||||||
|
|
||||||
/* Base vector complex-complex multiply and accumulate */
|
/* Base vector complex-complex multiply and accumulate */
|
||||||
static void mac_real_vec_n(const float *x, const float *h, float *y,
|
static void mac_real_vec_n(const float *x, const float *h, float *y,
|
||||||
int len, int step, int offset)
|
int len)
|
||||||
{
|
{
|
||||||
for (int i = offset; i < len; i += step)
|
for (int i=0; i<len; i++)
|
||||||
mac_real(&x[2 * i], &h[2 * i], y);
|
mac_real(&x[2 * i], &h[2 * i], y);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Base vector complex-complex multiply and accumulate */
|
/* Base vector complex-complex multiply and accumulate */
|
||||||
static void mac_cmplx_vec_n(const float *x, const float *h, float *y,
|
static void mac_cmplx_vec_n(const float *x, const float *h, float *y,
|
||||||
int len, int step, int offset)
|
int len)
|
||||||
{
|
{
|
||||||
for (int i = offset; i < len; i += step)
|
for (int i=0; i<len; i++)
|
||||||
mac_cmplx(&x[2 * i], &h[2 * i], y);
|
mac_cmplx(&x[2 * i], &h[2 * i], y);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,14 +57,12 @@ static void mac_cmplx_vec_n(const float *x, const float *h, float *y,
|
|||||||
int _base_convolve_real(const float *x, int x_len,
|
int _base_convolve_real(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len,
|
int start, int len)
|
||||||
int step, int offset)
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
mac_real_vec_n(&x[2 * (i - (h_len - 1) + start)],
|
mac_real_vec_n(&x[2 * (i - (h_len - 1) + start)],
|
||||||
h,
|
h,
|
||||||
&y[2 * i], h_len,
|
&y[2 * i], h_len);
|
||||||
step, offset);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
@@ -76,14 +72,13 @@ int _base_convolve_real(const float *x, int x_len,
|
|||||||
int _base_convolve_complex(const float *x, int x_len,
|
int _base_convolve_complex(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len,
|
int start, int len)
|
||||||
int step, int offset)
|
|
||||||
{
|
{
|
||||||
for (int i = 0; i < len; i++) {
|
for (int i = 0; i < len; i++) {
|
||||||
mac_cmplx_vec_n(&x[2 * (i - (h_len - 1) + start)],
|
mac_cmplx_vec_n(&x[2 * (i - (h_len - 1) + start)],
|
||||||
h,
|
h,
|
||||||
&y[2 * i],
|
&y[2 * i],
|
||||||
h_len, step, offset);
|
h_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
@@ -91,10 +86,10 @@ int _base_convolve_complex(const float *x, int x_len,
|
|||||||
|
|
||||||
/* Buffer validity checks */
|
/* Buffer validity checks */
|
||||||
int bounds_check(int x_len, int h_len, int y_len,
|
int bounds_check(int x_len, int h_len, int y_len,
|
||||||
int start, int len, int step)
|
int start, int len)
|
||||||
{
|
{
|
||||||
if ((x_len < 1) || (h_len < 1) ||
|
if ((x_len < 1) || (h_len < 1) ||
|
||||||
(y_len < 1) || (len < 1) || (step < 1)) {
|
(y_len < 1) || (len < 1)) {
|
||||||
fprintf(stderr, "Convolve: Invalid input\n");
|
fprintf(stderr, "Convolve: Invalid input\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -113,10 +108,9 @@ int bounds_check(int x_len, int h_len, int y_len,
|
|||||||
int base_convolve_real(const float *x, int x_len,
|
int base_convolve_real(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len,
|
int start, int len)
|
||||||
int step, int offset)
|
|
||||||
{
|
{
|
||||||
if (bounds_check(x_len, h_len, y_len, start, len, step) < 0)
|
if (bounds_check(x_len, h_len, y_len, start, len) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
memset(y, 0, len * 2 * sizeof(float));
|
memset(y, 0, len * 2 * sizeof(float));
|
||||||
@@ -124,17 +118,16 @@ int base_convolve_real(const float *x, int x_len,
|
|||||||
return _base_convolve_real(x, x_len,
|
return _base_convolve_real(x, x_len,
|
||||||
h, h_len,
|
h, h_len,
|
||||||
y, y_len,
|
y, y_len,
|
||||||
start, len, step, offset);
|
start, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* API: Non-aligned (no SSE) complex-complex */
|
/* API: Non-aligned (no SSE) complex-complex */
|
||||||
int base_convolve_complex(const float *x, int x_len,
|
int base_convolve_complex(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len,
|
int start, int len)
|
||||||
int step, int offset)
|
|
||||||
{
|
{
|
||||||
if (bounds_check(x_len, h_len, y_len, start, len, step) < 0)
|
if (bounds_check(x_len, h_len, y_len, start, len) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
memset(y, 0, len * 2 * sizeof(float));
|
memset(y, 0, len * 2 * sizeof(float));
|
||||||
@@ -142,11 +135,11 @@ int base_convolve_complex(const float *x, int x_len,
|
|||||||
return _base_convolve_complex(x, x_len,
|
return _base_convolve_complex(x, x_len,
|
||||||
h, h_len,
|
h, h_len,
|
||||||
y, y_len,
|
y, y_len,
|
||||||
start, len, step, offset);
|
start, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Aligned filter tap allocation */
|
/* Aligned filter tap allocation */
|
||||||
void *convolve_h_alloc(int len)
|
void *convolve_h_alloc(size_t len)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_SSE3
|
#ifdef HAVE_SSE3
|
||||||
return memalign(16, len * 2 * sizeof(float));
|
return memalign(16, len * 2 * sizeof(float));
|
||||||
@@ -1,18 +1,20 @@
|
|||||||
/*
|
/*
|
||||||
* Fast Fourier transform
|
* Fast Fourier transform
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012 Tom Tsou <tom@tsou.cc>
|
* Copyright (C) 2012 Tom Tsou <tom@tsou.cc>
|
||||||
*
|
*
|
||||||
|
* SPDX-License-Identifier: LGPL-2.1+
|
||||||
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* This program is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU Affero General Public License as published by
|
* it under the terms of the GNU Affero General Public License as published by
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
* (at your option) any later version.
|
* (at your option) any later version.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU Affero General Public License for more details.
|
* GNU Affero General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the GNU Affero 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/>.
|
||||||
* See the COPYING file in the main directory for details.
|
* See the COPYING file in the main directory for details.
|
||||||
@@ -32,9 +34,9 @@ struct fft_hdl {
|
|||||||
fftwf_plan fft_plan;
|
fftwf_plan fft_plan;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*! \brief Initialize FFT backend
|
/*! \brief Initialize FFT backend
|
||||||
* \param[in] reverse FFT direction
|
* \param[in] reverse FFT direction
|
||||||
* \param[in] m FFT length
|
* \param[in] m FFT length
|
||||||
* \param[in] istride input stride count
|
* \param[in] istride input stride count
|
||||||
* \param[in] ostride output stride count
|
* \param[in] ostride output stride count
|
||||||
* \param[in] in input buffer (FFTW aligned)
|
* \param[in] in input buffer (FFTW aligned)
|
||||||
@@ -92,7 +94,7 @@ void fft_free(void *ptr)
|
|||||||
free(ptr);
|
free(ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Free FFT backend resources
|
/*! \brief Free FFT backend resources
|
||||||
*/
|
*/
|
||||||
void free_fft(struct fft_hdl *hdl)
|
void free_fft(struct fft_hdl *hdl)
|
||||||
{
|
{
|
||||||
@@ -101,7 +103,7 @@ void free_fft(struct fft_hdl *hdl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*! \brief Run multiple DFT operations with the initialized plan
|
/*! \brief Run multiple DFT operations with the initialized plan
|
||||||
* \param[in] hdl handle to an intitialized fft struct
|
* \param[in] hdl handle to an initialized fft struct
|
||||||
*
|
*
|
||||||
* Input and output buffers are configured with init_fft().
|
* Input and output buffers are configured with init_fft().
|
||||||
*/
|
*/
|
||||||
@@ -1,11 +1,15 @@
|
|||||||
if !ARCH_ARM
|
|
||||||
AM_CFLAGS = -Wall -std=gnu99 -I${srcdir}/../common
|
AM_CFLAGS = -Wall -std=gnu99 -I${srcdir}/../common
|
||||||
|
|
||||||
noinst_LTLIBRARIES = libarch.la
|
noinst_LTLIBRARIES = libarch.la
|
||||||
noinst_LTLIBRARIES += libarch_sse_3.la
|
noinst_LTLIBRARIES += libarch_sse_3.la
|
||||||
noinst_LTLIBRARIES += libarch_sse_4_1.la
|
noinst_LTLIBRARIES += libarch_sse_4_1.la
|
||||||
|
|
||||||
libarch_la_LIBADD =
|
noinst_HEADERS = \
|
||||||
|
convert_sse_3.h \
|
||||||
|
convert_sse_4_1.h \
|
||||||
|
convolve_sse_3.h
|
||||||
|
|
||||||
|
libarch_la_LIBADD = $(top_builddir)/Transceiver52M/arch/common/libarch_common.la
|
||||||
|
|
||||||
# SSE 3 specific code
|
# SSE 3 specific code
|
||||||
if HAVE_SSE3
|
if HAVE_SSE3
|
||||||
@@ -25,8 +29,5 @@ libarch_la_LIBADD += libarch_sse_4_1.la
|
|||||||
endif
|
endif
|
||||||
|
|
||||||
libarch_la_SOURCES = \
|
libarch_la_SOURCES = \
|
||||||
../common/convolve_base.c \
|
|
||||||
../common/convert_base.c \
|
|
||||||
convert.c \
|
convert.c \
|
||||||
convolve.c
|
convolve.c
|
||||||
endif
|
|
||||||
@@ -11,10 +11,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
@@ -27,7 +23,7 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Architecture dependant function pointers */
|
/* Architecture dependent function pointers */
|
||||||
struct convert_cpu_context {
|
struct convert_cpu_context {
|
||||||
void (*convert_si16_ps_16n) (float *, const short *, int);
|
void (*convert_si16_ps_16n) (float *, const short *, int);
|
||||||
void (*convert_si16_ps) (float *, const short *, int);
|
void (*convert_si16_ps) (float *, const short *, int);
|
||||||
@@ -11,10 +11,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
@@ -11,10 +11,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -11,10 +11,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
@@ -11,10 +11,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -11,10 +11,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
@@ -27,28 +23,28 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Architecture dependant function pointers */
|
/* Architecture dependent function pointers */
|
||||||
struct convolve_cpu_context {
|
struct convolve_cpu_context {
|
||||||
void (*conv_cmplx_4n) (const float *, int, const float *, int, float *,
|
void (*conv_cmplx_4n) (const float *, int, const float *, int, float *,
|
||||||
int, int, int, int, int);
|
int, int, int);
|
||||||
void (*conv_cmplx_8n) (const float *, int, const float *, int, float *,
|
void (*conv_cmplx_8n) (const float *, int, const float *, int, float *,
|
||||||
int, int, int, int, int);
|
int, int, int);
|
||||||
void (*conv_cmplx) (const float *, int, const float *, int, float *,
|
void (*conv_cmplx) (const float *, int, const float *, int, float *,
|
||||||
int, int, int, int, int);
|
int, int, int);
|
||||||
void (*conv_real4) (const float *, int, const float *, int, float *,
|
void (*conv_real4) (const float *, int, const float *, int, float *,
|
||||||
int, int, int, int, int);
|
int, int, int);
|
||||||
void (*conv_real8) (const float *, int, const float *, int, float *,
|
void (*conv_real8) (const float *, int, const float *, int, float *,
|
||||||
int, int, int, int, int);
|
int, int, int);
|
||||||
void (*conv_real12) (const float *, int, const float *, int, float *,
|
void (*conv_real12) (const float *, int, const float *, int, float *,
|
||||||
int, int, int, int, int);
|
int, int, int);
|
||||||
void (*conv_real16) (const float *, int, const float *, int, float *,
|
void (*conv_real16) (const float *, int, const float *, int, float *,
|
||||||
int, int, int, int, int);
|
int, int, int);
|
||||||
void (*conv_real20) (const float *, int, const float *, int, float *,
|
void (*conv_real20) (const float *, int, const float *, int, float *,
|
||||||
int, int, int, int, int);
|
int, int, int);
|
||||||
void (*conv_real4n) (const float *, int, const float *, int, float *,
|
void (*conv_real4n) (const float *, int, const float *, int, float *,
|
||||||
int, int, int, int, int);
|
int, int, int);
|
||||||
void (*conv_real) (const float *, int, const float *, int, float *, int,
|
void (*conv_real) (const float *, int, const float *, int, float *, int,
|
||||||
int, int, int, int);
|
int, int);
|
||||||
};
|
};
|
||||||
static struct convolve_cpu_context c;
|
static struct convolve_cpu_context c;
|
||||||
|
|
||||||
@@ -56,19 +52,17 @@ static struct convolve_cpu_context c;
|
|||||||
int _base_convolve_real(const float *x, int x_len,
|
int _base_convolve_real(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len,
|
int start, int len);
|
||||||
int step, int offset);
|
|
||||||
|
|
||||||
int _base_convolve_complex(const float *x, int x_len,
|
int _base_convolve_complex(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len,
|
int start, int len);
|
||||||
int step, int offset);
|
|
||||||
|
|
||||||
int bounds_check(int x_len, int h_len, int y_len,
|
int bounds_check(int x_len, int h_len, int y_len,
|
||||||
int start, int len, int step);
|
int start, int len);
|
||||||
|
|
||||||
/* API: Initalize convolve module */
|
/* API: Initialize convolve module */
|
||||||
void convolve_init(void)
|
void convolve_init(void)
|
||||||
{
|
{
|
||||||
c.conv_cmplx_4n = (void *)_base_convolve_complex;
|
c.conv_cmplx_4n = (void *)_base_convolve_complex;
|
||||||
@@ -99,46 +93,38 @@ void convolve_init(void)
|
|||||||
/* API: Aligned complex-real */
|
/* API: Aligned complex-real */
|
||||||
int convolve_real(const float *x, int x_len,
|
int convolve_real(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len, int start, int len, int step, int offset)
|
float *y, int y_len, int start, int len)
|
||||||
{
|
{
|
||||||
if (bounds_check(x_len, h_len, y_len, start, len, step) < 0)
|
#ifndef __OPTIMIZE__
|
||||||
|
if (bounds_check(x_len, h_len, y_len, start, len) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
#endif
|
||||||
memset(y, 0, len * 2 * sizeof(float));
|
memset(y, 0, len * 2 * sizeof(float));
|
||||||
|
|
||||||
if (step <= 4) {
|
switch (h_len) {
|
||||||
switch (h_len) {
|
case 4:
|
||||||
case 4:
|
c.conv_real4(x, x_len, h, h_len, y, y_len, start, len);
|
||||||
c.conv_real4(x, x_len, h, h_len, y, y_len, start, len,
|
break;
|
||||||
step, offset);
|
case 8:
|
||||||
break;
|
c.conv_real8(x, x_len, h, h_len, y, y_len, start, len);
|
||||||
case 8:
|
break;
|
||||||
c.conv_real8(x, x_len, h, h_len, y, y_len, start, len,
|
case 12:
|
||||||
step, offset);
|
c.conv_real12(x, x_len, h, h_len, y, y_len, start, len);
|
||||||
break;
|
break;
|
||||||
case 12:
|
case 16:
|
||||||
c.conv_real12(x, x_len, h, h_len, y, y_len, start, len,
|
c.conv_real16(x, x_len, h, h_len, y, y_len, start, len);
|
||||||
step, offset);
|
break;
|
||||||
break;
|
case 20:
|
||||||
case 16:
|
c.conv_real20(x, x_len, h, h_len, y, y_len, start, len);
|
||||||
c.conv_real16(x, x_len, h, h_len, y, y_len, start, len,
|
break;
|
||||||
step, offset);
|
default:
|
||||||
break;
|
if (!(h_len % 4))
|
||||||
case 20:
|
c.conv_real4n(x, x_len, h, h_len, y, y_len,
|
||||||
c.conv_real20(x, x_len, h, h_len, y, y_len, start, len,
|
start, len);
|
||||||
step, offset);
|
else
|
||||||
break;
|
c.conv_real(x, x_len, h, h_len, y, y_len, start,
|
||||||
default:
|
len);
|
||||||
if (!(h_len % 4))
|
}
|
||||||
c.conv_real4n(x, x_len, h, h_len, y, y_len,
|
|
||||||
start, len, step, offset);
|
|
||||||
else
|
|
||||||
c.conv_real(x, x_len, h, h_len, y, y_len, start,
|
|
||||||
len, step, offset);
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
c.conv_real(x, x_len, h, h_len, y, y_len, start, len, step,
|
|
||||||
offset);
|
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
@@ -147,26 +133,20 @@ int convolve_real(const float *x, int x_len,
|
|||||||
int convolve_complex(const float *x, int x_len,
|
int convolve_complex(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len, int step, int offset)
|
int start, int len)
|
||||||
{
|
{
|
||||||
if (bounds_check(x_len, h_len, y_len, start, len, step) < 0)
|
#ifndef __OPTIMIZE__
|
||||||
|
if (bounds_check(x_len, h_len, y_len, start, len) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
#endif
|
||||||
memset(y, 0, len * 2 * sizeof(float));
|
memset(y, 0, len * 2 * sizeof(float));
|
||||||
|
|
||||||
if (step <= 4) {
|
if (!(h_len % 8))
|
||||||
if (!(h_len % 8))
|
c.conv_cmplx_8n(x, x_len, h, h_len, y, y_len, start, len);
|
||||||
c.conv_cmplx_8n(x, x_len, h, h_len, y, y_len, start,
|
else if (!(h_len % 4))
|
||||||
len, step, offset);
|
c.conv_cmplx_4n(x, x_len, h, h_len, y, y_len, start, len);
|
||||||
else if (!(h_len % 4))
|
else
|
||||||
c.conv_cmplx_4n(x, x_len, h, h_len, y, y_len, start,
|
c.conv_cmplx(x, x_len, h, h_len, y, y_len, start, len);
|
||||||
len, step, offset);
|
|
||||||
else
|
|
||||||
c.conv_cmplx(x, x_len, h, h_len, y, y_len, start, len,
|
|
||||||
step, offset);
|
|
||||||
} else
|
|
||||||
c.conv_cmplx(x, x_len, h, h_len, y, y_len, start, len, step,
|
|
||||||
offset);
|
|
||||||
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
@@ -11,10 +11,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <malloc.h>
|
#include <malloc.h>
|
||||||
@@ -34,12 +30,12 @@
|
|||||||
void sse_conv_real4(const float *x, int x_len,
|
void sse_conv_real4(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len, int step, int offset)
|
int start, int len)
|
||||||
{
|
{
|
||||||
/* NOTE: The parameter list of this function has to match the parameter
|
/* NOTE: The parameter list of this function has to match the parameter
|
||||||
* list of _base_convolve_real() in convolve_base.c. This specific
|
* list of _base_convolve_real() in convolve_base.c. This specific
|
||||||
* implementation, ignores some of the parameters of
|
* implementation, ignores some of the parameters of
|
||||||
* _base_convolve_complex(), which are: x_len, y_len, offset, step */
|
* _base_convolve_complex(), which are: x_len, y_len. */
|
||||||
|
|
||||||
__m128 m0, m1, m2, m3, m4, m5, m6, m7;
|
__m128 m0, m1, m2, m3, m4, m5, m6, m7;
|
||||||
|
|
||||||
@@ -75,7 +71,7 @@ void sse_conv_real4(const float *x, int x_len,
|
|||||||
void sse_conv_real8(const float *x, int x_len,
|
void sse_conv_real8(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len, int step, int offset)
|
int start, int len)
|
||||||
{
|
{
|
||||||
/* See NOTE in sse_conv_real4() */
|
/* See NOTE in sse_conv_real4() */
|
||||||
|
|
||||||
@@ -126,7 +122,7 @@ void sse_conv_real8(const float *x, int x_len,
|
|||||||
void sse_conv_real12(const float *x, int x_len,
|
void sse_conv_real12(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len, int step, int offset)
|
int start, int len)
|
||||||
{
|
{
|
||||||
/* See NOTE in sse_conv_real4() */
|
/* See NOTE in sse_conv_real4() */
|
||||||
|
|
||||||
@@ -192,7 +188,7 @@ void sse_conv_real12(const float *x, int x_len,
|
|||||||
void sse_conv_real16(const float *x, int x_len,
|
void sse_conv_real16(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len, int step, int offset)
|
int start, int len)
|
||||||
{
|
{
|
||||||
/* See NOTE in sse_conv_real4() */
|
/* See NOTE in sse_conv_real4() */
|
||||||
|
|
||||||
@@ -271,7 +267,7 @@ void sse_conv_real16(const float *x, int x_len,
|
|||||||
void sse_conv_real20(const float *x, int x_len,
|
void sse_conv_real20(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len, int step, int offset)
|
int start, int len)
|
||||||
{
|
{
|
||||||
/* See NOTE in sse_conv_real4() */
|
/* See NOTE in sse_conv_real4() */
|
||||||
|
|
||||||
@@ -361,7 +357,7 @@ void sse_conv_real20(const float *x, int x_len,
|
|||||||
void sse_conv_real4n(const float *x, int x_len,
|
void sse_conv_real4n(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len, int step, int offset)
|
int start, int len)
|
||||||
{
|
{
|
||||||
/* See NOTE in sse_conv_real4() */
|
/* See NOTE in sse_conv_real4() */
|
||||||
|
|
||||||
@@ -408,12 +404,12 @@ void sse_conv_real4n(const float *x, int x_len,
|
|||||||
void sse_conv_cmplx_4n(const float *x, int x_len,
|
void sse_conv_cmplx_4n(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len, int step, int offset)
|
int start, int len)
|
||||||
{
|
{
|
||||||
/* NOTE: The parameter list of this function has to match the parameter
|
/* NOTE: The parameter list of this function has to match the parameter
|
||||||
* list of _base_convolve_complex() in convolve_base.c. This specific
|
* list of _base_convolve_complex() in convolve_base.c. This specific
|
||||||
* implementation, ignores some of the parameters of
|
* implementation, ignores some of the parameters of
|
||||||
* _base_convolve_complex(), which are: x_len, y_len, offset, step. */
|
* _base_convolve_complex(), which are: x_len, y_len. */
|
||||||
|
|
||||||
__m128 m0, m1, m2, m3, m4, m5, m6, m7;
|
__m128 m0, m1, m2, m3, m4, m5, m6, m7;
|
||||||
|
|
||||||
@@ -466,7 +462,7 @@ void sse_conv_cmplx_4n(const float *x, int x_len,
|
|||||||
void sse_conv_cmplx_8n(const float *x, int x_len,
|
void sse_conv_cmplx_8n(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len, int step, int offset)
|
int start, int len)
|
||||||
{
|
{
|
||||||
/* See NOTE in sse_conv_cmplx_4n() */
|
/* See NOTE in sse_conv_cmplx_4n() */
|
||||||
|
|
||||||
@@ -11,10 +11,6 @@
|
|||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
* Lesser General Public License for more details.
|
* Lesser General Public License for more details.
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU Lesser General Public
|
|
||||||
* License along with this library; if not, write to the Free Software
|
|
||||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
@@ -23,46 +19,46 @@
|
|||||||
void sse_conv_real4(const float *x, int x_len,
|
void sse_conv_real4(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len, int step, int offset);
|
int start, int len);
|
||||||
|
|
||||||
/* 8-tap SSE complex-real convolution */
|
/* 8-tap SSE complex-real convolution */
|
||||||
void sse_conv_real8(const float *x, int x_len,
|
void sse_conv_real8(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len, int step, int offset);
|
int start, int len);
|
||||||
|
|
||||||
/* 12-tap SSE complex-real convolution */
|
/* 12-tap SSE complex-real convolution */
|
||||||
void sse_conv_real12(const float *x, int x_len,
|
void sse_conv_real12(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len, int step, int offset);
|
int start, int len);
|
||||||
|
|
||||||
/* 16-tap SSE complex-real convolution */
|
/* 16-tap SSE complex-real convolution */
|
||||||
void sse_conv_real16(const float *x, int x_len,
|
void sse_conv_real16(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len, int step, int offset);
|
int start, int len);
|
||||||
|
|
||||||
/* 20-tap SSE complex-real convolution */
|
/* 20-tap SSE complex-real convolution */
|
||||||
void sse_conv_real20(const float *x, int x_len,
|
void sse_conv_real20(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len, int step, int offset);
|
int start, int len);
|
||||||
|
|
||||||
/* 4*N-tap SSE complex-real convolution */
|
/* 4*N-tap SSE complex-real convolution */
|
||||||
void sse_conv_real4n(const float *x, int x_len,
|
void sse_conv_real4n(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len, int step, int offset);
|
int start, int len);
|
||||||
|
|
||||||
/* 4*N-tap SSE complex-complex convolution */
|
/* 4*N-tap SSE complex-complex convolution */
|
||||||
void sse_conv_cmplx_4n(const float *x, int x_len,
|
void sse_conv_cmplx_4n(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len, int step, int offset);
|
int start, int len);
|
||||||
|
|
||||||
/* 8*N-tap SSE complex-complex convolution */
|
/* 8*N-tap SSE complex-complex convolution */
|
||||||
void sse_conv_cmplx_8n(const float *x, int x_len,
|
void sse_conv_cmplx_8n(const float *x, int x_len,
|
||||||
const float *h, int h_len,
|
const float *h, int h_len,
|
||||||
float *y, int y_len,
|
float *y, int y_len,
|
||||||
int start, int len, int step, int offset);
|
int start, int len);
|
||||||
23
Transceiver52M/device/Makefile.am
Normal file
23
Transceiver52M/device/Makefile.am
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
include $(top_srcdir)/Makefile.common
|
||||||
|
|
||||||
|
SUBDIRS = common
|
||||||
|
|
||||||
|
if DEVICE_IPC
|
||||||
|
SUBDIRS += ipc
|
||||||
|
endif
|
||||||
|
|
||||||
|
if DEVICE_USRP1
|
||||||
|
SUBDIRS += usrp1
|
||||||
|
endif
|
||||||
|
|
||||||
|
if DEVICE_UHD
|
||||||
|
SUBDIRS += uhd
|
||||||
|
endif
|
||||||
|
|
||||||
|
if DEVICE_LMS
|
||||||
|
SUBDIRS += lms
|
||||||
|
endif
|
||||||
|
|
||||||
|
if DEVICE_BLADE
|
||||||
|
SUBDIRS += bladerf
|
||||||
|
endif
|
||||||
11
Transceiver52M/device/bladerf/Makefile.am
Normal file
11
Transceiver52M/device/bladerf/Makefile.am
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
include $(top_srcdir)/Makefile.common
|
||||||
|
|
||||||
|
AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES) -I${srcdir}/../common
|
||||||
|
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS) $(LIBOSMOVTY_CFLAGS) $(BLADE_CFLAGS)
|
||||||
|
|
||||||
|
noinst_HEADERS = bladerf.h
|
||||||
|
|
||||||
|
noinst_LTLIBRARIES = libdevice.la
|
||||||
|
|
||||||
|
libdevice_la_SOURCES = bladerf.cpp
|
||||||
|
libdevice_la_LIBADD = $(top_builddir)/Transceiver52M/device/common/libdevice_common.la
|
||||||
611
Transceiver52M/device/bladerf/bladerf.cpp
Normal file
611
Transceiver52M/device/bladerf/bladerf.cpp
Normal file
@@ -0,0 +1,611 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 sysmocom - s.f.m.c. GmbH
|
||||||
|
*
|
||||||
|
* Author: Eric Wild <ewild@sysmocom.de>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* See the COPYING file in the main directory for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <libbladeRF.h>
|
||||||
|
#include "radioDevice.h"
|
||||||
|
#include "bladerf.h"
|
||||||
|
#include "Threads.h"
|
||||||
|
#include "Logger.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <osmocom/core/utils.h>
|
||||||
|
#include <osmocom/gsm/gsm_utils.h>
|
||||||
|
#include <osmocom/vty/cpu_sched_vty.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SAMPLE_BUF_SZ (1 << 20)
|
||||||
|
|
||||||
|
#define B2XX_TIMING_4_4SPS 6.18462e-5
|
||||||
|
|
||||||
|
#define CHKRET() \
|
||||||
|
{ \
|
||||||
|
if (status != 0) \
|
||||||
|
LOGC(DDEV, ERROR) << bladerf_strerror(status); \
|
||||||
|
}
|
||||||
|
|
||||||
|
static const dev_map_t dev_param_map{
|
||||||
|
{ std::make_tuple(blade_dev_type::BLADE2, 4, 4), { 1, 26e6, GSMRATE, B2XX_TIMING_4_4SPS, "B200 4 SPS" } },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const power_map_t dev_band_nom_power_param_map{
|
||||||
|
{ std::make_tuple(blade_dev_type::BLADE2, GSM_BAND_850), { 89.75, 13.3, -7.5 } },
|
||||||
|
{ std::make_tuple(blade_dev_type::BLADE2, GSM_BAND_900), { 89.75, 13.3, -7.5 } },
|
||||||
|
{ std::make_tuple(blade_dev_type::BLADE2, GSM_BAND_1800), { 89.75, 7.5, -11.0 } },
|
||||||
|
{ std::make_tuple(blade_dev_type::BLADE2, GSM_BAND_1900), { 89.75, 7.7, -11.0 } },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* So far measurements done for B210 show really close to linear relationship
|
||||||
|
* between gain and real output power, so we simply adjust the measured offset
|
||||||
|
*/
|
||||||
|
static double TxGain2TxPower(const dev_band_desc &desc, double tx_gain_db)
|
||||||
|
{
|
||||||
|
return desc.nom_out_tx_power - (desc.nom_uhd_tx_gain - tx_gain_db);
|
||||||
|
}
|
||||||
|
static double TxPower2TxGain(const dev_band_desc &desc, double tx_power_dbm)
|
||||||
|
{
|
||||||
|
return desc.nom_uhd_tx_gain - (desc.nom_out_tx_power - tx_power_dbm);
|
||||||
|
}
|
||||||
|
|
||||||
|
blade_device::blade_device(InterfaceType iface, const struct trx_cfg *cfg)
|
||||||
|
: RadioDevice(iface, cfg), band_manager(dev_band_nom_power_param_map, dev_param_map), dev(nullptr),
|
||||||
|
rx_gain_min(0.0), rx_gain_max(0.0), tx_spp(0), rx_spp(0), started(false), aligned(false), drop_cnt(0),
|
||||||
|
prev_ts(0), ts_initial(0), ts_offset(0), async_event_thrd(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
blade_device::~blade_device()
|
||||||
|
{
|
||||||
|
if (dev) {
|
||||||
|
bladerf_enable_module(dev, BLADERF_CHANNEL_RX(0), false);
|
||||||
|
bladerf_enable_module(dev, BLADERF_CHANNEL_TX(0), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
stop();
|
||||||
|
|
||||||
|
for (size_t i = 0; i < rx_buffers.size(); i++)
|
||||||
|
delete rx_buffers[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void blade_device::init_gains()
|
||||||
|
{
|
||||||
|
double tx_gain_min, tx_gain_max;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
const struct bladerf_range *r;
|
||||||
|
bladerf_get_gain_range(dev, BLADERF_RX, &r);
|
||||||
|
|
||||||
|
rx_gain_min = r->min;
|
||||||
|
rx_gain_max = r->max;
|
||||||
|
LOGC(DDEV, INFO) << "Supported Rx gain range [" << rx_gain_min << "; " << rx_gain_max << "]";
|
||||||
|
|
||||||
|
for (size_t i = 0; i < rx_gains.size(); i++) {
|
||||||
|
double gain = (rx_gain_min + rx_gain_max) / 2;
|
||||||
|
status = bladerf_set_gain_mode(dev, BLADERF_CHANNEL_RX(i), BLADERF_GAIN_MGC);
|
||||||
|
CHKRET()
|
||||||
|
bladerf_gain_mode m;
|
||||||
|
bladerf_get_gain_mode(dev, BLADERF_CHANNEL_RX(i), &m);
|
||||||
|
LOGC(DDEV, INFO) << (m == BLADERF_GAIN_MANUAL ? "gain manual" : "gain AUTO");
|
||||||
|
|
||||||
|
status = bladerf_set_gain(dev, BLADERF_CHANNEL_RX(i), 0);
|
||||||
|
CHKRET()
|
||||||
|
int actual_gain;
|
||||||
|
status = bladerf_get_gain(dev, BLADERF_CHANNEL_RX(i), &actual_gain);
|
||||||
|
CHKRET()
|
||||||
|
LOGC(DDEV, INFO) << "Default setting Rx gain for channel " << i << " to " << gain << " scale "
|
||||||
|
<< r->scale << " actual " << actual_gain;
|
||||||
|
rx_gains[i] = actual_gain;
|
||||||
|
|
||||||
|
status = bladerf_set_gain(dev, BLADERF_CHANNEL_RX(i), 0);
|
||||||
|
CHKRET()
|
||||||
|
status = bladerf_get_gain(dev, BLADERF_CHANNEL_RX(i), &actual_gain);
|
||||||
|
CHKRET()
|
||||||
|
LOGC(DDEV, INFO) << "Default setting Rx gain for channel " << i << " to " << gain << " scale "
|
||||||
|
<< r->scale << " actual " << actual_gain;
|
||||||
|
rx_gains[i] = actual_gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = bladerf_get_gain_range(dev, BLADERF_TX, &r);
|
||||||
|
CHKRET()
|
||||||
|
tx_gain_min = r->min;
|
||||||
|
tx_gain_max = r->max;
|
||||||
|
LOGC(DDEV, INFO) << "Supported Tx gain range [" << tx_gain_min << "; " << tx_gain_max << "]";
|
||||||
|
|
||||||
|
for (size_t i = 0; i < tx_gains.size(); i++) {
|
||||||
|
double gain = (tx_gain_min + tx_gain_max) / 2;
|
||||||
|
status = bladerf_set_gain(dev, BLADERF_CHANNEL_TX(i), 30);
|
||||||
|
CHKRET()
|
||||||
|
int actual_gain;
|
||||||
|
status = bladerf_get_gain(dev, BLADERF_CHANNEL_TX(i), &actual_gain);
|
||||||
|
CHKRET()
|
||||||
|
LOGC(DDEV, INFO) << "Default setting Tx gain for channel " << i << " to " << gain << " scale "
|
||||||
|
<< r->scale << " actual " << actual_gain;
|
||||||
|
tx_gains[i] = actual_gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void blade_device::set_rates()
|
||||||
|
{
|
||||||
|
struct bladerf_rational_rate rate = { 0, static_cast<uint64_t>((1625e3 * 4)), 6 }, actual;
|
||||||
|
auto status = bladerf_set_rational_sample_rate(dev, BLADERF_CHANNEL_RX(0), &rate, &actual);
|
||||||
|
CHKRET()
|
||||||
|
status = bladerf_set_rational_sample_rate(dev, BLADERF_CHANNEL_TX(0), &rate, &actual);
|
||||||
|
CHKRET()
|
||||||
|
|
||||||
|
tx_rate = rx_rate = (double)rate.num / (double)rate.den;
|
||||||
|
|
||||||
|
LOGC(DDEV, INFO) << "Rates set to" << tx_rate << " / " << rx_rate;
|
||||||
|
|
||||||
|
bladerf_set_bandwidth(dev, BLADERF_CHANNEL_RX(0), (bladerf_bandwidth)2e6, (bladerf_bandwidth *)NULL);
|
||||||
|
bladerf_set_bandwidth(dev, BLADERF_CHANNEL_TX(0), (bladerf_bandwidth)2e6, (bladerf_bandwidth *)NULL);
|
||||||
|
|
||||||
|
ts_offset = 60; // FIXME: actual blade offset, should equal b2xx
|
||||||
|
}
|
||||||
|
|
||||||
|
double blade_device::setRxGain(double db, size_t chan)
|
||||||
|
{
|
||||||
|
if (chan >= rx_gains.size()) {
|
||||||
|
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
bladerf_set_gain(dev, BLADERF_CHANNEL_RX(chan), 30); //db);
|
||||||
|
int actual_gain;
|
||||||
|
bladerf_get_gain(dev, BLADERF_CHANNEL_RX(chan), &actual_gain);
|
||||||
|
|
||||||
|
rx_gains[chan] = actual_gain;
|
||||||
|
|
||||||
|
LOGC(DDEV, INFO) << "Set RX gain to " << rx_gains[chan] << "dB (asked for " << db << "dB)";
|
||||||
|
|
||||||
|
return rx_gains[chan];
|
||||||
|
}
|
||||||
|
|
||||||
|
double blade_device::getRxGain(size_t chan)
|
||||||
|
{
|
||||||
|
if (chan >= rx_gains.size()) {
|
||||||
|
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rx_gains[chan];
|
||||||
|
}
|
||||||
|
|
||||||
|
double blade_device::rssiOffset(size_t chan)
|
||||||
|
{
|
||||||
|
double rssiOffset;
|
||||||
|
dev_band_desc desc;
|
||||||
|
|
||||||
|
if (chan >= rx_gains.size()) {
|
||||||
|
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_dev_band_desc(desc);
|
||||||
|
rssiOffset = rx_gains[chan] + desc.rxgain2rssioffset_rel;
|
||||||
|
return rssiOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
double blade_device::setPowerAttenuation(int atten, size_t chan)
|
||||||
|
{
|
||||||
|
double tx_power, db;
|
||||||
|
dev_band_desc desc;
|
||||||
|
|
||||||
|
if (chan >= tx_gains.size()) {
|
||||||
|
LOGC(DDEV, ALERT) << "Requested non-existent channel" << chan;
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_dev_band_desc(desc);
|
||||||
|
tx_power = desc.nom_out_tx_power - atten;
|
||||||
|
db = TxPower2TxGain(desc, tx_power);
|
||||||
|
|
||||||
|
bladerf_set_gain(dev, BLADERF_CHANNEL_TX(chan), 30);
|
||||||
|
int actual_gain;
|
||||||
|
bladerf_get_gain(dev, BLADERF_CHANNEL_RX(chan), &actual_gain);
|
||||||
|
|
||||||
|
tx_gains[chan] = actual_gain;
|
||||||
|
|
||||||
|
LOGC(DDEV, INFO)
|
||||||
|
<< "Set TX gain to " << tx_gains[chan] << "dB, ~" << TxGain2TxPower(desc, tx_gains[chan]) << " dBm "
|
||||||
|
<< "(asked for " << db << " dB, ~" << tx_power << " dBm)";
|
||||||
|
|
||||||
|
return desc.nom_out_tx_power - TxGain2TxPower(desc, tx_gains[chan]);
|
||||||
|
}
|
||||||
|
double blade_device::getPowerAttenuation(size_t chan)
|
||||||
|
{
|
||||||
|
dev_band_desc desc;
|
||||||
|
if (chan >= tx_gains.size()) {
|
||||||
|
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
get_dev_band_desc(desc);
|
||||||
|
return desc.nom_out_tx_power - TxGain2TxPower(desc, tx_gains[chan]);
|
||||||
|
}
|
||||||
|
|
||||||
|
int blade_device::getNominalTxPower(size_t chan)
|
||||||
|
{
|
||||||
|
dev_band_desc desc;
|
||||||
|
get_dev_band_desc(desc);
|
||||||
|
|
||||||
|
return desc.nom_out_tx_power;
|
||||||
|
}
|
||||||
|
|
||||||
|
int blade_device::open()
|
||||||
|
{
|
||||||
|
bladerf_log_set_verbosity(BLADERF_LOG_LEVEL_VERBOSE);
|
||||||
|
bladerf_set_usb_reset_on_open(true);
|
||||||
|
auto success = bladerf_open(&dev, cfg->dev_args);
|
||||||
|
if (success != 0) {
|
||||||
|
struct bladerf_devinfo *info;
|
||||||
|
auto num_devs = bladerf_get_device_list(&info);
|
||||||
|
LOGC(DDEV, ALERT) << "No bladerf devices found with identifier '" << cfg->dev_args << "'";
|
||||||
|
if (num_devs) {
|
||||||
|
for (int i = 0; i < num_devs; i++)
|
||||||
|
LOGC(DDEV, ALERT) << "Found device:" << info[i].product << " serial " << info[i].serial;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (strcmp("bladerf2", bladerf_get_board_name(dev))) {
|
||||||
|
LOGC(DDEV, ALERT) << "Only BladeRF2 supported! found:" << bladerf_get_board_name(dev);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_type = blade_dev_type::BLADE2;
|
||||||
|
tx_window = TX_WINDOW_FIXED;
|
||||||
|
update_band_dev(dev_key(dev_type, tx_sps, rx_sps));
|
||||||
|
|
||||||
|
struct bladerf_devinfo info;
|
||||||
|
bladerf_get_devinfo(dev, &info);
|
||||||
|
LOGC(DDEV, INFO) << "Using discovered bladerf device " << info.serial;
|
||||||
|
|
||||||
|
tx_freqs.resize(chans);
|
||||||
|
rx_freqs.resize(chans);
|
||||||
|
tx_gains.resize(chans);
|
||||||
|
rx_gains.resize(chans);
|
||||||
|
rx_buffers.resize(chans);
|
||||||
|
|
||||||
|
switch (cfg->clock_ref) {
|
||||||
|
case REF_INTERNAL:
|
||||||
|
case REF_EXTERNAL:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOGC(DDEV, ALERT) << "Invalid reference type";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cfg->clock_ref == REF_EXTERNAL) {
|
||||||
|
bool is_locked;
|
||||||
|
int status = bladerf_set_pll_enable(dev, true);
|
||||||
|
CHKRET()
|
||||||
|
status = bladerf_set_pll_refclk(dev, 10000000);
|
||||||
|
CHKRET()
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
usleep(50 * 1000);
|
||||||
|
status = bladerf_get_pll_lock_state(dev, &is_locked);
|
||||||
|
CHKRET()
|
||||||
|
if (is_locked)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!is_locked) {
|
||||||
|
LOGC(DDEV, ALERT) << "unable to lock refclk!";
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGC(DDEV, INFO)
|
||||||
|
<< "Selected clock source is " << ((cfg->clock_ref == REF_INTERNAL) ? "internal" : "external 10Mhz");
|
||||||
|
|
||||||
|
set_rates();
|
||||||
|
|
||||||
|
/*
|
||||||
|
1ts = 3/5200s
|
||||||
|
1024*2 = small gap(~180us) every 9.23ms = every 16 ts? -> every 2 frames
|
||||||
|
1024*1 = large gap(~627us) every 9.23ms = every 16 ts? -> every 2 frames
|
||||||
|
|
||||||
|
rif convertbuffer = 625*4 = 2500 -> 4 ts
|
||||||
|
rif rxtxbuf = 4 * segment(625*4) = 10000 -> 16 ts
|
||||||
|
*/
|
||||||
|
const unsigned int num_buffers = 256;
|
||||||
|
const unsigned int buffer_size = 1024 * 4; /* Must be a multiple of 1024 */
|
||||||
|
const unsigned int num_transfers = 32;
|
||||||
|
const unsigned int timeout_ms = 3500;
|
||||||
|
|
||||||
|
bladerf_sync_config(dev, BLADERF_RX_X1, BLADERF_FORMAT_SC16_Q11_META, num_buffers, buffer_size, num_transfers,
|
||||||
|
timeout_ms);
|
||||||
|
|
||||||
|
bladerf_sync_config(dev, BLADERF_TX_X1, BLADERF_FORMAT_SC16_Q11_META, num_buffers, buffer_size, num_transfers,
|
||||||
|
timeout_ms);
|
||||||
|
|
||||||
|
/* Number of samples per over-the-wire packet */
|
||||||
|
tx_spp = rx_spp = buffer_size;
|
||||||
|
|
||||||
|
size_t buf_len = SAMPLE_BUF_SZ / sizeof(uint32_t);
|
||||||
|
for (size_t i = 0; i < rx_buffers.size(); i++)
|
||||||
|
rx_buffers[i] = new smpl_buf(buf_len);
|
||||||
|
|
||||||
|
pkt_bufs = std::vector<std::vector<short> >(chans, std::vector<short>(2 * rx_spp));
|
||||||
|
for (size_t i = 0; i < pkt_bufs.size(); i++)
|
||||||
|
pkt_ptrs.push_back(&pkt_bufs[i].front());
|
||||||
|
|
||||||
|
init_gains();
|
||||||
|
|
||||||
|
return NORMAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool blade_device::restart()
|
||||||
|
{
|
||||||
|
/* Allow 100 ms delay to align multi-channel streams */
|
||||||
|
double delay = 0.2;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
status = bladerf_enable_module(dev, BLADERF_CHANNEL_RX(0), true);
|
||||||
|
CHKRET()
|
||||||
|
status = bladerf_enable_module(dev, BLADERF_CHANNEL_TX(0), true);
|
||||||
|
CHKRET()
|
||||||
|
|
||||||
|
bladerf_timestamp now;
|
||||||
|
status = bladerf_get_timestamp(dev, BLADERF_RX, &now);
|
||||||
|
ts_initial = now + rx_rate * delay;
|
||||||
|
LOGC(DDEV, INFO) << "Initial timestamp " << ts_initial << std::endl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool blade_device::start()
|
||||||
|
{
|
||||||
|
LOGC(DDEV, INFO) << "Starting USRP...";
|
||||||
|
|
||||||
|
if (started) {
|
||||||
|
LOGC(DDEV, ERROR) << "Device already started";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!restart())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
started = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool blade_device::stop()
|
||||||
|
{
|
||||||
|
if (!started)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* reset internal buffer timestamps */
|
||||||
|
for (size_t i = 0; i < rx_buffers.size(); i++)
|
||||||
|
rx_buffers[i]->reset();
|
||||||
|
|
||||||
|
band_reset();
|
||||||
|
|
||||||
|
started = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int blade_device::readSamples(std::vector<short *> &bufs, int len, bool *overrun, TIMESTAMP timestamp, bool *underrun)
|
||||||
|
{
|
||||||
|
ssize_t rc;
|
||||||
|
uint64_t ts;
|
||||||
|
|
||||||
|
if (bufs.size() != chans) {
|
||||||
|
LOGC(DDEV, ALERT) << "Invalid channel combination " << bufs.size();
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*overrun = false;
|
||||||
|
*underrun = false;
|
||||||
|
|
||||||
|
// Shift read time with respect to transmit clock
|
||||||
|
timestamp += ts_offset;
|
||||||
|
|
||||||
|
ts = timestamp;
|
||||||
|
LOGC(DDEV, DEBUG) << "Requested timestamp = " << ts;
|
||||||
|
|
||||||
|
// Check that timestamp is valid
|
||||||
|
rc = rx_buffers[0]->avail_smpls(timestamp);
|
||||||
|
if (rc < 0) {
|
||||||
|
LOGC(DDEV, ERROR) << rx_buffers[0]->str_code(rc);
|
||||||
|
LOGC(DDEV, ERROR) << rx_buffers[0]->str_status(timestamp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct bladerf_metadata meta = {};
|
||||||
|
meta.timestamp = ts;
|
||||||
|
|
||||||
|
while (rx_buffers[0]->avail_smpls(timestamp) < len) {
|
||||||
|
thread_enable_cancel(false);
|
||||||
|
int status = bladerf_sync_rx(dev, pkt_ptrs[0], len, &meta, 200U);
|
||||||
|
thread_enable_cancel(true);
|
||||||
|
|
||||||
|
if (status != 0)
|
||||||
|
LOGC(DDEV, ERROR) << "RX broken: " << bladerf_strerror(status);
|
||||||
|
if (meta.flags & BLADERF_META_STATUS_OVERRUN)
|
||||||
|
LOGC(DDEV, ERROR) << "RX borken, OVERRUN: " << bladerf_strerror(status);
|
||||||
|
|
||||||
|
size_t num_smpls = meta.actual_count;
|
||||||
|
;
|
||||||
|
ts = meta.timestamp;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < rx_buffers.size(); i++) {
|
||||||
|
rc = rx_buffers[i]->write((short *)&pkt_bufs[i].front(), num_smpls, ts);
|
||||||
|
|
||||||
|
// Continue on local overrun, exit on other errors
|
||||||
|
if ((rc < 0)) {
|
||||||
|
LOGC(DDEV, ERROR) << rx_buffers[i]->str_code(rc);
|
||||||
|
LOGC(DDEV, ERROR) << rx_buffers[i]->str_status(timestamp);
|
||||||
|
if (rc != smpl_buf::ERROR_OVERFLOW)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
meta = {};
|
||||||
|
meta.timestamp = ts + num_smpls;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < rx_buffers.size(); i++) {
|
||||||
|
rc = rx_buffers[i]->read(bufs[i], len, timestamp);
|
||||||
|
if ((rc < 0) || (rc != len)) {
|
||||||
|
LOGC(DDEV, ERROR) << rx_buffers[i]->str_code(rc);
|
||||||
|
LOGC(DDEV, ERROR) << rx_buffers[i]->str_status(timestamp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
int blade_device::writeSamples(std::vector<short *> &bufs, int len, bool *underrun, unsigned long long timestamp)
|
||||||
|
{
|
||||||
|
*underrun = false;
|
||||||
|
static bool first_tx = true;
|
||||||
|
struct bladerf_metadata meta = {};
|
||||||
|
if (first_tx) {
|
||||||
|
meta.timestamp = timestamp;
|
||||||
|
meta.flags = BLADERF_META_FLAG_TX_BURST_START;
|
||||||
|
first_tx = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_enable_cancel(false);
|
||||||
|
int status = bladerf_sync_tx(dev, (const void *)bufs[0], len, &meta, 200U);
|
||||||
|
thread_enable_cancel(true);
|
||||||
|
|
||||||
|
if (status != 0)
|
||||||
|
LOGC(DDEV, ERROR) << "TX broken: " << bladerf_strerror(status);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool blade_device::updateAlignment(TIMESTAMP timestamp)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool blade_device::set_freq(double freq, size_t chan, bool tx)
|
||||||
|
{
|
||||||
|
if (tx) {
|
||||||
|
bladerf_set_frequency(dev, BLADERF_CHANNEL_TX(chan), freq);
|
||||||
|
bladerf_frequency f;
|
||||||
|
bladerf_get_frequency(dev, BLADERF_CHANNEL_TX(chan), &f);
|
||||||
|
tx_freqs[chan] = f;
|
||||||
|
} else {
|
||||||
|
bladerf_set_frequency(dev, BLADERF_CHANNEL_RX(chan), freq);
|
||||||
|
bladerf_frequency f;
|
||||||
|
bladerf_get_frequency(dev, BLADERF_CHANNEL_RX(chan), &f);
|
||||||
|
rx_freqs[chan] = f;
|
||||||
|
}
|
||||||
|
LOGCHAN(chan, DDEV, INFO) << "set_freq(" << freq << ", " << (tx ? "TX" : "RX") << "): " << std::endl;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool blade_device::setTxFreq(double wFreq, size_t chan)
|
||||||
|
{
|
||||||
|
if (chan >= tx_freqs.size()) {
|
||||||
|
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ScopedLock lock(tune_lock);
|
||||||
|
|
||||||
|
if (!update_band_from_freq(wFreq, chan, true))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!set_freq(wFreq, chan, true))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool blade_device::setRxFreq(double wFreq, size_t chan)
|
||||||
|
{
|
||||||
|
if (chan >= rx_freqs.size()) {
|
||||||
|
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ScopedLock lock(tune_lock);
|
||||||
|
|
||||||
|
if (!update_band_from_freq(wFreq, chan, false))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return set_freq(wFreq, chan, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
double blade_device::getTxFreq(size_t chan)
|
||||||
|
{
|
||||||
|
if (chan >= tx_freqs.size()) {
|
||||||
|
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tx_freqs[chan];
|
||||||
|
}
|
||||||
|
|
||||||
|
double blade_device::getRxFreq(size_t chan)
|
||||||
|
{
|
||||||
|
if (chan >= rx_freqs.size()) {
|
||||||
|
LOGC(DDEV, ALERT) << "Requested non-existent channel " << chan;
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rx_freqs[chan];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool blade_device::requiresRadioAlign()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
GSM::Time blade_device::minLatency()
|
||||||
|
{
|
||||||
|
return GSM::Time(6, 7);
|
||||||
|
}
|
||||||
|
|
||||||
|
TIMESTAMP blade_device::initialWriteTimestamp()
|
||||||
|
{
|
||||||
|
return ts_initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
TIMESTAMP blade_device::initialReadTimestamp()
|
||||||
|
{
|
||||||
|
return ts_initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
double blade_device::fullScaleInputValue()
|
||||||
|
{
|
||||||
|
return (double)2047;
|
||||||
|
}
|
||||||
|
|
||||||
|
double blade_device::fullScaleOutputValue()
|
||||||
|
{
|
||||||
|
return (double)2047;
|
||||||
|
}
|
||||||
|
|
||||||
|
RadioDevice *RadioDevice::make(InterfaceType type, const struct trx_cfg *cfg)
|
||||||
|
{
|
||||||
|
return new blade_device(type, cfg);
|
||||||
|
}
|
||||||
195
Transceiver52M/device/bladerf/bladerf.h
Normal file
195
Transceiver52M/device/bladerf/bladerf.h
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 sysmocom - s.f.m.c. GmbH
|
||||||
|
*
|
||||||
|
* Author: Eric Wild <ewild@sysmocom.de>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* See the COPYING file in the main directory for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
#include "config.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "bandmanager.h"
|
||||||
|
#include "radioDevice.h"
|
||||||
|
#include "smpl_buf.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <osmocom/gsm/gsm_utils.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class blade_dev_type { BLADE1, BLADE2 };
|
||||||
|
|
||||||
|
struct dev_band_desc {
|
||||||
|
/* Maximum UHD Tx Gain which can be set/used without distorting the
|
||||||
|
output signal, and the resulting real output power measured when that
|
||||||
|
gain is used. Correct measured values only provided for B210 so far. */
|
||||||
|
double nom_uhd_tx_gain; /* dB */
|
||||||
|
double nom_out_tx_power; /* dBm */
|
||||||
|
/* Factor used to infer base real RSSI offset on the Rx path based on current
|
||||||
|
configured RxGain. The resulting rssiOffset is added to the per burst
|
||||||
|
calculated energy in upper layers. These values were empirically
|
||||||
|
found and may change based on multiple factors, see OS#4468.
|
||||||
|
rssiOffset = rxGain + rxgain2rssioffset_rel;
|
||||||
|
*/
|
||||||
|
double rxgain2rssioffset_rel; /* dB */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Device parameter descriptor */
|
||||||
|
struct dev_desc {
|
||||||
|
unsigned channels;
|
||||||
|
double mcr;
|
||||||
|
double rate;
|
||||||
|
double offset;
|
||||||
|
std::string desc_str;
|
||||||
|
};
|
||||||
|
|
||||||
|
using dev_key = std::tuple<blade_dev_type, int, int>;
|
||||||
|
using dev_band_key = std::tuple<blade_dev_type, enum gsm_band>;
|
||||||
|
using power_map_t = std::map<dev_band_key, dev_band_desc>;
|
||||||
|
using dev_map_t = std::map<dev_key, dev_desc>;
|
||||||
|
|
||||||
|
class blade_device : public RadioDevice, public band_manager<power_map_t, dev_map_t> {
|
||||||
|
public:
|
||||||
|
blade_device(InterfaceType iface, const struct trx_cfg *cfg);
|
||||||
|
~blade_device();
|
||||||
|
|
||||||
|
int open();
|
||||||
|
bool start();
|
||||||
|
bool stop();
|
||||||
|
bool restart();
|
||||||
|
enum TxWindowType getWindowType()
|
||||||
|
{
|
||||||
|
return tx_window;
|
||||||
|
}
|
||||||
|
|
||||||
|
int readSamples(std::vector<short *> &bufs, int len, bool *overrun, TIMESTAMP timestamp, bool *underrun);
|
||||||
|
|
||||||
|
int writeSamples(std::vector<short *> &bufs, int len, bool *underrun, TIMESTAMP timestamp);
|
||||||
|
|
||||||
|
bool updateAlignment(TIMESTAMP timestamp);
|
||||||
|
|
||||||
|
bool setTxFreq(double wFreq, size_t chan);
|
||||||
|
bool setRxFreq(double wFreq, size_t chan);
|
||||||
|
|
||||||
|
TIMESTAMP initialWriteTimestamp();
|
||||||
|
TIMESTAMP initialReadTimestamp();
|
||||||
|
|
||||||
|
double fullScaleInputValue();
|
||||||
|
double fullScaleOutputValue();
|
||||||
|
|
||||||
|
double setRxGain(double db, size_t chan);
|
||||||
|
double getRxGain(size_t chan);
|
||||||
|
double maxRxGain(void)
|
||||||
|
{
|
||||||
|
return rx_gain_max;
|
||||||
|
}
|
||||||
|
double minRxGain(void)
|
||||||
|
{
|
||||||
|
return rx_gain_min;
|
||||||
|
}
|
||||||
|
double rssiOffset(size_t chan);
|
||||||
|
|
||||||
|
double setPowerAttenuation(int atten, size_t chan);
|
||||||
|
double getPowerAttenuation(size_t chan = 0);
|
||||||
|
|
||||||
|
int getNominalTxPower(size_t chan = 0);
|
||||||
|
|
||||||
|
double getTxFreq(size_t chan);
|
||||||
|
double getRxFreq(size_t chan);
|
||||||
|
double getRxFreq();
|
||||||
|
|
||||||
|
bool setRxAntenna(const std::string &ant, size_t chan)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
std::string getRxAntenna(size_t chan)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
bool setTxAntenna(const std::string &ant, size_t chan)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
std::string getTxAntenna(size_t chan)
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
};
|
||||||
|
|
||||||
|
bool requiresRadioAlign();
|
||||||
|
|
||||||
|
GSM::Time minLatency();
|
||||||
|
|
||||||
|
inline double getSampleRate()
|
||||||
|
{
|
||||||
|
return tx_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Receive and process asynchronous message
|
||||||
|
@return true if message received or false on timeout or error
|
||||||
|
*/
|
||||||
|
bool recv_async_msg();
|
||||||
|
|
||||||
|
enum err_code {
|
||||||
|
ERROR_TIMING = -1,
|
||||||
|
ERROR_TIMEOUT = -2,
|
||||||
|
ERROR_UNRECOVERABLE = -3,
|
||||||
|
ERROR_UNHANDLED = -4,
|
||||||
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
|
struct bladerf *dev;
|
||||||
|
void *usrp_dev;
|
||||||
|
|
||||||
|
enum TxWindowType tx_window;
|
||||||
|
enum blade_dev_type dev_type;
|
||||||
|
|
||||||
|
double tx_rate, rx_rate;
|
||||||
|
|
||||||
|
double rx_gain_min, rx_gain_max;
|
||||||
|
|
||||||
|
std::vector<double> tx_gains, rx_gains;
|
||||||
|
std::vector<double> tx_freqs, rx_freqs;
|
||||||
|
size_t tx_spp, rx_spp;
|
||||||
|
|
||||||
|
bool started;
|
||||||
|
bool aligned;
|
||||||
|
|
||||||
|
size_t drop_cnt;
|
||||||
|
uint64_t prev_ts;
|
||||||
|
|
||||||
|
TIMESTAMP ts_initial, ts_offset;
|
||||||
|
std::vector<smpl_buf *> rx_buffers;
|
||||||
|
/* Sample buffers used to receive samples: */
|
||||||
|
std::vector<std::vector<short> > pkt_bufs;
|
||||||
|
/* Used to call UHD API: Buffer pointer of each elem in pkt_ptrs will
|
||||||
|
point to corresponding buffer of vector pkt_bufs. */
|
||||||
|
std::vector<short *> pkt_ptrs;
|
||||||
|
|
||||||
|
void init_gains();
|
||||||
|
void set_channels(bool swap);
|
||||||
|
void set_rates();
|
||||||
|
bool flush_recv(size_t num_pkts);
|
||||||
|
|
||||||
|
bool set_freq(double freq, size_t chan, bool tx);
|
||||||
|
|
||||||
|
Thread *async_event_thrd;
|
||||||
|
Mutex tune_lock;
|
||||||
|
};
|
||||||
12
Transceiver52M/device/common/Makefile.am
Normal file
12
Transceiver52M/device/common/Makefile.am
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
include $(top_srcdir)/Makefile.common
|
||||||
|
|
||||||
|
AM_CPPFLAGS = -Wall $(STD_DEFINES_AND_INCLUDES)
|
||||||
|
AM_CXXFLAGS = -lpthread $(LIBOSMOCORE_CFLAGS)
|
||||||
|
|
||||||
|
|
||||||
|
noinst_HEADERS = radioDevice.h smpl_buf.h bandmanager.h
|
||||||
|
|
||||||
|
noinst_LTLIBRARIES = libdevice_common.la
|
||||||
|
|
||||||
|
libdevice_common_la_SOURCES = \
|
||||||
|
smpl_buf.cpp
|
||||||
137
Transceiver52M/device/common/bandmanager.h
Normal file
137
Transceiver52M/device/common/bandmanager.h
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
#pragma once
|
||||||
|
/*
|
||||||
|
* (C) 2022 by sysmocom s.f.m.c. GmbH <info@sysmocom.de>
|
||||||
|
* All Rights Reserved
|
||||||
|
*
|
||||||
|
* Author: Eric Wild <ewild@sysmocom.de>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
#include "Logger.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <osmocom/gsm/gsm_utils.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename powermapt, typename devmapt>
|
||||||
|
class band_manager {
|
||||||
|
using powerkeyt = typename powermapt::key_type;
|
||||||
|
using powermappedt = typename powermapt::mapped_type;
|
||||||
|
using devkeyt = typename devmapt::key_type;
|
||||||
|
devkeyt m_dev_type;
|
||||||
|
const powermapt &m_power_map;
|
||||||
|
const devmapt &m_dev_map;
|
||||||
|
powerkeyt m_fallback;
|
||||||
|
enum gsm_band m_band;
|
||||||
|
powermappedt m_band_desc;
|
||||||
|
bool band_ass_curr_sess{}; /* true if "band" was set after last POWEROFF */
|
||||||
|
|
||||||
|
// looks up either first tuple element (->enum) or straight enum
|
||||||
|
template <typename T, typename std::enable_if<std::is_enum<T>::value>::type *dummy = nullptr>
|
||||||
|
auto key_helper(T &t) -> T
|
||||||
|
{
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
auto key_helper(T t) -> typename std::tuple_element<0, T>::type
|
||||||
|
{
|
||||||
|
return std::get<0>(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
void assign_band_desc(enum gsm_band req_band)
|
||||||
|
{
|
||||||
|
auto key = key_helper(m_dev_type);
|
||||||
|
auto fallback_key = key_helper(m_fallback);
|
||||||
|
auto it = m_power_map.find({ key, req_band });
|
||||||
|
if (it == m_power_map.end()) {
|
||||||
|
auto desc = m_dev_map.at(m_dev_type);
|
||||||
|
LOGC(DDEV, ERROR) << "No Tx Power measurements exist for device " << desc.desc_str
|
||||||
|
<< " on band " << gsm_band_name(req_band) << ", using fallback..";
|
||||||
|
it = m_power_map.find({ fallback_key, req_band });
|
||||||
|
}
|
||||||
|
OSMO_ASSERT(it != m_power_map.end());
|
||||||
|
m_band_desc = it->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_band(enum gsm_band req_band)
|
||||||
|
{
|
||||||
|
if (band_ass_curr_sess && req_band != m_band) {
|
||||||
|
LOGC(DDEV, ALERT) << "Requesting band " << gsm_band_name(req_band)
|
||||||
|
<< " different from previous band " << gsm_band_name(m_band);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (req_band != m_band) {
|
||||||
|
m_band = req_band;
|
||||||
|
assign_band_desc(m_band);
|
||||||
|
}
|
||||||
|
band_ass_curr_sess = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
band_manager(const devkeyt &dev_type, const powermapt &power_map, const devmapt &dev_map, powerkeyt fallback)
|
||||||
|
: m_dev_type(dev_type), m_power_map(power_map), m_dev_map(dev_map), m_fallback(fallback),
|
||||||
|
m_band((enum gsm_band)0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
band_manager(const powermapt &power_map, const devmapt &dev_map)
|
||||||
|
: m_dev_type(dev_map.begin()->first), m_power_map(power_map), m_dev_map(dev_map),
|
||||||
|
m_fallback(m_power_map.begin()->first), m_band((enum gsm_band)0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
void band_reset()
|
||||||
|
{
|
||||||
|
band_ass_curr_sess = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_band_dev(devkeyt dev_type) {
|
||||||
|
m_dev_type = dev_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void get_dev_band_desc(powermappedt &desc)
|
||||||
|
{
|
||||||
|
if (m_band == 0) {
|
||||||
|
LOGC(DDEV, ERROR)
|
||||||
|
<< "Power parameters requested before Tx Frequency was set! Providing band 900 by default...";
|
||||||
|
assign_band_desc(GSM_BAND_900);
|
||||||
|
}
|
||||||
|
desc = m_band_desc;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool update_band_from_freq(double wFreq, int chan, bool is_tx)
|
||||||
|
{
|
||||||
|
enum gsm_band req_band;
|
||||||
|
auto dirstr = is_tx ? "Tx" : "Rx";
|
||||||
|
auto req_arfcn = gsm_freq102arfcn(wFreq / 1000 / 100, !is_tx);
|
||||||
|
if (req_arfcn == 0xffff) {
|
||||||
|
LOGCHAN(chan, DDEV, ALERT)
|
||||||
|
<< "Unknown ARFCN for " << dirstr << " Frequency " << wFreq / 1000 << " kHz";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (gsm_arfcn2band_rc(req_arfcn, &req_band) < 0) {
|
||||||
|
LOGCHAN(chan, DDEV, ALERT) << "Unknown GSM band for " << dirstr << " Frequency " << wFreq
|
||||||
|
<< " Hz (ARFCN " << req_arfcn << " )";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return set_band(req_band);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2008 Free Software Foundation, Inc.
|
* Copyright 2008 Free Software Foundation, Inc.
|
||||||
*
|
*
|
||||||
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribuion.
|
* This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribution.
|
||||||
*
|
*
|
||||||
* This use of this software may be subject to additional restrictions.
|
* This use of this software may be subject to additional restrictions.
|
||||||
* See the LEGAL file in the main directory for details.
|
* See the LEGAL file in the main directory for details.
|
||||||
@@ -18,6 +18,14 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include "GSMCommon.h"
|
||||||
|
#include "Logger.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "config_defs.h"
|
||||||
|
#include "osmo_signal.h"
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#endif
|
#endif
|
||||||
@@ -33,7 +41,7 @@ class RadioDevice {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
/* Available transport bus types */
|
/* Available transport bus types */
|
||||||
enum TxWindowType { TX_WINDOW_USRP1, TX_WINDOW_FIXED };
|
enum TxWindowType { TX_WINDOW_USRP1, TX_WINDOW_FIXED, TX_WINDOW_LMS1 };
|
||||||
|
|
||||||
/* Radio interface types */
|
/* Radio interface types */
|
||||||
enum InterfaceType {
|
enum InterfaceType {
|
||||||
@@ -43,22 +51,15 @@ class RadioDevice {
|
|||||||
MULTI_ARFCN,
|
MULTI_ARFCN,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ReferenceType {
|
static RadioDevice *make(InterfaceType type, const struct trx_cfg *cfg);
|
||||||
REF_INTERNAL,
|
|
||||||
REF_EXTERNAL,
|
|
||||||
REF_GPS,
|
|
||||||
};
|
|
||||||
|
|
||||||
static RadioDevice *make(size_t tx_sps, size_t rx_sps, InterfaceType type,
|
|
||||||
size_t chans = 1, double offset = 0.0);
|
|
||||||
|
|
||||||
/** Initialize the USRP */
|
/** Initialize the USRP */
|
||||||
virtual int open(const std::string &args, int ref, bool swap_channels)=0;
|
virtual int open() = 0;
|
||||||
|
|
||||||
virtual ~RadioDevice() { }
|
virtual ~RadioDevice() { }
|
||||||
|
|
||||||
/** Start the USRP */
|
/** Start the USRP */
|
||||||
virtual bool start(bool txOnly = false)=0;
|
virtual bool start()=0;
|
||||||
|
|
||||||
/** Stop the USRP */
|
/** Stop the USRP */
|
||||||
virtual bool stop()=0;
|
virtual bool stop()=0;
|
||||||
@@ -66,9 +67,6 @@ class RadioDevice {
|
|||||||
/** Get the Tx window type */
|
/** Get the Tx window type */
|
||||||
virtual enum TxWindowType getWindowType()=0;
|
virtual enum TxWindowType getWindowType()=0;
|
||||||
|
|
||||||
/** Enable thread priority */
|
|
||||||
virtual void setPriority(float prio = 0.5) = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Read samples from the radio.
|
Read samples from the radio.
|
||||||
@param buf preallocated buf to contain read result
|
@param buf preallocated buf to contain read result
|
||||||
@@ -76,24 +74,20 @@ class RadioDevice {
|
|||||||
@param overrun Set if read buffer has been overrun, e.g. data not being read fast enough
|
@param overrun Set if read buffer has been overrun, e.g. data not being read fast enough
|
||||||
@param timestamp The timestamp of the first samples to be read
|
@param timestamp The timestamp of the first samples to be read
|
||||||
@param underrun Set if radio does not have data to transmit, e.g. data not being sent fast enough
|
@param underrun Set if radio does not have data to transmit, e.g. data not being sent fast enough
|
||||||
@param RSSI The received signal strength of the read result
|
|
||||||
@return The number of samples actually read
|
@return The number of samples actually read
|
||||||
*/
|
*/
|
||||||
virtual int readSamples(std::vector<short *> &bufs, int len, bool *overrun,
|
virtual int readSamples(std::vector<short *> &bufs, int len, bool *overrun,
|
||||||
TIMESTAMP timestamp = 0xffffffff, bool *underrun = 0,
|
TIMESTAMP timestamp = 0xffffffff, bool *underrun = 0) = 0;
|
||||||
unsigned *RSSI = 0) = 0;
|
|
||||||
/**
|
/**
|
||||||
Write samples to the radio.
|
Write samples to the radio.
|
||||||
@param buf Contains the data to be written.
|
@param buf Contains the data to be written.
|
||||||
@param len number of samples to write.
|
@param len number of samples to write.
|
||||||
@param underrun Set if radio does not have data to transmit, e.g. data not being sent fast enough
|
@param underrun Set if radio does not have data to transmit, e.g. data not being sent fast enough
|
||||||
@param timestamp The timestamp of the first sample of the data buffer.
|
@param timestamp The timestamp of the first sample of the data buffer.
|
||||||
@param isControl Set if data is a control packet, e.g. a ping command
|
|
||||||
@return The number of samples actually written
|
@return The number of samples actually written
|
||||||
*/
|
*/
|
||||||
virtual void triggerGPIO(TIMESTAMP timestamp) = 0;
|
|
||||||
virtual int writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
|
virtual int writeSamples(std::vector<short *> &bufs, int len, bool *underrun,
|
||||||
TIMESTAMP timestamp, bool isControl = false) = 0;
|
TIMESTAMP timestamp) = 0;
|
||||||
|
|
||||||
/** Update the alignment between the read and write timestamps */
|
/** Update the alignment between the read and write timestamps */
|
||||||
virtual bool updateAlignment(TIMESTAMP timestamp)=0;
|
virtual bool updateAlignment(TIMESTAMP timestamp)=0;
|
||||||
@@ -128,21 +122,110 @@ class RadioDevice {
|
|||||||
/** return minimum Rx Gain **/
|
/** return minimum Rx Gain **/
|
||||||
virtual double minRxGain(void) = 0;
|
virtual double minRxGain(void) = 0;
|
||||||
|
|
||||||
/** sets the transmit chan gain, returns the gain setting **/
|
/** return base RSSI offset to apply for received samples **/
|
||||||
virtual double setTxGain(double dB, size_t chan = 0) = 0;
|
virtual double rssiOffset(size_t chan) = 0;
|
||||||
|
|
||||||
/** return maximum Tx Gain **/
|
/** returns the Nominal transmit output power of the transceiver in dBm, negative on error **/
|
||||||
virtual double maxTxGain(void) = 0;
|
virtual int getNominalTxPower(size_t chan = 0) = 0;
|
||||||
|
|
||||||
/** return minimum Tx Gain **/
|
/** sets the RX path to use, returns true if successful and false otherwise */
|
||||||
virtual double minTxGain(void) = 0;
|
virtual bool setRxAntenna(const std::string &ant, size_t chan = 0) = 0;
|
||||||
|
|
||||||
|
/** return the used RX path */
|
||||||
|
virtual std::string getRxAntenna(size_t chan = 0) = 0;
|
||||||
|
|
||||||
|
/** sets the RX path to use, returns true if successful and false otherwise */
|
||||||
|
virtual bool setTxAntenna(const std::string &ant, size_t chan = 0) = 0;
|
||||||
|
|
||||||
|
/** return the used RX path */
|
||||||
|
virtual std::string getTxAntenna(size_t chan = 0) = 0;
|
||||||
|
|
||||||
|
/** return whether user drives synchronization of Tx/Rx of USRP */
|
||||||
|
virtual bool requiresRadioAlign() = 0;
|
||||||
|
|
||||||
|
/** Minimum latency that the device can achieve */
|
||||||
|
virtual GSM::Time minLatency() = 0;
|
||||||
|
|
||||||
/** Return internal status values */
|
/** Return internal status values */
|
||||||
virtual double getTxFreq(size_t chan = 0) = 0;
|
virtual double getTxFreq(size_t chan = 0) = 0;
|
||||||
virtual double getRxFreq(size_t chan = 0) = 0;
|
virtual double getRxFreq(size_t chan = 0) = 0;
|
||||||
virtual double getSampleRate()=0;
|
virtual double getSampleRate()=0;
|
||||||
virtual double numberRead()=0;
|
|
||||||
virtual double numberWritten()=0;
|
virtual double setPowerAttenuation(int atten, size_t chan) = 0;
|
||||||
|
virtual double getPowerAttenuation(size_t chan=0) = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
size_t tx_sps, rx_sps;
|
||||||
|
InterfaceType iface;
|
||||||
|
size_t chans;
|
||||||
|
double lo_offset;
|
||||||
|
std::vector<std::string> tx_paths, rx_paths;
|
||||||
|
std::vector<struct device_counters> m_ctr;
|
||||||
|
const struct trx_cfg *cfg;
|
||||||
|
|
||||||
|
#define charp2str(a) ((a) ? std::string(a) : std::string(""))
|
||||||
|
|
||||||
|
RadioDevice(InterfaceType type, const struct trx_cfg *cfg)
|
||||||
|
: tx_sps(cfg->tx_sps), rx_sps(cfg->rx_sps), iface(type), chans(cfg->num_chans), lo_offset(cfg->offset),
|
||||||
|
m_ctr(chans), cfg(cfg)
|
||||||
|
{
|
||||||
|
/* Generate vector of rx/tx_path: */
|
||||||
|
for (unsigned int i = 0; i < cfg->num_chans; i++) {
|
||||||
|
rx_paths.push_back(charp2str(cfg->chans[i].rx_path));
|
||||||
|
tx_paths.push_back(charp2str(cfg->chans[i].tx_path));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iface == MULTI_ARFCN) {
|
||||||
|
LOGC(DDEV, INFO) << "Multi-ARFCN: " << chans << " logical chans -> 1 physical chans";
|
||||||
|
chans = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < chans; i++) {
|
||||||
|
memset(&m_ctr[i], 0, sizeof(m_ctr[i]));
|
||||||
|
m_ctr[i].chan = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool set_antennas() {
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
for (i = 0; i < tx_paths.size(); i++) {
|
||||||
|
if (tx_paths[i] == "")
|
||||||
|
continue;
|
||||||
|
if (iface == MULTI_ARFCN && i > 0) {
|
||||||
|
LOGCHAN(i, DDEV, NOTICE) << "Not setting Tx antenna "
|
||||||
|
<< tx_paths[i]
|
||||||
|
<< " for a logical channel";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGCHAN(i, DDEV, DEBUG) << "Configuring Tx antenna " << tx_paths[i];
|
||||||
|
if (!setTxAntenna(tx_paths[i], i)) {
|
||||||
|
LOGCHAN(i, DDEV, ALERT) << "Failed configuring Tx antenna " << tx_paths[i];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < rx_paths.size(); i++) {
|
||||||
|
if (rx_paths[i] == "")
|
||||||
|
continue;
|
||||||
|
if (iface == MULTI_ARFCN && i > 0) {
|
||||||
|
LOGCHAN(i, DDEV, NOTICE) << "Not setting Rx antenna "
|
||||||
|
<< rx_paths[i]
|
||||||
|
<< " for a logical channel";
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOGCHAN(i, DDEV, DEBUG) << "Configuring Rx antenna " << rx_paths[i];
|
||||||
|
if (!setRxAntenna(rx_paths[i], i)) {
|
||||||
|
LOGCHAN(i, DDEV, ALERT) << "Failed configuring Rx antenna " << rx_paths[i];
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LOG(INFO) << "Antennas configured successfully";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
181
Transceiver52M/device/common/smpl_buf.cpp
Normal file
181
Transceiver52M/device/common/smpl_buf.cpp
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
* Sample Buffer - Allows reading and writing of timed samples
|
||||||
|
*
|
||||||
|
* Copyright 2010,2011 Free Software Foundation, Inc.
|
||||||
|
* Copyright (C) 2015 Ettus Research LLC
|
||||||
|
* Copyright 2019 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||||
|
*
|
||||||
|
* Author: Tom Tsou <tom.tsou@ettus.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* See the COPYING file in the main directory for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "smpl_buf.h"
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
smpl_buf::smpl_buf(size_t len)
|
||||||
|
: buf_len(len)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
data = new uint32_t[len];
|
||||||
|
}
|
||||||
|
|
||||||
|
smpl_buf::~smpl_buf()
|
||||||
|
{
|
||||||
|
delete[] data;
|
||||||
|
}
|
||||||
|
|
||||||
|
void smpl_buf::reset()
|
||||||
|
{
|
||||||
|
time_start = 0;
|
||||||
|
time_end = 0;
|
||||||
|
data_start = 0;
|
||||||
|
data_end = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t smpl_buf::avail_smpls(TIMESTAMP timestamp) const
|
||||||
|
{
|
||||||
|
if (timestamp < time_start)
|
||||||
|
return ERROR_TIMESTAMP;
|
||||||
|
else if (timestamp >= time_end)
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return time_end - timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t smpl_buf::read(void *buf, size_t len, TIMESTAMP timestamp)
|
||||||
|
{
|
||||||
|
int type_sz = 2 * sizeof(short);
|
||||||
|
|
||||||
|
// Check for valid read
|
||||||
|
if (timestamp < time_start)
|
||||||
|
return ERROR_TIMESTAMP;
|
||||||
|
if (timestamp >= time_end)
|
||||||
|
return 0;
|
||||||
|
if (len >= buf_len)
|
||||||
|
return ERROR_READ;
|
||||||
|
|
||||||
|
// How many samples should be copied
|
||||||
|
size_t num_smpls = time_end - timestamp;
|
||||||
|
if (num_smpls > len)
|
||||||
|
num_smpls = len;
|
||||||
|
|
||||||
|
// Starting index
|
||||||
|
size_t read_start = (data_start + (timestamp - time_start)) % buf_len;
|
||||||
|
|
||||||
|
// Read it
|
||||||
|
if (read_start + num_smpls < buf_len) {
|
||||||
|
size_t numBytes = len * type_sz;
|
||||||
|
memcpy(buf, data + read_start, numBytes);
|
||||||
|
} else {
|
||||||
|
size_t first_cp = (buf_len - read_start) * type_sz;
|
||||||
|
size_t second_cp = len * type_sz - first_cp;
|
||||||
|
|
||||||
|
memcpy(buf, data + read_start, first_cp);
|
||||||
|
memcpy((char*) buf + first_cp, data, second_cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
data_start = (read_start + len) % buf_len;
|
||||||
|
time_start = timestamp + len;
|
||||||
|
|
||||||
|
if (time_start > time_end)
|
||||||
|
return ERROR_READ;
|
||||||
|
else
|
||||||
|
return num_smpls;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t smpl_buf::write(void *buf, size_t len, TIMESTAMP timestamp)
|
||||||
|
{
|
||||||
|
int type_sz = 2 * sizeof(short);
|
||||||
|
|
||||||
|
// Check for valid write
|
||||||
|
if ((len == 0) || (len >= buf_len))
|
||||||
|
return ERROR_WRITE;
|
||||||
|
if ((timestamp + len) <= time_end)
|
||||||
|
return ERROR_TIMESTAMP;
|
||||||
|
|
||||||
|
if (timestamp < time_end) {
|
||||||
|
LOGC(DDEV, ERR) << "Overwriting old buffer data: timestamp="
|
||||||
|
<< timestamp << " time_end=" << time_end;
|
||||||
|
// Do not return error here, because it's a rounding error and is not fatal
|
||||||
|
}
|
||||||
|
if (timestamp > time_end && time_end != 0) {
|
||||||
|
LOGC(DDEV, ERR) << "Skipping buffer data: timestamp="
|
||||||
|
<< timestamp << " time_end=" << time_end;
|
||||||
|
// Do not return error here, because it's a rounding error and is not fatal
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starting index
|
||||||
|
size_t write_start = (data_start + (timestamp - time_start)) % buf_len;
|
||||||
|
|
||||||
|
// Write it
|
||||||
|
if ((write_start + len) < buf_len) {
|
||||||
|
size_t numBytes = len * type_sz;
|
||||||
|
memcpy(data + write_start, buf, numBytes);
|
||||||
|
} else {
|
||||||
|
size_t first_cp = (buf_len - write_start) * type_sz;
|
||||||
|
size_t second_cp = len * type_sz - first_cp;
|
||||||
|
|
||||||
|
memcpy(data + write_start, buf, first_cp);
|
||||||
|
memcpy(data, (char*) buf + first_cp, second_cp);
|
||||||
|
}
|
||||||
|
|
||||||
|
data_end = (write_start + len) % buf_len;
|
||||||
|
time_end = timestamp + len;
|
||||||
|
|
||||||
|
if (!data_start)
|
||||||
|
data_start = write_start;
|
||||||
|
|
||||||
|
if (((write_start + len) > buf_len) && (data_end > data_start))
|
||||||
|
return ERROR_OVERFLOW;
|
||||||
|
else if (time_end <= time_start)
|
||||||
|
return ERROR_WRITE;
|
||||||
|
else
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string smpl_buf::str_status(TIMESTAMP timestamp) const
|
||||||
|
{
|
||||||
|
std::ostringstream ost("Sample buffer: ");
|
||||||
|
|
||||||
|
ost << "timestamp = " << timestamp;
|
||||||
|
ost << ", length = " << buf_len;
|
||||||
|
ost << ", time_start = " << time_start;
|
||||||
|
ost << ", time_end = " << time_end;
|
||||||
|
ost << ", data_start = " << data_start;
|
||||||
|
ost << ", data_end = " << data_end;
|
||||||
|
|
||||||
|
return ost.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string smpl_buf::str_code(int code)
|
||||||
|
{
|
||||||
|
switch (code) {
|
||||||
|
case ERROR_TIMESTAMP:
|
||||||
|
return "Sample buffer: Requested timestamp is not valid";
|
||||||
|
case ERROR_READ:
|
||||||
|
return "Sample buffer: Read error";
|
||||||
|
case ERROR_WRITE:
|
||||||
|
return "Sample buffer: Write error";
|
||||||
|
case ERROR_OVERFLOW:
|
||||||
|
return "Sample buffer: Overrun";
|
||||||
|
default:
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "Sample buffer: Unknown error " << code;
|
||||||
|
return ss.str();
|
||||||
|
}
|
||||||
|
}
|
||||||
93
Transceiver52M/device/common/smpl_buf.h
Normal file
93
Transceiver52M/device/common/smpl_buf.h
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/*
|
||||||
|
* Sample Buffer - Allows reading and writing of timed samples
|
||||||
|
*
|
||||||
|
* Copyright 2010,2011 Free Software Foundation, Inc.
|
||||||
|
* Copyright (C) 2015 Ettus Research LLC
|
||||||
|
* Copyright 2019 sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
|
||||||
|
*
|
||||||
|
* Author: Tom Tsou <tom.tsou@ettus.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: AGPL-3.0+
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
* See the COPYING file in the main directory for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "radioDevice.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
Sample Buffer - Allows reading and writing of timed samples using osmo-trx
|
||||||
|
timestamps. Time conversions are handled
|
||||||
|
internally or accessible through the static convert calls.
|
||||||
|
*/
|
||||||
|
class smpl_buf {
|
||||||
|
public:
|
||||||
|
/** Sample buffer constructor
|
||||||
|
@param len number of 32-bit samples the buffer should hold
|
||||||
|
@param timestamp
|
||||||
|
*/
|
||||||
|
smpl_buf(size_t len);
|
||||||
|
~smpl_buf();
|
||||||
|
|
||||||
|
/** Reset this buffer, keeps the size
|
||||||
|
*/
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
/** Query number of samples available for reading
|
||||||
|
@param timestamp time of first sample
|
||||||
|
@return number of available samples or error
|
||||||
|
*/
|
||||||
|
ssize_t avail_smpls(TIMESTAMP timestamp) const;
|
||||||
|
|
||||||
|
/** Read and write
|
||||||
|
@param buf pointer to buffer
|
||||||
|
@param len number of samples desired to read or write
|
||||||
|
@param timestamp time of first stample
|
||||||
|
@return number of actual samples read or written or error
|
||||||
|
*/
|
||||||
|
ssize_t read(void *buf, size_t len, TIMESTAMP timestamp);
|
||||||
|
ssize_t write(void *buf, size_t len, TIMESTAMP timestamp);
|
||||||
|
|
||||||
|
/** Buffer status string
|
||||||
|
@return a formatted string describing internal buffer state
|
||||||
|
*/
|
||||||
|
std::string str_status(TIMESTAMP timestamp) const;
|
||||||
|
|
||||||
|
/** Formatted error string
|
||||||
|
@param code an error code
|
||||||
|
@return a formatted error string
|
||||||
|
*/
|
||||||
|
static std::string str_code(int code);
|
||||||
|
|
||||||
|
enum err_code {
|
||||||
|
ERROR_TIMESTAMP = -1,
|
||||||
|
ERROR_READ = -2,
|
||||||
|
ERROR_WRITE = -3,
|
||||||
|
ERROR_OVERFLOW = -4
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t *data;
|
||||||
|
size_t buf_len;
|
||||||
|
|
||||||
|
TIMESTAMP time_start;
|
||||||
|
TIMESTAMP time_end;
|
||||||
|
|
||||||
|
size_t data_start;
|
||||||
|
size_t data_end;
|
||||||
|
};
|
||||||
1273
Transceiver52M/device/ipc/IPCDevice.cpp
Normal file
1273
Transceiver52M/device/ipc/IPCDevice.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user