mirror of
https://github.com/g4klx/MMDVM.git
synced 2026-10-16 16:54:12 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02000c8049 | ||
|
|
2509ab5ba1 | ||
|
|
2de9e4d533 | ||
|
|
fda1e3dcf4 | ||
|
|
cb3ed795d0 | ||
|
|
632ddda68b | ||
|
|
b6093406ad | ||
|
|
8d9b49bdb0 | ||
|
|
625ec93af8 | ||
|
|
b2111553c6 | ||
|
|
252d54a484 | ||
|
|
1ad9799123 | ||
|
|
6d67b9f104 | ||
|
|
fb85505433 | ||
|
|
823b91c97d | ||
|
|
2a001f491d | ||
|
|
b5ba384495 | ||
|
|
d8f138066e | ||
|
|
6964251122 | ||
|
|
0fca178bd7 | ||
|
|
a60ecb3e57 | ||
|
|
a2978d9e91 | ||
|
|
e304f5cce2 | ||
|
|
99a7df7c13 | ||
|
|
6dfe1a9271 | ||
|
|
9ff59570c7 | ||
|
|
d5e9b5a315 | ||
|
|
1ac0628c1c | ||
|
|
dc41fd83d2 | ||
|
|
20013e3adc | ||
|
|
5960fb97f3 | ||
|
|
8f8dc92a14 | ||
|
|
ccdbe126e0 | ||
|
|
d29a0bc3a6 | ||
|
|
4ff057069b | ||
|
|
f8d8f85841 | ||
|
|
ad77fd60fd | ||
|
|
aab8f5469f | ||
|
|
f1d6a8b36e | ||
|
|
843997ccad | ||
|
|
d5f2d1c382 | ||
|
|
c99f50575d | ||
|
|
29c8cf9414 | ||
|
|
2c6e2c2a11 | ||
|
|
8d10555dc9 | ||
|
|
14d5098018 | ||
|
|
52a351d0f1 | ||
|
|
43f84ae968 | ||
|
|
a73376671c | ||
|
|
759efd1da4 | ||
|
|
ea0c1953cc | ||
|
|
a29cb23a75 | ||
|
|
bb66c72ef3 | ||
|
|
2da28ede64 | ||
|
|
a7ac55795d | ||
|
|
835ef46aef | ||
|
|
3de10fe98b | ||
|
|
7ad70d04a4 | ||
|
|
e210062365 | ||
|
|
f9fcdc5292 | ||
|
|
0ea732780d | ||
|
|
33d922b8c2 | ||
|
|
114c2bcb15 | ||
|
|
6dbda2795a | ||
|
|
6a80d0ec09 | ||
|
|
0e8f20e1cc | ||
|
|
af11be16dc | ||
|
|
e332dbba8e | ||
|
|
746d915bf9 | ||
|
|
c896cf823e | ||
|
|
c2959466fd | ||
|
|
121c76f3d8 | ||
|
|
22cb16f831 | ||
|
|
57e18e337f | ||
|
|
e1d1ac4a4d | ||
|
|
64fe59382f | ||
|
|
a2e2853241 | ||
|
|
598d32287d | ||
|
|
53d8cfa360 | ||
|
|
1309ad9326 | ||
|
|
411d439d78 | ||
|
|
ec9428d63e | ||
|
|
2a4b28c35e | ||
|
|
4f060c0047 | ||
|
|
1ed3a4c9d5 | ||
|
|
f414288c9b | ||
|
|
72cd2ce03e | ||
|
|
9137af8e3f | ||
|
|
cdfe3d0ec9 | ||
|
|
4dfab06a50 | ||
|
|
47649171fc | ||
|
|
0bd79fa440 | ||
|
|
26d055a67b | ||
|
|
5db1adb5ea | ||
|
|
f86b5435bb | ||
|
|
31f0e24588 | ||
|
|
04d0b15545 | ||
|
|
f14222e77d | ||
|
|
7fabddd7f1 | ||
|
|
5039dfbe68 | ||
|
|
f9f81b9b8e | ||
|
|
3cc5d67696 | ||
|
|
3f960f9fc5 | ||
|
|
489853f200 | ||
|
|
2cf2ce4dfa | ||
|
|
96e1a765f9 | ||
|
|
04982c25c0 | ||
|
|
a3ffa9ed36 | ||
|
|
e7a22482db | ||
|
|
5f29808b80 | ||
|
|
063b21f999 | ||
|
|
89b8641955 | ||
|
|
6397c720e8 | ||
|
|
50c1e5aa3f | ||
|
|
970d02773f | ||
|
|
625749a546 | ||
|
|
d75042dc4c | ||
|
|
296ac88842 | ||
|
|
48e863d1d0 | ||
|
|
7b915f9cac | ||
|
|
e330c9f52a | ||
|
|
9470b1d6d3 | ||
|
|
388620b182 | ||
|
|
72e45177f3 | ||
|
|
90b82621f2 | ||
|
|
ff375abb0e | ||
|
|
cfcb7ed852 | ||
|
|
b245be464f | ||
|
|
139003d4c7 | ||
|
|
c47eacd010 | ||
|
|
6b01f12602 | ||
|
|
7169836621 | ||
|
|
c84d227242 | ||
|
|
4f93c6022c | ||
|
|
81f6b6be53 | ||
|
|
fa9f89700f | ||
|
|
9023b6ae13 | ||
|
|
df23e15c91 | ||
|
|
51e5e7b851 | ||
|
|
8e52bdcc5c | ||
|
|
1332c6544b | ||
|
|
703ed2628d | ||
|
|
f3943a7888 | ||
|
|
737454281a | ||
|
|
1aef42bb21 | ||
|
|
9550299e4d | ||
|
|
056dd908b3 | ||
|
|
62f239ccc9 | ||
|
|
f8879e1f25 | ||
|
|
994226e4b1 | ||
|
|
2cc6c1f68f | ||
|
|
8e8cf35b19 | ||
|
|
66de35b6d8 | ||
|
|
43e00bbe1d | ||
|
|
f31b682625 | ||
|
|
7dc420c8ff | ||
|
|
df0a9ebe72 | ||
|
|
66feb9d50b | ||
|
|
0b14b0b73f | ||
|
|
50706c6f09 | ||
|
|
e957f0154e | ||
|
|
b10c72fd78 | ||
|
|
496afcb40e | ||
|
|
9467b10e5c | ||
|
|
13c5f7b0b4 | ||
|
|
435544f7a1 | ||
|
|
b64712f657 | ||
|
|
d23c0900c1 | ||
|
|
a0a3080da2 | ||
|
|
0fad84b46d | ||
|
|
1b40044a23 | ||
|
|
a671263398 | ||
|
|
ca1cc7096a | ||
|
|
a5aabd8fac | ||
|
|
6d0e57ea88 | ||
|
|
1d04c1e903 | ||
|
|
042c26b3bb | ||
|
|
b4a125a759 | ||
|
|
8ecf80ff8f | ||
|
|
6786b9b6b1 | ||
|
|
86ffc69b30 | ||
|
|
5d4df6ffd9 | ||
|
|
eac2aa4ac1 | ||
|
|
8cbd52aa72 | ||
|
|
99b853a976 | ||
|
|
15bc1a4027 | ||
|
|
75e32e1b71 | ||
|
|
7ebc4044f9 | ||
|
|
1836ba928e | ||
|
|
c54c13c146 | ||
|
|
17a3743cd8 | ||
|
|
4a5a260c28 | ||
|
|
4bcc1e88c4 | ||
|
|
4cba5931f4 | ||
|
|
89458a2c93 | ||
|
|
c91a42f53d | ||
|
|
470a070d96 | ||
|
|
36537c981c | ||
|
|
c85978a4e3 | ||
|
|
d0062a55f8 | ||
|
|
66ea3ad0d1 | ||
|
|
3ad443dc2a | ||
|
|
da16ee277c | ||
|
|
85acdc7121 | ||
|
|
a2518e99f2 | ||
|
|
0f51ddd0bd | ||
|
|
aaa72e769f | ||
|
|
0e8fdb381a | ||
|
|
0b31c40c2b | ||
|
|
2b3df4e901 | ||
|
|
807f01ba72 | ||
|
|
03f18451f7 | ||
|
|
16c3d418eb | ||
|
|
55df5fe04c | ||
|
|
b0ba3b5dd8 | ||
|
|
05d21c0a14 | ||
|
|
26a703c68c | ||
|
|
6c3dd265ab | ||
|
|
c04e207821 | ||
|
|
67e0bf02e2 | ||
|
|
3bb7cde322 | ||
|
|
fa29a27695 | ||
|
|
7302dc8bd7 | ||
|
|
bb7383a301 | ||
|
|
61a69d8536 | ||
|
|
5a11fcea5b | ||
|
|
05775f0bfa | ||
|
|
973a1391d7 | ||
|
|
5d45649096 | ||
|
|
e91c4417cb | ||
|
|
ff3e6feeb6 | ||
|
|
0e2a83bc7b | ||
|
|
c84dbd02e5 | ||
|
|
c0aad5effa | ||
|
|
e0234dfc00 | ||
|
|
e30eb3adaf | ||
|
|
7c9385beab | ||
|
|
4c6601d778 | ||
|
|
e3a951b33b | ||
|
|
97192602d8 | ||
|
|
604957b3e2 | ||
|
|
bb731e7890 | ||
|
|
c81d13395b | ||
|
|
9b0fed975c | ||
|
|
18bc0a75b8 | ||
|
|
f1a43ee520 | ||
|
|
b73bca237d | ||
|
|
e7ff0d1898 | ||
|
|
880df2536d | ||
|
|
09b6929100 | ||
|
|
9afcf3acc9 | ||
|
|
5ca9313db8 | ||
|
|
feff1ee2c7 | ||
|
|
77e0deee76 | ||
|
|
d7cd7096d0 | ||
|
|
5d1b66dde3 | ||
|
|
96364dc189 | ||
|
|
a816818e3f | ||
|
|
61ae1fc83a | ||
|
|
eb9c0dfd93 | ||
|
|
79a09e61fa | ||
|
|
9978a75651 | ||
|
|
bd16d13531 | ||
|
|
f00d729264 | ||
|
|
a4ddc2a060 | ||
|
|
a938c8b708 | ||
|
|
aa7a484c7a | ||
|
|
915be8c279 | ||
|
|
87feadd451 | ||
|
|
419ab89ee9 | ||
|
|
fcdb582893 | ||
|
|
5e85565208 | ||
|
|
2d876b8d8e | ||
|
|
4feca3c5b7 | ||
|
|
f8e119c26b | ||
|
|
edddbedd4b | ||
|
|
baa4f7aa4c | ||
|
|
de3c257f79 | ||
|
|
b027e1d1bf | ||
|
|
0a5c496a3a | ||
|
|
5b32fecc0a | ||
|
|
92a4db9886 | ||
|
|
cc785e3225 | ||
|
|
be0690e587 | ||
|
|
69e39e36b0 | ||
|
|
b2f33fd4d2 | ||
|
|
200199c5d4 | ||
|
|
1465d6f91d | ||
|
|
373aed13c8 | ||
|
|
b23620ede3 | ||
|
|
da87afc8d4 | ||
|
|
626a280d27 | ||
|
|
4b267c2e1e | ||
|
|
cf18f95a92 | ||
|
|
dac0f26e5d | ||
|
|
13993891ec | ||
|
|
849c2a0f50 | ||
|
|
172ac615a8 | ||
|
|
30031d8e95 | ||
|
|
b2de5defa4 | ||
|
|
177c7548ae | ||
|
|
b9bfc36e6f | ||
|
|
980c529107 | ||
|
|
5156ca13b7 | ||
|
|
d08a3690b0 | ||
|
|
e8ed77241c | ||
|
|
82dcc44a2d | ||
|
|
93a8e63233 | ||
|
|
4ffaa62855 | ||
|
|
f9530ee82a | ||
|
|
d66c6d7f9c | ||
|
|
458a3d2d24 | ||
|
|
6f4c19c006 | ||
|
|
a31cf3d6f8 | ||
|
|
3fb0631953 | ||
|
|
028d0cf609 | ||
|
|
6824d5662a | ||
|
|
1bc8726046 | ||
|
|
05c8c130b6 | ||
|
|
5051a13711 | ||
|
|
103116e410 | ||
|
|
d973238596 | ||
|
|
4d664c4aa4 | ||
|
|
bd4096b6be | ||
|
|
f92d93772c | ||
|
|
b963b2b848 | ||
|
|
9dadb51f11 | ||
|
|
23cf22d87d | ||
|
|
d2d50e21e1 | ||
|
|
8c38fdb36d | ||
|
|
4fe1c11250 | ||
|
|
394ab8dfd1 | ||
|
|
5295e0bdc3 | ||
|
|
c638dbe55a | ||
|
|
6ac6deba10 | ||
|
|
d2ce76fe89 | ||
|
|
0b27ec5443 | ||
|
|
868d33ebd2 | ||
|
|
9fab1e0823 | ||
|
|
242bc7b322 | ||
|
|
e5c25f55fe | ||
|
|
33f88344c3 | ||
|
|
103d937152 | ||
|
|
e721dedf1e | ||
|
|
176e067ab9 | ||
|
|
2057ef5206 | ||
|
|
5c2659deaa | ||
|
|
4f9d5a8c70 | ||
|
|
8ecd8b67f4 | ||
|
|
22c40e1d96 | ||
|
|
a720ceeb54 | ||
|
|
f8d082e2dd | ||
|
|
507a4bf64c | ||
|
|
7a75db2aeb | ||
|
|
ce0aebce48 | ||
|
|
906de3ad11 | ||
|
|
bf5ad25609 | ||
|
|
f19009b132 | ||
|
|
526a53cd8c | ||
|
|
57730d7f81 | ||
|
|
f936bc6fe8 | ||
|
|
3f1f1d1586 | ||
|
|
7940025095 | ||
|
|
63847ebe62 | ||
|
|
03f5056236 | ||
|
|
23ff29c8f1 | ||
|
|
1b0229ca6c | ||
|
|
ae6cbcd9e7 | ||
|
|
1c599138ad | ||
|
|
9170c398be | ||
|
|
04fd9838b5 | ||
|
|
8d340cbfba | ||
|
|
87c3b57ae4 | ||
|
|
7befef2f4a | ||
|
|
b2dcbb2df8 | ||
|
|
0a51b4c34e | ||
|
|
3b653dca6a | ||
|
|
046a1de51a | ||
|
|
ae58f8eb64 | ||
|
|
e4c351d5d0 | ||
|
|
0b0a59497f | ||
|
|
939b019592 | ||
|
|
3d54519dbf | ||
|
|
94f566aacc | ||
|
|
a765e863c0 | ||
|
|
9e552ba1ab | ||
|
|
b03fead62d | ||
|
|
2825c25607 | ||
|
|
5ed8eeda6f | ||
|
|
1aef1a39f2 | ||
|
|
a310bf0547 | ||
|
|
116b51bd8d | ||
|
|
c05e7bf873 | ||
|
|
c14ae56e2d | ||
|
|
32a71bfbf6 | ||
|
|
7435074c0f | ||
|
|
ec202d7fb9 | ||
|
|
6575cba982 | ||
|
|
a17bd9cc1d | ||
|
|
f7e5c2436c | ||
|
|
85816d5bec | ||
|
|
ebdba2bdb9 | ||
|
|
6d5b864cba | ||
|
|
c8a450b00d | ||
|
|
61ccd79c5f | ||
|
|
c55002534e | ||
|
|
8ca756ec22 | ||
|
|
d1c106b3b8 | ||
|
|
564260b2f1 | ||
|
|
4a85122483 | ||
|
|
bc889f3d26 | ||
|
|
95e76f387c | ||
|
|
4a5f985d02 | ||
|
|
bbe56f5082 | ||
|
|
4b0c3d88f3 | ||
|
|
c103ac91b3 | ||
|
|
ebd87584da | ||
|
|
a9a985182f | ||
|
|
db6fde90e0 | ||
|
|
74228c506e | ||
|
|
bcd43006ac | ||
|
|
cf616caef9 | ||
|
|
7ab6e51c2c | ||
|
|
7a549e96ba | ||
|
|
3e4d709225 | ||
|
|
031563e727 | ||
|
|
3f80248477 | ||
|
|
c84d81d91c | ||
|
|
ef65268b45 | ||
|
|
9d725b9479 | ||
|
|
b4647d8d1b | ||
|
|
f28a22802d | ||
|
|
8a60fc1ecb | ||
|
|
dfad6d8409 | ||
|
|
b94b8afb77 | ||
|
|
0f37bfa20d | ||
|
|
d6d03158d0 | ||
|
|
7c863671c9 | ||
|
|
2a6db2ab52 | ||
|
|
c8a345a301 | ||
|
|
37efcb3d4f | ||
|
|
ff7a9fdd4e | ||
|
|
9ccbb842bf | ||
|
|
73d3bd5778 | ||
|
|
f785a5260a | ||
|
|
03716daca0 | ||
|
|
9987140790 | ||
|
|
6b00f7d27a | ||
|
|
98fffb9b77 | ||
|
|
000da1889f | ||
|
|
0a634b1223 | ||
|
|
5456f403a1 | ||
|
|
461182bf60 | ||
|
|
580ba0b536 | ||
|
|
5e3c4c91bb | ||
|
|
3875da80e7 | ||
|
|
6af252f315 | ||
|
|
e46ef4f9ce | ||
|
|
3bae422a8e | ||
|
|
d7526891c5 | ||
|
|
6563ee2fb2 | ||
|
|
c0952d73d1 | ||
|
|
4d780389bf | ||
|
|
5c9abf2eeb | ||
|
|
11997ca017 | ||
|
|
ed36d13c8f | ||
|
|
119eea161e | ||
|
|
d67809eda6 | ||
|
|
428d36da90 | ||
|
|
328e88856a | ||
|
|
99966e20ad | ||
|
|
1fef7772cb | ||
|
|
f8ab4fe9bd | ||
|
|
c2e785cdc4 | ||
|
|
5f19cfcb49 | ||
|
|
5405395e1a | ||
|
|
3c95d1f604 | ||
|
|
da8023eabf | ||
|
|
0d55ba317d | ||
|
|
404dc3d99d | ||
|
|
4821d0e959 | ||
|
|
db3649827f | ||
|
|
5bec0d0780 | ||
|
|
110062bf65 | ||
|
|
f3c621307a | ||
|
|
03177a05e7 | ||
|
|
e93b08380d | ||
|
|
012b366143 | ||
|
|
fd8bc07b61 | ||
|
|
68106058d6 | ||
|
|
d62c945887 | ||
|
|
0aea9aef38 | ||
|
|
88409dccd2 | ||
|
|
f705656178 | ||
|
|
5c61ee6be8 | ||
|
|
a4af04fae2 | ||
|
|
6b28efc011 | ||
|
|
8c6289802f | ||
|
|
78d79d4124 | ||
|
|
76d2058075 | ||
|
|
dcd8142c51 | ||
|
|
88c530d9e6 | ||
|
|
61d5dd6eb3 | ||
|
|
9eb6bc1a60 | ||
|
|
2098146af8 | ||
|
|
ef32988827 | ||
|
|
ce05dec2e6 | ||
|
|
895bed1f70 | ||
|
|
dbea23f171 | ||
|
|
ead9747f95 | ||
|
|
5fe665a6d3 | ||
|
|
3515b16222 | ||
|
|
a5c162a75e | ||
|
|
b5a56487b1 | ||
|
|
d151c100db | ||
|
|
56ced0d939 | ||
|
|
b6cb23d876 | ||
|
|
20a0a875f3 | ||
|
|
d6c1bea80a | ||
|
|
6d4ec5d8a1 | ||
|
|
474dce0141 | ||
|
|
5adbe6d0d5 | ||
|
|
28adbef81b | ||
|
|
c86d53d9d4 | ||
|
|
eb33bdde5a | ||
|
|
0a89469ffc | ||
|
|
bdd4f395ad | ||
|
|
4ae2999e95 | ||
|
|
077bb3b366 | ||
|
|
b0ca829cf6 | ||
|
|
c11ff6bf20 | ||
|
|
e1b99f6ee4 | ||
|
|
4c792ff668 | ||
|
|
260dca9664 | ||
|
|
91a15a5782 | ||
|
|
03f15d8689 | ||
|
|
86bf20b06b | ||
|
|
41ffe6d2eb | ||
|
|
41946ff0aa | ||
|
|
0ca06e2219 | ||
|
|
59ed3f07c8 | ||
|
|
e20630a425 | ||
|
|
ec8a2bc9ff | ||
|
|
b21c1f21a4 | ||
|
|
01b3dcc689 | ||
|
|
23f27cf496 | ||
|
|
9410e724b8 | ||
|
|
6f7b95a15c | ||
|
|
d5c2fe9280 | ||
|
|
450005d611 | ||
|
|
97a72f5b7f | ||
|
|
ce6d03ae13 | ||
|
|
23f7b6a750 | ||
|
|
36a4404c5c | ||
|
|
66241f2f1b | ||
|
|
e5aab0f165 | ||
|
|
14a4dc2bf9 | ||
|
|
42408d5a9a | ||
|
|
55cb3945df | ||
|
|
a4a95ba5d0 | ||
|
|
8a1ac05df2 | ||
|
|
78ae7f3b33 | ||
|
|
c783d6d101 | ||
|
|
3ea95ce53d | ||
|
|
16d978cea2 | ||
|
|
e43c992249 | ||
|
|
e78fc5b701 | ||
|
|
eebfc56013 | ||
|
|
1d4bd4e409 | ||
|
|
9f28d2f69a | ||
|
|
9c01a6328a | ||
|
|
46528127dc | ||
|
|
b34d3c3dbd | ||
|
|
2bc99deec2 | ||
|
|
a6b6219c6d | ||
|
|
caaf090b10 | ||
|
|
01b7641bd1 | ||
|
|
b42ddbbf42 | ||
|
|
f32b8dc4e8 | ||
|
|
9e6a4ca6df | ||
|
|
91e5d588b0 | ||
|
|
555c308749 | ||
|
|
7b88e883f9 | ||
|
|
e7b52023c6 | ||
|
|
e7a40343b1 | ||
|
|
dfc262bbcd | ||
|
|
615c705044 | ||
|
|
c59c32b350 | ||
|
|
d69df42de4 | ||
|
|
99dafe6327 | ||
|
|
5da3c9352d | ||
|
|
fdc15b355f | ||
|
|
4f49f65a1c | ||
|
|
d99e21f0f9 | ||
|
|
9b5bbee265 | ||
|
|
b5ca5e3839 | ||
|
|
b988750e78 | ||
|
|
78a51d416d | ||
|
|
3a539e1243 | ||
|
|
db133c819e | ||
|
|
02d5218baa | ||
|
|
394d0cbc6b | ||
|
|
b4456aed28 | ||
|
|
9e56268156 | ||
|
|
94e65ba6cc | ||
|
|
2ec02e53e3 | ||
|
|
c6e9227aee | ||
|
|
e1d1faea82 | ||
|
|
4871ad1210 | ||
|
|
7b03336469 | ||
|
|
b846e5a7f3 | ||
|
|
ee1d512132 | ||
|
|
628665175c | ||
|
|
a921df7335 | ||
|
|
6bbc716e4b | ||
|
|
cf448158cb | ||
|
|
6a6688ea8d | ||
|
|
c86ba51523 | ||
|
|
a8eae44209 | ||
|
|
efa407a579 | ||
|
|
b54dc34215 | ||
|
|
167296200d | ||
|
|
ca6601ca6d | ||
|
|
8d7b4ef84d | ||
|
|
2279162db5 | ||
|
|
9cfbdebc7b | ||
|
|
7583446380 | ||
|
|
94b4fe3fd6 | ||
|
|
d86b10fc1d | ||
|
|
7996a45125 | ||
|
|
655e7f8218 | ||
|
|
c2a3f83a9f | ||
|
|
0505e76422 | ||
|
|
265828b127 | ||
|
|
4134a656b0 | ||
|
|
cd0bd6e5c4 | ||
|
|
418ce895cb | ||
|
|
8a9510b48a | ||
|
|
b22ada3fa2 | ||
|
|
b4ac4838fd | ||
|
|
89000729d2 | ||
|
|
abea72b4d5 | ||
|
|
76c3e5786c | ||
|
|
793407fe16 | ||
|
|
990bf2a16a | ||
|
|
ea37f67b91 | ||
|
|
a805652f48 | ||
|
|
eb4cd221b2 | ||
|
|
a244b86f36 | ||
|
|
56a12a61c2 | ||
|
|
595f38b796 | ||
|
|
d6b7796c25 | ||
|
|
70e1fd4264 | ||
|
|
00bc8be152 | ||
|
|
cce2cc3cfc | ||
|
|
1f5a4f1ad7 | ||
|
|
a60059bc90 | ||
|
|
6c6b6c19fc | ||
|
|
5b1075f0f7 | ||
|
|
17007dd1e4 | ||
|
|
8f317fd332 | ||
|
|
1cee9e19c0 | ||
|
|
5b313b7cec | ||
|
|
8b52d372eb | ||
|
|
f4637585f6 | ||
|
|
3e03fcff8e | ||
|
|
74682e7ac0 | ||
|
|
20cf355e7e | ||
|
|
04ca97e5f8 | ||
|
|
669acb99e8 | ||
|
|
ba81fa7396 | ||
|
|
8540964097 | ||
|
|
9d1ebc0f8f | ||
|
|
786e57d043 | ||
|
|
902b079de2 | ||
|
|
54f54ab518 | ||
|
|
f8d767913e | ||
|
|
266db8bedb | ||
|
|
6c4496e034 | ||
|
|
8db83708ca | ||
|
|
7f45a0da83 | ||
|
|
ce03ad4ab7 | ||
|
|
ae9e35ccad | ||
|
|
9e5234539e | ||
|
|
dea7c714c0 | ||
|
|
4690186812 | ||
|
|
399b6e1d85 | ||
|
|
c2ed9d4ae7 | ||
|
|
1dc23a4aa6 | ||
|
|
61b05dd5af | ||
|
|
00a7f15011 | ||
|
|
8a5d5bc286 | ||
|
|
c80c6a7797 | ||
|
|
96c214c359 | ||
|
|
6d5f098e41 | ||
|
|
e53aec348e | ||
|
|
9722c85585 | ||
|
|
1a9c0d3ee7 | ||
|
|
7b68017411 | ||
|
|
a2cf35629b | ||
|
|
2506690e98 | ||
|
|
7e15d1ac70 | ||
|
|
0fb75f974e | ||
|
|
99ac6146d9 | ||
|
|
6161d298f7 | ||
|
|
7f181133c7 | ||
|
|
1d6ca99df9 | ||
|
|
baed701a6c | ||
|
|
8b31a53e4e | ||
|
|
f6f1198873 | ||
|
|
4b17bcd991 | ||
|
|
852785b616 | ||
|
|
1034670ac4 | ||
|
|
ff8bf96abb | ||
|
|
edc53fc347 | ||
|
|
3760404af9 | ||
|
|
68dfdf0c21 | ||
|
|
5bd01645fa | ||
|
|
f31cceac18 | ||
|
|
1b48c4de1c | ||
|
|
a6ed1e9667 | ||
|
|
c7eb072d2f | ||
|
|
caa73c6c4a | ||
|
|
9386fb2e11 | ||
|
|
9c9b759db5 | ||
|
|
cfb6e31e2f | ||
|
|
4f6f519dc7 | ||
|
|
fe8e8329ad | ||
|
|
38bcf1f4c4 | ||
|
|
6a1c06576b | ||
|
|
27b3773f00 | ||
|
|
871c328914 | ||
|
|
fa251afdcb | ||
|
|
27618658a9 | ||
|
|
bb42bdc422 | ||
|
|
f15fcc17ec | ||
|
|
59a9b3018f | ||
|
|
07b7801821 | ||
|
|
3d430cbe44 | ||
|
|
fd27ffa464 | ||
|
|
42517d691e | ||
|
|
53f51820fa | ||
|
|
61a86b7f06 | ||
|
|
696964a3a4 | ||
|
|
23228a0027 | ||
|
|
b4bef6e7c3 | ||
|
|
d2548f9e84 | ||
|
|
4a01e9b3a1 | ||
|
|
8a245e7313 | ||
|
|
c132a58d2e | ||
|
|
9cf91ddc7f | ||
|
|
016ed333ec | ||
|
|
453fb33b76 | ||
|
|
9c1410eaae | ||
|
|
5d1a54eee5 | ||
|
|
4f516a827f | ||
|
|
acb2004843 | ||
|
|
0f43670066 | ||
|
|
ab3cdbc277 | ||
|
|
9efe38d825 | ||
|
|
132cde0864 | ||
|
|
bc969ff5e5 | ||
|
|
ee3f2a0e6d | ||
|
|
421031323d | ||
|
|
6118653053 | ||
|
|
1a5bc9cf8c | ||
|
|
06ef230ad5 | ||
|
|
9d4779e4c3 | ||
|
|
d5531177f2 | ||
|
|
f2c50083d8 | ||
|
|
838d813ab9 | ||
|
|
dffc6f0a5a | ||
|
|
7a042c10ad | ||
|
|
0c44b8ca25 | ||
|
|
6f29fe62b1 | ||
|
|
937c0b8b97 | ||
|
|
941d77bd51 | ||
|
|
6a0fa19c07 | ||
|
|
a14ebca9e0 | ||
|
|
61b4093aec | ||
|
|
555197b0a2 | ||
|
|
bb6a554919 | ||
|
|
c0941c4856 | ||
|
|
e93b264d9c | ||
|
|
fcdbb8cda0 | ||
|
|
a4ff8920e5 | ||
|
|
db1c01f4dc | ||
|
|
ab50521f74 | ||
|
|
5843ca0e3d | ||
|
|
6b0868b8f2 | ||
|
|
a49871cd8b | ||
|
|
78f5d34373 | ||
|
|
9bcaba0419 | ||
|
|
a25b634366 | ||
|
|
4039f576ae | ||
|
|
03aa405b41 | ||
|
|
546243eec6 | ||
|
|
a033ee66fd | ||
|
|
70dfb0964e | ||
|
|
ab09848afd | ||
|
|
ed7b57d618 | ||
|
|
e8010137f7 | ||
|
|
c2d5c31db1 | ||
|
|
5f2375e99e | ||
|
|
fd56870d22 | ||
|
|
5bc21fa192 | ||
|
|
33293258f3 | ||
|
|
aee9cac546 | ||
|
|
c9b553bc2e | ||
|
|
12dc9183da | ||
|
|
8c38341c17 | ||
|
|
418b63b9ca | ||
|
|
e697a91710 | ||
|
|
e04057a5b5 | ||
|
|
e17d771d41 | ||
|
|
38516074dd | ||
|
|
3814d4243c | ||
|
|
bcbfb66131 | ||
|
|
9560c77358 | ||
|
|
785cb5584b | ||
|
|
917b303a0f | ||
|
|
80d659d7d0 | ||
|
|
90111dc43d | ||
|
|
9110f5404f | ||
|
|
df1210eaea | ||
|
|
a9b761d1dc | ||
|
|
8c970b26db | ||
|
|
d89b68ff76 | ||
|
|
7fafd762d2 | ||
|
|
a6affb765e | ||
|
|
2f9eb3523d | ||
|
|
3b5e1afb54 | ||
|
|
8b019d49fd | ||
|
|
d92a00ae6e | ||
|
|
b83d13fe3a | ||
|
|
bc6c650973 | ||
|
|
1bb474dfef | ||
|
|
18ec4bafb6 | ||
|
|
b2c490e0bd | ||
|
|
4221ac45b1 | ||
|
|
ec5100bf6f | ||
|
|
ac4249bbb1 | ||
|
|
f3a3132a6c | ||
|
|
4bc0f36b49 | ||
|
|
9d1fbcfc73 | ||
|
|
609c2ead53 | ||
|
|
37daa04a6c | ||
|
|
20a4cf0378 | ||
|
|
693f517aec | ||
|
|
4549027e95 | ||
|
|
b3a1961279 | ||
|
|
afae6e552c | ||
|
|
5ee6a0d6db | ||
|
|
49e0d13967 | ||
|
|
53067d36d0 | ||
|
|
a5568efd51 | ||
|
|
d4d1f8282b | ||
|
|
79b0b141a2 | ||
|
|
850978a954 | ||
|
|
f97e53f1eb | ||
|
|
dfd2a4db38 | ||
|
|
eab91cca3a | ||
|
|
1e7c06de45 | ||
|
|
b15933bf8a | ||
|
|
df5ab3de60 | ||
|
|
9a7b07027a | ||
|
|
8b13a3c8a6 | ||
|
|
1ce71bcd62 | ||
|
|
ed13addd3d | ||
|
|
3e937a71d9 | ||
|
|
a59da0ebd2 | ||
|
|
33f4d35e2b | ||
|
|
048888f45b | ||
|
|
57fde3afcc | ||
|
|
8777c2b29c | ||
|
|
8330ed7dcf | ||
|
|
9f47e67630 | ||
|
|
d0f320a862 | ||
|
|
a05eaee855 | ||
|
|
4b5f496a0c | ||
|
|
fca53dc67e | ||
|
|
52fbd4f6ce | ||
|
|
d22c86e4d8 | ||
|
|
cc1b6d1367 | ||
|
|
2ff955631f | ||
|
|
f66e32fbb4 | ||
|
|
33527dd3e9 | ||
|
|
442dbe0b6a | ||
|
|
fc200c4cd7 | ||
|
|
7266f5c53b | ||
|
|
957d0d8d34 | ||
|
|
c69c573000 | ||
|
|
cb30a8d357 | ||
|
|
38f6d7d9d8 | ||
|
|
461e7c942e | ||
|
|
773cda818d | ||
|
|
625a6c1a79 | ||
|
|
414f3eb193 | ||
|
|
bef0d9cfd6 | ||
|
|
1a270642cd | ||
|
|
75eccb751e | ||
|
|
2c76d67098 | ||
|
|
0585d817cb | ||
|
|
5d0d2d0bd9 |
@@ -0,0 +1,5 @@
|
|||||||
|
*.o
|
||||||
|
obj/
|
||||||
|
bin/
|
||||||
|
GitVersion.h
|
||||||
|
build/
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[submodule "STM32F4XX_Lib"]
|
||||||
|
path = STM32F4XX_Lib
|
||||||
|
url = https://github.com/juribeparada/STM32F4XX_Lib.git
|
||||||
|
[submodule "STM32F7XX_Lib"]
|
||||||
|
path = STM32F7XX_Lib
|
||||||
|
url = https://github.com/juribeparada/STM32F7XX_Lib.git
|
||||||
|
[submodule "STM32F10X_Lib"]
|
||||||
|
path = STM32F10X_Lib
|
||||||
|
url = https://github.com/shawnchain/STM32F10X_Lib.git
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(AX25DEFINES_H)
|
||||||
|
#define AX25DEFINES_H
|
||||||
|
|
||||||
|
const uint8_t AX25_RADIO_SYMBOL_LENGTH = 20U; // At 24 kHz sample rate
|
||||||
|
|
||||||
|
const uint8_t AX25_FRAME_START = 0x7EU;
|
||||||
|
const uint8_t AX25_FRAME_END = 0x7EU;
|
||||||
|
const uint8_t AX25_FRAME_ABORT = 0xFEU;
|
||||||
|
|
||||||
|
const uint8_t AX25_MAX_ONES = 5U;
|
||||||
|
|
||||||
|
const uint16_t AX25_MIN_FRAME_LENGTH = 17U; // Callsign (7) + Callsign (7) + Control (1) + Checksum (2)
|
||||||
|
|
||||||
|
const uint16_t AX25_MAX_FRAME_LENGTH = 330U; // Callsign (7) + Callsign (7) + 8 Digipeaters (56) +
|
||||||
|
// Control (1) + PID (1) + Data (256) + Checksum (2)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
@@ -0,0 +1,314 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright 2015-2019 Mobilinkd LLC <[email protected]>
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "AX25Demodulator.h"
|
||||||
|
#include "AX25Defines.h"
|
||||||
|
|
||||||
|
const float32_t SAMPLE_RATE = 24000.0F;
|
||||||
|
const float32_t SYMBOL_RATE = 1200.0F;
|
||||||
|
|
||||||
|
const uint16_t DELAY_LEN = 11U;
|
||||||
|
|
||||||
|
const float32_t SAMPLES_PER_SYMBOL = SAMPLE_RATE / SYMBOL_RATE;
|
||||||
|
const float32_t PLL_LIMIT = SAMPLES_PER_SYMBOL / 2.0F;
|
||||||
|
|
||||||
|
const uint32_t LPF_FILTER_LEN = 48U;
|
||||||
|
|
||||||
|
q15_t LPF_FILTER_COEFFS[] = {
|
||||||
|
-2, -8, -17, -28, -40, -47, -47, -34,
|
||||||
|
-5, 46, 122, 224, 354, 510, 689, 885,
|
||||||
|
1092, 1302, 1506, 1693, 1856, 1987, 2077, 2124,
|
||||||
|
2124, 2077, 1987, 1856, 1693, 1506, 1302, 1092,
|
||||||
|
885, 689, 510, 354, 224, 122, 46, -5,
|
||||||
|
-34, -47, -47, -40, -28, -17, -8, -2
|
||||||
|
};
|
||||||
|
|
||||||
|
// Lock low-pass filter taps (80Hz Bessel)
|
||||||
|
// scipy.signal:
|
||||||
|
// b, a = bessel(4, [80.0/(1200/2)], 'lowpass')
|
||||||
|
//
|
||||||
|
const uint8_t PLL_IIR_SIZE = 5U;
|
||||||
|
|
||||||
|
const float32_t PLL_LOCK_B[] = {
|
||||||
|
1.077063e-03,4.308253e-03,6.462379e-03,4.308253e-03,1.077063e-03};
|
||||||
|
|
||||||
|
const float32_t PLL_LOCK_A[] = {
|
||||||
|
1.000000e+00,-2.774567e+00,2.962960e+00,-1.437990e+00,2.668296e-01};
|
||||||
|
|
||||||
|
// 64 Hz loop filter.
|
||||||
|
// scipy.signal:
|
||||||
|
// loop_coeffs = firwin(9, [64.0/(1200/2)], width = None,
|
||||||
|
// pass_zero = True, scale = True, window='hann')
|
||||||
|
//
|
||||||
|
const uint32_t PLL_FILTER_LEN = 7U;
|
||||||
|
|
||||||
|
float32_t PLL_FILTER_COEFFS[] = {3.196252e-02F, 1.204223e-01F, 2.176819e-01F, 2.598666e-01F, 2.176819e-01F, 1.204223e-01F, 3.196252e-02F};
|
||||||
|
|
||||||
|
CAX25Demodulator::CAX25Demodulator(int8_t n) :
|
||||||
|
m_frame(),
|
||||||
|
m_twist(n),
|
||||||
|
m_lpfFilter(),
|
||||||
|
m_lpfState(),
|
||||||
|
m_delayLine(NULL),
|
||||||
|
m_delayPos(0U),
|
||||||
|
m_nrziState(false),
|
||||||
|
m_pllFilter(),
|
||||||
|
m_pllState(),
|
||||||
|
m_pllLast(false),
|
||||||
|
m_pllBits(1U),
|
||||||
|
m_pllCount(0.0F),
|
||||||
|
m_pllJitter(0.0F),
|
||||||
|
m_pllDCD(false),
|
||||||
|
m_iirHistory(),
|
||||||
|
m_hdlcOnes(0U),
|
||||||
|
m_hdlcFlag(false),
|
||||||
|
m_hdlcBuffer(0U),
|
||||||
|
m_hdlcBits(0U),
|
||||||
|
m_hdlcState(AX25_IDLE)
|
||||||
|
{
|
||||||
|
m_delayLine = new bool[DELAY_LEN];
|
||||||
|
|
||||||
|
m_lpfFilter.numTaps = LPF_FILTER_LEN;
|
||||||
|
m_lpfFilter.pState = m_lpfState;
|
||||||
|
m_lpfFilter.pCoeffs = LPF_FILTER_COEFFS;
|
||||||
|
|
||||||
|
m_pllFilter.numTaps = PLL_FILTER_LEN;
|
||||||
|
m_pllFilter.pState = m_pllState;
|
||||||
|
m_pllFilter.pCoeffs = PLL_FILTER_COEFFS;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < PLL_IIR_SIZE; i++)
|
||||||
|
m_iirHistory[i] = 0.0F;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAX25Demodulator::process(q15_t* samples, uint8_t length, CAX25Frame& frame)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
q15_t fa[RX_BLOCK_SIZE];
|
||||||
|
m_twist.process(samples, fa, RX_BLOCK_SIZE);
|
||||||
|
|
||||||
|
int16_t buffer[RX_BLOCK_SIZE];
|
||||||
|
for (uint8_t i = 0; i < length; i++) {
|
||||||
|
bool level = (fa[i] >= 0);
|
||||||
|
bool delayed = delay(level);
|
||||||
|
buffer[i] = (int16_t(level ^ delayed) << 1) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
q15_t fc[RX_BLOCK_SIZE];
|
||||||
|
::arm_fir_fast_q15(&m_lpfFilter, buffer, fc, RX_BLOCK_SIZE);
|
||||||
|
|
||||||
|
for (uint8_t i = 0; i < length; i++) {
|
||||||
|
bool bit = fc[i] >= 0;
|
||||||
|
bool sample = PLL(bit);
|
||||||
|
|
||||||
|
if (sample) {
|
||||||
|
// We will only ever get one frame because there are
|
||||||
|
// not enough bits in a block for more than one.
|
||||||
|
if (result) {
|
||||||
|
HDLC(NRZI(bit));
|
||||||
|
} else {
|
||||||
|
result = HDLC(NRZI(bit));
|
||||||
|
if (result) {
|
||||||
|
// Copy the frame data.
|
||||||
|
::memcpy(frame.m_data, m_frame.m_data, AX25_MAX_PACKET_LEN);
|
||||||
|
frame.m_length = m_frame.m_length;
|
||||||
|
frame.m_fcs = m_frame.m_fcs;
|
||||||
|
m_frame.m_length = 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAX25Demodulator::delay(bool b)
|
||||||
|
{
|
||||||
|
bool r = m_delayLine[m_delayPos];
|
||||||
|
|
||||||
|
m_delayLine[m_delayPos++] = b;
|
||||||
|
|
||||||
|
if (m_delayPos >= DELAY_LEN)
|
||||||
|
m_delayPos = 0U;
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAX25Demodulator::NRZI(bool b)
|
||||||
|
{
|
||||||
|
bool result = (b == m_nrziState);
|
||||||
|
|
||||||
|
m_nrziState = b;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAX25Demodulator::PLL(bool input)
|
||||||
|
{
|
||||||
|
bool sample = false;
|
||||||
|
|
||||||
|
if (input != m_pllLast || m_pllBits > 16U) {
|
||||||
|
// Record transition.
|
||||||
|
m_pllLast = input;
|
||||||
|
|
||||||
|
if (m_pllCount > PLL_LIMIT)
|
||||||
|
m_pllCount -= SAMPLES_PER_SYMBOL;
|
||||||
|
|
||||||
|
float32_t adjust = m_pllBits > 16U ? 5.0F : 0.0F;
|
||||||
|
float32_t offset = m_pllCount / float32_t(m_pllBits);
|
||||||
|
float32_t jitter;
|
||||||
|
::arm_fir_f32(&m_pllFilter, &offset, &jitter, 1U);
|
||||||
|
|
||||||
|
float32_t absOffset = adjust;
|
||||||
|
if (offset < 0.0F)
|
||||||
|
absOffset -= offset;
|
||||||
|
else
|
||||||
|
absOffset += offset;
|
||||||
|
m_pllJitter = iir(absOffset);
|
||||||
|
|
||||||
|
m_pllCount -= jitter / 2.0F;
|
||||||
|
m_pllBits = 1U;
|
||||||
|
} else {
|
||||||
|
if (m_pllCount > PLL_LIMIT) {
|
||||||
|
sample = true;
|
||||||
|
m_pllCount -= SAMPLES_PER_SYMBOL;
|
||||||
|
m_pllBits++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pllCount += 1.0F;
|
||||||
|
|
||||||
|
return sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAX25Demodulator::HDLC(bool b)
|
||||||
|
{
|
||||||
|
if (m_hdlcOnes == AX25_MAX_ONES) {
|
||||||
|
if (b) {
|
||||||
|
// flag byte
|
||||||
|
m_hdlcFlag = true;
|
||||||
|
} else {
|
||||||
|
// bit stuffing...
|
||||||
|
m_hdlcFlag = false;
|
||||||
|
m_hdlcOnes = 0U;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_hdlcBuffer >>= 1;
|
||||||
|
m_hdlcBuffer |= b ? 128U : 0U;
|
||||||
|
m_hdlcBits++; // Free-running until Sync byte.
|
||||||
|
|
||||||
|
if (b)
|
||||||
|
m_hdlcOnes++;
|
||||||
|
else
|
||||||
|
m_hdlcOnes = 0U;
|
||||||
|
|
||||||
|
if (m_hdlcFlag) {
|
||||||
|
bool result = false;
|
||||||
|
|
||||||
|
switch (m_hdlcBuffer) {
|
||||||
|
case AX25_FRAME_END:
|
||||||
|
if (m_frame.m_length >= AX25_MIN_FRAME_LENGTH) {
|
||||||
|
result = m_frame.checkCRC();
|
||||||
|
if (!result)
|
||||||
|
m_frame.m_length = 0U;
|
||||||
|
} else {
|
||||||
|
m_frame.m_length = 0U;
|
||||||
|
}
|
||||||
|
m_hdlcState = AX25_SYNC;
|
||||||
|
m_hdlcFlag = false;
|
||||||
|
m_hdlcBits = 0U;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AX25_FRAME_ABORT:
|
||||||
|
// Frame aborted
|
||||||
|
m_frame.m_length = 0U;
|
||||||
|
m_hdlcState = AX25_IDLE;
|
||||||
|
m_hdlcFlag = false;
|
||||||
|
m_hdlcBits = 0U;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (m_hdlcState) {
|
||||||
|
case AX25_IDLE:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AX25_SYNC:
|
||||||
|
if (m_hdlcBits == 8U) { // 8th bit.
|
||||||
|
// Start of frame data.
|
||||||
|
m_hdlcState = AX25_RECEIVE;
|
||||||
|
m_frame.append(m_hdlcBuffer);
|
||||||
|
m_hdlcBits = 0U;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AX25_RECEIVE:
|
||||||
|
if (m_hdlcBits == 8U) { // 8th bit.
|
||||||
|
m_frame.append(m_hdlcBuffer);
|
||||||
|
m_hdlcBits = 0U;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25Demodulator::setTwist(int8_t n)
|
||||||
|
{
|
||||||
|
m_twist.setTwist(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAX25Demodulator::isDCD()
|
||||||
|
{
|
||||||
|
if (m_pllJitter <= (SAMPLES_PER_SYMBOL * 0.03F))
|
||||||
|
m_pllDCD = true;
|
||||||
|
else if (m_pllJitter >= (SAMPLES_PER_SYMBOL * 0.15F))
|
||||||
|
m_pllDCD = false;
|
||||||
|
|
||||||
|
return m_pllDCD;
|
||||||
|
}
|
||||||
|
|
||||||
|
float32_t CAX25Demodulator::iir(float32_t input)
|
||||||
|
{
|
||||||
|
for (int8_t i = int8_t(PLL_IIR_SIZE) - 1; i != 0; i--)
|
||||||
|
m_iirHistory[i] = m_iirHistory[i - 1];
|
||||||
|
|
||||||
|
m_iirHistory[0] = input;
|
||||||
|
for (uint8_t i = 1U; i < PLL_IIR_SIZE; i++)
|
||||||
|
m_iirHistory[0] -= PLL_LOCK_A[i] * m_iirHistory[i];
|
||||||
|
|
||||||
|
float32_t result = 0.0F;
|
||||||
|
for (uint8_t i = 0U; i < PLL_IIR_SIZE; i++)
|
||||||
|
result += PLL_LOCK_B[i] * m_iirHistory[i];
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(AX25Demodulator_H)
|
||||||
|
#define AX25Demodulator_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#include "AX25Frame.h"
|
||||||
|
#include "AX25Twist.h"
|
||||||
|
|
||||||
|
enum AX25_STATE {
|
||||||
|
AX25_IDLE,
|
||||||
|
AX25_SYNC,
|
||||||
|
AX25_RECEIVE
|
||||||
|
};
|
||||||
|
|
||||||
|
class CAX25Demodulator {
|
||||||
|
public:
|
||||||
|
CAX25Demodulator(int8_t n);
|
||||||
|
|
||||||
|
bool process(q15_t* samples, uint8_t length, CAX25Frame& frame);
|
||||||
|
|
||||||
|
void setTwist(int8_t n);
|
||||||
|
|
||||||
|
bool isDCD();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CAX25Frame m_frame;
|
||||||
|
CAX25Twist m_twist;
|
||||||
|
arm_fir_instance_q15 m_lpfFilter;
|
||||||
|
q15_t m_lpfState[70U]; // NoTaps + BlockSize - 1, 48 + 20 - 1 plus some spare
|
||||||
|
bool* m_delayLine;
|
||||||
|
uint16_t m_delayPos;
|
||||||
|
bool m_nrziState;
|
||||||
|
arm_fir_instance_f32 m_pllFilter;
|
||||||
|
float32_t m_pllState[20U]; // NoTaps + BlockSize - 1, 7 + 1 - 1 plus some spare
|
||||||
|
bool m_pllLast;
|
||||||
|
uint8_t m_pllBits;
|
||||||
|
float32_t m_pllCount;
|
||||||
|
float32_t m_pllJitter;
|
||||||
|
bool m_pllDCD;
|
||||||
|
float32_t m_iirHistory[5U];
|
||||||
|
uint16_t m_hdlcOnes;
|
||||||
|
bool m_hdlcFlag;
|
||||||
|
uint16_t m_hdlcBuffer;
|
||||||
|
uint16_t m_hdlcBits;
|
||||||
|
AX25_STATE m_hdlcState;
|
||||||
|
|
||||||
|
bool delay(bool b);
|
||||||
|
bool NRZI(bool b);
|
||||||
|
bool PLL(bool b);
|
||||||
|
bool HDLC(bool b);
|
||||||
|
float32_t iir(float32_t input);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+122
@@ -0,0 +1,122 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "AX25Frame.h"
|
||||||
|
|
||||||
|
const uint16_t CCITT_TABLE[] = {
|
||||||
|
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 };
|
||||||
|
|
||||||
|
CAX25Frame::CAX25Frame(const uint8_t* data, uint16_t length) :
|
||||||
|
m_data(),
|
||||||
|
m_length(0U),
|
||||||
|
m_fcs(0U)
|
||||||
|
{
|
||||||
|
for (uint16_t i = 0U; i < length && i < (AX25_MAX_PACKET_LEN - 2U); i++)
|
||||||
|
m_data[m_length++] = data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
CAX25Frame::CAX25Frame() :
|
||||||
|
m_data(),
|
||||||
|
m_length(0U),
|
||||||
|
m_fcs(0U)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAX25Frame::append(uint16_t c)
|
||||||
|
{
|
||||||
|
if (m_length == AX25_MAX_PACKET_LEN)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
m_data[m_length++] = uint8_t(c);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAX25Frame::checkCRC()
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
uint16_t crc16;
|
||||||
|
uint8_t crc8[2U];
|
||||||
|
};
|
||||||
|
|
||||||
|
crc16 = 0xFFFFU;
|
||||||
|
for (uint16_t i = 0U; i < (m_length - 2U); i++)
|
||||||
|
crc16 = uint16_t(crc8[1U]) ^ CCITT_TABLE[crc8[0U] ^ m_data[i]];
|
||||||
|
|
||||||
|
crc16 = ~crc16;
|
||||||
|
|
||||||
|
if (crc8[0U] == m_data[m_length - 2U] && crc8[1U] == m_data[m_length - 1U]) {
|
||||||
|
m_fcs = crc16;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25Frame::addCRC()
|
||||||
|
{
|
||||||
|
union {
|
||||||
|
uint16_t crc16;
|
||||||
|
uint8_t crc8[2U];
|
||||||
|
};
|
||||||
|
|
||||||
|
crc16 = 0xFFFFU;
|
||||||
|
for (uint16_t i = 0U; i < m_length; i++)
|
||||||
|
crc16 = uint16_t(crc8[1U]) ^ CCITT_TABLE[crc8[0U] ^ m_data[i]];
|
||||||
|
|
||||||
|
crc16 = ~crc16;
|
||||||
|
|
||||||
|
m_fcs = crc16;
|
||||||
|
|
||||||
|
m_data[m_length++] = crc8[0U];
|
||||||
|
m_data[m_length++] = crc8[1U];
|
||||||
|
}
|
||||||
|
|
||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(AX25Frame_H)
|
||||||
|
#define AX25Frame_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
const uint16_t AX25_MAX_PACKET_LEN = 300U;
|
||||||
|
|
||||||
|
class CAX25Frame {
|
||||||
|
public:
|
||||||
|
CAX25Frame(const uint8_t* data, uint16_t length);
|
||||||
|
CAX25Frame();
|
||||||
|
|
||||||
|
bool append(uint16_t c);
|
||||||
|
|
||||||
|
bool checkCRC();
|
||||||
|
|
||||||
|
void addCRC();
|
||||||
|
|
||||||
|
uint8_t m_data[AX25_MAX_PACKET_LEN];
|
||||||
|
uint16_t m_length;
|
||||||
|
uint16_t m_fcs;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+205
@@ -0,0 +1,205 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "AX25RX.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generated with Scipy Filter, 152 coefficients, 1100-2300Hz bandpass,
|
||||||
|
* Hann window, starting and ending 0 value coefficients removed.
|
||||||
|
*
|
||||||
|
* np.array(
|
||||||
|
* firwin2(152,
|
||||||
|
* [
|
||||||
|
* 0.0,
|
||||||
|
* 1000.0/(sample_rate/2),
|
||||||
|
* 1100.0/(sample_rate/2),
|
||||||
|
* 2350.0/(sample_rate/2),
|
||||||
|
* 2500.0/(sample_rate/2),
|
||||||
|
* 1.0
|
||||||
|
* ],
|
||||||
|
* [0,0,1,1,0,0],
|
||||||
|
* antisymmetric = False,
|
||||||
|
* window='hann') * 32768,
|
||||||
|
* dtype=int)[10:-10]
|
||||||
|
*/
|
||||||
|
|
||||||
|
const uint32_t FILTER_LEN = 130U;
|
||||||
|
|
||||||
|
q15_t FILTER_COEFFS[] = {
|
||||||
|
5, 12, 18, 21, 19, 11, -2, -15, -25, -27,
|
||||||
|
-21, -11, -3, -5, -19, -43, -69, -83, -73, -35,
|
||||||
|
27, 98, 155, 180, 163, 109, 39, -20, -45, -26,
|
||||||
|
23, 74, 89, 39, -81, -247, -407, -501, -480, -334,
|
||||||
|
-92, 175, 388, 479, 429, 275, 99, 5, 68, 298,
|
||||||
|
626, 913, 994, 740, 115, -791, -1770, -2544, -2847, -2509,
|
||||||
|
-1527, -76, 1518, 2875, 3653, 3653, 2875, 1518, -76, -1527,
|
||||||
|
-2509, -2847, -2544, -1770, -791, 115, 740, 994, 913, 626,
|
||||||
|
298, 68, 5, 99, 275, 429, 479, 388, 175, -92,
|
||||||
|
-334, -480, -501, -407, -247, -81, 39, 89, 74, 23,
|
||||||
|
-26, -45, -20, 39, 109, 163, 180, 155, 98, 27,
|
||||||
|
-35, -73, -83, -69, -43, -19, -5, -3, -11, -21,
|
||||||
|
-27, -25, -15, -2, 11, 19, 21, 18, 12, 5
|
||||||
|
};
|
||||||
|
|
||||||
|
CAX25RX::CAX25RX() :
|
||||||
|
m_filter(),
|
||||||
|
m_state(),
|
||||||
|
m_demod1(3),
|
||||||
|
m_demod2(6),
|
||||||
|
m_demod3(9),
|
||||||
|
m_lastFCS(0U),
|
||||||
|
m_count(0U),
|
||||||
|
m_slotTime(30U),
|
||||||
|
m_slotCount(0U),
|
||||||
|
m_pPersist(128U),
|
||||||
|
m_dcd(false),
|
||||||
|
m_canTX(false),
|
||||||
|
m_x(1U),
|
||||||
|
m_a(0xB7U),
|
||||||
|
m_b(0x73U),
|
||||||
|
m_c(0xF6U)
|
||||||
|
{
|
||||||
|
m_filter.numTaps = FILTER_LEN;
|
||||||
|
m_filter.pState = m_state;
|
||||||
|
m_filter.pCoeffs = FILTER_COEFFS;
|
||||||
|
|
||||||
|
initRand();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25RX::samples(q15_t* samples, uint8_t length)
|
||||||
|
{
|
||||||
|
q15_t output[RX_BLOCK_SIZE];
|
||||||
|
::arm_fir_fast_q15(&m_filter, samples, output, RX_BLOCK_SIZE);
|
||||||
|
|
||||||
|
m_count++;
|
||||||
|
|
||||||
|
CAX25Frame frame;
|
||||||
|
|
||||||
|
bool ret = m_demod1.process(output, length, frame);
|
||||||
|
if (ret) {
|
||||||
|
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
|
||||||
|
m_lastFCS = frame.m_fcs;
|
||||||
|
m_count = 0U;
|
||||||
|
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
|
||||||
|
}
|
||||||
|
DEBUG1("Decoder 1 reported");
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = m_demod2.process(output, length, frame);
|
||||||
|
if (ret) {
|
||||||
|
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
|
||||||
|
m_lastFCS = frame.m_fcs;
|
||||||
|
m_count = 0U;
|
||||||
|
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
|
||||||
|
}
|
||||||
|
DEBUG1("Decoder 2 reported");
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = m_demod3.process(output, length, frame);
|
||||||
|
if (ret) {
|
||||||
|
if (frame.m_fcs != m_lastFCS || m_count > 2U) {
|
||||||
|
m_lastFCS = frame.m_fcs;
|
||||||
|
m_count = 0U;
|
||||||
|
serial.writeAX25Data(frame.m_data, frame.m_length - 2U);
|
||||||
|
}
|
||||||
|
DEBUG1("Decoder 3 reported");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_slotCount += RX_BLOCK_SIZE;
|
||||||
|
if (m_slotCount >= m_slotTime) {
|
||||||
|
m_slotCount = 0U;
|
||||||
|
|
||||||
|
bool dcd1 = m_demod1.isDCD();
|
||||||
|
bool dcd2 = m_demod2.isDCD();
|
||||||
|
bool dcd3 = m_demod3.isDCD();
|
||||||
|
|
||||||
|
if (dcd1 || dcd2 || dcd3) {
|
||||||
|
if (!m_dcd) {
|
||||||
|
io.setDecode(true);
|
||||||
|
io.setADCDetection(true);
|
||||||
|
m_dcd = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_canTX = false;
|
||||||
|
} else {
|
||||||
|
if (m_dcd) {
|
||||||
|
io.setDecode(false);
|
||||||
|
io.setADCDetection(false);
|
||||||
|
m_dcd = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_canTX = m_pPersist >= rand();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAX25RX::canTX() const
|
||||||
|
{
|
||||||
|
return m_canTX;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25RX::setParams(int8_t twist, uint8_t slotTime, uint8_t pPersist)
|
||||||
|
{
|
||||||
|
m_demod1.setTwist(twist - 3);
|
||||||
|
m_demod2.setTwist(twist);
|
||||||
|
m_demod3.setTwist(twist + 3);
|
||||||
|
|
||||||
|
m_slotTime = slotTime * 240U; // Slot time in samples
|
||||||
|
m_pPersist = pPersist;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Taken from https://www.electro-tech-online.com/threads/ultra-fast-pseudorandom-number-generator-for-8-bit.124249/
|
||||||
|
//X ABC Algorithm Random Number Generator for 8-Bit Devices:
|
||||||
|
//This is a small PRNG, experimentally verified to have at least a 50 million byte period
|
||||||
|
//by generating 50 million bytes and observing that there were no overapping sequences and repeats.
|
||||||
|
//This generator passes serial correlation, entropy , Monte Carlo Pi value, arithmetic mean,
|
||||||
|
//And many other statistical tests. This generator may have a period of up to 2^32, but this has
|
||||||
|
//not been verified.
|
||||||
|
//
|
||||||
|
// By XORing 3 bytes into the a,b, and c registers, you can add in entropy from
|
||||||
|
//an external source easily.
|
||||||
|
//
|
||||||
|
//This generator is free to use, but is not suitable for cryptography due to its short period(by //cryptographic standards) and simple construction. No attempt was made to make this generator
|
||||||
|
// suitable for cryptographic use.
|
||||||
|
//
|
||||||
|
//Due to the use of a constant counter, the generator should be resistant to latching up.
|
||||||
|
//A significant performance gain is had in that the x variable is only ever incremented.
|
||||||
|
//
|
||||||
|
//Only 4 bytes of ram are needed for the internal state, and generating a byte requires 3 XORs , //2 ADDs, one bit shift right , and one increment. Difficult or slow operations like multiply, etc
|
||||||
|
//were avoided for maximum speed on ultra low power devices.
|
||||||
|
|
||||||
|
|
||||||
|
void CAX25RX::initRand() //Can also be used to seed the rng with more entropy during use.
|
||||||
|
{
|
||||||
|
m_a = (m_a ^ m_c ^ m_x);
|
||||||
|
m_b = (m_b + m_a);
|
||||||
|
m_c = (m_c + (m_b >> 1) ^ m_a);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CAX25RX::rand()
|
||||||
|
{
|
||||||
|
m_x++; //x is incremented every round and is not affected by any other variable
|
||||||
|
|
||||||
|
m_a = (m_a ^ m_c ^ m_x); //note the mix of addition and XOR
|
||||||
|
m_b = (m_b + m_a); //And the use of very few instructions
|
||||||
|
m_c = (m_c + (m_b >> 1) ^ m_a); //the right shift is to ensure that high-order bits from b can affect
|
||||||
|
|
||||||
|
return uint8_t(m_c); //low order bits of other variables
|
||||||
|
}
|
||||||
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(AX25RX_H)
|
||||||
|
#define AX25RX_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#include "AX25Demodulator.h"
|
||||||
|
|
||||||
|
class CAX25RX {
|
||||||
|
public:
|
||||||
|
CAX25RX();
|
||||||
|
|
||||||
|
void samples(q15_t* samples, uint8_t length);
|
||||||
|
|
||||||
|
void setParams(int8_t twist, uint8_t slotTime, uint8_t pPersist);
|
||||||
|
|
||||||
|
bool canTX() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
arm_fir_instance_q15 m_filter;
|
||||||
|
q15_t m_state[160U]; // NoTaps + BlockSize - 1, 130 + 20 - 1 plus some spare
|
||||||
|
CAX25Demodulator m_demod1;
|
||||||
|
CAX25Demodulator m_demod2;
|
||||||
|
CAX25Demodulator m_demod3;
|
||||||
|
uint16_t m_lastFCS;
|
||||||
|
uint32_t m_count;
|
||||||
|
uint32_t m_slotTime;
|
||||||
|
uint32_t m_slotCount;
|
||||||
|
uint8_t m_pPersist;
|
||||||
|
bool m_dcd;
|
||||||
|
bool m_canTX;
|
||||||
|
uint8_t m_x;
|
||||||
|
uint8_t m_a;
|
||||||
|
uint8_t m_b;
|
||||||
|
uint8_t m_c;
|
||||||
|
|
||||||
|
void initRand();
|
||||||
|
uint8_t rand();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+186
@@ -0,0 +1,186 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "AX25TX.h"
|
||||||
|
|
||||||
|
#include "AX25Defines.h"
|
||||||
|
#include "AX25Frame.h"
|
||||||
|
|
||||||
|
|
||||||
|
const uint8_t START_FLAG[] = { AX25_FRAME_START };
|
||||||
|
const uint8_t END_FLAG[] = { AX25_FRAME_END };
|
||||||
|
|
||||||
|
const uint8_t BIT_MASK_TABLE1[] = { 0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U };
|
||||||
|
|
||||||
|
#define WRITE_BIT1(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE1[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE1[(i)&7])
|
||||||
|
#define READ_BIT1(p,i) (p[(i)>>3] & BIT_MASK_TABLE1[(i)&7])
|
||||||
|
|
||||||
|
const uint8_t BIT_MASK_TABLE2[] = { 0x01U, 0x02U, 0x04U, 0x08U, 0x10U, 0x20U, 0x40U, 0x80U };
|
||||||
|
|
||||||
|
#define WRITE_BIT2(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE2[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE2[(i)&7])
|
||||||
|
#define READ_BIT2(p,i) (p[(i)>>3] & BIT_MASK_TABLE2[(i)&7])
|
||||||
|
|
||||||
|
const uint16_t AUDIO_TABLE_LEN = 120U;
|
||||||
|
|
||||||
|
const q15_t AUDIO_TABLE_DATA[] = {
|
||||||
|
0, 214, 428, 641, 851, 1060, 1265, 1468, 1666, 1859, 2048, 2230, 2407, 2577, 2740, 2896, 3043, 3182, 3313, 3434, 3546, 3649,
|
||||||
|
3741, 3823, 3895, 3955, 4006, 4045, 4073, 4089, 4095, 4089, 4073, 4045, 4006, 3955, 3895, 3823, 3741, 3649, 3546, 3434, 3313,
|
||||||
|
3182, 3043, 2896, 2740, 2577, 2407, 2230, 2048, 1859, 1666, 1468, 1265, 1060, 851, 641, 428, 214, 0, -214, -428, -641, -851,
|
||||||
|
-1060, -1265, -1468, -1666, -1859, -2047, -2230, -2407, -2577, -2740, -2896, -3043, -3182, -3313, -3434, -3546, -3649, -3741,
|
||||||
|
-3823, -3895, -3955, -4006, -4045, -4073, -4089, -4095, -4089, -4073, -4045, -4006, -3955, -3895, -3823, -3741, -3649, -3546,
|
||||||
|
-3434, -3313, -3182, -3043, -2896, -2740, -2577, -2407, -2230, -2047, -1859, -1666, -1468, -1265, -1060, -851, -641, -428, -214
|
||||||
|
};
|
||||||
|
|
||||||
|
CAX25TX::CAX25TX() :
|
||||||
|
m_poBuffer(),
|
||||||
|
m_poLen(0U),
|
||||||
|
m_poPtr(0U),
|
||||||
|
m_txDelay(360U),
|
||||||
|
m_tablePtr(0U),
|
||||||
|
m_nrzi(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25TX::process()
|
||||||
|
{
|
||||||
|
if (m_poLen == 0U)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!m_duplex) {
|
||||||
|
if (m_poPtr == 0U) {
|
||||||
|
bool tx = ax25RX.canTX();
|
||||||
|
if (!tx)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t space = io.getSpace();
|
||||||
|
|
||||||
|
while (space > AX25_RADIO_SYMBOL_LENGTH) {
|
||||||
|
bool b = READ_BIT1(m_poBuffer, m_poPtr) != 0U;
|
||||||
|
m_poPtr++;
|
||||||
|
|
||||||
|
writeBit(b);
|
||||||
|
|
||||||
|
space -= AX25_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
if (m_poPtr >= m_poLen) {
|
||||||
|
m_poPtr = 0U;
|
||||||
|
m_poLen = 0U;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CAX25TX::writeData(const uint8_t* data, uint16_t length)
|
||||||
|
{
|
||||||
|
CAX25Frame frame(data, length);
|
||||||
|
frame.addCRC();
|
||||||
|
|
||||||
|
m_poLen = 0U;
|
||||||
|
m_poPtr = 0U;
|
||||||
|
m_nrzi = false;
|
||||||
|
m_tablePtr = 0U;
|
||||||
|
|
||||||
|
// Add TX delay
|
||||||
|
for (uint16_t i = 0U; i < m_txDelay; i++, m_poLen++) {
|
||||||
|
bool preamble = NRZI(false);
|
||||||
|
WRITE_BIT1(m_poBuffer, m_poLen, preamble);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the Start Flag
|
||||||
|
for (uint16_t i = 0U; i < 8U; i++, m_poLen++) {
|
||||||
|
bool b1 = READ_BIT1(START_FLAG, i) != 0U;
|
||||||
|
bool b2 = NRZI(b1);
|
||||||
|
WRITE_BIT1(m_poBuffer, m_poLen, b2);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t ones = 0U;
|
||||||
|
for (uint16_t i = 0U; i < (frame.m_length * 8U); i++) {
|
||||||
|
bool b1 = READ_BIT2(frame.m_data, i) != 0U;
|
||||||
|
bool b2 = NRZI(b1);
|
||||||
|
WRITE_BIT1(m_poBuffer, m_poLen, b2);
|
||||||
|
m_poLen++;
|
||||||
|
|
||||||
|
if (b1) {
|
||||||
|
ones++;
|
||||||
|
if (ones == AX25_MAX_ONES) {
|
||||||
|
// Bit stuffing
|
||||||
|
bool b = NRZI(false);
|
||||||
|
WRITE_BIT1(m_poBuffer, m_poLen, b);
|
||||||
|
m_poLen++;
|
||||||
|
ones = 0U;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ones = 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the End Flag
|
||||||
|
for (uint16_t i = 0U; i < 8U; i++, m_poLen++) {
|
||||||
|
bool b1 = READ_BIT1(END_FLAG, i) != 0U;
|
||||||
|
bool b2 = NRZI(b1);
|
||||||
|
WRITE_BIT1(m_poBuffer, m_poLen, b2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25TX::writeBit(bool b)
|
||||||
|
{
|
||||||
|
q15_t buffer[AX25_RADIO_SYMBOL_LENGTH];
|
||||||
|
for (uint8_t i = 0U; i < AX25_RADIO_SYMBOL_LENGTH; i++) {
|
||||||
|
q15_t value = AUDIO_TABLE_DATA[m_tablePtr];
|
||||||
|
|
||||||
|
if (b) {
|
||||||
|
// De-emphasise the lower frequency by 6dB
|
||||||
|
value >>= 2;
|
||||||
|
m_tablePtr += 6U;
|
||||||
|
} else {
|
||||||
|
m_tablePtr += 11U;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[i] = value;
|
||||||
|
|
||||||
|
if (m_tablePtr >= AUDIO_TABLE_LEN)
|
||||||
|
m_tablePtr -= AUDIO_TABLE_LEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
io.write(STATE_AX25, buffer, AX25_RADIO_SYMBOL_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25TX::setTXDelay(uint8_t delay)
|
||||||
|
{
|
||||||
|
m_txDelay = delay * 12U;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CAX25TX::getSpace() const
|
||||||
|
{
|
||||||
|
return m_poLen == 0U ? 255U : 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CAX25TX::NRZI(bool b)
|
||||||
|
{
|
||||||
|
if (!b)
|
||||||
|
m_nrzi = !m_nrzi;
|
||||||
|
|
||||||
|
return m_nrzi;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(AX25TX_H)
|
||||||
|
#define AX25TX_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
class CAX25TX {
|
||||||
|
public:
|
||||||
|
CAX25TX();
|
||||||
|
|
||||||
|
uint8_t writeData(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
|
void process();
|
||||||
|
|
||||||
|
void setTXDelay(uint8_t delay);
|
||||||
|
|
||||||
|
uint8_t getSpace() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t m_poBuffer[600U];
|
||||||
|
uint16_t m_poLen;
|
||||||
|
uint16_t m_poPtr;
|
||||||
|
uint16_t m_txDelay;
|
||||||
|
uint16_t m_tablePtr;
|
||||||
|
bool m_nrzi;
|
||||||
|
|
||||||
|
void writeBit(bool b);
|
||||||
|
bool NRZI(bool b);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+311
@@ -0,0 +1,311 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "AX25Twist.h"
|
||||||
|
|
||||||
|
// 1200Hz = -12dB, 2200Hz = 0dB; 3381Hz cutoff; cosine.
|
||||||
|
q15_t dB12[] = {
|
||||||
|
176,
|
||||||
|
-812,
|
||||||
|
-3916,
|
||||||
|
-7586,
|
||||||
|
23536,
|
||||||
|
-7586,
|
||||||
|
-3916,
|
||||||
|
-812,
|
||||||
|
176
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -11dB, 2200Hz = 0dB; 3258Hz cutoff; cosine.
|
||||||
|
q15_t dB11[] = {
|
||||||
|
121,
|
||||||
|
-957,
|
||||||
|
-3959,
|
||||||
|
-7383,
|
||||||
|
23871,
|
||||||
|
-7383,
|
||||||
|
-3959,
|
||||||
|
-957,
|
||||||
|
121
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -10dB, 2200Hz = 0dB; 3118Hz cutoff; cosine.
|
||||||
|
q15_t dB10[] = {
|
||||||
|
56,
|
||||||
|
-1110,
|
||||||
|
-3987,
|
||||||
|
-7141,
|
||||||
|
24254,
|
||||||
|
-7141,
|
||||||
|
-3987,
|
||||||
|
-1110,
|
||||||
|
56
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -9dB, 2200Hz = 0dB; 2959Hz cutoff; cosine.
|
||||||
|
q15_t dB9[] = {
|
||||||
|
-19,
|
||||||
|
-1268,
|
||||||
|
-3994,
|
||||||
|
-6856,
|
||||||
|
24688,
|
||||||
|
-6856,
|
||||||
|
-3994,
|
||||||
|
-1268,
|
||||||
|
-19
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -8dB, 2200Hz = 0dB; 2778Hz cutoff; cosine.
|
||||||
|
q15_t dB8[] = {
|
||||||
|
-104,
|
||||||
|
-1424,
|
||||||
|
-3968,
|
||||||
|
-6516,
|
||||||
|
25182,
|
||||||
|
-6516,
|
||||||
|
-3968,
|
||||||
|
-1424,
|
||||||
|
-104
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -7dB, 2200Hz = 0dB; 2573Hz cutoff; cosine.
|
||||||
|
q15_t dB7[] = {
|
||||||
|
-196,
|
||||||
|
-1565,
|
||||||
|
-3896,
|
||||||
|
-6114,
|
||||||
|
25742,
|
||||||
|
-6114,
|
||||||
|
-3896,
|
||||||
|
-1565,
|
||||||
|
-196
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -6dB, 2200Hz = 0dB; 2343Hz cutoff; cosine.
|
||||||
|
q15_t dB6[] = {
|
||||||
|
-288,
|
||||||
|
-1676,
|
||||||
|
-3761,
|
||||||
|
-5642,
|
||||||
|
26370,
|
||||||
|
-5642,
|
||||||
|
-3761,
|
||||||
|
-1676,
|
||||||
|
-288
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -5dB, 2200Hz = 0dB; 2085Hz cutoff; cosine.
|
||||||
|
q15_t dB5[] = {
|
||||||
|
-370,
|
||||||
|
-1735,
|
||||||
|
-3545,
|
||||||
|
-5088,
|
||||||
|
27075,
|
||||||
|
-5088,
|
||||||
|
-3545,
|
||||||
|
-1735,
|
||||||
|
-370
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -4dB, 2200Hz = 0dB; 1790Hz cutoff; cosine.
|
||||||
|
q15_t dB4[] = {
|
||||||
|
-432,
|
||||||
|
-1715,
|
||||||
|
-3220,
|
||||||
|
-4427,
|
||||||
|
27880,
|
||||||
|
-4427,
|
||||||
|
-3220,
|
||||||
|
-1715,
|
||||||
|
-432
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -3dB, 2200Hz = 0dB; 1456Hz cutoff; cosine.
|
||||||
|
q15_t dB3[] = {
|
||||||
|
-452,
|
||||||
|
-1582,
|
||||||
|
-2759,
|
||||||
|
-3646,
|
||||||
|
28792,
|
||||||
|
-3646,
|
||||||
|
-2759,
|
||||||
|
-1582,
|
||||||
|
-452
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -2dB, 2200Hz = 0dB; 1070Hz cutoff; cosine.
|
||||||
|
q15_t dB2[] = {
|
||||||
|
-408,
|
||||||
|
-1295,
|
||||||
|
-2123,
|
||||||
|
-2710,
|
||||||
|
29846,
|
||||||
|
-2710,
|
||||||
|
-2123,
|
||||||
|
-1295,
|
||||||
|
-408
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = -1dB, 2200Hz = 0dB; 605Hz cutoff; cosine.
|
||||||
|
q15_t dB1[] = {
|
||||||
|
-268,
|
||||||
|
-795,
|
||||||
|
-1244,
|
||||||
|
-1546,
|
||||||
|
31116,
|
||||||
|
-1546,
|
||||||
|
-1244,
|
||||||
|
-795,
|
||||||
|
-268
|
||||||
|
};
|
||||||
|
|
||||||
|
q15_t dB0[] = {
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
32767,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = 0dB, 2200Hz = -1dB; 4130Hz cutoff; cosine.
|
||||||
|
q15_t dB_1[] = {
|
||||||
|
-419,
|
||||||
|
-177,
|
||||||
|
3316,
|
||||||
|
8650,
|
||||||
|
11278,
|
||||||
|
8650,
|
||||||
|
3316,
|
||||||
|
-177,
|
||||||
|
-419
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = 0dB, 2200Hz = -2dB; 3190Hz cutoff; cosine.
|
||||||
|
q15_t dB_2[] = {
|
||||||
|
-90,
|
||||||
|
1033,
|
||||||
|
3975,
|
||||||
|
7267,
|
||||||
|
8711,
|
||||||
|
7267,
|
||||||
|
3975,
|
||||||
|
1033,
|
||||||
|
-90
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = 0dB, 2200Hz = -3dB; 2330Hz cutoff; cosine.
|
||||||
|
q15_t dB_3[] = {
|
||||||
|
292,
|
||||||
|
1680,
|
||||||
|
3752,
|
||||||
|
5615,
|
||||||
|
6362,
|
||||||
|
5615,
|
||||||
|
3752,
|
||||||
|
1680,
|
||||||
|
292
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = 0dB, 2200Hz = -4dB; 2657Hz cutoff; boxcar.
|
||||||
|
q15_t dB_4[] = {
|
||||||
|
917,
|
||||||
|
3024,
|
||||||
|
5131,
|
||||||
|
6684,
|
||||||
|
7255,
|
||||||
|
6684,
|
||||||
|
5131,
|
||||||
|
3024,
|
||||||
|
917
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = 0dB, 2200Hz = -5dB; 2360Hz cutoff; boxcar.
|
||||||
|
q15_t dB_5[] = {
|
||||||
|
1620,
|
||||||
|
3339,
|
||||||
|
4925,
|
||||||
|
6042,
|
||||||
|
6444,
|
||||||
|
6042,
|
||||||
|
4925,
|
||||||
|
3339,
|
||||||
|
1620
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1200Hz = 0dB, 2200Hz = -6dB; 2067Hz cutoff; boxcar.
|
||||||
|
q15_t dB_6[] = {
|
||||||
|
2161,
|
||||||
|
3472,
|
||||||
|
4605,
|
||||||
|
5373,
|
||||||
|
5644,
|
||||||
|
5373,
|
||||||
|
4605,
|
||||||
|
3472,
|
||||||
|
2161
|
||||||
|
};
|
||||||
|
|
||||||
|
q15_t* coeffs[] = {
|
||||||
|
dB12,
|
||||||
|
dB11,
|
||||||
|
dB10,
|
||||||
|
dB9,
|
||||||
|
dB8,
|
||||||
|
dB7,
|
||||||
|
dB6,
|
||||||
|
dB5,
|
||||||
|
dB4,
|
||||||
|
dB3,
|
||||||
|
dB2,
|
||||||
|
dB1,
|
||||||
|
dB0,
|
||||||
|
dB_1,
|
||||||
|
dB_2,
|
||||||
|
dB_3,
|
||||||
|
dB_4,
|
||||||
|
dB_5,
|
||||||
|
dB_6
|
||||||
|
};
|
||||||
|
|
||||||
|
CAX25Twist::CAX25Twist(int8_t n) :
|
||||||
|
m_filter(),
|
||||||
|
m_state()
|
||||||
|
{
|
||||||
|
setTwist(n);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25Twist::process(q15_t* in, q15_t* out, uint8_t length)
|
||||||
|
{
|
||||||
|
::arm_fir_fast_q15(&m_filter, in, out, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAX25Twist::setTwist(int8_t n)
|
||||||
|
{
|
||||||
|
uint8_t twist = uint8_t(n + 6);
|
||||||
|
|
||||||
|
m_filter.numTaps = 9;
|
||||||
|
m_filter.pState = m_state;
|
||||||
|
m_filter.pCoeffs = coeffs[twist];
|
||||||
|
}
|
||||||
|
|
||||||
+39
@@ -0,0 +1,39 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(AX25Twist_H)
|
||||||
|
#define AX25Twist_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
|
||||||
|
class CAX25Twist {
|
||||||
|
public:
|
||||||
|
CAX25Twist(int8_t n);
|
||||||
|
|
||||||
|
void process(q15_t* in, q15_t* out, uint8_t length);
|
||||||
|
|
||||||
|
void setTwist(int8_t n);
|
||||||
|
|
||||||
|
private:
|
||||||
|
arm_fir_instance_q15 m_filter;
|
||||||
|
q15_t m_state[40U]; // NoTaps + BlockSize - 1, 9 + 20 - 1 plus some spare
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+8
-8
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -22,12 +22,12 @@
|
|||||||
#include "CWIdTX.h"
|
#include "CWIdTX.h"
|
||||||
|
|
||||||
q15_t TONE[] = {
|
q15_t TONE[] = {
|
||||||
0, 261, 518, 765, 1000, 1218, 1414, 1587, 1732, 1848, 1932, 1983, 2000, 1983, 1932, 1848, 1732, 1587, 1414, 1218, 1000, 765, 518, 261, 0, -261, -518, -765, -1000, -1218, -1414,
|
0, 518, 1000, 1414, 1732, 1932, 2000, 1932, 1732, 1414, 1000, 518, 0, -518, -1000, -1414, -1732, -1932, -2000, -1932, -1732, -1414, -1000, -518};
|
||||||
-1587, -1732, -1848, -1932, -1983, -2000, -1983, -1932, -1848, -1732, -1587, -1414, -1218, -1000, -765, -518, -261};
|
|
||||||
q15_t SILENCE[] = {
|
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
||||||
|
|
||||||
const uint8_t CYCLE_LENGTH = 48U;
|
q15_t SILENCE[] = {
|
||||||
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
|
|
||||||
|
const uint8_t CYCLE_LENGTH = 24U;
|
||||||
|
|
||||||
const uint8_t DOT_LENGTH = 50U;
|
const uint8_t DOT_LENGTH = 50U;
|
||||||
|
|
||||||
@@ -77,6 +77,7 @@ const struct {
|
|||||||
{',', 0xEEAEE000U, 22U},
|
{',', 0xEEAEE000U, 22U},
|
||||||
{'-', 0xEAAE0000U, 18U},
|
{'-', 0xEAAE0000U, 18U},
|
||||||
{'=', 0xEAB80000U, 16U},
|
{'=', 0xEAB80000U, 16U},
|
||||||
|
{'.', 0xBAEB8000U, 20U},
|
||||||
{' ', 0x00000000U, 4U},
|
{' ', 0x00000000U, 4U},
|
||||||
{0U, 0x00000000U, 0U}
|
{0U, 0x00000000U, 0U}
|
||||||
};
|
};
|
||||||
@@ -124,7 +125,7 @@ void CCWIdTX::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CCWIdTX::write(const uint8_t* data, uint8_t length)
|
uint8_t CCWIdTX::write(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
::memset(m_poBuffer, 0x00U, 1000U * sizeof(uint8_t));
|
::memset(m_poBuffer, 0x00U, 1000U * sizeof(uint8_t));
|
||||||
|
|
||||||
@@ -170,4 +171,3 @@ void CCWIdTX::reset()
|
|||||||
m_poPtr = 0U;
|
m_poPtr = 0U;
|
||||||
m_n = 0U;
|
m_n = 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016,2020 by Colin Durbridge G4EML
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -28,7 +28,7 @@ public:
|
|||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
uint8_t write(const uint8_t* data, uint8_t length);
|
uint8_t write(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2015,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -208,7 +208,7 @@ void CCalDMR::dmrdmo1k()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CCalDMR::write(const uint8_t* data, uint8_t length)
|
uint8_t CCalDMR::write(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != 1U)
|
if (length != 1U)
|
||||||
return 4U;
|
return 4U;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2015,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -41,7 +41,7 @@ public:
|
|||||||
void createData1k(uint8_t n);
|
void createData1k(uint8_t n);
|
||||||
void createDataDMO1k(uint8_t n);
|
void createDataDMO1k(uint8_t n);
|
||||||
|
|
||||||
uint8_t write(const uint8_t* data, uint8_t length);
|
uint8_t write(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_transmit;
|
bool m_transmit;
|
||||||
|
|||||||
+1
-1
@@ -24,7 +24,7 @@
|
|||||||
const unsigned int BUFFER_LENGTH = 200U;
|
const unsigned int BUFFER_LENGTH = 200U;
|
||||||
|
|
||||||
const uint32_t PLLMAX = 0x10000U;
|
const uint32_t PLLMAX = 0x10000U;
|
||||||
const uint32_t PLLINC = PLLMAX / DSTAR_RADIO_SYMBOL_LENGTH;
|
const uint32_t PLLINC = PLLMAX / DSTAR_RADIO_BIT_LENGTH;
|
||||||
const uint32_t INC = PLLINC / 32U;
|
const uint32_t INC = PLLINC / 32U;
|
||||||
|
|
||||||
// D-Star bit order version of 0x55 0x2D 0x16
|
// D-Star bit order version of 0x55 0x2D 0x16
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2016,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -162,7 +162,7 @@ void CCalDStarTX::process()
|
|||||||
m_count = (m_count + 1U) % (30U * 21U);
|
m_count = (m_count + 1U) % (30U * 21U);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CCalDStarTX::write(const uint8_t* data, uint8_t length)
|
uint8_t CCalDStarTX::write(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != 1U)
|
if (length != 1U)
|
||||||
return 4U;
|
return 4U;
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -26,7 +26,7 @@ class CCalDStarTX {
|
|||||||
public:
|
public:
|
||||||
CCalDStarTX();
|
CCalDStarTX();
|
||||||
|
|
||||||
uint8_t write(const uint8_t* data, uint8_t length);
|
uint8_t write(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2015,2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
|
* Copyright (C) 2020 by Phil Taylor M0VSE
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "CalFM.h"
|
||||||
|
|
||||||
|
|
||||||
|
const struct TONE_TABLE {
|
||||||
|
uint16_t frequency;
|
||||||
|
uint16_t length;
|
||||||
|
q31_t increment;
|
||||||
|
} TONE_TABLE_DATA[] = {
|
||||||
|
{2495U, 10U, 223248821},
|
||||||
|
{2079U, 12U, 186025772},
|
||||||
|
{1633U, 15U, 146118367},
|
||||||
|
{1247U, 19U, 111579672},
|
||||||
|
{1039U, 23U, 93012886},
|
||||||
|
{956U, 25U, 85541432}};
|
||||||
|
|
||||||
|
const uint8_t TONE_TABLE_DATA_LEN = 6U;
|
||||||
|
|
||||||
|
CCalFM::CCalFM() :
|
||||||
|
m_frequency(0),
|
||||||
|
m_length(0),
|
||||||
|
m_tone(NULL),
|
||||||
|
m_level(128 * 12),
|
||||||
|
m_transmit(false),
|
||||||
|
m_audioSeq(0),
|
||||||
|
m_lastState(STATE_IDLE)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCalFM::process()
|
||||||
|
{
|
||||||
|
const TONE_TABLE* entry = NULL;
|
||||||
|
|
||||||
|
if (m_modemState != m_lastState)
|
||||||
|
{
|
||||||
|
switch (m_modemState) {
|
||||||
|
case STATE_FMCAL10K:
|
||||||
|
m_frequency = 956U;
|
||||||
|
break;
|
||||||
|
case STATE_FMCAL12K:
|
||||||
|
m_frequency = 1039U;
|
||||||
|
break;
|
||||||
|
case STATE_FMCAL15K:
|
||||||
|
m_frequency = 1247U;
|
||||||
|
break;
|
||||||
|
case STATE_FMCAL20K:
|
||||||
|
m_frequency = 1633U;
|
||||||
|
break;
|
||||||
|
case STATE_FMCAL25K:
|
||||||
|
m_frequency = 2079U;
|
||||||
|
break;
|
||||||
|
case STATE_FMCAL30K:
|
||||||
|
m_frequency = 2495U;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
m_frequency = 0U;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < TONE_TABLE_DATA_LEN; i++) {
|
||||||
|
if (TONE_TABLE_DATA[i].frequency == m_frequency) {
|
||||||
|
entry = TONE_TABLE_DATA + i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_length = entry->length;
|
||||||
|
|
||||||
|
delete[] m_tone;
|
||||||
|
m_tone = new q15_t[m_length];
|
||||||
|
|
||||||
|
q31_t arg = 0;
|
||||||
|
for (uint16_t i = 0U; i < m_length; i++) {
|
||||||
|
q63_t value = ::arm_sin_q31(arg) * q63_t(m_level);
|
||||||
|
m_tone[i] = q15_t(__SSAT((value >> 31), 16));
|
||||||
|
|
||||||
|
arg += entry->increment;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_lastState=m_modemState;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_transmit)
|
||||||
|
{
|
||||||
|
uint16_t space = io.getSpace();
|
||||||
|
while (space > m_length)
|
||||||
|
{
|
||||||
|
io.write(m_modemState,m_tone,m_length);
|
||||||
|
space -= m_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t CCalFM::write(const uint8_t* data, uint16_t length)
|
||||||
|
{
|
||||||
|
if (length != 1U)
|
||||||
|
return 4U;
|
||||||
|
|
||||||
|
m_transmit = data[0U] == 1U;
|
||||||
|
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009-2015,2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
|
* Copyright (C) 2020 by Phil Taylor M0VSE
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(CALFM_H)
|
||||||
|
#define CALFM_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
class CCalFM {
|
||||||
|
public:
|
||||||
|
CCalFM();
|
||||||
|
|
||||||
|
void process();
|
||||||
|
void fm10kcal();
|
||||||
|
void fm12k5cal();
|
||||||
|
void fm15kcal();
|
||||||
|
void fm20kcal();
|
||||||
|
void fm25kcal();
|
||||||
|
void fm30kcal();
|
||||||
|
|
||||||
|
uint8_t write(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t m_frequency;
|
||||||
|
uint16_t m_length;
|
||||||
|
q15_t* m_tone;
|
||||||
|
q15_t m_level;
|
||||||
|
bool m_transmit;
|
||||||
|
uint8_t m_audioSeq;
|
||||||
|
uint8_t m_lastState;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -79,7 +80,7 @@ void CCalNXDN::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CCalNXDN::write(const uint8_t* data, uint8_t length)
|
uint8_t CCalNXDN::write(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != 1U)
|
if (length != 1U)
|
||||||
return 4U;
|
return 4U;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -32,7 +33,7 @@ public:
|
|||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
uint8_t write(const uint8_t* data, uint8_t length);
|
uint8_t write(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_transmit;
|
bool m_transmit;
|
||||||
|
|||||||
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -82,7 +83,7 @@ void CCalP25::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CCalP25::write(const uint8_t* data, uint8_t length)
|
uint8_t CCalP25::write(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != 1U)
|
if (length != 1U)
|
||||||
return 4U;
|
return 4U;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
* Copyright (C) 2018 by Andy Uribe CA6JAU
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -34,7 +35,7 @@ public:
|
|||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
uint8_t write(const uint8_t* data, uint8_t length);
|
uint8_t write(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool m_transmit;
|
bool m_transmit;
|
||||||
|
|||||||
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 by Florian Wolters DF2ET
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "CalPOCSAG.h"
|
||||||
|
|
||||||
|
|
||||||
|
CCalPOCSAG::CCalPOCSAG() :
|
||||||
|
m_state(POCSAGCAL_IDLE)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CCalPOCSAG::process()
|
||||||
|
{
|
||||||
|
if (m_state == POCSAGCAL_IDLE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint16_t space = io.getSpace();
|
||||||
|
if (space <= 165U)
|
||||||
|
return;
|
||||||
|
|
||||||
|
pocsagTX.writeByte(0xAAU);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CCalPOCSAG::write(const uint8_t* data, uint16_t length)
|
||||||
|
{
|
||||||
|
if (length != 1U)
|
||||||
|
return 4U;
|
||||||
|
|
||||||
|
m_state = data[0U] == 1U ? POCSAGCAL_TX : POCSAGCAL_IDLE;
|
||||||
|
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019 by Florian Wolters DF2ET
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(CALPOCSAG_H)
|
||||||
|
#define CALPOCSAG_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
enum POCSAGCAL {
|
||||||
|
POCSAGCAL_IDLE,
|
||||||
|
POCSAGCAL_TX
|
||||||
|
};
|
||||||
|
|
||||||
|
class CCalPOCSAG {
|
||||||
|
public:
|
||||||
|
CCalPOCSAG();
|
||||||
|
|
||||||
|
void process();
|
||||||
|
|
||||||
|
uint8_t write(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
POCSAGCAL m_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -35,27 +35,34 @@
|
|||||||
// For 19.2 MHz
|
// For 19.2 MHz
|
||||||
// #define EXTERNAL_OSC 19200000
|
// #define EXTERNAL_OSC 19200000
|
||||||
|
|
||||||
|
// Use a higher baudrate for host communication. Required for FM network !
|
||||||
|
#define SERIAL_SPEED 115200 //suitable for most older boards (Arduino, Due STM32F1_POG etc). External FM will NOT work with this !
|
||||||
|
// #define SERIAL_SPEED 230400 // Only works on newer board M4, M7, Teensy. External FM might work with this
|
||||||
|
// #define SERIAL_SPEED 460800 // Only works on newer board M4, M7, Teensy. External FM should work with this
|
||||||
|
|
||||||
// Allow the use of the COS line to lockout the modem
|
// Allow the use of the COS line to lockout the modem
|
||||||
// #define USE_COS_AS_LOCKOUT
|
// #define USE_COS_AS_LOCKOUT
|
||||||
|
|
||||||
// Use pins to output the current mode via LEDs
|
// Use pins to output the current mode via LEDs
|
||||||
// #define MODE_LEDS
|
#define MODE_LEDS
|
||||||
|
|
||||||
// For the original Arduino Due pin layout
|
// For the original Arduino Due pin layout
|
||||||
// #define ARDUINO_DUE_PAPA
|
// #define ARDUINO_DUE_PAPA
|
||||||
|
|
||||||
// For the ZUM V1.0 and V1.0.1 boards pin layout
|
#if defined(STM32F1)
|
||||||
// #define ARDUINO_DUE_ZUM_V10
|
|
||||||
|
|
||||||
// For the SQ6POG board
|
// For the SQ6POG board
|
||||||
// #define STM32F1_POG
|
#define STM32F1_POG
|
||||||
|
#else
|
||||||
|
// For the ZUM V1.0 and V1.0.1 boards pin layout
|
||||||
|
#define ARDUINO_DUE_ZUM_V10
|
||||||
|
#endif
|
||||||
|
|
||||||
// For the SP8NTH board
|
// For the SP8NTH board
|
||||||
// #define ARDUINO_DUE_NTH
|
// #define ARDUINO_DUE_NTH
|
||||||
|
|
||||||
// For ST Nucleo-64 STM32F446RE board
|
// For ST Nucleo-64 STM32F446RE board
|
||||||
// #define STM32F4_NUCLEO_MORPHO_HEADER
|
// #define STM32F4_NUCLEO_MORPHO_HEADER
|
||||||
#define STM32F4_NUCLEO_ARDUINO_HEADER
|
// #define STM32F4_NUCLEO_ARDUINO_HEADER
|
||||||
|
|
||||||
// Use separate mode pins to switch external channel/filters/bandwidth for example
|
// Use separate mode pins to switch external channel/filters/bandwidth for example
|
||||||
// #define MODE_PINS
|
// #define MODE_PINS
|
||||||
@@ -64,13 +71,13 @@
|
|||||||
// #define VK6MST_TEENSY_PI3_SHIELD_I2C
|
// #define VK6MST_TEENSY_PI3_SHIELD_I2C
|
||||||
|
|
||||||
// Pass RSSI information to the host
|
// Pass RSSI information to the host
|
||||||
#define SEND_RSSI_DATA
|
// #define SEND_RSSI_DATA
|
||||||
|
|
||||||
// Use the modem as a serial repeater for Nextion displays
|
// Use the modem as a serial repeater for Nextion displays
|
||||||
// #define SERIAL_REPEATER
|
// #define SERIAL_REPEATER
|
||||||
|
|
||||||
// To reduce CPU load, you can remove the DC blocker by commenting out the next line
|
// To reduce CPU load, you can remove the DC blocker by commenting out the next line
|
||||||
// #define USE_DCBLOCKER
|
#define USE_DCBLOCKER
|
||||||
|
|
||||||
// Constant Service LED once repeater is running
|
// Constant Service LED once repeater is running
|
||||||
// Do not use if employing an external hardware watchdog
|
// Do not use if employing an external hardware watchdog
|
||||||
@@ -82,7 +89,8 @@
|
|||||||
// Use the D-Star and DMR LEDs for POCSAG
|
// Use the D-Star and DMR LEDs for POCSAG
|
||||||
// #define USE_ALTERNATE_POCSAG_LEDS
|
// #define USE_ALTERNATE_POCSAG_LEDS
|
||||||
|
|
||||||
// Select BOXCAR Filter into D-Star
|
// Use the D-Star and YSF LEDs for FM
|
||||||
// #define DSTARBOXCAR
|
#define USE_ALTERNATE_FM_LEDS
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@
|
|||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "DMRDefines.h"
|
#include "DMRDefines.h"
|
||||||
|
|
||||||
const uint16_t DMO_BUFFER_LENGTH_SAMPLES = 2880U; // 60ms at 48 kHz
|
const uint16_t DMO_BUFFER_LENGTH_SAMPLES = 1440U; // 60ms at 24 kHz
|
||||||
|
|
||||||
enum DMORX_STATE {
|
enum DMORX_STATE {
|
||||||
DMORXS_NONE,
|
DMORXS_NONE,
|
||||||
|
|||||||
+8
-13
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
*
|
*
|
||||||
@@ -22,16 +22,10 @@
|
|||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "DMRSlotType.h"
|
#include "DMRSlotType.h"
|
||||||
|
|
||||||
// Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB
|
// Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB
|
||||||
static q15_t RRC_0_2_FILTER[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 850, 592, 219, -234, -720, -1179,
|
static q15_t RRC_0_2_FILTER[] = {0, 0, 0, 0, 850, 219, -720, -1548, -1795, -1172, 237, 1927, 3120, 3073, 1447, -1431, -4544, -6442,
|
||||||
-1548, -1769, -1795, -1597, -1172, -544, 237, 1092, 1927, 2637,
|
-5735, -1633, 5651, 14822, 23810, 30367, 32767, 30367, 23810, 14822, 5651, -1633, -5735, -6442,
|
||||||
3120, 3286, 3073, 2454, 1447, 116, -1431, -3043, -4544, -5739,
|
-4544, -1431, 1447, 3073, 3120, 1927, 237, -1172, -1795, -1548, -720, 219, 850}; // numTaps = 45, L = 5
|
||||||
-6442, -6483, -5735, -4121, -1633, 1669, 5651, 10118, 14822,
|
|
||||||
19484, 23810, 27520, 30367, 32156, 32767, 32156, 30367, 27520,
|
|
||||||
23810, 19484, 14822, 10118, 5651, 1669, -1633, -4121, -5735,
|
|
||||||
-6483, -6442, -5739, -4544, -3043, -1431, 116, 1447, 2454,
|
|
||||||
3073, 3286, 3120, 2637, 1927, 1092, 237, -544, -1172, -1597,
|
|
||||||
-1795, -1769, -1548, -1179, -720, -234, 219, 592, 850}; // numTaps = 90, L = 10
|
|
||||||
const uint16_t RRC_0_2_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L
|
const uint16_t RRC_0_2_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L
|
||||||
|
|
||||||
const q15_t DMR_LEVELA = 1362;
|
const q15_t DMR_LEVELA = 1362;
|
||||||
@@ -80,7 +74,7 @@ void CDMRDMOTX::process()
|
|||||||
m_poLen = m_txDelay;
|
m_poLen = m_txDelay;
|
||||||
} else {
|
} else {
|
||||||
for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++)
|
for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++)
|
||||||
m_poBuffer[i] = m_fifo.get();
|
m_fifo.get(m_poBuffer[i]);
|
||||||
|
|
||||||
for (unsigned int i = 0U; i < 39U; i++)
|
for (unsigned int i = 0U; i < 39U; i++)
|
||||||
m_poBuffer[i + DMR_FRAME_LENGTH_BYTES] = PR_FILL[i];
|
m_poBuffer[i + DMR_FRAME_LENGTH_BYTES] = PR_FILL[i];
|
||||||
@@ -110,7 +104,7 @@ void CDMRDMOTX::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CDMRDMOTX::writeData(const uint8_t* data, uint8_t length)
|
uint8_t CDMRDMOTX::writeData(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != (DMR_FRAME_LENGTH_BYTES + 1U))
|
if (length != (DMR_FRAME_LENGTH_BYTES + 1U))
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -166,3 +160,4 @@ void CDMRDMOTX::setTXDelay(uint8_t delay)
|
|||||||
if (m_txDelay > 1200U)
|
if (m_txDelay > 1200U)
|
||||||
m_txDelay = 1200U;
|
m_txDelay = 1200U;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -23,13 +23,13 @@
|
|||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "DMRDefines.h"
|
#include "DMRDefines.h"
|
||||||
|
|
||||||
#include "SerialRB.h"
|
#include "RingBuffer.h"
|
||||||
|
|
||||||
class CDMRDMOTX {
|
class CDMRDMOTX {
|
||||||
public:
|
public:
|
||||||
CDMRDMOTX();
|
CDMRDMOTX();
|
||||||
|
|
||||||
uint8_t writeData(const uint8_t* data, uint8_t length);
|
uint8_t writeData(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ public:
|
|||||||
uint8_t getSpace() const;
|
uint8_t getSpace() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CSerialRB m_fifo;
|
CRingBuffer<uint8_t> m_fifo;
|
||||||
arm_fir_interpolate_instance_q15 m_modFilter;
|
arm_fir_interpolate_instance_q15 m_modFilter;
|
||||||
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
|
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
|
||||||
uint8_t m_poBuffer[1200U];
|
uint8_t m_poBuffer[1200U];
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2016 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,7 +19,7 @@
|
|||||||
#if !defined(DMRDEFINES_H)
|
#if !defined(DMRDEFINES_H)
|
||||||
#define DMRDEFINES_H
|
#define DMRDEFINES_H
|
||||||
|
|
||||||
const unsigned int DMR_RADIO_SYMBOL_LENGTH = 10U; // At 48 kHz sample rate
|
const unsigned int DMR_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
|
||||||
|
|
||||||
const unsigned int DMR_FRAME_LENGTH_BYTES = 33U;
|
const unsigned int DMR_FRAME_LENGTH_BYTES = 33U;
|
||||||
const unsigned int DMR_FRAME_LENGTH_BITS = DMR_FRAME_LENGTH_BYTES * 8U;
|
const unsigned int DMR_FRAME_LENGTH_BITS = DMR_FRAME_LENGTH_BYTES * 8U;
|
||||||
|
|||||||
+2
-2
@@ -24,8 +24,8 @@
|
|||||||
|
|
||||||
const q15_t SCALING_FACTOR = 19505; // Q15(0.60)
|
const q15_t SCALING_FACTOR = 19505; // Q15(0.60)
|
||||||
|
|
||||||
const uint8_t MAX_SYNC_SYMBOLS_ERRS = 4U;
|
const uint8_t MAX_SYNC_SYMBOLS_ERRS = 2U;
|
||||||
const uint8_t MAX_SYNC_BYTES_ERRS = 6U;
|
const uint8_t MAX_SYNC_BYTES_ERRS = 3U;
|
||||||
|
|
||||||
const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
|
const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
|
||||||
|
|
||||||
|
|||||||
+6
-6
@@ -22,15 +22,15 @@
|
|||||||
#include "DMRSlotType.h"
|
#include "DMRSlotType.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
|
||||||
const uint16_t SCAN_START = 790U;
|
const uint16_t SCAN_START = 400U;
|
||||||
const uint16_t SCAN_END = 920U;
|
const uint16_t SCAN_END = 490U;
|
||||||
|
|
||||||
const q15_t SCALING_FACTOR = 19505; // Q15(0.60)
|
const q15_t SCALING_FACTOR = 19505; // Q15(0.60)
|
||||||
|
|
||||||
const uint8_t MAX_SYNC_SYMBOLS_ERRS = 4U;
|
const uint8_t MAX_SYNC_SYMBOLS_ERRS = 2U;
|
||||||
const uint8_t MAX_SYNC_BYTES_ERRS = 6U;
|
const uint8_t MAX_SYNC_BYTES_ERRS = 3U;
|
||||||
|
|
||||||
const uint8_t MAX_SYNC_LOST_FRAMES = 26U;
|
const uint8_t MAX_SYNC_LOST_FRAMES = 13U;
|
||||||
|
|
||||||
const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
|
const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
|
||||||
|
|
||||||
@@ -97,7 +97,7 @@ bool CDMRSlotRX::processSample(q15_t sample, uint16_t rssi)
|
|||||||
return m_state != DMRRXS_NONE;
|
return m_state != DMRRXS_NONE;
|
||||||
|
|
||||||
// Ensure that the buffer doesn't overflow
|
// Ensure that the buffer doesn't overflow
|
||||||
if (m_dataPtr > m_endPtr || m_dataPtr >= 1900U)
|
if (m_dataPtr > m_endPtr || m_dataPtr >= 900U)
|
||||||
return m_state != DMRRXS_NONE;
|
return m_state != DMRRXS_NONE;
|
||||||
|
|
||||||
m_buffer[m_dataPtr] = sample;
|
m_buffer[m_dataPtr] = sample;
|
||||||
|
|||||||
+2
-2
@@ -44,7 +44,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool m_slot;
|
bool m_slot;
|
||||||
uint32_t m_bitBuffer[DMR_RADIO_SYMBOL_LENGTH];
|
uint32_t m_bitBuffer[DMR_RADIO_SYMBOL_LENGTH];
|
||||||
q15_t m_buffer[1900U];
|
q15_t m_buffer[900U];
|
||||||
uint16_t m_bitPtr;
|
uint16_t m_bitPtr;
|
||||||
uint16_t m_dataPtr;
|
uint16_t m_dataPtr;
|
||||||
uint16_t m_syncPtr;
|
uint16_t m_syncPtr;
|
||||||
@@ -62,7 +62,7 @@ private:
|
|||||||
DMRRX_STATE m_state;
|
DMRRX_STATE m_state;
|
||||||
uint8_t m_n;
|
uint8_t m_n;
|
||||||
uint8_t m_type;
|
uint8_t m_type;
|
||||||
uint16_t m_rssi[1900U];
|
uint16_t m_rssi[900U];
|
||||||
|
|
||||||
void correlateSync(bool first);
|
void correlateSync(bool first);
|
||||||
void samplesToBits(uint16_t start, uint8_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold);
|
void samplesToBits(uint16_t start, uint8_t count, uint8_t* buffer, uint16_t offset, q15_t centre, q15_t threshold);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
*
|
*
|
||||||
@@ -22,16 +22,10 @@
|
|||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "DMRSlotType.h"
|
#include "DMRSlotType.h"
|
||||||
|
|
||||||
// Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB
|
// Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB
|
||||||
static q15_t RRC_0_2_FILTER[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 850, 592, 219, -234, -720, -1179,
|
static q15_t RRC_0_2_FILTER[] = {0, 0, 0, 0, 850, 219, -720, -1548, -1795, -1172, 237, 1927, 3120, 3073, 1447, -1431, -4544, -6442,
|
||||||
-1548, -1769, -1795, -1597, -1172, -544, 237, 1092, 1927, 2637,
|
-5735, -1633, 5651, 14822, 23810, 30367, 32767, 30367, 23810, 14822, 5651, -1633, -5735, -6442,
|
||||||
3120, 3286, 3073, 2454, 1447, 116, -1431, -3043, -4544, -5739,
|
-4544, -1431, 1447, 3073, 3120, 1927, 237, -1172, -1795, -1548, -720, 219, 850}; // numTaps = 45, L = 5
|
||||||
-6442, -6483, -5735, -4121, -1633, 1669, 5651, 10118, 14822,
|
|
||||||
19484, 23810, 27520, 30367, 32156, 32767, 32156, 30367, 27520,
|
|
||||||
23810, 19484, 14822, 10118, 5651, 1669, -1633, -4121, -5735,
|
|
||||||
-6483, -6442, -5739, -4544, -3043, -1431, 116, 1447, 2454,
|
|
||||||
3073, 3286, 3120, 2637, 1927, 1092, 237, -544, -1172, -1597,
|
|
||||||
-1795, -1769, -1548, -1179, -720, -234, 219, 592, 850}; // numTaps = 90, L = 10
|
|
||||||
const uint16_t RRC_0_2_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L
|
const uint16_t RRC_0_2_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L
|
||||||
|
|
||||||
const q15_t DMR_LEVELA = 1362;
|
const q15_t DMR_LEVELA = 1362;
|
||||||
@@ -150,7 +144,7 @@ void CDMRTX::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CDMRTX::writeData1(const uint8_t* data, uint8_t length)
|
uint8_t CDMRTX::writeData1(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != (DMR_FRAME_LENGTH_BYTES + 1U))
|
if (length != (DMR_FRAME_LENGTH_BYTES + 1U))
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -174,7 +168,7 @@ uint8_t CDMRTX::writeData1(const uint8_t* data, uint8_t length)
|
|||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CDMRTX::writeData2(const uint8_t* data, uint8_t length)
|
uint8_t CDMRTX::writeData2(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != (DMR_FRAME_LENGTH_BYTES + 1U))
|
if (length != (DMR_FRAME_LENGTH_BYTES + 1U))
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -198,7 +192,7 @@ uint8_t CDMRTX::writeData2(const uint8_t* data, uint8_t length)
|
|||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CDMRTX::writeShortLC(const uint8_t* data, uint8_t length)
|
uint8_t CDMRTX::writeShortLC(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != 9U)
|
if (length != 9U)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -214,7 +208,7 @@ uint8_t CDMRTX::writeShortLC(const uint8_t* data, uint8_t length)
|
|||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CDMRTX::writeAbort(const uint8_t* data, uint8_t length)
|
uint8_t CDMRTX::writeAbort(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != 1U)
|
if (length != 1U)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -299,7 +293,7 @@ void CDMRTX::createData(uint8_t slotIndex)
|
|||||||
{
|
{
|
||||||
if (m_fifo[slotIndex].getData() >= DMR_FRAME_LENGTH_BYTES && m_frameCount >= STARTUP_COUNT && m_abortCount[slotIndex] >= ABORT_COUNT) {
|
if (m_fifo[slotIndex].getData() >= DMR_FRAME_LENGTH_BYTES && m_frameCount >= STARTUP_COUNT && m_abortCount[slotIndex] >= ABORT_COUNT) {
|
||||||
for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) {
|
for (unsigned int i = 0U; i < DMR_FRAME_LENGTH_BYTES; i++) {
|
||||||
m_poBuffer[i] = m_fifo[slotIndex].get();
|
m_fifo[slotIndex].get(m_poBuffer[i]);
|
||||||
m_markBuffer[i] = MARK_NONE;
|
m_markBuffer[i] = MARK_NONE;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "DMRDefines.h"
|
#include "DMRDefines.h"
|
||||||
|
|
||||||
#include "SerialRB.h"
|
#include "RingBuffer.h"
|
||||||
|
|
||||||
enum DMRTXSTATE {
|
enum DMRTXSTATE {
|
||||||
DMRTXSTATE_IDLE,
|
DMRTXSTATE_IDLE,
|
||||||
@@ -38,11 +38,11 @@ class CDMRTX {
|
|||||||
public:
|
public:
|
||||||
CDMRTX();
|
CDMRTX();
|
||||||
|
|
||||||
uint8_t writeData1(const uint8_t* data, uint8_t length);
|
uint8_t writeData1(const uint8_t* data, uint16_t length);
|
||||||
uint8_t writeData2(const uint8_t* data, uint8_t length);
|
uint8_t writeData2(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
uint8_t writeShortLC(const uint8_t* data, uint8_t length);
|
uint8_t writeShortLC(const uint8_t* data, uint16_t length);
|
||||||
uint8_t writeAbort(const uint8_t* data, uint8_t length);
|
uint8_t writeAbort(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
void setStart(bool start);
|
void setStart(bool start);
|
||||||
void setCal(bool start);
|
void setCal(bool start);
|
||||||
@@ -59,7 +59,7 @@ public:
|
|||||||
void setColorCode(uint8_t colorCode);
|
void setColorCode(uint8_t colorCode);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CSerialRB m_fifo[2U];
|
CRingBuffer<uint8_t> m_fifo[2U];
|
||||||
arm_fir_interpolate_instance_q15 m_modFilter;
|
arm_fir_interpolate_instance_q15 m_modFilter;
|
||||||
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
|
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
|
||||||
DMRTXSTATE m_state;
|
DMRTXSTATE m_state;
|
||||||
|
|||||||
+10
-30
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2015,2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2015 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -19,46 +19,26 @@
|
|||||||
#if !defined(DSTARDEFINES_H)
|
#if !defined(DSTARDEFINES_H)
|
||||||
#define DSTARDEFINES_H
|
#define DSTARDEFINES_H
|
||||||
|
|
||||||
const unsigned int DSTAR_RADIO_SYMBOL_LENGTH = 10U; // At 48 kHz sample rate
|
const unsigned int DSTAR_RADIO_BIT_LENGTH = 5U; // At 24 kHz sample rate
|
||||||
|
|
||||||
const unsigned int DSTAR_HEADER_LENGTH_BYTES = 41U;
|
const unsigned int DSTAR_HEADER_LENGTH_BYTES = 41U;
|
||||||
|
const unsigned int DSTAR_HEADER_LENGTH_BITS = DSTAR_HEADER_LENGTH_BYTES * 8U;
|
||||||
|
|
||||||
const unsigned int DSTAR_FEC_SECTION_LENGTH_BYTES = 83U;
|
const unsigned int DSTAR_FEC_SECTION_LENGTH_BYTES = 83U;
|
||||||
const unsigned int DSTAR_FEC_SECTION_LENGTH_SYMBOLS = 660U;
|
const unsigned int DSTAR_FEC_SECTION_LENGTH_BITS = 660U;
|
||||||
const unsigned int DSTAR_FEC_SECTION_LENGTH_SAMPLES = DSTAR_FEC_SECTION_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH;
|
|
||||||
|
|
||||||
const unsigned int DSTAR_DATA_LENGTH_BYTES = 12U;
|
const unsigned int DSTAR_DATA_LENGTH_BYTES = 12U;
|
||||||
const unsigned int DSTAR_DATA_LENGTH_SYMBOLS = DSTAR_DATA_LENGTH_BYTES * 8U;
|
const unsigned int DSTAR_DATA_LENGTH_BITS = DSTAR_DATA_LENGTH_BYTES * 8U;
|
||||||
const unsigned int DSTAR_DATA_LENGTH_SAMPLES = DSTAR_DATA_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH;
|
|
||||||
|
|
||||||
const unsigned int DSTAR_END_SYNC_LENGTH_BYTES = 6U;
|
const uint8_t DSTAR_EOT_BYTES[] = {0x55, 0x55, 0x55, 0x55, 0xC8, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||||
const unsigned int DSTAR_END_SYNC_LENGTH_BITS = DSTAR_END_SYNC_LENGTH_BYTES * 8U;
|
const unsigned int DSTAR_EOT_LENGTH_BYTES = 6U;
|
||||||
|
const unsigned int DSTAR_EOT_LENGTH_BITS = DSTAR_EOT_LENGTH_BYTES * 8U;
|
||||||
|
|
||||||
const unsigned int DSTAR_FRAME_SYNC_LENGTH_BYTES = 3U;
|
const uint8_t DSTAR_DATA_SYNC_LENGTH_BYTES = 3U;
|
||||||
const unsigned int DSTAR_FRAME_SYNC_LENGTH_SYMBOLS = DSTAR_FRAME_SYNC_LENGTH_BYTES * 8U;
|
const uint8_t DSTAR_DATA_SYNC_LENGTH_BITS = DSTAR_DATA_SYNC_LENGTH_BYTES * 8U;
|
||||||
const unsigned int DSTAR_FRAME_SYNC_LENGTH_SAMPLES = DSTAR_FRAME_SYNC_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH;
|
|
||||||
|
|
||||||
const unsigned int DSTAR_DATA_SYNC_LENGTH_BYTES = 3U;
|
|
||||||
const unsigned int DSTAR_DATA_SYNC_LENGTH_SYMBOLS = DSTAR_DATA_SYNC_LENGTH_BYTES * 8U;
|
|
||||||
const unsigned int DSTAR_DATA_SYNC_LENGTH_SAMPLES = DSTAR_DATA_SYNC_LENGTH_SYMBOLS * DSTAR_RADIO_SYMBOL_LENGTH;
|
|
||||||
|
|
||||||
const uint8_t DSTAR_DATA_SYNC_BYTES[] = {0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x55, 0x2D, 0x16};
|
const uint8_t DSTAR_DATA_SYNC_BYTES[] = {0x9E, 0x8D, 0x32, 0x88, 0x26, 0x1A, 0x3F, 0x61, 0xE8, 0x55, 0x2D, 0x16};
|
||||||
|
|
||||||
// D-Star bit order version of 0x55 0x6E 0x0A
|
|
||||||
const uint32_t DSTAR_FRAME_SYNC_DATA = 0x00557650U;
|
|
||||||
const uint32_t DSTAR_FRAME_SYNC_MASK = 0x00FFFFFFU;
|
|
||||||
const bool DSTAR_FRAME_SYNC_SYMBOLS[] = {false, true, false, true, false, true, false, true, false, true, true, true, false, true, true, false, false, true, false, true, false, false, false, false};
|
|
||||||
|
|
||||||
// D-Star bit order version of 0x55 0x2D 0x16
|
|
||||||
const uint32_t DSTAR_DATA_SYNC_DATA = 0x00AAB468U;
|
|
||||||
const uint32_t DSTAR_DATA_SYNC_MASK = 0x00FFFFFFU;
|
|
||||||
const bool DSTAR_DATA_SYNC_SYMBOLS[] = {true, false, true, false, true, false, true, false, true, false, true, true, false, true, false, false, false, true, true, false, true, false, false, false};
|
|
||||||
|
|
||||||
// D-Star bit order version of 0x55 0x55 0xC8 0x7A
|
|
||||||
const uint32_t DSTAR_END_SYNC_DATA = 0xAAAA135EU;
|
|
||||||
const uint32_t DSTAR_END_SYNC_MASK = 0xFFFFFFFFU;
|
|
||||||
const uint8_t DSTAR_END_SYNC_BYTES[] = {0x55, 0x55, 0x55, 0x55, 0xC8, 0x7A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
|
||||||
|
|
||||||
const uint8_t DSTAR_SLOW_DATA_TYPE_TEXT = 0x40U;
|
const uint8_t DSTAR_SLOW_DATA_TYPE_TEXT = 0x40U;
|
||||||
const uint8_t DSTAR_SLOW_DATA_TYPE_HEADER = 0x50U;
|
const uint8_t DSTAR_SLOW_DATA_TYPE_HEADER = 0x50U;
|
||||||
|
|
||||||
|
|||||||
+129
-231
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
@@ -23,12 +22,18 @@
|
|||||||
#include "DStarRX.h"
|
#include "DStarRX.h"
|
||||||
#include "Utils.h"
|
#include "Utils.h"
|
||||||
|
|
||||||
const unsigned int MAX_FRAMES = 150U;
|
const unsigned int BUFFER_LENGTH = 200U;
|
||||||
|
|
||||||
|
const uint32_t PLLMAX = 0x10000U;
|
||||||
|
const uint32_t PLLINC = PLLMAX / DSTAR_RADIO_BIT_LENGTH;
|
||||||
|
const uint32_t INC = PLLINC / 32U;
|
||||||
|
|
||||||
|
const unsigned int MAX_SYNC_BITS = 100U * DSTAR_DATA_LENGTH_BITS;
|
||||||
|
|
||||||
// D-Star bit order version of 0x55 0x55 0x6E 0x0A
|
// D-Star bit order version of 0x55 0x55 0x6E 0x0A
|
||||||
const uint32_t FRAME_SYNC_DATA = 0x00557650U;
|
const uint32_t FRAME_SYNC_DATA = 0x00557650U;
|
||||||
const uint32_t FRAME_SYNC_MASK = 0x00FFFFFFU;
|
const uint32_t FRAME_SYNC_MASK = 0x00FFFFFFU;
|
||||||
const uint8_t FRAME_SYNC_ERRS = 1U;
|
const uint8_t FRAME_SYNC_ERRS = 2U;
|
||||||
|
|
||||||
// D-Star bit order version of 0x55 0x2D 0x16
|
// D-Star bit order version of 0x55 0x2D 0x16
|
||||||
const uint32_t DATA_SYNC_DATA = 0x00AAB468U;
|
const uint32_t DATA_SYNC_DATA = 0x00AAB468U;
|
||||||
@@ -232,24 +237,14 @@ const uint16_t CCITT_TABLE[] = {
|
|||||||
0xf78fU, 0xe606U, 0xd49dU, 0xc514U, 0xb1abU, 0xa022U, 0x92b9U, 0x8330U,
|
0xf78fU, 0xe606U, 0xd49dU, 0xc514U, 0xb1abU, 0xa022U, 0x92b9U, 0x8330U,
|
||||||
0x7bc7U, 0x6a4eU, 0x58d5U, 0x495cU, 0x3de3U, 0x2c6aU, 0x1ef1U, 0x0f78U};
|
0x7bc7U, 0x6a4eU, 0x58d5U, 0x495cU, 0x3de3U, 0x2c6aU, 0x1ef1U, 0x0f78U};
|
||||||
|
|
||||||
const uint16_t NOENDPTR = 9999U;
|
|
||||||
|
|
||||||
CDStarRX::CDStarRX() :
|
CDStarRX::CDStarRX() :
|
||||||
|
m_pll(0U),
|
||||||
|
m_prev(false),
|
||||||
m_rxState(DSRXS_NONE),
|
m_rxState(DSRXS_NONE),
|
||||||
m_bitBuffer(),
|
m_patternBuffer(0x00U),
|
||||||
m_headerBuffer(),
|
m_rxBuffer(),
|
||||||
m_dataBuffer(),
|
m_rxBufferBits(0U),
|
||||||
m_bitPtr(0U),
|
m_dataBits(0U),
|
||||||
m_headerPtr(0U),
|
|
||||||
m_dataPtr(0U),
|
|
||||||
m_startPtr(NOENDPTR),
|
|
||||||
m_syncPtr(NOENDPTR),
|
|
||||||
m_minSyncPtr(NOENDPTR),
|
|
||||||
m_maxSyncPtr(NOENDPTR),
|
|
||||||
m_maxFrameCorr(0),
|
|
||||||
m_maxDataCorr(0),
|
|
||||||
m_frameCount(0U),
|
|
||||||
m_countdown(0U),
|
|
||||||
m_mar(0U),
|
m_mar(0U),
|
||||||
m_pathMetric(),
|
m_pathMetric(),
|
||||||
m_pathMemory0(),
|
m_pathMemory0(),
|
||||||
@@ -264,18 +259,12 @@ m_rssiCount(0U)
|
|||||||
|
|
||||||
void CDStarRX::reset()
|
void CDStarRX::reset()
|
||||||
{
|
{
|
||||||
|
m_pll = 0U;
|
||||||
|
m_prev = false;
|
||||||
m_rxState = DSRXS_NONE;
|
m_rxState = DSRXS_NONE;
|
||||||
m_headerPtr = 0U;
|
m_patternBuffer = 0x00U;
|
||||||
m_dataPtr = 0U;
|
m_rxBufferBits = 0U;
|
||||||
m_bitPtr = 0U;
|
m_dataBits = 0U;
|
||||||
m_maxFrameCorr = 0;
|
|
||||||
m_maxDataCorr = 0;
|
|
||||||
m_startPtr = NOENDPTR;
|
|
||||||
m_syncPtr = NOENDPTR;
|
|
||||||
m_minSyncPtr = NOENDPTR;
|
|
||||||
m_maxSyncPtr = NOENDPTR;
|
|
||||||
m_frameCount = 0U;
|
|
||||||
m_countdown = 0U;
|
|
||||||
m_rssiAccum = 0U;
|
m_rssiAccum = 0U;
|
||||||
m_rssiCount = 0U;
|
m_rssiCount = 0U;
|
||||||
}
|
}
|
||||||
@@ -286,117 +275,125 @@ void CDStarRX::samples(const q15_t* samples, const uint16_t* rssi, uint8_t lengt
|
|||||||
m_rssiAccum += rssi[i];
|
m_rssiAccum += rssi[i];
|
||||||
m_rssiCount++;
|
m_rssiCount++;
|
||||||
|
|
||||||
q15_t sample = samples[i];
|
bool bit = samples[i] < 0;
|
||||||
|
|
||||||
m_bitBuffer[m_bitPtr] <<= 1;
|
if (bit != m_prev) {
|
||||||
if (sample < 0)
|
if (m_pll < (PLLMAX / 2U))
|
||||||
m_bitBuffer[m_bitPtr] |= 0x01U;
|
m_pll += INC;
|
||||||
|
else
|
||||||
m_dataBuffer[m_dataPtr] = sample;
|
m_pll -= INC;
|
||||||
|
|
||||||
switch (m_rxState) {
|
|
||||||
case DSRXS_HEADER:
|
|
||||||
processHeader(sample);
|
|
||||||
break;
|
|
||||||
case DSRXS_DATA:
|
|
||||||
processData();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
processNone(sample);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_dataPtr++;
|
m_prev = bit;
|
||||||
if (m_dataPtr >= DSTAR_DATA_LENGTH_SAMPLES)
|
|
||||||
m_dataPtr = 0U;
|
|
||||||
|
|
||||||
m_bitPtr++;
|
m_pll += PLLINC;
|
||||||
if (m_bitPtr >= DSTAR_RADIO_SYMBOL_LENGTH)
|
|
||||||
m_bitPtr = 0U;
|
if (m_pll >= PLLMAX) {
|
||||||
|
m_pll -= PLLMAX;
|
||||||
|
|
||||||
|
switch (m_rxState) {
|
||||||
|
case DSRXS_NONE:
|
||||||
|
processNone(bit);
|
||||||
|
break;
|
||||||
|
case DSRXS_HEADER:
|
||||||
|
processHeader(bit);
|
||||||
|
break;
|
||||||
|
case DSRXS_DATA:
|
||||||
|
processData(bit);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDStarRX::processNone(q15_t sample)
|
void CDStarRX::processNone(bool bit)
|
||||||
{
|
{
|
||||||
// Fuzzy matching of the frame sync sequence
|
m_patternBuffer <<= 1;
|
||||||
bool ret = correlateFrameSync();
|
if (bit)
|
||||||
if (ret) {
|
m_patternBuffer |= 0x01U;
|
||||||
m_countdown = 5U;
|
|
||||||
|
|
||||||
m_headerBuffer[m_headerPtr] = sample;
|
// Fuzzy matching of the frame sync sequence
|
||||||
m_headerPtr++;
|
if (countBits32((m_patternBuffer & FRAME_SYNC_MASK) ^ FRAME_SYNC_DATA) <= FRAME_SYNC_ERRS) {
|
||||||
|
DEBUG1("DStarRX: found frame sync in None");
|
||||||
|
|
||||||
|
::memset(m_rxBuffer, 0x00U, DSTAR_FEC_SECTION_LENGTH_BYTES);
|
||||||
|
m_rxBufferBits = 0U;
|
||||||
|
|
||||||
m_rssiAccum = 0U;
|
m_rssiAccum = 0U;
|
||||||
m_rssiCount = 0U;
|
m_rssiCount = 0U;
|
||||||
|
|
||||||
m_rxState = DSRXS_HEADER;
|
m_rxState = DSRXS_HEADER;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fuzzy matching of the data sync bit sequence
|
// Exact matching of the data sync bit sequence
|
||||||
ret = correlateDataSync();
|
if (countBits32((m_patternBuffer & DATA_SYNC_MASK) ^ DATA_SYNC_DATA) == 0U) {
|
||||||
if (ret) {
|
|
||||||
DEBUG1("DStarRX: found data sync in None");
|
DEBUG1("DStarRX: found data sync in None");
|
||||||
|
|
||||||
io.setDecode(true);
|
io.setDecode(true);
|
||||||
io.setADCDetection(true);
|
io.setADCDetection(true);
|
||||||
|
|
||||||
|
// Suppress RSSI on the dummy sync message
|
||||||
|
m_rssiAccum = 0U;
|
||||||
|
m_rssiCount = 0U;
|
||||||
|
|
||||||
|
::memcpy(m_rxBuffer, DSTAR_DATA_SYNC_BYTES, DSTAR_DATA_LENGTH_BYTES);
|
||||||
|
writeRSSIData(m_rxBuffer);
|
||||||
|
|
||||||
|
::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U);
|
||||||
|
m_rxBufferBits = 0U;
|
||||||
|
|
||||||
|
m_dataBits = MAX_SYNC_BITS;
|
||||||
m_rxState = DSRXS_DATA;
|
m_rxState = DSRXS_DATA;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDStarRX::processHeader(q15_t sample)
|
void CDStarRX::processHeader(bool bit)
|
||||||
{
|
{
|
||||||
if (m_countdown > 0U) {
|
m_patternBuffer <<= 1;
|
||||||
correlateFrameSync();
|
if (bit)
|
||||||
m_countdown--;
|
m_patternBuffer |= 0x01U;
|
||||||
}
|
|
||||||
|
|
||||||
m_headerBuffer[m_headerPtr] = sample;
|
WRITE_BIT2(m_rxBuffer, m_rxBufferBits, bit);
|
||||||
m_headerPtr++;
|
m_rxBufferBits++;
|
||||||
|
|
||||||
// A full FEC header
|
// A full FEC header
|
||||||
if (m_headerPtr == (DSTAR_FEC_SECTION_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH)) {
|
if (m_rxBufferBits == DSTAR_FEC_SECTION_LENGTH_BITS) {
|
||||||
uint8_t buffer[DSTAR_FEC_SECTION_LENGTH_BYTES];
|
// Process the scrambling, interleaving and FEC, then return if the chcksum was correct
|
||||||
samplesToBits(m_headerBuffer, DSTAR_RADIO_SYMBOL_LENGTH, DSTAR_FEC_SECTION_LENGTH_SYMBOLS, buffer, DSTAR_FEC_SECTION_LENGTH_SAMPLES);
|
unsigned char header[DSTAR_HEADER_LENGTH_BYTES];
|
||||||
|
bool ok = rxHeader(m_rxBuffer, header);
|
||||||
// Process the scrambling, interleaving and FEC, then return true if the chcksum was correct
|
if (ok) {
|
||||||
uint8_t header[DSTAR_HEADER_LENGTH_BYTES];
|
|
||||||
bool ok = rxHeader(buffer, header);
|
|
||||||
if (!ok) {
|
|
||||||
// The checksum failed, return to looking for syncs
|
|
||||||
m_rxState = DSRXS_NONE;
|
|
||||||
m_maxFrameCorr = 0;
|
|
||||||
m_maxDataCorr = 0;
|
|
||||||
} else {
|
|
||||||
io.setDecode(true);
|
io.setDecode(true);
|
||||||
io.setADCDetection(true);
|
io.setADCDetection(true);
|
||||||
|
|
||||||
writeRSSIHeader(header);
|
writeRSSIHeader(header);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ready to start the first data section
|
::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U);
|
||||||
if (m_headerPtr == (DSTAR_FEC_SECTION_LENGTH_SAMPLES + 2U * DSTAR_RADIO_SYMBOL_LENGTH)) {
|
m_rxBufferBits = 0U;
|
||||||
m_frameCount = 0U;
|
|
||||||
m_dataPtr = 0U;
|
|
||||||
|
|
||||||
m_startPtr = 952U;
|
|
||||||
m_syncPtr = 942U;
|
|
||||||
m_maxSyncPtr = 944U;
|
|
||||||
m_minSyncPtr = 940U;
|
|
||||||
|
|
||||||
DEBUG5("DStarRX: calc start/sync/max/min", m_startPtr, m_syncPtr, m_maxSyncPtr, m_minSyncPtr);
|
|
||||||
|
|
||||||
m_rxState = DSRXS_DATA;
|
m_rxState = DSRXS_DATA;
|
||||||
|
m_dataBits = MAX_SYNC_BITS;
|
||||||
|
} else {
|
||||||
|
// The checksum failed, return to looking for syncs
|
||||||
|
m_rxState = DSRXS_NONE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDStarRX::processData()
|
void CDStarRX::processData(bool bit)
|
||||||
{
|
{
|
||||||
|
m_patternBuffer <<= 1;
|
||||||
|
if (bit)
|
||||||
|
m_patternBuffer |= 0x01U;
|
||||||
|
|
||||||
|
WRITE_BIT2(m_rxBuffer, m_rxBufferBits, bit);
|
||||||
|
m_rxBufferBits++;
|
||||||
|
|
||||||
// Fuzzy matching of the end frame sequences
|
// Fuzzy matching of the end frame sequences
|
||||||
if (countBits32((m_bitBuffer[m_bitPtr] & DSTAR_END_SYNC_MASK) ^ DSTAR_END_SYNC_DATA) <= END_SYNC_ERRS) {
|
if (countBits32((m_patternBuffer & END_SYNC_MASK) ^ END_SYNC_DATA) <= END_SYNC_ERRS) {
|
||||||
DEBUG1("DStarRX: Found end sync in Data");
|
DEBUG1("DStarRX: Found end sync in Data");
|
||||||
|
|
||||||
io.setDecode(false);
|
io.setDecode(false);
|
||||||
@@ -404,24 +401,35 @@ void CDStarRX::processData()
|
|||||||
|
|
||||||
serial.writeDStarEOT();
|
serial.writeDStarEOT();
|
||||||
|
|
||||||
m_maxFrameCorr = 0;
|
|
||||||
m_maxDataCorr = 0;
|
|
||||||
|
|
||||||
m_rxState = DSRXS_NONE;
|
m_rxState = DSRXS_NONE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fuzzy matching of the data sync bit sequence
|
// Fuzzy matching of the data sync bit sequence
|
||||||
if (m_minSyncPtr < m_maxSyncPtr) {
|
bool syncSeen = false;
|
||||||
if (m_dataPtr >= m_minSyncPtr && m_dataPtr <= m_maxSyncPtr)
|
if (m_rxBufferBits >= (DSTAR_DATA_LENGTH_BITS - 3U)) {
|
||||||
correlateDataSync();
|
if (countBits32((m_patternBuffer & DATA_SYNC_MASK) ^ DATA_SYNC_DATA) <= DATA_SYNC_ERRS) {
|
||||||
} else {
|
m_rxBufferBits = DSTAR_DATA_LENGTH_BITS;
|
||||||
if (m_dataPtr >= m_minSyncPtr || m_dataPtr <= m_maxSyncPtr)
|
m_dataBits = MAX_SYNC_BITS;
|
||||||
correlateDataSync();
|
syncSeen = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We've not seen a data sync for too long, signal RXLOST and change to RX_NONE
|
// Check to see if the sync is arriving late
|
||||||
if (m_frameCount >= MAX_FRAMES) {
|
if (m_rxBufferBits == DSTAR_DATA_LENGTH_BITS && !syncSeen) {
|
||||||
|
for (uint8_t i = 1U; i <= 3U; i++) {
|
||||||
|
uint32_t syncMask = DATA_SYNC_MASK >> i;
|
||||||
|
uint32_t syncData = DATA_SYNC_DATA >> i;
|
||||||
|
if (countBits32((m_patternBuffer & syncMask) ^ syncData) <= DATA_SYNC_ERRS) {
|
||||||
|
m_rxBufferBits -= i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_dataBits--;
|
||||||
|
|
||||||
|
if (m_dataBits == 0U) {
|
||||||
DEBUG1("DStarRX: data sync timed out, lost lock");
|
DEBUG1("DStarRX: data sync timed out, lost lock");
|
||||||
|
|
||||||
io.setDecode(false);
|
io.setDecode(false);
|
||||||
@@ -429,35 +437,24 @@ void CDStarRX::processData()
|
|||||||
|
|
||||||
serial.writeDStarLost();
|
serial.writeDStarLost();
|
||||||
|
|
||||||
m_maxFrameCorr = 0;
|
|
||||||
m_maxDataCorr = 0;
|
|
||||||
|
|
||||||
m_rxState = DSRXS_NONE;
|
m_rxState = DSRXS_NONE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send a data frame to the host if the required number of bits have been received
|
// Send a data frame to the host if the required number of bits have been received, or if a data sync has been seen
|
||||||
if (m_dataPtr == m_maxSyncPtr) {
|
if (m_rxBufferBits == DSTAR_DATA_LENGTH_BITS) {
|
||||||
uint8_t buffer[DSTAR_DATA_LENGTH_BYTES + 2U];
|
if (syncSeen) {
|
||||||
samplesToBits(m_dataBuffer, m_startPtr, DSTAR_DATA_LENGTH_SYMBOLS, buffer, DSTAR_DATA_LENGTH_SAMPLES);
|
m_rxBuffer[9U] = DSTAR_DATA_SYNC_BYTES[9U];
|
||||||
|
m_rxBuffer[10U] = DSTAR_DATA_SYNC_BYTES[10U];
|
||||||
if ((m_frameCount % 21U) == 0U) {
|
m_rxBuffer[11U] = DSTAR_DATA_SYNC_BYTES[11U];
|
||||||
if (m_frameCount == 0U) {
|
writeRSSIData(m_rxBuffer);
|
||||||
buffer[9U] = DSTAR_DATA_SYNC_BYTES[9U];
|
|
||||||
buffer[10U] = DSTAR_DATA_SYNC_BYTES[10U];
|
|
||||||
buffer[11U] = DSTAR_DATA_SYNC_BYTES[11U];
|
|
||||||
DEBUG5("DStarRX: found start/sync/max/min", m_startPtr, m_syncPtr, m_maxSyncPtr, m_minSyncPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
writeRSSIData(buffer);
|
|
||||||
} else {
|
} else {
|
||||||
serial.writeDStarData(buffer, DSTAR_DATA_LENGTH_BYTES);
|
serial.writeDStarData(m_rxBuffer, DSTAR_DATA_LENGTH_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_frameCount++;
|
// Start the next frame
|
||||||
|
::memset(m_rxBuffer, 0x00U, DSTAR_DATA_LENGTH_BYTES + 2U);
|
||||||
m_maxFrameCorr = 0;
|
m_rxBufferBits = 0U;
|
||||||
m_maxDataCorr = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,105 +500,6 @@ void CDStarRX::writeRSSIData(unsigned char* data)
|
|||||||
m_rssiCount = 0U;
|
m_rssiCount = 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CDStarRX::correlateFrameSync()
|
|
||||||
{
|
|
||||||
if (countBits32((m_bitBuffer[m_bitPtr] & DSTAR_FRAME_SYNC_MASK) ^ DSTAR_FRAME_SYNC_DATA) <= FRAME_SYNC_ERRS) {
|
|
||||||
uint16_t ptr = m_dataPtr + DSTAR_DATA_LENGTH_SAMPLES - DSTAR_FRAME_SYNC_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH;
|
|
||||||
if (ptr >= DSTAR_DATA_LENGTH_SAMPLES)
|
|
||||||
ptr -= DSTAR_DATA_LENGTH_SAMPLES;
|
|
||||||
|
|
||||||
q31_t corr = 0;
|
|
||||||
|
|
||||||
for (uint8_t i = 0U; i < DSTAR_FRAME_SYNC_LENGTH_SYMBOLS; i++) {
|
|
||||||
q15_t val = m_dataBuffer[ptr];
|
|
||||||
|
|
||||||
if (DSTAR_FRAME_SYNC_SYMBOLS[i])
|
|
||||||
corr -= val;
|
|
||||||
else
|
|
||||||
corr += val;
|
|
||||||
|
|
||||||
ptr += DSTAR_RADIO_SYMBOL_LENGTH;
|
|
||||||
if (ptr >= DSTAR_DATA_LENGTH_SAMPLES)
|
|
||||||
ptr -= DSTAR_DATA_LENGTH_SAMPLES;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (corr > m_maxFrameCorr) {
|
|
||||||
m_maxFrameCorr = corr;
|
|
||||||
m_headerPtr = 0U;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CDStarRX::correlateDataSync()
|
|
||||||
{
|
|
||||||
uint8_t maxErrs = 0U;
|
|
||||||
if (m_rxState == DSRXS_DATA)
|
|
||||||
maxErrs = DATA_SYNC_ERRS;
|
|
||||||
|
|
||||||
if (countBits32((m_bitBuffer[m_bitPtr] & DSTAR_DATA_SYNC_MASK) ^ DSTAR_DATA_SYNC_DATA) <= maxErrs) {
|
|
||||||
uint16_t ptr = m_dataPtr + DSTAR_DATA_LENGTH_SAMPLES - DSTAR_DATA_SYNC_LENGTH_SAMPLES + DSTAR_RADIO_SYMBOL_LENGTH;
|
|
||||||
if (ptr >= DSTAR_DATA_LENGTH_SAMPLES)
|
|
||||||
ptr -= DSTAR_DATA_LENGTH_SAMPLES;
|
|
||||||
|
|
||||||
q31_t corr = 0;
|
|
||||||
|
|
||||||
for (uint8_t i = 0U; i < DSTAR_DATA_SYNC_LENGTH_SYMBOLS; i++) {
|
|
||||||
q15_t val = m_dataBuffer[ptr];
|
|
||||||
|
|
||||||
if (DSTAR_DATA_SYNC_SYMBOLS[i])
|
|
||||||
corr -= val;
|
|
||||||
else
|
|
||||||
corr += val;
|
|
||||||
|
|
||||||
ptr += DSTAR_RADIO_SYMBOL_LENGTH;
|
|
||||||
if (ptr >= DSTAR_DATA_LENGTH_SAMPLES)
|
|
||||||
ptr -= DSTAR_DATA_LENGTH_SAMPLES;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (corr > m_maxDataCorr) {
|
|
||||||
m_maxDataCorr = corr;
|
|
||||||
m_frameCount = 0U;
|
|
||||||
|
|
||||||
m_syncPtr = m_dataPtr;
|
|
||||||
|
|
||||||
m_startPtr = m_dataPtr + DSTAR_RADIO_SYMBOL_LENGTH;
|
|
||||||
if (m_startPtr >= DSTAR_DATA_LENGTH_SAMPLES)
|
|
||||||
m_startPtr -= DSTAR_DATA_LENGTH_SAMPLES;
|
|
||||||
|
|
||||||
m_maxSyncPtr = m_syncPtr + 1U;
|
|
||||||
if (m_maxSyncPtr >= DSTAR_DATA_LENGTH_SAMPLES)
|
|
||||||
m_maxSyncPtr -= DSTAR_DATA_LENGTH_SAMPLES;
|
|
||||||
|
|
||||||
m_minSyncPtr = m_syncPtr + DSTAR_DATA_LENGTH_SAMPLES - 1U;
|
|
||||||
if (m_minSyncPtr >= DSTAR_DATA_LENGTH_SAMPLES)
|
|
||||||
m_minSyncPtr -= DSTAR_DATA_LENGTH_SAMPLES;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDStarRX::samplesToBits(const q15_t* inBuffer, uint16_t start, uint16_t count, uint8_t* outBuffer, uint16_t limit)
|
|
||||||
{
|
|
||||||
for (uint16_t i = 0U; i < count; i++) {
|
|
||||||
q15_t sample = inBuffer[start];
|
|
||||||
|
|
||||||
if (sample < 0)
|
|
||||||
WRITE_BIT2(outBuffer, i, true);
|
|
||||||
else
|
|
||||||
WRITE_BIT2(outBuffer, i, false);
|
|
||||||
|
|
||||||
start += DSTAR_RADIO_SYMBOL_LENGTH;
|
|
||||||
if (start >= limit)
|
|
||||||
start -= limit;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CDStarRX::rxHeader(uint8_t* in, uint8_t* out)
|
bool CDStarRX::rxHeader(uint8_t* in, uint8_t* out)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|||||||
@@ -37,21 +37,13 @@ public:
|
|||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
uint32_t m_pll;
|
||||||
|
bool m_prev;
|
||||||
DSRX_STATE m_rxState;
|
DSRX_STATE m_rxState;
|
||||||
uint32_t m_bitBuffer[DSTAR_RADIO_SYMBOL_LENGTH];
|
uint32_t m_patternBuffer;
|
||||||
q15_t m_headerBuffer[DSTAR_FEC_SECTION_LENGTH_SAMPLES + 2U * DSTAR_RADIO_SYMBOL_LENGTH];
|
uint8_t m_rxBuffer[100U];
|
||||||
q15_t m_dataBuffer[DSTAR_DATA_LENGTH_SAMPLES];
|
unsigned int m_rxBufferBits;
|
||||||
uint16_t m_bitPtr;
|
unsigned int m_dataBits;
|
||||||
uint16_t m_headerPtr;
|
|
||||||
uint16_t m_dataPtr;
|
|
||||||
uint16_t m_startPtr;
|
|
||||||
uint16_t m_syncPtr;
|
|
||||||
uint16_t m_minSyncPtr;
|
|
||||||
uint16_t m_maxSyncPtr;
|
|
||||||
q31_t m_maxFrameCorr;
|
|
||||||
q31_t m_maxDataCorr;
|
|
||||||
uint16_t m_frameCount;
|
|
||||||
uint8_t m_countdown;
|
|
||||||
unsigned int m_mar;
|
unsigned int m_mar;
|
||||||
int m_pathMetric[4U];
|
int m_pathMetric[4U];
|
||||||
unsigned int m_pathMemory0[42U];
|
unsigned int m_pathMemory0[42U];
|
||||||
@@ -62,12 +54,9 @@ private:
|
|||||||
uint32_t m_rssiAccum;
|
uint32_t m_rssiAccum;
|
||||||
uint16_t m_rssiCount;
|
uint16_t m_rssiCount;
|
||||||
|
|
||||||
void processNone(q15_t sample);
|
void processNone(bool bit);
|
||||||
void processHeader(q15_t sample);
|
void processHeader(bool bit);
|
||||||
void processData();
|
void processData(bool bit);
|
||||||
bool correlateFrameSync();
|
|
||||||
bool correlateDataSync();
|
|
||||||
void samplesToBits(const q15_t* inBuffer, uint16_t start, uint16_t count, uint8_t* outBuffer, uint16_t limit);
|
|
||||||
void writeRSSIHeader(unsigned char* header);
|
void writeRSSIHeader(unsigned char* header);
|
||||||
void writeRSSIData(unsigned char* data);
|
void writeRSSIData(unsigned char* data);
|
||||||
bool rxHeader(uint8_t* in, uint8_t* out);
|
bool rxHeader(uint8_t* in, uint8_t* out);
|
||||||
|
|||||||
+21
-20
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2017,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -27,10 +27,8 @@ const uint8_t BIT_SYNC = 0xAAU;
|
|||||||
|
|
||||||
const uint8_t FRAME_SYNC[] = {0xEAU, 0xA6U, 0x00U};
|
const uint8_t FRAME_SYNC[] = {0xEAU, 0xA6U, 0x00U};
|
||||||
|
|
||||||
// Generated using gaussfir(0.35, 1, 10) in MATLAB
|
// Generated using gaussfir(0.35, 1, 5) in MATLAB
|
||||||
static q15_t GAUSSIAN_0_35_FILTER[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1001, 1942, 3514, 5930,
|
static q15_t GAUSSIAN_0_35_FILTER[] = {0, 0, 0, 0, 1001, 3514, 9333, 18751, 28499, 32767, 28499, 18751, 9333, 3514, 1001}; // numTaps = 15, L = 5
|
||||||
9333, 13699, 18751, 23938, 28499, 31644, 32767, 31644,
|
|
||||||
28499, 23938, 18751, 13699, 9333, 5930, 3514, 1942, 1001}; // numTaps = 30, L = 10
|
|
||||||
const uint16_t GAUSSIAN_0_35_FILTER_PHASE_LEN = 3U; // phaseLength = numTaps/L
|
const uint16_t GAUSSIAN_0_35_FILTER_PHASE_LEN = 3U; // phaseLength = numTaps/L
|
||||||
|
|
||||||
const q15_t DSTAR_LEVEL0 = -841;
|
const q15_t DSTAR_LEVEL0 = -841;
|
||||||
@@ -198,9 +196,9 @@ m_poLen(0U),
|
|||||||
m_poPtr(0U),
|
m_poPtr(0U),
|
||||||
m_txDelay(60U) // 100ms
|
m_txDelay(60U) // 100ms
|
||||||
{
|
{
|
||||||
::memset(m_modState, 0x00U, 15U * sizeof(q15_t));
|
::memset(m_modState, 0x00U, 20U * sizeof(q15_t));
|
||||||
|
|
||||||
m_modFilter.L = DSTAR_RADIO_SYMBOL_LENGTH;
|
m_modFilter.L = DSTAR_RADIO_BIT_LENGTH;
|
||||||
m_modFilter.phaseLength = GAUSSIAN_0_35_FILTER_PHASE_LEN;
|
m_modFilter.phaseLength = GAUSSIAN_0_35_FILTER_PHASE_LEN;
|
||||||
m_modFilter.pCoeffs = GAUSSIAN_0_35_FILTER;
|
m_modFilter.pCoeffs = GAUSSIAN_0_35_FILTER;
|
||||||
m_modFilter.pState = m_modState;
|
m_modFilter.pState = m_modState;
|
||||||
@@ -218,12 +216,13 @@ void CDStarTX::process()
|
|||||||
for (uint16_t i = 0U; i < m_txDelay; i++)
|
for (uint16_t i = 0U; i < m_txDelay; i++)
|
||||||
m_poBuffer[m_poLen++] = BIT_SYNC;
|
m_poBuffer[m_poLen++] = BIT_SYNC;
|
||||||
} else {
|
} else {
|
||||||
|
uint8_t dummy;
|
||||||
// Pop the type byte off
|
// Pop the type byte off
|
||||||
m_buffer.get();
|
m_buffer.get(dummy);
|
||||||
|
|
||||||
uint8_t header[DSTAR_HEADER_LENGTH_BYTES];
|
uint8_t header[DSTAR_HEADER_LENGTH_BYTES];
|
||||||
for (uint8_t i = 0U; i < DSTAR_HEADER_LENGTH_BYTES; i++)
|
for (uint8_t i = 0U; i < DSTAR_HEADER_LENGTH_BYTES; i++)
|
||||||
header[i] = m_buffer.get();
|
m_buffer.get(header[i]);
|
||||||
|
|
||||||
uint8_t buffer[86U];
|
uint8_t buffer[86U];
|
||||||
txHeader(header, buffer + 2U);
|
txHeader(header, buffer + 2U);
|
||||||
@@ -241,21 +240,23 @@ void CDStarTX::process()
|
|||||||
|
|
||||||
if (type == DSTAR_DATA && m_poLen == 0U) {
|
if (type == DSTAR_DATA && m_poLen == 0U) {
|
||||||
// Pop the type byte off
|
// Pop the type byte off
|
||||||
m_buffer.get();
|
uint8_t dummy;
|
||||||
|
m_buffer.get(dummy);
|
||||||
|
|
||||||
for (uint8_t i = 0U; i < DSTAR_DATA_LENGTH_BYTES; i++)
|
for (uint8_t i = 0U; i < DSTAR_DATA_LENGTH_BYTES; i++)
|
||||||
m_poBuffer[m_poLen++] = m_buffer.get();
|
m_buffer.get(m_poBuffer[m_poLen++]);
|
||||||
|
|
||||||
m_poPtr = 0U;
|
m_poPtr = 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == DSTAR_EOT && m_poLen == 0U) {
|
if (type == DSTAR_EOT && m_poLen == 0U) {
|
||||||
// Pop the type byte off
|
// Pop the type byte off
|
||||||
m_buffer.get();
|
uint8_t dummy;
|
||||||
|
m_buffer.get(dummy);
|
||||||
|
|
||||||
for (uint8_t j = 0U; j < 3U; j++) {
|
for (uint8_t j = 0U; j < 3U; j++) {
|
||||||
for (uint8_t i = 0U; i < DSTAR_END_SYNC_LENGTH_BYTES; i++)
|
for (uint8_t i = 0U; i < DSTAR_EOT_LENGTH_BYTES; i++)
|
||||||
m_poBuffer[m_poLen++] = DSTAR_END_SYNC_BYTES[i];
|
m_poBuffer[m_poLen++] = DSTAR_EOT_BYTES[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
m_poPtr = 0U;
|
m_poPtr = 0U;
|
||||||
@@ -264,11 +265,11 @@ void CDStarTX::process()
|
|||||||
if (m_poLen > 0U) {
|
if (m_poLen > 0U) {
|
||||||
uint16_t space = io.getSpace();
|
uint16_t space = io.getSpace();
|
||||||
|
|
||||||
while (space > (8U * DSTAR_RADIO_SYMBOL_LENGTH)) {
|
while (space > (8U * DSTAR_RADIO_BIT_LENGTH)) {
|
||||||
uint8_t c = m_poBuffer[m_poPtr++];
|
uint8_t c = m_poBuffer[m_poPtr++];
|
||||||
writeByte(c);
|
writeByte(c);
|
||||||
|
|
||||||
space -= 8U * DSTAR_RADIO_SYMBOL_LENGTH;
|
space -= 8U * DSTAR_RADIO_BIT_LENGTH;
|
||||||
|
|
||||||
if (m_poPtr >= m_poLen) {
|
if (m_poPtr >= m_poLen) {
|
||||||
m_poPtr = 0U;
|
m_poPtr = 0U;
|
||||||
@@ -279,7 +280,7 @@ void CDStarTX::process()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CDStarTX::writeHeader(const uint8_t* header, uint8_t length)
|
uint8_t CDStarTX::writeHeader(const uint8_t* header, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != DSTAR_HEADER_LENGTH_BYTES)
|
if (length != DSTAR_HEADER_LENGTH_BYTES)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -298,7 +299,7 @@ uint8_t CDStarTX::writeHeader(const uint8_t* header, uint8_t length)
|
|||||||
return 0U;
|
return 0U;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CDStarTX::writeData(const uint8_t* data, uint8_t length)
|
uint8_t CDStarTX::writeData(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != DSTAR_DATA_LENGTH_BYTES)
|
if (length != DSTAR_DATA_LENGTH_BYTES)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -414,7 +415,7 @@ void CDStarTX::txHeader(const uint8_t* in, uint8_t* out) const
|
|||||||
void CDStarTX::writeByte(uint8_t c)
|
void CDStarTX::writeByte(uint8_t c)
|
||||||
{
|
{
|
||||||
q15_t inBuffer[8U];
|
q15_t inBuffer[8U];
|
||||||
q15_t outBuffer[DSTAR_RADIO_SYMBOL_LENGTH * 8U];
|
q15_t outBuffer[DSTAR_RADIO_BIT_LENGTH * 8U];
|
||||||
|
|
||||||
uint8_t mask = 0x01U;
|
uint8_t mask = 0x01U;
|
||||||
|
|
||||||
@@ -429,7 +430,7 @@ void CDStarTX::writeByte(uint8_t c)
|
|||||||
|
|
||||||
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 8U);
|
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 8U);
|
||||||
|
|
||||||
io.write(STATE_DSTAR, outBuffer, DSTAR_RADIO_SYMBOL_LENGTH * 8U);
|
io.write(STATE_DSTAR, outBuffer, DSTAR_RADIO_BIT_LENGTH * 8U);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDStarTX::setTXDelay(uint8_t delay)
|
void CDStarTX::setTXDelay(uint8_t delay)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -21,14 +21,14 @@
|
|||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
#include "SerialRB.h"
|
#include "RingBuffer.h"
|
||||||
|
|
||||||
class CDStarTX {
|
class CDStarTX {
|
||||||
public:
|
public:
|
||||||
CDStarTX();
|
CDStarTX();
|
||||||
|
|
||||||
uint8_t writeHeader(const uint8_t* header, uint8_t length);
|
uint8_t writeHeader(const uint8_t* header, uint16_t length);
|
||||||
uint8_t writeData(const uint8_t* data, uint8_t length);
|
uint8_t writeData(const uint8_t* data, uint16_t length);
|
||||||
uint8_t writeEOT();
|
uint8_t writeEOT();
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
@@ -38,9 +38,9 @@ public:
|
|||||||
uint8_t getSpace() const;
|
uint8_t getSpace() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CSerialRB m_buffer;
|
CRingBuffer<uint8_t> m_buffer;
|
||||||
arm_fir_interpolate_instance_q15 m_modFilter;
|
arm_fir_interpolate_instance_q15 m_modFilter;
|
||||||
q15_t m_modState[15U]; // blockSize + phaseLength - 1, 8 + 3 - 1 plus some spare
|
q15_t m_modState[20U]; // blockSize + phaseLength - 1, 8 + 9 - 1 plus some spare
|
||||||
uint8_t m_poBuffer[600U];
|
uint8_t m_poBuffer[600U];
|
||||||
uint16_t m_poLen;
|
uint16_t m_poLen;
|
||||||
uint16_t m_poPtr;
|
uint16_t m_poPtr;
|
||||||
|
|||||||
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(FM_H)
|
||||||
|
#define FM_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
#include "FMBlanking.h"
|
||||||
|
#include "FMCTCSSRX.h"
|
||||||
|
#include "FMCTCSSTX.h"
|
||||||
|
#include "FMTimeout.h"
|
||||||
|
#include "FMKeyer.h"
|
||||||
|
#include "FMTimer.h"
|
||||||
|
#include "RingBuffer.h"
|
||||||
|
#include "FMDirectForm1.h"
|
||||||
|
#include "FMDownSampler.h"
|
||||||
|
#include "FMUpSampler.h"
|
||||||
|
#include "FMNoiseSquelch.h"
|
||||||
|
|
||||||
|
enum FM_STATE {
|
||||||
|
FS_LISTENING,
|
||||||
|
FS_KERCHUNK_RF,
|
||||||
|
FS_RELAYING_RF,
|
||||||
|
FS_RELAYING_WAIT_RF,
|
||||||
|
FS_TIMEOUT_RF,
|
||||||
|
FS_TIMEOUT_WAIT_RF,
|
||||||
|
FS_KERCHUNK_EXT,
|
||||||
|
FS_RELAYING_EXT,
|
||||||
|
FS_RELAYING_WAIT_EXT,
|
||||||
|
FS_TIMEOUT_EXT,
|
||||||
|
FS_TIMEOUT_WAIT_EXT,
|
||||||
|
FS_HANG
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class CFM {
|
||||||
|
public:
|
||||||
|
CFM();
|
||||||
|
|
||||||
|
void samples(bool cos, q15_t* samples, uint8_t length);
|
||||||
|
|
||||||
|
void process();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
uint8_t setCallsign(const char* callsign, uint8_t speed, uint16_t frequency, uint8_t time, uint8_t holdoff, uint8_t highLevel, uint8_t lowLevel, bool callsignAtStart, bool callsignAtEnd, bool callsignAtLatch);
|
||||||
|
uint8_t setAck(const char* rfAck, uint8_t speed, uint16_t frequency, uint8_t minTime, uint16_t delay, uint8_t level);
|
||||||
|
uint8_t setMisc(uint16_t timeout, uint8_t timeoutLevel, uint8_t ctcssFrequency, uint8_t ctcssHighThreshold, uint8_t ctcssLowThreshold, uint8_t ctcssLevel, uint8_t kerchunkTime, uint8_t hangTime, uint8_t accessMode, bool cosInvert, bool noiseSquelch, uint8_t squelchHighThreshold, uint8_t squelchLowThreshold, uint8_t rfAudioBoost, uint8_t maxDev, uint8_t rxLevel);
|
||||||
|
uint8_t setExt(const char* ack, uint8_t audioBoost, uint8_t speed, uint16_t frequency, uint8_t level);
|
||||||
|
|
||||||
|
uint8_t getSpace() const;
|
||||||
|
|
||||||
|
uint8_t writeData(const uint8_t* data, uint8_t length);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CFMKeyer m_callsign;
|
||||||
|
CFMKeyer m_rfAck;
|
||||||
|
CFMKeyer m_extAck;
|
||||||
|
CFMCTCSSRX m_ctcssRX;
|
||||||
|
CFMCTCSSTX m_ctcssTX;
|
||||||
|
CFMNoiseSquelch m_squelch;
|
||||||
|
CFMTimeout m_timeoutTone;
|
||||||
|
FM_STATE m_state;
|
||||||
|
bool m_callsignAtStart;
|
||||||
|
bool m_callsignAtEnd;
|
||||||
|
bool m_callsignAtLatch;
|
||||||
|
CFMTimer m_callsignTimer;
|
||||||
|
CFMTimer m_timeoutTimer;
|
||||||
|
CFMTimer m_holdoffTimer;
|
||||||
|
CFMTimer m_kerchunkTimer;
|
||||||
|
CFMTimer m_ackMinTimer;
|
||||||
|
CFMTimer m_ackDelayTimer;
|
||||||
|
CFMTimer m_hangTimer;
|
||||||
|
CFMTimer m_statusTimer;
|
||||||
|
CFMTimer m_reverseTimer;
|
||||||
|
bool m_needReverse;
|
||||||
|
CFMDirectFormI m_filterStage1;
|
||||||
|
CFMDirectFormI m_filterStage2;
|
||||||
|
CFMDirectFormI m_filterStage3;
|
||||||
|
CFMBlanking m_blanking;
|
||||||
|
uint8_t m_accessMode;
|
||||||
|
bool m_cosInvert;
|
||||||
|
bool m_noiseSquelch;
|
||||||
|
q15_t m_rfAudioBoost;
|
||||||
|
q15_t m_extAudioBoost;
|
||||||
|
CFMDownSampler m_downSampler;
|
||||||
|
bool m_extEnabled;
|
||||||
|
q15_t m_rxLevel;
|
||||||
|
CRingBuffer<q15_t> m_inputRFRB;
|
||||||
|
CRingBuffer<q15_t> m_outputRFRB;
|
||||||
|
CFMUpSampler m_inputExtRB;
|
||||||
|
|
||||||
|
void stateMachine(bool validRFSignal, bool validExtSignal);
|
||||||
|
|
||||||
|
void duplexStateMachine(bool validRFSignal, bool validExtSignal);
|
||||||
|
void listeningStateDuplex(bool validRFSignal, bool validExtSignal);
|
||||||
|
void kerchunkRFStateDuplex(bool validSignal);
|
||||||
|
void relayingRFStateDuplex(bool validSignal);
|
||||||
|
void relayingRFWaitStateDuplex(bool validSignal);
|
||||||
|
void timeoutRFStateDuplex(bool validSignal);
|
||||||
|
void timeoutRFWaitStateDuplex(bool validSignal);
|
||||||
|
void kerchunkExtStateDuplex(bool validSignal);
|
||||||
|
void relayingExtStateDuplex(bool validSignal);
|
||||||
|
void relayingExtWaitStateDuplex(bool validSignal);
|
||||||
|
void timeoutExtStateDuplex(bool validSignal);
|
||||||
|
void timeoutExtWaitStateDuplex(bool validSignal);
|
||||||
|
void hangStateDuplex(bool validRFSignal, bool validExtSignal);
|
||||||
|
|
||||||
|
void simplexStateMachine(bool validRFSignal, bool validExtSignal);
|
||||||
|
void listeningStateSimplex(bool validRFSignal, bool validExtSignal);
|
||||||
|
void relayingRFStateSimplex(bool validSignal);
|
||||||
|
void relayingRFWaitStateSimplex(bool validSignal);
|
||||||
|
void timeoutRFStateSimplex(bool validSignal);
|
||||||
|
void timeoutRFWaitStateSimplex(bool validSignal);
|
||||||
|
void relayingExtStateSimplex(bool validSignal);
|
||||||
|
void relayingExtWaitStateSimplex(bool validSignal);
|
||||||
|
void timeoutExtStateSimplex(bool validSignal);
|
||||||
|
void timeoutExtWaitStateSimplex(bool validSignal);
|
||||||
|
|
||||||
|
void clock(uint8_t length);
|
||||||
|
|
||||||
|
void sendCallsign();
|
||||||
|
void beginRelaying();
|
||||||
|
|
||||||
|
void insertDelay(uint16_t ms);
|
||||||
|
void insertSilence(uint16_t ms);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "FMBlanking.h"
|
||||||
|
|
||||||
|
// 2000 Hz sine wave at 24000 Hz sample rate
|
||||||
|
const q31_t TONE[] = {0, 16384, 28378, 32767, 28378, 16384, 0, -16383, -28377, -32767, -28377, -16383};
|
||||||
|
|
||||||
|
const uint8_t TONE_LEN = 12U;
|
||||||
|
|
||||||
|
const uint32_t BLEEP_LEN = 2400U; // 100ms
|
||||||
|
|
||||||
|
CFMBlanking::CFMBlanking() :
|
||||||
|
m_posValue(0),
|
||||||
|
m_negValue(0),
|
||||||
|
m_level(128 * 128),
|
||||||
|
m_running(false),
|
||||||
|
m_pos(0U),
|
||||||
|
m_n(0U)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMBlanking::setParams(uint8_t value, uint8_t level)
|
||||||
|
{
|
||||||
|
m_posValue = q15_t(value * 128);
|
||||||
|
m_negValue = -m_posValue;
|
||||||
|
|
||||||
|
m_level = q15_t(level * 128);
|
||||||
|
}
|
||||||
|
|
||||||
|
q15_t CFMBlanking::process(q15_t sample)
|
||||||
|
{
|
||||||
|
if (m_posValue == 0)
|
||||||
|
return sample;
|
||||||
|
|
||||||
|
if (!m_running) {
|
||||||
|
if (sample >= m_posValue) {
|
||||||
|
m_running = true;
|
||||||
|
m_pos = 0U;
|
||||||
|
m_n = 0U;
|
||||||
|
} else if (sample <= m_negValue) {
|
||||||
|
m_running = true;
|
||||||
|
m_pos = 0U;
|
||||||
|
m_n = 0U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_running)
|
||||||
|
return sample;
|
||||||
|
|
||||||
|
if (m_pos <= BLEEP_LEN) {
|
||||||
|
q31_t value = TONE[m_n++] * m_level;
|
||||||
|
sample = q15_t(__SSAT((value >> 15), 16));
|
||||||
|
if (m_n >= TONE_LEN)
|
||||||
|
m_n = 0U;
|
||||||
|
} else {
|
||||||
|
sample = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pos++;
|
||||||
|
if (m_pos >= 12000U)
|
||||||
|
m_running = false;
|
||||||
|
|
||||||
|
return sample;
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(FMBlanking_H)
|
||||||
|
#define FMBlanking_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
class CFMBlanking {
|
||||||
|
public:
|
||||||
|
CFMBlanking();
|
||||||
|
|
||||||
|
void setParams(uint8_t value, uint8_t level);
|
||||||
|
|
||||||
|
q15_t process(q15_t sample);
|
||||||
|
|
||||||
|
private:
|
||||||
|
q15_t m_posValue;
|
||||||
|
q15_t m_negValue;
|
||||||
|
q15_t m_level;
|
||||||
|
bool m_running;
|
||||||
|
uint32_t m_pos;
|
||||||
|
uint8_t m_n;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
+175
@@ -0,0 +1,175 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "FMCTCSSRX.h"
|
||||||
|
|
||||||
|
const struct RX_CTCSS_TABLE {
|
||||||
|
uint8_t frequency;
|
||||||
|
q63_t coeffDivTwo;
|
||||||
|
} RX_CTCSS_TABLE_DATA[] = {
|
||||||
|
{ 67U, 2147153298},
|
||||||
|
{ 69U, 2147130228},
|
||||||
|
{ 71U, 2147103212},
|
||||||
|
{ 74U, 2147076297},
|
||||||
|
{ 77U, 2147047330},
|
||||||
|
{ 79U, 2147016195},
|
||||||
|
{ 82U, 2146982775},
|
||||||
|
{ 85U, 2146946945},
|
||||||
|
{ 88U, 2146907275},
|
||||||
|
{ 91U, 2146867538},
|
||||||
|
{ 94U, 2146822298},
|
||||||
|
{ 97U, 2146785526},
|
||||||
|
{100U, 2146747759},
|
||||||
|
{103U, 2146695349},
|
||||||
|
{107U, 2146637984},
|
||||||
|
{110U, 2146578604},
|
||||||
|
{114U, 2146513835},
|
||||||
|
{118U, 2146445080},
|
||||||
|
{123U, 2146370355},
|
||||||
|
{127U, 2146291161},
|
||||||
|
{131U, 2146205372},
|
||||||
|
{136U, 2146112589},
|
||||||
|
{141U, 2146014479},
|
||||||
|
{146U, 2145910829},
|
||||||
|
{151U, 2145796971},
|
||||||
|
{156U, 2145676831},
|
||||||
|
{159U, 2145604646},
|
||||||
|
{162U, 2145547790},
|
||||||
|
{165U, 2145468230},
|
||||||
|
{167U, 2145409363},
|
||||||
|
{171U, 2145324517},
|
||||||
|
{173U, 2145261046},
|
||||||
|
{177U, 2145170643},
|
||||||
|
{179U, 2145102321},
|
||||||
|
{183U, 2145006080},
|
||||||
|
{186U, 2144932648},
|
||||||
|
{189U, 2144830280},
|
||||||
|
{192U, 2144748638},
|
||||||
|
{196U, 2144639788},
|
||||||
|
{199U, 2144555290},
|
||||||
|
{203U, 2144436713},
|
||||||
|
{206U, 2144346237},
|
||||||
|
{210U, 2144217348},
|
||||||
|
{218U, 2143983951},
|
||||||
|
{225U, 2143735870},
|
||||||
|
{229U, 2143622139},
|
||||||
|
{233U, 2143469001},
|
||||||
|
{241U, 2143182299},
|
||||||
|
{250U, 2142874683},
|
||||||
|
{254U, 2142733729}};
|
||||||
|
|
||||||
|
const uint8_t CTCSS_TABLE_DATA_LEN = 50U;
|
||||||
|
|
||||||
|
// 4Hz bandwidth
|
||||||
|
const uint16_t N = 24000U / 4U;
|
||||||
|
|
||||||
|
CFMCTCSSRX::CFMCTCSSRX() :
|
||||||
|
m_coeffDivTwo(0),
|
||||||
|
m_highThreshold(0),
|
||||||
|
m_lowThreshold(0),
|
||||||
|
m_count(0U),
|
||||||
|
m_q0(0),
|
||||||
|
m_q1(0),
|
||||||
|
m_state(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CFMCTCSSRX::setParams(uint8_t frequency, uint8_t highThreshold, uint8_t lowThreshold)
|
||||||
|
{
|
||||||
|
m_coeffDivTwo = 0;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < CTCSS_TABLE_DATA_LEN; i++) {
|
||||||
|
if (RX_CTCSS_TABLE_DATA[i].frequency == frequency) {
|
||||||
|
m_coeffDivTwo = RX_CTCSS_TABLE_DATA[i].coeffDivTwo;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_coeffDivTwo == 0)
|
||||||
|
return 4U;
|
||||||
|
|
||||||
|
m_highThreshold = q31_t(highThreshold);
|
||||||
|
m_lowThreshold = q31_t(lowThreshold);
|
||||||
|
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFMCTCSSRX::process(q15_t sample)
|
||||||
|
{
|
||||||
|
//get more dynamic into the decoder by multiplying the sample by 1.5
|
||||||
|
q31_t sample31 = q31_t(sample) + (q31_t(sample) >> 1);
|
||||||
|
|
||||||
|
q31_t q2 = m_q1;
|
||||||
|
m_q1 = m_q0;
|
||||||
|
|
||||||
|
// Q31 multiplication, t3 = m_coeffDivTwo * 2 * m_q1
|
||||||
|
q63_t t1 = m_coeffDivTwo * m_q1;
|
||||||
|
q31_t t2 = __SSAT((t1 >> 31), 31);
|
||||||
|
q31_t t3 = t2 * 2;
|
||||||
|
|
||||||
|
// m_q0 = m_coeffDivTwo * m_q1 * 2 - q2 + sample
|
||||||
|
m_q0 = t3 - q2 + sample31;
|
||||||
|
|
||||||
|
m_count++;
|
||||||
|
if (m_count == N) {
|
||||||
|
// Q31 multiplication, t2 = m_q0 * m_q0
|
||||||
|
q63_t t1 = q63_t(m_q0) * q63_t(m_q0);
|
||||||
|
q31_t t2 = __SSAT((t1 >> 31), 31);
|
||||||
|
|
||||||
|
// Q31 multiplication, t4 = m_q0 * m_q0
|
||||||
|
q63_t t3 = q63_t(m_q1) * q63_t(m_q1);
|
||||||
|
q31_t t4 = __SSAT((t3 >> 31), 31);
|
||||||
|
|
||||||
|
// Q31 multiplication, t9 = m_q0 * m_q1 * m_coeffDivTwo * 2
|
||||||
|
q63_t t5 = q63_t(m_q0) * q63_t(m_q1);
|
||||||
|
q31_t t6 = __SSAT((t5 >> 31), 31);
|
||||||
|
q63_t t7 = t6 * m_coeffDivTwo;
|
||||||
|
q31_t t8 = __SSAT((t7 >> 31), 31);
|
||||||
|
q31_t t9 = t8 * 2;
|
||||||
|
|
||||||
|
// value = m_q0 * m_q0 + m_q1 * m_q1 - m_q0 * m_q1 * m_coeffDivTwo * 2
|
||||||
|
q31_t value = t2 + t4 - t9;
|
||||||
|
|
||||||
|
bool previousState = m_state;
|
||||||
|
|
||||||
|
q31_t threshold = m_highThreshold;
|
||||||
|
if (previousState)
|
||||||
|
threshold = m_lowThreshold;
|
||||||
|
|
||||||
|
m_state = value >= threshold;
|
||||||
|
|
||||||
|
if (previousState != m_state)
|
||||||
|
DEBUG4("CTCSS Value / Threshold / Valid", value, threshold, m_state);
|
||||||
|
|
||||||
|
m_count = 0U;
|
||||||
|
m_q0 = 0;
|
||||||
|
m_q1 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMCTCSSRX::reset()
|
||||||
|
{
|
||||||
|
m_q0 = 0;
|
||||||
|
m_q1 = 0;
|
||||||
|
m_state = false;
|
||||||
|
m_count = 0U;
|
||||||
|
}
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(FMCTCSSRX_H)
|
||||||
|
#define FMCTCSSRX_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
class CFMCTCSSRX {
|
||||||
|
public:
|
||||||
|
CFMCTCSSRX();
|
||||||
|
|
||||||
|
uint8_t setParams(uint8_t frequency, uint8_t highThreshold, uint8_t lowThreshold);
|
||||||
|
|
||||||
|
bool process(q15_t sample);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
q63_t m_coeffDivTwo;
|
||||||
|
q31_t m_highThreshold;
|
||||||
|
q31_t m_lowThreshold;
|
||||||
|
uint16_t m_count;
|
||||||
|
q31_t m_q0;
|
||||||
|
q31_t m_q1;
|
||||||
|
bool m_state;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
+128
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "FMCTCSSTX.h"
|
||||||
|
|
||||||
|
const struct TX_CTCSS_TABLE {
|
||||||
|
uint8_t frequency;
|
||||||
|
uint16_t length;
|
||||||
|
q31_t increment;
|
||||||
|
} TX_CTCSS_TABLE_DATA[] = {
|
||||||
|
{ 67U, 358U, 5995059},
|
||||||
|
{ 69U, 346U, 6200860},
|
||||||
|
{ 71U, 334U, 6433504},
|
||||||
|
{ 74U, 323U, 6657200},
|
||||||
|
{ 77U, 312U, 6889844},
|
||||||
|
{ 79U, 301U, 7131436},
|
||||||
|
{ 82U, 291U, 7381976},
|
||||||
|
{ 85U, 281U, 7641463},
|
||||||
|
{ 88U, 271U, 7918846},
|
||||||
|
{ 91U, 262U, 8187282},
|
||||||
|
{ 94U, 253U, 8482561},
|
||||||
|
{ 97U, 246U, 8715205},
|
||||||
|
{100U, 240U, 8947849},
|
||||||
|
{103U, 232U, 9261024},
|
||||||
|
{107U, 224U, 9592094},
|
||||||
|
{110U, 216U, 9923165},
|
||||||
|
{114U, 209U, 10272131},
|
||||||
|
{118U, 202U, 10630045},
|
||||||
|
{123U, 195U, 11005854},
|
||||||
|
{127U, 189U, 11390612},
|
||||||
|
{131U, 182U, 11793265},
|
||||||
|
{136U, 176U, 12213814},
|
||||||
|
{141U, 170U, 12643310},
|
||||||
|
{146U, 164U, 13081755},
|
||||||
|
{151U, 159U, 13547043},
|
||||||
|
{156U, 153U, 14021279},
|
||||||
|
{159U, 150U, 14298662},
|
||||||
|
{162U, 148U, 14513411},
|
||||||
|
{165U, 145U, 14808690},
|
||||||
|
{167U, 143U, 15023438},
|
||||||
|
{171U, 140U, 15327665},
|
||||||
|
{173U, 138U, 15551361},
|
||||||
|
{177U, 135U, 15864536},
|
||||||
|
{179U, 133U, 16097180},
|
||||||
|
{183U, 131U, 16419303},
|
||||||
|
{186U, 129U, 16660894},
|
||||||
|
{189U, 126U, 16991965},
|
||||||
|
{192U, 124U, 17251452},
|
||||||
|
{196U, 122U, 17591471},
|
||||||
|
{199U, 120U, 17850958},
|
||||||
|
{203U, 118U, 18208872},
|
||||||
|
{206U, 116U, 18477308},
|
||||||
|
{210U, 114U, 18853117},
|
||||||
|
{218U, 110U, 19515258},
|
||||||
|
{225U, 106U, 20195295},
|
||||||
|
{229U, 105U, 20499521},
|
||||||
|
{233U, 103U, 20902175},
|
||||||
|
{241U, 99U, 21635898},
|
||||||
|
{250U, 96U, 22396465},
|
||||||
|
{254U, 94U, 22736484}};
|
||||||
|
|
||||||
|
const uint8_t CTCSS_TABLE_DATA_LEN = 50U;
|
||||||
|
|
||||||
|
CFMCTCSSTX::CFMCTCSSTX() :
|
||||||
|
m_values(NULL),
|
||||||
|
m_length(0U),
|
||||||
|
m_n(0U)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CFMCTCSSTX::setParams(uint8_t frequency, uint8_t level)
|
||||||
|
{
|
||||||
|
const TX_CTCSS_TABLE* entry = NULL;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; i < CTCSS_TABLE_DATA_LEN; i++) {
|
||||||
|
if (TX_CTCSS_TABLE_DATA[i].frequency == frequency) {
|
||||||
|
entry = TX_CTCSS_TABLE_DATA + i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entry == NULL)
|
||||||
|
return 4U;
|
||||||
|
|
||||||
|
m_length = entry->length;
|
||||||
|
|
||||||
|
delete[] m_values;
|
||||||
|
m_values = new q15_t[m_length];
|
||||||
|
|
||||||
|
q31_t arg = 0;
|
||||||
|
for (uint16_t i = 0U; i < m_length; i++) {
|
||||||
|
q63_t value = ::arm_sin_q31(arg) * q63_t(level * 13);
|
||||||
|
m_values[i] = q15_t(__SSAT((value >> 31), 16));
|
||||||
|
|
||||||
|
arg += entry->increment;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
q15_t CFMCTCSSTX::getAudio(bool reverse)
|
||||||
|
{
|
||||||
|
q15_t sample = m_values[m_n++];
|
||||||
|
if (m_n >= m_length)
|
||||||
|
m_n = 0U;
|
||||||
|
|
||||||
|
if (reverse)
|
||||||
|
return -sample;
|
||||||
|
else
|
||||||
|
return sample;
|
||||||
|
}
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(FMCTCSSTX_H)
|
||||||
|
#define FMCTCSSTX_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
class CFMCTCSSTX {
|
||||||
|
public:
|
||||||
|
CFMCTCSSTX();
|
||||||
|
|
||||||
|
uint8_t setParams(uint8_t frequency, uint8_t level);
|
||||||
|
|
||||||
|
q15_t getAudio(bool reverse);
|
||||||
|
|
||||||
|
private:
|
||||||
|
q15_t* m_values;
|
||||||
|
uint16_t m_length;
|
||||||
|
uint16_t m_n;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
+111
@@ -0,0 +1,111 @@
|
|||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
This header file has been taken from:
|
||||||
|
"A Collection of Useful C++ Classes for Digital Signal Processing"
|
||||||
|
By Vinnie Falco
|
||||||
|
Bernd Porr adapted it for Linux and turned it into a filter using
|
||||||
|
fixed point arithmetic.
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
License: MIT License (http://www.opensource.org/licenses/mit-license.php)
|
||||||
|
Copyright (c) 2009 by Vinnie Falco
|
||||||
|
Copyright (C) 2013-2017, Bernd Porr, [email protected]
|
||||||
|
Copyright (C) 2020 , Mario Molitor , [email protected]
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
||||||
|
*******************************************************************************/
|
||||||
|
|
||||||
|
// based on https://raw.githubusercontent.com/berndporr/iir_fixed_point/master/DirectFormI.h
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#ifndef DIRECTFORMI_H_
|
||||||
|
#define DIRECTFORMI_H_
|
||||||
|
class CFMDirectFormI
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
// convenience function which takes the a0 argument but ignores it!
|
||||||
|
CFMDirectFormI(const q31_t b0, const q31_t b1, const q31_t b2,
|
||||||
|
const q31_t, const q31_t a1, const q31_t a2)
|
||||||
|
{
|
||||||
|
// FIR coefficients
|
||||||
|
c_b0 = b0;
|
||||||
|
c_b1 = b1;
|
||||||
|
c_b2 = b2;
|
||||||
|
// IIR coefficients
|
||||||
|
c_a1 = a1;
|
||||||
|
c_a2 = a2;
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
CFMDirectFormI(const CFMDirectFormI &my)
|
||||||
|
{
|
||||||
|
// delay line
|
||||||
|
m_x2 = my.m_x2; // x[n-2]
|
||||||
|
m_y2 = my.m_y2; // y[n-2]
|
||||||
|
m_x1 = my.m_x1; // x[n-1]
|
||||||
|
m_y1 = my.m_y1; // y[n-1]
|
||||||
|
|
||||||
|
// coefficients
|
||||||
|
c_b0 = my.c_b0;
|
||||||
|
c_b1 = my.c_b1;
|
||||||
|
c_b2 = my.c_b2; // FIR
|
||||||
|
c_a1 = my.c_a1;
|
||||||
|
c_a2 = my.c_a2; // IIR
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset ()
|
||||||
|
{
|
||||||
|
m_x1 = 0;
|
||||||
|
m_x2 = 0;
|
||||||
|
m_y1 = 0;
|
||||||
|
m_y2 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// filtering operation: one sample in and one out
|
||||||
|
inline q15_t filter(const q15_t in)
|
||||||
|
{
|
||||||
|
// calculate the output
|
||||||
|
register q31_t out_upscaled = c_b0 * in
|
||||||
|
+ c_b1 * m_x1
|
||||||
|
+ c_b2 * m_x2
|
||||||
|
- c_a1 * m_y1
|
||||||
|
- c_a2 * m_y2;
|
||||||
|
|
||||||
|
q15_t out = __SSAT(out_upscaled >> 15, 15);
|
||||||
|
|
||||||
|
// update the delay lines
|
||||||
|
m_x2 = m_x1;
|
||||||
|
m_y2 = m_y1;
|
||||||
|
m_x1 = in;
|
||||||
|
m_y1 = out;
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
// delay line
|
||||||
|
q31_t m_x2; // x[n-2]
|
||||||
|
q31_t m_y2; // y[n-2]
|
||||||
|
q31_t m_x1; // x[n-1]
|
||||||
|
q31_t m_y1; // y[n-1]
|
||||||
|
|
||||||
|
// coefficients
|
||||||
|
q31_t c_b0,c_b1,c_b2; // FIR
|
||||||
|
q31_t c_a1,c_a2; // IIR
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* DIRECTFORMI_H */
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2020 by Geoffrey Merck F4FXL - KC3FRA
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "FMDownSampler.h"
|
||||||
|
|
||||||
|
CFMDownSampler::CFMDownSampler(uint16_t length) :
|
||||||
|
m_ringBuffer(length),
|
||||||
|
m_samplePack(0U),
|
||||||
|
m_samplePackPointer(NULL),
|
||||||
|
m_sampleIndex(0U)
|
||||||
|
{
|
||||||
|
m_samplePackPointer = (uint8_t*)&m_samplePack;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMDownSampler::addSample(q15_t sample)
|
||||||
|
{
|
||||||
|
uint32_t usample = uint32_t(int32_t(sample) + 2048);
|
||||||
|
//only take one of three samples
|
||||||
|
switch(m_sampleIndex){
|
||||||
|
case 0:
|
||||||
|
m_samplePack = usample << 12;
|
||||||
|
break;
|
||||||
|
case 3:{
|
||||||
|
m_samplePack |= usample;
|
||||||
|
|
||||||
|
//we did not use MSB; skip it
|
||||||
|
TSamplePairPack pair{m_samplePackPointer[0U], m_samplePackPointer[1U], m_samplePackPointer[2U]};
|
||||||
|
|
||||||
|
m_ringBuffer.put(pair);
|
||||||
|
|
||||||
|
m_samplePack = 0U;//reset the sample pack
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
//Just skip this sample
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_sampleIndex++;
|
||||||
|
if (m_sampleIndex >= 6U)//did we pack two samples ?
|
||||||
|
m_sampleIndex = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFMDownSampler::getPackedData(TSamplePairPack& data)
|
||||||
|
{
|
||||||
|
return m_ringBuffer.get(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t CFMDownSampler::getData()
|
||||||
|
{
|
||||||
|
return m_ringBuffer.getData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMDownSampler::reset()
|
||||||
|
{
|
||||||
|
m_sampleIndex = 0U;
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2020 by Geoffrey Merck F4FXL - KC3FRA
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(FMDOWNSAMPLER_H)
|
||||||
|
#define FMDOWNSAMPLER_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "RingBuffer.h"
|
||||||
|
#include "FMSamplePairPack.h"
|
||||||
|
|
||||||
|
class CFMDownSampler {
|
||||||
|
public:
|
||||||
|
CFMDownSampler(uint16_t length);
|
||||||
|
|
||||||
|
void addSample(q15_t sample);
|
||||||
|
|
||||||
|
bool getPackedData(TSamplePairPack& data);
|
||||||
|
|
||||||
|
uint16_t getData();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CRingBuffer<TSamplePairPack> m_ringBuffer;
|
||||||
|
uint32_t m_samplePack;
|
||||||
|
uint8_t* m_samplePackPointer;
|
||||||
|
uint8_t m_sampleIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
+216
@@ -0,0 +1,216 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "FMKeyer.h"
|
||||||
|
|
||||||
|
const struct {
|
||||||
|
char c;
|
||||||
|
uint32_t pattern;
|
||||||
|
uint8_t length;
|
||||||
|
} SYMBOL_LIST[] = {
|
||||||
|
{'A', 0xB8000000U, 8U},
|
||||||
|
{'B', 0xEA800000U, 12U},
|
||||||
|
{'C', 0xEBA00000U, 14U},
|
||||||
|
{'D', 0xEA000000U, 10U},
|
||||||
|
{'E', 0x80000000U, 4U},
|
||||||
|
{'F', 0xAE800000U, 12U},
|
||||||
|
{'G', 0xEE800000U, 12U},
|
||||||
|
{'H', 0xAA000000U, 10U},
|
||||||
|
{'I', 0xA0000000U, 6U},
|
||||||
|
{'J', 0xBBB80000U, 16U},
|
||||||
|
{'K', 0xEB800000U, 12U},
|
||||||
|
{'L', 0xBA800000U, 12U},
|
||||||
|
{'M', 0xEE000000U, 10U},
|
||||||
|
{'N', 0xE8000000U, 8U},
|
||||||
|
{'O', 0xEEE00000U, 14U},
|
||||||
|
{'P', 0xBBA00000U, 14U},
|
||||||
|
{'Q', 0xEEB80000U, 16U},
|
||||||
|
{'R', 0xBA000000U, 10U},
|
||||||
|
{'S', 0xA8000000U, 8U},
|
||||||
|
{'T', 0xE0000000U, 6U},
|
||||||
|
{'U', 0xAE000000U, 10U},
|
||||||
|
{'V', 0xAB800000U, 12U},
|
||||||
|
{'W', 0xBB800000U, 12U},
|
||||||
|
{'X', 0xEAE00000U, 14U},
|
||||||
|
{'Y', 0xEBB80000U, 16U},
|
||||||
|
{'Z', 0xEEA00000U, 14U},
|
||||||
|
{'1', 0xBBBB8000U, 20U},
|
||||||
|
{'2', 0xAEEE0000U, 18U},
|
||||||
|
{'3', 0xABB80000U, 16U},
|
||||||
|
{'4', 0xAAE00000U, 14U},
|
||||||
|
{'5', 0xAA800000U, 12U},
|
||||||
|
{'6', 0xEAA00000U, 14U},
|
||||||
|
{'7', 0xEEA80000U, 16U},
|
||||||
|
{'8', 0xEEEA0000U, 18U},
|
||||||
|
{'9', 0xEEEE8000U, 20U},
|
||||||
|
{'0', 0xEEEEE000U, 22U},
|
||||||
|
{'/', 0xEAE80000U, 16U},
|
||||||
|
{'?', 0xAEEA0000U, 18U},
|
||||||
|
{',', 0xEEAEE000U, 22U},
|
||||||
|
{'-', 0xEAAE0000U, 18U},
|
||||||
|
{'=', 0xEAB80000U, 16U},
|
||||||
|
{'.', 0xBAEB8000U, 20U},
|
||||||
|
{' ', 0x00000000U, 4U},
|
||||||
|
{0U, 0x00000000U, 0U}
|
||||||
|
};
|
||||||
|
|
||||||
|
const uint8_t BIT_MASK_TABLE[] = {0x80U, 0x40U, 0x20U, 0x10U, 0x08U, 0x04U, 0x02U, 0x01U};
|
||||||
|
|
||||||
|
#define WRITE_BIT_FM(p,i,b) p[(i)>>3] = (b) ? (p[(i)>>3] | BIT_MASK_TABLE[(i)&7]) : (p[(i)>>3] & ~BIT_MASK_TABLE[(i)&7])
|
||||||
|
#define READ_BIT_FM(p,i) (p[(i)>>3] & BIT_MASK_TABLE[(i)&7])
|
||||||
|
|
||||||
|
CFMKeyer::CFMKeyer() :
|
||||||
|
m_wanted(false),
|
||||||
|
m_poBuffer(),
|
||||||
|
m_poLen(0U),
|
||||||
|
m_poPos(0U),
|
||||||
|
m_dotLen(0U),
|
||||||
|
m_dotPos(0U),
|
||||||
|
m_audio(NULL),
|
||||||
|
m_audioLen(0U),
|
||||||
|
m_audioPos(0U),
|
||||||
|
m_highLevel(0U),
|
||||||
|
m_lowLevel(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t CFMKeyer::setParams(const char* text, uint8_t speed, uint16_t frequency, uint8_t highLevel, uint8_t lowLevel)
|
||||||
|
{
|
||||||
|
m_poLen = 0U;
|
||||||
|
|
||||||
|
for (uint8_t i = 0U; text[i] != '\0'; i++) {
|
||||||
|
for (uint8_t j = 0U; SYMBOL_LIST[j].c != 0U; j++) {
|
||||||
|
if (SYMBOL_LIST[j].c == text[i]) {
|
||||||
|
uint32_t MASK = 0x80000000U;
|
||||||
|
for (uint8_t k = 0U; k < SYMBOL_LIST[j].length; k++, m_poLen++, MASK >>= 1) {
|
||||||
|
bool b = (SYMBOL_LIST[j].pattern & MASK) == MASK;
|
||||||
|
WRITE_BIT_FM(m_poBuffer, m_poLen, b);
|
||||||
|
|
||||||
|
if (m_poLen >= 995U) {
|
||||||
|
m_poLen = 0U;
|
||||||
|
return 4U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_highLevel = q15_t(highLevel);
|
||||||
|
m_lowLevel = q15_t(lowLevel);
|
||||||
|
|
||||||
|
m_dotLen = 24000U / speed; // In samples
|
||||||
|
|
||||||
|
m_audioLen = 24000U / frequency; // In samples
|
||||||
|
|
||||||
|
delete[] m_audio;
|
||||||
|
m_audio = new bool[m_audioLen];
|
||||||
|
|
||||||
|
for (uint16_t i = 0U; i < m_audioLen; i++) {
|
||||||
|
if (i < (m_audioLen / 2U))
|
||||||
|
m_audio[i] = true;
|
||||||
|
else
|
||||||
|
m_audio[i] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
q15_t CFMKeyer::getHighAudio()
|
||||||
|
{
|
||||||
|
q15_t output = 0U;
|
||||||
|
if (!m_wanted)
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
bool b = READ_BIT_FM(m_poBuffer, m_poPos);
|
||||||
|
if (b)
|
||||||
|
output = m_audio[m_audioPos] ? m_highLevel : -m_highLevel;
|
||||||
|
|
||||||
|
m_audioPos++;
|
||||||
|
if (m_audioPos >= m_audioLen)
|
||||||
|
m_audioPos = 0U;
|
||||||
|
m_dotPos++;
|
||||||
|
if (m_dotPos >= m_dotLen) {
|
||||||
|
m_dotPos = 0U;
|
||||||
|
m_poPos++;
|
||||||
|
if (m_poPos >= m_poLen) {
|
||||||
|
stop();
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
q15_t CFMKeyer::getLowAudio()
|
||||||
|
{
|
||||||
|
q15_t output = 0U;
|
||||||
|
if (!m_wanted)
|
||||||
|
return 0U;
|
||||||
|
|
||||||
|
bool b = READ_BIT_FM(m_poBuffer, m_poPos);
|
||||||
|
if (b)
|
||||||
|
output = m_audio[m_audioPos] ? m_lowLevel : -m_lowLevel;
|
||||||
|
|
||||||
|
m_audioPos++;
|
||||||
|
if (m_audioPos >= m_audioLen)
|
||||||
|
m_audioPos = 0U;
|
||||||
|
m_dotPos++;
|
||||||
|
if (m_dotPos >= m_dotLen) {
|
||||||
|
m_dotPos = 0U;
|
||||||
|
m_poPos++;
|
||||||
|
if (m_poPos >= m_poLen) {
|
||||||
|
stop();
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMKeyer::start()
|
||||||
|
{
|
||||||
|
if (isRunning())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_wanted = true;
|
||||||
|
m_poPos = 0U;
|
||||||
|
m_dotPos = 0U;
|
||||||
|
m_audioPos = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMKeyer::stop()
|
||||||
|
{
|
||||||
|
m_wanted = false;
|
||||||
|
m_poPos = 0U;
|
||||||
|
m_dotPos = 0U;
|
||||||
|
m_audioPos = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFMKeyer::isWanted() const
|
||||||
|
{
|
||||||
|
return m_wanted;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFMKeyer::isRunning() const
|
||||||
|
{
|
||||||
|
return m_poPos > 0U || m_dotPos > 0U || m_audioPos > 0U;
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(FMKeyer_H)
|
||||||
|
#define FMKeyer_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
class CFMKeyer {
|
||||||
|
public:
|
||||||
|
CFMKeyer();
|
||||||
|
|
||||||
|
uint8_t setParams(const char* text, uint8_t speed, uint16_t frequency, uint8_t highLevel, uint8_t lowLevel);
|
||||||
|
|
||||||
|
q15_t getHighAudio();
|
||||||
|
q15_t getLowAudio();
|
||||||
|
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
bool isRunning() const;
|
||||||
|
|
||||||
|
bool isWanted() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_wanted;
|
||||||
|
uint8_t m_poBuffer[1000U];
|
||||||
|
uint16_t m_poLen;
|
||||||
|
uint16_t m_poPos;
|
||||||
|
uint16_t m_dotLen;
|
||||||
|
uint16_t m_dotPos;
|
||||||
|
bool* m_audio;
|
||||||
|
uint16_t m_audioLen;
|
||||||
|
uint16_t m_audioPos;
|
||||||
|
q15_t m_highLevel;
|
||||||
|
q15_t m_lowLevel;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,127 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "FMNoiseSquelch.h"
|
||||||
|
|
||||||
|
// 4500Hz centre frequency
|
||||||
|
const q31_t COEFF_DIV_TWO = 821806413;
|
||||||
|
|
||||||
|
// 400Hz bandwidth
|
||||||
|
const uint16_t N = 24000U / 400U;
|
||||||
|
|
||||||
|
CFMNoiseSquelch::CFMNoiseSquelch() :
|
||||||
|
m_highThreshold(0),
|
||||||
|
m_lowThreshold(0),
|
||||||
|
m_count(0U),
|
||||||
|
m_q0(0),
|
||||||
|
m_q1(0),
|
||||||
|
m_state(false),
|
||||||
|
m_validCount(0U)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMNoiseSquelch::setParams(uint8_t highThreshold, uint8_t lowThreshold)
|
||||||
|
{
|
||||||
|
m_highThreshold = q31_t(highThreshold);
|
||||||
|
m_lowThreshold = q31_t(lowThreshold);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFMNoiseSquelch::process(q15_t sample)
|
||||||
|
{
|
||||||
|
//get more dynamic into the decoder by multiplying the sample by 64
|
||||||
|
q31_t sample31 = q31_t(sample) << 6; //+ (q31_t(sample) >> 1);
|
||||||
|
|
||||||
|
q31_t q2 = m_q1;
|
||||||
|
m_q1 = m_q0;
|
||||||
|
|
||||||
|
// Q31 multiplication, t3 = m_coeffDivTwo * 2 * m_q1
|
||||||
|
q63_t t1 = COEFF_DIV_TWO * m_q1;
|
||||||
|
q31_t t2 = __SSAT((t1 >> 31), 31);
|
||||||
|
q31_t t3 = t2 * 2;
|
||||||
|
|
||||||
|
// m_q0 = m_coeffDivTwo * m_q1 * 2 - q2 + sample
|
||||||
|
m_q0 = t3 - q2 + sample31;
|
||||||
|
|
||||||
|
m_count++;
|
||||||
|
if (m_count == N) {
|
||||||
|
// Q31 multiplication, t2 = m_q0 * m_q0
|
||||||
|
q63_t t1 = q63_t(m_q0) * q63_t(m_q0);
|
||||||
|
q31_t t2 = __SSAT((t1 >> 31), 31);
|
||||||
|
|
||||||
|
// Q31 multiplication, t4 = m_q0 * m_q0
|
||||||
|
q63_t t3 = q63_t(m_q1) * q63_t(m_q1);
|
||||||
|
q31_t t4 = __SSAT((t3 >> 31), 31);
|
||||||
|
|
||||||
|
// Q31 multiplication, t9 = m_q0 * m_q1 * m_coeffDivTwo * 2
|
||||||
|
q63_t t5 = q63_t(m_q0) * q63_t(m_q1);
|
||||||
|
q31_t t6 = __SSAT((t5 >> 31), 31);
|
||||||
|
q63_t t7 = t6 * COEFF_DIV_TWO;
|
||||||
|
q31_t t8 = __SSAT((t7 >> 31), 31);
|
||||||
|
q31_t t9 = t8 * 2;
|
||||||
|
|
||||||
|
// value = m_q0 * m_q0 + m_q1 * m_q1 - m_q0 * m_q1 * m_coeffDivTwo * 2
|
||||||
|
q31_t value = t2 + t4 - t9;
|
||||||
|
|
||||||
|
bool previousState = m_state;
|
||||||
|
|
||||||
|
q31_t threshold = m_highThreshold;
|
||||||
|
if (previousState)
|
||||||
|
threshold = m_lowThreshold;
|
||||||
|
|
||||||
|
if (!m_state) {
|
||||||
|
if (value < threshold)
|
||||||
|
m_validCount++;
|
||||||
|
else
|
||||||
|
m_validCount = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_state) {
|
||||||
|
if (value >= threshold)
|
||||||
|
m_invalidCount++;
|
||||||
|
else
|
||||||
|
m_invalidCount = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_state = m_validCount >= 10U && m_invalidCount < 10U;
|
||||||
|
|
||||||
|
if(previousState && !m_state)
|
||||||
|
m_invalidCount = 0U;
|
||||||
|
|
||||||
|
if (previousState != m_state) {
|
||||||
|
DEBUG4("Noise Squelch Value / Threshold / Valid", value, threshold, m_state);
|
||||||
|
DEBUG3("Valid Count / Invalid Count", m_validCount, m_invalidCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_count = 0U;
|
||||||
|
m_q0 = 0;
|
||||||
|
m_q1 = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMNoiseSquelch::reset()
|
||||||
|
{
|
||||||
|
m_q0 = 0;
|
||||||
|
m_q1 = 0;
|
||||||
|
m_state = false;
|
||||||
|
m_count = 0U;
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(FMNOISESQUELCH_H)
|
||||||
|
#define FMNOISESQUELCH_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
class CFMNoiseSquelch {
|
||||||
|
public:
|
||||||
|
CFMNoiseSquelch();
|
||||||
|
|
||||||
|
void setParams(uint8_t highThreshold, uint8_t lowThreshold);
|
||||||
|
|
||||||
|
bool process(q15_t sample);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
q31_t m_highThreshold;
|
||||||
|
q31_t m_lowThreshold;
|
||||||
|
uint16_t m_count;
|
||||||
|
q31_t m_q0;
|
||||||
|
q31_t m_q1;
|
||||||
|
bool m_state;
|
||||||
|
uint8_t m_validCount;
|
||||||
|
uint8_t m_invalidCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2020 by Geoffrey Merck F4FXL - KC3FRA
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(TSAMPLEPACK_H)
|
||||||
|
#define TSAMPLEPACK_H
|
||||||
|
|
||||||
|
struct TSamplePairPack {
|
||||||
|
uint8_t byte0;
|
||||||
|
uint8_t byte1;
|
||||||
|
uint8_t byte2;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "FMTimeout.h"
|
||||||
|
|
||||||
|
// 400 Hz sine wave at 24000 Hz sample rate
|
||||||
|
const q15_t BUSY_AUDIO[] = {0, 3426, 6813, 10126, 13328, 16384, 19261, 21926, 24351, 26510, 28378, 29935, 31164, 32052, 32588, 32767, 32588, 32052, 31164, 29935, 28378, 26510, 24351,
|
||||||
|
21926, 19261, 16384, 13328, 10126, 6813, 3425, 0, -3425, -6813, -10126, -13328, -16384, -19261, -21926, -24351, -26510, -28378, -29935, -31164, -32052,
|
||||||
|
-32588, -32768, -32588, -32052, -31164, -29935, -28378, -26510, -24351, -21926, -19261, -16384, -13328, -10126, -6813, -3425};
|
||||||
|
const uint8_t BUSY_AUDIO_LEN = 60U;
|
||||||
|
|
||||||
|
CFMTimeout::CFMTimeout() :
|
||||||
|
m_level(128 * 128),
|
||||||
|
m_running(false),
|
||||||
|
m_pos(0U),
|
||||||
|
m_n(0U)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMTimeout::setParams(uint8_t level)
|
||||||
|
{
|
||||||
|
m_level = q15_t(level * 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
q15_t CFMTimeout::getAudio()
|
||||||
|
{
|
||||||
|
q15_t sample = 0;
|
||||||
|
if (!m_running)
|
||||||
|
return sample;
|
||||||
|
|
||||||
|
if (m_pos >= 12000U) {
|
||||||
|
q31_t sample31 = BUSY_AUDIO[m_n] * m_level;
|
||||||
|
sample = q15_t(__SSAT((sample31 >> 15), 16));
|
||||||
|
|
||||||
|
m_n++;
|
||||||
|
if (m_n >= BUSY_AUDIO_LEN)
|
||||||
|
m_n = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pos++;
|
||||||
|
if (m_pos >= 24000U)
|
||||||
|
m_pos = 0U;
|
||||||
|
|
||||||
|
return sample;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMTimeout::start()
|
||||||
|
{
|
||||||
|
m_running = true;
|
||||||
|
m_pos = 0U;
|
||||||
|
m_n = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMTimeout::stop()
|
||||||
|
{
|
||||||
|
m_running = false;
|
||||||
|
}
|
||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(FMTimeout_H)
|
||||||
|
#define FMTimeout_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
class CFMTimeout {
|
||||||
|
public:
|
||||||
|
CFMTimeout();
|
||||||
|
|
||||||
|
void setParams(uint8_t level);
|
||||||
|
|
||||||
|
void start();
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
q15_t getAudio();
|
||||||
|
|
||||||
|
private:
|
||||||
|
q15_t m_level;
|
||||||
|
bool m_running;
|
||||||
|
uint32_t m_pos;
|
||||||
|
uint8_t m_n;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
+70
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009,2010,2015,2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "Globals.h"
|
||||||
|
#include "FMTimer.h"
|
||||||
|
|
||||||
|
CFMTimer::CFMTimer() :
|
||||||
|
m_timeout(0U),
|
||||||
|
m_timer(0U)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMTimer::setTimeout(uint16_t secs, uint32_t msecs)
|
||||||
|
{
|
||||||
|
m_timeout = (secs * 24000U) + (msecs * 24U);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t CFMTimer::getTimeout() const
|
||||||
|
{
|
||||||
|
return m_timeout / 24U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMTimer::start()
|
||||||
|
{
|
||||||
|
if (m_timeout > 0U)
|
||||||
|
m_timer = 1U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMTimer::stop()
|
||||||
|
{
|
||||||
|
m_timer = 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMTimer::clock(uint8_t length)
|
||||||
|
{
|
||||||
|
if (m_timer > 0U && m_timeout > 0U)
|
||||||
|
m_timer += length;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFMTimer::isRunning() const
|
||||||
|
{
|
||||||
|
return m_timer > 0U;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFMTimer::hasExpired() const
|
||||||
|
{
|
||||||
|
if (m_timeout == 0U || m_timer == 0U)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (m_timer > m_timeout)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2009,2010,2015,2020 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; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(FMTimer_H)
|
||||||
|
#define FMTimer_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
|
||||||
|
class CFMTimer {
|
||||||
|
public:
|
||||||
|
CFMTimer();
|
||||||
|
|
||||||
|
void setTimeout(uint16_t secs, uint32_t msecs);
|
||||||
|
|
||||||
|
uint32_t getTimeout() const;
|
||||||
|
|
||||||
|
void start();
|
||||||
|
|
||||||
|
void stop();
|
||||||
|
|
||||||
|
void clock(uint8_t length);
|
||||||
|
|
||||||
|
bool isRunning() const;
|
||||||
|
|
||||||
|
bool hasExpired() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint32_t m_timeout;
|
||||||
|
uint32_t m_timer;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2020 by Geoffrey Merck F4FXL - KC3FRA
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "FMUpSampler.h"
|
||||||
|
|
||||||
|
const uint32_t FM_UPSAMPLE_MASK = 0x00000FFFU;
|
||||||
|
|
||||||
|
CFMUpSampler::CFMUpSampler() :
|
||||||
|
m_upSampleIndex(0),
|
||||||
|
m_pack(0U),
|
||||||
|
m_packPointer(NULL),
|
||||||
|
m_samples(3600U), //300ms of 12 bit 8kHz audio
|
||||||
|
m_running(false)
|
||||||
|
{
|
||||||
|
m_packPointer = (uint8_t*)&m_pack;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMUpSampler::reset()
|
||||||
|
{
|
||||||
|
m_upSampleIndex = 0U;
|
||||||
|
m_pack = 0U;
|
||||||
|
m_samples.reset();
|
||||||
|
m_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CFMUpSampler::addData(const uint8_t* data, uint16_t length)
|
||||||
|
{
|
||||||
|
TSamplePairPack* packPointer = (TSamplePairPack*)data;
|
||||||
|
TSamplePairPack* packPointerEnd = packPointer + (length / 3U);
|
||||||
|
while(packPointer != packPointerEnd) {
|
||||||
|
m_samples.put(*packPointer);
|
||||||
|
packPointer++;
|
||||||
|
}
|
||||||
|
if(!m_running)
|
||||||
|
m_running = m_samples.getData() > 300U;//75ms of audio
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CFMUpSampler::getSample(q15_t& sample)
|
||||||
|
{
|
||||||
|
if(!m_running)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (m_upSampleIndex)
|
||||||
|
{
|
||||||
|
case 0: {
|
||||||
|
TSamplePairPack pairPack;
|
||||||
|
if(!m_samples.get(pairPack)) {
|
||||||
|
m_running = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_pack = 0U;
|
||||||
|
m_packPointer = (uint8_t*)&m_pack;
|
||||||
|
|
||||||
|
m_packPointer[0U] = pairPack.byte0;
|
||||||
|
m_packPointer[1U] = pairPack.byte1;
|
||||||
|
m_packPointer[2U] = pairPack.byte2;
|
||||||
|
|
||||||
|
sample = q15_t(m_pack >> 12) - 2048;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 3:
|
||||||
|
sample = q15_t(m_pack & FM_UPSAMPLE_MASK) - 2048;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
sample = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_upSampleIndex++;
|
||||||
|
if(m_upSampleIndex >= 6U)
|
||||||
|
m_upSampleIndex = 0U;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t CFMUpSampler::getSpace() const
|
||||||
|
{
|
||||||
|
//return available space in bytes
|
||||||
|
return m_samples.getSpace() * sizeof(TSamplePairPack);
|
||||||
|
}
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2020 by Geoffrey Merck F4FXL - KC3FRA
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(FMUPSAMPLER_H)
|
||||||
|
#define FMUPSAMPLER_H
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "RingBuffer.h"
|
||||||
|
#include "FMSamplePairPack.h"
|
||||||
|
|
||||||
|
class CFMUpSampler {
|
||||||
|
public:
|
||||||
|
CFMUpSampler();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void addData(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
|
bool getSample(q15_t& sample);
|
||||||
|
|
||||||
|
uint16_t getSpace() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint8_t m_upSampleIndex;
|
||||||
|
uint32_t m_pack;
|
||||||
|
uint8_t * m_packPointer;
|
||||||
|
CRingBuffer<TSamplePairPack> m_samples;
|
||||||
|
bool m_running;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1 +0,0 @@
|
|||||||
#define GITVERSION "0000000"
|
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -28,6 +28,7 @@
|
|||||||
#include "STM32Utils.h"
|
#include "STM32Utils.h"
|
||||||
#else
|
#else
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
#undef PI //Undefine PI to get rid of annoying warning as it is also defined in arm_math.h.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__SAM3X8E__) || defined(STM32F105xC)
|
#if defined(__SAM3X8E__) || defined(STM32F105xC)
|
||||||
@@ -50,6 +51,8 @@ enum MMDVM_STATE {
|
|||||||
STATE_P25 = 4,
|
STATE_P25 = 4,
|
||||||
STATE_NXDN = 5,
|
STATE_NXDN = 5,
|
||||||
STATE_POCSAG = 6,
|
STATE_POCSAG = 6,
|
||||||
|
STATE_FM = 10,
|
||||||
|
STATE_AX25 = 11,
|
||||||
|
|
||||||
// Dummy states start at 90
|
// Dummy states start at 90
|
||||||
STATE_NXDNCAL1K = 91,
|
STATE_NXDNCAL1K = 91,
|
||||||
@@ -60,7 +63,15 @@ enum MMDVM_STATE {
|
|||||||
STATE_RSSICAL = 96,
|
STATE_RSSICAL = 96,
|
||||||
STATE_CWID = 97,
|
STATE_CWID = 97,
|
||||||
STATE_DMRCAL = 98,
|
STATE_DMRCAL = 98,
|
||||||
STATE_DSTARCAL = 99
|
STATE_DSTARCAL = 99,
|
||||||
|
STATE_INTCAL = 100,
|
||||||
|
STATE_POCSAGCAL = 101,
|
||||||
|
STATE_FMCAL10K = 102,
|
||||||
|
STATE_FMCAL12K = 103,
|
||||||
|
STATE_FMCAL15K = 104,
|
||||||
|
STATE_FMCAL20K = 105,
|
||||||
|
STATE_FMCAL25K = 106,
|
||||||
|
STATE_FMCAL30K = 107
|
||||||
};
|
};
|
||||||
|
|
||||||
#include "SerialPort.h"
|
#include "SerialPort.h"
|
||||||
@@ -80,13 +91,18 @@ enum MMDVM_STATE {
|
|||||||
#include "POCSAGTX.h"
|
#include "POCSAGTX.h"
|
||||||
#include "CalDStarRX.h"
|
#include "CalDStarRX.h"
|
||||||
#include "CalDStarTX.h"
|
#include "CalDStarTX.h"
|
||||||
|
#include "CalFM.h"
|
||||||
#include "CalDMR.h"
|
#include "CalDMR.h"
|
||||||
#include "CalP25.h"
|
#include "CalP25.h"
|
||||||
#include "CalNXDN.h"
|
#include "CalNXDN.h"
|
||||||
|
#include "CalPOCSAG.h"
|
||||||
#include "CalRSSI.h"
|
#include "CalRSSI.h"
|
||||||
#include "CWIdTX.h"
|
#include "CWIdTX.h"
|
||||||
|
#include "AX25RX.h"
|
||||||
|
#include "AX25TX.h"
|
||||||
#include "Debug.h"
|
#include "Debug.h"
|
||||||
#include "IO.h"
|
#include "IO.h"
|
||||||
|
#include "FM.h"
|
||||||
|
|
||||||
const uint8_t MARK_SLOT1 = 0x08U;
|
const uint8_t MARK_SLOT1 = 0x08U;
|
||||||
const uint8_t MARK_SLOT2 = 0x04U;
|
const uint8_t MARK_SLOT2 = 0x04U;
|
||||||
@@ -94,8 +110,8 @@ const uint8_t MARK_NONE = 0x00U;
|
|||||||
|
|
||||||
const uint16_t RX_BLOCK_SIZE = 2U;
|
const uint16_t RX_BLOCK_SIZE = 2U;
|
||||||
|
|
||||||
const uint16_t TX_RINGBUFFER_SIZE = 1000U;
|
const uint16_t TX_RINGBUFFER_SIZE = 500U;
|
||||||
const uint16_t RX_RINGBUFFER_SIZE = 1200U;
|
const uint16_t RX_RINGBUFFER_SIZE = 600U;
|
||||||
|
|
||||||
#if defined(STM32F105xC) || defined(__MK20DX256__)
|
#if defined(STM32F105xC) || defined(__MK20DX256__)
|
||||||
const uint16_t TX_BUFFER_LEN = 2000U;
|
const uint16_t TX_BUFFER_LEN = 2000U;
|
||||||
@@ -111,6 +127,8 @@ extern bool m_ysfEnable;
|
|||||||
extern bool m_p25Enable;
|
extern bool m_p25Enable;
|
||||||
extern bool m_nxdnEnable;
|
extern bool m_nxdnEnable;
|
||||||
extern bool m_pocsagEnable;
|
extern bool m_pocsagEnable;
|
||||||
|
extern bool m_fmEnable;
|
||||||
|
extern bool m_ax25Enable;
|
||||||
|
|
||||||
extern bool m_duplex;
|
extern bool m_duplex;
|
||||||
|
|
||||||
@@ -141,11 +159,17 @@ extern CNXDNTX nxdnTX;
|
|||||||
|
|
||||||
extern CPOCSAGTX pocsagTX;
|
extern CPOCSAGTX pocsagTX;
|
||||||
|
|
||||||
|
extern CFM fm;
|
||||||
|
extern CAX25RX ax25RX;
|
||||||
|
extern CAX25TX ax25TX;
|
||||||
|
|
||||||
extern CCalDStarRX calDStarRX;
|
extern CCalDStarRX calDStarRX;
|
||||||
extern CCalDStarTX calDStarTX;
|
extern CCalDStarTX calDStarTX;
|
||||||
extern CCalDMR calDMR;
|
extern CCalDMR calDMR;
|
||||||
|
extern CCalFM calFM;
|
||||||
extern CCalP25 calP25;
|
extern CCalP25 calP25;
|
||||||
extern CCalNXDN calNXDN;
|
extern CCalNXDN calNXDN;
|
||||||
|
extern CCalPOCSAG calPOCSAG;
|
||||||
extern CCalRSSI calRSSI;
|
extern CCalRSSI calRSSI;
|
||||||
|
|
||||||
extern CCWIdTX cwIdTX;
|
extern CCWIdTX cwIdTX;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2015 by Jim Mclaughlin KI6ZUM
|
* Copyright (C) 2015 by Jim Mclaughlin KI6ZUM
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
*
|
*
|
||||||
@@ -22,41 +22,35 @@
|
|||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "IO.h"
|
#include "IO.h"
|
||||||
|
|
||||||
// Generated using [b, a] = butter(1, 0.0005) in MATLAB
|
// Generated using [b, a] = butter(1, 0.001) in MATLAB
|
||||||
static q31_t DC_FILTER[] = {1685306, 0, 1685306, 0, 2144113034, 0}; // {b0, 0, b1, b2, -a1, -a2}
|
static q31_t DC_FILTER[] = {3367972, 0, 3367972, 0, 2140747704, 0}; // {b0, 0, b1, b2, -a1, -a2}
|
||||||
const uint32_t DC_FILTER_STAGES = 1U; // One Biquad stage
|
const uint32_t DC_FILTER_STAGES = 1U; // One Biquad stage
|
||||||
|
|
||||||
|
// Generated using rcosdesign(0.2, 8, 5, 'sqrt') in MATLAB
|
||||||
|
static q15_t RRC_0_2_FILTER[] = {401, 104, -340, -731, -847, -553, 112, 909, 1472, 1450, 683, -675, -2144, -3040, -2706, -770, 2667, 6995,
|
||||||
|
11237, 14331, 15464, 14331, 11237, 6995, 2667, -770, -2706, -3040, -2144, -675, 683, 1450, 1472, 909, 112,
|
||||||
|
-553, -847, -731, -340, 104, 401, 0};
|
||||||
|
const uint16_t RRC_0_2_FILTER_LEN = 42U;
|
||||||
|
|
||||||
// Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB
|
// Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB
|
||||||
static q15_t RRC_0_2_FILTER[] = {284, 198, 73, -78, -240, -393, -517, -590, -599, -533, -391, -181, 79, 364, 643, 880, 1041, 1097, 1026, 819,
|
static q15_t NXDN_0_2_FILTER[] = {284, 198, 73, -78, -240, -393, -517, -590, -599, -533, -391, -181, 79, 364, 643, 880, 1041, 1097, 1026, 819,
|
||||||
483, 39, -477, -1016, -1516, -1915, -2150, -2164, -1914, -1375, -545, 557, 1886, 3376, 4946, 6502, 7946, 9184,
|
483, 39, -477, -1016, -1516, -1915, -2150, -2164, -1914, -1375, -545, 557, 1886, 3376, 4946, 6502, 7946, 9184,
|
||||||
10134, 10731, 10935, 10731, 10134, 9184, 7946, 6502, 4946, 3376, 1886, 557, -545, -1375, -1914, -2164, -2150,
|
10134, 10731, 10935, 10731, 10134, 9184, 7946, 6502, 4946, 3376, 1886, 557, -545, -1375, -1914, -2164, -2150,
|
||||||
-1915, -1516, -1016, -477, 39, 483, 819, 1026, 1097, 1041, 880, 643, 364, 79, -181, -391, -533, -599, -590,
|
-1915, -1516, -1016, -477, 39, 483, 819, 1026, 1097, 1041, 880, 643, 364, 79, -181, -391, -533, -599, -590,
|
||||||
-517, -393, -240, -78, 73, 198, 284, 0};
|
-517, -393, -240, -78, 73, 198, 284, 0};
|
||||||
const uint16_t RRC_0_2_FILTER_LEN = 82U;
|
const uint16_t NXDN_0_2_FILTER_LEN = 82U;
|
||||||
|
|
||||||
// Generated using rcosdesign(0.2, 8, 20, 'sqrt') in MATLAB
|
static q15_t NXDN_ISINC_FILTER[] = {790, -1085, -1073, -553, 747, 2341, 3156, 2152, -893, -4915, -7834, -7536, -3102, 4441, 12354, 17394, 17394,
|
||||||
static q15_t NXDN_0_2_FILTER[] = {201, 174, 140, 99, 52, 0, -55, -112, -170, -226, -278, -325, -365, -397, -417, -427, -424, -407, -377, -333, -277, -208,
|
12354, 4441, -3102, -7536, -7834, -4915, -893, 2152, 3156, 2341, 747, -553, -1073, -1085, 790};
|
||||||
-128, -40, 56, 156, 258, 358, 455, 544, 622, 687, 736, 766, 775, 762, 725, 664, 579, 471, 342, 193, 27, -151, -338, -528,
|
|
||||||
-718, -901, -1072, -1225, -1354, -1454, -1520, -1547, -1530, -1466, -1353, -1189, -972, -704, -385, -18, 394, 846, 1333,
|
|
||||||
1850, 2388, 2940, 3498, 4053, 4598, 5122, 5619, 6079, 6494, 6859, 7166, 7410, 7588, 7696, 7732, 7696, 7588, 7410, 7166,
|
|
||||||
6859, 6494, 6079, 5619, 5122, 4598, 4053, 3498, 2940, 2388, 1850, 1333, 846, 394, -18, -385, -704, -972, -1189, -1353,
|
|
||||||
-1466, -1530, -1547, -1520, -1454, -1354, -1225, -1072, -901, -718, -528, -338, -151, 27, 193, 342, 471, 579, 664, 725,
|
|
||||||
762, 775, 766, 736, 687, 622, 544, 455, 358, 258, 156, 56, -40, -128, -208, -277, -333, -377, -407, -424, -427, -417, -397,
|
|
||||||
-365, -325, -278, -226, -170, -112, -55, 0, 52, 99, 140, 174, 201, 0};
|
|
||||||
const uint16_t NXDN_0_2_FILTER_LEN = 162U;
|
|
||||||
|
|
||||||
static q15_t NXDN_ISINC_FILTER[] = {7616, -1333, -1856, -2611, -3399, -4006, -4230, -3918, -2988, -1458, 561, 2867, 5200, 7276, 8832, 9665,
|
|
||||||
9665, 8832, 7276, 5200, 2867, 561, -1458, -2988, -3918, -4230, -4006, -3399, -2611, -1856, -1333, 7616};
|
|
||||||
const uint16_t NXDN_ISINC_FILTER_LEN = 32U;
|
const uint16_t NXDN_ISINC_FILTER_LEN = 32U;
|
||||||
|
|
||||||
#if !defined (DSTARBOXCAR)
|
// Generated using gaussfir(0.5, 4, 5) in MATLAB
|
||||||
// Generated using gaussfir(0.5, 4, 10) in MATLAB
|
static q15_t GAUSSIAN_0_5_FILTER[] = {8, 104, 760, 3158, 7421, 9866, 7421, 3158, 760, 104, 8, 0};
|
||||||
static q15_t GAUSSIAN_0_5_FILTER[] = {1, 4, 15, 52, 151, 380, 832, 1579, 2599, 3710, 4594, 4933, 4594, 3710, 2599, 1579, 832, 380, 151, 52, 15, 4, 1, 0};
|
const uint16_t GAUSSIAN_0_5_FILTER_LEN = 12U;
|
||||||
const uint16_t GAUSSIAN_0_5_FILTER_LEN = 24U;
|
|
||||||
#endif
|
|
||||||
// One symbol boxcar filter
|
// One symbol boxcar filter
|
||||||
static q15_t BOXCAR_FILTER[] = {6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 0, 0};
|
static q15_t BOXCAR_FILTER[] = {12000, 12000, 12000, 12000, 12000, 0};
|
||||||
const uint16_t BOXCAR_FILTER_LEN = 12U;
|
const uint16_t BOXCAR_FILTER_LEN = 6U;
|
||||||
|
|
||||||
const uint16_t DC_OFFSET = 2048U;
|
const uint16_t DC_OFFSET = 2048U;
|
||||||
|
|
||||||
@@ -68,16 +62,12 @@ m_rssiBuffer(RX_RINGBUFFER_SIZE),
|
|||||||
m_dcFilter(),
|
m_dcFilter(),
|
||||||
m_dcState(),
|
m_dcState(),
|
||||||
m_rrcFilter(),
|
m_rrcFilter(),
|
||||||
#if !defined (DSTARBOXCAR)
|
|
||||||
m_gaussianFilter(),
|
m_gaussianFilter(),
|
||||||
#endif
|
|
||||||
m_boxcarFilter(),
|
m_boxcarFilter(),
|
||||||
m_nxdnFilter(),
|
m_nxdnFilter(),
|
||||||
m_nxdnISincFilter(),
|
m_nxdnISincFilter(),
|
||||||
m_rrcState(),
|
m_rrcState(),
|
||||||
#if !defined (DSTARBOXCAR)
|
|
||||||
m_gaussianState(),
|
m_gaussianState(),
|
||||||
#endif
|
|
||||||
m_boxcarState(),
|
m_boxcarState(),
|
||||||
m_nxdnState(),
|
m_nxdnState(),
|
||||||
m_nxdnISincState(),
|
m_nxdnISincState(),
|
||||||
@@ -90,8 +80,11 @@ m_ysfTXLevel(128 * 128),
|
|||||||
m_p25TXLevel(128 * 128),
|
m_p25TXLevel(128 * 128),
|
||||||
m_nxdnTXLevel(128 * 128),
|
m_nxdnTXLevel(128 * 128),
|
||||||
m_pocsagTXLevel(128 * 128),
|
m_pocsagTXLevel(128 * 128),
|
||||||
|
m_fmTXLevel(128 * 128),
|
||||||
|
m_ax25TXLevel(128 * 128),
|
||||||
m_rxDCOffset(DC_OFFSET),
|
m_rxDCOffset(DC_OFFSET),
|
||||||
m_txDCOffset(DC_OFFSET),
|
m_txDCOffset(DC_OFFSET),
|
||||||
|
m_useCOSAsLockout(false),
|
||||||
m_ledCount(0U),
|
m_ledCount(0U),
|
||||||
m_ledValue(true),
|
m_ledValue(true),
|
||||||
m_detect(false),
|
m_detect(false),
|
||||||
@@ -100,12 +93,10 @@ m_dacOverflow(0U),
|
|||||||
m_watchdog(0U),
|
m_watchdog(0U),
|
||||||
m_lockout(false)
|
m_lockout(false)
|
||||||
{
|
{
|
||||||
::memset(m_rrcState, 0x00U, 140U * sizeof(q15_t));
|
::memset(m_rrcState, 0x00U, 70U * sizeof(q15_t));
|
||||||
#if !defined (DSTARBOXCAR)
|
::memset(m_gaussianState, 0x00U, 40U * sizeof(q15_t));
|
||||||
::memset(m_gaussianState, 0x00U, 80U * sizeof(q15_t));
|
::memset(m_boxcarState, 0x00U, 30U * sizeof(q15_t));
|
||||||
#endif
|
::memset(m_nxdnState, 0x00U, 110U * sizeof(q15_t));
|
||||||
::memset(m_boxcarState, 0x00U, 60U * sizeof(q15_t));
|
|
||||||
::memset(m_nxdnState, 0x00U, 220U * sizeof(q15_t));
|
|
||||||
::memset(m_nxdnISincState, 0x00U, 60U * sizeof(q15_t));
|
::memset(m_nxdnISincState, 0x00U, 60U * sizeof(q15_t));
|
||||||
::memset(m_dcState, 0x00U, 4U * sizeof(q31_t));
|
::memset(m_dcState, 0x00U, 4U * sizeof(q31_t));
|
||||||
|
|
||||||
@@ -117,11 +108,11 @@ m_lockout(false)
|
|||||||
m_rrcFilter.numTaps = RRC_0_2_FILTER_LEN;
|
m_rrcFilter.numTaps = RRC_0_2_FILTER_LEN;
|
||||||
m_rrcFilter.pState = m_rrcState;
|
m_rrcFilter.pState = m_rrcState;
|
||||||
m_rrcFilter.pCoeffs = RRC_0_2_FILTER;
|
m_rrcFilter.pCoeffs = RRC_0_2_FILTER;
|
||||||
#if !defined (DSTARBOXCAR)
|
|
||||||
m_gaussianFilter.numTaps = GAUSSIAN_0_5_FILTER_LEN;
|
m_gaussianFilter.numTaps = GAUSSIAN_0_5_FILTER_LEN;
|
||||||
m_gaussianFilter.pState = m_gaussianState;
|
m_gaussianFilter.pState = m_gaussianState;
|
||||||
m_gaussianFilter.pCoeffs = GAUSSIAN_0_5_FILTER;
|
m_gaussianFilter.pCoeffs = GAUSSIAN_0_5_FILTER;
|
||||||
#endif
|
|
||||||
m_boxcarFilter.numTaps = BOXCAR_FILTER_LEN;
|
m_boxcarFilter.numTaps = BOXCAR_FILTER_LEN;
|
||||||
m_boxcarFilter.pState = m_boxcarState;
|
m_boxcarFilter.pState = m_boxcarState;
|
||||||
m_boxcarFilter.pCoeffs = BOXCAR_FILTER;
|
m_boxcarFilter.pCoeffs = BOXCAR_FILTER;
|
||||||
@@ -143,130 +134,95 @@ void CIO::selfTest()
|
|||||||
{
|
{
|
||||||
bool ledValue = false;
|
bool ledValue = false;
|
||||||
|
|
||||||
for (uint8_t i = 0; i < 6; i++) {
|
for (uint8_t i = 0U; i < 6U; i++) {
|
||||||
ledValue = !ledValue;
|
ledValue = !ledValue;
|
||||||
|
|
||||||
// We exclude PTT to avoid trigger the transmitter
|
// We exclude PTT to avoid trigger the transmitter
|
||||||
setLEDInt(ledValue);
|
setLEDInt(ledValue);
|
||||||
setCOSInt(ledValue);
|
setCOSInt(ledValue);
|
||||||
#if defined(MODE_PINS)
|
#if defined(MODE_LEDS)
|
||||||
setDStarInt(ledValue);
|
setDStarInt(ledValue);
|
||||||
setDMRInt(ledValue);
|
setDMRInt(ledValue);
|
||||||
setYSFInt(ledValue);
|
setYSFInt(ledValue);
|
||||||
setP25Int(ledValue);
|
setP25Int(ledValue);
|
||||||
|
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
||||||
setNXDNInt(ledValue);
|
setNXDNInt(ledValue);
|
||||||
|
#endif
|
||||||
|
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
setPOCSAGInt(ledValue);
|
setPOCSAGInt(ledValue);
|
||||||
|
#endif
|
||||||
|
#if !defined(USE_ALTERNATE_FM_LEDS)
|
||||||
|
setFMInt(ledValue);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
delayInt(250);
|
delayInt(250);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(MODE_PINS)
|
#if defined(MODE_LEDS)
|
||||||
setDStarInt(true);
|
|
||||||
setDMRInt(false);
|
|
||||||
setYSFInt(false);
|
|
||||||
setP25Int(false);
|
|
||||||
setNXDNInt(false);
|
|
||||||
setPOCSAGInt(false);
|
|
||||||
|
|
||||||
delayInt(250);
|
|
||||||
|
|
||||||
setDStarInt(true);
|
|
||||||
setDMRInt(true);
|
|
||||||
setYSFInt(false);
|
|
||||||
setP25Int(false);
|
|
||||||
setNXDNInt(false);
|
|
||||||
setPOCSAGInt(false);
|
|
||||||
|
|
||||||
delayInt(250);
|
|
||||||
|
|
||||||
setDStarInt(true);
|
|
||||||
setDMRInt(true);
|
|
||||||
setYSFInt(true);
|
|
||||||
setP25Int(false);
|
|
||||||
setNXDNInt(false);
|
|
||||||
setPOCSAGInt(false);
|
|
||||||
|
|
||||||
delayInt(250);
|
|
||||||
|
|
||||||
setDStarInt(true);
|
|
||||||
setDMRInt(true);
|
|
||||||
setYSFInt(true);
|
|
||||||
setP25Int(true);
|
|
||||||
setNXDNInt(false);
|
|
||||||
setPOCSAGInt(false);
|
|
||||||
|
|
||||||
delayInt(250);
|
|
||||||
|
|
||||||
setDStarInt(true);
|
|
||||||
setDMRInt(true);
|
|
||||||
setYSFInt(true);
|
|
||||||
setP25Int(true);
|
|
||||||
setNXDNInt(true);
|
|
||||||
setPOCSAGInt(false);
|
|
||||||
|
|
||||||
delayInt(250);
|
|
||||||
|
|
||||||
setDStarInt(true);
|
|
||||||
setDMRInt(true);
|
|
||||||
setYSFInt(true);
|
|
||||||
setP25Int(true);
|
|
||||||
setNXDNInt(true);
|
|
||||||
setPOCSAGInt(true);
|
|
||||||
|
|
||||||
delayInt(250);
|
|
||||||
|
|
||||||
setDStarInt(true);
|
|
||||||
setDMRInt(true);
|
|
||||||
setYSFInt(true);
|
|
||||||
setP25Int(true);
|
|
||||||
setNXDNInt(true);
|
|
||||||
setPOCSAGInt(false);
|
|
||||||
|
|
||||||
delayInt(250);
|
|
||||||
|
|
||||||
setDStarInt(true);
|
|
||||||
setDMRInt(true);
|
|
||||||
setYSFInt(true);
|
|
||||||
setP25Int(true);
|
|
||||||
setNXDNInt(false);
|
|
||||||
setPOCSAGInt(false);
|
|
||||||
|
|
||||||
delayInt(250);
|
|
||||||
|
|
||||||
setDStarInt(true);
|
|
||||||
setDMRInt(true);
|
|
||||||
setYSFInt(true);
|
|
||||||
setP25Int(false);
|
|
||||||
setNXDNInt(false);
|
|
||||||
setPOCSAGInt(false);
|
|
||||||
|
|
||||||
delayInt(250);
|
|
||||||
|
|
||||||
setDStarInt(true);
|
|
||||||
setDMRInt(true);
|
|
||||||
setYSFInt(false);
|
|
||||||
setP25Int(false);
|
|
||||||
setNXDNInt(false);
|
|
||||||
setPOCSAGInt(false);
|
|
||||||
|
|
||||||
delayInt(250);
|
|
||||||
|
|
||||||
setDStarInt(true);
|
|
||||||
setDMRInt(false);
|
|
||||||
setYSFInt(false);
|
|
||||||
setP25Int(false);
|
|
||||||
setNXDNInt(false);
|
|
||||||
setPOCSAGInt(false);
|
|
||||||
|
|
||||||
delayInt(250);
|
|
||||||
|
|
||||||
setDStarInt(false);
|
setDStarInt(false);
|
||||||
setDMRInt(false);
|
setDMRInt(false);
|
||||||
setYSFInt(false);
|
setYSFInt(false);
|
||||||
setP25Int(false);
|
setP25Int(false);
|
||||||
|
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
||||||
setNXDNInt(false);
|
setNXDNInt(false);
|
||||||
|
#endif
|
||||||
|
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
setPOCSAGInt(false);
|
setPOCSAGInt(false);
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(USE_ALTERNATE_FM_LEDS)
|
||||||
|
setFMInt(false);
|
||||||
|
#endif
|
||||||
|
setDStarInt(true);
|
||||||
|
|
||||||
|
delayInt(250);
|
||||||
|
setDMRInt(true);
|
||||||
|
|
||||||
|
delayInt(250);
|
||||||
|
setYSFInt(true);
|
||||||
|
|
||||||
|
delayInt(250);
|
||||||
|
setP25Int(true);
|
||||||
|
|
||||||
|
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
||||||
|
delayInt(250);
|
||||||
|
setNXDNInt(true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
|
delayInt(250);
|
||||||
|
setPOCSAGInt(true);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(USE_ALTERNATE_FM_LEDS)
|
||||||
|
delayInt(250);
|
||||||
|
setFMInt(true);
|
||||||
|
|
||||||
|
delayInt(250);
|
||||||
|
setFMInt(false);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
|
delayInt(250);
|
||||||
|
setPOCSAGInt(false);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(USE_ALTERNATE_NXDN_LEDS)
|
||||||
|
delayInt(250);
|
||||||
|
setNXDNInt(false);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
delayInt(250);
|
||||||
|
setP25Int(false);
|
||||||
|
|
||||||
|
delayInt(250);
|
||||||
|
setYSFInt(false);
|
||||||
|
|
||||||
|
delayInt(250);
|
||||||
|
setDMRInt(false);
|
||||||
|
|
||||||
|
delayInt(250);
|
||||||
|
setDStarInt(false);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIO::start()
|
void CIO::start()
|
||||||
@@ -278,7 +234,7 @@ void CIO::start()
|
|||||||
|
|
||||||
m_started = true;
|
m_started = true;
|
||||||
|
|
||||||
setMode();
|
setMode(STATE_IDLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIO::process()
|
void CIO::process()
|
||||||
@@ -286,12 +242,11 @@ void CIO::process()
|
|||||||
m_ledCount++;
|
m_ledCount++;
|
||||||
if (m_started) {
|
if (m_started) {
|
||||||
// Two seconds timeout
|
// Two seconds timeout
|
||||||
if (m_watchdog >= 96000U) {
|
if (m_watchdog >= 48000U) {
|
||||||
if (m_modemState == STATE_DSTAR || m_modemState == STATE_DMR || m_modemState == STATE_YSF || m_modemState == STATE_P25 || m_modemState == STATE_NXDN) {
|
if (m_modemState == STATE_DSTAR || m_modemState == STATE_DMR || m_modemState == STATE_YSF || m_modemState == STATE_P25 || m_modemState == STATE_NXDN || m_modemState == STATE_POCSAG) {
|
||||||
if (m_modemState == STATE_DMR && m_tx)
|
if (m_modemState == STATE_DMR && m_tx)
|
||||||
dmrTX.setStart(false);
|
dmrTX.setStart(false);
|
||||||
m_modemState = STATE_IDLE;
|
setMode(STATE_IDLE);
|
||||||
setMode();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_watchdog = 0U;
|
m_watchdog = 0U;
|
||||||
@@ -300,14 +255,14 @@ void CIO::process()
|
|||||||
#if defined(CONSTANT_SRV_LED)
|
#if defined(CONSTANT_SRV_LED)
|
||||||
setLEDInt(true);
|
setLEDInt(true);
|
||||||
#else
|
#else
|
||||||
if (m_ledCount >= 48000U) {
|
if (m_ledCount >= 24000U) {
|
||||||
m_ledCount = 0U;
|
m_ledCount = 0U;
|
||||||
m_ledValue = !m_ledValue;
|
m_ledValue = !m_ledValue;
|
||||||
setLEDInt(m_ledValue);
|
setLEDInt(m_ledValue);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
if (m_ledCount >= 480000U) {
|
if (m_ledCount >= 240000U) {
|
||||||
m_ledCount = 0U;
|
m_ledCount = 0U;
|
||||||
m_ledValue = !m_ledValue;
|
m_ledValue = !m_ledValue;
|
||||||
setLEDInt(m_ledValue);
|
setLEDInt(m_ledValue);
|
||||||
@@ -315,14 +270,14 @@ void CIO::process()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(USE_COS_AS_LOCKOUT)
|
if (m_useCOSAsLockout)
|
||||||
m_lockout = getCOSInt();
|
m_lockout = getCOSInt();
|
||||||
#endif
|
|
||||||
|
|
||||||
// Switch off the transmitter if needed
|
// Switch off the transmitter if needed
|
||||||
if (m_txBuffer.getData() == 0U && m_tx) {
|
if (m_txBuffer.getData() == 0U && m_tx) {
|
||||||
m_tx = false;
|
m_tx = false;
|
||||||
setPTTInt(m_pttInvert ? true : false);
|
setPTTInt(m_pttInvert ? true : false);
|
||||||
|
DEBUG1("TX OFF");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_rxBuffer.getData() >= RX_BLOCK_SIZE) {
|
if (m_rxBuffer.getData() >= RX_BLOCK_SIZE) {
|
||||||
@@ -331,15 +286,16 @@ void CIO::process()
|
|||||||
uint16_t rssi[RX_BLOCK_SIZE];
|
uint16_t rssi[RX_BLOCK_SIZE];
|
||||||
|
|
||||||
for (uint16_t i = 0U; i < RX_BLOCK_SIZE; i++) {
|
for (uint16_t i = 0U; i < RX_BLOCK_SIZE; i++) {
|
||||||
uint16_t sample;
|
TSample sample;
|
||||||
m_rxBuffer.get(sample, control[i]);
|
m_rxBuffer.get(sample);
|
||||||
|
control[i] = sample.control;
|
||||||
m_rssiBuffer.get(rssi[i]);
|
m_rssiBuffer.get(rssi[i]);
|
||||||
|
|
||||||
// Detect ADC overflow
|
// Detect ADC overflow
|
||||||
if (m_detect && (sample == 0U || sample == 4095U))
|
if (m_detect && (sample.sample == 0U || sample.sample == 4095U))
|
||||||
m_adcOverflow++;
|
m_adcOverflow++;
|
||||||
|
|
||||||
q15_t res1 = q15_t(sample) - m_rxDCOffset;
|
q15_t res1 = q15_t(sample.sample) - m_rxDCOffset;
|
||||||
q31_t res2 = res1 * m_rxLevel;
|
q31_t res2 = res1 * m_rxLevel;
|
||||||
samples[i] = q15_t(__SSAT((res2 >> 15), 16));
|
samples[i] = q15_t(__SSAT((res2 >> 15), 16));
|
||||||
}
|
}
|
||||||
@@ -370,17 +326,9 @@ void CIO::process()
|
|||||||
if (m_dstarEnable) {
|
if (m_dstarEnable) {
|
||||||
q15_t GMSKVals[RX_BLOCK_SIZE];
|
q15_t GMSKVals[RX_BLOCK_SIZE];
|
||||||
#if defined(USE_DCBLOCKER)
|
#if defined(USE_DCBLOCKER)
|
||||||
#if !defined (DSTARBOXCAR)
|
|
||||||
::arm_fir_fast_q15(&m_gaussianFilter, dcSamples, GMSKVals, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_gaussianFilter, dcSamples, GMSKVals, RX_BLOCK_SIZE);
|
||||||
#else
|
|
||||||
::arm_fir_fast_q15(&m_boxcarFilter, dcSamples, GMSKVals, RX_BLOCK_SIZE);
|
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
#if !defined (DSTARBOXCAR)
|
|
||||||
::arm_fir_fast_q15(&m_gaussianFilter, samples, GMSKVals, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_gaussianFilter, samples, GMSKVals, RX_BLOCK_SIZE);
|
||||||
#else
|
|
||||||
::arm_fir_fast_q15(&m_boxcarFilter, samples, GMSKVals, RX_BLOCK_SIZE);
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE);
|
dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE);
|
||||||
}
|
}
|
||||||
@@ -422,21 +370,30 @@ void CIO::process()
|
|||||||
dmrDMORX.samples(RRCVals, rssi, RX_BLOCK_SIZE);
|
dmrDMORX.samples(RRCVals, rssi, RX_BLOCK_SIZE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (m_fmEnable) {
|
||||||
|
bool cos = getCOSInt();
|
||||||
|
#if defined(USE_DCBLOCKER)
|
||||||
|
fm.samples(cos, dcSamples, RX_BLOCK_SIZE);
|
||||||
|
#else
|
||||||
|
fm.samples(cos, samples, RX_BLOCK_SIZE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_ax25Enable) {
|
||||||
|
#if defined(USE_DCBLOCKER)
|
||||||
|
ax25RX.samples(dcSamples, RX_BLOCK_SIZE);
|
||||||
|
#else
|
||||||
|
ax25RX.samples(samples, RX_BLOCK_SIZE);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
} else if (m_modemState == STATE_DSTAR) {
|
} else if (m_modemState == STATE_DSTAR) {
|
||||||
if (m_dstarEnable) {
|
if (m_dstarEnable) {
|
||||||
q15_t GMSKVals[RX_BLOCK_SIZE];
|
q15_t GMSKVals[RX_BLOCK_SIZE];
|
||||||
#if defined(USE_DCBLOCKER)
|
#if defined(USE_DCBLOCKER)
|
||||||
#if !defined (DSTARBOXCAR)
|
|
||||||
::arm_fir_fast_q15(&m_gaussianFilter, dcSamples, GMSKVals, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_gaussianFilter, dcSamples, GMSKVals, RX_BLOCK_SIZE);
|
||||||
#else
|
|
||||||
::arm_fir_fast_q15(&m_boxcarFilter, dcSamples, GMSKVals, RX_BLOCK_SIZE);
|
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
#if !defined (DSTARBOXCAR)
|
|
||||||
::arm_fir_fast_q15(&m_gaussianFilter, samples, GMSKVals, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_gaussianFilter, samples, GMSKVals, RX_BLOCK_SIZE);
|
||||||
#else
|
|
||||||
::arm_fir_fast_q15(&m_boxcarFilter, samples, GMSKVals, RX_BLOCK_SIZE);
|
|
||||||
#endif
|
|
||||||
#endif
|
#endif
|
||||||
dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE);
|
dstarRX.samples(GMSKVals, rssi, RX_BLOCK_SIZE);
|
||||||
}
|
}
|
||||||
@@ -488,13 +445,21 @@ void CIO::process()
|
|||||||
|
|
||||||
nxdnRX.samples(NXDNVals, rssi, RX_BLOCK_SIZE);
|
nxdnRX.samples(NXDNVals, rssi, RX_BLOCK_SIZE);
|
||||||
}
|
}
|
||||||
|
} else if (m_modemState == STATE_FM) {
|
||||||
|
bool cos = getCOSInt();
|
||||||
|
#if defined(USE_DCBLOCKER)
|
||||||
|
fm.samples(cos, dcSamples, RX_BLOCK_SIZE);
|
||||||
|
if (m_ax25Enable)
|
||||||
|
ax25RX.samples(dcSamples, RX_BLOCK_SIZE);
|
||||||
|
#else
|
||||||
|
fm.samples(cos, samples, RX_BLOCK_SIZE);
|
||||||
|
if (m_ax25Enable)
|
||||||
|
ax25RX.samples(samples, RX_BLOCK_SIZE);
|
||||||
|
#endif
|
||||||
} else if (m_modemState == STATE_DSTARCAL) {
|
} else if (m_modemState == STATE_DSTARCAL) {
|
||||||
q15_t GMSKVals[RX_BLOCK_SIZE];
|
q15_t GMSKVals[RX_BLOCK_SIZE];
|
||||||
#if !defined (DSTARBOXCAR)
|
|
||||||
::arm_fir_fast_q15(&m_gaussianFilter, samples, GMSKVals, RX_BLOCK_SIZE);
|
::arm_fir_fast_q15(&m_gaussianFilter, samples, GMSKVals, RX_BLOCK_SIZE);
|
||||||
#else
|
|
||||||
::arm_fir_fast_q15(&m_boxcarFilter, samples, GMSKVals, RX_BLOCK_SIZE);
|
|
||||||
#endif
|
|
||||||
calDStarRX.samples(GMSKVals, RX_BLOCK_SIZE);
|
calDStarRX.samples(GMSKVals, RX_BLOCK_SIZE);
|
||||||
} else if (m_modemState == STATE_RSSICAL) {
|
} else if (m_modemState == STATE_RSSICAL) {
|
||||||
calRSSI.samples(rssi, RX_BLOCK_SIZE);
|
calRSSI.samples(rssi, RX_BLOCK_SIZE);
|
||||||
@@ -514,6 +479,7 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t
|
|||||||
if (!m_tx) {
|
if (!m_tx) {
|
||||||
m_tx = true;
|
m_tx = true;
|
||||||
setPTTInt(m_pttInvert ? false : true);
|
setPTTInt(m_pttInvert ? false : true);
|
||||||
|
DEBUG1("TX ON");
|
||||||
}
|
}
|
||||||
|
|
||||||
q15_t txLevel = 0;
|
q15_t txLevel = 0;
|
||||||
@@ -536,6 +502,12 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t
|
|||||||
case STATE_POCSAG:
|
case STATE_POCSAG:
|
||||||
txLevel = m_pocsagTXLevel;
|
txLevel = m_pocsagTXLevel;
|
||||||
break;
|
break;
|
||||||
|
case STATE_FM:
|
||||||
|
txLevel = m_fmTXLevel;
|
||||||
|
break;
|
||||||
|
case STATE_AX25:
|
||||||
|
txLevel = m_ax25TXLevel;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
txLevel = m_cwIdTXLevel;
|
txLevel = m_cwIdTXLevel;
|
||||||
break;
|
break;
|
||||||
@@ -551,9 +523,9 @@ void CIO::write(MMDVM_STATE mode, q15_t* samples, uint16_t length, const uint8_t
|
|||||||
m_dacOverflow++;
|
m_dacOverflow++;
|
||||||
|
|
||||||
if (control == NULL)
|
if (control == NULL)
|
||||||
m_txBuffer.put(res3, MARK_NONE);
|
m_txBuffer.put({res3, MARK_NONE});
|
||||||
else
|
else
|
||||||
m_txBuffer.put(res3, control[i]);
|
m_txBuffer.put({res3, control[i]});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -575,19 +547,37 @@ void CIO::setADCDetection(bool detect)
|
|||||||
m_detect = detect;
|
m_detect = detect;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIO::setMode()
|
void CIO::setMode(MMDVM_STATE state)
|
||||||
{
|
{
|
||||||
#if defined(MODE_PINS)
|
if (state == m_modemState)
|
||||||
setDStarInt(m_modemState == STATE_DSTAR);
|
return;
|
||||||
setDMRInt(m_modemState == STATE_DMR);
|
|
||||||
setYSFInt(m_modemState == STATE_YSF);
|
#if defined(MODE_LEDS)
|
||||||
setP25Int(m_modemState == STATE_P25);
|
switch (m_modemState) {
|
||||||
setNXDNInt(m_modemState == STATE_NXDN);
|
case STATE_DSTAR: setDStarInt(false); break;
|
||||||
setPOCSAGInt(m_modemState == STATE_POCSAG);
|
case STATE_DMR: setDMRInt(false); break;
|
||||||
|
case STATE_YSF: setYSFInt(false); break;
|
||||||
|
case STATE_P25: setP25Int(false); break;
|
||||||
|
case STATE_NXDN: setNXDNInt(false); break;
|
||||||
|
case STATE_POCSAG: setPOCSAGInt(false); break;
|
||||||
|
case STATE_FM: setFMInt(false); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (state) {
|
||||||
|
case STATE_DSTAR: setDStarInt(true); break;
|
||||||
|
case STATE_DMR: setDMRInt(true); break;
|
||||||
|
case STATE_YSF: setYSFInt(true); break;
|
||||||
|
case STATE_P25: setP25Int(true); break;
|
||||||
|
case STATE_NXDN: setNXDNInt(true); break;
|
||||||
|
case STATE_POCSAG: setPOCSAGInt(true); break;
|
||||||
|
case STATE_FM: setFMInt(true); break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
m_modemState = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, int16_t txDCOffset, int16_t rxDCOffset)
|
void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout)
|
||||||
{
|
{
|
||||||
m_pttInvert = pttInvert;
|
m_pttInvert = pttInvert;
|
||||||
|
|
||||||
@@ -599,10 +589,14 @@ void CIO::setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rx
|
|||||||
m_p25TXLevel = q15_t(p25TXLevel * 128);
|
m_p25TXLevel = q15_t(p25TXLevel * 128);
|
||||||
m_nxdnTXLevel = q15_t(nxdnTXLevel * 128);
|
m_nxdnTXLevel = q15_t(nxdnTXLevel * 128);
|
||||||
m_pocsagTXLevel = q15_t(pocsagTXLevel * 128);
|
m_pocsagTXLevel = q15_t(pocsagTXLevel * 128);
|
||||||
|
m_fmTXLevel = q15_t(fmTXLevel * 128);
|
||||||
|
m_ax25TXLevel = q15_t(ax25TXLevel * 128);
|
||||||
|
|
||||||
m_rxDCOffset = DC_OFFSET + rxDCOffset;
|
m_rxDCOffset = DC_OFFSET + rxDCOffset;
|
||||||
m_txDCOffset = DC_OFFSET + txDCOffset;
|
m_txDCOffset = DC_OFFSET + txDCOffset;
|
||||||
|
|
||||||
|
m_useCOSAsLockout = useCOSAsLockout;
|
||||||
|
|
||||||
if (rxInvert)
|
if (rxInvert)
|
||||||
m_rxLevel = -m_rxLevel;
|
m_rxLevel = -m_rxLevel;
|
||||||
|
|
||||||
@@ -649,4 +643,3 @@ bool CIO::hasLockout() const
|
|||||||
{
|
{
|
||||||
return m_lockout;
|
return m_lockout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -21,8 +21,12 @@
|
|||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
|
|
||||||
#include "SampleRB.h"
|
#include "RingBuffer.h"
|
||||||
#include "RSSIRB.h"
|
|
||||||
|
struct TSample {
|
||||||
|
volatile uint16_t sample;
|
||||||
|
volatile uint8_t control;
|
||||||
|
};
|
||||||
|
|
||||||
class CIO {
|
class CIO {
|
||||||
public:
|
public:
|
||||||
@@ -38,11 +42,11 @@ public:
|
|||||||
|
|
||||||
void setDecode(bool dcd);
|
void setDecode(bool dcd);
|
||||||
void setADCDetection(bool detect);
|
void setADCDetection(bool detect);
|
||||||
void setMode();
|
void setMode(MMDVM_STATE state);
|
||||||
|
|
||||||
void interrupt();
|
void interrupt();
|
||||||
|
|
||||||
void setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, int16_t txDCOffset, int16_t rxDCOffset);
|
void setParameters(bool rxInvert, bool txInvert, bool pttInvert, uint8_t rxLevel, uint8_t cwIdTXLevel, uint8_t dstarTXLevel, uint8_t dmrTXLevel, uint8_t ysfTXLevel, uint8_t p25TXLevel, uint8_t nxdnTXLevel, uint8_t pocsagTXLevel, uint8_t fmTXLevel, uint8_t ax25TXLevel, int16_t txDCOffset, int16_t rxDCOffset, bool useCOSAsLockout);
|
||||||
|
|
||||||
void getOverflow(bool& adcOverflow, bool& dacOverflow);
|
void getOverflow(bool& adcOverflow, bool& dacOverflow);
|
||||||
|
|
||||||
@@ -59,26 +63,22 @@ public:
|
|||||||
private:
|
private:
|
||||||
bool m_started;
|
bool m_started;
|
||||||
|
|
||||||
CSampleRB m_rxBuffer;
|
CRingBuffer<TSample> m_rxBuffer;
|
||||||
CSampleRB m_txBuffer;
|
CRingBuffer<TSample> m_txBuffer;
|
||||||
CRSSIRB m_rssiBuffer;
|
CRingBuffer<uint16_t> m_rssiBuffer;
|
||||||
|
|
||||||
arm_biquad_casd_df1_inst_q31 m_dcFilter;
|
arm_biquad_casd_df1_inst_q31 m_dcFilter;
|
||||||
q31_t m_dcState[4];
|
q31_t m_dcState[4];
|
||||||
|
|
||||||
arm_fir_instance_q15 m_rrcFilter;
|
arm_fir_instance_q15 m_rrcFilter;
|
||||||
#if !defined (DSTARBOXCAR)
|
|
||||||
arm_fir_instance_q15 m_gaussianFilter;
|
arm_fir_instance_q15 m_gaussianFilter;
|
||||||
#endif
|
|
||||||
arm_fir_instance_q15 m_boxcarFilter;
|
arm_fir_instance_q15 m_boxcarFilter;
|
||||||
arm_fir_instance_q15 m_nxdnFilter;
|
arm_fir_instance_q15 m_nxdnFilter;
|
||||||
arm_fir_instance_q15 m_nxdnISincFilter;
|
arm_fir_instance_q15 m_nxdnISincFilter;
|
||||||
q15_t m_rrcState[140U]; // NoTaps + BlockSize - 1, 82 + 20 - 1 plus some spare
|
q15_t m_rrcState[70U]; // NoTaps + BlockSize - 1, 42 + 20 - 1 plus some spare
|
||||||
#if !defined (DSTARBOXCAR)
|
q15_t m_gaussianState[40U]; // NoTaps + BlockSize - 1, 12 + 20 - 1 plus some spare
|
||||||
q15_t m_gaussianState[80U]; // NoTaps + BlockSize - 1, 24 + 20 - 1 plus some spare
|
q15_t m_boxcarState[30U]; // NoTaps + BlockSize - 1, 6 + 20 - 1 plus some spare
|
||||||
#endif
|
q15_t m_nxdnState[110U]; // NoTaps + BlockSize - 1, 82 + 20 - 1 plus some spare
|
||||||
q15_t m_boxcarState[60U]; // NoTaps + BlockSize - 1, 12 + 20 - 1 plus some spare
|
|
||||||
q15_t m_nxdnState[220U]; // NoTaps + BlockSize - 1, 162 + 20 - 1 plus some spare
|
|
||||||
q15_t m_nxdnISincState[60U]; // NoTaps + BlockSize - 1, 32 + 20 - 1 plus some spare
|
q15_t m_nxdnISincState[60U]; // NoTaps + BlockSize - 1, 32 + 20 - 1 plus some spare
|
||||||
|
|
||||||
bool m_pttInvert;
|
bool m_pttInvert;
|
||||||
@@ -90,10 +90,14 @@ private:
|
|||||||
q15_t m_p25TXLevel;
|
q15_t m_p25TXLevel;
|
||||||
q15_t m_nxdnTXLevel;
|
q15_t m_nxdnTXLevel;
|
||||||
q15_t m_pocsagTXLevel;
|
q15_t m_pocsagTXLevel;
|
||||||
|
q15_t m_fmTXLevel;
|
||||||
|
q15_t m_ax25TXLevel;
|
||||||
|
|
||||||
uint16_t m_rxDCOffset;
|
uint16_t m_rxDCOffset;
|
||||||
uint16_t m_txDCOffset;
|
uint16_t m_txDCOffset;
|
||||||
|
|
||||||
|
bool m_useCOSAsLockout;
|
||||||
|
|
||||||
uint32_t m_ledCount;
|
uint32_t m_ledCount;
|
||||||
bool m_ledValue;
|
bool m_ledValue;
|
||||||
|
|
||||||
@@ -122,9 +126,9 @@ private:
|
|||||||
void setP25Int(bool on);
|
void setP25Int(bool on);
|
||||||
void setNXDNInt(bool on);
|
void setNXDNInt(bool on);
|
||||||
void setPOCSAGInt(bool on);
|
void setPOCSAGInt(bool on);
|
||||||
|
void setFMInt(bool on);
|
||||||
|
|
||||||
void delayInt(unsigned int dly);
|
void delayInt(unsigned int dly);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2015 by Jim Mclaughlin KI6ZUM
|
* Copyright (C) 2015 by Jim Mclaughlin KI6ZUM
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
*
|
*
|
||||||
@@ -35,6 +35,7 @@
|
|||||||
#define PIN_P25 19
|
#define PIN_P25 19
|
||||||
#define PIN_NXDN 20
|
#define PIN_NXDN 20
|
||||||
#define PIN_POCSAG 4
|
#define PIN_POCSAG 4
|
||||||
|
#define PIN_FM 5
|
||||||
#define ADC_CHER_Chan (1<<7) // ADC on Due pin A0 - Due AD7 - (1 << 7)
|
#define ADC_CHER_Chan (1<<7) // ADC on Due pin A0 - Due AD7 - (1 << 7)
|
||||||
#define ADC_ISR_EOC_Chan ADC_ISR_EOC7
|
#define ADC_ISR_EOC_Chan ADC_ISR_EOC7
|
||||||
#define ADC_CDR_Chan 7
|
#define ADC_CDR_Chan 7
|
||||||
@@ -50,6 +51,7 @@
|
|||||||
#define PIN_P25 6
|
#define PIN_P25 6
|
||||||
#define PIN_NXDN 5
|
#define PIN_NXDN 5
|
||||||
#define PIN_POCSAG 4
|
#define PIN_POCSAG 4
|
||||||
|
#define PIN_FM 3
|
||||||
#define ADC_CHER_Chan (1<<13) // ADC on Due pin A11 - Due AD13 - (1 << 13)
|
#define ADC_CHER_Chan (1<<13) // ADC on Due pin A11 - Due AD13 - (1 << 13)
|
||||||
#define ADC_ISR_EOC_Chan ADC_ISR_EOC13
|
#define ADC_ISR_EOC_Chan ADC_ISR_EOC13
|
||||||
#define ADC_CDR_Chan 13
|
#define ADC_CDR_Chan 13
|
||||||
@@ -67,6 +69,7 @@
|
|||||||
#define PIN_P25 6
|
#define PIN_P25 6
|
||||||
#define PIN_NXDN 5
|
#define PIN_NXDN 5
|
||||||
#define PIN_POCSAG 4
|
#define PIN_POCSAG 4
|
||||||
|
#define PIN_FM 3
|
||||||
#define ADC_CHER_Chan (1<<7) // ADC on Due pin A0 - Due AD7 - (1 << 7)
|
#define ADC_CHER_Chan (1<<7) // ADC on Due pin A0 - Due AD7 - (1 << 7)
|
||||||
#define ADC_ISR_EOC_Chan ADC_ISR_EOC7
|
#define ADC_ISR_EOC_Chan ADC_ISR_EOC7
|
||||||
#define ADC_CDR_Chan 7
|
#define ADC_CDR_Chan 7
|
||||||
@@ -107,6 +110,9 @@ void CIO::initInt()
|
|||||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
pinMode(PIN_POCSAG, OUTPUT);
|
pinMode(PIN_POCSAG, OUTPUT);
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
|
pinMode(PIN_FM, OUTPUT);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,11 +158,11 @@ void CIO::startInt()
|
|||||||
TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_CLEAR |
|
TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_CLEAR |
|
||||||
TC_CMR_BCPB_CLEAR | TC_CMR_BCPC_CLEAR;
|
TC_CMR_BCPB_CLEAR | TC_CMR_BCPC_CLEAR;
|
||||||
#if defined(EXTERNAL_OSC)
|
#if defined(EXTERNAL_OSC)
|
||||||
t->TC_RC = EXTERNAL_OSC / 48000; // Counter resets on RC, so sets period in terms of the external clock
|
t->TC_RC = EXTERNAL_OSC / 24000; // Counter resets on RC, so sets period in terms of the external clock
|
||||||
t->TC_RA = EXTERNAL_OSC / 96000; // Roughly square wave
|
t->TC_RA = EXTERNAL_OSC / 48000; // Roughly square wave
|
||||||
#else
|
#else
|
||||||
t->TC_RC = 875; // Counter resets on RC, so sets period in terms of 42MHz internal clock
|
t->TC_RC = 1750; // Counter resets on RC, so sets period in terms of 42MHz internal clock
|
||||||
t->TC_RA = 438; // Roughly square wave
|
t->TC_RA = 880; // Roughly square wave
|
||||||
#endif
|
#endif
|
||||||
t->TC_CMR = (t->TC_CMR & 0xFFF0FFFF) | TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET; // Set clear and set from RA and RC compares
|
t->TC_CMR = (t->TC_CMR & 0xFFF0FFFF) | TC_CMR_ACPA_CLEAR | TC_CMR_ACPC_SET; // Set clear and set from RA and RC compares
|
||||||
t->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; // re-enable local clocking and switch to hardware trigger source.
|
t->TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; // re-enable local clocking and switch to hardware trigger source.
|
||||||
@@ -179,14 +185,13 @@ void CIO::startInt()
|
|||||||
void CIO::interrupt()
|
void CIO::interrupt()
|
||||||
{
|
{
|
||||||
if ((ADC->ADC_ISR & ADC_ISR_EOC_Chan) == ADC_ISR_EOC_Chan) { // Ensure there was an End-of-Conversion and we read the ISR reg
|
if ((ADC->ADC_ISR & ADC_ISR_EOC_Chan) == ADC_ISR_EOC_Chan) { // Ensure there was an End-of-Conversion and we read the ISR reg
|
||||||
uint8_t control = MARK_NONE;
|
TSample sample = {DC_OFFSET, MARK_NONE};
|
||||||
uint16_t sample = DC_OFFSET;
|
|
||||||
|
|
||||||
m_txBuffer.get(sample, control);
|
m_txBuffer.get(sample);
|
||||||
DACC->DACC_CDR = sample;
|
DACC->DACC_CDR = sample.sample;
|
||||||
|
|
||||||
sample = ADC->ADC_CDR[ADC_CDR_Chan];
|
sample.sample = ADC->ADC_CDR[ADC_CDR_Chan];
|
||||||
m_rxBuffer.put(sample, control);
|
m_rxBuffer.put(sample);
|
||||||
|
|
||||||
#if defined(SEND_RSSI_DATA)
|
#if defined(SEND_RSSI_DATA)
|
||||||
m_rssiBuffer.put(ADC->ADC_CDR[RSSI_CDR_Chan]);
|
m_rssiBuffer.put(ADC->ADC_CDR[RSSI_CDR_Chan]);
|
||||||
@@ -258,10 +263,19 @@ void CIO::setPOCSAGInt(bool on)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CIO::setFMInt(bool on)
|
||||||
|
{
|
||||||
|
#if defined(USE_ALTERNATE_FM_LEDS)
|
||||||
|
digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
|
||||||
|
digitalWrite(PIN_YSF, on ? HIGH : LOW);
|
||||||
|
#else
|
||||||
|
digitalWrite(PIN_FM, on ? HIGH : LOW);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void CIO::delayInt(unsigned int dly)
|
void CIO::delayInt(unsigned int dly)
|
||||||
{
|
{
|
||||||
delay(dly);
|
delay(dly);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2019,2020 by BG5HHP
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _IO_PINS_H
|
||||||
|
#define _IO_PINS_H
|
||||||
|
|
||||||
|
#if !defined(CONFIG_H)
|
||||||
|
#error "Requires Config.h to be included first!"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(STM32F4_RPT_HAT_TGO)
|
||||||
|
#include "pins/pins_f4_rpt_tgo.h"
|
||||||
|
|
||||||
|
#elif defined(STM32F4_DISCOVERY)
|
||||||
|
#include "pins/pins_f4_discovery.h"
|
||||||
|
|
||||||
|
#elif defined(STM32F4_PI)
|
||||||
|
#include "pins/pins_f4_pi.h"
|
||||||
|
|
||||||
|
#elif defined(STM32F722_PI)
|
||||||
|
#include "pins/pins_f7_pi.h"
|
||||||
|
|
||||||
|
#elif defined(STM32F4_F4M)
|
||||||
|
#include "pins/pins_f4_f4m.h"
|
||||||
|
|
||||||
|
#elif defined(STM32F722_F7M)
|
||||||
|
#include "pins/pins_f7_f7m.h"
|
||||||
|
|
||||||
|
#elif defined(STM32F722_RPT_HAT)
|
||||||
|
#include "pins/pins_f7_rpt_hat.h"
|
||||||
|
|
||||||
|
#elif defined(STM32F4_NUCLEO)
|
||||||
|
#if defined(STM32F4_NUCLEO_MORPHO_HEADER)
|
||||||
|
#include "pins/pins_f4_nucleo_morpho.h"
|
||||||
|
#elif defined(STM32F4_NUCLEO_ARDUINO_HEADER)
|
||||||
|
#include "pins/pins_f4_nucleo_arduino.h"
|
||||||
|
#else
|
||||||
|
#error "Either STM32F4_NUCLEO_MORPHO_HEADER or STM32F4_NUCLEO_ARDUINO_HEADER need to be defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(STM32F7_NUCLEO)
|
||||||
|
#include "pins/pins_f7_nucleo.h"
|
||||||
|
|
||||||
|
#elif defined(STM32F4_DVM)
|
||||||
|
#include "pins/pins_f4_stm32dvm_v3.h"
|
||||||
|
|
||||||
|
#elif defined(DRCC_DVM_NQF)
|
||||||
|
#include "pins/pins_f4_drcc_nqf.h"
|
||||||
|
|
||||||
|
#elif defined(STM32F4_EDA_405) || defined(STM32F4_EDA_446)
|
||||||
|
#include "pins/pins_f4_stm32eda.h"
|
||||||
|
|
||||||
|
#else
|
||||||
|
#error "A valid board type macro need to be defined."
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif //#ifndef _IO_PINS_H
|
||||||
+17
-8
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
|
* Copyright (C) 2016 by Jim McLaughlin KI6ZUM
|
||||||
* Copyright (C) 2016, 2017 by Andy Uribe CA6JAU
|
* Copyright (C) 2016, 2017 by Andy Uribe CA6JAU
|
||||||
* Copyright (C) 2017,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2017,2018,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2017 by Wojciech Krutnik N0CALL
|
* Copyright (C) 2017 by Wojciech Krutnik N0CALL
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -111,7 +111,7 @@ USART1_RXD PA10 input (AF)
|
|||||||
const uint16_t DC_OFFSET = 2048U;
|
const uint16_t DC_OFFSET = 2048U;
|
||||||
|
|
||||||
// Sampling frequency
|
// Sampling frequency
|
||||||
#define SAMP_FREQ 48000
|
#define SAMP_FREQ 24000
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
void TIM2_IRQHandler() {
|
void TIM2_IRQHandler() {
|
||||||
@@ -367,9 +367,10 @@ void CIO::startInt()
|
|||||||
|
|
||||||
void CIO::interrupt()
|
void CIO::interrupt()
|
||||||
{
|
{
|
||||||
uint8_t control = MARK_NONE;
|
TSample sample = {DC_OFFSET, MARK_NONE};
|
||||||
uint16_t sample = DC_OFFSET;
|
#if defined(SEND_RSSI_DATA)
|
||||||
uint16_t rawRSSI = 0U;
|
uint16_t rawRSSI = 0U;
|
||||||
|
#endif
|
||||||
bitband_t eoc = (bitband_t)BITBAND_PERIPH(&ADC1->SR, ADC_SR_EOS_Pos);
|
bitband_t eoc = (bitband_t)BITBAND_PERIPH(&ADC1->SR, ADC_SR_EOS_Pos);
|
||||||
bitband_t adon = (bitband_t)BITBAND_PERIPH(&ADC1->CR2, ADC_CR2_ADON_Pos);
|
bitband_t adon = (bitband_t)BITBAND_PERIPH(&ADC1->CR2, ADC_CR2_ADON_Pos);
|
||||||
#if defined(SEND_RSSI_DATA)
|
#if defined(SEND_RSSI_DATA)
|
||||||
@@ -383,12 +384,12 @@ void CIO::interrupt()
|
|||||||
*rssi_adon = 1;
|
*rssi_adon = 1;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_txBuffer.get(sample, control);
|
m_txBuffer.get(sample);
|
||||||
DAC->DHR12R1 = sample; // Send the value to the DAC
|
DAC->DHR12R1 = sample.sample; // Send the value to the DAC
|
||||||
|
|
||||||
// Read value from ADC1 and ADC2
|
// Read value from ADC1 and ADC2
|
||||||
sample = ADC1->DR; // read conversion result; EOC is cleared by this read
|
sample.sample = ADC1->DR; // read conversion result; EOC is cleared by this read
|
||||||
m_rxBuffer.put(sample, control);
|
m_rxBuffer.put(sample);
|
||||||
#if defined(SEND_RSSI_DATA)
|
#if defined(SEND_RSSI_DATA)
|
||||||
rawRSSI = ADC2->DR;
|
rawRSSI = ADC2->DR;
|
||||||
m_rssiBuffer.put(rawRSSI);
|
m_rssiBuffer.put(rawRSSI);
|
||||||
@@ -458,6 +459,14 @@ void CIO::setPOCSAGInt(bool on)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CIO::setFMInt(bool on)
|
||||||
|
{
|
||||||
|
#if defined(USE_ALTERNATE_FM_LEDS)
|
||||||
|
BB_DSTAR = !!on;
|
||||||
|
BB_YSF = !!on;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void CIO::delayInt(unsigned int dly)
|
void CIO::delayInt(unsigned int dly)
|
||||||
{
|
{
|
||||||
delay(dly);
|
delay(dly);
|
||||||
|
|||||||
+25
-11
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2016,2017,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2016,2017,2018,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -37,9 +37,11 @@
|
|||||||
#if defined(__MK20DX256__)
|
#if defined(__MK20DX256__)
|
||||||
#define PIN_NXDN 2
|
#define PIN_NXDN 2
|
||||||
#define PIN_POCSAG 3
|
#define PIN_POCSAG 3
|
||||||
|
#define PIN_FM 4
|
||||||
#else
|
#else
|
||||||
#define PIN_NXDN 24
|
#define PIN_NXDN 24
|
||||||
#define PIN_POCSAG 25
|
#define PIN_POCSAG 25
|
||||||
|
#define PIN_FM 26
|
||||||
#endif
|
#endif
|
||||||
#define PIN_ADC 5 // A0, Pin 14
|
#define PIN_ADC 5 // A0, Pin 14
|
||||||
#define PIN_RSSI 4 // Teensy 3.5/3.6, A16, Pin 35. Teensy 3.1/3.2, A17, Pin 28
|
#define PIN_RSSI 4 // Teensy 3.5/3.6, A16, Pin 35. Teensy 3.1/3.2, A17, Pin 28
|
||||||
@@ -76,6 +78,9 @@ void CIO::initInt()
|
|||||||
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
#if !defined(USE_ALTERNATE_POCSAG_LEDS)
|
||||||
pinMode(PIN_POCSAG, OUTPUT);
|
pinMode(PIN_POCSAG, OUTPUT);
|
||||||
#endif
|
#endif
|
||||||
|
#if !defined(USE_ALTERNATE_FM_LEDS)
|
||||||
|
pinMode(PIN_FM, OUTPUT);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +130,7 @@ void CIO::startInt()
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(EXTERNAL_OSC)
|
#if defined(EXTERNAL_OSC)
|
||||||
// Set ADC0 to trigger from the LPTMR at 48 kHz
|
// Set ADC0 to trigger from the LPTMR at 24 kHz
|
||||||
SIM_SOPT7 = SIM_SOPT7_ADC0ALTTRGEN | // Enable ADC0 alternate trigger
|
SIM_SOPT7 = SIM_SOPT7_ADC0ALTTRGEN | // Enable ADC0 alternate trigger
|
||||||
SIM_SOPT7_ADC0TRGSEL(14); // Trigger ADC0 by LPTMR0
|
SIM_SOPT7_ADC0TRGSEL(14); // Trigger ADC0 by LPTMR0
|
||||||
|
|
||||||
@@ -134,14 +139,14 @@ void CIO::startInt()
|
|||||||
SIM_SCGC5 |= SIM_SCGC5_LPTIMER; // Enable Low Power Timer Access
|
SIM_SCGC5 |= SIM_SCGC5_LPTIMER; // Enable Low Power Timer Access
|
||||||
LPTMR0_CSR = 0; // Disable
|
LPTMR0_CSR = 0; // Disable
|
||||||
LPTMR0_PSR = LPTMR_PSR_PBYP; // Bypass prescaler/filter
|
LPTMR0_PSR = LPTMR_PSR_PBYP; // Bypass prescaler/filter
|
||||||
LPTMR0_CMR = (EXTERNAL_OSC / 48000) - 1; // Frequency divided by CMR + 1
|
LPTMR0_CMR = (EXTERNAL_OSC / 24000) - 1; // Frequency divided by CMR + 1
|
||||||
LPTMR0_CSR = LPTMR_CSR_TPS(2) | // Pin: 0=CMP0, 1=xtal, 2=pin13
|
LPTMR0_CSR = LPTMR_CSR_TPS(2) | // Pin: 0=CMP0, 1=xtal, 2=pin13
|
||||||
LPTMR_CSR_TMS; // Mode Select, 0=timer, 1=counter
|
LPTMR_CSR_TMS; // Mode Select, 0=timer, 1=counter
|
||||||
LPTMR0_CSR |= LPTMR_CSR_TEN; // Enable
|
LPTMR0_CSR |= LPTMR_CSR_TEN; // Enable
|
||||||
#else
|
#else
|
||||||
// Setup PDB for ADC0 at 48 kHz
|
// Setup PDB for ADC0 at 24 kHz
|
||||||
SIM_SCGC6 |= SIM_SCGC6_PDB; // Enable PDB clock
|
SIM_SCGC6 |= SIM_SCGC6_PDB; // Enable PDB clock
|
||||||
PDB0_MOD = (F_BUS / 48000) - 1; // Timer period - 1
|
PDB0_MOD = (F_BUS / 24000) - 1; // Timer period - 1
|
||||||
PDB0_IDLY = 0; // Interrupt delay
|
PDB0_IDLY = 0; // Interrupt delay
|
||||||
PDB0_CH0C1 = PDB_CHnC1_TOS | PDB_CHnC1_EN; // Enable pre-trigger for ADC0
|
PDB0_CH0C1 = PDB_CHnC1_TOS | PDB_CHnC1_EN; // Enable pre-trigger for ADC0
|
||||||
PDB0_SC = PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | // SW trigger, enable interrupts, continuous mode
|
PDB0_SC = PDB_SC_TRGSEL(15) | PDB_SC_PDBEN | // SW trigger, enable interrupts, continuous mode
|
||||||
@@ -156,15 +161,14 @@ void CIO::startInt()
|
|||||||
|
|
||||||
void CIO::interrupt()
|
void CIO::interrupt()
|
||||||
{
|
{
|
||||||
uint8_t control = MARK_NONE;
|
TSample sample = {DC_OFFSET, MARK_NONE};
|
||||||
uint16_t sample = DC_OFFSET;
|
|
||||||
|
|
||||||
m_txBuffer.get(sample, control);
|
m_txBuffer.get(sample);
|
||||||
*(int16_t *)&(DAC0_DAT0L) = sample;
|
*(int16_t *)&(DAC0_DAT0L) = sample.sample;
|
||||||
|
|
||||||
if ((ADC0_SC1A & ADC_SC1_COCO) == ADC_SC1_COCO) {
|
if ((ADC0_SC1A & ADC_SC1_COCO) == ADC_SC1_COCO) {
|
||||||
sample = ADC0_RA;
|
sample.sample = ADC0_RA;
|
||||||
m_rxBuffer.put(sample, control);
|
m_rxBuffer.put(sample);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(SEND_RSSI_DATA)
|
#if defined(SEND_RSSI_DATA)
|
||||||
@@ -243,6 +247,16 @@ void CIO::setPOCSAGInt(bool on)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CIO::setFMInt(bool on)
|
||||||
|
{
|
||||||
|
#if defined(USE_ALTERNATE_FM_LEDS)
|
||||||
|
digitalWrite(PIN_DSTAR, on ? HIGH : LOW);
|
||||||
|
digitalWrite(PIN_YSF, on ? HIGH : LOW);
|
||||||
|
#else
|
||||||
|
digitalWrite(PIN_FM, on ? HIGH : LOW);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
void CIO::delayInt(unsigned int dly)
|
void CIO::delayInt(unsigned int dly)
|
||||||
{
|
{
|
||||||
delay(dly);
|
delay(dly);
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2016 by Mathis Schmieder DB9MAT
|
* Copyright (C) 2016 by Mathis Schmieder DB9MAT
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
*
|
*
|
||||||
@@ -32,6 +32,8 @@ bool m_ysfEnable = true;
|
|||||||
bool m_p25Enable = true;
|
bool m_p25Enable = true;
|
||||||
bool m_nxdnEnable = true;
|
bool m_nxdnEnable = true;
|
||||||
bool m_pocsagEnable = true;
|
bool m_pocsagEnable = true;
|
||||||
|
bool m_fmEnable = true;
|
||||||
|
bool m_ax25Enable = true;
|
||||||
|
|
||||||
bool m_duplex = true;
|
bool m_duplex = true;
|
||||||
|
|
||||||
@@ -59,11 +61,17 @@ CNXDNTX nxdnTX;
|
|||||||
|
|
||||||
CPOCSAGTX pocsagTX;
|
CPOCSAGTX pocsagTX;
|
||||||
|
|
||||||
|
CFM fm;
|
||||||
|
CAX25RX ax25RX;
|
||||||
|
CAX25TX ax25TX;
|
||||||
|
|
||||||
CCalDStarRX calDStarRX;
|
CCalDStarRX calDStarRX;
|
||||||
CCalDStarTX calDStarTX;
|
CCalDStarTX calDStarTX;
|
||||||
CCalDMR calDMR;
|
CCalDMR calDMR;
|
||||||
CCalP25 calP25;
|
CCalP25 calP25;
|
||||||
CCalNXDN calNXDN;
|
CCalNXDN calNXDN;
|
||||||
|
CCalFM calFM;
|
||||||
|
CCalPOCSAG calPOCSAG;
|
||||||
CCalRSSI calRSSI;
|
CCalRSSI calRSSI;
|
||||||
|
|
||||||
CCWIdTX cwIdTX;
|
CCWIdTX cwIdTX;
|
||||||
@@ -105,6 +113,12 @@ void loop()
|
|||||||
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
|
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
|
||||||
pocsagTX.process();
|
pocsagTX.process();
|
||||||
|
|
||||||
|
if (m_ax25Enable && (m_modemState == STATE_IDLE || m_modemState == STATE_FM))
|
||||||
|
ax25TX.process();
|
||||||
|
|
||||||
|
if (m_fmEnable && m_modemState == STATE_FM)
|
||||||
|
fm.process();
|
||||||
|
|
||||||
if (m_modemState == STATE_DSTARCAL)
|
if (m_modemState == STATE_DSTARCAL)
|
||||||
calDStarTX.process();
|
calDStarTX.process();
|
||||||
|
|
||||||
@@ -117,6 +131,12 @@ void loop()
|
|||||||
if (m_modemState == STATE_NXDNCAL1K)
|
if (m_modemState == STATE_NXDNCAL1K)
|
||||||
calNXDN.process();
|
calNXDN.process();
|
||||||
|
|
||||||
|
if (m_modemState == STATE_POCSAGCAL)
|
||||||
|
calPOCSAG.process();
|
||||||
|
|
||||||
|
if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K ||m_modemState == STATE_FMCAL30K)
|
||||||
|
calFM.process();
|
||||||
|
|
||||||
if (m_modemState == STATE_IDLE)
|
if (m_modemState == STATE_IDLE)
|
||||||
cwIdTX.process();
|
cwIdTX.process();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2016 by Colin Durbridge G4EML
|
* Copyright (C) 2016 by Colin Durbridge G4EML
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -29,6 +29,8 @@ bool m_ysfEnable = true;
|
|||||||
bool m_p25Enable = true;
|
bool m_p25Enable = true;
|
||||||
bool m_nxdnEnable = true;
|
bool m_nxdnEnable = true;
|
||||||
bool m_pocsagEnable = true;
|
bool m_pocsagEnable = true;
|
||||||
|
bool m_fmEnable = true;
|
||||||
|
bool m_ax25Enable = true;
|
||||||
|
|
||||||
bool m_duplex = true;
|
bool m_duplex = true;
|
||||||
|
|
||||||
@@ -56,11 +58,17 @@ CNXDNTX nxdnTX;
|
|||||||
|
|
||||||
CPOCSAGTX pocsagTX;
|
CPOCSAGTX pocsagTX;
|
||||||
|
|
||||||
|
CFM fm;
|
||||||
|
CAX25RX ax25RX;
|
||||||
|
CAX25TX ax25TX;
|
||||||
|
|
||||||
CCalDStarRX calDStarRX;
|
CCalDStarRX calDStarRX;
|
||||||
CCalDStarTX calDStarTX;
|
CCalDStarTX calDStarTX;
|
||||||
CCalDMR calDMR;
|
CCalDMR calDMR;
|
||||||
|
CCalFM calFM;
|
||||||
CCalP25 calP25;
|
CCalP25 calP25;
|
||||||
CCalNXDN calNXDN;
|
CCalNXDN calNXDN;
|
||||||
|
CCalPOCSAG calPOCSAG;
|
||||||
CCalRSSI calRSSI;
|
CCalRSSI calRSSI;
|
||||||
|
|
||||||
CCWIdTX cwIdTX;
|
CCWIdTX cwIdTX;
|
||||||
@@ -102,19 +110,30 @@ void loop()
|
|||||||
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
|
if (m_pocsagEnable && (m_modemState == STATE_POCSAG || pocsagTX.busy()))
|
||||||
pocsagTX.process();
|
pocsagTX.process();
|
||||||
|
|
||||||
|
if (m_ax25Enable && (m_modemState == STATE_IDLE || m_modemState == STATE_FM))
|
||||||
|
ax25TX.process();
|
||||||
|
|
||||||
|
if (m_fmEnable && m_modemState == STATE_FM)
|
||||||
|
fm.process();
|
||||||
|
|
||||||
if (m_modemState == STATE_DSTARCAL)
|
if (m_modemState == STATE_DSTARCAL)
|
||||||
calDStarTX.process();
|
calDStarTX.process();
|
||||||
|
|
||||||
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
|
if (m_modemState == STATE_DMRCAL || m_modemState == STATE_LFCAL || m_modemState == STATE_DMRCAL1K || m_modemState == STATE_DMRDMO1K)
|
||||||
calDMR.process();
|
calDMR.process();
|
||||||
|
|
||||||
|
if (m_modemState == STATE_FMCAL10K || m_modemState == STATE_FMCAL12K || m_modemState == STATE_FMCAL15K || m_modemState == STATE_FMCAL20K || m_modemState == STATE_FMCAL25K || m_modemState == STATE_FMCAL30K)
|
||||||
|
calFM.process();
|
||||||
|
|
||||||
if (m_modemState == STATE_P25CAL1K)
|
if (m_modemState == STATE_P25CAL1K)
|
||||||
calP25.process();
|
calP25.process();
|
||||||
|
|
||||||
if (m_modemState == STATE_NXDNCAL1K)
|
if (m_modemState == STATE_NXDNCAL1K)
|
||||||
calNXDN.process();
|
calNXDN.process();
|
||||||
|
|
||||||
|
if (m_modemState == STATE_POCSAGCAL)
|
||||||
|
calPOCSAG.process();
|
||||||
|
|
||||||
if (m_modemState == STATE_IDLE)
|
if (m_modemState == STATE_IDLE)
|
||||||
cwIdTX.process();
|
cwIdTX.process();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,360 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
|
||||||
<Project version="2G - 2.0.5" name="MMDVM_STM32F4xx">
|
|
||||||
<Target name="MMDVM_Discovery_407" isCurrent="0">
|
|
||||||
<Device manufacturerId="9" manufacturerName="ST" chipId="261" chipName="STM32F407VG" boardId="" boardName="" boardUrl="" coreId="" coreName=""/>
|
|
||||||
<BuildOption>
|
|
||||||
<Compile>
|
|
||||||
<Option name="OptimizationLevel" value="4"/>
|
|
||||||
<Option name="UseFPU" value="0"/>
|
|
||||||
<Option name="UserEditCompiler" value=""/>
|
|
||||||
<Option name="SupportCPlusplus" value="1"/>
|
|
||||||
<Option name="FPU" value="2"/>
|
|
||||||
<Option name="DEBUG" value="2"/>
|
|
||||||
<Option name="WARNING" value="1"/>
|
|
||||||
<Includepaths>
|
|
||||||
<Includepath path="."/>
|
|
||||||
</Includepaths>
|
|
||||||
<DefinedSymbols>
|
|
||||||
<Define name="STM32F4XX"/>
|
|
||||||
<Define name="USE_STDPERIPH_DRIVER"/>
|
|
||||||
<Define name="__ASSEMBLY__"/>
|
|
||||||
<Define name="SUPPORT_CPLUSPLUS"/>
|
|
||||||
<Define name="STM32F40_41xxx"/>
|
|
||||||
<Define name="HSE_VALUE=8000000"/>
|
|
||||||
<Define name="STM32F4_DISCOVERY"/>
|
|
||||||
<Define name="__FPU_USED"/>
|
|
||||||
</DefinedSymbols>
|
|
||||||
</Compile>
|
|
||||||
<Link useDefault="0">
|
|
||||||
<Option name="DiscardUnusedSection" value="0"/>
|
|
||||||
<Option name="UserEditLinkder" value=""/>
|
|
||||||
<Option name="UseMemoryLayout" value="0"/>
|
|
||||||
<Option name="nostartfiles" value="1"/>
|
|
||||||
<Option name="LTO" value="0"/>
|
|
||||||
<Option name="IsNewStartupCode" value="1"/>
|
|
||||||
<Option name="Library" value="Semihosting"/>
|
|
||||||
<Option name="UserEditLinker" value="-lstdc++; --specs=nano.specs;"/>
|
|
||||||
<LinkedLibraries>
|
|
||||||
<Libset dir="stm32f4xx_lib\cmsis\lib\gcc\" libs="arm_cortexm4lf_math"/>
|
|
||||||
</LinkedLibraries>
|
|
||||||
<MemoryAreas debugInFlashNotRAM="1">
|
|
||||||
<Memory name="IROM1" type="ReadOnly" size="0x00100000" startValue="0x08000000"/>
|
|
||||||
<Memory name="IRAM1" type="ReadWrite" size="0x00020000" startValue="0x20000000"/>
|
|
||||||
<Memory name="IROM2" type="ReadOnly" size="" startValue=""/>
|
|
||||||
<Memory name="IRAM2" type="ReadWrite" size="0x00010000" startValue="0x10000000"/>
|
|
||||||
</MemoryAreas>
|
|
||||||
<LocateLinkFile path="./stm32f4xx_link.ld" type="0"/>
|
|
||||||
</Link>
|
|
||||||
<Output>
|
|
||||||
<Option name="OutputFileType" value="0"/>
|
|
||||||
<Option name="Path" value="./"/>
|
|
||||||
<Option name="Name" value="MMDVM_DIS"/>
|
|
||||||
<Option name="HEX" value="1"/>
|
|
||||||
<Option name="BIN" value="1"/>
|
|
||||||
</Output>
|
|
||||||
<User>
|
|
||||||
<UserRun name="Run#1" type="Before" checked="0" value=""/>
|
|
||||||
<UserRun name="Run#1" type="After" checked="0" value=""/>
|
|
||||||
</User>
|
|
||||||
</BuildOption>
|
|
||||||
<DebugOption>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.adapter" value="ST-Link"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.debugMode" value="SWD"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.clockDiv" value="1M"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.corerunToMain" value="1"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.jlinkgdbserver" value=""/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.userDefineGDBScript" value=""/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.targetEndianess" value="0"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.jlinkResetMode" value="Type 0: Normal"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.resetMode" value="SYSRESETREQ"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.ifSemihost" value="0"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.ifCacheRom" value="1"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.ipAddress" value="127.0.0.1"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.portNumber" value="2009"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.autoDownload" value="1"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.verify" value="1"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.downloadFuction" value="Erase Effected"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.defaultAlgorithm" value="STM32F4xx_1024.elf"/>
|
|
||||||
</DebugOption>
|
|
||||||
<ExcludeFile/>
|
|
||||||
</Target>
|
|
||||||
<Target name="MMDVM_Pi_446" isCurrent="0">
|
|
||||||
<Device manufacturerId="9" manufacturerName="ST" chipId="344" chipName="STM32F407VG" boardId="" boardName="" boardUrl="" coreId="" coreName=""/>
|
|
||||||
<BuildOption>
|
|
||||||
<Compile>
|
|
||||||
<Option name="OptimizationLevel" value="4"/>
|
|
||||||
<Option name="UseFPU" value="0"/>
|
|
||||||
<Option name="UserEditCompiler" value=""/>
|
|
||||||
<Option name="SupportCPlusplus" value="1"/>
|
|
||||||
<Option name="FPU" value="2"/>
|
|
||||||
<Includepaths>
|
|
||||||
<Includepath path="."/>
|
|
||||||
</Includepaths>
|
|
||||||
<DefinedSymbols>
|
|
||||||
<Define name="STM32F4XX"/>
|
|
||||||
<Define name="USE_STDPERIPH_DRIVER"/>
|
|
||||||
<Define name="__ASSEMBLY__"/>
|
|
||||||
<Define name="SUPPORT_CPLUSPLUS"/>
|
|
||||||
<Define name="__FPU_USED"/>
|
|
||||||
<Define name="STM32F446xx"/>
|
|
||||||
<Define name="HSE_VALUE=12000000"/>
|
|
||||||
<Define name="STM32F4_PI"/>
|
|
||||||
<Define name="ARDUINO_MODE_PINS"/>
|
|
||||||
</DefinedSymbols>
|
|
||||||
</Compile>
|
|
||||||
<Link useDefault="0">
|
|
||||||
<Option name="DiscardUnusedSection" value="0"/>
|
|
||||||
<Option name="UserEditLinkder" value=""/>
|
|
||||||
<Option name="UseMemoryLayout" value="0"/>
|
|
||||||
<Option name="nostartfiles" value="1"/>
|
|
||||||
<Option name="LTO" value="0"/>
|
|
||||||
<Option name="IsNewStartupCode" value="1"/>
|
|
||||||
<Option name="Library" value="Semihosting"/>
|
|
||||||
<Option name="UserEditLinker" value="-lstdc++; --specs=nano.specs;"/>
|
|
||||||
<LinkedLibraries>
|
|
||||||
<Libset dir="stm32f4xx_lib\cmsis\lib\gcc\" libs="arm_cortexm4lf_math"/>
|
|
||||||
</LinkedLibraries>
|
|
||||||
<MemoryAreas debugInFlashNotRAM="1">
|
|
||||||
<Memory name="IROM1" type="ReadOnly" size="0x00100000" startValue="0x08000000"/>
|
|
||||||
<Memory name="IRAM1" type="ReadWrite" size="0x00020000" startValue="0x20000000"/>
|
|
||||||
<Memory name="IROM2" type="ReadOnly" size="" startValue=""/>
|
|
||||||
<Memory name="IRAM2" type="ReadWrite" size="0x00010000" startValue="0x10000000"/>
|
|
||||||
</MemoryAreas>
|
|
||||||
<LocateLinkFile path="./stm32f4xx_link.ld" type="0"/>
|
|
||||||
</Link>
|
|
||||||
<Output>
|
|
||||||
<Option name="OutputFileType" value="0"/>
|
|
||||||
<Option name="Path" value="./"/>
|
|
||||||
<Option name="Name" value="MMDVM_PI"/>
|
|
||||||
<Option name="HEX" value="1"/>
|
|
||||||
<Option name="BIN" value="1"/>
|
|
||||||
</Output>
|
|
||||||
<User>
|
|
||||||
<UserRun name="Run#1" type="Before" checked="0" value=""/>
|
|
||||||
<UserRun name="Run#1" type="After" checked="0" value=""/>
|
|
||||||
</User>
|
|
||||||
</BuildOption>
|
|
||||||
<DebugOption>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.adapter" value="ST-Link"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.debugMode" value="SWD"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.clockDiv" value="1M"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.corerunToMain" value="1"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.jlinkgdbserver" value=""/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.userDefineGDBScript" value=""/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.targetEndianess" value="0"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.jlinkResetMode" value="Type 0: Normal"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.resetMode" value="SYSRESETREQ"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.ifSemihost" value="0"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.ifCacheRom" value="1"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.ipAddress" value="127.0.0.1"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.portNumber" value="2009"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.autoDownload" value="1"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.verify" value="1"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.downloadFuction" value="Erase Effected"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.defaultAlgorithm" value="STM32F4xx_1024.elf"/>
|
|
||||||
</DebugOption>
|
|
||||||
<ExcludeFile/>
|
|
||||||
</Target>
|
|
||||||
<Target name="MMDVM_Nucleo_446" isCurrent="1">
|
|
||||||
<Device manufacturerId="9" manufacturerName="ST" chipId="261" chipName="STM32F407VG" boardId="" boardName="" boardUrl="" coreId="" coreName=""/>
|
|
||||||
<BuildOption>
|
|
||||||
<Compile>
|
|
||||||
<Option name="OptimizationLevel" value="4"/>
|
|
||||||
<Option name="UseFPU" value="0"/>
|
|
||||||
<Option name="UserEditCompiler" value=""/>
|
|
||||||
<Option name="SupportCPlusplus" value="1"/>
|
|
||||||
<Option name="FPU" value="2"/>
|
|
||||||
<Option name="DEBUG" value="2"/>
|
|
||||||
<Option name="WARNING" value="0"/>
|
|
||||||
<Includepaths>
|
|
||||||
<Includepath path="."/>
|
|
||||||
</Includepaths>
|
|
||||||
<DefinedSymbols>
|
|
||||||
<Define name="STM32F4XX"/>
|
|
||||||
<Define name="USE_STDPERIPH_DRIVER"/>
|
|
||||||
<Define name="__ASSEMBLY__"/>
|
|
||||||
<Define name="SUPPORT_CPLUSPLUS"/>
|
|
||||||
<Define name="HSE_VALUE=8000000"/>
|
|
||||||
<Define name="__FPU_USED"/>
|
|
||||||
<Define name="STM32F4_NUCLEO"/>
|
|
||||||
<Define name="STM32F446xx"/>
|
|
||||||
</DefinedSymbols>
|
|
||||||
</Compile>
|
|
||||||
<Link useDefault="0">
|
|
||||||
<Option name="DiscardUnusedSection" value="0"/>
|
|
||||||
<Option name="UserEditLinkder" value=""/>
|
|
||||||
<Option name="UseMemoryLayout" value="0"/>
|
|
||||||
<Option name="nostartfiles" value="1"/>
|
|
||||||
<Option name="LTO" value="0"/>
|
|
||||||
<Option name="IsNewStartupCode" value="1"/>
|
|
||||||
<Option name="Library" value="Semihosting"/>
|
|
||||||
<Option name="UserEditLinker" value="-lstdc++; --specs=nano.specs;"/>
|
|
||||||
<LinkedLibraries>
|
|
||||||
<Libset dir="stm32f4xx_lib\cmsis\lib\gcc\" libs="arm_cortexm4lf_math"/>
|
|
||||||
</LinkedLibraries>
|
|
||||||
<MemoryAreas debugInFlashNotRAM="1">
|
|
||||||
<Memory name="IROM1" type="ReadOnly" size="0x00100000" startValue="0x08000000"/>
|
|
||||||
<Memory name="IRAM1" type="ReadWrite" size="0x00020000" startValue="0x20000000"/>
|
|
||||||
<Memory name="IROM2" type="ReadOnly" size="" startValue=""/>
|
|
||||||
<Memory name="IRAM2" type="ReadWrite" size="0x00010000" startValue="0x10000000"/>
|
|
||||||
</MemoryAreas>
|
|
||||||
<LocateLinkFile path="./stm32f4xx_link.ld" type="0"/>
|
|
||||||
</Link>
|
|
||||||
<Output>
|
|
||||||
<Option name="OutputFileType" value="0"/>
|
|
||||||
<Option name="Path" value="./"/>
|
|
||||||
<Option name="Name" value="MMDVM_NUCLEO"/>
|
|
||||||
<Option name="HEX" value="1"/>
|
|
||||||
<Option name="BIN" value="1"/>
|
|
||||||
</Output>
|
|
||||||
<User>
|
|
||||||
<UserRun name="Run#1" type="Before" checked="0" value=""/>
|
|
||||||
<UserRun name="Run#1" type="After" checked="0" value=""/>
|
|
||||||
</User>
|
|
||||||
</BuildOption>
|
|
||||||
<DebugOption>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.adapter" value="ST-Link"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.debugMode" value="SWD"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.clockDiv" value="1M"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.corerunToMain" value="1"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.jlinkgdbserver" value=""/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.userDefineGDBScript" value=""/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.targetEndianess" value="0"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.jlinkResetMode" value="Type 0: Normal"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.resetMode" value="SYSRESETREQ"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.ifSemihost" value="0"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.ifCacheRom" value="1"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.ipAddress" value="127.0.0.1"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.portNumber" value="2009"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.autoDownload" value="1"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.verify" value="1"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.downloadFuction" value="Erase Effected"/>
|
|
||||||
<Option name="org.coocox.codebugger.gdbjtag.core.defaultAlgorithm" value="STM32F4xx_1024.elf"/>
|
|
||||||
</DebugOption>
|
|
||||||
<ExcludeFile/>
|
|
||||||
</Target>
|
|
||||||
<Components path="./"/>
|
|
||||||
<LocalComponents/>
|
|
||||||
<Files>
|
|
||||||
<File name="DMRIdleRX.h" path="DMRIdleRX.h" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/source/stm32f4xx_dac.c" path="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/source/stm32f4xx_dac.c" type="1"/>
|
|
||||||
<File name="DMRDMOTX.cpp" path="DMRDMOTX.cpp" type="1"/>
|
|
||||||
<File name="DMRRX.cpp" path="DMRRX.cpp" type="1"/>
|
|
||||||
<File name="YSFRX.cpp" path="YSFRX.cpp" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/Device/stm32f4xx.h" path="STM32F4XX_Lib/Device/stm32f4xx.h" type="1"/>
|
|
||||||
<File name="SampleRB.cpp" path="SampleRB.cpp" type="1"/>
|
|
||||||
<File name="CalDStarTX.h" path="CalDStarTX.h" type="1"/>
|
|
||||||
<File name="CalNXDN.cpp" path="CalNXDN.cpp" type="1"/>
|
|
||||||
<File name="NXDNTX.cpp" path="NXDNTX.cpp" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/CMSIS/Include/core_cm4.h" path="STM32F4XX_Lib/CMSIS/Include/core_cm4.h" type="1"/>
|
|
||||||
<File name="I2CTeensy.cpp" path="I2CTeensy.cpp" type="1"/>
|
|
||||||
<File name="DMRSlotRX.h" path="DMRSlotRX.h" type="1"/>
|
|
||||||
<File name="YSFRX.h" path="YSFRX.h" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/source/stm32f4xx_tim.c" path="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/source/stm32f4xx_tim.c" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/CMSIS/Include" path="" type="2"/>
|
|
||||||
<File name="NXDNRX.cpp" path="NXDNRX.cpp" type="1"/>
|
|
||||||
<File name="IO.cpp" path="IO.cpp" type="1"/>
|
|
||||||
<File name="DMRDMORX.cpp" path="DMRDMORX.cpp" type="1"/>
|
|
||||||
<File name="P25RX.h" path="P25RX.h" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/source/misc.c" path="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/source/misc.c" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/CMSIS" path="" type="2"/>
|
|
||||||
<File name="SerialArduino.cpp" path="SerialArduino.cpp" type="1"/>
|
|
||||||
<File name="SerialPort.cpp" path="SerialPort.cpp" type="1"/>
|
|
||||||
<File name="CalP25.cpp" path="CalP25.cpp" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/Device/stm32f4xx_conf.h" path="STM32F4XX_Lib/Device/stm32f4xx_conf.h" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/source/stm32f4xx_adc.c" path="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/source/stm32f4xx_adc.c" type="1"/>
|
|
||||||
<File name="IOSTM_CMSIS.cpp" path="IOSTM_CMSIS.cpp" type="1"/>
|
|
||||||
<File name="DStarTX.cpp" path="DStarTX.cpp" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/source/stm32f4xx_usart.c" path="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/source/stm32f4xx_usart.c" type="1"/>
|
|
||||||
<File name="YSFTX.h" path="YSFTX.h" type="1"/>
|
|
||||||
<File name="SampleRB.h" path="SampleRB.h" type="1"/>
|
|
||||||
<File name="SerialSTM_CMSIS.cpp" path="SerialSTM_CMSIS.cpp" type="1"/>
|
|
||||||
<File name="DMRRX.h" path="DMRRX.h" type="1"/>
|
|
||||||
<File name="IOTeensy.cpp" path="IOTeensy.cpp" type="1"/>
|
|
||||||
<File name="MMDVM.cpp" path="MMDVM.cpp" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/CMSIS/Include/core_cmSimd.h" path="STM32F4XX_Lib/CMSIS/Include/core_cmSimd.h" type="1"/>
|
|
||||||
<File name="POCSAGTX.cpp" path="POCSAGTX.cpp" type="1"/>
|
|
||||||
<File name="DMRDMORX.h" path="DMRDMORX.h" type="1"/>
|
|
||||||
<File name="GitVersion.h" path="GitVersion.h" type="1"/>
|
|
||||||
<File name="SerialPort.h" path="SerialPort.h" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/include/stm32f4xx_dac.h" path="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/include/stm32f4xx_dac.h" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/CMSIS/Include/core_cmFunc.h" path="STM32F4XX_Lib/CMSIS/Include/core_cmFunc.h" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/Device/system_stm32f4xx.h" path="STM32F4XX_Lib/Device/system_stm32f4xx.h" type="1"/>
|
|
||||||
<File name="CWIdTX.h" path="CWIdTX.h" type="1"/>
|
|
||||||
<File name="CalDStarTX.cpp" path="CalDStarTX.cpp" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/source" path="" type="2"/>
|
|
||||||
<File name="POCSAGTX.h" path="POCSAGTX.h" type="1"/>
|
|
||||||
<File name="DMRDMOTX.h" path="DMRDMOTX.h" type="1"/>
|
|
||||||
<File name="CalDMR.h" path="CalDMR.h" type="1"/>
|
|
||||||
<File name="IODue.cpp" path="IODue.cpp" type="1"/>
|
|
||||||
<File name="DMRTX.cpp" path="DMRTX.cpp" type="1"/>
|
|
||||||
<File name="CalRSSI.h" path="CalRSSI.h" type="1"/>
|
|
||||||
<File name="P25RX.cpp" path="P25RX.cpp" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/CMSIS/Lib/GCC" path="" type="2"/>
|
|
||||||
<File name="STM32F4XX_Lib" path="" type="2"/>
|
|
||||||
<File name="STM32F4XX_Lib/CMSIS/Include/core_cmInstr.h" path="STM32F4XX_Lib/CMSIS/Include/core_cmInstr.h" type="1"/>
|
|
||||||
<File name="DMRTX.h" path="DMRTX.h" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/Device/system_stm32f4xx.c" path="STM32F4XX_Lib/Device/system_stm32f4xx.c" type="1"/>
|
|
||||||
<File name="RSSIRB.h" path="RSSIRB.h" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/Device/startup/startup_stm32f4xx.c" path="STM32F4XX_Lib/Device/startup/startup_stm32f4xx.c" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/Device/startup" path="" type="2"/>
|
|
||||||
<File name="SerialRB.h" path="SerialRB.h" type="1"/>
|
|
||||||
<File name="NXDNDefines.h" path="NXDNDefines.h" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/include/stm32f4xx_gpio.h" path="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/include/stm32f4xx_gpio.h" type="1"/>
|
|
||||||
<File name="NXDNTX.h" path="NXDNTX.h" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver" path="" type="2"/>
|
|
||||||
<File name="DMRDefines.h" path="DMRDefines.h" type="1"/>
|
|
||||||
<File name="CalDMR.cpp" path="CalDMR.cpp" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/include/stm32f4xx_adc.h" path="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/include/stm32f4xx_adc.h" type="1"/>
|
|
||||||
<File name="SerialSTM.cpp" path="SerialSTM.cpp" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/CMSIS/Lib/GCC/libarm_cortexM4lf_math.a" path="STM32F4XX_Lib/CMSIS/Lib/GCC/libarm_cortexM4lf_math.a" type="1"/>
|
|
||||||
<File name="DStarDefines.h" path="DStarDefines.h" type="1"/>
|
|
||||||
<File name="DStarRX.h" path="DStarRX.h" type="1"/>
|
|
||||||
<File name="NXDNRX.h" path="NXDNRX.h" type="1"/>
|
|
||||||
<File name="Config.h" path="Config.h" type="1"/>
|
|
||||||
<File name="RingBuff.h" path="RingBuff.h" type="1"/>
|
|
||||||
<File name="DMRSlotType.cpp" path="DMRSlotType.cpp" type="1"/>
|
|
||||||
<File name="Globals.h" path="Globals.h" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/Device" path="" type="2"/>
|
|
||||||
<File name="CalDStarRX.cpp" path="CalDStarRX.cpp" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/include/stm32f4xx_tim.h" path="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/include/stm32f4xx_tim.h" type="1"/>
|
|
||||||
<File name="CalNXDN.h" path="CalNXDN.h" type="1"/>
|
|
||||||
<File name="CalDStarRX.h" path="CalDStarRX.h" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/include" path="" type="2"/>
|
|
||||||
<File name="CalRSSI.cpp" path="CalRSSI.cpp" type="1"/>
|
|
||||||
<File name="IO.h" path="IO.h" type="1"/>
|
|
||||||
<File name="Utils.cpp" path="Utils.cpp" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/CMSIS/Lib/.DS_Store" path="STM32F4XX_Lib/CMSIS/Lib/.DS_Store" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/CMSIS/.DS_Store" path="STM32F4XX_Lib/CMSIS/.DS_Store" type="1"/>
|
|
||||||
<File name="Utils.h" path="Utils.h" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/CMSIS/Lib" path="" type="2"/>
|
|
||||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/.DS_Store" path="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/.DS_Store" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/CMSIS/Include/.DS_Store" path="STM32F4XX_Lib/CMSIS/Include/.DS_Store" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/CMSIS/Include/arm_math.h" path="STM32F4XX_Lib/CMSIS/Include/arm_math.h" type="1"/>
|
|
||||||
<File name="YSFDefines.h" path="YSFDefines.h" type="1"/>
|
|
||||||
<File name="DStarTX.h" path="DStarTX.h" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/source/stm32f4xx_rcc.c" path="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/source/stm32f4xx_rcc.c" type="1"/>
|
|
||||||
<File name="CalP25.h" path="CalP25.h" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/Device/.DS_Store" path="STM32F4XX_Lib/Device/.DS_Store" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/include/stm32f4xx_rcc.h" path="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/include/stm32f4xx_rcc.h" type="1"/>
|
|
||||||
<File name="P25Defines.h" path="P25Defines.h" type="1"/>
|
|
||||||
<File name="DMRSlotType.h" path="DMRSlotType.h" type="1"/>
|
|
||||||
<File name="Debug.h" path="Debug.h" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/include/misc.h" path="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/include/misc.h" type="1"/>
|
|
||||||
<File name="P25TX.h" path="P25TX.h" type="1"/>
|
|
||||||
<File name="RSSIRB.cpp" path="RSSIRB.cpp" type="1"/>
|
|
||||||
<File name="DStarRX.cpp" path="DStarRX.cpp" type="1"/>
|
|
||||||
<File name="IOSTM.cpp" path="IOSTM.cpp" type="1"/>
|
|
||||||
<File name="DMRSlotRX.cpp" path="DMRSlotRX.cpp" type="1"/>
|
|
||||||
<File name="P25TX.cpp" path="P25TX.cpp" type="1"/>
|
|
||||||
<File name="SerialRB.cpp" path="SerialRB.cpp" type="1"/>
|
|
||||||
<File name="CWIdTX.cpp" path="CWIdTX.cpp" type="1"/>
|
|
||||||
<File name="DMRIdleRX.cpp" path="DMRIdleRX.cpp" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/include/stm32f4xx_usart.h" path="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/include/stm32f4xx_usart.h" type="1"/>
|
|
||||||
<File name="STM32Utils.h" path="STM32Utils.h" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/.DS_Store" path="STM32F4XX_Lib/.DS_Store" type="1"/>
|
|
||||||
<File name="YSFTX.cpp" path="YSFTX.cpp" type="1"/>
|
|
||||||
<File name="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/source/stm32f4xx_gpio.c" path="STM32F4XX_Lib/STM32F4xx_StdPeriph_Driver/source/stm32f4xx_gpio.c" type="1"/>
|
|
||||||
</Files>
|
|
||||||
<Bookmarks/>
|
|
||||||
</Project>
|
|
||||||
@@ -25,6 +25,7 @@ F7_LIB_PATH=./STM32F7XX_Lib
|
|||||||
# MCU external clock frequency (Hz)
|
# MCU external clock frequency (Hz)
|
||||||
CLK_MMDVM_PI=12000000
|
CLK_MMDVM_PI=12000000
|
||||||
CLK_NUCLEO=8000000
|
CLK_NUCLEO=8000000
|
||||||
|
CLK_12MHZ=12000000
|
||||||
|
|
||||||
# Directory Structure
|
# Directory Structure
|
||||||
BINDIR=bin
|
BINDIR=bin
|
||||||
@@ -93,6 +94,8 @@ ifndef $(OSC)
|
|||||||
OSC=$(CLK_MMDVM_PI)
|
OSC=$(CLK_MMDVM_PI)
|
||||||
else ifeq ($(MAKECMDGOALS),pi-f722)
|
else ifeq ($(MAKECMDGOALS),pi-f722)
|
||||||
OSC=$(CLK_MMDVM_PI)
|
OSC=$(CLK_MMDVM_PI)
|
||||||
|
else ifeq ($(MAKECMDGOALS),drcc_nqf)
|
||||||
|
OSC=$(CLK_12MHZ)
|
||||||
else
|
else
|
||||||
OSC=$(CLK_NUCLEO)
|
OSC=$(CLK_NUCLEO)
|
||||||
endif
|
endif
|
||||||
@@ -128,10 +131,19 @@ DEFS_NUCLEO_F767=-DUSE_HAL_DRIVER -DSTM32F767xx -DSTM32F7XX -DSTM32F7_NUCLEO -DH
|
|||||||
DEFS_PI_F722=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_PI -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
DEFS_PI_F722=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_PI -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||||
# MMDVM-F7M F0DEI board:
|
# MMDVM-F7M F0DEI board:
|
||||||
DEFS_F7M=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_F7M -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
DEFS_F7M=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_F7M -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||||
# MMDVM-F7-Hat F0DEI, DB9MAT, DF2ET board:
|
# MMDVM_RPT_Hat F0DEI, DB9MAT, DF2ET board:
|
||||||
DEFS_F7HAT=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_F7HAT -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
DEFS_RPT_HAT=-DUSE_HAL_DRIVER -DSTM32F722xx -DSTM32F7XX -DSTM32F722_RPT_HAT -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||||
# STM32F4 DVM board:
|
# STM32F4 DVM board:
|
||||||
DEFS_DVM=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_DVM -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
DEFS_DVM=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_DVM -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||||
|
# MMDVM_RPT_Hat BG4TGO, BG5HHP board:
|
||||||
|
DEFS_RPT_HAT_TGO=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F40_41xxx -DSTM32F4_RPT_HAT_TGO -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||||
|
# DRCC_DVM BG7NQF board:
|
||||||
|
DEFS_DRCC_DVM=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DDRCC_DVM -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||||
|
# WA0EDA F405 MTR2K, MASTR3 board:
|
||||||
|
DEFS_EDA_405=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F40_41xxx -DSTM32F4_EDA_405 -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||||
|
# WA0EDA F446 MTR2K, MASTR3 board:
|
||||||
|
DEFS_EDA_446=-DUSE_STDPERIPH_DRIVER -DSTM32F4XX -DSTM32F446xx -DSTM32F4_EDA_446 -DHSE_VALUE=$(OSC) -DMADEBYMAKEFILE
|
||||||
|
|
||||||
|
|
||||||
# Build compiler flags
|
# Build compiler flags
|
||||||
CFLAGS_F4=-c $(MCFLAGS_F4) $(INCLUDES_F4)
|
CFLAGS_F4=-c $(MCFLAGS_F4) $(INCLUDES_F4)
|
||||||
@@ -147,10 +159,10 @@ LDFLAGS_F722 =-T stm32f722_link.ld $(MCFLAGS_F7) --specs=nosys.specs $(INCLUDES_
|
|||||||
# Common flags
|
# Common flags
|
||||||
CFLAGS=-Os -ffunction-sections -fdata-sections -fno-builtin -Wno-implicit -DCUSTOM_NEW -DNO_EXCEPTIONS
|
CFLAGS=-Os -ffunction-sections -fdata-sections -fno-builtin -Wno-implicit -DCUSTOM_NEW -DNO_EXCEPTIONS
|
||||||
CXXFLAGS=-Os -fno-exceptions -ffunction-sections -fdata-sections -fno-builtin -fno-rtti -DCUSTOM_NEW -DNO_EXCEPTIONS
|
CXXFLAGS=-Os -fno-exceptions -ffunction-sections -fdata-sections -fno-builtin -fno-rtti -DCUSTOM_NEW -DNO_EXCEPTIONS
|
||||||
LDFLAGS=-Os --specs=nano.specs
|
LDFLAGS=-Os --specs=nano.specs -Wl,-Map=bin/mmdvm.map
|
||||||
|
|
||||||
# Build Rules
|
# Build Rules
|
||||||
.PHONY: all release dis pi pi-f722 f4m nucleo f767 dvm clean
|
.PHONY: all release dis pi pi-f722 f4m nucleo f767 dvm drcc_nqf clean
|
||||||
|
|
||||||
# Default target: Nucleo-64 F446RE board
|
# Default target: Nucleo-64 F446RE board
|
||||||
all: nucleo
|
all: nucleo
|
||||||
@@ -179,11 +191,17 @@ f7m: CXXFLAGS+=$(CXXFLAGS_F7) $(DEFS_F7M)
|
|||||||
f7m: LDFLAGS+=$(LDFLAGS_F722)
|
f7m: LDFLAGS+=$(LDFLAGS_F722)
|
||||||
f7m: release_f7
|
f7m: release_f7
|
||||||
|
|
||||||
f7hat: GitVersion.h
|
rpt_hat: GitVersion.h
|
||||||
f7hat: CFLAGS+=$(CFLAGS_F7) $(DEFS_F7HAT)
|
rpt_hat: CFLAGS+=$(CFLAGS_F7) $(DEFS_RPT_HAT)
|
||||||
f7hat: CXXFLAGS+=$(CXXFLAGS_F7) $(DEFS_F7HAT)
|
rpt_hat: CXXFLAGS+=$(CXXFLAGS_F7) $(DEFS_RPT_HAT)
|
||||||
f7hat: LDFLAGS+=$(LDFLAGS_F722)
|
rpt_hat: LDFLAGS+=$(LDFLAGS_F722)
|
||||||
f7hat: release_f7
|
rpt_hat: release_f7
|
||||||
|
|
||||||
|
rpt_hat_tgo: GitVersion.h
|
||||||
|
rpt_hat_tgo: CFLAGS+=$(CFLAGS_F4) $(DEFS_RPT_HAT_TGO)
|
||||||
|
rpt_hat_tgo: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_RPT_HAT_TGO)
|
||||||
|
rpt_hat_tgo: LDFLAGS+=$(LDFLAGS_F4)
|
||||||
|
rpt_hat_tgo: release_f4
|
||||||
|
|
||||||
nucleo: GitVersion.h
|
nucleo: GitVersion.h
|
||||||
nucleo: CFLAGS+=$(CFLAGS_F4) $(DEFS_NUCLEO)
|
nucleo: CFLAGS+=$(CFLAGS_F4) $(DEFS_NUCLEO)
|
||||||
@@ -209,6 +227,24 @@ dvm: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DVM)
|
|||||||
dvm: LDFLAGS+=$(LDFLAGS_F4)
|
dvm: LDFLAGS+=$(LDFLAGS_F4)
|
||||||
dvm: release_f4
|
dvm: release_f4
|
||||||
|
|
||||||
|
drcc_nqf: GitVersion.h
|
||||||
|
drcc_nqf: CFLAGS+=$(CFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_NQF
|
||||||
|
drcc_nqf: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_DRCC_DVM) -DDRCC_DVM_NQF
|
||||||
|
drcc_nqf: LDFLAGS+=$(LDFLAGS_F4)
|
||||||
|
drcc_nqf: release_f4
|
||||||
|
|
||||||
|
eda405: GitVersion.h
|
||||||
|
eda405: CFLAGS+=$(CFLAGS_F4) $(DEFS_EDA_405)
|
||||||
|
eda405: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_EDA_405)
|
||||||
|
eda405: LDFLAGS+=$(LDFLAGS_F4)
|
||||||
|
eda405: release_f4
|
||||||
|
|
||||||
|
eda446: GitVersion.h
|
||||||
|
eda446: CFLAGS+=$(CFLAGS_F4) $(DEFS_EDA_446)
|
||||||
|
eda446: CXXFLAGS+=$(CXXFLAGS_F4) $(DEFS_EDA_446)
|
||||||
|
eda446: LDFLAGS+=$(LDFLAGS_F4)
|
||||||
|
eda446: release_f4
|
||||||
|
|
||||||
release_f4: $(BINDIR)
|
release_f4: $(BINDIR)
|
||||||
release_f4: $(OBJDIR_F4)
|
release_f4: $(OBJDIR_F4)
|
||||||
release_f4: $(BINDIR)/$(BINHEX_F4)
|
release_f4: $(BINDIR)/$(BINHEX_F4)
|
||||||
@@ -330,22 +366,21 @@ endif
|
|||||||
|
|
||||||
deploy-f4m: deploy-pi
|
deploy-f4m: deploy-pi
|
||||||
deploy-dvm: deploy-pi
|
deploy-dvm: deploy-pi
|
||||||
|
deploy-eda405: deploy-pi
|
||||||
|
deploy-eda446: deploy-pi
|
||||||
|
|
||||||
deploy-pi-f7:
|
deploy-pi-f7:
|
||||||
ifneq ($(wildcard /usr/local/bin/stm32flash),)
|
ifneq ($(wildcard /usr/local/bin/stm32flash),)
|
||||||
-/usr/local/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
|
-/usr/local/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
|
||||||
-/usr/local/bin/stm32ld /dev/ttyAMA0 57600 bin/$(BINBIN_F7)
|
|
||||||
/usr/local/bin/stm32flash -v -w bin/$(BINBIN_F7) -g 0x0 -R -c /dev/ttyAMA0
|
/usr/local/bin/stm32flash -v -w bin/$(BINBIN_F7) -g 0x0 -R -c /dev/ttyAMA0
|
||||||
endif
|
|
||||||
|
|
||||||
ifneq ($(wildcard /usr/bin/stm32flash),)
|
else ifneq ($(wildcard /usr/bin/stm32flash),)
|
||||||
-/usr/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
|
-/usr/bin/stm32flash -i 20,-21,21:-20,21 /dev/ttyAMA0
|
||||||
-/usr/bin/stm32ld /dev/ttyAMA0 57600 bin/$(BINBIN_F7)
|
|
||||||
/usr/bin/stm32flash -v -w bin/$(BINBIN_F7) -g 0x0 -R -c /dev/ttyAMA0
|
/usr/bin/stm32flash -v -w bin/$(BINBIN_F7) -g 0x0 -R -c /dev/ttyAMA0
|
||||||
endif
|
endif
|
||||||
|
|
||||||
deploy-f7m: deploy-pi-f7
|
deploy-f7m: deploy-pi-f7
|
||||||
deploy-f7hat: deploy-pi-f7
|
deploy-rpt_hat: deploy-pi-f7
|
||||||
|
|
||||||
# Export the current git version if the index file exists, else 000...
|
# Export the current git version if the index file exists, else 000...
|
||||||
GitVersion.h:
|
GitVersion.h:
|
||||||
@@ -360,3 +395,7 @@ else
|
|||||||
echo "#define GITVERSION \"0000000\"" > $@
|
echo "#define GITVERSION \"0000000\"" > $@
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
flash_f4:
|
||||||
|
@echo "flashing firmware..."
|
||||||
|
st-flash write bin/$(BINBIN_F4) 0x8000000
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/make
|
#!/usr/bin/make
|
||||||
# makefile for the arduino due (works with arduino IDE 1.6.11)
|
# makefile for the arduino due (works with arduino IDE 1.6.12)
|
||||||
#
|
#
|
||||||
# The original file can be found at https://github.com/pauldreik/arduino-due-makefile
|
# The original file can be found at https://github.com/pauldreik/arduino-due-makefile
|
||||||
#
|
#
|
||||||
@@ -34,7 +34,7 @@ OBJCOPY:=$(ADIR)/packages/arduino/tools/arm-none-eabi-gcc/4.8.3-2014q1/bin/arm-n
|
|||||||
|
|
||||||
C:=$(CC)
|
C:=$(CC)
|
||||||
#SAM:=arduino/sam/
|
#SAM:=arduino/sam/
|
||||||
SAM:=$(ADIR)/packages/arduino/hardware/sam/1.6.11
|
SAM:=$(ADIR)/packages/arduino/hardware/sam/1.6.12
|
||||||
#CMSIS:=arduino/sam/system/CMSIS/
|
#CMSIS:=arduino/sam/system/CMSIS/
|
||||||
#LIBSAM:=arduino/sam/system/libsam
|
#LIBSAM:=arduino/sam/system/libsam
|
||||||
TMPDIR:=$(PWD)/build
|
TMPDIR:=$(PWD)/build
|
||||||
|
|||||||
+18
-4
@@ -25,7 +25,7 @@ STARTUP:=$(SYSDIR)/startup_stm32f105xc.S
|
|||||||
STARTUP_DEFS=
|
STARTUP_DEFS=
|
||||||
|
|
||||||
# Include directory for CMSIS
|
# Include directory for CMSIS
|
||||||
CMSISDIR:=/opt/STM32Cube_FW_F1_V1.4.0/Drivers/CMSIS
|
CMSISDIR:=STM32F10X_Lib/CMSIS
|
||||||
|
|
||||||
# Libraries
|
# Libraries
|
||||||
LIBDIR:=
|
LIBDIR:=
|
||||||
@@ -65,7 +65,7 @@ COMMON_FLAGS =-mthumb -mlittle-endian -mcpu=$(MCPU)
|
|||||||
COMMON_FLAGS+= -Wall
|
COMMON_FLAGS+= -Wall
|
||||||
COMMON_FLAGS+= -I. -I$(CMSISDIR)/Include -I$(CMSISDIR)/Device/ST/STM32F1xx/Include -I$(SYSDIR)
|
COMMON_FLAGS+= -I. -I$(CMSISDIR)/Include -I$(CMSISDIR)/Device/ST/STM32F1xx/Include -I$(SYSDIR)
|
||||||
COMMON_FLAGS+= $(addprefix -I,$(INCDIR))
|
COMMON_FLAGS+= $(addprefix -I,$(INCDIR))
|
||||||
COMMON_FLAGS+= -D$(MCU)
|
COMMON_FLAGS+= -D$(MCU) -DMADEBYMAKEFILE -DSTM32F1
|
||||||
COMMON_FLAGS+= -Os -flto -ffunction-sections -fdata-sections
|
COMMON_FLAGS+= -Os -flto -ffunction-sections -fdata-sections
|
||||||
COMMON_FLAGS+= -g
|
COMMON_FLAGS+= -g
|
||||||
# Assembler flags
|
# Assembler flags
|
||||||
@@ -91,7 +91,7 @@ DEPENDS:=$(CSRC:%.c=$(OBJDIR)/%.d) $(CXXSRC:%.cpp=$(OBJDIR)/%.d)
|
|||||||
|
|
||||||
# Targets
|
# Targets
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: $(DIS) $(HEX)
|
all: GitVersion.h $(DIS) $(HEX)
|
||||||
$(SIZE) $(ELF)
|
$(SIZE) $(ELF)
|
||||||
|
|
||||||
.PHONY: program
|
.PHONY: program
|
||||||
@@ -116,7 +116,7 @@ debug: $(ELF)
|
|||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
$(RM) $(OBJ) $(HEX) $(ELF) $(DIS) $(MAP) $(DEPENDS)
|
$(RM) $(OBJ) $(HEX) $(ELF) $(DIS) $(MAP) $(DEPENDS) GitVersion.h
|
||||||
|
|
||||||
# implicit rules
|
# implicit rules
|
||||||
.elf.hex:
|
.elf.hex:
|
||||||
@@ -149,3 +149,17 @@ $(DIS): $(ELF)
|
|||||||
|
|
||||||
# include dependecies
|
# include dependecies
|
||||||
-include $(DEPENDS)
|
-include $(DEPENDS)
|
||||||
|
|
||||||
|
# Export the current git version if the index file exists, else 000...
|
||||||
|
GitVersion.h:
|
||||||
|
ifdef SYSTEMROOT
|
||||||
|
echo #define GITVERSION "0000000" > $@
|
||||||
|
else ifdef SystemRoot
|
||||||
|
echo #define GITVERSION "0000000" > $@
|
||||||
|
else
|
||||||
|
ifneq ("$(wildcard .git/index)","")
|
||||||
|
echo "#define GITVERSION \"$(shell git rev-parse --short HEAD)\"" > $@
|
||||||
|
else
|
||||||
|
echo "#define GITVERSION \"0000000\"" > $@
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|||||||
+1
-1
@@ -19,7 +19,7 @@
|
|||||||
#if !defined(NXDNDEFINES_H)
|
#if !defined(NXDNDEFINES_H)
|
||||||
#define NXDNDEFINES_H
|
#define NXDNDEFINES_H
|
||||||
|
|
||||||
const unsigned int NXDN_RADIO_SYMBOL_LENGTH = 20U; // At 48 kHz sample rate
|
const unsigned int NXDN_RADIO_SYMBOL_LENGTH = 10U; // At 24 kHz sample rate
|
||||||
|
|
||||||
const unsigned int NXDN_FRAME_LENGTH_BITS = 384U;
|
const unsigned int NXDN_FRAME_LENGTH_BITS = 384U;
|
||||||
const unsigned int NXDN_FRAME_LENGTH_BYTES = NXDN_FRAME_LENGTH_BITS / 8U;
|
const unsigned int NXDN_FRAME_LENGTH_BYTES = NXDN_FRAME_LENGTH_BITS / 8U;
|
||||||
|
|||||||
+62
-22
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2018,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -23,21 +23,19 @@
|
|||||||
|
|
||||||
#include "NXDNDefines.h"
|
#include "NXDNDefines.h"
|
||||||
|
|
||||||
// NXDN RRC filter + SINC filter
|
// Generated using rcosdesign(0.2, 8, 10, 'sqrt') in MATLAB
|
||||||
static q15_t RRC_0_2_FILTER[] = {51, 71, 92, 112, 129, 141, 144, 138, 120, 87, 39, -26, -107, -204, -314, -437, -567, -702, -835,
|
static q15_t RRC_0_2_FILTER[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 850, 592, 219, -234, -720, -1179, -1548, -1769, -1795, -1597, -1172,
|
||||||
-932,-1066, -1176, -1257, -1304, -1314, -1284, -1213, -1099, -944, -749, -519, -257, 30, 335, 651,
|
-544, 237, 1092, 1927, 2637, 3120, 3286, 3073, 2454, 1447, 116, -1431, -3043, -4544, -5739, -6442,
|
||||||
968, 1277, 1569, 1832, 2058, 2237, 2360, 2420, 2412, 2329, 2170, 1935, 1623, 1239, 790, 283, -271,
|
-6483, -5735, -4121, -1633, 1669, 5651, 10118, 14822, 19484, 23810, 27520, 30367, 32156, 32767,
|
||||||
-858, -1466, -2076, -2671, -3233, -3742, -4178, -4521, -4754, -4857, -4815, -4614, -4242, -3690,
|
32156, 30367, 27520, 23810, 19484, 14822, 10118, 5651, 1669, -1633, -4121, -5735, -6483, -6442,
|
||||||
-2952, -2025, -912, 385, 1855, 3488, 5266, 7172, 9183, 11274, 13418, 15585, 17746, 19869, 21923,
|
-5739, -4544, -3043, -1431, 116, 1447, 2454, 3073, 3286, 3120, 2637, 1927, 1092, 237, -544, -1172,
|
||||||
23876, 25700, 27364, 28844, 30116, 31159, 31956, 32495, 32767, 32767, 32495, 31956, 31159, 30116,
|
-1597, -1795, -1769, -1548, -1179, -720, -234, 219, 592, 850}; // numTaps = 90, L = 10
|
||||||
28844, 27364, 25700, 23876, 21923, 19869, 17746, 15585, 13418, 11274, 9183, 7172, 5266, 3488, 1855,
|
|
||||||
385, -912, -2025, -2952, -3690, -4242, -4614, -4815, -4857, -4754, -4521, -4178, -3742, -3233, -2671,
|
|
||||||
-2076, -1466, -858, -271, 283, 790, 1239, 1623, 1935, 2170, 2329, 2412, 2420, 2360, 2237, 2058, 1832,
|
|
||||||
1569, 1277, 968, 651, 335, 30, -257, -519, -749, -944, -1099, -1213, -1284, -1314, -1304, -1257,
|
|
||||||
-1176, -1066, -932, -835, -702, -567, -437, -314, -204, -107, -26, 39, 87, 120, 138, 144, 141, 129,
|
|
||||||
112, 92, 71, 51}; // numTaps = 180, L = 20
|
|
||||||
const uint16_t RRC_0_2_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L
|
const uint16_t RRC_0_2_FILTER_PHASE_LEN = 9U; // phaseLength = numTaps/L
|
||||||
|
|
||||||
|
static q15_t NXDN_SINC_FILTER[] = {572, -1003, -253, 254, 740, 1290, 1902, 2527, 3090, 3517, 3747, 3747, 3517, 3090, 2527, 1902,
|
||||||
|
1290, 740, 254, -253, -1003, 572};
|
||||||
|
const uint16_t NXDN_SINC_FILTER_LEN = 22U;
|
||||||
|
|
||||||
const q15_t NXDN_LEVELA = 735;
|
const q15_t NXDN_LEVELA = 735;
|
||||||
const q15_t NXDN_LEVELB = 245;
|
const q15_t NXDN_LEVELB = 245;
|
||||||
const q15_t NXDN_LEVELC = -245;
|
const q15_t NXDN_LEVELC = -245;
|
||||||
@@ -49,26 +47,32 @@ const uint8_t NXDN_SYNC = 0x5FU;
|
|||||||
CNXDNTX::CNXDNTX() :
|
CNXDNTX::CNXDNTX() :
|
||||||
m_buffer(TX_BUFFER_LEN),
|
m_buffer(TX_BUFFER_LEN),
|
||||||
m_modFilter(),
|
m_modFilter(),
|
||||||
|
m_sincFilter(),
|
||||||
m_modState(),
|
m_modState(),
|
||||||
|
m_sincState(),
|
||||||
m_poBuffer(),
|
m_poBuffer(),
|
||||||
m_poLen(0U),
|
m_poLen(0U),
|
||||||
m_poPtr(0U),
|
m_poPtr(0U),
|
||||||
m_txDelay(240U) // 200ms
|
m_txDelay(240U), // 200ms
|
||||||
|
m_txHang(3000U), // 5s
|
||||||
|
m_txCount(0U)
|
||||||
{
|
{
|
||||||
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
|
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
|
||||||
|
::memset(m_sincState, 0x00U, 70U * sizeof(q15_t));
|
||||||
|
|
||||||
m_modFilter.L = NXDN_RADIO_SYMBOL_LENGTH;
|
m_modFilter.L = NXDN_RADIO_SYMBOL_LENGTH;
|
||||||
m_modFilter.phaseLength = RRC_0_2_FILTER_PHASE_LEN;
|
m_modFilter.phaseLength = RRC_0_2_FILTER_PHASE_LEN;
|
||||||
m_modFilter.pCoeffs = RRC_0_2_FILTER;
|
m_modFilter.pCoeffs = RRC_0_2_FILTER;
|
||||||
m_modFilter.pState = m_modState;
|
m_modFilter.pState = m_modState;
|
||||||
|
|
||||||
|
m_sincFilter.numTaps = NXDN_SINC_FILTER_LEN;
|
||||||
|
m_sincFilter.pState = m_sincState;
|
||||||
|
m_sincFilter.pCoeffs = NXDN_SINC_FILTER;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CNXDNTX::process()
|
void CNXDNTX::process()
|
||||||
{
|
{
|
||||||
if (m_buffer.getData() == 0U && m_poLen == 0U)
|
if (m_poLen == 0U && m_buffer.getData() > 0U) {
|
||||||
return;
|
|
||||||
|
|
||||||
if (m_poLen == 0U) {
|
|
||||||
if (!m_tx) {
|
if (!m_tx) {
|
||||||
for (uint16_t i = 0U; i < m_txDelay; i++)
|
for (uint16_t i = 0U; i < m_txDelay; i++)
|
||||||
m_poBuffer[m_poLen++] = NXDN_SYNC;
|
m_poBuffer[m_poLen++] = NXDN_SYNC;
|
||||||
@@ -77,7 +81,8 @@ void CNXDNTX::process()
|
|||||||
m_poBuffer[m_poLen++] = NXDN_PREAMBLE[2U];
|
m_poBuffer[m_poLen++] = NXDN_PREAMBLE[2U];
|
||||||
} else {
|
} else {
|
||||||
for (uint8_t i = 0U; i < NXDN_FRAME_LENGTH_BYTES; i++) {
|
for (uint8_t i = 0U; i < NXDN_FRAME_LENGTH_BYTES; i++) {
|
||||||
uint8_t c = m_buffer.get();
|
uint8_t c = 0U;
|
||||||
|
m_buffer.get(c);
|
||||||
m_poBuffer[m_poLen++] = c;
|
m_poBuffer[m_poLen++] = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,6 +98,8 @@ void CNXDNTX::process()
|
|||||||
writeByte(c);
|
writeByte(c);
|
||||||
|
|
||||||
space -= 4U * NXDN_RADIO_SYMBOL_LENGTH;
|
space -= 4U * NXDN_RADIO_SYMBOL_LENGTH;
|
||||||
|
if (m_duplex)
|
||||||
|
m_txCount = m_txHang;
|
||||||
|
|
||||||
if (m_poPtr >= m_poLen) {
|
if (m_poPtr >= m_poLen) {
|
||||||
m_poPtr = 0U;
|
m_poPtr = 0U;
|
||||||
@@ -100,10 +107,23 @@ void CNXDNTX::process()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (m_txCount > 0U) {
|
||||||
|
// Transmit silence until the hang timer has expired.
|
||||||
|
uint16_t space = io.getSpace();
|
||||||
|
|
||||||
|
while (space > (4U * NXDN_RADIO_SYMBOL_LENGTH)) {
|
||||||
|
writeSilence();
|
||||||
|
|
||||||
|
space -= 4U * NXDN_RADIO_SYMBOL_LENGTH;
|
||||||
|
m_txCount--;
|
||||||
|
|
||||||
|
if (m_txCount == 0U)
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CNXDNTX::writeData(const uint8_t* data, uint8_t length)
|
uint8_t CNXDNTX::writeData(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != (NXDN_FRAME_LENGTH_BYTES + 1U))
|
if (length != (NXDN_FRAME_LENGTH_BYTES + 1U))
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -121,6 +141,7 @@ uint8_t CNXDNTX::writeData(const uint8_t* data, uint8_t length)
|
|||||||
void CNXDNTX::writeByte(uint8_t c)
|
void CNXDNTX::writeByte(uint8_t c)
|
||||||
{
|
{
|
||||||
q15_t inBuffer[4U];
|
q15_t inBuffer[4U];
|
||||||
|
q15_t intBuffer[NXDN_RADIO_SYMBOL_LENGTH * 4U];
|
||||||
q15_t outBuffer[NXDN_RADIO_SYMBOL_LENGTH * 4U];
|
q15_t outBuffer[NXDN_RADIO_SYMBOL_LENGTH * 4U];
|
||||||
|
|
||||||
const uint8_t MASK = 0xC0U;
|
const uint8_t MASK = 0xC0U;
|
||||||
@@ -142,7 +163,22 @@ void CNXDNTX::writeByte(uint8_t c)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, outBuffer, 4U);
|
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, intBuffer, 4U);
|
||||||
|
|
||||||
|
::arm_fir_fast_q15(&m_sincFilter, intBuffer, outBuffer, NXDN_RADIO_SYMBOL_LENGTH * 4U);
|
||||||
|
|
||||||
|
io.write(STATE_NXDN, outBuffer, NXDN_RADIO_SYMBOL_LENGTH * 4U);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CNXDNTX::writeSilence()
|
||||||
|
{
|
||||||
|
q15_t inBuffer[4U] = {0x00U, 0x00U, 0x00U, 0x00U};
|
||||||
|
q15_t intBuffer[NXDN_RADIO_SYMBOL_LENGTH * 4U];
|
||||||
|
q15_t outBuffer[NXDN_RADIO_SYMBOL_LENGTH * 4U];
|
||||||
|
|
||||||
|
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, intBuffer, 4U);
|
||||||
|
|
||||||
|
::arm_fir_fast_q15(&m_sincFilter, intBuffer, outBuffer, NXDN_RADIO_SYMBOL_LENGTH * 4U);
|
||||||
|
|
||||||
io.write(STATE_NXDN, outBuffer, NXDN_RADIO_SYMBOL_LENGTH * 4U);
|
io.write(STATE_NXDN, outBuffer, NXDN_RADIO_SYMBOL_LENGTH * 4U);
|
||||||
}
|
}
|
||||||
@@ -160,3 +196,7 @@ uint8_t CNXDNTX::getSpace() const
|
|||||||
return m_buffer.getSpace() / NXDN_FRAME_LENGTH_BYTES;
|
return m_buffer.getSpace() / NXDN_FRAME_LENGTH_BYTES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CNXDNTX::setParams(uint8_t txHang)
|
||||||
|
{
|
||||||
|
m_txHang = txHang * 600U;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015,2016,2017,2018,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -21,13 +21,13 @@
|
|||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
#include "SerialRB.h"
|
#include "RingBuffer.h"
|
||||||
|
|
||||||
class CNXDNTX {
|
class CNXDNTX {
|
||||||
public:
|
public:
|
||||||
CNXDNTX();
|
CNXDNTX();
|
||||||
|
|
||||||
uint8_t writeData(const uint8_t* data, uint8_t length);
|
uint8_t writeData(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
@@ -35,17 +35,23 @@ public:
|
|||||||
|
|
||||||
uint8_t getSpace() const;
|
uint8_t getSpace() const;
|
||||||
|
|
||||||
|
void setParams(uint8_t txHang);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CSerialRB m_buffer;
|
CRingBuffer<uint8_t> m_buffer;
|
||||||
arm_fir_interpolate_instance_q15 m_modFilter;
|
arm_fir_interpolate_instance_q15 m_modFilter;
|
||||||
|
arm_fir_instance_q15 m_sincFilter;
|
||||||
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
|
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
|
||||||
|
q15_t m_sincState[70U]; // NoTaps + BlockSize - 1, 22 + 40 - 1 plus some spare
|
||||||
uint8_t m_poBuffer[1200U];
|
uint8_t m_poBuffer[1200U];
|
||||||
uint16_t m_poLen;
|
uint16_t m_poLen;
|
||||||
uint16_t m_poPtr;
|
uint16_t m_poPtr;
|
||||||
uint16_t m_txDelay;
|
uint16_t m_txDelay;
|
||||||
|
uint32_t m_txHang;
|
||||||
|
uint32_t m_txCount;
|
||||||
|
|
||||||
void writeByte(uint8_t c);
|
void writeByte(uint8_t c);
|
||||||
|
void writeSilence();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
+6
-1
@@ -20,7 +20,7 @@
|
|||||||
#if !defined(P25DEFINES_H)
|
#if !defined(P25DEFINES_H)
|
||||||
#define P25DEFINES_H
|
#define P25DEFINES_H
|
||||||
|
|
||||||
const unsigned int P25_RADIO_SYMBOL_LENGTH = 10U; // At 48 kHz sample rate
|
const unsigned int P25_RADIO_SYMBOL_LENGTH = 5U; // At 24 kHz sample rate
|
||||||
|
|
||||||
const unsigned int P25_HDR_FRAME_LENGTH_BYTES = 99U;
|
const unsigned int P25_HDR_FRAME_LENGTH_BYTES = 99U;
|
||||||
const unsigned int P25_HDR_FRAME_LENGTH_BITS = P25_HDR_FRAME_LENGTH_BYTES * 8U;
|
const unsigned int P25_HDR_FRAME_LENGTH_BITS = P25_HDR_FRAME_LENGTH_BYTES * 8U;
|
||||||
@@ -47,6 +47,11 @@ const unsigned int P25_TSDU_FRAME_LENGTH_BITS = P25_TSDU_FRAME_LENGTH_BYTES
|
|||||||
const unsigned int P25_TSDU_FRAME_LENGTH_SYMBOLS = P25_TSDU_FRAME_LENGTH_BYTES * 4U;
|
const unsigned int P25_TSDU_FRAME_LENGTH_SYMBOLS = P25_TSDU_FRAME_LENGTH_BYTES * 4U;
|
||||||
const unsigned int P25_TSDU_FRAME_LENGTH_SAMPLES = P25_TSDU_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
|
const unsigned int P25_TSDU_FRAME_LENGTH_SAMPLES = P25_TSDU_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
|
const unsigned int P25_PDU_HDR_FRAME_LENGTH_BYTES = 45U;
|
||||||
|
const unsigned int P25_PDU_HDR_FRAME_LENGTH_BITS = P25_PDU_HDR_FRAME_LENGTH_BYTES * 8U;
|
||||||
|
const unsigned int P25_PDU_HDR_FRAME_LENGTH_SYMBOLS = P25_PDU_HDR_FRAME_LENGTH_BYTES * 4U;
|
||||||
|
const unsigned int P25_PDU_HDR_FRAME_LENGTH_SAMPLES = P25_PDU_HDR_FRAME_LENGTH_SYMBOLS * P25_RADIO_SYMBOL_LENGTH;
|
||||||
|
|
||||||
const unsigned int P25_SYNC_LENGTH_BYTES = 6U;
|
const unsigned int P25_SYNC_LENGTH_BYTES = 6U;
|
||||||
const unsigned int P25_SYNC_LENGTH_BITS = P25_SYNC_LENGTH_BYTES * 8U;
|
const unsigned int P25_SYNC_LENGTH_BITS = P25_SYNC_LENGTH_BYTES * 8U;
|
||||||
const unsigned int P25_SYNC_LENGTH_SYMBOLS = P25_SYNC_LENGTH_BYTES * 4U;
|
const unsigned int P25_SYNC_LENGTH_SYMBOLS = P25_SYNC_LENGTH_BYTES * 4U;
|
||||||
|
|||||||
@@ -199,6 +199,18 @@ void CP25RX::processHdr(q15_t sample)
|
|||||||
serial.writeP25Hdr(frame, P25_HDR_FRAME_LENGTH_BYTES + 1U);
|
serial.writeP25Hdr(frame, P25_HDR_FRAME_LENGTH_BYTES + 1U);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case P25_DUID_PDU: {
|
||||||
|
calculateLevels(m_hdrSyncPtr, P25_PDU_HDR_FRAME_LENGTH_SYMBOLS);
|
||||||
|
|
||||||
|
DEBUG4("P25RX: sync found in PDU pos/centre/threshold", m_hdrSyncPtr, m_centreVal, m_thresholdVal);
|
||||||
|
|
||||||
|
uint8_t frame[P25_PDU_HDR_FRAME_LENGTH_BYTES + 1U];
|
||||||
|
samplesToBits(m_hdrSyncPtr, P25_PDU_HDR_FRAME_LENGTH_SYMBOLS, frame, 8U, m_centreVal, m_thresholdVal);
|
||||||
|
|
||||||
|
frame[0U] = 0x01U;
|
||||||
|
serial.writeP25Hdr(frame, P25_PDU_HDR_FRAME_LENGTH_BYTES + 1U);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case P25_DUID_TSDU: {
|
case P25_DUID_TSDU: {
|
||||||
calculateLevels(m_hdrStartPtr, P25_TSDU_FRAME_LENGTH_SYMBOLS);
|
calculateLevels(m_hdrStartPtr, P25_TSDU_FRAME_LENGTH_SYMBOLS);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2016,2017,2020 by Jonathan Naylor G4KLX
|
||||||
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
* Copyright (C) 2017 by Andy Uribe CA6JAU
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
@@ -23,23 +23,17 @@
|
|||||||
|
|
||||||
#include "P25Defines.h"
|
#include "P25Defines.h"
|
||||||
|
|
||||||
// Generated using rcosdesign(0.2, 8, 10, 'normal') in MATLAB
|
// Generated using rcosdesign(0.2, 8, 5, 'normal') in MATLAB
|
||||||
static q15_t RC_0_2_FILTER[] = {-444, -897, -1311, -1636, -1825, -1840, -1659, -1278, -712, 0,
|
// numTaps = 40, L = 5
|
||||||
800, 1613, 2354, 2936, 3277, 3310, 2994, 2315, 1296, 0, -1478,
|
static q15_t RC_0_2_FILTER[] = {-897, -1636, -1840, -1278, 0, 1613, 2936, 3310, 2315, 0, -3011, -5627, -6580, -4839,
|
||||||
-3011, -4448, -5627, -6386, -6580, -6090, -4839, -2800, 0, 3474,
|
0, 7482, 16311, 24651, 30607, 32767, 30607, 24651, 16311, 7482, 0, -4839, -6580, -5627,
|
||||||
7482, 11835, 16311, 20666, 24651, 28032, 30607, 32219, 32767,
|
-3011, 0, 2315, 3310, 2936, 1613, 0, -1278, -1840, -1636, -897, 0}; // numTaps = 40, L = 5
|
||||||
32219, 30607, 28032, 24651, 20666, 16311, 11835, 7482, 3474, 0,
|
|
||||||
-2800, -4839, -6090, -6580, -6386, -5627, -4448, -3011, -1478,
|
|
||||||
0, 1296, 2315, 2994, 3310, 3277, 2936, 2354, 1613, 800, 0, -712,
|
|
||||||
-1278, -1659, -1840, -1825, -1636, -1311, -897, -444, 0}; // numTaps = 80, L = 10
|
|
||||||
const uint16_t RC_0_2_FILTER_PHASE_LEN = 8U; // phaseLength = numTaps/L
|
const uint16_t RC_0_2_FILTER_PHASE_LEN = 8U; // phaseLength = numTaps/L
|
||||||
|
|
||||||
// Generated in MATLAB using the following commands, and then normalised for unity gain
|
static q15_t LOWPASS_FILTER[] = {124, -188, -682, 1262, 556, -621, -1912, -911, 2058, 3855, 1234, -4592, -7692, -2799,
|
||||||
// shape2 = 'Inverse-sinc Lowpass';
|
8556, 18133, 18133, 8556, -2799, -7692, -4592, 1234, 3855, 2058, -911, -1912, -621,
|
||||||
// d2 = fdesign.interpolator(1, shape2);
|
556, 1262, -682, -188, 124};
|
||||||
// h2 = design(d2, 'SystemObject', true);
|
const uint16_t LOWPASS_FILTER_LEN = 32U;
|
||||||
static q15_t LOWPASS_FILTER[] = {1294, -2251, 4312, -8402, 20999, 20999, -8402, 4312, -2251, 1294};
|
|
||||||
const uint16_t LOWPASS_FILTER_LEN = 10U;
|
|
||||||
|
|
||||||
const q15_t P25_LEVELA = 1260;
|
const q15_t P25_LEVELA = 1260;
|
||||||
const q15_t P25_LEVELB = 420;
|
const q15_t P25_LEVELB = 420;
|
||||||
@@ -57,7 +51,9 @@ m_lpState(),
|
|||||||
m_poBuffer(),
|
m_poBuffer(),
|
||||||
m_poLen(0U),
|
m_poLen(0U),
|
||||||
m_poPtr(0U),
|
m_poPtr(0U),
|
||||||
m_txDelay(240U) // 200ms
|
m_txDelay(240U), // 200ms
|
||||||
|
m_txHang(6000U), // 5s
|
||||||
|
m_txCount(0U)
|
||||||
{
|
{
|
||||||
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
|
::memset(m_modState, 0x00U, 16U * sizeof(q15_t));
|
||||||
::memset(m_lpState, 0x00U, 60U * sizeof(q15_t));
|
::memset(m_lpState, 0x00U, 60U * sizeof(q15_t));
|
||||||
@@ -74,17 +70,16 @@ m_txDelay(240U) // 200ms
|
|||||||
|
|
||||||
void CP25TX::process()
|
void CP25TX::process()
|
||||||
{
|
{
|
||||||
if (m_buffer.getData() == 0U && m_poLen == 0U)
|
if (m_poLen == 0U && m_buffer.getData() > 0U) {
|
||||||
return;
|
|
||||||
|
|
||||||
if (m_poLen == 0U) {
|
|
||||||
if (!m_tx) {
|
if (!m_tx) {
|
||||||
for (uint16_t i = 0U; i < m_txDelay; i++)
|
for (uint16_t i = 0U; i < m_txDelay; i++)
|
||||||
m_poBuffer[m_poLen++] = P25_START_SYNC;
|
m_poBuffer[m_poLen++] = P25_START_SYNC;
|
||||||
} else {
|
} else {
|
||||||
uint8_t length = m_buffer.get();
|
uint8_t length;
|
||||||
|
m_buffer.get(length);
|
||||||
for (uint8_t i = 0U; i < length; i++) {
|
for (uint8_t i = 0U; i < length; i++) {
|
||||||
uint8_t c = m_buffer.get();
|
uint8_t c = 0U;
|
||||||
|
m_buffer.get(c);
|
||||||
m_poBuffer[m_poLen++] = c;
|
m_poBuffer[m_poLen++] = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,6 +95,8 @@ void CP25TX::process()
|
|||||||
writeByte(c);
|
writeByte(c);
|
||||||
|
|
||||||
space -= 4U * P25_RADIO_SYMBOL_LENGTH;
|
space -= 4U * P25_RADIO_SYMBOL_LENGTH;
|
||||||
|
if (m_duplex)
|
||||||
|
m_txCount = m_txHang;
|
||||||
|
|
||||||
if (m_poPtr >= m_poLen) {
|
if (m_poPtr >= m_poLen) {
|
||||||
m_poPtr = 0U;
|
m_poPtr = 0U;
|
||||||
@@ -107,10 +104,23 @@ void CP25TX::process()
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if (m_txCount > 0U) {
|
||||||
|
// Transmit silence until the hang timer has expired.
|
||||||
|
uint16_t space = io.getSpace();
|
||||||
|
|
||||||
|
while (space > (4U * P25_RADIO_SYMBOL_LENGTH)) {
|
||||||
|
writeSilence();
|
||||||
|
|
||||||
|
space -= 4U * P25_RADIO_SYMBOL_LENGTH;
|
||||||
|
m_txCount--;
|
||||||
|
|
||||||
|
if (m_txCount == 0U)
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CP25TX::writeData(const uint8_t* data, uint8_t length)
|
uint8_t CP25TX::writeData(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length < (P25_TERM_FRAME_LENGTH_BYTES + 1U))
|
if (length < (P25_TERM_FRAME_LENGTH_BYTES + 1U))
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -158,6 +168,19 @@ void CP25TX::writeByte(uint8_t c)
|
|||||||
io.write(STATE_P25, outBuffer, P25_RADIO_SYMBOL_LENGTH * 4U);
|
io.write(STATE_P25, outBuffer, P25_RADIO_SYMBOL_LENGTH * 4U);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CP25TX::writeSilence()
|
||||||
|
{
|
||||||
|
q15_t inBuffer[4U] = {0x00U, 0x00U, 0x00U, 0x00U};
|
||||||
|
q15_t intBuffer[P25_RADIO_SYMBOL_LENGTH * 4U];
|
||||||
|
q15_t outBuffer[P25_RADIO_SYMBOL_LENGTH * 4U];
|
||||||
|
|
||||||
|
::arm_fir_interpolate_q15(&m_modFilter, inBuffer, intBuffer, 4U);
|
||||||
|
|
||||||
|
::arm_fir_fast_q15(&m_lpFilter, intBuffer, outBuffer, P25_RADIO_SYMBOL_LENGTH * 4U);
|
||||||
|
|
||||||
|
io.write(STATE_P25, outBuffer, P25_RADIO_SYMBOL_LENGTH * 4U);
|
||||||
|
}
|
||||||
|
|
||||||
void CP25TX::setTXDelay(uint8_t delay)
|
void CP25TX::setTXDelay(uint8_t delay)
|
||||||
{
|
{
|
||||||
m_txDelay = 600U + uint16_t(delay) * 12U; // 500ms + tx delay
|
m_txDelay = 600U + uint16_t(delay) * 12U; // 500ms + tx delay
|
||||||
@@ -170,3 +193,8 @@ uint8_t CP25TX::getSpace() const
|
|||||||
{
|
{
|
||||||
return m_buffer.getSpace() / P25_LDU_FRAME_LENGTH_BYTES;
|
return m_buffer.getSpace() / P25_LDU_FRAME_LENGTH_BYTES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CP25TX::setParams(uint8_t txHang)
|
||||||
|
{
|
||||||
|
m_txHang = txHang * 1200U;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2016,2017 by Jonathan Naylor G4KLX
|
* Copyright (C) 2016,2017,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -21,13 +21,13 @@
|
|||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
#include "SerialRB.h"
|
#include "RingBuffer.h"
|
||||||
|
|
||||||
class CP25TX {
|
class CP25TX {
|
||||||
public:
|
public:
|
||||||
CP25TX();
|
CP25TX();
|
||||||
|
|
||||||
uint8_t writeData(const uint8_t* data, uint8_t length);
|
uint8_t writeData(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
@@ -35,8 +35,10 @@ public:
|
|||||||
|
|
||||||
uint8_t getSpace() const;
|
uint8_t getSpace() const;
|
||||||
|
|
||||||
|
void setParams(uint8_t txHang);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CSerialRB m_buffer;
|
CRingBuffer<uint8_t> m_buffer;
|
||||||
arm_fir_interpolate_instance_q15 m_modFilter;
|
arm_fir_interpolate_instance_q15 m_modFilter;
|
||||||
arm_fir_instance_q15 m_lpFilter;
|
arm_fir_instance_q15 m_lpFilter;
|
||||||
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
|
q15_t m_modState[16U]; // blockSize + phaseLength - 1, 4 + 9 - 1 plus some spare
|
||||||
@@ -45,9 +47,11 @@ private:
|
|||||||
uint16_t m_poLen;
|
uint16_t m_poLen;
|
||||||
uint16_t m_poPtr;
|
uint16_t m_poPtr;
|
||||||
uint16_t m_txDelay;
|
uint16_t m_txDelay;
|
||||||
|
uint32_t m_txHang;
|
||||||
|
uint32_t m_txCount;
|
||||||
|
|
||||||
void writeByte(uint8_t c);
|
void writeByte(uint8_t c);
|
||||||
|
void writeSilence();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
+11
-11
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2009-2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2009-2018,2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -24,18 +24,18 @@ const uint16_t POCSAG_FRAME_LENGTH_BYTES = 17U * sizeof(uint32_t);
|
|||||||
|
|
||||||
const uint16_t POCSAG_PREAMBLE_LENGTH_BYTES = 18U * sizeof(uint32_t);
|
const uint16_t POCSAG_PREAMBLE_LENGTH_BYTES = 18U * sizeof(uint32_t);
|
||||||
|
|
||||||
const uint16_t POCSAG_RADIO_SYMBOL_LENGTH = 40U; // at 48Khz
|
const uint16_t POCSAG_RADIO_SYMBOL_LENGTH = 20U;
|
||||||
|
|
||||||
const q15_t POCSAG_LEVEL1[] = { 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700};
|
const q15_t POCSAG_LEVEL1[] = { 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700, 1700};
|
||||||
const q15_t POCSAG_LEVEL0[] = {-1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700};
|
const q15_t POCSAG_LEVEL0[] = {-1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700, -1700};
|
||||||
|
|
||||||
static q15_t SHAPING_FILTER[] = {2730, 2730, 2730, 2730, 2730, 2730, 2730, 2730, 2730, 2730, 2730, 2730};
|
static q15_t SHAPING_FILTER[] = {5461, 5461, 5461, 5461, 5461, 5461};
|
||||||
const uint16_t SHAPING_FILTER_LEN = 12U;
|
const uint16_t SHAPING_FILTER_LEN = 6U;
|
||||||
|
|
||||||
const uint8_t POCSAG_SYNC = 0xAAU;
|
const uint8_t POCSAG_SYNC = 0xAAU;
|
||||||
|
|
||||||
CPOCSAGTX::CPOCSAGTX() :
|
CPOCSAGTX::CPOCSAGTX() :
|
||||||
m_buffer(TX_BUFFER_LEN),
|
m_buffer(4000U),
|
||||||
m_modFilter(),
|
m_modFilter(),
|
||||||
m_modState(),
|
m_modState(),
|
||||||
m_poBuffer(),
|
m_poBuffer(),
|
||||||
@@ -43,7 +43,7 @@ m_poLen(0U),
|
|||||||
m_poPtr(0U),
|
m_poPtr(0U),
|
||||||
m_txDelay(POCSAG_PREAMBLE_LENGTH_BYTES)
|
m_txDelay(POCSAG_PREAMBLE_LENGTH_BYTES)
|
||||||
{
|
{
|
||||||
::memset(m_modState, 0x00U, 180U * sizeof(q15_t));
|
::memset(m_modState, 0x00U, 170U * sizeof(q15_t));
|
||||||
|
|
||||||
m_modFilter.numTaps = SHAPING_FILTER_LEN;
|
m_modFilter.numTaps = SHAPING_FILTER_LEN;
|
||||||
m_modFilter.pState = m_modState;
|
m_modFilter.pState = m_modState;
|
||||||
@@ -61,7 +61,8 @@ void CPOCSAGTX::process()
|
|||||||
m_poBuffer[m_poLen++] = POCSAG_SYNC;
|
m_poBuffer[m_poLen++] = POCSAG_SYNC;
|
||||||
} else {
|
} else {
|
||||||
for (uint8_t i = 0U; i < POCSAG_FRAME_LENGTH_BYTES; i++) {
|
for (uint8_t i = 0U; i < POCSAG_FRAME_LENGTH_BYTES; i++) {
|
||||||
uint8_t c = m_buffer.get();
|
uint8_t c = 0U;
|
||||||
|
m_buffer.get(c);
|
||||||
m_poBuffer[m_poLen++] = c;
|
m_poBuffer[m_poLen++] = c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,7 +96,7 @@ bool CPOCSAGTX::busy()
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t CPOCSAGTX::writeData(const uint8_t* data, uint8_t length)
|
uint8_t CPOCSAGTX::writeData(const uint8_t* data, uint16_t length)
|
||||||
{
|
{
|
||||||
if (length != POCSAG_FRAME_LENGTH_BYTES)
|
if (length != POCSAG_FRAME_LENGTH_BYTES)
|
||||||
return 4U;
|
return 4U;
|
||||||
@@ -146,4 +147,3 @@ uint8_t CPOCSAGTX::getSpace() const
|
|||||||
{
|
{
|
||||||
return m_buffer.getSpace() / POCSAG_FRAME_LENGTH_BYTES;
|
return m_buffer.getSpace() / POCSAG_FRAME_LENGTH_BYTES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-7
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (C) 2015,2016,2017,2018 by Jonathan Naylor G4KLX
|
* Copyright (C) 2015-2020 by Jonathan Naylor G4KLX
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* This program is free software; you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@@ -21,13 +21,15 @@
|
|||||||
|
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
|
|
||||||
#include "SerialRB.h"
|
#include "RingBuffer.h"
|
||||||
|
|
||||||
class CPOCSAGTX {
|
class CPOCSAGTX {
|
||||||
public:
|
public:
|
||||||
CPOCSAGTX();
|
CPOCSAGTX();
|
||||||
|
|
||||||
uint8_t writeData(const uint8_t* data, uint8_t length);
|
uint8_t writeData(const uint8_t* data, uint16_t length);
|
||||||
|
|
||||||
|
void writeByte(uint8_t c);
|
||||||
|
|
||||||
void process();
|
void process();
|
||||||
|
|
||||||
@@ -38,15 +40,13 @@ public:
|
|||||||
bool busy();
|
bool busy();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CSerialRB m_buffer;
|
CRingBuffer<uint8_t> m_buffer;
|
||||||
arm_fir_instance_q15 m_modFilter;
|
arm_fir_instance_q15 m_modFilter;
|
||||||
q15_t m_modState[180U]; // NoTaps + BlockSize - 1, 12 + 160 - 1 plus some spare
|
q15_t m_modState[170U]; // NoTaps + BlockSize - 1, 6 + 160 - 1 plus some spare
|
||||||
uint8_t m_poBuffer[200U];
|
uint8_t m_poBuffer[200U];
|
||||||
uint16_t m_poLen;
|
uint16_t m_poLen;
|
||||||
uint16_t m_poPtr;
|
uint16_t m_poPtr;
|
||||||
uint16_t m_txDelay;
|
uint16_t m_txDelay;
|
||||||
|
|
||||||
void writeByte(uint8_t c);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,7 +1,17 @@
|
|||||||
This is the source code of the MMDVM firmware that supports D-Star, DMR, System Fusion, P25, NXDN, and POCSAG modes.
|
This is the source code of the MMDVM firmware that supports D-Star, DMR,
|
||||||
|
System Fusion, P25, NXDN, POCSAG, and FM modes.
|
||||||
|
|
||||||
It runs on the Arduino Due, the ST-Micro STM32F1xxx, STM32F4xxx and STM32F7xxx processors, as well as the Teensy 3.1/3.2/3.5/3.6. What these platforms have in common is the use of an ARM Cortex-M3 or M4 processor with a clock speed greater than 70 MHz, and access to at least one analogue to digital converter and one digital to analogue converter.
|
It runs on the Arduino Due, the ST-Micro STM32F1xxx, STM32F4xxx and STM32F7xxx
|
||||||
|
processors, as well as the Teensy 3.1/3.2/3.5/3.6. What these platforms have in
|
||||||
|
common is the use of an ARM Cortex-M3, M4, or M7 processors with a clock speed
|
||||||
|
greater than 70 MHz, and access to at least one analogue to digital converter
|
||||||
|
and one digital to analogue converter.
|
||||||
|
|
||||||
In order to build this software for the Arduino Due, you will need to edit a file within the Arduino GUI and that is detailed in the BUILD.txt file. The STM32 support is being supplied via the Coocox IDE with ARM GCC. The Teensy support uses Teensyduino.
|
In order to build this software for the Arduino Due, you will need to edit a
|
||||||
|
file within the Arduino GUI and that is detailed in the BUILD.txt file. The
|
||||||
|
STM32 support is being supplied via the ARM GCC compiler. The Teensy support
|
||||||
|
uses Teensyduino.
|
||||||
|
|
||||||
This software is licenced under the GPL v2 and is intended for amateur and educational use only. Use of this software for commercial purposes is strictly forbidden.
|
This software is licenced under the GPL v2 and is intended for amateur and
|
||||||
|
educational use only. Use of this software for commercial purposes is strictly
|
||||||
|
forbidden.
|
||||||
|
|||||||
-102
@@ -1,102 +0,0 @@
|
|||||||
/*
|
|
||||||
TX fifo control - Copyright (C) KI6ZUM 2015
|
|
||||||
Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with this library; if not, write to the
|
|
||||||
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
||||||
Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "RSSIRB.h"
|
|
||||||
|
|
||||||
CRSSIRB::CRSSIRB(uint16_t length) :
|
|
||||||
m_length(length),
|
|
||||||
m_head(0U),
|
|
||||||
m_tail(0U),
|
|
||||||
m_full(false),
|
|
||||||
m_overflow(false)
|
|
||||||
{
|
|
||||||
m_rssi = new uint16_t[length];
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t CRSSIRB::getSpace() const
|
|
||||||
{
|
|
||||||
uint16_t n = 0U;
|
|
||||||
|
|
||||||
if (m_tail == m_head)
|
|
||||||
n = m_full ? 0U : m_length;
|
|
||||||
else if (m_tail < m_head)
|
|
||||||
n = m_length - m_head + m_tail;
|
|
||||||
else
|
|
||||||
n = m_tail - m_head;
|
|
||||||
|
|
||||||
if (n > m_length)
|
|
||||||
n = 0U;
|
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t CRSSIRB::getData() const
|
|
||||||
{
|
|
||||||
if (m_tail == m_head)
|
|
||||||
return m_full ? m_length : 0U;
|
|
||||||
else if (m_tail < m_head)
|
|
||||||
return m_head - m_tail;
|
|
||||||
else
|
|
||||||
return m_length - m_tail + m_head;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CRSSIRB::put(uint16_t rssi)
|
|
||||||
{
|
|
||||||
if (m_full) {
|
|
||||||
m_overflow = true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_rssi[m_head] = rssi;
|
|
||||||
|
|
||||||
m_head++;
|
|
||||||
if (m_head >= m_length)
|
|
||||||
m_head = 0U;
|
|
||||||
|
|
||||||
if (m_head == m_tail)
|
|
||||||
m_full = true;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CRSSIRB::get(uint16_t& rssi)
|
|
||||||
{
|
|
||||||
if (m_head == m_tail && !m_full)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
rssi = m_rssi[m_tail];
|
|
||||||
|
|
||||||
m_full = false;
|
|
||||||
|
|
||||||
m_tail++;
|
|
||||||
if (m_tail >= m_length)
|
|
||||||
m_tail = 0U;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CRSSIRB::hasOverflowed()
|
|
||||||
{
|
|
||||||
bool overflow = m_overflow;
|
|
||||||
|
|
||||||
m_overflow = false;
|
|
||||||
|
|
||||||
return overflow;
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
/*
|
|
||||||
Serial fifo control - Copyright (C) KI6ZUM 2015
|
|
||||||
Copyright (C) 2015,2016 by Jonathan Naylor G4KLX
|
|
||||||
|
|
||||||
This library is free software; you can redistribute it and/or
|
|
||||||
modify it under the terms of the GNU Library General Public
|
|
||||||
License as published by the Free Software Foundation; either
|
|
||||||
version 2 of the License, or (at your option) any later version.
|
|
||||||
|
|
||||||
This library is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
||||||
Library General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Library General Public
|
|
||||||
License along with this library; if not, write to the
|
|
||||||
Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
|
|
||||||
Boston, MA 02110-1301, USA.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if !defined(RSSIRB_H)
|
|
||||||
#define RSSIRB_H
|
|
||||||
|
|
||||||
#if defined(STM32F4XX)
|
|
||||||
#include "stm32f4xx.h"
|
|
||||||
#elif defined(STM32F7XX)
|
|
||||||
#include "stm32f7xx.h"
|
|
||||||
#elif defined(STM32F105xC)
|
|
||||||
#include "stm32f1xx.h"
|
|
||||||
#include <cstddef>
|
|
||||||
#else
|
|
||||||
#include <Arduino.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class CRSSIRB {
|
|
||||||
public:
|
|
||||||
CRSSIRB(uint16_t length);
|
|
||||||
|
|
||||||
uint16_t getSpace() const;
|
|
||||||
|
|
||||||
uint16_t getData() const;
|
|
||||||
|
|
||||||
bool put(uint16_t rssi);
|
|
||||||
|
|
||||||
bool get(uint16_t& rssi);
|
|
||||||
|
|
||||||
bool hasOverflowed();
|
|
||||||
|
|
||||||
private:
|
|
||||||
uint16_t m_length;
|
|
||||||
volatile uint16_t* m_rssi;
|
|
||||||
volatile uint16_t m_head;
|
|
||||||
volatile uint16_t m_tail;
|
|
||||||
volatile bool m_full;
|
|
||||||
bool m_overflow;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2020 by Geoffrey Merck F4FXL - KC3FRA
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(RINGBUFFER_H)
|
||||||
|
#define RINGBUFFER_H
|
||||||
|
|
||||||
|
#if defined(STM32F4XX)
|
||||||
|
#include "stm32f4xx.h"
|
||||||
|
#elif defined(STM32F7XX)
|
||||||
|
#include "stm32f7xx.h"
|
||||||
|
#elif defined(STM32F105xC)
|
||||||
|
#include "stm32f1xx.h"
|
||||||
|
#include <cstddef>
|
||||||
|
#else
|
||||||
|
#include <Arduino.h>
|
||||||
|
#undef PI
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__SAM3X8E__) || defined(STM32F105xC)
|
||||||
|
#define ARM_MATH_CM3
|
||||||
|
#elif defined(STM32F7XX)
|
||||||
|
#define ARM_MATH_CM7
|
||||||
|
#elif defined(STM32F4XX) || defined(__MK20DX256__) || defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||||
|
#define ARM_MATH_CM4
|
||||||
|
#else
|
||||||
|
#error "Unknown processor type"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <arm_math.h>
|
||||||
|
|
||||||
|
template <typename TDATATYPE>
|
||||||
|
class CRingBuffer {
|
||||||
|
public:
|
||||||
|
CRingBuffer(uint16_t length = 370U);
|
||||||
|
|
||||||
|
uint16_t getSpace() const;
|
||||||
|
|
||||||
|
uint16_t getData() const;
|
||||||
|
|
||||||
|
bool put(TDATATYPE item) volatile;
|
||||||
|
|
||||||
|
bool get(TDATATYPE& item) volatile;
|
||||||
|
|
||||||
|
TDATATYPE peek() const;
|
||||||
|
|
||||||
|
bool hasOverflowed();
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint16_t m_length;
|
||||||
|
TDATATYPE* m_buffer;
|
||||||
|
volatile uint16_t m_head;
|
||||||
|
volatile uint16_t m_tail;
|
||||||
|
volatile bool m_full;
|
||||||
|
bool m_overflow;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "RingBuffer.impl.h"
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2020 by Jonathan Naylor G4KLX
|
||||||
|
* Copyright (C) 2020 by Geoffrey Merck F4FXL - KC3FRA
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "RingBuffer.h"
|
||||||
|
|
||||||
|
template <typename TDATATYPE> CRingBuffer<TDATATYPE>::CRingBuffer(uint16_t length) :
|
||||||
|
m_length(length),
|
||||||
|
m_head(0U),
|
||||||
|
m_tail(0U),
|
||||||
|
m_full(false),
|
||||||
|
m_overflow(false)
|
||||||
|
{
|
||||||
|
m_buffer = new TDATATYPE[length];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDATATYPE> uint16_t CRingBuffer<TDATATYPE>::getSpace() const
|
||||||
|
{
|
||||||
|
uint16_t n = 0U;
|
||||||
|
|
||||||
|
if (m_tail == m_head)
|
||||||
|
n = m_full ? 0U : m_length;
|
||||||
|
else if (m_tail < m_head)
|
||||||
|
n = m_length - m_head + m_tail;
|
||||||
|
else
|
||||||
|
n = m_tail - m_head;
|
||||||
|
|
||||||
|
if (n > m_length)
|
||||||
|
n = 0U;
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDATATYPE> uint16_t CRingBuffer<TDATATYPE>::getData() const
|
||||||
|
{
|
||||||
|
if (m_tail == m_head)
|
||||||
|
return m_full ? m_length : 0U;
|
||||||
|
else if (m_tail < m_head)
|
||||||
|
return m_head - m_tail;
|
||||||
|
else
|
||||||
|
return m_length - m_tail + m_head;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDATATYPE> bool CRingBuffer<TDATATYPE>::put(TDATATYPE item) volatile
|
||||||
|
{
|
||||||
|
if (m_full) {
|
||||||
|
m_overflow = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_buffer[m_head] = item;
|
||||||
|
|
||||||
|
m_head++;
|
||||||
|
if (m_head >= m_length)
|
||||||
|
m_head = 0U;
|
||||||
|
|
||||||
|
if (m_head == m_tail)
|
||||||
|
m_full = true;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDATATYPE> TDATATYPE CRingBuffer<TDATATYPE>::peek() const
|
||||||
|
{
|
||||||
|
return m_buffer[m_tail];
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDATATYPE> bool CRingBuffer<TDATATYPE>::get(TDATATYPE& item) volatile
|
||||||
|
{
|
||||||
|
if (m_head == m_tail && !m_full)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
item = m_buffer[m_tail];
|
||||||
|
|
||||||
|
m_full = false;
|
||||||
|
|
||||||
|
m_tail++;
|
||||||
|
if (m_tail >= m_length)
|
||||||
|
m_tail = 0U;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDATATYPE> bool CRingBuffer<TDATATYPE>::hasOverflowed()
|
||||||
|
{
|
||||||
|
bool overflow = m_overflow;
|
||||||
|
|
||||||
|
m_overflow = false;
|
||||||
|
|
||||||
|
return overflow;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TDATATYPE> void CRingBuffer<TDATATYPE>::reset()
|
||||||
|
{
|
||||||
|
m_head = 0U;
|
||||||
|
m_tail = 0U;
|
||||||
|
m_full = false;
|
||||||
|
m_overflow = false;
|
||||||
|
}
|
||||||
Submodule
+1
Submodule STM32F10X_Lib added at 417e0c2f4a
Submodule
+1
Submodule STM32F4XX_Lib added at bcd346f530
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,664 +0,0 @@
|
|||||||
/**************************************************************************//**
|
|
||||||
* @file core_cmFunc.h
|
|
||||||
* @brief CMSIS Cortex-M Core Function Access Header File
|
|
||||||
* @version V4.10
|
|
||||||
* @date 18. March 2015
|
|
||||||
*
|
|
||||||
* @note
|
|
||||||
*
|
|
||||||
******************************************************************************/
|
|
||||||
/* Copyright (c) 2009 - 2015 ARM LIMITED
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
- Redistributions of source code must retain the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer.
|
|
||||||
- Redistributions in binary form must reproduce the above copyright
|
|
||||||
notice, this list of conditions and the following disclaimer in the
|
|
||||||
documentation and/or other materials provided with the distribution.
|
|
||||||
- Neither the name of ARM nor the names of its contributors may be used
|
|
||||||
to endorse or promote products derived from this software without
|
|
||||||
specific prior written permission.
|
|
||||||
*
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
||||||
ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDERS AND CONTRIBUTORS BE
|
|
||||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
||||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
||||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
||||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
||||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
||||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef __CORE_CMFUNC_H
|
|
||||||
#define __CORE_CMFUNC_H
|
|
||||||
|
|
||||||
|
|
||||||
/* ########################### Core Function Access ########################### */
|
|
||||||
/** \ingroup CMSIS_Core_FunctionInterface
|
|
||||||
\defgroup CMSIS_Core_RegAccFunctions CMSIS Core Register Access Functions
|
|
||||||
@{
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if defined ( __CC_ARM ) /*------------------RealView Compiler -----------------*/
|
|
||||||
/* ARM armcc specific functions */
|
|
||||||
|
|
||||||
#if (__ARMCC_VERSION < 400677)
|
|
||||||
#error "Please use ARM Compiler Toolchain V4.0.677 or later!"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* intrinsic void __enable_irq(); */
|
|
||||||
/* intrinsic void __disable_irq(); */
|
|
||||||
|
|
||||||
/** \brief Get Control Register
|
|
||||||
|
|
||||||
This function returns the content of the Control Register.
|
|
||||||
|
|
||||||
\return Control Register value
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE uint32_t __get_CONTROL(void)
|
|
||||||
{
|
|
||||||
register uint32_t __regControl __ASM("control");
|
|
||||||
return(__regControl);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Set Control Register
|
|
||||||
|
|
||||||
This function writes the given value to the Control Register.
|
|
||||||
|
|
||||||
\param [in] control Control Register value to set
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE void __set_CONTROL(uint32_t control)
|
|
||||||
{
|
|
||||||
register uint32_t __regControl __ASM("control");
|
|
||||||
__regControl = control;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Get IPSR Register
|
|
||||||
|
|
||||||
This function returns the content of the IPSR Register.
|
|
||||||
|
|
||||||
\return IPSR Register value
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE uint32_t __get_IPSR(void)
|
|
||||||
{
|
|
||||||
register uint32_t __regIPSR __ASM("ipsr");
|
|
||||||
return(__regIPSR);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Get APSR Register
|
|
||||||
|
|
||||||
This function returns the content of the APSR Register.
|
|
||||||
|
|
||||||
\return APSR Register value
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE uint32_t __get_APSR(void)
|
|
||||||
{
|
|
||||||
register uint32_t __regAPSR __ASM("apsr");
|
|
||||||
return(__regAPSR);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Get xPSR Register
|
|
||||||
|
|
||||||
This function returns the content of the xPSR Register.
|
|
||||||
|
|
||||||
\return xPSR Register value
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE uint32_t __get_xPSR(void)
|
|
||||||
{
|
|
||||||
register uint32_t __regXPSR __ASM("xpsr");
|
|
||||||
return(__regXPSR);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Get Process Stack Pointer
|
|
||||||
|
|
||||||
This function returns the current value of the Process Stack Pointer (PSP).
|
|
||||||
|
|
||||||
\return PSP Register value
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE uint32_t __get_PSP(void)
|
|
||||||
{
|
|
||||||
register uint32_t __regProcessStackPointer __ASM("psp");
|
|
||||||
return(__regProcessStackPointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Set Process Stack Pointer
|
|
||||||
|
|
||||||
This function assigns the given value to the Process Stack Pointer (PSP).
|
|
||||||
|
|
||||||
\param [in] topOfProcStack Process Stack Pointer value to set
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE void __set_PSP(uint32_t topOfProcStack)
|
|
||||||
{
|
|
||||||
register uint32_t __regProcessStackPointer __ASM("psp");
|
|
||||||
__regProcessStackPointer = topOfProcStack;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Get Main Stack Pointer
|
|
||||||
|
|
||||||
This function returns the current value of the Main Stack Pointer (MSP).
|
|
||||||
|
|
||||||
\return MSP Register value
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE uint32_t __get_MSP(void)
|
|
||||||
{
|
|
||||||
register uint32_t __regMainStackPointer __ASM("msp");
|
|
||||||
return(__regMainStackPointer);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Set Main Stack Pointer
|
|
||||||
|
|
||||||
This function assigns the given value to the Main Stack Pointer (MSP).
|
|
||||||
|
|
||||||
\param [in] topOfMainStack Main Stack Pointer value to set
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE void __set_MSP(uint32_t topOfMainStack)
|
|
||||||
{
|
|
||||||
register uint32_t __regMainStackPointer __ASM("msp");
|
|
||||||
__regMainStackPointer = topOfMainStack;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Get Priority Mask
|
|
||||||
|
|
||||||
This function returns the current state of the priority mask bit from the Priority Mask Register.
|
|
||||||
|
|
||||||
\return Priority Mask value
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE uint32_t __get_PRIMASK(void)
|
|
||||||
{
|
|
||||||
register uint32_t __regPriMask __ASM("primask");
|
|
||||||
return(__regPriMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Set Priority Mask
|
|
||||||
|
|
||||||
This function assigns the given value to the Priority Mask Register.
|
|
||||||
|
|
||||||
\param [in] priMask Priority Mask
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE void __set_PRIMASK(uint32_t priMask)
|
|
||||||
{
|
|
||||||
register uint32_t __regPriMask __ASM("primask");
|
|
||||||
__regPriMask = (priMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if (__CORTEX_M >= 0x03) || (__CORTEX_SC >= 300)
|
|
||||||
|
|
||||||
/** \brief Enable FIQ
|
|
||||||
|
|
||||||
This function enables FIQ interrupts by clearing the F-bit in the CPSR.
|
|
||||||
Can only be executed in Privileged modes.
|
|
||||||
*/
|
|
||||||
#define __enable_fault_irq __enable_fiq
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Disable FIQ
|
|
||||||
|
|
||||||
This function disables FIQ interrupts by setting the F-bit in the CPSR.
|
|
||||||
Can only be executed in Privileged modes.
|
|
||||||
*/
|
|
||||||
#define __disable_fault_irq __disable_fiq
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Get Base Priority
|
|
||||||
|
|
||||||
This function returns the current value of the Base Priority register.
|
|
||||||
|
|
||||||
\return Base Priority register value
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE uint32_t __get_BASEPRI(void)
|
|
||||||
{
|
|
||||||
register uint32_t __regBasePri __ASM("basepri");
|
|
||||||
return(__regBasePri);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Set Base Priority
|
|
||||||
|
|
||||||
This function assigns the given value to the Base Priority register.
|
|
||||||
|
|
||||||
\param [in] basePri Base Priority value to set
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE void __set_BASEPRI(uint32_t basePri)
|
|
||||||
{
|
|
||||||
register uint32_t __regBasePri __ASM("basepri");
|
|
||||||
__regBasePri = (basePri & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Set Base Priority with condition
|
|
||||||
|
|
||||||
This function assigns the given value to the Base Priority register only if BASEPRI masking is disabled,
|
|
||||||
or the new value increases the BASEPRI priority level.
|
|
||||||
|
|
||||||
\param [in] basePri Base Priority value to set
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE void __set_BASEPRI_MAX(uint32_t basePri)
|
|
||||||
{
|
|
||||||
register uint32_t __regBasePriMax __ASM("basepri_max");
|
|
||||||
__regBasePriMax = (basePri & 0xff);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Get Fault Mask
|
|
||||||
|
|
||||||
This function returns the current value of the Fault Mask register.
|
|
||||||
|
|
||||||
\return Fault Mask register value
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE uint32_t __get_FAULTMASK(void)
|
|
||||||
{
|
|
||||||
register uint32_t __regFaultMask __ASM("faultmask");
|
|
||||||
return(__regFaultMask);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Set Fault Mask
|
|
||||||
|
|
||||||
This function assigns the given value to the Fault Mask register.
|
|
||||||
|
|
||||||
\param [in] faultMask Fault Mask value to set
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE void __set_FAULTMASK(uint32_t faultMask)
|
|
||||||
{
|
|
||||||
register uint32_t __regFaultMask __ASM("faultmask");
|
|
||||||
__regFaultMask = (faultMask & (uint32_t)1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* (__CORTEX_M >= 0x03) || (__CORTEX_SC >= 300) */
|
|
||||||
|
|
||||||
|
|
||||||
#if (__CORTEX_M == 0x04) || (__CORTEX_M == 0x07)
|
|
||||||
|
|
||||||
/** \brief Get FPSCR
|
|
||||||
|
|
||||||
This function returns the current value of the Floating Point Status/Control register.
|
|
||||||
|
|
||||||
\return Floating Point Status/Control register value
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE uint32_t __get_FPSCR(void)
|
|
||||||
{
|
|
||||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
|
||||||
register uint32_t __regfpscr __ASM("fpscr");
|
|
||||||
return(__regfpscr);
|
|
||||||
#else
|
|
||||||
return(0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Set FPSCR
|
|
||||||
|
|
||||||
This function assigns the given value to the Floating Point Status/Control register.
|
|
||||||
|
|
||||||
\param [in] fpscr Floating Point Status/Control value to set
|
|
||||||
*/
|
|
||||||
__STATIC_INLINE void __set_FPSCR(uint32_t fpscr)
|
|
||||||
{
|
|
||||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
|
||||||
register uint32_t __regfpscr __ASM("fpscr");
|
|
||||||
__regfpscr = (fpscr);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* (__CORTEX_M == 0x04) || (__CORTEX_M == 0x07) */
|
|
||||||
|
|
||||||
|
|
||||||
#elif defined ( __GNUC__ ) /*------------------ GNU Compiler ---------------------*/
|
|
||||||
/* GNU gcc specific functions */
|
|
||||||
|
|
||||||
/** \brief Enable IRQ Interrupts
|
|
||||||
|
|
||||||
This function enables IRQ interrupts by clearing the I-bit in the CPSR.
|
|
||||||
Can only be executed in Privileged modes.
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_irq(void)
|
|
||||||
{
|
|
||||||
__ASM volatile ("cpsie i" : : : "memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Disable IRQ Interrupts
|
|
||||||
|
|
||||||
This function disables IRQ interrupts by setting the I-bit in the CPSR.
|
|
||||||
Can only be executed in Privileged modes.
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_irq(void)
|
|
||||||
{
|
|
||||||
__ASM volatile ("cpsid i" : : : "memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Get Control Register
|
|
||||||
|
|
||||||
This function returns the content of the Control Register.
|
|
||||||
|
|
||||||
\return Control Register value
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_CONTROL(void)
|
|
||||||
{
|
|
||||||
uint32_t result;
|
|
||||||
|
|
||||||
__ASM volatile ("MRS %0, control" : "=r" (result) );
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Set Control Register
|
|
||||||
|
|
||||||
This function writes the given value to the Control Register.
|
|
||||||
|
|
||||||
\param [in] control Control Register value to set
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_CONTROL(uint32_t control)
|
|
||||||
{
|
|
||||||
__ASM volatile ("MSR control, %0" : : "r" (control) : "memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Get IPSR Register
|
|
||||||
|
|
||||||
This function returns the content of the IPSR Register.
|
|
||||||
|
|
||||||
\return IPSR Register value
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_IPSR(void)
|
|
||||||
{
|
|
||||||
uint32_t result;
|
|
||||||
|
|
||||||
__ASM volatile ("MRS %0, ipsr" : "=r" (result) );
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Get APSR Register
|
|
||||||
|
|
||||||
This function returns the content of the APSR Register.
|
|
||||||
|
|
||||||
\return APSR Register value
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_APSR(void)
|
|
||||||
{
|
|
||||||
uint32_t result;
|
|
||||||
|
|
||||||
__ASM volatile ("MRS %0, apsr" : "=r" (result) );
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Get xPSR Register
|
|
||||||
|
|
||||||
This function returns the content of the xPSR Register.
|
|
||||||
|
|
||||||
\return xPSR Register value
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_xPSR(void)
|
|
||||||
{
|
|
||||||
uint32_t result;
|
|
||||||
|
|
||||||
__ASM volatile ("MRS %0, xpsr" : "=r" (result) );
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Get Process Stack Pointer
|
|
||||||
|
|
||||||
This function returns the current value of the Process Stack Pointer (PSP).
|
|
||||||
|
|
||||||
\return PSP Register value
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_PSP(void)
|
|
||||||
{
|
|
||||||
register uint32_t result;
|
|
||||||
|
|
||||||
__ASM volatile ("MRS %0, psp\n" : "=r" (result) );
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Set Process Stack Pointer
|
|
||||||
|
|
||||||
This function assigns the given value to the Process Stack Pointer (PSP).
|
|
||||||
|
|
||||||
\param [in] topOfProcStack Process Stack Pointer value to set
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_PSP(uint32_t topOfProcStack)
|
|
||||||
{
|
|
||||||
__ASM volatile ("MSR psp, %0\n" : : "r" (topOfProcStack) : "sp");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Get Main Stack Pointer
|
|
||||||
|
|
||||||
This function returns the current value of the Main Stack Pointer (MSP).
|
|
||||||
|
|
||||||
\return MSP Register value
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_MSP(void)
|
|
||||||
{
|
|
||||||
register uint32_t result;
|
|
||||||
|
|
||||||
__ASM volatile ("MRS %0, msp\n" : "=r" (result) );
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Set Main Stack Pointer
|
|
||||||
|
|
||||||
This function assigns the given value to the Main Stack Pointer (MSP).
|
|
||||||
|
|
||||||
\param [in] topOfMainStack Main Stack Pointer value to set
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_MSP(uint32_t topOfMainStack)
|
|
||||||
{
|
|
||||||
__ASM volatile ("MSR msp, %0\n" : : "r" (topOfMainStack) : "sp");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Get Priority Mask
|
|
||||||
|
|
||||||
This function returns the current state of the priority mask bit from the Priority Mask Register.
|
|
||||||
|
|
||||||
\return Priority Mask value
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_PRIMASK(void)
|
|
||||||
{
|
|
||||||
uint32_t result;
|
|
||||||
|
|
||||||
__ASM volatile ("MRS %0, primask" : "=r" (result) );
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Set Priority Mask
|
|
||||||
|
|
||||||
This function assigns the given value to the Priority Mask Register.
|
|
||||||
|
|
||||||
\param [in] priMask Priority Mask
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_PRIMASK(uint32_t priMask)
|
|
||||||
{
|
|
||||||
__ASM volatile ("MSR primask, %0" : : "r" (priMask) : "memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#if (__CORTEX_M >= 0x03)
|
|
||||||
|
|
||||||
/** \brief Enable FIQ
|
|
||||||
|
|
||||||
This function enables FIQ interrupts by clearing the F-bit in the CPSR.
|
|
||||||
Can only be executed in Privileged modes.
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __enable_fault_irq(void)
|
|
||||||
{
|
|
||||||
__ASM volatile ("cpsie f" : : : "memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Disable FIQ
|
|
||||||
|
|
||||||
This function disables FIQ interrupts by setting the F-bit in the CPSR.
|
|
||||||
Can only be executed in Privileged modes.
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __disable_fault_irq(void)
|
|
||||||
{
|
|
||||||
__ASM volatile ("cpsid f" : : : "memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Get Base Priority
|
|
||||||
|
|
||||||
This function returns the current value of the Base Priority register.
|
|
||||||
|
|
||||||
\return Base Priority register value
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_BASEPRI(void)
|
|
||||||
{
|
|
||||||
uint32_t result;
|
|
||||||
|
|
||||||
__ASM volatile ("MRS %0, basepri" : "=r" (result) );
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Set Base Priority
|
|
||||||
|
|
||||||
This function assigns the given value to the Base Priority register.
|
|
||||||
|
|
||||||
\param [in] basePri Base Priority value to set
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_BASEPRI(uint32_t value)
|
|
||||||
{
|
|
||||||
__ASM volatile ("MSR basepri, %0" : : "r" (value) : "memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Set Base Priority with condition
|
|
||||||
|
|
||||||
This function assigns the given value to the Base Priority register only if BASEPRI masking is disabled,
|
|
||||||
or the new value increases the BASEPRI priority level.
|
|
||||||
|
|
||||||
\param [in] basePri Base Priority value to set
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_BASEPRI_MAX(uint32_t value)
|
|
||||||
{
|
|
||||||
__ASM volatile ("MSR basepri_max, %0" : : "r" (value) : "memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Get Fault Mask
|
|
||||||
|
|
||||||
This function returns the current value of the Fault Mask register.
|
|
||||||
|
|
||||||
\return Fault Mask register value
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FAULTMASK(void)
|
|
||||||
{
|
|
||||||
uint32_t result;
|
|
||||||
|
|
||||||
__ASM volatile ("MRS %0, faultmask" : "=r" (result) );
|
|
||||||
return(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Set Fault Mask
|
|
||||||
|
|
||||||
This function assigns the given value to the Fault Mask register.
|
|
||||||
|
|
||||||
\param [in] faultMask Fault Mask value to set
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_FAULTMASK(uint32_t faultMask)
|
|
||||||
{
|
|
||||||
__ASM volatile ("MSR faultmask, %0" : : "r" (faultMask) : "memory");
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* (__CORTEX_M >= 0x03) */
|
|
||||||
|
|
||||||
|
|
||||||
#if (__CORTEX_M == 0x04) || (__CORTEX_M == 0x07)
|
|
||||||
|
|
||||||
/** \brief Get FPSCR
|
|
||||||
|
|
||||||
This function returns the current value of the Floating Point Status/Control register.
|
|
||||||
|
|
||||||
\return Floating Point Status/Control register value
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE uint32_t __get_FPSCR(void)
|
|
||||||
{
|
|
||||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
|
||||||
uint32_t result;
|
|
||||||
|
|
||||||
/* Empty asm statement works as a scheduling barrier */
|
|
||||||
__ASM volatile ("");
|
|
||||||
__ASM volatile ("VMRS %0, fpscr" : "=r" (result) );
|
|
||||||
__ASM volatile ("");
|
|
||||||
return(result);
|
|
||||||
#else
|
|
||||||
return(0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/** \brief Set FPSCR
|
|
||||||
|
|
||||||
This function assigns the given value to the Floating Point Status/Control register.
|
|
||||||
|
|
||||||
\param [in] fpscr Floating Point Status/Control value to set
|
|
||||||
*/
|
|
||||||
__attribute__( ( always_inline ) ) __STATIC_INLINE void __set_FPSCR(uint32_t fpscr)
|
|
||||||
{
|
|
||||||
#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
|
|
||||||
/* Empty asm statement works as a scheduling barrier */
|
|
||||||
__ASM volatile ("");
|
|
||||||
__ASM volatile ("VMSR fpscr, %0" : : "r" (fpscr) : "vfpcc");
|
|
||||||
__ASM volatile ("");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* (__CORTEX_M == 0x04) || (__CORTEX_M == 0x07) */
|
|
||||||
|
|
||||||
|
|
||||||
#elif defined ( __ICCARM__ ) /*------------------ ICC Compiler -------------------*/
|
|
||||||
/* IAR iccarm specific functions */
|
|
||||||
#include <cmsis_iar.h>
|
|
||||||
|
|
||||||
|
|
||||||
#elif defined ( __TMS470__ ) /*---------------- TI CCS Compiler ------------------*/
|
|
||||||
/* TI CCS specific functions */
|
|
||||||
#include <cmsis_ccs.h>
|
|
||||||
|
|
||||||
|
|
||||||
#elif defined ( __TASKING__ ) /*------------------ TASKING Compiler --------------*/
|
|
||||||
/* TASKING carm specific functions */
|
|
||||||
/*
|
|
||||||
* The CMSIS functions have been implemented as intrinsics in the compiler.
|
|
||||||
* Please use "carm -?i" to get an up to date list of all intrinsics,
|
|
||||||
* Including the CMSIS ones.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
#elif defined ( __CSMC__ ) /*------------------ COSMIC Compiler -------------------*/
|
|
||||||
/* Cosmic specific functions */
|
|
||||||
#include <cmsis_csm.h>
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*@} end of CMSIS_Core_RegAccFunctions */
|
|
||||||
|
|
||||||
#endif /* __CORE_CMFUNC_H */
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user