mirror of
https://github.com/lwvmobile/dsd-fme.git
synced 2026-11-13 01:07:24 -05:00
Compare commits
997 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa7fd116a7 | ||
|
|
199913ce53 | ||
|
|
1ac2d84dc0 | ||
|
|
c55128fc21 | ||
|
|
a6cb8b6989 | ||
|
|
676c5f0f09 | ||
|
|
9acc014274 | ||
|
|
2237d16696 | ||
|
|
180fd1bfb0 | ||
|
|
77bcff0dcc | ||
|
|
b43e566f98 | ||
|
|
f4e0412368 | ||
|
|
18ec24f0e8 | ||
|
|
bf10289223 | ||
|
|
e3c3d15dce | ||
|
|
b726cc8faf | ||
|
|
133746d3a3 | ||
|
|
56adbfe6fd | ||
|
|
c2e5b919d6 | ||
|
|
b675a8fbcd | ||
|
|
d5d84d598e | ||
|
|
aac17ca47d | ||
|
|
ead9bb77ec | ||
|
|
91aac9b61a | ||
|
|
d0aa9e66ca | ||
|
|
b8f92e9661 | ||
|
|
78cb583a4d | ||
|
|
69f6710898 | ||
|
|
ca3c648e3a | ||
|
|
cc581637c5 | ||
|
|
5a05011992 | ||
|
|
daa200d655 | ||
|
|
34b0040b04 | ||
|
|
24c08dfbbd | ||
|
|
390c7939f9 | ||
|
|
fa6fe06068 | ||
|
|
7193bca136 | ||
|
|
67b7272b05 | ||
|
|
88c9959e8e | ||
|
|
e4dcad7873 | ||
|
|
bd1f6881ce | ||
|
|
4b7b5d5a29 | ||
|
|
42c5bd16cd | ||
|
|
501e7c762c | ||
|
|
a01a01b533 | ||
|
|
6d56db17f4 | ||
|
|
d0040fd2a1 | ||
|
|
e5dd5eed5d | ||
|
|
dda84e74bc | ||
|
|
19712bf401 | ||
|
|
76b6aa46bd | ||
|
|
20ca710523 | ||
|
|
f98bad18b9 | ||
|
|
0ecc9765dd | ||
|
|
5d26333676 | ||
|
|
2d2af754c5 | ||
|
|
3939a5b1cf | ||
|
|
fc99153c80 | ||
|
|
076c7d669b | ||
|
|
c8020c76ae | ||
|
|
696c9663dd | ||
|
|
92144ee482 | ||
|
|
bd0b3f2856 | ||
|
|
529148ee18 | ||
|
|
810aa04eb0 | ||
|
|
20abfd4b8e | ||
|
|
bb76449560 | ||
|
|
fc6b35c7f5 | ||
|
|
e6da485117 | ||
|
|
d6160f7b7a | ||
|
|
2aedef7e77 | ||
|
|
11fd605d6b | ||
|
|
7b87ecca87 | ||
|
|
ea996f6442 | ||
|
|
e0182068b2 | ||
|
|
cd01902023 | ||
|
|
5e386e90e0 | ||
|
|
e28121f5b3 | ||
|
|
7a25e5d998 | ||
|
|
c6488a4a26 | ||
|
|
f32d18a5a3 | ||
|
|
3297bd1e9e | ||
|
|
6f9ce1f7ad | ||
|
|
a21d0ac05e | ||
|
|
584ca9e17a | ||
|
|
fb1abfbd26 | ||
|
|
e6dd71f338 | ||
|
|
46bf41fe15 | ||
|
|
01b6eccf4c | ||
|
|
e1924db1ff | ||
|
|
76309399b0 | ||
|
|
9cbb4ec36b | ||
|
|
973af860cf | ||
|
|
bc90ade337 | ||
|
|
ab54b2f6f8 | ||
|
|
72626546c5 | ||
|
|
c08dcb064c | ||
|
|
7525735df1 | ||
|
|
f28559ae6b | ||
|
|
e8957aa90f | ||
|
|
4fdc302809 | ||
|
|
c32b2bd7aa | ||
|
|
a121f33be8 | ||
|
|
f65e65fb47 | ||
|
|
a4ddcd4220 | ||
|
|
481dd0adb5 | ||
|
|
001d28aaf8 | ||
|
|
86e0a3ad77 | ||
|
|
a6a300e7c5 | ||
|
|
55a1d5a9f3 | ||
|
|
81f9cd6ee6 | ||
|
|
459151b4bf | ||
|
|
fcad1789dc | ||
|
|
1c3204e5d7 | ||
|
|
84df9bbca7 | ||
|
|
d073e7cae8 | ||
|
|
3c2ce0bb18 | ||
|
|
9aee34a501 | ||
|
|
cc5248e958 | ||
|
|
d880d05ea5 | ||
|
|
d882962b9c | ||
|
|
241cc05f80 | ||
|
|
cdcdc106ef | ||
|
|
a6bb5ed28d | ||
|
|
e1348b838b | ||
|
|
677ad50f79 | ||
|
|
6903d230fa | ||
|
|
b2cc2d4c11 | ||
|
|
763d28981c | ||
|
|
f274f74f44 | ||
|
|
9dfbcc886f | ||
|
|
5e0f64a7c2 | ||
|
|
18f24215e5 | ||
|
|
23e1c23789 | ||
|
|
a46523ee84 | ||
|
|
dc9aa270e5 | ||
|
|
ae528f844f | ||
|
|
d52c2b6426 | ||
|
|
29cd61fdcd | ||
|
|
daecac1612 | ||
|
|
abbf153785 | ||
|
|
1667019662 | ||
|
|
e2fbece993 | ||
|
|
d157dee956 | ||
|
|
9506bd5f77 | ||
|
|
2222d86e02 | ||
|
|
2161c3d762 | ||
|
|
eb5de342ba | ||
|
|
2ca9117783 | ||
|
|
b1809e9403 | ||
|
|
d1b11bc53c | ||
|
|
c61d2dd35d | ||
|
|
d8958662d9 | ||
|
|
801cdead80 | ||
|
|
5098cdb445 | ||
|
|
f229f0d648 | ||
|
|
cbaed9337b | ||
|
|
66ff2551e9 | ||
|
|
0a7e86a8fa | ||
|
|
e3c96f2d5d | ||
|
|
24741ed420 | ||
|
|
1f6f8f194b | ||
|
|
102966482b | ||
|
|
eb7929e758 | ||
|
|
8bbfdf2671 | ||
|
|
958400eaf6 | ||
|
|
20e862a6a0 | ||
|
|
8cbb30b036 | ||
|
|
9696042156 | ||
|
|
56b27dd055 | ||
|
|
a388e9ad85 | ||
|
|
2e93cca73a | ||
|
|
6a694444c5 | ||
|
|
8227b49b59 | ||
|
|
dd483c3300 | ||
|
|
f217f17c52 | ||
|
|
be3f69a2d0 | ||
|
|
bf96b96fdf | ||
|
|
c7537cca96 | ||
|
|
14a87465ce | ||
|
|
8c8df5b1b4 | ||
|
|
a56c736c06 | ||
|
|
7ff3e3e79b | ||
|
|
c5713c52da | ||
|
|
5bea494193 | ||
|
|
e48b715f4f | ||
|
|
12ac9460b9 | ||
|
|
c8c72eadab | ||
|
|
cd476bb463 | ||
|
|
53617bd366 | ||
|
|
99f2606d4d | ||
|
|
2aebdf79f3 | ||
|
|
c840544d25 | ||
|
|
927df66e9a | ||
|
|
7f4443c77f | ||
|
|
1600e6c0d4 | ||
|
|
0c86ba29fc | ||
|
|
b2f6b158e3 | ||
|
|
6ab2f69111 | ||
|
|
0097942732 | ||
|
|
3686e7fdd2 | ||
|
|
0e8f3362b9 | ||
|
|
078142bd3f | ||
|
|
304817b68e | ||
|
|
e48c05a0ab | ||
|
|
4cdcefb980 | ||
|
|
dcc818e9c3 | ||
|
|
0037064958 | ||
|
|
c0ccbf73d0 | ||
|
|
500d0387fd | ||
|
|
0f077832cf | ||
|
|
449468f566 | ||
|
|
fd2444f2cd | ||
|
|
d6968dffdd | ||
|
|
b50119e0bc | ||
|
|
58e90298eb | ||
|
|
224dc1e68c | ||
|
|
e9262f18db | ||
|
|
14b4af8b33 | ||
|
|
af271f62f3 | ||
|
|
6f9fba9fbf | ||
|
|
afa329b5e4 | ||
|
|
d8395fff59 | ||
|
|
81abd65da1 | ||
|
|
a48c197ecc | ||
|
|
85d53896de | ||
|
|
8b844aa6e3 | ||
|
|
578117d82a | ||
|
|
363c99ceca | ||
|
|
a93177eb61 | ||
|
|
d6181e2dcd | ||
|
|
f9b74cf7e2 | ||
|
|
d4740550e4 | ||
|
|
d91c44f6f3 | ||
|
|
e59b46448a | ||
|
|
d826391d16 | ||
|
|
5406960f26 | ||
|
|
8f1d1e4934 | ||
|
|
54b6fd67e7 | ||
|
|
1568ee6176 | ||
|
|
6978ac9cd3 | ||
|
|
1961eb832a | ||
|
|
c38423c251 | ||
|
|
ecd3ec1c61 | ||
|
|
66e8bcd86a | ||
|
|
23b1036c6b | ||
|
|
0d4ab17d0a | ||
|
|
b38a692fc5 | ||
|
|
2ff96a6b91 | ||
|
|
9089d6568a | ||
|
|
73c43b030e | ||
|
|
42fa737844 | ||
|
|
e4f61115c6 | ||
|
|
3bb9994589 | ||
|
|
23f6c75257 | ||
|
|
3bac7ba99b | ||
|
|
56a5df86a0 | ||
|
|
50d707a8e3 | ||
|
|
aa49e5869b | ||
|
|
d982a2b91e | ||
|
|
a92736bb3a | ||
|
|
54386285cc | ||
|
|
676027a56f | ||
|
|
cdc0d9e012 | ||
|
|
32d4c0ed72 | ||
|
|
16959cac7a | ||
|
|
f2f20f8f94 | ||
|
|
1a8efd5835 | ||
|
|
5a01c7a4db | ||
|
|
1b18139e41 | ||
|
|
263b3bbeda | ||
|
|
cba01aaa59 | ||
|
|
d4599b05a0 | ||
|
|
200287316d | ||
|
|
1d05f3d851 | ||
|
|
8e8d987686 | ||
|
|
343512e9bf | ||
|
|
af612c058b | ||
|
|
d81e8be3cf | ||
|
|
fb93289538 | ||
|
|
92a2217e80 | ||
|
|
b6d41260e7 | ||
|
|
bb6b54990f | ||
|
|
016d27e22d | ||
|
|
17a336e27d | ||
|
|
c3f3573a99 | ||
|
|
81dab2f0b6 | ||
|
|
a80e534179 | ||
|
|
8310f87504 | ||
|
|
f27057c790 | ||
|
|
649d267fa5 | ||
|
|
d8a7e5d366 | ||
|
|
8ccc241743 | ||
|
|
af922d209d | ||
|
|
958d0debbb | ||
|
|
2016891bd5 | ||
|
|
412cb26c0f | ||
|
|
3fc983f273 | ||
|
|
b5d24f9c00 | ||
|
|
a432173cd6 | ||
|
|
5440161ff9 | ||
|
|
bb542c475c | ||
|
|
aef834e914 | ||
|
|
fd44120874 | ||
|
|
0e9b2b245d | ||
|
|
eacbd21c50 | ||
|
|
deca8e74a8 | ||
|
|
9eefbb26d8 | ||
|
|
b637462ee8 | ||
|
|
7fc513e09e | ||
|
|
802e1c96bd | ||
|
|
0bc75f6f78 | ||
|
|
32a3ba535b | ||
|
|
2e898d997b | ||
|
|
817b335349 | ||
|
|
e9d551f4cb | ||
|
|
33933e914e | ||
|
|
8e230a08b5 | ||
|
|
dfc4f6f304 | ||
|
|
5a3061f942 | ||
|
|
b40281fda3 | ||
|
|
966fbf8c6a | ||
|
|
ca65f1b209 | ||
|
|
a5d73f06d2 | ||
|
|
56b0e8440e | ||
|
|
b6a12b6ceb | ||
|
|
15a12acfd3 | ||
|
|
c534e0f1fe | ||
|
|
5e68580fa6 | ||
|
|
e6d83e7305 | ||
|
|
d56cf106b4 | ||
|
|
4279ccf292 | ||
|
|
846b202192 | ||
|
|
330ebe2bf3 | ||
|
|
79b4a5e720 | ||
|
|
8186b62a91 | ||
|
|
20f0c852aa | ||
|
|
9e4ae23c0b | ||
|
|
585f6f2fa5 | ||
|
|
a4fba3b19c | ||
|
|
a2180eb5d3 | ||
|
|
514161fefa | ||
|
|
bba059f35f | ||
|
|
5977f865e3 | ||
|
|
ade7c0477f | ||
|
|
a2fded8340 | ||
|
|
005e15c45f | ||
|
|
e9962a8923 | ||
|
|
c6611eae9c | ||
|
|
261193959c | ||
|
|
e7a71eabb6 | ||
|
|
afba84e584 | ||
|
|
96faff7711 | ||
|
|
94166b493c | ||
|
|
6a0b1b2dcf | ||
|
|
5c8e3d95a7 | ||
|
|
4c91588af6 | ||
|
|
35c05654a5 | ||
|
|
fbc9b5fab8 | ||
|
|
1126ab6578 | ||
|
|
0842613b24 | ||
|
|
bf4a4b574c | ||
|
|
380657679e | ||
|
|
0a214af29b | ||
|
|
b008122149 | ||
|
|
7b6feb9e4f | ||
|
|
e4861bf94c | ||
|
|
587a3f01a2 | ||
|
|
8d5c82356e | ||
|
|
df039ab1c1 | ||
|
|
f5e3c6eddd | ||
|
|
fc01712132 | ||
|
|
7ec0bf83b4 | ||
|
|
504476c5db | ||
|
|
f78dbd57bc | ||
|
|
d2b27fdf25 | ||
|
|
3aa20f82b9 | ||
|
|
402b2f0264 | ||
|
|
4dd2328e10 | ||
|
|
98bcdd203e | ||
|
|
741ed51d08 | ||
|
|
5d8e07228e | ||
|
|
4a43a48b2e | ||
|
|
0ef3b4ab4b | ||
|
|
00e0f00974 | ||
|
|
91181f9e93 | ||
|
|
5c42c50a40 | ||
|
|
36399386c5 | ||
|
|
8eee4cd699 | ||
|
|
1410e8bd81 | ||
|
|
915375fb1c | ||
|
|
52fff28dc4 | ||
|
|
bd035622b8 | ||
|
|
44163710f9 | ||
|
|
44b1ccdeae | ||
|
|
34113cb782 | ||
|
|
2a336a9275 | ||
|
|
5c08a9193c | ||
|
|
2cae7f9c18 | ||
|
|
e056c97d9d | ||
|
|
dc49e0d08b | ||
|
|
b639f6af28 | ||
|
|
6b45c4ba9b | ||
|
|
2062502a59 | ||
|
|
a490d9ead2 | ||
|
|
c73832ac2c | ||
|
|
fe1fa79f70 | ||
|
|
f2f29f2287 | ||
|
|
3181e58b19 | ||
|
|
6204aec2a5 | ||
|
|
267180ed0e | ||
|
|
8d9cbb3720 | ||
|
|
8af6d2e185 | ||
|
|
abeb92ff8a | ||
|
|
be47075611 | ||
|
|
1640b58ae4 | ||
|
|
7a34d531b1 | ||
|
|
0af814c72f | ||
|
|
1477190dea | ||
|
|
b0cd1881bb | ||
|
|
44ad75ec17 | ||
|
|
1ce487dc13 | ||
|
|
ed9a96fdc8 | ||
|
|
c677efda49 | ||
|
|
fea4f97b89 | ||
|
|
f2e3834e0a | ||
|
|
b8b62ef69a | ||
|
|
4a8a4a088a | ||
|
|
9308c5b251 | ||
|
|
cdfe9435d3 | ||
|
|
f6cd915f4d | ||
|
|
1dfd59801e | ||
|
|
c4513fab7a | ||
|
|
a3b8839897 | ||
|
|
9e009867ff | ||
|
|
e95e2218d9 | ||
|
|
a9742043b8 | ||
|
|
05eef039c9 | ||
|
|
818e952b7b | ||
|
|
38b962aacf | ||
|
|
0217202801 | ||
|
|
ef07b48540 | ||
|
|
db67a8b227 | ||
|
|
4e2c4577d5 | ||
|
|
e581c96560 | ||
|
|
f3505269d0 | ||
|
|
20ccdbbced | ||
|
|
fc2fb99502 | ||
|
|
143c560958 | ||
|
|
d122d7e935 | ||
|
|
d0f9bb4bad | ||
|
|
ac752029bd | ||
|
|
5b994f5129 | ||
|
|
ec7d7c24a5 | ||
|
|
1d49481f2d | ||
|
|
7ca8cb421c | ||
|
|
4eb44b3c67 | ||
|
|
e16e4b61fc | ||
|
|
fbd04fa869 | ||
|
|
7f9b852f36 | ||
|
|
f5a7ab2b77 | ||
|
|
ffe6098fb8 | ||
|
|
157ca8c043 | ||
|
|
b722e43a3a | ||
|
|
2ba9953d33 | ||
|
|
bb2199ee84 | ||
|
|
4efec4e4ef | ||
|
|
12cf9aa80f | ||
|
|
e5a42dbb11 | ||
|
|
67eaeadc03 | ||
|
|
acb5c16c30 | ||
|
|
d16e775e46 | ||
|
|
11d4c8c49c | ||
|
|
1477880720 | ||
|
|
9290098081 | ||
|
|
eeb6924369 | ||
|
|
c02d7c0ba0 | ||
|
|
324191d79f | ||
|
|
e613b85829 | ||
|
|
49f81da4df | ||
|
|
826c99d563 | ||
|
|
2441664b19 | ||
|
|
5c733c0660 | ||
|
|
73824084ad | ||
|
|
209d4e039e | ||
|
|
fa4e84bc77 | ||
|
|
4946897914 | ||
|
|
57e3f518dd | ||
|
|
08a548339c | ||
|
|
36c337ede8 | ||
|
|
f6bb325dac | ||
|
|
626869992e | ||
|
|
5422b337bb | ||
|
|
b6f270be05 | ||
|
|
3ea813ebbc | ||
|
|
53980c98ed | ||
|
|
536372d877 | ||
|
|
896f3a8533 | ||
|
|
68bbea64d5 | ||
|
|
711a4cb871 | ||
|
|
8fd1d8fe35 | ||
|
|
23c396cbe8 | ||
|
|
e91c21fadb | ||
|
|
15a8f80344 | ||
|
|
5130899a67 | ||
|
|
f5ac9ff0b2 | ||
|
|
14dd045312 | ||
|
|
fbb00f78fe | ||
|
|
a5d23d9e12 | ||
|
|
a2b3da5b5a | ||
|
|
a9417afd67 | ||
|
|
438f89bf4c | ||
|
|
2f2eecddfc | ||
|
|
2fceee5a2f | ||
|
|
62c70cbf92 | ||
|
|
b97014ff0b | ||
|
|
68edb9463c | ||
|
|
178f88a28f | ||
|
|
f7d103c6a2 | ||
|
|
10d10063f0 | ||
|
|
dba3b79266 | ||
|
|
0441b8fdbd | ||
|
|
ea399e50a8 | ||
|
|
66f710e877 | ||
|
|
0f227e40c3 | ||
|
|
136ed75342 | ||
|
|
61cefa6a87 | ||
|
|
cc7504c280 | ||
|
|
07139b3d7d | ||
|
|
638f212525 | ||
|
|
9f624e0b62 | ||
|
|
eefe1bac5e | ||
|
|
532c1cc3b6 | ||
|
|
b1c40ed6e7 | ||
|
|
94dbd1512d | ||
|
|
c73d45d553 | ||
|
|
d1efa05164 | ||
|
|
7af5ffe9fa | ||
|
|
8141ea2e78 | ||
|
|
ec4ace1514 | ||
|
|
eb5cbaad93 | ||
|
|
f5d0575978 | ||
|
|
a0d9e349c2 | ||
|
|
7ca65cf687 | ||
|
|
b4a0e2e9f3 | ||
|
|
73f0d5df44 | ||
|
|
b003d0a210 | ||
|
|
83f390ba88 | ||
|
|
c8aafb1be0 | ||
|
|
3086b7852e | ||
|
|
8f6796d6f6 | ||
|
|
e9b1d76a98 | ||
|
|
afba623b20 | ||
|
|
9b92855b4e | ||
|
|
4138f92917 | ||
|
|
0bb9dd760c | ||
|
|
8b4f91ed8b | ||
|
|
a8fd2c7834 | ||
|
|
8670b99d69 | ||
|
|
6bd37821a9 | ||
|
|
215594a2a8 | ||
|
|
3f31d4ffe0 | ||
|
|
4a83c1beae | ||
|
|
67a78d8be0 | ||
|
|
14ba90a33f | ||
|
|
66fd3fd7bf | ||
|
|
d1ffcda819 | ||
|
|
f81575335e | ||
|
|
163db6b872 | ||
|
|
e6927d8115 | ||
|
|
3a19bf5583 | ||
|
|
181a6a5695 | ||
|
|
0d2244fac0 | ||
|
|
bd7d43de79 | ||
|
|
c37400bf81 | ||
|
|
bab139e2e4 | ||
|
|
6714761d8e | ||
|
|
467992ceff | ||
|
|
cb84f7469e | ||
|
|
ad4013d7d2 | ||
|
|
5b0e40e758 | ||
|
|
05a9268aef | ||
|
|
f3d2dbb4dd | ||
|
|
370d6be28e | ||
|
|
3224f0af37 | ||
|
|
5a73bcac8b | ||
|
|
af76c8de0d | ||
|
|
a3ecbe7414 | ||
|
|
4e04056f4b | ||
|
|
d8cf47b225 | ||
|
|
57d4c7afbe | ||
|
|
cb5c160fbf | ||
|
|
5390a52313 | ||
|
|
1d78e000da | ||
|
|
90700e7d28 | ||
|
|
0e9c2fc3dc | ||
|
|
4d24e93905 | ||
|
|
1505103c18 | ||
|
|
861ca3cb54 | ||
|
|
c228207588 | ||
|
|
09f92579ee | ||
|
|
a277707a4d | ||
|
|
41a236d244 | ||
|
|
837bfac5f5 | ||
|
|
2f05bfacfa | ||
|
|
f61c59ccc0 | ||
|
|
a682d9e882 | ||
|
|
88b3145cfd | ||
|
|
7199848f16 | ||
|
|
b7bb59dbba | ||
|
|
eb9152fb4e | ||
|
|
2ec4250e5b | ||
|
|
092da7b6d0 | ||
|
|
df6d7a6609 | ||
|
|
7f34ff9340 | ||
|
|
12e4b4cd6f | ||
|
|
6189ec95fa | ||
|
|
0f6140a30a | ||
|
|
5cb14c356b | ||
|
|
44cdfd912d | ||
|
|
ec4c4637df | ||
|
|
e5a7f8c41a | ||
|
|
03fb413750 | ||
|
|
f22d61df62 | ||
|
|
d20de53f91 | ||
|
|
3ba7a96bbd | ||
|
|
3e36e5e78d | ||
|
|
83edd7ff2b | ||
|
|
416edcbd59 | ||
|
|
65ce60f6b5 | ||
|
|
e461335b2e | ||
|
|
b9223e5207 | ||
|
|
805fdd7583 | ||
|
|
2b847c2270 | ||
|
|
6043b14c13 | ||
|
|
11b353089b | ||
|
|
b39d5d8401 | ||
|
|
5d44425b10 | ||
|
|
f45f4fe413 | ||
|
|
10ed2eac5a | ||
|
|
222cd706bf | ||
|
|
18714523c7 | ||
|
|
6c89c6260b | ||
|
|
48006c28c0 | ||
|
|
634eba522f | ||
|
|
81588b3201 | ||
|
|
1ca0f8a7d5 | ||
|
|
7133ad9dae | ||
|
|
caf21d2f0c | ||
|
|
2b0a85f99f | ||
|
|
3a3f717236 | ||
|
|
b4c7c60427 | ||
|
|
0f2dfe4dca | ||
|
|
f0cc508bf9 | ||
|
|
5b46fb8ab3 | ||
|
|
1a87f81f08 | ||
|
|
af6a5b39de | ||
|
|
2c839f7fd2 | ||
|
|
af0c0a4418 | ||
|
|
c495c90ef9 | ||
|
|
f8be80318b | ||
|
|
dbea859331 | ||
|
|
2463fe22f7 | ||
|
|
dc0c78e14d | ||
|
|
a2ac82c470 | ||
|
|
c402dfff96 | ||
|
|
3f586d9c98 | ||
|
|
4ab74a6bf0 | ||
|
|
d89507ebde | ||
|
|
806fe955cb | ||
|
|
c82e028032 | ||
|
|
357f59b290 | ||
|
|
cbd3d98151 | ||
|
|
5a39fe65db | ||
|
|
37c61aa5cb | ||
|
|
74d08ffaa6 | ||
|
|
171f372a4a | ||
|
|
3924c70386 | ||
|
|
656d7b2add | ||
|
|
66ec027bd2 | ||
|
|
6ad98fbf69 | ||
|
|
9b4e790095 | ||
|
|
e69451b0d7 | ||
|
|
1d30d5ec32 | ||
|
|
710e76d0ab | ||
|
|
994e728bfb | ||
|
|
2fd250b357 | ||
|
|
ed68f41f0e | ||
|
|
16e84ae104 | ||
|
|
4f1ecda2ad | ||
|
|
685c8aebe4 | ||
|
|
6de3e6c9f3 | ||
|
|
a848f9c0fe | ||
|
|
7d6c3dc67c | ||
|
|
2263ddae63 | ||
|
|
f8b9d47c6d | ||
|
|
064cc21b2b | ||
|
|
56da871ce2 | ||
|
|
ddc2a52a33 | ||
|
|
ec9c220ad7 | ||
|
|
02a27111d3 | ||
|
|
4c3a3e0959 | ||
|
|
ea40e3e3b7 | ||
|
|
ab873d3821 | ||
|
|
3cd1eefad8 | ||
|
|
8b48328431 | ||
|
|
2c842f5115 | ||
|
|
4ad5a8f9dd | ||
|
|
33cbad7618 | ||
|
|
504ee431b5 | ||
|
|
53fca195ba | ||
|
|
12dbd90509 | ||
|
|
2339cee016 | ||
|
|
4c44a47c61 | ||
|
|
11d4b2b330 | ||
|
|
cb57478fcc | ||
|
|
672e5cbd44 | ||
|
|
c1eb511855 | ||
|
|
2ccc27c03b | ||
|
|
43c1c9823b | ||
|
|
a3530c58a0 | ||
|
|
48ddba2ab8 | ||
|
|
9b554dfd93 | ||
|
|
edf465d03c | ||
|
|
e7a477dc88 | ||
|
|
7c461844ad | ||
|
|
ab29dd8e6a | ||
|
|
800fc3101e | ||
|
|
13ec6855f8 | ||
|
|
6a649376fc | ||
|
|
1ee3dba499 | ||
|
|
94487fd1c0 | ||
|
|
4af78289b2 | ||
|
|
5ee669aa18 | ||
|
|
6afb0d718f | ||
|
|
ea1f0bdf2f | ||
|
|
184b8b6a39 | ||
|
|
0fc9380b00 | ||
|
|
9f330e7902 | ||
|
|
d756ab6574 | ||
|
|
beb96f73db | ||
|
|
f053e53e76 | ||
|
|
c994f00e5d | ||
|
|
5834914e91 | ||
|
|
2b71652b23 | ||
|
|
d44c050ca4 | ||
|
|
1e9ea14a51 | ||
|
|
f6fdbfa922 | ||
|
|
7a341fa1c9 | ||
|
|
786f306eac | ||
|
|
b61b77e773 | ||
|
|
bba8579192 | ||
|
|
aca0adc4c5 | ||
|
|
b996d95b1c | ||
|
|
71be900630 | ||
|
|
5530d2ac9c | ||
|
|
a64c4187e5 | ||
|
|
568a8521c0 | ||
|
|
ab186da2f3 | ||
|
|
11d72c39d3 | ||
|
|
8669f6c309 | ||
|
|
fdaeae1307 | ||
|
|
010ff8cb60 | ||
|
|
12c7379d2a | ||
|
|
ae462d74a5 | ||
|
|
aa2600cdc2 | ||
|
|
69034b7c2f | ||
|
|
49ea9f7f52 | ||
|
|
670e4e7bec | ||
|
|
5b4d624bb2 | ||
|
|
1a4440f1ab | ||
|
|
c917c61b85 | ||
|
|
a239cd94fe | ||
|
|
a6c83a7fbb | ||
|
|
c7e52ab4fe | ||
|
|
df14508778 | ||
|
|
178b76f092 | ||
|
|
36fbbfd4d7 | ||
|
|
d1903b1574 | ||
|
|
fea03a0242 | ||
|
|
2ed2dc36aa | ||
|
|
2223183805 | ||
|
|
25affc5b54 | ||
|
|
ad13d06acc | ||
|
|
291f9ed963 | ||
|
|
455a7a9329 | ||
|
|
7e9eadaea5 | ||
|
|
387f2253b1 | ||
|
|
af401a7e5b | ||
|
|
4404c1afed | ||
|
|
417a48cc71 | ||
|
|
9acff308b9 | ||
|
|
48c9ae4b28 | ||
|
|
c3c4956ebb | ||
|
|
9751eb165f | ||
|
|
409321eb43 | ||
|
|
6f2682d667 | ||
|
|
46196cf283 | ||
|
|
80526be3ed | ||
|
|
d26d45eb7e | ||
|
|
36f522922d | ||
|
|
d70cab2499 | ||
|
|
6583fbe8f7 | ||
|
|
b3383cd543 | ||
|
|
9596301aee | ||
|
|
fbbd4285f5 | ||
|
|
97bc736f86 | ||
|
|
460b8999c3 | ||
|
|
88d7a59afe | ||
|
|
6be364c6ce | ||
|
|
3d83c0b06c | ||
|
|
3b9185fc40 | ||
|
|
5897131f05 | ||
|
|
c7a83c8c51 | ||
|
|
0eda6f5cf1 | ||
|
|
718d049927 | ||
|
|
e0c2e740d2 | ||
|
|
aab0208605 | ||
|
|
d037d2e0ad | ||
|
|
dd8e48789f | ||
|
|
d37ccf2883 | ||
|
|
6fb16cbd95 | ||
|
|
7a3e1a67da | ||
|
|
0f5c019d44 | ||
|
|
9092259ce1 | ||
|
|
079ed7e8cc | ||
|
|
3bb8a5608f | ||
|
|
142fb0c60e | ||
|
|
d088d09328 | ||
|
|
baca1be1b3 | ||
|
|
47c43f9c9c | ||
|
|
b1dcbeb459 | ||
|
|
ceb98222b6 | ||
|
|
34338ce2b1 | ||
|
|
3ef8c846c6 | ||
|
|
325bff80d0 | ||
|
|
fcf680a138 | ||
|
|
05b9e29724 | ||
|
|
fcfe06e1b2 | ||
|
|
7e4a537035 | ||
|
|
62bf2d91ca | ||
|
|
003b956d2c | ||
|
|
c408a57198 | ||
|
|
9f0e0adee8 | ||
|
|
b23705b7b6 | ||
|
|
eaec87ac44 | ||
|
|
4f012390c0 | ||
|
|
d125d12132 | ||
|
|
617b5d8072 | ||
|
|
4b81636947 | ||
|
|
4c8f0f3c50 | ||
|
|
130afdc278 | ||
|
|
a4aab9a56d | ||
|
|
2b8ce4b248 | ||
|
|
be165c8c77 | ||
|
|
46fa8b5c60 | ||
|
|
628b9c30c2 | ||
|
|
13a453193a | ||
|
|
b58b2b578a | ||
|
|
b66cac75d2 | ||
|
|
6573521363 | ||
|
|
f5ed83289f | ||
|
|
2859ad3927 | ||
|
|
aaa8e5c3f1 | ||
|
|
f6673b6f59 | ||
|
|
f3dac806a8 | ||
|
|
92db25f56d | ||
|
|
4e60c61eb0 | ||
|
|
fd9f9126d7 | ||
|
|
7e6b3adf9d | ||
|
|
e0bddd6699 | ||
|
|
d98040895d | ||
|
|
5a8b6f1d4a | ||
|
|
4ca81a5dc2 | ||
|
|
7222e71c08 | ||
|
|
cb9e6c632c | ||
|
|
005d356859 | ||
|
|
7a94be9292 | ||
|
|
9ae874449f | ||
|
|
1e95db0977 | ||
|
|
93ccc668d7 | ||
|
|
defa6455d6 | ||
|
|
7c5fef56e9 | ||
|
|
6ed5e0bcab | ||
|
|
31157b72ab | ||
|
|
0cb68d7c53 | ||
|
|
b67a3bb6de | ||
|
|
d0086a5f96 | ||
|
|
2b84518caf | ||
|
|
60593dcce9 | ||
|
|
fad831d1aa | ||
|
|
3c11d72652 | ||
|
|
97a17df9d1 | ||
|
|
2523383b14 | ||
|
|
a50f3b714f | ||
|
|
df3f58b05e | ||
|
|
2debc3e5f1 | ||
|
|
f383d165fd | ||
|
|
5324d53c47 | ||
|
|
f0f067510f | ||
|
|
2bdcc9cc65 | ||
|
|
0b0754c1d5 | ||
|
|
502607a608 | ||
|
|
290a2204ba | ||
|
|
f175834e45 | ||
|
|
98f9e36291 | ||
|
|
5f8aedb864 | ||
|
|
b674f277d9 | ||
|
|
386cf93eb1 | ||
|
|
7ee04e58c5 | ||
|
|
9eaaa323fe | ||
|
|
6605925162 | ||
|
|
6fbda52998 | ||
|
|
8e60a7b6a8 | ||
|
|
e18cbf730e | ||
|
|
8db618f83d | ||
|
|
60807e09ab | ||
|
|
c55f8b71fd | ||
|
|
cc1fb3b33c | ||
|
|
cfcbf6a8da | ||
|
|
dd5c11acb3 | ||
|
|
fd998e2bf7 | ||
|
|
6a9aa076b8 | ||
|
|
45eb53f245 | ||
|
|
74fa117850 | ||
|
|
5dd236ec96 | ||
|
|
55b190ef49 | ||
|
|
df3c0dcab4 | ||
|
|
d077cd8316 | ||
|
|
05caba143b | ||
|
|
f2767707ef | ||
|
|
4e338dede9 | ||
|
|
f207eba8f9 | ||
|
|
3e9dc91e81 | ||
|
|
c39b0e6e43 | ||
|
|
a9995c695a | ||
|
|
f062fe0ef3 | ||
|
|
5f30a6aad6 | ||
|
|
e0c574c470 | ||
|
|
68c471d639 | ||
|
|
1c05c6da6e | ||
|
|
8f61ac63a3 | ||
|
|
840dbac8b0 | ||
|
|
a0c7d16905 | ||
|
|
9655ab0bd7 | ||
|
|
9e6b3b7978 | ||
|
|
d8181ec79e | ||
|
|
f8cd8d715f | ||
|
|
20c55d073b | ||
|
|
1e854adb84 | ||
|
|
6ab62d006a | ||
|
|
9d0fe07931 | ||
|
|
b45e563e54 | ||
|
|
ad0c849dc4 | ||
|
|
3229737e6c | ||
|
|
596451eba0 | ||
|
|
c23ff4fe0c | ||
|
|
134f2e8e21 | ||
|
|
01a2b6959a | ||
|
|
7299b78c3b | ||
|
|
9b35ef5c83 | ||
|
|
75972cb024 | ||
|
|
461031d3f1 | ||
|
|
772eb7f810 | ||
|
|
3f4ff87078 | ||
|
|
1553973718 | ||
|
|
95c3d8fd27 | ||
|
|
d7b36f32c0 | ||
|
|
9b9cb78ddf | ||
|
|
e40e89ae81 | ||
|
|
2f6214fe72 | ||
|
|
271a7e459a | ||
|
|
e3dde6f7f9 | ||
|
|
16110bd251 | ||
|
|
945f93d678 | ||
|
|
2630e98128 | ||
|
|
855fdd64e8 | ||
|
|
158ae7c520 | ||
|
|
7bd0a10c65 | ||
|
|
e0376bc009 | ||
|
|
25765ef4d0 | ||
|
|
9965f8a36d | ||
|
|
4763717b59 | ||
|
|
8c8dea4142 | ||
|
|
ac816f9207 | ||
|
|
040ea148b0 | ||
|
|
27960ae4be | ||
|
|
5fb79e9baa | ||
|
|
de3e5e7f60 | ||
|
|
e3bafe96e9 | ||
|
|
f978a8759e | ||
|
|
260ec82ea1 | ||
|
|
e40c32d8ad | ||
|
|
5d147c9f04 | ||
|
|
3683f6c631 | ||
|
|
20271c6df5 | ||
|
|
fa73feded2 |
12
.gitignore
vendored
12
.gitignore
vendored
@@ -1,2 +1,10 @@
|
||||
*.o
|
||||
dsd
|
||||
*.[ao]
|
||||
*.so*
|
||||
*.dylib
|
||||
build
|
||||
*.sh
|
||||
*.csv
|
||||
examples
|
||||
*.bin
|
||||
*.ans
|
||||
*.patch
|
||||
|
||||
78
CHANGELOG
78
CHANGELOG
@@ -1,78 +0,0 @@
|
||||
1.4.1
|
||||
New features:
|
||||
Several new sync types for existing formats now recognized:
|
||||
Decodes voice from NXDN 4800 (6.25kHz) signals
|
||||
Decodes voice from NXDN 9600 (12.5kHz) repeater output
|
||||
Decodes voice from DMR/MotoTRBO simplex/repeater input
|
||||
Decodes voice from X2-TDMA simplex/repeater input
|
||||
|
||||
Fixed bugs:
|
||||
renamed "input:" to "inlvl:" to reduce confusion. This value
|
||||
indicates the audio input level, NOT the "decode success
|
||||
rate". Voice decode errors are indicated by the errorbars "=".
|
||||
|
||||
1.4
|
||||
New features:
|
||||
Decodes voice from NXDN 9600 (12.5 kHz) simplex/repeater input
|
||||
NXDN96 frames enabled by default
|
||||
Improved resistance to NXDN96 sync false positives
|
||||
|
||||
Fixed bugs:
|
||||
.wav file header updated after playing .imb/.amb data files
|
||||
.imb/.amb files now have correct tgid in filename
|
||||
|
||||
1.3.1 New features:
|
||||
Support for ProVoice EA sync
|
||||
CTRL-C is now caught so .wav files can be properly closed
|
||||
DSD now shows mbelib version as well as it's own version
|
||||
-R resume option now triggers on any TSDU so control channels can be left
|
||||
in conventional scanlists.
|
||||
Auto output gain now has 0.5 second hold time for faster error burst recovery
|
||||
(was 1.5 seconds)
|
||||
Audio output upsampling function simplified and improved
|
||||
|
||||
Fixed bugs:
|
||||
DSD_Author.pgp now has correct public key (was copy of mbelib_Author key)
|
||||
TGID and SRC are now cleared after TDULC or TDU.
|
||||
Voice error counter is now reset in noCarrier()
|
||||
TGID and SRC were not displaying for X2-TDMA frames
|
||||
Fixed buffer issue in resumeScan()
|
||||
Fixed error in .wav file headers preventing playback on some apps
|
||||
|
||||
1.3 New features:
|
||||
Decodes voice from ProVoice signals (requires -fp option)
|
||||
algid and kid are now shown in hex notation
|
||||
|
||||
Fixed bugs:
|
||||
auto output gain now has faster rise time
|
||||
MoTDMA is now correctly labeled X2-TDMA
|
||||
|
||||
1.2 New features:
|
||||
Decodes voice for DMR standard (including MOTOTRBO)
|
||||
Full metadata (src, talkgroup, lcinfo, mfid, lcformat, mi, algid, keyid) for X2-TDMA
|
||||
TDMA slot identification for X2-TDMA/DMR/MOTOTRBO
|
||||
Identifies non-voice frame types for X2-TDMA/DMR/MOTOTRBO
|
||||
Frame only (no voice yet) support for 9600 baud NXDN
|
||||
Auto leveling audio output gain (default) and -g option for fixed gain
|
||||
GFSK modulation optimizations and improved C4FM/GFSK/QPSK auto detect
|
||||
|
||||
Fixed bugs:
|
||||
nac was showing wrong ID
|
||||
P25 metadata (lcinfo, mfid, lfcormat, mi, keyid, algid, lsd) are now
|
||||
printed out in the correct bit order (MSB -> LSB), was reversed.
|
||||
fixed serveral bugs in dsd_upsample.c, with improved quality
|
||||
|
||||
1.1 New features:
|
||||
Scanner control options to allow scan resume during certain TDULC
|
||||
Improved upsampling function audio quality
|
||||
Greatly improved handling of X2-TDMA frames
|
||||
Much faster QPSK decision point tracking by default
|
||||
|
||||
Fixed bugs:
|
||||
playMbeFiles was not output to .wav file when -w was given
|
||||
Now correctly detects/handles Mot and P25 talkgroup formats
|
||||
PDU frames were not detected
|
||||
|
||||
1.0.3 Fixed buggy C4FM/QPSK auto detection and added -A option to adjust it.
|
||||
|
||||
1.0 Initial release
|
||||
119
CMakeLists.txt
Normal file
119
CMakeLists.txt
Normal file
@@ -0,0 +1,119 @@
|
||||
#Ubuntu 20.04 uses 3.16.3
|
||||
#Ubuntu 22.04 uses 3.22.1
|
||||
#Arch currently on 3.26.3
|
||||
#Cygwin currently using 3.23.2 (or newer)
|
||||
cmake_minimum_required(VERSION 3.10.2)
|
||||
project(dsd-fme)
|
||||
|
||||
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake/")
|
||||
#Set curses to ncurses, and wide true for ascii
|
||||
set(CURSES_NEED_NCURSES TRUE)
|
||||
set(CURSES_NEED_WIDE TRUE)
|
||||
|
||||
#use cmake option -DAERO=ON to enable Aero Builds (OSS support and specific tweaks)
|
||||
option(AERO
|
||||
"Build for Aero Environments (Cygwin)" OFF)
|
||||
if (AERO)
|
||||
add_definitions(-DAERO_BUILD)
|
||||
endif ()
|
||||
|
||||
#use cmake option -DCOLORS=OFF to disable color output
|
||||
option(COLORS
|
||||
"Build with Colors Enabled" ON)
|
||||
if (COLORS)
|
||||
add_definitions(-DPRETTY_COLORS)
|
||||
endif ()
|
||||
|
||||
#use cmake option -DPVC=ON to enable Provoice Conventional Frame Sync
|
||||
option(PVC
|
||||
"Build with Provoice Conventional Frame Sync Enabled" OFF)
|
||||
if (PVC)
|
||||
add_definitions(-DPVCONVENTIONAL)
|
||||
endif ()
|
||||
|
||||
|
||||
#use cmake option -DLZ=ON to enable LimaZulu Requested NXDN Tweaks
|
||||
option(LZ
|
||||
"Build with new LimaZulu Requested NXDN Tweaks Enabled" OFF)
|
||||
if (LZ)
|
||||
add_definitions(-DLIMAZULUTWEAKS)
|
||||
endif ()
|
||||
|
||||
#use cmake option -DSID=ON to enable P25p1 Soft ID decoding -- Experimental
|
||||
option(SID
|
||||
"Build with P25p1 LSD/Soft ID Enabled" OFF)
|
||||
if (SID)
|
||||
add_definitions(-DSOFTID)
|
||||
endif ()
|
||||
|
||||
|
||||
include(git_revision)
|
||||
git_describe(GIT_TAG)
|
||||
|
||||
find_package(LibSndFile REQUIRED)
|
||||
find_package(MBE REQUIRED)
|
||||
find_package(ITPP REQUIRED)
|
||||
find_package(RTLSDR)
|
||||
find_package(Curses REQUIRED)
|
||||
find_package(PulseAudio REQUIRED)
|
||||
find_package(CODEC2)
|
||||
|
||||
include_directories(SYSTEM ${LIBSNDFILE_INCLUDE_DIR} ${MBE_INCLUDE_DIR} ${ITPP_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIRS} ${CURSES_INCLUDE_DIR})
|
||||
set(LIBS ${MBE_LIBRARY} ${LIBSNDFILE_LIBRARY} ${ITPP_LIBRARY} ${PULSEAUDIO_SIMPLE_LIBRARY} ${CURSES_LIBRARY})
|
||||
|
||||
if(RTLSDR_FOUND)
|
||||
find_package(Threads)
|
||||
include_directories(SYSTEM ${RTLSDR_INCLUDE_DIRS})
|
||||
list(APPEND LIBS ${RTLSDR_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
|
||||
add_definitions(-DUSE_RTLSDR)
|
||||
endif(RTLSDR_FOUND)
|
||||
|
||||
if(CODEC2_FOUND)
|
||||
include_directories(SYSTEM ${CODEC2_INCLUDE_DIRS})
|
||||
list(APPEND LIBS ${CODEC2_LIBRARIES})
|
||||
add_definitions(-DUSE_CODEC2)
|
||||
endif(CODEC2_FOUND)
|
||||
|
||||
FILE(GLOB SRCS src/*.c src/*.cpp)
|
||||
FILE(GLOB HEADERS include/*.h include/*.hpp)
|
||||
|
||||
if(NOT RTLSDR_FOUND)
|
||||
list(REMOVE_ITEM SRCS ${CMAKE_CURRENT_SOURCE_DIR}/src/rtl_sdr_fm.cpp)
|
||||
endif(NOT RTLSDR_FOUND)
|
||||
|
||||
configure_file("src/git_ver.c.in" "${CMAKE_CURRENT_BINARY_DIR}/git_ver.c" @ONLY)
|
||||
list(APPEND SRCS "${CMAKE_CURRENT_BINARY_DIR}/git_ver.c")
|
||||
|
||||
include_directories("${PROJECT_SOURCE_DIR}/include")
|
||||
|
||||
ADD_EXECUTABLE(dsd-fme ${SRCS} ${HEADERS})
|
||||
TARGET_LINK_LIBRARIES(dsd-fme ${LIBS})
|
||||
|
||||
target_compile_options(dsd-fme PRIVATE -Wunused-but-set-variable -Wunused-variable -Wunused-parameter
|
||||
-Wempty-body -Wunused-label $<$<COMPILE_LANGUAGE:C>:-Wpointer-sign>)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
install(TARGETS dsd-fme DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
|
||||
# man page
|
||||
find_program(HELP2MAN_FOUND help2man)
|
||||
if (HELP2MAN_FOUND)
|
||||
add_custom_command(TARGET dsd-fme POST_BUILD
|
||||
COMMAND help2man
|
||||
ARGS -n "Digital Speech Decoder"
|
||||
--version-string=${GIT_TAG}
|
||||
-o ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme.1
|
||||
--no-info
|
||||
$<TARGET_FILE:dsd-fme>
|
||||
)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dsd-fme.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
|
||||
endif()
|
||||
|
||||
# uninstall target
|
||||
configure_file(
|
||||
"cmake/cmake_uninstall.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
||||
IMMEDIATE @ONLY)
|
||||
|
||||
add_custom_target(uninstall
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
19
COPYRIGHT
19
COPYRIGHT
@@ -1,3 +1,18 @@
|
||||
dstar_header.c/h, descramble.h, and fcs.h are under the following license:
|
||||
|
||||
dstar_header.c/h and fcs.h: Copyright (C) 2010 by Kristoff Bonne, ON1ARF
|
||||
descramble.h: Copyright (C) 2011 by Jonathan Naylor, G4KLX
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
All other code is under the following license:
|
||||
|
||||
Copyright (C) 2010 DSD Author
|
||||
GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
|
||||
@@ -12,3 +27,7 @@ INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
# Digital Speech Decoder - Florida Man Edition
|
||||
|
||||
This version of DSD is a flavor blend of [szechyjs](https://github.com/szechyjs/dsd "szechyjs") RTL branch and some of my own additions, along with portions of DMR and NXDN code from the [LouisErigHerve](https://github.com/LouisErigHerve/dsd "LouisErigHerve") branch. This code also borrows snippets, inspiration, and ideas from other open source works including [Boatbod OP25](https://github.com/boatbod/op25 "Boatbod OP25"), [DSDcc](https://github.com/f4exb/dsdcc "DSDcc"), [SDTRunk](https://github.com/DSheirer/sdrtrunk "SDRTrunk"), [MMDVMHost](https://github.com/g4klx/MMDVMHost "MMDVMHost"), [LFSR](https://github.com/mattames/LFSR "LFSR"), and [EZPWD-Reed-Solomon](https://github.com/pjkundert/ezpwd-reed-solomon "EZPWD"). This project wouldn't be possible without a few good people providing me plenty of sample audio files to run over and over again. Special thanks to jurek1111, KrisMar, noamlivne, racingfan360, iScottyBotty, LimaZulu and hrh17 for the many hours of wav samples submitted by them.
|
||||
|
||||
115
Makefile
115
Makefile
@@ -1,115 +0,0 @@
|
||||
# Copyright (C) 2010 DSD Author
|
||||
# GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
# PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
CC = gcc
|
||||
CFLAGS = -O2 -Wall
|
||||
INCLUDES = -I. -I/usr/local/include -I/usr/include
|
||||
LIBS = -L/usr/local/lib -lm -lmbe
|
||||
INSTALL=install
|
||||
AR=ar
|
||||
RANLIB=ranlib
|
||||
DEST_BASE=/usr/local
|
||||
DEST_INC=${DEST_BASE}/include
|
||||
DEST_LIB=${DEST_BASE}/lib
|
||||
DEST_BIN=${DEST_BASE}/bin
|
||||
OBJS = dsd_main.o dsd_symbol.o dsd_dibit.o dsd_frame_sync.o dsd_file.o dsd_audio.o dsd_serial.o dsd_frame.o dsd_mbe.o dsd_upsample.o p25p1_hdu.o p25p1_ldu1.o p25p1_ldu2.o p25p1_tdulc.o p25_lcw.o x2tdma_voice.o x2tdma_data.o dstar.o nxdn_voice.o nxdn_data.o dmr_voice.o dmr_data.o provoice.o
|
||||
|
||||
all: dsd
|
||||
|
||||
build: all
|
||||
|
||||
dsd_main.o: dsd_main.c dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_main.c -o dsd_main.o
|
||||
|
||||
dsd_symbol.o: dsd_symbol.c dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_symbol.c -o dsd_symbol.o
|
||||
|
||||
dsd_dibit.o: dsd_dibit.c dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_dibit.c -o dsd_dibit.o
|
||||
|
||||
dsd_frame_sync.o: dsd_frame_sync.c dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_frame_sync.c -o dsd_frame_sync.o
|
||||
|
||||
dsd_file.o: dsd_file.c dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_file.c -o dsd_file.o
|
||||
|
||||
dsd_audio.o: dsd_audio.c dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_audio.c -o dsd_audio.o
|
||||
|
||||
dsd_serial.o: dsd_serial.c dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_serial.c -o dsd_serial.o
|
||||
|
||||
dsd_frame.o: dsd_frame.c dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_frame.c -o dsd_frame.o
|
||||
|
||||
dsd_mbe.o: dsd_mbe.c dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_mbe.c -o dsd_mbe.o
|
||||
|
||||
dsd_upsample.o: dsd_upsample.c dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c dsd_upsample.c -o dsd_upsample.o
|
||||
|
||||
p25p1_hdu.o: p25p1_hdu.c dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c p25p1_hdu.c -o p25p1_hdu.o
|
||||
|
||||
p25p1_ldu1.o: p25p1_ldu1.c p25p1_const.h dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c p25p1_ldu1.c -o p25p1_ldu1.o
|
||||
|
||||
p25p1_ldu2.o: p25p1_ldu2.c p25p1_const.h dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c p25p1_ldu2.c -o p25p1_ldu2.o
|
||||
|
||||
p25p1_tdulc.o: p25p1_tdulc.c dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c p25p1_tdulc.c -o p25p1_tdulc.o
|
||||
|
||||
p25_lcw.o: p25_lcw.c dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c p25_lcw.c -o p25_lcw.o
|
||||
|
||||
x2tdma_voice.o: x2tdma_voice.c x2tdma_const.h dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c x2tdma_voice.c -o x2tdma_voice.o
|
||||
|
||||
x2tdma_data.o: x2tdma_data.c x2tdma_const.h dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c x2tdma_data.c -o x2tdma_data.o
|
||||
|
||||
dstar.o: dstar.c dstar_const.h dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c dstar.c -o dstar.o
|
||||
|
||||
nxdn48_voice.o: nxdn48_voice.c nxdn_const.h dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c nxdn48_voice.c -o nxdn48_voice.o
|
||||
|
||||
nxdn_voice.o: nxdn_voice.c nxdn_const.h dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c nxdn_voice.c -o nxdn_voice.o
|
||||
|
||||
nxdn_data.o: nxdn_data.c nxdn_const.h dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c nxdn_data.c -o nxdn_data.o
|
||||
|
||||
dmr_voice.o: dmr_voice.c dmr_const.h dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c dmr_voice.c -o dmr_voice.o
|
||||
|
||||
dmr_data.o: dmr_data.c dmr_const.h dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c dmr_data.c -o dmr_data.o
|
||||
|
||||
provoice.o: provoice.c provoice_const.h dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(INCLUDES) -c provoice.c -o provoice.o
|
||||
|
||||
dsd: $(OBJS) dsd.h config.h
|
||||
$(CC) $(CFLAGS) $(LIBS) -o dsd $(OBJS)
|
||||
|
||||
clean:
|
||||
rm -f *.o
|
||||
rm -f dsd
|
||||
|
||||
install: dsd
|
||||
$(INSTALL) dsd $(DEST_BIN)
|
||||
chgrp uucp $(DEST_BIN)/dsd
|
||||
chmod g+s $(DEST_BIN)/dsd
|
||||
521
README
521
README
@@ -1,521 +0,0 @@
|
||||
Digital Speech Decoder 1.4
|
||||
Copyright (C) 2010 DSD Author
|
||||
GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
DSD is able to decode several digital voice formats from discriminator
|
||||
tap audio and synthesize the decoded speech. Speech
|
||||
synthesis requires mbelib, which is a separate package. DSD 1.4.1
|
||||
requires mbelib 1.1 or later.
|
||||
|
||||
Supported formats in version 1.4.1:
|
||||
|
||||
P25 Phase 1 Widely deployed radio standard used in public safety
|
||||
and amateur radio.
|
||||
|
||||
Support includes decoding and synthesis of speech,
|
||||
display of all link control info, and the ability to save
|
||||
and replay .imb data files
|
||||
|
||||
ProVoice EDACS Digital voice format used by public safety and
|
||||
amateur radio.
|
||||
|
||||
Support includes decoding and synthesis of speech and
|
||||
the ability to save and replay .imb data files.
|
||||
Note: not enabled by default, use -fp to enable.
|
||||
|
||||
X2-TDMA Two slot TDMA system currently being deployed by several
|
||||
public safety organizations. Based on the DMR
|
||||
standard with extensions for P25 style signaling.
|
||||
|
||||
Support includes decoding and synthesis of speech,
|
||||
display of all link control info, and the ability to save
|
||||
and replay .amb data files
|
||||
|
||||
DMR/MOTOTRBO "Digital Mobile Radio" Eurpoean two slot TDMA standard.
|
||||
MOTOTRBO is a popular implementation of this standard.
|
||||
|
||||
Support includes decoding and synthesis of speech and
|
||||
the ability to save and replay .amb data files.
|
||||
|
||||
NXDN Digital radio standard used by NEXEDGE and IDAS brands.
|
||||
Supports both 9600 baud (12.5 kHz) and
|
||||
4800 baud (6.25 kHz) digital voice.
|
||||
|
||||
Support includes decoding and synthesis of speech and
|
||||
the ability to save and replay .amb data files.
|
||||
|
||||
Development (no speech) support only:
|
||||
|
||||
D-STAR Amateur radio digital voice standard
|
||||
|
||||
Development support only. DSD recognized frames and can
|
||||
extract the voice bits but speech is not yet decoded.
|
||||
D-STAR likely uses a version of AMBE not yet supported by
|
||||
mbelib. The voice bit interleave pattern also needs to be
|
||||
determined.
|
||||
Note: not enabled by default, use -fd to enable.
|
||||
|
||||
Unsupported formats in version 1.4 considered for future development:
|
||||
|
||||
P25 Phase 2 This is not yet a published standard. Full support is
|
||||
expected once the standard is published and there are
|
||||
systems operating to test against. Phase 2 will use
|
||||
a vocoder supported by mbelib.
|
||||
|
||||
OpenSKY It is possible that the four slot version uses a vocoder
|
||||
supported by mbelib. The two slot version does not.
|
||||
|
||||
Supported demodulation optimizations in version 1.4:
|
||||
|
||||
C4FM Continuous envelope 2 or 4 level FSK with relatively
|
||||
sharp transitions between symbols. Used by most P25
|
||||
systems.
|
||||
|
||||
Optimizations include calibrating decision points only
|
||||
during sync, 4/10 sample window per symbol, and symbol
|
||||
edge timing calibration.
|
||||
|
||||
GFSK Continuous envelope 2 or 4 level FSK with a narrower
|
||||
Gaussian/"raised cosine" filter that affects transitions
|
||||
between symbols. Used by DMR/MOTOTRBO, NXDN and many
|
||||
others. Noisy C4FM signals may be detected as GFSK
|
||||
|
||||
but this is ok, the optimization changes will help with
|
||||
noisy signals.
|
||||
|
||||
Optimizations are similar to C4FM except symbol transitions
|
||||
are only kept out of the middle 4 samples and only the
|
||||
middle two samples are used.
|
||||
|
||||
QPSK Quadrature Phase Shift Keying (and variants) used in
|
||||
some P25 systems and all known X2-TDMA systems. May be
|
||||
advertised under the marketing term "LSM"
|
||||
|
||||
Optimizations include continuous decision point
|
||||
calibration, using middle two samples, and using the
|
||||
symbol midpoint "spike" for symbol timing.
|
||||
|
||||
Installation
|
||||
|
||||
DSD should easily compile on any Linux or *BSD system with gcc.
|
||||
Just untar and run "make" or "make install". There are some debugging/
|
||||
development options in config.h that normal users will want to leave
|
||||
disabled as they can severely impact performance.
|
||||
|
||||
Operation
|
||||
|
||||
There are two main operating modes, "Live scanner" and "Play files"
|
||||
|
||||
Usage: dsd [options] Live scanner mode
|
||||
|
||||
Live Scanner mode takes 48KHz/16 bit mono audio samples from a
|
||||
sound card input and decodes speech in real time. Options are provided
|
||||
for controling information display and saving mbe data files.
|
||||
The synthesized speech can be output to a soundcard and/or a
|
||||
.wav file.
|
||||
|
||||
Usage: dsd [options] -r <files> Read/Play saved mbe data from file(s)
|
||||
|
||||
|
||||
Play files mode reads mbe data from files specified on the command
|
||||
line (including wildcards) and synthesizes speech from those files.
|
||||
The synthesized speech can be output to a soundcard and/or a
|
||||
.wav file. The -r command line options is used to activate Play files
|
||||
mode.
|
||||
|
||||
Display modes
|
||||
|
||||
There are two main display modes in Live scanner mode. "Errorbars"
|
||||
and "Datascope".
|
||||
|
||||
Errorbars mode output for P25 Phase 1 looks like this:
|
||||
|
||||
|
||||
Sync: -P25p1 mod: C4FM inlvl: 39% nac: 5C2 src: 0 tg: 32464 TDULC
|
||||
Sync: -P25p1 mod: C4FM inlvl: 39% nac: 5C2 src: 0 tg: 32464 TDULC
|
||||
Sync: -P25p1 mod: C4FM inlvl: 39% nac: 5C2 src: 0 tg: 32464 TDULC
|
||||
Sync: -P25p1 mod: C4FM inlvl: 39% nac: 5C2 src: 0 tg: 32464 TDULC
|
||||
Sync: -P25p1 mod: C4FM inlvl: 38% nac: 5C2 src: 0 tg: 32464 TDU
|
||||
Sync: -P25p1 mod: C4FM inlvl: 38% nac: 5C2 src: 0 tg: 32464 HDU
|
||||
Sync: -P25p1 mod: C4FM inlvl: 42% nac: 5C2 src: 0 tg: 32464 LDU1 e:
|
||||
Sync: (-P25p1) mod: C4FM inlvl: 39% nac: 5C2 src: 52610 tg: 32464 (LDU2) e:
|
||||
Sync: -P25p1 mod: C4FM inlvl: 38% nac: 5C2 src: 52610 tg: 32464 LDU1 e:
|
||||
Sync: -P25p1 mod: C4FM inlvl: 39% nac: 5C2 src: 52610 tg: 32464 LDU2 e:
|
||||
Sync: -P25p1 mod: C4FM inlvl: 39% nac: 5C2 src: 52610 tg: 32464 LDU1 e:
|
||||
Sync: -P25p1 mod: C4FM inlvl: 39% nac: 5C2 src: 52610 tg: 32464 LDU2 e:
|
||||
Sync: -P25p1 mod: C4FM inlvl: 39% nac: 5C2 src: 52610 tg: 32464 LDU1 e:
|
||||
|
||||
"Sync" indicates the frame type detected and whether the polarity is
|
||||
positive or negative. DSD automatically detects and handles either
|
||||
polarity except for DMR/MOTOTRBO/X2-TDMA which unfortunatley use both
|
||||
sync polarities.
|
||||
|
||||
Most combinations of transmitter, receiver and soundcard show netagive
|
||||
(-) polarity for X2-TDMA signals and (+) polarity for DMR/MOTOTRBO so
|
||||
those are the defaults.
|
||||
|
||||
********
|
||||
You may need to use the -x option to select non-inverted polarity if
|
||||
you are not getting usable X2-TDMA/MOTOTRBO/DMR speech. As they use both
|
||||
normal and inverted sync it is not possible to detect polariy
|
||||
automatically.
|
||||
********
|
||||
|
||||
"mod" indicates the current demodulation optimizations.
|
||||
|
||||
"inlvl" indicates the audio input level. QPSK signals tend to appear
|
||||
much "wider" than C4FM from a discriminator tap so it is important
|
||||
to set your input gain using a QPSK signal if you plan to montir them.
|
||||
It is not necessary nor desirable to get to 100%, in fact your sound
|
||||
card may max out below 100%. It is best to use the Datascope mode for
|
||||
setting input gain (see below). Typical values with good results are
|
||||
40% for C4FM and 66% for QPSK.
|
||||
|
||||
"nac" is the P25 Phase 1 Network Access Code. This is a 12 bit field
|
||||
in each P25 Phase 1 header. It should not be confused with the 16
|
||||
bit System ID used in non-P25 trunking control channels.
|
||||
|
||||
"src" is the radio id of the trasmitting subscriber unit.
|
||||
|
||||
"tg" is the talkgroup derived from link control information.
|
||||
|
||||
"HDU/LDU1/LDU2/TDU/TDULC" are P25 Phase 1 frame types, referred to as
|
||||
frame subtype within DSD.
|
||||
|
||||
"e:" is the beginning of the errorbars display. Each "=" indicates a
|
||||
detected error within the voice data. "R" and "M" indicat that a voice
|
||||
frame was repeated or muted due to excessive errors.
|
||||
|
||||
Values in parentheses () indicate an assumption (soft decision) was
|
||||
made based on the previous frame.
|
||||
|
||||
Errorbars mode output for X2-TDMA looks like this:
|
||||
|
||||
Sync: -X2-TDMA mod: QPSK inlvl: 59% src: 17211 tg: 197 [SLOT0] slot1 VOICE e:
|
||||
Sync: -X2-TDMA mod: QPSK inlvl: 47% src: 17211 tg: 197 [SLOT0] slot1 VOICE e:
|
||||
Sync: -X2-TDMA mod: QPSK inlvl: 43% src: 17211 tg: 197 [SLOT0] slot1 VOICE e:
|
||||
Sync: (-X2-TDMA) mod: QPSK inlvl: 28% src: 17211 tg: 197 [SLOT0] slot1 VOICE e:
|
||||
|
||||
DMR/MOTOTRBO display is similar except it does not yet show source
|
||||
and talkgroup information.
|
||||
|
||||
As of version 1.2 DSD shows which specific TDMA slots are active (with
|
||||
capital SLOT letters) and which slot is currently being monitored (with
|
||||
square brackets []. Noisy/degraded signals will affect the accuracy
|
||||
of this display.
|
||||
|
||||
The frame subtypes (Voice/LC etc) are shown based on the DMR standard
|
||||
types.
|
||||
|
||||
Datascope mode output looks like this:
|
||||
|
||||
|
||||
Demod mode: C4FM Nac: 8C3
|
||||
Frame Type: P25 Phase 1 Talkgroup: 16528
|
||||
Frame Subtype: LDU1 Source: 0
|
||||
TDMA activity: slot0 slot1 Voice errors:
|
||||
+----------------------------------------------------------------+
|
||||
| # ^ !| ^ # |
|
||||
| * | * |
|
||||
| * | * |
|
||||
| * | * * |
|
||||
| * * | * * |
|
||||
| * * | ** * |
|
||||
| * ** | ** * |
|
||||
| ** ** | ** * |
|
||||
| ** ** | ** * |
|
||||
| ** ** | ** * |
|
||||
+----------------------------------------------------------------+
|
||||
C4FM Example
|
||||
|
||||
Demod mode: C4FM Nac: 126
|
||||
Frame Type: P25 Phase 1 Talkgroup: 25283
|
||||
Frame Subtype: LDU2 Source: 0
|
||||
TDMA activity: slot0 slot1 Voice errors:
|
||||
+----------------------------------------------------------------+
|
||||
| # ^ ! ^ # |
|
||||
| * | |
|
||||
| * | |
|
||||
| ** | |
|
||||
| ** | * |
|
||||
| * ** | * * |
|
||||
| ** ** | * * |
|
||||
| *** ** | ** * |
|
||||
| *** ** | *** * |
|
||||
| *** **** | **** * * |
|
||||
+----------------------------------------------------------------+
|
||||
QPSK Example
|
||||
|
||||
|
||||
At the top is various information about the signal, similar to the
|
||||
information provided in Errorbars mode. The large box is similar to
|
||||
a spectrum analyzer viewing the channel bandwidth.
|
||||
|
||||
The horizontal axis is the input audio level, minimum on the left and
|
||||
maximum on the right. The vertical axis is the number of samples
|
||||
seend at each audio level.
|
||||
|
||||
The "*" symbols represent the number of audio
|
||||
samples that were at each level during the aggregation period.
|
||||
(default = 36 symbols) The -S options controls the aggregation period
|
||||
as well as the QPSK tracking symbol buffer, so changing that will affect
|
||||
QPSK performance as well as the Datascope display.
|
||||
|
||||
As you can see from the figures above, clean C4FM signals tend to have
|
||||
four very sharply defined audio levels. The datascope pattern also
|
||||
tends to be faily stable with minor shifts left and right as the
|
||||
receiver tries to frequency track any DC offset.
|
||||
|
||||
QPSK signals on the other hand tend to appear much broader (and artifact
|
||||
of how they are distored by FM PLL discriminators). They also tend
|
||||
to vary wildly in width and centering. This is especially true when
|
||||
monitoring simulcast systems. Muliple QPSK signals interfere much more
|
||||
dramatically with an FM discriminator than C4FM signals.
|
||||
|
||||
*******
|
||||
For this reason it is important to isolate your receiver to one
|
||||
transmitter tower, _especially_ for QPSK signals.
|
||||
*******
|
||||
|
||||
The "#" symbols indicate the detected min/max values that are used
|
||||
to calibrate the symbol decision points. These are indicated by
|
||||
"!" for the center decision point and "^" for the mid decision points.
|
||||
|
||||
Display Options
|
||||
|
||||
There are several options to control the type and quantity of
|
||||
information displayed in Errorbars mode:
|
||||
|
||||
-e Show Frame Info and errorbars (default)
|
||||
-pe Show P25 encryption sync bits
|
||||
-pl Show P25 link control bits
|
||||
-ps Show P25 status bits and low speed data
|
||||
-pt Show P25 talkgroup info
|
||||
-q Don't show Frame Info/errorbars
|
||||
-s Datascope (disables other display options)
|
||||
-t Show symbol timing during sync
|
||||
-v <num> Frame information Verbosity
|
||||
-z <num> Frame rate for datascope
|
||||
|
||||
Most of these options are self explanitory. Symbol timing is a noisy
|
||||
option that allows you to view the quality of the frame sync samples
|
||||
and accuracy of the symbol timing adjustments.
|
||||
|
||||
Symbol Timing display looks like this:
|
||||
|
||||
Symbol Timing:
|
||||
----------
|
||||
----------
|
||||
----------
|
||||
----------
|
||||
----------
|
||||
-+++++++++ 1
|
||||
+---------- 0
|
||||
----------
|
||||
++++++++++ 0
|
||||
++++++++++
|
||||
---------- 0
|
||||
----------
|
||||
++++++++++ 0
|
||||
++++++++++
|
||||
++++++++++
|
||||
++++++++++
|
||||
---------- 0
|
||||
++++++++++ 0
|
||||
---------- 0
|
||||
++++++++++ 0
|
||||
++++++++++
|
||||
++++++++++
|
||||
++++++++++
|
||||
++++++++++
|
||||
C4FM example
|
||||
|
||||
Symbol Timing:
|
||||
+---------
|
||||
----------
|
||||
----------
|
||||
----------
|
||||
-----X---- 5
|
||||
--+++O++++- 4
|
||||
----------
|
||||
----X----- 4
|
||||
++++O++--- 4
|
||||
--++O++++- 4
|
||||
----X----- 4
|
||||
----------
|
||||
++++O+++-- 4
|
||||
-+++O+++-- 4
|
||||
--++O+++-- 4
|
||||
--++O+++-- 4
|
||||
----------
|
||||
++++O++++- 4
|
||||
----------
|
||||
++++O+++-- 4
|
||||
-+++O++++- 4
|
||||
-+++O+++++ 4
|
||||
-+++O++--- 4
|
||||
--++O+++-- 4
|
||||
QPSK example
|
||||
|
||||
Symbol timing is only displayed for symbols during the frame sync
|
||||
period. Each horizontal line represents the 10 audio samples for each
|
||||
symbol. "-" indicates an audio sample below the center reference level
|
||||
and "+" represents a sample above center. "X" indicates a low spike
|
||||
below a reference threshold (reference minimum for C4FM and 80%
|
||||
of reference minimum for QPSK). "O" represents a high spike above
|
||||
the high reference threshold. The numbers to the right indicate which
|
||||
sample position the targeted transition occurred (+/- for C4FM or
|
||||
spike high/low for QPSK). The number of audio samples for the next
|
||||
symbol are adjusted to get this value closer to the target (0 for
|
||||
C4FM and 4 for QPSK). This shows how DSD maintains accurate symbol
|
||||
timing. Symbol timing adjustments are only made during sync, which
|
||||
is the only time reliable transitions can be observed.
|
||||
|
||||
In both examples above the symbol timing was off by one sample at
|
||||
the beginning of the frame sync period and was adjusted. Generally
|
||||
if you see any spike values "X/O" in C4FM mode, or lots of them in
|
||||
QPSK mode it indicates noise on the input signal.
|
||||
|
||||
Input/Output Options
|
||||
|
||||
-i <device> Audio input device (default is /dev/audio)
|
||||
-o <device> Audio output device (default is /dev/audio)
|
||||
-d <dir> Create mbe data files, use this directory
|
||||
-g <num> Audio output gain (default = 0 = auto)
|
||||
-n Do not send synthesized speech to audio output device
|
||||
-w <file> Output synthesized speech to a .wav file
|
||||
|
||||
The audio in device can be a sound card OR a .wav file if the file
|
||||
is in the exact format 48k/16bits/mono/pcm. Audio in should be an
|
||||
unfilterd discriminator tap signal.
|
||||
|
||||
The audio out device should be a sound card (use the -w options to
|
||||
output to a .wav file).
|
||||
|
||||
If the audio in device is the same as the audio out device, the
|
||||
synthesized speech has to be upsampled to the 48k sample rate required
|
||||
for input. A fast upsample function is provided but still leaves some
|
||||
artifacts.
|
||||
|
||||
********
|
||||
The best sound and minimum cpu usage is achieved with separate sound
|
||||
cards for input and output
|
||||
********
|
||||
|
||||
if you specify different input/output devices DSD will use 8k as the
|
||||
output sample rate and the lack of resampling results in much better
|
||||
audio as well as lowe cpu consumption.
|
||||
|
||||
If you are using onboard "AC97" sound device you may find that DSD uses
|
||||
much more cpu than expected, in some cases more than is available.
|
||||
This is because many AC97 sound devices are designed to rely on CPU
|
||||
processing power instead of hardware. You may also find that 8k sample
|
||||
rate output is upsampled in the driver using a very basic algorithim
|
||||
resulting in severe distortion. The solution is to use a real hardware
|
||||
sound device (pci card, usb device etc).
|
||||
|
||||
As of version 1.2 DSD now automatically levels the output audio. This
|
||||
greately improves readability and eliminates the painful effects of
|
||||
noise bursts. You can specify a fixed audio output gain with the -g
|
||||
option.
|
||||
|
||||
Scanner control options:
|
||||
|
||||
-B <num> Serial port baud rate (default=115200)
|
||||
-C <device> Serial port for scanner control (default=/dev/ttyUSB0)
|
||||
-R <num> Resume scan after <num> TDULC frames or any PDU or TSDU
|
||||
|
||||
|
||||
On some P25 systems Packet Data Units (PDU) are sent on the same
|
||||
frequencies used for voice traffic. If done constantly this can
|
||||
be a severe hinderance to scanning the system in conventional
|
||||
mode. The -R option enables sending a "resume scan" command to
|
||||
a scanner connected to a serial port. Use -B and -C to set the baud
|
||||
rate and serial port device if necessary.
|
||||
|
||||
Decoder options
|
||||
|
||||
-fa Auto-detect frame type (default)
|
||||
-f1 Decode only P25 Phase 1
|
||||
-fd Decode only D-STAR* (no audio)
|
||||
-fi Decode only NXDN48* (6.25 kHz) / IDAS*
|
||||
-fn Decode only NXDN96 (12.5 kHz)
|
||||
-fp Decode only ProVoice*
|
||||
-fr Decode only DMR/MOTOTRBO
|
||||
-fx Decode only X2-TDMA
|
||||
-ma Auto-select modulation optimizations (default)
|
||||
-mc Use only C4FM modulation optimizations
|
||||
-mg Use only GFSK modulation optimizations
|
||||
-mq Use only QPSK modulation optimizations
|
||||
-u <num> Unvoiced speech quality (default=3)
|
||||
-xx Expect non-inverted X2-TDMA signal
|
||||
-xr Expect inverted DMR/MOTOTRBO signal
|
||||
|
||||
* denotes frame types that cannot be auto-detected.
|
||||
|
||||
ProVoice and NXDN48 not auto-detected as use different symbol
|
||||
rates (9600 and 2400) than most formats (4800). D-STAR is not
|
||||
enabled by default as voice decode does not work and it has a
|
||||
short sync word that is prone to false triggering. It is included
|
||||
for development/testing only.
|
||||
|
||||
MBE speech synthesis is broken down into two main types of sounds,
|
||||
"Voiced" and "Unvoiced". Voiced speech bands are synthesized with
|
||||
a single sine wave centered in the frequency band with the appropriate
|
||||
phase and amplitude.
|
||||
|
||||
Unvoiced speech is supposed to be generated with a noise source, 256
|
||||
point DFT a number of band filters, followed by a 256 point inverse DFT.
|
||||
For computational simplicity mbelib uses a different method. For each
|
||||
unvoiced speech band, a number of sine waves are generated, each with a
|
||||
different random initial phase. The number of waves used per band is
|
||||
controlled by the -u option. A setting of 4 would approximate the
|
||||
performance of the 256 point DFT method as the maximum number of voice
|
||||
bands is 56, and very low frequencies are not synthesized. Values less
|
||||
than 3 have a noticable lack of unvoiced speech and/or artifacts. The
|
||||
defualt of 3 provides good speech quality with reasonable cpu use.
|
||||
Increasing the quality above the default rapidly consumes more CPU for
|
||||
increasingly diminishing returns.
|
||||
|
||||
|
||||
Advanced decoder options
|
||||
-A <num> QPSK modulation auto detection threshold (default=26)
|
||||
-S <num> Symbol buffer size for QPSK decision point tracking
|
||||
(default=36)
|
||||
-M <num> Min/Max buffer size for QPSK decision point tracking
|
||||
(default=15)
|
||||
|
||||
Encryption
|
||||
|
||||
********
|
||||
Decryption of speech is NOT supported, even if you lawfully posess the
|
||||
encryption keys. Decryption support will not be added in the future as
|
||||
the authors wish to steer as far away from the legal issues associated
|
||||
with encryption as possible.
|
||||
********
|
||||
|
||||
We realize that there are many legitemate and lawful uses of decryption
|
||||
software including system/interoperability testing and lawful monitoring.
|
||||
This software is distributed under a liberal BSD license so there is
|
||||
nothing to stop others from supplying patches, forking this project or
|
||||
incorporating it into a commercial product and adding decryption support.
|
||||
|
||||
There is support for displaying the encryption sync bits transmitted in
|
||||
the clear on P25 Phase 1 systems. These bits do not allow for the
|
||||
decryption of signals without the secret encryption keys. The
|
||||
encryption sync bits are useful for determining whether a signal is
|
||||
encrypted vs merely noisy or degraded. As the encryption sync bits
|
||||
typically include long strings of zeros when a transmission is not
|
||||
encrypted they can also be used to visually estimate bit error rates.
|
||||
32
README.md
Normal file
32
README.md
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
# Digital Speech Decoder - Florida Man Edition
|
||||
|
||||
DSD-FME is an evolution of the original DSD project from 'DSD Author' using the base code of [szechyjs](https://github.com/szechyjs/dsd "szechyjs"), some code and ideas from [LouisErigHerve](https://github.com/LouisErigHerve/dsd "LouisErigHerve"), [Boatbod OP25](https://github.com/boatbod/op25 "Boatbod OP25") and
|
||||
[Osmocom OP25](https://gitea.osmocom.org/op25/op25 "Osmocom OP25"), along with other snippets of code, information, and inspirations from other projects including [DSDcc](https://github.com/f4exb/dsdcc "DSDcc"), [SDRTRunk](https://github.com/DSheirer/sdrtrunk "SDRTrunk"), [MMDVMHost](https://github.com/g4klx/MMDVMHost "MMDVMHost"), [LFSR](https://github.com/mattames/LFSR "LFSR"), [OK-DMRlib](https://github.com/OK-DMR/ok-dmrlib "OK-DMRlib"), and [EZPWD-Reed-Solomon](https://github.com/pjkundert/ezpwd-reed-solomon "EZPWD"), Eric Cottrell, SP5WWP and others. Finally, this is all brought together with original code to extend the fuctionality and add new features including NCurses Terminal and Menu system, Pulse Audio, TCP Direct Link Audio, RIGCTL, Trunking Features, LRRP/GPS Mapping, P25 Phase 2, EDACS, YSF, M17, OP25 Capture Bin compatability, etc. DSD-FME is primarily focused with Linux Desktop users in mind, so please understand that this version may not compile, compile easily, or run correctly in other environments.
|
||||
|
||||
This project wouldn't be possible without a few good people providing me plenty of sample audio files to run over and over again. Special thanks to jurek1111, KrisMar, noamlivne, racingfan360, iScottyBotty, LimaZulu, Forts, thewraithe2008, RayAir, Cretu, and others for the many hours of wav samples and information provided by them. Most importantly, HRH17, whose insight, information, samples, and willingness to let me remote into a computer half-way across the globe in order to test trunking features are what make DSD-FME what it has become. I'd also like to thank mrscanner2008 for providing an additional remote where additional NXDN Type-C, 'Idas' Type-D, and XPT decoding and trunking could be sorted out. Thanks to volo-zyko for cleaning up a lot of code. Thank you everybody.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## Information
|
||||
|
||||
See the [examples](https://github.com/lwvmobile/dsd-fme/tree/audio_work/examples "examples") folder for information on [cloning and installing](https://github.com/lwvmobile/dsd-fme/blob/audio_work/examples/Install_Notes.md "cloning and installing"), [example usage](https://github.com/lwvmobile/dsd-fme/blob/audio_work/examples/Example_Usage.md "example usage"), and [trunking examples](https://github.com/lwvmobile/dsd-fme/blob/audio_work/examples/trunking.sh "trunking examples").
|
||||
|
||||
## License
|
||||
Copyright (C) 2010 DSD Author
|
||||
GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
31
cmake/FindCODEC2.cmake
Normal file
31
cmake/FindCODEC2.cmake
Normal file
@@ -0,0 +1,31 @@
|
||||
# - Try to find CODEC2
|
||||
# Once done this will define
|
||||
|
||||
#Seems to work on Cygwin as well now -- more testing for may be required
|
||||
# Not sure what causes the 'Package 'codec2', required by 'virtual:world', not found' message, but seems to work anyways
|
||||
# -- Checking for module 'codec2'
|
||||
# -- Package 'codec2', required by 'virtual:world', not found
|
||||
# -- Found CODEC2: /usr/local/lib/libcodec2.dll.a
|
||||
|
||||
if (NOT CODEC2_FOUND)
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(CODEC2_PKG codec2)
|
||||
set(CODEC2_DEFINITIONS ${PC_CODEC2_CFLAGS_OTHER})
|
||||
|
||||
find_path(CODEC2_INCLUDE_DIR
|
||||
NAMES codec2/codec2.h codec2.h
|
||||
HINTS ${CODEC2_PKG_INCLUDE_DIRS})
|
||||
|
||||
find_library(CODEC2_LIBRARY
|
||||
NAMES codec2/codec2 codec2
|
||||
HINTS ${CODEC2_PKG_LIBRARY_DIRS})
|
||||
|
||||
set(CODEC2_LIBRARIES ${CODEC2_LIBRARY})
|
||||
set(CODEC2_INCLUDE_DIRS ${CODEC2_INCLUDE_DIR})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(CODEC2 DEFAULT_MSG CODEC2_LIBRARY CODEC2_INCLUDE_DIR)
|
||||
mark_as_advanced(CODEC2_INCLUDE_DIR CODEC2_LIBRARY)
|
||||
|
||||
endif (NOT CODEC2_FOUND)
|
||||
15
cmake/FindITPP.cmake
Normal file
15
cmake/FindITPP.cmake
Normal file
@@ -0,0 +1,15 @@
|
||||
# - Try to find ITPP
|
||||
# Once done this will define
|
||||
#
|
||||
# ITPP_FOUND - System has ITPP
|
||||
# ITPP_INCLUDE_DIR - The ITPP include directory
|
||||
# ITPP_LIBRARY - The library needed to use ITPP
|
||||
#
|
||||
|
||||
find_path(ITPP_INCLUDE_DIR itpp/itcomm.h)
|
||||
|
||||
set(ITPP_NAMES ${ITPP_NAMES} itpp libitpp libitpp.dll)
|
||||
FIND_LIBRARY(ITPP_LIBRARY NAMES ${ITPP_NAMES})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(ITPP DEFAULT_MSG ITPP_LIBRARY ITPP_INCLUDE_DIR)
|
||||
16
cmake/FindLibSndFile.cmake
Normal file
16
cmake/FindLibSndFile.cmake
Normal file
@@ -0,0 +1,16 @@
|
||||
# - Try to find Libsndfile
|
||||
# Once done this will define
|
||||
#
|
||||
# LIBSNDFILE_FOUND - System has LIBSNDFILE
|
||||
# LIBSNDFILE_INCLUDE_DIR - The SNDFILE include directory
|
||||
# LIBSNDFILE_LIBRARY - The library needed to use SNDFILE
|
||||
#
|
||||
|
||||
find_path(LIBSNDFILE_INCLUDE_DIR sndfile.h)
|
||||
|
||||
SET(LIBSNDFILE_NAMES ${LIBSNDFILE_NAMES} sndfile libsndfile)
|
||||
FIND_LIBRARY(LIBSNDFILE_LIBRARY NAMES ${LIBSNDFILE_NAMES})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(LibSndFile DEFAULT_MSG LIBSNDFILE_LIBRARY
|
||||
LIBSNDFILE_INCLUDE_DIR)
|
||||
15
cmake/FindMBE.cmake
Normal file
15
cmake/FindMBE.cmake
Normal file
@@ -0,0 +1,15 @@
|
||||
# - Try to find MBE
|
||||
# Once done this will define
|
||||
#
|
||||
# MBE_FOUND - System has MBE
|
||||
# MBE_INCLUDE_DIR - The MBE include directory
|
||||
# MBE_LIBRARY - The library needed to use MBE
|
||||
#
|
||||
|
||||
find_path(MBE_INCLUDE_DIR mbelib.h)
|
||||
|
||||
set(MBE_NAMES ${MBE_NAMES} mbe libmbe)
|
||||
find_library(MBE_LIBRARY NAMES ${MBE_NAMES})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(MBE DEFAULT_MSG MBE_LIBRARY MBE_INCLUDE_DIR)
|
||||
68
cmake/FindPulseAudio.cmake
Normal file
68
cmake/FindPulseAudio.cmake
Normal file
@@ -0,0 +1,68 @@
|
||||
#.rst:
|
||||
# FindPulseAudio
|
||||
# --------------
|
||||
# Finds the PulseAudio library
|
||||
#
|
||||
# This will define the following variables::
|
||||
#
|
||||
# PULSEAUDIO_FOUND - system has the PulseAudio library
|
||||
# PULSEAUDIO_INCLUDE_DIRS - the PulseAudio include directory
|
||||
# PULSEAUDIO_LIBRARIES - the libraries needed to use PulseAudio
|
||||
# PULSEAUDIO_DEFINITIONS - the definitions needed to use PulseAudio
|
||||
#
|
||||
# and the following imported targets::
|
||||
#
|
||||
# PulseAudio::PulseAudio - The PulseAudio library
|
||||
|
||||
if(PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(PC_PULSEAUDIO libpulse>=11.0.0 QUIET)
|
||||
pkg_check_modules(PC_PULSEAUDIO_MAINLOOP libpulse-mainloop-glib>=11.0.0 QUIET)
|
||||
pkg_check_modules(PC_PULSEAUDIO_SIMPLE libpulse-simple>=11.0.0 QUIET)
|
||||
endif()
|
||||
|
||||
find_path(PULSEAUDIO_INCLUDE_DIR NAMES pulse/pulseaudio.h pulse/simple.h
|
||||
PATHS ${PC_PULSEAUDIO_INCLUDEDIR} ${PC_PULSEAUDIO_INCLUDE_DIRS})
|
||||
|
||||
find_library(PULSEAUDIO_LIBRARY NAMES pulse libpulse
|
||||
PATHS ${PC_PULSEAUDIO_LIBDIR} ${PC_PULSEAUDIO_LIBRARY_DIRS})
|
||||
|
||||
find_library(PULSEAUDIO_SIMPLE_LIBRARY NAMES pulse-simple libpulse-simple
|
||||
PATHS ${PC_PULSEAUDIO_LIBDIR} ${PC_PULSEAUDIO_LIBRARY_DIRS})
|
||||
|
||||
find_library(PULSEAUDIO_MAINLOOP_LIBRARY NAMES pulse-mainloop pulse-mainloop-glib libpulse-mainloop-glib
|
||||
PATHS ${PC_PULSEAUDIO_LIBDIR} ${PC_PULSEAUDIO_LIBRARY_DIRS})
|
||||
|
||||
if(PC_PULSEAUDIO_VERSION)
|
||||
set(PULSEAUDIO_VERSION_STRING ${PC_PULSEAUDIO_VERSION})
|
||||
elseif(PULSEAUDIO_INCLUDE_DIR AND EXISTS "${PULSEAUDIO_INCLUDE_DIR}/pulse/version.h")
|
||||
file(STRINGS "${PULSEAUDIO_INCLUDE_DIR}/pulse/version.h" pulseaudio_version_str REGEX "^#define[\t ]+pa_get_headers_version\\(\\)[\t ]+\\(\".*\"\\).*")
|
||||
string(REGEX REPLACE "^#define[\t ]+pa_get_headers_version\\(\\)[\t ]+\\(\"([^\"]+)\"\\).*" "\\1" PULSEAUDIO_VERSION_STRING "${pulseaudio_version_str}")
|
||||
unset(pulseaudio_version_str)
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(PulseAudio
|
||||
REQUIRED_VARS PULSEAUDIO_LIBRARY PULSEAUDIO_MAINLOOP_LIBRARY PULSEAUDIO_SIMPLE_LIBRARY PULSEAUDIO_INCLUDE_DIR
|
||||
VERSION_VAR PULSEAUDIO_VERSION_STRING)
|
||||
|
||||
if(PULSEAUDIO_FOUND)
|
||||
set(PULSEAUDIO_INCLUDE_DIRS ${PULSEAUDIO_INCLUDE_DIR})
|
||||
set(PULSEAUDIO_LIBRARIES ${PULSEAUDIO_LIBRARY} ${PULSEAUDIO_MAINLOOP_LIBRARY} ${PULSEAUDIO_SIMPLE_LIBRARY})
|
||||
set(PULSEAUDIO_DEFINITIONS -DHAS_PULSEAUDIO=1)
|
||||
|
||||
if(NOT TARGET PulseAudio::PulseAudioMainloop)
|
||||
add_library(PulseAudio::PulseAudioMainloop UNKNOWN IMPORTED)
|
||||
set_target_properties(PulseAudio::PulseAudioMainloop PROPERTIES
|
||||
IMPORTED_LOCATION "${PULSEAUDIO_MAINLOOP_LIBRARY}")
|
||||
endif()
|
||||
if(NOT TARGET PulseAudio::PulseAudio)
|
||||
add_library(PulseAudio::PulseAudio UNKNOWN IMPORTED)
|
||||
set_target_properties(PulseAudio::PulseAudio PROPERTIES
|
||||
IMPORTED_LOCATION "${PULSEAUDIO_LIBRARY}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${PULSEAUDIO_INCLUDE_DIR}"
|
||||
INTERFACE_COMPILE_DEFINITIONS HAVE_LIBPULSE=1
|
||||
INTERFACE_LINK_LIBRARIES PulseAudio::PulseAudioMainloop)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
mark_as_advanced(PULSEAUDIO_INCLUDE_DIR PULSEAUDIO_LIBRARY PULSEAUDIO_MAINLOOP_LIBRARY PULSEAUDIO_SIMPLE_LIBRARY)
|
||||
29
cmake/FindRTLSDR.cmake
Normal file
29
cmake/FindRTLSDR.cmake
Normal file
@@ -0,0 +1,29 @@
|
||||
# - Try to find rtlsdr - the hardware driver for the realtek chip in the dvb receivers
|
||||
# Once done this will define
|
||||
# RTLSDR_FOUND - System has rtlsdr
|
||||
# RTLSDR_LIBRARIES - The rtlsdr libraries
|
||||
# RTLSDR_INCLUDE_DIRS - The rtlsdr include directories
|
||||
# RTLSDR_LIB_DIRS - The rtlsdr library directories
|
||||
|
||||
if (NOT RTLSDR_FOUND)
|
||||
|
||||
find_package(PkgConfig)
|
||||
pkg_check_modules(RTLSDR_PKG librtlsdr)
|
||||
set(RTLSDR_DEFINITIONS ${PC_RTLSDR_CFLAGS_OTHER})
|
||||
|
||||
find_path(RTLSDR_INCLUDE_DIR
|
||||
NAMES rtl-sdr.h
|
||||
HINTS ${RTLSDR_PKG_INCLUDE_DIRS})
|
||||
|
||||
find_library(RTLSDR_LIBRARY
|
||||
NAMES rtlsdr
|
||||
HINTS ${RTLSDR_PKG_LIBRARY_DIRS})
|
||||
|
||||
set(RTLSDR_LIBRARIES ${RTLSDR_LIBRARY})
|
||||
set(RTLSDR_INCLUDE_DIRS ${RTLSDR_INCLUDE_DIR})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(RTLSDR DEFAULT_MSG RTLSDR_LIBRARY RTLSDR_INCLUDE_DIR)
|
||||
mark_as_advanced(RTLSDR_INCLUDE_DIR RTLSDR_LIBRARY)
|
||||
|
||||
endif (NOT RTLSDR_FOUND)
|
||||
23
cmake/cmake_uninstall.cmake.in
Normal file
23
cmake/cmake_uninstall.cmake.in
Normal file
@@ -0,0 +1,23 @@
|
||||
if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
|
||||
message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
|
||||
endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
|
||||
|
||||
file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
|
||||
string(REGEX REPLACE "\n" ";" files "${files}")
|
||||
cmake_policy(SET CMP0007 OLD)
|
||||
list(REVERSE files)
|
||||
foreach (file ${files})
|
||||
message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
|
||||
if (EXISTS "$ENV{DESTDIR}${file}")
|
||||
execute_process(
|
||||
COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}"
|
||||
OUTPUT_VARIABLE rm_out
|
||||
RESULT_VARIABLE rm_retval
|
||||
)
|
||||
if(NOT ${rm_retval} EQUAL 0)
|
||||
message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
|
||||
endif (NOT ${rm_retval} EQUAL 0)
|
||||
else (EXISTS "$ENV{DESTDIR}${file}")
|
||||
message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
|
||||
endif (EXISTS "$ENV{DESTDIR}${file}")
|
||||
endforeach(file)
|
||||
130
cmake/git_revision.cmake
Normal file
130
cmake/git_revision.cmake
Normal file
@@ -0,0 +1,130 @@
|
||||
# - Returns a version string from Git
|
||||
#
|
||||
# These functions force a re-configure on each git commit so that you can
|
||||
# trust the values of the variables in your build system.
|
||||
#
|
||||
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the refspec and sha hash of the current head revision
|
||||
#
|
||||
# git_describe(<var> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the results of git describe on the source tree, and adjusting
|
||||
# the output so that it tests false if an error occurs.
|
||||
#
|
||||
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
|
||||
#
|
||||
# Returns the results of git describe --exact-match on the source tree,
|
||||
# and adjusting the output so that it tests false if there was no exact
|
||||
# matching tag.
|
||||
#
|
||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||
#
|
||||
# Original Author:
|
||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com
|
||||
# Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright Iowa State University 2009-2010.
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
if(__get_git_revision_description)
|
||||
return()
|
||||
endif()
|
||||
set(__get_git_revision_description YES)
|
||||
|
||||
# We must run the following at "include" time, not at function call time,
|
||||
# to find the path to this module rather than the path to a calling list file
|
||||
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
|
||||
|
||||
function(get_git_head_revision _refspecvar _hashvar)
|
||||
set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
||||
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
|
||||
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
|
||||
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
|
||||
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
|
||||
# We have reached the root directory, we are not in git
|
||||
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
||||
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
|
||||
endwhile()
|
||||
# check if this is a submodule
|
||||
if(NOT IS_DIRECTORY ${GIT_DIR})
|
||||
file(READ ${GIT_DIR} submodule)
|
||||
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
|
||||
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
|
||||
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
|
||||
endif()
|
||||
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
|
||||
if(NOT EXISTS "${GIT_DATA}")
|
||||
file(MAKE_DIRECTORY "${GIT_DATA}")
|
||||
endif()
|
||||
|
||||
if(NOT EXISTS "${GIT_DIR}/HEAD")
|
||||
return()
|
||||
endif()
|
||||
set(HEAD_FILE "${GIT_DATA}/HEAD")
|
||||
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
|
||||
|
||||
configure_file("cmake/git_revision.cmake.in"
|
||||
"${GIT_DATA}/grabRef.cmake"
|
||||
@ONLY)
|
||||
include("${GIT_DATA}/grabRef.cmake")
|
||||
|
||||
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
|
||||
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_describe _var)
|
||||
if(NOT GIT_FOUND)
|
||||
find_package(Git QUIET)
|
||||
endif()
|
||||
get_git_head_revision(refspec hash)
|
||||
if(NOT GIT_FOUND)
|
||||
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
if(NOT hash)
|
||||
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# TODO sanitize
|
||||
#if((${ARGN}" MATCHES "&&") OR
|
||||
# (ARGN MATCHES "||") OR
|
||||
# (ARGN MATCHES "\\;"))
|
||||
# message("Please report the following error to the project!")
|
||||
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
|
||||
#endif()
|
||||
|
||||
#message(STATUS "Arguments to execute_process: ${ARGN}")
|
||||
|
||||
execute_process(COMMAND
|
||||
"${GIT_EXECUTABLE}"
|
||||
describe
|
||||
${hash}
|
||||
${ARGN}
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_SOURCE_DIR}"
|
||||
RESULT_VARIABLE
|
||||
res
|
||||
OUTPUT_VARIABLE
|
||||
out
|
||||
ERROR_QUIET
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE)
|
||||
if(NOT res EQUAL 0)
|
||||
set(out "${out}-${res}-NOTFOUND")
|
||||
endif()
|
||||
|
||||
set(${_var} "${out}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(git_get_exact_tag _var)
|
||||
git_describe(out --exact-match ${ARGN})
|
||||
set(${_var} "${out}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
38
cmake/git_revision.cmake.in
Normal file
38
cmake/git_revision.cmake.in
Normal file
@@ -0,0 +1,38 @@
|
||||
#
|
||||
# Internal file for GetGitRevisionDescription.cmake
|
||||
#
|
||||
# Requires CMake 2.6 or newer (uses the 'function' command)
|
||||
#
|
||||
# Original Author:
|
||||
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
|
||||
# http://academic.cleardefinition.com
|
||||
# Iowa State University HCI Graduate Program/VRAC
|
||||
#
|
||||
# Copyright Iowa State University 2009-2010.
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or copy at
|
||||
# http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
set(HEAD_HASH)
|
||||
|
||||
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
|
||||
|
||||
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
|
||||
if(HEAD_CONTENTS MATCHES "ref")
|
||||
# named branch
|
||||
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
|
||||
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
|
||||
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
elseif(EXISTS "@GIT_DIR@/logs/${HEAD_REF}")
|
||||
configure_file("@GIT_DIR@/logs/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
set(HEAD_HASH "${HEAD_REF}")
|
||||
endif()
|
||||
else()
|
||||
# detached HEAD
|
||||
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
|
||||
endif()
|
||||
|
||||
if(NOT HEAD_HASH)
|
||||
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
|
||||
string(STRIP "${HEAD_HASH}" HEAD_HASH)
|
||||
endif()
|
||||
3
configure
vendored
3
configure
vendored
@@ -1,3 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "There is no configure script, just run make"
|
||||
240
dmr_data.c
240
dmr_data.c
@@ -1,240 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
void
|
||||
processDMRdata (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
int i, dibit;
|
||||
int *dibit_p;
|
||||
char sync[25];
|
||||
char syncdata[25];
|
||||
char cachdata[13];
|
||||
char cc[5];
|
||||
char bursttype[5];
|
||||
|
||||
#ifdef DMR_DUMP
|
||||
int k;
|
||||
char syncbits[49];
|
||||
char cachbits[25];
|
||||
#endif
|
||||
|
||||
cc[4] = 0;
|
||||
bursttype[4] = 0;
|
||||
|
||||
dibit_p = state->dibit_buf_p - 90;
|
||||
|
||||
// CACH
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if (opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
cachdata[i] = dibit;
|
||||
if (i == 2)
|
||||
{
|
||||
state->currentslot = (1 & (dibit >> 1)); // bit 1
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
state->slot0light[0] = '[';
|
||||
state->slot0light[6] = ']';
|
||||
state->slot1light[0] = ' ';
|
||||
state->slot1light[6] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
state->slot1light[0] = '[';
|
||||
state->slot1light[6] = ']';
|
||||
state->slot0light[0] = ' ';
|
||||
state->slot0light[6] = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
cachdata[12] = 0;
|
||||
|
||||
#ifdef DMR_DUMP
|
||||
k = 0;
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
dibit = cachdata[i];
|
||||
cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
k++;
|
||||
cachbits[k] = (1 & dibit) + 48; // bit 0
|
||||
k++;
|
||||
}
|
||||
cachbits[24] = 0;
|
||||
printf ("%s ", cachbits);
|
||||
#endif
|
||||
|
||||
// current slot
|
||||
dibit_p += 49;
|
||||
|
||||
// slot type
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if (opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
cc[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
cc[1] = (1 & dibit) + 48; // bit 0
|
||||
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if (opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
cc[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
cc[3] = (1 & dibit) + 48; // bit 0
|
||||
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if (opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
bursttype[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
bursttype[1] = (1 & dibit) + 48; // bit 0
|
||||
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if (opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
bursttype[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
bursttype[3] = (1 & dibit) + 48; // bit 0
|
||||
|
||||
// parity bit
|
||||
dibit_p++;
|
||||
|
||||
if (strcmp (bursttype, "0000") == 0)
|
||||
{
|
||||
sprintf (state->fsubtype, " PI Header ");
|
||||
}
|
||||
else if (strcmp (bursttype, "0001") == 0)
|
||||
{
|
||||
sprintf (state->fsubtype, " VOICE Header ");
|
||||
}
|
||||
else if (strcmp (bursttype, "0010") == 0)
|
||||
{
|
||||
sprintf (state->fsubtype, " TLC ");
|
||||
}
|
||||
else if (strcmp (bursttype, "0011") == 0)
|
||||
{
|
||||
sprintf (state->fsubtype, " CSBK ");
|
||||
}
|
||||
else if (strcmp (bursttype, "0100") == 0)
|
||||
{
|
||||
sprintf (state->fsubtype, " MBC Header ");
|
||||
}
|
||||
else if (strcmp (bursttype, "0101") == 0)
|
||||
{
|
||||
sprintf (state->fsubtype, " MBC ");
|
||||
}
|
||||
else if (strcmp (bursttype, "0110") == 0)
|
||||
{
|
||||
sprintf (state->fsubtype, " DATA Header ");
|
||||
}
|
||||
else if (strcmp (bursttype, "0111") == 0)
|
||||
{
|
||||
sprintf (state->fsubtype, " RATE 1/2 DATA");
|
||||
}
|
||||
else if (strcmp (bursttype, "1000") == 0)
|
||||
{
|
||||
sprintf (state->fsubtype, " RATE 3/4 DATA");
|
||||
}
|
||||
else if (strcmp (bursttype, "1001") == 0)
|
||||
{
|
||||
sprintf (state->fsubtype, " Slot idle ");
|
||||
}
|
||||
else if (strcmp (bursttype, "1010") == 0)
|
||||
{
|
||||
sprintf (state->fsubtype, " Rate 1 DATA ");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (state->fsubtype, " ");
|
||||
}
|
||||
|
||||
// signaling data or sync
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if (opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
syncdata[i] = dibit;
|
||||
sync[i] = (dibit | 1) + 48;
|
||||
}
|
||||
sync[24] = 0;
|
||||
syncdata[24] = 0;
|
||||
|
||||
#ifdef DMR_DUMP
|
||||
k = 0;
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
dibit = syncdata[i];
|
||||
syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
k++;
|
||||
syncbits[k] = (1 & dibit) + 48; // bit 0
|
||||
k++;
|
||||
}
|
||||
syncbits[48] = 0;
|
||||
printf ("%s ", syncbits);
|
||||
#endif
|
||||
|
||||
if ((strcmp (sync, DMR_BS_DATA_SYNC) == 0) || (strcmp (sync, DMR_MS_DATA_SYNC) == 0))
|
||||
{
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
sprintf (state->slot0light, "[slot0]");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (state->slot1light, "[slot1]");
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printf ("%s %s ", state->slot0light, state->slot1light);
|
||||
}
|
||||
|
||||
// current slot second half, cach, next slot 1st half
|
||||
skipDibit (opts, state, 120);
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
if (strcmp (state->fsubtype, " ") == 0)
|
||||
{
|
||||
printf (" Unknown burst type: %s\n", bursttype);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("%s\n", state->fsubtype);
|
||||
}
|
||||
}
|
||||
}
|
||||
382
dmr_voice.c
382
dmr_voice.c
@@ -1,382 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
#include "dmr_const.h"
|
||||
|
||||
void
|
||||
processDMRvoice (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
// extracts AMBE frames from DMR frame
|
||||
int i, j, dibit;
|
||||
int *dibit_p;
|
||||
char ambe_fr[4][24];
|
||||
char ambe_fr2[4][24];
|
||||
char ambe_fr3[4][24];
|
||||
const int *w, *x, *y, *z;
|
||||
char sync[25];
|
||||
char syncdata[25];
|
||||
char cachdata[13];
|
||||
int mutecurrentslot;
|
||||
int msMode;
|
||||
|
||||
#ifdef DMR_DUMP
|
||||
int k;
|
||||
char syncbits[49];
|
||||
char cachbits[25];
|
||||
#endif
|
||||
|
||||
mutecurrentslot = 0;
|
||||
msMode = 0;
|
||||
|
||||
dibit_p = state->dibit_buf_p - 144;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
// 2nd half of previous slot
|
||||
for (i = 0; i < 54; i++)
|
||||
{
|
||||
if (j > 0)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if (opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CACH
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
if (j > 0)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if (opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
}
|
||||
cachdata[i] = dibit;
|
||||
if (i == 2)
|
||||
{
|
||||
state->currentslot = (1 & (dibit >> 1)); // bit 1
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
state->slot0light[0] = '[';
|
||||
state->slot0light[6] = ']';
|
||||
state->slot1light[0] = ' ';
|
||||
state->slot1light[6] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
state->slot1light[0] = '[';
|
||||
state->slot1light[6] = ']';
|
||||
state->slot0light[0] = ' ';
|
||||
state->slot0light[6] = ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
cachdata[12] = 0;
|
||||
|
||||
|
||||
#ifdef DMR_DUMP
|
||||
k = 0;
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
dibit = cachdata[i];
|
||||
cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
k++;
|
||||
cachbits[k] = (1 & dibit) + 48; // bit 0
|
||||
k++;
|
||||
}
|
||||
cachbits[24] = 0;
|
||||
printf ("%s ", cachbits);
|
||||
#endif
|
||||
|
||||
// current slot frame 1
|
||||
w = rW;
|
||||
x = rX;
|
||||
y = rY;
|
||||
z = rZ;
|
||||
for (i = 0; i < 36; i++)
|
||||
{
|
||||
if (j > 0)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if (opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
}
|
||||
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr[*y][*z] = (1 & dibit); // bit 0
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
}
|
||||
|
||||
// current slot frame 2 first half
|
||||
w = rW;
|
||||
x = rX;
|
||||
y = rY;
|
||||
z = rZ;
|
||||
for (i = 0; i < 18; i++)
|
||||
{
|
||||
if (j > 0)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if (opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
}
|
||||
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
}
|
||||
|
||||
// signaling data or sync
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
if (j > 0)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if (opts->inverted_dmr == 1)
|
||||
{
|
||||
dibit = (dibit ^ 2);
|
||||
}
|
||||
}
|
||||
syncdata[i] = dibit;
|
||||
sync[i] = (dibit | 1) + 48;
|
||||
}
|
||||
sync[24] = 0;
|
||||
syncdata[24] = 0;
|
||||
|
||||
if ((strcmp (sync, DMR_BS_DATA_SYNC) == 0) || (strcmp (sync, DMR_MS_DATA_SYNC) == 0))
|
||||
{
|
||||
mutecurrentslot = 1;
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
sprintf (state->slot0light, "[slot0]");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (state->slot1light, "[slot1]");
|
||||
}
|
||||
}
|
||||
else if ((strcmp (sync, DMR_BS_VOICE_SYNC) == 0) || (strcmp (sync, DMR_MS_VOICE_SYNC) == 0))
|
||||
{
|
||||
mutecurrentslot = 0;
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
sprintf (state->slot0light, "[SLOT0]");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (state->slot1light, "[SLOT1]");
|
||||
}
|
||||
}
|
||||
if ((strcmp (sync, DMR_MS_VOICE_SYNC) == 0) || (strcmp (sync, DMR_MS_DATA_SYNC) == 0))
|
||||
{
|
||||
msMode = 1;
|
||||
}
|
||||
|
||||
if ((j == 0) && (opts->errorbars == 1))
|
||||
{
|
||||
printf ("%s %s VOICE e:", state->slot0light, state->slot1light);
|
||||
}
|
||||
|
||||
#ifdef DMR_DUMP
|
||||
k = 0;
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
dibit = syncdata[i];
|
||||
syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
k++;
|
||||
syncbits[k] = (1 & dibit) + 48; // bit 0
|
||||
k++;
|
||||
}
|
||||
syncbits[48] = 0;
|
||||
printf ("%s ", syncbits);
|
||||
#endif
|
||||
|
||||
// current slot frame 2 second half
|
||||
for (i = 0; i < 18; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
}
|
||||
|
||||
if (mutecurrentslot == 0)
|
||||
{
|
||||
if (state->firstframe == 1)
|
||||
{ // we don't know if anything received before the first sync after no carrier is valid
|
||||
state->firstframe = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
// current slot frame 3
|
||||
w = rW;
|
||||
x = rX;
|
||||
y = rY;
|
||||
z = rZ;
|
||||
for (i = 0; i < 36; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr3[*y][*z] = (1 & dibit); // bit 0
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
}
|
||||
if (mutecurrentslot == 0)
|
||||
{
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
}
|
||||
|
||||
// CACH
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
cachdata[i] = dibit;
|
||||
}
|
||||
cachdata[12] = 0;
|
||||
|
||||
#ifdef DMR_DUMP
|
||||
k = 0;
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
dibit = cachdata[i];
|
||||
cachbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
k++;
|
||||
cachbits[k] = (1 & dibit) + 48; // bit 0
|
||||
k++;
|
||||
}
|
||||
cachbits[24] = 0;
|
||||
printf ("%s ", cachbits);
|
||||
#endif
|
||||
|
||||
|
||||
// next slot
|
||||
skipDibit (opts, state, 54);
|
||||
|
||||
// signaling data or sync
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
syncdata[i] = dibit;
|
||||
sync[i] = (dibit | 1) + 48;
|
||||
}
|
||||
sync[24] = 0;
|
||||
syncdata[24] = 0;
|
||||
|
||||
if ((strcmp (sync, DMR_BS_DATA_SYNC) == 0) || (msMode == 1))
|
||||
{
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
sprintf (state->slot1light, " slot1 ");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (state->slot0light, " slot0 ");
|
||||
}
|
||||
}
|
||||
else if (strcmp (sync, DMR_BS_VOICE_SYNC) == 0)
|
||||
{
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
sprintf (state->slot1light, " SLOT1 ");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (state->slot0light, " SLOT0 ");
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DMR_DUMP
|
||||
k = 0;
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
dibit = syncdata[i];
|
||||
syncbits[k] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
k++;
|
||||
syncbits[k] = (1 & dibit) + 48; // bit 0
|
||||
k++;
|
||||
}
|
||||
syncbits[48] = 0;
|
||||
printf ("%s ", syncbits);
|
||||
#endif
|
||||
|
||||
if (j == 5)
|
||||
{
|
||||
// 2nd half next slot
|
||||
skipDibit (opts, state, 54);
|
||||
|
||||
// CACH
|
||||
skipDibit (opts, state, 12);
|
||||
|
||||
// first half current slot
|
||||
skipDibit (opts, state, 54);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
}
|
||||
52
download-and-install-Arch.sh
Normal file
52
download-and-install-Arch.sh
Normal file
@@ -0,0 +1,52 @@
|
||||
#! /bin/bash
|
||||
#
|
||||
cdir=$(pwd)
|
||||
clear
|
||||
printf "Digital Speech Decoder: Florida Man Edition - Auto Installer For Arch Linux\n
|
||||
This will install the required packages, clone, build, and install DSD-FME only.
|
||||
This has been tested on Arch 2023.08.01 and Manjaro XFCE 22.1.3 Minimal.\n
|
||||
MBELib is considered a requirement on this build.
|
||||
You must view the Patent Notice prior to continuing.
|
||||
The Patent Notice can be found at the site below.
|
||||
https://github.com/lwvmobile/mbelib#readme
|
||||
Please confirm that you have viewed the patent notice by entering y below.\n\n"
|
||||
read -p "Have you viewed the patent notice? y/N " ANSWER
|
||||
ANSWER=$(printf "$ANSWER"|tr '[:upper:]' '[:lower:]')
|
||||
if [ "$ANSWER" = "y" ]; then
|
||||
|
||||
sudo pacman -Syu #always run a full update first, partial upgrades aren't supported in Arch -- including downloading dependencies, that may require an updated dependency, and breaks same dependency on another package, a.k.a, dependency hell
|
||||
sudo pacman -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel libsndfile git wget
|
||||
|
||||
printf "Installing itpp 4.3.1 from Arch Strike --Tested on Arch 2023.08.01 and Manjaro XFCE 22.1.3 Minimal\n"
|
||||
wget https://mirror.archstrike.org/x86_64/archstrike/itpp-4.3.1-3-x86_64.pkg.tar.xz
|
||||
sudo pacman -U itpp-4.3.1-3-x86_64.pkg.tar.xz
|
||||
sudo rm -R itpp-4.3.1-3-x86_64.pkg.tar.xz
|
||||
|
||||
git clone https://github.com/lwvmobile/mbelib
|
||||
cd mbelib
|
||||
git checkout ambe_tones
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j $(nproc)
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
sudo cp /usr/local/lib/libmbe.so /usr/lib/libmbe.so
|
||||
cd $cdir
|
||||
|
||||
git clone https://github.com/lwvmobile/dsd-fme
|
||||
### For branch audio_work - git clone --branch audio_work https://github.com/lwvmobile/dsd-fme
|
||||
cd dsd-fme
|
||||
#git checkout audio_work
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j $(nproc)
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
|
||||
printf "Any issues, Please report to either:\nhttps://github.com/lwvmobile/dsd-fme/issues or\nhttps://forums.radioreference.com/threads/dsd-fme.438137/\n\n"
|
||||
|
||||
else
|
||||
printf "Sorry, you cannot build DSD-FME without acknowledging the Patent Notice.\n\n"
|
||||
fi
|
||||
17
download-and-install-nodeps.sh
Normal file
17
download-and-install-nodeps.sh
Normal file
@@ -0,0 +1,17 @@
|
||||
#! /bin/bash
|
||||
clear
|
||||
printf "\nDigital Speech Decoder: Florida Man Edition - Auto Installer\n
|
||||
This will clone, build, and install DSD-FME only.
|
||||
If DSD-FME has never been installed on this machine,
|
||||
then you will need to install the dependencies first!
|
||||
Please run download-and-install.sh instead.\n\n"
|
||||
read -p "Press Enter to continue..." x
|
||||
git clone https://github.com/lwvmobile/dsd-fme
|
||||
cd dsd-fme
|
||||
#git checkout audio_work
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j $(nproc)
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
44
download-and-install.sh
Normal file
44
download-and-install.sh
Normal file
@@ -0,0 +1,44 @@
|
||||
#! /bin/bash
|
||||
#
|
||||
cdir=$(pwd)
|
||||
clear
|
||||
printf "Digital Speech Decoder: Florida Man Edition - Auto Installer\n
|
||||
MBELib is considered a requirement on this build.
|
||||
You must view the Patent Notice prior to continuing.
|
||||
The Patent Notice can be found at the site below.
|
||||
https://github.com/lwvmobile/mbelib#readme
|
||||
Please confirm that you have viewed the patent notice by entering y below:\n\n"
|
||||
read -p "Have you viewed the patent notice? y/N " ANSWER
|
||||
ANSWER=$(printf "$ANSWER"|tr '[:upper:]' '[:lower:]')
|
||||
if [ "$ANSWER" = "y" ]; then
|
||||
sudo apt update
|
||||
sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev libcodec2-dev
|
||||
chkitpp=$(sudo apt list libitpp-dev 2>&1|grep -ci "installed")
|
||||
if [ "$chkitpp" -lt "1" ];then
|
||||
printf "\nFor some reason, ITPP did NOT install!\nYou may have to manually install it.\n\n"
|
||||
read -p "Press Enter to exit..." x
|
||||
exit 1
|
||||
fi
|
||||
git clone https://github.com/lwvmobile/mbelib
|
||||
cd mbelib
|
||||
git checkout ambe_tones
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j $(nproc)
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
cd $cdir
|
||||
git clone https://github.com/lwvmobile/dsd-fme
|
||||
cd dsd-fme
|
||||
#git checkout audio_work
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j $(nproc)
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
else
|
||||
printf "\nSorry, you cannot build DSD-FME without acknowledging the Patent Notice.\nExiting...\n\n"
|
||||
exit 2
|
||||
fi
|
||||
BIN
dsd-fme-qgis-map.qgz
Normal file
BIN
dsd-fme-qgis-map.qgz
Normal file
Binary file not shown.
BIN
dsd-fme2.png
Normal file
BIN
dsd-fme2.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 94 KiB |
BIN
dsd-fme3.png
Normal file
BIN
dsd-fme3.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 127 KiB |
247
dsd.h
247
dsd.h
@@ -1,247 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
#include <string.h>
|
||||
#define __USE_XOPEN
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#ifdef SOLARIS
|
||||
#include <sys/audioio.h>
|
||||
#endif
|
||||
#ifdef BSD
|
||||
#include <sys/soundcard.h>
|
||||
#endif
|
||||
#include <math.h>
|
||||
#include <mbelib.h>
|
||||
|
||||
/*
|
||||
* global variables
|
||||
*/
|
||||
int exitflag;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int onesymbol;
|
||||
char mbe_in_file[1024];
|
||||
FILE *mbe_in_f;
|
||||
int errorbars;
|
||||
int datascope;
|
||||
int symboltiming;
|
||||
int verbose;
|
||||
int p25enc;
|
||||
int p25lc;
|
||||
int p25status;
|
||||
int p25tg;
|
||||
int scoperate;
|
||||
char audio_in_dev[1024];
|
||||
int audio_in_fd;
|
||||
char audio_out_dev[1024];
|
||||
int audio_out_fd;
|
||||
int split;
|
||||
int playoffset;
|
||||
char mbe_out_dir[1024];
|
||||
char mbe_out_file[1024];
|
||||
FILE *mbe_out_f;
|
||||
float audio_gain;
|
||||
int audio_out;
|
||||
char wav_out_file[1024];
|
||||
FILE *wav_out_f;
|
||||
int wav_out_fd;
|
||||
int serial_baud;
|
||||
char serial_dev[1024];
|
||||
int serial_fd;
|
||||
int resume;
|
||||
int frame_dstar;
|
||||
int frame_x2tdma;
|
||||
int frame_p25p1;
|
||||
int frame_nxdn48;
|
||||
int frame_nxdn96;
|
||||
int frame_dmr;
|
||||
int frame_provoice;
|
||||
int mod_c4fm;
|
||||
int mod_qpsk;
|
||||
int mod_gfsk;
|
||||
int uvquality;
|
||||
int inverted_x2tdma;
|
||||
int inverted_dmr;
|
||||
int mod_threshold;
|
||||
int ssize;
|
||||
int msize;
|
||||
int playfiles;
|
||||
int delay;
|
||||
} dsd_opts;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int *dibit_buf;
|
||||
int *dibit_buf_p;
|
||||
int repeat;
|
||||
short *audio_out_buf;
|
||||
short *audio_out_buf_p;
|
||||
float *audio_out_float_buf;
|
||||
float *audio_out_float_buf_p;
|
||||
float audio_out_temp_buf[160];
|
||||
float *audio_out_temp_buf_p;
|
||||
int audio_out_idx;
|
||||
int audio_out_idx2;
|
||||
int wav_out_bytes;
|
||||
int center;
|
||||
int jitter;
|
||||
int synctype;
|
||||
int min;
|
||||
int max;
|
||||
int lmid;
|
||||
int umid;
|
||||
int minref;
|
||||
int maxref;
|
||||
int lastsample;
|
||||
int sbuf[128];
|
||||
int sidx;
|
||||
int maxbuf[1024];
|
||||
int minbuf[1024];
|
||||
int midx;
|
||||
char err_str[64];
|
||||
char fsubtype[16];
|
||||
char ftype[16];
|
||||
int symbolcnt;
|
||||
int rf_mod;
|
||||
int numflips;
|
||||
int lastsynctype;
|
||||
int lastp25type;
|
||||
int offset;
|
||||
int carrier;
|
||||
char tg[25][16];
|
||||
int tgcount;
|
||||
int lasttg;
|
||||
int lastsrc;
|
||||
int nac;
|
||||
int errs;
|
||||
int errs2;
|
||||
int mbe_file_type;
|
||||
int optind;
|
||||
int numtdulc;
|
||||
int firstframe;
|
||||
char slot0light[8];
|
||||
char slot1light[8];
|
||||
float aout_gain;
|
||||
float aout_max_buf[200];
|
||||
float *aout_max_buf_p;
|
||||
int aout_max_buf_idx;
|
||||
int samplesPerSymbol;
|
||||
int symbolCenter;
|
||||
char algid[9];
|
||||
char keyid[17];
|
||||
int currentslot;
|
||||
mbe_parms *cur_mp;
|
||||
mbe_parms *prev_mp;
|
||||
mbe_parms *prev_mp_enhanced;
|
||||
} dsd_state;
|
||||
|
||||
/*
|
||||
* Frame sync patterns
|
||||
*/
|
||||
#define INV_P25P1_SYNC "333331331133111131311111"
|
||||
#define P25P1_SYNC "111113113311333313133333"
|
||||
|
||||
#define X2TDMA_BS_VOICE_SYNC "113131333331313331113311"
|
||||
#define X2TDMA_BS_DATA_SYNC "331313111113131113331133"
|
||||
#define X2TDMA_MS_DATA_SYNC "313113333111111133333313"
|
||||
#define X2TDMA_MS_VOICE_SYNC "131331111333333311111131"
|
||||
|
||||
#define DSTAR_SYNC "313131313133131113313111"
|
||||
#define INV_DSTAR_SYNC "131313131311313331131333"
|
||||
|
||||
#define NXDN_MS_DATA_SYNC "313133113131111333"
|
||||
#define INV_NXDN_MS_DATA_SYNC "131311331313333111"
|
||||
#define NXDN_MS_VOICE_SYNC "313133113131113133"
|
||||
#define INV_NXDN_MS_VOICE_SYNC "131311331313331311"
|
||||
#define INV_NXDN_BS_DATA_SYNC "131311331313333131"
|
||||
#define NXDN_BS_DATA_SYNC "313133113131111313"
|
||||
#define INV_NXDN_BS_VOICE_SYNC "131311331313331331"
|
||||
#define NXDN_BS_VOICE_SYNC "313133113131113113"
|
||||
|
||||
#define DMR_BS_DATA_SYNC "313333111331131131331131"
|
||||
#define DMR_BS_VOICE_SYNC "131111333113313313113313"
|
||||
#define DMR_MS_DATA_SYNC "311131133313133331131113"
|
||||
#define DMR_MS_VOICE_SYNC "133313311131311113313331"
|
||||
|
||||
#define INV_PROVOICE_SYNC "31313111333133133311331133113311"
|
||||
#define PROVOICE_SYNC "13131333111311311133113311331133"
|
||||
#define INV_PROVOICE_EA_SYNC "13313133113113333311313133133311"
|
||||
#define PROVOICE_EA_SYNC "31131311331331111133131311311133"
|
||||
|
||||
/*
|
||||
* function prototypes
|
||||
*/
|
||||
void processDMRdata (dsd_opts * opts, dsd_state * state);
|
||||
void processDMRvoice (dsd_opts * opts, dsd_state * state);
|
||||
void processAudio (dsd_opts * opts, dsd_state * state);
|
||||
void writeSynthesizedVoice (dsd_opts * opts, dsd_state * state);
|
||||
void playSynthesizedVoice (dsd_opts * opts, dsd_state * state);
|
||||
void openAudioOutDevice (dsd_opts * opts, int speed);
|
||||
void openAudioInDevice (dsd_opts * opts);
|
||||
int getDibit (dsd_opts * opts, dsd_state * state);
|
||||
void skipDibit (dsd_opts * opts, dsd_state * state, int count);
|
||||
void saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d);
|
||||
void saveAmbe2250Data (dsd_opts * opts, dsd_state * state, char *ambe_d);
|
||||
int readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d);
|
||||
int readAmbe2250Data (dsd_opts * opts, dsd_state * state, char *ambe_d);
|
||||
void openMbeInFile (dsd_opts * opts, dsd_state * state);
|
||||
void closeMbeOutFile (dsd_opts * opts, dsd_state * state);
|
||||
void openMbeOutFile (dsd_opts * opts, dsd_state * state);
|
||||
void openWavOutFile (dsd_opts * opts, dsd_state * state);
|
||||
void closeWavOutFile (dsd_opts * opts, dsd_state * state);
|
||||
void printFrameInfo (dsd_opts * opts, dsd_state * state);
|
||||
void processFrame (dsd_opts * opts, dsd_state * state);
|
||||
void printFrameSync (dsd_opts * opts, dsd_state * state, char *frametype, int offset, char *modulation);
|
||||
int getFrameSync (dsd_opts * opts, dsd_state * state);
|
||||
int comp (const void *a, const void *b);
|
||||
void noCarrier (dsd_opts * opts, dsd_state * state);
|
||||
void initOpts (dsd_opts * opts);
|
||||
void initState (dsd_state * state);
|
||||
void usage ();
|
||||
void liveScanner (dsd_opts * opts, dsd_state * state);
|
||||
void cleanupAndExit (dsd_opts * opts, dsd_state * state);
|
||||
void sigfun (int sig);
|
||||
int main (int argc, char **argv);
|
||||
void playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv);
|
||||
void processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24]);
|
||||
void openSerial (dsd_opts * opts, dsd_state * state);
|
||||
void resumeScan (dsd_opts * opts, dsd_state * state);
|
||||
int getSymbol (dsd_opts * opts, dsd_state * state, int have_sync);
|
||||
void upsample (dsd_state * state, float invalue);
|
||||
void processDSTAR (dsd_opts * opts, dsd_state * state);
|
||||
void processNXDNVoice (dsd_opts * opts, dsd_state * state);
|
||||
void processNXDNData (dsd_opts * opts, dsd_state * state);
|
||||
void processP25lcw (dsd_opts * opts, dsd_state * state, char *lcformat, char *mfid, char *lcinfo);
|
||||
void processHDU (dsd_opts * opts, dsd_state * state);
|
||||
void processLDU1 (dsd_opts * opts, dsd_state * state);
|
||||
void processLDU2 (dsd_opts * opts, dsd_state * state);
|
||||
void processTDULC (dsd_opts * opts, dsd_state * state);
|
||||
void processProVoice (dsd_opts * opts, dsd_state * state);
|
||||
void processX2TDMAdata (dsd_opts * opts, dsd_state * state);
|
||||
void processX2TDMAvoice (dsd_opts * opts, dsd_state * state);
|
||||
369
dsd_audio.c
369
dsd_audio.c
@@ -1,369 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
void
|
||||
processAudio (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
int i, n;
|
||||
float aout_abs, max, gainfactor, gaindelta, maxbuf;
|
||||
|
||||
if (opts->audio_gain == (float) 0)
|
||||
{
|
||||
// detect max level
|
||||
max = 0;
|
||||
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
|
||||
for (n = 0; n < 160; n++)
|
||||
{
|
||||
aout_abs = fabsf (*state->audio_out_temp_buf_p);
|
||||
if (aout_abs > max)
|
||||
{
|
||||
max = aout_abs;
|
||||
}
|
||||
state->audio_out_temp_buf_p++;
|
||||
}
|
||||
*state->aout_max_buf_p = max;
|
||||
state->aout_max_buf_p++;
|
||||
state->aout_max_buf_idx++;
|
||||
if (state->aout_max_buf_idx > 24)
|
||||
{
|
||||
state->aout_max_buf_idx = 0;
|
||||
state->aout_max_buf_p = state->aout_max_buf;
|
||||
}
|
||||
|
||||
// lookup max history
|
||||
for (i = 0; i < 25; i++)
|
||||
{
|
||||
maxbuf = state->aout_max_buf[i];
|
||||
if (maxbuf > max)
|
||||
{
|
||||
max = maxbuf;
|
||||
}
|
||||
}
|
||||
|
||||
// determine optimal gain level
|
||||
if (max > (float) 0)
|
||||
{
|
||||
gainfactor = ((float) 30000 / max);
|
||||
}
|
||||
else
|
||||
{
|
||||
gainfactor = (float) 50;
|
||||
}
|
||||
if (gainfactor < state->aout_gain)
|
||||
{
|
||||
state->aout_gain = gainfactor;
|
||||
gaindelta = (float) 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (gainfactor > (float) 50)
|
||||
{
|
||||
gainfactor = (float) 50;
|
||||
}
|
||||
gaindelta = gainfactor - state->aout_gain;
|
||||
if (gaindelta > ((float) 0.05 * state->aout_gain))
|
||||
{
|
||||
gaindelta = ((float) 0.05 * state->aout_gain);
|
||||
}
|
||||
}
|
||||
gaindelta /= (float) 160;
|
||||
}
|
||||
else
|
||||
{
|
||||
gaindelta = (float) 0;
|
||||
}
|
||||
|
||||
// adjust output gain
|
||||
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
|
||||
for (n = 0; n < 160; n++)
|
||||
{
|
||||
*state->audio_out_temp_buf_p = (state->aout_gain + ((float) n * gaindelta)) * (*state->audio_out_temp_buf_p);
|
||||
state->audio_out_temp_buf_p++;
|
||||
}
|
||||
state->aout_gain += ((float) 160 * gaindelta);
|
||||
|
||||
// copy audio datat to output buffer and upsample if necessary
|
||||
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
|
||||
if (opts->split == 0)
|
||||
{
|
||||
for (n = 0; n < 160; n++)
|
||||
{
|
||||
upsample (state, *state->audio_out_temp_buf_p);
|
||||
state->audio_out_temp_buf_p++;
|
||||
state->audio_out_float_buf_p += 6;
|
||||
state->audio_out_idx += 6;
|
||||
state->audio_out_idx2 += 6;
|
||||
}
|
||||
state->audio_out_float_buf_p -= (960 + opts->playoffset);
|
||||
// copy to output (short) buffer
|
||||
for (n = 0; n < 960; n++)
|
||||
{
|
||||
if (*state->audio_out_float_buf_p > (float) 32760)
|
||||
{
|
||||
*state->audio_out_float_buf_p = (float) 32760;
|
||||
}
|
||||
else if (*state->audio_out_float_buf_p < (float) -32760)
|
||||
{
|
||||
*state->audio_out_float_buf_p = (float) -32760;
|
||||
}
|
||||
*state->audio_out_buf_p = (short) *state->audio_out_float_buf_p;
|
||||
state->audio_out_buf_p++;
|
||||
state->audio_out_float_buf_p++;
|
||||
}
|
||||
state->audio_out_float_buf_p += opts->playoffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (n = 0; n < 160; n++)
|
||||
{
|
||||
if (*state->audio_out_temp_buf_p > (float) 32760)
|
||||
{
|
||||
*state->audio_out_temp_buf_p = (float) 32760;
|
||||
}
|
||||
else if (*state->audio_out_temp_buf_p < (float) -32760)
|
||||
{
|
||||
*state->audio_out_temp_buf_p = (float) -32760;
|
||||
}
|
||||
*state->audio_out_buf_p = (short) *state->audio_out_temp_buf_p;
|
||||
state->audio_out_buf_p++;
|
||||
state->audio_out_temp_buf_p++;
|
||||
state->audio_out_idx++;
|
||||
state->audio_out_idx2++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
writeSynthesizedVoice (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
int n;
|
||||
short aout_buf[160];
|
||||
short *aout_buf_p;
|
||||
ssize_t result;
|
||||
|
||||
aout_buf_p = aout_buf;
|
||||
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
|
||||
for (n = 0; n < 160; n++)
|
||||
{
|
||||
if (*state->audio_out_temp_buf_p > (float) 32760)
|
||||
{
|
||||
*state->audio_out_temp_buf_p = (float) 32760;
|
||||
}
|
||||
else if (*state->audio_out_temp_buf_p < (float) -32760)
|
||||
{
|
||||
*state->audio_out_temp_buf_p = (float) -32760;
|
||||
}
|
||||
*aout_buf_p = (short) *state->audio_out_temp_buf_p;
|
||||
aout_buf_p++;
|
||||
state->audio_out_temp_buf_p++;
|
||||
}
|
||||
|
||||
result = write (opts->wav_out_fd, aout_buf, 320);
|
||||
fflush (opts->wav_out_f);
|
||||
state->wav_out_bytes += 320;
|
||||
}
|
||||
|
||||
void
|
||||
playSynthesizedVoice (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
ssize_t result;
|
||||
|
||||
if (state->audio_out_idx > opts->delay)
|
||||
{
|
||||
// output synthesized speech to sound card
|
||||
result = write (opts->audio_out_fd, (state->audio_out_buf_p - state->audio_out_idx), (state->audio_out_idx * 2));
|
||||
state->audio_out_idx = 0;
|
||||
}
|
||||
|
||||
if (state->audio_out_idx2 >= 800000)
|
||||
{
|
||||
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
||||
state->audio_out_buf_p = state->audio_out_buf + 100;
|
||||
memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
|
||||
memset (state->audio_out_buf, 0, 100 * sizeof (short));
|
||||
state->audio_out_idx2 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
openAudioOutDevice (dsd_opts * opts, int speed)
|
||||
{
|
||||
|
||||
#ifdef SOLARIS
|
||||
sample_info_t aset, aget;
|
||||
|
||||
opts->audio_out_fd = open (opts->audio_out_dev, O_WRONLY);
|
||||
if (opts->audio_out_fd == -1)
|
||||
{
|
||||
printf ("Error, couldn't open %s\n", opts->audio_out_dev);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
// get current
|
||||
ioctl (opts->audio_out_fd, AUDIO_GETINFO, &aset);
|
||||
|
||||
aset.record.sample_rate = speed;
|
||||
aset.play.sample_rate = speed;
|
||||
aset.record.channels = 1;
|
||||
aset.play.channels = 1;
|
||||
aset.record.precision = 16;
|
||||
aset.play.precision = 16;
|
||||
aset.record.encoding = AUDIO_ENCODING_LINEAR;
|
||||
aset.play.encoding = AUDIO_ENCODING_LINEAR;
|
||||
|
||||
if (ioctl (opts->audio_out_fd, AUDIO_SETINFO, &aset) == -1)
|
||||
{
|
||||
printf ("Error setting sample device parameters\n");
|
||||
exit (1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BSD
|
||||
|
||||
int fmt;
|
||||
|
||||
opts->audio_out_fd = open (opts->audio_out_dev, O_WRONLY);
|
||||
if (opts->audio_out_fd == -1)
|
||||
{
|
||||
printf ("Error, couldn't open %s\n", opts->audio_out_dev);
|
||||
opts->audio_out = 0;
|
||||
}
|
||||
|
||||
fmt = 0;
|
||||
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_RESET) < 0)
|
||||
{
|
||||
printf ("ioctl reset error \n");
|
||||
}
|
||||
fmt = speed;
|
||||
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SPEED, &fmt) < 0)
|
||||
{
|
||||
printf ("ioctl speed error \n");
|
||||
}
|
||||
fmt = 0;
|
||||
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_STEREO, &fmt) < 0)
|
||||
{
|
||||
printf ("ioctl stereo error \n");
|
||||
}
|
||||
fmt = AFMT_S16_LE;
|
||||
if (ioctl (opts->audio_out_fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
|
||||
{
|
||||
printf ("ioctl setfmt error \n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
printf ("Audio Out Device: %s\n", opts->audio_out_dev);
|
||||
}
|
||||
|
||||
void
|
||||
openAudioInDevice (dsd_opts * opts)
|
||||
{
|
||||
|
||||
#ifdef SOLARIS
|
||||
sample_info_t aset, aget;
|
||||
int rgain;
|
||||
|
||||
rgain = 64;
|
||||
|
||||
if (opts->split == 1)
|
||||
{
|
||||
opts->audio_in_fd = open (opts->audio_in_dev, O_RDONLY);
|
||||
}
|
||||
else
|
||||
{
|
||||
opts->audio_in_fd = open (opts->audio_in_dev, O_RDWR);
|
||||
}
|
||||
if (opts->audio_in_fd == -1)
|
||||
{
|
||||
printf ("Error, couldn't open /dev/audio\n");
|
||||
}
|
||||
|
||||
// get current
|
||||
ioctl (opts->audio_in_fd, AUDIO_GETINFO, &aset);
|
||||
|
||||
aset.record.sample_rate = 48000;
|
||||
aset.play.sample_rate = 48000;
|
||||
aset.record.channels = 1;
|
||||
aset.play.channels = 1;
|
||||
aset.record.precision = 16;
|
||||
aset.play.precision = 16;
|
||||
aset.record.encoding = AUDIO_ENCODING_LINEAR;
|
||||
aset.play.encoding = AUDIO_ENCODING_LINEAR;
|
||||
aset.record.port = AUDIO_LINE_IN;
|
||||
aset.record.gain = rgain;
|
||||
|
||||
if (ioctl (opts->audio_in_fd, AUDIO_SETINFO, &aset) == -1)
|
||||
{
|
||||
printf ("Error setting sample device parameters\n");
|
||||
exit (1);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BSD
|
||||
int fmt;
|
||||
|
||||
if (opts->split == 1)
|
||||
{
|
||||
opts->audio_in_fd = open (opts->audio_in_dev, O_RDONLY);
|
||||
}
|
||||
else
|
||||
{
|
||||
opts->audio_in_fd = open (opts->audio_in_dev, O_RDWR);
|
||||
}
|
||||
|
||||
if (opts->audio_in_fd == -1)
|
||||
{
|
||||
printf ("Error, couldn't open %s\n", opts->audio_in_dev);
|
||||
opts->audio_out = 0;
|
||||
}
|
||||
|
||||
fmt = 0;
|
||||
if (ioctl (opts->audio_in_fd, SNDCTL_DSP_RESET) < 0)
|
||||
{
|
||||
printf ("ioctl reset error \n");
|
||||
}
|
||||
fmt = 48000;
|
||||
if (ioctl (opts->audio_in_fd, SNDCTL_DSP_SPEED, &fmt) < 0)
|
||||
{
|
||||
printf ("ioctl speed error \n");
|
||||
}
|
||||
fmt = 0;
|
||||
if (ioctl (opts->audio_in_fd, SNDCTL_DSP_STEREO, &fmt) < 0)
|
||||
{
|
||||
printf ("ioctl stereo error \n");
|
||||
}
|
||||
fmt = AFMT_S16_LE;
|
||||
if (ioctl (opts->audio_in_fd, SNDCTL_DSP_SETFMT, &fmt) < 0)
|
||||
{
|
||||
printf ("ioctl setfmt error \n");
|
||||
}
|
||||
#endif
|
||||
|
||||
if (opts->split == 1)
|
||||
{
|
||||
printf ("Audio In Device: %s\n", opts->audio_in_dev);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Audio In/Out Device: %s\n", opts->audio_in_dev);
|
||||
}
|
||||
}
|
||||
290
dsd_dibit.c
290
dsd_dibit.c
@@ -1,290 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
int
|
||||
getDibit (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
// returns one dibit value
|
||||
int i, j, o, symbol;
|
||||
int sbuf2[128];
|
||||
int spectrum[64];
|
||||
char modulation[8];
|
||||
int lmin, lmax, lsum;
|
||||
|
||||
state->numflips = 0;
|
||||
|
||||
symbol = getSymbol (opts, state, 1);
|
||||
state->sbuf[state->sidx] = symbol;
|
||||
|
||||
for (i = 0; i < opts->ssize; i++)
|
||||
{
|
||||
sbuf2[i] = state->sbuf[i];
|
||||
}
|
||||
|
||||
qsort (sbuf2, opts->ssize, sizeof (int), comp);
|
||||
// continuous update of min/max in rf_mod=1 (QPSK) mode
|
||||
// in c4fm min/max must only be updated during sync
|
||||
if (state->rf_mod == 1)
|
||||
{
|
||||
lmin = (sbuf2[0] + sbuf2[1]) / 2;
|
||||
lmax = (sbuf2[(opts->ssize - 1)] + sbuf2[(opts->ssize - 2)]) / 2;
|
||||
state->minbuf[state->midx] = lmin;
|
||||
state->maxbuf[state->midx] = lmax;
|
||||
if (state->midx == (opts->msize - 1))
|
||||
{
|
||||
state->midx = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->midx++;
|
||||
}
|
||||
lsum = 0;
|
||||
for (i = 0; i < opts->msize; i++)
|
||||
{
|
||||
lsum += state->minbuf[i];
|
||||
}
|
||||
state->min = lsum / opts->msize;
|
||||
lsum = 0;
|
||||
for (i = 0; i < opts->msize; i++)
|
||||
{
|
||||
lsum += state->maxbuf[i];
|
||||
}
|
||||
state->max = lsum / opts->msize;
|
||||
state->center = ((state->max) + (state->min)) / 2;
|
||||
state->umid = (((state->max) - state->center) * 5 / 8) + state->center;
|
||||
state->lmid = (((state->min) - state->center) * 5 / 8) + state->center;
|
||||
state->maxref = ((state->max) * 0.80);
|
||||
state->minref = ((state->min) * 0.80);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->maxref = state->max;
|
||||
state->minref = state->min;
|
||||
}
|
||||
|
||||
if (state->sidx == (opts->ssize - 1))
|
||||
{
|
||||
|
||||
state->sidx = 0;
|
||||
|
||||
if (opts->datascope == 1)
|
||||
{
|
||||
if (state->rf_mod == 0)
|
||||
{
|
||||
sprintf (modulation, "C4FM");
|
||||
}
|
||||
else if (state->rf_mod == 1)
|
||||
{
|
||||
sprintf (modulation, "QPSK");
|
||||
}
|
||||
else if (state->rf_mod == 2)
|
||||
{
|
||||
sprintf (modulation, "GFSK");
|
||||
}
|
||||
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
spectrum[i] = 0;
|
||||
}
|
||||
for (i = 0; i < opts->ssize; i++)
|
||||
{
|
||||
o = (sbuf2[i] + 32768) / 1024;
|
||||
spectrum[o]++;
|
||||
}
|
||||
if (state->symbolcnt > (4800 / opts->scoperate))
|
||||
{
|
||||
state->symbolcnt = 0;
|
||||
printf ("\n");
|
||||
printf ("Demod mode: %s Nac: %4X\n", modulation, state->nac);
|
||||
printf ("Frame Type: %s Talkgroup: %7i\n", state->ftype, state->lasttg);
|
||||
printf ("Frame Subtype: %s Source: %12i\n", state->fsubtype, state->lastsrc);
|
||||
printf ("TDMA activity: %s %s Voice errors: %s\n", state->slot0light, state->slot1light, state->err_str);
|
||||
printf ("+----------------------------------------------------------------+\n");
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
printf ("|");
|
||||
for (j = 0; j < 64; j++)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
if ((j == ((state->min) + 32768) / 1024) || (j == ((state->max) + 32768) / 1024))
|
||||
{
|
||||
printf ("#");
|
||||
}
|
||||
else if ((j == ((state->lmid) + 32768) / 1024) || (j == ((state->umid) + 32768) / 1024))
|
||||
{
|
||||
printf ("^");
|
||||
}
|
||||
else if (j == (state->center + 32768) / 1024)
|
||||
{
|
||||
printf ("!");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (j == 32)
|
||||
{
|
||||
printf ("|");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf (" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (spectrum[j] > 9 - i)
|
||||
{
|
||||
printf ("*");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (j == 32)
|
||||
{
|
||||
printf ("|");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf (" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf ("|\n");
|
||||
}
|
||||
printf ("+----------------------------------------------------------------+\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
state->sidx++;
|
||||
}
|
||||
|
||||
// determine dibit state
|
||||
if ((state->synctype == 6) || (state->synctype == 14))
|
||||
{
|
||||
if (symbol > state->center)
|
||||
{
|
||||
*state->dibit_buf_p = 1;
|
||||
state->dibit_buf_p++;
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
{
|
||||
*state->dibit_buf_p = 3;
|
||||
state->dibit_buf_p++;
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
else if ((state->synctype == 7) || (state->synctype == 15))
|
||||
{
|
||||
if (symbol > state->center)
|
||||
{
|
||||
*state->dibit_buf_p = 1;
|
||||
state->dibit_buf_p++;
|
||||
return (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
*state->dibit_buf_p = 3;
|
||||
state->dibit_buf_p++;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
else if ((state->synctype == 1) || (state->synctype == 3) || (state->synctype == 5) || (state->synctype == 9) || (state->synctype == 11) || (state->synctype == 13))
|
||||
{
|
||||
if (symbol > state->center)
|
||||
{
|
||||
if (symbol > state->umid)
|
||||
{
|
||||
*state->dibit_buf_p = 1; // store non-inverted values in dibit_buf
|
||||
state->dibit_buf_p++;
|
||||
return (3);
|
||||
}
|
||||
else
|
||||
{
|
||||
*state->dibit_buf_p = 0;
|
||||
state->dibit_buf_p++;
|
||||
return (2);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (symbol < state->lmid)
|
||||
{
|
||||
*state->dibit_buf_p = 3;
|
||||
state->dibit_buf_p++;
|
||||
return (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
*state->dibit_buf_p = 2;
|
||||
state->dibit_buf_p++;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (symbol > state->center)
|
||||
{
|
||||
if (symbol > state->umid)
|
||||
{
|
||||
*state->dibit_buf_p = 1;
|
||||
state->dibit_buf_p++;
|
||||
return (1);
|
||||
}
|
||||
else
|
||||
{
|
||||
*state->dibit_buf_p = 0;
|
||||
state->dibit_buf_p++;
|
||||
return (0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (symbol < state->lmid)
|
||||
{
|
||||
*state->dibit_buf_p = 3;
|
||||
state->dibit_buf_p++;
|
||||
return (3);
|
||||
}
|
||||
else
|
||||
{
|
||||
*state->dibit_buf_p = 2;
|
||||
state->dibit_buf_p++;
|
||||
return (2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
skipDibit (dsd_opts * opts, dsd_state * state, int count)
|
||||
{
|
||||
|
||||
short sample;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < (count); i++)
|
||||
{
|
||||
sample = getDibit (opts, state);
|
||||
}
|
||||
}
|
||||
406
dsd_file.c
406
dsd_file.c
@@ -1,406 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
void
|
||||
saveImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
|
||||
{
|
||||
int i, j, k;
|
||||
unsigned char b;
|
||||
unsigned char err;
|
||||
|
||||
err = (unsigned char) state->errs2;
|
||||
fputc (err, opts->mbe_out_f);
|
||||
|
||||
k = 0;
|
||||
for (i = 0; i < 11; i++)
|
||||
{
|
||||
b = 0;
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
b = b << 1;
|
||||
b = b + imbe_d[k];
|
||||
k++;
|
||||
}
|
||||
fputc (b, opts->mbe_out_f);
|
||||
}
|
||||
fflush (opts->mbe_out_f);
|
||||
}
|
||||
|
||||
void
|
||||
saveAmbe2250Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
|
||||
{
|
||||
int i, j, k;
|
||||
unsigned char b;
|
||||
unsigned char err;
|
||||
|
||||
err = (unsigned char) state->errs2;
|
||||
fputc (err, opts->mbe_out_f);
|
||||
|
||||
k = 0;
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
b = 0;
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
b = b << 1;
|
||||
b = b + ambe_d[k];
|
||||
k++;
|
||||
}
|
||||
fputc (b, opts->mbe_out_f);
|
||||
}
|
||||
b = ambe_d[48];
|
||||
fputc (b, opts->mbe_out_f);
|
||||
fflush (opts->mbe_out_f);
|
||||
}
|
||||
|
||||
int
|
||||
readImbe4400Data (dsd_opts * opts, dsd_state * state, char *imbe_d)
|
||||
{
|
||||
|
||||
int i, j, k;
|
||||
unsigned char b;
|
||||
|
||||
state->errs2 = fgetc (opts->mbe_in_f);
|
||||
state->errs = state->errs2;
|
||||
|
||||
k = 0;
|
||||
for (i = 0; i < 11; i++)
|
||||
{
|
||||
b = fgetc (opts->mbe_in_f);
|
||||
if (feof (opts->mbe_in_f))
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
imbe_d[k] = (b & 128) >> 7;
|
||||
b = b << 1;
|
||||
b = b & 255;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
readAmbe2250Data (dsd_opts * opts, dsd_state * state, char *ambe_d)
|
||||
{
|
||||
|
||||
int i, j, k;
|
||||
unsigned char b;
|
||||
|
||||
state->errs2 = fgetc (opts->mbe_in_f);
|
||||
state->errs = state->errs2;
|
||||
|
||||
k = 0;
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
b = fgetc (opts->mbe_in_f);
|
||||
if (feof (opts->mbe_in_f))
|
||||
{
|
||||
return (1);
|
||||
}
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
ambe_d[k] = (b & 128) >> 7;
|
||||
b = b << 1;
|
||||
b = b & 255;
|
||||
k++;
|
||||
}
|
||||
}
|
||||
b = fgetc (opts->mbe_in_f);
|
||||
ambe_d[48] = (b & 1);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
openMbeInFile (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
char cookie[5];
|
||||
|
||||
opts->mbe_in_f = fopen (opts->mbe_in_file, "ro");
|
||||
if (opts->mbe_in_f == NULL)
|
||||
{
|
||||
printf ("Error: could not open %s\n", opts->mbe_in_file);
|
||||
}
|
||||
|
||||
// read cookie
|
||||
cookie[0] = fgetc (opts->mbe_in_f);
|
||||
cookie[1] = fgetc (opts->mbe_in_f);
|
||||
cookie[2] = fgetc (opts->mbe_in_f);
|
||||
cookie[3] = fgetc (opts->mbe_in_f);
|
||||
cookie[4] = 0;
|
||||
if (strstr (cookie, ".amb") != NULL)
|
||||
{
|
||||
state->mbe_file_type = 1;
|
||||
}
|
||||
else if (strstr (cookie, ".imb") != NULL)
|
||||
{
|
||||
state->mbe_file_type = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->mbe_file_type = -1;
|
||||
printf ("Error - unrecognized file type\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
closeMbeOutFile (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
char shell[255], newfilename[64], ext[5], datestr[32];
|
||||
char tgid[17];
|
||||
int sum, i, j;
|
||||
int talkgroup;
|
||||
struct tm timep;
|
||||
int result;
|
||||
|
||||
if (opts->mbe_out_f != NULL)
|
||||
{
|
||||
if ((state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15))
|
||||
{
|
||||
sprintf (ext, ".imb");
|
||||
strptime (opts->mbe_out_file, "%s.imb", &timep);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (ext, ".amb");
|
||||
strptime (opts->mbe_out_file, "%s.amb", &timep);
|
||||
}
|
||||
|
||||
if (state->tgcount > 0)
|
||||
{
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
sum = 0;
|
||||
for (j = 0; j < state->tgcount; j++)
|
||||
{
|
||||
sum = sum + state->tg[j][i] - 48;
|
||||
}
|
||||
tgid[i] = (char) (((float) sum / (float) state->tgcount) + 48.5);
|
||||
}
|
||||
tgid[16] = 0;
|
||||
talkgroup = (int) strtol (tgid, NULL, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
talkgroup = 0;
|
||||
}
|
||||
|
||||
fflush (opts->mbe_out_f);
|
||||
fclose (opts->mbe_out_f);
|
||||
opts->mbe_out_f = NULL;
|
||||
strftime (datestr, 31, "%Y-%m-%d-%H%M%S", &timep);
|
||||
sprintf (newfilename, "nac%X-%s-tg%i%s", state->nac, datestr, talkgroup, ext);
|
||||
sprintf (shell, "mv %s %s", opts->mbe_out_file, newfilename);
|
||||
result = system (shell);
|
||||
|
||||
state->tgcount = 0;
|
||||
for (i = 0; i < 25; i++)
|
||||
{
|
||||
for (j = 0; j < 16; j++)
|
||||
{
|
||||
state->tg[i][j] = 48;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
openMbeOutFile (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
struct timeval tv;
|
||||
int i, j;
|
||||
char ext[5];
|
||||
|
||||
if ((state->synctype == 0) || (state->synctype == 1) || (state->synctype == 14) || (state->synctype == 15))
|
||||
{
|
||||
sprintf (ext, ".imb");
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (ext, ".amb");
|
||||
}
|
||||
|
||||
// reset talkgroup id buffer
|
||||
for (i = 0; i < 12; i++)
|
||||
{
|
||||
for (j = 0; j < 25; j++)
|
||||
{
|
||||
state->tg[j][i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
state->tgcount = 0;
|
||||
|
||||
gettimeofday (&tv, NULL);
|
||||
sprintf (opts->mbe_out_file, "%i%s", (int) tv.tv_sec, ext);
|
||||
opts->mbe_out_f = fopen (opts->mbe_out_file, "w");
|
||||
if (opts->mbe_out_f == NULL)
|
||||
{
|
||||
printf ("Error, couldn't open %s\n", opts->mbe_out_file);
|
||||
}
|
||||
|
||||
// write magic
|
||||
fprintf (opts->mbe_out_f, "%s", ext);
|
||||
|
||||
fflush (opts->mbe_out_f);
|
||||
}
|
||||
|
||||
void
|
||||
openWavOutFile (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
opts->wav_out_f = fopen (opts->wav_out_file, "w");
|
||||
if (opts->wav_out_f == NULL)
|
||||
{
|
||||
printf ("Error - could not open wav output file %s\n", opts->wav_out_file);
|
||||
return;
|
||||
}
|
||||
opts->wav_out_fd = fileno (opts->wav_out_f);
|
||||
state->wav_out_bytes = 0;
|
||||
|
||||
fprintf (opts->wav_out_f, "RIFF");
|
||||
// total length
|
||||
fputc (0, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
|
||||
fprintf (opts->wav_out_f, "WAVE");
|
||||
fprintf (opts->wav_out_f, "fmt ");
|
||||
|
||||
// length of format chunk
|
||||
fputc (16, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
|
||||
// always 0x1
|
||||
fputc (1, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
|
||||
// channels
|
||||
fputc (1, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
|
||||
// sample rate
|
||||
fputc (64, opts->wav_out_f);
|
||||
fputc (31, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
|
||||
// bytes per second
|
||||
fputc (176, opts->wav_out_f);
|
||||
fputc (62, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
|
||||
// block align
|
||||
fputc (2, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
|
||||
// bits/sample
|
||||
fputc (16, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
|
||||
// data chunk header
|
||||
fprintf (opts->wav_out_f, "data");
|
||||
|
||||
// length of data
|
||||
fputc (0, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
|
||||
fflush (opts->wav_out_f);
|
||||
}
|
||||
|
||||
void
|
||||
closeWavOutFile (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
int length;
|
||||
|
||||
if (opts->wav_out_f != NULL)
|
||||
{
|
||||
rewind (opts->wav_out_f);
|
||||
length = state->wav_out_bytes;
|
||||
|
||||
fprintf (opts->wav_out_f, "RIFF");
|
||||
// total length
|
||||
fputc (((36 + length) & 0xff), opts->wav_out_f);
|
||||
fputc ((((36 + length) >> 8) & 0xff), opts->wav_out_f);
|
||||
fputc ((((36 + length) >> 16) & 0xff), opts->wav_out_f);
|
||||
fputc ((((36 + length) >> 24) & 0xff), opts->wav_out_f);
|
||||
|
||||
fprintf (opts->wav_out_f, "WAVE");
|
||||
fprintf (opts->wav_out_f, "fmt ");
|
||||
|
||||
// length of format chunk
|
||||
fputc (16, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
|
||||
// always 0x1
|
||||
fputc (1, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
|
||||
// channels
|
||||
fputc (1, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
|
||||
// sample rate
|
||||
fputc (64, opts->wav_out_f);
|
||||
fputc (31, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
|
||||
// bytes per second
|
||||
fputc (128, opts->wav_out_f);
|
||||
fputc (62, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
|
||||
// block align
|
||||
fputc (2, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
|
||||
// bits/sample
|
||||
fputc (16, opts->wav_out_f);
|
||||
fputc (0, opts->wav_out_f);
|
||||
|
||||
// data chunk header
|
||||
fprintf (opts->wav_out_f, "data");
|
||||
|
||||
// length of data
|
||||
fputc ((length & 0xff), opts->wav_out_f);
|
||||
fputc (((length >> 8) & 0xff), opts->wav_out_f);
|
||||
fputc (((length >> 16) & 0xff), opts->wav_out_f);
|
||||
fputc (((length >> 24) & 0xff), opts->wav_out_f);
|
||||
|
||||
fflush (opts->wav_out_f);
|
||||
}
|
||||
}
|
||||
448
dsd_frame.c
448
dsd_frame.c
@@ -1,448 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
void
|
||||
printFrameInfo (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
int level;
|
||||
|
||||
level = (int) (((float) state->max / (float) 32768) * (float) 100);
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
printf ("inlvl: %2i%% ", level);
|
||||
}
|
||||
if (state->nac != 0)
|
||||
{
|
||||
printf ("nac: %4X ", state->nac);
|
||||
}
|
||||
|
||||
if (opts->verbose > 1)
|
||||
{
|
||||
printf ("src: %8i ", state->lastsrc);
|
||||
}
|
||||
printf ("tg: %5i ", state->lasttg);
|
||||
}
|
||||
|
||||
void
|
||||
processFrame (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
int i, j, dibit;
|
||||
char duid[3];
|
||||
char nac[13];
|
||||
int level;
|
||||
|
||||
duid[2] = 0;
|
||||
j = 0;
|
||||
|
||||
if (state->rf_mod == 1)
|
||||
{
|
||||
state->maxref = (state->max * 0.80);
|
||||
state->minref = (state->min * 0.80);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->maxref = state->max;
|
||||
state->minref = state->min;
|
||||
}
|
||||
|
||||
if ((state->synctype == 8) || (state->synctype == 9))
|
||||
{
|
||||
state->rf_mod = 2;
|
||||
state->nac = 0;
|
||||
state->lastsrc = 0;
|
||||
state->lasttg = 0;
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
level = (int) (((float) state->max / (float) 32768) * (float) 100);
|
||||
printf ("inlvl: %2i%% ", level);
|
||||
}
|
||||
}
|
||||
state->nac = 0;
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
sprintf (state->fsubtype, " VOICE ");
|
||||
processNXDNVoice (opts, state);
|
||||
return;
|
||||
}
|
||||
else if ((state->synctype == 16) || (state->synctype == 17))
|
||||
{
|
||||
state->rf_mod = 2;
|
||||
state->nac = 0;
|
||||
state->lastsrc = 0;
|
||||
state->lasttg = 0;
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
level = (int) (((float) state->max / (float) 32768) * (float) 100);
|
||||
printf ("inlvl: %2i%% ", level);
|
||||
}
|
||||
}
|
||||
state->nac = 0;
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
sprintf (state->fsubtype, " DATA ");
|
||||
processNXDNData (opts, state);
|
||||
return;
|
||||
}
|
||||
else if ((state->synctype == 6) || (state->synctype == 7))
|
||||
{
|
||||
state->nac = 0;
|
||||
state->lastsrc = 0;
|
||||
state->lasttg = 0;
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
level = (int) (((float) state->max / (float) 32768) * (float) 100);
|
||||
printf ("inlvl: %2i%% ", level);
|
||||
}
|
||||
}
|
||||
state->nac = 0;
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
sprintf (state->fsubtype, " VOICE ");
|
||||
processDSTAR (opts, state);
|
||||
return;
|
||||
}
|
||||
else if ((state->synctype >= 10) && (state->synctype <= 13))
|
||||
{
|
||||
state->nac = 0;
|
||||
state->lastsrc = 0;
|
||||
state->lasttg = 0;
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
level = (int) (((float) state->max / (float) 32768) * (float) 100);
|
||||
printf ("inlvl: %2i%% ", level);
|
||||
}
|
||||
}
|
||||
if ((state->synctype == 11) || (state->synctype == 12))
|
||||
{
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
sprintf (state->fsubtype, " VOICE ");
|
||||
processDMRvoice (opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
closeMbeOutFile (opts, state);
|
||||
state->err_str[0] = 0;
|
||||
processDMRdata (opts, state);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if ((state->synctype >= 2) && (state->synctype <= 5))
|
||||
{
|
||||
state->nac = 0;
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
}
|
||||
if ((state->synctype == 3) || (state->synctype == 4))
|
||||
{
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
sprintf (state->fsubtype, " VOICE ");
|
||||
processX2TDMAvoice (opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
closeMbeOutFile (opts, state);
|
||||
state->err_str[0] = 0;
|
||||
processX2TDMAdata (opts, state);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if ((state->synctype == 14) || (state->synctype == 15))
|
||||
{
|
||||
state->nac = 0;
|
||||
state->lastsrc = 0;
|
||||
state->lasttg = 0;
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
level = (int) (((float) state->max / (float) 32768) * (float) 100);
|
||||
printf ("inlvl: %2i%% ", level);
|
||||
}
|
||||
}
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL))
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
sprintf (state->fsubtype, " VOICE ");
|
||||
processProVoice (opts, state);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
j = 0;
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
nac[j] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
j++;
|
||||
nac[j] = (1 & dibit) + 48; // bit 0
|
||||
j++;
|
||||
}
|
||||
nac[12] = 0;
|
||||
state->nac = strtol (nac, NULL, 2);
|
||||
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
duid[i] = getDibit (opts, state) + 48;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp (duid, "00") == 0)
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
printf (" HDU\n");
|
||||
}
|
||||
if (opts->mbe_out_dir[0] != 0)
|
||||
{
|
||||
closeMbeOutFile (opts, state);
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
|
||||
state->lastp25type = 2;
|
||||
sprintf (state->fsubtype, " HDU ");
|
||||
processHDU (opts, state);
|
||||
}
|
||||
else if (strcmp (duid, "11") == 0)
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
printf (" LDU1 ");
|
||||
}
|
||||
if (opts->mbe_out_dir[0] != 0)
|
||||
{
|
||||
if (opts->mbe_out_f == NULL)
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
}
|
||||
state->lastp25type = 1;
|
||||
sprintf (state->fsubtype, " LDU1 ");
|
||||
state->numtdulc = 0;
|
||||
processLDU1 (opts, state);
|
||||
}
|
||||
else if (strcmp (duid, "22") == 0)
|
||||
{
|
||||
if (state->lastp25type != 1)
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
printf (" Ignoring LDU2 not preceeded by LDU1\n");
|
||||
}
|
||||
state->lastp25type = 0;
|
||||
sprintf (state->fsubtype, " ");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
printf (" LDU2 ");
|
||||
}
|
||||
if (opts->mbe_out_dir[0] != 0)
|
||||
{
|
||||
if (opts->mbe_out_f == NULL)
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
}
|
||||
state->lastp25type = 2;
|
||||
sprintf (state->fsubtype, " LDU2 ");
|
||||
state->numtdulc = 0;
|
||||
processLDU2 (opts, state);
|
||||
}
|
||||
}
|
||||
else if (strcmp (duid, "33") == 0)
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
printf (" TDULC\n");
|
||||
}
|
||||
if (opts->mbe_out_dir[0] != 0)
|
||||
{
|
||||
closeMbeOutFile (opts, state);
|
||||
}
|
||||
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
|
||||
state->lasttg = 0;
|
||||
state->lastsrc = 0;
|
||||
state->lastp25type = 0;
|
||||
state->err_str[0] = 0;
|
||||
sprintf (state->fsubtype, " TDULC ");
|
||||
state->numtdulc++;
|
||||
if ((opts->resume > 0) && (state->numtdulc > opts->resume))
|
||||
{
|
||||
resumeScan (opts, state);
|
||||
}
|
||||
processTDULC (opts, state);
|
||||
state->err_str[0] = 0;
|
||||
}
|
||||
else if (strcmp (duid, "03") == 0)
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
printf (" TDU\n");
|
||||
}
|
||||
if (opts->mbe_out_dir[0] != 0)
|
||||
{
|
||||
closeMbeOutFile (opts, state);
|
||||
}
|
||||
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
|
||||
state->lasttg = 0;
|
||||
state->lastsrc = 0;
|
||||
state->lastp25type = 0;
|
||||
state->err_str[0] = 0;
|
||||
sprintf (state->fsubtype, " TDU ");
|
||||
skipDibit (opts, state, 40);
|
||||
}
|
||||
else if (strcmp (duid, "13") == 0)
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
printf (" TSDU\n");
|
||||
}
|
||||
if (opts->resume > 0)
|
||||
{
|
||||
resumeScan (opts, state);
|
||||
}
|
||||
state->lasttg = 0;
|
||||
state->lastsrc = 0;
|
||||
state->lastp25type = 3;
|
||||
sprintf (state->fsubtype, " TSDU ");
|
||||
skipDibit (opts, state, 328);
|
||||
}
|
||||
else if (strcmp (duid, "30") == 0)
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
printf (" PDU\n");
|
||||
}
|
||||
if (opts->resume > 0)
|
||||
{
|
||||
resumeScan (opts, state);
|
||||
}
|
||||
if (opts->mbe_out_dir[0] != 0)
|
||||
{
|
||||
if (opts->mbe_out_f == NULL)
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
}
|
||||
state->lastp25type = 4;
|
||||
sprintf (state->fsubtype, " PDU ");
|
||||
}
|
||||
// try to guess based on previous frame if unknown type
|
||||
else if (state->lastp25type == 1)
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
printf ("(LDU2) ");
|
||||
}
|
||||
if (opts->mbe_out_dir[0] != 0)
|
||||
{
|
||||
if (opts->mbe_out_f == NULL)
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
}
|
||||
state->lastp25type = 0;
|
||||
sprintf (state->fsubtype, "(LDU2) ");
|
||||
state->numtdulc = 0;
|
||||
processLDU2 (opts, state);
|
||||
}
|
||||
else if (state->lastp25type == 2)
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
printf ("(LDU1) ");
|
||||
}
|
||||
if (opts->mbe_out_dir[0] != 0)
|
||||
{
|
||||
if (opts->mbe_out_f == NULL)
|
||||
{
|
||||
openMbeOutFile (opts, state);
|
||||
}
|
||||
}
|
||||
state->lastp25type = 0;
|
||||
sprintf (state->fsubtype, "(LDU1) ");
|
||||
state->numtdulc = 0;
|
||||
processLDU1 (opts, state);
|
||||
}
|
||||
else if (state->lastp25type == 3)
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
printf (" (TSDU)\n");
|
||||
}
|
||||
state->lastp25type = 0;
|
||||
sprintf (state->fsubtype, "(TSDU) ");
|
||||
skipDibit (opts, state, 328);
|
||||
}
|
||||
else if (state->lastp25type == 4)
|
||||
{
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
printf (" (PDU)\n");
|
||||
}
|
||||
state->lastp25type = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->lastp25type = 0;
|
||||
sprintf (state->fsubtype, " ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameInfo (opts, state);
|
||||
printf (" duid:%s *Unknown DUID*\n", duid);
|
||||
}
|
||||
}
|
||||
}
|
||||
792
dsd_frame_sync.c
792
dsd_frame_sync.c
@@ -1,792 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
void
|
||||
printFrameSync (dsd_opts * opts, dsd_state * state, char *frametype, int offset, char *modulation)
|
||||
{
|
||||
|
||||
if (opts->verbose > 0)
|
||||
{
|
||||
printf ("Sync: %s ", frametype);
|
||||
}
|
||||
if (opts->verbose > 2)
|
||||
{
|
||||
printf ("o: %4i ", offset);
|
||||
}
|
||||
if (opts->verbose > 1)
|
||||
{
|
||||
printf ("mod: %s ", modulation);
|
||||
}
|
||||
if (opts->verbose > 2)
|
||||
{
|
||||
printf ("g: %f ", state->aout_gain);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
getFrameSync (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
/* detects frame sync and returns frame type
|
||||
* 0 = +P25p1
|
||||
* 1 = -P25p1
|
||||
* 2 = +X2-TDMA (non inverted signal data frame)
|
||||
* 3 = +X2-TDMA (inverted signal voice frame)
|
||||
* 4 = -X2-TDMA (non inverted signal voice frame)
|
||||
* 5 = -X2-TDMA (inverted signal data frame)
|
||||
* 6 = +D-STAR
|
||||
* 7 = -D-STAR
|
||||
* 8 = +NXDN (non inverted voice frame)
|
||||
* 9 = -NXDN (inverted voice frame)
|
||||
* 10 = +DMR (non inverted singlan data frame)
|
||||
* 11 = -DMR (inverted signal voice frame)
|
||||
* 12 = +DMR (non inverted signal voice frame)
|
||||
* 13 = -DMR (inverted signal data frame)
|
||||
* 14 = +ProVoice
|
||||
* 15 = -ProVoice
|
||||
* 16 = +NXDN (non inverted data frame)
|
||||
* 17 = -NXDN (inverted data frame)
|
||||
*/
|
||||
|
||||
int i, j, t, o, dibit, sync, symbol, synctest_pos, lastt;
|
||||
char synctest[25];
|
||||
char synctest18[19];
|
||||
char synctest32[33];
|
||||
char modulation[8];
|
||||
char *synctest_p;
|
||||
char synctest_buf[10240];
|
||||
int lmin, lmax, lidx;
|
||||
int lbuf[24], lbuf2[24];
|
||||
int lsum;
|
||||
char spectrum[64];
|
||||
|
||||
for (i = 18; i < 24; i++)
|
||||
{
|
||||
lbuf[i] = 0;
|
||||
lbuf2[i] = 0;
|
||||
}
|
||||
|
||||
// detect frame sync
|
||||
t = 0;
|
||||
synctest[24] = 0;
|
||||
synctest18[18] = 0;
|
||||
synctest32[32] = 0;
|
||||
synctest_pos = 0;
|
||||
synctest_p = synctest_buf + 10;
|
||||
sync = 0;
|
||||
lmin = 0;
|
||||
lmax = 0;
|
||||
lidx = 0;
|
||||
lastt = 0;
|
||||
state->numflips = 0;
|
||||
if ((opts->symboltiming == 1) && (state->carrier == 1))
|
||||
{
|
||||
printf ("\nSymbol Timing:\n");
|
||||
}
|
||||
while (sync == 0)
|
||||
{
|
||||
t++;
|
||||
symbol = getSymbol (opts, state, 0);
|
||||
lbuf[lidx] = symbol;
|
||||
state->sbuf[state->sidx] = symbol;
|
||||
if (lidx == 23)
|
||||
{
|
||||
lidx = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lidx++;
|
||||
}
|
||||
if (state->sidx == (opts->ssize - 1))
|
||||
{
|
||||
state->sidx = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->sidx++;
|
||||
}
|
||||
|
||||
if (lastt == 23)
|
||||
{
|
||||
lastt = 0;
|
||||
if (state->numflips > opts->mod_threshold)
|
||||
{
|
||||
if (opts->mod_qpsk == 1)
|
||||
{
|
||||
state->rf_mod = 1;
|
||||
}
|
||||
}
|
||||
else if (state->numflips > 18)
|
||||
{
|
||||
if (opts->mod_gfsk == 1)
|
||||
{
|
||||
state->rf_mod = 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (opts->mod_c4fm == 1)
|
||||
{
|
||||
state->rf_mod = 0;
|
||||
}
|
||||
}
|
||||
state->numflips = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastt++;
|
||||
}
|
||||
|
||||
//determine dibit state
|
||||
if (symbol > 0)
|
||||
{
|
||||
*state->dibit_buf_p = 1;
|
||||
state->dibit_buf_p++;
|
||||
dibit = 49;
|
||||
}
|
||||
else
|
||||
{
|
||||
*state->dibit_buf_p = 3;
|
||||
state->dibit_buf_p++;
|
||||
dibit = 51;
|
||||
}
|
||||
|
||||
*synctest_p = dibit;
|
||||
if (t >= 18)
|
||||
{
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
lbuf2[i] = lbuf[i];
|
||||
}
|
||||
qsort (lbuf2, 24, sizeof (int), comp);
|
||||
lmin = (lbuf2[2] + lbuf2[3] + lbuf2[4]) / 3;
|
||||
lmax = (lbuf2[21] + lbuf2[20] + lbuf2[19]) / 3;
|
||||
|
||||
if (state->rf_mod == 1)
|
||||
{
|
||||
state->minbuf[state->midx] = lmin;
|
||||
state->maxbuf[state->midx] = lmax;
|
||||
if (state->midx == (opts->msize - 1))
|
||||
{
|
||||
state->midx = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
state->midx++;
|
||||
}
|
||||
lsum = 0;
|
||||
for (i = 0; i < opts->msize; i++)
|
||||
{
|
||||
lsum += state->minbuf[i];
|
||||
}
|
||||
state->min = lsum / opts->msize;
|
||||
lsum = 0;
|
||||
for (i = 0; i < opts->msize; i++)
|
||||
{
|
||||
lsum += state->maxbuf[i];
|
||||
}
|
||||
state->max = lsum / opts->msize;
|
||||
state->center = ((state->max) + (state->min)) / 2;
|
||||
state->maxref = ((state->max) * 0.80);
|
||||
state->minref = ((state->min) * 0.80);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->maxref = state->max;
|
||||
state->minref = state->min;
|
||||
}
|
||||
|
||||
if (state->rf_mod == 0)
|
||||
{
|
||||
sprintf (modulation, "C4FM");
|
||||
}
|
||||
else if (state->rf_mod == 1)
|
||||
{
|
||||
sprintf (modulation, "QPSK");
|
||||
}
|
||||
else if (state->rf_mod == 2)
|
||||
{
|
||||
sprintf (modulation, "GFSK");
|
||||
}
|
||||
|
||||
if (opts->datascope == 1)
|
||||
{
|
||||
if (lidx == 0)
|
||||
{
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
spectrum[i] = 0;
|
||||
}
|
||||
for (i = 0; i < 24; i++)
|
||||
{
|
||||
o = (lbuf2[i] + 32768) / 1024;
|
||||
spectrum[o]++;
|
||||
}
|
||||
if (state->symbolcnt > (4800 / opts->scoperate))
|
||||
{
|
||||
state->symbolcnt = 0;
|
||||
printf ("\n");
|
||||
printf ("Demod mode: %s Nac: %4X\n", modulation, state->nac);
|
||||
printf ("Frame Type: %s Talkgroup: %7i\n", state->ftype, state->lasttg);
|
||||
printf ("Frame Subtype: %s Source: %12i\n", state->fsubtype, state->lastsrc);
|
||||
printf ("TDMA activity: %s %s Voice errors: %s\n", state->slot0light, state->slot1light, state->err_str);
|
||||
printf ("+----------------------------------------------------------------+\n");
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
printf ("|");
|
||||
for (j = 0; j < 64; j++)
|
||||
{
|
||||
if (i == 0)
|
||||
{
|
||||
if ((j == ((state->min) + 32768) / 1024) || (j == ((state->max) + 32768) / 1024))
|
||||
{
|
||||
printf ("#");
|
||||
}
|
||||
else if (j == (state->center + 32768) / 1024)
|
||||
{
|
||||
printf ("!");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (j == 32)
|
||||
{
|
||||
printf ("|");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf (" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (spectrum[j] > 9 - i)
|
||||
{
|
||||
printf ("*");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (j == 32)
|
||||
{
|
||||
printf ("|");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf (" ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
printf ("|\n");
|
||||
}
|
||||
printf ("+----------------------------------------------------------------+\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strncpy (synctest, (synctest_p - 23), 24);
|
||||
if (opts->frame_p25p1 == 1)
|
||||
{
|
||||
if (strcmp (synctest, P25P1_SYNC) == 0)
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
sprintf (state->ftype, " P25 Phase 1 ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " +P25p1 ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 0;
|
||||
return (0);
|
||||
}
|
||||
if (strcmp (synctest, INV_P25P1_SYNC) == 0)
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
sprintf (state->ftype, " P25 Phase 1 ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " -P25p1 ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 1;
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
if (opts->frame_x2tdma == 1)
|
||||
{
|
||||
if ((strcmp (synctest, X2TDMA_BS_DATA_SYNC) == 0) || (strcmp (synctest, X2TDMA_MS_DATA_SYNC) == 0))
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + (lmax)) / 2;
|
||||
state->min = ((state->min) + (lmin)) / 2;
|
||||
if (opts->inverted_x2tdma == 0)
|
||||
{
|
||||
// data frame
|
||||
sprintf (state->ftype, " X2-TDMA ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " +X2-TDMA ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 2;
|
||||
return (2);
|
||||
}
|
||||
else
|
||||
{
|
||||
// inverted voice frame
|
||||
sprintf (state->ftype, " X2-TDMA ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " -X2-TDMA ", synctest_pos + 1, modulation);
|
||||
}
|
||||
if (state->lastsynctype != 3)
|
||||
{
|
||||
state->firstframe = 1;
|
||||
}
|
||||
state->lastsynctype = 3;
|
||||
return (3);
|
||||
}
|
||||
}
|
||||
if ((strcmp (synctest, X2TDMA_BS_VOICE_SYNC) == 0) || (strcmp (synctest, X2TDMA_MS_VOICE_SYNC) == 0))
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
if (opts->inverted_x2tdma == 0)
|
||||
{
|
||||
// voice frame
|
||||
sprintf (state->ftype, " X2-TDMA ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " +X2-TDMA ", synctest_pos + 1, modulation);
|
||||
}
|
||||
if (state->lastsynctype != 4)
|
||||
{
|
||||
state->firstframe = 1;
|
||||
}
|
||||
state->lastsynctype = 4;
|
||||
return (4);
|
||||
}
|
||||
else
|
||||
{
|
||||
// inverted data frame
|
||||
sprintf (state->ftype, " X2-TDMA ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " -X2-TDMA ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 5;
|
||||
return (5);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opts->frame_dmr == 1)
|
||||
{
|
||||
if ((strcmp (synctest, DMR_MS_DATA_SYNC) == 0) || (strcmp (synctest, DMR_BS_DATA_SYNC) == 0))
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + (lmax)) / 2;
|
||||
state->min = ((state->min) + (lmin)) / 2;
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
// data frame
|
||||
sprintf (state->ftype, " DMR ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " +DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 10;
|
||||
return (10);
|
||||
}
|
||||
else
|
||||
{
|
||||
// inverted voice frame
|
||||
sprintf (state->ftype, " DMR ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " -DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
if (state->lastsynctype != 11)
|
||||
{
|
||||
state->firstframe = 1;
|
||||
}
|
||||
state->lastsynctype = 11;
|
||||
return (11);
|
||||
}
|
||||
}
|
||||
if ((strcmp (synctest, DMR_MS_VOICE_SYNC) == 0) || (strcmp (synctest, DMR_BS_VOICE_SYNC) == 0))
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
// voice frame
|
||||
sprintf (state->ftype, " DMR ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " +DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
if (state->lastsynctype != 12)
|
||||
{
|
||||
state->firstframe = 1;
|
||||
}
|
||||
state->lastsynctype = 12;
|
||||
return (12);
|
||||
}
|
||||
else
|
||||
{
|
||||
// inverted data frame
|
||||
sprintf (state->ftype, " DMR ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " -DMR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 13;
|
||||
return (13);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opts->frame_provoice == 1)
|
||||
{
|
||||
strncpy (synctest32, (synctest_p - 31), 32);
|
||||
if ((strcmp (synctest32, PROVOICE_SYNC) == 0) || (strcmp (synctest32, PROVOICE_EA_SYNC) == 0))
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
sprintf (state->ftype, " ProVoice ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " -ProVoice ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 14;
|
||||
return (14);
|
||||
}
|
||||
else if ((strcmp (synctest32, INV_PROVOICE_SYNC) == 0) || (strcmp (synctest32, INV_PROVOICE_EA_SYNC) == 0))
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
sprintf (state->ftype, " ProVoice ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " -ProVoice ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 15;
|
||||
return (15);
|
||||
}
|
||||
|
||||
}
|
||||
if ((opts->frame_nxdn96 == 1) || (opts->frame_nxdn48 == 1))
|
||||
{
|
||||
strncpy (synctest18, (synctest_p - 17), 18);
|
||||
if ((strcmp (synctest18, NXDN_BS_VOICE_SYNC) == 0) || (strcmp (synctest18, NXDN_MS_VOICE_SYNC) == 0))
|
||||
{
|
||||
if ((state->lastsynctype == 8) || (state->lastsynctype == 16))
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
if (state->samplesPerSymbol == 20)
|
||||
{
|
||||
sprintf (state->ftype, " NXDN48 ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " +NXDN48 ", synctest_pos + 1, modulation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (state->ftype, " NXDN96 ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " +NXDN96 ", synctest_pos + 1, modulation);
|
||||
}
|
||||
}
|
||||
state->lastsynctype = 8;
|
||||
return (8);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->lastsynctype = 8;
|
||||
}
|
||||
}
|
||||
else if ((strcmp (synctest18, INV_NXDN_BS_VOICE_SYNC) == 0) || (strcmp (synctest18, INV_NXDN_MS_VOICE_SYNC) == 0))
|
||||
{
|
||||
if ((state->lastsynctype == 9) || (state->lastsynctype == 17))
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
if (state->samplesPerSymbol == 20)
|
||||
{
|
||||
sprintf (state->ftype, " NXDN48 ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " -NXDN48 ", synctest_pos + 1, modulation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (state->ftype, " NXDN96 ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " -NXDN96 ", synctest_pos + 1, modulation);
|
||||
}
|
||||
}
|
||||
state->lastsynctype = 9;
|
||||
return (9);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->lastsynctype = 9;
|
||||
}
|
||||
}
|
||||
else if ((strcmp (synctest18, NXDN_BS_DATA_SYNC) == 0) || (strcmp (synctest18, NXDN_MS_DATA_SYNC) == 0))
|
||||
{
|
||||
if ((state->lastsynctype == 8) || (state->lastsynctype == 16))
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
if (state->samplesPerSymbol == 20)
|
||||
{
|
||||
sprintf (state->ftype, " NXDN48 ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " +NXDN48 ", synctest_pos + 1, modulation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (state->ftype, " NXDN96 ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " +NXDN96 ", synctest_pos + 1, modulation);
|
||||
}
|
||||
}
|
||||
state->lastsynctype = 16;
|
||||
return (16);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->lastsynctype = 16;
|
||||
}
|
||||
}
|
||||
else if ((strcmp (synctest18, INV_NXDN_BS_DATA_SYNC) == 0) || (strcmp (synctest18, INV_NXDN_MS_DATA_SYNC) == 0))
|
||||
{
|
||||
if ((state->lastsynctype == 9) || (state->lastsynctype == 17))
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
sprintf (state->ftype, " NXDN ");
|
||||
if (state->samplesPerSymbol == 20)
|
||||
{
|
||||
sprintf (state->ftype, " NXDN48 ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " -NXDN48 ", synctest_pos + 1, modulation);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (state->ftype, " NXDN96 ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " -NXDN96 ", synctest_pos + 1, modulation);
|
||||
}
|
||||
}
|
||||
state->lastsynctype = 17;
|
||||
return (17);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->lastsynctype = 17;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opts->frame_dstar == 1)
|
||||
{
|
||||
if (strcmp (synctest, DSTAR_SYNC) == 0)
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
sprintf (state->ftype, " D-STAR ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " +D-STAR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 6;
|
||||
return (6);
|
||||
}
|
||||
if (strcmp (synctest, INV_DSTAR_SYNC) == 0)
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
sprintf (state->ftype, " D-STAR ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, " -D-STAR ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = 7;
|
||||
return (7);
|
||||
}
|
||||
}
|
||||
|
||||
if ((t == 24) && (state->lastsynctype != -1))
|
||||
{
|
||||
if ((state->lastsynctype == 0) && ((state->lastp25type == 1) || (state->lastp25type == 2)))
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + (lmax)) / 2;
|
||||
state->min = ((state->min) + (lmin)) / 2;
|
||||
sprintf (state->ftype, "(P25 Phase 1)");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, "(+P25p1) ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = -1;
|
||||
return (0);
|
||||
}
|
||||
else if ((state->lastsynctype == 1) && ((state->lastp25type == 1) || (state->lastp25type == 2)))
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
sprintf (state->ftype, "(P25 Phase 1)");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, "(-P25p1) ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = -1;
|
||||
return (1);
|
||||
}
|
||||
else if ((state->lastsynctype == 3) && ((strcmp (synctest, X2TDMA_BS_VOICE_SYNC) != 0) || (strcmp (synctest, X2TDMA_MS_VOICE_SYNC) != 0)))
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
sprintf (state->ftype, "(X2-TDMA) ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, "(-X2-TDMA) ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = -1;
|
||||
return (3);
|
||||
}
|
||||
else if ((state->lastsynctype == 4) && ((strcmp (synctest, X2TDMA_BS_DATA_SYNC) != 0) || (strcmp (synctest, X2TDMA_MS_DATA_SYNC) != 0)))
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
sprintf (state->ftype, "(X2-TDMA) ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, "(+X2-TDMA) ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = -1;
|
||||
return (4);
|
||||
}
|
||||
else if ((state->lastsynctype == 11) && ((strcmp (synctest, DMR_BS_VOICE_SYNC) != 0) || (strcmp (synctest, DMR_MS_VOICE_SYNC) != 0)))
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
sprintf (state->ftype, "(DMR) ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, "(-DMR) ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = -1;
|
||||
return (11);
|
||||
}
|
||||
else if ((state->lastsynctype == 12) && ((strcmp (synctest, DMR_BS_DATA_SYNC) != 0) || (strcmp (synctest, DMR_MS_DATA_SYNC) != 0)))
|
||||
{
|
||||
state->carrier = 1;
|
||||
state->offset = synctest_pos;
|
||||
state->max = ((state->max) + lmax) / 2;
|
||||
state->min = ((state->min) + lmin) / 2;
|
||||
sprintf (state->ftype, "(DMR) ");
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printFrameSync (opts, state, "(+DMR) ", synctest_pos + 1, modulation);
|
||||
}
|
||||
state->lastsynctype = -1;
|
||||
return (12);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (exitflag == 1)
|
||||
{
|
||||
cleanupAndExit (opts, state);
|
||||
}
|
||||
|
||||
if (synctest_pos < 10200)
|
||||
{
|
||||
synctest_pos++;
|
||||
synctest_p++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// buffer reset
|
||||
synctest_pos = 0;
|
||||
synctest_p = synctest_buf;
|
||||
noCarrier (opts, state);
|
||||
}
|
||||
|
||||
if (state->lastsynctype != 1)
|
||||
{
|
||||
if (synctest_pos >= 1800)
|
||||
{
|
||||
if ((opts->errorbars == 1) && (opts->verbose > 1) && (state->carrier == 1))
|
||||
{
|
||||
printf ("Sync: no sync\n");
|
||||
}
|
||||
noCarrier (opts, state);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
697
dsd_main.c
697
dsd_main.c
@@ -1,697 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#define _MAIN
|
||||
|
||||
#include "dsd.h"
|
||||
#include "p25p1_const.h"
|
||||
#include "x2tdma_const.h"
|
||||
#include "dstar_const.h"
|
||||
#include "nxdn_const.h"
|
||||
#include "dmr_const.h"
|
||||
#include "provoice_const.h"
|
||||
|
||||
int
|
||||
comp (const void *a, const void *b)
|
||||
{
|
||||
if (*((const int *) a) == *((const int *) b))
|
||||
return 0;
|
||||
else if (*((const int *) a) < *((const int *) b))
|
||||
return -1;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
state->dibit_buf_p = state->dibit_buf + 200;
|
||||
memset (state->dibit_buf, 0, sizeof (int) * 200);
|
||||
if (opts->mbe_out_f != NULL)
|
||||
{
|
||||
closeMbeOutFile (opts, state);
|
||||
}
|
||||
state->jitter = -1;
|
||||
state->lastsynctype = -1;
|
||||
state->carrier = 0;
|
||||
state->max = 15000;
|
||||
state->min = -15000;
|
||||
state->center = 0;
|
||||
state->err_str[0] = 0;
|
||||
sprintf (state->fsubtype, " ");
|
||||
sprintf (state->ftype, " ");
|
||||
state->errs = 0;
|
||||
state->errs2 = 0;
|
||||
state->lasttg = 0;
|
||||
state->lastsrc = 0;
|
||||
state->lastp25type = 0;
|
||||
state->repeat = 0;
|
||||
state->nac = 0;
|
||||
state->numtdulc = 0;
|
||||
sprintf (state->slot0light, " slot0 ");
|
||||
sprintf (state->slot1light, " slot1 ");
|
||||
state->firstframe = 0;
|
||||
if (opts->audio_gain == (float) 0)
|
||||
{
|
||||
state->aout_gain = 25;
|
||||
}
|
||||
memset (state->aout_max_buf, 0, sizeof (float) * 200);
|
||||
state->aout_max_buf_p = state->aout_max_buf;
|
||||
state->aout_max_buf_idx = 0;
|
||||
sprintf (state->algid, "________");
|
||||
sprintf (state->keyid, "________________");
|
||||
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
|
||||
}
|
||||
|
||||
void
|
||||
initOpts (dsd_opts * opts)
|
||||
{
|
||||
|
||||
opts->onesymbol = 10;
|
||||
opts->mbe_in_file[0] = 0;
|
||||
opts->mbe_in_f = NULL;
|
||||
opts->errorbars = 1;
|
||||
opts->datascope = 0;
|
||||
opts->symboltiming = 0;
|
||||
opts->verbose = 2;
|
||||
opts->p25enc = 0;
|
||||
opts->p25lc = 0;
|
||||
opts->p25status = 0;
|
||||
opts->p25tg = 0;
|
||||
opts->scoperate = 15;
|
||||
sprintf (opts->audio_in_dev, "/dev/audio");
|
||||
opts->audio_in_fd = -1;
|
||||
sprintf (opts->audio_out_dev, "/dev/audio");
|
||||
opts->audio_out_fd = -1;
|
||||
opts->split = 0;
|
||||
opts->playoffset = 0;
|
||||
opts->mbe_out_dir[0] = 0;
|
||||
opts->mbe_out_file[0] = 0;
|
||||
opts->mbe_out_f = NULL;
|
||||
opts->audio_gain = 0;
|
||||
opts->audio_out = 1;
|
||||
opts->wav_out_file[0] = 0;
|
||||
opts->wav_out_f = NULL;
|
||||
opts->wav_out_fd = -1;
|
||||
opts->serial_baud = 115200;
|
||||
sprintf (opts->serial_dev, "/dev/ttyUSB0");
|
||||
opts->resume = 0;
|
||||
opts->frame_dstar = 0;
|
||||
opts->frame_x2tdma = 1;
|
||||
opts->frame_p25p1 = 1;
|
||||
opts->frame_nxdn48 = 0;
|
||||
opts->frame_nxdn96 = 1;
|
||||
opts->frame_dmr = 1;
|
||||
opts->frame_provoice = 0;
|
||||
opts->mod_c4fm = 1;
|
||||
opts->mod_qpsk = 1;
|
||||
opts->mod_gfsk = 1;
|
||||
opts->uvquality = 3;
|
||||
opts->inverted_x2tdma = 1; // most transmitter + scanner + sound card combinations show inverted signals for this
|
||||
opts->inverted_dmr = 0; // most transmitter + scanner + sound card combinations show non-inverted signals for this
|
||||
opts->mod_threshold = 26;
|
||||
opts->ssize = 36;
|
||||
opts->msize = 15;
|
||||
opts->playfiles = 0;
|
||||
opts->delay = 0;
|
||||
}
|
||||
|
||||
void
|
||||
initState (dsd_state * state)
|
||||
{
|
||||
|
||||
int i, j;
|
||||
|
||||
state->dibit_buf = malloc (sizeof (int) * 1000000);
|
||||
state->dibit_buf_p = state->dibit_buf + 200;
|
||||
memset (state->dibit_buf, 0, sizeof (int) * 200);
|
||||
state->repeat = 0;
|
||||
state->audio_out_buf = malloc (sizeof (short) * 1000000);
|
||||
memset (state->audio_out_buf, 0, 100 * sizeof (short));
|
||||
state->audio_out_buf_p = state->audio_out_buf + 100;
|
||||
state->audio_out_float_buf = malloc (sizeof (float) * 1000000);
|
||||
memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
|
||||
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
||||
state->audio_out_idx = 0;
|
||||
state->audio_out_idx2 = 0;
|
||||
state->audio_out_temp_buf_p = state->audio_out_temp_buf;
|
||||
state->wav_out_bytes = 0;
|
||||
state->center = 0;
|
||||
state->jitter = -1;
|
||||
state->synctype = -1;
|
||||
state->min = -15000;
|
||||
state->max = 15000;
|
||||
state->lmid = 0;
|
||||
state->umid = 0;
|
||||
state->minref = -12000;
|
||||
state->maxref = 12000;
|
||||
state->lastsample = 0;
|
||||
for (i = 0; i < 128; i++)
|
||||
{
|
||||
state->sbuf[i] = 0;
|
||||
}
|
||||
state->sidx = 0;
|
||||
for (i = 0; i < 1024; i++)
|
||||
{
|
||||
state->maxbuf[i] = 15000;
|
||||
}
|
||||
for (i = 0; i < 1024; i++)
|
||||
{
|
||||
state->minbuf[i] = -15000;
|
||||
}
|
||||
state->midx = 0;
|
||||
state->err_str[0] = 0;
|
||||
sprintf (state->fsubtype, " ");
|
||||
sprintf (state->ftype, " ");
|
||||
state->symbolcnt = 0;
|
||||
state->rf_mod = 0;
|
||||
state->numflips = 0;
|
||||
state->lastsynctype = -1;
|
||||
state->lastp25type = 0;
|
||||
state->offset = 0;
|
||||
state->carrier = 0;
|
||||
for (i = 0; i < 25; i++)
|
||||
{
|
||||
for (j = 0; j < 16; j++)
|
||||
{
|
||||
state->tg[i][j] = 48;
|
||||
}
|
||||
}
|
||||
state->tgcount = 0;
|
||||
state->lasttg = 0;
|
||||
state->lastsrc = 0;
|
||||
state->nac = 0;
|
||||
state->errs = 0;
|
||||
state->errs2 = 0;
|
||||
state->mbe_file_type = -1;
|
||||
state->optind = 0;
|
||||
state->numtdulc = 0;
|
||||
state->firstframe = 0;
|
||||
sprintf (state->slot0light, " slot0 ");
|
||||
sprintf (state->slot1light, " slot1 ");
|
||||
state->aout_gain = 25;
|
||||
memset (state->aout_max_buf, 0, sizeof (float) * 200);
|
||||
state->aout_max_buf_p = state->aout_max_buf;
|
||||
state->aout_max_buf_idx = 0;
|
||||
state->samplesPerSymbol = 10;
|
||||
state->symbolCenter = 4;
|
||||
sprintf (state->algid, "________");
|
||||
sprintf (state->keyid, "________________");
|
||||
state->currentslot = 0;
|
||||
state->cur_mp = malloc (sizeof (mbe_parms));
|
||||
state->prev_mp = malloc (sizeof (mbe_parms));
|
||||
state->prev_mp_enhanced = malloc (sizeof (mbe_parms));
|
||||
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
|
||||
}
|
||||
|
||||
void
|
||||
usage ()
|
||||
{
|
||||
printf ("\n");
|
||||
printf ("Usage:\n");
|
||||
printf (" dsd [options] Live scanner mode\n");
|
||||
printf (" dsd [options] -r <files> Read/Play saved mbe data from file(s)\n");
|
||||
printf (" dsd -h Show help\n");
|
||||
printf ("\n");
|
||||
printf ("Display Options:\n");
|
||||
printf (" -e Show Frame Info and errorbars (default)\n");
|
||||
printf (" -pe Show P25 encryption sync bits\n");
|
||||
printf (" -pl Show P25 link control bits\n");
|
||||
printf (" -ps Show P25 status bits and low speed data\n");
|
||||
printf (" -pt Show P25 talkgroup info\n");
|
||||
printf (" -q Don't show Frame Info/errorbars\n");
|
||||
printf (" -s Datascope (disables other display options)\n");
|
||||
printf (" -t Show symbol timing during sync\n");
|
||||
printf (" -v <num> Frame information Verbosity\n");
|
||||
printf (" -z <num> Frame rate for datascope\n");
|
||||
printf ("\n");
|
||||
printf ("Input/Output options:\n");
|
||||
printf (" -i <device> Audio input device (default is /dev/audio)\n");
|
||||
printf (" -o <device> Audio output device (default is /dev/audio)\n");
|
||||
printf (" -d <dir> Create mbe data files, use this directory\n");
|
||||
printf (" -g <num> Audio output gain (default = 0 = auto)\n");
|
||||
printf (" -n Do not send synthesized speech to audio output device\n");
|
||||
printf (" -w <file> Output synthesized speech to a .wav file\n");
|
||||
printf ("\n");
|
||||
printf ("Scanner control options:\n");
|
||||
printf (" -B <num> Serial port baud rate (default=115200)\n");
|
||||
printf (" -C <device> Serial port for scanner control (default=/dev/ttyUSB0)\n");
|
||||
printf (" -R <num> Resume scan after <num> TDULC frames or any PDU or TSDU\n");
|
||||
printf ("\n");
|
||||
printf ("Decoder options:\n");
|
||||
printf (" -fa Auto-detect frame type (default)\n");
|
||||
printf (" -f1 Decode only P25 Phase 1\n");
|
||||
printf (" -fd Decode only D-STAR* (no audio)\n");
|
||||
printf (" -fi Decode only NXDN48* (6.25 kHz) / IDAS*\n");
|
||||
printf (" -fn Decode only NXDN96 (12.5 kHz)\n");
|
||||
printf (" -fp Decode only ProVoice*\n");
|
||||
printf (" -fr Decode only DMR/MOTOTRBO\n");
|
||||
printf (" -fx Decode only X2-TDMA\n");
|
||||
printf (" -ma Auto-select modulation optimizations (default)\n");
|
||||
printf (" -mc Use only C4FM modulation optimizations\n");
|
||||
printf (" -mg Use only GFSK modulation optimizations\n");
|
||||
printf (" -mq Use only QPSK modulation optimizations\n");
|
||||
printf (" -u <num> Unvoiced speech quality (default=3)\n");
|
||||
printf (" -xx Expect non-inverted X2-TDMA signal\n");
|
||||
printf (" -xr Expect inverted DMR/MOTOTRBO signal\n");
|
||||
printf ("\n");
|
||||
printf (" * denotes frame types that cannot be auto-detected.\n");
|
||||
printf ("\n");
|
||||
printf ("Advanced decoder options:\n");
|
||||
printf (" -A <num> QPSK modulation auto detection threshold (default=26)\n");
|
||||
printf (" -S <num> Symbol buffer size for QPSK decision point tracking\n");
|
||||
printf (" (default=36)\n");
|
||||
printf (" -M <num> Min/Max buffer size for QPSK decision point tracking\n");
|
||||
printf (" (default=15)\n");
|
||||
exit (0);
|
||||
}
|
||||
|
||||
void
|
||||
liveScanner (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
noCarrier (opts, state);
|
||||
state->synctype = getFrameSync (opts, state);
|
||||
// recalibrate center/umid/lmid
|
||||
state->center = ((state->max) + (state->min)) / 2;
|
||||
state->umid = (((state->max) - state->center) * 5 / 8) + state->center;
|
||||
state->lmid = (((state->min) - state->center) * 5 / 8) + state->center;
|
||||
while (state->synctype != -1)
|
||||
{
|
||||
processFrame (opts, state);
|
||||
state->synctype = getFrameSync (opts, state);
|
||||
// recalibrate center/umid/lmid
|
||||
state->center = ((state->max) + (state->min)) / 2;
|
||||
state->umid = (((state->max) - state->center) * 5 / 8) + state->center;
|
||||
state->lmid = (((state->min) - state->center) * 5 / 8) + state->center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cleanupAndExit (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
noCarrier (opts, state);
|
||||
if (opts->wav_out_f != NULL)
|
||||
{
|
||||
closeWavOutFile (opts, state);
|
||||
}
|
||||
printf ("Exiting.\n");
|
||||
exit (0);
|
||||
}
|
||||
|
||||
void
|
||||
sigfun (int sig)
|
||||
{
|
||||
exitflag = 1;
|
||||
signal (SIGINT, SIG_DFL);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
|
||||
int c;
|
||||
extern char *optarg;
|
||||
extern int optind, opterr, optopt;
|
||||
dsd_opts opts;
|
||||
dsd_state state;
|
||||
char versionstr[25];
|
||||
mbe_printVersion (versionstr);
|
||||
|
||||
printf ("Digital Speech Decoder 1.4.1\n");
|
||||
printf ("mbelib version %s\n", versionstr);
|
||||
|
||||
initOpts (&opts);
|
||||
initState (&state);
|
||||
|
||||
exitflag = 0;
|
||||
signal (SIGINT, sigfun);
|
||||
|
||||
while ((c = getopt (argc, argv, "hep:qstv:z:i:o:d:g:nw:B:C:R:f:m:u:x:A:S:M:r")) != -1)
|
||||
{
|
||||
opterr = 0;
|
||||
switch (c)
|
||||
{
|
||||
case 'h':
|
||||
usage ();
|
||||
exit (0);
|
||||
case 'e':
|
||||
opts.errorbars = 1;
|
||||
opts.datascope = 0;
|
||||
break;
|
||||
case 'p':
|
||||
if (optarg[0] == 'e')
|
||||
{
|
||||
opts.p25enc = 1;
|
||||
}
|
||||
else if (optarg[0] == 'l')
|
||||
{
|
||||
opts.p25lc = 1;
|
||||
}
|
||||
else if (optarg[0] == 's')
|
||||
{
|
||||
opts.p25status = 1;
|
||||
}
|
||||
else if (optarg[0] == 't')
|
||||
{
|
||||
opts.p25tg = 1;
|
||||
}
|
||||
break;
|
||||
case 'q':
|
||||
opts.errorbars = 0;
|
||||
opts.verbose = 0;
|
||||
break;
|
||||
case 's':
|
||||
opts.errorbars = 0;
|
||||
opts.p25enc = 0;
|
||||
opts.p25lc = 0;
|
||||
opts.p25status = 0;
|
||||
opts.p25tg = 0;
|
||||
opts.datascope = 1;
|
||||
opts.symboltiming = 0;
|
||||
break;
|
||||
case 't':
|
||||
opts.symboltiming = 1;
|
||||
opts.errorbars = 1;
|
||||
opts.datascope = 0;
|
||||
break;
|
||||
case 'v':
|
||||
sscanf (optarg, "%d", &opts.verbose);
|
||||
break;
|
||||
case 'z':
|
||||
sscanf (optarg, "%d", &opts.scoperate);
|
||||
opts.errorbars = 0;
|
||||
opts.p25enc = 0;
|
||||
opts.p25lc = 0;
|
||||
opts.p25status = 0;
|
||||
opts.p25tg = 0;
|
||||
opts.datascope = 1;
|
||||
opts.symboltiming = 0;
|
||||
printf ("Setting datascope frame rate to %i frame per second.\n", opts.scoperate);
|
||||
break;
|
||||
case 'i':
|
||||
sscanf (optarg, "%s", opts.audio_in_dev);
|
||||
break;
|
||||
case 'o':
|
||||
sscanf (optarg, "%s", opts.audio_out_dev);
|
||||
break;
|
||||
case 'd':
|
||||
sscanf (optarg, "%s", opts.mbe_out_dir);
|
||||
printf ("Writing mbe data files to directory %s\n", opts.mbe_out_dir);
|
||||
break;
|
||||
case 'g':
|
||||
sscanf (optarg, "%f", &opts.audio_gain);
|
||||
if (opts.audio_gain <= (float) 0)
|
||||
{
|
||||
opts.audio_gain = (float) 0;
|
||||
printf ("Enabling audio out auto-gain\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("Setting audio out gain to %f\n", opts.audio_gain);
|
||||
state.aout_gain = opts.audio_gain;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
opts.audio_out = 0;
|
||||
printf ("Disabling audio output to soundcard.\n");
|
||||
break;
|
||||
case 'w':
|
||||
sscanf (optarg, "%s", opts.wav_out_file);
|
||||
printf ("Writing audio to file %s\n", opts.wav_out_file);
|
||||
openWavOutFile (&opts, &state);
|
||||
break;
|
||||
case 'B':
|
||||
sscanf (optarg, "%d", &opts.serial_baud);
|
||||
break;
|
||||
case 'C':
|
||||
sscanf (optarg, "%s", opts.serial_dev);
|
||||
break;
|
||||
case 'R':
|
||||
sscanf (optarg, "%d", &opts.resume);
|
||||
printf ("Enabling scan resume after %i TDULC frames\n", opts.resume);
|
||||
break;
|
||||
case 'f':
|
||||
if (optarg[0] == 'a')
|
||||
{
|
||||
opts.frame_dstar = 0;
|
||||
opts.frame_x2tdma = 1;
|
||||
opts.frame_p25p1 = 1;
|
||||
opts.frame_nxdn48 = 0;
|
||||
opts.frame_nxdn96 = 1;
|
||||
opts.frame_dmr = 1;
|
||||
opts.frame_provoice = 0;
|
||||
}
|
||||
else if (optarg[0] == 'd')
|
||||
{
|
||||
opts.frame_dstar = 1;
|
||||
opts.frame_x2tdma = 0;
|
||||
opts.frame_p25p1 = 0;
|
||||
opts.frame_nxdn48 = 0;
|
||||
opts.frame_nxdn96 = 0;
|
||||
opts.frame_dmr = 0;
|
||||
opts.frame_provoice = 0;
|
||||
printf ("Decoding only D-STAR frames.\n");
|
||||
}
|
||||
else if (optarg[0] == 'x')
|
||||
{
|
||||
opts.frame_dstar = 0;
|
||||
opts.frame_x2tdma = 1;
|
||||
opts.frame_p25p1 = 0;
|
||||
opts.frame_nxdn48 = 0;
|
||||
opts.frame_nxdn96 = 0;
|
||||
opts.frame_dmr = 0;
|
||||
opts.frame_provoice = 0;
|
||||
printf ("Decoding only X2-TDMA frames.\n");
|
||||
}
|
||||
else if (optarg[0] == 'p')
|
||||
{
|
||||
opts.frame_dstar = 0;
|
||||
opts.frame_x2tdma = 0;
|
||||
opts.frame_p25p1 = 0;
|
||||
opts.frame_nxdn48 = 0;
|
||||
opts.frame_nxdn96 = 0;
|
||||
opts.frame_dmr = 0;
|
||||
opts.frame_provoice = 1;
|
||||
state.samplesPerSymbol = 5;
|
||||
state.symbolCenter = 2;
|
||||
opts.mod_c4fm = 0;
|
||||
opts.mod_qpsk = 0;
|
||||
opts.mod_gfsk = 1;
|
||||
state.rf_mod = 2;
|
||||
printf ("Setting symbol rate to 9600 / second\n");
|
||||
printf ("Enabling only GFSK modulation optimizations.\n");
|
||||
printf ("Decoding only ProVoice frames.\n");
|
||||
}
|
||||
else if (optarg[0] == '1')
|
||||
{
|
||||
opts.frame_dstar = 0;
|
||||
opts.frame_x2tdma = 0;
|
||||
opts.frame_p25p1 = 1;
|
||||
opts.frame_nxdn48 = 0;
|
||||
opts.frame_nxdn96 = 0;
|
||||
opts.frame_dmr = 0;
|
||||
opts.frame_provoice = 0;
|
||||
printf ("Decoding only P25 Phase 1 frames.\n");
|
||||
}
|
||||
else if (optarg[0] == 'i')
|
||||
{
|
||||
opts.frame_dstar = 0;
|
||||
opts.frame_x2tdma = 0;
|
||||
opts.frame_p25p1 = 0;
|
||||
opts.frame_nxdn48 = 1;
|
||||
opts.frame_nxdn96 = 0;
|
||||
opts.frame_dmr = 0;
|
||||
opts.frame_provoice = 0;
|
||||
state.samplesPerSymbol = 20;
|
||||
state.symbolCenter = 10;
|
||||
opts.mod_c4fm = 0;
|
||||
opts.mod_qpsk = 0;
|
||||
opts.mod_gfsk = 1;
|
||||
state.rf_mod = 2;
|
||||
printf ("Setting symbol rate to 2400 / second\n");
|
||||
printf ("Enabling only GFSK modulation optimizations.\n");
|
||||
printf ("Decoding only NXDN 4800 baud frames.\n");
|
||||
}
|
||||
else if (optarg[0] == 'n')
|
||||
{
|
||||
opts.frame_dstar = 0;
|
||||
opts.frame_x2tdma = 0;
|
||||
opts.frame_p25p1 = 0;
|
||||
opts.frame_nxdn48 = 0;
|
||||
opts.frame_nxdn96 = 1;
|
||||
opts.frame_dmr = 0;
|
||||
opts.frame_provoice = 0;
|
||||
opts.mod_c4fm = 0;
|
||||
opts.mod_qpsk = 0;
|
||||
opts.mod_gfsk = 1;
|
||||
state.rf_mod = 2;
|
||||
printf ("Enabling only GFSK modulation optimizations.\n");
|
||||
printf ("Decoding only NXDN 9600 baud frames.\n");
|
||||
}
|
||||
else if (optarg[0] == 'r')
|
||||
{
|
||||
opts.frame_dstar = 0;
|
||||
opts.frame_x2tdma = 0;
|
||||
opts.frame_p25p1 = 0;
|
||||
opts.frame_nxdn48 = 0;
|
||||
opts.frame_nxdn96 = 0;
|
||||
opts.frame_dmr = 1;
|
||||
opts.frame_provoice = 0;
|
||||
printf ("Decoding only DMR/MOTOTRBO frames.\n");
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
if (optarg[0] == 'a')
|
||||
{
|
||||
opts.mod_c4fm = 1;
|
||||
opts.mod_qpsk = 1;
|
||||
opts.mod_gfsk = 1;
|
||||
state.rf_mod = 0;
|
||||
}
|
||||
else if (optarg[0] == 'c')
|
||||
{
|
||||
opts.mod_c4fm = 1;
|
||||
opts.mod_qpsk = 0;
|
||||
opts.mod_gfsk = 0;
|
||||
state.rf_mod = 0;
|
||||
printf ("Enabling only C4FM modulation optimizations.\n");
|
||||
}
|
||||
else if (optarg[0] == 'g')
|
||||
{
|
||||
opts.mod_c4fm = 0;
|
||||
opts.mod_qpsk = 0;
|
||||
opts.mod_gfsk = 1;
|
||||
state.rf_mod = 2;
|
||||
printf ("Enabling only GFSK modulation optimizations.\n");
|
||||
}
|
||||
else if (optarg[0] == 'q')
|
||||
{
|
||||
opts.mod_c4fm = 0;
|
||||
opts.mod_qpsk = 1;
|
||||
opts.mod_gfsk = 0;
|
||||
state.rf_mod = 1;
|
||||
printf ("Enabling only QPSK modulation optimizations.\n");
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
sscanf (optarg, "%i", &opts.uvquality);
|
||||
if (opts.uvquality < 1)
|
||||
{
|
||||
opts.uvquality = 1;
|
||||
}
|
||||
else if (opts.uvquality > 64)
|
||||
{
|
||||
opts.uvquality = 64;
|
||||
}
|
||||
printf ("Setting unvoice speech quality to %i waves per band.\n", opts.uvquality);
|
||||
break;
|
||||
case 'x':
|
||||
if (optarg[0] == 'x')
|
||||
{
|
||||
opts.inverted_x2tdma = 0;
|
||||
printf ("Expecting non-inverted X2-TDMA signals.\n");
|
||||
}
|
||||
else if (optarg[0] == 'r')
|
||||
{
|
||||
opts.inverted_dmr = 1;
|
||||
printf ("Expecting inverted DMR/MOTOTRBO signals.\n");
|
||||
}
|
||||
break;
|
||||
case 'A':
|
||||
sscanf (optarg, "%i", &opts.mod_threshold);
|
||||
printf ("Setting C4FM/QPSK auto detection threshold to %i\n", opts.mod_threshold);
|
||||
break;
|
||||
case 'S':
|
||||
sscanf (optarg, "%i", &opts.ssize);
|
||||
if (opts.ssize > 128)
|
||||
{
|
||||
opts.ssize = 128;
|
||||
}
|
||||
else if (opts.ssize < 1)
|
||||
{
|
||||
opts.ssize = 1;
|
||||
}
|
||||
printf ("Setting QPSK symbol buffer to %i\n", opts.ssize);
|
||||
break;
|
||||
case 'M':
|
||||
sscanf (optarg, "%i", &opts.msize);
|
||||
if (opts.msize > 1024)
|
||||
{
|
||||
opts.msize = 1024;
|
||||
}
|
||||
else if (opts.msize < 1)
|
||||
{
|
||||
opts.msize = 1;
|
||||
}
|
||||
printf ("Setting QPSK Min/Max buffer to %i\n", opts.msize);
|
||||
break;
|
||||
case 'r':
|
||||
opts.playfiles = 1;
|
||||
opts.errorbars = 0;
|
||||
opts.datascope = 0;
|
||||
state.optind = optind;
|
||||
break;
|
||||
default:
|
||||
usage ();
|
||||
exit (0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (opts.resume > 0)
|
||||
{
|
||||
openSerial (&opts, &state);
|
||||
}
|
||||
|
||||
if (opts.playfiles == 1)
|
||||
{
|
||||
opts.split = 1;
|
||||
opts.playoffset = 0;
|
||||
opts.delay = 0;
|
||||
openAudioOutDevice (&opts, 8000);
|
||||
}
|
||||
else if (strcmp (opts.audio_in_dev, opts.audio_out_dev) != 0)
|
||||
{
|
||||
opts.split = 1;
|
||||
opts.playoffset = 0;
|
||||
opts.delay = 0;
|
||||
openAudioOutDevice (&opts, 8000);
|
||||
openAudioInDevice (&opts);
|
||||
}
|
||||
else
|
||||
{
|
||||
opts.split = 0;
|
||||
opts.playoffset = 25; // 38
|
||||
opts.delay = 0;
|
||||
openAudioInDevice (&opts);
|
||||
opts.audio_out_fd = opts.audio_in_fd;
|
||||
}
|
||||
|
||||
if (opts.playfiles == 1)
|
||||
{
|
||||
playMbeFiles (&opts, &state, argc, argv);
|
||||
}
|
||||
else
|
||||
{
|
||||
liveScanner (&opts, &state);
|
||||
}
|
||||
cleanupAndExit (&opts, &state);
|
||||
return (0);
|
||||
}
|
||||
126
dsd_mbe.c
126
dsd_mbe.c
@@ -1,126 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
void
|
||||
playMbeFiles (dsd_opts * opts, dsd_state * state, int argc, char **argv)
|
||||
{
|
||||
|
||||
int i;
|
||||
char imbe_d[88];
|
||||
char ambe_d[49];
|
||||
|
||||
for (i = state->optind; i < argc; i++)
|
||||
{
|
||||
sprintf (opts->mbe_in_file, "%s", argv[i]);
|
||||
openMbeInFile (opts, state);
|
||||
mbe_initMbeParms (state->cur_mp, state->prev_mp, state->prev_mp_enhanced);
|
||||
printf ("playing %s\n", opts->mbe_in_file);
|
||||
while (feof (opts->mbe_in_f) == 0)
|
||||
{
|
||||
if (state->mbe_file_type == 0)
|
||||
{
|
||||
readImbe4400Data (opts, state, imbe_d);
|
||||
mbe_processImbe4400Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||
processAudio (opts, state);
|
||||
if (opts->wav_out_fd != -1)
|
||||
{
|
||||
writeSynthesizedVoice (opts, state);
|
||||
}
|
||||
|
||||
if (opts->audio_out == 1)
|
||||
{
|
||||
playSynthesizedVoice (opts, state);
|
||||
}
|
||||
}
|
||||
else if (state->mbe_file_type == 1)
|
||||
{
|
||||
readAmbe2250Data (opts, state, ambe_d);
|
||||
mbe_processAmbe2250Dataf (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||
processAudio (opts, state);
|
||||
if (opts->wav_out_fd != -1)
|
||||
{
|
||||
writeSynthesizedVoice (opts, state);
|
||||
}
|
||||
if (opts->audio_out == 1)
|
||||
{
|
||||
playSynthesizedVoice (opts, state);
|
||||
}
|
||||
}
|
||||
if (exitflag == 1)
|
||||
{
|
||||
cleanupAndExit (opts, state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char ambe_fr[4][24], char imbe7100_fr[7][24])
|
||||
{
|
||||
|
||||
int i;
|
||||
char imbe_d[88];
|
||||
char ambe_d[49];
|
||||
|
||||
for (i = 0; i < 88; i++)
|
||||
{
|
||||
imbe_d[i] = 0;
|
||||
}
|
||||
|
||||
if ((state->synctype == 0) || (state->synctype == 1))
|
||||
{
|
||||
mbe_processImbe7200x4400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe_fr, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||
if (opts->mbe_out_f != NULL)
|
||||
{
|
||||
saveImbe4400Data (opts, state, imbe_d);
|
||||
}
|
||||
}
|
||||
else if ((state->synctype == 14) || (state->synctype == 15))
|
||||
{
|
||||
mbe_processImbe7100x4400Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, imbe7100_fr, imbe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||
if (opts->mbe_out_f != NULL)
|
||||
{
|
||||
saveImbe4400Data (opts, state, imbe_d);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mbe_processAmbe3600x2250Framef (state->audio_out_temp_buf, &state->errs, &state->errs2, state->err_str, ambe_fr, ambe_d, state->cur_mp, state->prev_mp, state->prev_mp_enhanced, opts->uvquality);
|
||||
if (opts->mbe_out_f != NULL)
|
||||
{
|
||||
saveAmbe2250Data (opts, state, ambe_d);
|
||||
}
|
||||
}
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printf ("%s", state->err_str);
|
||||
}
|
||||
|
||||
processAudio (opts, state);
|
||||
if (opts->wav_out_fd != -1)
|
||||
{
|
||||
writeSynthesizedVoice (opts, state);
|
||||
}
|
||||
|
||||
if (opts->audio_out == 1)
|
||||
{
|
||||
playSynthesizedVoice (opts, state);
|
||||
}
|
||||
}
|
||||
200
dsd_symbol.c
200
dsd_symbol.c
@@ -1,200 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
int
|
||||
getSymbol (dsd_opts * opts, dsd_state * state, int have_sync)
|
||||
{
|
||||
|
||||
short sample;
|
||||
int i, sum, symbol, count;
|
||||
ssize_t result;
|
||||
|
||||
sum = 0;
|
||||
count = 0;
|
||||
for (i = 0; i < state->samplesPerSymbol; i++)
|
||||
{
|
||||
// timing control
|
||||
if ((i == 0) && (have_sync == 0))
|
||||
{
|
||||
if (state->samplesPerSymbol == 20)
|
||||
{
|
||||
if ((state->jitter >= 7) && (state->jitter <= 10))
|
||||
{
|
||||
i--;
|
||||
}
|
||||
else if ((state->jitter >= 11) && (state->jitter <= 14))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else if (state->rf_mod == 1)
|
||||
{
|
||||
if ((state->jitter >= 0) && (state->jitter < state->symbolCenter))
|
||||
{
|
||||
i++; // fall back
|
||||
}
|
||||
else if ((state->jitter > state->symbolCenter) && (state->jitter < 10))
|
||||
{
|
||||
i--; // catch up
|
||||
}
|
||||
}
|
||||
else if (state->rf_mod == 2)
|
||||
{
|
||||
if ((state->jitter >= state->symbolCenter - 1) && (state->jitter <= state->symbolCenter))
|
||||
{
|
||||
i--;
|
||||
}
|
||||
else if ((state->jitter >= state->symbolCenter + 1) && (state->jitter <= state->symbolCenter + 2))
|
||||
{
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else if (state->rf_mod == 0)
|
||||
{
|
||||
if ((state->jitter > 0) && (state->jitter <= state->symbolCenter))
|
||||
{
|
||||
i--; // catch up
|
||||
}
|
||||
else if ((state->jitter > state->symbolCenter) && (state->jitter < state->samplesPerSymbol))
|
||||
{
|
||||
i++; // fall back
|
||||
}
|
||||
}
|
||||
state->jitter = -1;
|
||||
}
|
||||
|
||||
result = read (opts->audio_in_fd, &sample, 2);
|
||||
if ((sample > state->max) && (have_sync == 1) && (state->rf_mod == 0))
|
||||
{
|
||||
sample = state->max;
|
||||
}
|
||||
else if ((sample < state->min) && (have_sync == 1) && (state->rf_mod == 0))
|
||||
{
|
||||
sample = state->min;
|
||||
}
|
||||
|
||||
if (sample > state->center)
|
||||
{
|
||||
if (state->lastsample < state->center)
|
||||
{
|
||||
state->numflips += 1;
|
||||
}
|
||||
if (sample > (state->maxref * 1.25))
|
||||
{
|
||||
if (state->lastsample < (state->maxref * 1.25))
|
||||
{
|
||||
state->numflips += 1;
|
||||
}
|
||||
if ((state->jitter < 0) && (state->rf_mod == 1))
|
||||
{ // first spike out of place
|
||||
state->jitter = i;
|
||||
}
|
||||
if ((opts->symboltiming == 1) && (have_sync == 0) && (state->lastsynctype != -1))
|
||||
{
|
||||
printf ("O");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((opts->symboltiming == 1) && (have_sync == 0) && (state->lastsynctype != -1))
|
||||
{
|
||||
printf ("+");
|
||||
}
|
||||
if ((state->jitter < 0) && (state->lastsample < state->center) && (state->rf_mod != 1))
|
||||
{ // first transition edge
|
||||
state->jitter = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // sample < 0
|
||||
if (state->lastsample > state->center)
|
||||
{
|
||||
state->numflips += 1;
|
||||
}
|
||||
if (sample < (state->minref * 1.25))
|
||||
{
|
||||
if (state->lastsample > (state->minref * 1.25))
|
||||
{
|
||||
state->numflips += 1;
|
||||
}
|
||||
if ((state->jitter < 0) && (state->rf_mod == 1))
|
||||
{ // first spike out of place
|
||||
state->jitter = i;
|
||||
}
|
||||
if ((opts->symboltiming == 1) && (have_sync == 0) && (state->lastsynctype != -1))
|
||||
{
|
||||
printf ("X");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((opts->symboltiming == 1) && (have_sync == 0) && (state->lastsynctype != -1))
|
||||
{
|
||||
printf ("-");
|
||||
}
|
||||
if ((state->jitter < 0) && (state->lastsample > state->center) && (state->rf_mod != 1))
|
||||
{ // first transition edge
|
||||
state->jitter = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (state->samplesPerSymbol == 20)
|
||||
{
|
||||
if ((i >= 9) && (i <= 11))
|
||||
{
|
||||
sum += sample;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (state->samplesPerSymbol == 5)
|
||||
{
|
||||
if (i == 2)
|
||||
{
|
||||
sum += sample;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((i >= state->symbolCenter - 1) && (i <= state->symbolCenter + 2) && (state->rf_mod == 0)) || (((i == state->symbolCenter) || (i == state->symbolCenter + 1)) && (state->rf_mod != 0)))
|
||||
{
|
||||
sum += sample;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
state->lastsample = sample;
|
||||
}
|
||||
symbol = (sum / count);
|
||||
|
||||
if ((opts->symboltiming == 1) && (have_sync == 0) && (state->lastsynctype != -1))
|
||||
{
|
||||
if (state->jitter >= 0)
|
||||
{
|
||||
printf (" %i\n", state->jitter);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
state->symbolcnt++;
|
||||
return (symbol);
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
void
|
||||
upsample (dsd_state * state, float invalue)
|
||||
{
|
||||
|
||||
int i, j, sum;
|
||||
float *outbuf1, c, d;
|
||||
|
||||
outbuf1 = state->audio_out_float_buf_p;
|
||||
outbuf1--;
|
||||
c = *outbuf1;
|
||||
d = invalue;
|
||||
// basic triangle interpolation
|
||||
outbuf1++;
|
||||
*outbuf1 = ((invalue * (float) 0.166) + (c * (float) 0.834));
|
||||
outbuf1++;
|
||||
*outbuf1 = ((invalue * (float) 0.332) + (c * (float) 0.668));
|
||||
outbuf1++;
|
||||
*outbuf1 = ((invalue * (float) 0.5) + (c * (float) 0.5));
|
||||
outbuf1++;
|
||||
*outbuf1 = ((invalue * (float) 0.668) + (c * (float) 0.332));
|
||||
outbuf1++;
|
||||
*outbuf1 = ((invalue * (float) 0.834) + (c * (float) 0.166));
|
||||
outbuf1++;
|
||||
*outbuf1 = d;
|
||||
outbuf1++;
|
||||
|
||||
if (state->audio_out_idx2 > 24)
|
||||
{
|
||||
// smoothing
|
||||
outbuf1 -= 16;
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
sum = 0;
|
||||
outbuf1 -= 2;
|
||||
sum += *outbuf1;
|
||||
outbuf1 += 2;
|
||||
sum += *outbuf1;
|
||||
outbuf1 += 2;
|
||||
sum += *outbuf1;
|
||||
outbuf1 -= 2;
|
||||
*outbuf1 = (sum / (float) 3);
|
||||
outbuf1++;
|
||||
}
|
||||
outbuf1 -= 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
79
dstar.c
79
dstar.c
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note: D-STAR support is very incomplete and does not work yet
|
||||
* It is unknown if the ambe3600x2250 decoder is even compatible with D-STAR
|
||||
* voice frames. If it is then the interleave pattern needs to be determined.
|
||||
* GMSK modulation optimizations will also required to get a usable bit error
|
||||
* rate. This was included mainly as an example of how other systmes might
|
||||
* be supported.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
#include "dstar_const.h"
|
||||
|
||||
void
|
||||
processDSTAR (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
// extracts AMBE frames from D-STAR voice frame
|
||||
int i, j, dibit;
|
||||
char ambe_fr[4][24];
|
||||
char dstar[300];
|
||||
const int *w, *x;
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printf ("e:");
|
||||
}
|
||||
|
||||
#ifdef DSTAR_DUMP
|
||||
printf ("\n");
|
||||
#endif
|
||||
|
||||
for (j = 0; j < 210; j++) // 210 is very long but used for debugging
|
||||
{
|
||||
// voice frame
|
||||
w = dW;
|
||||
x = dX;
|
||||
for (i = 0; i < 72; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
dstar[i] = dibit + 48;
|
||||
ambe_fr[*w][*x] = (1 & dibit);
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
dstar[i] = 32;
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
|
||||
// data frame
|
||||
for (i = 73; i < 97; i++)
|
||||
{
|
||||
dstar[i] = getDibit (opts, state) + 48;
|
||||
}
|
||||
dstar[i] = 0;
|
||||
|
||||
#ifdef DSTAR_DUMP
|
||||
printf ("%s\n", dstar);
|
||||
#endif
|
||||
}
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
311
dstar_const.h
311
dstar_const.h
@@ -1,311 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* dstar interleave experiments
|
||||
*/
|
||||
|
||||
#ifndef _MAIN
|
||||
|
||||
extern const int dW[72];
|
||||
extern const int dX[72];
|
||||
|
||||
#else
|
||||
|
||||
/*
|
||||
* 4x18
|
||||
*/
|
||||
/*
|
||||
const int dW[72] = {
|
||||
0,0,1,2,
|
||||
0,0,1,2,
|
||||
0,0,1,2,
|
||||
0,0,1,2,
|
||||
0,0,1,3,
|
||||
0,0,1,3,
|
||||
0,1,1,3,
|
||||
0,1,1,3,
|
||||
0,1,1,3,
|
||||
0,1,1,3,
|
||||
0,1,1,3,
|
||||
0,1,2,3,
|
||||
0,1,2,3,
|
||||
0,1,2,3,
|
||||
0,1,2,3,
|
||||
0,1,2,3,
|
||||
0,1,2,3,
|
||||
0,1,2,3
|
||||
};
|
||||
|
||||
const int dX[72] = {
|
||||
23,5,10,3,
|
||||
22,4,9,2,
|
||||
21,3,8,1,
|
||||
20,2,7,0,
|
||||
19,1,6,13,
|
||||
18,0,5,12,
|
||||
17,22,4,11,
|
||||
16,21,3,10,
|
||||
15,20,2,9,
|
||||
14,19,1,8,
|
||||
13,18,0,7,
|
||||
12,17,10,6,
|
||||
11,16,9,5,
|
||||
10,15,8,4,
|
||||
9,14,7,3,
|
||||
8,13,6,2,
|
||||
7,12,5,1,
|
||||
6,11,4,0
|
||||
};
|
||||
*/
|
||||
|
||||
/*
|
||||
* 3x24 alt
|
||||
*/
|
||||
const int dW[72] = {
|
||||
1, 0, 3,
|
||||
1, 0, 3,
|
||||
1, 0, 3,
|
||||
1, 0, 3,
|
||||
1, 0, 3,
|
||||
1, 0, 3,
|
||||
1, 0, 3,
|
||||
1, 0, 3,
|
||||
1, 0, 3,
|
||||
1, 0, 3,
|
||||
1, 0, 3,
|
||||
1, 0, 3,
|
||||
1, 0, 3,
|
||||
1, 0, 2,
|
||||
1, 0, 2,
|
||||
1, 0, 2,
|
||||
1, 0, 2,
|
||||
1, 0, 2,
|
||||
1, 0, 2,
|
||||
1, 0, 2,
|
||||
1, 0, 2,
|
||||
1, 0, 2,
|
||||
1, 0, 2,
|
||||
0, 3, 2,
|
||||
};
|
||||
|
||||
const int dX[72] = {
|
||||
22, 22, 12,
|
||||
21, 21, 11,
|
||||
20, 20, 10,
|
||||
19, 19, 9,
|
||||
18, 18, 8,
|
||||
17, 17, 7,
|
||||
16, 16, 6,
|
||||
15, 15, 5,
|
||||
14, 14, 4,
|
||||
13, 13, 3,
|
||||
12, 12, 2,
|
||||
11, 11, 1,
|
||||
10, 10, 0,
|
||||
9, 9, 10,
|
||||
8, 8, 9,
|
||||
7, 7, 8,
|
||||
6, 6, 7,
|
||||
5, 5, 6,
|
||||
4, 4, 5,
|
||||
3, 3, 4,
|
||||
2, 2, 3,
|
||||
1, 1, 2,
|
||||
0, 0, 1,
|
||||
23, 13, 0
|
||||
};
|
||||
|
||||
/*
|
||||
* 3x24
|
||||
*/
|
||||
/*
|
||||
const int dW[72] = {
|
||||
0,1,2,
|
||||
0,1,2,
|
||||
0,1,2,
|
||||
0,1,2,
|
||||
0,1,2,
|
||||
0,1,2,
|
||||
0,1,2,
|
||||
0,1,2,
|
||||
0,1,2,
|
||||
0,1,2,
|
||||
0,1,3,
|
||||
0,1,3,
|
||||
0,1,3,
|
||||
0,1,3,
|
||||
0,1,3,
|
||||
0,1,3,
|
||||
0,1,3,
|
||||
0,1,3,
|
||||
0,1,3,
|
||||
0,1,3,
|
||||
0,1,3,
|
||||
0,1,3,
|
||||
0,1,3,
|
||||
0,2,3,
|
||||
};
|
||||
|
||||
const int dX[72] = {
|
||||
23,22,9,
|
||||
22,21,8,
|
||||
21,20,7,
|
||||
20,19,6,
|
||||
19,18,5,
|
||||
18,17,4,
|
||||
17,16,3,
|
||||
16,15,2,
|
||||
15,14,1,
|
||||
14,13,0,
|
||||
13,12,13,
|
||||
12,11,12,
|
||||
11,10,11,
|
||||
10,9,10,
|
||||
9,8,9,
|
||||
8,7,8,
|
||||
7,6,7,
|
||||
6,5,6,
|
||||
5,4,5,
|
||||
4,3,4,
|
||||
3,2,3,
|
||||
2,1,2,
|
||||
1,0,1,
|
||||
0,10,0
|
||||
};
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* 2x36
|
||||
*/
|
||||
/*
|
||||
const int dW[72] = {
|
||||
0,1,
|
||||
0,1,
|
||||
0,1,
|
||||
0,1,
|
||||
0,1,
|
||||
0,1,
|
||||
0,1,
|
||||
0,1,
|
||||
0,1,
|
||||
0,1,
|
||||
0,1,
|
||||
0,2,
|
||||
0,2,
|
||||
0,2,
|
||||
0,2,
|
||||
0,2,
|
||||
0,2,
|
||||
0,2,
|
||||
0,2,
|
||||
0,2,
|
||||
0,2,
|
||||
0,2,
|
||||
0,3,
|
||||
0,3,
|
||||
1,3,
|
||||
1,3,
|
||||
1,3,
|
||||
1,3,
|
||||
1,3,
|
||||
1,3,
|
||||
1,3,
|
||||
1,3,
|
||||
1,3,
|
||||
1,3,
|
||||
1,3,
|
||||
1,3
|
||||
};
|
||||
|
||||
const int dX[72] = {
|
||||
23,10,
|
||||
22,9,
|
||||
21,8,
|
||||
20,7,
|
||||
19,6,
|
||||
18,5,
|
||||
17,4,
|
||||
16,3,
|
||||
15,2,
|
||||
14,1,
|
||||
13,0,
|
||||
12,10,
|
||||
11,9,
|
||||
10,8,
|
||||
9,7,
|
||||
8,6,
|
||||
7,5,
|
||||
6,4,
|
||||
5,3,
|
||||
4,2,
|
||||
3,1,
|
||||
2,0,
|
||||
1,13,
|
||||
0,12,
|
||||
22,11,
|
||||
21,10,
|
||||
20,9,
|
||||
19,8,
|
||||
18,7,
|
||||
17,6,
|
||||
16,5,
|
||||
15,4,
|
||||
14,3,
|
||||
13,2,
|
||||
12,1,
|
||||
11,0
|
||||
};
|
||||
*/
|
||||
|
||||
/*
|
||||
* non-interleaved
|
||||
*/
|
||||
/*
|
||||
const int dW[72] = {
|
||||
0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,
|
||||
1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,
|
||||
1,1,1,1,1,1,
|
||||
1,1,1,1,1,2,
|
||||
2,2,2,2,2,2,
|
||||
2,2,2,2,3,3,
|
||||
3,3,3,3,3,3,
|
||||
3,3,3,3,3,3
|
||||
};
|
||||
|
||||
const int dX[72] = {
|
||||
23,22,21,20,19,18,
|
||||
17,16,15,14,13,12,
|
||||
11,10,9,8,7,6,
|
||||
5,4,3,2,1,0,
|
||||
22,21,20,19,18,17,
|
||||
16,15,14,13,12,11,
|
||||
10,9,8,7,6,5,
|
||||
4,3,2,1,0,10,
|
||||
9,8,7,6,5,4,
|
||||
3,2,1,0,13,12,
|
||||
11,10,9,8,7,6,
|
||||
5,4,3,2,1,0
|
||||
};
|
||||
*/
|
||||
|
||||
#endif
|
||||
272
examples/Example_Usage.md
Normal file
272
examples/Example_Usage.md
Normal file
@@ -0,0 +1,272 @@
|
||||
### Example Usage and Notes!
|
||||
|
||||
`dsd-fme` is all you need to run for pulse input, pulse output, and auto detect for DMR BS/MS, and P25. To use other decoding methods which cannot be auto detected, please use the following command line switches. Make sure to route audio into and out of DSD-FME using pavucontrol and virtual sinks as needed.
|
||||
|
||||
```
|
||||
-ft XDMA decoder class (P25p1 and p2, YSF, and DMR Stereo)
|
||||
-fs DMR Stereo, also may need to use -xr if inverted DMR
|
||||
-fa Legacy Auto (not recommended)
|
||||
-fi NXDN48
|
||||
-fn NXDN96
|
||||
-fp EDACS/Provoice
|
||||
-fm dPMR, also may need to use -xd if inverted dPMR.
|
||||
-f1 P25P1
|
||||
-f2 P25P2 (may need to specify wacn/sys/nac manually if traffic channel)
|
||||
-fx X2-TDMA
|
||||
-fy YSF
|
||||
-fz M17 Audio
|
||||
```
|
||||
|
||||
## Conventional Frequency Scanner
|
||||
This feature is used to allow DSD-FME to use RIGCTL or RTL input and cycle through frequencies to attain a frame sync.
|
||||
|
||||
This works almost identically to how the trunkng methods work, but instead of locking onto a control channel and tuning based on its decoding, it tunes through all loaded frequencies in a CSV file and stops when it finds a frame sync. This method is meant for loading a bunch of conventional non-trunking frequencies that signal only when voice or short data bursts are present (DMR T2, Conventional P25 P1, Conventional NXDN, etc) and decode them until the frame sync stops and then resume its scan. This method uses SDR++ RIGCTL, or RTL internal handling to go through signal. -Y is the scan switch. Note: This method will NOT perform at a level similar to a real hardware scanner, SDR tuning is not nearly as fast or reliable at locking onto signal.
|
||||
|
||||
To scan through a mixture of DMR and P25 Conventional, use:
|
||||
`dsd-fme -i tcp -C channel_map.csv -G group.csv -Y -U 4532 -N 2> log.ans`
|
||||
|
||||
To scan through NXDN48 only conventional, use:
|
||||
`dsd-fme -fi -i tcp -C channel_map.csv -Y -U 4532 -N 2> log.ans`
|
||||
|
||||
To scan through NXDN96 only conventional, use:
|
||||
`dsd-fme -fn -i tcp -C channel_map.csv -Y -U 4532 -N 2> log.ans`
|
||||
|
||||
The Channel Map setup will be identical to any of the channel maps found for trunking systems, channel numbers do not matter and can be arbitrarily organized, and frequencies can be duplicated to be 'scanned' more frequently in larger CSV files. Scan speed by default is 1 second, and is most stable at that speed. This can be adjusted by using the `-t 2` option, for example, to specify 2 seconds of hang time per frequency. ~~If activity occurs on a frequency, an additional 2 seconds of 'hangtime' will occur on that frequency for any follow up voice activity.~~ Using `-t 0` will forego the one second wait time, and this can work in some situations, but is not advised as it may skip during the middle of transmissions, or skip over them entirely without a framesync.
|
||||
|
||||
Please Note: DMR Simplex may not behave well on scan, I have not been able to test it as such, but given the nature of the on-off timeslot signalling on DMR Simplex, missed frame syncs and skipping/resuming scan may occur.
|
||||
|
||||
## Trunking Examples
|
||||
Please see trunking.sh for sample start up scripts or scroll down to the bottom for more explanation.
|
||||
|
||||
## Example Usage - Default Decoder, Ncurses Terminal, Pulse Input/Output, and Log Console to file
|
||||
`dsd-fme -N 2> voice.log`
|
||||
|
||||
and in a second terminal tab, same folder, run
|
||||
|
||||
`tail -n 40 -f voice.log`
|
||||
|
||||
Then you can open up your pavucontrol "Pulse Audio Volume Control" or "Volume Control" application and route input into DSD-FME from any application and DSD-FME output to the left and right speakers respectively. (unlock the channel in the application stream and adjust left and right independently)
|
||||
|
||||
### Input ###
|
||||
|
||||
--TCP Direct Audio Link with SDR++
|
||||
|
||||
`dsd-fme -i tcp` Currently defaults to localhost:7355 (SDR++ defaults)
|
||||
|
||||
`dsd-fme -i tcp:192.168.7.5:7356` (remote host and custom port)
|
||||
|
||||
--48000/9600 Mono Wav File Input
|
||||
|
||||
`dsd-fme -i filename.wav` 48k/1 Audio (SDR++, GQRX wav recordings)
|
||||
|
||||
`dsd-fme -i filename.wav -s 96000` 96k/1 (DSDPlus Raw Signal Wav Files)
|
||||
|
||||
Wav File Input Note: Due to 96000 rate audio requiring me to double the symbol rate and center, be sure to use the -s 96000 at the very end of the startup command. Also, some NXDN48/96 may have difficulties decoding properly with wav file input.
|
||||
|
||||
## Example Usage - RTL2832 Dongle Input
|
||||
Short Setup (all default values):
|
||||
|
||||
`dsd-fme -i rtl`
|
||||
|
||||
Detailed Setup:
|
||||
|
||||
`dsd-fme -ft -i rtl:0:154.9875M:26:-2:8:0:6020 `
|
||||
|
||||
```
|
||||
RTL-SDR options:
|
||||
Usage: rtl:dev:freq:gain:ppm:bw:sq:udp
|
||||
NOTE: all arguments after rtl are optional now for trunking, but user configuration is recommended
|
||||
dev <num> RTL-SDR Device Index Number
|
||||
freq <num> RTL-SDR Frequency (851800000 or 851.8M)
|
||||
gain <num> RTL-SDR Device Gain (0-49)(default = 0; Hardware AGC recommended)
|
||||
ppm <num> RTL-SDR PPM Error (default = 0)
|
||||
bw <num> RTL-SDR Bandwidth kHz (default = 12)(8, 12, 16, 24)
|
||||
sq <num> RTL-SDR Squelch Level vs RMS Value (Optional)
|
||||
udp <num> RTL-SDR Legacy UDP Remote Port (Optional -- External Use Only)
|
||||
Example: dsd-fme-zdev -fs -i rtl -C cap_plus_channel.csv -T
|
||||
Example: dsd-fme-zdev -fp -i rtl:0:851.375M:22:-2:24:0:6021
|
||||
|
||||
```
|
||||
|
||||
## Example Usage - Extra Payload/PDU Logging
|
||||
|
||||
`dsd-fme -Z -N 2> log.ans`
|
||||
|
||||
and in a second terminal tab, same folder, run
|
||||
|
||||
`tail -n 40 -f log.ans`
|
||||
|
||||
### EDACS/P25/NXDN/DMR Simple/Single VFO Trunking ###
|
||||
|
||||
EDACS Trunking (w/ channel map import)
|
||||
|
||||
--EDACS/PV Trunking using RIGCTL and TCP Direct Link Audio inside of SDR++ (Tested and Working on EDACS/EDACS-EA with Provoice, Analog Voice Monitoring and Per Call is Experimental)
|
||||
|
||||
`dsd-fme -i tcp -fp -C channel_map.csv -G group.csv -T -U 4532 -N 2> log.ans`
|
||||
|
||||
--NXDN48 Trunking (standard band plan) with SDR++ (untested for frequency accuracy)
|
||||
|
||||
`dsd-fme -fi -i tcp -T -U 4532 -N 2> log.ans`
|
||||
|
||||
--NXDN48 Trunking (w/ channel map import) with SDR++ (put control channel frequency at channel 0 in channel_map.csv)
|
||||
|
||||
`dsd-fme -fi -i tcp -T -U 4532 -C channel_map.csv -N 2> log.ans`
|
||||
|
||||
--DMR Trunking (w/ channel map import) with SDR++ (put control channel frequency at channel 0 (TIII and Con+) in channel_map.csv)
|
||||
|
||||
`dsd-fme -fs -i tcp -T -U 4532 -C channel_map.csv -N 2> log.ans`
|
||||
|
||||
--P25 Trunking P1 and P2 (C4FM) with SDR++
|
||||
|
||||
`dsd-fme -i tcp -T -U 4532 -N 2> log.ans`
|
||||
|
||||
--P25 Trunking (QPSK) with P1 Control Channel (Should switch symbol rate and center on Phase 2 audio channels)
|
||||
|
||||
`dsd-fme -i tcp -T -U 4532 -N -mq 2> log.ans`
|
||||
|
||||
--P25 Trunking Phase 2 TDMA Control Channel systems with QPSK (non Phase 1 systems)
|
||||
|
||||
`dsd-fme -i tcp -T -U 4532 -N -f2 -m2 2> log.ans`
|
||||
|
||||
Trunking Note1: All samples above can also be run with the RTL input method and setting of RTL UDP remote port. In terms of performance, however, SDR++ will do a much better job on weaker/marginal signal compared to the RTL input. RTL input should only be used on strong signal.
|
||||
|
||||
`dsd-fme -fp -i rtl:0:851.8M:22:-2:24:0:6020 -T -C channel_map.csv -G group.csv -N 2> log.ans`
|
||||
|
||||
Trunking Note2: QPSK Phase 1 and Phase 2 Systems may be subceptible to LSM distortion issues, but seem to do okay, but require really good signal. Some CRC issues still occur with Phase 2 TDMA LCCH Mac Signal that can affect reliability, I believe this issue is ultimately caused by the PSK demodulation inside of FME. I also don't believe this will work on 8-level PSK, but I cannot determine that at the moment. Update: I have improved the LCCH Mac Signal decoding my increasing the QPSK decision point buffers to their maximum values.
|
||||
|
||||
Trunking Note3: DMR Trunking has been coded, and some testing and tweaks have been carried out. Cap+, Con+, and TIII systems seem to do well with trunking now. Placing the frequency for the control channel at channel map 0 in your channel_map.csv file is not required now if using RIGCTL or the RTL Input, both can poll the VFO for the current frequency if it believes its on a control channel, but setting a fake channel number (i.e. 999) first with the CC frequency will result in finding the CC faster on startup if desired. If you need to map out your channels for TIII, you can observe the console output and look for channel numbers. For conveniece I have included the DSDPlus style LSN-esque numbering into the console print so it will make it easier for users from DSDPlus to map frequencies into the channel_map.csv file. Make sure your channel numbers are the lpcn (12-bit logical physical channel number - decimal format) values from the log, and not the LPCN+TS (13-bit DSDPlus LSN) values. Notice: TIII Site ID value needs work to determine proper DMRLA values for system area and sub area.
|
||||
|
||||
```
|
||||
00:43:00 Sync: +DMR [slot1] slot2 | Color Code=00 | CSBK
|
||||
Talkgroup Voice Channel Grant (TV_GRANT) - Logical
|
||||
LPCN: 0075; TS: 2; LPCN+TS: 0152; Target: 16518173 - Source: 16533625
|
||||
|
||||
```
|
||||
|
||||
Use channel 75 in your import file, which would correspond to dsdplus channels 151 and 152 (151 = TS1 / 152 = TS2).
|
||||
|
||||
For Connect Plus, enumerate your list from 1 to the last channel and add the frequency. For Capacity Plus, LSN 1 and 2 will share the same frequency, 3 and 4 will share, 5 and 6 will share, and 7-8 will share, as Capacity Plus counts each 'channel' as two seperate channels (LSN), one for each time slot. Capacity Plus Quirk: DSD-FME makes its best effort to follow the rest channel in the event that the sync is lost for longer than the hangtime, but occassionally, DSD-FME may lose the rest channel and will have to hunt through all frequencies to find it again.
|
||||
|
||||
Trunking Note4: NXDN Trunking v1 will require a channel map. Please see the example folder for an appropriate channel map. NOTICE: NXDN trunking has been fixed on the RTL (rtl_fm) input method and works correctly now using a soft squelch value to determine when to look for frame sync. Tests show this works very well, but squelch adjustments may be required to differentiate the noise floor from the signal.
|
||||
|
||||
NXDN Trunking Update: NXDN DFA (Direct Frequency Assignment) has been coded from the v2 documents, so using a channel map may not be required, as long as the DFA is configured with standard values, and not 'system definable' values. This will only work on trunking systems that use DFA (newer systems) in accordance to the v2 CAI document NXDN TS 1-A Version 2.0 September 2016. If the system uses 'system definable' values, then make sure to put the channels in a channel map csv file as as the 16-bit OFN values for proper tuning.
|
||||
|
||||
NXDN Type-D/IDAS Update: Type-D or IDAS decoding/trunking has been coded now and tested on a small two channel system. Set up a channel map much like Type-C trunking. If preferred, insert channel 31 at the top of your channel map for the 'home repeater' or go to channel of choice during a TX_REL or DISC message. Extensive testing of Type-D has not been conducted. Some cavaets may currently include iffy per call wav file saving and potentially shifting SRC and TGT ID values due to how SCCH messages are handled and how Busy Repeater Messages are handled. Private calls will need to be enabled by enabling 'data calls', if desired. During testing, only data calls came on private calls, so this was set to disabled by default, but can be enabled with data calls enabled. Also, note that some home repeater channels may or may not carry calls from all systems.
|
||||
|
||||
Channel Map and Group CSV Note: Leave the top line of the channel_map.csv and group.csv as the label, do not delete the line, if no line is there, dsd_import skips the first line so it will not import the first channel or first group in those files if there is something there that isn't a label.
|
||||
|
||||
Hytera XPT: Code has been added for XPT system slco/flco/csbk decoding and trunking. The setup will be similar to Capacity Plus trunking in the csv file, listing each LSN channel to a frequency (see examples/hytera_xpt_chan.csv). Currently, this set up is working with smaller XPT systems that I have been able to test with.
|
||||
|
||||
## NCurses Keyboard Shortcuts ##
|
||||
|
||||
Some Keyboard Shortcuts have been implemented for testing to see how users like them. Just hope nobody pushes a key on accident and doesn't know which one it was or what it does. The current list of keyboard shortcuts include:
|
||||
|
||||
```
|
||||
esc or arrow keys - ncurses menu
|
||||
q - quit
|
||||
c - toggle compact mode
|
||||
h - toggle call history
|
||||
z - toggle console payloads
|
||||
a - toggle call alert beep
|
||||
4 - force privacy/scrambler key assertion over enc identifiers (dmr and nxdn)
|
||||
6 - force rc4 key assertion over missing pi header/le enc identifiers (dmr)
|
||||
i - toggle signal inversion on types that can't auto detect (dmr, dpmr)
|
||||
m - toggle c4fm/qpsk 10/4 (everything but phase 2 signal)
|
||||
M - toggle c4fm/qpsk 8/3 (phase 2 tdma control channel)
|
||||
R - start capturing symbol capture bin (date/time name file)
|
||||
r - stop capturing symbol capture bin
|
||||
spacebar - replay last symbol capture bin (captures must be stopped first)
|
||||
s - stop playing symbol capture bin or wav input file
|
||||
P - start per call decoded wav files (Capital P)
|
||||
p - stop per call decoded wav files (Lower p)
|
||||
t - toggle trunking (needs either rtl input, or rigctl connection)
|
||||
y - toggle scanner (needs either rtl input, or rigctl connection)
|
||||
1 - Toggle Voice Synthesis in TDMA Slot 1 or FDMA Conventional Voice
|
||||
2 - Toggle Voice Synthesis in TDMA Slot 2
|
||||
w - Toggle Trunking/Playback White List (Allow A Groups Only) / Black List (Block B or DE groups only) Mode
|
||||
g - Toggle Trunking Tuning to Group Calls (DMR T3, Con+, Cap+, P25, NXDN)
|
||||
u - Toggle Trunking Tuning to Private Calls (DMR T3, Cap+, P25)
|
||||
d - Toggle Trunking Tuning to Data Calls (DMR T3, NXDN)
|
||||
e - Toggle Trunking Tuning to Encrypted Calls (P25)
|
||||
8 - Connect to SDR++ TCP Audio Sink with Defaults/Retry Sink Connection on Disconnect
|
||||
9 - Connect to SDR++ RIGCTL Server with Defaults/Retry RIGCTL Connection
|
||||
D - Reset DMR Site Parms/Call Strings, etc.
|
||||
Z - Simulate NoCarrier/No VC/CC sync (capital Z)
|
||||
|
||||
! - Lockout Tuning/Playback of TG in Slot 1 or Conventional -- Current Session Only if no group.csv file specified
|
||||
@ - Lockout Tuning/Playback of TG in Slot 2 -- Current Session Only if no group.csv file specified
|
||||
|
||||
k - Hold TG in Slot 1 or Conventional, or clear current hold (Testing/WIP: DMR T3 Only)
|
||||
l - Hold TG in Slot 2 on TDMA Systems, or clear current hold (Testing/WIP: DMR T3 Only)
|
||||
|
||||
```
|
||||
|
||||
## Sending Audio to a Icecast 2 Server via FFmpeg (Windows)
|
||||
|
||||
Make sure to enable "Stereo Mix" from Volume Control Panel and then disable Windows Sounds.
|
||||
|
||||
```
|
||||
ffmpeg -f dshow -i audio="Stereo Mix (Realtek High Definition Audio)" -c:a aac -b:a 64k -content_type 'audio/aac' -vn -f adts icecast://source:password@192.168.5.251:8844/DSDFME
|
||||
```
|
||||
|
||||
## Sending Audio to a Icecast 2 Server via FFmpeg (Linux w/ Pulse Audio)
|
||||
|
||||
`pactl list short sources`
|
||||
|
||||
Choose Desired Device to Cast:
|
||||
|
||||
```
|
||||
0 auto_null.monitor module-null-sink.c s16le 2ch 48000Hz IDLE
|
||||
1 alsa_output.pci-0000_0d_00.3.analog-stereo.monitor module-alsa-card.c s16le 2ch 44100Hz RUNNING
|
||||
2 alsa_input.pci-0000_0d_00.3.analog-stereo module-alsa-card.c s16le 2ch 44100Hz RUNNING
|
||||
3 virtual_sink.monitor module-null-sink.c s16le 2ch 44100Hz RUNNING
|
||||
4 virtual_sink2.monitor module-null-sink.c s16le 2ch 44100Hz RUNNING
|
||||
7 alsa_output.pci-0000_0b_00.1.hdmi-stereo-extra1.monitor module-alsa-card.c s16le 2ch 44100Hz RUNNING
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
francis@12cores:~$ pactl list short sources
|
||||
0 auto_null.monitor module-null-sink.c s16le 2ch 48000Hz IDLE
|
||||
francis@12coresx:~$ ffmpeg -f pulse -i 0 -c:a libmp3lame -ab 64k -f mp3 icecast://source:password@XXXXXXXXX:8000
|
||||
|
||||
|
||||
```
|
||||
|
||||
Note: Do not run this command for ffmpeg/icecast piped to the main dsd-fme command, make sure these are running in seperate terminals.
|
||||
|
||||
## Sending Audio to UDP Target/Port
|
||||
|
||||
Audio can be sent to a target address on your local area network with the UDP blaster using the `-o udp:targetaddress:port` option.
|
||||
Note: Any analog audio monitoring will not function properly over UDP port (rate difference issues)
|
||||
|
||||
Example (Short 8k/2):
|
||||
`dsd-fme -fs -o udp:192.168.7.8:23470`
|
||||
|
||||
Receiving End (Short 8k/2):
|
||||
`socat stdio udp-listen:23470 | play --buffer 640 -q -b 16 -r 8000 -c2 -t s16 -`
|
||||
|
||||
Example (Short 8k/1):
|
||||
`dsd-fme -f1 -o udp:192.168.7.8:23469`
|
||||
|
||||
Receiving End (Short 8k/1):
|
||||
`socat stdio udp-listen:23469 | play --buffer 320 -q -b 16 -r 8000 -c1 -t s16 -`
|
||||
|
||||
Example (Float 8k/2):
|
||||
`dsd-fme -ft -y -o udp:192.168.7.8:23468`
|
||||
|
||||
Receiving End (Float 8k/2):
|
||||
`socat stdio udp-listen:23468 | play --buffer 1280 -q -b 16 -r 8000 -c2 -t f32 -`
|
||||
|
||||
Example (Float 8k/1):
|
||||
`dsd-fme -fi -y -o udp:192.168.7.8:23467`
|
||||
|
||||
Receiving End (Float 8k/1):
|
||||
`socat stdio udp-listen:23467 | play --buffer 640 -q -b 16 -r 8000 -c1 -t f32 -`
|
||||
|
||||
Note: --buffer option in play is calculated by (channels * samples * sizeof(samples)),
|
||||
where samples is 160 for mono, 320 for stereo, and short samples are 2 and float samples are 4.
|
||||
This is vital to prevent 'lag' or cut-off audio when the UDP audio doesn't fill the default buffer size.
|
||||
|
||||
Note2: Be sure to start the receiving end AFTER starting DSD-FME. If DSD-FME is restarted, make sure to restart the receiving end as well, as socat/UDP closes the UDP port listening when DSD-FME closes the UDP socket.
|
||||
205
examples/Install_Notes.md
Normal file
205
examples/Install_Notes.md
Normal file
@@ -0,0 +1,205 @@
|
||||
## How to clone and build this branch
|
||||
|
||||
### Ubuntu 22.04/20.04/LM20/Debian Bullseye or Newer:
|
||||
|
||||
Using the included download-and-install.sh should make for a simple and painless clone, build, and install on newer Debian/Ubuntu/Mint/Pi systems. Simply acquire or copy the script, and run it. Update: Ubuntu 23.04 and RPi Bullseye 64-bit has been tested working with the installer script and functions appropriately.
|
||||
|
||||
If you need all dependencies build and installed first (only on Debian/Ubuntu/Mint/Pi), run:
|
||||
|
||||
```
|
||||
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/audio_work/download-and-install.sh
|
||||
chmod +x download-and-install.sh
|
||||
./download-and-install.sh
|
||||
```
|
||||
|
||||
### Arch Based Distros:
|
||||
|
||||
```
|
||||
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/audio_work/download-and-install-Arch.sh
|
||||
chmod +x download-and-install-Arch.sh
|
||||
./download-and-install-Arch.sh
|
||||
```
|
||||
|
||||
### Other:
|
||||
|
||||
If you have dependencies already installed, please run this instead:
|
||||
|
||||
```
|
||||
wget https://raw.githubusercontent.com/lwvmobile/dsd-fme/audio_work/download-and-install-nodeps.sh
|
||||
chmod +x download-and-install-nodeps.sh
|
||||
./download-and-install-nodeps.sh
|
||||
```
|
||||
|
||||
## Manual Install
|
||||
|
||||
First, install dependency packages. This guide will assume you are using Debian/Ubuntu based distros. Check your package manager for equivalent packages if different.
|
||||
|
||||
Debian/Mint/Ubuntu/Pi
|
||||
|
||||
```
|
||||
sudo apt update
|
||||
sudo apt install libpulse-dev pavucontrol libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev libcodec2-dev
|
||||
```
|
||||
|
||||
Fedora 36/37 -- from https://github.com/lwvmobile/dsd-fme/issues/99
|
||||
|
||||
```
|
||||
sudo dnf update
|
||||
sudo dnf install libsndfile-devel fftw-devel lapack-devel rtl-sdr-devel pulseaudio-libs-devel libusb-devel cmake git ncurses ncurses-devel gcc wget pavucontrol gcc-c++ codec2-devel
|
||||
```
|
||||
|
||||
Arch -- https://github.com/lwvmobile/dsd-fme/issues/153 and https://github.com/lwvmobile/dsd-fme/issues/153
|
||||
|
||||
```
|
||||
sudo pacman -Syu
|
||||
sudo pacman -S libpulse cmake ncurses lapack perl fftw rtl-sdr codec2 base-devel libsndfile git wget rtl-sdr
|
||||
wget https://mirror.archstrike.org/x86_64/archstrike/itpp-4.3.1-3-x86_64.pkg.tar.xz
|
||||
sudo pacman -U itpp-4.3.1-3-x86_64.pkg.tar.xz
|
||||
```
|
||||
|
||||
## Headless Ubuntu Server/Pi
|
||||
|
||||
If running headless, swap out pavucontrol for pulsemixer, and also install pulseaudio as well. Attempting to install pavucontrol in a headless environment may attempt to install a minimal desktop environment. Note: Default behavior of pulseaudio in a headless environment may be to be muted, so check by opening pulsemixer and unmuting and routing audio appropriately.
|
||||
|
||||
```
|
||||
sudo apt install libpulse-dev libsndfile1-dev libfftw3-dev liblapack-dev socat libusb-1.0-0-dev libncurses5 libncurses5-dev rtl-sdr librtlsdr-dev libusb-1.0-0-dev cmake git wget make build-essential libitpp-dev libncursesw5-dev pulsemixer pulseaudio libcodec2-dev
|
||||
```
|
||||
|
||||
### Build and Install ITPP - ONLY IF NOT IN REPO!!
|
||||
|
||||
```
|
||||
wget -O itpp-latest.tar.bz2 http://sourceforge.net/projects/itpp/files/latest/download?source=files
|
||||
tar xjf itpp*
|
||||
#if you can't cd into this folder, double check folder name first
|
||||
cd itpp-4.3.1
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
cd ..
|
||||
cd ..
|
||||
```
|
||||
|
||||
MBELib is considered a requirement in this build. You must read this notice prior to continuing. [MBElib Patent Notice](https://github.com/lwvmobile/mbelib#readme "MBElib Patent Notice")
|
||||
|
||||
```
|
||||
git clone https://github.com/lwvmobile/mbelib
|
||||
git checkout ambe_tones
|
||||
cd mbelib
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
cd ..
|
||||
cd ..
|
||||
```
|
||||
|
||||
Note: Some environment/distro users (Cygwin, Arch, and others) may need to manually copy any libmbe files found in the build folder to the /usr/lib folder on root.
|
||||
|
||||
```
|
||||
cp libmbe* /usr/lib
|
||||
cp cygmbe* /usr/lib
|
||||
cp cygmbe* /bin
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
sudo cp libmbe* /usr/lib
|
||||
sudo cp cygmbe* /usr/lib
|
||||
sudo cp cygmbe* /bin
|
||||
```
|
||||
|
||||
Finish by running these steps to clone and build DSD-FME.
|
||||
|
||||
```
|
||||
git clone https://github.com/lwvmobile/dsd-fme
|
||||
cd dsd-fme
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
|
||||
```
|
||||
|
||||
### Windows Cygwin Builds
|
||||
|
||||
If using RTL input support, you must install libusb-win32 before proceeding with Cygwin installation. You will also need to build and compile a version of librtlsdr, but this can be tricky, and personally, I had to resort to using a much older version of the source code to get it to build at all with the rtl support in the precompiled 'Aero' builds.
|
||||
|
||||
Then install all dependencies available in the repo prior to building, either directly selecting them during setup with the setup-x86.exe or setup-x64.exe or by issuing a command similar to this:
|
||||
|
||||
```
|
||||
setup-x64.exe --packages libpulse-devel,libpulse-mainloop-glib0,libpulse-simple0,libpulse0,pulseaudio,pulseaudio-debuginfo,pulseaudio-equalizer,pulseaudio-module-x11,pulseaudio-module-zeroconf,pulseaudio-utils,sox-fmt-pulseaudio,xfce-pulseaudio-plugin,libusb0,libusb1.0,libusb1.0-debuginfo,libusb1.0-devel,libncurses++w10,libncurses-devel,libncursesw10,ncurses,cmake,gcc-core,gcc-debuginfo,gcc-objc,git,make,socat,sox,sox-fmt-ao,unzip,wget,gcc-g++,libsndfile-devel
|
||||
```
|
||||
|
||||
Then manually install ITPP and MBElib, see above install notes. Be sure to run `cp libmbe* /usr/lib` after compiling MBElib.
|
||||
|
||||
Then you can build and install using
|
||||
|
||||
```
|
||||
git clone https://github.com/lwvmobile/dsd-fme
|
||||
cd dsd-fme
|
||||
mkdir build
|
||||
cd build
|
||||
# -DAERO=ON is optional, but recommended if you want the older OSS support as well
|
||||
cmake -DAERO=ON ..
|
||||
make
|
||||
make install
|
||||
```
|
||||
|
||||
### Virtual Sinks
|
||||
|
||||
You may wish to direct sound into DSD-FME via Virtual Sinks. You may set up a Virtual Sink or two on your machine for routing audio in and out of applications to other applications using the following command, and opening up pavucontrol "PulseAudio Volume Control" in the menu (or `pulsemixer` in headless mode) to change line out of application to virtual sink, and line in of DSD-FME to monitor of virtual sink. This command will not persist past a reboot, so you will need to invoke them each time you reboot, or search for how to add this to your conf files for persistency if desired. Note: This setup is completely optional if using TCP Network Sink Audio and/or RTL Input.
|
||||
|
||||
```
|
||||
pactl load-module module-null-sink sink_name=virtual_sink sink_properties=device.description=Virtual_Sink
|
||||
pactl load-module module-null-sink sink_name=virtual_sink2 sink_properties=device.description=Virtual_Sink2
|
||||
```
|
||||
|
||||
Already have this branch, and just want to pull the latest build? You can run the rebuild.sh file in the dsd-fme folder, or manually do the pull with the commands:
|
||||
|
||||
```
|
||||
##Open your clone folder##
|
||||
git pull
|
||||
##cd into your build folder##
|
||||
cd build
|
||||
cmake ..
|
||||
make -j `nproc`
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
```
|
||||
|
||||
### Applying Patches -- Recommended For Advanced Users Only
|
||||
|
||||
More experimental or potentially functionality changing or temperamental features may be included as seperate .patch files inside of the patch folder, and are not included in the source code by default.
|
||||
If users wish to try or use these patches, then they can apply patches and build/rebuild with the following procedure. Make sure you have changed to the dsd-fme directory first, either by the top
|
||||
command, or by otherwise opening the terminal to the clone folder.
|
||||
|
||||
```
|
||||
cd dsd-fme
|
||||
git apply patch/patchname.patch
|
||||
cd build
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
If you later wish to update to the latest version via `git pull`, you may first need to reset any patches, perform the `git pull`, and then reapply patches.
|
||||
A procedure for this is similar to, but not limited to:
|
||||
|
||||
```
|
||||
cd dsd-fme
|
||||
git reset --hard
|
||||
git pull
|
||||
git apply patch/xyz.patch
|
||||
cd build
|
||||
make
|
||||
sudo make install
|
||||
```
|
||||
|
||||
NOTE: Patches can potential break over time with further changes to code, requiring merge resolution or other manual intervention to re-apply patches.
|
||||
10
examples/capacity_plus_chan.csv
Normal file
10
examples/capacity_plus_chan.csv
Normal file
@@ -0,0 +1,10 @@
|
||||
LSN(dec),frequency(Hz) (do not delete this line or won't import properly)
|
||||
1,858606250
|
||||
2,858606250
|
||||
3,859606250
|
||||
4,859606250
|
||||
5,860606250
|
||||
6,860606250
|
||||
7,861606250
|
||||
8,861606250
|
||||
|
||||
|
19
examples/connect_plus_chan.csv
Normal file
19
examples/connect_plus_chan.csv
Normal file
@@ -0,0 +1,19 @@
|
||||
ChannelNumber(dec),frequency(Hz) (do not delete this line or won't import properly)
|
||||
999,862093750,default cc (come here first), optional use non-existent channel as first entry
|
||||
1,863093750
|
||||
2,862093750
|
||||
3,861093750
|
||||
4,860093750
|
||||
5,859093750
|
||||
6,863593750
|
||||
7,862593750
|
||||
8,861593750
|
||||
9,860593750
|
||||
10,859593750
|
||||
11,863393750
|
||||
12,862393750
|
||||
13,861393750
|
||||
14,860393750
|
||||
15,859393750
|
||||
|
||||
|
||||
|
8
examples/dmr_t3_chan.csv
Normal file
8
examples/dmr_t3_chan.csv
Normal file
@@ -0,0 +1,8 @@
|
||||
ChannelNumber(dec),frequency(Hz) (do not delete this line or won't import properly)
|
||||
999,456318750,default cc (come here first), optional use non-existent channel as first entry
|
||||
36,455756250
|
||||
54,455981250
|
||||
81,456318750
|
||||
|
||||
|
||||
|
||||
|
6
examples/edacs_channel_map.csv
Normal file
6
examples/edacs_channel_map.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
LSN(dec),frequency(Hz) (do not delete this line or won't import properly)
|
||||
1,851375000
|
||||
2,851800000
|
||||
3,855987500
|
||||
4,858487500
|
||||
5,852312500
|
||||
|
5
examples/group.csv
Normal file
5
examples/group.csv
Normal file
@@ -0,0 +1,5 @@
|
||||
DEC,Mode(A- Allow, B - Block, DE - Digital Enc),Name of Group,Tag (do not delete this line or won't import properly)
|
||||
100,B,Example Name,Tag
|
||||
1449,A,Fire Dispatch,Fire
|
||||
929,A,Fire Tac,Fire
|
||||
22033,DE,Law Dispatch,Law
|
||||
|
10
examples/hytera_xpt_chan.csv
Normal file
10
examples/hytera_xpt_chan.csv
Normal file
@@ -0,0 +1,10 @@
|
||||
LSN(dec),frequency(Hz) (do not delete this line or won't import properly)
|
||||
1,858606250
|
||||
2,858606250
|
||||
3,859606250
|
||||
4,859606250
|
||||
5,860606250
|
||||
6,860606250
|
||||
7,861606250
|
||||
8,861606250
|
||||
|
||||
|
6
examples/multi_key.csv
Normal file
6
examples/multi_key.csv
Normal file
@@ -0,0 +1,6 @@
|
||||
key id or tg id (dec), key number or value (dec) //NXDN Scrambler, BP, 10-char Hytera BP only
|
||||
2,70
|
||||
1,123
|
||||
100,70
|
||||
12,48713912656
|
||||
672560,254
|
||||
|
5
examples/multi_key_hex.csv
Normal file
5
examples/multi_key_hex.csv
Normal file
@@ -0,0 +1,5 @@
|
||||
key id(hex), key value (hex) //10-char Hytera BP, RC4
|
||||
1,1234567890
|
||||
2,ABCDEF1234
|
||||
C,0B57935150
|
||||
64,0B57935150
|
||||
|
8
examples/nxdn_chan_map.csv
Normal file
8
examples/nxdn_chan_map.csv
Normal file
@@ -0,0 +1,8 @@
|
||||
channel(dec), freq(Hz)
|
||||
141,423862500
|
||||
142,424337500
|
||||
143,424912500
|
||||
203,424100000
|
||||
204,424625000
|
||||
271,422650000
|
||||
302,423287500
|
||||
|
5
examples/nxdn_sc_key.csv
Normal file
5
examples/nxdn_sc_key.csv
Normal file
@@ -0,0 +1,5 @@
|
||||
key(dec) or tg(dec), value(dec), load any single keys as key 0
|
||||
0,23466
|
||||
1,12345
|
||||
2,32700
|
||||
63,32767
|
||||
|
45
examples/trunking.sh
Normal file
45
examples/trunking.sh
Normal file
@@ -0,0 +1,45 @@
|
||||
#example trunking sh scripts (SDR++ with RIGCTL and RTL Input)
|
||||
#make sure to put a # in front of all lines except the one you wish to use
|
||||
|
||||
#P25 P1 FDMA CC with C4FM
|
||||
#dsd-fme -i tcp -U 4532 -T -N 2> log.ans
|
||||
#dsd-fme -i rtl:0:850M:0:-2:12 -T -N 2> log.ans
|
||||
|
||||
#P25 P1 FDMA CC with QPSK (Simulcast)
|
||||
#dsd-fme -i tcp:192.168.7.8:7355 -U 4532 -T -mq -N 2> log.ans
|
||||
#dsd-fme -i rtl:0:855.625M:0:-2:12 -T -mq -N 2> log.ans
|
||||
|
||||
#P25 P2 TDMA CC with C4FM
|
||||
#dsd-fme -i tcp:192.168.7.8:7355 -U 4532 -T -f2 -N 2> log.ans
|
||||
#dsd-fme -i rtl:0:855.625M:0:-2:12 -T -f2 -m2 -N 2> log.ans
|
||||
|
||||
#DMR TIII, Con+, Cap+, XPT
|
||||
dsd-fme -fs -i tcp -U 4532 -T -C dmr_t3_chan.csv -G group.csv -N 2> log.ans
|
||||
#dsd-fme -fs -i rtl:0:450M:44:-2:8 -T -C connect_plus_chan.csv -G group.csv -N 2> log.ans
|
||||
|
||||
#EDACS/EDACS-EA Digital Only
|
||||
#dsd-fme -fp -i tcp:192.168.7.5:7355 -U 4532 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
||||
#dsd-fme -fp -i rtl:0:850M:44:-2:24 -T -C edacs_channel_map.csv -G group.csv -N 2> log.ans
|
||||
|
||||
#NXDN48 Type-C or Type-D Trunking with Channel Map
|
||||
#dsd-fme -fi -i tcp -T -U 4532 -C nxdn_channel_map.csv -N 2> log.ans
|
||||
#dsd-fme -fi -i rtl:0:855.625M:0:-2:12:100 -T -C nxdn_channel_map.csv -N 2> log.ans
|
||||
|
||||
#NXDN48 Type-C Trunking with DFA
|
||||
#dsd-fme -fi -i tcp -T -U 4532 -N 2> log.ans
|
||||
#dsd-fme -fi -i rtl:0:855.625M:0:-2:12:100 -T -N 2> log.ans
|
||||
|
||||
#NXDN96 Trunking with Channel Map
|
||||
#dsd-fme -fn -i tcp -T -U 4532 -C nxdn_channel_map.csv -N 2> log.ans
|
||||
#dsd-fme -fn -i rtl -T -C nxdn_channel_map.csv -N 2> log.ans
|
||||
|
||||
#Notes: parameters after -i tcp can be omitted if using localhost as the default hostname to connect
|
||||
#and 7355 as the default port number. -U is the port number for RIGCTL and will mirror the tcp hostname
|
||||
#running under the assumption that the user will be connnecting the VFO to the same instance of SDR++
|
||||
#You can also specify an ip address to connect to a remote SDR++ instance, make sure that the settings
|
||||
#inside of SDR++ match, i.e., change in SDR++ from 'localhost' to an IP to bind to (machine's IP address)
|
||||
|
||||
#Note2: RTL input should only be used on strong signal, the SDR++ VFO will perform much better on marginal signal
|
||||
#paramters after -i rtl can also be omitted now if using the default configurations
|
||||
|
||||
#Having a -G group.csv is purely optional, but useful if you want to block groups, or give groups names
|
||||
412
include/Golay24.hpp
Normal file
412
include/Golay24.hpp
Normal file
@@ -0,0 +1,412 @@
|
||||
|
||||
#ifndef GOLAY24_HPP_7a68240afda9406facf81fcad3851111
|
||||
#define GOLAY24_HPP_7a68240afda9406facf81fcad3851111
|
||||
|
||||
/**
|
||||
* Based on the work of Mr Hank Wallace.
|
||||
*
|
||||
* Code adapted from http://www.aqdi.com/golay.htm
|
||||
*
|
||||
* Tried before with the implementation from ITPP library but couldn't make it produce the same outputs
|
||||
* expected from the P25 transmissions that I have tested. This implementation does work.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define POLY 0xAE3
|
||||
|
||||
class Golay24
|
||||
{
|
||||
private:
|
||||
unsigned int golay(unsigned int cw)
|
||||
/* This function calculates [23,12] Golay codewords.
|
||||
The format of the returned int is
|
||||
[checkbits(11),data(12)]. */
|
||||
{
|
||||
int i;
|
||||
unsigned int c;
|
||||
cw&=0xfffl;
|
||||
c=cw; /* save original codeword */
|
||||
for (i=1; i<=12; i++) /* examine each data bit */
|
||||
{
|
||||
if (cw & 1) /* test data bit */
|
||||
cw^=POLY; /* XOR polynomial */
|
||||
cw>>=1; /* shift intermediate result */
|
||||
}
|
||||
return((cw<<12)|c); /* assemble codeword */
|
||||
}
|
||||
|
||||
int parity(unsigned int cw)
|
||||
/* This function checks the overall parity of codeword cw.
|
||||
If parity is even, 0 is returned, else 1. */
|
||||
{
|
||||
unsigned char p;
|
||||
|
||||
/* XOR the bytes of the codeword */
|
||||
p=*(unsigned char*)&cw;
|
||||
p^=*((unsigned char*)&cw+1);
|
||||
p^=*((unsigned char*)&cw+2);
|
||||
|
||||
/* XOR the halves of the intermediate result */
|
||||
p=p ^ (p>>4);
|
||||
p=p ^ (p>>2);
|
||||
p=p ^ (p>>1);
|
||||
|
||||
/* return the parity result */
|
||||
return(p & 1);
|
||||
}
|
||||
|
||||
unsigned int syndrome(unsigned int cw)
|
||||
/* This function calculates and returns the syndrome
|
||||
of a [23,12] Golay codeword. */
|
||||
{
|
||||
int i;
|
||||
cw&=0x7fffffl;
|
||||
for (i=1; i<=12; i++) /* examine each data bit */
|
||||
{
|
||||
if (cw & 1) /* test data bit */
|
||||
cw^=POLY; /* XOR polynomial */
|
||||
cw>>=1; /* shift intermediate result */
|
||||
}
|
||||
return(cw<<12); /* value pairs with upper bits of cw */
|
||||
}
|
||||
|
||||
int weight(unsigned int cw)
|
||||
/* This function calculates the weight of
|
||||
23 bit codeword cw. */
|
||||
{
|
||||
int bits,k;
|
||||
|
||||
/* nibble weight table */
|
||||
const char wgt[16] = {0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4};
|
||||
|
||||
bits=0; /* bit counter */
|
||||
k=0;
|
||||
/* do all bits, six nibbles max */
|
||||
while ((k<6) && (cw))
|
||||
{
|
||||
bits=bits+wgt[cw & 0xf];
|
||||
cw>>=4;
|
||||
k++;
|
||||
}
|
||||
|
||||
return(bits);
|
||||
}
|
||||
|
||||
unsigned int rotate_left(unsigned int cw, int n)
|
||||
/* This function rotates 23 bit codeword cw left by n bits. */
|
||||
{
|
||||
int i;
|
||||
|
||||
if (n != 0)
|
||||
{
|
||||
for (i=1; i<=n; i++)
|
||||
{
|
||||
if ((cw & 0x400000l) != 0)
|
||||
cw=(cw << 1) | 1;
|
||||
else
|
||||
cw<<=1;
|
||||
}
|
||||
}
|
||||
|
||||
return(cw & 0x7fffffl);
|
||||
}
|
||||
|
||||
unsigned int rotate_right(unsigned int cw, int n)
|
||||
/* This function rotates 23 bit codeword cw right by n bits. */
|
||||
{
|
||||
int i;
|
||||
|
||||
if (n != 0)
|
||||
{
|
||||
for (i=1; i<=n; i++)
|
||||
{
|
||||
if ((cw & 1) != 0)
|
||||
cw=(cw >> 1) | 0x400000l;
|
||||
else
|
||||
cw>>=1;
|
||||
}
|
||||
}
|
||||
|
||||
return(cw & 0x7fffffl);
|
||||
}
|
||||
|
||||
public:
|
||||
unsigned int correct(unsigned int cw, int *errs, unsigned int *errors_detected)
|
||||
/* This function corrects Golay [23,12] codeword cw, returning the
|
||||
corrected codeword. This function will produce the corrected codeword
|
||||
for three or fewer errors. It will produce some other valid Golay
|
||||
codeword for four or more errors, possibly not the intended
|
||||
one. *errs is set to the number of bit errors corrected. */
|
||||
{
|
||||
unsigned char
|
||||
w; /* current syndrome limit weight, 2 or 3 */
|
||||
unsigned int
|
||||
mask; /* mask for bit flipping */
|
||||
int
|
||||
i,j; /* index */
|
||||
unsigned int
|
||||
s, /* calculated syndrome */
|
||||
cwsaver; /* saves initial value of cw */
|
||||
|
||||
cwsaver=cw; /* save */
|
||||
*errs=0;
|
||||
*errors_detected = 0;
|
||||
|
||||
w=3; /* initial syndrome weight threshold */
|
||||
j=-1; /* -1 = no trial bit flipping on first pass */
|
||||
mask=1;
|
||||
while (j<23) /* flip each trial bit */
|
||||
{
|
||||
if (j != -1) /* toggle a trial bit */
|
||||
{
|
||||
if (j>0) /* restore last trial bit */
|
||||
{
|
||||
cw=cwsaver ^ mask;
|
||||
mask+=mask; /* point to next bit */
|
||||
}
|
||||
cw=cwsaver ^ mask; /* flip next trial bit */
|
||||
w=2; /* lower the threshold while bit diddling */
|
||||
}
|
||||
|
||||
s=syndrome(cw); /* look for errors */
|
||||
if (s) /* errors exist */
|
||||
{
|
||||
(*errors_detected)++;
|
||||
for (i=0; i<23; i++) /* check syndrome of each cyclic shift */
|
||||
{
|
||||
if ((*errs=weight(s)) <= w) /* syndrome matches error pattern */
|
||||
{
|
||||
cw=cw ^ s; /* remove errors */
|
||||
cw=rotate_right(cw,i); /* unrotate data */
|
||||
return(s=cw);
|
||||
}
|
||||
else
|
||||
{
|
||||
cw=rotate_left(cw,1); /* rotate to next pattern */
|
||||
s=syndrome(cw); /* calc new syndrome */
|
||||
}
|
||||
}
|
||||
j++; /* toggle next trial bit */
|
||||
}
|
||||
else
|
||||
{
|
||||
return(cw); /* return corrected codeword */
|
||||
}
|
||||
}
|
||||
|
||||
return(cwsaver); /* return original if no corrections */
|
||||
} /* correct */
|
||||
|
||||
unsigned int encode(unsigned int data)
|
||||
{
|
||||
unsigned int codeword =golay(data); /* make a test codeword */
|
||||
if (parity(codeword)) {
|
||||
codeword^=0x800000l;
|
||||
}
|
||||
|
||||
return codeword;
|
||||
}
|
||||
|
||||
unsigned int encode23(unsigned int data)
|
||||
{
|
||||
return golay(data); /* make a test codeword */
|
||||
}
|
||||
|
||||
int decode(int *errs, unsigned int *cw)
|
||||
/* This function decodes codeword *cw. Here error correction is attempted,
|
||||
with *errs set to the number of
|
||||
bits corrected, and returning 0 if no errors exist, or 1 if parity errors
|
||||
exist. */
|
||||
{
|
||||
unsigned int parity_bit;
|
||||
unsigned int detected_errors;
|
||||
parity_bit=*cw & 0x800000l; /* save parity bit */
|
||||
*cw&=~0x800000l; /* remove parity bit for correction */
|
||||
|
||||
*cw=correct(*cw, errs, &detected_errors); /* correct up to three bits */
|
||||
*cw|=parity_bit; /* restore parity bit */
|
||||
|
||||
/* check for 4 bit errors */
|
||||
if (parity(*cw)) /* odd parity is an error */
|
||||
return(1);
|
||||
|
||||
return(0); /* no errors */
|
||||
} /* decode */
|
||||
|
||||
int detect(int *errs, unsigned int cw)
|
||||
/* This function decodes codeword cw. Here error detection is performed on cw,
|
||||
returning 0 if no errors exist, 1 if an overall parity error exists, and
|
||||
2 if a codeword error exists. */
|
||||
{
|
||||
*errs=0;
|
||||
if (parity(cw)) /* odd parity is an error */
|
||||
{
|
||||
*errs=1;
|
||||
return(1);
|
||||
}
|
||||
if (syndrome(cw))
|
||||
{
|
||||
*errs=1;
|
||||
return(2);
|
||||
}
|
||||
else
|
||||
return(0); /* no errors */
|
||||
|
||||
} /* decode */
|
||||
};
|
||||
|
||||
/**
|
||||
* Convenience class that adapts Mr Wallace's implementation to the input/output format of DSD.
|
||||
* DSD works with data stored in char arrays where each element represents a bit (0 and 1 values).
|
||||
* The original implementation works with codewords that pack the 24 bits of information (12 data and
|
||||
* another 12 of parity) in an integer.
|
||||
*/
|
||||
class DSDGolay24 : public Golay24
|
||||
{
|
||||
public:
|
||||
unsigned int adapt_to_codeword(const char* word, unsigned int length, const char* parity)
|
||||
{
|
||||
unsigned int codeword = 0;
|
||||
|
||||
// Data needs to be packed with the 12 bits of parity as the most significant
|
||||
// bits and 12 bits of data as the less significant. All these discovered by trial and error.
|
||||
for (unsigned int i=0; i<12; i++) {
|
||||
assert(parity[11-i] == 0 || parity[11-i] == 1);
|
||||
codeword <<= 1;
|
||||
codeword |= parity[11-i];
|
||||
}
|
||||
for (unsigned int i=0; i<length; i++) {
|
||||
char bit = word[length-1-i];
|
||||
assert(bit == 0 || bit == 1);
|
||||
codeword <<= 1;
|
||||
codeword |= bit;
|
||||
}
|
||||
// We only have length bits of data. We fill up the less significant bits of codeword with zeros.
|
||||
if (length < 12) {
|
||||
codeword <<= (12 - length);
|
||||
}
|
||||
|
||||
return codeword;
|
||||
}
|
||||
|
||||
void adapt_to_word(unsigned int codeword, char* word, unsigned int length)
|
||||
{
|
||||
// put back in word the bits from codeword
|
||||
for (unsigned int i=0, mask = 1<<(12-length); i<length; i++, mask<<=1) {
|
||||
word[i] = (codeword & mask) != 0? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int adapt_from_word(char* word, unsigned int length)
|
||||
{
|
||||
unsigned int codeword = 0;
|
||||
|
||||
// encode the hex bits into a codeword
|
||||
for (unsigned int i=0; i<length; i++) {
|
||||
int bit = word[length-1-i];
|
||||
assert(bit == 0 || bit == 1);
|
||||
codeword <<= 1;
|
||||
codeword |= bit;
|
||||
}
|
||||
|
||||
// We only have length bits of data. We fill up the less significant bits of codeword with zeros.
|
||||
if (length < 12) {
|
||||
codeword <<= (12-length);
|
||||
}
|
||||
|
||||
return codeword;
|
||||
}
|
||||
|
||||
/**
|
||||
* Important method that takes an hex word, a 12 bit parity word and uses the Golay24 implementation
|
||||
* to error correct it.
|
||||
* \param hex The data to error correct, packed in an array of 6 chars, representing a bit each.
|
||||
* \param parity The 12 bits of parity packed in an array of chars.
|
||||
* \param fixed_errors Output argument, returns the number of errors detected and fixed.
|
||||
* \return 1 if we were unable to correct the hex word. Too many errors detected.
|
||||
* in this case the original data remains unchanged.
|
||||
* 0 if the data was successfully error corrected.
|
||||
*/
|
||||
int decode_6(char* hex, const char* parity, int* fixed_errors)
|
||||
{
|
||||
unsigned int codeword = adapt_to_codeword(hex, 6, parity);
|
||||
// codeword now contains:
|
||||
// bits 0- 5: zeros
|
||||
// bits 6-11: hex bits
|
||||
// bits 12-23: golay (24,12) parity bits
|
||||
|
||||
// bits are ordered from left to right, so bit 0 is the most significant and bit 23 is the less.
|
||||
|
||||
int uncorrectable_errors = Golay24::decode(fixed_errors, &codeword);
|
||||
|
||||
// codeword is now hopefully fixed
|
||||
|
||||
// If there are uncorrectable errors and the fixed proposal includes ones
|
||||
// in bits 0-5 then probably the fix is not good and we discard it.
|
||||
// Bits 0-5 should always be zero, if there is a problem it's on the other bits
|
||||
// from 6 to 24.
|
||||
if (uncorrectable_errors == 1 && (codeword & 0x3f) != 0) {
|
||||
// discard, don't touch hex
|
||||
} else {
|
||||
// put it back into our hex format
|
||||
adapt_to_word(codeword, hex, 6);
|
||||
uncorrectable_errors = 0;
|
||||
}
|
||||
|
||||
return uncorrectable_errors;
|
||||
}
|
||||
|
||||
int decode_12(char* dodeca, const char* parity, int* fixed_errors)
|
||||
{
|
||||
unsigned int codeword = adapt_to_codeword(dodeca, 12, parity);
|
||||
// codeword contains:
|
||||
// bits 0-11: dodeca bits
|
||||
// bits 12-23: golay (24,12) parity bits
|
||||
|
||||
// bits are ordered from left to right, so bit 0 is the most significant and bit 23 is the less.
|
||||
|
||||
int uncorrectable_errors = Golay24::decode(fixed_errors, &codeword);
|
||||
|
||||
// codeword is now hopefully fixed
|
||||
|
||||
// If there are uncorrectable errors and the fixed proposal includes ones
|
||||
// in bits 0-5 then probably the fix is not good and we discard it.
|
||||
// Bits 0-5 should always be zero, if there is a problem it's on the other bits
|
||||
// from 6 to 24.
|
||||
if (uncorrectable_errors == 1 && (codeword & 0x3f) != 0) {
|
||||
// discard, don't touch hex
|
||||
} else {
|
||||
// put it back into our hex format
|
||||
adapt_to_word(codeword, dodeca, 12);
|
||||
uncorrectable_errors = 0;
|
||||
}
|
||||
|
||||
return uncorrectable_errors;
|
||||
}
|
||||
|
||||
void encode_6(char* hex, char* out_parity)
|
||||
{
|
||||
unsigned int data = adapt_from_word(hex, 6);
|
||||
unsigned int codeword = Golay24::encode(data);
|
||||
|
||||
// Fill up the parity
|
||||
for (unsigned int i=0, mask = 1<<12; i<12; i++, mask<<=1) {
|
||||
out_parity[i] = (codeword & mask) != 0? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
void encode_12(char* dodeca, char* out_parity)
|
||||
{
|
||||
unsigned int data = adapt_from_word(dodeca, 12);
|
||||
unsigned int codeword = Golay24::encode(data);
|
||||
|
||||
// Fill up the parity
|
||||
for (unsigned int i=0, mask = 1<<12; i<12; i++, mask<<=1) {
|
||||
out_parity[i] = (codeword & mask) != 0? 1 : 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // GOLAY24_HPP_7a68240afda9406facf81fcad3851111
|
||||
413
include/Hamming.hpp
Normal file
413
include/Hamming.hpp
Normal file
@@ -0,0 +1,413 @@
|
||||
|
||||
#ifndef HAMMING_HPP_e7123c3795b94d14b5774d5d8f016a04
|
||||
#define HAMMING_HPP_e7123c3795b94d14b5774d5d8f016a04
|
||||
|
||||
#include <bitset>
|
||||
#include <string>
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
#include <iostream>
|
||||
|
||||
/**
|
||||
* \brief Holds data for the Hamming_10_6_3 class. See next.
|
||||
*/
|
||||
class Hamming_10_6_3_data
|
||||
{
|
||||
public:
|
||||
std::bitset<10> g0;
|
||||
std::bitset<10> g1;
|
||||
std::bitset<10> g2;
|
||||
std::bitset<10> g3;
|
||||
std::bitset<10> g4;
|
||||
std::bitset<10> g5;
|
||||
|
||||
std::bitset<6> gt0;
|
||||
std::bitset<6> gt1;
|
||||
std::bitset<6> gt2;
|
||||
std::bitset<6> gt3;
|
||||
|
||||
std::bitset<10> h0;
|
||||
std::bitset<10> h1;
|
||||
std::bitset<10> h2;
|
||||
std::bitset<10> h3;
|
||||
|
||||
int bad_bit_table[16];
|
||||
|
||||
Hamming_10_6_3_data()
|
||||
{
|
||||
// G matrix come from the APCO 25 reference documentation:
|
||||
g0 = std::bitset<10>(std::string("1000001110"));
|
||||
g1 = std::bitset<10>(std::string("0100001101"));
|
||||
g2 = std::bitset<10>(std::string("0010001011"));
|
||||
g3 = std::bitset<10>(std::string("0001000111"));
|
||||
g4 = std::bitset<10>(std::string("0000100011"));
|
||||
g5 = std::bitset<10>(std::string("0000011100"));
|
||||
|
||||
gt0 = std::bitset<6>(std::string("111001"));
|
||||
gt1 = std::bitset<6>(std::string("110101"));
|
||||
gt2 = std::bitset<6>(std::string("101110"));
|
||||
gt3 = std::bitset<6>(std::string("011110"));
|
||||
|
||||
// H matrix, calculated transposing G. See wikipedia.
|
||||
h0 = std::bitset<10>(std::string("1110011000"));
|
||||
h1 = std::bitset<10>(std::string("1101010100"));
|
||||
h2 = std::bitset<10>(std::string("1011100010"));
|
||||
h3 = std::bitset<10>(std::string("0111100001"));
|
||||
|
||||
// bad_bit_table indicates which is the bit to correct from the calculated syndromes.
|
||||
// It's calculated from the previous matrices: See the left-most column of the matrix whose rows are
|
||||
// h0,h1,h2 and h3. It's [1 1 1 0]. It means: when the syndrome value is the binary number 1110, the
|
||||
// bit that is wrong is the bit 9 (the left-most column is for the bit 9). Another example with
|
||||
// the right-most column: it's column is [0 0 0 1], so when the syndrome is 0001, the bit to fix is
|
||||
// bit 0 (one of the parity bits).
|
||||
bad_bit_table[ 1] = 0;
|
||||
bad_bit_table[ 2] = 1;
|
||||
bad_bit_table[ 4] = 2;
|
||||
bad_bit_table[ 8] = 3;
|
||||
bad_bit_table[12] = 4;
|
||||
bad_bit_table[ 3] = 5;
|
||||
bad_bit_table[ 7] = 6;
|
||||
bad_bit_table[11] = 7;
|
||||
bad_bit_table[13] = 8;
|
||||
bad_bit_table[14] = 9;
|
||||
|
||||
// If the syndrome is zero, then the data is correct, no errors detected.
|
||||
bad_bit_table[ 0] = -2;
|
||||
|
||||
// Incorrect values, if the syndrome gets one of this values, then we fail to correct the data.
|
||||
bad_bit_table[ 5] = -1;
|
||||
bad_bit_table[ 6] = -1;
|
||||
bad_bit_table[ 9] = -1;
|
||||
bad_bit_table[10] = -1;
|
||||
bad_bit_table[15] = -1;
|
||||
}
|
||||
};
|
||||
|
||||
class Hamming_15_11_3_data
|
||||
{
|
||||
public:
|
||||
std::bitset<15> g0;
|
||||
std::bitset<15> g1;
|
||||
std::bitset<15> g2;
|
||||
std::bitset<15> g3;
|
||||
std::bitset<15> g4;
|
||||
std::bitset<15> g5;
|
||||
std::bitset<15> g6;
|
||||
std::bitset<15> g7;
|
||||
std::bitset<15> g8;
|
||||
std::bitset<15> g9;
|
||||
std::bitset<15> g10;
|
||||
|
||||
|
||||
std::bitset<11> gt0;
|
||||
std::bitset<11> gt1;
|
||||
std::bitset<11> gt2;
|
||||
std::bitset<11> gt3;
|
||||
|
||||
std::bitset<15> h0;
|
||||
std::bitset<15> h1;
|
||||
std::bitset<15> h2;
|
||||
std::bitset<15> h3;
|
||||
|
||||
int bad_bit_table[16];
|
||||
|
||||
Hamming_15_11_3_data()
|
||||
{
|
||||
// G matrix come from the APCO 25 reference documentation:
|
||||
g0 = std::bitset<15>(std::string("100000000001111"));
|
||||
g1 = std::bitset<15>(std::string("010000000001110"));
|
||||
g2 = std::bitset<15>(std::string("001000000001101"));
|
||||
g3 = std::bitset<15>(std::string("000100000001100"));
|
||||
g4 = std::bitset<15>(std::string("000010000001011"));
|
||||
g5 = std::bitset<15>(std::string("000001000001010"));
|
||||
g6 = std::bitset<15>(std::string("000000100001001"));
|
||||
g7 = std::bitset<15>(std::string("000000010000111"));
|
||||
g8 = std::bitset<15>(std::string("000000001000110"));
|
||||
g9 = std::bitset<15>(std::string("000000000100101"));
|
||||
g10 = std::bitset<15>(std::string("000000000010011"));
|
||||
|
||||
gt0 = std::bitset<11>(std::string("11111110000"));
|
||||
gt1 = std::bitset<11>(std::string("11110001110"));
|
||||
gt2 = std::bitset<11>(std::string("11001101101"));
|
||||
gt3 = std::bitset<11>(std::string("10101011011"));
|
||||
|
||||
// H matrix, calculated transposing G. See wikipedia.
|
||||
h0 = std::bitset<15>(std::string("111111100001000"));
|
||||
h1 = std::bitset<15>(std::string("111100011100100"));
|
||||
h2 = std::bitset<15>(std::string("110011011010010"));
|
||||
h3 = std::bitset<15>(std::string("101010110110001"));
|
||||
|
||||
// bad_bit_table indicates which is the bit to correct from the calculated syndromes.
|
||||
// It's calculated from the previous matrices: See the left-most column of the matrix whose rows are
|
||||
// h0,h1,h2 and h3. It's [1 1 1 0]. It means: when the syndrome value is the binary number 1110, the
|
||||
// bit that is wrong is the bit 9 (the left-most column is for the bit 9). Another example with
|
||||
// the right-most column: it's column is [0 0 0 1], so when the syndrome is 0001, the bit to fix is
|
||||
// bit 0 (one of the parity bits).
|
||||
bad_bit_table[ 1] = 0;
|
||||
bad_bit_table[ 2] = 1;
|
||||
bad_bit_table[ 4] = 2;
|
||||
bad_bit_table[ 8] = 3;
|
||||
bad_bit_table[12] = 4;
|
||||
bad_bit_table[ 3] = 5;
|
||||
bad_bit_table[ 7] = 6;
|
||||
bad_bit_table[11] = 7;
|
||||
bad_bit_table[13] = 8;
|
||||
bad_bit_table[14] = 9;
|
||||
|
||||
// If the syndrome is zero, then the data is correct, no errors detected.
|
||||
bad_bit_table[ 0] = -2;
|
||||
|
||||
// Incorrect values, if the syndrome gets one of this values, then we fail to correct the data.
|
||||
bad_bit_table[ 5] = -1;
|
||||
bad_bit_table[ 6] = -1;
|
||||
bad_bit_table[ 9] = -1;
|
||||
bad_bit_table[10] = -1;
|
||||
bad_bit_table[15] = -1;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An interface used by the two implementations defined here.
|
||||
*/
|
||||
class Hamming_Inteface
|
||||
{
|
||||
public:
|
||||
virtual ~Hamming_Inteface()
|
||||
{
|
||||
// Does nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Decodes using the Hamming (10,6,3) algorithm a sequence of 10 bits expressed as an integer.
|
||||
* \arg input The number to decode.
|
||||
* \arg output A pointer to int where the decoded result is stored.
|
||||
* \return Count of detected errors.
|
||||
*/
|
||||
virtual int decode(int input, int* output) = 0;
|
||||
|
||||
/**
|
||||
* \brief Decodes using the Hamming (10,6,3) algorithm a sequence of 10 bits expressed as a pointer
|
||||
* to six chars (data) and a pointer to four chars (parity). Altogether ten chars, each holding one bit.
|
||||
* \arg hex A pointer to six chars. If error are detected the values are modified acordingly.
|
||||
* \arg parity A pointer to four chars. Represent the parity of the data.
|
||||
* \return Count of detected errors.
|
||||
*/
|
||||
virtual int decode(char* hex, char* parity) = 0;
|
||||
|
||||
virtual int encode(int input) = 0;
|
||||
|
||||
virtual void encode(char* hex, char* out_parity) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Hamming (10,6,3) error correction implementation.
|
||||
*/
|
||||
class Hamming_10_6_3 : public Hamming_Inteface
|
||||
{
|
||||
private:
|
||||
static Hamming_10_6_3_data data;
|
||||
|
||||
public:
|
||||
/**
|
||||
* \brief Decodes using the Hamming (10,6,3) algorithm a sequence of 10 bits expressed as a std::bitset.
|
||||
* \arg input The sequence to decode.
|
||||
* \return Count of detected errors.
|
||||
*/
|
||||
int decode(std::bitset<10>& input);
|
||||
|
||||
int decode(int input, int* output)
|
||||
{
|
||||
assert (input < 1024 && input >= 0);
|
||||
|
||||
std::bitset<10> bitset_input(input);
|
||||
int error_count = decode(bitset_input);
|
||||
if (error_count == 1) {
|
||||
// t has possibly been modified
|
||||
input = (int)bitset_input.to_ulong();
|
||||
} else {
|
||||
// both in case that there were no errors or there were irrecoverable errors we leave the data as
|
||||
// it is
|
||||
}
|
||||
|
||||
// discard the four parity bits at the end
|
||||
*output = input >> 4;
|
||||
|
||||
return error_count;
|
||||
}
|
||||
|
||||
int decode(char* hex, char* parity)
|
||||
{
|
||||
// Make a bitset from hex and parity
|
||||
std::bitset<10> value;
|
||||
// in the bitset 9 is the left-most and 0 is the right-most
|
||||
for (unsigned int i=0; i<6; i++) {
|
||||
value[9-i] = (hex[i] == 1)? true : false;
|
||||
}
|
||||
for (unsigned int i=0; i<4; i++) {
|
||||
value[3-i] = (parity[i] == 1)? true : false;
|
||||
}
|
||||
|
||||
int error_count = decode(value);
|
||||
|
||||
// Modify hex if needed
|
||||
if (error_count == 1) {
|
||||
for (unsigned int i=0; i<6; i++) {
|
||||
hex[i] = value[9-i];
|
||||
}
|
||||
} else {
|
||||
// No errors or irrecoverable errors, in both cases don't touch the input
|
||||
}
|
||||
|
||||
return error_count;
|
||||
}
|
||||
|
||||
int encode(std::bitset<6>& input);
|
||||
|
||||
int encode(int input)
|
||||
{
|
||||
assert (input < 64 && input >= 0);
|
||||
|
||||
std::bitset<6> bitset_input(input);
|
||||
|
||||
return encode(bitset_input);
|
||||
}
|
||||
|
||||
void encode(char* hex, char* out_parity)
|
||||
{
|
||||
// Make a bitset from hex
|
||||
std::bitset<6> value;
|
||||
// in the bitset 5 is the left-most and 0 is the right-most
|
||||
for (unsigned int i=0; i<6; i++) {
|
||||
value[5-i] = (hex[i] == 1)? true : false;
|
||||
}
|
||||
|
||||
int parity = encode(value);
|
||||
|
||||
// Put the calculated parity in the form of a char array
|
||||
for (int i=3; i>=0; i--) {
|
||||
out_parity[i] = parity & 1;
|
||||
parity >>= 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Stores data for the Hamming_10_6_3_TableImpl that comes next.
|
||||
*/
|
||||
class Hamming_10_6_3_TableImpl_data
|
||||
{
|
||||
public:
|
||||
int fixed_values[1024];
|
||||
int error_counts[1024];
|
||||
int encode_parities[64];
|
||||
|
||||
/**
|
||||
* \brief On initialization it builds a table to calculate every possible outcome (there are 1024) before
|
||||
* hand. Uses Hamming_10_6_3 to build the table.
|
||||
*/
|
||||
Hamming_10_6_3_TableImpl_data()
|
||||
{
|
||||
Hamming_10_6_3 hamming;
|
||||
|
||||
// Build the tables
|
||||
for (int i=0; i<1024; i++) {
|
||||
int fixed;
|
||||
int error_count = hamming.decode(i, &fixed);
|
||||
fixed_values[i] = fixed;
|
||||
error_counts[i] = error_count;
|
||||
}
|
||||
|
||||
for (int i=0; i<64; i++) {
|
||||
int parity = hamming.encode(i);
|
||||
encode_parities[i] = parity;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* \brief Hamming (10,6,3) error correction implementation.
|
||||
*/
|
||||
class Hamming_10_6_3_TableImpl : public Hamming_Inteface
|
||||
{
|
||||
private:
|
||||
static Hamming_10_6_3_TableImpl_data data;
|
||||
|
||||
public:
|
||||
int decode(int input, int* output);
|
||||
|
||||
static int convert_hex_to_int(char* hex)
|
||||
{
|
||||
// Make an int from hex
|
||||
int value = 0;
|
||||
// in the bitset 9 is the left-most and 0 is the right-most
|
||||
for (unsigned int i=0; i<6; i++) {
|
||||
assert(hex[i] == 0 || hex[i] == 1);
|
||||
value <<= 1;
|
||||
value |= hex[i];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static int convert_hex_parity_to_int(char* hex, char* parity)
|
||||
{
|
||||
// Make an int from hex and parity
|
||||
int value = 0;
|
||||
// in the bitset 9 is the left-most and 0 is the right-most
|
||||
for (unsigned int i=0; i<6; i++) {
|
||||
assert(hex[i] == 0 || hex[i] == 1);
|
||||
value <<= 1;
|
||||
value |= hex[i];
|
||||
}
|
||||
for (unsigned int i=0; i<4; i++) {
|
||||
assert(parity[i] == 0 || parity[i] == 1);
|
||||
value <<= 1;
|
||||
value |= parity[i];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
static void convert_int_to_hex(int value, char* hex)
|
||||
{
|
||||
unsigned int v = value;
|
||||
for (unsigned int i=0; i<6; i++) {
|
||||
hex[5-i] = v & 1;
|
||||
v >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
int decode(char* hex, char* parity)
|
||||
{
|
||||
int value = convert_hex_parity_to_int(hex, parity);
|
||||
int fixed;
|
||||
int error_count = decode(value, &fixed);
|
||||
|
||||
// Modify hex if needed
|
||||
if (error_count == 1) {
|
||||
convert_int_to_hex(fixed, hex);
|
||||
} else {
|
||||
// No errors or irrecoverable errors, in both cases don't touch the input
|
||||
}
|
||||
|
||||
return error_count;
|
||||
}
|
||||
|
||||
int encode(int input);
|
||||
|
||||
void encode(char* hex, char* out_parity)
|
||||
{
|
||||
int value = convert_hex_to_int(hex);
|
||||
int parity = encode(value);
|
||||
|
||||
// Put the calculated parity in the form of a char array
|
||||
for (int i=3; i>=0; i--) {
|
||||
out_parity[i] = parity & 1;
|
||||
parity >>= 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // HAMMING_HPP_e7123c3795b94d14b5774d5d8f016a04
|
||||
670
include/ReedSolomon.hpp
Normal file
670
include/ReedSolomon.hpp
Normal file
@@ -0,0 +1,670 @@
|
||||
|
||||
#ifndef REEDSOLOMON_HPP_b1405fdab6374ba2a4e65e8d45ec3d80
|
||||
#define REEDSOLOMON_HPP_b1405fdab6374ba2a4e65e8d45ec3d80
|
||||
|
||||
/**
|
||||
* Code taken and adapted from www.eccpage.com/rs.c
|
||||
* Credit goes to Mr Simon Rockliff.
|
||||
*
|
||||
* Tried before with the implementation from ITPP library but couldn't make it produce the same outputs
|
||||
* expected from the P25 transmissions that I have tested. This implementation does work.
|
||||
*/
|
||||
|
||||
/* This program is an encoder/decoder for Reed-Solomon codes. Encoding is in
|
||||
systematic form, decoding via the Berlekamp iterative algorithm.
|
||||
In the present form , the constants mm, nn, tt, and kk=nn-2tt must be
|
||||
specified (the double letters are used simply to avoid clashes with
|
||||
other n,k,t used in other programs into which this was incorporated!)
|
||||
Also, the irreducible polynomial used to generate GF(2**mm) must also be
|
||||
entered -- these can be found in Lin and Costello, and also Clark and Cain.
|
||||
|
||||
The representation of the elements of GF(2**m) is either in index form,
|
||||
where the number is the power of the primitive element alpha, which is
|
||||
convenient for multiplication (add the powers modulo 2**m-1) or in
|
||||
polynomial form, where the bits represent the coefficients of the
|
||||
polynomial representation of the number, which is the most convenient form
|
||||
for addition. The two forms are swapped between via lookup tables.
|
||||
This leads to fairly messy looking expressions, but unfortunately, there
|
||||
is no easy alternative when working with Galois arithmetic.
|
||||
|
||||
The code is not written in the most elegant way, but to the best
|
||||
of my knowledge, (no absolute guarantees!), it works.
|
||||
However, when including it into a simulation program, you may want to do
|
||||
some conversion of global variables (used here because I am lazy!) to
|
||||
local variables where appropriate, and passing parameters (eg array
|
||||
addresses) to the functions may be a sensible move to reduce the number
|
||||
of global variables and thus decrease the chance of a bug being introduced.
|
||||
|
||||
This program does not handle erasures at present, but should not be hard
|
||||
to adapt to do this, as it is just an adjustment to the Berlekamp-Massey
|
||||
algorithm. It also does not attempt to decode past the BCH bound -- see
|
||||
Blahut "Theory and practice of error control codes" for how to do this.
|
||||
|
||||
Simon Rockliff, University of Adelaide 21/9/89
|
||||
|
||||
26/6/91 Slight modifications to remove a compiler dependent bug which hadn't
|
||||
previously surfaced. A few extra comments added for clarity.
|
||||
Appears to all work fine, ready for posting to net!
|
||||
|
||||
Notice
|
||||
--------
|
||||
This program may be freely modified and/or given to whoever wants it.
|
||||
A condition of such distribution is that the author's contribution be
|
||||
acknowledged by his name being left in the comments heading the program,
|
||||
however no responsibility is accepted for any financial or other loss which
|
||||
may result from some unforseen errors or malfunctioning of the program
|
||||
during use.
|
||||
Simon Rockliff, 26th June 1991
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
|
||||
template <int TT>
|
||||
class ReedSolomon_63
|
||||
{
|
||||
private:
|
||||
static const int MM = 6; /* RS code over GF(2**mm) */
|
||||
static const int NN = 63; /* nn=2**mm -1 length of codeword */
|
||||
//int tt; /* number of errors that can be corrected */
|
||||
//int kk; /* kk = nn-2*tt */
|
||||
static const int KK = NN-2*TT;
|
||||
// distance = nn-kk+1 = 2*tt+1
|
||||
|
||||
int* alpha_to;
|
||||
int* index_of;
|
||||
int* gg;
|
||||
|
||||
void generate_gf(int* generator_polinomial)
|
||||
/* generate GF(2**mm) from the irreducible polynomial p(X) in pp[0]..pp[mm]
|
||||
lookup tables: index->polynomial form alpha_to[] contains j=alpha**i;
|
||||
polynomial form -> index form index_of[j=alpha**i] = i
|
||||
alpha=2 is the primitive element of GF(2**mm)
|
||||
*/
|
||||
{
|
||||
register int i, mask;
|
||||
|
||||
mask = 1;
|
||||
alpha_to[MM] = 0;
|
||||
for (i = 0; i < MM; i++) {
|
||||
alpha_to[i] = mask;
|
||||
index_of[alpha_to[i]] = i;
|
||||
if (generator_polinomial[i] != 0)
|
||||
alpha_to[MM] ^= mask;
|
||||
mask <<= 1;
|
||||
}
|
||||
index_of[alpha_to[MM]] = MM;
|
||||
mask >>= 1;
|
||||
for (i = MM + 1; i < NN; i++) {
|
||||
if (alpha_to[i - 1] >= mask)
|
||||
alpha_to[i] = alpha_to[MM] ^ ((alpha_to[i - 1] ^ mask) << 1);
|
||||
else
|
||||
alpha_to[i] = alpha_to[i - 1] << 1;
|
||||
index_of[alpha_to[i]] = i;
|
||||
}
|
||||
index_of[0] = -1;
|
||||
}
|
||||
|
||||
void gen_poly()
|
||||
/* Obtain the generator polynomial of the tt-error correcting, length
|
||||
nn=(2**mm -1) Reed Solomon code from the product of (X+alpha**i), i=1..2*tt
|
||||
*/
|
||||
{
|
||||
register int i, j;
|
||||
|
||||
gg[0] = 2; /* primitive element alpha = 2 for GF(2**mm) */
|
||||
gg[1] = 1; /* g(x) = (X+alpha) initially */
|
||||
for (i = 2; i <= NN - KK; i++) {
|
||||
gg[i] = 1;
|
||||
for (j = i - 1; j > 0; j--)
|
||||
if (gg[j] != 0)
|
||||
gg[j] = gg[j - 1] ^ alpha_to[(index_of[gg[j]] + i) % NN];
|
||||
else
|
||||
gg[j] = gg[j - 1];
|
||||
gg[0] = alpha_to[(index_of[gg[0]] + i) % NN]; /* gg[0] can never be zero */
|
||||
}
|
||||
/* convert gg[] to index form for quicker encoding */
|
||||
for (i = 0; i <= NN - KK; i++)
|
||||
gg[i] = index_of[gg[i]];
|
||||
}
|
||||
|
||||
public:
|
||||
ReedSolomon_63()
|
||||
{
|
||||
alpha_to = new int[NN + 1];
|
||||
index_of = new int[NN + 1];
|
||||
gg = new int[NN - KK + 1];
|
||||
|
||||
// Polynom used in P25 is alpha**6+alpha+1
|
||||
int generator_polinomial[] = { 1, 1, 0, 0, 0, 0, 1 }; /* specify irreducible polynomial coeffts */
|
||||
|
||||
generate_gf(generator_polinomial);
|
||||
|
||||
gen_poly();
|
||||
}
|
||||
|
||||
virtual ~ReedSolomon_63()
|
||||
{
|
||||
delete[] gg;
|
||||
delete[] index_of;
|
||||
delete[] alpha_to;
|
||||
}
|
||||
|
||||
void encode(const int* data, int* bb)
|
||||
/* take the string of symbols in data[i], i=0..(k-1) and encode systematically
|
||||
to produce 2*tt parity symbols in bb[0]..bb[2*tt-1]
|
||||
data[] is input and bb[] is output in polynomial form.
|
||||
Encoding is done by using a feedback shift register with appropriate
|
||||
connections specified by the elements of gg[], which was generated above.
|
||||
Codeword is c(X) = data(X)*X**(nn-kk)+ b(X) */
|
||||
{
|
||||
register int i, j;
|
||||
int feedback;
|
||||
|
||||
for (i = 0; i < NN - KK; i++)
|
||||
bb[i] = 0;
|
||||
for (i = KK - 1; i >= 0; i--) {
|
||||
feedback = index_of[data[i] ^ bb[NN - KK - 1]];
|
||||
if (feedback != -1) {
|
||||
for (j = NN - KK - 1; j > 0; j--)
|
||||
if (gg[j] != -1)
|
||||
bb[j] = bb[j - 1] ^ alpha_to[(gg[j] + feedback) % NN];
|
||||
else
|
||||
bb[j] = bb[j - 1];
|
||||
bb[0] = alpha_to[(gg[0] + feedback) % NN];
|
||||
} else {
|
||||
for (j = NN - KK - 1; j > 0; j--)
|
||||
bb[j] = bb[j - 1];
|
||||
bb[0] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int decode(const int* input, int* recd)
|
||||
/* assume we have received bits grouped into mm-bit symbols in recd[i],
|
||||
i=0..(nn-1), and recd[i] is polynomial form.
|
||||
We first compute the 2*tt syndromes by substituting alpha**i into rec(X) and
|
||||
evaluating, storing the syndromes in s[i], i=1..2tt (leave s[0] zero) .
|
||||
Then we use the Berlekamp iteration to find the error location polynomial
|
||||
elp[i]. If the degree of the elp is >tt, we cannot correct all the errors
|
||||
and hence just put out the information symbols uncorrected. If the degree of
|
||||
elp is <=tt, we substitute alpha**i , i=1..n into the elp to get the roots,
|
||||
hence the inverse roots, the error location numbers. If the number of errors
|
||||
located does not equal the degree of the elp, we have more than tt errors
|
||||
and cannot correct them. Otherwise, we then solve for the error value at
|
||||
the error location and correct the error. The procedure is that found in
|
||||
Lin and Costello. For the cases where the number of errors is known to be too
|
||||
large to correct, the information symbols as received are output (the
|
||||
advantage of systematic encoding is that hopefully some of the information
|
||||
symbols will be okay and that if we are in luck, the errors are in the
|
||||
parity part of the transmitted codeword). Of course, these insoluble cases
|
||||
can be returned as error flags to the calling routine if desired. */
|
||||
{
|
||||
register int i, j, u, q;
|
||||
int elp[NN - KK + 2][NN - KK], d[NN - KK + 2], l[NN - KK + 2], u_lu[NN - KK
|
||||
+ 2], s[NN - KK + 1];
|
||||
int count = 0, syn_error = 0, root[TT], loc[TT], z[TT + 1], err[NN], reg[TT
|
||||
+ 1];
|
||||
|
||||
int irrecoverable_error = 0;
|
||||
|
||||
for (int i = 0; i < NN; i++)
|
||||
recd[i] = index_of[input[i]]; /* put recd[i] into index form (ie as powers of alpha) */
|
||||
|
||||
/* first form the syndromes */
|
||||
for (i = 1; i <= NN - KK; i++) {
|
||||
s[i] = 0;
|
||||
for (j = 0; j < NN; j++)
|
||||
if (recd[j] != -1)
|
||||
s[i] ^= alpha_to[(recd[j] + i * j) % NN]; /* recd[j] in index form */
|
||||
/* convert syndrome from polynomial form to index form */
|
||||
if (s[i] != 0)
|
||||
syn_error = 1; /* set flag if non-zero syndrome => error */
|
||||
s[i] = index_of[s[i]];
|
||||
}
|
||||
|
||||
if (syn_error) /* if errors, try and correct */
|
||||
{
|
||||
/* compute the error location polynomial via the Berlekamp iterative algorithm,
|
||||
following the terminology of Lin and Costello : d[u] is the 'mu'th
|
||||
discrepancy, where u='mu'+1 and 'mu' (the Greek letter!) is the step number
|
||||
ranging from -1 to 2*tt (see L&C), l[u] is the
|
||||
degree of the elp at that step, and u_l[u] is the difference between the
|
||||
step number and the degree of the elp.
|
||||
*/
|
||||
/* initialise table entries */
|
||||
d[0] = 0; /* index form */
|
||||
d[1] = s[1]; /* index form */
|
||||
elp[0][0] = 0; /* index form */
|
||||
elp[1][0] = 1; /* polynomial form */
|
||||
for (i = 1; i < NN - KK; i++) {
|
||||
elp[0][i] = -1; /* index form */
|
||||
elp[1][i] = 0; /* polynomial form */
|
||||
}
|
||||
l[0] = 0;
|
||||
l[1] = 0;
|
||||
u_lu[0] = -1;
|
||||
u_lu[1] = 0;
|
||||
u = 0;
|
||||
|
||||
do {
|
||||
u++;
|
||||
if (d[u] == -1) {
|
||||
l[u + 1] = l[u];
|
||||
for (i = 0; i <= l[u]; i++) {
|
||||
elp[u + 1][i] = elp[u][i];
|
||||
elp[u][i] = index_of[elp[u][i]];
|
||||
}
|
||||
} else
|
||||
/* search for words with greatest u_lu[q] for which d[q]!=0 */
|
||||
{
|
||||
q = u - 1;
|
||||
while ((d[q] == -1) && (q > 0))
|
||||
q--;
|
||||
/* have found first non-zero d[q] */
|
||||
if (q > 0) {
|
||||
j = q;
|
||||
do {
|
||||
j--;
|
||||
if ((d[j] != -1) && (u_lu[q] < u_lu[j]))
|
||||
q = j;
|
||||
} while (j > 0);
|
||||
};
|
||||
|
||||
/* have now found q such that d[u]!=0 and u_lu[q] is maximum */
|
||||
/* store degree of new elp polynomial */
|
||||
if (l[u] > l[q] + u - q)
|
||||
l[u + 1] = l[u];
|
||||
else
|
||||
l[u + 1] = l[q] + u - q;
|
||||
|
||||
/* form new elp(x) */
|
||||
for (i = 0; i < NN - KK; i++)
|
||||
elp[u + 1][i] = 0;
|
||||
for (i = 0; i <= l[q]; i++)
|
||||
if (elp[q][i] != -1)
|
||||
elp[u + 1][i + u - q] = alpha_to[(d[u] + NN - d[q]
|
||||
+ elp[q][i]) % NN];
|
||||
for (i = 0; i <= l[u]; i++) {
|
||||
elp[u + 1][i] ^= elp[u][i];
|
||||
elp[u][i] = index_of[elp[u][i]]; /*convert old elp value to index*/
|
||||
}
|
||||
}
|
||||
u_lu[u + 1] = u - l[u + 1];
|
||||
|
||||
/* form (u+1)th discrepancy */
|
||||
if (u < NN - KK) /* no discrepancy computed on last iteration */
|
||||
{
|
||||
if (s[u + 1] != -1)
|
||||
d[u + 1] = alpha_to[s[u + 1]];
|
||||
else
|
||||
d[u + 1] = 0;
|
||||
for (i = 1; i <= l[u + 1]; i++)
|
||||
if ((s[u + 1 - i] != -1) && (elp[u + 1][i] != 0))
|
||||
d[u + 1] ^= alpha_to[(s[u + 1 - i]
|
||||
+ index_of[elp[u + 1][i]]) % NN];
|
||||
d[u + 1] = index_of[d[u + 1]]; /* put d[u+1] into index form */
|
||||
}
|
||||
} while ((u < NN - KK) && (l[u + 1] <= TT));
|
||||
|
||||
u++;
|
||||
if (l[u] <= TT) /* can correct error */
|
||||
{
|
||||
/* put elp into index form */
|
||||
for (i = 0; i <= l[u]; i++)
|
||||
elp[u][i] = index_of[elp[u][i]];
|
||||
|
||||
/* find roots of the error location polynomial */
|
||||
for (i = 1; i <= l[u]; i++)
|
||||
reg[i] = elp[u][i];
|
||||
count = 0;
|
||||
for (i = 1; i <= NN; i++) {
|
||||
q = 1;
|
||||
for (j = 1; j <= l[u]; j++)
|
||||
if (reg[j] != -1) {
|
||||
reg[j] = (reg[j] + j) % NN;
|
||||
q ^= alpha_to[reg[j]];
|
||||
};
|
||||
if (!q) /* store root and error location number indices */
|
||||
{
|
||||
root[count] = i;
|
||||
loc[count] = NN - i;
|
||||
count++;
|
||||
};
|
||||
};
|
||||
|
||||
if (count == l[u]) /* no. roots = degree of elp hence <= tt errors */
|
||||
{
|
||||
/* form polynomial z(x) */
|
||||
for (i = 1; i <= l[u]; i++) /* Z[0] = 1 always - do not need */
|
||||
{
|
||||
if ((s[i] != -1) && (elp[u][i] != -1))
|
||||
z[i] = alpha_to[s[i]] ^ alpha_to[elp[u][i]];
|
||||
else if ((s[i] != -1) && (elp[u][i] == -1))
|
||||
z[i] = alpha_to[s[i]];
|
||||
else if ((s[i] == -1) && (elp[u][i] != -1))
|
||||
z[i] = alpha_to[elp[u][i]];
|
||||
else
|
||||
z[i] = 0;
|
||||
for (j = 1; j < i; j++)
|
||||
if ((s[j] != -1) && (elp[u][i - j] != -1))
|
||||
z[i] ^= alpha_to[(elp[u][i - j] + s[j]) % NN];
|
||||
z[i] = index_of[z[i]]; /* put into index form */
|
||||
};
|
||||
|
||||
/* evaluate errors at locations given by error location numbers loc[i] */
|
||||
for (i = 0; i < NN; i++) {
|
||||
err[i] = 0;
|
||||
if (recd[i] != -1) /* convert recd[] to polynomial form */
|
||||
recd[i] = alpha_to[recd[i]];
|
||||
else
|
||||
recd[i] = 0;
|
||||
}
|
||||
for (i = 0; i < l[u]; i++) /* compute numerator of error term first */
|
||||
{
|
||||
err[loc[i]] = 1; /* accounts for z[0] */
|
||||
for (j = 1; j <= l[u]; j++)
|
||||
if (z[j] != -1)
|
||||
err[loc[i]] ^= alpha_to[(z[j] + j * root[i]) % NN];
|
||||
if (err[loc[i]] != 0) {
|
||||
err[loc[i]] = index_of[err[loc[i]]];
|
||||
q = 0; /* form denominator of error term */
|
||||
for (j = 0; j < l[u]; j++)
|
||||
if (j != i)
|
||||
q += index_of[1
|
||||
^ alpha_to[(loc[j] + root[i]) % NN]];
|
||||
q = q % NN;
|
||||
err[loc[i]] = alpha_to[(err[loc[i]] - q + NN) % NN];
|
||||
recd[loc[i]] ^= err[loc[i]]; /*recd[i] must be in polynomial form */
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* no. roots != degree of elp => >tt errors and cannot solve */
|
||||
irrecoverable_error = 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* elp has degree >tt hence cannot solve */
|
||||
irrecoverable_error = 1;
|
||||
}
|
||||
|
||||
} else {
|
||||
/* no non-zero syndromes => no errors: output received codeword */
|
||||
for (i = 0; i < NN; i++)
|
||||
if (recd[i] != -1) /* convert recd[] to polynomial form */
|
||||
recd[i] = alpha_to[recd[i]];
|
||||
else
|
||||
recd[i] = 0;
|
||||
}
|
||||
|
||||
if (irrecoverable_error) {
|
||||
for (i = 0; i < NN; i++) /* could return error flag if desired */
|
||||
if (recd[i] != -1) /* convert recd[] to polynomial form */
|
||||
recd[i] = alpha_to[recd[i]];
|
||||
else
|
||||
recd[i] = 0; /* just output received codeword as is */
|
||||
}
|
||||
|
||||
return irrecoverable_error;
|
||||
}
|
||||
|
||||
protected:
|
||||
int bin_to_hex(const char* input)
|
||||
{
|
||||
int output = ((input[0] != 0)? 32 : 0) |
|
||||
((input[1] != 0)? 16 : 0) |
|
||||
((input[2] != 0)? 8 : 0) |
|
||||
((input[3] != 0)? 4 : 0) |
|
||||
((input[4] != 0)? 2 : 0) |
|
||||
((input[5] != 0)? 1 : 0);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void hex_to_bin(int input, char* output)
|
||||
{
|
||||
output[0] = ((input & 32) != 0)? 1 : 0;
|
||||
output[1] = ((input & 16) != 0)? 1 : 0;
|
||||
output[2] = ((input & 8) != 0)? 1 : 0;
|
||||
output[3] = ((input & 4) != 0)? 1 : 0;
|
||||
output[4] = ((input & 2) != 0)? 1 : 0;
|
||||
output[5] = ((input & 1) != 0)? 1 : 0;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Convenience class that does a Reed-Solomon (36,20,17) error correction adapting input and output to
|
||||
* the DSD data format: hex words packed as char arrays.
|
||||
*/
|
||||
class DSDReedSolomon_36_20_17 : public ReedSolomon_63<8>
|
||||
{
|
||||
public:
|
||||
// tt = (dd-1)/2
|
||||
// dd = 17 --> tt = 8
|
||||
DSDReedSolomon_36_20_17() : ReedSolomon_63<8>()
|
||||
{
|
||||
// Does nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Does a Reed-Solomon decode adapting the input and output to the expected DSD data format.
|
||||
* \param hex_data Data packed bits, originally a char[20][6], so containing 20 hex works, each char
|
||||
* is a bit. Bits are corrected in place.
|
||||
* \param hex_parity Parity packed bits, originally a char[16][6], 16 hex words.
|
||||
* \return 1 if irrecoverable errors have been detected, 0 otherwise.
|
||||
*/
|
||||
int decode(char* hex_data, const char* hex_parity)
|
||||
{
|
||||
int input[63];
|
||||
int output[63];
|
||||
|
||||
// First put the parity data, 16 hex words
|
||||
for(unsigned int i=0; i<16; i++) {
|
||||
input[i] = bin_to_hex(hex_parity + i*6);
|
||||
}
|
||||
|
||||
// Then the 20 hex words of data
|
||||
for(unsigned int i=16; i<16+20; i++) {
|
||||
input[i] = bin_to_hex(hex_data + (i-16)*6);
|
||||
}
|
||||
|
||||
// Fill up with zeros to complete the 47 expected hex words of data
|
||||
for(unsigned int i=16+20; i<63; i++) {
|
||||
input[i] = 0;
|
||||
}
|
||||
|
||||
// Now we can call decode on the base class
|
||||
int irrecoverable_errors = ReedSolomon_63<8>::decode(input, output);
|
||||
|
||||
// Convert it back to binary and put it into hex_data. If decode failed we should have
|
||||
// the input unchanged.
|
||||
for(unsigned int i=16; i<16+20; i++) {
|
||||
hex_to_bin(output[i], hex_data + (i-16)*6);
|
||||
}
|
||||
|
||||
return irrecoverable_errors;
|
||||
}
|
||||
|
||||
void encode(const char* hex_data, char* out_hex_parity)
|
||||
{
|
||||
int input[47];
|
||||
int output[63];
|
||||
|
||||
// Put the 20 hex words of data
|
||||
for(unsigned int i=0; i<20; i++) {
|
||||
input[i] = bin_to_hex(hex_data + i*6);
|
||||
}
|
||||
|
||||
// Fill up with zeros to complete the 47 expected hex words of data
|
||||
for(unsigned int i=20; i<47; i++) {
|
||||
input[i] = 0;
|
||||
}
|
||||
|
||||
// Now we can call encode on the base class
|
||||
ReedSolomon_63<8>::encode(input, output);
|
||||
|
||||
// Convert it back to binary form and put it into the parity
|
||||
for(unsigned int i=0; i<16; i++) {
|
||||
hex_to_bin(output[i], out_hex_parity + i*6);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Convenience class that does a Reed-Solomon (24,12,13) error correction adapting input and output to
|
||||
* the DSD data format: hex words packed as char arrays.
|
||||
*/
|
||||
class DSDReedSolomon_24_12_13 : public ReedSolomon_63<6>
|
||||
{
|
||||
public:
|
||||
// tt = (dd-1)/2
|
||||
// dd = 13 --> tt = 6
|
||||
DSDReedSolomon_24_12_13() : ReedSolomon_63<6>()
|
||||
{
|
||||
// Does nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Does a Reed-Solomon decode adapting the input and output to the expected DSD data format.
|
||||
* \param hex_data Data packed bits, originally a char[12][6], so containing 12 hex works, each char
|
||||
* is a bit. Bits are corrected in place.
|
||||
* \param hex_parity Parity packed bits, originally a char[12][6], 12 hex words.
|
||||
* \return 1 if irrecoverable errors have been detected, 0 otherwise.
|
||||
*/
|
||||
int decode(char* hex_data, const char* hex_parity)
|
||||
{
|
||||
int input[63];
|
||||
int output[63];
|
||||
|
||||
// First put the parity data, 12 hex words
|
||||
for(unsigned int i=0; i<12; i++) {
|
||||
input[i] = bin_to_hex(hex_parity + i*6);
|
||||
}
|
||||
|
||||
// Then the 12 hex words of data
|
||||
for(unsigned int i=12; i<12+12; i++) {
|
||||
input[i] = bin_to_hex(hex_data + (i-12)*6);
|
||||
}
|
||||
|
||||
// Fill up with zeros to complete the 51 expected hex words of data
|
||||
for(unsigned int i=12+12; i<63; i++) {
|
||||
input[i] = 0;
|
||||
}
|
||||
|
||||
// Now we can call decode on the base class
|
||||
int irrecoverable_errors = ReedSolomon_63<6>::decode(input, output);
|
||||
|
||||
// Convert it back to binary and put it into hex_data. If decode failed we should have
|
||||
// the input unchanged.
|
||||
for(unsigned int i=12; i<12+12; i++) {
|
||||
hex_to_bin(output[i], hex_data + (i-12)*6);
|
||||
}
|
||||
|
||||
return irrecoverable_errors;
|
||||
}
|
||||
|
||||
void encode(const char* hex_data, char* out_hex_parity)
|
||||
{
|
||||
int input[51];
|
||||
int output[63];
|
||||
|
||||
// Put the 12 hex words of data
|
||||
for(unsigned int i=0; i<12; i++) {
|
||||
input[i] = bin_to_hex(hex_data + i*6);
|
||||
}
|
||||
|
||||
// Fill up with zeros to complete the 51 expected hex words of data
|
||||
for(unsigned int i=12; i<51; i++) {
|
||||
input[i] = 0;
|
||||
}
|
||||
|
||||
// Now we can call encode on the base class
|
||||
ReedSolomon_63<6>::encode(input, output);
|
||||
|
||||
// Convert it back to binary form and put it into the parity
|
||||
for(unsigned int i=0; i<12; i++) {
|
||||
hex_to_bin(output[i], out_hex_parity + i*6);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Convenience class that does a Reed-Solomon (24,16,9) error correction adapting input and output to
|
||||
* the DSD data format: hex words packed as char arrays.
|
||||
*/
|
||||
class DSDReedSolomon_24_16_9 : public ReedSolomon_63<4>
|
||||
{
|
||||
public:
|
||||
// tt = (dd-1)/2
|
||||
// dd = 9 --> tt = 4
|
||||
DSDReedSolomon_24_16_9() : ReedSolomon_63<4>()
|
||||
{
|
||||
// Does nothing
|
||||
}
|
||||
|
||||
/**
|
||||
* Does a Reed-Solomon decode adapting the input and output to the expected DSD data format.
|
||||
* \param hex_data Data packed bits, originally a char[16][6], so containing 16 hex works, each char
|
||||
* is a bit. Bits are corrected in place.
|
||||
* \param hex_parity Parity packed bits, originally a char[8][6], 8 hex words.
|
||||
* \return 1 if irrecoverable errors have been detected, 0 otherwise.
|
||||
*/
|
||||
int decode(char* hex_data, const char* hex_parity)
|
||||
{
|
||||
int input[63];
|
||||
int output[63];
|
||||
|
||||
// First put the parity data, 8 hex words
|
||||
for(unsigned int i=0; i<8; i++) {
|
||||
input[i] = bin_to_hex(hex_parity + i*6);
|
||||
}
|
||||
|
||||
// Then the 16 hex words of data
|
||||
for(unsigned int i=8; i<8+16; i++) {
|
||||
input[i] = bin_to_hex(hex_data + (i-8)*6);
|
||||
}
|
||||
|
||||
// Fill up with zeros to complete the 55 expected hex words of data
|
||||
for(unsigned int i=8+16; i<63; i++) {
|
||||
input[i] = 0;
|
||||
}
|
||||
|
||||
// Now we can call decode on the base class
|
||||
int irrecoverable_errors = ReedSolomon_63<4>::decode(input, output);
|
||||
|
||||
// Convert it back to binary and put it into hex_data. If decode failed we should have
|
||||
// the input unchanged.
|
||||
for(unsigned int i=8; i<8+16; i++) {
|
||||
hex_to_bin(output[i], hex_data + (i-8)*6);
|
||||
}
|
||||
|
||||
return irrecoverable_errors;
|
||||
}
|
||||
|
||||
void encode(const char* hex_data, char* out_hex_parity)
|
||||
{
|
||||
int input[55];
|
||||
int output[63];
|
||||
|
||||
// Put the 16 hex words of data
|
||||
for(unsigned int i=0; i<16; i++) {
|
||||
input[i] = bin_to_hex(hex_data + i*6);
|
||||
}
|
||||
|
||||
// Fill up with zeros to complete the 55 expected hex words of data
|
||||
for(unsigned int i=16; i<55; i++) {
|
||||
input[i] = 0;
|
||||
}
|
||||
|
||||
// Now we can call encode on the base class
|
||||
ReedSolomon_63<4>::encode(input, output);
|
||||
|
||||
// Convert it back to binary form and put it into the parity
|
||||
for(unsigned int i=0; i<8; i++) {
|
||||
hex_to_bin(output[i], out_hex_parity + i*6);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // REEDSOLOMON_HPP_b1405fdab6374ba2a4e65e8d45ec3d80
|
||||
298
include/descramble.h
Normal file
298
include/descramble.h
Normal file
@@ -0,0 +1,298 @@
|
||||
/* descramble.h */
|
||||
|
||||
// Functions for processing the radio-header:
|
||||
// descramble
|
||||
// deinterleave
|
||||
// FECdecoder
|
||||
|
||||
// (C) 2011 Jonathan Naylor G4KLX
|
||||
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
// This code was originally written by JOnathan Naylor, G4KLX, as part
|
||||
// of the "pcrepeatercontroller" project
|
||||
// More info:
|
||||
// http://groups.yahoo.com/group/pcrepeatercontroller
|
||||
|
||||
|
||||
|
||||
// Changes:
|
||||
// Convert C++ to C
|
||||
|
||||
// Version 20111106: initial release
|
||||
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
// function traceBack
|
||||
int traceBack (int * out, int * m_pathMemory0, int * m_pathMemory1, int * m_pathMemory2, int * m_pathMemory3) {
|
||||
enum FEC_STATE { S0, S1, S2, S3 } state;
|
||||
int loop;
|
||||
int length=0;
|
||||
|
||||
state=S0;
|
||||
|
||||
for (loop=329; loop >= 0; loop--, length++) {
|
||||
|
||||
switch (state) {
|
||||
case S0: // if state S0
|
||||
if (m_pathMemory0[loop]) {
|
||||
state = S2; // lower path
|
||||
} else {
|
||||
state = S0; // upper path
|
||||
} // end else - if
|
||||
out[loop]=0;
|
||||
break;
|
||||
|
||||
case S1: // if state S1
|
||||
if (m_pathMemory1[loop]) {
|
||||
state = S2; // lower path
|
||||
} else {
|
||||
state = S0; // upper path
|
||||
} // end else - if
|
||||
out[loop]=1;
|
||||
break;
|
||||
|
||||
case S2: // if state S2
|
||||
if (m_pathMemory2[loop]) {
|
||||
state = S3; // lower path
|
||||
} else {
|
||||
state = S1; // upper path
|
||||
} // end else - if
|
||||
out[loop]=0;
|
||||
break;
|
||||
|
||||
case S3: // if state S3
|
||||
if (m_pathMemory3[loop]) {
|
||||
state = S3; // lower path
|
||||
} else {
|
||||
state = S1; // upper path
|
||||
} // end else - if
|
||||
out[loop]=1;
|
||||
break;
|
||||
|
||||
} // end switch
|
||||
} // end for
|
||||
|
||||
return(length);
|
||||
}; // end function
|
||||
|
||||
|
||||
|
||||
// function viterbiDecode
|
||||
|
||||
void viterbiDecode (int n, int *data, int *m_pathMemory0, int *m_pathMemory1, int *m_pathMemory2, int *m_pathMemory3, int *m_pathMetric) {
|
||||
int tempMetric[4];
|
||||
int metric[8];
|
||||
int loop;
|
||||
|
||||
int m1;
|
||||
int m2;
|
||||
|
||||
metric[0]=(data[1]^0)+(data[0]^0);
|
||||
metric[1]=(data[1]^1)+(data[0]^1);
|
||||
metric[2]=(data[1]^1)+(data[0]^0);
|
||||
metric[3]=(data[1]^0)+(data[0]^1);
|
||||
metric[4]=(data[1]^1)+(data[0]^1);
|
||||
metric[5]=(data[1]^0)+(data[0]^0);
|
||||
metric[6]=(data[1]^0)+(data[0]^1);
|
||||
metric[7]=(data[1]^1)+(data[0]^0);
|
||||
|
||||
// Pres. state = S0, Prev. state = S0 & S2
|
||||
m1=metric[0]+m_pathMetric[0];
|
||||
m2=metric[4]+m_pathMetric[2];
|
||||
if (m1<m2) {
|
||||
m_pathMemory0[n]=0;
|
||||
tempMetric[0]=m1;
|
||||
} else {
|
||||
m_pathMemory0[n]=1;
|
||||
tempMetric[0]=m2;
|
||||
}; // end else - if
|
||||
|
||||
// Pres. state = S1, Prev. state = S0 & S2
|
||||
m1=metric[1]+m_pathMetric[0];
|
||||
m2=metric[5]+m_pathMetric[2];
|
||||
if (m1<m2) {
|
||||
m_pathMemory1[n]=0;
|
||||
tempMetric[1]=m1;
|
||||
} else {
|
||||
m_pathMemory1[n]=1;
|
||||
tempMetric[1]=m2;
|
||||
}; // end else - if
|
||||
|
||||
// Pres. state = S2, Prev. state = S2 & S3
|
||||
m1=metric[2]+m_pathMetric[1];
|
||||
m2=metric[6]+m_pathMetric[3];
|
||||
if (m1<m2) {
|
||||
m_pathMemory2[n]=0;
|
||||
tempMetric[2]=m1;
|
||||
} else {
|
||||
m_pathMemory2[n]=1;
|
||||
tempMetric[2]=m2;
|
||||
}
|
||||
|
||||
// Pres. state = S3, Prev. state = S1 & S3
|
||||
m1=metric[3]+m_pathMetric[1];
|
||||
m2=metric[7]+m_pathMetric[3];
|
||||
if (m1 < m2) {
|
||||
m_pathMemory3[n]=0;
|
||||
tempMetric[3]=m1;
|
||||
} else {
|
||||
m_pathMemory3[n]=1;
|
||||
tempMetric[3]=m2;
|
||||
}; // end else - if
|
||||
|
||||
for (loop=0;loop<4;loop++) {
|
||||
m_pathMetric[loop]=tempMetric[loop];
|
||||
}; // end for
|
||||
|
||||
}; // end function ViterbiDecode
|
||||
|
||||
|
||||
// function FECdecoder
|
||||
// returns outlen
|
||||
int FECdecoder (int * in, int * out) {
|
||||
int outLen;
|
||||
|
||||
int m_pathMemory0[330];
|
||||
int m_pathMemory1[330];
|
||||
int m_pathMemory2[330];
|
||||
int m_pathMemory3[330];
|
||||
int m_pathMetric[4];
|
||||
|
||||
int loop,loop2;
|
||||
|
||||
int n=0;
|
||||
|
||||
memset(m_pathMemory0,0,330*sizeof(int));
|
||||
memset(m_pathMemory1,0,330*sizeof(int));
|
||||
memset(m_pathMemory2,0,330*sizeof(int));
|
||||
memset(m_pathMemory3,0,330*sizeof(int));
|
||||
|
||||
for (loop=0;loop<4;loop++) {
|
||||
m_pathMetric[loop]=0;
|
||||
}; // end for
|
||||
|
||||
|
||||
for (loop2=0;loop2<660;loop2+=2, n++) {
|
||||
int data[2];
|
||||
|
||||
if (in[loop2]) {
|
||||
data[1]=1;
|
||||
} else {
|
||||
data[1]=0;
|
||||
}; // end else - if
|
||||
|
||||
if (in[loop2+1]) {
|
||||
data[0]=1;
|
||||
} else {
|
||||
data[0]=0;
|
||||
}; // end else - if
|
||||
|
||||
viterbiDecode(n, data, m_pathMemory0, m_pathMemory1, m_pathMemory2, m_pathMemory3, m_pathMetric);
|
||||
}; // end for
|
||||
|
||||
outLen=traceBack(out, m_pathMemory0, m_pathMemory1, m_pathMemory2, m_pathMemory3);
|
||||
|
||||
// Swap endian-ness
|
||||
// code removed (done converting bits into octets), done in main program
|
||||
|
||||
//for (loop=0;loop<330;loop+=8) {
|
||||
// int temp;
|
||||
// temp=out[loop];out[loop]=out[loop+7];out[loop+7]=temp;
|
||||
// temp=out[loop+1];out[loop+1]=out[loop+6];out[loop+6]=temp;
|
||||
// temp=out[loop+2];out[loop+2]=out[loop+5];out[loop+5]=temp;
|
||||
// temp=out[loop+3];out[loop+3]=out[loop+4];out[loop+4]=temp;
|
||||
//}
|
||||
|
||||
return(outLen);
|
||||
|
||||
}; // end function FECdecoder
|
||||
|
||||
|
||||
// function deinterleave
|
||||
void deinterleave (int * in, int * out) {
|
||||
|
||||
int k=0;
|
||||
int loop=0;
|
||||
// function starts here
|
||||
|
||||
// init vars
|
||||
k=0;
|
||||
|
||||
for (loop=0;loop<660;loop++) {
|
||||
out[k]=in[loop];
|
||||
|
||||
k += 24;
|
||||
|
||||
if (k >= 672) {
|
||||
k -= 671;
|
||||
} else if (k >= 660) {
|
||||
k -= 647;
|
||||
}; // end elsif - if
|
||||
}; // end for
|
||||
|
||||
}; // end function deinterleave
|
||||
|
||||
|
||||
|
||||
/// function scramble
|
||||
|
||||
void scramble (int * in,int * out) {
|
||||
|
||||
static const int SCRAMBLER_TABLE_BITS[] = {
|
||||
0,0,0,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,
|
||||
0,0,1,0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,
|
||||
1,1,0,1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,
|
||||
1,1,1,1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,
|
||||
0,0,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,
|
||||
0,1,0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,
|
||||
1,0,1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,
|
||||
1,1,1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,
|
||||
0,0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,
|
||||
1,0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,
|
||||
0,1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,1,
|
||||
1,1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,
|
||||
0,1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,
|
||||
0,0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,0,
|
||||
1,0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,1,1,
|
||||
1,1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,
|
||||
1,1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,
|
||||
0,1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,0,1,
|
||||
0,1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0,1,0,0,0,0,1,0,1,0,1,0,1,1,1,1,
|
||||
1,0,1,0,0,1,0,1,0,0,0,1,1,0,1,1,1,0,0,0,1,1,1,1,1,1,1,0,0,0,0,1,
|
||||
1,1,0,1,1,1,1,0,0,1,0,1,1,0,0,1,0,0,1,0,0,0,0,0,0,1,0,0,0,1,0,0,
|
||||
1,1,0,0,0,1,0,1,1,1,0,1,0,1,1,0,1,1,0,0,0,0,0,1,1,0,0,1,1,0,1,0,
|
||||
1,0,0,1,1,1,0,0,1,1,1,1,0,1,1,0};
|
||||
|
||||
const int SCRAMBLER_TABLE_BITS_LENGTH=720;
|
||||
|
||||
int loop=0;
|
||||
int m_count=0;
|
||||
|
||||
|
||||
for (loop=0; loop < 660; loop++) {
|
||||
out[loop] = in[loop] ^ SCRAMBLER_TABLE_BITS[m_count++];
|
||||
|
||||
if (m_count >= SCRAMBLER_TABLE_BITS_LENGTH) {
|
||||
m_count = 0U;
|
||||
}; // end if
|
||||
}; // end for
|
||||
|
||||
}; // end function scramble
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -15,19 +15,25 @@
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* NXDN AMBE interleave schedule
|
||||
*/
|
||||
|
||||
//#ifdef __cplusplus
|
||||
//extern "C" {
|
||||
//#endif
|
||||
|
||||
|
||||
#ifndef _MAIN
|
||||
extern const int nW[36];
|
||||
extern const int nX[36];
|
||||
extern const int nY[36];
|
||||
extern const int nZ[36];
|
||||
extern const int dPmrW[36];
|
||||
extern const int dPmrX[36];
|
||||
extern const int dPmrY[36];
|
||||
extern const int dPmrZ[36];
|
||||
|
||||
#else
|
||||
|
||||
const int nW[36] = { 0, 1, 0, 1, 0, 1,
|
||||
//#else
|
||||
/*
|
||||
* dPMR AMBE interleave schedule
|
||||
*/
|
||||
// bit 1
|
||||
const int dPmrW[36] = {
|
||||
0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 1,
|
||||
0, 1, 0, 1, 0, 2,
|
||||
@@ -35,7 +41,8 @@ const int nW[36] = { 0, 1, 0, 1, 0, 1,
|
||||
0, 2, 0, 2, 0, 2
|
||||
};
|
||||
|
||||
const int nX[36] = { 23, 10, 22, 9, 21, 8,
|
||||
const int dPmrX[36] = {
|
||||
23, 10, 22, 9, 21, 8,
|
||||
20, 7, 19, 6, 18, 5,
|
||||
17, 4, 16, 3, 15, 2,
|
||||
14, 1, 13, 0, 12, 10,
|
||||
@@ -43,7 +50,9 @@ const int nX[36] = { 23, 10, 22, 9, 21, 8,
|
||||
8, 6, 7, 5, 6, 4
|
||||
};
|
||||
|
||||
const int nY[36] = { 0, 2, 0, 2, 0, 2,
|
||||
// bit 0
|
||||
const int dPmrY[36] = {
|
||||
0, 2, 0, 2, 0, 2,
|
||||
0, 2, 0, 3, 0, 3,
|
||||
1, 3, 1, 3, 1, 3,
|
||||
1, 3, 1, 3, 1, 3,
|
||||
@@ -51,7 +60,8 @@ const int nY[36] = { 0, 2, 0, 2, 0, 2,
|
||||
1, 3, 1, 3, 1, 3
|
||||
};
|
||||
|
||||
const int nZ[36] = { 5, 3, 4, 2, 3, 1,
|
||||
const int dPmrZ[36] = {
|
||||
5, 3, 4, 2, 3, 1,
|
||||
2, 0, 1, 13, 0, 12,
|
||||
22, 11, 21, 10, 20, 9,
|
||||
19, 8, 18, 7, 17, 6,
|
||||
@@ -60,3 +70,7 @@ const int nZ[36] = { 5, 3, 4, 2, 3, 1,
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
//#ifdef __cplusplus
|
||||
//}
|
||||
//#endif
|
||||
1288
include/dsd.h
Normal file
1288
include/dsd.h
Normal file
File diff suppressed because it is too large
Load Diff
129
include/dstar_const.h
Normal file
129
include/dstar_const.h
Normal file
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* dstar interleave experiments
|
||||
*/
|
||||
|
||||
#ifndef _MAIN
|
||||
|
||||
extern const int dW[72];
|
||||
extern const int dX[72];
|
||||
|
||||
#else
|
||||
const int dW[72] = {
|
||||
|
||||
// 0-11
|
||||
0, 0,
|
||||
3, 2,
|
||||
1, 1,
|
||||
0, 0,
|
||||
1, 1,
|
||||
0, 0,
|
||||
|
||||
// 12-23
|
||||
3, 2,
|
||||
1, 1,
|
||||
3, 2,
|
||||
1, 1,
|
||||
0, 0,
|
||||
3, 2,
|
||||
|
||||
// 24-35
|
||||
0, 0,
|
||||
3, 2,
|
||||
1, 1,
|
||||
0, 0,
|
||||
1, 1,
|
||||
0, 0,
|
||||
|
||||
// 36-47
|
||||
3, 2,
|
||||
1, 1,
|
||||
3, 2,
|
||||
1, 1,
|
||||
0, 0,
|
||||
3, 2,
|
||||
|
||||
// 48-59
|
||||
0, 0,
|
||||
3, 2,
|
||||
1, 1,
|
||||
0, 0,
|
||||
1, 1,
|
||||
0, 0,
|
||||
|
||||
// 60-71
|
||||
3, 2,
|
||||
1, 1,
|
||||
3, 3,
|
||||
2, 1,
|
||||
0, 0,
|
||||
3, 3,
|
||||
};
|
||||
const int dX[72] = {
|
||||
|
||||
// 0-11
|
||||
10, 22,
|
||||
11, 9,
|
||||
10, 22,
|
||||
11, 23,
|
||||
8, 20,
|
||||
9, 21,
|
||||
|
||||
// 12-23
|
||||
10, 8,
|
||||
9, 21,
|
||||
8, 6,
|
||||
7, 19,
|
||||
8, 20,
|
||||
9, 7,
|
||||
|
||||
// 24-35
|
||||
6, 18,
|
||||
7, 5,
|
||||
6, 18,
|
||||
7, 19,
|
||||
4, 16,
|
||||
5, 17,
|
||||
|
||||
// 36-47
|
||||
6, 4,
|
||||
5, 17,
|
||||
4, 2,
|
||||
3, 15,
|
||||
4, 16,
|
||||
5, 3,
|
||||
|
||||
// 48-59
|
||||
2, 14,
|
||||
3, 1,
|
||||
2, 14,
|
||||
3, 15,
|
||||
0, 12,
|
||||
1, 13,
|
||||
|
||||
// 60-71
|
||||
2, 0,
|
||||
1, 13,
|
||||
0, 12,
|
||||
10, 11,
|
||||
0, 12,
|
||||
1, 13,
|
||||
};
|
||||
|
||||
#endif
|
||||
6
include/dstar_header.h
Normal file
6
include/dstar_header.h
Normal file
@@ -0,0 +1,6 @@
|
||||
/* This is the header file for dstar_header.c, which is under the GPL. */
|
||||
|
||||
#ifndef _DSTAR_HEADER_H
|
||||
#define _DSTAR_HEADER_H
|
||||
//void dstar_header_decode(int radioheaderbuffer[660]);
|
||||
#endif /* _DSTAR_HEADER_H */
|
||||
89
include/fcs.h
Normal file
89
include/fcs.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/* fcs.h */
|
||||
|
||||
// Viterbi decoder using Traceback method.
|
||||
|
||||
// Original Source was written by Sho Tamaoki and Tom Wada
|
||||
// See http://www.lsi.ie.u-ryukyu.ac.jp/~sho/midterm/
|
||||
// Modified by Satoshi Yasuda 7m3tjz/ad6gz
|
||||
// Modified by Jonathan Nayor, G4KLX (C) 2009
|
||||
|
||||
// Converted from C++ to C by Kristoff Bonne, ON1ARF
|
||||
|
||||
/*
|
||||
* Copyright (C) 2010 by Kristoff Bonne, ON1ARF
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; version 2 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
static const unsigned short ccittTab[] = {
|
||||
0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf,
|
||||
0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7,
|
||||
0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e,
|
||||
0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876,
|
||||
0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd,
|
||||
0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5,
|
||||
0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c,
|
||||
0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974,
|
||||
0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb,
|
||||
0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3,
|
||||
0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a,
|
||||
0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72,
|
||||
0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9,
|
||||
0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1,
|
||||
0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738,
|
||||
0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70,
|
||||
0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7,
|
||||
0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff,
|
||||
0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036,
|
||||
0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e,
|
||||
0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5,
|
||||
0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd,
|
||||
0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134,
|
||||
0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c,
|
||||
0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3,
|
||||
0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb,
|
||||
0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232,
|
||||
0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a,
|
||||
0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1,
|
||||
0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9,
|
||||
0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330,
|
||||
0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78};
|
||||
|
||||
|
||||
uint16_t calc_fcs (unsigned char * dvstartframe, int size) {
|
||||
// this function calculated the CRC-values of a DSTAR digital
|
||||
// voice frame. It calculates this value on octets 0 up to 38 of the D-STAR
|
||||
// radio header (fields flag1, flag2, flag3, destination, departure, companion,
|
||||
// own1 and own2)
|
||||
uint16_t m_crc;
|
||||
int loop;
|
||||
unsigned short tmp;
|
||||
|
||||
m_crc=0xFFFF;
|
||||
|
||||
for (loop=0; loop < size; loop++) {
|
||||
tmp = (m_crc & 0x00ff) ^ dvstartframe[loop];
|
||||
|
||||
m_crc = (m_crc >> 8) ^ ccittTab[tmp];
|
||||
|
||||
} // end for
|
||||
|
||||
// calculate and save crc-value in fields 54 and 55 of dvframe
|
||||
m_crc = ~m_crc;
|
||||
|
||||
tmp = m_crc;
|
||||
m_crc = (m_crc << 8) | (tmp >> 8 & 0xFF);
|
||||
|
||||
|
||||
// done
|
||||
return(m_crc);
|
||||
}; // end function
|
||||
1
include/git_ver.h
Normal file
1
include/git_ver.h
Normal file
@@ -0,0 +1 @@
|
||||
extern const char GIT_TAG[];
|
||||
82
include/nxdn_const.h
Normal file
82
include/nxdn_const.h
Normal file
@@ -0,0 +1,82 @@
|
||||
// Portions Below from Osmocom OP25
|
||||
// NXDN Encoder (C) Copyright 2019 Max H. Parke KA1RBI
|
||||
// thx gr-ysf fr_vch_decoder_bb_impl.cc * Copyright 2015 Mathias Weyland *
|
||||
// OP25 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.
|
||||
//
|
||||
// OP25 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 OP25; see the file COPYING. If not, write to the Free
|
||||
// Software Foundation, Inc., 51 Franklin Street, Boston, MA
|
||||
// 02110-1301, USA.
|
||||
|
||||
static const uint8_t PERM_12_5[] = {
|
||||
0,12,24,36,48,
|
||||
1,13,25,37,49,
|
||||
2,14,26,38,50,
|
||||
3,15,27,39,51,
|
||||
4,16,28,40,52,
|
||||
5,17,29,41,53,
|
||||
6,18,30,42,54,
|
||||
7,19,31,43,55,
|
||||
8,20,32,44,56,
|
||||
9,21,33,45,57,
|
||||
10,22,34,46,58,
|
||||
11,23,35,47,59
|
||||
};
|
||||
|
||||
static const uint8_t PERM_16_9[] = {
|
||||
0, 16, 32, 48, 64, 80, 96, 112, 128,
|
||||
1, 17, 33, 49, 65, 81, 97, 113, 129,
|
||||
2, 18, 34, 50, 66, 82, 98, 114, 130,
|
||||
3, 19, 35, 51, 67, 83, 99, 115, 131,
|
||||
4, 20, 36, 52, 68, 84, 100, 116, 132,
|
||||
5, 21, 37, 53, 69, 85, 101, 117, 133,
|
||||
6, 22, 38, 54, 70, 86, 102, 118, 134,
|
||||
7, 23, 39, 55, 71, 87, 103, 119, 135,
|
||||
8, 24, 40, 56, 72, 88, 104, 120, 136,
|
||||
9, 25, 41, 57, 73, 89, 105, 121, 137,
|
||||
10, 26, 42, 58, 74, 90, 106, 122, 138,
|
||||
11, 27, 43, 59, 75, 91, 107, 123, 139,
|
||||
12, 28, 44, 60, 76, 92, 108, 124, 140,
|
||||
13, 29, 45, 61, 77, 93, 109, 125, 141,
|
||||
14, 30, 46, 62, 78, 94, 110, 126, 142,
|
||||
15, 31, 47, 63, 79, 95, 111, 127, 143
|
||||
};
|
||||
|
||||
static const uint16_t PERM_12_25[] = {
|
||||
0,12,24,36,48,60,72,84,96,108,120,132,144,156,168,180,192,204,216,228,240,252,264,276,288,
|
||||
1,13,25,37,49,61,73,85,97,109,121,133,145,157,169,181,193,205,217,229,241,253,265,277,289,
|
||||
2,14,26,38,50,62,74,86,98,110,122,134,146,158,170,182,194,206,218,230,242,254,266,278,290,
|
||||
3,15,27,39,51,63,75,87,99,111,123,135,147,159,171,183,195,207,219,231,243,255,267,279,291,
|
||||
4,16,28,40,52,64,76,88,100,112,124,136,148,160,172,184,196,208,220,232,244,256,268,280,292,
|
||||
5,17,29,41,53,65,77,89,101,113,125,137,149,161,173,185,197,209,221,233,245,257,269,281,293,
|
||||
6,18,30,42,54,66,78,90,102,114,126,138,150,162,174,186,198,210,222,234,246,258,270,282,294,
|
||||
7,19,31,43,55,67,79,91,103,115,127,139,151,163,175,187,199,211,223,235,247,259,271,283,295,
|
||||
8,20,32,44,56,68,80,92,104,116,128,140,152,164,176,188,200,212,224,236,248,260,272,284,296,
|
||||
9,21,33,45,57,69,81,93,105,117,129,141,153,165,177,189,201,213,225,237,249,261,273,285,297,
|
||||
10,22,34,46,58,70,82,94,106,118,130,142,154,166,178,190,202,214,226,238,250,262,274,286,298,
|
||||
11,23,35,47,59,71,83,95,107,119,131,143,155,167,179,191,203,215,227,239,251,263,275,287,299
|
||||
};
|
||||
|
||||
static const uint16_t PERM_12_29[] = {
|
||||
0,12,24,36,48,60,72,84,96,108,120,132,144,156,168,180,192,204,216,228,240,252,264,276,288,300,312,324,336,
|
||||
1,13,25,37,49,61,73,85,97,109,121,133,145,157,169,181,193,205,217,229,241,253,265,277,289,301,313,325,337,
|
||||
2,14,26,38,50,62,74,86,98,110,122,134,146,158,170,182,194,206,218,230,242,254,266,278,290,302,314,326,338,
|
||||
3,15,27,39,51,63,75,87,99,111,123,135,147,159,171,183,195,207,219,231,243,255,267,279,291,303,315,327,339,
|
||||
4,16,28,40,52,64,76,88,100,112,124,136,148,160,172,184,196,208,220,232,244,256,268,280,292,304,316,328,340,
|
||||
5,17,29,41,53,65,77,89,101,113,125,137,149,161,173,185,197,209,221,233,245,257,269,281,293,305,317,329,341,
|
||||
6,18,30,42,54,66,78,90,102,114,126,138,150,162,174,186,198,210,222,234,246,258,270,282,294,306,318,330,342,
|
||||
7,19,31,43,55,67,79,91,103,115,127,139,151,163,175,187,199,211,223,235,247,259,271,283,295,307,319,331,343,
|
||||
8,20,32,44,56,68,80,92,104,116,128,140,152,164,176,188,200,212,224,236,248,260,272,284,296,308,320,332,344,
|
||||
9,21,33,45,57,69,81,93,105,117,129,141,153,165,177,189,201,213,225,237,249,261,273,285,297,309,321,333,345,
|
||||
10,22,34,46,58,70,82,94,106,118,130,142,154,166,178,190,202,214,226,238,250,262,274,286,298,310,322,334,346,
|
||||
11,23,35,47,59,71,83,95,107,119,131,143,155,167,179,191,203,215,227,239,251,263,275,287,299,311,323,335,347
|
||||
};
|
||||
|
||||
60
include/p25p1_check_hdu.h
Normal file
60
include/p25p1_check_hdu.h
Normal file
@@ -0,0 +1,60 @@
|
||||
|
||||
#ifndef P25P1_CHECK_HDU_H_f5f079faf2d64cf5831e1da1ab83b9ba
|
||||
#define P25P1_CHECK_HDU_H_f5f079faf2d64cf5831e1da1ab83b9ba
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Attempts to correct an hex (6-bit) word using the Golay(24,12,8) FEC.
|
||||
* \param hex The 6-bit word to error correct, given as a char array of 6 elements, one bit each.
|
||||
* \param parity A 12-bit word with the Golay parity data, given as a char array of 12 elements.
|
||||
* \param fixed_error Output. Filled with the number of errors fixed in the input.
|
||||
* \return 1 if there were uncorrectable errors in the input, 0 otherwise.
|
||||
*/
|
||||
int check_and_fix_golay_24_6(char* hex, char* parity, int* fixed_errors);
|
||||
|
||||
/**
|
||||
* Attempts to correct a 12-bit word using the Golay(24,12,8) FEC.
|
||||
* \param dodeca The 12-bit word to error correct, given as a char array of 12 elements, one bit each.
|
||||
* \param parity A 12-bit word with the Golay parity data, given as a char array of 12 elements.
|
||||
* \param fixed_error Output. Filled with the number of errors fixed in the input.
|
||||
* \return 1 if there were uncorrectable errors in the input, 0 otherwise.
|
||||
*/
|
||||
int check_and_fix_golay_24_12(char* dodeca, char* parity, int* fixed_errors);
|
||||
|
||||
/**
|
||||
* Encodes an hex word using the Golay(24,12,8) FEC.
|
||||
* \param hex A 6-bit word to encode.
|
||||
* \param out_parity The address to be filled with the calculated Golay parity.
|
||||
*/
|
||||
void encode_golay_24_6(char* hex, char* out_parity);
|
||||
|
||||
/**
|
||||
* Encodes an 12-bitword using the Golay(24,12,8) FEC.
|
||||
* \param dodeca A 12-bit word to encode.
|
||||
* \param out_parity The address to be filled with the calculated Golay parity.
|
||||
*/
|
||||
void encode_golay_24_12(char* dodeca, char* out_parity);
|
||||
|
||||
/**
|
||||
* Attempts to correct 20 hex words using the Reed-Solomon(36,20,17) FEC.
|
||||
* \param data The packed hex words, each of 6 chars, one after the other.
|
||||
* \param parity The corresponding 16 hex words with the parity information.
|
||||
* \return 1 if irrecoverable errors have been detected, 0 otherwise.
|
||||
*/
|
||||
int check_and_fix_redsolomon_36_20_17(char* data, char* parity);
|
||||
|
||||
/**
|
||||
* Calculates the Reed-Solomon parity of 20 words of 6 bits each.
|
||||
* \param hex_data The address with the words whose parity we want to calculate.
|
||||
* \param fixed_parity The address to be filled with the calculated parity. 16 words of 6 bits are produced.
|
||||
*/
|
||||
void encode_reedsolomon_36_20_17(char* hex_data, char* fixed_parity);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // P25P1_CHECK_HDU_H_f5f079faf2d64cf5831e1da1ab83b9ba
|
||||
58
include/p25p1_check_ldu.h
Normal file
58
include/p25p1_check_ldu.h
Normal file
@@ -0,0 +1,58 @@
|
||||
|
||||
#ifndef P25P1_CHECK_LDU_H_c1734445a67e47caa25673d7a4ce7520
|
||||
#define P25P1_CHECK_LDU_H_c1734445a67e47caa25673d7a4ce7520
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Attempts to error correct a hex (6-bit) word using the Hamming(10,6,3) FEC.
|
||||
* \param hex The 6-bit word to error correct.
|
||||
* \param parity The parity to use in the error correction. 4 bits.
|
||||
* \return The estimated error count. It might be erroneous.
|
||||
*/
|
||||
int check_and_fix_hamming_10_6_3(char* hex, char* parity);
|
||||
|
||||
/**
|
||||
* Encodes an hex word with the Hamming(10,6,3) FEC.
|
||||
* \param hex The 6-bit word to error correct.
|
||||
* \param out_parity The address where to store the calculated parity. 4 bytes are used, one for each bit.
|
||||
*/
|
||||
void encode_hamming_10_6_3(char* hex, char* out_parity);
|
||||
|
||||
/**
|
||||
* Attempts to correct 12 hex words using the Reed-Solomon(24,12,13) FEC.
|
||||
* \param data The packed hex words, each of 6 chars, one after the other.
|
||||
* \param parity The corresponding 12 hex words with the parity information.
|
||||
* \return 1 if irrecoverable errors have been detected, 0 otherwise.
|
||||
*/
|
||||
int check_and_fix_reedsolomon_24_12_13(char* data, char* parity);
|
||||
|
||||
/**
|
||||
* Encodes 12 hex words with the Reed-Solomon(24,12,13) FEC.
|
||||
* \param hex_data The packed 12 hex words to encode.
|
||||
* \fixed_parity The address were to store the 12 hex words with the Reed-Solomon parity.
|
||||
*/
|
||||
void encode_reedsolomon_24_12_13(char* hex_data, char* fixed_parity);
|
||||
|
||||
/**
|
||||
* Attempts to correct 16 hex words using the Reed-Solomon(24,16,9) FEC.
|
||||
* \param data The packed 16 hex words, each of 6 chars, one after the other.
|
||||
* \param parity The corresponding 8 hex words with the parity information.
|
||||
* \return 1 if irrecoverable errors have been detected, 0 otherwise.
|
||||
*/
|
||||
int check_and_fix_reedsolomon_24_16_9(char* data, char* parity);
|
||||
|
||||
/**
|
||||
* Encodes 12 hex words with the Reed-Solomon(24,16,9) FEC.
|
||||
* \param hex_data The packed 16 hex words to encode.
|
||||
* \fixed_parity The address were to store the 8 hex words with the Reed-Solomon parity.
|
||||
*/
|
||||
void encode_reedsolomon_24_16_9(char* hex_data, char* fixed_parity);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // P25P1_CHECK_LDU_H_c1734445a67e47caa25673d7a4ce7520
|
||||
26
include/p25p1_check_nid.h
Normal file
26
include/p25p1_check_nid.h
Normal file
@@ -0,0 +1,26 @@
|
||||
|
||||
#ifndef P25P1_CHECK_NID_H_3af071e917ea43fdb51326e2cbfbde0a
|
||||
#define P25P1_CHECK_NID_H_3af071e917ea43fdb51326e2cbfbde0a
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Checks a NID value, returns the fixed NAC, DUID and also an indication if it failed to decode the NID.
|
||||
* \param bch_code Input. An array to the 63 bytes, each containing one bit of the NID. This includes the
|
||||
* NAC (12 bits), DUID (4 bits) and 47 bits of BCH parity.
|
||||
* \param new_nac Output. An address where to store the calculated NAC value after error correction. Should
|
||||
* be large enough to accommodate for an integer.
|
||||
* \param new_duid Output. An address where to store the calculated DUID value after error correction. Should
|
||||
* be able to accommodate 3 chars.
|
||||
* \param parity Input. The parity value read.
|
||||
* \return 0 if there were errors processing the NID.
|
||||
*/
|
||||
int check_NID(char* bch_code, int* new_nac, char* new_duid, unsigned char parity);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // P25P1_CHECK_NID_H_3af071e917ea43fdb51326e2cbfbde0a
|
||||
73
include/p25p1_hdu.h
Normal file
73
include/p25p1_hdu.h
Normal file
@@ -0,0 +1,73 @@
|
||||
|
||||
#ifndef P25P1_HDU_H_9f95c3a5072842e8aaf94444e1452d20
|
||||
#define P25P1_HDU_H_9f95c3a5072842e8aaf94444e1452d20
|
||||
|
||||
|
||||
#include "p25p1_heuristics.h"
|
||||
|
||||
/**
|
||||
* Reads a dibit (two bits) from the stream of data. Takes into account the periodic occurrence of status
|
||||
* bits that show up every 36 dibits. Status bits are discarded.
|
||||
* \param opts A pointer the the DSD options.
|
||||
* \param state A pointer the the DSD state structure.
|
||||
* \param output A pointer to be filled with the dibit read. Two bytes used for each dibit.
|
||||
* \param status_count Variable used to keep track of the status symbols in the dibit stream. There is one
|
||||
* status every 36 dibits. With this counter we can skip the status.
|
||||
* \param analog_signal A pointer with the actual analog value read from the input signal and that has been
|
||||
* interpreted as the dibit we are returning in output.
|
||||
* \param did_read_status Address were a boolean is returned. This is set to true when one status symbol was
|
||||
* read (and skipped). This indicates that the sequence on dibits has been broken and is used by the P25
|
||||
* heuristics.
|
||||
*/
|
||||
int read_dibit (dsd_opts* opts, dsd_state* state, char* output, int* status_count, int* analog_signal,
|
||||
int* did_read_status);
|
||||
|
||||
/**
|
||||
* Reads a number of dibits and stores its value together with the actual analog value that has been
|
||||
* intrepreted as the dibit into an AnalogSignal structure. This is used later in the P25 heuristics module
|
||||
* to improve the accuracy of the digitizer.
|
||||
* \param opts A pointer the the DSD options.
|
||||
* \param state A pointer the the DSD state structure.
|
||||
* \param output A pointer to be filled with the dibits read.
|
||||
* \param count The number of bits to read (remember: 1 dibit = 2 bits).
|
||||
* \param status_count Variable used to keep track of the status symbols in the dibit stream. There is one
|
||||
* status every 36 dibits. With this counter we can skip the status.
|
||||
* \param analog_signal_array The pointer to the start of a sequence of AnalogSignal structures. The
|
||||
* information is updated for each dibit read.
|
||||
* \param analog_signal_index The actual index into the AnalogSignal array. This is increased here wich each
|
||||
* dibit read.
|
||||
*/
|
||||
void read_dibit_update_analog_data (dsd_opts* opts, dsd_state* state, char* buffer, unsigned int count,
|
||||
int* status_count, AnalogSignal* analog_signal_array, int* analog_signal_index);
|
||||
|
||||
/**
|
||||
* Reads a word, made up of length bits or length/2 dibits. Also keeps track of the status dibits.
|
||||
*/
|
||||
void read_word (dsd_opts* opts, dsd_state* state, char* word, unsigned int length, int* status_count,
|
||||
AnalogSignal* analog_signal_array, int* analog_signal_index);
|
||||
|
||||
/**
|
||||
* Reads 4 bits from the stream of data. Those are the parity bits that follow each hex word.
|
||||
*/
|
||||
void read_hamm_parity (dsd_opts* opts, dsd_state* state, char* parity, int* status_count,
|
||||
AnalogSignal* analog_signal_array, int* analog_signal_index);
|
||||
|
||||
/**
|
||||
* Reads 12 bits from the stream of data. Those are the extended Golay parity bits that follow a word of data.
|
||||
*/
|
||||
void read_golay24_parity (dsd_opts* opts, dsd_state* state, char* parity, int* status_count, AnalogSignal* analog_signal_array, int* analog_signal_index);
|
||||
|
||||
/**
|
||||
* Reads bits from the data stream that should all be zeros. This is valuable information for the
|
||||
* heuristics module and we update it.
|
||||
* \param opts A pointer the the DSD options.
|
||||
* \param state A pointer the the DSD state structure.
|
||||
* \param analog_signal_array The pointer to the start of a sequence of AnalogSignal structures.
|
||||
* \param length Number of bits to read.
|
||||
* \param status_count Variable used to keep track of the status symbols in the dibit stream.
|
||||
* \param new_sequence Bool used to update the sequence_broken value of the first AnalogSignal element.
|
||||
*/
|
||||
void read_zeros(dsd_opts* opts, dsd_state* state, AnalogSignal* analog_signal_array, unsigned int length,
|
||||
int* status_count, int new_sequence);
|
||||
|
||||
#endif // P25P1_HDU_H_9f95c3a5072842e8aaf94444e1452d20
|
||||
91
include/p25p1_heuristics.h
Normal file
91
include/p25p1_heuristics.h
Normal file
@@ -0,0 +1,91 @@
|
||||
|
||||
#ifndef P25P1_HEURISTICS_H_030dd3530b7546abbb56f8dd1e66a2f6
|
||||
#define P25P1_HEURISTICS_H_030dd3530b7546abbb56f8dd1e66a2f6
|
||||
|
||||
#define HEURISTICS_SIZE 200
|
||||
typedef struct
|
||||
{
|
||||
int values[HEURISTICS_SIZE];
|
||||
float means[HEURISTICS_SIZE];
|
||||
int index;
|
||||
int count;
|
||||
float sum;
|
||||
float var_sum;
|
||||
} SymbolHeuristics;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned int bit_count;
|
||||
unsigned int bit_error_count;
|
||||
SymbolHeuristics symbols[4][4];
|
||||
} P25Heuristics;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int value;
|
||||
int dibit;
|
||||
int corrected_dibit;
|
||||
int sequence_broken;
|
||||
} AnalogSignal;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"{
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Initializes the heuristics state.
|
||||
* \param heuristics The P25Heuristics structure to initialize.
|
||||
*/
|
||||
void initialize_p25_heuristics(P25Heuristics* heuristics);
|
||||
|
||||
/**
|
||||
* Important method that estimates the most likely symbol for a given analog signal value and previous dibit.
|
||||
* This is called by the digitizer.
|
||||
* \param rf_mod Indicates the modulation used. The previous dibit is only used on C4FM.
|
||||
* \param heuristics Pointer to the P25Heuristics module with all the needed state information.
|
||||
* \param previous_dibit The previous dibit.
|
||||
* \param analog_value The signal's analog value we want to interpret as a dibit.
|
||||
* \param dibit Address were to store the estimated dibit.
|
||||
* \return A boolean set to true if we are able to estimate a dibit. The reason why we might not be able
|
||||
* to estimate it is because we don't have enough information to model the Gaussians (not enough data
|
||||
* has been passed to contribute_to_heuristics).
|
||||
*/
|
||||
int estimate_symbol(int rf_mod, P25Heuristics* heuristics, int previous_dibit, int analog_value, int* dibit);
|
||||
|
||||
/**
|
||||
* Log some useful information on the heuristics state.
|
||||
*/
|
||||
void debug_print_heuristics(P25Heuristics* heuristics);
|
||||
|
||||
/**
|
||||
* This method contributes valuable information from dibits whose value we are confident is correct. We take
|
||||
* the dibits and corresponding analog signal values to model the Gaussians for each dibit (and previous
|
||||
* dibit if enabled).
|
||||
* \param rf_mod Indicates the modulation used. The previous dibit is only used on C4FM.
|
||||
* \param heuristics Pointer to the P25Heuristics module with all the needed state information.
|
||||
* \param analog_signal_array Sequence of AnalogSignal which contain the cleared dibits and analog values.
|
||||
* \param count number of cleared dibits passed (= number of elements to use from analog_signal_array).
|
||||
*/
|
||||
void contribute_to_heuristics(int rf_mod, P25Heuristics* heuristics, AnalogSignal* analog_signal_array, int count);
|
||||
|
||||
/**
|
||||
* Updates the estimate for the BER (bit error rate). Mind this is method is not called for every single
|
||||
* bit in the data stream but only for those bits over which we have an estimate of its error rate,
|
||||
* specifically the bits that are protected by Reed-Solomon codes.
|
||||
* \param heuristics The heuristics state.
|
||||
* \param bits The number of bits we have read.
|
||||
* \param errors The number of errors we estimate in those bits.
|
||||
*/
|
||||
void update_error_stats(P25Heuristics* heuristics, int bits, int errors);
|
||||
|
||||
/**
|
||||
* Returns the estimate for the BER (bit error rate).
|
||||
* \return The estimated BER. This is just the percentage of errors over the processed bits.
|
||||
*/
|
||||
float get_P25_BER_estimate(P25Heuristics* heuristics);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // P25P1_HEURISTICS_H_030dd3530b7546abbb56f8dd1e66a2f6
|
||||
49
include/p25p1_ldu.h
Normal file
49
include/p25p1_ldu.h
Normal file
@@ -0,0 +1,49 @@
|
||||
|
||||
#ifndef P25P1_LDU_H_a3c417fcb7804991b0e6d828066bd133
|
||||
#define P25P1_LDU_H_a3c417fcb7804991b0e6d828066bd133
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
#include "p25p1_hdu.h"
|
||||
#include "p25p1_const.h"
|
||||
#include "p25p1_heuristics.h"
|
||||
|
||||
/**
|
||||
* Separate imbe frames and deinterleave.
|
||||
* This important methods read the IMBE data from the stream and passes it to the vocoder to produce audio.
|
||||
* \param opts The DSD options.
|
||||
* \param state The DSD state.
|
||||
* \status_count An index that allows us to skip the status words interleaved every 36 dibit in the data
|
||||
* stream.
|
||||
*/
|
||||
void process_IMBE (dsd_opts* opts, dsd_state* state, int* status_count);
|
||||
|
||||
/**
|
||||
* Reads an hex word, its parity bits and attempts to error correct it using the Hamming FEC.
|
||||
* \param opts The DSD options.
|
||||
* \param state The DSD state.
|
||||
* \param hex Pointer where to store the read hex word. Six bytes, one per bit.
|
||||
* \param status_count An index that allows us to skip the status words interleaved every 36 dibit in the data
|
||||
* stream.
|
||||
* \param analog_singal_array Pointer to a sequence of AnalogSignal elements.
|
||||
* \param analog_signal_index The current index in the analog_singal_array. This value is increased on each
|
||||
* dibit read.
|
||||
*/
|
||||
void read_and_correct_hex_word (dsd_opts* opts, dsd_state* state, char* hex, int* status_count,
|
||||
AnalogSignal* analog_signal_array, int* analog_signal_index);
|
||||
|
||||
/**
|
||||
* Correct the information in analog_signal_array according with the content of data, which has been
|
||||
* error corrected and should be valid.
|
||||
* \param Dibits that have already been error corrected and we trust are correct.
|
||||
* \count Number of dibits.
|
||||
* \param analog_signal_array Pointer to a sequence of AnalogSignal elements, as many as the value of count.
|
||||
*/
|
||||
void correct_hamming_dibits(char* hex_data, int hex_count, AnalogSignal* analog_signal_array);
|
||||
|
||||
/**
|
||||
* Logs some debug info.
|
||||
*/
|
||||
void debug_ldu_header(dsd_state* state);
|
||||
|
||||
#endif // P25P1_LDU_H_a3c417fcb7804991b0e6d828066bd133
|
||||
6
include/pa_devs.h
Normal file
6
include/pa_devs.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#ifndef PA_DEVS_H
|
||||
#define PA_DEVS_H
|
||||
|
||||
void printPortAudioDevices();
|
||||
|
||||
#endif
|
||||
8
install.sh
Normal file
8
install.sh
Normal file
@@ -0,0 +1,8 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make -j $(nproc)
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
124
nxdn96.c
124
nxdn96.c
@@ -1,124 +0,0 @@
|
||||
#include "dsd.h"
|
||||
#include "nxdn96_const.h"
|
||||
|
||||
void
|
||||
processNXDN96 (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
int i, j, k, dibit;
|
||||
|
||||
char ambe_fr[4][24];
|
||||
const int *w, *x, *y, *z;
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printf ("VOICE e:");
|
||||
}
|
||||
|
||||
#ifdef NXDN_DUMP
|
||||
printf ("\n");
|
||||
#endif
|
||||
|
||||
for (k = 0; k < 4; k++)
|
||||
{
|
||||
for (i = 0; i < 222; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef NXDN_DUMP
|
||||
printf ("%c", dibit + 48);
|
||||
#endif
|
||||
}
|
||||
#ifdef NXDN_DUMP
|
||||
printf (" ");
|
||||
#endif
|
||||
|
||||
if (k < 3)
|
||||
{
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
w = nW;
|
||||
x = nX;
|
||||
y = nY;
|
||||
z = nZ;
|
||||
for (i = 0; i < 36; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef NXDN_DUMP
|
||||
printf ("%c", dibit + 48);
|
||||
#endif
|
||||
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr[*y][*z] = (1 & dibit); // bit 0
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
}
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
#ifdef NXDN_DUMP
|
||||
printf (" ");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (j = 0; j < 3; j++) // we skip the last voice frame until frame sync can work with < 24 symbols
|
||||
{
|
||||
w = nW;
|
||||
x = nX;
|
||||
y = nY;
|
||||
z = nZ;
|
||||
for (i = 0; i < 36; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef NXDN_DUMP
|
||||
printf ("%c", dibit + 48);
|
||||
#endif
|
||||
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr[*y][*z] = (1 & dibit); // bit 0
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
}
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
#ifdef NXDN_DUMP
|
||||
printf (" ");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (k < 3)
|
||||
{
|
||||
for (i = 0; i < 18; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef NXDN_DUMP
|
||||
printf ("%c", dibit + 48);
|
||||
#endif
|
||||
}
|
||||
#ifdef NXDN_DUMP
|
||||
printf (" ");
|
||||
#endif
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 30; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef NXDN_DUMP
|
||||
printf ("%c", dibit + 48);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NXDN_DUMP
|
||||
printf ("\n");
|
||||
#endif
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
}
|
||||
36
nxdn_data.c
36
nxdn_data.c
@@ -1,36 +0,0 @@
|
||||
#include "dsd.h"
|
||||
|
||||
void
|
||||
processNXDNData (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
int i, dibit;
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printf ("DATA ");
|
||||
}
|
||||
|
||||
for (i = 0; i < 30; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef NXDN_DUMP
|
||||
printf ("%c", dibit + 48);
|
||||
#endif
|
||||
}
|
||||
#ifdef NXDN_DUMP
|
||||
printf (" ");
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 144; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef NXDN_DUMP
|
||||
printf ("%c", dibit + 48);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
59
nxdn_voice.c
59
nxdn_voice.c
@@ -1,59 +0,0 @@
|
||||
#include "dsd.h"
|
||||
#include "nxdn_const.h"
|
||||
|
||||
void
|
||||
processNXDNVoice (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
int i, j, dibit;
|
||||
char ambe_fr[4][24];
|
||||
const int *w, *x, *y, *z;
|
||||
const char *pr;
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printf ("VOICE e:");
|
||||
}
|
||||
|
||||
for (i = 0; i < 30; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef NXDN_DUMP
|
||||
printf ("%c", dibit + 48);
|
||||
#endif
|
||||
}
|
||||
#ifdef NXDN_DUMP
|
||||
printf (" ");
|
||||
#endif
|
||||
|
||||
pr = nxdnpr;
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
w = nW;
|
||||
x = nX;
|
||||
y = nY;
|
||||
z = nZ;
|
||||
for (i = 0; i < 36; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef NXDN_DUMP
|
||||
printf ("%c", dibit + 48);
|
||||
#endif
|
||||
ambe_fr[*w][*x] = *pr ^ (1 & (dibit >> 1)); // bit 1
|
||||
pr++;
|
||||
ambe_fr[*y][*z] = (1 & dibit); // bit 0
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
}
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
#ifdef NXDN_DUMP
|
||||
printf (" ");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
160
p25_lcw.c
160
p25_lcw.c
@@ -1,160 +0,0 @@
|
||||
#include "dsd.h"
|
||||
|
||||
void
|
||||
processP25lcw (dsd_opts * opts, dsd_state * state, char *lcformat, char *mfid, char *lcinfo)
|
||||
{
|
||||
|
||||
char tgid[17], tmpstr[255];
|
||||
long talkgroup, source;
|
||||
int i, j;
|
||||
|
||||
tgid[16] = 0;
|
||||
|
||||
if (opts->p25lc == 1)
|
||||
{
|
||||
printf ("lcformat: %s mfid: %s lcinfo: %s ", lcformat, mfid, lcinfo);
|
||||
if (opts->p25tg == 0)
|
||||
{
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp (lcformat, "00000100") == 0)
|
||||
{
|
||||
|
||||
// first tg is the active channel
|
||||
j = 0;
|
||||
for (i = 40; i < 52; i++)
|
||||
{
|
||||
if (state->tgcount < 24)
|
||||
{
|
||||
state->tg[state->tgcount][j] = lcinfo[i];
|
||||
}
|
||||
tmpstr[j] = lcinfo[i];
|
||||
j++;
|
||||
}
|
||||
tmpstr[12] = 48;
|
||||
tmpstr[13] = 48;
|
||||
tmpstr[14] = 48;
|
||||
tmpstr[15] = 48;
|
||||
tmpstr[16] = 0;
|
||||
talkgroup = strtol (tmpstr, NULL, 2);
|
||||
state->lasttg = talkgroup;
|
||||
if (state->tgcount < 24)
|
||||
{
|
||||
state->tgcount = state->tgcount + 1;
|
||||
}
|
||||
if (opts->p25tg == 1)
|
||||
{
|
||||
printf ("tg: %li ", talkgroup);
|
||||
}
|
||||
|
||||
if (opts->p25tg == 1)
|
||||
{
|
||||
printf ("tg: %li ", talkgroup);
|
||||
|
||||
// the remaining 3 appear to be other active tg's on the system
|
||||
j = 0;
|
||||
for (i = 28; i < 40; i++)
|
||||
{
|
||||
tmpstr[j] = lcinfo[i];
|
||||
j++;
|
||||
}
|
||||
tmpstr[12] = 48;
|
||||
tmpstr[13] = 48;
|
||||
tmpstr[14] = 48;
|
||||
tmpstr[15] = 48;
|
||||
tmpstr[16] = 0;
|
||||
talkgroup = strtol (tmpstr, NULL, 2);
|
||||
printf ("%li ", talkgroup);
|
||||
j = 0;
|
||||
for (i = 16; i < 28; i++)
|
||||
{
|
||||
tmpstr[j] = lcinfo[i];
|
||||
j++;
|
||||
}
|
||||
tmpstr[12] = 48;
|
||||
tmpstr[13] = 48;
|
||||
tmpstr[14] = 48;
|
||||
tmpstr[15] = 48;
|
||||
tmpstr[16] = 0;
|
||||
talkgroup = strtol (tmpstr, NULL, 2);
|
||||
printf ("%li ", talkgroup);
|
||||
j = 0;
|
||||
for (i = 4; i < 16; i++)
|
||||
{
|
||||
tmpstr[j] = lcinfo[i];
|
||||
j++;
|
||||
}
|
||||
tmpstr[12] = 48;
|
||||
tmpstr[13] = 48;
|
||||
tmpstr[14] = 48;
|
||||
tmpstr[15] = 48;
|
||||
tmpstr[16] = 0;
|
||||
talkgroup = strtol (tmpstr, NULL, 2);
|
||||
printf ("%li\n", talkgroup);
|
||||
}
|
||||
}
|
||||
|
||||
else if (strcmp (lcformat, "00000000") == 0)
|
||||
{
|
||||
j = 0;
|
||||
if (strcmp (mfid, "10010000") == 0)
|
||||
{
|
||||
for (i = 20; i < 32; i++)
|
||||
{
|
||||
if (state->tgcount < 24)
|
||||
{
|
||||
state->tg[state->tgcount][j] = lcinfo[i];
|
||||
}
|
||||
tmpstr[j] = lcinfo[i];
|
||||
j++;
|
||||
}
|
||||
tmpstr[12] = 48;
|
||||
tmpstr[13] = 48;
|
||||
tmpstr[14] = 48;
|
||||
tmpstr[15] = 48;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 16; i < 32; i++)
|
||||
{
|
||||
if (state->tgcount < 24)
|
||||
{
|
||||
state->tg[state->tgcount][j] = lcinfo[i];
|
||||
}
|
||||
tmpstr[j] = lcinfo[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
tmpstr[16] = 0;
|
||||
talkgroup = strtol (tmpstr, NULL, 2);
|
||||
state->lasttg = talkgroup;
|
||||
if (state->tgcount < 24)
|
||||
{
|
||||
state->tgcount = state->tgcount + 1;
|
||||
}
|
||||
if (opts->p25tg == 1)
|
||||
{
|
||||
printf ("tg: %li ", talkgroup);
|
||||
}
|
||||
|
||||
j = 0;
|
||||
for (i = 32; i < 56; i++)
|
||||
{
|
||||
tmpstr[j] = lcinfo[i];
|
||||
j++;
|
||||
}
|
||||
tmpstr[24] = 0;
|
||||
source = strtol (tmpstr, NULL, 2);
|
||||
state->lastsrc = source;
|
||||
if (opts->p25tg == 1)
|
||||
{
|
||||
printf ("src: %li emr: %c\n", source, lcinfo[0]);
|
||||
}
|
||||
}
|
||||
else if ((opts->p25tg == 1) && (opts->p25lc == 1))
|
||||
{
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
316
p25p1_hdu.c
316
p25p1_hdu.c
@@ -1,316 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
void
|
||||
processHDU (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
char mi[73], mfid[9], algid[9], kid[17], tgid[17], tmpstr[255];
|
||||
int dibit, count, i, j;
|
||||
long talkgroup;
|
||||
int algidhex, kidhex;
|
||||
|
||||
mi[72] = 0;
|
||||
mfid[8] = 0;
|
||||
algid[8] = 0;
|
||||
kid[16] = 0;
|
||||
tgid[16] = 0;
|
||||
|
||||
skipDibit (opts, state, 25);
|
||||
count = 57;
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
mi[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[1] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[3] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[4] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[5] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
mi[6] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[7] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[8] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[9] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[10] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[11] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 7);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
mi[12] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[13] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[14] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[15] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[16] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[17] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
mi[18] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[19] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[20] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[21] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[22] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[23] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
mi[24] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[25] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[26] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[27] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[28] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[29] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
mi[30] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[31] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[32] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[33] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[34] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[35] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 7);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
mi[36] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[37] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[38] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[39] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[40] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[41] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
mi[42] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[43] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[44] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[45] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[46] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[47] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
mi[48] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[49] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[50] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[51] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[52] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[53] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
mi[54] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[55] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[56] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[57] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[58] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[59] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 7);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
mi[60] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[61] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[62] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[63] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[64] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[65] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
mi[66] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[67] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[68] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[69] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[70] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[71] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
mfid[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mfid[1] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mfid[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mfid[3] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mfid[4] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mfid[5] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
mfid[6] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mfid[7] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
algid[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
algid[1] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 1);
|
||||
dibit = getDibit (opts, state);
|
||||
algid[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
algid[3] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
algid[4] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
algid[5] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
algid[6] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
algid[7] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
kid[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
kid[1] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
kid[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
kid[3] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
kid[4] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
kid[5] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
kid[6] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
kid[7] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
kid[8] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
kid[9] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
kid[10] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
kid[11] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
kid[12] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
kid[13] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
kid[14] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
kid[15] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 1);
|
||||
dibit = getDibit (opts, state);
|
||||
tgid[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
tgid[1] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
tgid[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
tgid[3] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
tgid[4] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
tgid[5] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
tgid[6] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
tgid[7] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
tgid[8] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
tgid[9] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
tgid[10] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
tgid[11] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
tgid[12] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
tgid[13] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
tgid[14] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
tgid[15] = (1 & dibit) + 48; // bit 0
|
||||
|
||||
skipDibit (opts, state, 160);
|
||||
|
||||
if (opts->p25enc == 1)
|
||||
{
|
||||
algidhex = strtol (algid, NULL, 2);
|
||||
kidhex = strtol (kid, NULL, 2);
|
||||
printf ("mi: %s algid: $%x kid: $%x\n", mi, algidhex, kidhex);
|
||||
}
|
||||
if (opts->p25lc == 1)
|
||||
{
|
||||
printf ("mfid: %s tgid: %s ", mfid, tgid);
|
||||
if (opts->p25tg == 0)
|
||||
{
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
|
||||
j = 0;
|
||||
if (strcmp (mfid, "10010000") == 0)
|
||||
{
|
||||
for (i = 4; i < 16; i++)
|
||||
{
|
||||
if (state->tgcount < 24)
|
||||
{
|
||||
state->tg[state->tgcount][j] = tgid[i];
|
||||
}
|
||||
tmpstr[j] = tgid[i];
|
||||
j++;
|
||||
}
|
||||
tmpstr[12] = 48;
|
||||
tmpstr[13] = 48;
|
||||
tmpstr[14] = 48;
|
||||
tmpstr[15] = 48;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
if (state->tgcount < 24)
|
||||
{
|
||||
state->tg[state->tgcount][j] = tgid[i];
|
||||
}
|
||||
tmpstr[j] = tgid[i];
|
||||
j++;
|
||||
}
|
||||
}
|
||||
tmpstr[16] = 0;
|
||||
talkgroup = strtol (tmpstr, NULL, 2);
|
||||
state->lasttg = talkgroup;
|
||||
if (state->tgcount < 24)
|
||||
{
|
||||
state->tgcount = state->tgcount + 1;
|
||||
}
|
||||
if (opts->p25tg == 1)
|
||||
{
|
||||
printf ("tg: %li\n", talkgroup);
|
||||
}
|
||||
}
|
||||
295
p25p1_ldu1.c
295
p25p1_ldu1.c
@@ -1,295 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
#include "p25p1_const.h"
|
||||
|
||||
void
|
||||
processLDU1 (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
// extracts IMBE frames rom LDU frame
|
||||
int i, j, k, dibit, stats, count, scount;
|
||||
char imbe_fr[8][23];
|
||||
char lcformat[9], mfid[9], lcinfo[57], lsd1[9], lsd2[9], status[25];
|
||||
const int *w, *x, *y, *z;
|
||||
|
||||
lcformat[8] = 0;
|
||||
mfid[8] = 0;
|
||||
lcinfo[56] = 0;
|
||||
lsd1[8] = 0;
|
||||
lsd2[8] = 0;
|
||||
status[24] = 0;
|
||||
|
||||
skipDibit (opts, state, 3);
|
||||
status[0] = getDibit (opts, state) + 48;
|
||||
skipDibit (opts, state, 21);
|
||||
count = 57;
|
||||
scount = 1;
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printf ("e:");
|
||||
}
|
||||
|
||||
// separate imbe frames and deinterleave
|
||||
stats = 21; // we skip the status dibits that occur every 36 symbols
|
||||
// the first IMBE frame starts 14 symbols before next status
|
||||
// so we start counter at 22
|
||||
for (i = 0; i < 9; i++)
|
||||
{ // 9 IMBE frames per LDU
|
||||
w = iW;
|
||||
x = iX;
|
||||
y = iY;
|
||||
z = iZ;
|
||||
for (j = 0; j < 72; j++)
|
||||
{
|
||||
if (stats == 35)
|
||||
{
|
||||
status[scount] = getDibit (opts, state) + 48;
|
||||
scount++;
|
||||
stats = 1;
|
||||
count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
stats++;
|
||||
}
|
||||
dibit = getDibit (opts, state);
|
||||
count++;
|
||||
imbe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
imbe_fr[*y][*z] = (1 & dibit); // bit 0
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
}
|
||||
processMbeFrame (opts, state, imbe_fr, NULL, NULL);
|
||||
|
||||
// skip over non imbe data sometimes between frames
|
||||
if ((i < 4) || (i == 8))
|
||||
{
|
||||
k = 0;
|
||||
}
|
||||
else if (i == 7)
|
||||
{
|
||||
//k=16;
|
||||
k = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
k = 20;
|
||||
}
|
||||
for (j = 0; j < k; j++)
|
||||
{
|
||||
if (stats == 35)
|
||||
{
|
||||
status[scount] = getDibit (opts, state) + 48;
|
||||
scount++;
|
||||
count++;
|
||||
stats = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
stats++;
|
||||
}
|
||||
skipDibit (opts, state, 1);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (i == 1)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
lcformat[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcformat[1] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcformat[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcformat[3] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcformat[4] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcformat[5] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
dibit = getDibit (opts, state);
|
||||
lcformat[6] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcformat[7] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mfid[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mfid[1] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mfid[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mfid[3] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
status[scount] = getDibit (opts, state) + 48;
|
||||
scount++;
|
||||
dibit = getDibit (opts, state);
|
||||
mfid[4] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mfid[5] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mfid[6] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mfid[7] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[1] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[3] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[4] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[5] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[6] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[7] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
stats = 10;
|
||||
}
|
||||
else if (i == 2)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[8] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[9] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[10] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[11] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[12] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[13] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[14] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[15] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[16] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[17] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[18] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[19] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[20] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[21] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[22] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[23] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[24] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[25] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[26] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[27] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[28] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[29] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[30] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[31] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
stats = 32;
|
||||
}
|
||||
else if (i == 3)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[32] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[33] = (1 & dibit) + 48; // bit 0
|
||||
status[scount] = getDibit (opts, state) + 48;
|
||||
scount++;
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[34] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[35] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[36] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[37] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[38] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[39] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[40] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[41] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[42] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[43] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[44] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[45] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[46] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[47] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[48] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[49] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[50] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[51] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[52] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[53] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[54] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[55] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
stats = 19;
|
||||
}
|
||||
else if (i == 7)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
lsd1[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lsd1[1] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lsd1[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lsd1[3] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lsd1[4] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lsd1[5] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lsd1[6] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lsd1[7] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 4);
|
||||
dibit = getDibit (opts, state);
|
||||
lsd2[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lsd2[1] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lsd2[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lsd2[3] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lsd2[4] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lsd2[5] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lsd2[6] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lsd2[7] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 4);
|
||||
stats = 33;
|
||||
}
|
||||
}
|
||||
// trailing status symbol
|
||||
status[scount] = getDibit (opts, state) + 48;
|
||||
scount++;
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
if (opts->p25status == 1)
|
||||
{
|
||||
printf ("status: %s lsd1: %s lsd2: %s\n", status, lsd1, lsd2);
|
||||
}
|
||||
|
||||
processP25lcw (opts, state, lcformat, mfid, lcinfo);
|
||||
}
|
||||
352
p25p1_ldu2.c
352
p25p1_ldu2.c
@@ -1,352 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
#include "p25p1_const.h"
|
||||
|
||||
void
|
||||
processLDU2 (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
// extracts IMBE frames rom LDU frame
|
||||
int i, j, k, dibit, stats, count, scount;
|
||||
char imbe_fr[8][23];
|
||||
char mi[73], algid[9], kid[17], lsd3[9], lsd4[9], status[25];
|
||||
const int *w, *x, *y, *z;
|
||||
int algidhex, kidhex;
|
||||
|
||||
status[24] = 0;
|
||||
mi[72] = 0;
|
||||
algid[8] = 0;
|
||||
kid[16] = 0;
|
||||
lsd3[8] = 0;
|
||||
lsd4[8] = 0;
|
||||
|
||||
skipDibit (opts, state, 3);
|
||||
status[0] = getDibit (opts, state) + 48;
|
||||
skipDibit (opts, state, 21);
|
||||
scount = 1;
|
||||
|
||||
count = 57;
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printf ("e:");
|
||||
}
|
||||
|
||||
// separate imbe frames and deinterleave
|
||||
stats = 21;
|
||||
// we skip the status dibits that occur every 36 symbols
|
||||
// the first IMBE frame starts 14 symbols before next status
|
||||
// so we start counter at 22
|
||||
for (i = 0; i < 9; i++)
|
||||
{ // 9 IMBE frames per LDU
|
||||
w = iW;
|
||||
x = iX;
|
||||
y = iY;
|
||||
z = iZ;
|
||||
for (j = 0; j < 72; j++)
|
||||
{
|
||||
if (stats == 35)
|
||||
{
|
||||
status[scount] = getDibit (opts, state) + 48;
|
||||
scount++;
|
||||
stats = 1;
|
||||
count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
stats++;
|
||||
}
|
||||
dibit = getDibit (opts, state);
|
||||
count++;
|
||||
imbe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
imbe_fr[*y][*z] = (1 & dibit); // bit 0
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
}
|
||||
processMbeFrame (opts, state, imbe_fr, NULL, NULL);
|
||||
|
||||
// skip over non imbe data sometimes between frames
|
||||
if ((i < 5) || (i == 8))
|
||||
{
|
||||
k = 0;
|
||||
}
|
||||
else if (i == 7)
|
||||
{
|
||||
//k=16;
|
||||
k = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
k = 20;
|
||||
}
|
||||
|
||||
for (j = 0; j < k; j++)
|
||||
{
|
||||
if (stats == 35)
|
||||
{
|
||||
status[scount] = getDibit (opts, state) + 48;
|
||||
scount++;
|
||||
count++;
|
||||
stats = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
stats++;
|
||||
}
|
||||
skipDibit (opts, state, 1);
|
||||
count++;
|
||||
}
|
||||
|
||||
if (i == 1)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
mi[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[1] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[3] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[4] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[5] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
dibit = getDibit (opts, state);
|
||||
mi[6] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[7] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[8] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[9] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[10] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[11] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
status[scount] = getDibit (opts, state) + 48;
|
||||
scount++;
|
||||
dibit = getDibit (opts, state);
|
||||
mi[12] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[13] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[14] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[15] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[16] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[17] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
dibit = getDibit (opts, state);
|
||||
mi[18] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[19] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[20] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[21] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[22] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[23] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
stats = 10;
|
||||
}
|
||||
else if (i == 2)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
mi[24] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[25] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[26] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[27] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[28] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[29] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
dibit = getDibit (opts, state);
|
||||
mi[30] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[31] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[32] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[33] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[34] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[35] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
dibit = getDibit (opts, state);
|
||||
mi[36] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[37] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[38] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[39] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[40] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[41] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
dibit = getDibit (opts, state);
|
||||
mi[42] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[43] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[44] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[45] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[46] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[47] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
stats = 32;
|
||||
}
|
||||
else if (i == 3)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
mi[48] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[49] = (1 & dibit) + 48; // bit 0
|
||||
status[scount] = getDibit (opts, state) + 48;
|
||||
scount++;
|
||||
dibit = getDibit (opts, state);
|
||||
mi[50] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[51] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[52] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[53] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
dibit = getDibit (opts, state);
|
||||
mi[54] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[55] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[56] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[57] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[58] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[59] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
dibit = getDibit (opts, state);
|
||||
mi[60] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[61] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[62] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[63] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[64] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[65] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
dibit = getDibit (opts, state);
|
||||
mi[66] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[67] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[68] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[69] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mi[70] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mi[71] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
stats = 19;
|
||||
}
|
||||
else if (i == 4)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
algid[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
algid[1] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
algid[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
algid[3] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
algid[4] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
algid[5] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
dibit = getDibit (opts, state);
|
||||
algid[6] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
algid[7] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
kid[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
kid[1] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
kid[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
kid[3] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
dibit = getDibit (opts, state);
|
||||
kid[4] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
kid[5] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
kid[6] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
kid[7] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
kid[8] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
kid[9] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 1);
|
||||
status[scount] = getDibit (opts, state) + 48;
|
||||
scount++;
|
||||
skipDibit (opts, state, 1);
|
||||
dibit = getDibit (opts, state);
|
||||
kid[10] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
kid[11] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
kid[12] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
kid[13] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
kid[14] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
kid[15] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 2);
|
||||
stats = 6;
|
||||
}
|
||||
else if (i == 7)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
lsd3[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lsd3[1] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lsd3[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lsd3[3] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lsd3[4] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lsd3[5] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lsd3[6] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lsd3[7] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 4);
|
||||
dibit = getDibit (opts, state);
|
||||
lsd4[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lsd4[1] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lsd4[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lsd4[3] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lsd4[4] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lsd4[5] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lsd4[6] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lsd4[7] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 4);
|
||||
stats = 33;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//trailing status symbol
|
||||
status[scount] = getDibit (opts, state) + 48;
|
||||
scount++;
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
if (opts->p25status == 1)
|
||||
{
|
||||
printf ("status: %s lsd3: %s lsd4: %s\n", status, lsd3, lsd4);
|
||||
}
|
||||
if (opts->p25enc == 1)
|
||||
{
|
||||
algidhex = strtol (algid, NULL, 2);
|
||||
kidhex = strtol (kid, NULL, 2);
|
||||
printf ("mi: %s algid: $%x kid: $%x\n", mi, algidhex, kidhex);
|
||||
}
|
||||
}
|
||||
158
p25p1_tdulc.c
158
p25p1_tdulc.c
@@ -1,158 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010 DSD Author
|
||||
* GPG Key ID: 0x3F1D7FD0 (74EF 430D F7F2 0A48 FCE6 F630 FAA2 635D 3F1D 7FD0)
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
* PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
void
|
||||
processTDULC (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
char lcinfo[57], lcformat[9], mfid[9];
|
||||
int dibit, count;
|
||||
|
||||
lcformat[8] = 0;
|
||||
mfid[8] = 0;
|
||||
lcinfo[56] = 0;
|
||||
|
||||
skipDibit (opts, state, 25);
|
||||
count = 57;
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
lcformat[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcformat[1] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcformat[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcformat[3] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcformat[4] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcformat[5] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcformat[6] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcformat[7] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mfid[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mfid[1] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mfid[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mfid[3] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
mfid[4] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mfid[5] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
mfid[6] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
mfid[7] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 1);
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[0] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[1] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[2] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[3] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[4] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[5] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[6] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[7] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[8] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[9] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[10] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[11] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[12] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[13] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[14] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[15] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[16] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[17] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[18] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[19] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[20] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[21] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[22] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[23] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[24] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[25] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[26] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[27] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[28] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[29] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[30] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[31] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[32] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[33] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 1);
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[34] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[35] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[36] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[37] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[38] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[39] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[40] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[41] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[42] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[43] = (1 & dibit) + 48; // bit 0
|
||||
skipDibit (opts, state, 6);
|
||||
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[44] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[45] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[46] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[47] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[48] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[49] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[50] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[51] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[52] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[53] = (1 & dibit) + 48; // bit 0
|
||||
dibit = getDibit (opts, state);
|
||||
lcinfo[54] = (1 & (dibit >> 1)) + 48; // bit 1
|
||||
lcinfo[55] = (1 & dibit) + 48; // bit 0
|
||||
|
||||
skipDibit (opts, state, 91);
|
||||
|
||||
processP25lcw (opts, state, lcformat, mfid, lcinfo);
|
||||
}
|
||||
120
patch/dmr_data_voice_call_tg_src_persistency_ncurses2.patch
Normal file
120
patch/dmr_data_voice_call_tg_src_persistency_ncurses2.patch
Normal file
@@ -0,0 +1,120 @@
|
||||
diff --git a/src/dmr_block.c b/src/dmr_block.c
|
||||
index 893b0e8..e7f9de7 100644
|
||||
--- a/src/dmr_block.c
|
||||
+++ b/src/dmr_block.c
|
||||
@@ -783,6 +783,6 @@ void dmr_reset_blocks (dsd_opts * opts, dsd_state * state)
|
||||
//reset some strings -- resetting call string here causes random blink on ncurses terminal (cap+)
|
||||
// sprintf (state->call_string[0], "%s", " "); //21 spaces
|
||||
// sprintf (state->call_string[1], "%s", " "); //21 spaces
|
||||
- sprintf (state->dmr_lrrp_gps[0], "%s", "");
|
||||
- sprintf (state->dmr_lrrp_gps[1], "%s", "");
|
||||
+ // sprintf (state->dmr_lrrp_gps[0], "%s", ""); //disabled for dmr data call persistence #174
|
||||
+ // sprintf (state->dmr_lrrp_gps[1], "%s", ""); //disabled for dmr data call persistence #174
|
||||
}
|
||||
\ No newline at end of file
|
||||
diff --git a/src/dmr_data.c b/src/dmr_data.c
|
||||
index 3541152..3cae906 100644
|
||||
--- a/src/dmr_data.c
|
||||
+++ b/src/dmr_data.c
|
||||
@@ -267,7 +267,20 @@ dmr_data_sync (dsd_opts * opts, dsd_state * state)
|
||||
state->color_code_ok = SlotTypeOk;
|
||||
|
||||
//not sure why I still have two variables for this, need to look and see what state->color_code still ties into
|
||||
- if (SlotTypeOk == 1) state->dmr_color_code = state->color_code;
|
||||
+ if (SlotTypeOk == 1)
|
||||
+ {
|
||||
+ if (state->dmr_color_code != state->color_code)
|
||||
+ {
|
||||
+ //Zero out values on color code change #174
|
||||
+ state->lasttg = 0;
|
||||
+ state->lasttgR =0;
|
||||
+ state->lastsrc = 0;
|
||||
+ state->lastsrcR = 0;
|
||||
+ sprintf (state->dmr_lrrp_gps[0], "%s", "");
|
||||
+ sprintf (state->dmr_lrrp_gps[1], "%s", "");
|
||||
+ state->dmr_color_code = state->color_code;
|
||||
+ }
|
||||
+ }
|
||||
|
||||
/* Reconstitute the burst type */
|
||||
burst = (uint8_t)((SlotType[4] << 3) + (SlotType[5] << 2) + (SlotType[6] << 1) + SlotType[7]);
|
||||
diff --git a/src/dsd_main.c b/src/dsd_main.c
|
||||
index 5531ef3..5598793 100644
|
||||
--- a/src/dsd_main.c
|
||||
+++ b/src/dsd_main.c
|
||||
@@ -257,10 +257,10 @@ if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5
|
||||
//zero out right away if not trunking
|
||||
if (opts->p25_trunk == 0)
|
||||
{
|
||||
- state->lasttg = 0;
|
||||
- state->lastsrc = 0;
|
||||
- state->lasttgR = 0;
|
||||
- state->lastsrcR = 0;
|
||||
+ // state->lasttg = 0; //disabled for dmr voice call persistence #174
|
||||
+ // state->lastsrc = 0; //disabled for dmr voice call persistence #174
|
||||
+ // state->lasttgR = 0; //disabled for dmr voice call persistence #174
|
||||
+ // state->lastsrcR = 0; //disabled for dmr voice call persistence #174
|
||||
|
||||
//zero out vc frequencies?
|
||||
state->p25_vc_freq[0] = 0;
|
||||
@@ -290,10 +290,10 @@ if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5
|
||||
//mainly bugfix for ncurses and per call wavs (edacs) and also signal fade, etc
|
||||
if (opts->p25_trunk == 1 && opts->p25_is_tuned == 1 && time(NULL) - state->last_cc_sync_time > opts->trunk_hangtime)
|
||||
{
|
||||
- state->lasttg = 0;
|
||||
- state->lastsrc = 0;
|
||||
- state->lasttgR = 0;
|
||||
- state->lastsrcR = 0;
|
||||
+ // state->lasttg = 0; //disabled for dmr voice call persistence #174
|
||||
+ // state->lastsrc = 0; //disabled for dmr voice call persistence #174
|
||||
+ // state->lasttgR = 0; //disabled for dmr voice call persistence #174
|
||||
+ // state->lastsrcR = 0; //disabled for dmr voice call persistence #174
|
||||
|
||||
}
|
||||
|
||||
@@ -431,7 +431,7 @@ if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5
|
||||
memset(state->dmr_alias_len, 0, sizeof(state->dmr_alias_len));
|
||||
memset(state->dmr_alias_block_segment, 0, sizeof(state->dmr_alias_block_segment));
|
||||
memset(state->dmr_embedded_gps, 0, sizeof(state->dmr_embedded_gps));
|
||||
- memset(state->dmr_lrrp_gps, 0, sizeof(state->dmr_lrrp_gps));
|
||||
+ // memset(state->dmr_lrrp_gps, 0, sizeof(state->dmr_lrrp_gps));
|
||||
|
||||
// memset(state->active_channel, 0, sizeof(state->active_channel));
|
||||
|
||||
diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c
|
||||
index 4646e77..e9ecab1 100644
|
||||
--- a/src/dsd_ncurses.c
|
||||
+++ b/src/dsd_ncurses.c
|
||||
@@ -3104,7 +3104,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
//LRRP
|
||||
- if(state->dmrburstL != 16) //only during data and no trunking
|
||||
+ // if(state->dmrburstL != 16) //only during data and no trunking //disabled for dmr data call persistence #174
|
||||
{
|
||||
attron(COLOR_PAIR(4));
|
||||
printw ("%s", state->dmr_lrrp_gps[0]);
|
||||
@@ -3298,7 +3298,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
//LRRP
|
||||
- if(state->dmrburstR != 16) //only during data and no trunking
|
||||
+ // if(state->dmrburstR != 16) //only during data and no trunking //disabled for dmr data call persistence #174
|
||||
{
|
||||
attron(COLOR_PAIR(4));
|
||||
printw ("%s", state->dmr_lrrp_gps[1]);
|
||||
@@ -3978,10 +3978,10 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
dmr_reset_blocks (opts, state);
|
||||
|
||||
//zero out additional items
|
||||
- state->lasttg = 0;
|
||||
- state->lasttgR = 0;
|
||||
- state->lastsrc = 0;
|
||||
- state->lastsrcR = 0;
|
||||
+ // state->lasttg = 0; //disabled for dmr voice call persistence #174
|
||||
+ // state->lasttgR = 0; //disabled for dmr voice call persistence #174
|
||||
+ // state->lastsrc = 0; //disabled for dmr voice call persistence #174
|
||||
+ // state->lastsrcR = 0; //disabled for dmr voice call persistence #174
|
||||
state->payload_algid = 0;
|
||||
state->payload_algidR = 0;
|
||||
state->payload_keyid = 0;
|
||||
274
patch/enable_both_slots_p2_trunking.patch
Normal file
274
patch/enable_both_slots_p2_trunking.patch
Normal file
@@ -0,0 +1,274 @@
|
||||
diff --git a/src/p25p2_vpdu.c b/src/p25p2_vpdu.c
|
||||
index 5155bd7..3cf0480 100644
|
||||
--- a/src/p25p2_vpdu.c
|
||||
+++ b/src/p25p2_vpdu.c
|
||||
@@ -155,16 +155,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
- if (channel & 1) //VCH1
|
||||
- {
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
- }
|
||||
- else //VCH0
|
||||
- {
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
- }
|
||||
+ // if (channel & 1) //VCH1
|
||||
+ // {
|
||||
+ // opts->slot1_on = 0;
|
||||
+ // opts->slot2_on = 1;
|
||||
+ // }
|
||||
+ // else //VCH0
|
||||
+ // {
|
||||
+ // opts->slot1_on = 1;
|
||||
+ // opts->slot2_on = 0;
|
||||
+ // }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -255,16 +255,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
- if (channel & 1) //VCH1
|
||||
- {
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
- }
|
||||
- else //VCH0
|
||||
- {
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
- }
|
||||
+ // if (channel & 1) //VCH1
|
||||
+ // {
|
||||
+ // opts->slot1_on = 0;
|
||||
+ // opts->slot2_on = 1;
|
||||
+ // }
|
||||
+ // else //VCH0
|
||||
+ // {
|
||||
+ // opts->slot1_on = 1;
|
||||
+ // opts->slot2_on = 0;
|
||||
+ // }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -386,16 +386,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
- if (tunable_chan & 1) //VCH1
|
||||
- {
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
- }
|
||||
- else //VCH0
|
||||
- {
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
- }
|
||||
+ // if (tunable_chan & 1) //VCH1
|
||||
+ // {
|
||||
+ // opts->slot1_on = 0;
|
||||
+ // opts->slot2_on = 1;
|
||||
+ // }
|
||||
+ // else //VCH0
|
||||
+ // {
|
||||
+ // opts->slot1_on = 1;
|
||||
+ // opts->slot2_on = 0;
|
||||
+ // }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -511,16 +511,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
- if (channel & 1) //VCH1
|
||||
- {
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
- }
|
||||
- else //VCH0
|
||||
- {
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
- }
|
||||
+ // if (channel & 1) //VCH1
|
||||
+ // {
|
||||
+ // opts->slot1_on = 0;
|
||||
+ // opts->slot2_on = 1;
|
||||
+ // }
|
||||
+ // else //VCH0
|
||||
+ // {
|
||||
+ // opts->slot1_on = 1;
|
||||
+ // opts->slot2_on = 0;
|
||||
+ // }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -642,16 +642,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
- if (channel & 1) //VCH1
|
||||
- {
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
- }
|
||||
- else //VCH0
|
||||
- {
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
- }
|
||||
+ // if (channel & 1) //VCH1
|
||||
+ // {
|
||||
+ // opts->slot1_on = 0;
|
||||
+ // opts->slot2_on = 1;
|
||||
+ // }
|
||||
+ // else //VCH0
|
||||
+ // {
|
||||
+ // opts->slot1_on = 1;
|
||||
+ // opts->slot2_on = 0;
|
||||
+ // }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -748,16 +748,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
- if (channel & 1) //VCH1
|
||||
- {
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
- }
|
||||
- else //VCH0
|
||||
- {
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
- }
|
||||
+ // if (channel & 1) //VCH1
|
||||
+ // {
|
||||
+ // opts->slot1_on = 0;
|
||||
+ // opts->slot2_on = 1;
|
||||
+ // }
|
||||
+ // else //VCH0
|
||||
+ // {
|
||||
+ // opts->slot1_on = 1;
|
||||
+ // opts->slot2_on = 0;
|
||||
+ // }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -918,16 +918,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
- if (tunable_chan & 1) //VCH1
|
||||
- {
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
- }
|
||||
- else //VCH0
|
||||
- {
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
- }
|
||||
+ // if (tunable_chan & 1) //VCH1
|
||||
+ // {
|
||||
+ // opts->slot1_on = 0;
|
||||
+ // opts->slot2_on = 1;
|
||||
+ // }
|
||||
+ // else //VCH0
|
||||
+ // {
|
||||
+ // opts->slot1_on = 1;
|
||||
+ // opts->slot2_on = 0;
|
||||
+ // }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1109,16 +1109,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
- if (tunable_chan & 1) //VCH1
|
||||
- {
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
- }
|
||||
- else //VCH0
|
||||
- {
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
- }
|
||||
+ // if (tunable_chan & 1) //VCH1
|
||||
+ // {
|
||||
+ // opts->slot1_on = 0;
|
||||
+ // opts->slot2_on = 1;
|
||||
+ // }
|
||||
+ // else //VCH0
|
||||
+ // {
|
||||
+ // opts->slot1_on = 1;
|
||||
+ // opts->slot2_on = 0;
|
||||
+ // }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1245,16 +1245,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
- if (tunable_chan & 1) //VCH1
|
||||
- {
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
- }
|
||||
- else //VCH0
|
||||
- {
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
- }
|
||||
+ // if (tunable_chan & 1) //VCH1
|
||||
+ // {
|
||||
+ // opts->slot1_on = 0;
|
||||
+ // opts->slot2_on = 1;
|
||||
+ // }
|
||||
+ // else //VCH0
|
||||
+ // {
|
||||
+ // opts->slot1_on = 1;
|
||||
+ // opts->slot2_on = 0;
|
||||
+ // }
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1374,16 +1374,16 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
//shim fix to stutter/lag by only enabling slot on the target/channel we tuned to
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
- if (channelt & 1) //VCH1
|
||||
- {
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
- }
|
||||
- else //VCH0
|
||||
- {
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
- }
|
||||
+ // if (channelt & 1) //VCH1
|
||||
+ // {
|
||||
+ // opts->slot1_on = 0;
|
||||
+ // opts->slot2_on = 1;
|
||||
+ // }
|
||||
+ // else //VCH0
|
||||
+ // {
|
||||
+ // opts->slot1_on = 1;
|
||||
+ // opts->slot2_on = 0;
|
||||
+ // }
|
||||
|
||||
}
|
||||
|
||||
319
patch/enable_pref_slots_p2_trunking.patch
Normal file
319
patch/enable_pref_slots_p2_trunking.patch
Normal file
@@ -0,0 +1,319 @@
|
||||
diff --git a/src/p25p1_mdpu.c b/src/p25p1_mdpu.c
|
||||
index 7d29860..00c1828 100644
|
||||
--- a/src/p25p1_mdpu.c
|
||||
+++ b/src/p25p1_mdpu.c
|
||||
@@ -527,13 +527,13 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
if (channelt & 1) //VCH1
|
||||
{
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
+ //opts->slot1_on = 0;
|
||||
+ opts->slot_preference = 1;
|
||||
}
|
||||
else //VCH0
|
||||
{
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
+ opts->slot_preference = 0;
|
||||
+ //opts->slot2_on = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -644,13 +644,13 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
if (channelt & 1) //VCH1
|
||||
{
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
+ //opts->slot1_on = 0;
|
||||
+ opts->slot_preference = 1;
|
||||
}
|
||||
else //VCH0
|
||||
{
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
+ opts->slot_preference = 0;
|
||||
+ //opts->slot2_on = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -753,13 +753,13 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
if (channel & 1) //VCH1
|
||||
{
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
+ //opts->slot1_on = 0;
|
||||
+ opts->slot_preference = 1;
|
||||
}
|
||||
else //VCH0
|
||||
{
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
+ opts->slot_preference = 0;
|
||||
+ //opts->slot2_on = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -876,13 +876,13 @@ void processMPDU(dsd_opts * opts, dsd_state * state)
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
if (channelt & 1) //VCH1
|
||||
{
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
+ //opts->slot1_on = 0;
|
||||
+ opts->slot_preference = 1;
|
||||
}
|
||||
else //VCH0
|
||||
{
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
+ opts->slot_preference = 0;
|
||||
+ //opts->slot2_on = 0;
|
||||
}
|
||||
|
||||
}
|
||||
diff --git a/src/p25p1_tsbk.c b/src/p25p1_tsbk.c
|
||||
index c801b7f..345335a 100644
|
||||
--- a/src/p25p1_tsbk.c
|
||||
+++ b/src/p25p1_tsbk.c
|
||||
@@ -294,13 +294,13 @@ void processTSBK(dsd_opts * opts, dsd_state * state)
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
if (channel & 1) //VCH1
|
||||
{
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
+ //opts->slot1_on = 0;
|
||||
+ opts->slot_preference = 1;
|
||||
}
|
||||
else //VCH0
|
||||
{
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
+ opts->slot_preference = 0;
|
||||
+ //opts->slot2_on = 0;
|
||||
}
|
||||
|
||||
}
|
||||
diff --git a/src/p25p2_vpdu.c b/src/p25p2_vpdu.c
|
||||
index 468b71a..1b14d71 100644
|
||||
--- a/src/p25p2_vpdu.c
|
||||
+++ b/src/p25p2_vpdu.c
|
||||
@@ -75,8 +75,6 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
|
||||
//Temp Fix: Disable Slot Playback when MAC_SIGNAL present (good CRC),
|
||||
//during trunking, will re-enable when call grant is received, prevent lagging:
|
||||
- if (opts->p25_trunk == 1 && opts->p25_is_tuned == 0) opts->slot1_on = 0;
|
||||
- if (opts->p25_trunk == 1 && opts->p25_is_tuned == 0) opts->slot2_on = 0;
|
||||
|
||||
//TODO: Iron out issues with audio playing in every non SACCH slot when no voice present
|
||||
//without it stuttering during actual voice
|
||||
@@ -156,13 +154,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
if (channel & 1) //VCH1
|
||||
{
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
+ //opts->slot1_on = 0;
|
||||
+ opts->slot_preference = 1;
|
||||
}
|
||||
else //VCH0
|
||||
{
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
+ opts->slot_preference = 0;
|
||||
+ //opts->slot2_on = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -256,13 +254,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
if (channel & 1) //VCH1
|
||||
{
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
+ //opts->slot1_on = 0;
|
||||
+ opts->slot_preference = 1;
|
||||
}
|
||||
else //VCH0
|
||||
{
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
+ opts->slot_preference = 0;
|
||||
+ //opts->slot2_on = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -387,13 +385,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
if (tunable_chan & 1) //VCH1
|
||||
{
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
+ //opts->slot1_on = 0;
|
||||
+ opts->slot_preference = 1;
|
||||
}
|
||||
else //VCH0
|
||||
{
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
+ opts->slot_preference = 0;
|
||||
+ //opts->slot2_on = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -512,13 +510,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
if (channel & 1) //VCH1
|
||||
{
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
+ //opts->slot1_on = 0;
|
||||
+ opts->slot_preference = 1;
|
||||
}
|
||||
else //VCH0
|
||||
{
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
+ opts->slot_preference = 0;
|
||||
+ //opts->slot2_on = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -643,13 +641,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
if (channel & 1) //VCH1
|
||||
{
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
+ //opts->slot1_on = 0;
|
||||
+ opts->slot_preference = 1;
|
||||
}
|
||||
else //VCH0
|
||||
{
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
+ opts->slot_preference = 0;
|
||||
+ //opts->slot2_on = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -749,13 +747,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
if (channel & 1) //VCH1
|
||||
{
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
+ //opts->slot1_on = 0;
|
||||
+ opts->slot_preference = 1;
|
||||
}
|
||||
else //VCH0
|
||||
{
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
+ opts->slot_preference = 0;
|
||||
+ //opts->slot2_on = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -919,13 +917,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
if (tunable_chan & 1) //VCH1
|
||||
{
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
+ //opts->slot1_on = 0;
|
||||
+ opts->slot_preference = 1;
|
||||
}
|
||||
else //VCH0
|
||||
{
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
+ opts->slot_preference = 0;
|
||||
+ //opts->slot2_on = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1110,13 +1108,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
if (tunable_chan & 1) //VCH1
|
||||
{
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
+ //opts->slot1_on = 0;
|
||||
+ opts->slot_preference = 1;
|
||||
}
|
||||
else //VCH0
|
||||
{
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
+ opts->slot_preference = 0;
|
||||
+ //opts->slot2_on = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1246,13 +1244,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
if (tunable_chan & 1) //VCH1
|
||||
{
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
+ //opts->slot1_on = 0;
|
||||
+ opts->slot_preference = 1;
|
||||
}
|
||||
else //VCH0
|
||||
{
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
+ opts->slot_preference = 0;
|
||||
+ //opts->slot2_on = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1375,13 +1373,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
if (channelt & 1) //VCH1
|
||||
{
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
+ //opts->slot1_on = 0;
|
||||
+ opts->slot_preference = 1;
|
||||
}
|
||||
else //VCH0
|
||||
{
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
+ opts->slot_preference = 0;
|
||||
+ //opts->slot2_on = 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1498,13 +1496,13 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
//this will only occur in realtime tuning, not not required .bin or .wav playback
|
||||
if (channelt & 1) //VCH1
|
||||
{
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot2_on = 1;
|
||||
+ //opts->slot1_on = 0;
|
||||
+ opts->slot_preference = 1;
|
||||
}
|
||||
else //VCH0
|
||||
{
|
||||
- opts->slot1_on = 1;
|
||||
- opts->slot2_on = 0;
|
||||
+ opts->slot_preference = 0;
|
||||
+ //opts->slot2_on = 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1516,9 +1514,6 @@ void process_MAC_VPDU(dsd_opts * opts, dsd_state * state, int type, unsigned lon
|
||||
state->samplesPerSymbol = 10;
|
||||
state->symbolCenter = 4;
|
||||
opts->frame_p25p1 = 1; //enable, just in case it isn't already
|
||||
-
|
||||
- //enable voice on slot 1 (just in case they start talking too, but probably won't)
|
||||
- opts->slot1_on = 1;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,461 @@
|
||||
diff --git a/src/dmr_csbk.c b/src/dmr_csbk.c
|
||||
index 129a087..0b7f4e2 100644
|
||||
--- a/src/dmr_csbk.c
|
||||
+++ b/src/dmr_csbk.c
|
||||
@@ -424,6 +424,25 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
//rigctl
|
||||
if (opts->use_rigctl == 1)
|
||||
{
|
||||
+ if (state->currentslot == 0)
|
||||
+ {
|
||||
+ //close any perCall wav files that are open
|
||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f != NULL)
|
||||
+ {
|
||||
+ closeWavOutFileL (opts, state);
|
||||
+ opts->wav_out_f = NULL;
|
||||
+ }
|
||||
+ }
|
||||
+ else if (state->currentslot == 1)
|
||||
+ {
|
||||
+ //close any perCall wav files that are open
|
||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR != NULL)
|
||||
+ {
|
||||
+ closeWavOutFileR (opts, state);
|
||||
+ opts->wav_out_fR = NULL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
//Guess I forgot to add this condition here
|
||||
if (GetCurrentFreq(opts->rigctl_sockfd) != state->p25_cc_freq)
|
||||
dmr_reset_blocks (opts, state); //reset all block gathering since we are tuning away from current frequency
|
||||
@@ -443,6 +462,26 @@ void dmr_cspdu (dsd_opts * opts, dsd_state * state, uint8_t cs_pdu_bits[], uint8
|
||||
else if (opts->audio_in_type == 3)
|
||||
{
|
||||
#ifdef USE_RTLSDR
|
||||
+
|
||||
+ if (state->currentslot == 0)
|
||||
+ {
|
||||
+ //close any perCall wav files that are open
|
||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f != NULL)
|
||||
+ {
|
||||
+ closeWavOutFileL (opts, state);
|
||||
+ opts->wav_out_f = NULL;
|
||||
+ }
|
||||
+ }
|
||||
+ else if (state->currentslot == 1)
|
||||
+ {
|
||||
+ //close any perCall wav files that are open
|
||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR != NULL)
|
||||
+ {
|
||||
+ closeWavOutFileR (opts, state);
|
||||
+ opts->wav_out_fR = NULL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
//Guess I forgot to add this condition here
|
||||
uint32_t tempf = (uint32_t)state->p25_cc_freq;
|
||||
if (opts->rtlsdr_center_freq != tempf)
|
||||
diff --git a/src/dmr_flco.c b/src/dmr_flco.c
|
||||
index 828de02..916eb62 100644
|
||||
--- a/src/dmr_flco.c
|
||||
+++ b/src/dmr_flco.c
|
||||
@@ -10,6 +10,38 @@
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#include "dsd.h"
|
||||
+//I really just need to make ONE consolidated date and time function that works correctly
|
||||
+char * getDateFLC(void) {
|
||||
+ #ifdef AERO_BUILD
|
||||
+ char datename[80];
|
||||
+ #else
|
||||
+ char datename[99];
|
||||
+ #endif
|
||||
+ char * curr2;
|
||||
+ struct tm * to;
|
||||
+ time_t t;
|
||||
+ t = time(NULL);
|
||||
+ to = localtime( & t);
|
||||
+ strftime(datename, sizeof(datename), "%Y%m%d", to);
|
||||
+ curr2 = strtok(datename, " ");
|
||||
+ return curr2;
|
||||
+}
|
||||
+
|
||||
+//fix from YorgosTheodorakis fork -- https://github.com/YorgosTheodorakis/dsd-fme/commit/7884ee555521a887d388152b3b1f11f20433a94b
|
||||
+char * getTimeFLC(void) //get pretty hhmmss timestamp
|
||||
+{
|
||||
+ char * curr = (char *) malloc(9);
|
||||
+ time_t t = time(NULL);
|
||||
+ struct tm * ptm = localtime(& t);
|
||||
+ sprintf(
|
||||
+ curr,
|
||||
+ "%02d%02d%02d",
|
||||
+ ptm->tm_hour,
|
||||
+ ptm->tm_min,
|
||||
+ ptm->tm_sec
|
||||
+ );
|
||||
+ return curr;
|
||||
+}
|
||||
|
||||
//combined flco handler (vlc, tlc, emb), minus the superfluous structs and strings
|
||||
void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t CRCCorrect, uint32_t IrrecoverableErrors, uint8_t type)
|
||||
@@ -304,6 +336,14 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
state->dmr_so = so;
|
||||
state->lasttg = target;
|
||||
state->lastsrc = source;
|
||||
+ char * timestr;
|
||||
+ timestr = getTimeFLC();
|
||||
+ //open wav file here if not already opened
|
||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f == NULL)
|
||||
+ {
|
||||
+ sprintf (opts->wav_out_file, "./%s/%s %s CC %d - TG %d - RD %d", opts->wav_out_dir, getDateFLC(), timestr, state->dmr_color_code, target, source);
|
||||
+ openWavOutFileL (opts, state);
|
||||
+ }
|
||||
}
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
@@ -311,6 +351,14 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
state->dmr_soR = so;
|
||||
state->lasttgR = target;
|
||||
state->lastsrcR = source;
|
||||
+ char * timestr;
|
||||
+ timestr = getTimeFLC();
|
||||
+ //open wav file here if not already opened
|
||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR == NULL)
|
||||
+ {
|
||||
+ sprintf (opts->wav_out_fileR, "./%s/%s %s CC %d - TG %d - RD %d", opts->wav_out_dir, getDateFLC(), timestr, state->dmr_color_code, target, source);
|
||||
+ openWavOutFileR (opts, state);
|
||||
+ }
|
||||
}
|
||||
|
||||
//update cc amd vc sync time for trunking purposes (particularly Con+)
|
||||
@@ -337,6 +385,12 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
//reset gain
|
||||
if (opts->floating_point == 1)
|
||||
state->aout_gain = opts->audio_gain;
|
||||
+ //close any perCall wav files that are open
|
||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f != NULL)
|
||||
+ {
|
||||
+ closeWavOutFileL (opts, state);
|
||||
+ opts->wav_out_f = NULL;
|
||||
+ }
|
||||
}
|
||||
if (state->currentslot == 1)
|
||||
{
|
||||
@@ -350,6 +404,12 @@ void dmr_flco (dsd_opts * opts, dsd_state * state, uint8_t lc_bits[], uint32_t C
|
||||
//reset gain
|
||||
if (opts->floating_point == 1)
|
||||
state->aout_gainR = opts->audio_gain;
|
||||
+ //close any perCall wav files that are open
|
||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR != NULL)
|
||||
+ {
|
||||
+ closeWavOutFileR (opts, state);
|
||||
+ opts->wav_out_fR = NULL;
|
||||
+ }
|
||||
}
|
||||
|
||||
}
|
||||
diff --git a/src/dsd_file.c b/src/dsd_file.c
|
||||
index 8e9094c..e8441ec 100644
|
||||
--- a/src/dsd_file.c
|
||||
+++ b/src/dsd_file.c
|
||||
@@ -366,7 +366,7 @@ void closeMbeOutFile (dsd_opts * opts, dsd_state * state)
|
||||
fclose (opts->mbe_out_f);
|
||||
opts->mbe_out_f = NULL;
|
||||
opts->mbe_out = 0;
|
||||
- fprintf (stderr, "\nClosing MBE out file 1.\n");
|
||||
+ // fprintf (stderr, "\nClosing MBE out file 1.\n");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -385,7 +385,7 @@ void closeMbeOutFileR (dsd_opts * opts, dsd_state * state)
|
||||
fclose (opts->mbe_out_fR);
|
||||
opts->mbe_out_fR = NULL;
|
||||
opts->mbe_outR = 0;
|
||||
- fprintf (stderr, "\nClosing MBE out file 2.\n");
|
||||
+ // fprintf (stderr, "\nClosing MBE out file 2.\n");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -420,7 +420,7 @@ void openMbeOutFile (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
state->tgcount = 0;
|
||||
-
|
||||
+ //TODO: Change the date/time functions here to operate without using colons
|
||||
sprintf (opts->mbe_out_file, "%s %s S1%s", getDateF(), getTimeF(), ext);
|
||||
|
||||
sprintf (opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_file);
|
||||
@@ -467,7 +467,7 @@ void openMbeOutFileR (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
state->tgcount = 0;
|
||||
-
|
||||
+ //TODO: Change the date/time functions here to operate without using colons
|
||||
sprintf (opts->mbe_out_fileR, "%s %s S2%s", getDateF(), getTimeF(), ext);
|
||||
|
||||
sprintf (opts->mbe_out_path, "%s%s", opts->mbe_out_dir, opts->mbe_out_fileR);
|
||||
@@ -557,6 +557,19 @@ void closeWavOutFile (dsd_opts * opts, dsd_state * state)
|
||||
UNUSED(state);
|
||||
|
||||
sf_close(opts->wav_out_f);
|
||||
+ char shell[2065], newfilename[1032];
|
||||
+ int result;
|
||||
+ sprintf (newfilename, "%s.wav", opts->wav_out_file);
|
||||
+#ifdef AERO_BUILD
|
||||
+ result = rename (opts->wav_out_file, newfilename);
|
||||
+ UNUSED(shell);
|
||||
+#else
|
||||
+ sprintf (shell, "mv '%s' '%s'", opts->wav_out_file, newfilename);
|
||||
+ result = system (shell);
|
||||
+#endif
|
||||
+ // fprintf (stderr, "\n Close WAV FileF %s; Result: %d \n", newfilename, result);
|
||||
+ UNUSED(result);
|
||||
+
|
||||
}
|
||||
|
||||
void closeWavOutFileL (dsd_opts * opts, dsd_state * state)
|
||||
@@ -564,6 +577,19 @@ void closeWavOutFileL (dsd_opts * opts, dsd_state * state)
|
||||
UNUSED(state);
|
||||
|
||||
sf_close(opts->wav_out_f);
|
||||
+ char shell[2065], newfilename[1032];
|
||||
+ int result;
|
||||
+ sprintf (newfilename, "%s.wav", opts->wav_out_file);
|
||||
+#ifdef AERO_BUILD
|
||||
+ result = rename (opts->wav_out_file, newfilename);
|
||||
+ UNUSED(shell);
|
||||
+#else
|
||||
+ sprintf (shell, "mv '%s' '%s'", opts->wav_out_file, newfilename);
|
||||
+ result = system (shell);
|
||||
+#endif
|
||||
+ // fprintf (stderr, "\n Close WAV FileL %s; Result: %d \n", newfilename, result);
|
||||
+ UNUSED(result);
|
||||
+
|
||||
}
|
||||
|
||||
void closeWavOutFileR (dsd_opts * opts, dsd_state * state)
|
||||
@@ -571,6 +597,18 @@ void closeWavOutFileR (dsd_opts * opts, dsd_state * state)
|
||||
UNUSED(state);
|
||||
|
||||
sf_close(opts->wav_out_fR);
|
||||
+ char shell[2065], newfilename[1032];
|
||||
+ int result;
|
||||
+ sprintf (newfilename, "%s.wav", opts->wav_out_fileR);
|
||||
+#ifdef AERO_BUILD
|
||||
+ result = rename (opts->wav_out_fileR, newfilename);
|
||||
+ UNUSED(shell);
|
||||
+#else
|
||||
+ sprintf (shell, "mv '%s' '%s'", opts->wav_out_fileR, newfilename);
|
||||
+ result = system (shell);
|
||||
+#endif
|
||||
+ // fprintf (stderr, "\n Close WAV FileR %s; Result: %d \n", newfilename, result);
|
||||
+ UNUSED(result);
|
||||
}
|
||||
|
||||
void closeWavOutFileRaw (dsd_opts * opts, dsd_state * state)
|
||||
diff --git a/src/dsd_main.c b/src/dsd_main.c
|
||||
index 1d2616b..c3a216d 100644
|
||||
--- a/src/dsd_main.c
|
||||
+++ b/src/dsd_main.c
|
||||
@@ -107,6 +107,19 @@ void
|
||||
noCarrier (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
|
||||
+ //close any perCall wav files that are open
|
||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_f != NULL)
|
||||
+ {
|
||||
+ closeWavOutFileL (opts, state);
|
||||
+ opts->wav_out_f = NULL;
|
||||
+ }
|
||||
+ if (opts->dmr_stereo_wav == 1 && opts->wav_out_fR != NULL)
|
||||
+ {
|
||||
+ closeWavOutFileR (opts, state);
|
||||
+ opts->wav_out_fR = NULL;
|
||||
+ }
|
||||
+ //end perCall wav file close
|
||||
+
|
||||
#ifdef AERO_BUILD
|
||||
//TODO: Investigate why getSymbol needs to be run first in this context...truly confused here
|
||||
if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5
|
||||
@@ -1568,9 +1581,9 @@ main (int argc, char **argv)
|
||||
}
|
||||
|
||||
#ifdef AERO_BUILD
|
||||
- fprintf (stderr, "Build Version: AW (20231015) \n");
|
||||
+ fprintf (stderr, "Build Version: AW (20231214) G Build\n");
|
||||
#else
|
||||
- fprintf (stderr, "Build Version: AW %s \n", GIT_TAG);
|
||||
+ fprintf (stderr, "Build Version: AW %s G Build\n", GIT_TAG);
|
||||
#endif
|
||||
fprintf (stderr,"MBElib Version: %s\n", versionstr);
|
||||
|
||||
diff --git a/src/dsd_mbe.c b/src/dsd_mbe.c
|
||||
index 9f609ca..f23209c 100644
|
||||
--- a/src/dsd_mbe.c
|
||||
+++ b/src/dsd_mbe.c
|
||||
@@ -1191,7 +1191,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
if (state->dmr_encL == 0 || opts->dmr_mute_encL == 0)
|
||||
{
|
||||
//write wav to per call on left channel Slot 1
|
||||
- writeSynthesizedVoice (opts, state);
|
||||
+ if (opts->wav_out_f != NULL)
|
||||
+ writeSynthesizedVoice (opts, state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1201,7 +1202,8 @@ processMbeFrame (dsd_opts * opts, dsd_state * state, char imbe_fr[8][23], char a
|
||||
if (state->dmr_encR == 0 || opts->dmr_mute_encR == 0)
|
||||
{
|
||||
//write wav to per call on right channel Slot 2
|
||||
- writeSynthesizedVoiceR (opts, state);
|
||||
+ if (opts->wav_out_fR != NULL)
|
||||
+ writeSynthesizedVoiceR (opts, state);
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c
|
||||
index 4646e77..ab5497e 100644
|
||||
--- a/src/dsd_ncurses.c
|
||||
+++ b/src/dsd_ncurses.c
|
||||
@@ -999,7 +999,7 @@ void ncursesMenu (dsd_opts * opts, dsd_state * state)
|
||||
if (choicec == 12)
|
||||
{
|
||||
//flesh out all closewavs and sprint "" wav filenames
|
||||
- closeWavOutFile (opts, state);
|
||||
+ // closeWavOutFile (opts, state);
|
||||
closeWavOutFileL (opts, state);
|
||||
closeWavOutFileR (opts, state);
|
||||
//closeWavOutFileRaw (opts, state);
|
||||
@@ -2063,6 +2063,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->dmr_stereo_wav == 1 && src != 0 ) //&& tgn != 0, some TG can be 0 on NXDN
|
||||
{
|
||||
//close old first, assign name based on time and radio, open wav file
|
||||
+ if (opts->wav_out_f != NULL)
|
||||
closeWavOutFileL (opts, state);
|
||||
sprintf (opts->wav_out_file, "./%s/%s %s NXDN - RAN %d - TGT %d - SRC %d.wav", opts->wav_out_dir, getDateN(), timestr, rn, tgn, src);
|
||||
openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
||||
@@ -2105,13 +2106,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
call_matrix[9][5] = time(NULL);
|
||||
|
||||
//open wav file if enabled and both rd and tg are not 0
|
||||
- if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0)
|
||||
- {
|
||||
- //close old first, assign name based on time and radio, open wav file
|
||||
- closeWavOutFileL (opts, state);
|
||||
- sprintf (opts->wav_out_file, "./%s/%s %s MS - CC %d - TG %d - RD %d.wav", opts->wav_out_dir, getDateN(), timestr, dcc, tg, rd);
|
||||
- openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
||||
- }
|
||||
+ // if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0)
|
||||
+ // {
|
||||
+ // //close old first, assign name based on time and radio, open wav file
|
||||
+ // if (opts->wav_out_f != NULL)
|
||||
+ // closeWavOutFileL (opts, state);
|
||||
+ // sprintf (opts->wav_out_file, "./%s/%s %s MS - CC %d - TG %d - RD %d.wav", opts->wav_out_dir, getDateN(), timestr, dcc, tg, rd);
|
||||
+ // openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
||||
+ // }
|
||||
|
||||
if (opts->call_alert == 1 && rd != 0 && tg != 0)
|
||||
{
|
||||
@@ -2126,7 +2128,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
|
||||
//DMR BS Slot 1 - matrix 0-4
|
||||
- if ( call_matrix[4][2] != rd && (lls == 11 || lls == 12 || lls == 10 || lls == 13 || lls == 35 || lls == 36) )
|
||||
+ if ( call_matrix[4][2] != rd && (lls == 11 || lls == 12 || lls == 10 || lls == 13 ) ) //|| lls == 35 || lls == 36
|
||||
{
|
||||
|
||||
for (short int k = 0; k < 4; k++)
|
||||
@@ -2147,14 +2149,14 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
call_matrix[4][5] = time(NULL);
|
||||
|
||||
//open wav file if enabled and both rd and tg are not 0
|
||||
- if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0)
|
||||
- {
|
||||
- //close old first, assign name based on time and radio, open wav file
|
||||
- closeWavOutFileL (opts, state);
|
||||
-
|
||||
- sprintf (opts->wav_out_file, "./%s/%s %s CC %d - TG %d - RD %d.wav", opts->wav_out_dir, getDateN(), timestr, dcc, tg, rd);
|
||||
- openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
||||
- }
|
||||
+ // if (opts->dmr_stereo_wav == 1 && rd != 0 && tg != 0)
|
||||
+ // {
|
||||
+ // //close old first, assign name based on time and radio, open wav file
|
||||
+ // if (opts->wav_out_f != NULL)
|
||||
+ // closeWavOutFileL (opts, state);
|
||||
+ // sprintf (opts->wav_out_file, "./%s/%s %s CC %d - TG %d - RD %d", opts->wav_out_dir, getDateN(), timestr, dcc, tg, rd);
|
||||
+ // openWavOutFileL (opts, state); //testing for now, will want to move to per call later
|
||||
+ // }
|
||||
|
||||
if (opts->call_alert == 1 && rd != 0 && tg != 0)
|
||||
{
|
||||
@@ -2190,20 +2192,21 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
call_matrix[9][5] = time(NULL);
|
||||
|
||||
//open wav file if enabled and both rdR and tgR are not 0
|
||||
- if (opts->dmr_stereo_wav == 1 && rdR != 0 && tgR != 0)
|
||||
- {
|
||||
- //close old first, assign name based on time and radio, open wav file
|
||||
- closeWavOutFileR (opts, state);
|
||||
- sprintf (opts->wav_out_fileR, "./%s/%s %s CC %d - TG %d - RD %d.wav", opts->wav_out_dir, getDateN(), timestr, dcc, tgR, rdR);
|
||||
- openWavOutFileR (opts, state); //testing for now, will want to move to per call later
|
||||
- }
|
||||
+ // if (opts->dmr_stereo_wav == 1 && rdR != 0 && tgR != 0)
|
||||
+ // {
|
||||
+ // //close old first, assign name based on time and radio, open wav file
|
||||
+ // if (opts->wav_out_fR != NULL)
|
||||
+ // closeWavOutFileR (opts, state);
|
||||
+ // sprintf (opts->wav_out_fileR, "./%s/%s %s CC %d - TG %d - RD %d", opts->wav_out_dir, getDateN(), timestr, dcc, tgR, rdR);
|
||||
+ // openWavOutFileR (opts, state); //testing for now, will want to move to per call later
|
||||
+ // }
|
||||
|
||||
- if (opts->call_alert == 1 && rdR != 0 && tgR != 0)
|
||||
- {
|
||||
- //fprintf (stderr, "BEEP 1 BS RIGHT\n");
|
||||
- beeper (opts, state, 1);
|
||||
- state->dmr_end_alert[1] = 0; //new voice frame, okay to beep at the end of it
|
||||
- }
|
||||
+ // if (opts->call_alert == 1 && rdR != 0 && tgR != 0)
|
||||
+ // {
|
||||
+ // //fprintf (stderr, "BEEP 1 BS RIGHT\n");
|
||||
+ // beeper (opts, state, 1);
|
||||
+ // state->dmr_end_alert[1] = 0; //new voice frame, okay to beep at the end of it
|
||||
+ // }
|
||||
|
||||
memset(state->dmr_alias_block_segment[1], 0, sizeof(state->dmr_alias_block_segment[1]));
|
||||
sprintf (state->dmr_embedded_gps[1], "%s", "");
|
||||
@@ -2275,7 +2278,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
if (opts->ncurses_compact == 1)
|
||||
{
|
||||
printw ("------------------------------------------------------------------------------\n");
|
||||
- printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "AW (20231015)");
|
||||
+ printw ("| Digital Speech Decoder: Florida Man Edition - Aero %s \n", "AW (20231214)");
|
||||
printw ("------------------------------------------------------------------------------\n");
|
||||
}
|
||||
#elif LIMAZULUTWEAKS
|
||||
@@ -2313,13 +2316,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
if (i == 4 && opts->frame_m17 == 1) printw (" CODEC2");
|
||||
#endif
|
||||
#ifdef AERO_BUILD
|
||||
- if (i == 5) printw (" %s ", "Aero Build");
|
||||
- if (i == 6) printw (" AW (20231015) \n");
|
||||
+ if (i == 5) printw (" %s ", "G Build");
|
||||
+ if (i == 6) printw (" AW (20231214) \n");
|
||||
#elif ZDEV_BUILD
|
||||
- if (i == 5) printw (" %s ", "AW ");
|
||||
+ if (i == 5) printw (" %s ", "AW G Build");
|
||||
if (i == 6) printw (" %s \n", GIT_TAG);
|
||||
#else
|
||||
- if (i == 5) printw (" %s ", "AW ");
|
||||
+ if (i == 5) printw (" %s ", "AW G Build");
|
||||
if (i == 6) printw (" %s \n", GIT_TAG);
|
||||
#endif
|
||||
else printw ("\n");
|
||||
@@ -3913,7 +3916,7 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
if (c == 112) //'p' key - stop all per call wav files
|
||||
{
|
||||
//hope this one doesn't cause random crashing or garbage writing
|
||||
- closeWavOutFile (opts, state);
|
||||
+ // closeWavOutFile (opts, state);
|
||||
closeWavOutFileL (opts, state);
|
||||
closeWavOutFileR (opts, state);
|
||||
sprintf (opts->wav_out_file, "%s", "");
|
||||
769
patch/p25p2_superframe_18V_enc_check.patch
Normal file
769
patch/p25p2_superframe_18V_enc_check.patch
Normal file
@@ -0,0 +1,769 @@
|
||||
diff --git a/include/dsd.h b/include/dsd.h
|
||||
index 0b47dee..f459528 100644
|
||||
--- a/include/dsd.h
|
||||
+++ b/include/dsd.h
|
||||
@@ -437,8 +437,8 @@ typedef struct
|
||||
//new stereo short sample storage
|
||||
short s_l[160]; //single sample left
|
||||
short s_r[160]; //single sample right
|
||||
- short s_l4[4][160]; //quad sample for up to a P25p2 4V
|
||||
- short s_r4[4][160]; //quad sample for up to a P25p2 4V
|
||||
+ short s_l4[36][160]; //quad sample for up to a P25p2 4V
|
||||
+ short s_r4[36][160]; //quad sample for up to a P25p2 4V
|
||||
//new stereo short sample storage tapped from 48_k internal upsampling
|
||||
short s_lu[160*6]; //single sample left
|
||||
short s_ru[160*6]; //single sample right
|
||||
@@ -654,6 +654,7 @@ typedef struct
|
||||
int p2_vch_chan_num; //vch channel number (0 or 1, not the 0-11 TS)
|
||||
int ess_b[2][96]; //external storage for ESS_B fragments
|
||||
int fourv_counter[2]; //external reference counter for ESS_B fragment collection
|
||||
+ int voice_counter[2]; //external reference counter for 18V x 2 P25p2 Superframe
|
||||
int p2_is_lcch; //flag to tell us when a frame is lcch and not sacch
|
||||
|
||||
//iden freq storage for frequency calculations
|
||||
@@ -926,6 +927,7 @@ void agf (dsd_opts * opts, dsd_state * state, float samp[160], int slot); //floa
|
||||
void playSynthesizedVoiceSS (dsd_opts * opts, dsd_state * state); //short stereo mix
|
||||
void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state); //short stereo mix 3v2 DMR
|
||||
void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state); //short stereo mix 4v2 P25p2
|
||||
+void playSynthesizedVoiceSS18 (dsd_opts * opts, dsd_state * state); //short stereo mix 18V Superframe
|
||||
void upsampleS (short invalue, short prev, short outbuf[6]); //upsample 8k to 48k short
|
||||
//
|
||||
void openAudioOutDevice (dsd_opts * opts, int speed);
|
||||
diff --git a/src/dsd_audio2.c b/src/dsd_audio2.c
|
||||
index a836afc..5eaf3c4 100644
|
||||
--- a/src/dsd_audio2.c
|
||||
+++ b/src/dsd_audio2.c
|
||||
@@ -906,8 +906,31 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
||||
//CHEAT: Using the slot on/off, use that to set encL or encR back on
|
||||
//as a simple way to turn off voice synthesis in a particular slot
|
||||
//its not really 'disabled', we just aren't playing it
|
||||
- if (opts->slot1_on == 0) encL = 1;
|
||||
- if (opts->slot2_on == 0) encR = 1;
|
||||
+ // if (opts->slot1_on == 0) encL = 1;
|
||||
+ // if (opts->slot2_on == 0) encR = 1;
|
||||
+
|
||||
+ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only
|
||||
+ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default
|
||||
+ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well
|
||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on
|
||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
||||
+ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
||||
+ else if (opts->slot_preference == 0 && state->dmrburstL == 16 && encL == 0) //slot 1 is preferred, and voice in slot 1
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
||||
+ else if (opts->slot_preference == 1 && state->dmrburstR == 16 && encR == 0) //slot 2 is preferred, and voice in slot 2
|
||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
||||
+ else if (state->dmrburstL == 16 && state->dmrburstR != 16 && encL == 0) //voice in left, no voice in right
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
||||
+ else if (state->dmrburstR == 16 && state->dmrburstL != 16 && encR == 0) //voice in right, no voice in left
|
||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
||||
+ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels)
|
||||
+
|
||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
||||
+ {
|
||||
+ encL = 1;
|
||||
+ encR = 1;
|
||||
+ }
|
||||
|
||||
//WIP: Mute if on B list (or not W list)
|
||||
char modeL[8];
|
||||
@@ -944,12 +967,37 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
||||
if (strcmp(modeL, "B") == 0) encL = 1;
|
||||
if (strcmp(modeR, "B") == 0) encR = 1;
|
||||
|
||||
+ //check to see if we need to enable slot and toggle slot preference here
|
||||
+ //this method will always favor slot 2 (this is a patch anyways, so....meh)
|
||||
+ if (strcmp(modeL, "A") == 0)
|
||||
+ {
|
||||
+ opts->slot1_on = 1;
|
||||
+ opts->slot_preference = 0;
|
||||
+ }
|
||||
+ if (strcmp(modeR, "A") == 0)
|
||||
+ {
|
||||
+ opts->slot2_on = 1;
|
||||
+ opts->slot_preference = 1;
|
||||
+ }
|
||||
+
|
||||
//if TG Hold in place, mute anything but that TG #132
|
||||
- if (state->tg_hold != 0 && state->tg_hold != TGL) encL = 1;
|
||||
- if (state->tg_hold != 0 && state->tg_hold != TGR) encR = 1;
|
||||
- //likewise, override and unmute if TG hold matches TG
|
||||
- if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0;
|
||||
- if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0;
|
||||
+ if (state->tg_hold != 0 && state->tg_hold != TGL)
|
||||
+ encL = 1;
|
||||
+ if (state->tg_hold != 0 && state->tg_hold != TGR)
|
||||
+ encR = 1;
|
||||
+ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference)
|
||||
+ if (state->tg_hold != 0 && state->tg_hold == TGL)
|
||||
+ {
|
||||
+ encL = 0;
|
||||
+ opts->slot1_on = 1;
|
||||
+ opts->slot_preference = 0;
|
||||
+ }
|
||||
+ if (state->tg_hold != 0 && state->tg_hold == TGR)
|
||||
+ {
|
||||
+ encR = 0;
|
||||
+ opts->slot2_on = 1;
|
||||
+ opts->slot_preference = 1;
|
||||
+ }
|
||||
|
||||
//interleave left and right channels from the short storage area
|
||||
for (i = 0; i < 160; i++)
|
||||
@@ -1092,8 +1140,31 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
||||
//CHEAT: Using the slot on/off, use that to set encL or encR back on
|
||||
//as a simple way to turn off voice synthesis in a particular slot
|
||||
//its not really 'disabled', we just aren't playing it
|
||||
- if (opts->slot1_on == 0) encL = 1;
|
||||
- if (opts->slot2_on == 0) encR = 1;
|
||||
+ // if (opts->slot1_on == 0) encL = 1;
|
||||
+ // if (opts->slot2_on == 0) encR = 1;
|
||||
+
|
||||
+ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only
|
||||
+ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default
|
||||
+ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well
|
||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on
|
||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
||||
+ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
||||
+ else if (opts->slot_preference == 0 && state->dmrburstL == 21 && encL == 0) //slot 1 is preferred, and voice in slot 1
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
||||
+ else if (opts->slot_preference == 1 && state->dmrburstR == 21 && encR == 0) //slot 2 is preferred, and voice in slot 2
|
||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
||||
+ else if (state->dmrburstL == 21 && state->dmrburstR != 21 && encL == 0) //voice in left, no voice in right
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
||||
+ else if (state->dmrburstR == 21 && state->dmrburstL != 21 && encR == 0) //voice in right, no voice in left
|
||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
||||
+ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels)
|
||||
+
|
||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
||||
+ {
|
||||
+ encL = 1;
|
||||
+ encR = 1;
|
||||
+ }
|
||||
|
||||
//WIP: Mute if on B list (or not W list)
|
||||
char modeL[8];
|
||||
@@ -1130,12 +1201,37 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
||||
if (strcmp(modeL, "B") == 0) encL = 1;
|
||||
if (strcmp(modeR, "B") == 0) encR = 1;
|
||||
|
||||
+ //check to see if we need to enable slot and toggle slot preference here
|
||||
+ //this method will always favor slot 2 (this is a patch anyways, so....meh)
|
||||
+ if (strcmp(modeL, "A") == 0)
|
||||
+ {
|
||||
+ opts->slot1_on = 1;
|
||||
+ opts->slot_preference = 0;
|
||||
+ }
|
||||
+ if (strcmp(modeR, "A") == 0)
|
||||
+ {
|
||||
+ opts->slot2_on = 1;
|
||||
+ opts->slot_preference = 1;
|
||||
+ }
|
||||
+
|
||||
//if TG Hold in place, mute anything but that TG #132
|
||||
- if (state->tg_hold != 0 && state->tg_hold != TGL) encL = 1;
|
||||
- if (state->tg_hold != 0 && state->tg_hold != TGR) encR = 1;
|
||||
- //likewise, override and unmute if TG hold matches TG
|
||||
- if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0;
|
||||
- if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0;
|
||||
+ if (state->tg_hold != 0 && state->tg_hold != TGL)
|
||||
+ encL = 1;
|
||||
+ if (state->tg_hold != 0 && state->tg_hold != TGR)
|
||||
+ encR = 1;
|
||||
+ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference)
|
||||
+ if (state->tg_hold != 0 && state->tg_hold == TGL)
|
||||
+ {
|
||||
+ encL = 0;
|
||||
+ opts->slot1_on = 1;
|
||||
+ opts->slot_preference = 0;
|
||||
+ }
|
||||
+ if (state->tg_hold != 0 && state->tg_hold == TGR)
|
||||
+ {
|
||||
+ encR = 0;
|
||||
+ opts->slot2_on = 1;
|
||||
+ opts->slot_preference = 1;
|
||||
+ }
|
||||
|
||||
//interleave left and right channels from the short storage area
|
||||
for (i = 0; i < 160; i++)
|
||||
@@ -1238,6 +1334,226 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
|
||||
+//short stereo mix 18v superframe
|
||||
+void playSynthesizedVoiceSS18 (dsd_opts * opts, dsd_state * state)
|
||||
+{
|
||||
+
|
||||
+ //NOTE: This will run once every superframe during a sacch field
|
||||
+ //exact implementation to be determined
|
||||
+
|
||||
+ int i, j;
|
||||
+ uint8_t encL, encR;
|
||||
+
|
||||
+ short stereo_sf[18][320]; //8k 2-channel stereo interleave mix for full superframe
|
||||
+ // memset (stereo_sf, 1, 18*sizeof(short)); //I don't think 18*sizeof(short) was large enough, should probably be 18*320*sizeof(short)
|
||||
+ memset (stereo_sf, 1, sizeof(stereo_sf));
|
||||
+
|
||||
+ short empty[320];
|
||||
+ memset (empty, 1, sizeof(empty));
|
||||
+
|
||||
+ //p25p2 enc checkdown for whether or not to fill the stereo sample or not for playback or writing
|
||||
+ encL = encR = 1;
|
||||
+ if (state->payload_algid == 0 || state->payload_algid == 0x80)
|
||||
+ encL = 0;
|
||||
+ if (state->payload_algidR == 0 || state->payload_algidR == 0x80)
|
||||
+ encR = 0;
|
||||
+
|
||||
+ //checkdown to see if we can lift the 'mute' if a key is available
|
||||
+ if (encL)
|
||||
+ {
|
||||
+ if (state->payload_algid == 0xAA)
|
||||
+ {
|
||||
+ if (state->R != 0)
|
||||
+ {
|
||||
+ encL = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (encR)
|
||||
+ {
|
||||
+ if (state->payload_algidR == 0xAA)
|
||||
+ {
|
||||
+ if (state->RR != 0)
|
||||
+ {
|
||||
+ encR = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ //TODO: add option to bypass enc with a toggle as well
|
||||
+
|
||||
+ //CHEAT: Using the slot on/off, use that to set encL or encR back on
|
||||
+ //as a simple way to turn off voice synthesis in a particular slot
|
||||
+ //its not really 'disabled', we just aren't playing it
|
||||
+ // if (opts->slot1_on == 0) encL = 1;
|
||||
+ // if (opts->slot2_on == 0) encR = 1;
|
||||
+
|
||||
+ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only
|
||||
+ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default
|
||||
+ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well
|
||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on
|
||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
||||
+ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
||||
+ else if (opts->slot_preference == 0 && state->dmrburstL == 21 && encL == 0) //slot 1 is preferred, and voice in slot 1
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
||||
+ else if (opts->slot_preference == 1 && state->dmrburstR == 21 && encR == 0) //slot 2 is preferred, and voice in slot 2
|
||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
||||
+ else if (state->dmrburstL == 21 && state->dmrburstR != 21 && encL == 0) //voice in left, no voice in right
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
||||
+ else if (state->dmrburstR == 21 && state->dmrburstL != 21 && encR == 0) //voice in right, no voice in left
|
||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
||||
+ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels)
|
||||
+
|
||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
||||
+ {
|
||||
+ encL = 1;
|
||||
+ encR = 1;
|
||||
+ }
|
||||
+
|
||||
+ //WIP: Mute if on B list (or not W list)
|
||||
+ char modeL[8];
|
||||
+ sprintf (modeL, "%s", "");
|
||||
+ char modeR[8];
|
||||
+ sprintf (modeR, "%s", "");
|
||||
+
|
||||
+ int TGL = state->lasttg;
|
||||
+ int TGR = state->lasttgR;
|
||||
+
|
||||
+ //if we are using allow/whitelist mode, then write 'B' to mode for block
|
||||
+ //comparison below will look for an 'A' to write to mode if it is allowed
|
||||
+ if (opts->trunk_use_allow_list == 1)
|
||||
+ {
|
||||
+ sprintf (modeL, "%s", "B");
|
||||
+ sprintf (modeR, "%s", "B");
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < state->group_tally; i++)
|
||||
+ {
|
||||
+ if (state->group_array[i].groupNumber == TGL)
|
||||
+ {
|
||||
+ strcpy (modeL, state->group_array[i].groupMode);
|
||||
+ // break; //need to keep going to check other potential slot group
|
||||
+ }
|
||||
+ if (state->group_array[i].groupNumber == TGR)
|
||||
+ {
|
||||
+ strcpy (modeR, state->group_array[i].groupMode);
|
||||
+ // break; //need to keep going to check other potential slot group
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ //flag either left or right as 'enc' to mute if B
|
||||
+ if (strcmp(modeL, "B") == 0) encL = 1;
|
||||
+ if (strcmp(modeR, "B") == 0) encR = 1;
|
||||
+
|
||||
+ //check to see if we need to enable slot and toggle slot preference here
|
||||
+ //this method will always favor slot 2 (this is a patch anyways, so....meh)
|
||||
+ if (strcmp(modeL, "A") == 0)
|
||||
+ {
|
||||
+ opts->slot1_on = 1;
|
||||
+ opts->slot_preference = 0;
|
||||
+ }
|
||||
+ if (strcmp(modeR, "A") == 0)
|
||||
+ {
|
||||
+ opts->slot2_on = 1;
|
||||
+ opts->slot_preference = 1;
|
||||
+ }
|
||||
+
|
||||
+ //if TG Hold in place, mute anything but that TG #132
|
||||
+ if (state->tg_hold != 0 && state->tg_hold != TGL)
|
||||
+ encL = 1;
|
||||
+ if (state->tg_hold != 0 && state->tg_hold != TGR)
|
||||
+ encR = 1;
|
||||
+ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference)
|
||||
+ if (state->tg_hold != 0 && state->tg_hold == TGL)
|
||||
+ {
|
||||
+ encL = 0;
|
||||
+ opts->slot1_on = 1;
|
||||
+ opts->slot_preference = 0;
|
||||
+ }
|
||||
+ if (state->tg_hold != 0 && state->tg_hold == TGR)
|
||||
+ {
|
||||
+ encR = 0;
|
||||
+ opts->slot2_on = 1;
|
||||
+ opts->slot_preference = 1;
|
||||
+ }
|
||||
+
|
||||
+ //at this point, if both channels are still flagged as enc, then we can skip all playback/writing functions
|
||||
+ if (encL && encR)
|
||||
+ goto SS18_END;
|
||||
+
|
||||
+ //interleave left and right channels from the short storage area
|
||||
+ for (j = 0; j < 18; j++)
|
||||
+ {
|
||||
+ for (i = 0; i < 160; i++)
|
||||
+ {
|
||||
+ if (!encL)
|
||||
+ stereo_sf[j][i*2+0] = state->s_l4[j][i];
|
||||
+ if (!encR)
|
||||
+ stereo_sf[j][i*2+1] = state->s_r4[j][i];
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (opts->audio_out_type == 0) //Pulse Audio
|
||||
+ {
|
||||
+ for (j = 0; j < 18; j++)
|
||||
+ {
|
||||
+ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely
|
||||
+ pa_simple_write(opts->pulse_digi_dev_out, stereo_sf[j], 320*2, NULL);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (opts->audio_out_type == 8) //UDP Audio
|
||||
+ {
|
||||
+ for (j = 0; j < 18; j++)
|
||||
+ {
|
||||
+ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely
|
||||
+ udp_socket_blaster (opts, state, 320*2, stereo_sf[j]);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ if (opts->audio_out_type == 1 || opts->audio_out_type == 2) //STDOUT or OSS 8k/2channel
|
||||
+ {
|
||||
+ for (j = 0; j < 18; j++)
|
||||
+ {
|
||||
+ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely
|
||||
+ write (opts->audio_out_fd, stereo_sf[j], 320*2);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ SS18_END:
|
||||
+
|
||||
+ //run cleanup since we pulled stuff from processAudio
|
||||
+ state->audio_out_idx = 0;
|
||||
+ state->audio_out_idxR = 0;
|
||||
+
|
||||
+ //set float temp buffer to baseline
|
||||
+ memset (state->s_l4, 1, sizeof(state->s_l4));
|
||||
+ memset (state->s_r4, 1, sizeof(state->s_r4));
|
||||
+
|
||||
+ if (state->audio_out_idx2 >= 800000)
|
||||
+ {
|
||||
+ state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
||||
+ state->audio_out_buf_p = state->audio_out_buf + 100;
|
||||
+ memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
|
||||
+ memset (state->audio_out_buf, 0, 100 * sizeof (short));
|
||||
+ state->audio_out_idx2 = 0;
|
||||
+ }
|
||||
+
|
||||
+ if (state->audio_out_idx2R >= 800000)
|
||||
+ {
|
||||
+ state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
|
||||
+ state->audio_out_buf_pR = state->audio_out_bufR + 100;
|
||||
+ memset (state->audio_out_float_bufR, 0, 100 * sizeof (float));
|
||||
+ memset (state->audio_out_bufR, 0, 100 * sizeof (short));
|
||||
+ state->audio_out_idx2R = 0;
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
+
|
||||
//largely borrowed from Boatbod OP25 (simplified single tone ID version)
|
||||
void soft_tonef (float samp[160], int n, int ID, int AD)
|
||||
{
|
||||
diff --git a/src/dsd_main.c b/src/dsd_main.c
|
||||
index 1d2616b..02590a6 100644
|
||||
--- a/src/dsd_main.c
|
||||
+++ b/src/dsd_main.c
|
||||
@@ -382,6 +382,8 @@ if(opts->frame_m17 == 1) //&& opts->audio_in_type == 5
|
||||
}
|
||||
state->fourv_counter[0] = 0;
|
||||
state->fourv_counter[1] = 0;
|
||||
+ state->voice_counter[0] = 0;
|
||||
+ state->voice_counter[1] = 0;
|
||||
|
||||
//values displayed in ncurses terminal
|
||||
// state->p25_vc_freq[0] = 0;
|
||||
@@ -745,7 +747,7 @@ initOpts (dsd_opts * opts)
|
||||
//slot preference is used during OSS audio playback to
|
||||
//prefer one tdma voice slot over another when both are playing back
|
||||
//this is a fix to OSS 48k/1 output
|
||||
- opts->slot_preference = 0; //default prefer slot 1 -- state->currentslot = 0;
|
||||
+ opts->slot_preference = 2; //default prefer slot 1 -- state->currentslot = 0;
|
||||
|
||||
//hardset slots to synthesize
|
||||
opts->slot1_on = 1;
|
||||
@@ -941,6 +943,8 @@ initState (dsd_state * state)
|
||||
}
|
||||
state->fourv_counter[0] = 0;
|
||||
state->fourv_counter[1] = 0;
|
||||
+ state->voice_counter[0] = 0;
|
||||
+ state->voice_counter[1] = 0;
|
||||
|
||||
state->K = 0;
|
||||
state->R = 0;
|
||||
diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c
|
||||
index 4646e77..fc3f28b 100644
|
||||
--- a/src/dsd_ncurses.c
|
||||
+++ b/src/dsd_ncurses.c
|
||||
@@ -2568,11 +2568,11 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
printw ("| Voice Error: [%i][%i] Slot 1 (1)", state->errs, state->errs2);
|
||||
if (opts->slot1_on == 0) printw (" OFF");
|
||||
- if (opts->slot1_on == 1) printw (" ON");
|
||||
+ if (opts->slot1_on == 1) printw (" ON"); if (opts->slot_preference == 0) printw (" *Preferred");
|
||||
printw ("\n");
|
||||
printw ("| Voice Error: [%i][%i] Slot 2 (2)", state->errsR, state->errs2R);
|
||||
if (opts->slot2_on == 0) printw (" OFF");
|
||||
- if (opts->slot2_on == 1) printw (" ON");
|
||||
+ if (opts->slot2_on == 1) printw (" ON"); if (opts->slot_preference == 1) printw (" *Preferred");
|
||||
printw ("\n");
|
||||
}
|
||||
printw ("------------------------------------------------------------------------------\n");
|
||||
@@ -3654,8 +3654,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
//switching, but want to control each seperately plz
|
||||
if (opts->slot1_on == 1)
|
||||
{
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot_preference = 1; //slot 2
|
||||
+ opts->slot1_on = 0; if (opts->slot_preference == 0) opts->slot_preference = 2;
|
||||
+ // opts->slot_preference = 1; //slot 2
|
||||
//clear any previously buffered audio
|
||||
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
||||
state->audio_out_buf_p = state->audio_out_buf + 100;
|
||||
@@ -3680,8 +3680,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
//switching, but want to control each seperately plz
|
||||
if (opts->slot2_on == 1)
|
||||
{
|
||||
- opts->slot2_on = 0;
|
||||
- opts->slot_preference = 0; //slot 1
|
||||
+ opts->slot2_on = 0; if (opts->slot_preference == 1) opts->slot_preference = 2;
|
||||
+ // opts->slot_preference = 0; //slot 1
|
||||
//clear any previously buffered audio
|
||||
state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
|
||||
state->audio_out_buf_pR = state->audio_out_bufR + 100;
|
||||
@@ -3701,6 +3701,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
}
|
||||
|
||||
+ if (c == 51) //'3' key, cycle slot preferences
|
||||
+ {
|
||||
+ if (opts->slot_preference < 2)
|
||||
+ opts->slot_preference++;
|
||||
+ else opts->slot_preference = 0;
|
||||
+ }
|
||||
+
|
||||
if (c == 43) //+ key, increment audio_gain
|
||||
{
|
||||
|
||||
diff --git a/src/p25p2_frame.c b/src/p25p2_frame.c
|
||||
index c391eba..99a4840 100644
|
||||
--- a/src/p25p2_frame.c
|
||||
+++ b/src/p25p2_frame.c
|
||||
@@ -490,18 +490,27 @@ void process_4V (dsd_opts * opts, dsd_state * state)
|
||||
// else state->dmrburstR = 21;
|
||||
// }
|
||||
// #endif
|
||||
+
|
||||
+ //unsure of the best location for these counter resets
|
||||
+ if (state->voice_counter[0] >= 18)
|
||||
+ state->voice_counter[0] = 0;
|
||||
+
|
||||
+ if (state->voice_counter[1] >= 18)
|
||||
+ state->voice_counter[1] = 0;
|
||||
|
||||
processMbeFrame (opts, state, NULL, ambe_fr1, NULL);
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
||||
- memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
||||
+ // memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
||||
+ memcpy(state->s_l4[(state->voice_counter[0]++)%18], state->s_l, sizeof(state->s_l));
|
||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(state->f_r4[0], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
||||
- memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r));
|
||||
+ // memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r));
|
||||
+ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r));
|
||||
memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru));
|
||||
}
|
||||
|
||||
@@ -509,13 +518,15 @@ void process_4V (dsd_opts * opts, dsd_state * state)
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
||||
- memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
||||
+ // memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
||||
+ memcpy(state->s_l4[(state->voice_counter[0]++)%18], state->s_l, sizeof(state->s_l));
|
||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(state->f_r4[1], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
||||
- memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r));
|
||||
+ // memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r));
|
||||
+ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r));
|
||||
memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru));
|
||||
}
|
||||
|
||||
@@ -523,13 +534,15 @@ void process_4V (dsd_opts * opts, dsd_state * state)
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
||||
- memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
||||
+ // memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
||||
+ memcpy(state->s_l4[(state->voice_counter[0]++)%18], state->s_l, sizeof(state->s_l));
|
||||
memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(state->f_r4[2], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
||||
- memcpy(state->s_r4[2], state->s_r, sizeof(state->s_r));
|
||||
+ // memcpy(state->s_r4[2], state->s_r, sizeof(state->s_r));
|
||||
+ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r));
|
||||
memcpy(state->s_r4u[2], state->s_ru, sizeof(state->s_ru));
|
||||
}
|
||||
|
||||
@@ -537,13 +550,15 @@ void process_4V (dsd_opts * opts, dsd_state * state)
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
memcpy(state->f_l4[3], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
||||
- memcpy(state->s_l4[3], state->s_l, sizeof(state->s_l));
|
||||
+ // memcpy(state->s_l4[3], state->s_l, sizeof(state->s_l));
|
||||
+ memcpy(state->s_l4[(state->voice_counter[0]++)%18], state->s_l, sizeof(state->s_l));
|
||||
memcpy(state->s_l4u[3], state->s_lu, sizeof(state->s_lu));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(state->f_r4[3], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
||||
- memcpy(state->s_r4[3], state->s_r, sizeof(state->s_r));
|
||||
+ // memcpy(state->s_r4[3], state->s_r, sizeof(state->s_r));
|
||||
+ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r));
|
||||
memcpy(state->s_r4u[3], state->s_ru, sizeof(state->s_ru));
|
||||
}
|
||||
|
||||
@@ -709,17 +724,26 @@ void process_2V (dsd_opts * opts, dsd_state * state)
|
||||
// }
|
||||
// #endif
|
||||
|
||||
+ //unsure of the best location for these counter resets
|
||||
+ if (state->voice_counter[0] >= 18)
|
||||
+ state->voice_counter[0] = 0;
|
||||
+
|
||||
+ if (state->voice_counter[1] >= 18)
|
||||
+ state->voice_counter[1] = 0;
|
||||
+
|
||||
processMbeFrame (opts, state, NULL, ambe_fr1, NULL);
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
||||
- memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
||||
+ // memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
||||
+ memcpy(state->s_l4[(state->voice_counter[0]++)%18], state->s_l, sizeof(state->s_l));
|
||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(state->f_r4[0], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
||||
- memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r));
|
||||
+ // memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r));
|
||||
+ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r));
|
||||
memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru));
|
||||
}
|
||||
|
||||
@@ -727,17 +751,19 @@ void process_2V (dsd_opts * opts, dsd_state * state)
|
||||
if(state->currentslot == 0)
|
||||
{
|
||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
||||
- memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
||||
+ // memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
||||
+ memcpy(state->s_l4[(state->voice_counter[0]++)%18], state->s_l, sizeof(state->s_l));
|
||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(state->f_r4[1], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
||||
- memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r));
|
||||
+ // memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r));
|
||||
+ memcpy(state->s_r4[(state->voice_counter[1]++)%18], state->s_r, sizeof(state->s_r));
|
||||
memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru));
|
||||
}
|
||||
-
|
||||
+ // if (state->currentslot == 0) state->voice_counter[0] = 0; if (state->currentslot == 1) state->voice_counter[1] = 0;
|
||||
process_ESS(opts, state);
|
||||
|
||||
//reset drop bytes after a 2V
|
||||
@@ -930,6 +956,8 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
||||
state->p2_is_lcch = 0;
|
||||
state->fourv_counter[0] = 0;
|
||||
state->fourv_counter[1] = 0;
|
||||
+ state->voice_counter[0] = 0;
|
||||
+ state->voice_counter[1] = 0;
|
||||
|
||||
goto END;
|
||||
}
|
||||
@@ -949,8 +977,32 @@ void process_P2_DUID (dsd_opts * opts, dsd_state * state)
|
||||
if (sacch == 0 && ts_counter & 1 && opts->floating_point == 1 && opts->pulse_digi_rate_out == 8000)
|
||||
playSynthesizedVoiceFS4 (opts, state);
|
||||
|
||||
- if (sacch == 0 && ts_counter & 1 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000)
|
||||
- playSynthesizedVoiceSS4 (opts, state);
|
||||
+ // if (sacch == 0 && ts_counter & 1 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000)
|
||||
+ // playSynthesizedVoiceSS4 (opts, state);
|
||||
+
|
||||
+ // fprintf (stderr, " VCH0: %d;", state->voice_counter[0]); //debug
|
||||
+ // fprintf (stderr, " VCH1: %d;", state->voice_counter[1]); //debug
|
||||
+
|
||||
+ //this works, but may still have an element of 'dual voice stutter' which was my initial complaint, but shouldn't 'lag' during trunking operations (hopefully)
|
||||
+ if ( (state->voice_counter[0] >= 18 || state->voice_counter[1] >= 18 ) && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) //&& ts_counter & 1
|
||||
+ {
|
||||
+ playSynthesizedVoiceSS18 (opts, state);
|
||||
+ state->voice_counter[0] = 0; //reset
|
||||
+ state->voice_counter[1] = 0; //reset
|
||||
+ }
|
||||
+
|
||||
+ //these two will work, but NOT at the same time on dual voice
|
||||
+ // if (state->voice_counter[0] >= 18 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) //&& ts_counter & 1
|
||||
+ // {
|
||||
+ // playSynthesizedVoiceSS18 (opts, state);
|
||||
+ // state->voice_counter[0] = 0; //reset
|
||||
+ // }
|
||||
+
|
||||
+ // if (state->voice_counter[1] >= 18 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000) //&& ts_counter & 1
|
||||
+ // {
|
||||
+ // playSynthesizedVoiceSS18 (opts, state);
|
||||
+ // state->voice_counter[1] = 0; //reset
|
||||
+ // }
|
||||
|
||||
//debug: fix burst indicator for ncurses if marginal signal
|
||||
// if (voice)
|
||||
diff --git a/src/p25p2_xcch.c b/src/p25p2_xcch.c
|
||||
index 101d1e4..847fe71 100644
|
||||
--- a/src/p25p2_xcch.c
|
||||
+++ b/src/p25p2_xcch.c
|
||||
@@ -122,6 +122,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
{
|
||||
//reset fourv_counter and dropbyte on PTT
|
||||
state->fourv_counter[0] = 0;
|
||||
+ state->voice_counter[0] = 0;
|
||||
state->dropL = 256;
|
||||
|
||||
state->dmrburstL = 20;
|
||||
@@ -171,6 +172,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
{
|
||||
//reset fourv_counter and dropbyte on PTT
|
||||
state->fourv_counter[1] = 0;
|
||||
+ state->voice_counter[1] = 0;
|
||||
state->dropR = 256;
|
||||
state->payload_algidR = 0; //zero this out as well
|
||||
|
||||
@@ -230,6 +232,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
{
|
||||
|
||||
state->fourv_counter[0] = 0;
|
||||
+ state->voice_counter[0] = 0;
|
||||
state->dropL = 256;
|
||||
state->dmrburstL = 23;
|
||||
state->payload_algid = 0;
|
||||
@@ -258,6 +261,7 @@ void process_SACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[180]
|
||||
{
|
||||
|
||||
state->fourv_counter[1] = 0;
|
||||
+ state->voice_counter[1] = 0;
|
||||
state->dropR = 256;
|
||||
state->dmrburstR = 23;
|
||||
state->payload_algidR = 0;
|
||||
@@ -498,6 +502,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
{
|
||||
//reset fourv_counter and dropbyte on PTT
|
||||
state->fourv_counter[0] = 0;
|
||||
+ state->voice_counter[0] = 0;
|
||||
state->dropL = 256;
|
||||
|
||||
state->dmrburstL = 20;
|
||||
@@ -538,6 +543,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
{
|
||||
//reset fourv_counter and dropbyte on PTT
|
||||
state->fourv_counter[1] = 0;
|
||||
+ state->voice_counter[1] = 0;
|
||||
state->dropR = 256;
|
||||
|
||||
state->dmrburstR = 20;
|
||||
@@ -594,6 +600,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
{
|
||||
|
||||
state->fourv_counter[0] = 0;
|
||||
+ state->voice_counter[0] = 0;
|
||||
state->dropL = 256;
|
||||
state->dmrburstL = 23;
|
||||
state->payload_algid = 0; //zero this out as well
|
||||
@@ -622,6 +629,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
{
|
||||
|
||||
state->fourv_counter[1] = 0;
|
||||
+ state->voice_counter[1] = 0;
|
||||
state->dropR = 256;
|
||||
state->dmrburstR = 23;
|
||||
state->payload_algidR = 0; //zero this out as well
|
||||
@@ -723,6 +731,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
state->payload_keyid = 0;
|
||||
state->dmrburstL = 24;
|
||||
state->fourv_counter[0] = 0;
|
||||
+ state->voice_counter[0] = 0;
|
||||
state->lastsrc = 0;
|
||||
state->lasttg = 0;
|
||||
|
||||
@@ -733,6 +742,7 @@ void process_FACCH_MAC_PDU (dsd_opts * opts, dsd_state * state, int payload[156]
|
||||
state->payload_keyidR = 0;
|
||||
state->dmrburstR = 24;
|
||||
state->fourv_counter[1] = 0;
|
||||
+ state->voice_counter[1] = 0;
|
||||
state->lastsrcR = 0;
|
||||
state->lasttgR = 0;
|
||||
|
||||
452
patch/wolf_tdma_mono_stereo.patch
Normal file
452
patch/wolf_tdma_mono_stereo.patch
Normal file
@@ -0,0 +1,452 @@
|
||||
diff --git a/src/dsd_audio2.c b/src/dsd_audio2.c
|
||||
index a836afc..5eaf3c4 100644
|
||||
--- a/src/dsd_audio2.c
|
||||
+++ b/src/dsd_audio2.c
|
||||
@@ -906,8 +906,31 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
||||
//CHEAT: Using the slot on/off, use that to set encL or encR back on
|
||||
//as a simple way to turn off voice synthesis in a particular slot
|
||||
//its not really 'disabled', we just aren't playing it
|
||||
- if (opts->slot1_on == 0) encL = 1;
|
||||
- if (opts->slot2_on == 0) encR = 1;
|
||||
+ // if (opts->slot1_on == 0) encL = 1;
|
||||
+ // if (opts->slot2_on == 0) encR = 1;
|
||||
+
|
||||
+ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only
|
||||
+ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default
|
||||
+ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well
|
||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on
|
||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
||||
+ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
||||
+ else if (opts->slot_preference == 0 && state->dmrburstL == 16 && encL == 0) //slot 1 is preferred, and voice in slot 1
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
||||
+ else if (opts->slot_preference == 1 && state->dmrburstR == 16 && encR == 0) //slot 2 is preferred, and voice in slot 2
|
||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
||||
+ else if (state->dmrburstL == 16 && state->dmrburstR != 16 && encL == 0) //voice in left, no voice in right
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
||||
+ else if (state->dmrburstR == 16 && state->dmrburstL != 16 && encR == 0) //voice in right, no voice in left
|
||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
||||
+ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels)
|
||||
+
|
||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
||||
+ {
|
||||
+ encL = 1;
|
||||
+ encR = 1;
|
||||
+ }
|
||||
|
||||
//WIP: Mute if on B list (or not W list)
|
||||
char modeL[8];
|
||||
@@ -944,12 +967,37 @@ void playSynthesizedVoiceSS3 (dsd_opts * opts, dsd_state * state)
|
||||
if (strcmp(modeL, "B") == 0) encL = 1;
|
||||
if (strcmp(modeR, "B") == 0) encR = 1;
|
||||
|
||||
+ //check to see if we need to enable slot and toggle slot preference here
|
||||
+ //this method will always favor slot 2 (this is a patch anyways, so....meh)
|
||||
+ if (strcmp(modeL, "A") == 0)
|
||||
+ {
|
||||
+ opts->slot1_on = 1;
|
||||
+ opts->slot_preference = 0;
|
||||
+ }
|
||||
+ if (strcmp(modeR, "A") == 0)
|
||||
+ {
|
||||
+ opts->slot2_on = 1;
|
||||
+ opts->slot_preference = 1;
|
||||
+ }
|
||||
+
|
||||
//if TG Hold in place, mute anything but that TG #132
|
||||
- if (state->tg_hold != 0 && state->tg_hold != TGL) encL = 1;
|
||||
- if (state->tg_hold != 0 && state->tg_hold != TGR) encR = 1;
|
||||
- //likewise, override and unmute if TG hold matches TG
|
||||
- if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0;
|
||||
- if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0;
|
||||
+ if (state->tg_hold != 0 && state->tg_hold != TGL)
|
||||
+ encL = 1;
|
||||
+ if (state->tg_hold != 0 && state->tg_hold != TGR)
|
||||
+ encR = 1;
|
||||
+ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference)
|
||||
+ if (state->tg_hold != 0 && state->tg_hold == TGL)
|
||||
+ {
|
||||
+ encL = 0;
|
||||
+ opts->slot1_on = 1;
|
||||
+ opts->slot_preference = 0;
|
||||
+ }
|
||||
+ if (state->tg_hold != 0 && state->tg_hold == TGR)
|
||||
+ {
|
||||
+ encR = 0;
|
||||
+ opts->slot2_on = 1;
|
||||
+ opts->slot_preference = 1;
|
||||
+ }
|
||||
|
||||
//interleave left and right channels from the short storage area
|
||||
for (i = 0; i < 160; i++)
|
||||
@@ -1092,8 +1140,31 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
||||
//CHEAT: Using the slot on/off, use that to set encL or encR back on
|
||||
//as a simple way to turn off voice synthesis in a particular slot
|
||||
//its not really 'disabled', we just aren't playing it
|
||||
- if (opts->slot1_on == 0) encL = 1;
|
||||
- if (opts->slot2_on == 0) encR = 1;
|
||||
+ // if (opts->slot1_on == 0) encL = 1;
|
||||
+ // if (opts->slot2_on == 0) encR = 1;
|
||||
+
|
||||
+ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only
|
||||
+ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default
|
||||
+ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well
|
||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on
|
||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
||||
+ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
||||
+ else if (opts->slot_preference == 0 && state->dmrburstL == 21 && encL == 0) //slot 1 is preferred, and voice in slot 1
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
||||
+ else if (opts->slot_preference == 1 && state->dmrburstR == 21 && encR == 0) //slot 2 is preferred, and voice in slot 2
|
||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
||||
+ else if (state->dmrburstL == 21 && state->dmrburstR != 21 && encL == 0) //voice in left, no voice in right
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
||||
+ else if (state->dmrburstR == 21 && state->dmrburstL != 21 && encR == 0) //voice in right, no voice in left
|
||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
||||
+ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels)
|
||||
+
|
||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
||||
+ {
|
||||
+ encL = 1;
|
||||
+ encR = 1;
|
||||
+ }
|
||||
|
||||
//WIP: Mute if on B list (or not W list)
|
||||
char modeL[8];
|
||||
@@ -1130,12 +1201,37 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
||||
if (strcmp(modeL, "B") == 0) encL = 1;
|
||||
if (strcmp(modeR, "B") == 0) encR = 1;
|
||||
|
||||
+ //check to see if we need to enable slot and toggle slot preference here
|
||||
+ //this method will always favor slot 2 (this is a patch anyways, so....meh)
|
||||
+ if (strcmp(modeL, "A") == 0)
|
||||
+ {
|
||||
+ opts->slot1_on = 1;
|
||||
+ opts->slot_preference = 0;
|
||||
+ }
|
||||
+ if (strcmp(modeR, "A") == 0)
|
||||
+ {
|
||||
+ opts->slot2_on = 1;
|
||||
+ opts->slot_preference = 1;
|
||||
+ }
|
||||
+
|
||||
//if TG Hold in place, mute anything but that TG #132
|
||||
- if (state->tg_hold != 0 && state->tg_hold != TGL) encL = 1;
|
||||
- if (state->tg_hold != 0 && state->tg_hold != TGR) encR = 1;
|
||||
- //likewise, override and unmute if TG hold matches TG
|
||||
- if (state->tg_hold != 0 && state->tg_hold == TGL) encL = 0;
|
||||
- if (state->tg_hold != 0 && state->tg_hold == TGR) encR = 0;
|
||||
+ if (state->tg_hold != 0 && state->tg_hold != TGL)
|
||||
+ encL = 1;
|
||||
+ if (state->tg_hold != 0 && state->tg_hold != TGR)
|
||||
+ encR = 1;
|
||||
+ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference)
|
||||
+ if (state->tg_hold != 0 && state->tg_hold == TGL)
|
||||
+ {
|
||||
+ encL = 0;
|
||||
+ opts->slot1_on = 1;
|
||||
+ opts->slot_preference = 0;
|
||||
+ }
|
||||
+ if (state->tg_hold != 0 && state->tg_hold == TGR)
|
||||
+ {
|
||||
+ encR = 0;
|
||||
+ opts->slot2_on = 1;
|
||||
+ opts->slot_preference = 1;
|
||||
+ }
|
||||
|
||||
//interleave left and right channels from the short storage area
|
||||
for (i = 0; i < 160; i++)
|
||||
@@ -1238,6 +1334,226 @@ void playSynthesizedVoiceSS4 (dsd_opts * opts, dsd_state * state)
|
||||
|
||||
}
|
||||
|
||||
+//short stereo mix 18v superframe
|
||||
+void playSynthesizedVoiceSS18 (dsd_opts * opts, dsd_state * state)
|
||||
+{
|
||||
+
|
||||
+ //NOTE: This will run once every superframe during a sacch field
|
||||
+ //exact implementation to be determined
|
||||
+
|
||||
+ int i, j;
|
||||
+ uint8_t encL, encR;
|
||||
+
|
||||
+ short stereo_sf[18][320]; //8k 2-channel stereo interleave mix for full superframe
|
||||
+ // memset (stereo_sf, 1, 18*sizeof(short)); //I don't think 18*sizeof(short) was large enough, should probably be 18*320*sizeof(short)
|
||||
+ memset (stereo_sf, 1, sizeof(stereo_sf));
|
||||
+
|
||||
+ short empty[320];
|
||||
+ memset (empty, 1, sizeof(empty));
|
||||
+
|
||||
+ //p25p2 enc checkdown for whether or not to fill the stereo sample or not for playback or writing
|
||||
+ encL = encR = 1;
|
||||
+ if (state->payload_algid == 0 || state->payload_algid == 0x80)
|
||||
+ encL = 0;
|
||||
+ if (state->payload_algidR == 0 || state->payload_algidR == 0x80)
|
||||
+ encR = 0;
|
||||
+
|
||||
+ //checkdown to see if we can lift the 'mute' if a key is available
|
||||
+ if (encL)
|
||||
+ {
|
||||
+ if (state->payload_algid == 0xAA)
|
||||
+ {
|
||||
+ if (state->R != 0)
|
||||
+ {
|
||||
+ encL = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (encR)
|
||||
+ {
|
||||
+ if (state->payload_algidR == 0xAA)
|
||||
+ {
|
||||
+ if (state->RR != 0)
|
||||
+ {
|
||||
+ encR = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ //TODO: add option to bypass enc with a toggle as well
|
||||
+
|
||||
+ //CHEAT: Using the slot on/off, use that to set encL or encR back on
|
||||
+ //as a simple way to turn off voice synthesis in a particular slot
|
||||
+ //its not really 'disabled', we just aren't playing it
|
||||
+ // if (opts->slot1_on == 0) encL = 1;
|
||||
+ // if (opts->slot2_on == 0) encR = 1;
|
||||
+
|
||||
+ //this may have some unintended side effects that I haven't tested/explored yet, that's why its a patch only
|
||||
+ //particularly in regards to 'Aero' Builds with their OSS Jank and slot_preference = 3 by default
|
||||
+ //if rounds of testing in various scenaries looks good, I may expand this to P25p2 and the Float Variants as well
|
||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 1 && encR == 0) //slot 1 is hard off and slot 2 is on
|
||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
||||
+ else if (opts->slot1_on == 1 && opts->slot2_on == 0 && encL == 0) //slot 2 is hard off and slot 1 is on
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
||||
+ else if (opts->slot_preference == 0 && state->dmrburstL == 21 && encL == 0) //slot 1 is preferred, and voice in slot 1
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
||||
+ else if (opts->slot_preference == 1 && state->dmrburstR == 21 && encR == 0) //slot 2 is preferred, and voice in slot 2
|
||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
||||
+ else if (state->dmrburstL == 21 && state->dmrburstR != 21 && encL == 0) //voice in left, no voice in right
|
||||
+ memcpy (state->s_r4, state->s_l4, sizeof(state->s_r4)); //copy left to right
|
||||
+ else if (state->dmrburstR == 21 && state->dmrburstL != 21 && encR == 0) //voice in right, no voice in left
|
||||
+ memcpy (state->s_l4, state->s_r4, sizeof(state->s_l4)); //copy right to left
|
||||
+ //else if voice in both, and both slots on, and no preference on slot, then regular stereo interleave (left and right channels)
|
||||
+
|
||||
+ if (opts->slot1_on == 0 && opts->slot2_on == 0) //both slots are hard off, disable playback
|
||||
+ {
|
||||
+ encL = 1;
|
||||
+ encR = 1;
|
||||
+ }
|
||||
+
|
||||
+ //WIP: Mute if on B list (or not W list)
|
||||
+ char modeL[8];
|
||||
+ sprintf (modeL, "%s", "");
|
||||
+ char modeR[8];
|
||||
+ sprintf (modeR, "%s", "");
|
||||
+
|
||||
+ int TGL = state->lasttg;
|
||||
+ int TGR = state->lasttgR;
|
||||
+
|
||||
+ //if we are using allow/whitelist mode, then write 'B' to mode for block
|
||||
+ //comparison below will look for an 'A' to write to mode if it is allowed
|
||||
+ if (opts->trunk_use_allow_list == 1)
|
||||
+ {
|
||||
+ sprintf (modeL, "%s", "B");
|
||||
+ sprintf (modeR, "%s", "B");
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < state->group_tally; i++)
|
||||
+ {
|
||||
+ if (state->group_array[i].groupNumber == TGL)
|
||||
+ {
|
||||
+ strcpy (modeL, state->group_array[i].groupMode);
|
||||
+ // break; //need to keep going to check other potential slot group
|
||||
+ }
|
||||
+ if (state->group_array[i].groupNumber == TGR)
|
||||
+ {
|
||||
+ strcpy (modeR, state->group_array[i].groupMode);
|
||||
+ // break; //need to keep going to check other potential slot group
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ //flag either left or right as 'enc' to mute if B
|
||||
+ if (strcmp(modeL, "B") == 0) encL = 1;
|
||||
+ if (strcmp(modeR, "B") == 0) encR = 1;
|
||||
+
|
||||
+ //check to see if we need to enable slot and toggle slot preference here
|
||||
+ //this method will always favor slot 2 (this is a patch anyways, so....meh)
|
||||
+ if (strcmp(modeL, "A") == 0)
|
||||
+ {
|
||||
+ opts->slot1_on = 1;
|
||||
+ opts->slot_preference = 0;
|
||||
+ }
|
||||
+ if (strcmp(modeR, "A") == 0)
|
||||
+ {
|
||||
+ opts->slot2_on = 1;
|
||||
+ opts->slot_preference = 1;
|
||||
+ }
|
||||
+
|
||||
+ //if TG Hold in place, mute anything but that TG #132
|
||||
+ if (state->tg_hold != 0 && state->tg_hold != TGL)
|
||||
+ encL = 1;
|
||||
+ if (state->tg_hold != 0 && state->tg_hold != TGR)
|
||||
+ encR = 1;
|
||||
+ //likewise, override and unmute if TG hold matches TG (and turn on slot and set preference)
|
||||
+ if (state->tg_hold != 0 && state->tg_hold == TGL)
|
||||
+ {
|
||||
+ encL = 0;
|
||||
+ opts->slot1_on = 1;
|
||||
+ opts->slot_preference = 0;
|
||||
+ }
|
||||
+ if (state->tg_hold != 0 && state->tg_hold == TGR)
|
||||
+ {
|
||||
+ encR = 0;
|
||||
+ opts->slot2_on = 1;
|
||||
+ opts->slot_preference = 1;
|
||||
+ }
|
||||
+
|
||||
+ //at this point, if both channels are still flagged as enc, then we can skip all playback/writing functions
|
||||
+ if (encL && encR)
|
||||
+ goto SS18_END;
|
||||
+
|
||||
+ //interleave left and right channels from the short storage area
|
||||
+ for (j = 0; j < 18; j++)
|
||||
+ {
|
||||
+ for (i = 0; i < 160; i++)
|
||||
+ {
|
||||
+ if (!encL)
|
||||
+ stereo_sf[j][i*2+0] = state->s_l4[j][i];
|
||||
+ if (!encR)
|
||||
+ stereo_sf[j][i*2+1] = state->s_r4[j][i];
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (opts->audio_out_type == 0) //Pulse Audio
|
||||
+ {
|
||||
+ for (j = 0; j < 18; j++)
|
||||
+ {
|
||||
+ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely
|
||||
+ pa_simple_write(opts->pulse_digi_dev_out, stereo_sf[j], 320*2, NULL);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (opts->audio_out_type == 8) //UDP Audio
|
||||
+ {
|
||||
+ for (j = 0; j < 18; j++)
|
||||
+ {
|
||||
+ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely
|
||||
+ udp_socket_blaster (opts, state, 320*2, stereo_sf[j]);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ if (opts->audio_out_type == 1 || opts->audio_out_type == 2) //STDOUT or OSS 8k/2channel
|
||||
+ {
|
||||
+ for (j = 0; j < 18; j++)
|
||||
+ {
|
||||
+ if (memcmp(empty, stereo_sf[j], sizeof(empty)) != 0) //may not work as intended because its stereo and one will have something in it most likely
|
||||
+ write (opts->audio_out_fd, stereo_sf[j], 320*2);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ SS18_END:
|
||||
+
|
||||
+ //run cleanup since we pulled stuff from processAudio
|
||||
+ state->audio_out_idx = 0;
|
||||
+ state->audio_out_idxR = 0;
|
||||
+
|
||||
+ //set float temp buffer to baseline
|
||||
+ memset (state->s_l4, 1, sizeof(state->s_l4));
|
||||
+ memset (state->s_r4, 1, sizeof(state->s_r4));
|
||||
+
|
||||
+ if (state->audio_out_idx2 >= 800000)
|
||||
+ {
|
||||
+ state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
||||
+ state->audio_out_buf_p = state->audio_out_buf + 100;
|
||||
+ memset (state->audio_out_float_buf, 0, 100 * sizeof (float));
|
||||
+ memset (state->audio_out_buf, 0, 100 * sizeof (short));
|
||||
+ state->audio_out_idx2 = 0;
|
||||
+ }
|
||||
+
|
||||
+ if (state->audio_out_idx2R >= 800000)
|
||||
+ {
|
||||
+ state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
|
||||
+ state->audio_out_buf_pR = state->audio_out_bufR + 100;
|
||||
+ memset (state->audio_out_float_bufR, 0, 100 * sizeof (float));
|
||||
+ memset (state->audio_out_bufR, 0, 100 * sizeof (short));
|
||||
+ state->audio_out_idx2R = 0;
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
+
|
||||
//largely borrowed from Boatbod OP25 (simplified single tone ID version)
|
||||
void soft_tonef (float samp[160], int n, int ID, int AD)
|
||||
{
|
||||
diff --git a/src/dsd_main.c b/src/dsd_main.c
|
||||
index 1d2616b..924bf00 100644
|
||||
--- a/src/dsd_main.c
|
||||
+++ b/src/dsd_main.c
|
||||
@@ -745,7 +745,7 @@ initOpts (dsd_opts * opts)
|
||||
//slot preference is used during OSS audio playback to
|
||||
//prefer one tdma voice slot over another when both are playing back
|
||||
//this is a fix to OSS 48k/1 output
|
||||
- opts->slot_preference = 0; //default prefer slot 1 -- state->currentslot = 0;
|
||||
+ opts->slot_preference = 2; //default prefer slot 1 -- state->currentslot = 0;
|
||||
|
||||
//hardset slots to synthesize
|
||||
opts->slot1_on = 1;
|
||||
diff --git a/src/dsd_ncurses.c b/src/dsd_ncurses.c
|
||||
index 4646e77..fc3f28b 100644
|
||||
--- a/src/dsd_ncurses.c
|
||||
+++ b/src/dsd_ncurses.c
|
||||
@@ -2568,11 +2568,11 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
printw ("| Voice Error: [%i][%i] Slot 1 (1)", state->errs, state->errs2);
|
||||
if (opts->slot1_on == 0) printw (" OFF");
|
||||
- if (opts->slot1_on == 1) printw (" ON");
|
||||
+ if (opts->slot1_on == 1) printw (" ON"); if (opts->slot_preference == 0) printw (" *Preferred");
|
||||
printw ("\n");
|
||||
printw ("| Voice Error: [%i][%i] Slot 2 (2)", state->errsR, state->errs2R);
|
||||
if (opts->slot2_on == 0) printw (" OFF");
|
||||
- if (opts->slot2_on == 1) printw (" ON");
|
||||
+ if (opts->slot2_on == 1) printw (" ON"); if (opts->slot_preference == 1) printw (" *Preferred");
|
||||
printw ("\n");
|
||||
}
|
||||
printw ("------------------------------------------------------------------------------\n");
|
||||
@@ -3654,8 +3654,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
//switching, but want to control each seperately plz
|
||||
if (opts->slot1_on == 1)
|
||||
{
|
||||
- opts->slot1_on = 0;
|
||||
- opts->slot_preference = 1; //slot 2
|
||||
+ opts->slot1_on = 0; if (opts->slot_preference == 0) opts->slot_preference = 2;
|
||||
+ // opts->slot_preference = 1; //slot 2
|
||||
//clear any previously buffered audio
|
||||
state->audio_out_float_buf_p = state->audio_out_float_buf + 100;
|
||||
state->audio_out_buf_p = state->audio_out_buf + 100;
|
||||
@@ -3680,8 +3680,8 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
//switching, but want to control each seperately plz
|
||||
if (opts->slot2_on == 1)
|
||||
{
|
||||
- opts->slot2_on = 0;
|
||||
- opts->slot_preference = 0; //slot 1
|
||||
+ opts->slot2_on = 0; if (opts->slot_preference == 1) opts->slot_preference = 2;
|
||||
+ // opts->slot_preference = 0; //slot 1
|
||||
//clear any previously buffered audio
|
||||
state->audio_out_float_buf_pR = state->audio_out_float_bufR + 100;
|
||||
state->audio_out_buf_pR = state->audio_out_bufR + 100;
|
||||
@@ -3701,6 +3701,13 @@ ncursesPrinter (dsd_opts * opts, dsd_state * state)
|
||||
}
|
||||
}
|
||||
|
||||
+ if (c == 51) //'3' key, cycle slot preferences
|
||||
+ {
|
||||
+ if (opts->slot_preference < 2)
|
||||
+ opts->slot_preference++;
|
||||
+ else opts->slot_preference = 0;
|
||||
+ }
|
||||
+
|
||||
if (c == 43) //+ key, increment audio_gain
|
||||
{
|
||||
|
||||
519
provoice.c
519
provoice.c
@@ -1,519 +0,0 @@
|
||||
#include "dsd.h"
|
||||
#include "provoice_const.h"
|
||||
|
||||
void
|
||||
processProVoice (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
int i, j, dibit;
|
||||
|
||||
char imbe7100_fr1[7][24];
|
||||
char imbe7100_fr2[7][24];
|
||||
const int *w, *x;
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printf ("VOICE e:");
|
||||
}
|
||||
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf (" ");
|
||||
#endif
|
||||
|
||||
// lid
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf (" ");
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 64; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf (" ");
|
||||
#endif
|
||||
|
||||
// imbe frames 1,2 first half
|
||||
w = pW;
|
||||
x = pX;
|
||||
|
||||
for (i = 0; i < 11; i++)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
}
|
||||
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf (" ");
|
||||
#endif
|
||||
|
||||
// spacer bits
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
printf (" ");
|
||||
#endif
|
||||
|
||||
// imbe frames 1,2 second half
|
||||
|
||||
for (j = 0; j < 2; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
}
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
w -= 5;
|
||||
x -= 5;
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
}
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
w -= 5;
|
||||
x -= 5;
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf (" ");
|
||||
#endif
|
||||
|
||||
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1);
|
||||
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr2);
|
||||
|
||||
// spacer bits
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
printf (" ");
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf (" ");
|
||||
#endif
|
||||
|
||||
// imbe frames 3,4 first half
|
||||
w = pW;
|
||||
x = pX;
|
||||
for (i = 0; i < 11; i++)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
}
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 4; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf (" ");
|
||||
#endif
|
||||
|
||||
// spacer bits
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
printf ("_");
|
||||
#endif
|
||||
|
||||
// imbe frames 3,4 second half
|
||||
for (j = 0; j < 2; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
}
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
w -= 5;
|
||||
x -= 5;
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf (" ");
|
||||
#endif
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
w -= 6;
|
||||
x -= 6;
|
||||
for (j = 0; j < 6; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
}
|
||||
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr1[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("_");
|
||||
#endif
|
||||
w -= 5;
|
||||
x -= 5;
|
||||
for (j = 0; j < 5; j++)
|
||||
{
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
imbe7100_fr2[*w][*x] = dibit;
|
||||
w++;
|
||||
x++;
|
||||
}
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf (" ");
|
||||
#endif
|
||||
|
||||
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr1);
|
||||
processMbeFrame (opts, state, NULL, NULL, imbe7100_fr2);
|
||||
|
||||
// spacer bits
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
#endif
|
||||
dibit = getDibit (opts, state);
|
||||
#ifdef PROVOICE_DUMP
|
||||
printf ("%i", dibit);
|
||||
printf (" ");
|
||||
#endif
|
||||
|
||||
if (opts->errorbars == 1)
|
||||
{
|
||||
printf ("\n");
|
||||
}
|
||||
}
|
||||
15
rebuild.sh
Normal file
15
rebuild.sh
Normal file
@@ -0,0 +1,15 @@
|
||||
#! /bin/bash
|
||||
#
|
||||
clear
|
||||
printf "DSD-FME Digital Speech Decoder - Florida Man Edition
|
||||
Automatic Git Pull and Rebuild\n\n"
|
||||
sleep 1
|
||||
##Open your clone folder##
|
||||
git pull
|
||||
sleep 2
|
||||
##cd into your build folder##
|
||||
cd build
|
||||
cmake ..
|
||||
make -j $(nproc)
|
||||
sudo make install
|
||||
sudo ldconfig
|
||||
7
src/1.c
Normal file
7
src/1.c
Normal file
@@ -0,0 +1,7 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* 1.c
|
||||
* Placeholder File 1 -- This file is for temporary code storage
|
||||
*
|
||||
*
|
||||
*
|
||||
*-----------------------------------------------------------------------------*/
|
||||
7
src/2.c
Normal file
7
src/2.c
Normal file
@@ -0,0 +1,7 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* 2.c
|
||||
* Placeholder File 2 -- This file is for temporary code storage
|
||||
*
|
||||
*
|
||||
*
|
||||
*-----------------------------------------------------------------------------*/
|
||||
87
src/3.c
Normal file
87
src/3.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* 3.c
|
||||
* Placeholder File 3 -- This file is for temporary code storage
|
||||
*
|
||||
* A 1/2 Rate Convolutional Decoder for NXDN/M17/YSF
|
||||
* Used as a secondary decoder in case convolutional decoder fails (second opinion)
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
static const int PARITY[] = {0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1};
|
||||
|
||||
// trellis_1_2 encode: source is in bits, result in bits
|
||||
void trellis_encode(uint8_t result[], const uint8_t source[], int result_len, int reg)
|
||||
{
|
||||
for (int i=0; i<result_len; i+=2) {
|
||||
reg = (reg << 1) | source[i>>1];
|
||||
result[i] = PARITY[reg & 0x19];
|
||||
result[i+1] = PARITY[reg & 0x17];
|
||||
}
|
||||
}
|
||||
|
||||
// simplified trellis 2:1 decode; source and result in bits
|
||||
// assumes that encoding was done with NTEST trailing zero bits
|
||||
// result_len should be set to the actual number of data bits
|
||||
// in the original unencoded message (excl. these trailing bits)
|
||||
void trellis_decode(uint8_t result[], const uint8_t source[], int result_len)
|
||||
{
|
||||
int reg = 0;
|
||||
int min_d;
|
||||
int min_bt;
|
||||
static const int NTEST = 4;
|
||||
static const int NTESTC = 1 << NTEST;
|
||||
uint8_t bt[NTEST];
|
||||
uint8_t tt[NTEST*2];
|
||||
int dstats[4];
|
||||
int sum;
|
||||
for (int p=0; p < 4; p++)
|
||||
dstats[p] = 0;
|
||||
for (int p=0; p < result_len; p++) {
|
||||
for (int i=0; i<NTESTC; i++) {
|
||||
bt[0] = (i&8)>>3;
|
||||
bt[1] = (i&4)>>2;
|
||||
bt[2] = (i&2)>>1;
|
||||
bt[3] = (i&1);
|
||||
trellis_encode(tt, bt, NTEST*2, reg);
|
||||
sum=0;
|
||||
for (int j=0; j<NTEST*2; j++) {
|
||||
sum += tt[j] ^ source[p*2+j];
|
||||
}
|
||||
if (i == 0 || sum < min_d) {
|
||||
min_d = sum;
|
||||
min_bt = bt[0];
|
||||
}
|
||||
}
|
||||
result[p] = min_bt;
|
||||
reg = (reg << 1) | min_bt;
|
||||
dstats[(min_d > 3) ? 3 : min_d] += 1;
|
||||
}
|
||||
|
||||
//debug output
|
||||
// fprintf (stderr, "\n stats\t%d %d %d %d\n", dstats[0], dstats[1], dstats[2], dstats[3]);
|
||||
}
|
||||
|
||||
//Original Copyright/License
|
||||
|
||||
/* -*- c++ -*- */
|
||||
/*
|
||||
* NXDN Encoder/Decoder (C) Copyright 2019 Max H. Parke KA1RBI
|
||||
*
|
||||
* This file is part of OP25
|
||||
*
|
||||
* This 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.
|
||||
*
|
||||
* This software 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 software; see the file COPYING. If not, write to
|
||||
* the Free Software Foundation, Inc., 51 Franklin Street,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
7
src/4.c
Normal file
7
src/4.c
Normal file
@@ -0,0 +1,7 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* 4.c
|
||||
* Placeholder File 4 -- This file is for temporary code storage
|
||||
*
|
||||
*
|
||||
*
|
||||
*-----------------------------------------------------------------------------*/
|
||||
7
src/5.c
Normal file
7
src/5.c
Normal file
@@ -0,0 +1,7 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* 5.c
|
||||
* Placeholder File 5 -- This file is for temporary code storage
|
||||
*
|
||||
*
|
||||
*
|
||||
*-----------------------------------------------------------------------------*/
|
||||
83
src/Hamming.cpp
Normal file
83
src/Hamming.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
|
||||
#include "Hamming.hpp"
|
||||
|
||||
// definition outside class declaration
|
||||
Hamming_10_6_3_data Hamming_10_6_3::data;
|
||||
|
||||
// definition outside class declaration
|
||||
// Should go *after* Hamming_10_6_3_data since Hamming_10_6_3_TableImpl_data constructor uses
|
||||
// Hamming_10_6_3 which in its turn depends on Hamming_10_6_3_data
|
||||
Hamming_10_6_3_TableImpl_data Hamming_10_6_3_TableImpl::data;
|
||||
|
||||
|
||||
int Hamming_10_6_3::decode(std::bitset<10>& input)
|
||||
{
|
||||
int error_count;
|
||||
|
||||
// Compute syndromes
|
||||
int s0 = ((data.h0 & input).count() & 1) << 3;
|
||||
int s1 = ((data.h1 & input).count() & 1) << 2;
|
||||
int s2 = ((data.h2 & input).count() & 1) << 1;
|
||||
int s3 = ((data.h3 & input).count() & 1);
|
||||
int parity = s0 | s1 | s2 | s3;
|
||||
|
||||
if (parity == 0) {
|
||||
//std::cout << input << " is OK" << std::endl;
|
||||
error_count = 0;
|
||||
} else {
|
||||
// Error detected, attempt to fix it
|
||||
int bad_bit_index = data.bad_bit_table[parity];
|
||||
|
||||
if (bad_bit_index < 0) {
|
||||
//std::cout << "Irrecoverable error: " << std::bitset<6>(input.to_string()) << std::endl;
|
||||
error_count = 2;
|
||||
} else {
|
||||
// Error in a data bit, or more than one error
|
||||
// If there is one erroneous bit, the bad one is the one indicated by parity
|
||||
if (bad_bit_index < 4) {
|
||||
// Error detected in a parity bit
|
||||
//std::cout << "Error on parity bit " << bad_bit_index << std::endl;
|
||||
error_count = 1;
|
||||
} else {
|
||||
input.flip(bad_bit_index);
|
||||
//std::cout << "Error on data bit " << bad_bit_index << ", hopefully fixed: " << std::bitset<6>(input.to_string()) << std::endl;
|
||||
error_count = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
//std::cout << std::endl;
|
||||
|
||||
return error_count;
|
||||
}
|
||||
|
||||
int Hamming_10_6_3::encode(std::bitset<6>& input)
|
||||
{
|
||||
// Compute syndromes
|
||||
int s0 = ((data.gt0 & input).count() & 1) << 3;
|
||||
int s1 = ((data.gt1 & input).count() & 1) << 2;
|
||||
int s2 = ((data.gt2 & input).count() & 1) << 1;
|
||||
int s3 = ((data.gt3 & input).count() & 1);
|
||||
int parity = s0 | s1 | s2 | s3;
|
||||
|
||||
return parity;
|
||||
}
|
||||
|
||||
int Hamming_10_6_3_TableImpl::decode(int input, int* output)
|
||||
{
|
||||
assert (input < 1024 && input >= 0);
|
||||
|
||||
// Making use of a table...
|
||||
|
||||
*output = data.fixed_values[input];
|
||||
|
||||
return data.error_counts[input];
|
||||
}
|
||||
|
||||
int Hamming_10_6_3_TableImpl::encode(int input)
|
||||
{
|
||||
assert (input < 64 && input >= 0);
|
||||
|
||||
// Making use of a table...
|
||||
|
||||
return data.encode_parities[input];
|
||||
}
|
||||
582
src/bptc.c
Normal file
582
src/bptc.c
Normal file
@@ -0,0 +1,582 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : bptc.c
|
||||
Author : MotoTRBO_Encrypted_DSD_Author
|
||||
Version : 1.0
|
||||
Date : 2017 - December - 11
|
||||
Copyright : None
|
||||
Description : BPTC library source
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
|
||||
/* Include ------------------------------------------------------------------*/
|
||||
#include "dsd.h"
|
||||
|
||||
|
||||
/* Define -------------------------------------------------------------------*/
|
||||
|
||||
|
||||
/* Global variables ---------------------------------------------------------*/
|
||||
const uint8_t BPTCInterleavingIndex[196] =
|
||||
{
|
||||
0, 181, 166, 151,
|
||||
136, 121, 106, 91,
|
||||
76, 61, 46, 31,
|
||||
16, 1, 182, 167,
|
||||
152, 137, 122, 107,
|
||||
92, 77, 62, 47,
|
||||
32, 17, 2, 183,
|
||||
168, 153, 138, 123,
|
||||
108, 93, 78, 63,
|
||||
48, 33, 18, 3,
|
||||
184, 169, 154, 139,
|
||||
124, 109, 94, 79,
|
||||
64, 49, 34, 19,
|
||||
4, 185, 170, 155,
|
||||
140, 125, 110, 95,
|
||||
80, 65, 50, 35,
|
||||
20, 5, 186, 171,
|
||||
156, 141, 126, 111,
|
||||
96, 81, 66, 51,
|
||||
36, 21, 6, 187,
|
||||
172, 157, 142, 127,
|
||||
112, 97, 82, 67,
|
||||
52, 37, 22, 7,
|
||||
188, 173, 158, 143,
|
||||
128, 113, 98, 83,
|
||||
68, 53, 38, 23,
|
||||
8, 189, 174, 159,
|
||||
144, 129, 114, 99,
|
||||
84, 69, 54, 39,
|
||||
24, 9, 190, 175,
|
||||
160, 145, 130, 115,
|
||||
100, 85, 70, 55,
|
||||
40, 25, 10, 191,
|
||||
176, 161, 146, 131,
|
||||
116, 101, 86, 71,
|
||||
56, 41, 26, 11,
|
||||
192, 177, 162, 147,
|
||||
132, 117, 102, 87,
|
||||
72, 57, 42, 27,
|
||||
12, 193, 178, 163,
|
||||
148, 133, 118, 103,
|
||||
88, 73, 58, 43,
|
||||
28, 13, 194, 179,
|
||||
164, 149, 134, 119,
|
||||
104, 89, 74, 59,
|
||||
44, 29, 14, 195,
|
||||
180, 165, 150, 135,
|
||||
120, 105, 90, 75,
|
||||
60, 45, 30, 15
|
||||
};
|
||||
|
||||
|
||||
const uint8_t BPTCDeInterleavingIndex[196] =
|
||||
{
|
||||
0, 13, 26, 39,
|
||||
52, 65, 78, 91,
|
||||
104, 117, 130, 143,
|
||||
156, 169, 182, 195,
|
||||
12, 25, 38, 51,
|
||||
64, 77, 90, 103,
|
||||
116, 129, 142, 155,
|
||||
168, 181, 194, 11,
|
||||
24, 37, 50, 63,
|
||||
76, 89, 102, 115,
|
||||
128, 141, 154, 167,
|
||||
180, 193, 10, 23,
|
||||
36, 49, 62, 75,
|
||||
88, 101, 114, 127,
|
||||
140, 153, 166, 179,
|
||||
192, 9, 22, 35,
|
||||
48, 61, 74, 87,
|
||||
100, 113, 126, 139,
|
||||
152, 165, 178, 191,
|
||||
8, 21, 34, 47,
|
||||
60, 73, 86, 99,
|
||||
112, 125, 138, 151,
|
||||
164, 177, 190, 7,
|
||||
20, 33, 46, 59,
|
||||
72, 85, 98, 111,
|
||||
124, 137, 150, 163,
|
||||
176, 189, 6, 19,
|
||||
32, 45, 58, 71,
|
||||
84, 97, 110, 123,
|
||||
136, 149, 162, 175,
|
||||
188, 5, 18, 31,
|
||||
44, 57, 70, 83,
|
||||
96, 109, 122, 135,
|
||||
148, 161, 174, 187,
|
||||
4, 17, 30, 43,
|
||||
56, 69, 82, 95,
|
||||
108, 121, 134, 147,
|
||||
160, 173, 186, 3,
|
||||
16, 29, 42, 55,
|
||||
68, 81, 94, 107,
|
||||
120, 133, 146, 159,
|
||||
172, 185, 2, 15,
|
||||
28, 41, 54, 67,
|
||||
80, 93, 106, 119,
|
||||
132, 145, 158, 171,
|
||||
184, 1, 14, 27,
|
||||
40, 53, 66, 79,
|
||||
92, 105, 118, 131,
|
||||
144, 157, 170, 183
|
||||
};
|
||||
|
||||
|
||||
const uint8_t DeInterleaveReverseChannelBptc[32] =
|
||||
{
|
||||
0, 17, 2, 19, 4, 21, 6, 23,
|
||||
8, 25, 10, 27, 12, 29, 14, 31,
|
||||
16, 1, 18, 3, 20, 5, 22, 7,
|
||||
24, 9, 26, 11, 28, 13, 30, 15
|
||||
};
|
||||
|
||||
const uint8_t DeInterleaveReverseChannelBptcPlacement[32] =
|
||||
{
|
||||
0, 16, 1, 17, 2, 18, 3, 19,
|
||||
4, 20, 5, 21, 6, 22, 7, 23,
|
||||
8, 24, 9, 25, 10, 26, 11, 27,
|
||||
12, 28, 13, 29, 14, 30, 15, 31
|
||||
};
|
||||
|
||||
/* Functions ----------------------------------------------------------------*/
|
||||
|
||||
|
||||
/*
|
||||
* @brief : This function deinterleave the DMR data by using BPTC (196,96)
|
||||
*
|
||||
* @param Input : Pointer of DMR input data interleaved (196 bytes)
|
||||
*
|
||||
* @param Output : Pointer where DMR deinterleaved data will be written (196 bytes)
|
||||
*
|
||||
* @return None
|
||||
*/
|
||||
void BPTCDeInterleaveDMRData(uint8_t * Input, uint8_t * Output)
|
||||
{
|
||||
uint32_t i, DeInterleaveIndex;
|
||||
|
||||
for(i = 0; i < 196; i++)
|
||||
{
|
||||
DeInterleaveIndex = BPTCDeInterleavingIndex[i];
|
||||
Output[DeInterleaveIndex] = (Input[i] & 1);
|
||||
}
|
||||
} /* End BPTCDeInterleaveDMRData() */
|
||||
|
||||
|
||||
/*
|
||||
* @brief : This function extract the 96 bits of a deinteleaved 196 bits
|
||||
* buffer using BPTC (196,96)
|
||||
*
|
||||
* @param InputDeInteleavedData : Pointer of DMR input data deinterleaved (196 bytes)
|
||||
*
|
||||
* @param DMRDataExtracted : Pointer where the DMR data will be written (96 bytes)
|
||||
*
|
||||
* @return The total number of irrecoverable Hamming check errors
|
||||
*/
|
||||
uint32_t BPTC_196x96_Extract_Data(uint8_t InputDeInteleavedData[196], uint8_t DMRDataExtracted[96], uint8_t R[3])
|
||||
{
|
||||
uint32_t i, j, k;
|
||||
uint8_t DataMatrix[13][15];
|
||||
uint8_t LineUncorrected[15];
|
||||
uint8_t LineCorrected[11];
|
||||
uint8_t ColumnUncorrected[13];
|
||||
uint8_t ColumnCorrected[9];
|
||||
uint32_t HammingIrrecoverableErrorNb = 0;
|
||||
|
||||
/* First step : Reconstitute the BPTC 15x11 matrix
|
||||
* Note : Input data shall be deinterleaved */
|
||||
k = 1; /* Discard R(3) bit - See DMR standard chapter B1.1 BPTC (196,96) */
|
||||
for(i = 0; i < 13; i++)
|
||||
{
|
||||
for(j = 0; j < 15; j++)
|
||||
{
|
||||
/* Only the LSBit of the byte is stored */
|
||||
DataMatrix[i][j] = (InputDeInteleavedData[k] & 1);
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Set to 0 R(0) to R(2) - See DMR standard chapter B1.1 BPTC (196,96) */
|
||||
// DataMatrix[0][0] = 0; /* R(2) */
|
||||
// DataMatrix[0][1] = 0; /* R(1) */
|
||||
// DataMatrix[0][2] = 0; /* R(0) */
|
||||
|
||||
/* Init the Hamming (15,11,3) library
|
||||
* Not needed because it has already been done
|
||||
* in the "InitAllFecFunction()" function */
|
||||
//Hamming_15_11_init();
|
||||
|
||||
/* Init the Hamming (13,9,3) library
|
||||
* Not needed because it has already been done
|
||||
* in the "InitAllFecFunction()" function */
|
||||
//Hamming_13_9_init();
|
||||
|
||||
/* Init the Hamming error counter */
|
||||
HammingIrrecoverableErrorNb = 0;
|
||||
|
||||
/* Process the the Hamming (15,11,3) code
|
||||
* check on each line (first time).
|
||||
* Do not check the 4th last lines */
|
||||
for(i = 0; i < 9; i++)
|
||||
{
|
||||
/* Get a full line */
|
||||
for(j = 0; j < 15; j++)
|
||||
{
|
||||
LineUncorrected[j] = DataMatrix[i][j];
|
||||
}
|
||||
|
||||
/* Apply Hamming (15,11,3) code correction */
|
||||
if(Hamming_15_11_decode(LineUncorrected, LineCorrected, 1) == false)
|
||||
{
|
||||
HammingIrrecoverableErrorNb++;
|
||||
}
|
||||
|
||||
/* Re-inject the line in the matrix (only the util data [11 bit],
|
||||
* not the Hamming part [4 bit]) */
|
||||
for(j = 0; j < 11; j++)
|
||||
{
|
||||
DataMatrix[i][j] = LineCorrected[j];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Process the the Hamming (15,11,3) code
|
||||
* check on each column/row (first time) */
|
||||
for(i = 0; i < 15; i++)
|
||||
{
|
||||
/* Get a full column */
|
||||
for(j = 0; j < 13; j++)
|
||||
{
|
||||
ColumnUncorrected[j] = DataMatrix[j][i];
|
||||
}
|
||||
|
||||
/* Apply Hamming (15,11,3) code correction */
|
||||
if(Hamming_13_9_decode(ColumnUncorrected, ColumnCorrected, 1) == false)
|
||||
{
|
||||
HammingIrrecoverableErrorNb++;
|
||||
}
|
||||
|
||||
/* Re-inject the column in the matrix (only the util data [11 bit],
|
||||
* not the Hamming part [4 bit]) */
|
||||
for(j = 0; j < 9; j++)
|
||||
{
|
||||
DataMatrix[j][i] = ColumnCorrected[j];
|
||||
}
|
||||
}
|
||||
|
||||
/* The first Hamming code check has maybe corrected bit
|
||||
* witch can be use to correct other bit, so make the
|
||||
* same operation twice */
|
||||
|
||||
/* Reset the number of irrecoverable errors */
|
||||
HammingIrrecoverableErrorNb = 0;
|
||||
|
||||
|
||||
/* Process the the Hamming (15,11,3) code
|
||||
* check on each line (second time).
|
||||
* Do not check the 4th last lines */
|
||||
for(i = 0; i < 9; i++)
|
||||
{
|
||||
/* Get a full line */
|
||||
for(j = 0; j < 15; j++)
|
||||
{
|
||||
LineUncorrected[j] = DataMatrix[i][j];
|
||||
}
|
||||
|
||||
/* Apply Hamming (15,11,3) code correction */
|
||||
if(Hamming_15_11_decode(LineUncorrected, LineCorrected, 1) == false)
|
||||
{
|
||||
/* Row/Line contains irrecoverable errors */
|
||||
HammingIrrecoverableErrorNb++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Row/Line contains correct data */
|
||||
}
|
||||
|
||||
/* Re-inject the line in the matrix (only the util data [11 bit],
|
||||
* not the Hamming part [4 bit]) */
|
||||
for(j = 0; j < 11; j++)
|
||||
{
|
||||
DataMatrix[i][j] = LineCorrected[j];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Process the the Hamming (15,11,3) code
|
||||
* check on each column/row (second time) */
|
||||
for(i = 0; i < 15; i++)
|
||||
{
|
||||
/* Get a full column */
|
||||
for(j = 0; j < 13; j++)
|
||||
{
|
||||
ColumnUncorrected[j] = DataMatrix[j][i];
|
||||
}
|
||||
|
||||
/* Apply Hamming (15,11,3) code correction */
|
||||
if(Hamming_13_9_decode(ColumnUncorrected, ColumnCorrected, 1) == false)
|
||||
{
|
||||
/* Row/Line contains irrecoverable errors */
|
||||
HammingIrrecoverableErrorNb++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Row/Line contains correct data */
|
||||
}
|
||||
|
||||
/* Re-inject the column in the matrix (only the util data [11 bit],
|
||||
* not the Hamming part [4 bit]) */
|
||||
for(j = 0; j < 9; j++)
|
||||
{
|
||||
DataMatrix[j][i] = ColumnCorrected[j];
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract the DMR data (96 bit) from the matrix */
|
||||
/* First line : Do not take R(2), R(1) and R(0) */
|
||||
k = 0;
|
||||
|
||||
for(i = 3; i < 11; i++)
|
||||
{
|
||||
DMRDataExtracted[k] = DataMatrix[0][i];
|
||||
k++;
|
||||
}
|
||||
|
||||
/* Next lines */
|
||||
for(i = 1; i < 9; i++)
|
||||
{
|
||||
for(j = 0; j < 11; j++)
|
||||
{
|
||||
DMRDataExtracted[k] = DataMatrix[i][j];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
/* R(0) to R(2) may be used to transport some
|
||||
* Restricted Access System (RAS) information,
|
||||
* So save these three bits after hamming correction
|
||||
* See patent US 2013/0288643 A1 */
|
||||
R[0] = DataMatrix[0][2]; /* Save R(0) */
|
||||
R[1] = DataMatrix[0][1]; /* Save R(1) */
|
||||
R[2] = DataMatrix[0][0]; /* Save R(2) */
|
||||
|
||||
/* Return the number of irrecoverable Hamming errors */
|
||||
return HammingIrrecoverableErrorNb;
|
||||
} /* End BPTC_196x96_Extract_Data() */
|
||||
|
||||
|
||||
/*
|
||||
* @brief : This function extract the 77 bits of a deinteleaved 128 bits
|
||||
* buffer using BPTC (128,77).
|
||||
*
|
||||
* @note : See DMR standard ETSI TS 102 361-1 chapter B.2.1 for details
|
||||
*
|
||||
* @param InputDeInteleavedData : Pointer of DMR input data deinterleaved (128 bytes
|
||||
act as a 16 x 8 byte data matrix)
|
||||
*
|
||||
* @param DMRDataExtracted : Pointer where the DMR data will be written (77 bytes)
|
||||
* DMRDataExtracted[0..71] = Util data (hamming corrected)
|
||||
* DMRDataExtracted[72..76] = 5 bit of CRC extracted (to be checked)
|
||||
*
|
||||
* @return 0 = All is OK
|
||||
* Other = Error - Irrecoverable Hamming parity check error number
|
||||
*/
|
||||
uint32_t BPTC_128x77_Extract_Data(uint8_t InputDataMatrix[8][16], uint8_t DMRDataExtracted[77])
|
||||
{
|
||||
uint32_t i, j, k;
|
||||
uint8_t DataMatrix[8][16];
|
||||
uint8_t LineUncorrected[16];
|
||||
uint8_t LineCorrected[11];
|
||||
uint32_t HammingIrrecoverableErrorNb = 0;
|
||||
uint32_t ParityCheckErrorNb = 0;
|
||||
uint32_t NbOfOne;
|
||||
|
||||
/* First step : Reconstitute the BPTC 16x8 matrix */
|
||||
for(i = 0; i < 8; i++)
|
||||
{
|
||||
for(j = 0; j < 16; j++)
|
||||
{
|
||||
/* Only the LSBit of the byte is stored */
|
||||
DataMatrix[i][j] = (InputDataMatrix[i][j] & 1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Init the Hamming (16,11,4) library
|
||||
* Not needed because it has already been done
|
||||
* in the "InitAllFecFunction()" function */
|
||||
//Hamming_16_11_4_init();
|
||||
|
||||
/* Process the the Hamming (16,11,4) code
|
||||
* check on each line.
|
||||
* Do not check the last line (line nb 8) */
|
||||
for(i = 0; i < 7; i++)
|
||||
{
|
||||
/* Get a full line */
|
||||
for(j = 0; j < 16; j++)
|
||||
{
|
||||
LineUncorrected[j] = DataMatrix[i][j];
|
||||
}
|
||||
|
||||
/* Apply Hamming (16,11,4) code correction */
|
||||
if(Hamming_16_11_4_decode(LineUncorrected, LineCorrected, 1) == false)
|
||||
{
|
||||
HammingIrrecoverableErrorNb++;
|
||||
}
|
||||
|
||||
/* Re-inject the line in the matrix (only the util data [11 bit],
|
||||
* not the Hamming part [4 bit]) */
|
||||
for(j = 0; j < 11; j++)
|
||||
{
|
||||
DataMatrix[i][j] = LineCorrected[j];
|
||||
}
|
||||
}
|
||||
|
||||
/* Extract the DMR data (77 bit) from the matrix */
|
||||
k = 0;
|
||||
|
||||
/* 2 first lines */
|
||||
for(i = 0; i < 2; i++)
|
||||
{
|
||||
for(j = 0; j < 11; j++)
|
||||
{
|
||||
DMRDataExtracted[k] = DataMatrix[i][j];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
/* 5 Next lines */
|
||||
for(i = 2; i < 7; i++)
|
||||
{
|
||||
for(j = 0; j < 10; j++)
|
||||
{
|
||||
DMRDataExtracted[k] = DataMatrix[i][j];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
/* 5 bit of CRC */
|
||||
for(i = 2; i < 7; i++)
|
||||
{
|
||||
DMRDataExtracted[k] = DataMatrix[i][10];
|
||||
k++;
|
||||
}
|
||||
|
||||
/* Verify the data integrity by checking
|
||||
* all column parity bit */
|
||||
ParityCheckErrorNb = 0;
|
||||
for(i = 0; i < 16; i++)
|
||||
{
|
||||
NbOfOne = 0;
|
||||
|
||||
/* Get a full column */
|
||||
for(j = 0; j < 7; j++)
|
||||
{
|
||||
NbOfOne += DataMatrix[j][i];
|
||||
}
|
||||
|
||||
/* Check the parity bit (number of "1"
|
||||
* must be even) */
|
||||
if((NbOfOne % 2) != DataMatrix[7][i])
|
||||
{
|
||||
ParityCheckErrorNb++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the number of irrecoverable Hamming errors +
|
||||
* the number of parity check error */
|
||||
return (HammingIrrecoverableErrorNb + ParityCheckErrorNb);
|
||||
} /* End BPTC_128x77_Extract_Data() */
|
||||
|
||||
|
||||
/*
|
||||
* @brief : This function extract the 32 bits of a deinteleaved 32 bits
|
||||
* buffer using Reverse Channel Single Burst BPTC.
|
||||
*
|
||||
* @note : See DMR standard ETSI TS 102 361-1 chapter B.2.2.2 for details
|
||||
*
|
||||
* @param InputInterleavedData : Pointer of DMR input data interleaved (32 bytes
|
||||
act as a 16 x 2 bits data matrix)
|
||||
*
|
||||
* @param DMRDataExtracted : Pointer where the DMR data will be written (77 bytes)
|
||||
* DMRDataExtracted[0..10] = Util data (Hamming corrected)
|
||||
* DMRDataExtracted[11..15] = Hamming data
|
||||
* DMRDataExtracted[16..31] = 16 bits of odd parity (to be checked)
|
||||
*
|
||||
* @param ParityCheckTypeOdd : 0 = Parity to check is even (used in Non-Reverse Channel Single Burst BPTC)
|
||||
* 1 = Parity to check is odd (used in Reverse Channel Single Burst BPTC)
|
||||
*
|
||||
* @return 0 = All is OK
|
||||
* Other = Error - Irrecoverable Hamming parity check error number
|
||||
*/
|
||||
uint32_t BPTC_16x2_Extract_Data(uint8_t InputInterleavedData[32], uint8_t DMRDataExtracted[32], uint32_t ParityCheckTypeOdd)
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t DataMatrix[32];
|
||||
uint8_t LineUncorrected[16];
|
||||
uint8_t LineCorrected[11];
|
||||
uint32_t HammingIrrecoverableErrorNb = 0;
|
||||
uint32_t ParityCheckOddErrorNb = 0;
|
||||
uint32_t ParityCheckEvenErrorNb = 0;
|
||||
|
||||
//TODO: make this so we can load either rc interleave, or single burst interleave
|
||||
for(i = 0; i < 32; i++)
|
||||
{
|
||||
DataMatrix[DeInterleaveReverseChannelBptcPlacement[DeInterleaveReverseChannelBptc[i]]] = InputInterleavedData[i] & 1;
|
||||
}
|
||||
|
||||
/* Copy the entire input buffer to the output buffer */
|
||||
for(i = 0; i < 32; i++)
|
||||
{
|
||||
DMRDataExtracted[i] = DataMatrix[i] & 1;
|
||||
}
|
||||
|
||||
/* Prepare the line to be corrected */
|
||||
for(i = 0; i < 16; i++)
|
||||
{
|
||||
LineUncorrected[i] = DataMatrix[i] & 1;
|
||||
}
|
||||
|
||||
/* Apply Hamming (16,11,4) code correction */
|
||||
if(Hamming_16_11_4_decode(LineUncorrected, LineCorrected, 1) == false)
|
||||
{
|
||||
HammingIrrecoverableErrorNb++;
|
||||
}
|
||||
|
||||
/* Copy the corrected content to the output buffer */
|
||||
for(i = 0; i < 11; i++)
|
||||
{
|
||||
DMRDataExtracted[i] = LineCorrected[i] & 1;
|
||||
}
|
||||
|
||||
/* Check Parity bits */
|
||||
for(i = 0; i < 16; i++)
|
||||
{
|
||||
/* Odd parity ==> If data = 1 then parity = 0
|
||||
* If data = 0 then parity = 1 */
|
||||
if((DMRDataExtracted[i] & 1) == (DMRDataExtracted[i + 16] & 1)) ParityCheckOddErrorNb++;
|
||||
if((DMRDataExtracted[i] & 1) != (DMRDataExtracted[i + 16] & 1)) ParityCheckEvenErrorNb++;
|
||||
}
|
||||
|
||||
//fprintf(stderr, "Hamming ERR=%u ; Parity odd ERR=%u, Parity even ERR=%u, ", HammingIrrecoverableErrorNb, ParityCheckOddErrorNb, ParityCheckEvenErrorNb);
|
||||
|
||||
//fprintf(stderr, "Content =\n");
|
||||
//for(i = 0; i < 32; i++)
|
||||
//{
|
||||
// fprintf(stderr, "%u", DMRDataExtracted[i] & 1);
|
||||
// if((i == 15) || (i == 31)) fprintf(stderr, "\n");
|
||||
// else fprintf(stderr, "-");
|
||||
//}
|
||||
|
||||
/* Return the number of irrecoverable Hamming errors +
|
||||
* the number of parity check error */
|
||||
if(ParityCheckTypeOdd) return (HammingIrrecoverableErrorNb + ParityCheckOddErrorNb);
|
||||
else return (HammingIrrecoverableErrorNb + ParityCheckEvenErrorNb);
|
||||
|
||||
} /* End BPTC_16x2_Extract_Data() */
|
||||
|
||||
|
||||
|
||||
/* End of file */
|
||||
214
src/dmr_34.c
Normal file
214
src/dmr_34.c
Normal file
@@ -0,0 +1,214 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* dmr_34.c
|
||||
* DMR (and P25) 3/4 Rate Simple Trellis Decoder
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2023-12 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#include "dsd.h"
|
||||
|
||||
uint8_t interleave[98] = {
|
||||
0, 1, 8, 9, 16, 17, 24, 25, 32, 33, 40, 41, 48, 49, 56, 57, 64, 65, 72, 73, 80, 81, 88, 89, 96, 97,
|
||||
2, 3, 10, 11, 18, 19, 26, 27, 34, 35, 42, 43, 50, 51, 58, 59, 66, 67, 74, 75, 82, 83, 90, 91,
|
||||
4, 5, 12, 13, 20, 21, 28, 29, 36, 37, 44, 45, 52, 53, 60, 61, 68, 69, 76, 77, 84, 85, 92, 93,
|
||||
6, 7, 14, 15, 22, 23, 30, 31, 38, 39, 46, 47, 54, 55, 62, 63, 70, 71, 78, 79, 86, 87, 94, 95};
|
||||
|
||||
//this is a convertion table for converting the dibit pairs into constellation points
|
||||
uint8_t constellation_map[16] = {
|
||||
11, 12, 0, 7, 14, 9, 5, 2, 10, 13, 1, 6, 15, 8, 4, 3
|
||||
};
|
||||
|
||||
//digitized dibit to OTA symbol conversion for reference
|
||||
//0 = +1; 1 = +3;
|
||||
//2 = -1; 3 = -3;
|
||||
|
||||
//finite state machine values
|
||||
uint8_t fsm[64] = {
|
||||
0, 8, 4, 12, 2, 10, 6, 14,
|
||||
4, 12, 2, 10, 6, 14, 0, 8,
|
||||
1, 9, 5, 13, 3, 11, 7, 15,
|
||||
5, 13, 3, 11, 7, 15, 1, 9,
|
||||
3, 11, 7, 15, 1, 9, 5, 13,
|
||||
7, 15, 1, 9, 5, 13, 3, 11,
|
||||
2, 10, 6, 14, 0, 8, 4, 12,
|
||||
6, 14, 0, 8, 4, 12, 2, 10};
|
||||
|
||||
//attempt to find the surviving path, or the 'best' path available (most positions gained)
|
||||
uint8_t fix_34(uint8_t * p, uint8_t state, int position)
|
||||
{
|
||||
int i, j, k, counter, best_p, best_v, survivors;
|
||||
uint8_t temp_s, tri, t;
|
||||
|
||||
//status of surviving paths -- debug
|
||||
int s[8];
|
||||
memset (s, 0, 8*sizeof(int));
|
||||
|
||||
//assign all potentially correct points to temporary storage
|
||||
uint8_t temp_p[8];
|
||||
temp_p[0] = (p[position] ^ 1) & 0xF;
|
||||
temp_p[1] = (p[position] ^ 3) & 0xF;
|
||||
temp_p[2] = (p[position] ^ 5) & 0xF;
|
||||
temp_p[3] = (p[position] ^ 7) & 0xF;
|
||||
temp_p[4] = (p[position] ^ 9) & 0xF;
|
||||
temp_p[5] = (p[position] ^ 11) & 0xF;
|
||||
temp_p[6] = (p[position] ^ 13) & 0xF;
|
||||
temp_p[7] = (p[position] ^ 15) & 0xF;
|
||||
|
||||
best_p = 0; //best position
|
||||
best_v = 0; //best path value
|
||||
|
||||
for (k = 0; k < 8; k++)
|
||||
{
|
||||
temp_s = state;
|
||||
counter = 0;
|
||||
tri = 0;
|
||||
for (i = position; i < 49; i++)
|
||||
{
|
||||
//assign temp t either as our temp_p, or next point of i
|
||||
if (i == position) t = temp_p[k];
|
||||
else t = p[i];
|
||||
|
||||
if (tri != 0xFF) //while the path survives
|
||||
{
|
||||
tri = 0xFF;
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
if ( fsm[(temp_s*8)+j] == t )
|
||||
{
|
||||
//return our tribit value and state for the next point
|
||||
tri = temp_s = (uint8_t)j;
|
||||
counter++;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (counter > best_p)
|
||||
{
|
||||
best_p = counter;
|
||||
best_v = k; //if we make it further on current path, assign as best path
|
||||
}
|
||||
|
||||
// surviving path -- made it to 49
|
||||
if (i == 48) s[k] = 1;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//NOTE: If there are no surviving paths, then that means there is another bit/point err
|
||||
//Ideally, at the end of a single or multiple fixes, there should only be one survivor, but in practice,
|
||||
//I've seen up to 4 surviving paths and somehow, get a good CRC and a good LRRP or LOCN decode
|
||||
//multiple survivors seems common when the starting err position is very close to 49
|
||||
|
||||
//tally number of surviving paths
|
||||
survivors = 0;
|
||||
for (k = 0; k < 8; k++)
|
||||
{
|
||||
if (s[k] == 1) survivors++;
|
||||
}
|
||||
|
||||
//debug
|
||||
// fprintf (stderr, "START: %d; BEST_P: %d; BEST_V: %d; Survivors: %d; Point: %d; ", position, best_p, best_v, survivors, temp_p[best_v]);
|
||||
|
||||
return temp_p[best_v]; //return the point value of the best path's starting point value
|
||||
}
|
||||
|
||||
uint32_t dmr_34(uint8_t * input, uint8_t treturn[18])
|
||||
{
|
||||
int i, j;
|
||||
uint32_t irr_err = 0; //irrecoverable errors
|
||||
|
||||
uint8_t deinterleaved_dibits[98];
|
||||
memset (deinterleaved_dibits, 0, sizeof(deinterleaved_dibits));
|
||||
|
||||
//deinterleave our input dibits
|
||||
for (i = 0; i < 98; i++)
|
||||
deinterleaved_dibits[interleave[i]] = input[i];
|
||||
|
||||
//pack the input into nibbles (dibit pairs)
|
||||
uint8_t nibs[49];
|
||||
memset (nibs, 0, sizeof(nibs));
|
||||
|
||||
for (i = 0; i < 49; i++)
|
||||
nibs[i] = (deinterleaved_dibits[i*2+0] << 2) | (deinterleaved_dibits[i*2+1] << 0);
|
||||
|
||||
//convert our dibit pairs into constellation point values
|
||||
uint8_t point[49];
|
||||
memset (point, 0xFF, sizeof(point));
|
||||
|
||||
for (i = 0; i < 49; i++)
|
||||
point[i] = constellation_map[nibs[i]];
|
||||
|
||||
//debug view points
|
||||
// fprintf (stderr, "\n P =");
|
||||
// for (i = 0; i < 49; i++)
|
||||
// fprintf (stderr, " %02d", point[i]);
|
||||
|
||||
//convert constellation points into tribit values using the FSM
|
||||
uint8_t state = 0;
|
||||
uint32_t tribits[49];
|
||||
memset (tribits, 0xF, sizeof(tribits));
|
||||
|
||||
for (i = 0; i < 49; i++)
|
||||
{
|
||||
|
||||
for (j = 0; j < 8; j++)
|
||||
{
|
||||
if ( fsm[(state*8)+j] == point[i] )
|
||||
{
|
||||
//return our tribit value and state for the next point
|
||||
tribits[i] = state = (uint8_t)j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//if tribit value is greater than 7, then we have a decoding error
|
||||
if (tribits[i] > 7)
|
||||
{
|
||||
irr_err++; //tally number of errors
|
||||
|
||||
//debug point, position of error, and state value
|
||||
// fprintf (stderr, "\n P: %d, %d:%d; ", point[i], i, state);
|
||||
|
||||
//attempt to fix point by looking for the best path from here
|
||||
point[i] = fix_34(point, state, i);
|
||||
|
||||
//Make a hard decision and flip point to fit in current state
|
||||
// point[i] ^= 7; //lucky number 7 (0111) //fallback
|
||||
|
||||
//decrement one and resume decoding
|
||||
i--;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//debug view tribits/states
|
||||
// fprintf (stderr, "\n T =");
|
||||
// for (i = 0; i < 49; i++)
|
||||
// fprintf (stderr, " %02d", tribits[i]);
|
||||
|
||||
//convert tribits into a return payload
|
||||
uint32_t temp = 0;
|
||||
|
||||
//break into chunks of 24 bit values and shuffle into 8-bit (byte) treturn values
|
||||
for (i = 0; i < 6; i++)
|
||||
{
|
||||
temp = (tribits[(i*8)+0] << 21) + (tribits[(i*8)+1] << 18) + (tribits[(i*8)+2] << 15) + (tribits[(i*8)+3] << 12) +
|
||||
(tribits[(i*8)+4] << 9) + (tribits[(i*8)+5] << 6) + (tribits[(i*8)+6] << 3) + (tribits[(i*8)+7] << 0);
|
||||
|
||||
treturn[(i*3)+0] = (temp >> 16) & 0xFF;
|
||||
treturn[(i*3)+1] = (temp >> 8) & 0xFF;
|
||||
treturn[(i*3)+2] = (temp >> 0) & 0xFF;
|
||||
}
|
||||
|
||||
//trellis point/state err tally
|
||||
// if (irr_err != 0)
|
||||
// fprintf (stderr, " P_ERR = %d", irr_err);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
1041
src/dmr_block.c
Normal file
1041
src/dmr_block.c
Normal file
File diff suppressed because it is too large
Load Diff
875
src/dmr_bs.c
Normal file
875
src/dmr_bs.c
Normal file
@@ -0,0 +1,875 @@
|
||||
/*-------------------------------------------------------------------------------
|
||||
* dmr_bs.c
|
||||
* DMR BS Voice Handling and Data Gathering Routines - "DMR STEREO"
|
||||
*
|
||||
* LWVMOBILE
|
||||
* 2022-12 DSD-FME Florida Man Edition
|
||||
*-----------------------------------------------------------------------------*/
|
||||
|
||||
#include "dsd.h"
|
||||
#include "dmr_const.h"
|
||||
|
||||
//A subroutine for processing each TDMA frame individually to allow for
|
||||
//processing voice and/or data on both BS slots (channels) simultaneously
|
||||
void dmrBS (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
int i, dibit;
|
||||
|
||||
char ambe_fr[4][24];
|
||||
char ambe_fr2[4][24];
|
||||
char ambe_fr3[4][24];
|
||||
|
||||
//redundancy check (carrier signal loss event)
|
||||
char redundancyA[36];
|
||||
char redundancyB[36];
|
||||
|
||||
//memcpy of ambe_fr for late entry
|
||||
uint8_t m1[4][24];
|
||||
uint8_t m2[4][24];
|
||||
uint8_t m3[4][24];
|
||||
|
||||
const int *w, *x, *y, *z;
|
||||
char sync[25];
|
||||
char syncdata[48];
|
||||
unsigned char EmbeddedSignalling[16];
|
||||
|
||||
uint8_t emb_ok = 0;
|
||||
uint8_t tact_okay = 0;
|
||||
uint8_t cach_err = 0;
|
||||
UNUSED(cach_err);
|
||||
|
||||
uint8_t internalslot;
|
||||
uint8_t vc1;
|
||||
uint8_t vc2;
|
||||
|
||||
//assign as nonsensical numbers
|
||||
uint8_t cc = 25;
|
||||
uint8_t power = 9; //power and pre-emption indicator
|
||||
uint8_t lcss = 9;
|
||||
UNUSED2(cc, lcss);
|
||||
|
||||
//would be ideal to grab all dibits and break them into bits to pass to new data handler?
|
||||
uint8_t dummy_bits[196];
|
||||
memset (dummy_bits, 0, sizeof(dummy_bits));
|
||||
|
||||
//add time to mirror printFrameSync
|
||||
char * getTime(void) //get pretty hh:mm:ss timestamp
|
||||
{
|
||||
time_t t = time(NULL);
|
||||
|
||||
char * curr;
|
||||
char * stamp = asctime(localtime( & t));
|
||||
|
||||
curr = strtok(stamp, " ");
|
||||
curr = strtok(NULL, " ");
|
||||
curr = strtok(NULL, " ");
|
||||
curr = strtok(NULL, " ");
|
||||
|
||||
return curr;
|
||||
}
|
||||
|
||||
//Init slot lights
|
||||
sprintf (state->slot1light, " slot1 ");
|
||||
sprintf (state->slot2light, " slot2 ");
|
||||
|
||||
//Init the color code status
|
||||
state->color_code_ok = 0;
|
||||
|
||||
vc1 = 2;
|
||||
vc2 = 2;
|
||||
|
||||
short int loop = 1;
|
||||
short int skipcount = 0;
|
||||
|
||||
//cach
|
||||
uint8_t cachdata[25];
|
||||
int cachInterleave[24] =
|
||||
{0, 7, 8, 9, 1, 10,
|
||||
11, 12, 2, 13, 14,
|
||||
15, 3, 16, 4, 17, 18,
|
||||
19, 5, 20, 21, 22, 6, 23
|
||||
};
|
||||
|
||||
//cach tact bits
|
||||
uint8_t tact_bits[7];
|
||||
|
||||
//Run Loop while the getting is good
|
||||
while (loop == 1) {
|
||||
|
||||
if (exitflag == 1)
|
||||
{
|
||||
cleanupAndExit (opts, state);
|
||||
}
|
||||
|
||||
memset (ambe_fr, 0, sizeof(ambe_fr));
|
||||
memset (ambe_fr2, 0, sizeof(ambe_fr2));
|
||||
memset (ambe_fr3, 0, sizeof(ambe_fr3));
|
||||
|
||||
internalslot = -1; //reset here so we know if this value is being set properly
|
||||
for(i = 0; i < 12; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
state->dmr_stereo_payload[i] = dibit;
|
||||
|
||||
cachdata[cachInterleave[(i*2)]] = (1 & (dibit >> 1)); // bit 1
|
||||
cachdata[cachInterleave[(i*2)+1]] = (1 & dibit); // bit 0
|
||||
}
|
||||
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
tact_bits[i] = cachdata[i];
|
||||
}
|
||||
|
||||
//disabled for dmr_cach testing
|
||||
tact_okay = 0;
|
||||
if ( Hamming_7_4_decode (tact_bits) ) tact_okay = 1;
|
||||
if (tact_okay != 1) goto END;
|
||||
|
||||
|
||||
internalslot = state->currentslot = tact_bits[1];
|
||||
|
||||
//Setup for first AMBE Frame
|
||||
//Interleave Schedule
|
||||
w = rW;
|
||||
x = rX;
|
||||
y = rY;
|
||||
z = rZ;
|
||||
|
||||
//First AMBE Frame, Full 36
|
||||
for(i = 0; i < 36; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
state->dmr_stereo_payload[i+12] = dibit;
|
||||
redundancyA[i] = dibit;
|
||||
|
||||
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
|
||||
}
|
||||
|
||||
//check for repetitive data if caught in a 'no carrier' loop? Just picking random values.
|
||||
//this will test for no carrier (input signal) and return us to no sync state if necessary
|
||||
if (redundancyA[16] == redundancyB[16] && redundancyA[27] == redundancyB[27] &&
|
||||
redundancyA[01] == redundancyB[01] && redundancyA[32] == redundancyB[32] &&
|
||||
redundancyA[03] == redundancyB[03] && redundancyA[33] == redundancyB[33] &&
|
||||
redundancyA[13] == redundancyB[13] && redundancyA[07] == redundancyB[07] )
|
||||
{
|
||||
goto END;
|
||||
}
|
||||
|
||||
//end redundancy test, set B to A
|
||||
memcpy (redundancyB, redundancyA, sizeof (redundancyA));
|
||||
|
||||
//Setup for Second AMBE Frame
|
||||
//Interleave Schedule
|
||||
w = rW;
|
||||
x = rX;
|
||||
y = rY;
|
||||
z = rZ;
|
||||
|
||||
//Second AMBE Frame, First Half 18 dibits just before Sync or EmbeddedSignalling
|
||||
for(i = 0; i < 18; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
state->dmr_stereo_payload[i+48] = dibit;
|
||||
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
|
||||
}
|
||||
|
||||
//signaling data or sync
|
||||
for(i = 0; i < 24; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
state->dmr_stereo_payload[i+66] = dibit;
|
||||
sync[i] = (dibit | 1) + 48; //how does this work again?
|
||||
|
||||
syncdata[(2*i)] = (1 & (dibit >> 1)); // bit 1
|
||||
syncdata[(2*i)+1] = (1 & dibit); // bit 0
|
||||
|
||||
//embedded link control
|
||||
if(internalslot == 0 && vc1 > 1 && vc1 < 7) //grab on vc1 values 2-5 B C D and E
|
||||
{
|
||||
state->dmr_embedded_signalling[internalslot][vc1-1][i*2] = (1 & (dibit >> 1)); // bit 1
|
||||
state->dmr_embedded_signalling[internalslot][vc1-1][i*2+1] = (1 & dibit); // bit 0
|
||||
}
|
||||
|
||||
if(internalslot == 1 && vc2 > 1 && vc2 < 7) //grab on vc2 values 2-5 B C D and E
|
||||
{
|
||||
state->dmr_embedded_signalling[internalslot][vc2-1][i*2] = (1 & (dibit >> 1)); // bit 1
|
||||
state->dmr_embedded_signalling[internalslot][vc2-1][i*2+1] = (1 & dibit); // bit 0
|
||||
}
|
||||
|
||||
}
|
||||
sync[24] = 0;
|
||||
|
||||
for(i = 0; i < 8; i++) EmbeddedSignalling[i] = syncdata[i];
|
||||
for(i = 0; i < 8; i++) EmbeddedSignalling[i + 8] = syncdata[i + 40];
|
||||
|
||||
//Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling
|
||||
for(i = 0; i < 18; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
state->dmr_stereo_payload[i+90] = dibit;
|
||||
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
|
||||
}
|
||||
|
||||
//Setup for Third AMBE Frame
|
||||
//Interleave Schedule
|
||||
w = rW;
|
||||
x = rX;
|
||||
y = rY;
|
||||
z = rZ;
|
||||
|
||||
//Third AMBE Frame, Full 36
|
||||
for(i = 0; i < 36; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
state->dmr_stereo_payload[i+108] = dibit;
|
||||
ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr3[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
|
||||
}
|
||||
|
||||
//reset vc counters to 1 if new voice sync frame on each slot
|
||||
if ( strcmp (sync, DMR_BS_VOICE_SYNC) == 0)
|
||||
{
|
||||
if (internalslot == 0) vc1 = 1;
|
||||
if (internalslot == 1) vc2 = 1;
|
||||
}
|
||||
|
||||
//check for sync pattern here after collected the rest of the payload, decide what to do with it
|
||||
if ( strcmp (sync, DMR_BS_DATA_SYNC) == 0 )
|
||||
{
|
||||
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
if (internalslot == 0)
|
||||
{
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr,"Sync: +DMR ");
|
||||
}
|
||||
else fprintf (stderr,"Sync: -DMR ");
|
||||
|
||||
vc1 = 1;
|
||||
|
||||
//close MBEout file - slot 1
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
}
|
||||
if (internalslot == 1)
|
||||
{
|
||||
if (opts->inverted_dmr == 0)
|
||||
{
|
||||
fprintf (stderr,"Sync: +DMR ");
|
||||
}
|
||||
else fprintf (stderr,"Sync: -DMR ");
|
||||
|
||||
vc2 = 1;
|
||||
|
||||
//close MBEout file - slot 2
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
|
||||
}
|
||||
dmr_data_sync (opts, state);
|
||||
skipcount++;
|
||||
goto SKIP;
|
||||
}
|
||||
|
||||
//only play voice on no data sync
|
||||
if (strcmp (sync, DMR_BS_DATA_SYNC) != 0) //we already have a tact ecc check, so we won't get here without that, see if there is any other eccs we can run just to make sure
|
||||
{
|
||||
|
||||
//check the embedded signalling, if bad at this point, we probably aren't quite in sync
|
||||
if(QR_16_7_6_decode(EmbeddedSignalling)) emb_ok = 1;
|
||||
else emb_ok = 0;
|
||||
|
||||
//disable the goto END; if this causes more problems than fixing on late entry dual voices i.e., lots of forced resyncs
|
||||
if ( (strcmp (sync, DMR_BS_VOICE_SYNC) != 0) && emb_ok == 0) goto END; //fprintf (stderr, "EMB BAD? ");
|
||||
else if (emb_ok == 1)
|
||||
{
|
||||
cc = ((EmbeddedSignalling[0] << 3) + (EmbeddedSignalling[1] << 2) + (EmbeddedSignalling[2] << 1) + EmbeddedSignalling[3]);
|
||||
power = EmbeddedSignalling[4];
|
||||
lcss = ((EmbeddedSignalling[5] << 1) + EmbeddedSignalling[6]);
|
||||
}
|
||||
|
||||
|
||||
skipcount = 0; //reset skip count if processing voice frames
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
|
||||
//simplifying things
|
||||
char polarity[3];
|
||||
char light[18];
|
||||
uint8_t vc;
|
||||
if (internalslot == 0)
|
||||
{
|
||||
state->dmrburstL = 16;
|
||||
vc = vc1;
|
||||
sprintf (light, "%s", " [SLOT1] slot2 ");
|
||||
//open MBEout file - slot 1
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
state->dmrburstR = 16;
|
||||
vc = vc2;
|
||||
sprintf (light, "%s", " slot1 [SLOT2] ");
|
||||
//open MBEout file - slot 2
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_fR == NULL)) openMbeOutFileR (opts, state);
|
||||
}
|
||||
if (opts->inverted_dmr == 0) sprintf (polarity, "%s", "+");
|
||||
else sprintf (polarity, "%s", "-");
|
||||
|
||||
fprintf (stderr,"Sync: %sDMR %s| Color Code=%02d | VC%d ", polarity, light, state->dmr_color_code, vc);
|
||||
|
||||
if (internalslot == 0 && vc1 == 6)
|
||||
{
|
||||
//process embedded link control
|
||||
fprintf (stderr, "\n");
|
||||
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
||||
//check the single burst/reverse channel opportunity -- moved
|
||||
// dmr_sbrc (opts, state, power);
|
||||
|
||||
}
|
||||
|
||||
if (internalslot == 1 && vc2 == 6)
|
||||
{
|
||||
//process embedded link control
|
||||
fprintf (stderr, "\n");
|
||||
dmr_data_burst_handler(opts, state, (uint8_t *)dummy_bits, 0xEB);
|
||||
//check the single burst/reverse channel opportunity -- moved
|
||||
// dmr_sbrc (opts, state, power);
|
||||
|
||||
}
|
||||
|
||||
if (opts->payload == 1) fprintf (stderr, "\n"); //extra line break necessary here
|
||||
|
||||
//copy ambe_fr frames first, running process mbe will correct them,
|
||||
//but this also leads to issues extracting good le mi values when
|
||||
//we go to do correction on them there too
|
||||
memcpy (m1, ambe_fr, sizeof(m1));
|
||||
memcpy (m2, ambe_fr2, sizeof(m2));
|
||||
memcpy (m3, ambe_fr3, sizeof(m3));
|
||||
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
if(internalslot == 0)
|
||||
{
|
||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
||||
memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
memcpy(state->f_r4[0], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
||||
memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r));
|
||||
memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru));
|
||||
}
|
||||
|
||||
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
if(internalslot == 0)
|
||||
{
|
||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
||||
memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
memcpy(state->f_r4[1], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
||||
memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r));
|
||||
memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru));
|
||||
}
|
||||
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
if(internalslot == 0)
|
||||
{
|
||||
memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
||||
memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
||||
memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
memcpy(state->f_r4[2], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
||||
memcpy(state->s_r4[2], state->s_r, sizeof(state->s_r));
|
||||
memcpy(state->s_r4u[2], state->s_ru, sizeof(state->s_ru));
|
||||
}
|
||||
|
||||
|
||||
//run sbrc here to look for the late entry key and alg after we observe potential errors in VC6
|
||||
if (internalslot == 0 && vc1 == 6) dmr_sbrc (opts, state, power);
|
||||
if (internalslot == 1 && vc2 == 6) dmr_sbrc (opts, state, power);
|
||||
|
||||
cach_err = dmr_cach (opts, state, cachdata);
|
||||
if (opts->payload == 0) fprintf (stderr, "\n");
|
||||
|
||||
// run alg refresh after vc6 ambe processing
|
||||
if (internalslot == 0 && vc1 == 6) dmr_alg_refresh (opts, state);
|
||||
if (internalslot == 1 && vc2 == 6) dmr_alg_refresh (opts, state);
|
||||
|
||||
dmr_late_entry_mi_fragment (opts, state, vc, m1, m2, m3);
|
||||
|
||||
//increment the vc counters
|
||||
if (internalslot == 0) vc1++;
|
||||
if (internalslot == 1) vc2++;
|
||||
|
||||
//update cc amd vc sync time for trunking purposes (particularly Con+)
|
||||
if (opts->p25_is_tuned == 1)
|
||||
{
|
||||
state->last_vc_sync_time = time(NULL);
|
||||
state->last_cc_sync_time = time(NULL);
|
||||
}
|
||||
|
||||
//'DSP' output to file
|
||||
if (opts->use_dsp_output == 1)
|
||||
{
|
||||
FILE * pFile; //file pointer
|
||||
pFile = fopen (opts->dsp_out_file, "a");
|
||||
fprintf (pFile, "\n%d 98 ", internalslot+1); //'98' is CACH designation value
|
||||
for (i = 0; i < 6; i++) //3 byte CACH
|
||||
{
|
||||
int cach_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
|
||||
fprintf (pFile, "%X", cach_byte);
|
||||
}
|
||||
fprintf (pFile, "\n%d 10 ", internalslot+1); //0x10 for voice burst
|
||||
for (i = 6; i < 72; i++) //33 bytes, no CACH
|
||||
{
|
||||
int dsp_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
|
||||
fprintf (pFile, "%X", dsp_byte);
|
||||
}
|
||||
fclose (pFile);
|
||||
}
|
||||
|
||||
//reset err checks
|
||||
cach_err = 1;
|
||||
tact_okay = 0;
|
||||
emb_ok = 0;
|
||||
|
||||
//reset emb components
|
||||
cc = 25;
|
||||
power = 9;
|
||||
lcss = 9;
|
||||
|
||||
//Extra safeguards to break loop
|
||||
// if ( (vc1 > 7 && vc2 > 7) ) goto END;
|
||||
if ( (vc1 > 14 || vc2 > 14) ) goto END;
|
||||
|
||||
}
|
||||
|
||||
SKIP:
|
||||
|
||||
//both working now, will need support added for ENC audio and no key
|
||||
//NOTE: We want this to play regardless of whether the slot is voice or data, to play silence in one slot and voice in the second, or voices in both
|
||||
if (internalslot == 1 && opts->floating_point == 1 && opts->pulse_digi_rate_out == 8000)
|
||||
playSynthesizedVoiceFS3 (opts, state); //Float Stereo Mix 3v2
|
||||
if (internalslot == 1 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000)
|
||||
playSynthesizedVoiceSS3 (opts, state); //Short Stereo Mix 3v2
|
||||
|
||||
if (skipcount > 3) //after 3 onsecutive data frames, drop back to getFrameSync and process with dmr_data_sync (need one more in order to push last voice on slot 2 only voice)
|
||||
{
|
||||
//set tests to all good so we don't get a bogus/redundant voice error
|
||||
cach_err = 0;
|
||||
tact_okay = 1;
|
||||
emb_ok = 1;
|
||||
goto END;
|
||||
}
|
||||
|
||||
//since we are in a while loop, run ncursesPrinter here.
|
||||
if (opts->use_ncurses_terminal == 1)
|
||||
{
|
||||
ncursesPrinter(opts, state);
|
||||
}
|
||||
|
||||
} // while loop
|
||||
|
||||
END:
|
||||
state->dmr_stereo = 0;
|
||||
state->errs = 0;
|
||||
state->errs2 = 0;
|
||||
state->errs2R = 0;
|
||||
state->errs2 = 0;
|
||||
|
||||
//close any open MBEout files
|
||||
if (opts->mbe_out_f != NULL) closeMbeOutFile (opts, state);
|
||||
if (opts->mbe_out_fR != NULL) closeMbeOutFileR (opts, state);
|
||||
|
||||
//clear out any stale audio storage buffers
|
||||
memset (state->f_l4, 0.0f, sizeof(state->f_l4));
|
||||
memset (state->f_r4, 0.0f, sizeof(state->f_r4));
|
||||
memset (state->s_l4, 0, sizeof(state->s_l4));
|
||||
memset (state->s_r4, 0, sizeof(state->s_r4));
|
||||
|
||||
//if we have a tact or emb err, then produce sync pattern/err message
|
||||
if (tact_okay != 1 || emb_ok != 1)
|
||||
{
|
||||
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
fprintf (stderr,"Sync: DMR ");
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, "| VOICE CACH/EMB ERR");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
fprintf (stderr, "\n");
|
||||
//run refresh if either slot had an active MI in it.
|
||||
if (state->payload_algid >= 0x21)
|
||||
{
|
||||
state->currentslot = 0;
|
||||
dmr_alg_refresh (opts, state);
|
||||
}
|
||||
if (state->payload_algidR >= 0x21)
|
||||
{
|
||||
state->currentslot = 1;
|
||||
dmr_alg_refresh (opts, state);
|
||||
}
|
||||
|
||||
//failsafe to reset all data header and blocks when bad tact or emb
|
||||
dmr_reset_blocks (opts, state);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Process buffered half frame and 2nd half and then jump to full BS decoding
|
||||
void dmrBSBootstrap (dsd_opts * opts, dsd_state * state)
|
||||
{
|
||||
int i, dibit;
|
||||
int *dibit_p;
|
||||
char ambe_fr[4][24];
|
||||
char ambe_fr2[4][24];
|
||||
char ambe_fr3[4][24];
|
||||
|
||||
memset (ambe_fr, 0, sizeof(ambe_fr));
|
||||
memset (ambe_fr2, 0, sizeof(ambe_fr2));
|
||||
memset (ambe_fr3, 0, sizeof(ambe_fr3));
|
||||
|
||||
//memcpy of ambe_fr for late entry
|
||||
uint8_t m1[4][24];
|
||||
uint8_t m2[4][24];
|
||||
uint8_t m3[4][24];
|
||||
|
||||
const int *w, *x, *y, *z;
|
||||
char sync[25];
|
||||
uint8_t tact_okay = 0;
|
||||
uint8_t cach_err = 0;
|
||||
uint8_t sync_okay = 1;
|
||||
UNUSED(cach_err);
|
||||
|
||||
uint8_t internalslot;
|
||||
|
||||
uint8_t cachdata[25];
|
||||
int cachInterleave[24] =
|
||||
{0, 7, 8, 9, 1, 10,
|
||||
11, 12, 2, 13, 14,
|
||||
15, 3, 16, 4, 17, 18,
|
||||
19, 5, 20, 21, 22, 6, 23
|
||||
};
|
||||
//add time to mirror printFrameSync
|
||||
char * getTime(void) //get pretty hh:mm:ss timestamp
|
||||
{
|
||||
time_t t = time(NULL);
|
||||
|
||||
char * curr;
|
||||
char * stamp = asctime(localtime( & t));
|
||||
|
||||
curr = strtok(stamp, " ");
|
||||
curr = strtok(NULL, " ");
|
||||
curr = strtok(NULL, " ");
|
||||
curr = strtok(NULL, " ");
|
||||
|
||||
return curr;
|
||||
}
|
||||
|
||||
//payload buffer
|
||||
//CACH + First Half Payload + Sync = 12 + 54 + 24
|
||||
dibit_p = state->dmr_payload_p - 90;
|
||||
for (i = 0; i < 90; i++) //90
|
||||
{
|
||||
dibit = *dibit_p;
|
||||
dibit_p++;
|
||||
if(opts->inverted_dmr == 1) dibit = (dibit ^ 2) & 3;
|
||||
state->dmr_stereo_payload[i] = dibit;
|
||||
}
|
||||
|
||||
for(i = 0; i < 12; i++)
|
||||
{
|
||||
dibit = state->dmr_stereo_payload[i];
|
||||
cachdata[cachInterleave[(i*2)]] = (1 & (dibit >> 1)); // bit 1
|
||||
cachdata[cachInterleave[(i*2)+1]] = (1 & dibit); // bit 0
|
||||
}
|
||||
|
||||
//cach tact bits
|
||||
uint8_t tact_bits[7];
|
||||
for (i = 0; i < 7; i++)
|
||||
{
|
||||
tact_bits[i] = cachdata[i];
|
||||
}
|
||||
|
||||
//decode and correct tact and compare
|
||||
if ( Hamming_7_4_decode (tact_bits) ) tact_okay = 1;
|
||||
if (tact_okay != 1) goto END;
|
||||
|
||||
internalslot = state->currentslot = tact_bits[1];
|
||||
|
||||
//Setup for first AMBE Frame
|
||||
|
||||
//Interleave Schedule
|
||||
w = rW;
|
||||
x = rX;
|
||||
y = rY;
|
||||
z = rZ;
|
||||
|
||||
//First AMBE Frame, Full 36
|
||||
for(i = 0; i < 36; i++)
|
||||
{
|
||||
dibit = state->dmr_stereo_payload[i+12];
|
||||
ambe_fr[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
|
||||
}
|
||||
|
||||
//Setup for Second AMBE Frame
|
||||
|
||||
//Interleave Schedule
|
||||
w = rW;
|
||||
x = rX;
|
||||
y = rY;
|
||||
z = rZ;
|
||||
|
||||
//Second AMBE Frame, First Half 18 dibits just before Sync or EmbeddedSignalling
|
||||
for(i = 0; i < 18; i++)
|
||||
{
|
||||
dibit = state->dmr_stereo_payload[i+48];
|
||||
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
|
||||
}
|
||||
|
||||
// signaling data or sync, just redo it
|
||||
for(i = 0; i < 24; i++)
|
||||
{
|
||||
dibit = state->dmr_stereo_payload[i+66];
|
||||
sync[i] = (dibit | 1) + 48;
|
||||
}
|
||||
sync[24] = 0;
|
||||
|
||||
if ( strcmp (sync, DMR_BS_VOICE_SYNC) != 0)
|
||||
{
|
||||
sync_okay = 0;
|
||||
goto END;
|
||||
}
|
||||
|
||||
//Continue Second AMBE Frame, 18 after Sync or EmbeddedSignalling
|
||||
for(i = 0; i < 18; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
state->dmr_stereo_payload[i+90] = dibit;
|
||||
ambe_fr2[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr2[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
|
||||
}
|
||||
|
||||
//Setup for Third AMBE Frame
|
||||
|
||||
//Interleave Schedule
|
||||
w = rW;
|
||||
x = rX;
|
||||
y = rY;
|
||||
z = rZ;
|
||||
|
||||
//Third AMBE Frame, Full 36
|
||||
for(i = 0; i < 36; i++)
|
||||
{
|
||||
dibit = getDibit(opts, state);
|
||||
state->dmr_stereo_payload[i+108] = dibit;
|
||||
ambe_fr3[*w][*x] = (1 & (dibit >> 1)); // bit 1
|
||||
ambe_fr3[*y][*z] = (1 & dibit); // bit 0
|
||||
|
||||
w++;
|
||||
x++;
|
||||
y++;
|
||||
z++;
|
||||
|
||||
}
|
||||
|
||||
//'DSP' output to file
|
||||
if (opts->use_dsp_output == 1)
|
||||
{
|
||||
FILE * pFile; //file pointer
|
||||
pFile = fopen (opts->dsp_out_file, "a");
|
||||
fprintf (pFile, "\n%d 98 ", internalslot+1); //'98' is CACH designation value
|
||||
for (i = 0; i < 6; i++) //3 byte CACH
|
||||
{
|
||||
int cach_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
|
||||
fprintf (pFile, "%X", cach_byte);
|
||||
}
|
||||
fprintf (pFile, "\n%d 10 ", internalslot+1); //0x10 for "voice burst"
|
||||
for (i = 6; i < 72; i++) //33 bytes, no CACH
|
||||
{
|
||||
int dsp_byte = (state->dmr_stereo_payload[i*2] << 2) | state->dmr_stereo_payload[i*2 + 1];
|
||||
fprintf (pFile, "%X", dsp_byte);
|
||||
}
|
||||
fclose (pFile);
|
||||
}
|
||||
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
char polarity[3];
|
||||
char light[18];
|
||||
|
||||
if (state->currentslot == 0)
|
||||
{
|
||||
sprintf (light, "%s", " [SLOT1] slot2 ");
|
||||
//open MBEout file - slot 1
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_f == NULL)) openMbeOutFile (opts, state);
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf (light, "%s", " slot1 [SLOT2] ");
|
||||
//open MBEout file - slot 2
|
||||
if ((opts->mbe_out_dir[0] != 0) && (opts->mbe_out_fR == NULL)) openMbeOutFileR (opts, state);
|
||||
}
|
||||
if (opts->inverted_dmr == 0) sprintf (polarity, "%s", "+");
|
||||
else sprintf (polarity, "%s", "-");
|
||||
|
||||
fprintf (stderr,"Sync: %sDMR %s| Color Code=%02d | VC1*", polarity, light, state->dmr_color_code);
|
||||
|
||||
dmr_alg_reset (opts, state);
|
||||
|
||||
//copy ambe_fr frames first, running process mbe will correct them,
|
||||
//but this also leads to issues extracting good le mi values when
|
||||
//we go to do correction on them there too
|
||||
memcpy (m1, ambe_fr, sizeof(m1));
|
||||
memcpy (m2, ambe_fr2, sizeof(m2));
|
||||
memcpy (m3, ambe_fr3, sizeof(m3));
|
||||
|
||||
if (opts->payload == 1) fprintf (stderr, "\n"); //extra line break necessary here
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
// processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
|
||||
processMbeFrame (opts, state, NULL, ambe_fr, NULL);
|
||||
if(internalslot == 0)
|
||||
{
|
||||
memcpy(state->f_l4[0], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
||||
memcpy(state->s_l4[0], state->s_l, sizeof(state->s_l));
|
||||
memcpy(state->s_l4u[0], state->s_lu, sizeof(state->s_lu));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
memcpy(state->f_r4[0], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
||||
memcpy(state->s_r4[0], state->s_r, sizeof(state->s_r));
|
||||
memcpy(state->s_r4u[0], state->s_ru, sizeof(state->s_ru));
|
||||
}
|
||||
|
||||
|
||||
processMbeFrame (opts, state, NULL, ambe_fr2, NULL);
|
||||
if(internalslot == 0)
|
||||
{
|
||||
memcpy(state->f_l4[1], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
||||
memcpy(state->s_l4[1], state->s_l, sizeof(state->s_l));
|
||||
memcpy(state->s_l4u[1], state->s_lu, sizeof(state->s_lu));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
memcpy(state->f_r4[1], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
||||
memcpy(state->s_r4[1], state->s_r, sizeof(state->s_r));
|
||||
memcpy(state->s_r4u[1], state->s_ru, sizeof(state->s_ru));
|
||||
}
|
||||
|
||||
processMbeFrame (opts, state, NULL, ambe_fr3, NULL);
|
||||
if(internalslot == 0)
|
||||
{
|
||||
memcpy(state->f_l4[2], state->audio_out_temp_buf, sizeof(state->audio_out_temp_buf));
|
||||
memcpy(state->s_l4[2], state->s_l, sizeof(state->s_l));
|
||||
memcpy(state->s_l4u[2], state->s_lu, sizeof(state->s_lu));
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
memcpy(state->f_r4[2], state->audio_out_temp_bufR, sizeof(state->audio_out_temp_bufR));
|
||||
memcpy(state->s_r4[2], state->s_r, sizeof(state->s_r));
|
||||
memcpy(state->s_r4u[2], state->s_ru, sizeof(state->s_ru));
|
||||
}
|
||||
|
||||
//collect the mi fragment
|
||||
dmr_late_entry_mi_fragment (opts, state, 1, m1, m2, m3);
|
||||
|
||||
cach_err = dmr_cach (opts, state, cachdata);
|
||||
if (opts->payload == 0) fprintf (stderr, "\n");
|
||||
|
||||
//update voice sync time for trunking purposes (particularly Con+)
|
||||
if (opts->p25_is_tuned == 1) state->last_vc_sync_time = time(NULL);
|
||||
|
||||
//NOTE: Only play on slot 1, if slot 0, then it'll play after the next TDMA frame in the BS loop instead
|
||||
if (internalslot == 1 && opts->floating_point == 1 && opts->pulse_digi_rate_out == 8000)
|
||||
playSynthesizedVoiceFS3 (opts, state); //Float Stereo Mix 3v2
|
||||
if (internalslot == 1 && opts->floating_point == 0 && opts->pulse_digi_rate_out == 8000)
|
||||
playSynthesizedVoiceSS3 (opts, state); //Short Stereo Mix 3v2
|
||||
|
||||
dmrBS (opts, state); //bootstrap into full TDMA frame for BS mode
|
||||
END:
|
||||
//if we have a tact err, then produce sync pattern/err message
|
||||
if (tact_okay != 1 || sync_okay != 1)
|
||||
{
|
||||
fprintf (stderr,"%s ", getTime());
|
||||
fprintf (stderr,"Sync: DMR ");
|
||||
fprintf (stderr, "%s", KRED);
|
||||
fprintf (stderr, "| VOICE CACH/SYNC ERR");
|
||||
fprintf (stderr, "%s", KNRM);
|
||||
fprintf (stderr, "\n");
|
||||
//run refresh if either slot had an active MI in it.
|
||||
if (state->payload_algid >= 0x21)
|
||||
{
|
||||
state->currentslot = 0;
|
||||
dmr_alg_refresh (opts, state);
|
||||
}
|
||||
if (state->payload_algidR >= 0x21)
|
||||
{
|
||||
state->currentslot = 1;
|
||||
dmr_alg_refresh (opts, state);
|
||||
}
|
||||
|
||||
//failsafe to reset all data header and blocks when bad tact or emb
|
||||
dmr_reset_blocks (opts, state);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user